From 0a56ee7dbb7f2e3a90d376595f4bfea55d5916a7 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 7 Oct 2022 08:09:07 +0200 Subject: [PATCH 1/8] add FW500 thermostat #666 --- src/device_library.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/device_library.h b/src/device_library.h index ad377e8c9..7cf0761fe 100644 --- a/src/device_library.h +++ b/src/device_library.h @@ -110,6 +110,7 @@ {109, DeviceType::THERMOSTAT, F("FB10"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, {110, DeviceType::THERMOSTAT, F("FB100"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, {111, DeviceType::THERMOSTAT, F("FR10"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model +{116, DeviceType::THERMOSTAT, F("FW500"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, {147, DeviceType::THERMOSTAT, F("FR50"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, {191, DeviceType::THERMOSTAT, F("FR120"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS | DeviceFlags::EMS_DEVICE_FLAG_JUNKERS_OLD}, // older model {192, DeviceType::THERMOSTAT, F("FW120"), DeviceFlags::EMS_DEVICE_FLAG_JUNKERS}, From bace01e4f70dc0f7666ce00352c7206e54e777e3 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 7 Oct 2022 10:56:52 +0200 Subject: [PATCH 2/8] show trailing zero for float values, #663 --- CHANGELOG_LATEST.md | 6 ++- src/dallassensor.cpp | 17 +++--- src/emsdevice.cpp | 122 +++++++++++-------------------------------- 3 files changed, 44 insertions(+), 101 deletions(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 6e4ea2a1e..d662aa539 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -4,10 +4,11 @@ ## Added -- Translations in Web UI and all device entity names to German. [#22](https://github.com/emsesp/EMS-ESP32/issues/22) +- Translations in Web UI and all device entity names (DE, NL, SE, PL, NO, ...). [#22](https://github.com/emsesp/EMS-ESP32/issues/22) - Add support for Lolin C3 mini [#620](https://github.com/emsesp/EMS-ESP32/pull/620) -- Add Greenstar 30Ri boiler +- Add devices: Greenstar 30Ri boiler, Junkers FW500 thermostat, Buderus BC30 controller - Add program memory info +- Add mqtt queue and connection infos - Add min/max setting to customizations - Adapt min/max if ems-value is not in this range - Add heatpump settings for inputs and limits @@ -20,6 +21,7 @@ - Discovery in HomeAssistant don't work with custom base topic. [#596](https://github.com/emsesp/EMS-ESP32/issues/596) Base topic containing `/` are changed to `_` - RF room temperature sensor are shown as thermostat +- render mqtt float json values with trailing zero ## **BREAKING CHANGES:** diff --git a/src/dallassensor.cpp b/src/dallassensor.cpp index 53fb0c8e5..6584bbd27 100644 --- a/src/dallassensor.cpp +++ b/src/dallassensor.cpp @@ -360,14 +360,15 @@ bool DallasSensor::command_info(const char * value, const int8_t id, JsonObject } for (const auto & sensor : sensors_) { + char val[10]; if (id == -1) { // show number and id JsonObject dataSensor = output.createNestedObject(sensor.name()); dataSensor["id"] = sensor.id(); if (Helpers::hasValue(sensor.temperature_c)) { - dataSensor["temp"] = Helpers::transformNumFloat((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); + dataSensor["temp"] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); } } else if (Helpers::hasValue(sensor.temperature_c)) { - output[sensor.name()] = Helpers::transformNumFloat((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); + output[sensor.name()] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); } } @@ -392,12 +393,13 @@ bool DallasSensor::get_value_info(JsonObject & output, const char * cmd, const i if (strcmp(command_s, sensor.name().c_str()) == 0) { output["id"] = sensor.id(); output["name"] = sensor.name(); + char val[10]; if (Helpers::hasValue(sensor.temperature_c)) { - output["value"] = Helpers::transformNumFloat((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); + output["value"] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); } output["type"] = F_(number); - output["min"] = Helpers::transformNumFloat(-55, 0, EMSESP::system_.fahrenheit() ? 2 : 0); - output["max"] = Helpers::transformNumFloat(125, 0, EMSESP::system_.fahrenheit() ? 2 : 0); + output["min"] = serialized(Helpers::render_value(val, -55, 0, EMSESP::system_.fahrenheit() ? 2 : 0)); + output["max"] = serialized(Helpers::render_value(val, 125, 0, EMSESP::system_.fahrenheit() ? 2 : 0)); output["uom"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); output["writeable"] = false; // if we're filtering on an attribute, go find it @@ -469,14 +471,15 @@ void DallasSensor::publish_values(const bool force) { for (auto & sensor : sensors_) { bool has_value = Helpers::hasValue(sensor.temperature_c); + char val[10]; if (Mqtt::is_nested()) { JsonObject dataSensor = doc.createNestedObject(sensor.id()); dataSensor["name"] = sensor.name(); if (has_value) { - dataSensor["temp"] = Helpers::transformNumFloat((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); + dataSensor["temp"] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); } } else if (has_value) { - doc[sensor.name()] = Helpers::transformNumFloat((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); + doc[sensor.name()] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); } // create the HA MQTT config diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index b07b97ec6..30034f65b 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -791,18 +791,19 @@ void EMSdevice::generate_values_web(JsonObject & output) { // note, the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; + char val[10]; if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) { - obj["v"] = Helpers::transformNumFloat(*(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit); + obj["v"] = serialized(Helpers::render_value(val, *(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { - obj["v"] = Helpers::transformNumFloat(*(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit); + obj["v"] = serialized(Helpers::render_value(val, *(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) { - obj["v"] = Helpers::transformNumFloat(*(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit); + obj["v"] = serialized(Helpers::render_value(val, *(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) { - obj["v"] = Helpers::transformNumFloat(*(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit); + obj["v"] = serialized(Helpers::render_value(val, *(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - obj["v"] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), dv.numeric_operator, fahrenheit); + obj["v"] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - obj["v"] = dv.numeric_operator ? (*(uint32_t *)(dv.value_p) / dv.numeric_operator) : *(uint32_t *)(dv.value_p); + obj["v"] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); } else { obj["v"] = ""; // must have a value for sorting to work } @@ -901,40 +902,20 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) { // handle Integers and Floats else { - int8_t num_op = dv.numeric_operator; - bool make_float; - if (num_op == 0) { - // no changes to number - make_float = false; - num_op = 1; // so it gets *1 - } else if (num_op < 0) { - // negative numbers, convert to a positive multiplier - make_float = false; - num_op *= -1; - } else { - // has a divider, make it a float - make_float = true; - } - - // always convert temperatures to floats with 1 decimal place - if ((dv.uom == DeviceValueUOM::DEGREES) || (dv.uom == DeviceValueUOM::DEGREES_R)) { - make_float = true; - } - + char val[10]; if (dv.type == DeviceValueType::INT) { - obj["v"] = make_float ? Helpers::transformNumFloat(*(int8_t *)(dv.value_p), num_op, fahrenheit) : *(int8_t *)(dv.value_p) * num_op; + obj["v"] = serialized(Helpers::render_value(val, *(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if (dv.type == DeviceValueType::UINT) { - obj["v"] = make_float ? Helpers::transformNumFloat(*(uint8_t *)(dv.value_p), num_op, fahrenheit) : *(uint8_t *)(dv.value_p) * num_op; + obj["v"] = serialized(Helpers::render_value(val, *(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if (dv.type == DeviceValueType::SHORT) { - obj["v"] = make_float ? Helpers::transformNumFloat(*(int16_t *)(dv.value_p), num_op, fahrenheit) : *(int16_t *)(dv.value_p) * num_op; + obj["v"] = serialized(Helpers::render_value(val, *(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if (dv.type == DeviceValueType::USHORT) { - obj["v"] = make_float ? Helpers::transformNumFloat(*(uint16_t *)(dv.value_p), num_op, fahrenheit) : *(uint16_t *)(dv.value_p) * num_op; + obj["v"] = serialized(Helpers::render_value(val, *(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if (dv.type == DeviceValueType::ULONG) { - obj["v"] = make_float ? Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op) : *(uint32_t *)(dv.value_p) * num_op; + obj["v"] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); } else if (dv.type == DeviceValueType::TIME) { // sometimes we need to divide by 60 - obj["v"] = (num_op == DeviceValueNumOp::DV_NUMOP_DIV60) ? (uint32_t)Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op) - : *(uint32_t *)(dv.value_p); + obj["v"] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); } } } @@ -1095,8 +1076,6 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 // search device value with this tag for (auto & dv : devicevalues_) { if (strcmp(command_s, Helpers::toLower(read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag)) { - int8_t num_op = dv.numeric_operator; - uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; const char * type = "type"; @@ -1117,6 +1096,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 json["circuit"] = tag_to_mqtt(dv.tag); } + char val[10]; switch (dv.type) { case DeviceValueType::ENUM: { if (*(uint8_t *)(dv.value_p) < dv.options_size) { @@ -1136,35 +1116,35 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 case DeviceValueType::USHORT: if (Helpers::hasValue(*(uint16_t *)(dv.value_p))) { - json[value] = Helpers::transformNumFloat(*(uint16_t *)(dv.value_p), num_op, fahrenheit); + json[value] = serialized(Helpers::render_value(val, *(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } json[type] = F_(number); break; case DeviceValueType::UINT: if (Helpers::hasValue(*(uint8_t *)(dv.value_p))) { - json[value] = Helpers::transformNumFloat(*(uint8_t *)(dv.value_p), num_op, fahrenheit); + json[value] = serialized(Helpers::render_value(val, *(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } json[type] = F_(number); break; case DeviceValueType::SHORT: if (Helpers::hasValue(*(int16_t *)(dv.value_p))) { - json[value] = Helpers::transformNumFloat(*(int16_t *)(dv.value_p), num_op, fahrenheit); + json[value] = serialized(Helpers::render_value(val, *(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } json[type] = F_(number); break; case DeviceValueType::INT: if (Helpers::hasValue(*(int8_t *)(dv.value_p))) { - json[value] = Helpers::transformNumFloat(*(int8_t *)(dv.value_p), num_op, fahrenheit); + json[value] = serialized(Helpers::render_value(val, *(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } json[type] = F_(number); break; case DeviceValueType::ULONG: if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - json[value] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op); + json[value] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); } json[type] = F_(number); break; @@ -1186,7 +1166,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 case DeviceValueType::TIME: if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - json[value] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op); + json[value] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); } json[type] = F_(number); break; @@ -1368,64 +1348,22 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; - - int8_t num_op = dv.numeric_operator; - bool make_float; - if (num_op == 0) { - // no changes to number - make_float = false; - num_op = 1; // so it gets *1 - } else if (num_op < 0) { - // negative numbers, convert to a positive multiplier - make_float = false; - num_op *= -1; - } else { - // has a divider, make it a float - make_float = true; - } - - // always convert temperatures to floats with 1 decimal place - if ((dv.uom == DeviceValueUOM::DEGREES) || (dv.uom == DeviceValueUOM::DEGREES_R)) { - make_float = true; - } - + char val[10]; if (dv.type == DeviceValueType::INT) { - if (make_float) { - json[name] = Helpers::transformNumFloat(*(int8_t *)(dv.value_p), num_op, fahrenheit); - } else { - json[name] = *(int8_t *)(dv.value_p) * num_op; - } + json[name] = serialized(Helpers::render_value(val, *(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if (dv.type == DeviceValueType::UINT) { - if (make_float) { - json[name] = Helpers::transformNumFloat(*(uint8_t *)(dv.value_p), num_op, fahrenheit); - } else { - json[name] = *(uint8_t *)(dv.value_p) * num_op; - } + json[name] = serialized(Helpers::render_value(val, *(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if (dv.type == DeviceValueType::SHORT) { - if (make_float) { - json[name] = Helpers::transformNumFloat(*(int16_t *)(dv.value_p), num_op, fahrenheit); - } else { - json[name] = *(int16_t *)(dv.value_p) * num_op; - } + json[name] = serialized(Helpers::render_value(val, *(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if (dv.type == DeviceValueType::USHORT) { - if (make_float) { - json[name] = Helpers::transformNumFloat(*(uint16_t *)(dv.value_p), num_op, fahrenheit); - } else { - json[name] = *(uint16_t *)(dv.value_p) * num_op; - } + json[name] = serialized(Helpers::render_value(val, *(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); } else if (dv.type == DeviceValueType::ULONG) { - if (make_float) { - json[name] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op, fahrenheit); - } else { - json[name] = *(uint32_t *)(dv.value_p) * num_op; - } + json[name] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - uint32_t time_value; - if (num_op == DeviceValueNumOp::DV_NUMOP_DIV60) { + uint32_t time_value = *(uint32_t *)(dv.value_p); + if (dv.numeric_operator == DeviceValueNumOp::DV_NUMOP_DIV60) { // sometimes we need to divide by 60 - time_value = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), num_op); - } else { - time_value = *(uint32_t *)(dv.value_p); + time_value /= 60; } if (output_target == OUTPUT_TARGET::API_VERBOSE || output_target == OUTPUT_TARGET::CONSOLE) { char time_s[60]; From d1fc050bede5da2bc6342abd9b038c8fca4f5439 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 7 Oct 2022 11:14:19 +0200 Subject: [PATCH 3/8] flags on signin page --- interface/src/SignIn.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interface/src/SignIn.tsx b/interface/src/SignIn.tsx index 297658e0e..3e2b02dd2 100644 --- a/interface/src/SignIn.tsx +++ b/interface/src/SignIn.tsx @@ -24,6 +24,8 @@ import { ReactComponent as NLflag } from './i18n/NL.svg'; import { ReactComponent as DEflag } from './i18n/DE.svg'; import { ReactComponent as GBflag } from './i18n/GB.svg'; import { ReactComponent as SEflag } from './i18n/SE.svg'; +import { ReactComponent as PLflag } from './i18n/PL.svg'; +import { ReactComponent as NOflag } from './i18n/NO.svg'; const SignIn: FC = () => { const authenticationContext = useContext(AuthenticationContext); @@ -125,6 +127,14 @@ const SignIn: FC = () => {  SE + + Date: Fri, 7 Oct 2022 11:21:57 +0200 Subject: [PATCH 4/8] render analog value --- src/analogsensor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp index 7d066cc33..e5dd70f19 100644 --- a/src/analogsensor.cpp +++ b/src/analogsensor.cpp @@ -390,7 +390,7 @@ void AnalogSensor::publish_values(const bool force) { case AnalogType::PWM_0: case AnalogType::PWM_1: case AnalogType::PWM_2: - dataSensor["value"] = sensor.value(); // float + dataSensor["value"] = serialized(Helpers::render_value(s, sensor.value(), 2)); // float break; default: dataSensor["value"] = (uint8_t)sensor.value(); // convert to char for 1 or 0 From 348932d92986e545391cfc7c95ef4d43697e6c56 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 7 Oct 2022 11:53:18 +0200 Subject: [PATCH 5/8] rollback web output, don't use serialized for webpack --- src/emsdevice.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 30034f65b..3cae2c594 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -791,19 +791,18 @@ void EMSdevice::generate_values_web(JsonObject & output) { // note, the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; - char val[10]; if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) { - obj["v"] = serialized(Helpers::render_value(val, *(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); + obj["v"] = Helpers::transformNumFloat(*(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { - obj["v"] = serialized(Helpers::render_value(val, *(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); + obj["v"] = Helpers::transformNumFloat(*(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) { - obj["v"] = serialized(Helpers::render_value(val, *(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); + obj["v"] = Helpers::transformNumFloat(*(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) { - obj["v"] = serialized(Helpers::render_value(val, *(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); + obj["v"] = Helpers::transformNumFloat(*(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - obj["v"] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); + obj["v"] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), dv.numeric_operator); } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - obj["v"] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); + obj["v"] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), dv.numeric_operator); } else { obj["v"] = ""; // must have a value for sorting to work } @@ -902,20 +901,19 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) { // handle Integers and Floats else { - char val[10]; if (dv.type == DeviceValueType::INT) { - obj["v"] = serialized(Helpers::render_value(val, *(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); + obj["v"] = Helpers::transformNumFloat(*(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if (dv.type == DeviceValueType::UINT) { - obj["v"] = serialized(Helpers::render_value(val, *(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); + obj["v"] = Helpers::transformNumFloat(*(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if (dv.type == DeviceValueType::SHORT) { - obj["v"] = serialized(Helpers::render_value(val, *(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); + obj["v"] = Helpers::transformNumFloat(*(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if (dv.type == DeviceValueType::USHORT) { - obj["v"] = serialized(Helpers::render_value(val, *(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit)); + obj["v"] = Helpers::transformNumFloat(*(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit); } else if (dv.type == DeviceValueType::ULONG) { - obj["v"] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); + obj["v"] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), dv.numeric_operator); } else if (dv.type == DeviceValueType::TIME) { // sometimes we need to divide by 60 - obj["v"] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator)); + obj["v"] = Helpers::transformNumFloat(*(uint32_t *)(dv.value_p), dv.numeric_operator); } } } From 95876e28bf1aee17795da03f1b00f6d648bc2a20 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 7 Oct 2022 12:06:46 +0200 Subject: [PATCH 6/8] Junkers Clock not writable --- src/devices/thermostat.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 585d0717c..5f3f6f144 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -3846,18 +3846,9 @@ void Thermostat::register_device_values() { MAKE_CF_CB(set_wwVacation)); break; case EMS_DEVICE_FLAG_JUNKERS: - if (has_flags(EMS_DEVICE_FLAG_JUNKERS_OLD)) { - // FR100 is not writable, see. https://github.com/emsesp/EMS-ESP32/issues/536 - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(tpl_datetime), FL_(dateTime), DeviceValueUOM::NONE); - } else { - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, - &dateTime_, - DeviceValueType::STRING, - FL_(tpl_datetime), - FL_(dateTime), - DeviceValueUOM::NONE, - MAKE_CF_CB(set_datetime)); - } + // FR100 is not writable, see. https://github.com/emsesp/EMS-ESP32/issues/536 + // also FW500 https://github.com/emsesp/EMS-ESP32/issues/666 + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(tpl_datetime), FL_(dateTime), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hybridStrategy_, DeviceValueType::ENUM, From a6e4122e4438da8351106d572a6fc99b1e6fc23c Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 7 Oct 2022 12:58:10 +0200 Subject: [PATCH 7/8] fix Junkers roomsensor enum --- src/devices/thermostat.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 5f3f6f144..d4778d314 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -680,13 +680,13 @@ void Thermostat::process_JunkersSet(std::shared_ptr telegram) { return; } - has_update(telegram, hc->daytemp, 17); // is * 2 - has_update(telegram, hc->nighttemp, 16); // is * 2 - has_update(telegram, hc->nofrosttemp, 15); // is * 2 - has_update(telegram, hc->control, 1); // remote: 0-off, 1-FB10, 2-FB100 - has_enumupdate(telegram, hc->program, 13, 1); // 1-6: 1 = A, 2 = B,... - has_enumupdate(telegram, hc->mode, 14, 1); // 0 = nofrost, 1 = eco, 2 = heat, 3 = auto - has_update(telegram, hc->roomsensor, 9); // 1-intern, 2-extern, 3-autoselect the lower value + has_update(telegram, hc->daytemp, 17); // is * 2 + has_update(telegram, hc->nighttemp, 16); // is * 2 + has_update(telegram, hc->nofrosttemp, 15); // is * 2 + has_update(telegram, hc->control, 1); // remote: 0-off, 1-FB10, 2-FB100 + has_enumupdate(telegram, hc->program, 13, 1); // 1-6: 1 = A, 2 = B,... + has_enumupdate(telegram, hc->mode, 14, 1); // 0 = nofrost, 1 = eco, 2 = heat, 3 = auto + has_enumupdate(telegram, hc->roomsensor, 9, 1); // 1-intern, 2-extern, 3-autoselect the lower value } // type 0x0179, ff @@ -1717,7 +1717,7 @@ bool Thermostat::set_roomsensor(const char * value, const int8_t id) { uint8_t ctrl = 0; if (model() == EMS_DEVICE_FLAG_JUNKERS && !has_flags(EMS_DEVICE_FLAG_JUNKERS_OLD)) { if (Helpers::value2enum(value, ctrl, FL_(enum_roomsensor))) { - write_command(set_typeids[hc->hc()], 9, ctrl); + write_command(set_typeids[hc->hc()], 9, ctrl + 1); return true; } } From d09d5a7dbed6c1cb02779a1461bcf27493aad2bb Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 7 Oct 2022 17:31:21 +0200 Subject: [PATCH 8/8] Junkers settime, dst always zero, no check against NTP --- src/devices/thermostat.cpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index d4778d314..e0abea12a 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -1364,10 +1364,11 @@ void Thermostat::process_RCTime(std::shared_ptr telegram) { strftime(newdatetime, sizeof(dateTime_), "%d.%m.%G %H:%M", tm_); has_update(dateTime_, newdatetime, sizeof(dateTime_)); - bool ivtclock = (telegram->message_data[0] & 0x80) == 0x80; // dont sync ivt-clock, #439 - time_t ttime = mktime(tm_); // thermostat time + bool ivtclock = (telegram->message_data[0] & 0x80) == 0x80; // dont sync ivt-clock, #439 + bool junkersclock = model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS; + time_t ttime = mktime(tm_); // thermostat time // correct thermostat clock if we have valid ntp time, and could write the command - if (!ivtclock && tset_ && EMSESP::system_.ntp_connected() && !EMSESP::system_.readonly_mode() && has_command(&dateTime_)) { + if (!ivtclock && !junkersclock && tset_ && EMSESP::system_.ntp_connected() && !EMSESP::system_.readonly_mode() && has_command(&dateTime_)) { double difference = difftime(now, ttime); if (difference > 15 || difference < -15) { set_datetime("ntp", -1); // set from NTP @@ -2165,6 +2166,10 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) { data[5] = tm_->tm_sec; data[6] = (tm_->tm_wday + 6) % 7; // Bosch counts from Mo, time from Su data[7] = tm_->tm_isdst + 2; // set DST and flag for ext. clock + if (model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) { + data[6]++; // Junkers use 1-7; + data[7] = 0; + } } else if (dt.length() == 23) { data[0] = (dt[7] - '0') * 100 + (dt[8] - '0') * 10 + (dt[9] - '0'); // year data[1] = (dt[3] - '0') * 10 + (dt[4] - '0'); // month @@ -2174,6 +2179,9 @@ bool Thermostat::set_datetime(const char * value, const int8_t id) { data[5] = (dt[17] - '0') * 10 + (dt[18] - '0'); // sec data[6] = (dt[20] - '0'); // day of week, Mo:0 data[7] = (dt[22] - '0') + 2; // DST and flag + if (model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) { + data[7] = 0; + } } else { LOG_WARNING(F("Set date: invalid data, wrong length")); return false; @@ -3847,8 +3855,18 @@ void Thermostat::register_device_values() { break; case EMS_DEVICE_FLAG_JUNKERS: // FR100 is not writable, see. https://github.com/emsesp/EMS-ESP32/issues/536 - // also FW500 https://github.com/emsesp/EMS-ESP32/issues/666 - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(tpl_datetime), FL_(dateTime), DeviceValueUOM::NONE); + // FW500 is not writable, see. https://github.com/emsesp/EMS-ESP32/issues/666 + if (has_flags(EMS_DEVICE_FLAG_JUNKERS_OLD)) { + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dateTime_, DeviceValueType::STRING, FL_(tpl_datetime), FL_(dateTime), DeviceValueUOM::NONE); + } else { + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &dateTime_, + DeviceValueType::STRING, + FL_(tpl_datetime), + FL_(dateTime), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_datetime)); + } register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hybridStrategy_, DeviceValueType::ENUM,