diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index b324aea35..d13cef5fa 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -79,7 +79,9 @@ typedef struct { uint8_t dallas_gpio; // pin for attaching external dallas temperature sensors bool dallas_parasite; // on/off is using parasite uint8_t tx_mode; // TX mode 1,2 or 3 + uint8_t bus_id; // BUS ID, defaults to 0x0B for the service key uint8_t master_thermostat; // Product ID of master thermostat to use, 0 for automatic + char * known_devices; // list of known deviceIDs for quick boot } _EMSESP_Settings; typedef struct { @@ -101,6 +103,7 @@ static const command_t project_cmds[] PROGMEM = { {true, "shower_alert ", "stop hot water to send 3 cold burst warnings after max shower time is exceeded"}, {true, "publish_time ", "set frequency for publishing data to MQTT (-1=off, 0=automatic)"}, {true, "tx_mode ", "changes Tx logic. 1=EMS generic, 2=EMS+, 3=HT3"}, + {true, "bus_id ", "EMS-ESP's deviceID. 0B=Service Key (default), 0D=Modem, 0A=Hand terminal, 0F=Time module, 12=Error module"}, {true, "master_thermostat [product id]", "set default thermostat to use. No argument lists options"}, {false, "info", "show current values deciphered from the EMS messages"}, @@ -112,9 +115,8 @@ static const command_t project_cmds[] PROGMEM = { {false, "publish", "publish all values to MQTT"}, {false, "refresh", "fetch values from the EMS devices"}, - {false, "devices", "list detected EMS devices"}, + {false, "devices [scan [deep]]", "list, ask Master or perform deep scan of EMS devices"}, {false, "queue", "show current Tx queue"}, - {false, "autodetect [scan]", "scan for EMS devices and external sensors. scan uses brute-force"}, {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"}, {false, "thermostat temp [hc] ", "set current thermostat temperature"}, @@ -259,6 +261,9 @@ void showInfo() { if (ems_getBusConnected()) { myDebug_P(PSTR(" Bus is connected, protocol: %s"), (ems_isHT3() ? "HT3" : "Buderus")); myDebug_P(PSTR(" Rx: # successful read requests=%d, # CRC errors=%d"), EMS_Sys_Status.emsRxPgks, EMS_Sys_Status.emxCrcErr); + if (strlen(EMSESP_Settings.known_devices) > 0) { + myDebug_P(PSTR(" Saved known device IDs: %s"), EMSESP_Settings.known_devices); + } if (ems_getTxCapable()) { char valuestr[8] = {0}; // for formatting floats @@ -550,7 +555,7 @@ void scanDallas() { char buffer[128]; char buffer2[128]; for (uint8_t i = 0; i < EMSESP_Settings.dallas_sensors; i++) { - myDebug_P(PSTR("External temperature sensor type: %s id: %s found"), ds18.getDeviceType(buffer, i), ds18.getDeviceID(buffer2, i)); + myDebug_P(PSTR("External temperature sensor found, type: %s id: %s"), ds18.getDeviceType(buffer, i), ds18.getDeviceID(buffer2, i)); } } } @@ -567,21 +572,28 @@ void publishSensorValues() { } // each payload per sensor is 30 bytes so calculate if we have enough space - if ((EMSESP_Settings.dallas_sensors * 30) > DS18_MQTT_PAYLOAD_MAXSIZE) { - myDebug("Error: too many Dallas sensors for MQTT payload"); - } + if ((EMSESP_Settings.dallas_sensors * 50) > DS18_MQTT_PAYLOAD_MAXSIZE) { + myDebug("Error: too many Dallas sensors for MQTT payload"); + } StaticJsonDocument doc; JsonObject sensors = doc.to(); bool hasdata = false; - char buffer[128] = {0}; + 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); if (sensorValue != DS18_DISCONNECTED) { - sensors[ds18.getDeviceID(buffer, i)] = sensorValue; - hasdata = true; + hasdata = true; + // create a nested object + // https://github.com/proddy/EMS-ESP/issues/327 + char sensorID[10]; // sensor{1-n} + 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] = ds18.getDeviceID(buffer, i); + dataSensor[PAYLOAD_EXTERNAL_SENSOR_TEMP] = sensorValue; } } @@ -800,47 +812,45 @@ void publishEMSValues(bool force) { JsonObject rootMixing = doc.to(); for (uint8_t hc_v = 1; hc_v <= EMS_MIXING_MAXHC; hc_v++) { - _EMS_MixingModule_HC * mixing = &EMS_MixingModule.hc[hc_v - 1]; + _EMS_MixingModule_HC * mixingHC = &EMS_MixingModule.hc[hc_v - 1]; // only send if we have an active Heating Circuit with real data - if (mixing->active) { - // build new json object + if (mixingHC->active) { char hc[10]; // hc{1-4} strlcpy(hc, MIXING_HC, sizeof(hc)); - strlcat(hc, _int_to_char(s, mixing->hc), sizeof(hc)); - JsonObject dataMixing = rootMixing.createNestedObject(hc); - if (mixing->flowTemp < EMS_VALUE_USHORT_NOTSET) - dataMixing["flowTemp"] = (float)mixing->flowTemp / 10; - if (mixing->flowSetTemp != EMS_VALUE_INT_NOTSET) - dataMixing["setflowTemp"] = mixing->flowSetTemp; - if (mixing->pumpMod != EMS_VALUE_INT_NOTSET) - dataMixing["pumpMod"] = mixing->pumpMod; - if (mixing->valveStatus != EMS_VALUE_INT_NOTSET) - dataMixing["valveStatus"] = mixing->valveStatus; + strlcat(hc, _int_to_char(s, mixingHC->hc), sizeof(hc)); + JsonObject dataMixingHC = rootMixing.createNestedObject(hc); + if (mixingHC->flowTemp < EMS_VALUE_USHORT_NOTSET) + dataMixingHC["flowTemp"] = (float)mixingHC->flowTemp / 10; + if (mixingHC->flowSetTemp != EMS_VALUE_INT_NOTSET) + dataMixingHC["setflowTemp"] = mixingHC->flowSetTemp; + if (mixingHC->pumpMod != EMS_VALUE_INT_NOTSET) + dataMixingHC["pumpMod"] = mixingHC->pumpMod; + if (mixingHC->valveStatus != EMS_VALUE_INT_NOTSET) + dataMixingHC["valveStatus"] = mixingHC->valveStatus; } } for (uint8_t wwc_v = 1; wwc_v <= EMS_MIXING_MAXWWC; wwc_v++) { - _EMS_MixingModule_WWC * mixing = &EMS_MixingModule.wwc[wwc_v - 1]; + _EMS_MixingModule_WWC * mixingWWC = &EMS_MixingModule.wwc[wwc_v - 1]; // only send if we have an active Warm water Circuit with real data - if (mixing->active) { - // build new json object + if (mixingWWC->active) { char wwc[10]; // wwc{1-2} strlcpy(wwc, MIXING_WWC, sizeof(wwc)); - strlcat(wwc, _int_to_char(s, mixing->wwc), sizeof(wwc)); + strlcat(wwc, _int_to_char(s, mixingWWC->wwc), sizeof(wwc)); JsonObject dataMixing = rootMixing.createNestedObject(wwc); - if (mixing->flowTemp < EMS_VALUE_USHORT_NOTSET) - dataMixing["wwTemp"] = (float)mixing->flowTemp / 10; - if (mixing->pumpMod != EMS_VALUE_INT_NOTSET) - dataMixing["pumpStatus"] = mixing->pumpMod; - if (mixing->tempStatus != EMS_VALUE_INT_NOTSET) - dataMixing["tempStatus"] = mixing->tempStatus; + if (mixingWWC->flowTemp < EMS_VALUE_USHORT_NOTSET) + dataMixing["wwTemp"] = (float)mixingWWC->flowTemp / 10; + if (mixingWWC->pumpMod != EMS_VALUE_INT_NOTSET) + dataMixing["pumpStatus"] = mixingWWC->pumpMod; + if (mixingWWC->tempStatus != EMS_VALUE_INT_NOTSET) + dataMixing["tempStatus"] = mixingWWC->tempStatus; } } data[0] = '\0'; // reset data for next package serializeJson(doc, data, sizeof(data)); - myDebugLog("Publishing mixing device data via MQTT"); + myDebugLog("Publishing mixing data via MQTT"); myESP.mqttPublish(TOPIC_MIXING_DATA, data); ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_MIXING); // unset flag } @@ -1039,6 +1049,11 @@ bool LoadSaveCallback(MYESP_FSACTION_t action, JsonObject settings) { EMSESP_Settings.master_thermostat = settings["master_thermostat"] | 0; // default to 0 (none) ems_setMasterThermostat(EMSESP_Settings.master_thermostat); + EMSESP_Settings.bus_id = settings["bus_id"] | EMS_BUSID_DEFAULT; // default to 0x0B (Service Key) + ems_setEMSbusid(EMSESP_Settings.bus_id); + + EMSESP_Settings.known_devices = strdup(settings["known_devices"] | ""); + return true; } @@ -1052,7 +1067,9 @@ bool LoadSaveCallback(MYESP_FSACTION_t action, JsonObject settings) { settings["shower_alert"] = EMSESP_Settings.shower_alert; settings["publish_time"] = EMSESP_Settings.publish_time; settings["tx_mode"] = EMSESP_Settings.tx_mode; + settings["bus_id"] = EMSESP_Settings.bus_id; settings["master_thermostat"] = EMSESP_Settings.master_thermostat; + settings["known_devices"] = EMSESP_Settings.known_devices; return true; } @@ -1171,6 +1188,18 @@ bool SetListCallback(MYESP_FSACTION_t action, uint8_t wc, const char * setting, } } + // bus_id + if ((strcmp(setting, "bus_id") == 0) && (wc == 2)) { + uint8_t id = strtoul(value, 0, 16); + if ((id == 0x0B) || (id == 0x0D) || (id == 0x0A) || (id == 0x0F) || (id == 0x12)) { + EMSESP_Settings.bus_id = id; + ems_setEMSbusid(id); + ok = true; + } else { + myDebug_P(PSTR("Error. Usage: set bus_id , with ID=0B, 0D, 0A, 0F or 12")); + } + } + // master_thermostat if (strcmp(setting, "master_thermostat") == 0) { if (wc == 1) { @@ -1206,6 +1235,7 @@ bool SetListCallback(MYESP_FSACTION_t action, uint8_t wc, const char * setting, myDebug_P(PSTR(" dallas_gpio=%d"), EMSESP_Settings.dallas_gpio); myDebug_P(PSTR(" dallas_parasite=%s"), EMSESP_Settings.dallas_parasite ? "on" : "off"); myDebug_P(PSTR(" tx_mode=%d"), EMSESP_Settings.tx_mode); + myDebug_P(PSTR(" bus_id=0x%02X"), EMSESP_Settings.bus_id); myDebug_P(PSTR(" listen_mode=%s"), EMSESP_Settings.listen_mode ? "on" : "off"); myDebug_P(PSTR(" shower_timer=%s"), EMSESP_Settings.shower_timer ? "on" : "off"); myDebug_P(PSTR(" shower_alert=%s"), EMSESP_Settings.shower_alert ? "on" : "off"); @@ -1274,6 +1304,27 @@ void TelnetCallback(uint8_t event) { } } +// get the list of know devices, as a string, and save them to the config file +void saveEMSDevices() { + if (Devices.empty()) { + return; + } + + char s[100]; + char buffer[16] = {0}; + s[0] = '\0'; + + for (std::list<_Detected_Device>::iterator it = Devices.begin(); it != Devices.end(); ++it) { + strlcat(s, _hextoa(it->device_id, buffer), sizeof(s)); + strlcat(s, " ", sizeof(s)); + } + + strlcpy(EMSESP_Settings.known_devices, s, sizeof(s)); + + myDebug("The device IDs %s%s%swill be automatically scanned when EMS-ESP boots up.", COLOR_BOLD_ON, EMSESP_Settings.known_devices, COLOR_BOLD_OFF); + myESP.saveSettings(); +} + // extra commands options for telnet debug window // wc is the word count, i.e. number of arguments. Everything is in lower case. void TelnetCommandCallback(uint8_t wc, const char * commandLine) { @@ -1297,32 +1348,46 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { } if (strcmp(first_cmd, "devices") == 0) { - ems_printDevices(); - ok = true; + if (wc == 1) { + // print + ems_printDevices(); + return; + } + + // wc = 2 or more. check for "scan" + char * second_cmd = _readWord(); + if (strcmp(second_cmd, "scan") == 0) { + if (wc == 2) { + // 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(); + ems_doReadCommand(EMS_TYPE_UBADevices, EMS_Boiler.device_id); + return; + } + + // wc is 3 or more. check for additional "force" argument + 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(); + ems_scanDevices(); + return; + } + } else if (strcmp(second_cmd, "save") == 0) { + saveEMSDevices(); + return; + } + + ok = false; // unknown command } + if (strcmp(first_cmd, "queue") == 0) { ems_printTxQueue(); ok = true; } - if (strcmp(first_cmd, "autodetect") == 0) { - if (wc == 2) { - char * second_cmd = _readWord(); - if (strcmp(second_cmd, "scan") == 0) { - ems_clearDeviceList(); - ems_scanDevices(); - ok = true; - } - } else { - myDebug("Scanning for new EMS devices and attached external sensors..."); - scanDallas(); - ems_clearDeviceList(); - ems_doReadCommand(EMS_TYPE_UBADevices, EMS_Boiler.device_id); - ok = true; - } - } - // logging if ((strcmp(first_cmd, "log") == 0) && (wc >= 2)) { char * second_cmd = _readWord(); @@ -1995,7 +2060,9 @@ void initEMSESP() { EMSESP_Settings.led_gpio = EMSESP_LED_GPIO; EMSESP_Settings.dallas_gpio = EMSESP_DALLAS_GPIO; EMSESP_Settings.tx_mode = EMS_TXMODE_DEFAULT; // default tx mode + EMSESP_Settings.bus_id = EMS_BUSID_DEFAULT; // Service Key is default EMSESP_Settings.master_thermostat = 0; + EMSESP_Settings.known_devices = nullptr; // shower settings EMSESP_Shower.timerStart = 0; @@ -2067,6 +2134,38 @@ void showerCheck() { } } +// this is called when we've first established an EMS connection +// go send out some spies to figure out what is on the bus and who's driving it +void startupEMSscan() { + if (EMSESP_Settings.listen_mode) { + return; + } + + // First scan anything we may have saved as known devices from a "devices save" command + if (strlen(EMSESP_Settings.known_devices) > 0) { + char * p; + char * temp = strdup(EMSESP_Settings.known_devices); // because strlok is destructive, make a copy + char value[10] = {0}; + // get first value + if ((p = strtok(temp, " "))) { // delimiter + strlcpy(value, p, sizeof(value)); + uint8_t val = (uint8_t)strtol(value, 0, 16); + ems_doReadCommand(EMS_TYPE_Version, val); + } + // and iterate until end + while (p != 0) { + if ((p = strtok(nullptr, " "))) { + strlcpy(value, p, sizeof(value)); + uint8_t val = (uint8_t)strtol(value, 0, 16); + ems_doReadCommand(EMS_TYPE_Version, val); + } + } + } + + // ask the Boiler to show us it's attached devices in case we missed anything + ems_discoverModels(); +} + // // SETUP // @@ -2102,12 +2201,10 @@ void setup() { myESP.setUseSerial(false); emsuart_init(); // start EMS bus transmissions myDebug_P(PSTR("[UART] Rx/Tx connection established")); - if (!EMSESP_Settings.listen_mode) { - // go and find the boiler and thermostat types, if not in listen mode - ems_discoverModels(); - } + 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 048550868..5198a9afd 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -95,7 +95,9 @@ void ems_init() { EMS_Sys_Status.emsPollFrequency = 0; EMS_Sys_Status.txRetryCount = 0; EMS_Sys_Status.emsIDMask = 0x00; - EMS_Sys_Status.emsPollAck[0] = EMS_ID_ME; + EMS_Sys_Status.emsTxMode = EMS_TXMODE_DEFAULT; + EMS_Sys_Status.emsbusid = EMS_BUSID_DEFAULT; + EMS_Sys_Status.emsPollAck[0] = EMS_BUSID_DEFAULT; // thermostat strlcpy(EMS_Thermostat.datetime, "?", sizeof(EMS_Thermostat.datetime)); @@ -442,6 +444,11 @@ void ems_setTxMode(uint8_t mode) { EMS_Sys_Status.emsTxMode = mode; } +void ems_setEMSbusid(uint8_t id) { + EMS_Sys_Status.emsbusid = id; + EMS_Sys_Status.emsPollAck[0] = id; +} + void ems_setMasterThermostat(uint8_t product_id) { EMS_Sys_Status.emsMasterThermostat = product_id; } @@ -577,7 +584,7 @@ void _ems_sendTelegram() { } // create the header - EMS_TxTelegram.data[0] = EMS_ID_ME ^ EMS_Sys_Status.emsIDMask; // src + EMS_TxTelegram.data[0] = EMS_Sys_Status.emsbusid ^ EMS_Sys_Status.emsIDMask; // src // dest if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_WRITE) { @@ -752,7 +759,7 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { if ((length >= 5) && (telegram[length - 1] == _crcCalculator(telegram, length))) { EMS_Sys_Status.emsTxStatus = EMS_TX_STATUS_IDLE; EMS_Sys_Status.emsIDMask = telegram[0] & 0x80; - EMS_Sys_Status.emsPollAck[0] = EMS_ID_ME ^ EMS_Sys_Status.emsIDMask; + EMS_Sys_Status.emsPollAck[0] = EMS_Sys_Status.emsbusid ^ EMS_Sys_Status.emsIDMask; } else return; // ignore the whole telegram Rx Telegram while in DETECT mode } @@ -779,7 +786,7 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { uint8_t value = telegram[0]; // 1st byte of data package // check first for a Poll for us - if ((value ^ 0x80 ^ EMS_Sys_Status.emsIDMask) == EMS_ID_ME) { + if ((value ^ 0x80 ^ EMS_Sys_Status.emsIDMask) == EMS_Sys_Status.emsbusid) { static uint32_t _last_emsPollFrequency = 0; uint32_t timenow_microsecs = micros(); EMS_Sys_Status.emsPollFrequency = (timenow_microsecs - _last_emsPollFrequency); @@ -919,7 +926,7 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) { (void)ems_getDeviceTypeDescription(dest, type_s); strlcat(output_str, type_s, sizeof(output_str)); - if (dest == EMS_ID_ME) { + if (dest == EMS_Sys_Status.emsbusid) { strlcpy(color_s, COLOR_YELLOW, sizeof(color_s)); // me } else if (dest == EMS_ID_NONE) { strlcpy(color_s, COLOR_GREEN, sizeof(color_s)); // broadcast @@ -1753,7 +1760,7 @@ 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 is 15 (I think) + * Junkers has 15 bytes of data */ void _process_UBADevices(_EMS_RxTelegram * EMS_RxTelegram) { if (EMS_RxTelegram->data_length > EMS_SYS_DEVICEMAP_LENGTH) { @@ -1774,8 +1781,8 @@ void _process_UBADevices(_EMS_RxTelegram * EMS_RxTelegram) { 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_ID_ME) { - // myDebug("[EMS] Detected new EMS Device with ID 0x%02X", device_id); + 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 } @@ -1921,7 +1928,7 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { * Figure out the boiler and thermostat types */ void ems_discoverModels() { - //myDebug_P(PSTR("Starting auto discover of EMS devices...")); + // ask Boiler for it's known devices ems_doReadCommand(EMS_TYPE_UBADevices, EMS_ID_BOILER); } @@ -2107,7 +2114,7 @@ bool ems_getDeviceTypeDescription(uint8_t device_id, char * buffer) { // check for the fixed device IDs we already know about, like 0x00 for broadcast, 0x0B for me, 0x08 for Boiler if (device_id == EMS_ID_BOILER) { device_type = EMS_DEVICE_TYPE_BOILER; - } else if (device_id == EMS_ID_ME) { + } else if (device_id == EMS_Sys_Status.emsbusid) { device_type = EMS_DEVICE_TYPE_SERVICEKEY; } else if (device_id == EMS_ID_NONE) { device_type = EMS_DEVICE_TYPE_NONE; @@ -2225,7 +2232,7 @@ void ems_printDevices() { for (uint8_t bit = 0; bit < 8; bit++) { if (byte & 0x01) { uint8_t device_id = ((data_byte + 1) * 8) + bit; - if (device_id != EMS_ID_ME) { + if (device_id != EMS_Sys_Status.emsbusid) { strlcat(s, " 0x", sizeof(s)); strlcat(s, _hextoa(device_id, buffer), sizeof(s)); } @@ -2236,7 +2243,6 @@ void ems_printDevices() { } strlcat(s, COLOR_BOLD_OFF, sizeof(s)); - myDebug_P(PSTR("")); // newline myDebug(s); // print out the ones we recognized @@ -2312,7 +2318,7 @@ void ems_sendRawTelegram(char * telegram) { strlcpy(value, p, sizeof(value)); EMS_TxTelegram.data[0] = (uint8_t)strtol(value, 0, 16); } - // and interate until end + // and iterate until end while (p != 0) { if ((p = strtok(nullptr, " ,"))) { strlcpy(value, p, sizeof(value)); @@ -2785,10 +2791,10 @@ void ems_setWarmTapWaterActivated(bool activated) { EMS_TxTelegram.comparisonPostRead = EMS_TxTelegram.type; // create header - EMS_TxTelegram.data[0] = EMS_ID_ME; // src - EMS_TxTelegram.data[1] = EMS_TxTelegram.dest; // dest - EMS_TxTelegram.data[2] = EMS_TxTelegram.type; // type - EMS_TxTelegram.data[3] = EMS_TxTelegram.offset; // offset + EMS_TxTelegram.data[0] = EMS_Sys_Status.emsbusid; // src + EMS_TxTelegram.data[1] = EMS_TxTelegram.dest; // dest + EMS_TxTelegram.data[2] = EMS_TxTelegram.type; // type + EMS_TxTelegram.data[3] = EMS_TxTelegram.offset; // offset // we use the special test mode 0x1D for this. Setting the first data to 5A puts the system into test mode and // a setting of 0x00 puts it back into normal operating mode @@ -2823,11 +2829,11 @@ void ems_startupTelegrams() { char s[20] = {0}; // Write type 0x1D to get out of function test mode - snprintf(s, sizeof(s), "%02X %02X 1D 00 00", EMS_ID_ME, EMS_Boiler.device_id); + snprintf(s, sizeof(s), "%02X %02X 1D 00 00", EMS_Sys_Status.emsbusid, EMS_Boiler.device_id); ems_sendRawTelegram(s); // Read type 0x01 - snprintf(s, sizeof(s), "%02X %02X 01 00 1B", EMS_ID_ME, EMS_Boiler.device_id | 0x80); + snprintf(s, sizeof(s), "%02X %02X 01 00 1B", EMS_Sys_Status.emsbusid, EMS_Boiler.device_id | 0x80); ems_sendRawTelegram(s); } @@ -2862,7 +2868,7 @@ void ems_testTelegram(uint8_t test_num) { telegram[0] = (uint8_t)strtol(value, 0, 16); } - // and interate until end + // and iterate until end while (p != 0) { if ((p = strtok(nullptr, " ,"))) { strlcpy(value, p, sizeof(value)); @@ -3011,7 +3017,7 @@ void _ems_processTelegram(_EMS_RxTelegram * EMS_RxTelegram) { // we're only interested in broadcast messages (dest is 0x00) or ones for us (dest is 0x0B) uint8_t dest = EMS_RxTelegram->dest; - if ((dest != EMS_ID_NONE) && (dest != EMS_ID_ME)) { + if ((dest != EMS_ID_NONE) && (dest != EMS_Sys_Status.emsbusid)) { return; } @@ -3048,7 +3054,7 @@ void _processType(_EMS_RxTelegram * EMS_RxTelegram) { uint8_t * telegram = EMS_RxTelegram->telegram; // if its an echo of ourselves from the master UBA, ignore. This should never happen mind you - if (EMS_RxTelegram->src == EMS_ID_ME) { + if (EMS_RxTelegram->src == EMS_Sys_Status.emsbusid) { if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_JABBER) _debugPrintTelegram("echo: ", EMS_RxTelegram, COLOR_WHITE); return; @@ -3066,7 +3072,7 @@ void _processType(_EMS_RxTelegram * EMS_RxTelegram) { // at this point we can assume TxStatus was EMS_TX_STATUS_WAIT as we just sent a read or validate telegram // for READ or VALIDATE the dest (telegram[1]) is always us, so check for this // and if not we probably didn't get any response so remove the last Tx from the queue and process the telegram anyway - if ((telegram[1] & 0x7F) != EMS_ID_ME) { + if ((telegram[1] & 0x7F) != EMS_Sys_Status.emsbusid) { _removeTxQueue(); _ems_processTelegram(EMS_RxTelegram); return; @@ -3215,8 +3221,6 @@ void ems_doReadCommand(uint16_t type, uint8_t dest) { * Find the versions of our connected devices */ void ems_scanDevices() { - myDebug_P(PSTR("Started scanning the EMS bus for known devices. This can take up to 10 seconds...")); - std::list Device_Ids; // create a new list Device_Ids.push_back(EMS_ID_BOILER); // UBAMaster/Boilers - 0x08 diff --git a/src/ems.h b/src/ems.h index 5693a6918..a28a15819 100644 --- a/src/ems.h +++ b/src/ems.h @@ -12,6 +12,9 @@ #include #include // std::list +// EMS bus IDs +#define EMS_BUSID_DEFAULT 0x0B // Default 0x0B (Service Key) + // EMS tx_mode types #define EMS_TXMODE_DEFAULT 1 // Default (was previously known as tx_mode 2 in v1.8.x) #define EMS_TXMODE_EMSPLUS 2 // EMS+ @@ -147,6 +150,7 @@ typedef struct { 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 } _EMS_Sys_Status; @@ -235,7 +239,7 @@ const _EMS_Device_Types EMS_Devices_Types[] = { {EMS_DEVICE_TYPE_UNKNOWN, EMS_MODELTYPE_UNKNOWN_STRING}, // the first, at index 0 is reserved for "unknown" {EMS_DEVICE_TYPE_NONE, "All"}, {EMS_DEVICE_TYPE_SERVICEKEY, "Me"}, - {EMS_DEVICE_TYPE_BOILER, "UBAMaster"}, + {EMS_DEVICE_TYPE_BOILER, "Boiler"}, {EMS_DEVICE_TYPE_THERMOSTAT, "Thermostat"}, {EMS_DEVICE_TYPE_MIXING, "Mixing Module"}, {EMS_DEVICE_TYPE_SOLAR, "Solar Module"}, @@ -243,7 +247,7 @@ const _EMS_Device_Types EMS_Devices_Types[] = { {EMS_DEVICE_TYPE_GATEWAY, "Gateway"}, {EMS_DEVICE_TYPE_SWITCH, "Switching Module"}, {EMS_DEVICE_TYPE_CONTROLLER, "Controller"}, - {EMS_DEVICE_TYPE_CONNECT, "Connect"} + {EMS_DEVICE_TYPE_CONNECT, "Connect Module"} }; @@ -462,6 +466,7 @@ void ems_setWarmWaterModeComfort(uint8_t comfort); void ems_setModels(); void ems_setTxDisabled(bool b); void ems_setTxMode(uint8_t mode); +void ems_setEMSbusid(uint8_t id); void ems_setMasterThermostat(uint8_t product_id); char * ems_getDeviceDescription(_EMS_DEVICE_TYPE device_type, char * buffer, bool name_only = false); bool ems_getDeviceTypeDescription(uint8_t device_id, char * buffer); diff --git a/src/ems_devices.h b/src/ems_devices.h index 87748f3f1..c46da34a5 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -12,7 +12,6 @@ #include "ems.h" // Fixed EMS Device IDs -#define EMS_ID_ME 0x0B // our device, hardcoded as the "Service Key" #define EMS_ID_BOILER 0x08 // all UBA Boilers have 0x08 /* diff --git a/src/version.h b/src/version.h index 303603e7a..325403ca9 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define APP_VERSION "1.9.5b34" +#define APP_VERSION "1.9.5b35" diff --git a/tools/wsemulator/wserver.js b/tools/wsemulator/wserver.js index 2f5f461e2..5e606ad21 100644 --- a/tools/wsemulator/wserver.js +++ b/tools/wsemulator/wserver.js @@ -98,7 +98,8 @@ var custom_configfile = { "shower_timer": true, "shower_alert": false, "publish_time": 10, - "tx_mode": 1 + "tx_mode": 1, + "bus_id": 11 } };