From 16815f51da3103f8ea37094479eab6dc804f7979 Mon Sep 17 00:00:00 2001 From: Florian Date: Sat, 7 Jan 2023 20:34:43 -0600 Subject: [PATCH] Add RTL_433 discovery with Home Assistant convention inspired from rtl_433_mqtt_hass.py (#1379) This also changes the topic structure when using the macro valueAsATopic=true, it adds as sub-topics the `type, subtype, and channel` when they exist. The id is the last subtopic to facilitate filtering, as it may change when replacing the batteries. Co-authored-by: NorthernMan54 <19808920+NorthernMan54@users.noreply.github.com> --- docs/integrate/home_assistant.md | 39 +++++- docs/use/rf.md | 3 +- main/ZgatewayBT.ino | 11 -- main/ZgatewayRTL_433.ino | 203 +++++++++++++++++++++++++++++-- main/ZmqttDiscovery.ino | 116 +++++++++--------- main/config_RF.h | 58 +++++++++ main/config_mqttDiscovery.h | 13 +- main/main.ino | 15 +++ platformio.ini | 34 +++--- 9 files changed, 389 insertions(+), 103 deletions(-) diff --git a/docs/integrate/home_assistant.md b/docs/integrate/home_assistant.md index 9e219c7..3c5555c 100644 --- a/docs/integrate/home_assistant.md +++ b/docs/integrate/home_assistant.md @@ -33,6 +33,42 @@ OMG will use the auto discovery functionality of home assistant to create gatewa ![](../img/OpenMQTTGateway_Home_Assistant_MQTT_discovery.png) +::: info +The Bluetooth and the RTL_433 gateway will create automatically devices and entities, the RF gateway will create DeviceTrigger. +The OpenMQTTGateway will also be available as a device to monitor its parameters and control it. The sensors (DHT for example) and actuators (relays) are attached to the gateway. +::: + +## RTL_433 auto discovery specificity + +Even if the RTL_433 gateway will create automatically the devices and entities, you may loose the link to them when you change the batteries. This is proper to the RF devices. In this case new device and entities will be created. You may bypass this by creating entities through manual configuration that filter following the device model and other parameters and don't take into account the id. +Example: +```yaml +mqtt: + sensor: + - state_topic: "+/+/RTL_433toMQTT/WS2032/+" +``` +instead of +```yaml +mqtt: + sensor: + - state_topic: "+/+/RTL_433toMQTT/WS2032/47998" +``` +Note also that the sensor may leverage channels, types or subtypes, they can be used in the filtering +Example: +In the example below 9 is the `subtype` and 1 is the `channel` +```yaml +mqtt: + sensor: + - state_topic: "+/+/RTL_433toMQTT/Prologue-TH/9/1/+" +``` +instead of +```yaml +mqtt: + sensor: + - state_topic: "+/+/RTL_433toMQTT/Prologue-TH/9/1/215" +``` + +Alternatively the rssi signal could be used also. ## MQTT Device Trigger and RF @@ -40,9 +76,6 @@ With OpenMQTTGateway [configured to receive RF signals](./setitup/rf.html) the m With autodiscovery enabled, HomeAssistant will discover a [MQTT Device Trigger](https://www.home-assistant.io/integrations/device_trigger.mqtt/) identified by the value field given in the mqtt argument. - - - ## Manual integration examples From @123, @finity, @denniz03, @jrockstad, @anarchking, @dkluivingh diff --git a/docs/use/rf.md b/docs/use/rf.md index b73801e..047037c 100644 --- a/docs/use/rf.md +++ b/docs/use/rf.md @@ -250,7 +250,7 @@ This feature is only available on a ESP32 based device with a supported transcei ### Supported hardware combinations - ESP32 based device with a CC1101 transceiver -- Heltec WiFi LoRa 32 (V2.1) +- Heltec WiFi LoRa 32 (V2.1) and LilyGo Lora 32 V2.1 ### Supported Decoders @@ -349,7 +349,6 @@ Delta applied to RSSI floor noise level to determine start and end of signal, de `home/OpenMQTTGateway/commands/MQTTtoRTL_433 {"rssi": 9}` - ### Retrieve current status of receiver `home/OpenMQTTGateway/commands/MQTTtoRTL_433 {"status":1}` diff --git a/main/ZgatewayBT.ino b/main/ZgatewayBT.ino index 1510db3..124201c 100644 --- a/main/ZgatewayBT.ino +++ b/main/ZgatewayBT.ino @@ -47,7 +47,6 @@ QueueHandle_t BLEQueue; # include # include -# include # include "ZgatewayBLEConnect.h" # include "soc/timer_group_reg.h" @@ -58,12 +57,6 @@ using namespace std; // Global struct to store live BT configuration data BTConfig_s BTConfig; -# define device_flags_init 0 << 0 -# define device_flags_isDisc 1 << 0 -# define device_flags_isWhiteL 1 << 1 -# define device_flags_isBlackL 1 << 2 -# define device_flags_connect 1 << 3 - TheengsDecoder decoder; struct decompose { @@ -412,10 +405,6 @@ void createOrUpdateDevice(const char* mac, uint8_t flags, int model, int mac_typ xSemaphoreGive(semaphoreCreateOrUpdateDevice); } -# define isWhite(device) device->isWhtL -# define isBlack(device) device->isBlkL -# define isDiscovered(device) device->isDisc - void dumpDevices() { for (vector::iterator it = devices.begin(); it != devices.end(); ++it) { BLEdevice* p = *it; diff --git a/main/ZgatewayRTL_433.ino b/main/ZgatewayRTL_433.ino index 82c088e..c93edcd 100644 --- a/main/ZgatewayRTL_433.ino +++ b/main/ZgatewayRTL_433.ino @@ -34,34 +34,215 @@ # include "ArduinoLog.h" # include "User_config.h" +# ifdef ZmqttDiscovery +# include "config_mqttDiscovery.h" +# endif char messageBuffer[JSON_MSG_BUFFER]; rtl_433_ESP rtl_433(-1); +# ifdef ZmqttDiscovery +SemaphoreHandle_t semaphorecreateOrUpdateDeviceRTL_433; +std::vector RTL_433devices; +int newRTL_433Devices = 0; + +static RTL_433device NO_DEVICE_FOUND = {{0}, + 0, + false}; + +RTL_433device* getDeviceById(const char* id); // Declared here to avoid pre-compilation issue (misplaced auto declaration by pio) +RTL_433device* getDeviceById(const char* id) { + Log.trace(F("getDeviceById %s" CR), id); + + for (std::vector::iterator it = RTL_433devices.begin(); it != RTL_433devices.end(); ++it) { + if ((strcmp((*it)->uniqueId, id) == 0)) { + return *it; + } + } + return &NO_DEVICE_FOUND; +} + +void dumpRTL_433Devices() { + for (std::vector::iterator it = RTL_433devices.begin(); it != RTL_433devices.end(); ++it) { + RTL_433device* p = *it; + Log.trace(F("uniqueId %s" CR), p->uniqueId); + Log.trace(F("modelName %s" CR), p->modelName); + Log.trace(F("isDisc %d" CR), p->isDisc); + } +} + +void createOrUpdateDeviceRTL_433(const char* id, const char* model, uint8_t flags) { + if (xSemaphoreTake(semaphorecreateOrUpdateDeviceRTL_433, pdMS_TO_TICKS(30000)) == pdFALSE) { + Log.error(F("[rtl_433] semaphorecreateOrUpdateDeviceRTL_433 Semaphore NOT taken" CR)); + return; + } + + RTL_433device* device = getDeviceById(id); + if (device == &NO_DEVICE_FOUND) { + Log.trace(F("add %s" CR), id); + //new device + device = new RTL_433device(); + if (strlcpy(device->uniqueId, id, uniqueIdSize) > uniqueIdSize) { + Log.warning(F("[rtl_433] Device id %s exceeds available space" CR), id); // Remove from production release ? + }; + if (strlcpy(device->modelName, model, modelNameSize) > modelNameSize) { + Log.warning(F("[rtl_433] Device model %s exceeds available space" CR), id); // Remove from production release ? + }; + device->isDisc = flags & device_flags_isDisc; + RTL_433devices.push_back(device); + newRTL_433Devices++; + } else { + Log.trace(F("update %s" CR), id); + + if (flags & device_flags_isDisc) { + device->isDisc = true; + } + } + + xSemaphoreGive(semaphorecreateOrUpdateDeviceRTL_433); +} + +// This function always should be called from the main core as it generates direct mqtt messages +// When overrideDiscovery=true, we publish discovery messages of known RTL_433devices (even if no new) +void launchRTL_433Discovery(bool overrideDiscovery) { + if (!overrideDiscovery && newRTL_433Devices == 0) + return; + if (xSemaphoreTake(semaphorecreateOrUpdateDeviceRTL_433, pdMS_TO_TICKS(1000)) == pdFALSE) { + Log.error(F("[rtl_433] semaphorecreateOrUpdateDeviceRTL_433 Semaphore NOT taken" CR)); + return; + } + newRTL_433Devices = 0; + std::vector localDevices = RTL_433devices; + xSemaphoreGive(semaphorecreateOrUpdateDeviceRTL_433); + for (std::vector::iterator it = localDevices.begin(); it != localDevices.end(); ++it) { + RTL_433device* pdevice = *it; + Log.trace(F("Device id %s" CR), pdevice->uniqueId); + // Do not launch discovery for the RTL_433devices already discovered (unless we have overrideDiscovery) or that are not unique by their MAC Address (Ibeacon, GAEN and Microsoft Cdp) + if (overrideDiscovery || !isDiscovered(pdevice)) { + size_t numRows = sizeof(parameters) / sizeof(parameters[0]); + for (int i = 0; i < numRows; i++) { + if (strstr(pdevice->uniqueId, parameters[i][0]) != 0) { + // Remove the key from the unique id to extract the device id + String idWoKey = pdevice->uniqueId; + idWoKey.remove(idWoKey.length() - (strlen(parameters[i][0]) + 1)); + Log.trace(F("idWoKey %s" CR), idWoKey.c_str()); +# if OpenHABDiscovery + String value_template = "{{ value_json." + String(parameters[i][0]) + "}}"; +# else + String value_template = "{{ value_json." + String(parameters[i][0]) + " | is_defined }}"; +# endif + String topic = subjectRTL_433toMQTT; +# if valueAsATopic + // Remove the key from the unique id to extract the device id + String idWoKeyAndModel = idWoKey; + idWoKeyAndModel.remove(0, strlen(pdevice->modelName)); + idWoKeyAndModel.replace("-", "/"); + Log.trace(F("idWoKeyAndModel %s" CR), idWoKeyAndModel.c_str()); + topic = topic + "/" + String(pdevice->modelName) + idWoKeyAndModel; +# endif + if (strcmp(parameters[i][0], "tamper") == 0 || strcmp(parameters[i][0], "alarm") == 0 || strcmp(parameters[i][0], "motion") == 0) { + createDiscovery("binary_sensor", //set Type + (char*)topic.c_str(), parameters[i][1], pdevice->uniqueId, //set state_topic,name,uniqueId + "", "", (char*)value_template.c_str(), //set availability_topic,device_class,value_template, + "1", "0", parameters[i][2], //set,payload_on,payload_off,unit_of_meas, + 0, //set off_delay + "", "", false, "", //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic + (char*)idWoKey.c_str(), "", pdevice->modelName, (char*)idWoKey.c_str(), false, // device name, device manufacturer, device model, device ID, retain + "" //State Class + ); + } else if (strcmp(parameters[i][0], "strike_count") == 0) { + createDiscovery("sensor", //set Type + (char*)topic.c_str(), parameters[i][1], pdevice->uniqueId, //set state_topic,name,uniqueId + "", "", (char*)value_template.c_str(), //set availability_topic,device_class,value_template, + "1", "0", parameters[i][2], //set,payload_on,payload_off,unit_of_meas, + 0, //set off_delay + "", "", false, "", //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic + (char*)idWoKey.c_str(), "", pdevice->modelName, (char*)idWoKey.c_str(), false, // device name, device manufacturer, device model, device ID, retain + stateClassTotalIncreasing //State Class + ); + } else { + createDiscovery("sensor", //set Type + (char*)topic.c_str(), parameters[i][1], pdevice->uniqueId, //set state_topic,name,uniqueId + "", "", (char*)value_template.c_str(), //set availability_topic,device_class,value_template, + "", "", parameters[i][2], //set,payload_on,payload_off,unit_of_meas, + 0, //set off_delay + "", "", false, "", //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic + (char*)idWoKey.c_str(), "", pdevice->modelName, (char*)idWoKey.c_str(), false, // device name, device manufacturer, device model, device ID, retain + stateClassMeasurement //State Class + ); + } + pdevice->isDisc = true; // we don't need the semaphore and all the search magic via createOrUpdateDevice + dumpRTL_433Devices(); + break; + } + } + if (!pdevice->isDisc) { + Log.trace(F("Device id %s was not discovered" CR), pdevice->uniqueId); // Remove from production release ? + } + } else { + Log.trace(F("Device already discovered or that doesn't require discovery %s" CR), pdevice->uniqueId); + } + } +} + +void storeRTL_433Discovery(JsonObject& RFrtl_433_ESPdata, const char* model, const char* uniqueid) { + //Sanitize model name + String modelSanitized = model; + modelSanitized.replace(" ", "_"); + modelSanitized.replace("/", "_"); + modelSanitized.replace(".", "_"); + modelSanitized.replace("&", ""); + + //Sensors translation matrix for sensors that requires statistics by using stateClassMeasurement + size_t numRows = sizeof(parameters) / sizeof(parameters[0]); + + for (int i = 0; i < numRows; i++) { + if (RFrtl_433_ESPdata.containsKey(parameters[i][0])) { + String key_id = String(uniqueid) + "-" + String(parameters[i][0]); + createOrUpdateDeviceRTL_433((char*)key_id.c_str(), (char*)modelSanitized.c_str(), device_flags_init); + } + } +} +# else +void storeRTL_433Discovery(JsonObject& RFrtl_433_ESPdata, const char* model, const char* uniqueid) {} +# endif + void rtl_433_Callback(char* message) { DynamicJsonDocument jsonBuffer2(JSON_MSG_BUFFER); JsonObject RFrtl_433_ESPdata = jsonBuffer2.to(); auto error = deserializeJson(jsonBuffer2, message); if (error) { - Log.error(F("deserializeJson() failed: %s" CR), error.c_str()); + Log.error(F("[rtl_433] deserializeJson() failed: %s" CR), error.c_str()); return; } unsigned long MQTTvalue = (int)RFrtl_433_ESPdata["id"] + round((float)RFrtl_433_ESPdata["temperature_C"]); - String topic = String(subjectRTL_433toMQTT); -# if valueAsATopic + String topic = subjectRTL_433toMQTT; String model = RFrtl_433_ESPdata["model"]; - String id = RFrtl_433_ESPdata["id"]; - if (model != 0) { - topic = topic + "/" + model; - if (id != 0) { - topic = topic + "/" + id; + String uniqueid; + + const char naming_keys[5][8] = {"type", "model", "subtype", "channel", "id"}; // from rtl_433_mqtt_hass.py + size_t numRows = sizeof(naming_keys) / sizeof(naming_keys[0]); + for (int i = 0; i < numRows; i++) { + if (RFrtl_433_ESPdata.containsKey(naming_keys[i])) { + if (uniqueid == 0) { + uniqueid = RFrtl_433_ESPdata[naming_keys[i]].as(); // Start of the unique id with the first key + } else { + uniqueid = uniqueid + "/" + RFrtl_433_ESPdata[naming_keys[i]].as(); // Following keys + } } } + +# if valueAsATopic + topic = topic + "/" + uniqueid; # endif + uniqueid.replace("/", "-"); + + Log.notice(F("uniqueid: %s" CR), uniqueid.c_str()); if (!isAduplicateSignal(MQTTvalue)) { + storeRTL_433Discovery(RFrtl_433_ESPdata, (char*)model.c_str(), (char*)uniqueid.c_str()); pub((char*)topic.c_str(), RFrtl_433_ESPdata); storeSignalValue(MQTTvalue); } @@ -72,6 +253,10 @@ void rtl_433_Callback(char* message) { void setupRTL_433() { rtl_433.setCallback(rtl_433_Callback, messageBuffer, JSON_MSG_BUFFER); +# ifdef ZmqttDiscovery + semaphorecreateOrUpdateDeviceRTL_433 = xSemaphoreCreateBinary(); + xSemaphoreGive(semaphorecreateOrUpdateDeviceRTL_433); +# endif Log.trace(F("ZgatewayRTL_433 command topic: %s%s%s" CR), mqtt_topic, gateway_name, subjectMQTTtoRTL_433); Log.notice(F("ZgatewayRTL_433 setup done " CR)); } @@ -124,7 +309,7 @@ extern void MQTTtoRTL_433(char* topicOri, JsonObject& RTLdata) { pub(subjectRTL_433toMQTT, RTLdata); } else { pub(subjectRTL_433toMQTT, "{\"Status\": \"Error\"}"); // Fail feedback - Log.error(F("MQTTtoRTL_433 Fail json" CR)); + Log.error(F("[rtl_433] MQTTtoRTL_433 Fail json" CR)); } enableActiveReceiver(false); } diff --git a/main/ZmqttDiscovery.ino b/main/ZmqttDiscovery.ino index 12f4c5c..df0ff0a 100644 --- a/main/ZmqttDiscovery.ino +++ b/main/ZmqttDiscovery.ino @@ -98,9 +98,9 @@ void createDiscoveryFromList(const char* mac, * @param device_name Valid only if gateway entry is false, The name of the device. * @param device_manufacturer Valid only if gateway entry is false, The manufacturer of the device. * @param device_model Valid only if gateway entry is false, The model of the device. - * @param device_mac Valid only if gateway entry is false, The connection of the device to the outside world + * @param device_id Valid only if gateway entry is false, The connection of the device to the outside world */ -void announceDeviceTrigger(bool use_gateway_info, char* topic, char* type, char* subtype, char* unique_id, char* device_name, char* device_manufacturer, char* device_model, char* device_mac) { +void announceDeviceTrigger(bool use_gateway_info, char* topic, char* type, char* subtype, char* unique_id, char* device_name, char* device_manufacturer, char* device_model, char* device_id) { //Create The Json StaticJsonDocument jsonBuffer; JsonObject sensor = jsonBuffer.to(); @@ -160,11 +160,11 @@ void announceDeviceTrigger(bool use_gateway_info, char* topic, char* type, char* identifiers.add(deviceid); /*Set Connection */ - if (device_mac[0] != 0) { + if (device_id[0] != 0) { JsonArray connections = device.createNestedArray("connections"); JsonArray connection_mac = connections.createNestedArray(); connection_mac.add("mac"); - connection_mac.add(device_mac); + connection_mac.add(device_id); } //Set manufacturer @@ -193,7 +193,7 @@ void announceDeviceTrigger(bool use_gateway_info, char* topic, char* type, char* } /** - * @brief Generate message and publish it on an MQTT discovery exploiter. For HA @see https://www.home-assistant.io/docs/mqtt/discovery/ + * @brief Generate message and publish it on an MQTT discovery explorer. For HA @see https://www.home-assistant.io/docs/mqtt/discovery/ * * @param sensor_type the Type * @param st_topic set state topic, @@ -213,7 +213,7 @@ void announceDeviceTrigger(bool use_gateway_info, char* topic, char* type, char* * @param device_name set device name, * @param device_manufacturer set device manufacturer, * @param device_model set device model, - * @param device_mac set device MAC, + * @param device_id set device(BLE)/entity(RTL_433) identification, * @param retainCmd set retain * @param state_class set state class * @@ -224,7 +224,7 @@ void createDiscovery(const char* sensor_type, const char* payload_on, const char* payload_off, const char* unit_of_meas, int off_delay, const char* payload_available, const char* payload_not_avalaible, bool gateway_entity, const char* cmd_topic, - const char* device_name, const char* device_manufacturer, const char* device_model, const char* device_mac, bool retainCmd, + const char* device_name, const char* device_manufacturer, const char* device_model, const char* device_id, bool retainCmd, const char* state_class, const char* state_off, const char* state_on) { StaticJsonDocument jsonBuffer; JsonObject sensor = jsonBuffer.to(); @@ -331,19 +331,15 @@ void createDiscovery(const char* sensor_type, device["sw_version"] = OMG_VERSION; identifiers.add(String(getMacAddress())); } else { - //Device representing the actual sensor/switch device - //The Device ID - char deviceid[13]; - memcpy(deviceid, &unique_id[0], 12); - deviceid[12] = '\0'; - identifiers.add(deviceid); - //The Connections - if (device_mac[0] != 0) { + if (device_id[0] != 0) { JsonArray connections = device.createNestedArray("connections"); JsonArray connection_mac = connections.createNestedArray(); connection_mac.add("mac"); - connection_mac.add(device_mac); + connection_mac.add(device_id); + //Device representing the actual sensor/switch device + //The Device ID + identifiers.add(device_id); } if (device_manufacturer[0]) { @@ -354,9 +350,13 @@ void createDiscovery(const char* sensor_type, device["model"] = device_model; } + // generate unique device name by adding the second half of the device_id only if device_name and device_id are different if (device_name[0]) { - // generate unique device name by adding the second half of the device_mac - device["name"] = device_name + String("-") + String(device_mac + 6); + if (strcmp(device_id, device_name) != 0) { + device["name"] = device_name + String("-") + String(device_id + 6); + } else { + device["name"] = device_name; + } } device["via_device"] = String(gateway_name); //device name of the board @@ -377,7 +377,7 @@ void pubMqttDiscovery() { Gateway_AnnouncementMsg, will_Message, "", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay Gateway_AnnouncementMsg, will_Message, true, "", //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); createDiscovery("sensor", //set Type @@ -386,10 +386,9 @@ void pubMqttDiscovery() { "", "", "s", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); - # if defined(ESP8266) || defined(ESP32) createDiscovery("sensor", //set Type subjectSYStoMQTT, "SYS: Free memory", (char*)getUniqueId("freemem", "").c_str(), //set state_topic,name,uniqueId @@ -397,7 +396,7 @@ void pubMqttDiscovery() { "", "", "B", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); createDiscovery("sensor", //set Type @@ -406,7 +405,7 @@ void pubMqttDiscovery() { "", "", "", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # ifndef ESP32_ETHERNET @@ -416,7 +415,7 @@ void pubMqttDiscovery() { "", "", "dB", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -429,7 +428,7 @@ void pubMqttDiscovery() { "", "", "", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC + "", "", "", "", false, // device name, device manufacturer, device model, device ID stateClassNone //State Class ); # endif @@ -440,7 +439,7 @@ void pubMqttDiscovery() { "", "", "V", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a child device, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); createDiscovery("sensor", //set Type @@ -449,7 +448,7 @@ void pubMqttDiscovery() { "", "", "A", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a child device, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); createDiscovery("sensor", //set Type @@ -458,7 +457,7 @@ void pubMqttDiscovery() { "", "", "V", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a child device, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); createDiscovery("sensor", //set Type @@ -467,7 +466,7 @@ void pubMqttDiscovery() { "", "", "A", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a child device, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -478,7 +477,7 @@ void pubMqttDiscovery() { "", "", "%", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a child device, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); createDiscovery("binary_sensor", //set Type @@ -487,7 +486,7 @@ void pubMqttDiscovery() { "", "", "%", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a child device, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); createDiscovery("binary_sensor", //set Type @@ -496,7 +495,7 @@ void pubMqttDiscovery() { "", "", "%", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, "", //set,payload_avalaible,payload_not avalaible ,is a child device, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -507,7 +506,7 @@ void pubMqttDiscovery() { "{\"cmd\":\"restart\"}", "", "", //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 - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); createDiscovery("button", //set Type @@ -516,7 +515,7 @@ void pubMqttDiscovery() { "{\"cmd\":\"erase\"}", "", "", //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 - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # ifdef ZsensorBME280 @@ -532,13 +531,12 @@ void pubMqttDiscovery() { }; for (int i = 0; i < BMEparametersCount; i++) { - //trc(BMEsensor[i][1]); createDiscovery(BMEsensor[i][0], BMETOPIC, BMEsensor[i][1], (char*)getUniqueId(BMEsensor[i][1], BMEsensor[i][2]).c_str(), will_Topic, BMEsensor[i][3], BMEsensor[i][4], BMEsensor[i][5], BMEsensor[i][6], BMEsensor[i][7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); } @@ -560,7 +558,7 @@ void pubMqttDiscovery() { will_Topic, HTUsensor[i][3], HTUsensor[i][4], HTUsensor[i][5], HTUsensor[i][6], HTUsensor[i][7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); } @@ -576,7 +574,7 @@ void pubMqttDiscovery() { will_Topic, LM75sensor[3], LM75sensor[4], LM75sensor[5], LM75sensor[6], LM75sensor[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -596,7 +594,7 @@ void pubMqttDiscovery() { will_Topic, AHTsensor[i][3], AHTsensor[i][4], AHTsensor[i][5], AHTsensor[i][6], AHTsensor[i][7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); } @@ -618,7 +616,7 @@ void pubMqttDiscovery() { will_Topic, DHTsensor[i][3], DHTsensor[i][4], DHTsensor[i][5], DHTsensor[i][6], DHTsensor[i][7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); } @@ -635,7 +633,7 @@ void pubMqttDiscovery() { will_Topic, ADCsensor[3], ADCsensor[4], ADCsensor[5], ADCsensor[6], ADCsensor[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -657,7 +655,7 @@ void pubMqttDiscovery() { will_Topic, BH1750sensor[i][3], BH1750sensor[i][4], BH1750sensor[i][5], BH1750sensor[i][6], BH1750sensor[i][7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); } @@ -680,7 +678,7 @@ void pubMqttDiscovery() { will_Topic, TSL2561sensor[i][3], TSL2561sensor[i][4], TSL2561sensor[i][5], TSL2561sensor[i][6], TSL2561sensor[i][7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); } @@ -697,7 +695,7 @@ void pubMqttDiscovery() { will_Topic, HCSR501sensor[3], HCSR501sensor[4], HCSR501sensor[5], HCSR501sensor[6], HCSR501sensor[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -713,7 +711,7 @@ void pubMqttDiscovery() { will_Topic, GPIOInputsensor[3], GPIOInputsensor[4], GPIOInputsensor[5], GPIOInputsensor[6], GPIOInputsensor[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -735,7 +733,7 @@ void pubMqttDiscovery() { will_Topic, INA226sensor[i][3], INA226sensor[i][4], INA226sensor[i][5], INA226sensor[i][6], INA226sensor[i][7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); } @@ -757,7 +755,7 @@ void pubMqttDiscovery() { will_Topic, actuatorONOFF[3], actuatorONOFF[4], actuatorONOFF[5], actuatorONOFF[6], actuatorONOFF[7], 0, "", "", true, subjectMQTTtoONOFF, - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -779,7 +777,7 @@ void pubMqttDiscovery() { will_Topic, RN8209sensor[i][3], RN8209sensor[i][4], RN8209sensor[i][5], RN8209sensor[i][6], RN8209sensor[i][7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); } @@ -797,7 +795,7 @@ void pubMqttDiscovery() { will_Topic, gatewayRF[3], gatewayRF[4], gatewayRF[5], gatewayRF[6], gatewayRF[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); @@ -815,7 +813,7 @@ void pubMqttDiscovery() { will_Topic, gatewayRF2[3], gatewayRF2[4], gatewayRF2[5], gatewayRF2[6], gatewayRF2[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -832,7 +830,7 @@ void pubMqttDiscovery() { will_Topic, gatewayRFM69[3], gatewayRFM69[4], gatewayRFM69[5], gatewayRFM69[6], gatewayRFM69[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -849,7 +847,7 @@ void pubMqttDiscovery() { will_Topic, gatewayLORA[3], gatewayLORA[4], gatewayLORA[5], gatewayLORA[6], gatewayLORA[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -866,7 +864,7 @@ void pubMqttDiscovery() { will_Topic, gatewaySRFB[3], gatewaySRFB[4], gatewaySRFB[5], gatewaySRFB[6], gatewaySRFB[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -883,7 +881,7 @@ void pubMqttDiscovery() { will_Topic, gatewayPilight[3], gatewayPilight[4], gatewayPilight[5], gatewayPilight[6], gatewayPilight[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -900,7 +898,7 @@ void pubMqttDiscovery() { will_Topic, gatewayIR[3], gatewayIR[4], gatewayIR[5], gatewayIR[6], gatewayIR[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -917,7 +915,7 @@ void pubMqttDiscovery() { will_Topic, gateway2G[3], gateway2G[4], gateway2G[5], gateway2G[6], gateway2G[7], 0, "", "", true, "", - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); # endif @@ -930,7 +928,7 @@ void pubMqttDiscovery() { "{\"interval\":{{value*1000}},\"save\":true}", "", "s", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, subjectMQTTtoBTset, //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain, + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain, stateClassNone //State Class ); createDiscovery("number", //set Type @@ -939,7 +937,7 @@ void pubMqttDiscovery() { "{\"scanbcnct\":{{value}},\"save\":true}", "", "", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay "", "", true, subjectMQTTtoBTset, //set,payload_avalaible,payload_not avalaible,is a gateway entity, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); createDiscovery("button", //set Type @@ -948,7 +946,7 @@ void pubMqttDiscovery() { "{\"interval\":0}", "", "", //set,payload_on,payload_off,unit_of_meas, 0, //set off_delay Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoBTset, //set,payload_avalaible,payload_not avalaible ,is a gateway entity, command topic - "", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain + "", "", "", "", false, // device name, device manufacturer, device model, device ID, retain stateClassNone //State Class ); createDiscovery("button", //set Type diff --git a/main/config_RF.h b/main/config_RF.h index a6c57a8..34b0a80 100644 --- a/main/config_RF.h +++ b/main/config_RF.h @@ -66,6 +66,64 @@ extern void disableRTLreceive(); extern int getRTLrssiThreshold(); extern int getRTLCurrentRSSI(); extern int getRTLMessageCount(); +# ifdef ZmqttDiscovery +extern void launchRTL_433Discovery(bool overrideDiscovery); +// This structure stores the entities of the RTL 433 devices and is they have been discovered or not +// The uniqueId is composed of the device id + the key + +# define uniqueIdSize 60 // longest model + longest key +# define modelNameSize 31 // longest model + +struct RTL_433device { + char uniqueId[uniqueIdSize]; + char modelName[modelNameSize]; + bool isDisc; +}; + +extern std::vector RTL_433devices; + +const char parameters[39][3][16] = { + // RTL_433 key, name, unit + {"temperature_C", "temperature", "°C"}, + {"temperature_1_C", "temperature", "°C"}, + {"temperature_2_C", "temperature", "°C"}, + {"temperature_F", "temperature", "°F"}, + {"time", "timestamp", ""}, + {"battery_ok", "battery", ""}, + {"humidity", "humidity", "%"}, + {"moisture", "moisture", "%"}, + {"pressure_hPa", "pressure", "hPa"}, + {"pressure_kPa", "pressure", "kPa"}, + {"wind_speed_km_h", "wind speed", "km/h"}, + {"wind_avg_km_h", "wind average", "km/h"}, + {"wind_avg_mi_h", "wind average", "mi/h"}, + {"wind_avg_m_s", "wind average", "m/s"}, + {"wind_speed_m_s", "wind speed", "m/s"}, + {"gust_speed_km_h", "gust speed", "km/h"}, + {"wind_max_km_h", "wind max", "km/h"}, + {"wind_max_m_s", "wind max", "m/s"}, + {"gust_speed_m_s", "gust speed", "m/s"}, + {"wind_dir_deg", "wind direction", "°"}, + {"rain_mm", "rain", "mm"}, + {"rain_mm_h", "rain", "mm/h"}, + {"rain_in", "rain", "in"}, + {"rain_rate_in_h", "rain", "in/h"}, + {"rssi", "rssi", "dB"}, + {"snr", "snr", "dB"}, + {"noise", "noise", "dB"}, + {"depth_cm", "depth", "cm"}, + {"power_W", "power", "W"}, + {"light_lux", "light", "lx"}, + {"lux", "lux", "lx"}, + {"uv", "uv", "UV index"}, + {"uvi", "uvi", "UV index"}, + {"storm_dist", "storm distance", "mi"}, + {"strike_distance", "strike distance", "mi"}, + {"tamper", "tamper", ""}, + {"alarm", "alarm", ""}, + {"motion", "motion", ""}, + {"strike_count", "strike count", ""}}; // from rtl_433_mqtt_hass.py +# endif #endif /*-------------------RF topics & parameters----------------------*/ //433Mhz MQTT Subjects and keys diff --git a/main/config_mqttDiscovery.h b/main/config_mqttDiscovery.h index b1cf5f6..63d9f56 100644 --- a/main/config_mqttDiscovery.h +++ b/main/config_mqttDiscovery.h @@ -112,7 +112,9 @@ void announceDeviceTrigger(bool use_gateway_info, char* device_model, char* device_mac); -#define discovery_Topic "homeassistant" +#ifndef discovery_Topic +# define discovery_Topic "homeassistant" +#endif // discovery_republish_on_reconnect false to publish discovery topics over MQTT only with first connect // discovery_republish_on_reconnect true to always republish discovery topics over MQTT when connection is re-established #ifndef discovery_republish_on_reconnect @@ -254,6 +256,13 @@ const char* availableHASSUnits[] = {"W", "bpm", "dB", "dBm", - "B"}; + "B", + "UV index", + "m/s", + "km/h", + "°", + "mm", + "mm/h", + "cm"}; #endif diff --git a/main/main.ino b/main/main.ino index 143ed6f..65bfbcf 100644 --- a/main/main.ino +++ b/main/main.ino @@ -201,6 +201,17 @@ unsigned long timer_led_measures = 0; static void* eClient = nullptr; static unsigned long last_ota_activity_millis = 0; #if defined(ESP8266) || defined(ESP32) +# include +// Flags definition for white list, black list, discovery management +# define device_flags_init 0 << 0 +# define device_flags_isDisc 1 << 0 +# define device_flags_isWhiteL 1 << 1 +# define device_flags_isBlackL 1 << 2 +# define device_flags_connect 1 << 3 +# define isWhite(device) device->isWhtL +# define isBlack(device) device->isBlkL +# define isDiscovered(device) device->isDisc + static bool mqtt_secure = MQTT_SECURE_DEFAULT; static uint8_t mqtt_ss_index = MQTT_SECURE_SELF_SIGNED_INDEX_DEFAULT; static String mqtt_cert = ""; @@ -1570,6 +1581,10 @@ void loop() { #endif #ifdef ZgatewayRTL_433 RTL_433Loop(); +# ifdef ZmqttDiscovery + if (disc) + launchRTL_433Discovery(publishDiscovery); +# endif #endif } else { // MQTT disconnected diff --git a/platformio.ini b/platformio.ini index 3379473..44e268c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -797,30 +797,30 @@ lib_deps = build_flags = ${com-esp.build_flags} ; *** OpenMQTTGateway Config *** - '-UZmqttDiscovery' ; disables MQTT Discovery - '-DvalueAsATopic=true' ; MQTT topic includes model and device + ;'-UZmqttDiscovery' ; disables MQTT Discovery + '-DvalueAsATopic=true' ; MQTT topic includes model and device '-DLOG_LEVEL=LOG_LEVEL_TRACE' '-DGateway_Name="OpenMQTTGateway_rtl_433_ESP"' ; *** OpenMQTTGateway Modules *** '-DZgatewayRTL_433="rtl_433"' '-DZradioCC1101="CC1101"' ; *** rtl_433_ESP Options *** -; '-DRTL_DEBUG=4' ; rtl_433 verbose mode +; '-DRTL_DEBUG=4' ; rtl_433 verbose mode ; '-DRTL_VERBOSE=58' ; LaCrosse TX141-Bv2, TX141TH-Bv2, TX141-Bv3, TX141W, TX145wsdth sensor ; '-DRAW_SIGNAL_DEBUG=true' ; display raw received messages -; '-DMEMORY_DEBUG=true' ; display memory usage information - '-DDEMOD_DEBUG=true' ; display signal debug info -; '-DMY_DEVICES=true' ; subset of devices - '-DPUBLISH_UNPARSED=true' ; publish unparsed signal details -; '-DRSSI_THRESHOLD=12' ; Apply a delta of 12 to average RSSI level -; '-DAVERAGE_RSSI=5000' ; Display RSSI floor ( Average of 5000 samples ) - '-DSIGNAL_RSSI=true' ; Display during signal receive +; '-DMEMORY_DEBUG=true' ; display memory usage information + '-DDEMOD_DEBUG=true' ; display signal debug info +; '-DMY_DEVICES=true' ; subset of devices + '-DPUBLISH_UNPARSED=true' ; publish unparsed signal details +; '-DRSSI_THRESHOLD=12' ; Apply a delta of 12 to average RSSI level +; '-DAVERAGE_RSSI=5000' ; Display RSSI floor ( Average of 5000 samples ) + '-DSIGNAL_RSSI=true' ; Display during signal receive '-DNO_DEAF_WORKAROUND=true' ; *** RF Module Options *** - '-DRF_CC1101="CC1101"' ; CC1101 Transceiver Module -; '-DRF_MODULE_CS=5' ; pin to be used as chip select - '-DRF_MODULE_GDO0=12' ; CC1101 pin GDO0 - '-DRF_MODULE_GDO2=27' ; CC1101 pin GDO2 + '-DRF_CC1101="CC1101"' ; CC1101 Transceiver Module +; '-DRF_MODULE_CS=5' ; pin to be used as chip select + '-DRF_MODULE_GDO0=12' ; CC1101 pin GDO0 + '-DRF_MODULE_GDO2=27' ; CC1101 pin GDO2 ; *** RadioLib Options *** ; '-DRADIOLIB_DEBUG=true' ; '-DRADIOLIB_VERBOSE=true' @@ -837,8 +837,8 @@ lib_deps = build_flags = ${com-esp.build_flags} ; *** OpenMQTTGateway Config *** - '-UZmqttDiscovery' ; disables MQTT Discovery - '-DvalueAsATopic=true' ; MQTT topic includes model and device + ;'-UZmqttDiscovery' ; disables MQTT Discovery + '-DvalueAsATopic=true' ; MQTT topic includes model and device '-DGateway_Name="OpenMQTTGateway_heltec_rtl_433_ESP"' ; *** OpenMQTTGateway Modules *** '-DZgatewayRTL_433="rtl_433"' @@ -860,7 +860,7 @@ lib_deps = build_flags = ${com-esp.build_flags} ; *** OpenMQTTGateway Config *** - '-UZmqttDiscovery' ; disables MQTT Discovery + ;'-UZmqttDiscovery' ; disables MQTT Discovery '-DvalueAsATopic=true' ; MQTT topic includes model and device '-DGateway_Name="OpenMQTTGateway_lilygo_rtl_433_ESP"' ; *** OpenMQTTGateway Modules ***