diff --git a/doc/home assistant/climate.yaml b/doc/home assistant/climate.yaml index 083b4246b..d2e70f472 100644 --- a/doc/home assistant/climate.yaml +++ b/doc/home assistant/climate.yaml @@ -5,12 +5,12 @@ - "heat" - "off" - mode_state_topic: "home/ems-esp/thermostat_data" - current_temperature_topic: "home/ems-esp/thermostat_data" - temperature_state_topic: "home/ems-esp/thermostat_data" + mode_state_topic: "home/ems-esp/thermostat_data1" + current_temperature_topic: "home/ems-esp/thermostat_data1" + temperature_state_topic: "home/ems-esp/thermostat_data1" - temperature_command_topic: "home/ems-esp/thermostat_cmd_temp" - mode_command_topic: "home/ems-esp/thermostat_cmd_mode" + temperature_command_topic: "home/ems-esp/thermostat_cmd_temp1" + mode_command_topic: "home/ems-esp/thermostat_cmd_mode1" mode_state_template: "{{ value_json.thermostat_mode }}" current_temperature_template: "{{ value_json.thermostat_currtemp }}" diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 5c1a07560..74ff85866 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -417,8 +417,7 @@ uint8_t _getThermostatMode(uint8_t hc_num) { } else if (mode == 1) { thermoMode = 0; } - } - else { // default for all other thermostats + } else { // default for all other thermostats if (mode == 0) { thermoMode = 3; // night } else if (mode == 1) { @@ -683,8 +682,8 @@ void showInfo() { for (uint8_t hc_num = 1; hc_num <= EMS_THERMOSTAT_MAXHC; hc_num++) { if (EMS_Mixing.hc[hc_num - 1].active) { - myDebug_P(PSTR(" Mixing Circuit %d"), hc_num); - _renderShortValue(" Current flow temperature", "C", EMS_Mixing.hc[hc_num - 1].flowTemp); + myDebug_P(PSTR(" Mixing Circuit %d"), hc_num); + _renderUShortValue(" Current flow temperature", "C", EMS_Mixing.hc[hc_num - 1].flowTemp); } } } @@ -722,22 +721,22 @@ void publishSensorValues() { bool hasdata = false; char label[8] = {0}; - // char valuestr[8] = {0}; // for formatting temp - // see if the sensor values have changed, if so send + // see if the sensor values have changed, if so send it on for (uint8_t i = 0; i < EMSESP_Settings.dallas_sensors; i++) { - double sensorValue = ds18.getValue(i); + // round to 2 decimal places. from https://arduinojson.org/v6/faq/how-to-configure-the-serialization-of-floats/ + double sensorValue = (int)(ds18.getValue(i) * 100 + 0.5) / 100.0; if (sensorValue != DS18_DISCONNECTED && sensorValue != DS18_CRC_ERROR) { sprintf(label, PAYLOAD_EXTERNAL_SENSORS, (i + 1)); - // sensors[label] = _float_to_char(valuestr, sensorValue); - sensors[label] = sensorValue; // TODO check if works - hasdata = true; + sensors[label] = sensorValue; + hasdata = true; } } if (hasdata) { char data[200] = {0}; serializeJson(doc, data, sizeof(data)); + myDebugLog("Publishing external sensor data via MQTT"); myESP.mqttPublish(TOPIC_EXTERNAL_SENSORS, data); } } @@ -872,20 +871,16 @@ void publishValues(bool force) { // handle the thermostat values if (ems_getThermostatEnabled()) { - uint8_t total_active_hc = 0; // number of HCs - bool hc_1_active = EMS_Thermostat.hc[EMS_THERMOSTAT_DEFAULTHC - 1].active; // do we have HC1 active? for (uint8_t hc_v = 1; hc_v <= EMS_THERMOSTAT_MAXHC; hc_v++) { _EMS_Thermostat_HC * thermostat = &EMS_Thermostat.hc[hc_v - 1]; // only send if we have an active Heating Circuit with real data if (thermostat->active) { - total_active_hc++; // increase count for #HCs we encounter - // build new json object doc.clear(); JsonObject rootThermostat = doc.to(); - rootThermostat[THERMOSTAT_HC] = _int_to_char(s, thermostat->hc); // heating circuit 1..4 + // rootThermostat[THERMOSTAT_HC] = _int_to_char(s, thermostat->hc); // heating circuit 1..4 // different logic depending on thermostat types if (ems_getThermostatModel() == EMS_MODEL_EASY) { @@ -949,14 +944,10 @@ void publishValues(bool force) { if ((previousThermostatPublishCRC != fchecksum) || force) { previousThermostatPublishCRC = fchecksum; char thermostat_topicname[20]; - strlcpy(thermostat_topicname, TOPIC_THERMOSTAT_DATA, sizeof(thermostat_topicname)); // "thermostat_data" - // if we have more than 1 active Heating Circuit - // or this is single HC and its not HC1 - // append topic name with the HC number - if ((total_active_hc > 1) || ((total_active_hc == 1) && (!hc_1_active))) { - char buffer[4]; - strlcat(thermostat_topicname, itoa(total_active_hc, buffer, 10), sizeof(thermostat_topicname)); - } + char buffer[4]; + // "thermostat_data" + Heating Cicruit # + strlcpy(thermostat_topicname, TOPIC_THERMOSTAT_DATA, sizeof(thermostat_topicname)); + strlcat(thermostat_topicname, itoa(hc_v, buffer, 10), sizeof(thermostat_topicname)); myDebugLog("Publishing thermostat data via MQTT"); myESP.mqttPublish(thermostat_topicname, data); } @@ -1456,7 +1447,8 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { } if (strcmp(first_cmd, "publish") == 0) { - publishValues(true); + do_publishValues(); + do_publishSensorValues(); ok = true; } @@ -1666,33 +1658,25 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { // subscribe to the 4 heating circuits char topic_s[50]; char buffer[4]; - - // subscribe to the normal batch to be backwards compatible - myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_TEMP); - myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_MODE); - myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_DAYTEMP); - myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_NIGHTTEMP); - myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP); - for (uint8_t hc = 1; hc <= EMS_THERMOSTAT_MAXHC; hc++) { strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_TEMP, sizeof(topic_s)); - strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); // add 1-4 at the end + strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); myESP.mqttSubscribe(topic_s); strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_MODE, sizeof(topic_s)); - strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); // add 1-4 at the end + strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); myESP.mqttSubscribe(topic_s); strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_DAYTEMP, sizeof(topic_s)); - strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); // add 1-4 at the end + strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); myESP.mqttSubscribe(topic_s); strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_NIGHTTEMP, sizeof(topic_s)); - strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); // add 1-4 at the end + strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); myESP.mqttSubscribe(topic_s); strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP, sizeof(topic_s)); - strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); // add 1-4 at the end + strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); myESP.mqttSubscribe(topic_s); } @@ -2187,16 +2171,17 @@ void loop() { // the main loop myESP.loop(); - // check Dallas sensors, every 2 seconds + // check Dallas sensors, using same schedule as publish_time (default 2 mins) // these values are published to MQTT separately via the timer publishSensorValuesTimer if (EMSESP_Settings.dallas_sensors != 0) { ds18.loop(); } - // publish the values to MQTT, only if the values have changed + // publish all the values to MQTT, only if the values have changed // although we don't want to publish when doing a deep scan of the thermostat if (ems_getEmsRefreshed() && (scanThermostat_count == 0)) { publishValues(false); + do_publishSensorValues(); ems_setEmsRefreshed(false); // reset } diff --git a/src/ems.cpp b/src/ems.cpp index 0f9b91517..5e363f35b 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -210,7 +210,7 @@ _EMS_Thermostat EMS_Thermostat; // for thermostat _EMS_SolarModule EMS_SolarModule; // for solar modules _EMS_HeatPump EMS_HeatPump; // for heatpumps _EMS_Mixing EMS_Mixing; // for mixing devices -_EMS_Other EMS_Other; // for other known EMS devices +_EMS_Other EMS_Other; // for other known EMS devices // CRC lookup table with poly 12 for faster checking const uint8_t ems_crc_table[] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, @@ -655,7 +655,7 @@ void _ems_sendTelegram() { EMS_TxTelegram.data[1] = EMS_TxTelegram.dest; } else { // for a READ or VALIDATE - EMS_TxTelegram.data[1] = (EMS_TxTelegram.dest | 0x80); // read has 8th bit set, always + EMS_TxTelegram.data[1] = (EMS_TxTelegram.dest | 0x80); // read has 8th bit set, always } // complete the rest of the header depending on EMS or EMS+ @@ -1489,13 +1489,12 @@ void _process_EasyStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { void _process_MMPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { uint8_t hc = (EMS_RxTelegram->type - EMS_TYPE_MMPLUSStatusMessage_HC1); // 0 to 3 - if (hc > 4) { + if (hc > EMS_THERMOSTAT_MAXHC) { return; // invalid type } EMS_Mixing.hc[hc].active = true; - - if (EMS_RxTelegram->data_length == 1) { + if (EMS_RxTelegram->data_length == 1) { } else if (EMS_RxTelegram->data_length > 8) { EMS_Mixing.hc[hc].flowTemp = _toShort(EMS_OFFSET_MMPLUSStatusMessage_flow_temp); } @@ -1508,7 +1507,7 @@ void _process_MMPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { // figure out which heating circuit uint8_t hc = (EMS_RxTelegram->type - EMS_TYPE_RCPLUSStatusMessage_HC1); // 0 to 3 - if (hc > 4) { + if (hc > EMS_THERMOSTAT_MAXHC) { return; // invalid type } EMS_Thermostat.hc[hc].active = true; @@ -1567,7 +1566,7 @@ void _process_JunkersStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { EMS_Thermostat.hc[hc].curr_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_curr); // value is * 10 EMS_Thermostat.hc[hc].setpoint_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_setpoint); // value is * 10 EMS_Thermostat.hc[hc].mode = _toByte(EMS_OFFSET_JunkersStatusMessage_mode); - EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT + EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } } @@ -2203,47 +2202,12 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { } } -/* - * See if we have a Junkers Heatronic 3 compatible device - * Do a read command for the version with the src having the MSB set - */ -void _ems_detectJunkers() { -#ifdef JUNKERS_DETECT - char s[30] = {0}; - snprintf(s, sizeof(s), "%02X %02X %02X 00 %02X", (EMS_ID_ME | 0x80), (EMS_ID_BOILER | 0x080), EMS_TYPE_Version, EMS_MAX_TELEGRAM_LENGTH); - ems_sendRawTelegram(s); -#endif -} - /* * Figure out the boiler and thermostat types */ void ems_discoverModels() { myDebug_P(PSTR("Starting auto discover of EMS devices...")); ems_doReadCommand(EMS_TYPE_UBADevices, EMS_ID_BOILER); - - // ems_startupTelegrams(); - - // TODO remove this part eventually, ems_discoverModels() - /* - - // boiler... - // ems_doReadCommand(EMS_TYPE_Version, EMS_ID_BOILER); - // _ems_detectJunkers(); // special hack for Junkers detection - - ems_doReadCommand(EMS_TYPE_Version, EMS_ID_SM); // check if there is Solar Module available - ems_doReadCommand(EMS_TYPE_Version, EMS_ID_HP); // check if there is HeatPump Module available - - // thermostat... - // if it hasn't been set, auto discover it - if (EMS_Thermostat.device_id == EMS_ID_NONE) { - ems_scanDevices(); // auto-discover it - } else { - // set the model as hardcoded (see my_devices.h) and fetch the version and product id - ems_doReadCommand(EMS_TYPE_Version, EMS_Thermostat.device_id); - } - - */ } /** @@ -2592,9 +2556,6 @@ void ems_scanDevices() { for (uint8_t device_id : Device_Ids) { ems_doReadCommand(EMS_TYPE_Version, device_id); } - - // add a check for Junkers onto the queue - _ems_detectJunkers(); } /** @@ -2845,7 +2806,7 @@ void ems_setThermostatTemp(float temperature, uint8_t hc_num, uint8_t temptype) return; } - if (hc_num < 1 || hc_num > 4) { + if (hc_num < 1 || hc_num > EMS_THERMOSTAT_MAXHC) { myDebug_P(PSTR("Invalid HC number")); return; } @@ -2955,7 +2916,7 @@ void ems_setThermostatMode(uint8_t mode, uint8_t hc_num) { return; } - if (hc_num < 1 || hc_num > 4) { + if (hc_num < 1 || hc_num > EMS_THERMOSTAT_MAXHC) { myDebug_P(PSTR("Invalid HC number")); return; } diff --git a/src/ems.h b/src/ems.h index ae9d6bdf9..4d5c25a98 100644 --- a/src/ems.h +++ b/src/ems.h @@ -276,7 +276,6 @@ typedef struct { typedef struct { uint8_t product_id; - uint8_t device_id; char model_string[50]; } _Mixing_Device; @@ -378,10 +377,10 @@ typedef struct { uint8_t model_id; uint8_t product_id; char version[10]; - uint8_t hc; // heating circuit 1,2, 3 or 4 - bool active; // true if there is data for this HC + uint8_t hc; // heating circuit 1, 2, 3 or 4 + bool active; // true if there is data for this HC - uint8_t flowTemp; + uint16_t flowTemp; } _EMS_Mixing_HC; // Mixer data