From 6e23ca029bca0d552020d5b902d65513c7084c9c Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 31 May 2023 11:35:35 -0500 Subject: [PATCH] [DISC] Add runtime configuration for OpenHAB (#1658) * [DISC] Add runtime configuration for OpenHAB Add an MQTT configurable system key "ohdiscovery" for OpenHAB auto discovery * Docs and environments update --- .github/workflows/build.yml | 2 - docs/integrate/openhab2.md | 3 - docs/integrate/openhab3.md | 6 +- docs/use/gateway.md | 9 +++ environments.ini | 29 --------- main/ZgatewayBT.ino | 4 -- main/ZgatewayRTL_433.ino | 7 --- main/ZmqttDiscovery.ino | 23 ++++++- main/config_mqttDiscovery.h | 117 ++++++++++++------------------------ main/main.ino | 9 ++- platformio.ini | 2 - 11 files changed, 83 insertions(+), 128 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f4bce91..316f60f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,6 @@ jobs: - "esp32dev-gf-sun-inverter" - "esp32dev-ir" - "esp32dev-ble" - - "esp32dev-ble-openhab" - "esp32dev-ble-mqtt-undecoded" - "esp32dev-ble-aws" - "esp32feather-ble" @@ -60,7 +59,6 @@ jobs: - "nodemcuv2-rf-cc1101" - "nodemcuv2-somfy-cc1101" - "manual-wifi-test" - - "openhab-test" - "nodemcuv2-mqtt-fw-test" - "rf-wifi-gateway" - "nodemcuv2-rf2" diff --git a/docs/integrate/openhab2.md b/docs/integrate/openhab2.md index 3c6e38b..9837fb5 100644 --- a/docs/integrate/openhab2.md +++ b/docs/integrate/openhab2.md @@ -7,9 +7,6 @@ So as to use the autodiscovery function you need to have: * The Jinga transformation addon installed * The Json transformation addon installed -You need to set `OpenHABAutoDiscovery` to true into `config_mqttDiscovery.h` -`#define OpenHABDiscovery true` - ::: tip If you are connecting to BLE devices it is highly recommended to set `filterConnectable` to `true` in [BT configuration](../use/ble.md#advanced-filter-out-connectable-devices). Otherwise you may encounter incomplete data. ::: diff --git a/docs/integrate/openhab3.md b/docs/integrate/openhab3.md index 8e1aac3..4a640a4 100644 --- a/docs/integrate/openhab3.md +++ b/docs/integrate/openhab3.md @@ -64,7 +64,7 @@ Bravo👏, second step done! Now let's add the Jinja transformation service. Second step done! ## Upload OpenMQTTGateway to an ESP32 -[Upload OpenMQTTGateway from the web](../upload/web-install.md) by selecting `esp32dev-ble-openhab` +[Upload OpenMQTTGateway from the web](../upload/web-install.md) by selecting the environment corresponding to your need. Or use another upload method from the Upload section. @@ -75,6 +75,10 @@ Or use another upload method from the Upload section that requires credentials b You should see the gateway connected to your broker by checking with an MQTT client like MQTT Explorer. +To make the auto discovery compatible with OpenHAB you have to send the following command with a retain flag. + +`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"ohdiscovery":true}'` + ## Adding the things 1. From the Administration click on "Things" under "Settings", you should see a number in the INBOX button diff --git a/docs/use/gateway.md b/docs/use/gateway.md index d4460f3..f9f241d 100644 --- a/docs/use/gateway.md +++ b/docs/use/gateway.md @@ -33,6 +33,15 @@ If you want the settings to be kept upon gateway restart, you can publish the co 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. ::: +## AutoDiscovery compatible with OpenHAB (default: false) +OpenHAB does not support the key `is_defined` in the json template, to remove it at runtime and make the auto discovery compatible you can use the following command with a retain flag. + +`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"ohdiscovery":true}'` + +::: tip +This command can also be used with other controllers that does not support the is_defined key. +::: + ## Change the WiFi credentials `mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"wifi_ssid":"ssid", "wifi_pass":"password"}'` diff --git a/environments.ini b/environments.ini index 5e363e5..146121e 100644 --- a/environments.ini +++ b/environments.ini @@ -239,23 +239,6 @@ build_flags = '-DGateway_Name="OMG_ESP32_BLE"' custom_description = Regular BLE gateway with adaptive scanning activated, automatically adapts the scan parameters depending on your devices -[env:esp32dev-ble-openhab] -platform = ${com.esp32_platform} -board = esp32dev -board_build.partitions = min_spiffs.csv -lib_deps = - ${com-esp32.lib_deps} - ${libraries.ble} - ${libraries.decoder} -build_flags = - ${com-esp32.build_flags} - '-DZgatewayBT="BT"' - '-DLED_SEND_RECEIVE=2' - '-DLED_SEND_RECEIVE_ON=0' - '-DOpenHABDiscovery=true' - '-DGateway_Name="OMG_ESP32_BLE_OH"' -custom_description = BLE gateway with OpenHAB discovery and adaptive scanning activated, automatically adapts the scan parameters depending on your devices - [env:esp32dev-ble-mqtt-undecoded] platform = ${com.esp32_platform} board = esp32dev @@ -1222,18 +1205,6 @@ build_flags = '-DGateway_Name="OMG_TEST_MANUAL_WIFI"' board_build.flash_mode = dout -[env:openhab-test] -platform = ${com.esp8266_platform} -board = nodemcuv2 -lib_deps = - ${com-esp.lib_deps} - ${libraries.wifimanager8266} -build_flags = - ${com-esp.build_flags} - '-DOpenHABDiscovery=true' - '-DGateway_Name="OMG_TEST_OPENHAB"' -board_build.flash_mode = dout - [env:nodemcuv2-mqtt-fw-test] platform = ${com.esp8266_platform} board = nodemcuv2 diff --git a/main/ZgatewayBT.ino b/main/ZgatewayBT.ino index 8cced4c..1b640ed 100644 --- a/main/ZgatewayBT.ino +++ b/main/ZgatewayBT.ino @@ -1102,11 +1102,7 @@ void launchBTDiscovery(bool overrideDiscovery) { Log.trace(F("Name: %s"), prop.value()["name"].as()); String entity_name = String(model_id.c_str()) + "-" + String(prop.key().c_str()); String unique_id = macWOdots + "-" + String(prop.key().c_str()); -# if OpenHABDiscovery - String value_template = "{{ value_json." + String(prop.key().c_str()) + "}}"; -# else String value_template = "{{ value_json." + String(prop.key().c_str()) + " | is_defined }}"; -# endif if (p->sensorModel_id == TheengsDecoder::BLE_ID_NUM::SBS1 && strcmp(prop.key().c_str(), "state") != 0) { String payload_on = "{\"SBS1\":\"on\",\"mac\":\"" + String(p->macAdr) + "\"}"; String payload_off = "{\"SBS1\":\"off\",\"mac\":\"" + String(p->macAdr) + "\"}"; diff --git a/main/ZgatewayRTL_433.ino b/main/ZgatewayRTL_433.ino index b28e0bd..8497547 100644 --- a/main/ZgatewayRTL_433.ino +++ b/main/ZgatewayRTL_433.ino @@ -127,17 +127,10 @@ void launchRTL_433Discovery(bool overrideDiscovery) { String idWoKey = pdevice->uniqueId; idWoKey.remove(idWoKey.length() - (strlen(parameters[i][0]) + 1)); DISCOVERY_TRACE_LOG(F("idWoKey %s" CR), idWoKey.c_str()); -# if OpenHABDiscovery - String value_template = "{{ value_json." + String(parameters[i][0]) + "}}"; - if (strcmp(parameters[i][0], "battery_ok") == 0)) { - value_template = "{{ float(value_json." + String(parameters[i][0]) + ") * 99 + 1 }}"; // https://github.com/merbanan/rtl_433/blob/93f0f30c28cfb6b82b8cc3753415b01a85bee91d/examples/rtl_433_mqtt_hass.py#L187 - } -# else String value_template = "{{ value_json." + String(parameters[i][0]) + " | is_defined }}"; if (strcmp(parameters[i][0], "battery_ok") == 0) { 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 } -# endif String topic = subjectRTL_433toMQTT; # if valueAsATopic // Remove the key from the unique id to extract the device id diff --git a/main/ZmqttDiscovery.ino b/main/ZmqttDiscovery.ino index 314a0a2..7fa8601 100644 --- a/main/ZmqttDiscovery.ino +++ b/main/ZmqttDiscovery.ino @@ -192,6 +192,20 @@ void announceDeviceTrigger(bool use_gateway_info, char* topic, char* type, char* pub_custom_topic((char*)topic_to_publish.c_str(), sensor, true); } +/* + * Remove a substring p from a given string s +*/ +std::string remove_substring(std::string s, const std::string& p) { + std::string::size_type n = p.length(); + + for (std::string::size_type i = s.find(p); + i != std::string::npos; + i = s.find(p)) + s.erase(i, n); + + return s; +} + /** * @brief Generate message and publish it on an MQTT discovery explorer. For HA @see https://www.home-assistant.io/docs/mqtt/discovery/ * @@ -280,8 +294,13 @@ void createDiscovery(const char* sensor_type, sensor["uniq_id"] = unique_id; //unique_id if (retainCmd) sensor["retain"] = retainCmd; // Retain command - if (value_template[0]) - sensor["val_tpl"] = value_template; //value_template + if (value_template[0]) { + if (strstr(value_template, " | is_defined") != NULL && OpenHABDisc) { + sensor["val_tpl"] = remove_substring(value_template, " | is_defined"); //OpenHAB compatible HA auto discovery + } else { + sensor["val_tpl"] = value_template; //HA Auto discovery + } + } if (payload_on[0]) { if (strcmp(sensor_type, "button") == 0) { sensor["pl_prs"] = payload_on; // payload_press for a button press diff --git a/main/config_mqttDiscovery.h b/main/config_mqttDiscovery.h index 410142f..48c066b 100644 --- a/main/config_mqttDiscovery.h +++ b/main/config_mqttDiscovery.h @@ -135,83 +135,46 @@ void announceDeviceTrigger(bool use_gateway_info, # define OpenHABDiscovery false #endif -#if OpenHABDiscovery // OpenHAB autodiscovery value key definition (is defined command is not supported by OpenHAB) -# define jsonBatt "{{ value_json.batt }}" -# define jsonLux "{{ value_json.lux }}" -# define jsonPres "{{ value_json.pres }}" -# define jsonFer "{{ value_json.fer }}" -# define jsonFor "{{ value_json.for }}" -# define jsonMoi "{{ value_json.moi }}" -# define jsonHum "{{ value_json.hum }}" -# define jsonStep "{{ value_json.steps }}" -# define jsonWeight "{{ value_json.weight }}" -# define jsonPresence "{{ value_json.presence }}" -# define jsonAltim "{{ value_json.altim }}" -# define jsonAltif "{{ value_json.altift }}" -# define jsonTempc "{{ value_json.tempc }}" -# define jsonTempc2 "{{ value_json.tempc2 }}" -# define jsonTempc3 "{{ value_json.tempc3 }}" -# define jsonTempc4 "{{ value_json.tempc4 }}" -# define jsonTempf "{{ value_json.tempf }}" -# define jsonMsg "{{ value_json.message }}" -# define jsonVal "{{ value_json.value }}" -# define jsonVolt "{{ value_json.volt }}" -# define jsonCurrent "{{ value_json.current }}" -# define jsonPower "{{ value_json.power }}" -# define jsonEnergy "{{ value_json.energy }}" -# define jsonGpio "{{ value_json.gpio }}" -# define jsonFtcd "{{ value_json.ftcd }}" -# define jsonWm2 "{{ value_json.wattsm2 }}" -# define jsonAdc "{{ value_json.adc }}" -# define jsonPa "{{ float(value_json.pa) * 0.01 }}" -# define jsonId "{{ value_json.id }}" -# define jsonAddress "{{ value_json.address }}" -# define jsonOpen "{{ value_json.open }}" -# define jsonTime "{{ value_json.time }}" -# define jsonCount "{{ value_json.count }}" -# define jsonAlarm "{{ value_json.alarm }}" -# define jsonInuse "{{ value_json.power | float > 0 }}" -# define jsonInuseRN8209 "{% if value_json.power > 0.02 -%} on {% else %} off {%- endif %}" -# define jsonVoltBM2 "{% if value_json.uuid is not defined -%} {{value_json.volt}} {%- endif %}" -#else // Home assistant autodiscovery value key definition -# define jsonBatt "{{ value_json.batt | is_defined }}" -# define jsonLux "{{ value_json.lux | is_defined }}" -# define jsonPres "{{ value_json.pres | is_defined }}" -# define jsonFer "{{ value_json.fer | is_defined }}" -# define jsonFor "{{ value_json.for | is_defined }}" -# define jsonMoi "{{ value_json.moi | is_defined }}" -# define jsonHum "{{ value_json.hum | is_defined }}" -# define jsonStep "{{ value_json.steps | is_defined }}" -# define jsonWeight "{{ value_json.weight | is_defined }}" -# define jsonPresence "{{ value_json.presence | is_defined }}" -# define jsonAltim "{{ value_json.altim | is_defined }}" -# define jsonAltif "{{ value_json.altift | is_defined }}" -# define jsonTempc "{{ value_json.tempc | is_defined }}" -# define jsonTempc2 "{{ value_json.tempc2 | is_defined }}" -# define jsonTempc3 "{{ value_json.tempc3 | is_defined }}" -# define jsonTempc4 "{{ value_json.tempc4 | is_defined }}" -# define jsonTempf "{{ value_json.tempf | is_defined }}" -# define jsonMsg "{{ value_json.message | is_defined }}" -# define jsonVal "{{ value_json.value | is_defined }}" -# define jsonVolt "{{ value_json.volt | is_defined }}" -# define jsonCurrent "{{ value_json.current | is_defined }}" -# define jsonPower "{{ value_json.power | is_defined }}" -# define jsonEnergy "{{ value_json.energy | is_defined }}" -# define jsonGpio "{{ value_json.gpio | is_defined }}" -# define jsonFtcd "{{ value_json.ftcd | is_defined }}" -# define jsonWm2 "{{ value_json.wattsm2 | is_defined }}" -# define jsonAdc "{{ value_json.adc | is_defined }}" -# define jsonPa "{{ float(value_json.pa) * 0.01 | is_defined }}" -# define jsonId "{{ value_json.id | is_defined }}" -# define jsonAddress "{{ value_json.address | is_defined }}" -# define jsonOpen "{{ value_json.open | is_defined }}" -# define jsonTime "{{ value_json.time | is_defined }}" -# define jsonCount "{{ value_json.count | is_defined }}" -# define jsonAlarm "{{ value_json.alarm | is_defined }}" -# define jsonInuse "{{ value_json.power | is_defined | float > 0 }}" -# define jsonInuseRN8209 "{% if value_json.power > 0.02 -%} on {% else %} off {%- endif %}" -# define jsonVoltBM2 "{% if value_json.uuid is not defined and value_json.volt is defined -%} {{value_json.volt}} {%- endif %}" -#endif +boolean OpenHABDisc = OpenHABDiscovery; + +// Home assistant autodiscovery value key definition +#define jsonBatt "{{ value_json.batt | is_defined }}" +#define jsonLux "{{ value_json.lux | is_defined }}" +#define jsonPres "{{ value_json.pres | is_defined }}" +#define jsonFer "{{ value_json.fer | is_defined }}" +#define jsonFor "{{ value_json.for | is_defined }}" +#define jsonMoi "{{ value_json.moi | is_defined }}" +#define jsonHum "{{ value_json.hum | is_defined }}" +#define jsonStep "{{ value_json.steps | is_defined }}" +#define jsonWeight "{{ value_json.weight | is_defined }}" +#define jsonPresence "{{ value_json.presence | is_defined }}" +#define jsonAltim "{{ value_json.altim | is_defined }}" +#define jsonAltif "{{ value_json.altift | is_defined }}" +#define jsonTempc "{{ value_json.tempc | is_defined }}" +#define jsonTempc2 "{{ value_json.tempc2 | is_defined }}" +#define jsonTempc3 "{{ value_json.tempc3 | is_defined }}" +#define jsonTempc4 "{{ value_json.tempc4 | is_defined }}" +#define jsonTempf "{{ value_json.tempf | is_defined }}" +#define jsonMsg "{{ value_json.message | is_defined }}" +#define jsonVal "{{ value_json.value | is_defined }}" +#define jsonVolt "{{ value_json.volt | is_defined }}" +#define jsonCurrent "{{ value_json.current | is_defined }}" +#define jsonPower "{{ value_json.power | is_defined }}" +#define jsonEnergy "{{ value_json.energy | is_defined }}" +#define jsonGpio "{{ value_json.gpio | is_defined }}" +#define jsonFtcd "{{ value_json.ftcd | is_defined }}" +#define jsonWm2 "{{ value_json.wattsm2 | is_defined }}" +#define jsonAdc "{{ value_json.adc | is_defined }}" +#define jsonPa "{{ float(value_json.pa) * 0.01 | is_defined }}" +#define jsonId "{{ value_json.id | is_defined }}" +#define jsonAddress "{{ value_json.address | is_defined }}" +#define jsonOpen "{{ value_json.open | is_defined }}" +#define jsonTime "{{ value_json.time | is_defined }}" +#define jsonCount "{{ value_json.count | is_defined }}" +#define jsonAlarm "{{ value_json.alarm | is_defined }}" +#define jsonInuse "{{ value_json.power | is_defined | float > 0 }}" +#define jsonInuseRN8209 "{% if value_json.power > 0.02 -%} on {% else %} off {%- endif %}" +#define jsonVoltBM2 "{% if value_json.uuid is not defined and value_json.volt is defined -%} {{value_json.volt}} {%- endif %}" #define stateClassNone "" #define stateClassMeasurement "measurement" diff --git a/main/main.ino b/main/main.ino index f51b5c8..b9083bd 100644 --- a/main/main.ino +++ b/main/main.ino @@ -1972,6 +1972,7 @@ String stateMeasures() { SYSdata["version"] = OMG_VERSION; # ifdef ZmqttDiscovery SYSdata["discovery"] = disc; + SYSdata["ohdiscovery"] = OpenHABDisc; # endif # if defined(ESP8266) || defined(ESP32) SYSdata["env"] = ENV_NAME; @@ -2445,7 +2446,13 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding stateMeasures(); } } - +# ifdef ZmqttDiscovery + if (SYSdata.containsKey("ohdiscovery") && SYSdata["ohdiscovery"].is()) { + OpenHABDisc = SYSdata["ohdiscovery"]; + Log.notice(F("OpenHAB discovery: %T" CR), OpenHABDisc); + stateMeasures(); + } +# endif if (SYSdata.containsKey("wifi_ssid") && SYSdata.containsKey("wifi_pass")) { # if defined(ZgatewayBT) && defined(ESP32) stopProcessing(); diff --git a/platformio.ini b/platformio.ini index 87c8bd1..655bb50 100644 --- a/platformio.ini +++ b/platformio.ini @@ -41,7 +41,6 @@ extra_configs = ;default_envs = esp32dev-gf-sun-inverter ;default_envs = esp32dev-ir ;default_envs = esp32dev-ble -;default_envs = esp32dev-ble-openhab ;default_envs = esp32dev-ble-mqtt-undecoded ;default_envs = esp32dev-ble-aws ;default_envs = esp32feather-ble @@ -82,7 +81,6 @@ extra_configs = ;default_envs = nodemcuv2-rf-cc1101 ;default_envs = nodemcuv2-somfy-cc1101 ;default_envs = manual-wifi-test -;default_envs = openhab-test ;default_envs = nodemcuv2-mqtt-fw-test ;default_envs = rf-wifi-gateway ;default_envs = nodemcuv2-rf2