Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/net/mqttHass.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ class MqttHass : public Mqtt {
MqttHass(WiFiClient&, const char*, const uint16_t, const char*, const char*);
bool isDiscoveryDone();
void setDiscoveryDone(bool);
void cleanupOldDiscovery(const Device*);
bool publishDevice(const Device*);
void subscribeDevice(const Device*);
void notifyAvailability(const Device*, const char*);
void notifyOnline(const Device*);
void notifyOffline(const Device*);
void notifyPower(const Device*);
void notifyPower(const Device*, DeviceStatus);
void notifyCover(const Device*);
void notifyBrightness(const Device* device);
};

Expand Down
3 changes: 1 addition & 2 deletions src/RF/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,7 @@ int Device::loadFromLittleFS(Device** devices, const unsigned int size) {

File f = LittleFS.open(LITTLEFS_CONFIG_FILENAME, "r");
if (!f) {
LOG.print(LITTLEFS_CONFIG_FILENAME);
LOG.println(" - File open failed");
// Normal on first boot — no devices saved yet
return 0;
}

Expand Down
5 changes: 5 additions & 0 deletions src/commands/callbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,11 @@ bool reloadConfig(const char*) {
}
g_nb_devices = Device::loadFromLittleFS(g_devices, MAX_YOKIS_DEVICES_NUM);

// Force MQTT re-discovery so new/removed devices are published to Home Assistant
#if MQTT_ENABLED
if (g_mqtt != NULL) g_mqtt->setDiscoveryDone(false);
#endif

// Reattach tickers to devices
for (uint8_t i = 0; i < g_nb_devices; i++) {
if (g_devices[i] != NULL) {
Expand Down
23 changes: 21 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,19 @@ void pollForStatus(Device* d) {

// Update device status - even if unchanged
// Hence, in case of hass restart, status are updated
d->setStatus(ds);
if (d->getMode() == DIMMER) {
d->setStatus(ds);
if (ds == ON && d->getBrightness() == 0)
d->setBrightness(BRIGHTNESS_MAX);
g_mqtt->notifyBrightness(d);
} else if (d->getMode() == SHUTTER || d->getMode() == SHUTTER_BUS) {
// For shutters, don't override status from polling.
// The RF status response doesn't reliably distinguish open/closed
// when the shutter is at rest. Keep the status set by the last
// command (OPEN/CLOSE/STOP) and just re-publish it for HA.
g_mqtt->notifyCover(d);
} else {
d->setStatus(ds);
g_mqtt->notifyPower(d);
}
} else {
Expand Down Expand Up @@ -328,9 +335,21 @@ void mqttCallback(char* topic, uint8_t* payload, unsigned int length) {
IrqManager::irqType = E2BP;
g_bp->setDevice(d);
switch (d->getMode()) {
case ON_OFF:
case SHUTTER:
case SHUTTER_BUS:
if (strcmp(mPayload, "OPEN") == 0) {
g_bp->on();
d->setStatus(ON);
} else if (strcmp(mPayload, "CLOSE") == 0) {
g_bp->off();
d->setStatus(OFF);
} else if (strcmp(mPayload, "STOP") == 0) {
g_bp->pauseShutter();
d->setStatus(PAUSE_SHUTTER);
}
g_mqtt->notifyCover(d);
break;
case ON_OFF:
case NO_RCPT:
if (strcmp(mPayload, "ON") == 0) {
g_bp->on();
Expand Down
84 changes: 81 additions & 3 deletions src/net/mqttHass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,34 @@ char* MqttHass::newMessageJson(const Device* device, char* buf) {
"}",
device->getName(), device->getName(),
device->getName(), device->getName());
} else if (device->getMode() == SHUTTER || device->getMode() == SHUTTER_BUS) {
sprintf(buf,
"{"
"\"name\":\"Shutter\","
"\"device_class\":\"shutter\","
"\"cmd_t\":\"~cmnd/COVER\","
"\"pl_open\":\"OPEN\","
"\"pl_cls\":\"CLOSE\","
"\"pl_stop\":\"STOP\","
"\"state_topic\":\"~tele/STATE\","
"\"state_open\":\"open\","
"\"state_closed\":\"closed\","
"\"state_stopped\":\"stopped\","
"\"val_tpl\":\"{{value_json.STATE}}\","
"\"avty_t\":\"~tele/LWT\","
"\"pl_avail\":\"Online\","
"\"pl_not_avail\":\"Offline\","
"\"uniq_id\":\"esp-%s\","
"\"device\":{"
"\"name\":\"%s\","
"\"identifiers\":[\"yokis-%s\"],"
"\"model\":\"MVR500ERX\","
"\"mf\":\"Yokis\""
"},"
"\"~\":\"%s/\""
"}",
device->getName(), device->getName(),
device->getName(), device->getName());
} else {
sprintf(buf,
"{"
Expand Down Expand Up @@ -92,16 +120,50 @@ char* MqttHass::newMessageJson(const Device* device, char* buf) {
}

char* MqttHass::newPublishTopic(const Device* device, char* buf) {
sprintf(buf, "%s/light/%s/config", HASS_PREFIX, device->getName());
const char* component;
if (device->getMode() == DIMMER) {
component = "light";
} else if (device->getMode() == SHUTTER || device->getMode() == SHUTTER_BUS) {
component = "cover";
} else {
component = "switch";
}
sprintf(buf, "%s/%s/%s/config", HASS_PREFIX, component, device->getName());
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change the current behavior where all switches are declared as light.

return buf;
}

// Remove stale discovery entries from old component types
// e.g. a switch that was previously published as a light
void MqttHass::cleanupOldDiscovery(const Device* device) {
char topic[128];
const char* components[] = {"light", "switch", "cover"};
const char* current;

if (device->getMode() == DIMMER) {
current = "light";
} else if (device->getMode() == SHUTTER || device->getMode() == SHUTTER_BUS) {
current = "cover";
} else {
current = "switch";
}

for (uint8_t i = 0; i < 3; i++) {
if (strcmp(components[i], current) != 0) {
sprintf(topic, "%s/%s/%s/config", HASS_PREFIX, components[i], device->getName());
this->publish(topic, "", true);
}
}
}

// Publish device to MQTT for HASS discovery
bool MqttHass::publishDevice(const Device* device) {
bool ret;
char topic[128];
char payload[MQTT_MAX_PACKET_SIZE];

// Clean up old retained entries under wrong component types
cleanupOldDiscovery(device);

newPublishTopic(device, topic);
newMessageJson(device, payload);

Expand Down Expand Up @@ -150,6 +212,19 @@ void MqttHass::notifyPower(const Device* device, DeviceStatus ds) {
publish(buf, bufPayload, false);
}

void MqttHass::notifyCover(const Device* device) {
char buf[64];
char bufPayload[64];

sprintf(buf, "%s/tele/STATE", device->getName());
const char* state;
if (device->getStatus() == ON) state = "open";
else if (device->getStatus() == PAUSE_SHUTTER) state = "stopped";
else state = "closed";
sprintf(bufPayload, "{\"STATE\":\"%s\"}", state);
publish(buf, bufPayload, false);
}

void MqttHass::notifyBrightness(const Device* device) {
char buf[64];
char bufPayload[64];
Expand All @@ -165,8 +240,8 @@ void MqttHass::notifyBrightness(const Device* device) {
void MqttHass::subscribeDevice(const Device* device) {
char buf[64];

if (device->getMode() == ON_OFF || device->getMode() == NO_RCPT) {
sprintf(buf, "%s/cmnd/POWER", device->getName());
if (device->getMode() == SHUTTER || device->getMode() == SHUTTER_BUS) {
sprintf(buf, "%s/cmnd/COVER", device->getName());
this->subscribe(buf);
} else if (device->getMode() == DIMMER) {
sprintf(buf, "%s/cmnd/POWER", device->getName());
Expand All @@ -175,6 +250,9 @@ void MqttHass::subscribeDevice(const Device* device) {
this->subscribe(buf);
sprintf(buf, "%s/cmnd/FX", device->getName());
this->subscribe(buf);
} else {
sprintf(buf, "%s/cmnd/POWER", device->getName());
this->subscribe(buf);
}
}
#endif