From a6c0a3b1d416f3a75f0027226909417417a6fb3e Mon Sep 17 00:00:00 2001 From: Florian Date: Sun, 30 Jul 2023 17:34:58 -0500 Subject: [PATCH] [SYS] Add save option to discovery and ohdiscovery key and remove discovery for Arduino boards (#1696) Enabling to keep discovery off if required Remove Mqtt discovery for Arduino UNO and ATMEGA --- docs/use/gateway.md | 6 ++- environments.ini | 3 ++ main/User_config.h | 8 +++- main/ZgatewayRF.ino | 2 +- main/ZgatewayRF2.ino | 2 +- main/ZgatewayRTL_433.ino | 4 +- main/ZmqttDiscovery.ino | 14 +++++- main/ZsensorDS1820.ino | 2 +- main/config_mqttDiscovery.h | 2 - main/main.ino | 93 +++++++++++++++++++++++++++++++------ 10 files changed, 110 insertions(+), 26 deletions(-) diff --git a/docs/use/gateway.md b/docs/use/gateway.md index f9f241dcd1..adbcc51766 100644 --- a/docs/use/gateway.md +++ b/docs/use/gateway.md @@ -27,7 +27,8 @@ You can deactivate the MQTT auto discovery function, this function enables to au ### Activate `mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"discovery":true}'` -If you want the settings to be kept upon gateway restart, you can publish the command with the retain flag. +If you want the settings to be kept upon gateway restart, you can save the state by adding `"save":true` (ESP32 only). +`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"discovery":false, "save":true}'` ::: tip Auto discovery is enable by default on release binaries, on platformio (except for UNO). With Arduino IDE please read the [advanced configuration section](../upload/advanced-configuration#auto-discovery) of the documentation. @@ -38,6 +39,9 @@ OpenHAB does not support the key `is_defined` in the json template, to remove it `mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"ohdiscovery":true}'` +If you want the settings to be kept upon gateway restart, you can save the state by adding `"save":true` (ESP32 only). +`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"ohdiscovery":true, "save":true}'` + ::: tip This command can also be used with other controllers that does not support the is_defined key. ::: diff --git a/environments.ini b/environments.ini index 2b636f06de..0de23702e5 100644 --- a/environments.ini +++ b/environments.ini @@ -1397,6 +1397,7 @@ build_flags = '-DZmqttDiscovery="HADiscovery"' '-DsimplePublishing=true' '-DGateway_Name="OMG_ATMEGA_ALL"' + '-UZmqttDiscovery="HADiscovery"' [env:uno-rf] platform = ${com.atmelavr_platform} @@ -1406,6 +1407,7 @@ lib_deps = ${libraries.rc-switch} build_flags = ${com-arduino-low-memory.build_flags} + '-UZmqttDiscovery="HADiscovery"' '-DZgatewayRF="RF"' '-DGateway_Name="OMG_1_RF"' '-DDISABLE_LOGGING' @@ -1421,6 +1423,7 @@ build_flags = ${com-arduino-low-memory.build_flags} '-DGateway_Name="OMG_1_FL"' '-DZactuatorFASTLED="FASTLED"' + '-UZmqttDiscovery="HADiscovery"' custom_description = FastLed control [env:esp32dev-ble-datatest] diff --git a/main/User_config.h b/main/User_config.h index 78be725cf1..136a2f610f 100644 --- a/main/User_config.h +++ b/main/User_config.h @@ -733,7 +733,6 @@ Preferences preferences; #endif #ifdef ZmqttDiscovery -bool disc = true; // Auto discovery with Home Assistant convention unsigned long lastDiscovery = 0; // Time of the last discovery to trigger automaticaly to off after DiscoveryAutoOffTimer #endif @@ -748,6 +747,13 @@ unsigned long lastDiscovery = 0; // Time of the last discovery to trigger automa # define isWhite(device) device->isWhtL # define isBlack(device) device->isBlkL # define isDiscovered(device) device->isDisc + +/*----------------CONFIGURABLE PARAMETERS-----------------*/ +struct SYSConfig_s { + bool discovery; // HA discovery convention + bool ohdiscovery; // OH discovery specificities +}; + #endif #if defined(ZgatewayRF) || defined(ZgatewayIR) || defined(ZgatewaySRFB) || defined(ZgatewayWeatherStation) || defined(ZgatewayRTL_433) diff --git a/main/ZgatewayRF.ino b/main/ZgatewayRF.ino index 7a18e217a1..dd12b8f1a1 100644 --- a/main/ZgatewayRF.ino +++ b/main/ZgatewayRF.ino @@ -164,7 +164,7 @@ void RFtoMQTT() { if (!isAduplicateSignal(MQTTvalue) && MQTTvalue != 0) { // conditions to avoid duplications of RF -->MQTT # if defined(ZmqttDiscovery) && !defined(RF_DISABLE_TRANSMIT) && defined(RFmqttDiscovery) //component creation for HA - if (disc) + if (SYSConfig.discovery) RFtoMQTTdiscovery(MQTTvalue); # endif pub(subjectRFtoMQTT, RFdata); diff --git a/main/ZgatewayRF2.ino b/main/ZgatewayRF2.ino index 43fae2830e..d97fec3968 100644 --- a/main/ZgatewayRF2.ino +++ b/main/ZgatewayRF2.ino @@ -131,7 +131,7 @@ void RF2toMQTT() { RF2data["address"] = (unsigned long)rf2rd.address; RF2data["switchType"] = (int)rf2rd.switchType; # ifdef ZmqttDiscovery //component creation for HA - if (disc) + if (SYSConfig.discovery) RF2toMQTTdiscovery(RF2data); # endif diff --git a/main/ZgatewayRTL_433.ino b/main/ZgatewayRTL_433.ino index 8da77d2b4c..63d9f4dc70 100644 --- a/main/ZgatewayRTL_433.ino +++ b/main/ZgatewayRTL_433.ino @@ -129,7 +129,7 @@ void launchRTL_433Discovery(bool overrideDiscovery) { DISCOVERY_TRACE_LOG(F("idWoKey %s" CR), idWoKey.c_str()); String value_template = "{{ value_json." + String(parameters[i][0]) + " | is_defined }}"; if (strcmp(parameters[i][0], "battery_ok") == 0) { - if (OpenHABDisc) { + if (SYSConfig.ohdiscovery) { value_template = "{{ value_json." + String(parameters[i][0]) + " * 99 + 1 }}"; // https://github.com/merbanan/rtl_433/blob/93f0f30c28cfb6b82b8cc3753415b01a85bee91d/examples/rtl_433_mqtt_hass.py#L187 } else { value_template = "{{ float(value_json." + String(parameters[i][0]) + ") * 99 + 1 | is_defined }}"; // https://github.com/merbanan/rtl_433/blob/93f0f30c28cfb6b82b8cc3753415b01a85bee91d/examples/rtl_433_mqtt_hass.py#L187 @@ -254,7 +254,7 @@ void rtl_433_Callback(char* message) { // Log.notice(F("uniqueid: %s" CR), uniqueid.c_str()); if (!isAduplicateSignal(MQTTvalue)) { # ifdef ZmqttDiscovery - if (disc) + if (SYSConfig.discovery) storeRTL_433Discovery(RFrtl_433_ESPdata, (char*)model.c_str(), (char*)uniqueid.c_str()); # endif pub((char*)topic.c_str(), RFrtl_433_ESPdata); diff --git a/main/ZmqttDiscovery.ino b/main/ZmqttDiscovery.ino index 7d96a1b1b6..92ecb937cb 100644 --- a/main/ZmqttDiscovery.ino +++ b/main/ZmqttDiscovery.ino @@ -295,7 +295,7 @@ void createDiscovery(const char* sensor_type, if (retainCmd) sensor["retain"] = retainCmd; // Retain command if (value_template[0]) { - if (strstr(value_template, " | is_defined") != NULL && OpenHABDisc) { + if (strstr(value_template, " | is_defined") != NULL && SYSConfig.ohdiscovery) { sensor["val_tpl"] = remove_substring(value_template, " | is_defined"); //OpenHAB compatible HA auto discovery } else { sensor["val_tpl"] = value_template; //HA Auto discovery @@ -487,7 +487,17 @@ void pubMqttDiscovery() { createDiscovery("switch", //set Type subjectSYStoMQTT, "SYS: Auto discovery", (char*)getUniqueId("discovery", "").c_str(), //set state_topic,name,uniqueId will_Topic, "", "{{ value_json.discovery }}", //set availability_topic,device_class,value_template, - "{\"discovery\":true}", "{\"discovery\":false}", "", //set,payload_on,payload_off,unit_of_meas, + "{\"discovery\":true,\"save\":true}", "{\"discovery\":false,\"save\":true}", "", //set,payload_on,payload_off,unit_of_meas, + 0, //set off_delay + Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoSYSset, //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic + "", "", "", "", true, // device name, device manufacturer, device model, device MAC, retain, + stateClassNone, //State Class + "false", "true" //state_off, state_on + ); + createDiscovery("switch", //set Type + subjectSYStoMQTT, "SYS: OpenHAB discovery", (char*)getUniqueId("ohdiscovery", "").c_str(), //set state_topic,name,uniqueId + will_Topic, "", "{{ value_json.ohdiscovery }}", //set availability_topic,device_class,value_template, + "{\"ohdiscovery\":true,\"save\":true}", "{\"ohdiscovery\":false,\"save\":true}", "", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoSYSset, //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic "", "", "", "", true, // device name, device manufacturer, device model, device MAC, retain, diff --git a/main/ZsensorDS1820.ino b/main/ZsensorDS1820.ino index b4385d7062..4b527b2919 100644 --- a/main/ZsensorDS1820.ino +++ b/main/ZsensorDS1820.ino @@ -101,7 +101,7 @@ void pubOneWire_HADiscovery() { // If zmqttDiscovery is enabled, create a sensor topic for each DS18b20 sensor found on the bus, using addr as uniqueID # ifdef ZmqttDiscovery // If zmqtt discovery is enabled, create a sensor topic for each DS18b20 sensor found on the bus, using addr as uniqueID - if (disc) { + if (SYSConfig.discovery) { for (int index = 0; index < ds1820_count; index++) { createDiscovery("sensor", (char*)(String(OW_TOPIC) + "/" + ds1820_addr[index]).c_str(), diff --git a/main/config_mqttDiscovery.h b/main/config_mqttDiscovery.h index 48c066ba27..d465b92455 100644 --- a/main/config_mqttDiscovery.h +++ b/main/config_mqttDiscovery.h @@ -135,8 +135,6 @@ void announceDeviceTrigger(bool use_gateway_info, # define OpenHABDiscovery false #endif -boolean OpenHABDisc = OpenHABDiscovery; - // Home assistant autodiscovery value key definition #define jsonBatt "{{ value_json.batt | is_defined }}" #define jsonLux "{{ value_json.lux | is_defined }}" diff --git a/main/main.ino b/main/main.ino index d2d0a41c7c..020ada33ba 100644 --- a/main/main.ino +++ b/main/main.ino @@ -224,6 +224,9 @@ unsigned long timer_led_measures = 0; static void* eClient = nullptr; static unsigned long last_ota_activity_millis = 0; #if defined(ESP8266) || defined(ESP32) +// Global struct to store live SYS configuration data +SYSConfig_s SYSConfig; + bool failSafeMode = false; static bool mqtt_secure = MQTT_SECURE_DEFAULT; static bool mqtt_cert_validate = MQTT_CERT_VALIDATE_DEFAULT; @@ -294,9 +297,9 @@ void Config_update(JsonObject& data, const char* key, T& var) { if (data.containsKey(key)) { if (var != data[key].as()) { var = data[key].as(); - Log.notice(F("Config %s changed: %s" CR), key, data[key].as()); + Log.notice(F("Config %s changed: %T" CR), key, data[key].as()); } else { - Log.notice(F("Config %s unchanged: %s" CR), key, data[key].as()); + Log.notice(F("Config %s unchanged: %T" CR), key, data[key].as()); } } } @@ -623,6 +626,48 @@ void delayWithOTA(long waitMillis) { #endif } +#ifdef ZmqttDiscovery +void SYSConfig_init() { + SYSConfig.discovery = true; + SYSConfig.ohdiscovery = OpenHABDiscovery; +} + +void SYSConfig_fromJson(JsonObject& SYSdata) { + Config_update(SYSdata, "discovery", SYSConfig.discovery); + Config_update(SYSdata, "ohdiscovery", SYSConfig.ohdiscovery); +} +#else +void SYSConfig_init() {} +void SYSConfig_fromJson(JsonObject& SYSdata) {} +#endif + +#if defined(ESP32) && defined(ZmqttDiscovery) +void SYSConfig_load() { + StaticJsonDocument jsonBuffer; + preferences.begin(Gateway_Short_Name, true); + if (preferences.isKey("SYSConfig")) { + auto error = deserializeJson(jsonBuffer, preferences.getString("SYSConfig", "{}")); + preferences.end(); + if (error) { + Log.error(F("SYS config deserialization failed: %s, buffer capacity: %u" CR), error.c_str(), jsonBuffer.capacity()); + return; + } + if (jsonBuffer.isNull()) { + Log.warning(F("SYS config is null" CR)); + return; + } + JsonObject jo = jsonBuffer.as(); + SYSConfig_fromJson(jo); + Log.notice(F("SYS config loaded" CR)); + } else { + preferences.end(); + Log.notice(F("SYS config not found" CR)); + } +} +#else // Function not available for ESP8266 +void SYSConfig_load() {} +#endif + void connectMQTT() { #ifndef ESPWifiManualSetup # if defined(ESP8266) || defined(ESP32) @@ -916,6 +961,9 @@ void setup() { modules.add(ZwebUI); #endif + SYSConfig_init(); + SYSConfig_load(); + #if defined(ESP8266) || defined(ESP32) if (mqtt_secure) { eClient = new WiFiClientSecure; @@ -1736,11 +1784,11 @@ void loop() { #ifdef ZmqttDiscovery // Deactivate autodiscovery after DiscoveryAutoOffTimer - if (disc && (now > lastDiscovery + DiscoveryAutoOffTimer)) - disc = false; + if (SYSConfig.discovery && (now > lastDiscovery + DiscoveryAutoOffTimer)) + SYSConfig.discovery = false; // at first connection we publish the discovery payloads // or, when we have just re-connected (only when discovery_republish_on_reconnect is enabled) - bool publishDiscovery = disc && (!connectedOnce || (discovery_republish_on_reconnect && justReconnected)); + bool publishDiscovery = SYSConfig.discovery && (!connectedOnce || (discovery_republish_on_reconnect && justReconnected)); if (publishDiscovery) { pubMqttDiscovery(); } @@ -1854,7 +1902,7 @@ void loop() { #endif #ifdef ZgatewayBT # ifdef ZmqttDiscovery - if (disc) + if (SYSConfig.discovery) launchBTDiscovery(publishDiscovery); # endif emptyBTQueue(); @@ -1885,7 +1933,7 @@ void loop() { #ifdef ZgatewayRTL_433 RTL_433Loop(); # ifdef ZmqttDiscovery - if (disc) + if (SYSConfig.discovery) launchRTL_433Discovery(publishDiscovery); # endif #endif @@ -2035,8 +2083,8 @@ String stateMeasures() { SYSdata["version"] = OMG_VERSION; # ifdef ZmqttDiscovery - SYSdata["discovery"] = disc; - SYSdata["ohdiscovery"] = OpenHABDisc; + SYSdata["discovery"] = SYSConfig.discovery; + SYSdata["ohdiscovery"] = SYSConfig.ohdiscovery; # endif # if defined(ESP8266) || defined(ESP32) SYSdata["env"] = ENV_NAME; @@ -2521,8 +2569,8 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding } # ifdef ZmqttDiscovery if (SYSdata.containsKey("ohdiscovery") && SYSdata["ohdiscovery"].is()) { - OpenHABDisc = SYSdata["ohdiscovery"]; - Log.notice(F("OpenHAB discovery: %T" CR), OpenHABDisc); + SYSConfig.ohdiscovery = SYSdata["ohdiscovery"]; + Log.notice(F("OpenHAB discovery: %T" CR), SYSConfig.ohdiscovery); stateMeasures(); } # endif @@ -2671,17 +2719,32 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding #ifdef ZmqttDiscovery if (SYSdata.containsKey("discovery")) { if (SYSdata["discovery"].is()) { - if (SYSdata["discovery"] == true && disc == false) + if (SYSdata["discovery"] == true && SYSConfig.discovery == false) lastDiscovery = millis(); - disc = SYSdata["discovery"]; + SYSConfig.discovery = SYSdata["discovery"]; stateMeasures(); - if (disc) + if (SYSConfig.discovery) pubMqttDiscovery(); } else { Log.error(F("Discovery command not a boolean" CR)); } - Log.notice(F("Discovery state: %T" CR), disc); + Log.notice(F("Discovery state: %T" CR), SYSConfig.discovery); } +# ifdef ESP32 + if (SYSdata.containsKey("save") && SYSdata["save"].as()) { + StaticJsonDocument jsonBuffer; + JsonObject jo = jsonBuffer.to(); + jo["discovery"] = SYSConfig.discovery; + jo["ohdiscovery"] = SYSConfig.ohdiscovery; + // Save config into NVS (non-volatile storage) + String conf = ""; + serializeJson(jsonBuffer, conf); + preferences.begin(Gateway_Short_Name, false); + int result = preferences.putString("SYSConfig", conf); + preferences.end(); + Log.notice(F("SYS Config_save: %s, result: %d" CR), conf.c_str(), result); + } +# endif #endif } }