From 93dff6493a6e7059e72ea9c6bc2459bcaac2d290 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 19 Feb 2020 22:22:12 +0100 Subject: [PATCH] optimize detection of EMS devices --- src/ems-esp.cpp | 26 ++++++++++---- src/ems.cpp | 93 ++++++++++++++++++------------------------------- src/ems.h | 38 ++++++++++---------- 3 files changed, 71 insertions(+), 86 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index d13cef5fa..19dc9629a 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -19,7 +19,7 @@ // Dallas external temp sensors #include "ds18.h" DS18 ds18; -#define DS18_MQTT_PAYLOAD_MAXSIZE 400 +#define DS18_MQTT_PAYLOAD_MAXSIZE 600 // public libraries #include // https://github.com/bblanchon/ArduinoJson @@ -115,7 +115,7 @@ static const command_t project_cmds[] PROGMEM = { {false, "publish", "publish all values to MQTT"}, {false, "refresh", "fetch values from the EMS devices"}, - {false, "devices [scan [deep]]", "list, ask Master or perform deep scan of EMS devices"}, + {false, "devices [scan] | [scan deep] | [save]", "list detected devices, quick scan or deep scan and save as known devices"}, {false, "queue", "show current Tx queue"}, {false, "send XX ...", "send raw telegram data to EMS bus (XX are hex values)"}, {false, "thermostat read ", "send read request to the thermostat for heating circuit hc 1-4"}, @@ -581,6 +581,7 @@ void publishSensorValues() { bool hasdata = false; char buffer[128] = {0}; // temp string buffer + // see if the sensor values have changed, if so send it on for (uint8_t i = 0; i < EMSESP_Settings.dallas_sensors; i++) { float sensorValue = ds18.getValue(i); @@ -597,12 +598,26 @@ void publishSensorValues() { } } + /* test code - https://github.com/proddy/EMS-ESP/issues/326 + float sensorValue = 23.43; + hasdata = true; + char sensorID[10]; // sensor{1-n} + for (uint8_t i = 0; i < 10; i++) { + strlcpy(sensorID, PAYLOAD_EXTERNAL_SENSOR_NUM, sizeof(sensorID)); + strlcat(sensorID, _int_to_char(buffer, i + 1), sizeof(sensorID)); + JsonObject dataSensor = sensors.createNestedObject(sensorID); + dataSensor[PAYLOAD_EXTERNAL_SENSOR_ID] = "28D45A79A2190310"; + dataSensor[PAYLOAD_EXTERNAL_SENSOR_TEMP] = sensorValue; + } + */ + if (!hasdata) { return; // nothing to send } char data[DS18_MQTT_PAYLOAD_MAXSIZE] = {0}; serializeJson(doc, data, sizeof(data)); + myDebugLog("Publishing external sensor data via MQTT"); myESP.mqttPublish(TOPIC_EXTERNAL_SENSORS, data); } @@ -1222,7 +1237,7 @@ bool SetListCallback(MYESP_FSACTION_t action, uint8_t wc, const char * setting, EMSESP_Settings.master_thermostat = pid; ems_setMasterThermostat(pid); // force a scan - ems_clearDeviceList(); + Devices.clear(); // init the device map ems_doReadCommand(EMS_TYPE_UBADevices, EMS_Boiler.device_id); ok = true; } @@ -1361,7 +1376,7 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { // just scan use UBA 0x07 telegram myDebug_P(PSTR("Requesting EMS bus master for its device list and scanning for external sensors...")); scanDallas(); - ems_clearDeviceList(); + Devices.clear(); // init the device map ems_doReadCommand(EMS_TYPE_UBADevices, EMS_Boiler.device_id); return; } @@ -1370,7 +1385,7 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { char * third_cmd = _readWord(); if (strcmp(third_cmd, "deep") == 0) { myDebug_P(PSTR("Started deep scan of EMS bus for our known devices. This can take up to 10 seconds...")); - ems_clearDeviceList(); + Devices.clear(); // init the device map ems_scanDevices(); return; } @@ -2204,7 +2219,6 @@ void setup() { startupEMSscan(); } - // enable regular checks to fetch data and publish using Tx (unless listen_mode is enabled) if (!EMSESP_Settings.listen_mode) { regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS diff --git a/src/ems.cpp b/src/ems.cpp index 5198a9afd..34232d717 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -78,7 +78,7 @@ bool ems_isHT3() { // init EMS device values, counters and buffers void ems_init() { - ems_clearDeviceList(); // init the device map + Devices.clear(); // init the device map // overall status EMS_Sys_Status.emsRxPgks = 0; @@ -445,6 +445,10 @@ void ems_setTxMode(uint8_t mode) { } void ems_setEMSbusid(uint8_t id) { + if ((id != 0x0B) && (id != 0x0A) && (id != 0x0D) && (id != 0x0F) && (id != 0x12)) { + id = EMS_BUSID_DEFAULT; + } + EMS_Sys_Status.emsbusid = id; EMS_Sys_Status.emsPollAck[0] = id; } @@ -1679,17 +1683,6 @@ void _process_RCTime(_EMS_RxTelegram * EMS_RxTelegram) { strlcpy(EMS_Thermostat.datetime, time_sp, sizeof(time_sp)); // store } -/* - * Clear devices list - */ -void ems_clearDeviceList() { - Devices.clear(); - - for (uint8_t i = 0; i < EMS_SYS_DEVICEMAP_LENGTH; i++) { - EMS_Sys_Status.emsDeviceMap[i] = 0x00; - } -} - /* * add an EMS device to our list of detected devices if its unique * returns true if already in list @@ -1761,35 +1754,41 @@ bool _addDevice(_EMS_DEVICE_TYPE device_type, uint8_t product_id, uint8_t device * type 0x07 - shows us the connected EMS devices * e.g. 08 00 07 00 0B 80 00 00 00 00 00 00 00 00 00 00 00 (CRC=47) #data=13 * Junkers has 15 bytes of data + * each byte is a bitmask for which devices are active + * byte 1 = range 0x08 - 0x0F, byte 2=0x10 - 0x17 etc... */ void _process_UBADevices(_EMS_RxTelegram * EMS_RxTelegram) { - if (EMS_RxTelegram->data_length > EMS_SYS_DEVICEMAP_LENGTH) { - return; // should be 13 or 15 bytes long + // exit it length is incorrect (13 or 15 bytes long) + // or didn't come from the boiler + // or we can't write to the EMS bus yet + if ((EMS_RxTelegram->data_length > EMS_SYS_DEVICEMAP_LENGTH) || (EMS_RxTelegram->src != EMS_ID_BOILER) || (ems_getTxDisabled())) { + return; } + // for each byte, check the bits and determine the device_id for (uint8_t data_byte = 0; data_byte < EMS_RxTelegram->data_length; data_byte++) { - uint8_t byte = EMS_RxTelegram->data[data_byte]; - uint8_t saved_byte = EMS_Sys_Status.emsDeviceMap[data_byte]; - - // see if this matches what we already have stored - if (byte != saved_byte) { - // we have something new - EMS_Sys_Status.emsDeviceMap[data_byte] = byte; // save new value - // go through all bits - // myDebug("Byte #%d 0x%02X", data_byte, byte); // for debugging - if (byte) { - for (uint8_t bit = 0; bit < 8; bit++) { - if ((byte & 0x01) && ((saved_byte & 0x01) == 0)) { - uint8_t device_id = ((data_byte + 1) * 8) + bit; - if (device_id != EMS_Sys_Status.emsbusid) { - myDebug("[EMS] Detected new EMS Device with ID 0x%02X. Fetching version information...", device_id); - if (!ems_getTxDisabled()) { - ems_doReadCommand(EMS_TYPE_Version, device_id); // get version, but ignore ourselves + uint8_t byte = EMS_RxTelegram->data[data_byte]; + if (byte) { + for (uint8_t bit = 0; bit < 8; bit++) { + if (byte & 0x01) { + uint8_t device_id = ((data_byte + 1) * 8) + bit; + // ignore ourselves, we're not an EMS device + if ((device_id != EMS_Sys_Status.emsbusid) && (!Devices.empty())) { + // see if we already have this device in our list + bool exists = false; + for (std::list<_Detected_Device>::iterator it = Devices.begin(); it != Devices.end(); ++it) { + if (it->device_id == device_id) { + exists = true; + break; } } + if (!exists) { + myDebug("[EMS] Detected new EMS Device with ID 0x%02X. Fetching version information...", device_id); + ems_doReadCommand(EMS_TYPE_Version, device_id); // get version, but ignore ourselves + } } - byte = byte >> 1; - saved_byte = saved_byte >> 1; + // advance 1 bit + byte = byte >> 1; } } } @@ -2219,38 +2218,12 @@ char * ems_getDeviceDescription(_EMS_DEVICE_TYPE device_type, char * buffer, boo * print out contents of the device list that was captured */ void ems_printDevices() { - char s[100]; - char buffer[16] = {0}; - - strlcpy(s, "These device IDs are on the EMS Bus:", sizeof(s)); - strlcat(s, COLOR_BOLD_ON, sizeof(s)); - - for (uint8_t data_byte = 0; data_byte < EMS_SYS_DEVICEMAP_LENGTH; data_byte++) { - uint8_t byte = EMS_Sys_Status.emsDeviceMap[data_byte]; - if (byte) { - // go through all bits - for (uint8_t bit = 0; bit < 8; bit++) { - if (byte & 0x01) { - uint8_t device_id = ((data_byte + 1) * 8) + bit; - if (device_id != EMS_Sys_Status.emsbusid) { - strlcat(s, " 0x", sizeof(s)); - strlcat(s, _hextoa(device_id, buffer), sizeof(s)); - } - } - byte = byte >> 1; - } - } - } - - strlcat(s, COLOR_BOLD_OFF, sizeof(s)); - myDebug(s); - // print out the ones we recognized if (!Devices.empty()) { bool have_unknowns = false; char device_string[100]; char device_type[30]; - myDebug_P(PSTR("and %d were recognized by EMS-ESP as:"), Devices.size()); + myDebug_P(PSTR("These %d were recognized by EMS-ESP:"), Devices.size()); for (std::list<_Detected_Device>::iterator it = Devices.begin(); it != Devices.end(); ++it) { ems_getDeviceTypeName(it->device_type, device_type); // get type string, e.g. "Boiler" if (it->known) { diff --git a/src/ems.h b/src/ems.h index a28a15819..006145821 100644 --- a/src/ems.h +++ b/src/ems.h @@ -134,25 +134,24 @@ typedef enum { typedef struct { _EMS_RX_STATUS emsRxStatus; _EMS_TX_STATUS emsTxStatus; - uint16_t emsRxPgks; // # successfull received - uint16_t emsTxPkgs; // # successfull sent - uint16_t emxCrcErr; // CRC errors - bool emsPollEnabled; // flag enable the response to poll messages - _EMS_SYS_LOGGING emsLogging; // logging - uint16_t emsLogging_ID; // the type or device ID to watch - uint8_t emsRefreshedFlags; // fresh data, needs to be pushed out to MQTT - bool emsBusConnected; // is there an active bus - uint32_t emsRxTimestamp; // timestamp of last EMS message received - uint32_t emsPollFrequency; // time between EMS polls - bool emsTxCapable; // able to send via Tx - bool emsTxDisabled; // true to prevent all Tx - uint8_t txRetryCount; // # times the last Tx was re-sent - uint8_t emsIDMask; // Buderus: 0x00, Junkers: 0x80 - uint8_t emsPollAck[1]; // acknowledge buffer for Poll - uint8_t emsTxMode; // Tx mode 1, 2 or 3 - uint8_t emsbusid; // EMS bus ID, default 0x0B for Service Key - uint8_t emsMasterThermostat; // product ID for the default thermostat to use - char emsDeviceMap[EMS_SYS_DEVICEMAP_LENGTH]; // contents of 0x07 telegram with bitmasks for all active EMS devices + uint16_t emsRxPgks; // # successfull received + uint16_t emsTxPkgs; // # successfull sent + uint16_t emxCrcErr; // CRC errors + bool emsPollEnabled; // flag enable the response to poll messages + _EMS_SYS_LOGGING emsLogging; // logging + uint16_t emsLogging_ID; // the type or device ID to watch + uint8_t emsRefreshedFlags; // fresh data, needs to be pushed out to MQTT + bool emsBusConnected; // is there an active bus + uint32_t emsRxTimestamp; // timestamp of last EMS message received + uint32_t emsPollFrequency; // time between EMS polls + bool emsTxCapable; // able to send via Tx + bool emsTxDisabled; // true to prevent all Tx + uint8_t txRetryCount; // # times the last Tx was re-sent + uint8_t emsIDMask; // Buderus: 0x00, Junkers: 0x80 + uint8_t emsPollAck[1]; // acknowledge buffer for Poll + uint8_t emsTxMode; // Tx mode 1, 2 or 3 + uint8_t emsbusid; // EMS bus ID, default 0x0B for Service Key + uint8_t emsMasterThermostat; // product ID for the default thermostat to use } _EMS_Sys_Status; // The Tx send package @@ -450,7 +449,6 @@ void ems_printTxQueue(); void ems_testTelegram(uint8_t test_num); void ems_startupTelegrams(); bool ems_checkEMSBUSAlive(); -void ems_clearDeviceList(); void ems_setThermostatTemp(float temperature, uint8_t hc, uint8_t temptype = 0); void ems_setThermostatMode(uint8_t mode, uint8_t hc); void ems_setWarmWaterTemp(uint8_t temperature);