diff --git a/interface/src/project/EMSESPDevicesForm.tsx b/interface/src/project/EMSESPDevicesForm.tsx index fdf77a36f..94608dab1 100644 --- a/interface/src/project/EMSESPDevicesForm.tsx +++ b/interface/src/project/EMSESPDevicesForm.tsx @@ -152,7 +152,7 @@ class EMSESPDevicesForm extends Component ID - Temperature + Temperature @@ -161,8 +161,8 @@ class EMSESPDevicesForm extends Component {sensorData.id} - - {sensorData.temp}°C + + {sensorData.temp.toFixed(1)}°C ))} @@ -285,7 +285,7 @@ class EMSESPDevicesForm extends Component {deviceData.name} - + {deviceData.value} diff --git a/interface/src/project/EMSESPSettingsController.tsx b/interface/src/project/EMSESPSettingsController.tsx index 157e0c235..dadcde600 100644 --- a/interface/src/project/EMSESPSettingsController.tsx +++ b/interface/src/project/EMSESPSettingsController.tsx @@ -100,18 +100,6 @@ function EMSESPSettingsControllerForm(props: EMSESPSettingsControllerFormProps) onChange={handleValueChange('tx_gpio')} margin="normal" /> - + } - label="Hide LED" + label="Invert/Hide LED" /> & WithTheme & WithWidthProps; const StyledTableCell = withStyles((theme: Theme) => @@ -75,7 +79,7 @@ class EMSESPStatusForm extends Component { Statistic - # Telegrams + # Telegrams @@ -83,25 +87,25 @@ class EMSESPStatusForm extends Component { (Rx) Received telegrams - {data.rx_received} + {formatNumber(data.rx_received)} (Rx) Incomplete telegrams - {data.crc_errors} + {formatNumber(data.crc_errors)} (Tx) Successfully sent telegrams - {data.tx_sent} + {formatNumber(data.tx_sent)} (Tx) Send Errors - {data.tx_errors} + {formatNumber(data.tx_errors)} diff --git a/lib/framework/APSettingsService.cpp b/lib/framework/APSettingsService.cpp index 66fdd1c04..57339cde7 100644 --- a/lib/framework/APSettingsService.cpp +++ b/lib/framework/APSettingsService.cpp @@ -15,12 +15,12 @@ void APSettingsService::begin() { } void APSettingsService::reconfigureAP() { - _lastManaged = millis() - MANAGE_NETWORK_DELAY; + _lastManaged = uuid::get_uptime() - MANAGE_NETWORK_DELAY; _reconfigureAp = true; } void APSettingsService::loop() { - unsigned long currentMillis = millis(); + unsigned long currentMillis = uuid::get_uptime(); unsigned long manageElapsed = (unsigned long)(currentMillis - _lastManaged); if (manageElapsed >= MANAGE_NETWORK_DELAY) { _lastManaged = currentMillis; diff --git a/lib/framework/APSettingsService.h b/lib/framework/APSettingsService.h index 01042d9d8..991edb23d 100644 --- a/lib/framework/APSettingsService.h +++ b/lib/framework/APSettingsService.h @@ -7,6 +7,8 @@ #include #include +#include + #define MANAGE_NETWORK_DELAY 10000 diff --git a/lib/framework/MqttSettingsService.cpp b/lib/framework/MqttSettingsService.cpp index a00baab1b..d75527c56 100644 --- a/lib/framework/MqttSettingsService.cpp +++ b/lib/framework/MqttSettingsService.cpp @@ -62,7 +62,7 @@ void MqttSettingsService::begin() { } void MqttSettingsService::loop() { - if (_reconfigureMqtt || (_disconnectedAt && (unsigned long)(millis() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) { + if (_reconfigureMqtt || (_disconnectedAt && (unsigned long)(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) { // reconfigure MQTT client configureMqtt(); @@ -107,7 +107,7 @@ void MqttSettingsService::onMqttDisconnect(AsyncMqttClientDisconnectReason reaso // Serial.print(F("Disconnected from MQTT reason: ")); // Serial.println((uint8_t)reason); _disconnectReason = reason; - _disconnectedAt = millis(); + _disconnectedAt = uuid::get_uptime(); } void MqttSettingsService::onConfigUpdated() { diff --git a/lib/framework/MqttSettingsService.h b/lib/framework/MqttSettingsService.h index 42bc5ab55..aedc78054 100644 --- a/lib/framework/MqttSettingsService.h +++ b/lib/framework/MqttSettingsService.h @@ -6,12 +6,13 @@ #include #include #include +#include #include "../../src/system.h" #include "../../src/mqtt.h" #include "../../src/sensors.h" -#define MQTT_RECONNECTION_DELAY 5000 +#define MQTT_RECONNECTION_DELAY 1000 #define MQTT_SETTINGS_FILE "/config/mqttSettings.json" #define MQTT_SETTINGS_SERVICE_PATH "/rest/mqttSettings" diff --git a/lib/framework/NTPStatus.cpp b/lib/framework/NTPStatus.cpp index 2275d2f76..5afb93b23 100644 --- a/lib/framework/NTPStatus.cpp +++ b/lib/framework/NTPStatus.cpp @@ -33,7 +33,7 @@ void NTPStatus::ntpStatus(AsyncWebServerRequest* request) { root["server"] = sntp_getservername(0); // device uptime in seconds - root["uptime"] = millis() / 1000; + root["uptime"] = uuid::get_uptime() / 1000; response->setLength(); request->send(response); diff --git a/lib/framework/NTPStatus.h b/lib/framework/NTPStatus.h index 7bb918059..893435847 100644 --- a/lib/framework/NTPStatus.h +++ b/lib/framework/NTPStatus.h @@ -16,6 +16,8 @@ #include #include #include +#include + #define MAX_NTP_STATUS_SIZE 1024 #define NTP_STATUS_SERVICE_PATH "/rest/ntpStatus" diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index ece522832..8a222615c 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -26,7 +26,20 @@ uuid::log::Logger Thermostat::logger_{F_(thermostat), uuid::log::Facility::CONSO Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand) : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { - if (EMSESP::actual_master_thermostat() == 0) { + + uint8_t actual_master_thermostat = EMSESP::actual_master_thermostat(); // what we're actually using + uint8_t master_thermostat = EMSESP_DEFAULT_MASTER_THERMOSTAT; + EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { + master_thermostat = settings.master_thermostat; // what the user has defined + }); + // if we're on auto mode, register this thermostat if it has a device id of 0x10, 0x17 or 0x18 + // or if its the master thermostat we defined + // see https://github.com/proddy/EMS-ESP/issues/362#issuecomment-629628161 + if ((master_thermostat == device_id) || ((master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT) && (device_id < 0x19) && + ((actual_master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT) || (device_id < actual_master_thermostat)))) { + + EMSESP::actual_master_thermostat(device_id); + actual_master_thermostat = device_id; this->reserve_mem(25); // reserve some space for the telegram registries, to avoid memory fragmentation // common telegram handlers @@ -58,7 +71,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i } else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20) { monitor_typeids = {0x91}; set_typeids = {0xA8}; - if (EMSESP::actual_master_thermostat() == 0) { + if (actual_master_thermostat == device_id) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) { register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, [&](std::shared_ptr t) { process_RC20Monitor(t); }); register_telegram_type(set_typeids[i], F("RC20Set"), false, [&](std::shared_ptr t) { process_RC20Set(t); }); @@ -70,7 +83,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i } else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20_2) { monitor_typeids = {0xAE}; set_typeids = {0xAD}; - if (EMSESP::actual_master_thermostat() == 0) { + if (actual_master_thermostat == device_id) { for (uint8_t i = 0; i < monitor_typeids.size(); i++) { register_telegram_type(monitor_typeids[i], F("RC20Monitor"), false, [&](std::shared_ptr t) { process_RC20Monitor_2(t); }); register_telegram_type(set_typeids[i], F("RC20Set"), false, [&](std::shared_ptr t) { process_RC20Set_2(t); }); @@ -122,29 +135,16 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i } } - uint8_t master_thermostat = 0; - EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { - master_thermostat = settings.master_thermostat; // what the user has defined - }); - EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) { mqtt_format_ = settings.mqtt_format; // single, nested or ha }); - uint8_t actual_master_thermostat = EMSESP::actual_master_thermostat(); // what we're actually using - uint8_t num_devices = EMSESP::count_devices(EMSdevice::DeviceType::THERMOSTAT) + 1; // including this thermostat - - // if we're on auto mode, register this thermostat if it has a device id of 0x10, 0x17 or 0x18 - // or if its the master thermostat we defined - // see https://github.com/proddy/EMS-ESP/issues/362#issuecomment-629628161 - if (((num_devices == 1) && (actual_master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT)) || (master_thermostat == device_id)) { - EMSESP::actual_master_thermostat(device_id); - LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X (as master)"), device_id); - add_commands(); - } else { + if (actual_master_thermostat != device_id) { LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X"), device_id); return; // don't fetch data if more than 1 thermostat } + LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X (as master)"), device_id); + add_commands(); // reserve some memory for the heating circuits (max 4 to start with) heating_circuits_.reserve(4); @@ -275,7 +275,8 @@ void Thermostat::publish_values() { JsonObject dataThermostat; // add external temp and other stuff specific to the RC30 and RC35 - if ((flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) && (mqtt_format_ == MQTT_format::SINGLE || mqtt_format_ == MQTT_format::CUSTOM)) { +// if ((flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) && (mqtt_format_ == MQTT_format::SINGLE || mqtt_format_ == MQTT_format::CUSTOM)) { + if (flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) { if (datetime_.size()) { rootThermostat["time"] = datetime_.c_str(); } @@ -579,9 +580,24 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) { doc["temp_step"] = "0.5"; JsonArray modes = doc.createNestedArray("modes"); - modes.add("off"); - modes.add("heat"); - modes.add("auto"); + uint8_t flags = (this->flags() & 0x0F); + if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20_2) { + modes.add("night"); + modes.add("day"); + } else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC300) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC100)) { + modes.add("eco"); + modes.add("comfort"); + modes.add("auto"); + } else if (flags == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) { + modes.add("nofrost"); + modes.add("eco"); + modes.add("heat"); + modes.add("auto"); + } else { // default for all other thermostats + modes.add("night"); + modes.add("day"); + modes.add("auto"); + } std::string topic(100, '\0'); // e.g homeassistant/climate/hc1/thermostat/config snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/config"), hc_num); @@ -1146,7 +1162,6 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) { flash_string_vector{F_(deviceid_mandatory)}, [](Shell & shell, const std::vector & arguments) { uint8_t value = Helpers::hextoint(arguments.front().c_str()); - EMSESP::emsespSettingsService.update( [&](EMSESPSettings & settings) { settings.master_thermostat = value; diff --git a/src/emsesp.cpp b/src/emsesp.cpp index bff89ea95..bab042262 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -286,7 +286,7 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) { char valuestr[8] = {0}; // for formatting temp shell.printfln(F("Dallas temperature sensors:")); for (const auto & device : sensor_devices()) { - shell.printfln(F(" ID: %s, Temperature: %s°C"), device.to_string().c_str(), Helpers::render_value(valuestr, device.temperature_c, 2)); + shell.printfln(F(" ID: %s, Temperature: %s°C"), device.to_string().c_str(), Helpers::render_value(valuestr, device.temperature_c, 1)); } shell.println(); } diff --git a/src/sensors.cpp b/src/sensors.cpp index 2b8256246..ecf8323c9 100644 --- a/src/sensors.cpp +++ b/src/sensors.cpp @@ -183,27 +183,27 @@ float Sensors::get_temperature_c(const uint8_t addr[]) { int16_t raw_value = ((int16_t)scratchpad[SCRATCHPAD_TEMP_MSB] << 8) | scratchpad[SCRATCHPAD_TEMP_LSB]; - // Adjust based on device resolution - int resolution = 9 + ((scratchpad[SCRATCHPAD_CONFIG] >> 5) & 0x3); - switch (resolution) { - case 9: - raw_value &= ~0x1; - break; - - case 10: - raw_value &= ~0x3; - break; - - case 11: - raw_value &= ~0x7; - break; - - case 12: - break; + if (addr[0] == TYPE_DS18S20) { + raw_value = (raw_value << 3) + 12 - scratchpad[SCRATCHPAD_CNT_REM]; + } else { + // Adjust based on device resolution + int resolution = 9 + ((scratchpad[SCRATCHPAD_CONFIG] >> 5) & 0x3); + switch (resolution) { + case 9: + raw_value &= ~0x7; + break; + case 10: + raw_value &= ~0x3; + break; + case 11: + raw_value &= ~0x1; + break; + case 12: + break; + } } - - uint32_t raw = (raw_value * 625) / 100; // round to 0.01 - return (float)raw / 100; + uint32_t raw = (raw_value * 625 + 500) / 1000; // round to 0.1 + return (float)raw / 10; #else return NAN; #endif @@ -254,7 +254,7 @@ void Sensors::publish_values() { StaticJsonDocument<100> doc; for (const auto & device : devices_) { char s[7]; // sensorrange -55.00 to 125.00 - doc["temp"] = Helpers::render_value(s, device.temperature_c, 2); + doc["temp"] = Helpers::render_value(s, device.temperature_c, 1); char topic[60]; // sensors{1-n} strlcpy(topic, "sensor_", 50); // create topic, e.g. home/ems-esp/sensor_28-EA41-9497-0E03-5F strlcat(topic, device.to_string().c_str(), 60); @@ -264,20 +264,13 @@ void Sensors::publish_values() { return; } - // const size_t capacity = num_devices * JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(num_devices); DynamicJsonDocument doc(100 * num_devices); uint8_t i = 1; // sensor count for (const auto & device : devices_) { char s[7]; if (mqtt_format_ == MQTT_format::CUSTOM) { - doc[device.to_string()] = Helpers::render_value(s, device.temperature_c, 2); - } else if (mqtt_format_ == MQTT_format::SINGLE) { - doc["id"] = device.to_string(); - doc["temp"] = Helpers::render_value(s, device.temperature_c, 2); - std::string topic(100, '\0'); - snprintf_P(&topic[0], 50, PSTR("sensor%d"), i); - Mqtt::publish(topic, doc); + doc[device.to_string()] = Helpers::render_value(s, device.temperature_c, 1); } else if ((mqtt_format_ == MQTT_format::NESTED) || (mqtt_format_ == MQTT_format::HA)) { // e.g. {"sensor1":{"id":"28-EA41-9497-0E03-5F","temp":"23.30"},"sensor2":{"id":"28-233D-9497-0C03-8B","temp":"24.0"}} char sensorID[10]; // sensor{1-n} @@ -285,7 +278,7 @@ void Sensors::publish_values() { strlcat(sensorID, Helpers::itoa(s, i), 10); JsonObject dataSensor = doc.createNestedObject(sensorID); dataSensor["id"] = device.to_string(); - dataSensor["temp"] = Helpers::render_value(s, device.temperature_c, 2); + dataSensor["temp"] = Helpers::render_value(s, device.temperature_c, 1); } // special for HA diff --git a/src/sensors.h b/src/sensors.h index 6fcaba010..4bd52f4c1 100644 --- a/src/sensors.h +++ b/src/sensors.h @@ -74,12 +74,13 @@ class Sensors { static constexpr size_t SCRATCHPAD_TEMP_MSB = 1; static constexpr size_t SCRATCHPAD_TEMP_LSB = 0; static constexpr size_t SCRATCHPAD_CONFIG = 4; + static constexpr size_t SCRATCHPAD_CNT_REM = 6; // dallas chips static constexpr uint8_t TYPE_DS18B20 = 0x28; static constexpr uint8_t TYPE_DS18S20 = 0x10; static constexpr uint8_t TYPE_DS1822 = 0x22; - static constexpr uint8_t TYPE_DS1825 = 0x3B; + static constexpr uint8_t TYPE_DS1825 = 0x3B; // also DS1826 static constexpr uint32_t READ_INTERVAL_MS = 5000; // 5 seconds static constexpr uint32_t CONVERSION_MS = 1000; // 1 seconds diff --git a/src/telegram.cpp b/src/telegram.cpp index 5b22c26ed..f6f3eb9ea 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -219,6 +219,7 @@ void RxService::add(uint8_t * data, uint8_t length) { // check if queue is full, if so remove top item to make space if (rx_telegrams_.size() >= MAX_RX_TELEGRAMS) { rx_telegrams_.pop_front(); + increment_telegram_error_count(); } rx_telegrams_.emplace_back(rx_telegram_id_++, std::move(telegram)); // add to queue diff --git a/src/telegram.h b/src/telegram.h index 1eca7bd82..f51984659 100644 --- a/src/telegram.h +++ b/src/telegram.h @@ -201,7 +201,7 @@ class RxService : public EMSbus { void loop(); void add(uint8_t * data, uint8_t length); - uint16_t telegram_count() const { + uint32_t telegram_count() const { return telegram_count_; } @@ -209,7 +209,7 @@ class RxService : public EMSbus { telegram_count_++; } - uint16_t telegram_error_count() const { + uint32_t telegram_error_count() const { return telegram_error_count_; } @@ -235,8 +235,8 @@ class RxService : public EMSbus { private: uint8_t rx_telegram_id_ = 0; // queue counter - uint16_t telegram_count_ = 0; // # Rx received - uint16_t telegram_error_count_ = 0; // # Rx CRC errors + uint32_t telegram_count_ = 0; // # Rx received + uint32_t telegram_error_count_ = 0; // # Rx CRC errors std::shared_ptr rx_telegram; // the incoming Rx telegram std::list rx_telegrams_; // the Rx Queue @@ -288,7 +288,7 @@ class TxService : public EMSbus { telegram_last_post_send_query_ = type_id; } - uint16_t telegram_read_count() const { + uint32_t telegram_read_count() const { return telegram_read_count_; } @@ -300,7 +300,7 @@ class TxService : public EMSbus { telegram_read_count_++; } - uint16_t telegram_fail_count() const { + uint32_t telegram_fail_count() const { return telegram_fail_count_; } @@ -312,7 +312,7 @@ class TxService : public EMSbus { telegram_fail_count_++; } - uint16_t telegram_write_count() const { + uint32_t telegram_write_count() const { return telegram_write_count_; } @@ -355,9 +355,9 @@ class TxService : public EMSbus { private: std::list tx_telegrams_; // the Tx queue - uint16_t telegram_read_count_ = 0; // # Tx successful reads - uint16_t telegram_write_count_ = 0; // # Tx successful writes - uint16_t telegram_fail_count_ = 0; // # Tx unsuccessful transmits + uint32_t telegram_read_count_ = 0; // # Tx successful reads + uint32_t telegram_write_count_ = 0; // # Tx successful writes + uint32_t telegram_fail_count_ = 0; // # Tx unsuccessful transmits std::shared_ptr telegram_last_; uint16_t telegram_last_post_send_query_; // which type ID to query after a successful send, to read back the values just written