2020-03-25 08:00:55 +00:00
|
|
|
#include "wled.h"
|
2020-03-31 00:38:08 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* MQTT communication protocol for home automation
|
|
|
|
*/
|
2018-09-28 21:53:51 +00:00
|
|
|
|
2019-12-10 23:59:15 +00:00
|
|
|
#ifdef WLED_ENABLE_MQTT
|
2020-02-22 16:20:34 +00:00
|
|
|
#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds
|
2019-12-10 23:59:15 +00:00
|
|
|
|
2018-09-30 18:24:57 +00:00
|
|
|
void parseMQTTBriPayload(char* payload)
|
|
|
|
{
|
2019-04-14 17:31:25 +00:00
|
|
|
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; colorUpdated(1);}
|
2019-03-27 20:31:59 +00:00
|
|
|
else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); colorUpdated(1);}
|
2018-09-30 18:24:57 +00:00
|
|
|
else {
|
|
|
|
uint8_t in = strtoul(payload, NULL, 10);
|
|
|
|
if (in == 0 && bri > 0) briLast = bri;
|
|
|
|
bri = in;
|
2021-07-09 16:54:28 +00:00
|
|
|
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
2018-09-28 21:53:51 +00:00
|
|
|
}
|
2018-09-30 18:24:57 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 16:00:36 +00:00
|
|
|
|
2019-02-17 18:21:09 +00:00
|
|
|
void onMqttConnect(bool sessionPresent)
|
|
|
|
{
|
|
|
|
//(re)subscribe to required topics
|
|
|
|
char subuf[38];
|
2019-08-17 10:27:06 +00:00
|
|
|
|
2021-05-07 10:41:39 +00:00
|
|
|
if (mqttDeviceTopic[0] != 0) {
|
2021-09-10 23:17:42 +00:00
|
|
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
2019-02-17 18:21:09 +00:00
|
|
|
mqtt->subscribe(subuf, 0);
|
2021-05-07 10:41:39 +00:00
|
|
|
strcat_P(subuf, PSTR("/col"));
|
2019-02-17 18:21:09 +00:00
|
|
|
mqtt->subscribe(subuf, 0);
|
2021-09-10 23:17:42 +00:00
|
|
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
2021-05-07 10:41:39 +00:00
|
|
|
strcat_P(subuf, PSTR("/api"));
|
2019-02-17 18:21:09 +00:00
|
|
|
mqtt->subscribe(subuf, 0);
|
|
|
|
}
|
|
|
|
|
2021-05-07 10:41:39 +00:00
|
|
|
if (mqttGroupTopic[0] != 0) {
|
2021-09-10 23:17:42 +00:00
|
|
|
strlcpy(subuf, mqttGroupTopic, 33);
|
2019-02-17 18:21:09 +00:00
|
|
|
mqtt->subscribe(subuf, 0);
|
2021-05-07 10:41:39 +00:00
|
|
|
strcat_P(subuf, PSTR("/col"));
|
2019-02-17 18:21:09 +00:00
|
|
|
mqtt->subscribe(subuf, 0);
|
2021-09-10 23:17:42 +00:00
|
|
|
strlcpy(subuf, mqttGroupTopic, 33);
|
2021-05-07 10:41:39 +00:00
|
|
|
strcat_P(subuf, PSTR("/api"));
|
2019-02-17 18:21:09 +00:00
|
|
|
mqtt->subscribe(subuf, 0);
|
|
|
|
}
|
2019-03-18 16:23:39 +00:00
|
|
|
|
2021-05-07 10:41:39 +00:00
|
|
|
usermods.onMqttConnect(sessionPresent);
|
|
|
|
|
2019-10-24 22:14:58 +00:00
|
|
|
doPublishMqtt = true;
|
2020-09-19 23:18:31 +00:00
|
|
|
DEBUG_PRINTLN(F("MQTT ready"));
|
2019-02-17 18:21:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
2018-09-30 18:24:57 +00:00
|
|
|
|
2020-09-19 23:18:31 +00:00
|
|
|
DEBUG_PRINT(F("MQTT msg: "));
|
2018-09-30 18:24:57 +00:00
|
|
|
DEBUG_PRINTLN(topic);
|
2020-08-19 22:13:06 +00:00
|
|
|
|
|
|
|
// paranoia check to avoid npe if no payload
|
|
|
|
if (payload==nullptr) {
|
2020-09-19 23:18:31 +00:00
|
|
|
DEBUG_PRINTLN(F("no payload -> leave"));
|
2020-08-19 22:13:06 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-05-17 08:38:07 +00:00
|
|
|
//make a copy of the payload to 0-terminate it
|
|
|
|
char* payloadStr = new char[len+1];
|
2021-05-20 19:41:39 +00:00
|
|
|
if (payloadStr == nullptr) return; //no mem
|
2021-05-17 08:38:07 +00:00
|
|
|
strncpy(payloadStr, payload, len);
|
|
|
|
payloadStr[len] = '\0';
|
2021-05-12 23:04:33 +00:00
|
|
|
DEBUG_PRINTLN(payloadStr);
|
2018-09-30 18:24:57 +00:00
|
|
|
|
2020-11-01 01:23:37 +00:00
|
|
|
size_t topicPrefixLen = strlen(mqttDeviceTopic);
|
|
|
|
if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) {
|
2021-05-07 10:41:39 +00:00
|
|
|
topic += topicPrefixLen;
|
2020-11-01 01:23:37 +00:00
|
|
|
} else {
|
2021-05-07 10:41:39 +00:00
|
|
|
topicPrefixLen = strlen(mqttGroupTopic);
|
|
|
|
if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) {
|
|
|
|
topic += topicPrefixLen;
|
|
|
|
} else {
|
|
|
|
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
|
2021-05-12 23:04:33 +00:00
|
|
|
usermods.onMqttMessage(topic, payloadStr);
|
2021-05-17 08:38:07 +00:00
|
|
|
delete[] payloadStr;
|
2021-05-07 10:41:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-11-01 01:23:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Prefix is stripped from the topic at this point
|
2018-09-30 18:24:57 +00:00
|
|
|
|
2021-05-07 10:41:39 +00:00
|
|
|
if (strcmp_P(topic, PSTR("/col")) == 0) {
|
2021-05-12 23:04:33 +00:00
|
|
|
colorFromDecOrHexString(col, (char*)payloadStr);
|
2021-07-09 16:54:28 +00:00
|
|
|
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
2021-05-07 10:41:39 +00:00
|
|
|
} else if (strcmp_P(topic, PSTR("/api")) == 0) {
|
2020-11-12 08:13:08 +00:00
|
|
|
if (payload[0] == '{') { //JSON API
|
|
|
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
|
2021-05-12 23:04:33 +00:00
|
|
|
deserializeJson(doc, payloadStr);
|
2021-07-09 16:42:52 +00:00
|
|
|
fileDoc = &doc;
|
2020-11-12 08:13:08 +00:00
|
|
|
deserializeState(doc.as<JsonObject>());
|
2021-07-09 16:42:52 +00:00
|
|
|
fileDoc = nullptr;
|
2020-11-12 08:13:08 +00:00
|
|
|
} else { //HTTP API
|
|
|
|
String apireq = "win&";
|
2021-05-12 23:04:33 +00:00
|
|
|
apireq += (char*)payloadStr;
|
2020-11-12 08:13:08 +00:00
|
|
|
handleSet(nullptr, apireq);
|
|
|
|
}
|
2021-05-07 10:41:39 +00:00
|
|
|
} else if (strlen(topic) != 0) {
|
|
|
|
// non standard topic, check with usermods
|
2021-05-12 23:04:33 +00:00
|
|
|
usermods.onMqttMessage(topic, payloadStr);
|
2021-05-07 10:41:39 +00:00
|
|
|
} else {
|
|
|
|
// topmost topic (just wled/MAC)
|
2021-05-12 23:04:33 +00:00
|
|
|
parseMQTTBriPayload(payloadStr);
|
2020-11-01 01:23:37 +00:00
|
|
|
}
|
2021-05-17 08:38:07 +00:00
|
|
|
delete[] payloadStr;
|
2018-09-28 21:53:51 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 16:00:36 +00:00
|
|
|
|
2019-02-17 18:21:09 +00:00
|
|
|
void publishMqtt()
|
2018-09-28 21:53:51 +00:00
|
|
|
{
|
2019-10-20 15:38:25 +00:00
|
|
|
doPublishMqtt = false;
|
2020-05-28 00:20:02 +00:00
|
|
|
if (!WLED_MQTT_CONNECTED) return;
|
2020-09-19 23:18:31 +00:00
|
|
|
DEBUG_PRINTLN(F("Publish MQTT"));
|
2018-09-28 21:53:51 +00:00
|
|
|
|
2018-10-04 14:50:12 +00:00
|
|
|
char s[10];
|
|
|
|
char subuf[38];
|
2019-08-17 10:27:06 +00:00
|
|
|
|
2021-05-07 10:41:39 +00:00
|
|
|
sprintf_P(s, PSTR("%u"), bri);
|
2021-09-10 23:17:42 +00:00
|
|
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
2021-05-07 10:41:39 +00:00
|
|
|
strcat_P(subuf, PSTR("/g"));
|
2019-02-17 18:21:09 +00:00
|
|
|
mqtt->publish(subuf, 0, true, s);
|
2018-10-04 14:50:12 +00:00
|
|
|
|
2021-05-07 10:41:39 +00:00
|
|
|
sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
2021-09-10 23:17:42 +00:00
|
|
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
2021-05-07 10:41:39 +00:00
|
|
|
strcat_P(subuf, PSTR("/c"));
|
2019-02-17 18:21:09 +00:00
|
|
|
mqtt->publish(subuf, 0, true, s);
|
2018-10-04 14:50:12 +00:00
|
|
|
|
2021-09-10 23:17:42 +00:00
|
|
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
2021-05-07 10:41:39 +00:00
|
|
|
strcat_P(subuf, PSTR("/status"));
|
2020-09-29 19:41:52 +00:00
|
|
|
mqtt->publish(subuf, 0, true, "online");
|
2019-11-10 21:13:07 +00:00
|
|
|
|
2019-03-16 01:09:37 +00:00
|
|
|
char apires[1024];
|
2019-12-04 01:01:47 +00:00
|
|
|
XML_response(nullptr, apires);
|
2021-09-10 23:17:42 +00:00
|
|
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
2021-05-07 10:41:39 +00:00
|
|
|
strcat_P(subuf, PSTR("/v"));
|
2021-05-23 16:49:23 +00:00
|
|
|
mqtt->publish(subuf, 0, false, apires);
|
2018-09-28 21:53:51 +00:00
|
|
|
}
|
|
|
|
|
2019-03-23 23:49:26 +00:00
|
|
|
|
2019-12-04 01:01:47 +00:00
|
|
|
//HA autodiscovery was removed in favor of the native integration in HA v0.102.0
|
2018-11-09 16:00:36 +00:00
|
|
|
|
2019-02-17 18:21:09 +00:00
|
|
|
bool initMqtt()
|
2018-09-28 21:53:51 +00:00
|
|
|
{
|
2019-12-13 00:23:07 +00:00
|
|
|
if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false;
|
2019-10-18 12:06:07 +00:00
|
|
|
|
2019-10-20 10:48:29 +00:00
|
|
|
if (mqtt == nullptr) {
|
|
|
|
mqtt = new AsyncMqttClient();
|
|
|
|
mqtt->onMessage(onMqttMessage);
|
|
|
|
mqtt->onConnect(onMqttConnect);
|
|
|
|
}
|
2019-05-21 16:50:56 +00:00
|
|
|
if (mqtt->connected()) return true;
|
2019-08-17 10:27:06 +00:00
|
|
|
|
2020-09-19 23:18:31 +00:00
|
|
|
DEBUG_PRINTLN(F("Reconnecting MQTT"));
|
2018-09-28 21:53:51 +00:00
|
|
|
IPAddress mqttIP;
|
|
|
|
if (mqttIP.fromString(mqttServer)) //see if server is IP or domain
|
|
|
|
{
|
2019-08-18 16:14:17 +00:00
|
|
|
mqtt->setServer(mqttIP, mqttPort);
|
2018-09-28 21:53:51 +00:00
|
|
|
} else {
|
2019-08-18 16:14:17 +00:00
|
|
|
mqtt->setServer(mqttServer, mqttPort);
|
2018-09-28 21:53:51 +00:00
|
|
|
}
|
2019-08-17 10:27:06 +00:00
|
|
|
mqtt->setClientId(mqttClientID);
|
2019-10-18 21:47:11 +00:00
|
|
|
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
|
2019-11-10 21:13:07 +00:00
|
|
|
|
2021-09-10 23:17:42 +00:00
|
|
|
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
2021-05-07 10:41:39 +00:00
|
|
|
strcat_P(mqttStatusTopic, PSTR("/status"));
|
2020-09-29 19:41:52 +00:00
|
|
|
mqtt->setWill(mqttStatusTopic, 0, true, "offline");
|
2020-02-22 16:20:34 +00:00
|
|
|
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
2019-02-17 18:21:09 +00:00
|
|
|
mqtt->connect();
|
2018-09-28 21:53:51 +00:00
|
|
|
return true;
|
|
|
|
}
|
2019-12-10 23:59:15 +00:00
|
|
|
|
|
|
|
#else
|
|
|
|
bool initMqtt(){return false;}
|
|
|
|
void publishMqtt(){}
|
|
|
|
#endif
|