diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 0edd337fa..fc45e7fc1 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -380,6 +380,8 @@ #define D_CMND_SWITCHRETAIN "SwitchRetain" #define D_CMND_POWERRETAIN "PowerRetain" #define D_CMND_SENSORRETAIN "SensorRetain" +#define D_CMND_INFORETAIN "InfoRetain" +#define D_CMND_STATERETAIN "StateRetain" #define D_CMND_PUBLISH "Publish" // Commands xdrv_01_webserver.ino diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index ac0d48699..b35a1c475 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -112,6 +112,8 @@ #define MQTT_POWER_RETAIN false // [PowerRetain] Power status message may send retain flag (false = off, true = on) #define MQTT_SWITCH_RETAIN false // [SwitchRetain] Switch may send retain flag (false = off, true = on) #define MQTT_SENSOR_RETAIN false // [SensorRetain] Sensor may send retain flag (false = off, true = on) +#define MQTT_INFO_RETAIN false // [InfoRetain] Info may send retain flag (false = off, true = on) +#define MQTT_STATE_RETAIN false // [StateRetain] State may send retain flag (false = off, true = on) #define MQTT_NO_HOLD_RETAIN false // [SetOption62] Disable retain flag on HOLD messages #define MQTT_NO_RETAIN false // [SetOption104] No Retain - disable all MQTT retained messages, some brokers don't support it: AWS IoT, Losant diff --git a/tasmota/settings.h b/tasmota/settings.h index 5f8484ea0..cb70f0a27 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -146,8 +146,8 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t zb_received_as_subtopic : 1; // bit 4 (v9.2.0.3) - SetOption118 - (Zigbee) Move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default uint32_t zb_omit_json_addr : 1; // bit 5 (v9.2.0.3) - SetOption119 - (Zigbee) Remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic uint32_t zb_topic_endpoint : 1; // bit 6 (v9.2.0.4) - SetOption120 - (Zigbee) Append endpoint number to topic if device dependent (use with SetOption89) - uint32_t spare07 : 1; // bit 7 - uint32_t spare08 : 1; // bit 8 + uint32_t mqtt_state_retain : 1; // bit 7 (v9.3.0.1) - CMND_STATERETAIN + uint32_t mqtt_info_retain : 1; // bit 8 (v9.3.0.1) - CMND_INFORETAIN uint32_t spare09 : 1; // bit 9 uint32_t spare10 : 1; // bit 10 uint32_t spare11 : 1; // bit 11 diff --git a/tasmota/settings.ino b/tasmota/settings.ino index 9a9d9dcb6..d4857bb15 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -831,6 +831,8 @@ void SettingsDefaultSet2(void) { flag.mqtt_button_retain |= MQTT_BUTTON_RETAIN; flag.mqtt_switch_retain |= MQTT_SWITCH_RETAIN; flag.mqtt_sensor_retain |= MQTT_SENSOR_RETAIN; + flag5.mqtt_info_retain |= MQTT_INFO_RETAIN; + flag5.mqtt_state_retain |= MQTT_STATE_RETAIN; // flag.mqtt_serial |= 0; flag.device_index_enable |= MQTT_POWER_FORMAT; flag3.time_append_timezone |= MQTT_APPEND_TIMEZONE; diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index f75a5cd89..3ce30232c 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -426,7 +426,8 @@ void CmndStatus(void) Response_P(PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_DEVICENAME "\":\"%s\",\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_LEDMASK "\":\"%04X\",\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_SWITCHTOPIC "\":\"%s\",\"" - D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"), + D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d,\"" + D_CMND_POWERRETAIN "\":%d,\"" D_CMND_INFORETAIN "\":%d,\"" D_CMND_STATERETAIN "\":%d}}"), ModuleNr(), EscapeJSONString(SettingsText(SET_DEVICENAME)).c_str(), stemp, TasmotaGlobal.mqtt_topic, SettingsText(SET_MQTT_BUTTON_TOPIC), TasmotaGlobal.power, Settings.poweronstate, Settings.ledstate, Settings.ledmask, Settings.save_data, @@ -436,7 +437,9 @@ void CmndStatus(void) Settings.flag.mqtt_button_retain, // CMND_BUTTONRETAIN Settings.flag.mqtt_switch_retain, // CMND_SWITCHRETAIN Settings.flag.mqtt_sensor_retain, // CMND_SENSORRETAIN - Settings.flag.mqtt_power_retain); // CMND_POWERRETAIN + Settings.flag.mqtt_power_retain, // CMND_POWERRETAIN + Settings.flag5.mqtt_info_retain, // CMND_INFORETAIN + Settings.flag5.mqtt_state_retain); // CMND_STATERETAIN MqttPublishPrefixTopic_P(STAT, PSTR(D_CMND_STATUS)); } @@ -629,7 +632,7 @@ void CmndState(void) ResponseClear(); MqttShowState(); if (Settings.flag3.hass_tele_on_power) { // SetOption59 - Send tele/%topic%/STATE in addition to stat/%topic%/RESULT - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), MQTT_TELE_RETAIN); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), Settings.flag5.mqtt_state_retain); } #ifdef USE_HOME_ASSISTANT if (Settings.flag.hass_discovery) { // SetOption19 - Control Home Assistantautomatic discovery (See SetOption59) diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index af9aca1e2..1e57256e6 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -715,7 +715,7 @@ void MqttPublishTeleState(void) { ResponseClear(); MqttShowState(); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), MQTT_TELE_RETAIN); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), Settings.flag5.mqtt_state_retain); #ifdef USE_DT_VARS DTVarsTeleperiod(); diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index 646df7037..b90007e44 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -48,7 +48,8 @@ const char kMqttCommands[] PROGMEM = "|" // No prefix #endif D_CMND_MQTTHOST "|" D_CMND_MQTTPORT "|" D_CMND_MQTTRETRY "|" D_CMND_STATETEXT "|" D_CMND_MQTTCLIENT "|" D_CMND_FULLTOPIC "|" D_CMND_PREFIX "|" D_CMND_GROUPTOPIC "|" D_CMND_TOPIC "|" D_CMND_PUBLISH "|" D_CMND_MQTTLOG "|" - D_CMND_BUTTONTOPIC "|" D_CMND_SWITCHTOPIC "|" D_CMND_BUTTONRETAIN "|" D_CMND_SWITCHRETAIN "|" D_CMND_POWERRETAIN "|" D_CMND_SENSORRETAIN ; + D_CMND_BUTTONTOPIC "|" D_CMND_SWITCHTOPIC "|" D_CMND_BUTTONRETAIN "|" D_CMND_SWITCHRETAIN "|" D_CMND_POWERRETAIN "|" + D_CMND_SENSORRETAIN "|" D_CMND_INFORETAIN "|" D_CMND_STATERETAIN ; SO_SYNONYMS(kMqttSynonyms, 90, @@ -73,7 +74,8 @@ void (* const MqttCommand[])(void) PROGMEM = { #endif &CmndMqttHost, &CmndMqttPort, &CmndMqttRetry, &CmndStateText, &CmndMqttClient, &CmndFullTopic, &CmndPrefix, &CmndGroupTopic, &CmndTopic, &CmndPublish, &CmndMqttlog, - &CmndButtonTopic, &CmndSwitchTopic, &CmndButtonRetain, &CmndSwitchRetain, &CmndPowerRetain, &CmndSensorRetain }; + &CmndButtonTopic, &CmndSwitchTopic, &CmndButtonRetain, &CmndSwitchRetain, &CmndPowerRetain, &CmndSensorRetain, + &CmndInfoRetain, &CmndStateRetain }; struct MQTT { uint16_t connect_count = 0; // MQTT re-connect count @@ -542,17 +544,17 @@ void MqttConnected(void) { char stopic2[TOPSZ]; Response_P(PSTR("{\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_FALLBACKTOPIC "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\"}"), ModuleName().c_str(), TasmotaGlobal.version, TasmotaGlobal.image_name, GetFallbackTopic_P(stopic, ""), GetGroupTopic_P(stopic2, "", SET_MQTT_GRP_TOPIC)); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "1")); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "1"), Settings.flag5.mqtt_info_retain); #ifdef USE_WEBSERVER if (Settings.webserver) { #if LWIP_IPV6 Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"IPv6Address\":\"%s\"}"), - (2 == Settings.webserver) ? PSTR(D_ADMIN) : PSTR(D_USER), NetworkHostname(), NetworkAddress().toString().c_str(), WifiGetIPv6().c_str()); + (2 == Settings.webserver) ? PSTR(D_ADMIN) : PSTR(D_USER), NetworkHostname(), NetworkAddress().toString().c_str(), WifiGetIPv6().c_str(), Settings.flag5.mqtt_info_retain); #else Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}"), - (2 == Settings.webserver) ? PSTR(D_ADMIN) : PSTR(D_USER), NetworkHostname(), NetworkAddress().toString().c_str()); + (2 == Settings.webserver) ? PSTR(D_ADMIN) : PSTR(D_USER), NetworkHostname(), NetworkAddress().toString().c_str(), Settings.flag5.mqtt_info_retain); #endif // LWIP_IPV6 = 1 - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "2")); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "2"), Settings.flag5.mqtt_info_retain); } #endif // USE_WEBSERVER Response_P(PSTR("{\"" D_JSON_RESTARTREASON "\":")); @@ -562,7 +564,7 @@ void MqttConnected(void) { ResponseAppend_P(PSTR("\"%s\""), GetResetReason().c_str()); } ResponseJsonEnd(); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "3")); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "3"), Settings.flag5.mqtt_info_retain); } MqttPublishAllPowerState(); @@ -1080,6 +1082,28 @@ void CmndSensorRetain(void) { ResponseCmndStateText(Settings.flag.mqtt_sensor_retain); // CMND_SENSORRETAIN } +void CmndInfoRetain(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + if (!XdrvMailbox.payload) { + ResponseClear(); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO), Settings.flag5.mqtt_info_retain); // CMND_INFORETAIN + } + Settings.flag5.mqtt_info_retain = XdrvMailbox.payload; // CMND_INFORETAIN + } + ResponseCmndStateText(Settings.flag5.mqtt_info_retain); // CMND_INFORETAIN +} + +void CmndStateRetain(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + if (!XdrvMailbox.payload) { + ResponseClear(); + MqttPublishPrefixTopic_P(STAT, PSTR(D_RSLT_STATE), Settings.flag5.mqtt_state_retain); // CMND_STATERETAIN + } + Settings.flag5.mqtt_state_retain = XdrvMailbox.payload; // CMND_STATERETAIN + } + ResponseCmndStateText(Settings.flag5.mqtt_state_retain); // CMND_STATERETAIN +} + /*********************************************************************************************\ * TLS private key and certificate - store into Flash \*********************************************************************************************/