From 0e6108b5a9ecdbd27b2035bfd3baa4dc24dfede7 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 22 Dec 2025 15:40:27 +0100 Subject: [PATCH 01/47] 3.7.3-dev.40 --- src/emsesp_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emsesp_version.h b/src/emsesp_version.h index 6de79fa7e..fc19ef37c 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.3-dev.39" +#define EMSESP_APP_VERSION "3.7.3-dev.40" From ea4d613d12a650e03a6544e21af165fc9b322ef3 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 22 Dec 2025 15:41:14 +0100 Subject: [PATCH 02/47] updates to add_ha_classes --- src/core/analogsensor.cpp | 4 +- src/core/emsdevice.cpp | 2 +- src/core/emsdevicevalue.h | 55 ++++++------ src/core/mqtt.cpp | 136 +++++++++++++++++++---------- src/core/mqtt.h | 2 +- src/web/WebCustomEntityService.cpp | 4 +- 6 files changed, 126 insertions(+), 77 deletions(-) diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index 1bb66e64c..4e461b9c1 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -809,9 +809,9 @@ void AnalogSensor::publish_values(const bool force) { std::string topic_str(topic); config["def_ent_id"] = topic_str.substr(0, topic_str.find("/")) + "." + uniq_s; + // add HA Discovery config Mqtt::add_ha_classes(config.as(), EMSdevice::DeviceType::ANALOGSENSOR, valueType, sensor.uom()); - // dev section with model is only created on the 1st sensor - Mqtt::add_ha_dev_section(config.as(), "Analog Sensors", !ha_dev_created); + Mqtt::add_ha_dev_section(config.as(), "Analog Sensors", !ha_dev_created); // dev section with model is only created on the 1st sensor Mqtt::add_ha_avty_section(config.as(), stat_t, val_cond); sensor.ha_registered = Mqtt::queue_ha(topic, config.as()); diff --git a/src/core/emsdevice.cpp b/src/core/emsdevice.cpp index e62169ca6..8d07660d0 100644 --- a/src/core/emsdevice.cpp +++ b/src/core/emsdevice.cpp @@ -1687,7 +1687,7 @@ void EMSdevice::get_value_json(JsonObject json, DeviceValue & dv) { } // add uom, state class and device class - Mqtt::add_ha_classes(json, device_type(), dv.type, dv.uom, dv.short_name, false); // no icon + Mqtt::add_ha_classes(json, device_type(), dv.type, dv.uom, dv.short_name, true); // display only json["readable"] = dv.type != DeviceValueType::CMD && !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE); json["writeable"] = dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY); diff --git a/src/core/emsdevicevalue.h b/src/core/emsdevicevalue.h index f6dcb3827..04d28809c 100644 --- a/src/core/emsdevicevalue.h +++ b/src/core/emsdevicevalue.h @@ -47,36 +47,37 @@ class DeviceValue { // Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevicevalue.cpp. Sequence is important!! // also used with HA as uom + // shows also the HA device class being used enum DeviceValueUOM : uint8_t { NONE = 0, // 0 - DEGREES, // 1 - °C - DEGREES_R, // 2 - °C (relative temperature) - PERCENT, // 3 - % - LMIN, // 4 - l/min - KWH, // 5 - kWh - WH, // 6 - Wh - HOURS, // 7 - h - MINUTES, // 8 - m - UA, // 9 - µA - BAR, // 10 - bar - KW, // 11 - kW - W, // 12 - W - KB, // 13 - kB - SECONDS, // 14 - s - DBM, // 15 - dBm - FAHRENHEIT, // 16 - °F - MV, // 17 - mV - SQM, // 18 - m² - M3, // 19 - m³ - L, // 20 - L + DEGREES, // 1 - °C - temperature + DEGREES_R, // 2 - °C (relative temperature) - temperature + PERCENT, // 3 - % - power factor + LMIN, // 4 - l/min - volume flow rate + KWH, // 5 - kWh - energy + WH, // 6 - Wh - energy + HOURS, // 7 - h - duration + MINUTES, // 8 - m - duration + UA, // 9 - µA - current + BAR, // 10 - bar - pressure + KW, // 11 - kW - power + W, // 12 - W - power + KB, // 13 - kB - data size + SECONDS, // 14 - s - duration + DBM, // 15 - dBm - signal strength + FAHRENHEIT, // 16 - °F - temperature + MV, // 17 - mV - voltage + SQM, // 18 - m² - area + M3, // 19 - m³ - volume + L, // 20 - L - volume KMIN, // 21 - K*min - K, // 22 - K - VOLTS, // 23 - V - MBAR, // 24 - mbar - LH, // 25 - l/h - CTKWH, // 26 - ct/kWh - HZ, // 27 - Hz - CONNECTIVITY // 28 - used in HA + K, // 22 - K - temperature + VOLTS, // 23 - V - voltage + MBAR, // 24 - mbar - atmospheric pressure + LH, // 25 - l/h - volume flow rate + CTKWH, // 26 - ct/kWh - monetary + HZ, // 27 - Hz - frequency + CONNECTIVITY // 28 - used in HA - connectivity }; // TAG mapping - maps to DeviceValueTAG_s in emsdevicevalue.cpp diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index 5fc577b72..e9e6819a3 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -62,8 +62,6 @@ std::string Mqtt::lastresponse_ = ""; // Home Assistant specific // icons from https://materialdesignicons.com used with the UOMs (unit of measurements) -MAKE_WORD(measurement) -MAKE_WORD(total_increasing) // MAKE_WORD_CUSTOM(icondegrees, "mdi:coolant-temperature") // DeviceValueUOM::DEGREES MAKE_WORD_CUSTOM(iconpercent, "mdi:percent-outline") // DeviceValueUOM::PERCENT MAKE_WORD_CUSTOM(iconkb, "mdi:memory") // DeviceValueUOM::KB @@ -1124,18 +1122,29 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev return queue_ha(topic, doc.as()); } -// Add the uom, state class, device class and an optional icon based on the uom -void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8_t type, const uint8_t uom, const char * entity, bool is_discovery) { +// Add the uom, state class, device class and an optional icon based on the uom (unless display_only is true) +// https://developers.home-assistant.io/docs/core/entity/sensor/ +// Home Assistant tracks the min, max and mean value during the statistics period +// For statistics, the sensor must have state_class set to either MEASUREMENT, TOTAL or TOTAL_INCREASING +// When set to MEASUREMENT the device_class must cannot be DATE, ENUM, ENERGY, GAS, MONETARY, TIMESTAMP, VOLUME or WATER +// +void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8_t type, const uint8_t uom, const char * entity, bool display_only) { if (device_type == EMSdevice::DeviceType::SYSTEM) { doc["ent_cat"] = "diagnostic"; // instead of 'config' } - // for HA discovery we use different namings - const char * dc_ha = is_discovery ? "dev_cla" : "device_class"; // device class - const char * sc_ha = is_discovery ? "stat_cla" : "state_class"; // state class - const char * uom_ha = is_discovery ? "unit_of_meas" : "uom"; // unit of measure + // For display_only, we don't use the aliases, also we don't display the icon + const char * dc_ha = display_only ? "device_class" : "dev_cla"; // device class, dev_cla + const char * sc_ha = display_only ? "state_class" : "stat_cla"; // state class, stat_cla + const char * uom_ha = display_only ? "uom" : "unit_of_meas"; // unit of measure, unit_of_meas + const char * ic_ha = display_only ? "icon" : "ic"; // icon, ic - // set uom, unless boolean + // state class constants + const char * sc_ha_measurement = "measurement"; + const char * sc_ha_total = "total"; + const char * sc_ha_total_increasing = "total_increasing"; + + // set uom, unless boolean - as HA is fussy with the naming // using HA uom specific codes from https://github.com/home-assistant/core/blob/dev/homeassistant/const.py if (type != DeviceValueType::BOOL) { if (uom == DeviceValueUOM::HOURS) { @@ -1144,6 +1153,8 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8 doc[uom_ha] = "min"; } else if (uom == DeviceValueUOM::SECONDS) { doc[uom_ha] = "s"; + } else if (uom == DeviceValueUOM::KB) { + doc[uom_ha] = "kB"; } else if (uom != DeviceValueUOM::NONE) { doc[uom_ha] = EMSdevice::uom_to_string(uom); // use default } else if (discovery_type() != discoveryType::HOMEASSISTANT) { @@ -1151,99 +1162,136 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8 } } - // set state and device class - // also icon, when there is no device class that sets one + // set state and device class - always + // see https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes switch (uom) { case DeviceValueUOM::DEGREES: case DeviceValueUOM::DEGREES_R: case DeviceValueUOM::K: - doc[sc_ha] = F_(measurement); + doc[sc_ha] = sc_ha_measurement; doc[dc_ha] = "temperature"; // override uom if fahrenheit doc[uom_ha] = EMSESP::system_.fahrenheit() ? DeviceValue::DeviceValueUOM_s[DeviceValueUOM::FAHRENHEIT] : DeviceValue::DeviceValueUOM_s[uom]; break; case DeviceValueUOM::PERCENT: - doc[sc_ha] = F_(measurement); + if (display_only) { + doc[ic_ha] = F_(iconpercent); // set icon + } + doc[sc_ha] = sc_ha_measurement; doc[dc_ha] = "power_factor"; - if (is_discovery) - doc["ic"] = F_(iconpercent); // icon break; case DeviceValueUOM::SECONDS: case DeviceValueUOM::MINUTES: case DeviceValueUOM::HOURS: if (type == DeviceValueType::TIME) { - doc[sc_ha] = F_(total_increasing); + doc[sc_ha] = sc_ha_total_increasing; } else { - doc[sc_ha] = F_(measurement); + doc[sc_ha] = sc_ha_measurement; } doc[dc_ha] = "duration"; // https://github.com/emsesp/EMS-ESP32/issues/822 break; case DeviceValueUOM::KB: - if (is_discovery) - doc["ic"] = F_(iconkb); + if (display_only) { + doc[ic_ha] = F_(iconkb); + } + doc[dc_ha] = "data_size"; break; case DeviceValueUOM::LMIN: case DeviceValueUOM::LH: - if (is_discovery) - doc["ic"] = F_(iconlmin); - doc[sc_ha] = F_(measurement); + if (display_only) { + doc[ic_ha] = F_(iconlmin); + } + doc[sc_ha] = sc_ha_measurement; + doc[dc_ha] = "volume_flow_rate"; break; case DeviceValueUOM::WH: // https://github.com/emsesp/EMS-ESP32/issues/1796 if (entity == FL_(energyToday)[0]) { - doc[sc_ha] = F_(total_increasing); + doc[sc_ha] = sc_ha_total_increasing; + doc[dc_ha] = "energy"; } else if (entity == FL_(energyLastHour)[0]) { - doc[sc_ha] = "total"; + doc[sc_ha] = sc_ha_total; + doc[dc_ha] = "energy"; } else { - doc[sc_ha] = F_(measurement); + doc[sc_ha] = sc_ha_measurement; // no device class for this } - doc[dc_ha] = "energy"; break; case DeviceValueUOM::KWH: - doc[sc_ha] = F_(total_increasing); + doc[sc_ha] = sc_ha_total_increasing; doc[dc_ha] = "energy"; break; case DeviceValueUOM::UA: - if (is_discovery) - doc["ic"] = F_(iconua); - doc[sc_ha] = F_(measurement); + if (display_only) { + doc[ic_ha] = F_(iconua); + } + doc[sc_ha] = sc_ha_measurement; + doc[dc_ha] = "current"; break; case DeviceValueUOM::BAR: - doc[sc_ha] = F_(measurement); + doc[sc_ha] = sc_ha_measurement; doc[dc_ha] = "pressure"; break; case DeviceValueUOM::W: case DeviceValueUOM::KW: - doc[sc_ha] = F_(measurement); + doc[sc_ha] = sc_ha_measurement; doc[dc_ha] = "power"; break; case DeviceValueUOM::DBM: - doc[sc_ha] = F_(measurement); + doc[sc_ha] = sc_ha_measurement; doc[dc_ha] = "signal_strength"; break; case DeviceValueUOM::CONNECTIVITY: - doc[sc_ha] = F_(measurement); + doc[sc_ha] = sc_ha_measurement; doc[dc_ha] = "connectivity"; break; - case DeviceValueUOM::NONE: + case DeviceValueUOM::MV: + case DeviceValueUOM::VOLTS: + doc[sc_ha] = sc_ha_measurement; + doc[dc_ha] = "voltage"; + break; + case DeviceValueUOM::MBAR: + doc[sc_ha] = sc_ha_measurement; + doc[dc_ha] = "atmospheric_pressure"; + break; + case DeviceValueUOM::CTKWH: + doc[sc_ha] = sc_ha_total_increasing; + doc[dc_ha] = "monetary"; + break; + case DeviceValueUOM::HZ: + doc[sc_ha] = sc_ha_measurement; + doc[dc_ha] = "frequency"; + break; + case DeviceValueUOM::M3: + case DeviceValueUOM::L: + // this could be Gas or Water, so going with the generic 'volume' for now + // state_class can't be a Measurement + doc[sc_ha] = sc_ha_total_increasing; + doc[dc_ha] = "volume"; + break; + case DeviceValueUOM::SQM: + doc[sc_ha] = sc_ha_measurement; + doc[dc_ha] = "area"; + break; + default: + // DeviceValueUOM::NONE: + // DeviceValueUOM::KMIN: // for device entities which have numerical values, with no UOM if ((type != DeviceValueType::STRING) && (type == DeviceValueType::INT8 || type == DeviceValueType::UINT8 || type == DeviceValueType::INT16 || type == DeviceValueType::UINT16 || type == DeviceValueType::UINT24 || type == DeviceValueType::UINT32)) { - if (is_discovery) - doc["ic"] = F_(iconnum); // set icon + if (display_only) { + doc[ic_ha] = F_(iconnum); // set icon + } // determine if its a measurement or total increasing // most of the values are measurement. for example Tx Reads will increment but can be reset to 0 after a restart // all the starts are increasing, and they are ULONGs if (type == DeviceValueType::UINT24 || type == DeviceValueType::UINT32) { - doc[sc_ha] = F_(total_increasing); + doc[sc_ha] = sc_ha_total_increasing; } else { - doc[sc_ha] = F_(measurement); // default to measurement + doc[sc_ha] = sc_ha_measurement; // default to measurement } } break; - default: - break; } } @@ -1444,9 +1492,8 @@ std::string Mqtt::tag_to_topic(uint8_t device_type, int8_t tag) { } } -// add devs section to an existing doc, only for HA -// under devs node it will create ids and name and optional mf, mdl, via_device -// name could be EMSdevice::device_type_2_device_name(dv.device_type)); +// adds dev section for HA Discovery to an existing JSON doc +// under devs node it will create ids and optional name, mf, mdl, sw and via_device void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const bool create_model, const char * model, const char * brand, const char * version) { // only works for HA if (discovery_type() != discoveryType::HOMEASSISTANT) { @@ -1488,6 +1535,7 @@ void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const bool crea } // adds avty section for HA Discovery to an existing JSON doc +// also adds LWT (Last Will and Testament) void Mqtt::add_ha_avty_section(JsonObject doc, const char * state_t, const char * cond1, const char * cond2, const char * negcond) { // only works for HA if (discovery_type() != discoveryType::HOMEASSISTANT) { diff --git a/src/core/mqtt.h b/src/core/mqtt.h index e51e16fac..8a2f82137 100644 --- a/src/core/mqtt.h +++ b/src/core/mqtt.h @@ -258,7 +258,7 @@ class Mqtt { static std::string tag_to_topic(uint8_t device_type, int8_t tag); static void - add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8_t type, const uint8_t uom, const char * entity = nullptr, bool is_discovery = true); + add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8_t type, const uint8_t uom, const char * entity = nullptr, bool display_only = false); static void add_ha_dev_section(JsonObject doc, const char * name = nullptr, const bool create_model = false, diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index dcb3ff23b..2b25953c4 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -352,8 +352,8 @@ void WebCustomEntityService::get_value_json(JsonObject output, CustomEntityItem } } - // add uom state class and device class - Mqtt::add_ha_classes(output, EMSdevice::DeviceType::SYSTEM, entity.value_type, entity.uom, nullptr, false); + // add uom state class and device class to output json, excluding icon + Mqtt::add_ha_classes(output, EMSdevice::DeviceType::SYSTEM, entity.value_type, entity.uom, nullptr, true); // display only render_value(output, entity, true); // create the "value" field } From c4a43183b3c16a19c7dd088a8c1dd6e99e16446a Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 22 Dec 2025 17:18:37 +0100 Subject: [PATCH 03/47] GPIOs not checked when board profile is adjusted #2841 --- src/core/console.cpp | 2 -- src/core/locale_common.h | 2 +- src/core/system.cpp | 61 +++++++++++++++++++++++----------- src/core/system.h | 10 ++++-- src/web/WebSettingsService.cpp | 59 ++++++++++++++++++-------------- 5 files changed, 84 insertions(+), 50 deletions(-) diff --git a/src/core/console.cpp b/src/core/console.cpp index 59ab70403..f7141baf0 100644 --- a/src/core/console.cpp +++ b/src/core/console.cpp @@ -100,8 +100,6 @@ static void setup_commands(std::shared_ptr const & commands) { EMSESP::show_sensor_values(shell); } else if (command == F_(mqtt)) { Mqtt::show_mqtt(shell); - } else if (command == F_(gpio)) { - EMSESP::system_.show_gpio(shell); } else { shell.printfln("Unknown show command"); } diff --git a/src/core/locale_common.h b/src/core/locale_common.h index 71f00e681..26ec0eb5c 100644 --- a/src/core/locale_common.h +++ b/src/core/locale_common.h @@ -159,7 +159,7 @@ MAKE_WORD_CUSTOM(deviceid_mandatory, "") MAKE_WORD_CUSTOM(device_type_optional, "[device]") MAKE_WORD_CUSTOM(invalid_log_level, "Invalid log level") MAKE_WORD_CUSTOM(log_level_optional, "[level]") -MAKE_WORD_CUSTOM(show_commands, "[system | users | devices | log | ems | values | mqtt | commands | gpio]") +MAKE_WORD_CUSTOM(show_commands, "[system | users | devices | log | ems | values | mqtt | commands]") MAKE_WORD_CUSTOM(name_mandatory, "") MAKE_WORD_CUSTOM(name_optional, "[name]") MAKE_WORD_CUSTOM(new_password_prompt1, "Enter new password: ") diff --git a/src/core/system.cpp b/src/core/system.cpp index be231c9cf..ae0e862d0 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -96,6 +96,8 @@ uint32_t System::max_alloc_mem_; uint32_t System::heap_mem_; std::vector> System::valid_system_gpios_; std::vector> System::used_gpios_; +std::vector> System::snapshot_used_gpios_; +std::vector> System::snapshot_valid_system_gpios_; // find the index of the language // 0 = EN, 1 = DE, etc... @@ -1015,22 +1017,6 @@ void System::show_users(uuid::console::Shell & shell) { shell.println(); } -// print GPIO available and used pins to console -void System::show_gpio(uuid::console::Shell & shell) { - shell.printfln("GPIO:"); - shell.printf(" In use (%d):", used_gpios_.size()); - for (const auto & gpio : used_gpios_) { - shell.printf(" %d", gpio); - } - shell.println(); - auto available = available_gpios(); - shell.printf(" Available (%d):", available.size()); - for (const auto & gpio : available) { - shell.printf(" %d", gpio); - } - shell.println(); -} - // shell command 'show system' void System::show_system(uuid::console::Shell & shell) { refreshHeapMem(); // refresh free heap and max alloc heap @@ -1068,8 +1054,20 @@ void System::show_system(uuid::console::Shell & shell) { } else { shell.printfln(" PSRAM: not available"); } - + // GPIOs + shell.printf(" GPIO in use (%d):", used_gpios_.size()); + for (const auto & gpio : used_gpios_) { + shell.printf(" %d", gpio); + } shell.println(); + auto available = available_gpios(); + shell.printf(" GPIO available (%d):", available.size()); + for (const auto & gpio : available) { + shell.printf(" %d", gpio); + } + shell.println(); + shell.println(); + shell.println("Network:"); switch (WiFi.status()) { @@ -2241,10 +2239,9 @@ bool System::load_board_profile(std::vector & data, const std::string & // format command - factory reset, removing all config files bool System::command_format(const char * value, const int8_t id) { - LOG_INFO("Formatting FS, removing all config files"); #ifndef EMSESP_STANDALONE if (LittleFS.format()) { - LOG_INFO("FS formatted successfully"); + LOG_INFO("Filesystem formatted successfully. All config files removed."); } else { LOG_ERROR("Format failed"); } @@ -2688,4 +2685,30 @@ std::vector System::available_gpios() { return gpios; } +// make a snapshot of the current GPIOs +void System::make_snapshot_gpios() { + snapshot_used_gpios_.clear(); + for (const auto & gpio : used_gpios_) { + snapshot_used_gpios_.push_back(gpio); + } + + snapshot_valid_system_gpios_.clear(); + for (const auto & gpio : valid_system_gpios_) { + snapshot_valid_system_gpios_.push_back(gpio); + } +} + +// restore the GPIOs from the snapshot +void System::restore_snapshot_gpios() { + used_gpios_.clear(); + for (const auto & gpio : snapshot_used_gpios_) { + used_gpios_.push_back(gpio); + } + + valid_system_gpios_.clear(); + for (const auto & gpio : snapshot_valid_system_gpios_) { + valid_system_gpios_.push_back(gpio); + } +} + } // namespace emsesp diff --git a/src/core/system.h b/src/core/system.h index 5e6fbd779..23d3c5b6e 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -145,9 +145,12 @@ class System { static void extractSettings(const char * filename, const char * section, JsonObject output); static bool saveSettings(const char * filename, const char * section, JsonObject input); + // GPIOs static bool add_gpio(uint8_t pin, const char * source_name); static std::vector available_gpios(); static bool load_board_profile(std::vector & data, const std::string & board_profile); + static void make_snapshot_gpios(); + static void restore_snapshot_gpios(); static bool readCommand(const char * data); @@ -301,7 +304,6 @@ class System { void show_system(uuid::console::Shell & shell); void show_users(uuid::console::Shell & shell); - void show_gpio(uuid::console::Shell & shell); void wifi_reconnect(); @@ -402,8 +404,10 @@ class System { static std::vector> string_range_to_vector(const std::string & range); - static std::vector> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used - static std::vector> used_gpios_; // list of GPIOs used by the application + static std::vector> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used + static std::vector> used_gpios_; // list of GPIOs used by the application + static std::vector> snapshot_used_gpios_; // snapshot of the used GPIOs + static std::vector> snapshot_valid_system_gpios_; // snapshot of the valid GPIOs int8_t wifi_quality(int8_t dBm); diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index 934b62b3c..3705a7188 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -91,6 +91,9 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { // make a copy of the settings to compare to later const WebSettings original_settings(settings); + // make a snapshot of the current GPIOs + EMSESP::system_.make_snapshot_gpios(); + reset_flags(); settings.version = root["version"] | EMSESP_DEFAULT_VERSION; // save the version, we use it later in System::check_upgrade() @@ -147,8 +150,6 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { EMSESP::system_.remove_gpio(1, true); EMSESP::system_.remove_gpio(3, true); #endif - // if any of the GPIOs have changed and re-validate them - bool have_valid_gpios = true; // free old gpios from used list to allow remapping EMSESP::system_.remove_gpio(original_settings.led_gpio); @@ -157,27 +158,32 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { EMSESP::system_.remove_gpio(original_settings.rx_gpio); EMSESP::system_.remove_gpio(original_settings.tx_gpio); - // now add new gpio assignment, start with rx/tx + // if any of the GPIOs have changed and re-validate them + bool have_valid_gpios = true; + + // Helper lambda for optional GPIOs (can be 0 to disable) + auto add_optional_gpio = [&have_valid_gpios](uint8_t & gpio, const char * name) { + if (gpio != 0 && !EMSESP::system_.add_gpio(gpio, name)) { + gpio = 0; // 0 means disabled + have_valid_gpios = false; + } + }; + + // add new gpio assignment check_flag(original_settings.rx_gpio, settings.rx_gpio, ChangeFlags::UART); - have_valid_gpios = have_valid_gpios && EMSESP::system_.add_gpio(settings.rx_gpio, "UART Rx"); + have_valid_gpios &= EMSESP::system_.add_gpio(settings.rx_gpio, "UART Rx"); check_flag(original_settings.tx_gpio, settings.tx_gpio, ChangeFlags::UART); - have_valid_gpios = have_valid_gpios && EMSESP::system_.add_gpio(settings.tx_gpio, "UART Tx"); + have_valid_gpios &= EMSESP::system_.add_gpio(settings.tx_gpio, "UART Tx"); check_flag(original_settings.led_gpio, settings.led_gpio, ChangeFlags::LED); - if (settings.led_gpio != 0 && !EMSESP::system_.add_gpio(settings.led_gpio, "LED")) { - settings.led_gpio = 0; // 0 means disabled - have_valid_gpios = false; - } + add_optional_gpio(settings.led_gpio, "LED"); check_flag(original_settings.dallas_gpio, settings.dallas_gpio, ChangeFlags::TEMPERATURE_SENSOR); - if (settings.dallas_gpio != 0 && !EMSESP::system_.add_gpio(settings.dallas_gpio, "Dallas")) { - settings.dallas_gpio = 0; // 0 means disabled - have_valid_gpios = false; - } + add_optional_gpio(settings.dallas_gpio, "Dallas"); check_flag(original_settings.pbutton_gpio, settings.pbutton_gpio, ChangeFlags::BUTTON); - have_valid_gpios = have_valid_gpios && EMSESP::system_.add_gpio(settings.pbutton_gpio, "Button"); + have_valid_gpios &= EMSESP::system_.add_gpio(settings.pbutton_gpio, "Button"); // check if the LED type, eth_phy_addr or eth_clock_mode have changed check_flag(original_settings.led_type, settings.led_type, ChangeFlags::LED); @@ -303,19 +309,23 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { settings.weblog_buffer = root["weblog_buffer"] | 25; // limit to 25 messages if no psram } + // save the settings if changed from the webUI + // if we encountered an invalid GPIO, rollback changes and don't save settings, and report the error to WebUI + if (!have_valid_gpios) { + // replace settings with original settings + settings = original_settings; // the original settings are still valid + // restore the GPIOs from the snapshot + EMSESP::system_.restore_snapshot_gpios(); + + // report the error to WebUI + EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO); + return StateUpdateResult::ERROR; // don't save the settings if the GPIOs are invalid + } + + // save the setting internally, for reference later EMSESP::system_.store_settings(settings); - // save the settings if changed from the webUI - // if we encountered an invalid GPIO, don't save settings and report the error - if (!have_valid_gpios) { -#if defined(EMSESP_DEBUG) - EMSESP::logger().debug("Warning: one or more GPIOs are invalid"); -#endif - EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO); - return StateUpdateResult::CHANGED; // save the settings anyway, without restart - } - if (has_flags(WebSettings::ChangeFlags::RESTART)) { return StateUpdateResult::CHANGED_RESTART; } @@ -503,7 +513,6 @@ void WebSettings::set_board_profile(WebSettings & settings) { settings.led_type = data[9]; // LED Type } - // returns true if the value was changed bool WebSettings::check_flag(int prev_v, int new_v, uint8_t flag) { if (prev_v != new_v) { From 5c8896887992ef7869999c51a0d31503368294b3 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 22 Dec 2025 17:43:11 +0100 Subject: [PATCH 04/47] reset data and remove Apply button when error --- interface/src/utils/useRest.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/interface/src/utils/useRest.ts b/interface/src/utils/useRest.ts index aa4096623..0d57abff9 100644 --- a/interface/src/utils/useRest.ts +++ b/interface/src/utils/useRest.ts @@ -60,21 +60,28 @@ export const useRest = ({ read, update }: RestRequestOptions) => { // Reset states before saving setRestartNeeded(false); setErrorMessage(undefined); - setDirtyFlags([]); - setOrigData(data as D); try { await writeData(data as D); + // Only update origData on successful save (dirtyFlags cleared by onSuccess handler) + setOrigData(data as D); } catch (error) { const message = error instanceof Error ? error.message : String(error); + if (message === REBOOT_ERROR_MESSAGE) { setRestartNeeded(true); - } else { - toast.error(message); - setErrorMessage(message); + return; // Early return - save succeeded but needs reboot } + + // Restore original data on validation error + if (origData) { + updateData({ data: origData }); + } + toast.error(message); + setErrorMessage(message); + setDirtyFlags([]); // Clear flags so user can retry } - }, [data, writeData]); + }, [data, writeData, origData, updateData]); return useMemo( () => ({ From 0267f00b48813a79e4e0eac865d81acf3e94eb98 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 23 Dec 2025 18:08:05 +0100 Subject: [PATCH 05/47] package update --- mock-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mock-api/package.json b/mock-api/package.json index c281edffa..4f1a1a7c0 100644 --- a/mock-api/package.json +++ b/mock-api/package.json @@ -15,5 +15,5 @@ "itty-router": "^5.0.22", "prettier": "^3.7.4" }, - "packageManager": "pnpm@10.26.1+sha512.664074abc367d2c9324fdc18037097ce0a8f126034160f709928e9e9f95d98714347044e5c3164d65bd5da6c59c6be362b107546292a8eecb7999196e5ce58fa" + "packageManager": "pnpm@10.26.2+sha512.0e308ff2005fc7410366f154f625f6631ab2b16b1d2e70238444dd6ae9d630a8482d92a451144debc492416896ed16f7b114a86ec68b8404b2443869e68ffda6" } From 7bb30d37cea421646ec318bbe6f761ab7461659b Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 23 Dec 2025 18:08:50 +0100 Subject: [PATCH 06/47] rollback to other partitions - #2837 --- interface/package.json | 4 +- interface/pnpm-lock.yaml | 136 +++++++++++++-------------- interface/src/app/status/Version.tsx | 111 +++++++++++++++++++++- interface/src/i18n/cz/index.ts | 3 +- interface/src/i18n/de/index.ts | 3 +- interface/src/i18n/en/index.ts | 3 +- interface/src/i18n/fr/index.ts | 3 +- interface/src/i18n/it/index.ts | 3 +- interface/src/i18n/nl/index.ts | 3 +- interface/src/i18n/no/index.ts | 3 +- interface/src/i18n/pl/index.ts | 3 +- interface/src/i18n/sk/index.ts | 3 +- interface/src/i18n/sv/index.ts | 3 +- interface/src/i18n/tr/index.ts | 3 +- interface/src/types/system.ts | 6 ++ mock-api/restServer.ts | 44 ++++++--- src/core/system.cpp | 134 +++++++++++++++++++++++--- src/core/system.h | 11 +++ src/web/WebStatusService.cpp | 18 ++++ 19 files changed, 389 insertions(+), 108 deletions(-) diff --git a/interface/package.json b/interface/package.json index b32094173..a62086556 100644 --- a/interface/package.json +++ b/interface/package.json @@ -62,10 +62,10 @@ "prettier": "^3.7.4", "rollup-plugin-visualizer": "^6.0.5", "terser": "^5.44.1", - "typescript-eslint": "^8.50.0", + "typescript-eslint": "^8.50.1", "vite": "^7.3.0", "vite-plugin-imagemin": "^0.6.1", "vite-tsconfig-paths": "^6.0.3" }, - "packageManager": "pnpm@10.26.1+sha512.664074abc367d2c9324fdc18037097ce0a8f126034160f709928e9e9f95d98714347044e5c3164d65bd5da6c59c6be362b107546292a8eecb7999196e5ce58fa" + "packageManager": "pnpm@10.26.2+sha512.0e308ff2005fc7410366f154f625f6631ab2b16b1d2e70238444dd6ae9d630a8482d92a451144debc492416896ed16f7b114a86ec68b8404b2443869e68ffda6" } diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index d255316e1..571d3c740 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -118,8 +118,8 @@ importers: specifier: ^5.44.1 version: 5.44.1 typescript-eslint: - specifier: ^8.50.0 - version: 8.50.0(eslint@9.39.2)(typescript@5.9.3) + specifier: ^8.50.1 + version: 8.50.1(eslint@9.39.2)(typescript@5.9.3) vite: specifier: ^7.3.0 version: 7.3.0(@types/node@25.0.3)(terser@5.44.1) @@ -888,63 +888,63 @@ packages: '@types/svgo@2.6.4': resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==} - '@typescript-eslint/eslint-plugin@8.50.0': - resolution: {integrity: sha512-O7QnmOXYKVtPrfYzMolrCTfkezCJS9+ljLdKW/+DCvRsc3UAz+sbH6Xcsv7p30+0OwUbeWfUDAQE0vpabZ3QLg==} + '@typescript-eslint/eslint-plugin@8.50.1': + resolution: {integrity: sha512-PKhLGDq3JAg0Jk/aK890knnqduuI/Qj+udH7wCf0217IGi4gt+acgCyPVe79qoT+qKUvHMDQkwJeKW9fwl8Cyw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.50.0 + '@typescript-eslint/parser': ^8.50.1 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.50.0': - resolution: {integrity: sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==} + '@typescript-eslint/parser@8.50.1': + resolution: {integrity: sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.50.0': - resolution: {integrity: sha512-Cg/nQcL1BcoTijEWyx4mkVC56r8dj44bFDvBdygifuS20f3OZCHmFbjF34DPSi07kwlFvqfv/xOLnJ5DquxSGQ==} + '@typescript-eslint/project-service@8.50.1': + resolution: {integrity: sha512-E1ur1MCVf+YiP89+o4Les/oBAVzmSbeRB0MQLfSlYtbWU17HPxZ6Bhs5iYmKZRALvEuBoXIZMOIRRc/P++Ortg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.50.0': - resolution: {integrity: sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A==} + '@typescript-eslint/scope-manager@8.50.1': + resolution: {integrity: sha512-mfRx06Myt3T4vuoHaKi8ZWNTPdzKPNBhiblze5N50//TSHOAQQevl/aolqA/BcqqbJ88GUnLqjjcBc8EWdBcVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.50.0': - resolution: {integrity: sha512-vxd3G/ybKTSlm31MOA96gqvrRGv9RJ7LGtZCn2Vrc5htA0zCDvcMqUkifcjrWNNKXHUU3WCkYOzzVSFBd0wa2w==} + '@typescript-eslint/tsconfig-utils@8.50.1': + resolution: {integrity: sha512-ooHmotT/lCWLXi55G4mvaUF60aJa012QzvLK0Y+Mp4WdSt17QhMhWOaBWeGTFVkb2gDgBe19Cxy1elPXylslDw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.50.0': - resolution: {integrity: sha512-7OciHT2lKCewR0mFoBrvZJ4AXTMe/sYOe87289WAViOocEmDjjv8MvIOT2XESuKj9jp8u3SZYUSh89QA4S1kQw==} + '@typescript-eslint/type-utils@8.50.1': + resolution: {integrity: sha512-7J3bf022QZE42tYMO6SL+6lTPKFk/WphhRPe9Tw/el+cEwzLz1Jjz2PX3GtGQVxooLDKeMVmMt7fWpYRdG5Etg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.50.0': - resolution: {integrity: sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w==} + '@typescript-eslint/types@8.50.1': + resolution: {integrity: sha512-v5lFIS2feTkNyMhd7AucE/9j/4V9v5iIbpVRncjk/K0sQ6Sb+Np9fgYS/63n6nwqahHQvbmujeBL7mp07Q9mlA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.50.0': - resolution: {integrity: sha512-W7SVAGBR/IX7zm1t70Yujpbk+zdPq/u4soeFSknWFdXIFuWsBGBOUu/Tn/I6KHSKvSh91OiMuaSnYp3mtPt5IQ==} + '@typescript-eslint/typescript-estree@8.50.1': + resolution: {integrity: sha512-woHPdW+0gj53aM+cxchymJCrh0cyS7BTIdcDxWUNsclr9VDkOSbqC13juHzxOmQ22dDkMZEpZB+3X1WpUvzgVQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.50.0': - resolution: {integrity: sha512-87KgUXET09CRjGCi2Ejxy3PULXna63/bMYv72tCAlDJC3Yqwln0HiFJ3VJMst2+mEtNtZu5oFvX4qJGjKsnAgg==} + '@typescript-eslint/utils@8.50.1': + resolution: {integrity: sha512-lCLp8H1T9T7gPbEuJSnHwnSuO9mDf8mfK/Nion5mZmiEaQD9sWf9W4dfeFqRyqRjF06/kBuTmAqcs9sewM2NbQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.50.0': - resolution: {integrity: sha512-Xzmnb58+Db78gT/CCj/PVCvK+zxbnsw6F+O1oheYszJbBSdEjVhQi3C/Xttzxgi/GLmpvOggRs1RFpiJ8+c34Q==} + '@typescript-eslint/visitor-keys@8.50.1': + resolution: {integrity: sha512-IrDKrw7pCRUR94zeuCSUWQ+w8JEf5ZX5jl/e6AHGSLi1/zIr0lgutfn/7JpfCey+urpgQEdrZVYzCaVVKiTwhQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} acorn-jsx@5.3.2: @@ -1614,8 +1614,8 @@ packages: resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} hasBin: true - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} @@ -2924,8 +2924,8 @@ packages: peerDependencies: typescript: '>=3.5.1' - typescript-eslint@8.50.0: - resolution: {integrity: sha512-Q1/6yNUmCpH94fbgMUMg2/BSAr/6U7GBk61kZTv1/asghQOWOjTlp9K8mixS5NcJmm2creY+UFfGeW/+OcA64A==} + typescript-eslint@8.50.1: + resolution: {integrity: sha512-ytTHO+SoYSbhAH9CrYnMhiLx8To6PSSvqnvXyPUgPETCvB6eBKmTI9w6XMPS3HsBRGkwTVBX+urA8dYQx6bHfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -3583,7 +3583,7 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 + fastq: 1.20.1 '@paralleldrive/cuid2@2.3.1': dependencies: @@ -3803,14 +3803,14 @@ snapshots: dependencies: '@types/node': 25.0.3 - '@typescript-eslint/eslint-plugin@8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.50.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.50.0 - '@typescript-eslint/type-utils': 8.50.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.50.0 + '@typescript-eslint/parser': 8.50.1(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.50.1 + '@typescript-eslint/type-utils': 8.50.1(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.50.1 eslint: 9.39.2 ignore: 7.0.5 natural-compare: 1.4.0 @@ -3819,41 +3819,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.50.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/parser@8.50.1(eslint@9.39.2)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.50.0 - '@typescript-eslint/types': 8.50.0 - '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.50.0 + '@typescript-eslint/scope-manager': 8.50.1 + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.50.1 debug: 4.4.3 eslint: 9.39.2 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.50.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.50.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@5.9.3) - '@typescript-eslint/types': 8.50.0 + '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) + '@typescript-eslint/types': 8.50.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.50.0': + '@typescript-eslint/scope-manager@8.50.1': dependencies: - '@typescript-eslint/types': 8.50.0 - '@typescript-eslint/visitor-keys': 8.50.0 + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/visitor-keys': 8.50.1 - '@typescript-eslint/tsconfig-utils@8.50.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.50.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.50.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.50.1(eslint@9.39.2)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.50.0 - '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.2 ts-api-utils: 2.1.0(typescript@5.9.3) @@ -3861,14 +3861,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.50.0': {} + '@typescript-eslint/types@8.50.1': {} - '@typescript-eslint/typescript-estree@8.50.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.50.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.50.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@5.9.3) - '@typescript-eslint/types': 8.50.0 - '@typescript-eslint/visitor-keys': 8.50.0 + '@typescript-eslint/project-service': 8.50.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/visitor-keys': 8.50.1 debug: 4.4.3 minimatch: 9.0.5 semver: 7.7.3 @@ -3878,20 +3878,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.50.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/utils@8.50.1(eslint@9.39.2)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2) - '@typescript-eslint/scope-manager': 8.50.0 - '@typescript-eslint/types': 8.50.0 - '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.50.1 + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) eslint: 9.39.2 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.50.0': + '@typescript-eslint/visitor-keys@8.50.1': dependencies: - '@typescript-eslint/types': 8.50.0 + '@typescript-eslint/types': 8.50.1 eslint-visitor-keys: 4.2.1 acorn-jsx@5.3.2(acorn@8.15.0): @@ -4662,7 +4662,7 @@ snapshots: dependencies: strnum: 1.1.2 - fastq@1.19.1: + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -5912,12 +5912,12 @@ snapshots: dependencies: typescript: 5.9.3 - typescript-eslint@8.50.0(eslint@9.39.2)(typescript@5.9.3): + typescript-eslint@8.50.1(eslint@9.39.2)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/parser': 8.50.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/parser': 8.50.1(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2)(typescript@5.9.3) eslint: 9.39.2 typescript: 5.9.3 transitivePeerDependencies: diff --git a/interface/src/app/status/Version.tsx b/interface/src/app/status/Version.tsx index f033224e4..363a090fa 100644 --- a/interface/src/app/status/Version.tsx +++ b/interface/src/app/status/Version.tsx @@ -269,6 +269,52 @@ const InstallDialog = memo( } ); +const InstallPreviousDialog = memo( + ({ + openInstallPreviousDialog, + version, + partition, + LL, + onClose, + onInstall + }: { + openInstallPreviousDialog: boolean; + version: string; + partition: string; + LL: TranslationFunctions; + onClose: () => void; + onInstall: (partition: string) => void; + }) => { + return ( + + Rollback Firmware + + {LL.INSTALL_VERSION(LL.INSTALL(), version)} + + + + + + + + ); + } +); + // Helper function moved outside component const getPlatform = (data: VersionData): string => { return `${data.esp_platform}-${data.flash_chip_size >= 16384 ? '16MB' : '4MB'}${data.psram ? '+' : ''}`; @@ -281,6 +327,12 @@ const Version = () => { // State management const [restarting, setRestarting] = useState(false); const [openInstallDialog, setOpenInstallDialog] = useState(false); + + const [previousVersion, setPreviousVersion] = useState(''); + const [previousPartition, setPreviousPartition] = useState(''); + const [openInstallPreviousDialog, setOpenInstallPreviousDialog] = + useState(false); + const [usingDevVersion, setUsingDevVersion] = useState(false); const [fetchDevVersion, setFetchDevVersion] = useState(false); const [devUpgradeAvailable, setDevUpgradeAvailable] = useState(false); @@ -299,6 +351,11 @@ const Version = () => { setStableUpgradeAvailable(data.stable_upgradeable); }); + const { send: sendSetPartition } = useRequest( + (partition: string) => callAction({ action: 'setPartition', param: partition }), + { immediate: false } + ); + const { data, send: loadData, @@ -331,12 +388,12 @@ const Version = () => { ); const doRestart = useCallback(async () => { - setRestarting(true); await sendAPI({ device: 'system', cmd: 'restart', id: 0 }).catch( (error: Error) => { toast.error(error.message); } ); + setRestarting(true); }, [sendAPI]); const installFirmwareURL = useCallback( @@ -344,11 +401,27 @@ const Version = () => { await sendUploadURL(url).catch((error: Error) => { toast.error(error.message); }); - setRestarting(true); + doRestart(); }, [sendUploadURL] ); + const installPreviousFirmware = useCallback( + async (partition: string) => { + await sendSetPartition(partition).catch((error: Error) => { + toast.error(error.message); + }); + setRestarting(true); + }, + [sendSetPartition] + ); + + const showPreviousDialog = useCallback((version: string, partition: string) => { + setOpenInstallPreviousDialog(true); + setPreviousVersion(version); + setPreviousPartition(partition); + }, []); + const showFirmwareDialog = useCallback((useDevVersion: boolean) => { setFetchDevVersion(useDevVersion); setOpenInstallDialog(true); @@ -358,6 +431,10 @@ const Version = () => { setOpenInstallDialog(false); }, []); + const closeInstallPreviousDialog = useCallback(() => { + setOpenInstallPreviousDialog(false); + }, []); + const handleVersionInfoClose = useCallback(() => { setShowVersionInfo(0); }, []); @@ -531,6 +608,28 @@ const Version = () => { alignItems: 'baseline' }} > + + {LL.PREVIOUS_VERSIONS()} + + + {data.partitions.map((partition) => ( + + v{partition.version} ({partition.partition}: {partition.size} + {' KB'}) + + + ))} + + {LL.STABLE()} @@ -591,6 +690,14 @@ const Version = () => { onClose={closeInstallDialog} onInstall={installFirmwareURL} /> + {LL.UPLOAD()} diff --git a/interface/src/i18n/cz/index.ts b/interface/src/i18n/cz/index.ts index 704ba83cc..3e7e28c41 100644 --- a/interface/src/i18n/cz/index.ts +++ b/interface/src/i18n/cz/index.ts @@ -355,7 +355,8 @@ const cz: Translation = { SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi', FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru', NO_DATA: 'Žádná data', - USER_PROFILE: 'Uživatelský profil' + USER_PROFILE: 'Uživatelský profil', + PREVIOUS_VERSIONS: 'Předchozí verze' }; export default cz; diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index 1e578fc24..8cbed793f 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -355,7 +355,8 @@ const de: Translation = { SWITCH_RELEASE_TYPE: 'Zum {0}-Release wechseln', FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation', NO_DATA: 'Keine Daten', - USER_PROFILE: 'Benutzerprofil' + USER_PROFILE: 'Benutzerprofil', + PREVIOUS_VERSIONS: 'Vorherige Versionen' }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index 38a6e3185..de2419099 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -355,7 +355,8 @@ const en: Translation = { SWITCH_RELEASE_TYPE: 'Switch to {0} release', FIRMWARE_VERSION_INFO: 'Firmware Version Information', NO_DATA: 'No data', - USER_PROFILE: 'User Profile' + USER_PROFILE: 'User Profile', + PREVIOUS_VERSIONS: 'Previous Versions' }; export default en; diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index cfbbaa81d..9c69ff857 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -355,7 +355,8 @@ const fr: Translation = { SWITCH_RELEASE_TYPE: 'Passer à la version {0}', FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware', NO_DATA: 'Aucune donnée', - USER_PROFILE: 'Profil utilisateur' + USER_PROFILE: 'Profil utilisateur', + PREVIOUS_VERSIONS: 'Versions précédentes' }; export default fr; diff --git a/interface/src/i18n/it/index.ts b/interface/src/i18n/it/index.ts index 3dba434f6..04b6072c2 100644 --- a/interface/src/i18n/it/index.ts +++ b/interface/src/i18n/it/index.ts @@ -355,7 +355,8 @@ const it: Translation = { SWITCH_RELEASE_TYPE: 'Cambia in {0} rilascio', FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware', NO_DATA: 'Nessun dato', - USER_PROFILE: 'Profilo utente' + USER_PROFILE: 'Profilo utente', + PREVIOUS_VERSIONS: 'Versioni precedenti' }; export default it; diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index 579202eb6..1ec6d8d07 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -355,7 +355,8 @@ const nl: Translation = { SWITCH_RELEASE_TYPE: 'Switch naar {0} release', FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie', NO_DATA: 'Geen data', - USER_PROFILE: 'Gebruikersprofiel' + USER_PROFILE: 'Gebruikersprofiel', + PREVIOUS_VERSIONS: 'Vorige versies' }; export default nl; \ No newline at end of file diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index a2fbbaa6c..4cd78a5bf 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -355,7 +355,8 @@ const no: Translation = { SWITCH_RELEASE_TYPE: 'Bytt til {0} utgivelse', FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon', NO_DATA: 'Ingen data', - USER_PROFILE: 'Brukerprofil' + USER_PROFILE: 'Brukerprofil', + PREVIOUS_VERSIONS: 'Tidligere versjoner' }; export default no; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index d50d6cefa..9895ec0de 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -355,7 +355,8 @@ const pl: BaseTranslation = { SWITCH_RELEASE_TYPE: 'Zmień na {0} wydanie', FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware', NO_DATA: 'Brak danych', - USER_PROFILE: 'Profil użytkownika' + USER_PROFILE: 'Profil użytkownika', + PREVIOUS_VERSIONS: 'Poprzednie wersje' }; export default pl; diff --git a/interface/src/i18n/sk/index.ts b/interface/src/i18n/sk/index.ts index 52e6f9c75..df5359000 100644 --- a/interface/src/i18n/sk/index.ts +++ b/interface/src/i18n/sk/index.ts @@ -355,7 +355,8 @@ const sk: Translation = { SWITCH_RELEASE_TYPE: 'Prepnúť na {0} verziu', FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware', NO_DATA: 'Žiadne dáta', - USER_PROFILE: 'Profil používateľa' + USER_PROFILE: 'Profil používateľa', + PREVIOUS_VERSIONS: 'Predchádzajúce verzie' }; export default sk; diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index 644484269..001a8d0b6 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -355,7 +355,8 @@ const sv: Translation = { SWITCH_RELEASE_TYPE: 'Byt till {0} utgåva', FIRMWARE_VERSION_INFO: 'Information om firmwareversion', NO_DATA: 'Ingen data', - USER_PROFILE: 'Användarprofil' + USER_PROFILE: 'Användarprofil', + PREVIOUS_VERSIONS: 'Tidigare versioner' }; export default sv; diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index 79824decd..3933401b8 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -355,7 +355,8 @@ const tr: Translation = { SWITCH_RELEASE_TYPE: '{0} sürümüne geç', FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi', NO_DATA: 'Hiçbir veri yok', - USER_PROFILE: 'Kullanıcı Profili' + USER_PROFILE: 'Kullanıcı Profili', + PREVIOUS_VERSIONS: 'Önceki Sürümler' }; export default tr; diff --git a/interface/src/types/system.ts b/interface/src/types/system.ts index ace517688..f5d6602f7 100644 --- a/interface/src/types/system.ts +++ b/interface/src/types/system.ts @@ -52,7 +52,13 @@ export interface SystemStatus { model: string; has_loader: boolean; has_partition: boolean; + partitions: { + partition: string; + version: string; + size: number; + }[]; status: number; // System Status Codes which matches SYSTEM_STATUS in System.h + developer_mode: boolean; temperature?: number; } diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts index 5ee3e539c..3710f4443 100644 --- a/mock-api/restServer.ts +++ b/mock-api/restServer.ts @@ -106,6 +106,20 @@ let system_status = { psram_size: 8189, free_psram: 8166, has_loader: true, + has_partition: true, + partitions: [ + { + partition: 'app1', + version: '3.7.3-dev.41', + size: 4672 + }, + { + partition: 'factory', + version: '3.7.3-dev.39', + size: 4672 + }, + ], + developer_mode: true, model: '', // model: 'BBQKees Electronics EMS Gateway E32 V2 (E32 V2.0 P3/2024011)', // status: 0, @@ -276,10 +290,10 @@ function updateMask(entity: any, de: any, dd: any) { const old_custom_name = dd.nodes[dd_objIndex].cn; console.log( 'comparing names, old (' + - old_custom_name + - ') with new (' + - new_custom_name + - ')' + old_custom_name + + ') with new (' + + new_custom_name + + ')' ); if (old_custom_name !== new_custom_name) { changed = true; @@ -375,15 +389,15 @@ function check_upgrade(version: string) { console.log( 'Upgrade this version (' + - THIS_VERSION + - ') to dev (' + - dev_version + - ') is ' + - (DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + - ' and to stable (' + - stable_version + - ') is ' + - (STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + THIS_VERSION + + ') to dev (' + + dev_version + + ') is ' + + (DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + + ' and to stable (' + + stable_version + + ') is ' + + (STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') ); data = { emsesp_version: THIS_VERSION, @@ -5135,6 +5149,10 @@ router // reset MQTT console.log('resetting MQTT...'); return status(200); + } else if (action === 'setPartition') { + // set partition + console.log('setting partition to', content.param); + return status(200); } } return status(404); // cmd not found diff --git a/src/core/system.cpp b/src/core/system.cpp index ae0e862d0..c0a1e15f9 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -21,9 +21,11 @@ #ifndef EMSESP_STANDALONE #include "esp_ota_ops.h" +#include "esp_partition.h" #endif #include +#include #include @@ -293,6 +295,100 @@ void System::store_nvs_values() { EMSESP::nvs_.end(); } +// Build up a list of all partitions and their version info +void System::get_partition_info() { + partition_info_.clear(); // clear existing data + +#ifdef EMSESP_STANDALONE + // dummy data for standalone mode + partition_info_["app0"] = {EMSESP_APP_VERSION, 0}; + partition_info_["app1"] = {"", 0}; + partition_info_["factory"] = {"", 0}; + partition_info_["boot"] = {"", 0}; +#else + + auto current_partition = (const char *)esp_ota_get_running_partition()->label; + + // update the current version and partition name in NVS, if needed (to save on flash wearing) + if (EMSESP::nvs_.isKey(current_partition)) { + if (EMSESP::nvs_.getString(current_partition) != EMSESP_APP_VERSION) { + EMSESP::nvs_.putString(current_partition, EMSESP_APP_VERSION); + } + } else { + EMSESP::nvs_.putString(current_partition, EMSESP_APP_VERSION); // create new entry + } + + // Loop through all available partitions and update map with the version info pulled from NVS + // Partitions can be app0, app1, factory, boot + esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, nullptr); + uint64_t buffer; + bool is_valid; + + while (it != nullptr) { + is_valid = true; + const esp_partition_t * part = esp_partition_get(it); + + if (part->label != nullptr && part->label[0] != '\0') { + // check if part is valid and not empty + esp_partition_read(part, 0, &buffer, 8); + if (buffer == 0xFFFFFFFFFFFFFFFF) { + // skip this partition + is_valid = false; + } + } + + // get the version from the NVS store, and add to map + if (is_valid) { + PartitionInfo info; + info.size = part->size / 1024; // in KB + if (EMSESP::nvs_.isKey(part->label)) { + info.version = EMSESP::nvs_.getString(part->label).c_str(); + } else { + info.version = ""; // no version, empty string + } + partition_info_[part->label] = info; + } + + it = esp_partition_next(it); + } + esp_partition_iterator_release(it); +#endif +} + +// sets the partition to use on the next restart +bool System::set_partition(const char * partitionname) { +#ifdef EMSESP_STANDALONE + return true; +#else + if (partitionname == nullptr) { + return false; + } + + // Find the partition by label + esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, partitionname); + if (it == nullptr) { + return false; // partition not found + } + + const esp_partition_t * partition = esp_partition_get(it); + esp_partition_iterator_release(it); + + if (partition == nullptr) { + return false; + } + + // Set the boot partition + esp_err_t err = esp_ota_set_boot_partition(partition); + if (err != ESP_OK) { + return false; + } + + // initiate the restart + EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_RESTART_REQUESTED); + return true; +#endif +} + // restart EMS-ESP // app0 or app1 // on 16MB we have the additional boot and factory partitions @@ -302,24 +398,25 @@ void System::system_restart(const char * partitionname) { if (partitionname != nullptr) { // Factory partition - label will be "factory" const esp_partition_t * partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL); - if (partition && strcmp(partition->label, partitionname) == 0) { + if (partition && !strcmp(partition->label, partitionname)) { esp_ota_set_boot_partition(partition); } else // try and find the partition by name - if (strcmp(esp_ota_get_running_partition()->label, partitionname) != 0) { + if (strcmp(esp_ota_get_running_partition()->label, partitionname)) { + // not found, get next one in cycle partition = esp_ota_get_next_update_partition(nullptr); if (!partition) { LOG_ERROR("Partition '%s' not found", partitionname); return; } - if (strcmp(partition->label, partitionname) != 0 && strcmp(partitionname, "boot") != 0) { + if (strcmp(partition->label, partitionname) && strcmp(partitionname, "boot") != 0) { partition = esp_ota_get_next_update_partition(partition); if (!partition || strcmp(partition->label, partitionname)) { LOG_ERROR("Partition '%s' not found", partitionname); return; } } - // check if partition is empty + // error if partition is empty uint64_t buffer; esp_partition_read(partition, 0, &buffer, 8); if (buffer == 0xFFFFFFFFFFFFFFFF) { @@ -456,6 +553,8 @@ void System::store_settings(WebSettings & settings) { // Starts up the UART Serial bridge void System::start() { + get_partition_info(); // get the partition info + #ifndef EMSESP_STANDALONE // disable bluetooth module // periph_module_disable(PERIPH_BT_MODULE); @@ -916,7 +1015,7 @@ void System::led_monitor() { // handle the step events (on odd numbers 3,5,7,etc). see if we need to turn on a LED // 1 flash is the EMS bus is not connected // 2 flashes if the network (wifi or ethernet) is not connected - // 3 flashes is both the bus and the network are not connected. Then you know you're truly f*cked. + // 3 flashes is both the bus and the network are not connected if (led_type_) { if (led_flash_step_ == 3) { if ((healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK) { @@ -1027,7 +1126,6 @@ void System::show_system(uuid::console::Shell & shell) { #ifndef EMSESP_STANDALONE shell.printfln(" Platform: %s (%s)", EMSESP_PLATFORM, ESP.getChipModel()); shell.printfln(" Model: %s", getBBQKeesGatewayDetails().c_str()); - shell.printfln(" Partition: %s", esp_ota_get_running_partition()->label); #endif shell.printfln(" Language: %s", locale().c_str()); shell.printfln(" Board profile: %s", board_profile().c_str()); @@ -1055,21 +1153,33 @@ void System::show_system(uuid::console::Shell & shell) { shell.printfln(" PSRAM: not available"); } // GPIOs - shell.printf(" GPIO in use (%d):", used_gpios_.size()); + shell.println(" GPIOs:"); + shell.printf(" in use:"); for (const auto & gpio : used_gpios_) { shell.printf(" %d", gpio); } - shell.println(); + shell.printfln(" (total %d)", used_gpios_.size()); auto available = available_gpios(); - shell.printf(" GPIO available (%d):", available.size()); + shell.printf(" available:"); for (const auto & gpio : available) { shell.printf(" %d", gpio); } - shell.println(); - shell.println(); + shell.printfln(" (total %d)", available.size()); + // List all partitions and their version info + shell.println(" Partitions:"); + for (const auto & partition : partition_info_) { + if (partition.second.version.empty()) { + continue; // no version, empty string + } + shell.printfln(" %s: v%s (%d KB) %s", + partition.first.c_str(), + partition.second.version.c_str(), + partition.second.size, + (esp_ota_get_running_partition()->label == partition.first) ? " ** active **" : ""); + } + shell.println(); shell.println("Network:"); - switch (WiFi.status()) { case WL_IDLE_STATUS: shell.printfln(" Status: Idle"); diff --git a/src/core/system.h b/src/core/system.h index 23d3c5b6e..154e4ee3e 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -74,6 +74,11 @@ enum SYSTEM_STATUS : uint8_t { enum FUSE_VALUE : uint8_t { ALL = 0, MFG = 1, MODEL = 2, BOARD = 3, REV = 4, BATCH = 5, FUSE = 6 }; +struct PartitionInfo { + std::string version; + size_t size; +}; + class System { public: void start(); @@ -104,6 +109,7 @@ class System { void store_nvs_values(); void system_restart(const char * partition = nullptr); + void get_partition_info(); void show_mem(const char * note); void store_settings(class WebSettings & settings); @@ -363,6 +369,10 @@ class System { static void remove_gpio(uint8_t pin, bool also_system = false); // remove a gpio from both valid (optional) and used lists + // Partition info map: partition name -> {version, size} + std::map, AllocatorPSRAM>> partition_info_; + static bool set_partition(const char * partitionname); + private: static uuid::log::Logger logger_; @@ -404,6 +414,7 @@ class System { static std::vector> string_range_to_vector(const std::string & range); + // GPIOs static std::vector> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used static std::vector> used_gpios_; // list of GPIOs used by the application static std::vector> snapshot_used_gpios_; // snapshot of the used GPIOs diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index e8d2a565b..1f604822d 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -146,6 +146,22 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) { root["has_partition"] = false; } + // get the partition info + EMSESP::system_.get_partition_info(); + JsonArray partitions = root["partitions"].to(); + for (const auto & partition : EMSESP::system_.partition_info_) { + // Skip partition if it's the running one, version is empty, or size is 0 + if (partition.first == (const char *)esp_ota_get_running_partition()->label || partition.second.version.empty() || partition.second.size == 0) { + continue; + } + JsonObject part = partitions.add(); + part["partition"] = partition.first; + part["version"] = partition.second.version; + part["size"] = partition.second.size; + } + + root["developer_mode"] = EMSESP::system_.developer_mode(); + // Also used in SystemMonitor.tsx root["status"] = EMSESP::system_.systemStatus(); // send the status. See System.h for status codes if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_PENDING_RESTART) { @@ -185,6 +201,8 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) if (action == "checkUpgrade") { ok = checkUpgrade(root, param); // param could be empty, if so only send back version + } else if (action == "setPartition") { + ok = EMSESP::system_.set_partition(param.c_str()); } else if (action == "export") { if (has_param) { ok = exportData(root, param); From 3d70e8c1e66e52a8f2be7517eaca132be9860b70 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 23 Dec 2025 19:32:25 +0100 Subject: [PATCH 07/47] clear_snapshot_gpios --- src/core/system.cpp | 8 ++++++++ src/core/system.h | 1 + src/web/WebSettingsService.cpp | 2 ++ 3 files changed, 11 insertions(+) diff --git a/src/core/system.cpp b/src/core/system.cpp index c0a1e15f9..08fe00a66 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -2819,6 +2819,14 @@ void System::restore_snapshot_gpios() { for (const auto & gpio : snapshot_valid_system_gpios_) { valid_system_gpios_.push_back(gpio); } + + // clear the snapshot + clear_snapshot_gpios(); +} + +void System::clear_snapshot_gpios() { + snapshot_used_gpios_.clear(); + snapshot_valid_system_gpios_.clear(); } } // namespace emsesp diff --git a/src/core/system.h b/src/core/system.h index 154e4ee3e..9705f7135 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -157,6 +157,7 @@ class System { static bool load_board_profile(std::vector & data, const std::string & board_profile); static void make_snapshot_gpios(); static void restore_snapshot_gpios(); + static void clear_snapshot_gpios(); static bool readCommand(const char * data); diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index 3705a7188..3564feeda 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -322,6 +322,8 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { return StateUpdateResult::ERROR; // don't save the settings if the GPIOs are invalid } + // clean up snapshot of the GPIOs + EMSESP::system_.clear_snapshot_gpios(); // save the setting internally, for reference later EMSESP::system_.store_settings(settings); From 35ad43b7b321ed6f43affd44ea62286b520515be Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 23 Dec 2025 23:27:22 +0100 Subject: [PATCH 08/47] package update --- interface/package.json | 2 +- interface/pnpm-lock.yaml | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/interface/package.json b/interface/package.json index a62086556..6b77ccc8b 100644 --- a/interface/package.json +++ b/interface/package.json @@ -37,7 +37,7 @@ "jwt-decode": "^4.0.0", "magic-string": "^0.30.21", "mime-types": "^3.0.2", - "preact": "^10.28.0", + "preact": "^10.28.1", "react": "^19.2.3", "react-dom": "^19.2.3", "react-icons": "^5.5.0", diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index 571d3c740..ed529379e 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -25,7 +25,7 @@ importers: version: 7.3.6(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(@types/react@19.2.7)(react@19.2.3))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@preact/compat': specifier: ^18.3.1 - version: 18.3.1(preact@10.28.0) + version: 18.3.1(preact@10.28.1) '@table-library/react-table-library': specifier: 4.1.15 version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -51,8 +51,8 @@ importers: specifier: ^3.0.2 version: 3.0.2 preact: - specifier: ^10.28.0 - version: 10.28.0 + specifier: ^10.28.1 + version: 10.28.1 react: specifier: ^19.2.3 version: 19.2.3 @@ -83,7 +83,7 @@ importers: version: 9.39.2 '@preact/preset-vite': specifier: ^2.10.2 - version: 2.10.2(@babel/core@7.28.5)(preact@10.28.0)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) + version: 2.10.2(@babel/core@7.28.5)(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) '@trivago/prettier-plugin-sort-imports': specifier: ^6.0.0 version: 6.0.0(prettier@3.7.4) @@ -2460,8 +2460,8 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - preact@10.28.0: - resolution: {integrity: sha512-rytDAoiXr3+t6OIP3WGlDd0ouCUG1iCWzkcY3++Nreuoi17y6T5i/zRhe6uYfoVcxq6YU+sBtJouuRDsq8vvqA==} + preact@10.28.1: + resolution: {integrity: sha512-u1/ixq/lVQI0CakKNvLDEcW5zfCjUQfZdK9qqWuIJtsezuyG6pk9TWj75GMuI/EzRSZB/VAE43sNWWZfiy8psw==} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -3591,16 +3591,16 @@ snapshots: '@popperjs/core@2.11.8': {} - '@preact/compat@18.3.1(preact@10.28.0)': + '@preact/compat@18.3.1(preact@10.28.1)': dependencies: - preact: 10.28.0 + preact: 10.28.1 - '@preact/preset-vite@2.10.2(@babel/core@7.28.5)(preact@10.28.0)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))': + '@preact/preset-vite@2.10.2(@babel/core@7.28.5)(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.5) - '@prefresh/vite': 2.4.11(preact@10.28.0)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) + '@prefresh/vite': 2.4.11(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1)) '@rollup/pluginutils': 4.2.1 babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.28.5) debug: 4.4.3 @@ -3613,20 +3613,20 @@ snapshots: '@prefresh/babel-plugin@0.5.2': {} - '@prefresh/core@1.5.9(preact@10.28.0)': + '@prefresh/core@1.5.9(preact@10.28.1)': dependencies: - preact: 10.28.0 + preact: 10.28.1 '@prefresh/utils@1.2.1': {} - '@prefresh/vite@2.4.11(preact@10.28.0)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))': + '@prefresh/vite@2.4.11(preact@10.28.1)(vite@7.3.0(@types/node@25.0.3)(terser@5.44.1))': dependencies: '@babel/core': 7.28.5 '@prefresh/babel-plugin': 0.5.2 - '@prefresh/core': 1.5.9(preact@10.28.0) + '@prefresh/core': 1.5.9(preact@10.28.1) '@prefresh/utils': 1.2.1 '@rollup/pluginutils': 4.2.1 - preact: 10.28.0 + preact: 10.28.1 vite: 7.3.0(@types/node@25.0.3)(terser@5.44.1) transitivePeerDependencies: - supports-color @@ -5473,7 +5473,7 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - preact@10.28.0: {} + preact@10.28.1: {} prelude-ls@1.2.1: {} From 537cf19e97451b8105b91f55fbd2384c8120ede8 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 23 Dec 2025 23:28:02 +0100 Subject: [PATCH 09/47] only show previous if in developer mode and there are something to show --- interface/src/app/status/Version.tsx | 59 +++++++++++++++++----------- mock-api/restServer.ts | 5 ++- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/interface/src/app/status/Version.tsx b/interface/src/app/status/Version.tsx index 363a090fa..9e33e006a 100644 --- a/interface/src/app/status/Version.tsx +++ b/interface/src/app/status/Version.tsx @@ -354,7 +354,9 @@ const Version = () => { const { send: sendSetPartition } = useRequest( (partition: string) => callAction({ action: 'setPartition', param: partition }), { immediate: false } - ); + ).onError((error) => { + toast.error(String(error.error?.message || 'An error occurred')); + }); const { data, @@ -401,7 +403,7 @@ const Version = () => { await sendUploadURL(url).catch((error: Error) => { toast.error(error.message); }); - doRestart(); + await doRestart(); }, [sendUploadURL] ); @@ -608,28 +610,37 @@ const Version = () => { alignItems: 'baseline' }} > - - {LL.PREVIOUS_VERSIONS()} - - - {data.partitions.map((partition) => ( - - v{partition.version} ({partition.partition}: {partition.size} - {' KB'}) - - - ))} - - + {data.partitions.length > 0 && data.developer_mode && ( + <> + + + {LL.PREVIOUS_VERSIONS()} + + + + {data.partitions.map((partition) => ( + + v{partition.version} ({partition.partition}:{' '} + {partition.size} + {' KB'}) + + + ))} + + + )} {LL.STABLE()} diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts index 3710f4443..be394c6e6 100644 --- a/mock-api/restServer.ts +++ b/mock-api/restServer.ts @@ -117,9 +117,10 @@ let system_status = { partition: 'factory', version: '3.7.3-dev.39', size: 4672 - }, + } ], - developer_mode: true, + // partitions: [], + developer_mode: false, model: '', // model: 'BBQKees Electronics EMS Gateway E32 V2 (E32 V2.0 P3/2024011)', // status: 0, From 790371a9e28b36e05826e68d0e671bff2d34b111 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 23 Dec 2025 23:28:10 +0100 Subject: [PATCH 10/47] minor optimizations --- src/core/system.cpp | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 08fe00a66..370b47ab8 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -322,18 +322,16 @@ void System::get_partition_info() { // Partitions can be app0, app1, factory, boot esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, nullptr); uint64_t buffer; - bool is_valid; while (it != nullptr) { - is_valid = true; - const esp_partition_t * part = esp_partition_get(it); + bool is_valid = true; + const esp_partition_t * part = esp_partition_get(it); if (part->label != nullptr && part->label[0] != '\0') { // check if part is valid and not empty esp_partition_read(part, 0, &buffer, 8); if (buffer == 0xFFFFFFFFFFFFFFFF) { - // skip this partition - is_valid = false; + is_valid = false; // skip this partition } } @@ -1764,8 +1762,8 @@ std::string System::get_metrics_prometheus() { bool has_nested_objects = false; for (JsonPair p : obj) { - std::string key = p.key().c_str(); - std::string path = prefix.empty() ? key : prefix + "." + key; + std::string key = p.key().c_str(); + // std::string path = prefix.empty() ? key : prefix + "." + key; std::string metric_name = prefix.empty() ? key : prefix + "_" + key; if (should_ignore(prefix, key)) { @@ -1898,25 +1896,23 @@ std::string System::get_metrics_prometheus() { if (!local_info_labels.empty() && !prefix.empty() && !has_nested_objects) { std::string info_metric = "emsesp_" + sanitize_name(prefix) + "_info"; if (seen_metrics.find(info_metric) == seen_metrics.end()) { - result += "# HELP " + info_metric + " info\n"; - result += "# TYPE " + info_metric + " gauge\n"; + result += "# HELP " + info_metric + " info\n# TYPE " + info_metric + " gauge\n"; seen_metrics[info_metric] = true; } result += info_metric; - if (!local_info_labels.empty()) { - result += "{"; - bool first = true; - for (const auto & label : local_info_labels) { - if (!first) { - result += ", "; - } - result += label.first + "=\"" + escape_label(label.second) + "\""; - first = false; + result += '{'; + for (size_t i = 0; i < local_info_labels.size(); ++i) { + if (i > 0) { + result += ", "; } - result += "}"; + const auto & label = local_info_labels[i]; + result += label.first; + result += "=\""; + result += escape_label(label.second); + result += '"'; } - result += " 1\n"; + result += "} 1\n"; } }; From 1a3f7fbbee10b78c32573cf5e7544629b5f11309 Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 24 Dec 2025 11:17:55 +0100 Subject: [PATCH 11/47] don't run pio as default --- scripts/update_all.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/update_all.sh b/scripts/update_all.sh index a79211b48..31992ecd8 100644 --- a/scripts/update_all.sh +++ b/scripts/update_all.sh @@ -25,6 +25,6 @@ pnpm build_webUI cd .. npx cspell "**" -platformio run -e build_modbus -platformio run -e build_standalone -platformio run -e native-test -t exec +# platformio run -e build_modbus +# platformio run -e build_standalone +# platformio run -e native-test -t exec From 0557def0b699df4750c5cf05fb76fb6fce5a83b7 Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 24 Dec 2025 11:18:22 +0100 Subject: [PATCH 12/47] add install date to firmware versions --- interface/src/app/status/Version.tsx | 186 ++++++++++++++++++++------- interface/src/types/system.ts | 1 + mock-api/restServer.ts | 30 +++-- src/core/system.cpp | 32 +++-- src/core/system.h | 6 +- src/web/WebStatusService.cpp | 9 +- 6 files changed, 192 insertions(+), 72 deletions(-) diff --git a/interface/src/app/status/Version.tsx b/interface/src/app/status/Version.tsx index 9e33e006a..d8fb7f2d2 100644 --- a/interface/src/app/status/Version.tsx +++ b/interface/src/app/status/Version.tsx @@ -86,6 +86,9 @@ const VersionInfoDialog = memo( showVersionInfo, latestVersion, latestDevVersion, + previousVersion, + partition, + size, locale, LL, onClose @@ -93,6 +96,9 @@ const VersionInfoDialog = memo( showVersionInfo: number; latestVersion?: VersionInfo; latestDevVersion?: VersionInfo; + previousVersion?: VersionInfo | undefined; + partition: string; + size: number; locale: string; LL: TranslationFunctions; onClose: () => void; @@ -100,8 +106,19 @@ const VersionInfoDialog = memo( if (showVersionInfo === 0) return null; const isStable = showVersionInfo === 1; - const version = isStable ? latestVersion : latestDevVersion; - const relNotesUrl = isStable ? STABLE_RELNOTES_URL : DEV_RELNOTES_URL; + const isDev = showVersionInfo === 2; + const isPrevious = showVersionInfo === 3; + + const version = isStable + ? latestVersion + : isDev + ? latestDevVersion + : previousVersion; + const relNotesUrl = isStable + ? STABLE_RELNOTES_URL + : isDev + ? DEV_RELNOTES_URL + : ''; return ( @@ -119,13 +136,17 @@ const VersionInfoDialog = memo( pr: 1, py: 0.5, fontSize: 13, - width: 90 + width: 140 }} > - {LL.TYPE(0)} + {isPrevious ? LL.TYPE(0) : LL.RELEASE_TYPE()} - {isStable ? LL.STABLE() : LL.DEVELOPMENT()} + {isStable + ? LL.STABLE() + : isDev + ? LL.DEVELOPMENT() + : 'Partition ' + LL.VERSION()} @@ -143,9 +164,53 @@ const VersionInfoDialog = memo( {LL.VERSION()} - {version?.name} + {isPrevious + ? typeof version === 'string' + ? version + : version?.name + : version?.name} + {isPrevious && ( + + + Partition + + + {partition} + + + )} + {isPrevious && ( + + + Size + + + {size} KB + + + )} {version?.published_at && ( - Build Date + {isPrevious ? 'Install Date' : 'Build Date'} {prettyDateTime(locale, new Date(version.published_at))} @@ -170,15 +235,17 @@ const VersionInfoDialog = memo( - + {!isPrevious && ( + + )} @@ -328,7 +395,9 @@ const Version = () => { const [restarting, setRestarting] = useState(false); const [openInstallDialog, setOpenInstallDialog] = useState(false); - const [previousVersion, setPreviousVersion] = useState(''); + const [previousVersion, setPreviousVersion] = useState( + undefined + ); const [previousPartition, setPreviousPartition] = useState(''); const [openInstallPreviousDialog, setOpenInstallPreviousDialog] = useState(false); @@ -340,7 +409,8 @@ const Version = () => { useState(false); const [internetLive, setInternetLive] = useState(false); const [downloadOnly, setDownloadOnly] = useState(false); - const [showVersionInfo, setShowVersionInfo] = useState(0); + const [showVersionInfo, setShowVersionInfo] = useState(0); // 1 = stable, 2 = dev, 3 = previous + const [firmwareSize, setFirmwareSize] = useState(0); const { send: sendCheckUpgrade } = useRequest( (versions: string) => callAction({ action: 'checkUpgrade', param: versions }), @@ -389,6 +459,16 @@ const Version = () => { [data?.emsesp_version] ); + const setPreviousVersionInfo = useCallback( + (version: string, partition: string, size: number, install_date: string) => { + setShowVersionInfo(3); + setPreviousVersion({ name: version, published_at: install_date }); + setPreviousPartition(partition); + setFirmwareSize(size); + }, + [] + ); + const doRestart = useCallback(async () => { await sendAPI({ device: 'system', cmd: 'restart', id: 0 }).catch( (error: Error) => { @@ -418,11 +498,14 @@ const Version = () => { [sendSetPartition] ); - const showPreviousDialog = useCallback((version: string, partition: string) => { - setOpenInstallPreviousDialog(true); - setPreviousVersion(version); - setPreviousPartition(partition); - }, []); + const showPreviousDialog = useCallback( + (version: string, partition: string, install_date: string) => { + setOpenInstallPreviousDialog(true); + setPreviousVersion({ name: version, published_at: install_date }); + setPreviousPartition(partition); + }, + [] + ); const showFirmwareDialog = useCallback((useDevVersion: boolean) => { setFetchDevVersion(useDevVersion); @@ -439,6 +522,8 @@ const Version = () => { const handleVersionInfoClose = useCallback(() => { setShowVersionInfo(0); + setPreviousVersion(undefined); + setPreviousPartition(''); }, []); // check upgrades - only once when both versions are available @@ -485,7 +570,7 @@ const Version = () => { {LL.LATEST_VERSION(usingDevVersion ? LL.DEVELOPMENT() : LL.STABLE())} - - ))} + {data.partitions + .filter( + (partition) => partition.partition !== data.partition + ) + .map((partition) => ( + + {partition.version} + + setPartitionVersionInfo(partition.partition) + } + aria-label={LL.FIRMWARE_VERSION_INFO()} + > + + + + + ))} )} @@ -783,9 +792,10 @@ const Version = () => { showVersionInfo={showVersionInfo} latestVersion={latestVersion} latestDevVersion={latestDevVersion} - previousVersion={previousVersion} + partitionVersion={partitionVersion} locale={locale} - partition={previousPartition} + partition={partition} + currentPartition={data?.partition ?? ''} size={firmwareSize} LL={LL} onClose={handleVersionInfoClose} @@ -801,13 +811,13 @@ const Version = () => { onClose={closeInstallDialog} onInstall={installFirmwareURL} /> - {LL.UPLOAD()} diff --git a/interface/src/i18n/cz/index.ts b/interface/src/i18n/cz/index.ts index 3e7e28c41..efc1c6887 100644 --- a/interface/src/i18n/cz/index.ts +++ b/interface/src/i18n/cz/index.ts @@ -356,7 +356,7 @@ const cz: Translation = { FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru', NO_DATA: 'Žádná data', USER_PROFILE: 'Uživatelský profil', - PREVIOUS_VERSIONS: 'Předchozí verze' + STORED_VERSIONS: 'Uložené verze' }; export default cz; diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index 8cbed793f..8aa4e1dc8 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -356,7 +356,7 @@ const de: Translation = { FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation', NO_DATA: 'Keine Daten', USER_PROFILE: 'Benutzerprofil', - PREVIOUS_VERSIONS: 'Vorherige Versionen' + STORED_VERSIONS: 'Gespeicherte Versionen' }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index de2419099..bdb05a480 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -356,7 +356,7 @@ const en: Translation = { FIRMWARE_VERSION_INFO: 'Firmware Version Information', NO_DATA: 'No data', USER_PROFILE: 'User Profile', - PREVIOUS_VERSIONS: 'Previous Versions' + STORED_VERSIONS: 'Stored Versions' }; export default en; diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index 9c69ff857..008df1fcd 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -356,7 +356,7 @@ const fr: Translation = { FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware', NO_DATA: 'Aucune donnée', USER_PROFILE: 'Profil utilisateur', - PREVIOUS_VERSIONS: 'Versions précédentes' + STORED_VERSIONS: 'Versions stockées' }; export default fr; diff --git a/interface/src/i18n/it/index.ts b/interface/src/i18n/it/index.ts index 04b6072c2..cd38ed18a 100644 --- a/interface/src/i18n/it/index.ts +++ b/interface/src/i18n/it/index.ts @@ -356,7 +356,7 @@ const it: Translation = { FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware', NO_DATA: 'Nessun dato', USER_PROFILE: 'Profilo utente', - PREVIOUS_VERSIONS: 'Versioni precedenti' + STORED_VERSIONS: 'Versioni memorizzate' }; export default it; diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index 1ec6d8d07..3f23c42db 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -356,7 +356,7 @@ const nl: Translation = { FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie', NO_DATA: 'Geen data', USER_PROFILE: 'Gebruikersprofiel', - PREVIOUS_VERSIONS: 'Vorige versies' + STORED_VERSIONS: 'Opgeslagen versies' }; export default nl; \ No newline at end of file diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index 4cd78a5bf..88af2bc43 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -356,7 +356,7 @@ const no: Translation = { FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon', NO_DATA: 'Ingen data', USER_PROFILE: 'Brukerprofil', - PREVIOUS_VERSIONS: 'Tidligere versjoner' + STORED_VERSIONS: 'Lagret versjoner' }; export default no; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index 9895ec0de..07b003447 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -356,7 +356,7 @@ const pl: BaseTranslation = { FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware', NO_DATA: 'Brak danych', USER_PROFILE: 'Profil użytkownika', - PREVIOUS_VERSIONS: 'Poprzednie wersje' + STORED_VERSIONS: 'Zapisane wersje' }; export default pl; diff --git a/interface/src/i18n/sk/index.ts b/interface/src/i18n/sk/index.ts index df5359000..7950f2e05 100644 --- a/interface/src/i18n/sk/index.ts +++ b/interface/src/i18n/sk/index.ts @@ -356,7 +356,7 @@ const sk: Translation = { FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware', NO_DATA: 'Žiadne dáta', USER_PROFILE: 'Profil používateľa', - PREVIOUS_VERSIONS: 'Predchádzajúce verzie' + STORED_VERSIONS: 'Uložené verzie' }; export default sk; diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index 001a8d0b6..a8fd58d23 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -356,7 +356,7 @@ const sv: Translation = { FIRMWARE_VERSION_INFO: 'Information om firmwareversion', NO_DATA: 'Ingen data', USER_PROFILE: 'Användarprofil', - PREVIOUS_VERSIONS: 'Tidigare versioner' + STORED_VERSIONS: 'Lagrad versioner' }; export default sv; diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index 3933401b8..d931077f1 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -356,7 +356,7 @@ const tr: Translation = { FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi', NO_DATA: 'Hiçbir veri yok', USER_PROFILE: 'Kullanıcı Profili', - PREVIOUS_VERSIONS: 'Önceki Sürümler' + STORED_VERSIONS: 'Kaydedilmiş Sürümler' }; export default tr; diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts index 2ae6c39d5..209f7e3c2 100644 --- a/mock-api/restServer.ts +++ b/mock-api/restServer.ts @@ -108,6 +108,12 @@ let system_status = { has_loader: true, has_partition: true, partitions: [ + { + partition: 'app0', // this one is active + version: 'XX.XX.XX', // defined later + install_date: '2025-03-01T13:29:13.999Z', + size: 4672 + }, { partition: 'app1', version: '3.7.3-dev.41', @@ -179,6 +185,7 @@ switch (version_test as number) { // set the version system_status.emsesp_version = THIS_VERSION; +system_status.partitions[0].version = THIS_VERSION; // app0 // set the ESP platform - using ESP32 will disable OTA and automatic version downloading let emulate_esp: string; diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index fa29a91c0..bc93d0dc0 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -146,12 +146,12 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) { root["has_partition"] = false; } - // get the partition info + // get the partition info for each partition, including the running one EMSESP::system_.get_partition_info(); JsonArray partitions = root["partitions"].to(); for (const auto & partition : EMSESP::system_.partition_info_) { - // Skip partition if it's the running one, version is empty, or size is 0 - if (partition.first == (const char *)esp_ota_get_running_partition()->label || partition.second.version.empty() || partition.second.size == 0) { + // Skip partition if it has no version, or it's size is 0 + if (partition.second.version.empty() || partition.second.size == 0) { continue; } JsonObject part = partitions.add(); From 18f8db79421c39b395a9b3f38ec376ebdade736f Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 24 Dec 2025 13:06:28 +0100 Subject: [PATCH 14/47] text changes --- interface/src/app/status/Version.tsx | 103 ++++++++++++++++----------- 1 file changed, 60 insertions(+), 43 deletions(-) diff --git a/interface/src/app/status/Version.tsx b/interface/src/app/status/Version.tsx index 0d27ec461..17a452f4a 100644 --- a/interface/src/app/status/Version.tsx +++ b/interface/src/app/status/Version.tsx @@ -60,6 +60,13 @@ const DEV_RELNOTES_URL = 'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md'; // Types for better type safety +interface PartitionData { + partition: string; + version: string; + install_date?: string; + size: number; +} + interface VersionData { emsesp_version: string; arduino_version: string; @@ -67,6 +74,9 @@ interface VersionData { flash_chip_size: number; psram: boolean; build_flags?: string; + partition: string; + partitions: PartitionData[]; + developer_mode: boolean; } interface UpgradeCheckData { @@ -294,7 +304,7 @@ const InstallDialog = memo( return ( - {`${LL.UPDATE()} ${fetchDevVersion ? LL.DEVELOPMENT() : LL.STABLE()} Firmware`} + {`${LL.INSTALL()} ${fetchDevVersion ? LL.DEVELOPMENT() : LL.STABLE()} Firmware`} @@ -357,7 +367,9 @@ const InstallPartitionDialog = memo( }) => { return ( - Rollback Firmware + + {LL.INSTALL()} {LL.STORED_VERSIONS()} + {LL.INSTALL_VERSION(LL.INSTALL(), version)} @@ -457,9 +469,11 @@ const Version = () => { // Memoized values const platform = useMemo(() => (data ? getPlatform(data) : ''), [data]); - const isDev = useMemo( - () => data?.emsesp_version.includes('dev') ?? false, - [data?.emsesp_version] + + // Memoize filtered partitions to avoid recomputing on every render + const otherPartitions = useMemo( + () => data?.partitions.filter((p) => p.partition !== data.partition) ?? [], + [data] ); const setPartitionVersionInfo = useCallback( @@ -496,7 +510,7 @@ const Version = () => { }); await doRestart(); }, - [sendUploadURL] + [sendUploadURL, doRestart] ); const installPartitionFirmware = useCallback( @@ -702,7 +716,7 @@ const Version = () => { alignItems: 'baseline' }} > - {data.partitions.length > 0 && data.developer_mode && ( + {otherPartitions.length > 0 && data.developer_mode && ( <> @@ -710,40 +724,36 @@ const Version = () => { - {data.partitions - .filter( - (partition) => partition.partition !== data.partition - ) - .map((partition) => ( - - {partition.version} - - setPartitionVersionInfo(partition.partition) - } - aria-label={LL.FIRMWARE_VERSION_INFO()} - > - - - - - ))} + {otherPartitions.map((partition) => ( + + {partition.version} + + setPartitionVersionInfo(partition.partition) + } + aria-label={LL.FIRMWARE_VERSION_INFO()} + > + + + + + ))} )} @@ -834,7 +844,6 @@ const Version = () => { loadData, LL, platform, - isDev, internetLive, latestVersion, latestDevVersion, @@ -848,7 +857,15 @@ const Version = () => { handleVersionInfoClose, closeInstallDialog, installFirmwareURL, - doRestart + doRestart, + otherPartitions, + setPartitionVersionInfo, + showPartitionDialog, + partitionVersion, + partition, + firmwareSize, + closeInstallPartitionDialog, + installPartitionFirmware ]); return {restarting ? : content}; From 39fcda59dac52616e8e2ce984b63665b703521bc Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 24 Dec 2025 13:24:48 +0100 Subject: [PATCH 15/47] update 3.7.3->3.8.0 --- CHANGELOG_LATEST.md | 5 ++++- Makefile | 2 +- interface/package.json | 2 +- mock-api/package.json | 2 +- mock-api/restServer.ts | 36 ++++++++++++++++++------------------ platformio.ini | 4 ++-- sonar-project.properties | 2 +- src/emsesp_version.h | 2 +- src/test/test.cpp | 4 ++-- 9 files changed, 31 insertions(+), 28 deletions(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index d3cb3a10b..db8964bff 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -2,7 +2,7 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/). -## [3.7.3] +## [3.8.0] ## Added @@ -38,6 +38,7 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/). - added LWT (Last Will and Testament) to MQTT entities in Home Assistant - added api/metrics endpoint for prometheus integration by @gr3enk [#2774](https://github.com/emsesp/EMS-ESP32/pull/2774) - added RTL8201 to eth phy list [#2800](https://github.com/emsesp/EMS-ESP32/issues/2800) +- added partitions to Web UI Version page, so previous firmware versions can be installed [#2837](https://github.com/emsesp/EMS-ESP32/issues/2837) ## Fixed @@ -59,6 +60,7 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/). - syslog timestamp [#2704](https://github.com/emsesp/EMS-ESP32/issues/2704) - fixed FS format command [#2720](https://github.com/emsesp/EMS-ESP32/discussions/2720) - dhw priority setting to boiler and mixer, telegrams 0x2CC, 0x2CD, etc. +- check for valid GPIOs when board profile is changed [#2841](https://github.com/emsesp/EMS-ESP32/issues/2841) ## Changed @@ -81,3 +83,4 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/). - move vectors and lists to PSRAM - removed unused last topic/payload echo-check - added Home Assistant device details to MQTT Discovery for all devices +- device_class and state_class changes for HA MQTT Discovery [#2825](https://github.com/emsesp/EMS-ESP32/issues/2825) diff --git a/Makefile b/Makefile index 51e990b4c..fdab1d661 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSO DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500 DEFINES += $(ARGS) -DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.3-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\" +DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.8.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\" #---------------------------------------------------------------------- # Sources & Files diff --git a/interface/package.json b/interface/package.json index 6b77ccc8b..60834c6ea 100644 --- a/interface/package.json +++ b/interface/package.json @@ -1,6 +1,6 @@ { "name": "EMS-ESP", - "version": "3.7.3", + "version": "3.8.0", "description": "EMS-ESP WebUI", "homepage": "https://emsesp.org", "author": "proddy, emsesp.org", diff --git a/mock-api/package.json b/mock-api/package.json index 4f1a1a7c0..2e0e4c3aa 100644 --- a/mock-api/package.json +++ b/mock-api/package.json @@ -1,6 +1,6 @@ { "name": "mock-api", - "version": "3.7.3", + "version": "3.8.0", "description": "mock api for EMS-ESP", "author": "proddy, emsesp.org", "license": "MIT", diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts index 209f7e3c2..bc51cbd9f 100644 --- a/mock-api/restServer.ts +++ b/mock-api/restServer.ts @@ -116,7 +116,7 @@ let system_status = { }, { partition: 'app1', - version: '3.7.3-dev.41', + version: '3.7.3-dev.40', install_date: '2025-03-01T13:29:13.999Z', size: 4672 }, @@ -139,8 +139,8 @@ let system_status = { let DEV_VERSION_IS_UPGRADEABLE: boolean; let STABLE_VERSION_IS_UPGRADEABLE: boolean; let THIS_VERSION: string; -let LATEST_STABLE_VERSION = '3.7.3'; -let LATEST_DEV_VERSION = '3.7.4-dev.2'; +let LATEST_STABLE_VERSION = '3.8.0'; +let LATEST_DEV_VERSION = '3.8.1-dev.2'; // scenarios for testing versioning let version_test = 0; // on latest stable, or switch to dev @@ -171,13 +171,13 @@ switch (version_test as number) { break; case 3: // upgrade dev to latest, or switch to stable - THIS_VERSION = '3.7.4-dev.3'; + THIS_VERSION = '3.8.0-dev.3'; STABLE_VERSION_IS_UPGRADEABLE = false; DEV_VERSION_IS_UPGRADEABLE = true; break; case 4: // downgrade to an older dev, or switch back to stable - THIS_VERSION = '3.7.3-dev.1'; + THIS_VERSION = '3.8.0-dev.1'; STABLE_VERSION_IS_UPGRADEABLE = true; DEV_VERSION_IS_UPGRADEABLE = false; break; @@ -300,10 +300,10 @@ function updateMask(entity: any, de: any, dd: any) { const old_custom_name = dd.nodes[dd_objIndex].cn; console.log( 'comparing names, old (' + - old_custom_name + - ') with new (' + - new_custom_name + - ')' + old_custom_name + + ') with new (' + + new_custom_name + + ')' ); if (old_custom_name !== new_custom_name) { changed = true; @@ -399,15 +399,15 @@ function check_upgrade(version: string) { console.log( 'Upgrade this version (' + - THIS_VERSION + - ') to dev (' + - dev_version + - ') is ' + - (DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + - ' and to stable (' + - stable_version + - ') is ' + - (STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + THIS_VERSION + + ') to dev (' + + dev_version + + ') is ' + + (DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + + ' and to stable (' + + stable_version + + ') is ' + + (STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') ); data = { emsesp_version: THIS_VERSION, diff --git a/platformio.ini b/platformio.ini index ef14a0ea5..5f8a3e87e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -228,7 +228,7 @@ build_src_flags = -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_UNITY -DARDUINOJSON_ENABLE_ARDUINO_STRING=1 - -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.3-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" + -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.8.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" -std=gnu++17 -Og -ggdb -Wall -Wextra -Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces @@ -284,7 +284,7 @@ build_flags = [env:standalone] extends = env:native build_flags = - -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.3-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" + -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.8.0-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\" ; Modbus ; Creating the modbus registers is a multi-step process. Before it was in a shell script called generate_csv_and_headers.sh diff --git a/sonar-project.properties b/sonar-project.properties index 5d2d7e740..cee91ae32 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,7 +1,7 @@ sonar.organization=emsesp sonar.projectKey=emsesp_EMS-ESP32 sonar.projectName=EMS-ESP32 -sonar.projectVersion=3.7.3 +sonar.projectVersion=3.8.0 sonar.sources=./src sonar.cfamily.compile-commands=bw-output/compile_commands.json sonar.sourceEncoding=UTF-8 diff --git a/src/emsesp_version.h b/src/emsesp_version.h index fc19ef37c..6c48997c1 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.3-dev.40" +#define EMSESP_APP_VERSION "3.8.0-dev.0" diff --git a/src/test/test.cpp b/src/test/test.cpp index 73324533d..3681fef2a 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -1334,7 +1334,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const // log shows first if you can upgrade to dev, and then if you can upgrade to stable // request.url("/rest/action"); // std::string LATEST_STABLE_VERSION = "3.7.2"; - // std::string LATEST_DEV_VERSION = "3.7.3-dev.3"; + // std::string LATEST_DEV_VERSION = "3.8.0-dev.3"; // std::string param = LATEST_DEV_VERSION + "," + LATEST_STABLE_VERSION; // std::string action = "{\"action\":\"checkUpgrade\", \"param\":\"" + param + "\"}"; // deserializeJson(doc, action); @@ -1352,7 +1352,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const // EMSESP::webStatusService.action(&request, doc.as()); // // case 3: upgrade an older dev to latest dev, no stable upgrades available. So true, false - // EMSESP::webStatusService.set_current_version("3.7.3-dev.2"); + // EMSESP::webStatusService.set_current_version("3.8.0-dev.2"); // EMSESP::webStatusService.action(&request, doc.as()); // char data6[] = "{\"device\":\"system\", \"cmd\":\"read\",\"value\":\"8 2 27 1\"}"; From a9511e6a298873898d22001de9cf4ac48735e239 Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 24 Dec 2025 16:59:18 +0100 Subject: [PATCH 16/47] implements #2848 --- CHANGELOG_LATEST.md | 1 + lib/PButton/PButton.h | 19 ++-- lib_standalone/Arduino.h | 2 + src/ESP32React/NetworkStatus.cpp | 1 - src/core/analogsensor.cpp | 12 +-- src/core/system.cpp | 162 ++++++++++++++++++++----------- src/core/system.h | 35 +++++-- src/core/telegram.cpp | 2 +- 8 files changed, 149 insertions(+), 85 deletions(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index db8964bff..4f8736371 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -39,6 +39,7 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/). - added api/metrics endpoint for prometheus integration by @gr3enk [#2774](https://github.com/emsesp/EMS-ESP32/pull/2774) - added RTL8201 to eth phy list [#2800](https://github.com/emsesp/EMS-ESP32/issues/2800) - added partitions to Web UI Version page, so previous firmware versions can be installed [#2837](https://github.com/emsesp/EMS-ESP32/issues/2837) +- button pressures show LED. On a long press (10 seconds) the LED flashes for 5 seconds to indicate a factory reset is about to happen. [#2848](https://github.com/emsesp/EMS-ESP32/issues/2848) ## Fixed diff --git a/lib/PButton/PButton.h b/lib/PButton/PButton.h index d7be73447..a7f85f9a0 100644 --- a/lib/PButton/PButton.h +++ b/lib/PButton/PButton.h @@ -36,6 +36,9 @@ class PButton { void onVLongPress(uint16_t, buttonEventHandler handler); bool init(uint8_t pin, bool pullMode); bool check(void); + bool button_busy() { + return buttonBusy_; + } private: uint16_t Debounce_; // Debounce period to prevent flickering when pressing or releasing the button (in ms) @@ -47,21 +50,21 @@ class PButton { bool pullMode_; bool enabled_; - bool state_; // Value read from button - bool lastState_; // Last value of button state - bool dblClickWaiting_; // whether we're waiting for a double click (down) - bool dblClickOnNextUp_; // whether to register a double click on next release, or whether to wait and click - bool singleClickOK_; // whether it's OK to do a single click + bool state_; // Value read from button + bool lastState_; // Last value of button state + bool dblClickWaiting_; // whether we're waiting for a double click (down) + bool dblClickOnNextUp_; // whether to register a double click on next release, or whether to wait and click + bool singleClickOK_; // whether it's OK to do a single click - uint32_t downTime_; // time the button was pressed down - uint32_t upTime_; // time the button was released + uint32_t downTime_; // time the button was pressed down + uint32_t upTime_; // time the button was released bool ignoreUP_; // whether to ignore the button release because the click+hold was triggered bool waitForUP_; // when held, whether to wait for the up event bool longPressHappened_; // whether or not the hold event happened already bool vLongPressHappened_; // whether or not the long hold event happened already - bool buttonBusy_; // false if idle + bool buttonBusy_; // false if idle buttonEventHandler cb_onClick, cb_onDblClick, cb_onLongPress, cb_onVLongPress; }; diff --git a/lib_standalone/Arduino.h b/lib_standalone/Arduino.h index 9fe2f9ec1..1ac2aea3b 100644 --- a/lib_standalone/Arduino.h +++ b/lib_standalone/Arduino.h @@ -59,6 +59,8 @@ typedef double double_t; #define snprintf snprintf_P // to keep backwards compatibility +#define IRAM_ATTR + void pinMode(uint8_t pin, uint8_t mode); void digitalWrite(uint8_t pin, uint8_t value); int digitalRead(uint8_t pin); diff --git a/src/ESP32React/NetworkStatus.cpp b/src/ESP32React/NetworkStatus.cpp index 3d82cb57b..a67a356ba 100644 --- a/src/ESP32React/NetworkStatus.cpp +++ b/src/ESP32React/NetworkStatus.cpp @@ -55,7 +55,6 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) { } } else if (wifi_status == WL_CONNECTED) { root["local_ip"] = WiFi.localIP().toString(); -// #if ESP_ARDUINO_VERSION_MAJOR < 3 #if ESP_IDF_VERSION_MAJOR < 5 root["local_ipv6"] = WiFi.localIPv6().toString(); #else diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index 4e461b9c1..d62701ded 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -289,11 +289,7 @@ void AnalogSensor::reload(bool get_nvs) { uint8_t r = v / 10000; uint8_t g = (v - r * 10000) / 100; uint8_t b = v % 100; -#if ESP_ARDUINO_VERSION_MAJOR < 3 - neopixelWrite(sensor.gpio(), 2 * r, 2 * g, 2 * b); -#else - rgbLedWrite(sensor.gpio(), 2 * r, 2 * g, 2 * b); -#endif + EMSESP_RGB_WRITE(sensor.gpio(), 2 * r, 2 * g, 2 * b); LOG_DEBUG("RGB set to %d, %d, %d", r, g, b); } else if (sensor.type() == AnalogType::DIGITAL_OUT) { LOG_DEBUG("Digital Write on GPIO %02d", sensor.gpio()); @@ -955,11 +951,7 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) { uint8_t r = v / 10000; uint8_t g = (v - r * 10000) / 100; uint8_t b = v % 100; -#if ESP_ARDUINO_VERSION_MAJOR < 3 - neopixelWrite(sensor.gpio(), 2 * r, 2 * g, 2 * b); -#else - rgbLedWrite(sensor.gpio(), 2 * r, 2 * g, 2 * b); -#endif + EMSESP_RGB_WRITE(sensor.gpio(), 2 * r, 2 * g, 2 * b); LOG_DEBUG("RGB set to %d, %d, %d", r, g, b); } else if (sensor.type() == AnalogType::PULSE) { uint8_t v = val; diff --git a/src/core/system.cpp b/src/core/system.cpp index df1aa2255..5c7941c11 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -92,10 +92,20 @@ uuid::syslog::SyslogService System::syslog_; uuid::log::Logger System::logger_{F_(system), uuid::log::Facility::KERN}; // init statics -PButton System::myPButton_; -bool System::test_set_all_active_ = false; -uint32_t System::max_alloc_mem_; -uint32_t System::heap_mem_; +PButton System::myPButton_; +bool System::test_set_all_active_ = false; +uint32_t System::max_alloc_mem_; +uint32_t System::heap_mem_; + +// LED flash timer for factory reset +volatile uint8_t System::led_flash_count_ = 0; +volatile bool System::led_flash_state_ = false; +uint8_t System::led_flash_gpio_ = 0; +uint8_t System::led_flash_type_ = 0; +#ifndef EMSESP_STANDALONE +hw_timer_t * System::led_flash_timer_ = nullptr; +#endif + std::vector> System::valid_system_gpios_; std::vector> System::used_gpios_; std::vector> System::snapshot_used_gpios_; @@ -405,6 +415,11 @@ bool System::set_partition(const char * partitionname) { // app0 or app1 // on 16MB we have the additional boot and factory partitions void System::system_restart(const char * partitionname) { +#ifdef EMSESP_DEBUG + EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL); + return; +#endif + #ifndef EMSESP_STANDALONE // see if we are forcing a partition to use if (partitionname != nullptr) { @@ -449,8 +464,9 @@ void System::system_restart(const char * partitionname) { store_nvs_values(); // save any NVS values Shell::loop_all(); // flush log to output Mqtt::disconnect(); // gracefully disconnect MQTT, needed for QOS1 + EMSuart::stop(); // stop UART so there is no interference delay(1000); // wait 1 second - ESP.restart(); + ESP.restart(); // ka-boom! #else EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL); if (partitionname != nullptr) { @@ -640,15 +656,71 @@ void System::button_OnDblClick(PButton & b) { EMSESP::esp32React.getNetworkSettingsService()->callUpdateHandlers(); // in case we've changed ssid or password } +// LED flash timer interrupt service routine +void IRAM_ATTR System::led_flash_timer_isr() { + led_flash_state_ = !led_flash_state_; // Toggle LED state + + if (led_flash_state_) { + led_flash_type_ ? EMSESP_RGB_WRITE(led_flash_gpio_, 255, 255, 255) : digitalWrite(led_flash_gpio_, LED_ON); // white, on + } else { + led_flash_type_ ? EMSESP_RGB_WRITE(led_flash_gpio_, 0, 0, 0) : digitalWrite(led_flash_gpio_, !LED_ON); // off + } + + // Increment flash count, 2 toggles = 1 flash cycle. And stop after 5 seconds (5000ms/100ms = 50) + if (led_flash_count_++ >= 50) { + stop_led_flash(); + } +} + +// Start the LED flash timer +void System::start_led_flash() { +#ifndef EMSESP_STANDALONE + // Don't start if already running + if (led_flash_timer_ != nullptr) { + return; + } + + // Get LED settings + EMSESP::webSettingsService.read([&](WebSettings & settings) { + led_flash_type_ = settings.led_type; + led_flash_gpio_ = settings.led_gpio; + }); + + // Reset counter and state + led_flash_count_ = 0; + led_flash_state_ = false; + + led_flash_timer_ = timerBegin(0, 80, true); // Create and start timer (prescaler 80 for 1us tick, counting up) + timerAttachInterrupt(led_flash_timer_, &led_flash_timer_isr, true); // Attach interrupt handler + timerAlarmWrite(led_flash_timer_, 100000, true); // Set alarm to trigger every 100ms + timerAlarmEnable(led_flash_timer_); // Enable the alarm +#endif +} + +// Stop the LED flash timer +void System::stop_led_flash() { +#ifndef EMSESP_STANDALONE + if (led_flash_timer_ != nullptr) { + // Stop and detach timer + timerAlarmDisable(led_flash_timer_); + timerDetachInterrupt(led_flash_timer_); + timerEnd(led_flash_timer_); + led_flash_timer_ = nullptr; + led_flash_type_ ? EMSESP_RGB_WRITE(led_flash_gpio_, 0, 0, 0) : digitalWrite(led_flash_gpio_, !LED_ON); // Turn off LED + } +#endif +} + // button long press void System::button_OnLongPress(PButton & b) { LOG_NOTICE("Button pressed - long press - perform factory reset"); + start_led_flash(); // Start the non-blocking LED flash timer for 5 seconds #ifndef EMSESP_STANDALONE System::command_format(nullptr, 0); #endif } -// button indefinite press - do nothing for now +// button indefinite press - boots to boot partition void System::button_OnVLongPress(PButton & b) { LOG_NOTICE("Button pressed - very long press - restart from factory/boot partition"); EMSESP::system_.system_restart("boot"); @@ -673,20 +745,12 @@ void System::button_init() { // set the LED to on or off when in normal operating mode void System::led_init() { // disabled old led port before setting new one -#if ESP_ARDUINO_VERSION_MAJOR < 3 - led_type_ ? neopixelWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); -#else - led_type_ ? rgbLedWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); -#endif + led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); if ((led_gpio_)) { // 0 means disabled if (led_type_) { // rgb LED WS2812B, use Neopixel -#if ESP_ARDUINO_VERSION_MAJOR < 3 - neopixelWrite(led_gpio_, 0, 0, 0); -#else - rgbLedWrite(led_gpio_, 0, 0, 0); -#endif + EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0); } else { pinMode(led_gpio_, OUTPUT); digitalWrite(led_gpio_, !LED_ON); // start with LED off @@ -945,20 +1009,12 @@ void System::system_check() { if (healthcheck_ == 0) { // everything is healthy, show LED permanently on or off depending on setting if (led_gpio_) { -#if ESP_ARDUINO_VERSION_MAJOR < 3 - led_type_ ? neopixelWrite(led_gpio_, 0, hide_led_ ? 0 : RGB_LED_BRIGHTNESS, 0) : digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); -#else - led_type_ ? rgbLedWrite(led_gpio_, 0, hide_led_ ? 0 : RGB_LED_BRIGHTNESS, 0) : digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); -#endif + led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, hide_led_ ? 0 : RGB_LED_BRIGHTNESS, 0) : digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); } } else { // turn off LED so we're ready to the flashes if (led_gpio_) { -#if ESP_ARDUINO_VERSION_MAJOR < 3 - led_type_ ? neopixelWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); -#else - led_type_ ? rgbLedWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); -#endif + led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); } } } @@ -991,15 +1047,27 @@ void System::commands_init() { // 2 x flash = the network (wifi or ethernet) is not connected // 3 x flash = both EMS bus and network are failing. This is a critical error! void System::led_monitor() { + // check if button is busy or has been pressed - LED on to white + static bool button_busy_ = false; + if (button_busy_ != myPButton_.button_busy()) { + button_busy_ = myPButton_.button_busy(); + if (button_busy_) { + led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 255, 255, 255) : digitalWrite(led_gpio_, LED_ON); // on + } else { + led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); // off + } + } + // we only need to run the LED healthcheck if there are errors - if (!healthcheck_ || !led_gpio_) { + if (!healthcheck_ || !led_gpio_ || button_busy_) { return; // all good } static uint32_t led_long_timer_ = 1; // 1 will kick it off immediately static uint32_t led_short_timer_ = 0; static uint8_t led_flash_step_ = 0; // 0 means we're not in the short flash timer - auto current_time = uuid::get_uptime(); + + auto current_time = uuid::get_uptime(); // first long pause before we start flashing if (led_long_timer_ && (uint32_t)(current_time - led_long_timer_) >= HEALTHCHECK_LED_LONG_DUARATION) { @@ -1018,11 +1086,7 @@ void System::led_monitor() { // reset the whole sequence led_long_timer_ = uuid::get_uptime(); led_flash_step_ = 0; -#if ESP_ARDUINO_VERSION_MAJOR < 3 - led_type_ ? neopixelWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); // LED off -#else - led_type_ ? rgbLedWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); // LED off -#endif + led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); // LED off } else if (led_flash_step_ % 2) { // handle the step events (on odd numbers 3,5,7,etc). see if we need to turn on a LED // 1 flash is the EMS bus is not connected @@ -1031,33 +1095,17 @@ void System::led_monitor() { if (led_type_) { if (led_flash_step_ == 3) { if ((healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK) { -#if ESP_ARDUINO_VERSION_MAJOR < 3 - neopixelWrite(led_gpio_, RGB_LED_BRIGHTNESS, 0, 0); // red -#else - rgbLedWrite(led_gpio_, RGB_LED_BRIGHTNESS, 0, 0); // red -#endif + EMSESP_RGB_WRITE(led_gpio_, RGB_LED_BRIGHTNESS, 0, 0); // red } else if ((healthcheck_ & HEALTHCHECK_NO_BUS) == HEALTHCHECK_NO_BUS) { -#if ESP_ARDUINO_VERSION_MAJOR < 3 - neopixelWrite(led_gpio_, 0, 0, RGB_LED_BRIGHTNESS); // blue -#else - rgbLedWrite(led_gpio_, 0, 0, RGB_LED_BRIGHTNESS); // blue -#endif + EMSESP_RGB_WRITE(led_gpio_, 0, 0, RGB_LED_BRIGHTNESS); // blue } } if (led_flash_step_ == 5 && (healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK) { -#if ESP_ARDUINO_VERSION_MAJOR < 3 - neopixelWrite(led_gpio_, RGB_LED_BRIGHTNESS, 0, 0); // red -#else - rgbLedWrite(led_gpio_, RGB_LED_BRIGHTNESS, 0, 0); // red -#endif + EMSESP_RGB_WRITE(led_gpio_, RGB_LED_BRIGHTNESS, 0, 0); // red } if ((led_flash_step_ == 7) && ((healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK) && ((healthcheck_ & HEALTHCHECK_NO_BUS) == HEALTHCHECK_NO_BUS)) { -#if ESP_ARDUINO_VERSION_MAJOR < 3 - neopixelWrite(led_gpio_, 0, 0, RGB_LED_BRIGHTNESS); // blue -#else - rgbLedWrite(led_gpio_, 0, 0, RGB_LED_BRIGHTNESS); // blue -#endif + EMSESP_RGB_WRITE(led_gpio_, 0, 0, RGB_LED_BRIGHTNESS); // blue } } else { if ((led_flash_step_ == 3) @@ -1075,17 +1123,13 @@ void System::led_monitor() { } if (led_on_) { - digitalWrite(led_gpio_, LED_ON); // LED off + digitalWrite(led_gpio_, LED_ON); // LED on } } } else { // turn the led off after the flash, on even number count if (led_on_) { -#if ESP_ARDUINO_VERSION_MAJOR < 3 - led_type_ ? neopixelWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); -#else - led_type_ ? rgbLedWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); -#endif + led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); led_on_ = false; } } diff --git a/src/core/system.h b/src/core/system.h index 8ca6d0576..832fbfef6 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -37,6 +37,12 @@ #include #include +#if ESP_ARDUINO_VERSION_MAJOR < 3 +#define EMSESP_RGB_WRITE neopixelWrite +#else +#define EMSESP_RGB_WRITE rgbLedWrite +#endif + #if CONFIG_IDF_TARGET_ESP32 // there is no official API available on the original ESP32 extern "C" { @@ -56,7 +62,7 @@ using uuid::console::Shell; #define EMSESP_CUSTOMSUPPORT_FILE "/config/customSupport.json" -#define RGB_LED_BRIGHTNESS 20 +#define RGB_LED_BRIGHTNESS 20 // 255 is max brightness namespace emsesp { @@ -391,9 +397,26 @@ class System { static void button_OnDblClick(PButton & b); static void button_OnLongPress(PButton & b); static void button_OnVLongPress(PButton & b); - static constexpr uint32_t BUTTON_Debounce = 40; // Debounce period to prevent flickering when pressing or releasing the button (in ms) - static constexpr uint32_t BUTTON_DblClickDelay = 250; // Max period between clicks for a double click event (in ms) - static constexpr uint32_t BUTTON_LongPressDelay = 9500; // Hold period for a long press event (in ms) - 10 seconds + static constexpr uint32_t BUTTON_Debounce = 40; // Debounce period to prevent flickering when pressing or releasing the button (in ms) + static constexpr uint32_t BUTTON_DblClickDelay = 250; // Max period between clicks for a double click event (in ms) + +// LED flash timer for factory reset +#ifndef EMSESP_STANDALONE + static hw_timer_t * led_flash_timer_; +#endif + static void IRAM_ATTR led_flash_timer_isr(); + static volatile uint8_t led_flash_count_; + static volatile bool led_flash_state_; + static uint8_t led_flash_gpio_; + static uint8_t led_flash_type_; + static void start_led_flash(); + static void stop_led_flash(); + +#ifdef EMSESP_DEBUG + static constexpr uint32_t BUTTON_LongPressDelay = 2000; // Hold period for a long press event (in ms) - 2 seconds, for debugging +#else + static constexpr uint32_t BUTTON_LongPressDelay = 9500; // Hold period for a long press event (in ms) - ~10 seconds +#endif static constexpr uint32_t BUTTON_VLongPressDelay = 20000; // Hold period for a very long press event (in ms) - 20 seconds // healthcheck @@ -402,8 +425,8 @@ class System { #else static constexpr uint32_t SYSTEM_CHECK_FREQUENCY = 5000; // do a system check every 5 seconds #endif - static constexpr uint32_t HEALTHCHECK_LED_LONG_DUARATION = 1500; - static constexpr uint32_t HEALTHCHECK_LED_FLASH_DUARATION = 150; + static constexpr uint32_t HEALTHCHECK_LED_LONG_DUARATION = 1500; // 1.5 seconds + static constexpr uint32_t HEALTHCHECK_LED_FLASH_DUARATION = 150; // 150ms static constexpr uint8_t HEALTHCHECK_NO_BUS = (1 << 0); // 1 static constexpr uint8_t HEALTHCHECK_NO_NETWORK = (1 << 1); // 2 static constexpr uint8_t LED_ON = HIGH; // LED on diff --git a/src/core/telegram.cpp b/src/core/telegram.cpp index 0f3298e46..ea9ba2b89 100644 --- a/src/core/telegram.cpp +++ b/src/core/telegram.cpp @@ -146,7 +146,7 @@ void RxService::add(uint8_t * data, uint8_t length) { } // ignore src==0, https://github.com/emsesp/EMS-ESP32/issues/2378 - if (!(data[0] & 0x7F)) { + if (!(data[0] & 0x7F) && bus_connected()) { LOG_WARNING("Invalid source: %s", Helpers::data_to_hex(data, length).c_str()); // include CRC return; } From 8a7511a9411214f17d37ab637c6df50e94a97553 Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 24 Dec 2025 17:55:27 +0100 Subject: [PATCH 17/47] default no sleep is true in standalone --- lib_standalone/ESP32React.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_standalone/ESP32React.h b/lib_standalone/ESP32React.h index 4da6036a6..23e3a5736 100644 --- a/lib_standalone/ESP32React.h +++ b/lib_standalone/ESP32React.h @@ -26,7 +26,7 @@ class DummySettings { public: // SYSTEM bool bandwidth20 = false; - bool nosleep = false; + bool nosleep = true; // MQTT uint16_t publish_time = 10; From 3bdc97d4d51a3c0c350d5e4b881d6bd6cf8d5067 Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 24 Dec 2025 17:56:07 +0100 Subject: [PATCH 18/47] rollback changes to get_metrics_prometheus() --- src/core/system.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 5c7941c11..6d6b9f4a5 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1820,8 +1820,8 @@ std::string System::get_metrics_prometheus() { bool has_nested_objects = false; for (JsonPair p : obj) { - std::string key = p.key().c_str(); - // std::string path = prefix.empty() ? key : prefix + "." + key; + std::string key = p.key().c_str(); + std::string path = prefix.empty() ? key : prefix + "." + key; std::string metric_name = prefix.empty() ? key : prefix + "_" + key; if (should_ignore(prefix, key)) { @@ -1954,23 +1954,25 @@ std::string System::get_metrics_prometheus() { if (!local_info_labels.empty() && !prefix.empty() && !has_nested_objects) { std::string info_metric = "emsesp_" + sanitize_name(prefix) + "_info"; if (seen_metrics.find(info_metric) == seen_metrics.end()) { - result += "# HELP " + info_metric + " info\n# TYPE " + info_metric + " gauge\n"; + result += "# HELP " + info_metric + " info\n"; + result += "# TYPE " + info_metric + " gauge\n"; seen_metrics[info_metric] = true; } result += info_metric; - result += '{'; - for (size_t i = 0; i < local_info_labels.size(); ++i) { - if (i > 0) { - result += ", "; + if (!local_info_labels.empty()) { + result += "{"; + bool first = true; + for (const auto & label : local_info_labels) { + if (!first) { + result += ", "; + } + result += label.first + "=\"" + escape_label(label.second) + "\""; + first = false; } - const auto & label = local_info_labels[i]; - result += label.first; - result += "=\""; - result += escape_label(label.second); - result += '"'; + result += "}"; } - result += "} 1\n"; + result += " 1\n"; } }; From 7e9f27a613171ee3327c7f7049751044349662d2 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 09:32:46 +0100 Subject: [PATCH 19/47] tidy up comments --- src/devices/connect.cpp | 9 +++--- src/devices/solar.cpp | 28 ++++++++---------- src/devices/ventilation.h | 62 --------------------------------------- 3 files changed, 17 insertions(+), 82 deletions(-) diff --git a/src/devices/connect.cpp b/src/devices/connect.cpp index 29bc56c6a..78c615187 100644 --- a/src/devices/connect.cpp +++ b/src/devices/connect.cpp @@ -81,11 +81,10 @@ void Connect::process_RCTime(std::shared_ptr telegram) { has_update(dateTime_, time, sizeof(dateTime_)); } -/* other values from 0x50 RF base -(0x087F), data: 00 00 -(0x0880), data: 01 04 -(0x0889), data: 00 80 80 01 -*/ +// other values from 0x50 RF base +// (0x087F), data: 00 00 +// (0x0880), data: 01 04 +// (0x0889), data: 00 80 80 01 void Connect::register_device_values_room(std::shared_ptr room) { auto tag = DeviceValueTAG::TAG_SRC1 + room->room(); register_device_value(tag, &room->temp_, DeviceValueType::INT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(roomTemp), DeviceValueUOM::DEGREES); diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index 95f8a2861..28ba574c4 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -563,21 +563,19 @@ void Solar::process_SM100Differential(std::shared_ptr telegram) has_update(telegram, diffControl_, 0); // is *10 } -/* process_SM100ParamCfg - type 0xF9 EMS 1.0 - * This telegram is used to inquire the min, default, max, and current values of a value that is usually read and written with another telegram ID - * The CS200 uses this method extensively to find out which values may be set in the SM100 - * e.g. B0 10 F9 00 FF 02 5A 03 17 00 00 00 14 00 00 00 3C 00 00 00 5A 00 00 00 59 29 - requested with 90 B0 F9 00 11 FF 02 5A 03 AF - * byte 0 = 0xFF - * byte 1-2 = telegram ID used to write this value - * byte 3 = offset in telegram used to write this value - * byte 4 = unknown - * bytes 5..8 = minimum value - * bytes 9..12 = default value - * bytes 13..16 = maximum value - * bytes 17..20 = current value - * - * e.g. B0 0B F9 00 00 02 5A 00 00 6E - */ +// process_SM100ParamCfg - type 0xF9 EMS 1.0 +// This telegram is used to inquire the min, default, max, and current values of a value that is usually read and written with another telegram ID +// The CS200 uses this method extensively to find out which values may be set in the SM100 +// e.g. B0 10 F9 00 FF 02 5A 03 17 00 00 00 14 00 00 00 3C 00 00 00 5A 00 00 00 59 29 - requested with 90 B0 F9 00 11 FF 02 5A 03 AF +// byte 0 = 0xFF +// byte 1-2 = telegram ID used to write this value +// byte 3 = offset in telegram used to write this value +// byte 4 = unknown +// bytes 5..8 = minimum value +// bytes 9..12 = default value +// bytes 13..16 = maximum value +// bytes 17..20 = current value +// e.g. B0 0B F9 00 00 02 5A 00 00 6E void Solar::process_SM100ParamCfg(std::shared_ptr telegram) { uint16_t t_id = EMS_VALUE_UINT16_NOTSET; uint8_t of = EMS_VALUE_UINT8_NOTSET; diff --git a/src/devices/ventilation.h b/src/devices/ventilation.h index 9421f85c9..21a3ee028 100644 --- a/src/devices/ventilation.h +++ b/src/devices/ventilation.h @@ -51,68 +51,6 @@ class Ventilation : public EMSdevice { bool set_ventMode(const char * value, const int8_t id); bool set_bypass(const char * value, const int8_t id); bool set_filter(const char * value, const int8_t id); - - - /* Sensors: - outdoor air temp (außenluft) - supply air temp (zuluft) - extract air temp (abluft) - away air temp (fortluft) - supply blower (zuluftgebläse) - supply blower mod (zuluftebläse drehzahl) - away blower (abluftgebläse) - away blower mod (abluftgebläse drehzahl) - Anschlussvariante - el. vorheizer - ext. el. vorheizreg. - nachheiz zulufttemp - mischer öffnen - mischer schließen - mischerposition - zuluft temp soll - zuluft temp ist - leistung nachheizreg. - erdwärmetauscher klappe - solekreispumpe - abluftfeuchte - abluftqualität - raumluftfechte - raumluftqualität - luftfeuchte fernbed. 1..4 - */ - /* Parameters: - Gerätetyp, - Nennvolumentstrom, - Filterlaufzeit 1-6-12 m - Filterwechsel confirm CMD - Lüftungsfrostschutz: _el._preheat_, Disballance | Interval - Ext. Frostschutz: on/_off_ - Bypass _on_, off - min. outdoortemp 12 15 19 °C - max. outdoortemp 21-24-30 C - Enthalpie Wärmetauscher instaliert nein-ja - Feuchteschutz AUs/ 1-24 h - Lüfterstufe 1-4, Drehzahlanpassung - ext. Luftfeuchtefühler inst.? _nein_, ja - Abluftfeuchtefühler inst.? _nein_, ja - Luftfeuchte Fernbed. _nein_, ja - Luftfeuchte: trocken, _normal_, feucht - Abluftqualitätsfühler inst. _ja_, nein - ext. Luftqualfühl? _nein_, ja - Lufqualität: ausreichend, _normal_, hoch - el. Nachheizregister inst. _nein_, ja - Nachheiz-Zuluft temp: 10-22-30 °C - Erdwärmetauscher inst? _nein_, Luft, Sole - Taster Funktion: nein, einschlafen, intensiv, bypass, party, kamin - ext. Störung aktivieren: _nein_, ja, invertiert - Dauer einschlafen: 15-60-120 min - Dauer Intensiv: 5-15-60 min - Dauer Bypass Abluft: 1-8-12 h - Dauer Bypass: 1-8-12 h - Dauer PArty 1-8-12 h - Dauer Kamin: 5-10-15 min - Volumenstromabgleich 90-100-110 % - */ }; } // namespace emsesp From d7b0614556c44b1f9319ba30c3054a033f667db8 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 09:32:57 +0100 Subject: [PATCH 20/47] add comment --- src/ESP32React/UploadFileService.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ESP32React/UploadFileService.cpp b/src/ESP32React/UploadFileService.cpp index 126d3e237..88b1aa436 100644 --- a/src/ESP32React/UploadFileService.cpp +++ b/src/ESP32React/UploadFileService.cpp @@ -133,6 +133,7 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) { return; } + // add MD5 to the response if (strlen(_md5.data()) == _md5.size() - 1) { auto * response = new AsyncJsonResponse(false); JsonObject root = response->getRoot(); From bbe1f133dce040db1f15c4ac726b3203d0677c33 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 09:33:17 +0100 Subject: [PATCH 21/47] add EMS_TXMODE_INIT and EMS_TXMODE_NONE --- src/uart/emsuart_esp32.cpp | 52 +++++++++++++++----------------------- src/uart/emsuart_esp32.h | 2 ++ 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index f4f0e0d17..b4f5ff692 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -16,9 +16,7 @@ * along with this program. If not, see . */ -/* - * ESP32 UART port by @ArwedL and improved by @MichaelDvP. See https://github.com/emsesp/EMS-ESP/issues/380 - */ +// ESP32 UART port by @ArwedL and improved by @MichaelDvP. See https://github.com/emsesp/EMS-ESP/issues/380 #ifndef EMSESP_STANDALONE @@ -35,12 +33,10 @@ uint8_t EMSuart::last_tx_src_ = 0; static TaskHandle_t xHandle; static QueueHandle_t uart_queue; -uint8_t tx_mode_ = 0xFF; +uint8_t tx_mode_ = EMS_TXMODE_INIT; uint32_t inverse_mask = 0; -/* -* receive task, wait for break and call incoming_telegram -*/ +// receive task, wait for break and call incoming_telegram void EMSuart::uart_event_task(void * pvParameters) { uart_event_t event; uint8_t telegram[EMS_MAXBUFFERSIZE]; @@ -69,11 +65,9 @@ void EMSuart::uart_event_task(void * pvParameters) { vTaskDelete(NULL); } -/* - * init UART driver - */ +// initialize UART driver void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t tx_gpio) { - if (tx_mode_ == 0xFF) { + if (tx_mode_ == EMS_TXMODE_INIT) { uart_config_t uart_config = {.baud_rate = EMSUART_BAUD, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, @@ -113,9 +107,7 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t uart_enable_intr_mask(EMSUART_NUM, UART_BRK_DET_INT_ENA | UART_RXFIFO_FULL_INT_ENA); } -/* - * Stop, disable interrupt - */ +// Stop, disable interrupt void EMSuart::stop() { if (tx_mode_ != 0xFF) { // only call after driver initialisation uart_disable_intr_mask(EMSUART_NUM, UART_BRK_DET_INT_ENA | UART_RXFIFO_FULL_INT_ENA); @@ -123,9 +115,7 @@ void EMSuart::stop() { } }; -/* - * generate by inverting tx - */ +// generate by inverting tx void IRAM_ATTR EMSuart::uart_gen_break(uint32_t length_us) { portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; portENTER_CRITICAL(&mux); @@ -135,35 +125,34 @@ void IRAM_ATTR EMSuart::uart_gen_break(uint32_t length_us) { portEXIT_CRITICAL(&mux); } -/* - * Sends a 1-byte poll, ending with a - */ +// Sends a 1-byte poll, ending with a void EMSuart::send_poll(const uint8_t data) { transmit(&data, 1); } -/* - * Send data to Tx line, ending with a - * buf contains the CRC and len is #bytes including the CRC - * returns code, 1=success - */ +// Send data to Tx line, ending with a +// buf contains the CRC and len is #bytes including the CRC +// returns code, 1=success uint8_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { if (len == 0 || len >= EMS_MAXBUFFERSIZE) { return EMS_TX_STATUS_ERR; } - if (tx_mode_ == 0) { + // TXMODE is OFF + if (tx_mode_ == EMS_TXMODE_OFF) { return EMS_TX_STATUS_OK; } - last_tx_src_ = len < 4 ? 0 : buf[0]; + last_tx_src_ = len < 4 ? 0 : buf[0]; // update last tx source - if (tx_mode_ == EMS_TXMODE_HW) { // hardware controlled mode + // TXMODE is hardware controlled mode + if (tx_mode_ == EMS_TXMODE_HW) { uart_write_bytes_with_break(EMSUART_NUM, buf, len, 10); return EMS_TX_STATUS_OK; } - if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ with long delay + // TXMODE is EMS+ with long delay + if (tx_mode_ == EMS_TXMODE_EMSPLUS) { for (uint8_t i = 0; i < len; i++) { uart_write_bytes(EMSUART_NUM, &buf[i], 1); delayMicroseconds(EMSUART_TX_WAIT_PLUS); @@ -172,7 +161,8 @@ uint8_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { return EMS_TX_STATUS_OK; } - if (tx_mode_ == EMS_TXMODE_HT3) { // HT3 with 7 bittimes delay + // TXMODE is HT3 with 7 bittimes delay + if (tx_mode_ == EMS_TXMODE_HT3) { for (uint8_t i = 0; i < len; i++) { uart_write_bytes(EMSUART_NUM, &buf[i], 1); delayMicroseconds(EMSUART_TX_WAIT_HT3); @@ -181,7 +171,7 @@ uint8_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { return EMS_TX_STATUS_OK; } - // mode 1: wait for echo after each byte + // TXMODE default: wait for echo after each byte for (uint8_t i = 0; i < len; i++) { size_t rx0, rx1; uart_get_buffered_data_len(EMSUART_NUM, &rx0); diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index 6a6f2f2d1..d0727f3ee 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -40,6 +40,8 @@ #define EMSUART_NUM UART_NUM_1 // on C3 and S2 there is no UART2, use UART1 for all #define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit +#define EMS_TXMODE_INIT 0xFF +#define EMS_TXMODE_OFF 0 #define EMS_TXMODE_DEFAULT 1 #define EMS_TXMODE_EMSPLUS 2 #define EMS_TXMODE_HT3 3 From 36271a2c24824fedaad1dd7abed6b81ae288cd5f Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 09:33:50 +0100 Subject: [PATCH 22/47] add comments --- src/core/console.cpp | 2 ++ src/core/telegram.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/console.cpp b/src/core/console.cpp index f7141baf0..f0b45cf00 100644 --- a/src/core/console.cpp +++ b/src/core/console.cpp @@ -367,6 +367,7 @@ static void setup_commands(std::shared_ptr const & commands) { commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, {F_(scan)}, [](Shell & shell, const std::vector & arguments) { EMSESP::scan_devices(); }); + /* removed scan deep commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, {F_(scan)}, {F_(deep_optional)}, [](Shell & shell, const std::vector & arguments) { if (arguments.empty()) { @@ -384,6 +385,7 @@ static void setup_commands(std::shared_ptr const & commands) { } }); */ + // read [offset] [length] commands->add_command(ShellContext::MAIN, CommandFlags::USER, diff --git a/src/core/telegram.h b/src/core/telegram.h index b6baeae71..99390f826 100644 --- a/src/core/telegram.h +++ b/src/core/telegram.h @@ -204,7 +204,6 @@ class EMSbus { #endif } - // sets the flag for EMS bus connected static void last_bus_activity(uint32_t timestamp) { // record the first time we connected to the BUS, as this will be our uptime From bbfec136e88c5ce4ef8d46ccbd60fe5815c4674b Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 09:33:59 +0100 Subject: [PATCH 23/47] use EMS_TXMODE_OFF --- src/core/telegram.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/telegram.cpp b/src/core/telegram.cpp index ea9ba2b89..5d6b5d797 100644 --- a/src/core/telegram.cpp +++ b/src/core/telegram.cpp @@ -272,8 +272,8 @@ void TxService::start() { // sends a 1 byte poll which is our own deviceID void TxService::send_poll() const { - //LOG_DEBUG("Ack %02X",ems_bus_id() ^ ems_mask()); - if (tx_mode()) { + // LOG_DEBUG("Ack %02X",ems_bus_id() ^ ems_mask()); + if (tx_mode() != EMS_TXMODE_OFF) { EMSuart::send_poll(ems_bus_id() ^ ems_mask()); } } @@ -309,7 +309,7 @@ void TxService::send() { delayed_send_ = 0; // if we're in read-only mode (tx_mode 0) forget the Tx call - if (tx_mode() != 0) { + if (tx_mode() != EMS_TXMODE_OFF) { send_telegram(tx_telegrams_.front()); } From fb698fd029af1d9af423d8fb567311a8a28a8e31 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 09:34:25 +0100 Subject: [PATCH 24/47] if LED flashing skip other chores --- src/core/emsesp.cpp | 13 ++- src/core/system.cpp | 265 ++++++++++++++++++++++++-------------------- src/core/system.h | 30 ++--- 3 files changed, 163 insertions(+), 145 deletions(-) diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index 081390993..be82dd158 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -1591,6 +1591,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { connect_time = uuid::get_uptime_sec(); } if (poll_id == EMSbus::ems_bus_id()) { + // TODO this could also be by coincidence, so we should add a counter to the EMSbus class to check if the poll_id is the same as the EMS_BUS_ID for a certain number of times EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active } if (wait_km_) { @@ -1810,10 +1811,14 @@ void EMSESP::shell_prompt() { // main loop calling all services void EMSESP::loop() { - uuid::loop(); // store system uptime - esp32React.loop(); // web services - system_.loop(); // does LED and checks system health, and syslog service - webLogService.loop(); // log in Web UI + uuid::loop(); // store system uptime + + // does LED and checks system health, and syslog service + if (system_.loop()) { + return; // LED flashing is active + } + + esp32React.loop(); // web services // run the loop, unless we're in the middle of an OTA upload if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_NORMAL || EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO) { diff --git a/src/core/system.cpp b/src/core/system.cpp index 6d6b9f4a5..c4bafad06 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -97,15 +97,14 @@ bool System::test_set_all_active_ = false; uint32_t System::max_alloc_mem_; uint32_t System::heap_mem_; -// LED flash timer for factory reset -volatile uint8_t System::led_flash_count_ = 0; -volatile bool System::led_flash_state_ = false; -uint8_t System::led_flash_gpio_ = 0; -uint8_t System::led_flash_type_ = 0; -#ifndef EMSESP_STANDALONE -hw_timer_t * System::led_flash_timer_ = nullptr; -#endif +// LED flash timer +uint8_t System::led_flash_gpio_ = 0; +uint8_t System::led_flash_type_ = 0; +uint32_t System::led_flash_start_time_ = 0; +uint32_t System::led_flash_duration_ = 0; +bool System::led_flash_timer_ = false; +// GPIOs std::vector> System::valid_system_gpios_; std::vector> System::used_gpios_; std::vector> System::snapshot_used_gpios_; @@ -310,8 +309,7 @@ void System::get_partition_info() { partition_info_.clear(); // clear existing data #ifdef EMSESP_STANDALONE - // dummy data for standalone mode - // version, size, install_date + // dummy data for standalone mode - version, size, install_date partition_info_["app0"] = {EMSESP_APP_VERSION, 0, ""}; partition_info_["app1"] = {"", 0, ""}; partition_info_["factory"] = {"", 0, ""}; @@ -339,7 +337,7 @@ void System::get_partition_info() { const esp_partition_t * part = esp_partition_get(it); if (part->label != nullptr && part->label[0] != '\0') { - // check if part is valid and not empty + // check if partition is valid and not empty esp_partition_read(part, 0, &buffer, 8); if (buffer == 0xFFFFFFFFFFFFFFFF) { is_valid = false; // skip this partition @@ -351,7 +349,7 @@ void System::get_partition_info() { PartitionInfo p_info; p_info.size = part->size / 1024; // set size in KB - // get version from NVS, if not found, use empty string + // if there is an entry for this partition in NVS, get the version from NVS, if not found, use empty string if (EMSESP::nvs_.isKey(part->label)) { p_info.version = EMSESP::nvs_.getString(part->label).c_str(); } else { @@ -412,14 +410,8 @@ bool System::set_partition(const char * partitionname) { } // restart EMS-ESP -// app0 or app1 -// on 16MB we have the additional boot and factory partitions +// app0 or app1, or boot/factory on 16MB boards void System::system_restart(const char * partitionname) { -#ifdef EMSESP_DEBUG - EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_NORMAL); - return; -#endif - #ifndef EMSESP_STANDALONE // see if we are forcing a partition to use if (partitionname != nullptr) { @@ -656,27 +648,40 @@ void System::button_OnDblClick(PButton & b) { EMSESP::esp32React.getNetworkSettingsService()->callUpdateHandlers(); // in case we've changed ssid or password } -// LED flash timer interrupt service routine -void IRAM_ATTR System::led_flash_timer_isr() { - led_flash_state_ = !led_flash_state_; // Toggle LED state +// LED flash white - every 70ms +void System::led_flash() { + static bool led_flash_state_ = false; + static uint32_t last_toggle_time_ = 0; + uint32_t current_time = uuid::get_uptime(); - if (led_flash_state_) { - led_flash_type_ ? EMSESP_RGB_WRITE(led_flash_gpio_, 255, 255, 255) : digitalWrite(led_flash_gpio_, LED_ON); // white, on - } else { - led_flash_type_ ? EMSESP_RGB_WRITE(led_flash_gpio_, 0, 0, 0) : digitalWrite(led_flash_gpio_, !LED_ON); // off + if (current_time - last_toggle_time_ >= 70) { + led_flash_state_ = !led_flash_state_; + last_toggle_time_ = current_time; + + if (led_flash_type_) { + uint8_t intensity = led_flash_state_ ? 100 : 0; + EMSESP_RGB_WRITE(led_flash_gpio_, intensity, intensity, intensity); // RGB LED + } else { + digitalWrite(led_flash_gpio_, led_flash_state_ ? LED_ON : !LED_ON); // Standard LED + } } - // Increment flash count, 2 toggles = 1 flash cycle. And stop after 5 seconds (5000ms/100ms = 50) - if (led_flash_count_++ >= 50) { - stop_led_flash(); + // after duration, turn off the LED + if (current_time - led_flash_start_time_ >= led_flash_duration_) { + if (led_flash_type_) { + EMSESP_RGB_WRITE(led_flash_gpio_, 0, 0, 0); + } else { + digitalWrite(led_flash_gpio_, !LED_ON); + } + led_flash_timer_ = false; + command_format(nullptr, 0); // Execute format operation } } -// Start the LED flash timer -void System::start_led_flash() { -#ifndef EMSESP_STANDALONE +// Start the LED flash timer - duration in seconds +void System::start_led_flash(uint8_t duration) { // Don't start if already running - if (led_flash_timer_ != nullptr) { + if (led_flash_timer_) { return; } @@ -687,43 +692,21 @@ void System::start_led_flash() { }); // Reset counter and state - led_flash_count_ = 0; - led_flash_state_ = false; - - led_flash_timer_ = timerBegin(0, 80, true); // Create and start timer (prescaler 80 for 1us tick, counting up) - timerAttachInterrupt(led_flash_timer_, &led_flash_timer_isr, true); // Attach interrupt handler - timerAlarmWrite(led_flash_timer_, 100000, true); // Set alarm to trigger every 100ms - timerAlarmEnable(led_flash_timer_); // Enable the alarm -#endif -} - -// Stop the LED flash timer -void System::stop_led_flash() { -#ifndef EMSESP_STANDALONE - if (led_flash_timer_ != nullptr) { - // Stop and detach timer - timerAlarmDisable(led_flash_timer_); - timerDetachInterrupt(led_flash_timer_); - timerEnd(led_flash_timer_); - led_flash_timer_ = nullptr; - led_flash_type_ ? EMSESP_RGB_WRITE(led_flash_gpio_, 0, 0, 0) : digitalWrite(led_flash_gpio_, !LED_ON); // Turn off LED - } -#endif + led_flash_start_time_ = uuid::get_uptime(); // current time + led_flash_duration_ = duration * 1000; // duration in milliseconds + led_flash_timer_ = true; // it's active } // button long press void System::button_OnLongPress(PButton & b) { - LOG_NOTICE("Button pressed - long press - perform factory reset"); - start_led_flash(); // Start the non-blocking LED flash timer for 5 seconds -#ifndef EMSESP_STANDALONE - System::command_format(nullptr, 0); -#endif + LOG_NOTICE("Button pressed - long press - restart EMS-ESP"); + EMSESP::system_.system_restart("boot"); } -// button indefinite press - boots to boot partition +// button indefinite press void System::button_OnVLongPress(PButton & b) { - LOG_NOTICE("Button pressed - very long press - restart from factory/boot partition"); - EMSESP::system_.system_restart("boot"); + LOG_NOTICE("Button pressed - very long press - perform factory reset"); + start_led_flash(5); // Start LED flash timer for 5 seconds } // push button @@ -762,32 +745,38 @@ void System::led_init() { void System::uart_init() { EMSuart::stop(); - - // start UART, GPIOs have already been checked - EMSuart::start(tx_mode_, rx_gpio_, tx_gpio_); - - EMSESP::txservice_.start(); // reset counters and send devices request + EMSuart::start(tx_mode_, rx_gpio_, tx_gpio_); // start UART, GPIOs have already been checked + EMSESP::txservice_.start(); // reset counters and send devices request } // checks system health and handles LED flashing wizardry -void System::loop() { +// returns true if the LED flash is active +bool System::loop() { // check if we're supposed to do a reset/restart if (systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_RESTART_REQUESTED) { system_restart(); } -#ifndef EMSESP_STANDALONE - myPButton_.check(); // check button press + // if LED flashing is active, run the LED flash + if (led_flash_timer_) { + led_flash(); + return true; // is active + } - // syslog + led_monitor(); // check status and report back using the LED + myPButton_.check(); // check button press + system_check(); // check system health + +// syslog +#ifndef EMSESP_STANDALONE if (syslog_enabled_) { syslog_.loop(); } - - led_monitor(); // check status and report back using the LED - system_check(); // check system health - send_info_mqtt(); #endif + + send_info_mqtt(); + + return false; // LED flashing is not active } // send MQTT info topic appended with the version information as JSON, as a retained flag @@ -966,8 +955,9 @@ void System::network_init() { // check health of system, done every 5 seconds void System::system_check() { - if (!last_system_check_ || ((uint32_t)(uuid::get_uptime() - last_system_check_) >= SYSTEM_CHECK_FREQUENCY)) { - last_system_check_ = uuid::get_uptime(); + uint32_t current_uptime = uuid::get_uptime(); + if (!last_system_check_ || ((uint32_t)(current_uptime - last_system_check_) >= SYSTEM_CHECK_FREQUENCY)) { + last_system_check_ = current_uptime; #ifndef EMSESP_STANDALONE #if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 @@ -1051,15 +1041,16 @@ void System::led_monitor() { static bool button_busy_ = false; if (button_busy_ != myPButton_.button_busy()) { button_busy_ = myPButton_.button_busy(); - if (button_busy_) { - led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 255, 255, 255) : digitalWrite(led_gpio_, LED_ON); // on + if (led_type_) { + EMSESP_RGB_WRITE(led_gpio_, button_busy_ ? 100 : 0, button_busy_ ? 100 : 0, button_busy_ ? 100 : 0); } else { - led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); // off + digitalWrite(led_gpio_, button_busy_ ? LED_ON : !LED_ON); } } // we only need to run the LED healthcheck if there are errors - if (!healthcheck_ || !led_gpio_ || button_busy_) { + // skip if we're in the led_flash_timer or if a button has been pressed + if (!healthcheck_ || !led_gpio_ || button_busy_ || led_flash_timer_) { return; // all good } @@ -1092,33 +1083,35 @@ void System::led_monitor() { // 1 flash is the EMS bus is not connected // 2 flashes if the network (wifi or ethernet) is not connected // 3 flashes is both the bus and the network are not connected + + // Cache healthcheck flags to avoid repeated bit operations + bool no_network = (healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK; + bool no_bus = (healthcheck_ & HEALTHCHECK_NO_BUS) == HEALTHCHECK_NO_BUS; + if (led_type_) { if (led_flash_step_ == 3) { - if ((healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK) { + if (no_network) { EMSESP_RGB_WRITE(led_gpio_, RGB_LED_BRIGHTNESS, 0, 0); // red - } else if ((healthcheck_ & HEALTHCHECK_NO_BUS) == HEALTHCHECK_NO_BUS) { + } else if (no_bus) { EMSESP_RGB_WRITE(led_gpio_, 0, 0, RGB_LED_BRIGHTNESS); // blue } } - if (led_flash_step_ == 5 && (healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK) { + if (led_flash_step_ == 5 && no_network) { EMSESP_RGB_WRITE(led_gpio_, RGB_LED_BRIGHTNESS, 0, 0); // red } - if ((led_flash_step_ == 7) && ((healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK) - && ((healthcheck_ & HEALTHCHECK_NO_BUS) == HEALTHCHECK_NO_BUS)) { + if ((led_flash_step_ == 7) && no_network && no_bus) { EMSESP_RGB_WRITE(led_gpio_, 0, 0, RGB_LED_BRIGHTNESS); // blue } } else { - if ((led_flash_step_ == 3) - && (((healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK) || ((healthcheck_ & HEALTHCHECK_NO_BUS) == HEALTHCHECK_NO_BUS))) { + if ((led_flash_step_ == 3) && (no_network || no_bus)) { led_on_ = true; } - if ((led_flash_step_ == 5) && ((healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK)) { + if ((led_flash_step_ == 5) && no_network) { led_on_ = true; } - if ((led_flash_step_ == 7) && ((healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK) - && ((healthcheck_ & HEALTHCHECK_NO_BUS) == HEALTHCHECK_NO_BUS)) { + if ((led_flash_step_ == 7) && no_network && no_bus) { led_on_ = true; } @@ -1231,7 +1224,7 @@ void System::show_system(uuid::console::Shell & shell) { partition.first.c_str(), partition.second.version.c_str(), partition.second.size, - (esp_ota_get_running_partition()->label == partition.first) ? " ** active **" : ""); + (esp_ota_get_running_partition()->label == partition.first) ? "* active *" : ""); } shell.println(); @@ -1423,12 +1416,13 @@ bool System::check_upgrade(bool factory_settings) { } if (factory_settings) { - return false; // fresh install, do nothing + return true; // fresh install, do nothing, no reboot required } version::Semver200_version this_version(EMSESP_APP_VERSION); - bool save_version = true; + bool save_version = true; + bool reboot_required = false; // compare versions if (this_version > settings_version) { @@ -1469,25 +1463,31 @@ bool System::check_upgrade(bool factory_settings) { }); } - // changes to Network - EMSESP::esp32React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) { - // Network Settings Wifi tx_power is now using the value * 4. - if (networkSettings.tx_power == 20) { - networkSettings.tx_power = WIFI_POWER_19_5dBm; // use 19.5 as we don't have 20 anymore - LOG_INFO("Upgrade: Setting WiFi TX Power to Auto"); - } - - // force WiFi sleep to off (was default on < 3.7.0-dev-33) - networkSettings.nosleep = true; - LOG_INFO("Upgrade: Disabling WiFi nosleep"); - - return StateUpdateResult::CHANGED; - }); + // changes pre < v3.7.0 + if (settings_version.major() == 3 && settings_version.minor() < 7) { + // network changes + // 1) WiFi Tx Power is now using the value * 4 (was 20) + // 2) WiFi sleep is now off by default (was on) + EMSESP::esp32React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) { + auto changed = StateUpdateResult::UNCHANGED; + if (networkSettings.tx_power == 20) { + networkSettings.tx_power = WIFI_POWER_19_5dBm; // use 19.5 as we don't have 20 anymore + LOG_INFO("Upgrade: Setting WiFi TX Power to Auto"); + changed = StateUpdateResult::CHANGED; + } + if (networkSettings.nosleep != true) { + networkSettings.nosleep = true; + LOG_INFO("Upgrade: Disabling WiFi nosleep"); + changed = StateUpdateResult::CHANGED; + } + return changed; + }); + } // changes to application settings EMSESP::webSettingsService.update([&](WebSettings & settings) { // force web buffer to 25 for those boards without psram - if (EMSESP::system_.PSram() == 0) { + if ((EMSESP::system_.PSram() == 0) && (settings.weblog_buffer != 25)) { settings.weblog_buffer = 25; return StateUpdateResult::CHANGED; } @@ -1496,24 +1496,27 @@ bool System::check_upgrade(bool factory_settings) { } else if (this_version < settings_version) { - // need downgrade + // downgrading LOG_NOTICE("Downgrading to version %d.%d.%d-%s", this_version.major(), this_version.minor(), this_version.patch(), this_version.prerelease().c_str()); } else { - // same version, do nothing - save_version = false; + save_version = false; // same version, do nothing } - // if we did a change, set the new version and save it, then reboot + // if we did a change, set the new version and save it, no need to reboot if (save_version) { EMSESP::webSettingsService.update([&](WebSettings & settings) { settings.version = EMSESP_APP_VERSION; + LOG_DEBUG("Upgrade: Setting version to %s", EMSESP_APP_VERSION); return StateUpdateResult::CHANGED; }); - // LOG_INFO("Upgrade: Setting version to %s", EMSESP_APP_VERSION); + } + + if (reboot_required) { + LOG_INFO("Upgrade: Rebooting to apply changes"); return true; // need reboot } - return false; + return false; // no reboot required } // convert settings file into json object @@ -1585,6 +1588,16 @@ bool System::command_service(const char * cmd, const char * value) { }); EMSESP::system_.analog_enabled(b); ok = true; + } else if (!strcmp(cmd, "settings/txmode")) { // TODO check + LOG_INFO("Setting TX mode to OFF"); // TODO remove this + EMSESP::webSettingsService.update([&](WebSettings & settings) { + // settings.tx_mode = EMS_TXMODE_OFF; + settings.tx_mode = 0; // TODO remove this + + return StateUpdateResult::CHANGED; + }); + EMSbus::tx_mode(EMS_TXMODE_OFF); + ok = true; } else if (!strcmp(cmd, "mqtt/enabled")) { EMSESP::esp32React.getMqttSettingsService()->update([&](MqttSettings & Settings) { Settings.enabled = b; @@ -1669,9 +1682,11 @@ bool System::get_value_info(JsonObject output, const char * cmd) { if (!strcmp(cmd, F_(entities))) { for (JsonPair p : root) { if (p.value().is()) { + const char * p_key = p.key().c_str(); // Cache the key for (JsonPair p1 : p.value().as()) { - JsonObject entity = output[std::string(p.key().c_str()) + "." + p1.key().c_str()].to(); - get_value_json(entity, p.key().c_str(), p1.key().c_str(), p1.value()); + const char * p1_key = p1.key().c_str(); // Cache the key + JsonObject entity = output[std::string(p_key) + "." + p1_key].to(); + get_value_json(entity, p_key, p1_key, p1.value()); } } } @@ -1706,14 +1721,16 @@ bool System::get_value_info(JsonObject output, const char * cmd) { // Loop through all the key-value pairs in root to find the key, case independent if (slash) { // search the top level first for (JsonPair p : root) { - if (p.value().is() && Helpers::toLower(p.key().c_str()) == cmd) { + const char * p_key = p.key().c_str(); // Cache the key + if (p.value().is() && Helpers::toLower(p_key) == cmd) { for (JsonPair p1 : p.value().as()) { - if (Helpers::toLower(p1.key().c_str()) == slash && !p1.value().is()) { + const char * p1_key = p1.key().c_str(); // Cache the key + if (Helpers::toLower(p1_key) == slash && !p1.value().is()) { if (val) { output["api_data"] = p1.value().as(); return true; } - get_value_json(output, p.key().c_str(), p1.key().c_str(), p1.value()); + get_value_json(output, p_key, p1_key, p1.value()); return true; } } @@ -2256,7 +2273,6 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node["pbuttonGPIO"] = EMSESP::system_.pbutton_gpio_; node["ledGPIO"] = EMSESP::system_.led_gpio_; node["ledType"] = settings.led_type; - node["ledType"] = settings.led_type; } node["hideLed"] = settings.hide_led; node["noTokenApi"] = settings.notoken_api; @@ -2405,12 +2421,15 @@ bool System::load_board_profile(std::vector & data, const std::string & // format command - factory reset, removing all config files bool System::command_format(const char * value, const int8_t id) { -#ifndef EMSESP_STANDALONE +#if !defined(EMSESP_STANDALONE) && !defined(EMSESP_DEBUG) + // don't really format the filesystem in debug or standalone mode if (LittleFS.format()) { LOG_INFO("Filesystem formatted successfully. All config files removed."); } else { LOG_ERROR("Format failed"); } +#else + LOG_INFO("Format command not available in standalone or debug mode"); #endif // restart will be handled by the main loop diff --git a/src/core/system.h b/src/core/system.h index 832fbfef6..48ffa410e 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -89,7 +89,7 @@ struct PartitionInfo { class System { public: void start(); - void loop(); + bool loop(); // returns true if the LED flash is active // commands static bool command_read(const char * value, const int8_t id); @@ -400,24 +400,18 @@ class System { static constexpr uint32_t BUTTON_Debounce = 40; // Debounce period to prevent flickering when pressing or releasing the button (in ms) static constexpr uint32_t BUTTON_DblClickDelay = 250; // Max period between clicks for a double click event (in ms) -// LED flash timer for factory reset -#ifndef EMSESP_STANDALONE - static hw_timer_t * led_flash_timer_; -#endif - static void IRAM_ATTR led_flash_timer_isr(); - static volatile uint8_t led_flash_count_; - static volatile bool led_flash_state_; - static uint8_t led_flash_gpio_; - static uint8_t led_flash_type_; - static void start_led_flash(); - static void stop_led_flash(); + // LED flash timer + static bool led_flash_timer_; + static uint8_t led_flash_gpio_; + static uint8_t led_flash_type_; + static uint32_t led_flash_start_time_; + static uint32_t led_flash_duration_; + static void start_led_flash(uint8_t duration); + static void led_flash(); -#ifdef EMSESP_DEBUG - static constexpr uint32_t BUTTON_LongPressDelay = 2000; // Hold period for a long press event (in ms) - 2 seconds, for debugging -#else - static constexpr uint32_t BUTTON_LongPressDelay = 9500; // Hold period for a long press event (in ms) - ~10 seconds -#endif - static constexpr uint32_t BUTTON_VLongPressDelay = 20000; // Hold period for a very long press event (in ms) - 20 seconds + // button press delays + static constexpr uint32_t BUTTON_LongPressDelay = 3000; // Hold period for a long press event (in ms) - ~3 seconds + static constexpr uint32_t BUTTON_VLongPressDelay = 9500; // Hold period for a very long press event (in ms) - !10 seconds // healthcheck #ifdef EMSESP_PINGTEST From 05baec85b7ae5c1812bf04d2241d02b8fc8607e3 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 10:10:27 +0100 Subject: [PATCH 25/47] implement txenabled system command - #2850 --- lib_standalone/emsuart_standalone.h | 6 ++++++ src/core/emsesp.cpp | 4 ++-- src/core/helpers.cpp | 1 + src/core/locale_common.h | 2 ++ src/core/locale_translations.h | 1 + src/core/shuntingYard.cpp | 26 ++++++++++++++--------- src/core/system.cpp | 33 ++++++++++++++++++++--------- src/core/system.h | 1 + 8 files changed, 52 insertions(+), 22 deletions(-) diff --git a/lib_standalone/emsuart_standalone.h b/lib_standalone/emsuart_standalone.h index dfab52a5c..6146f7372 100644 --- a/lib_standalone/emsuart_standalone.h +++ b/lib_standalone/emsuart_standalone.h @@ -21,6 +21,12 @@ #include "Arduino.h" +#define EMS_TXMODE_OFF 0 +#define EMS_TXMODE_DEFAULT 1 +#define EMS_TXMODE_EMSPLUS 2 +#define EMS_TXMODE_HT3 3 +#define EMS_TXMODE_HW 4 + namespace emsesp { #define EMS_TX_STATUS_ERR 0 diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index be82dd158..e7add50b0 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -1813,9 +1813,9 @@ void EMSESP::shell_prompt() { void EMSESP::loop() { uuid::loop(); // store system uptime - // does LED and checks system health, and syslog service + // handles LED and checks system health, and syslog service if (system_.loop()) { - return; // LED flashing is active + return; // LED flashing is active, skip the rest of the loop } esp32React.loop(); // web services diff --git a/src/core/helpers.cpp b/src/core/helpers.cpp index 207167ac8..9bd6d3d27 100644 --- a/src/core/helpers.cpp +++ b/src/core/helpers.cpp @@ -696,6 +696,7 @@ bool Helpers::value2string(const char * value, std::string & value_s) { // checks to see if a string (usually a command or payload cmd) looks like a boolean // on, off, true, false, 1, 0 +// uses translated words for on/off bool Helpers::value2bool(const char * value, bool & value_b) { if ((value == nullptr) || (strlen(value) == 0)) { return false; diff --git a/src/core/locale_common.h b/src/core/locale_common.h index 26ec0eb5c..c9c2de3c1 100644 --- a/src/core/locale_common.h +++ b/src/core/locale_common.h @@ -42,6 +42,7 @@ MAKE_WORD(system) MAKE_WORD(fetch) MAKE_WORD(restart) MAKE_WORD(format) +MAKE_WORD(txenabled) MAKE_WORD(raw) MAKE_WORD(watch) MAKE_WORD(syslog) @@ -168,6 +169,7 @@ MAKE_WORD_CUSTOM(password_prompt, "Password: ") MAKE_WORD_CUSTOM(unset, "") MAKE_WORD_CUSTOM(enable_mandatory, "") MAKE_WORD_CUSTOM(service_mandatory, "") +MAKE_WORD_CUSTOM(txenabled_cmd, "enable/disable TX") // more common names that don't need translations MAKE_NOTRANSLATION(1x3min, "1x3min") diff --git a/src/core/locale_translations.h b/src/core/locale_translations.h index b6470c8de..85d50d4ac 100644 --- a/src/core/locale_translations.h +++ b/src/core/locale_translations.h @@ -71,6 +71,7 @@ MAKE_WORD_TRANSLATION(changeloglevel_cmd, "change log level", "Ändere Protokoll MAKE_WORD_TRANSLATION(fetch_cmd, "refresh all EMS values", "Aktualisiere alle EMS-Werte", "Verversen alle EMS waardes", "uppdatera alla EMS-värden", "odśwież wszystkie wartości EMS", "oppfrisk alle EMS verdier", "", "Bütün EMS değerlerini yenile", "aggiornare tutti i valori EMS", "obnoviť všetky hodnoty EMS", "aktualizovat všechny EMS hodnoty") // TODO translate MAKE_WORD_TRANSLATION(restart_cmd, "restart EMS-ESP", "Neustart", "opnieuw opstarten", "starta om EMS-ESP", "uruchom ponownie EMS-ESP", "restart EMS-ESP", "redémarrer EMS-ESP", "EMS-ESPyi yeniden başlat", "riavvia EMS-ESP", "reštart EMS-ESP", "restartovat EMS-ESP") // TODO translate MAKE_WORD_TRANSLATION(format_cmd, "factory reset EMS-ESP", "EMS-ESP auf Werkseinstellungen zurücksetzen", "fabriksåterställ EMS-ESP", "", "", "", "", "", "", "továrenske nastavenie EMS-ESP", "tovární nastavení EMS-ESP") // TODO translate +MAKE_WORD_TRANSLATION(txenabled_cmd, "enable/disable TX", "TX aktivieren/deaktivieren", "TX inschakelen/uitschakelen", "aktivera/inaktivera TX", "włącz/wyłącz TX", "aktiver/deaktiver TX", "", "TX'i etkinleştir/devre dışı bırak", "abilita/disabilita TX", "povoliť/zakázať TX", "povolit/zakázat TX") // TODO translate MAKE_WORD_TRANSLATION(watch_cmd, "watch incoming telegrams", "Beobachte eingehende Telegramme", "inkomende telegrammen bekijken", "visa inkommande telegram", "obserwuj przyczodzące telegramy", "se innkommende telegrammer", "", "Gelen telegramları", "guardare i telegrammi in arrivo", "sledovať prichádzajúce telegramy", "sledovat příchozí telegramy") // TODO translate MAKE_WORD_TRANSLATION(publish_cmd, "publish all to MQTT", "Publiziere MQTT", "publiceer alles naar MQTT", "publicera allt till MQTT", "opublikuj wszystko na MQTT", "Publiser alt til MQTT", "", "Hepsini MQTTye gönder", "pubblica tutto su MQTT", "zverejniť všetko na MQTT", "publikovat vše do MQTT") // TODO translate MAKE_WORD_TRANSLATION(system_info_cmd, "show system info", "Zeige Systeminformationen", "toon systeemstatus", "visa systeminformation", "pokaż status systemu", "vis system status", "", "Sistem Durumunu Göster", "visualizza stati di sistema", "zobraziť stav systému", "zobrazit informace o systému") // TODO translate diff --git a/src/core/shuntingYard.cpp b/src/core/shuntingYard.cpp index 703befea0..62e738bfb 100644 --- a/src/core/shuntingYard.cpp +++ b/src/core/shuntingYard.cpp @@ -399,17 +399,23 @@ std::string commands(std::string & expr, bool quotes) { // checks for logic value int to_logic(const std::string & s) { - if (s.empty()) { - return -1; + bool value_b; + if (!Helpers::value2bool(s.c_str(), value_b)) { + return -1; // invalid } - auto l = Helpers::toLower(s); - if (s[0] == '1' || l == "on" || l == "true") { - return 1; - } - if (s[0] == '0' || l == "off" || l == "false") { - return 0; - } - return -1; + return value_b; + + // if (s.empty()) { + // return -1; + // } + // auto l = Helpers::toLower(s); + // if (s[0] == '1' || l == "on" || l == "true") { + // return 1; + // } + // if (s[0] == '0' || l == "off" || l == "false") { + // return 0; + // } + // return -1; } // number to string, remove trailing zeros diff --git a/src/core/system.cpp b/src/core/system.cpp index c4bafad06..1860db32b 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1019,6 +1019,7 @@ void System::commands_init() { Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, FL_(fetch_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(format), System::command_format, FL_(format_cmd), CommandFlag::ADMIN_ONLY); + Command::add(EMSdevice::DeviceType::SYSTEM, F_(txenabled), System::command_txenabled, FL_(txenabled_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, FL_(watch_cmd)); Command::add(EMSdevice::DeviceType::SYSTEM, F_(message), System::command_message, FL_(message_cmd)); #if defined(EMSESP_TEST) @@ -1588,16 +1589,6 @@ bool System::command_service(const char * cmd, const char * value) { }); EMSESP::system_.analog_enabled(b); ok = true; - } else if (!strcmp(cmd, "settings/txmode")) { // TODO check - LOG_INFO("Setting TX mode to OFF"); // TODO remove this - EMSESP::webSettingsService.update([&](WebSettings & settings) { - // settings.tx_mode = EMS_TXMODE_OFF; - settings.tx_mode = 0; // TODO remove this - - return StateUpdateResult::CHANGED; - }); - EMSbus::tx_mode(EMS_TXMODE_OFF); - ok = true; } else if (!strcmp(cmd, "mqtt/enabled")) { EMSESP::esp32React.getMqttSettingsService()->update([&](MqttSettings & Settings) { Settings.enabled = b; @@ -2419,6 +2410,28 @@ bool System::load_board_profile(std::vector & data, const std::string & return true; } +// txenabled command - temporarily pause the TX, setting Txmode to 0 +bool System::command_txenabled(const char * value, const int8_t id) { + bool arg; + if (!Helpers::value2bool(value, arg)) { + return false; // argument not recognized + } + if (arg) { + // if the TX mode is already off, revert back to the saved setting + if (EMSbus::tx_mode() == EMS_TXMODE_OFF) { + EMSESP::webSettingsService.read([&](WebSettings & settings) { + EMSbus::tx_mode(settings.tx_mode); + LOG_INFO("TX mode restored"); + }); + } else { + // otherwise set it to off + EMSbus::tx_mode(EMS_TXMODE_OFF); + LOG_INFO("TX mode set to OFF"); + } + } + return true; +} + // format command - factory reset, removing all config files bool System::command_format(const char * value, const int8_t id) { #if !defined(EMSESP_STANDALONE) && !defined(EMSESP_DEBUG) diff --git a/src/core/system.h b/src/core/system.h index 48ffa410e..6a0f4549c 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -103,6 +103,7 @@ class System { static bool command_info(const char * value, const int8_t id, JsonObject output); static bool command_response(const char * value, const int8_t id, JsonObject output); static bool command_service(const char * cmd, const char * value); + static bool command_txenabled(const char * value, const int8_t id); static bool get_value_info(JsonObject root, const char * cmd); static void get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val); From cc041510bee74748a4137f39e3fd2a30c89f87c2 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 10:18:58 +0100 Subject: [PATCH 26/47] fixes install time in NVS --- src/core/system.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 1860db32b..46ccc6f8a 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -347,23 +347,22 @@ void System::get_partition_info() { // get the version from the NVS store, and add to map if (is_valid) { PartitionInfo p_info; - p_info.size = part->size / 1024; // set size in KB + // default partition info + p_info.version = ""; + p_info.install_date = ""; + p_info.size = part->size / 1024; // set size in KB // if there is an entry for this partition in NVS, get the version from NVS, if not found, use empty string if (EMSESP::nvs_.isKey(part->label)) { p_info.version = EMSESP::nvs_.getString(part->label).c_str(); - } else { - p_info.version = ""; } // get install date from NTP if active and add if (ntp_connected_) { char time_string[25]; - time_t now = time(nullptr) - uuid::get_uptime_sec(); - strftime(time_string, sizeof(time_string), "%FT%T%z", localtime(&now)); + time_t now = time(nullptr); + strftime(time_string, sizeof(time_string), "%FT%T", localtime(&now)); p_info.install_date = time_string; - } else { - p_info.install_date = ""; } partition_info_[part->label] = p_info; From 5b8dd0a693631c68e6a472755c2a33fffd5acfad Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 11:56:48 +0100 Subject: [PATCH 27/47] msgpack update --- mock-api/package.json | 2 +- mock-api/pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mock-api/package.json b/mock-api/package.json index 2e0e4c3aa..f2b33531f 100644 --- a/mock-api/package.json +++ b/mock-api/package.json @@ -9,7 +9,7 @@ "format": "prettier -l -w '**/*.{ts,tsx,js,css,json,md}'" }, "dependencies": { - "@msgpack/msgpack": "^3.1.2", + "@msgpack/msgpack": "^3.1.3", "@trivago/prettier-plugin-sort-imports": "^6.0.0", "formidable": "^3.5.4", "itty-router": "^5.0.22", diff --git a/mock-api/pnpm-lock.yaml b/mock-api/pnpm-lock.yaml index ac74c52ec..0151c466c 100644 --- a/mock-api/pnpm-lock.yaml +++ b/mock-api/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@msgpack/msgpack': - specifier: ^3.1.2 - version: 3.1.2 + specifier: ^3.1.3 + version: 3.1.3 '@trivago/prettier-plugin-sort-imports': specifier: ^6.0.0 version: 6.0.0(prettier@3.7.4) @@ -76,8 +76,8 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@msgpack/msgpack@3.1.2': - resolution: {integrity: sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==} + '@msgpack/msgpack@3.1.3': + resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==} engines: {node: '>= 18'} '@noble/hashes@1.8.0': @@ -238,7 +238,7 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@msgpack/msgpack@3.1.2': {} + '@msgpack/msgpack@3.1.3': {} '@noble/hashes@1.8.0': {} From 1ede7028a5a77431b3d75991be19e864ef024f0d Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 12:06:31 +0100 Subject: [PATCH 28/47] add back missing webLogService.loop() --- src/core/emsesp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index e7add50b0..0c5d030bd 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -1818,7 +1818,8 @@ void EMSESP::loop() { return; // LED flashing is active, skip the rest of the loop } - esp32React.loop(); // web services + esp32React.loop(); // web services like network, AP, MQTT + webLogService.loop(); // log in Web UI // run the loop, unless we're in the middle of an OTA upload if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_NORMAL || EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO) { From 8c831ac0e9f33f4fba285f55eec2e2894fb5b4ee Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 13:33:38 +0100 Subject: [PATCH 29/47] only update partition info on boot --- src/web/WebStatusService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index bc93d0dc0..48680e915 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -147,7 +147,7 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) { } // get the partition info for each partition, including the running one - EMSESP::system_.get_partition_info(); + // the partition data is done once in System::start() and stored in partition_info_ JsonArray partitions = root["partitions"].to(); for (const auto & partition : EMSESP::system_.partition_info_) { // Skip partition if it has no version, or it's size is 0 From d30375f3c484e200d5d461ba5c77ac0e59ca0a7f Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 13:34:02 +0100 Subject: [PATCH 30/47] set_partition_install_date - when NVS connects --- src/core/system.cpp | 51 ++++++++++++++++++++++++++++++--------------- src/core/system.h | 2 ++ 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index 46ccc6f8a..b7efae044 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -318,7 +318,7 @@ void System::get_partition_info() { auto current_partition = (const char *)esp_ota_get_running_partition()->label; - // update the current version and partition name in NVS, if needed (to save on flash wearing) + // update the current version and partition name in NVS if not already set (saves on flash wearing) if (EMSESP::nvs_.isKey(current_partition)) { if (EMSESP::nvs_.getString(current_partition) != EMSESP_APP_VERSION) { EMSESP::nvs_.putString(current_partition, EMSESP_APP_VERSION); @@ -347,33 +347,44 @@ void System::get_partition_info() { // get the version from the NVS store, and add to map if (is_valid) { PartitionInfo p_info; - // default partition info p_info.version = ""; - p_info.install_date = ""; - p_info.size = part->size / 1024; // set size in KB + p_info.install_date = ""; // this will be added later when NTP is connected - // if there is an entry for this partition in NVS, get the version from NVS, if not found, use empty string + p_info.size = part->size / 1024; // set size in KB + + // if there is an entry for this partition in NVS, get it's version from NVS if (EMSESP::nvs_.isKey(part->label)) { p_info.version = EMSESP::nvs_.getString(part->label).c_str(); } - // get install date from NTP if active and add - if (ntp_connected_) { - char time_string[25]; - time_t now = time(nullptr); - strftime(time_string, sizeof(time_string), "%FT%T", localtime(&now)); - p_info.install_date = time_string; - } - partition_info_[part->label] = p_info; } - it = esp_partition_next(it); + it = esp_partition_next(it); // loop to next partition } esp_partition_iterator_release(it); #endif } +// set NTP install time/date for the current partition +// assumes NTP is connected and working +void System::set_partition_install_date(bool override) { +#ifndef EMSESP_STANDALONE + auto current_partition = (const char *)esp_ota_get_running_partition()->label; + // skip if it already has an install date + if (!partition_info_[current_partition].install_date.empty() && !override) { + return; + } + + // set current date/time from NTP + char time_string[25]; + time_t now = time(nullptr); + strftime(time_string, sizeof(time_string), "%FT%T", localtime(&now)); + partition_info_[current_partition].install_date = time_string; + LOG_DEBUG("Adding NTP install date %s to partition %s", time_string, current_partition); +#endif +} + // sets the partition to use on the next restart bool System::set_partition(const char * partitionname) { #ifdef EMSESP_STANDALONE @@ -570,7 +581,7 @@ void System::store_settings(WebSettings & settings) { developer_mode_ = settings.developer_mode; } -// Starts up the UART Serial bridge +// Starts up core services void System::start() { get_partition_info(); // get the partition info @@ -1220,11 +1231,12 @@ void System::show_system(uuid::console::Shell & shell) { if (partition.second.version.empty()) { continue; // no version, empty string } - shell.printfln(" %s: v%s (%d KB) %s", + shell.printfln(" %s: v%s (%d KB%s) %s", partition.first.c_str(), partition.second.version.c_str(), partition.second.size, - (esp_ota_get_running_partition()->label == partition.first) ? "* active *" : ""); + partition.second.install_date.empty() ? "" : (std::string(", installed ") + partition.second.install_date).c_str(), + (strcmp(esp_ota_get_running_partition()->label, partition.first.c_str()) == 0) ? "** active **" : ""); } shell.println(); @@ -2515,6 +2527,11 @@ void System::ntp_connected(bool b) { if (b != ntp_connected_) { if (b) { LOG_INFO("NTP connected"); +#ifdef EMSESP_DEBUG // reset the install date on startup if in debug mode + set_partition_install_date(true); +#else + set_partition_install_date(false); +#endif } else { LOG_WARNING("NTP disconnected"); // if turned off report it } diff --git a/src/core/system.h b/src/core/system.h index 6a0f4549c..aa5995978 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -392,6 +392,8 @@ class System { uint8_t systemStatus_; // uses SYSTEM_STATUS enum + void set_partition_install_date(bool override = false); + // button static PButton myPButton_; // PButton instance static void button_OnClick(PButton & b); From 4772a61e7c45cf9db6ff39da7324e167e382944d Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 15:24:56 +0100 Subject: [PATCH 31/47] use EMS_TXMODE_INIT --- src/uart/emsuart_esp32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index b4f5ff692..3e1659e09 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -109,7 +109,7 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t // Stop, disable interrupt void EMSuart::stop() { - if (tx_mode_ != 0xFF) { // only call after driver initialisation + if (tx_mode_ != EMS_TXMODE_INIT) { // only call after driver initialisation uart_disable_intr_mask(EMSUART_NUM, UART_BRK_DET_INT_ENA | UART_RXFIFO_FULL_INT_ENA); vTaskSuspend(xHandle); } From 2b6606d8addae3a1642044e2b3245b1c13f55e5a Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 15:25:41 +0100 Subject: [PATCH 32/47] disable uart when uploading, show when uploading, store flag showing its a new firmware --- src/ESP32React/UploadFileService.cpp | 22 ++++++++++++++++++++-- src/core/emsesp.cpp | 5 +++++ src/core/emsesp.h | 2 ++ src/core/system.cpp | 14 ++++++++++++-- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/ESP32React/UploadFileService.cpp b/src/ESP32React/UploadFileService.cpp index 88b1aa436..7a0312e6e 100644 --- a/src/ESP32React/UploadFileService.cpp +++ b/src/ESP32React/UploadFileService.cpp @@ -3,6 +3,7 @@ #include #include +#include static String getFilenameExtension(const String & filename) { const auto pos = filename.lastIndexOf('.'); @@ -81,6 +82,10 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri } #endif // it's firmware - initialize the ArduinoOTA updater + emsesp::EMSESP::logger().info("Uploading firmware file %s (size: %d bytes)", filename.c_str(), filesize); + // turn off UART to prevent interference with the upload + emsesp::EMSuart::stop(); + if (Update.begin(filesize - sizeof(esp_image_header_t))) { if (strlen(_md5.data()) == _md5.size() - 1) { Update.setMD5(_md5.data()); @@ -113,6 +118,8 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri } void UploadFileService::uploadComplete(AsyncWebServerRequest * request) { + emsesp::EMSESP::logger().info("Upload complete"); + // did we just complete uploading a json file? if (request->_tempFile) { request->_tempFile.close(); // close the file handle as the upload is now done @@ -126,6 +133,10 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) { // check if it was a firmware upgrade // if no error, send the success response as a JSON if (_is_firmware && !request->_tempObject) { + // set NVS to tell EMS-ESP this is a new firmware on next restart + // we do this by removing the install date + emsesp::EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, true); + AsyncWebServerResponse * response = request->beginResponse(200); request->send(response); emsesp::EMSESP::system_.systemStatus( @@ -147,6 +158,9 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) { } void UploadFileService::handleError(AsyncWebServerRequest * request, int code) { + emsesp::EMSESP::logger().info("Upload error: %d", code); + emsesp::EMSESP::system_.uart_init(); // re-enable UART + // if we have had an error already, do nothing if (request->_tempObject) { return; @@ -156,15 +170,19 @@ void UploadFileService::handleError(AsyncWebServerRequest * request, int code) { AsyncWebServerResponse * response = request->beginResponse(code); request->send(response); - // check for invalid extension and immediately kill the connection, which will through an error + // check for invalid extension and immediately kill the connection, which will throw an error // that is caught by the web code. Unfortunately the http error code is not sent to the client on fast network connections if (code == 406) { request->client()->close(true); - handleEarlyDisconnect(); + _is_firmware = false; + Update.abort(); } } void UploadFileService::handleEarlyDisconnect() { + emsesp::EMSESP::logger().info("Upload aborted"); + emsesp::EMSESP::system_.uart_init(); // re-enable UART + _is_firmware = false; Update.abort(); } diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index 0c5d030bd..9754ca180 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -1720,6 +1720,11 @@ void EMSESP::start() { #else LOG_INFO("EMS-ESP version %s", EMSESP_APP_VERSION); #endif + + if (!EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE)) { + LOG_DEBUG("Firmware is fresh"); + } + LOG_DEBUG("System is running in Debug mode"); LOG_INFO("Last system reset reason Core0: %s, Core1: %s", system_.reset_reason(0).c_str(), system_.reset_reason(1).c_str()); diff --git a/src/core/emsesp.h b/src/core/emsesp.h index 5fe7cfb99..c094f7f7a 100644 --- a/src/core/emsesp.h +++ b/src/core/emsesp.h @@ -96,6 +96,8 @@ using DeviceValueNumOp = DeviceValue::DeviceValueNumOp; class EMSESPShell; class Shower; +static constexpr const char * EMSESP_NVS_BOOT_NEW_FIRMWARE = "fresh_firmware"; // max 15 characters + class EMSESP { public: EMSESP(); diff --git a/src/core/system.cpp b/src/core/system.cpp index b7efae044..f9e7ce6f4 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -371,11 +371,21 @@ void System::get_partition_info() { void System::set_partition_install_date(bool override) { #ifndef EMSESP_STANDALONE auto current_partition = (const char *)esp_ota_get_running_partition()->label; - // skip if it already has an install date - if (!partition_info_[current_partition].install_date.empty() && !override) { + auto is_fresh_firmware = EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE); + + // reset flag after setting the install date + EMSESP::nvs_.putBool(EMSESP_NVS_BOOT_NEW_FIRMWARE, false); + + // skip if it already has an install date, unless override is true or the firmware is new + // EMSESP_NVS_BOOT_NEW_FIRMWARE is set in UploadFileService::uploadComplete() + if (!partition_info_[current_partition].install_date.empty() && !override && !is_fresh_firmware) { return; } + if (is_fresh_firmware) { + LOG_DEBUG("Firmware is fresh, setting the new install date"); + } + // set current date/time from NTP char time_string[25]; time_t now = time(nullptr); From 85ef8d7d50efe895dd77980448462f270c21b9ec Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 15:28:03 +0100 Subject: [PATCH 33/47] text changes --- src/ESP32React/UploadFileService.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ESP32React/UploadFileService.cpp b/src/ESP32React/UploadFileService.cpp index 7a0312e6e..6add611bb 100644 --- a/src/ESP32React/UploadFileService.cpp +++ b/src/ESP32React/UploadFileService.cpp @@ -118,7 +118,7 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri } void UploadFileService::uploadComplete(AsyncWebServerRequest * request) { - emsesp::EMSESP::logger().info("Upload complete"); + emsesp::EMSESP::logger().info("Upload successful"); // did we just complete uploading a json file? if (request->_tempFile) { @@ -180,7 +180,7 @@ void UploadFileService::handleError(AsyncWebServerRequest * request, int code) { } void UploadFileService::handleEarlyDisconnect() { - emsesp::EMSESP::logger().info("Upload aborted"); + emsesp::EMSESP::logger().info("Upload ended"); emsesp::EMSESP::system_.uart_init(); // re-enable UART _is_firmware = false; From 84bbd932167dc210a863537ebfc5e9913121c8fe Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 16:24:46 +0100 Subject: [PATCH 34/47] fix standalone --- lib_standalone/Preferences.h | 39 ++++++++++++++++++++---------------- src/core/emsesp.cpp | 3 +++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/lib_standalone/Preferences.h b/lib_standalone/Preferences.h index 227893420..07f24e8be 100644 --- a/lib_standalone/Preferences.h +++ b/lib_standalone/Preferences.h @@ -12,8 +12,8 @@ class Preferences { bool _readOnly; public: - Preferences(){}; - ~Preferences(){}; + Preferences() {}; + ~Preferences() {}; bool begin(const char * name, bool readOnly = false, const char * partition_label = NULL) { return true; @@ -26,44 +26,49 @@ class Preferences { return true; } + int getChar(const char * key, uint8_t defaultValue = 0) { + return 0; + } size_t putChar(const char * key, int8_t value) { return 0; } - size_t putUChar(const char * key, uint8_t value) { - return 0; - } - - size_t putDouble(const char * key, double value) { - return 0; - } uint8_t getUChar(const char * key, uint8_t defaultValue = 0) { return 0; } - - int getChar(const char * key, uint8_t defaultValue = 0) { + size_t putUChar(const char * key, uint8_t value) { return 0; } double getDouble(const char * key, double defaultValue = NAN) { return 0; } - - size_t putString(const char * key, const char * value) { + size_t putDouble(const char * key, double value) { return 0; } - size_t putString(const char * key, String value) { + + bool getBool(const char * key, bool defaultValue = false) { + return true; + } + size_t putBool(const char * key, bool value) { + return 0; + } + + String getString(const char * key, String defaultValue = String()) { + return ""; + } + size_t putString(const char * key, const char * value) { return 0; } size_t getString(const char * key, char * value, size_t maxLen) { return 0; } - String getString(const char * key, String defaultValue = String()) { - return ""; + size_t putString(const char * key, String value) { + return 0; } - // unused + // unused.... // void end(); // bool clear(); diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index 9754ca180..adf1c776e 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -1721,6 +1721,9 @@ void EMSESP::start() { LOG_INFO("EMS-ESP version %s", EMSESP_APP_VERSION); #endif + // check if the firmware is fresh + // this is set in UploadFileService::uploadComplete() + // and reset in System::set_partition_install_date() if (!EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE)) { LOG_DEBUG("Firmware is fresh"); } From 364f66b7d4ed6e58794b9fb9675833567a506e23 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 16:55:05 +0100 Subject: [PATCH 35/47] updated comment --- src/ESP32React/UploadFileService.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ESP32React/UploadFileService.cpp b/src/ESP32React/UploadFileService.cpp index 6add611bb..c86a6e31c 100644 --- a/src/ESP32React/UploadFileService.cpp +++ b/src/ESP32React/UploadFileService.cpp @@ -133,8 +133,7 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) { // check if it was a firmware upgrade // if no error, send the success response as a JSON if (_is_firmware && !request->_tempObject) { - // set NVS to tell EMS-ESP this is a new firmware on next restart - // we do this by removing the install date + // set NVS to tell EMS-ESP this is a new fresh firmware on next restart emsesp::EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, true); AsyncWebServerResponse * response = request->beginResponse(200); From 6746df37a131fd2e3991383dadee4a11caa24a60 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 26 Dec 2025 17:10:26 +0100 Subject: [PATCH 36/47] updated logic on fresh firmware install --- src/core/system.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index f9e7ce6f4..f7bca253e 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -371,19 +371,25 @@ void System::get_partition_info() { void System::set_partition_install_date(bool override) { #ifndef EMSESP_STANDALONE auto current_partition = (const char *)esp_ota_get_running_partition()->label; - auto is_fresh_firmware = EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE); + if (current_partition == nullptr) { + return; // fail-safe + } - // reset flag after setting the install date - EMSESP::nvs_.putBool(EMSESP_NVS_BOOT_NEW_FIRMWARE, false); - - // skip if it already has an install date, unless override is true or the firmware is new - // EMSESP_NVS_BOOT_NEW_FIRMWARE is set in UploadFileService::uploadComplete() - if (!partition_info_[current_partition].install_date.empty() && !override && !is_fresh_firmware) { + // skip if it already has an install date, unless override is true + if (!partition_info_[current_partition].install_date.empty() && !override) { return; } + // EMSESP_NVS_BOOT_NEW_FIRMWARE is set in UploadFileService::uploadComplete() + auto is_fresh_firmware = EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE); + // always reset flag after setting the install date + EMSESP::nvs_.putBool(EMSESP_NVS_BOOT_NEW_FIRMWARE, false); + + // check if the firmware is a new upload if (is_fresh_firmware) { - LOG_DEBUG("Firmware is fresh, setting the new install date"); + LOG_DEBUG("Firmware is fresh, setting the new install date in partition %s", current_partition); + } else { + return; // skip, not new } // set current date/time from NTP From 2a36f378b44b04cea70578c1292a1977c67dd459 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 27 Dec 2025 10:24:35 +0100 Subject: [PATCH 37/47] auto-formatting --- mock-api/restServer.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/mock-api/restServer.ts b/mock-api/restServer.ts index bc51cbd9f..c5974d417 100644 --- a/mock-api/restServer.ts +++ b/mock-api/restServer.ts @@ -300,10 +300,10 @@ function updateMask(entity: any, de: any, dd: any) { const old_custom_name = dd.nodes[dd_objIndex].cn; console.log( 'comparing names, old (' + - old_custom_name + - ') with new (' + - new_custom_name + - ')' + old_custom_name + + ') with new (' + + new_custom_name + + ')' ); if (old_custom_name !== new_custom_name) { changed = true; @@ -399,15 +399,15 @@ function check_upgrade(version: string) { console.log( 'Upgrade this version (' + - THIS_VERSION + - ') to dev (' + - dev_version + - ') is ' + - (DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + - ' and to stable (' + - stable_version + - ') is ' + - (STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + THIS_VERSION + + ') to dev (' + + dev_version + + ') is ' + + (DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + + ' and to stable (' + + stable_version + + ') is ' + + (STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') ); data = { emsesp_version: THIS_VERSION, From b8b8a501e1641919d7e58f1bfdfa6282751cf00f Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 27 Dec 2025 10:24:43 +0100 Subject: [PATCH 38/47] package update --- interface/pnpm-lock.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index ed529379e..74710a1ed 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -2884,8 +2884,8 @@ packages: resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} engines: {node: '>=0.10.0'} - ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + ts-api-utils@2.2.0: + resolution: {integrity: sha512-L6f5oQRAoLU1RwXz0Ab9mxsE7LtxeVB6AIR1lpkZMsOyg/JXeaxBaXa/FVCBZyNr9S9I4wkHrlZTklX+im+WMw==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -3814,7 +3814,7 @@ snapshots: eslint: 9.39.2 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.2.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -3856,7 +3856,7 @@ snapshots: '@typescript-eslint/utils': 8.50.1(eslint@9.39.2)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.2 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.2.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -3873,7 +3873,7 @@ snapshots: minimatch: 9.0.5 semver: 7.7.3 tinyglobby: 0.2.15 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.2.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -5882,7 +5882,7 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - ts-api-utils@2.1.0(typescript@5.9.3): + ts-api-utils@2.2.0(typescript@5.9.3): dependencies: typescript: 5.9.3 From 8d39893e5e5654c1825d76906881e8145329cdc2 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 27 Dec 2025 10:58:08 +0100 Subject: [PATCH 39/47] use Yellow RGB for flash and button --- src/core/system.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index f7bca253e..dc45af370 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -674,19 +674,19 @@ void System::button_OnDblClick(PButton & b) { EMSESP::esp32React.getNetworkSettingsService()->callUpdateHandlers(); // in case we've changed ssid or password } -// LED flash white - every 70ms +// LED flash every 100ms void System::led_flash() { static bool led_flash_state_ = false; static uint32_t last_toggle_time_ = 0; uint32_t current_time = uuid::get_uptime(); - if (current_time - last_toggle_time_ >= 70) { + if (current_time - last_toggle_time_ >= 100) { // every 100ms led_flash_state_ = !led_flash_state_; last_toggle_time_ = current_time; if (led_flash_type_) { - uint8_t intensity = led_flash_state_ ? 100 : 0; - EMSESP_RGB_WRITE(led_flash_gpio_, intensity, intensity, intensity); // RGB LED + uint8_t intensity = led_flash_state_ ? RGB_LED_BRIGHTNESS : 0; + EMSESP_RGB_WRITE(led_flash_gpio_, intensity, intensity, 0); // RGB LED - Yellow } else { digitalWrite(led_flash_gpio_, led_flash_state_ ? LED_ON : !LED_ON); // Standard LED } @@ -1024,11 +1024,13 @@ void System::system_check() { // see if we're better now if (healthcheck_ == 0) { // everything is healthy, show LED permanently on or off depending on setting + // Green on RGB LED, on/off on standard LED if (led_gpio_) { - led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, hide_led_ ? 0 : RGB_LED_BRIGHTNESS, 0) : digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); + led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, hide_led_ ? 0 : RGB_LED_BRIGHTNESS, 0) + : digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); // Green } } else { - // turn off LED so we're ready to the flashes + // turn off LED so we're ready for the warning flashes if (led_gpio_) { led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); } @@ -1060,16 +1062,13 @@ void System::commands_init() { } // uses LED to show system health -// 1 x flash = the EMS bus is not connected -// 2 x flash = the network (wifi or ethernet) is not connected -// 3 x flash = both EMS bus and network are failing. This is a critical error! void System::led_monitor() { - // check if button is busy or has been pressed - LED on to white + // if button is pressed, show LED (yellow on RGB LED, on/off on standard LED) static bool button_busy_ = false; if (button_busy_ != myPButton_.button_busy()) { button_busy_ = myPButton_.button_busy(); if (led_type_) { - EMSESP_RGB_WRITE(led_gpio_, button_busy_ ? 100 : 0, button_busy_ ? 100 : 0, button_busy_ ? 100 : 0); + EMSESP_RGB_WRITE(led_gpio_, button_busy_ ? RGB_LED_BRIGHTNESS : 0, button_busy_ ? RGB_LED_BRIGHTNESS : 0, 0); // Yellow } else { digitalWrite(led_gpio_, button_busy_ ? LED_ON : !LED_ON); } @@ -1107,11 +1106,10 @@ void System::led_monitor() { led_type_ ? EMSESP_RGB_WRITE(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); // LED off } else if (led_flash_step_ % 2) { // handle the step events (on odd numbers 3,5,7,etc). see if we need to turn on a LED - // 1 flash is the EMS bus is not connected - // 2 flashes if the network (wifi or ethernet) is not connected - // 3 flashes is both the bus and the network are not connected + // 1 flash (blue) is the EMS bus is not connected + // 2 flashes (red) if the network (wifi or ethernet) is not connected + // 3 flashes (red, red, blue) is both the bus and the network are not connected - // Cache healthcheck flags to avoid repeated bit operations bool no_network = (healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK; bool no_bus = (healthcheck_ & HEALTHCHECK_NO_BUS) == HEALTHCHECK_NO_BUS; From dfe95296d9eaf0e8abeb8b31d462d6f03afcfa57 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 27 Dec 2025 11:20:30 +0100 Subject: [PATCH 40/47] fix txmode on/off logic --- src/core/system.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/core/system.cpp b/src/core/system.cpp index dc45af370..736351b46 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -2441,17 +2441,21 @@ bool System::command_txenabled(const char * value, const int8_t id) { if (!Helpers::value2bool(value, arg)) { return false; // argument not recognized } + if (arg) { - // if the TX mode is already off, revert back to the saved setting + // Tx mode on + // if the TX mode was off, revert back to the saved setting if (EMSbus::tx_mode() == EMS_TXMODE_OFF) { EMSESP::webSettingsService.read([&](WebSettings & settings) { EMSbus::tx_mode(settings.tx_mode); - LOG_INFO("TX mode restored"); + LOG_INFO("TX mode restored (value %d)", settings.tx_mode); }); - } else { - // otherwise set it to off + } + } else { + // Tx mode off + if (EMSbus::tx_mode() != EMS_TXMODE_OFF) { EMSbus::tx_mode(EMS_TXMODE_OFF); - LOG_INFO("TX mode set to OFF"); + LOG_INFO("TX mode set to OFF (value %d)", EMS_TXMODE_OFF); } } return true; From d22a369333bf03ef4eb1013f48172c99803f5431 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 27 Dec 2025 11:20:38 +0100 Subject: [PATCH 41/47] add tests for txmode --- test/test_api/api_test.http | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/test/test_api/api_test.http b/test/test_api/api_test.http index 320779672..3192cb5ae 100755 --- a/test/test_api/api_test.http +++ b/test/test_api/api_test.http @@ -4,8 +4,8 @@ # The response will be shown in the right panel # @host = http://ems-esp.local -@host = http://192.168.1.65 -@host_dev = http://192.168.1.223 +@host = http://192.168.1.223 +@host_dev = http://192.168.1.65 @host_standalone = http://localhost:3080 @host_standalone2 = http://localhost:3082 @@ -145,6 +145,30 @@ Authorization: Bearer {{token}} ### +POST {{host_dev}}/api/system/txenabled +Content-Type: application/json +Authorization: Bearer {{token}} + +{ + "value" : "on" +} + +### + +POST {{host_dev}}/api/system/txenabled +Content-Type: application/json +Authorization: Bearer {{token}} + +{ + "value" : "off" +} + +### + +GET {{host_dev}}/api/system/settings/txMode/value + +### + GET {{host_dev}}/api/system/settings/locale/value ### From 11bef525686cc630a71105a3423b01b959fc3552 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 27 Dec 2025 17:33:46 +0100 Subject: [PATCH 42/47] fix HA mapping for uA and l/min --- src/core/mqtt.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/mqtt.cpp b/src/core/mqtt.cpp index e9e6819a3..17e8a1acb 100644 --- a/src/core/mqtt.cpp +++ b/src/core/mqtt.cpp @@ -1145,7 +1145,7 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8 const char * sc_ha_total_increasing = "total_increasing"; // set uom, unless boolean - as HA is fussy with the naming - // using HA uom specific codes from https://github.com/home-assistant/core/blob/dev/homeassistant/const.py + // map too HA uom specific codes from https://github.com/home-assistant/core/blob/dev/homeassistant/const.py if (type != DeviceValueType::BOOL) { if (uom == DeviceValueUOM::HOURS) { doc[uom_ha] = "h"; @@ -1155,6 +1155,8 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8 doc[uom_ha] = "s"; } else if (uom == DeviceValueUOM::KB) { doc[uom_ha] = "kB"; + } else if (uom == DeviceValueUOM::LMIN) { + doc[uom_ha] = "L/min"; } else if (uom != DeviceValueUOM::NONE) { doc[uom_ha] = EMSdevice::uom_to_string(uom); // use default } else if (discovery_type() != discoveryType::HOMEASSISTANT) { @@ -1225,7 +1227,7 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8 doc[ic_ha] = F_(iconua); } doc[sc_ha] = sc_ha_measurement; - doc[dc_ha] = "current"; + // doc[dc_ha] = "current"; // there is no uA in HA, only mA break; case DeviceValueUOM::BAR: doc[sc_ha] = sc_ha_measurement; From b5dd72288893f44de7c1727402deb724843340f7 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 27 Dec 2025 17:34:04 +0100 Subject: [PATCH 43/47] rename txenabled to txpause --- CHANGELOG_LATEST.md | 1 + src/core/system.cpp | 24 +++++++++++++++--------- src/core/system.h | 2 +- test/test_api/api_test.http | 4 ++-- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 4f8736371..91bc9e8cf 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -40,6 +40,7 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/). - added RTL8201 to eth phy list [#2800](https://github.com/emsesp/EMS-ESP32/issues/2800) - added partitions to Web UI Version page, so previous firmware versions can be installed [#2837](https://github.com/emsesp/EMS-ESP32/issues/2837) - button pressures show LED. On a long press (10 seconds) the LED flashes for 5 seconds to indicate a factory reset is about to happen. [#2848](https://github.com/emsesp/EMS-ESP32/issues/2848) +- added `txpause` command to pause the TX, by setting Txmode to 0 (disabled) [#2850](https://github.com/emsesp/EMS-ESP32/issues/2850) ## Fixed diff --git a/src/core/system.cpp b/src/core/system.cpp index 736351b46..b2ab4de79 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1047,7 +1047,7 @@ void System::commands_init() { Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, FL_(fetch_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(format), System::command_format, FL_(format_cmd), CommandFlag::ADMIN_ONLY); - Command::add(EMSdevice::DeviceType::SYSTEM, F_(txenabled), System::command_txenabled, FL_(txenabled_cmd), CommandFlag::ADMIN_ONLY); + Command::add(EMSdevice::DeviceType::SYSTEM, F_(txpause), System::command_txpause, FL_(txpause_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, FL_(watch_cmd)); Command::add(EMSdevice::DeviceType::SYSTEM, F_(message), System::command_message, FL_(message_cmd)); #if defined(EMSESP_TEST) @@ -1107,9 +1107,8 @@ void System::led_monitor() { } else if (led_flash_step_ % 2) { // handle the step events (on odd numbers 3,5,7,etc). see if we need to turn on a LED // 1 flash (blue) is the EMS bus is not connected - // 2 flashes (red) if the network (wifi or ethernet) is not connected + // 2 flashes (red, red) if the network (wifi or ethernet) is not connected // 3 flashes (red, red, blue) is both the bus and the network are not connected - bool no_network = (healthcheck_ & HEALTHCHECK_NO_NETWORK) == HEALTHCHECK_NO_NETWORK; bool no_bus = (healthcheck_ & HEALTHCHECK_NO_BUS) == HEALTHCHECK_NO_BUS; @@ -2435,27 +2434,34 @@ bool System::load_board_profile(std::vector & data, const std::string & return true; } -// txenabled command - temporarily pause the TX, setting Txmode to 0 -bool System::command_txenabled(const char * value, const int8_t id) { +// txpause command - temporarily pause the TX, by setting Txmode to 0 (disabled) +bool System::command_txpause(const char * value, const int8_t id) { bool arg; if (!Helpers::value2bool(value, arg)) { return false; // argument not recognized } - if (arg) { - // Tx mode on - // if the TX mode was off, revert back to the saved setting + if (!arg) { + // arg = false: Tx mode to 0 (disabled) to pause if (EMSbus::tx_mode() == EMS_TXMODE_OFF) { EMSESP::webSettingsService.read([&](WebSettings & settings) { EMSbus::tx_mode(settings.tx_mode); +#ifdef EMSESP_DEBUG LOG_INFO("TX mode restored (value %d)", settings.tx_mode); +#else + LOG_INFO("TX active"); +#endif }); } } else { - // Tx mode off + // pause = true: Tx mode to 0 (disabled) to pause if (EMSbus::tx_mode() != EMS_TXMODE_OFF) { EMSbus::tx_mode(EMS_TXMODE_OFF); +#ifdef EMSESP_DEBUG LOG_INFO("TX mode set to OFF (value %d)", EMS_TXMODE_OFF); +#else + LOG_INFO("TX paused"); +#endif } } return true; diff --git a/src/core/system.h b/src/core/system.h index aa5995978..91ee58722 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -103,7 +103,7 @@ class System { static bool command_info(const char * value, const int8_t id, JsonObject output); static bool command_response(const char * value, const int8_t id, JsonObject output); static bool command_service(const char * cmd, const char * value); - static bool command_txenabled(const char * value, const int8_t id); + static bool command_txpause(const char * value, const int8_t id); static bool get_value_info(JsonObject root, const char * cmd); static void get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val); diff --git a/test/test_api/api_test.http b/test/test_api/api_test.http index 3192cb5ae..1a37372bc 100755 --- a/test/test_api/api_test.http +++ b/test/test_api/api_test.http @@ -145,7 +145,7 @@ Authorization: Bearer {{token}} ### -POST {{host_dev}}/api/system/txenabled +POST {{host_dev}}/api/system/txpause Content-Type: application/json Authorization: Bearer {{token}} @@ -155,7 +155,7 @@ Authorization: Bearer {{token}} ### -POST {{host_dev}}/api/system/txenabled +POST {{host_dev}}/api/system/txpause Content-Type: application/json Authorization: Bearer {{token}} From 9fbed4761798513914310d8eb11c7576e21a8c57 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 27 Dec 2025 17:34:19 +0100 Subject: [PATCH 44/47] txenabled to txpause --- src/core/locale_common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/locale_common.h b/src/core/locale_common.h index c9c2de3c1..48eca147d 100644 --- a/src/core/locale_common.h +++ b/src/core/locale_common.h @@ -42,7 +42,7 @@ MAKE_WORD(system) MAKE_WORD(fetch) MAKE_WORD(restart) MAKE_WORD(format) -MAKE_WORD(txenabled) +MAKE_WORD(txpause) MAKE_WORD(raw) MAKE_WORD(watch) MAKE_WORD(syslog) @@ -169,7 +169,7 @@ MAKE_WORD_CUSTOM(password_prompt, "Password: ") MAKE_WORD_CUSTOM(unset, "") MAKE_WORD_CUSTOM(enable_mandatory, "") MAKE_WORD_CUSTOM(service_mandatory, "") -MAKE_WORD_CUSTOM(txenabled_cmd, "enable/disable TX") +MAKE_WORD_CUSTOM(txpause_cmd, "enable/disable TX") // more common names that don't need translations MAKE_NOTRANSLATION(1x3min, "1x3min") From cba249938afbe0c4c1c0f754d6d4d3ab801e4d13 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 27 Dec 2025 17:35:58 +0100 Subject: [PATCH 45/47] add missing translations (thanks to AI) --- src/core/locale_translations.h | 480 ++++++++++++++++----------------- 1 file changed, 240 insertions(+), 240 deletions(-) diff --git a/src/core/locale_translations.h b/src/core/locale_translations.h index 85d50d4ac..48aa28dd5 100644 --- a/src/core/locale_translations.h +++ b/src/core/locale_translations.h @@ -37,53 +37,53 @@ // if there is no translation, it will default to en // // device types, as display in Web and Console -MAKE_WORD_TRANSLATION(boiler_hp_device, "Boiler/HP", "Kessel/WP", "CV ketel/WP", "Värmepanna/VP", "Kocioł/PC", "Varmekjele/VP", "", "Kazan/IP", "Caldaia/PC", "Kotol/TČ", "Kotel/TČ") // TODO translate -MAKE_WORD_TRANSLATION(boiler_device, "Boiler", "Kessel", "CV ketel", "Värmepanna", "Kocioł", "Varmekjele", "", "Kazan", "Caldaia", "Kotol", "Kotel") // TODO translate -MAKE_WORD_TRANSLATION(thermostat_device, "Thermostat", "Thermostat", "Thermostaat", "Termostat", "Termostat", "Termostat", "", "Termostat", "Termostato", "Termostat", "Termostat") // TODO translate -MAKE_WORD_TRANSLATION(heatpump_device, "Heat Pump", "Wärmepumpe", "Warmtepomp", "Värmepump", "Pompa ciepła", "Varmepumpe", "", "Isı Pompası", "Pompa di Calore", "Tepelné čerpadlo", "Tepelné čerpadlo") // TODO translate -MAKE_WORD_TRANSLATION(solar_device, "Solar Module", "Solarmodul", "Solar Module", "Solmodul", "Moduł solarny", "Solmodul", "", "Güneş Enerjisi Cihazı", "Modulo Solare", "Solárny modul", "Solární modul") // TODO translate -MAKE_WORD_TRANSLATION(connect_device, "Connect Module", "Verbindungsmodul", "Connect Module", "Uppkopplingsmodul", "Moduł przyłączeń", "Sammenkoblingsmodul", "", "Güneş Enerjisi Cihazı", "Modulo connessione", "Pripojte modul", "Modul připojení") // TODO translate -MAKE_WORD_TRANSLATION(mixer_device, "Mixer Module", "Mischermodul", "Mixer Module", "Blandarmodul", "Moduł mieszacza", "Miksermodul", "", "Karışım Cihazı", "Modulo Miscela", "Modul mixera", "Směšovací modul") // TODO translate -MAKE_WORD_TRANSLATION(controller_device, "Controller Module", "Regelmodul", "Controller Module", "Styrmodul", "Moduł sterujący", "Styremodul", "", "Kontrol Ünitesi", "Modulo Controllo", "Modul ovládača", "Řídicí modul") // TODO translate -MAKE_WORD_TRANSLATION(switch_device, "Switch Module", "Schaltmodul", "Switch Module", "Relämodul", "Moduł przełączający", "Switch modul", "", "Anahtar", "Modulo Switch", "Spínací modul", "Spínací modul") // TODO translate -MAKE_WORD_TRANSLATION(gateway_device, "Gateway Module", "Gateway-Modul", "Gateway Module", "Gateway", "Moduł IP", "Gateway", "", "Ağ Geçidi", "Modulo Gateway", "Modul brány", "Modul brány") // TODO translate -MAKE_WORD_TRANSLATION(alert_device, "Alert Module", "Alarmmodul", "Alert Module", "Larmmodul", "Moduł alarmowy", "Alarmmodul", "", "Alarm Cihazı", "Module Avviso", "Modul upozornení", "Modul upozornění") // TODO translate -//MAKE_WORD_TRANSLATION(pump_device, "Pump Module", "Pumpenmodul", "Pump Module", "Pumpmodul", "Moduł pompy", "Pumpemodul", "", "Pompa", "Module Pompa", "Modul čerpadla", "Modul čerpadla") // TODO translate -MAKE_WORD_TRANSLATION(extension_device, "Extension Module", "Erweiterungsnmodul", "Module", "Utökningsmodul", "Moduł rozszerzeń", "Modul", "", "", "Module", "Rozširujúci modul", "Rozšiřující modul") // TODO translate -MAKE_WORD_TRANSLATION(heatsource_device, "Heatsource", "Wärmequelle", "Heatsource", "Värmekälla", "Źródło ciepła", "Varmekilde", "", "Isı Kaynağı", "Fonte di calore", "Tepelný zdroj", "Zdroj tepla") // TODO translate +MAKE_WORD_TRANSLATION(boiler_hp_device, "Boiler/HP", "Kessel/WP", "CV ketel/WP", "Värmepanna/VP", "Kocioł/PC", "Varmekjele/VP", "Chaudière/PC", "Kazan/IP", "Caldaia/PC", "Kotol/TČ", "Kotel/TČ") +MAKE_WORD_TRANSLATION(boiler_device, "Boiler", "Kessel", "CV ketel", "Värmepanna", "Kocioł", "Varmekjele", "Chaudière", "Kazan", "Caldaia", "Kotol", "Kotel") +MAKE_WORD_TRANSLATION(thermostat_device, "Thermostat", "Thermostat", "Thermostaat", "Termostat", "Termostat", "Termostat", "Thermostat", "Termostat", "Termostato", "Termostat", "Termostat") +MAKE_WORD_TRANSLATION(heatpump_device, "Heat Pump", "Wärmepumpe", "Warmtepomp", "Värmepump", "Pompa ciepła", "Varmepumpe", "Pompe à chaleur", "Isı Pompası", "Pompa di Calore", "Tepelné čerpadlo", "Tepelné čerpadlo") +MAKE_WORD_TRANSLATION(solar_device, "Solar Module", "Solarmodul", "Solar Module", "Solmodul", "Moduł solarny", "Solmodul", "Module solaire", "Güneş Enerjisi Cihazı", "Modulo Solare", "Solárny modul", "Solární modul") +MAKE_WORD_TRANSLATION(connect_device, "Connect Module", "Verbindungsmodul", "Connect Module", "Uppkopplingsmodul", "Moduł przyłączeń", "Sammenkoblingsmodul", "Module de connexion", "Bağlantı Modülü", "Modulo connessione", "Pripojte modul", "Modul připojení") +MAKE_WORD_TRANSLATION(mixer_device, "Mixer Module", "Mischermodul", "Mixer Module", "Blandarmodul", "Moduł mieszacza", "Miksermodul", "Module mélangeur", "Karışım Cihazı", "Modulo Miscela", "Modul mixera", "Směšovací modul") +MAKE_WORD_TRANSLATION(controller_device, "Controller Module", "Regelmodul", "Controller Module", "Styrmodul", "Moduł sterujący", "Styremodul", "Module de contrôle", "Kontrol Ünitesi", "Modulo Controllo", "Modul ovládača", "Řídicí modul") +MAKE_WORD_TRANSLATION(switch_device, "Switch Module", "Schaltmodul", "Switch Module", "Relämodul", "Moduł przełączający", "Switch modul", "Module commutateur", "Anahtar", "Modulo Switch", "Spínací modul", "Spínací modul") +MAKE_WORD_TRANSLATION(gateway_device, "Gateway Module", "Gateway-Modul", "Gateway Module", "Gateway", "Moduł IP", "Gateway", "Module passerelle", "Ağ Geçidi", "Modulo Gateway", "Modul brány", "Modul brány") +MAKE_WORD_TRANSLATION(alert_device, "Alert Module", "Alarmmodul", "Alert Module", "Larmmodul", "Moduł alarmowy", "Alarmmodul", "Module d'alerte", "Alarm Cihazı", "Module Avviso", "Modul upozornení", "Modul upozornění") +//MAKE_WORD_TRANSLATION(pump_device, "Pump Module", "Pumpenmodul", "Pump Module", "Pumpmodul", "Moduł pompy", "Pumpemodul", "", "Pompa", "Module Pompa", "Modul čerpadla", "Modul čerpadla") +MAKE_WORD_TRANSLATION(extension_device, "Extension Module", "Erweiterungsnmodul", "Module", "Utökningsmodul", "Moduł rozszerzeń", "Modul", "Module d'extension", "Genişletme Modülü", "Module", "Rozširujúci modul", "Rozšiřující modul") +MAKE_WORD_TRANSLATION(heatsource_device, "Heatsource", "Wärmequelle", "Heatsource", "Värmekälla", "Źródło ciepła", "Varmekilde", "Source de chaleur", "Isı Kaynağı", "Fonte di calore", "Tepelný zdroj", "Zdroj tepla") MAKE_WORD_TRANSLATION(sensors_device, "Sensors", "Sensoren", "Sensoren", "Sensorer", "Czujniki", "Sensorer", "Capteurs", "Sensör Cihazı", "Sensori", "Snímače", "Senzory") MAKE_WORD_TRANSLATION(unknown_device, "Unknown", "Unbekannt", "Onbekend", "Okänt", "Nieznane urządzenie", "Ukjent", "Inconnu", "Bilinmeyen", "Sconosciuto", "Neznámy", "Neznámé") -MAKE_WORD_TRANSLATION(custom_device, "Custom", "Nutzerdefiniert", "Aangepast", "Anpassad", "Niestandardowe", "", "", "Özel", "Personalizzato", "Vlastné", "Vlastní") // TODO translate -MAKE_WORD_TRANSLATION(custom_device_name, "Custom Entities", "Nutzer deklarierte Entitäten", "Gebruiker gedefineerd", "Egendefinierade entiteter", "Encje zdefiniowane przez użytkownika", "", "", "Kullanıcı tarafından tanımlanmış varlıklar", "Entità definita da utente", "Používateľom definované entity", "Vlastní entity") // TODO translate -MAKE_WORD_TRANSLATION(ventilation_device, "Ventilation", "Belüftung", "Ventilatie", "Ventilation", "Wentylacja", "", "", "Havalandırma", "Ventilazione", "Vetranie", "Větrání") // TODO translate -MAKE_WORD_TRANSLATION(water_device, "Water Module", "Wassermodul", "", "Vattenmodul", "Moduł wodny", "", "", "", "", "Modul vody", "Modul vody") // TODO translate -MAKE_WORD_TRANSLATION(pool_device, "Pool Module", "Poolmodul", "", "Poolmodul", "Moduł basenu", "", "", "", "", "Modul bazéna", "Modul bazénu") // TODO translate +MAKE_WORD_TRANSLATION(custom_device, "Custom", "Nutzerdefiniert", "Aangepast", "Anpassad", "Niestandardowe", "Tilpasset", "Personnalisé", "Özel", "Personalizzato", "Vlastné", "Vlastní") +MAKE_WORD_TRANSLATION(custom_device_name, "Custom Entities", "Nutzer deklarierte Entitäten", "Gebruiker gedefineerd", "Egendefinierade entiteter", "Encje zdefiniowane przez użytkownika", "Brukerdefinerte enheter", "Entités personnalisées", "Kullanıcı tarafından tanımlanmış varlıklar", "Entità definita da utente", "Používateľom definované entity", "Vlastní entity") +MAKE_WORD_TRANSLATION(ventilation_device, "Ventilation", "Belüftung", "Ventilatie", "Ventilation", "Wentylacja", "Ventilasjon", "Ventilation", "Havalandırma", "Ventilazione", "Vetranie", "Větrání") +MAKE_WORD_TRANSLATION(water_device, "Water Module", "Wassermodul", "Water Module", "Vattenmodul", "Moduł wodny", "Vannmodul", "Module d'eau", "Su Modülü", "Modulo Acqua", "Modul vody", "Modul vody") +MAKE_WORD_TRANSLATION(pool_device, "Pool Module", "Poolmodul", "Pool Module", "Poolmodul", "Moduł basenu", "Bassengmodul", "Module piscine", "Havuz Modülü", "Modulo Piscina", "Modul bazéna", "Modul bazénu") // commands -MAKE_WORD_TRANSLATION(info_cmd, "list all values (verbose)", "Liste aller Werte", "lijst van alle waardes", "lista alla värden", "wyświetl wszystkie wartości", "Viser alle verdier", "", "Tüm değerleri listele", "elenca tutti i valori", "zobraziť všetky hodnoty", "vypsat všechny hodnoty (podrobně)") // TODO translate -MAKE_WORD_TRANSLATION(commands_cmd, "list all commands", "Liste aller Kommandos", "lijst van alle commando's", "lista alla kommandon", "wyświetl wszystkie komendy", "Viser alle kommandoer", "", "Tüm komutları listele", "elencaa tutti i comandi", "zobraziť všetky príkazy", "vypsat všechny příkazy") // TODO translate -MAKE_WORD_TRANSLATION(entities_cmd, "list all entities", "Liste aller Entitäten", "lijst van alle entiteiten", "lista all entiteter", "wyświetl wszsytkie encje", "Viser alle enheter", "", "Tüm varlıkları listele", "elenca tutte le entità", "zobraziť všetky entity", "vypsat všechny entity") // TODO translate -MAKE_WORD_TRANSLATION(metrics_cmd, "list all prometheus metrics", "Liste aller Prometheus Metriken", "lijst van alle Prometheus metriken", "lista alla Prometheus metriker", "wyświetl wszystkie Prometheus metryki", "Viser alle Prometheus metrikker", "", "Tüm Prometheus metriklerini listele", "elenca tutte le metriche Prometheus", "zobraziť všetky Prometheus metriky", "vypsat všechny Prometheus metriky") // TODO translate -MAKE_WORD_TRANSLATION(send_cmd, "send a telegram", "Sende EMS-Telegramm", "stuur een telegram", "skicka ett telegram", "wyślij telegram", "send et telegram", "", "Bir telegram gönder", "invia un telegramma", "poslať telegram", "odeslat telegram") // TODO translate -MAKE_WORD_TRANSLATION(read_cmd, "send read request", "", "", "skicka en läsförfrågan", "", "", "", "", "", "odoslať žiadosť o prečítanie", "odeslat požadavek na čtení") // TODO translate -MAKE_WORD_TRANSLATION(setiovalue_cmd, "set I/O value", "Setze Werte E/A", "instellen standaardwaarde", "sätt ett I/O-värde", "ustaw wartość", "sett en io verdi", "", "Giriş/Çıkış değerlerini ayarla", "imposta valore io", "nastaviť hodnotu io", "nastavit hodnotu I/O") // TODO translate -MAKE_WORD_TRANSLATION(changeloglevel_cmd, "change log level", "Ändere Protokollebene", "aanpassen log niveau", "ändra logg-nivå", "zmień poziom log-u", "endre loggnivå", "", "Kayıt seviyesini değiştir", "cambia livello registrazione", "zmeniť úroveň protokolu", "změnit úroveň protokolování") // TODO translate -MAKE_WORD_TRANSLATION(fetch_cmd, "refresh all EMS values", "Aktualisiere alle EMS-Werte", "Verversen alle EMS waardes", "uppdatera alla EMS-värden", "odśwież wszystkie wartości EMS", "oppfrisk alle EMS verdier", "", "Bütün EMS değerlerini yenile", "aggiornare tutti i valori EMS", "obnoviť všetky hodnoty EMS", "aktualizovat všechny EMS hodnoty") // TODO translate -MAKE_WORD_TRANSLATION(restart_cmd, "restart EMS-ESP", "Neustart", "opnieuw opstarten", "starta om EMS-ESP", "uruchom ponownie EMS-ESP", "restart EMS-ESP", "redémarrer EMS-ESP", "EMS-ESPyi yeniden başlat", "riavvia EMS-ESP", "reštart EMS-ESP", "restartovat EMS-ESP") // TODO translate -MAKE_WORD_TRANSLATION(format_cmd, "factory reset EMS-ESP", "EMS-ESP auf Werkseinstellungen zurücksetzen", "fabriksåterställ EMS-ESP", "", "", "", "", "", "", "továrenske nastavenie EMS-ESP", "tovární nastavení EMS-ESP") // TODO translate -MAKE_WORD_TRANSLATION(txenabled_cmd, "enable/disable TX", "TX aktivieren/deaktivieren", "TX inschakelen/uitschakelen", "aktivera/inaktivera TX", "włącz/wyłącz TX", "aktiver/deaktiver TX", "", "TX'i etkinleştir/devre dışı bırak", "abilita/disabilita TX", "povoliť/zakázať TX", "povolit/zakázat TX") // TODO translate -MAKE_WORD_TRANSLATION(watch_cmd, "watch incoming telegrams", "Beobachte eingehende Telegramme", "inkomende telegrammen bekijken", "visa inkommande telegram", "obserwuj przyczodzące telegramy", "se innkommende telegrammer", "", "Gelen telegramları", "guardare i telegrammi in arrivo", "sledovať prichádzajúce telegramy", "sledovat příchozí telegramy") // TODO translate -MAKE_WORD_TRANSLATION(publish_cmd, "publish all to MQTT", "Publiziere MQTT", "publiceer alles naar MQTT", "publicera allt till MQTT", "opublikuj wszystko na MQTT", "Publiser alt til MQTT", "", "Hepsini MQTTye gönder", "pubblica tutto su MQTT", "zverejniť všetko na MQTT", "publikovat vše do MQTT") // TODO translate -MAKE_WORD_TRANSLATION(system_info_cmd, "show system info", "Zeige Systeminformationen", "toon systeemstatus", "visa systeminformation", "pokaż status systemu", "vis system status", "", "Sistem Durumunu Göster", "visualizza stati di sistema", "zobraziť stav systému", "zobrazit informace o systému") // TODO translate -MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplanelemente", "activeer tijdschema item", "aktivera schemalagt objekt", "aktywuj wybrany harmonogram", "", "", "program öğesini etkinleştir", "abilitare l'elemento programmato", "povoliť položku plánovania", "povolit položku plánování") // TODO translate -MAKE_WORD_TRANSLATION(entity_cmd, "set custom value", "Sende eigene Entitäten", "verstuur custom waarde", "sätt ett eget värde", "wyślij własną wartość", "", "", "emp üzerinde özel değer ayarla", "imposta valori personalizzati", "nastaviť vlastnú hodnotu", "nastavit vlastní hodnotu") // TODO translate -MAKE_WORD_TRANSLATION(commands_response, "get response", "Hole Antwort", "Verzoek om antwoord", "hämta svar", "uzyskaj odpowiedź", "", "", "gelen cevap", "", "získať odpoveď", "získat odpověď") // TODO translate -MAKE_WORD_TRANSLATION(coldshot_cmd, "send a cold shot of water", "Zugabe einer Menge kalten Wassers", "", "sckicka en liten mängd kallvatten", "uruchom tryśnięcie zimnej wody", "", "", "soğuk su gönder", "", "pošlite studenú dávku vody", "poslat studenou vodu") // TODO translate -MAKE_WORD_TRANSLATION(message_cmd, "send a message", "Eine Nachricht senden", "", "skicka ett meddelande", "", "", "", "", "", "poslať správu", "odeslat zprávu") // TODO translate -MAKE_WORD_TRANSLATION(values_cmd, "list all values", "Liste alle Werte auf", "", "lista alla värden", "", "", "", "", "", "vypísať všetky hodnoty", "vypsat všechny hodnoty") // TODO translate -MAKE_WORD_TRANSLATION(system_cmd, "system setting", "System Einstellung", "", "systeminställning", "", "", "", "", "", "vypísať všetky hodnoty", "vypsat všechny hodnoty") // TODO translate -MAKE_WORD_TRANSLATION(showertimer_cmd, "enable shower timer", "aktiviere Duschzeitmessung", "", "aktivera duschtimer", "", "", "", "", "", "povoliť časovač sprchovania", "povolit časovač sprchy") // TODO translate -MAKE_WORD_TRANSLATION(showeralert_cmd, "enable shower alert", "aktiviere Duschzeitwarnung", "", "aktivera duschvarning", "", "", "", "", "", "povoliť upozornenie na sprchu", "povolit alarm sprchy") // TODO translate +MAKE_WORD_TRANSLATION(info_cmd, "list all values (verbose)", "Liste aller Werte", "lijst van alle waardes", "lista alla värden", "wyświetl wszystkie wartości", "Viser alle verdier", "lister toutes les valeurs", "Tüm değerleri listele", "elenca tutti i valori", "zobraziť všetky hodnoty", "vypsat všechny hodnoty (podrobně)") +MAKE_WORD_TRANSLATION(commands_cmd, "list all commands", "Liste aller Kommandos", "lijst van alle commando's", "lista alla kommandon", "wyświetl wszystkie komendy", "Viser alle kommandoer", "lister toutes les commandes", "Tüm komutları listele", "elencaa tutti i comandi", "zobraziť všetky príkazy", "vypsat všechny příkazy") +MAKE_WORD_TRANSLATION(entities_cmd, "list all entities", "Liste aller Entitäten", "lijst van alle entiteiten", "lista all entiteter", "wyświetl wszsytkie encje", "Viser alle enheter", "lister toutes les entités", "Tüm varlıkları listele", "elenca tutte le entità", "zobraziť všetky entity", "vypsat všechny entity") +MAKE_WORD_TRANSLATION(metrics_cmd, "list all prometheus metrics", "Liste aller Prometheus Metriken", "lijst van alle Prometheus metriken", "lista alla Prometheus metriker", "wyświetl wszystkie Prometheus metryki", "Viser alle Prometheus metrikker", "lister toutes les métriques Prometheus", "Tüm Prometheus metriklerini listele", "elenca tutte le metriche Prometheus", "zobraziť všetky Prometheus metriky", "vypsat všechny Prometheus metriky") +MAKE_WORD_TRANSLATION(send_cmd, "send a telegram", "Sende EMS-Telegramm", "stuur een telegram", "skicka ett telegram", "wyślij telegram", "send et telegram", "envoyer un télégramme", "Bir telegram gönder", "invia un telegramma", "poslať telegram", "odeslat telegram") +MAKE_WORD_TRANSLATION(read_cmd, "send read request", "Sende Leseanfrage", "stuur leesaanvraag", "skicka en läsförfrågan", "wyślij żądanie odczytu", "send leseforespørsel", "envoyer une demande de lecture", "okuma isteği gönder", "invia richiesta di lettura", "odoslať žiadosť o prečítanie", "odeslat požadavek na čtení") +MAKE_WORD_TRANSLATION(setiovalue_cmd, "set I/O value", "Setze Werte E/A", "instellen standaardwaarde", "sätt ett I/O-värde", "ustaw wartość", "sett en io verdi", "définir valeur E/S", "Giriş/Çıkış değerlerini ayarla", "imposta valore io", "nastaviť hodnotu io", "nastavit hodnotu I/O") +MAKE_WORD_TRANSLATION(changeloglevel_cmd, "change log level", "Ändere Protokollebene", "aanpassen log niveau", "ändra logg-nivå", "zmień poziom log-u", "endre loggnivå", "changer le niveau de journal", "Kayıt seviyesini değiştir", "cambia livello registrazione", "zmeniť úroveň protokolu", "změnit úroveň protokolování") +MAKE_WORD_TRANSLATION(fetch_cmd, "refresh all EMS values", "Aktualisiere alle EMS-Werte", "Verversen alle EMS waardes", "uppdatera alla EMS-värden", "odśwież wszystkie wartości EMS", "oppfrisk alle EMS verdier", "actualiser toutes les valeurs EMS", "Bütün EMS değerlerini yenile", "aggiornare tutti i valori EMS", "obnoviť všetky hodnoty EMS", "aktualizovat všechny EMS hodnoty") +MAKE_WORD_TRANSLATION(restart_cmd, "restart EMS-ESP", "Neustart", "opnieuw opstarten", "starta om EMS-ESP", "uruchom ponownie EMS-ESP", "restart EMS-ESP", "redémarrer EMS-ESP", "EMS-ESPyi yeniden başlat", "riavvia EMS-ESP", "reštart EMS-ESP", "restartovat EMS-ESP") +MAKE_WORD_TRANSLATION(format_cmd, "factory reset EMS-ESP", "EMS-ESP auf Werkseinstellungen zurücksetzen", "fabrieksinstellingen EMS-ESP", "fabriksåterställ EMS-ESP", "zresetuj EMS-ESP do ustawień fabrycznych", "tilbakestill EMS-ESP til fabrikkinnstillinger", "réinitialisation EMS-ESP", "EMS-ESP fabrika ayarları", "ripristino di fabbrica EMS-ESP", "továrenske nastavenie EMS-ESP", "tovární nastavení EMS-ESP") +MAKE_WORD_TRANSLATION(watch_cmd, "watch incoming telegrams", "Beobachte eingehende Telegramme", "inkomende telegrammen bekijken", "visa inkommande telegram", "obserwuj przyczodzące telegramy", "se innkommende telegrammer", "surveiller les télégrammes entrants", "Gelen telegramları izle", "guardare i telegrammi in arrivo", "sledovať prichádzajúce telegramy", "sledovat příchozí telegramy") +MAKE_WORD_TRANSLATION(publish_cmd, "publish all to MQTT", "Publiziere MQTT", "publiceer alles naar MQTT", "publicera allt till MQTT", "opublikuj wszystko na MQTT", "Publiser alt til MQTT", "publier tout vers MQTT", "Hepsini MQTTye gönder", "pubblica tutto su MQTT", "zverejniť všetko na MQTT", "publikovat vše do MQTT") +MAKE_WORD_TRANSLATION(system_info_cmd, "show system info", "Zeige Systeminformationen", "toon systeemstatus", "visa systeminformation", "pokaż status systemu", "vis system status", "afficher les informations système", "Sistem Durumunu Göster", "visualizza stati di sistema", "zobraziť stav systému", "zobrazit informace o systému") +MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplanelemente", "activeer tijdschema item", "aktivera schemalagt objekt", "aktywuj wybrany harmonogram", "aktiver planlagt element", "activer élément programmé", "program öğesini etkinleştir", "abilitare l'elemento programmato", "povoliť položku plánovania", "povolit položku plánování") +MAKE_WORD_TRANSLATION(entity_cmd, "set custom value", "Sende eigene Entitäten", "verstuur custom waarde", "sätt ett eget värde", "wyślij własną wartość", "sett egendefinert verdi", "définir valeur personnalisée", "özel değer ayarla", "imposta valori personalizzati", "nastaviť vlastnú hodnotu", "nastavit vlastní hodnotu") +MAKE_WORD_TRANSLATION(commands_response, "get response", "Hole Antwort", "Verzoek om antwoord", "hämta svar", "uzyskaj odpowiedź", "få svar", "obtenir réponse", "yanıt al", "ottieni risposta", "získať odpoveď", "získat odpověď") +MAKE_WORD_TRANSLATION(coldshot_cmd, "send a cold shot of water", "Zugabe einer Menge kalten Wassers", "stuur koud water", "sckicka en liten mängd kallvatten", "uruchom tryśnięcie zimnej wody", "send kaldtvannspuls", "envoyer de l'eau froide", "soğuk su gönder", "invia acqua fredda", "pošlite studenú dávku vody", "poslat studenou vodu") +MAKE_WORD_TRANSLATION(message_cmd, "send a message", "Eine Nachricht senden", "stuur een bericht", "skicka ett meddelande", "wyślij wiadomość", "send en melding", "envoyer un message", "mesaj gönder", "invia un messaggio", "poslať správu", "odeslat zprávu") +MAKE_WORD_TRANSLATION(values_cmd, "list all values", "Liste alle Werte auf", "lijst alle waardes", "lista alla värden", "wyświetl wszystkie wartości", "list alle verdier", "lister toutes les valeurs", "tüm değerleri listele", "elenca tutti i valori", "vypísať všetky hodnoty", "vypsat všechny hodnoty") +MAKE_WORD_TRANSLATION(system_cmd, "system setting", "System Einstellung", "systeem instelling", "systeminställning", "ustawienie systemowe", "systeminnstilling", "paramètre système", "sistem ayarı", "impostazione di sistema", "nastavenie systému", "nastavení systému") +MAKE_WORD_TRANSLATION(showertimer_cmd, "enable shower timer", "aktiviere Duschzeitmessung", "activeer douche timer", "aktivera duschtimer", "aktywuj czasomierz prysznica", "aktiver dusjtimer", "activer minuteur de douche", "duş zamanlayıcısını etkinleştir", "abilita timer doccia", "povoliť časovač sprchovania", "povolit časovač sprchy") +MAKE_WORD_TRANSLATION(showeralert_cmd, "enable shower alert", "aktiviere Duschzeitwarnung", "activeer douche alarm", "aktivera duschvarning", "aktywuj alarm prysznica", "aktiver dusjvarsel", "activer alerte de douche", "duş uyarısını etkinleştir", "abilita allarme doccia", "povoliť upozornenie na sprchu", "povolit alarm sprchy") +MAKE_WORD_TRANSLATION(txpause_cmd, "pause EMS Tx", "EMS Tx pausieren", "pauzeer EMS Tx", "pausa EMS Tx", "wstrzymaj EMS Tx", "pause EMS Tx", "pause EMS Tx", "EMS Tx'i duraklat", "pausa EMS Tx", "pozastaviť EMS Tx", "pauzovat EMS Tx") // tags MAKE_WORD_TRANSLATION(tag_hc1, "hc1", "HK1", "hc1", "VK1", "OG1", "hc1", "hc1", "ID1", "hc1", "hc1", "hc1") @@ -187,7 +187,7 @@ MAKE_WORD_TRANSLATION(vacuum, "vacuum", "Vakuum", "vacuum", "Vakuum", "próżnia MAKE_WORD_TRANSLATION(co2_optimized, "co2 optimized", "CO2 optimiert", "CO2 geoptimaliseerd", "CO2-optimerad", "optymalizacja CO2", "co2 optimalisert", "optimisé en CO2", "CO2 verimli", "CO2 ottimizzato", "co2 optimalizované", "optimalizace CO2") MAKE_WORD_TRANSLATION(cost_optimized, "cost optimized", "kostenoptimiert", "kosten geoptimaliseerd", "kostnadsoptimerad", "optymalizacja kosztów", "kostnadsoptimalisert", "optimisé en coût", "maliyet odaklı", "costo ottimizzato", "nákladovo optimalizované", "optimalizace nákladů") MAKE_WORD_TRANSLATION(outside_temp_switched, "outside temp switched", "Außentemp. gesteuert", "buitentemp. gestuurd", "Utomhustemp korrigerad", "temperatura zewn. przeł.", "utetemp optimalisert", "contrôle par temp. ext.", "dış hava sıcaklığına bağlı", "temperatura esterna cambiata", "prepnuta vonkajsia teplota", "venkovní teplota přepnuta") -MAKE_WORD_TRANSLATION(co2_cost_mix, "co2 cost mix", "CO2-Kostenmix", "CO2-kostenmix", "CO2-Kostnadsmix", "mieszany koszt CO2", "", "coût mixte CO2", "karışık maliyet", "co2 cost mix", "co2 náklady mix", "mix nákladů CO2") // TODO translate +MAKE_WORD_TRANSLATION(co2_cost_mix, "co2 cost mix", "CO2-Kostenmix", "CO2-kostenmix", "CO2-Kostnadsmix", "mieszany koszt CO2", "CO2-kostnadsmiks", "coût mixte CO2", "karışık maliyet", "co2 cost mix", "co2 náklady mix", "mix nákladů CO2") MAKE_WORD_TRANSLATION(analog, "analog", "analog", "analoog", "analog", "analogowy", "analog", "analogique", "analog", "analogico", "analógový", "analogový") MAKE_WORD_TRANSLATION(normal, "normal", "normal", "normaal", "normal", "normalny", "normal", "normal", "normal", "normale", "normálny", "normální") MAKE_WORD_TRANSLATION(blocking, "blocking", "Blockierung", "blokkering", "Blockering", "blokowanie", "blokkering", "bloquant", "engelleme", "bloccaggio", "blokovanie", "blokování") @@ -195,10 +195,10 @@ MAKE_WORD_TRANSLATION(extern, "extern", "extern", "extern", "extern", "zewnętrz MAKE_WORD_TRANSLATION(intern, "intern", "intern", "intern", "intern", "wewnętrzny", "intern", "interne", "iç", "interno", "interný", "interní") MAKE_WORD_TRANSLATION(lower, "lower", "niedriger", "lager", "lägre", "mniejszy", "nedre", "inférieur", "daha düşük", "basso", "nízky", "nízký") MAKE_WORD_TRANSLATION(error, "error", "Fehler", "error", "Fel", "błąd", "feil", "erreur", "Hata", "errore", "error", "chyba") -MAKE_WORD_TRANSLATION(history, "history", "Fehlerspeicher", "", "historik", "historia", "", "", "", "", "história", "historie") // TODO translate +MAKE_WORD_TRANSLATION(history, "history", "Fehlerspeicher", "geschiedenis", "historik", "historia", "historikk", "historique", "geçmiş", "storico", "história", "historie") MAKE_WORD_TRANSLATION(message, "message", "Meldung", "melding", "meddelande", "komunikat", "melding", "message", "mesajı", "messaggio", "správa", "zpráva") MAKE_WORD_TRANSLATION(na, "n/a", "n/a", "n/a", "n/a", "nd.", "n/a", "n/c", "mevcut değil", "n/a", "n/a", "n/a") -MAKE_WORD_TRANSLATION(inverted, "inverted", "invertiert", "", "inverterad", "odwrócony", "", "", "", "", "invertovaný", "invertovaný") // TODO translate +MAKE_WORD_TRANSLATION(inverted, "inverted", "invertiert", "omgekeerd", "inverterad", "odwrócony", "invertert", "inversé", "ters", "invertito", "invertovaný", "invertovaný") // boiler MAKE_WORD_TRANSLATION(time, "time", "Zeit", "tijd", "Tid", "godzina", "tid", "heure", "zaman", "ora", "čas", "čas") @@ -214,27 +214,27 @@ MAKE_WORD_TRANSLATION(intelligent, "intelligent", "Intelligent", "intelligent", MAKE_WORD_TRANSLATION(flow, "flow", "Durchfluss", "volumestroom", "Flöde", "przepływ", "strømme", "débit", "akım", "flusso", "tok", "průtok") MAKE_WORD_TRANSLATION(manual, "manual", "Manuell", "handmatig", "Manuell", "ręczny", "manuell", "manuel", "manuel", "manuale", "manuálny", "manuální") MAKE_WORD_TRANSLATION(buffer, "buffer", "Speicher", "buffer", "Buffert", "bufor", "buffer", "buffer", "tampon", "Buffer", "zásobník", "zásobník") -MAKE_WORD_TRANSLATION(bufferedflow, "buffered flow", "Durchlaufspeicher", "doorstroombuffer", "Buffertflöde", "przepływ buforowany", "bufret strømning", "", "tampon akım", "memoria flusso", "zásobníkový prietok", "zásobníkový průtok") // TODO translate -MAKE_WORD_TRANSLATION(layeredbuffer, "layered buffer", "Schichtspeicher", "gelaagde buffer", "Lagrad buffert", "bufor warstwowy", "lagdelt buffer", "", "katmanlı akım", "strato memoria", "vrstvený zásobník", "vrstvený zásobník") // TODO translate +MAKE_WORD_TRANSLATION(bufferedflow, "buffered flow", "Durchlaufspeicher", "doorstroombuffer", "Buffertflöde", "przepływ buforowany", "bufret strømning", "flux tamponné", "tampon akım", "memoria flusso", "zásobníkový prietok", "zásobníkový průtok") +MAKE_WORD_TRANSLATION(layeredbuffer, "layered buffer", "Schichtspeicher", "gelaagde buffer", "Lagrad buffert", "bufor warstwowy", "lagdelt buffer", "tampon stratifié", "katmanlı tampon", "strato memoria", "vrstvený zásobník", "vrstvený zásobník") MAKE_WORD_TRANSLATION(maintenance, "maintenance", "Wartung", "onderhoud", "Underhåll", "przegląd", "vedlikehold", "maintenance", "bakım", "servizio", "údržba", "údržba") MAKE_WORD_TRANSLATION(heating, "heating", "Heizen", "verwarmen", "Uppvärmning", "ogrzewanie", "oppvarming", "chauffage", "ısıtma", "riscaldamento", "kúrenie", "topení") MAKE_WORD_TRANSLATION(cooling, "cooling", "Kühlen", "koelen", "Kyler", "chłodzenie", "kjøling", "refroidissement", "soğuma", "raffreddamento", "chladenie", "chlazení") -MAKE_WORD_TRANSLATION(heatandcool, "heating & cooling", "Heizen & Kühlen", "verwarmen & koelen", "Uppvärmning & Kyla", "ogrzewanie i chłodzenie", "", "", "ısıtma & soğutma", "", "kúrenie a chladenie", "topení a chlazení") // TODO translate +MAKE_WORD_TRANSLATION(heatandcool, "heating & cooling", "Heizen & Kühlen", "verwarmen & koelen", "Uppvärmning & Kyla", "ogrzewanie i chłodzenie", "oppvarming & kjøling", "chauffage et refroidissement", "ısıtma & soğutma", "riscaldamento e raffreddamento", "kúrenie a chladenie", "topení a chlazení") MAKE_WORD_TRANSLATION(disinfecting, "disinfecting", "Desinfizieren", "desinfecteren", "Desinficerar", "dezynfekcja termiczna", "desinfisering", "désinfection", "dezenfeksiyon", "disinfezione", "dezinfekcia", "dezinfekce") MAKE_WORD_TRANSLATION(no_heat, "no heat", "keine Wärme", "geen warmte", "Ingen värme", "brak ciepła", "ingen varme", "pas de chauffage", "ısınma yok", "nessun calore", "žiadne teplo", "bez tepla") MAKE_WORD_TRANSLATION(heatrequest, "heat request", "Wärmeanforderung", "verwarmingsverzoek", "Värmeförfrågan", "zapotrzebowanie na ciepło", "varmeforespørsel", "demande de chauffage", "ısınma ihtiyacı", "richiesta calore", "požiadavka na teplo", "požadavek na teplo") MAKE_WORD_TRANSLATION(valve, "valve", "Ventil", "klep", "Ventil", "zawór", "ventil", "valve", "vana", "valvola", "ventil", "ventil") -MAKE_WORD_TRANSLATION(proportional, "proportional", "proportional", "proportioneel", "proportionell", "proporcjonalny", "proposjonal", "", "oransal", "proporzionale", "proporcionálne", "proporcionální") // TODO translate -MAKE_WORD_TRANSLATION(deltaP1, "deltaP-1", "deltaP-1", "deltaP-1", "deltaP-1", "delta P-1", "deltaP-1", "", "deltaP-1", "deltaP-1", "deltaP-1", "deltaP-1") // TODO translate -MAKE_WORD_TRANSLATION(deltaP2, "deltaP-2", "deltaP-2", "deltaP-2", "deltaP-2", "delta P-2", "deltaP-2", "", "deltaP-2", "deltaP-2", "deltaP-2", "deltaP-2") // TODO translate -MAKE_WORD_TRANSLATION(deltaP3, "deltaP-3", "deltaP-3", "deltaP-3", "deltaP-3", "delta P-3", "deltaP-3", "", "deltaP-3", "deltaP-3", "deltaP-3", "deltaP-3") // TODO translate -MAKE_WORD_TRANSLATION(deltaP4, "deltaP-4", "deltaP-4", "deltaP-4", "deltaP-4", "delta P-4", "deltaP-4", "", "deltaP-4", "deltaP-4", "deltaP-4", "deltaP-4") // TODO translate -MAKE_WORD_TRANSLATION(pressure1, "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar") // TODO translate -MAKE_WORD_TRANSLATION(pressure2, "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar") // TODO translate -MAKE_WORD_TRANSLATION(pressure3, "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar") // TODO translate -MAKE_WORD_TRANSLATION(pressure4, "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar") // TODO translate -MAKE_WORD_TRANSLATION(pressure5, "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar") // TODO translate -MAKE_WORD_TRANSLATION(pressure6, "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar") // TODO translate +MAKE_WORD_TRANSLATION(proportional, "proportional", "proportional", "proportioneel", "proportionell", "proporcjonalny", "proposjonal", "proportionnel", "oransal", "proporzionale", "proporcionálne", "proporcionální") +MAKE_WORD_TRANSLATION(deltaP1, "deltaP-1", "deltaP-1", "deltaP-1", "deltaP-1", "delta P-1", "deltaP-1", "deltaP-1", "deltaP-1", "deltaP-1", "deltaP-1", "deltaP-1") +MAKE_WORD_TRANSLATION(deltaP2, "deltaP-2", "deltaP-2", "deltaP-2", "deltaP-2", "delta P-2", "deltaP-2", "deltaP-2", "deltaP-2", "deltaP-2", "deltaP-2", "deltaP-2") +MAKE_WORD_TRANSLATION(deltaP3, "deltaP-3", "deltaP-3", "deltaP-3", "deltaP-3", "delta P-3", "deltaP-3", "deltaP-3", "deltaP-3", "deltaP-3", "deltaP-3", "deltaP-3") +MAKE_WORD_TRANSLATION(deltaP4, "deltaP-4", "deltaP-4", "deltaP-4", "deltaP-4", "delta P-4", "deltaP-4", "deltaP-4", "deltaP-4", "deltaP-4", "deltaP-4", "deltaP-4") +MAKE_WORD_TRANSLATION(pressure1, "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar", "150mbar") +MAKE_WORD_TRANSLATION(pressure2, "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar", "200mbar") +MAKE_WORD_TRANSLATION(pressure3, "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar", "250mbar") +MAKE_WORD_TRANSLATION(pressure4, "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar", "300mbar") +MAKE_WORD_TRANSLATION(pressure5, "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar", "350mbar") +MAKE_WORD_TRANSLATION(pressure6, "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar", "400mbar") MAKE_WORD_TRANSLATION(pumpstep, "pumpstep", "Stufen") MAKE_WORD_TRANSLATION(consthigh, "const.high", "konst.hoch") MAKE_WORD_TRANSLATION(constmed, "const.medium", "konst.mittel") @@ -246,7 +246,7 @@ MAKE_WORD_TRANSLATION(proplow, "propo.low", "prop.niedrig") MAKE_WORD_TRANSLATION(none, "none", "keine", "geen", "ingen", "brak", "ingen", "aucun", "hiçbiri", "nessuno", "žiadny", "žádné") MAKE_WORD_TRANSLATION(hot_water, "hot water", "Warmwasser", "warm water", "varmvatten", "c.w.u.", "varmtvann", "eau chaude", "sıcak su", "acqua calda", "horúca voda", "horká voda") MAKE_WORD_TRANSLATION(pool, "pool", "Pool", "zwembad", "pool", "basen", "basseng", "piscine", "havuz", "piscina", "bazén", "bazén") -MAKE_WORD_TRANSLATION(pool_heating, "pool heating", "Pool beheizen", "", "", "", "", "", "", "", "ohrev bazéna", "ohřev bazénu") +MAKE_WORD_TRANSLATION(pool_heating, "pool heating", "Pool beheizen", "zwembadverwarming", "uppvärmning av pool", "ogrzewanie basenu", "bassengoppvarming", "chauffage piscine", "havuz ısıtma", "riscaldamento piscina", "ohrev bazéna", "ohřev bazénu") MAKE_WORD_TRANSLATION(outside_temp_alt, "outside temperature alt.", "Außentemp. alternativ", "alternatieve buitentemperatuur", "Alternativ utomhustemp.", "temp. zewn. alternat.", "alternativ utendørstemp.", "température extérieure alternative", "alternatif dış sıcaklık", "temperatura esterna alternativa", "vonkajšia teplota altern.", "venkovní teplota alt.") MAKE_WORD_TRANSLATION(outside_temp_par, "outside temperature parallel", "Außentemp. parallel", "buitentemperatuur parallel", "Parallell utomhustemp.", "temp. zewn. równoległa", "parallell utendørstemp.", "température extérieure parallèle", "paralel dış sıcaklık", "temperatura esterna parallela", "paralelne s vonkajšou teplotou", "paralelně s venkovní teplotou") MAKE_WORD_TRANSLATION(hp_preferred, "heatpump preferred", "Wärmepumpe bevorzugt", "voorkeur warmtepomp", "Värmepump föredraget", "preferowana pompa ciepła", "varmepumpe prioritert", "pompe à chaleur préférée", "tercih edilen pompa", "pompa di calore preferita", "preferované tepelné čerpadlo", "preferované tepelné čerpadlo") @@ -254,14 +254,14 @@ MAKE_WORD_TRANSLATION(boiler_only, "boiler only", "nur Kessel", "uitsluitend cv MAKE_WORD_TRANSLATION(reduced_output, "reduced output", "Reduzierte Leistung", "gereduceerde output", "Reducerad produktion", "zmniejszona wydajność", "redusert ytelse", "sortie réduite", "düşürülmüş çıkış", "riduzione uscita", "znížený výkon", "snížený výkon") MAKE_WORD_TRANSLATION(switchoff, "switch off hp", "WP ausschalten", "WP uitschakelen", "Värmepump avstängd", "wyłącz pompę ciepła", "slå av varmepumpe", "éteindre la PAC", "ısı pompasını kapat", "spegnimento pompa calore", "vypnúť tep. čerpadlo", "vypnout tepelné čerpadlo") MAKE_WORD_TRANSLATION(perm, "perm. reduced", "perm. reduziert", "permanent gereduceerd", "Permanent reducerad", "stale zmniejszona wydajność", "permanent redusert", "réduction permanente", "sürekli azaltılmış", "riduzione permanente", "trvalo znížené", "trvale sníženo") -MAKE_WORD_TRANSLATION(heat_ww, "heating & dhw", "Heizen & Warmwasser", "", "Uppvärmning & Varmvatten", "ogrzewanie i c.w.u.", "", "", "", "", "kúrenie a TÚV", "topení a TUV") -MAKE_WORD_TRANSLATION(cool_defrost, "cooling & defrost", "Kühlen & Abtauen", "", "Kyla & Avfrostning", "chłodzenie i odladzanie", "", "", "", "", "chladenie a rozmrazovanie", "chlazení a odmrazování") -MAKE_WORD_TRANSLATION(compressor_alarm, "compressor alarm", "Alarm Kompressor", "", "", "", "", "", "", "", "alarm kompresora", "alarm kompresoru") -MAKE_WORD_TRANSLATION(not_installed, "not installed", "Nicht installiert", "", "", "", "", "", "", "", "nenainštalované", "není nainstalováno") // TODO translate -MAKE_WORD_TRANSLATION(el_heater, "electric heater", "Elektroheizer", "", "", "", "", "", "", "", "elektrický ohrev", "elektrický ohřev") // TODO translate -MAKE_WORD_TRANSLATION(exclusive, "exclusive", "Exklusiv", "", "", "", "", "", "", "", "ekluzívne", "exkluzivní") // TODO translate -MAKE_WORD_TRANSLATION(parallel, "parallel", "Parallel", "", "", "", "", "", "", "", "paralelné", "paralelní") // TODO translate -MAKE_WORD_TRANSLATION(hybrid, "hybrid", "Hybrid", "", "", "", "", "", "", "", "hybridné", "hybridní") // TODO translate +MAKE_WORD_TRANSLATION(heat_ww, "heating & dhw", "Heizen & Warmwasser", "verwarmen & warmwater", "Uppvärmning & Varmvatten", "ogrzewanie i c.w.u.", "oppvarming & varmtvann", "chauffage et eau chaude sanitaire", "ısıtma ve sıcak su", "riscaldamento e acqua calda", "kúrenie a TÚV", "topení a TUV") +MAKE_WORD_TRANSLATION(cool_defrost, "cooling & defrost", "Kühlen & Abtauen", "koelen & ontdooien", "Kyla & Avfrostning", "chłodzenie i odladzanie", "kjøling & avriming", "refroidissement et dégivrage", "soğutma ve buz çözme", "raffreddamento e sbrinamento", "chladenie a rozmrazovanie", "chlazení a odmrazování") +MAKE_WORD_TRANSLATION(compressor_alarm, "compressor alarm", "Alarm Kompressor", "compressor alarm", "kompressorlarm", "alarm kompresora", "kompressoralarm", "alarme compresseur", "kompresör alarmı", "allarme compressore", "alarm kompresora", "alarm kompresoru") +MAKE_WORD_TRANSLATION(not_installed, "not installed", "Nicht installiert", "niet geïnstalleerd", "inte installerad", "nie zainstalowane", "ikke installert", "non installé", "kurulu değil", "non installato", "nenainštalované", "není nainstalováno") +MAKE_WORD_TRANSLATION(el_heater, "electric heater", "Elektroheizer", "elektrische verwarming", "elvärmare", "grzałka elektryczna", "elektrisk varmer", "chauffage électrique", "elektrikli ısıtıcı", "riscaldatore elettrico", "elektrický ohrev", "elektrický ohřev") +MAKE_WORD_TRANSLATION(exclusive, "exclusive", "Exklusiv", "exclusief", "exklusiv", "wyłączny", "eksklusiv", "exclusif", "özel", "esclusivo", "ekluzívne", "exkluzivní") +MAKE_WORD_TRANSLATION(parallel, "parallel", "Parallel", "parallel", "parallell", "równoległy", "parallell", "parallèle", "paralel", "parallelo", "paralelné", "paralelní") +MAKE_WORD_TRANSLATION(hybrid, "hybrid", "Hybrid", "hybride", "hybrid", "hybrydowy", "hybrid", "hybride", "hibrit", "ibrido", "hybridné", "hybridní") // thermostat MAKE_WORD_TRANSLATION(seltemp, "selTemp", "Solltemperatur", "doeltemperatuur", "Börtemperatur", "temperatura zadana", "innstilt temperatur", "consigne température", "ayarlanmış sıcaklık", "temperatura di consegna", "zadaná teplota", "zvolená teplota") @@ -282,16 +282,16 @@ MAKE_WORD_TRANSLATION(french, "french", "Französisch", "Frans", "Franska", "fra MAKE_WORD_TRANSLATION(italian, "italian", "Italienisch", "Italiaans", "Italienska", "włoski", "italiensk", "italien", "İtalyanca", "Italiano", "taliansky", "italština") MAKE_WORD_TRANSLATION(high, "high", "hoch", "hoog", "Hög", "wysoki", "høy", "haut", "yüksek", "alto", "vysoký", "vysoký") MAKE_WORD_TRANSLATION(low, "low", "niedrig", "laag", "Låg", "niski", "lav", "bas", "düşük", "basso", "nízky", "nízký") -MAKE_WORD_TRANSLATION(curve, "heatingcurve", "Heizkurve", "", "värmekurva", "krzywa grzania", "", "", "", "", "vykurovacia krivka", "křivka topení") // TODO translate +MAKE_WORD_TRANSLATION(curve, "heatingcurve", "Heizkurve", "stookkromme", "värmekurva", "krzywa grzania", "varmekurve", "courbe de chauffage", "ısıtma eğrisi", "curva di riscaldamento", "vykurovacia krivka", "křivka topení") MAKE_WORD_TRANSLATION(radiator, "radiator", "Heizkörper", "radiator", "Radiator", "grzejniki", "radiator", "radiateur", "radyatör", "radiatore", "radiátor", "radiátor") MAKE_WORD_TRANSLATION(convector, "convector", "Konvektor", "convector", "Konvektor", "konwektory", "konvektor", "convecteur", "convector", "convettore", "konvektor", "konvektor") MAKE_WORD_TRANSLATION(floor, "floor", "Fussboden", "vloer", "Golv", "podłoga", "gulv", "sol", "yer", "pavimento", "podlaha", "podlaha") -MAKE_WORD_TRANSLATION(roomflow, "roomflow", "Raum Fluß", "", "Rumsflöde", "", "", "", "", "", "prúdenie miestnosti", "průtok mistnosti") // TODO translate -MAKE_WORD_TRANSLATION(roomload, "roomload", "Raum Bedarf", "", "Rumsbehov", "", "", "", "", "", "izbová zaťaž", "zatížení místnosti") // TODO translate +MAKE_WORD_TRANSLATION(roomflow, "roomflow", "Raum Fluß", "kamer doorstroming", "Rumsflöde", "przepływ w pomieszczeniu", "romstrøm", "flux de la pièce", "oda akışı", "flusso della stanza", "prúdenie miestnosti", "průtok mistnosti") +MAKE_WORD_TRANSLATION(roomload, "roomload", "Raum Bedarf", "kamer behoefte", "Rumsbehov", "zapotrzebowanie pomieszczenia", "rombelastning", "charge de la pièce", "oda yükü", "carico della stanza", "izbová zaťaž", "zatížení místnosti") MAKE_WORD_TRANSLATION(summer, "summer", "Sommer", "zomer", "Sommar", "lato", "sommer", "été", "yaz", "estate", "leto", "léto") MAKE_WORD_TRANSLATION(winter, "winter", "Winter", "winter", "Vinter", "zima", "vinter", "hiver", "kış", "inverno", "zima", "zima") MAKE_WORD_TRANSLATION(outdoor, "outdoor", "Außen", "buiten", "Utomhus", "temp. zewnętrzna", "utendørs", "extérieur", "dış", "esterno", "vonku", "venkovní") -MAKE_WORD_TRANSLATION(room, "room", "Raum", "kamer", "Rum", "temp. w pomieszczeniu", "", "pièce", "oda", "camera", "izba", "dle teploty prostoru") // TODO translate +MAKE_WORD_TRANSLATION(room, "room", "Raum", "kamer", "Rum", "temp. w pomieszczeniu", "rom", "pièce", "oda", "camera", "izba", "dle teploty prostoru") MAKE_WORD_TRANSLATION(room_outdoor, "room outdoor", "Raum + Außen", "kamer + buiten", "Rum + Ute", "temp. w pom. i zewn.", "rom utendørs", "pièce extérieure", "oda ve dış", "camera esterna", "miestnosť vonku", "místnost venku") MAKE_WORD_TRANSLATION(power, "power", "Leistung", "vermogen", "Effekt", "moc", "effekt", "puissance", "güç", "potenza", "výkon", "výkon") MAKE_WORD_TRANSLATION(constant, "constant", "konstant", "constant", "Konstant", "stały", "konstant", "constant", "sabit", "costante", "konštantný", "konstantní") @@ -320,11 +320,11 @@ MAKE_WORD_TRANSLATION(smoke_temperature, "smoke temperature", "Abgastemperatur", MAKE_WORD_TRANSLATION(weather_compensated, "weather compensated", "Wetter kompensiert", "weer gecompenseerd", "Väderkompenserad", "skompensow. pogodą", "værkompensert", "compensation par l'extérieur", "hava durumuna göre dengelenmiş", "acqua compensata", "kompenzácia počasia", "dle venkovní teploty") MAKE_WORD_TRANSLATION(outside_basepoint, "outside basepoint", "Basispunkt Außentemp.", "buiten basispunt", "Utomhus baspunkt", "temp. zewn. z pkt. pocz.", "utendørs basispunkt", "point de base temp. ext.", "dış hava sıcaklığı taban noktası", "basepoint esterno", "vonkajší základný bod", "venkovní teplota s patním bodem") MAKE_WORD_TRANSLATION(functioning_mode, "functioning mode", "Funktionsweise", "functiemodus", "Driftläge", "tryb pracy", "driftsmodus", "mode de fonctionnement", "işletme konumu", "modalità di funzionamento", "funkčný režim", "provozní režim") -MAKE_WORD_TRANSLATION(unmixed, "unmixed", "ungemischt", "", "oshuntad", "niezmieszany", "", "", "", "", "nezmiešaný", "nemíchaný") // TODO translate -MAKE_WORD_TRANSLATION(unmixedIPM, "unmixed IPM", "ungemischt IPM", "", "oshuntad IPM", "niezmieszany IPM", "", "", "", "", "nezmiešaný IPM", "nemíchaný IPM") // TODO translate -MAKE_WORD_TRANSLATION(mixed, "mixed IPM", "gemischt IPM", "", "shuntad IPM", "zmieszany IPM", "", "", "", "", "zmiešaný IPM", "míchaný IPM") // TODO translate -MAKE_WORD_TRANSLATION(level, "level", "Level", "", "nivå", "", "", "", "", "", "úroveň", "úroveň") // TODO translate -MAKE_WORD_TRANSLATION(absolute, "absolute", "Absolut", "", "absolut", "", "", "", "", "", "absolútny", "absolutní") // TODO translate +MAKE_WORD_TRANSLATION(unmixed, "unmixed", "ungemischt", "ongemengd", "oshuntad", "niezmieszany", "umiksert", "non mélangé", "karışmamış", "non miscelato", "nezmiešaný", "nemíchaný") +MAKE_WORD_TRANSLATION(unmixedIPM, "unmixed IPM", "ungemischt IPM", "ongemengd IPM", "oshuntad IPM", "niezmieszany IPM", "umiksert IPM", "IPM non mélangé", "karışmamış IPM", "IPM non miscelato", "nezmiešaný IPM", "nemíchaný IPM") +MAKE_WORD_TRANSLATION(mixed, "mixed IPM", "gemischt IPM", "gemengd IPM", "shuntad IPM", "zmieszany IPM", "mikset IPM", "IPM mélangé", "karışık IPM", "IPM miscelato", "zmiešaný IPM", "míchaný IPM") +MAKE_WORD_TRANSLATION(level, "level", "Level", "niveau", "nivå", "poziom", "nivå", "niveau", "seviye", "livello", "úroveň", "úroveň") +MAKE_WORD_TRANSLATION(absolute, "absolute", "Absolut", "absoluut", "absolut", "absolutny", "absolutt", "absolu", "mutlak", "assoluto", "absolútny", "absolutní") // mixer MAKE_WORD_TRANSLATION(stopped, "stopped", "gestoppt", "gestopt", "stoppad", "zatrzymany", "stoppet", "arrêté", "durdu", "fermato", "zastavený", "zastavené") @@ -334,15 +334,15 @@ MAKE_WORD_TRANSLATION(open, "open", "offen", "open", "Öppen", "otwórz", "åpen MAKE_WORD_TRANSLATION(close, "close", "geschlossen", "Gesloten", "Stängd", "zamknij", "stengt", "fermé", "kapalı", "chiudere", "zatvoriť", "zavřít") // solar dhw -MAKE_WORD_TRANSLATION(cyl1, "cyl 1", "Zyl_1", "Cil 1", "Cyl 1", "cyl 1", "cyl 1", "cyl 1", "cly 1", "Cil 1", "cyl 1", "") -MAKE_WORD_TRANSLATION(cyl2, "cyl 2", "Zyl_2", "Cil 2", "Cyl 2", "cyl 2", "cyl 2", "cyl 2", "cly 1", "Cil 2", "cyl 2", "") +MAKE_WORD_TRANSLATION(cyl1, "cyl 1", "Zyl_1", "Cil 1", "Cyl 1", "cyl 1", "cyl 1", "cyl 1", "cly 1", "Cil 1", "cyl 1", "cyl 1") +MAKE_WORD_TRANSLATION(cyl2, "cyl 2", "Zyl_2", "Cil 2", "Cyl 2", "cyl 2", "cyl 2", "cyl 2", "cly 2", "Cil 2", "cyl 2", "cyl 2") // ventilation -MAKE_WORD_TRANSLATION(demand, "demand", "Bedarf", "vereist", "behov", "zapotrzebowanie", "", "", "talep", "richiesta", "požiadavka", "poptávka") // TODO translate -MAKE_WORD_TRANSLATION(intense, "intense", "Intensiv", "intensief", "intensiv", "intensywne", "", "", "yoğun", "intensivo", "intenzívne", "intenzivní") // TODO translate -MAKE_WORD_TRANSLATION(sleep, "sleep", "Einschlafen", "slaapmodus", "sova", "sen", "", "", "uyku", "notturno", "spiace", "spánek") // TODO translate -MAKE_WORD_TRANSLATION(partymode, "party", "Party", "party", "party", "impreza", "", "", "parti", "festa", "párty režim", "párty") // TODO translate -MAKE_WORD_TRANSLATION(fireplace, "fireplace", "Kamin", "haard", "Kamin", "kominek", "", "", "şömine", "camino", "krb", "krb") // TODO translate +MAKE_WORD_TRANSLATION(demand, "demand", "Bedarf", "vereist", "behov", "zapotrzebowanie", "krav", "demande", "talep", "richiesta", "požiadavka", "poptávka") +MAKE_WORD_TRANSLATION(intense, "intense", "Intensiv", "intensief", "intensiv", "intensywne", "intensiv", "intense", "yoğun", "intensivo", "intenzívne", "intenzivní") +MAKE_WORD_TRANSLATION(sleep, "sleep", "Einschlafen", "slaapmodus", "sova", "sen", "sove", "sommeil", "uyku", "notturno", "spiace", "spánek") +MAKE_WORD_TRANSLATION(partymode, "party", "Party", "party", "party", "impreza", "fest", "fête", "parti", "festa", "párty režim", "párty") +MAKE_WORD_TRANSLATION(fireplace, "fireplace", "Kamin", "haard", "Kamin", "kominek", "peis", "cheminée", "şömine", "camino", "krb", "krb") // SRC plus MAKE_WORD_TRANSLATION(chefhat, "mdi:chef-hat", "mdi:chef-hat") @@ -359,13 +359,13 @@ MAKE_WORD_TRANSLATION(washingmachine, "mdi:washing-machine", "mdi:washing-machin MAKE_WORD_TRANSLATION(bookshelf, "mdi:bookshelf", "mdi:bookshelf") // MQTT Discovery - this is special device entity for 'climate' -MAKE_TRANSLATION(haclimate, "haclimate", "mqtt discovery current room temperature", "Discovery aktuelle Raumtemperatur", "Discovery huidige kamertemperatuur", "MQTT Discovery för aktuell rumstemperatur", "termostat w HA", "HA Avlest temp", "", "Güncel osa sıcaklığı", "verifica temperatura ambiente attuale", "mqtt discovery aktuálna teplota v miestnosti", "mqtt discovery aktuální pokojová teplota") // TODO translate +MAKE_TRANSLATION(haclimate, "haclimate", "mqtt discovery current room temperature", "Discovery aktuelle Raumtemperatur", "Discovery huidige kamertemperatuur", "MQTT Discovery för aktuell rumstemperatur", "termostat w HA", "HA Avlest temp", "découverte mqtt température actuelle", "Güncel osa sıcaklığı", "verifica temperatura ambiente attuale", "mqtt discovery aktuálna teplota v miestnosti", "mqtt discovery aktuální pokojová teplota") // Entity translations: tag, mqtt, en, de, nl, sv, pl, no, fr, tr, it, sk, cz // Boiler -MAKE_TRANSLATION(chimneysweeper, "chimneysweeper", "chimney sweeper", "Schornsteinfeger", "", "", "", "", "", "", "kominár", "kominík") // TODO translate +MAKE_TRANSLATION(chimneysweeper, "chimneysweeper", "chimney sweeper", "Schornsteinfeger", "schoorsteenveger", "Sotare", "tryb kominiarza", "feier", "ramoneur", "baca temizleyici", "spazzacamino", "kominár", "kominík") MAKE_TRANSLATION(reset, "reset", "reset", "Reset", "Reset", "Återställ", "kasowanie komunikatu", "nullstill", "reset", "Sıfırla", "Reset", "reset", "reset") -MAKE_TRANSLATION(forceHeatingOff, "heatingoff", "force heating off", "Heizen abschalten", "", "Uppvärmning avstängd", "wymuś wyłączenie grzania", "", "", "", "", "vynútené vypnutie kúrenia", "vynutit vypnutí vytápění") // TODO translate +MAKE_TRANSLATION(forceHeatingOff, "heatingoff", "force heating off", "Heizen abschalten", "verwarming forceren uit", "Uppvärmning avstängd", "wymuś wyłączenie grzania", "tvungen oppvarming av", "forcer chauffage éteint", "ısıtmayı zorla kapat", "forzare riscaldamento spento", "vynútené vypnutie kúrenia", "vynutit vypnutí vytápění") MAKE_TRANSLATION(wwtapactivated, "tapactivated", "turn on/off", "Durchlauferhitzer aktiv", "zet aan/uit", "på/av", "system przygotowywania", "Varmtvann active", "ecs activée", "aç/kapa", "commuta on/off", "zapnúť/vypnúť", "zapnout/vypnout") MAKE_TRANSLATION(oilPreHeat, "oilpreheat", "oil preheating", "Ölvorwärmung", "Olie voorverwarming", "Förvärmning olja", "podgrzewanie oleju", "oljeforvarming", "préchauffage de l'huile", "Yakıt Ön ısıtma devrede", "preriscaldamento olio", "predohrev oleja", "předehřev oleje") MAKE_TRANSLATION(heatingActive, "heatingactive", "heating active", "Heizen aktiv", "Verwarming actief", "Uppvärmning aktiv", "c.o. aktywne", "oppvarming aktiv", "chauffage actif", "ısıtma devrede", "riscaldamento attivo", "vykurovanie aktívne", "Vytápění aktivní") @@ -398,7 +398,7 @@ MAKE_TRANSLATION(burnMinPower, "burnminpower", "burner min power", "Minimale Bre MAKE_TRANSLATION(burnMaxPower, "burnmaxpower", "burner max power", "Maximale Brennerleistung", "Maximaal brandervermogen", "Värmepanna Max Effekt", "maksymalna moc źródła ciepła", "varmekjele maks effekt", "puissance max brûleur", "kazan maksimum güç", "potenza massima bruciatore", "max. výkon horáka", "maximální výkon hořáku") MAKE_TRANSLATION(boilHystOn, "boilhyston", "hysteresis on temperature", "Einschaltdifferenz", "ketel aan hysterese verschil", "Hysteres aktiveringstemperatur", "histereza załączania", "hysterese på temperatur", "hysteresis température d'allumage", "gecikme sıcaklığı devrede", "isteresi sulla temperatura", "hysterézia teploty pri zapnutí", "hystereze teploty při zapnutí") MAKE_TRANSLATION(boilHystOff, "boilhystoff", "hysteresis off temperature", "Ausschaltdifferenz", "ketel uit hysterese verschil", "Hysteres inaktiveringstemperatur", "histereza wyłączania", "hysterese av temperatur", "hysteresis température d'extinction", "gecikme sıcaklığı kapalı", "isteresi fuori temperatura", "hysterézia teploty pri vypnutí", "hystereze teploty při vypnutí") -MAKE_TRANSLATION(boil2HystOn, "boil2hyston", "hysteresis stage 2 on temperature", "Einschaltdifferenz Stufe 2", "ketel aan hysterese verschil 2", "Hysteres aktiveringstemperatur 2", "histereza załączania stopnia 2", "", "hysteresis état 2 température d'allumage", "2. seviye gecikme sıcaklığı devrede", "stadio di isteresi 2 sulla temperatura", "2. stupeň hysterézie pri teplote", "hystereze teploty při zapnutí 2.stupeň") // TODO translate +MAKE_TRANSLATION(boil2HystOn, "boil2hyston", "hysteresis stage 2 on temperature", "Einschaltdifferenz Stufe 2", "ketel aan hysterese verschil 2", "Hysteres aktiveringstemperatur 2", "histereza załączania stopnia 2", "hysterese på temperatur 2", "hysteresis état 2 température d'allumage", "2. seviye gecikme sıcaklığı devrede", "stadio di isteresi 2 sulla temperatura", "2. stupeň hysterézie pri teplote", "hystereze teploty při zapnutí 2.stupeň") MAKE_TRANSLATION(boil2HystOff, "boil2hystoff", "hysteresis stage 2 off temperature", "Ausschaltdifferenz Stufe 2", "ketel uit hysterese verschil 2", "Hysteres inaktiveringstemperatur 2", "histereza wyłączania stopnia 2", "hysterese inaktiveringstemperatur 2", "hysteresis état 2 température d'extinction", "2. seviye gecikme sıcaklığı kapalı", "isteresi stadio 2 fuori temperatura", "teplota vypnutia hysterézneho stupňa 2", "hystereze teploty při vypnutí 2.stupeň") MAKE_TRANSLATION(setFlowTemp, "setflowtemp", "set flow temperature", "Sollwert Vorlauftemperatur", "Ingestelde aanvoertemperatuur", "Börvärde Flödestemperatur", "zadana temperatura zasilania", "innstilt turtemperatur", "température du flux définie", "akış sıcaklığını ayarla", "impostare temperatura di mandata", "nastavená teplota výstupu", "nastavená teplota výstupu") MAKE_TRANSLATION(setBurnPow, "setburnpow", "burner set power", "Sollwert Brennerleistung", "Ingesteld brandervermogen", "Värmepanna vald Effekt", "zadana moc palnika", "varmekjele valgt effekt", "puissance du brûleur définie", "kazan gücünü ayarla", "impostare potenza bruciatore", "nastavenie výkonu horáka", "nastavený výkon hořáku") @@ -418,18 +418,18 @@ MAKE_TRANSLATION(maintenanceType, "maintenance", "maintenance scheduled", "Wartu MAKE_TRANSLATION(maintenanceTime, "maintenancetime", "time to next maintenance", "Wartung in", "Onderhoud in", "Tid till nästa underhall", "czas do kolejnego przeglądu", "vedlikeholdstid", "durée avant la prochaine maintenance", "bakıma kalan süre", "tempo alla prossima manutenzione", "čas do ďalšej údržby", "čas do další údržby") MAKE_TRANSLATION(emergencyOps, "emergencyops", "emergency operation", "Notbetrieb", "Noodoperatie", "Nöddrift", "praca w trybie awaryjnym", "nøddrift", "opération d'urgence", "acil durum çalışması", "operazione di emergenza", "núdzová prevádzka", "nouzový provoz") MAKE_TRANSLATION(emergencyTemp, "emergencytemp", "emergency temperature", "Notfalltemperatur", "Noodtemperatuur", "Nöddrift temperatur", "temperatura w trybie awaryjnym", "nødtemperatur", "température d'urgence", "acil durum sıcaklığı", "temperatura di emergenza", "núdzová teplota", "nouzová teplota") -MAKE_TRANSLATION(pumpMode, "pumpmode", "boiler pump mode", "Kesselpumpenmodus", "Ketelpomp modus", "", "tryb pracy pompy kotła", "pumpemodus", "", "pompa modu", "modalità pompa caldaia", "režim kotlového čerpadla", "režim čerpadla kotle") // TODO translate -MAKE_TRANSLATION(pumpCharacter, "pumpcharacter", "boiler pump characteristic", "Charakteristik der Kesselpumpe", "karakteristiek ketelpomp", "pannpumpsegenskaper", "charakterystyka pompy kotłowej", "kjelepumpekarakteristikk", "caractéristique de la pompe de la chaudière", "gazan nasosy", "caratteristica della pompa della caldaia", "charakteristika kotlového čerpadla", "charakteristika čerpadla kotle") // TODO translate -MAKE_TRANSLATION(pumpOnTemp, "pumpontemp", "pump logic temperature", "Pumpenlogiktemperatur", "", "Pumplogiktemperatur", "", "", "", "", "", "teplota logiky čerpadla", "teplota logiky čerpadla") // TODO translate -MAKE_TRANSLATION(headertemp, "headertemp", "low loss header", "Hydr. Weiche", "open verdeler", "Fördelare", "sprzęgło hydrauliczne", "", "bouteille de déc. hydr.", "isı bloğu gidiş suyu sıc.", "comp. idr.", "nízkostratová hlavica", "hydraulický oddělovač") // TODO translate -MAKE_TRANSLATION(heatblock, "heatblock", "heating block", "Wärmezelle", "Aanvoertemp. warmtecel", "Värmeblock", "blok grzewczy", "", "départ corps de chauffe", "Hid.denge kabı sıcaklığı", "mandata scamb. pr.", "vykurovací blok", "blok topení") // TODO translate +MAKE_TRANSLATION(pumpMode, "pumpmode", "boiler pump mode", "Kesselpumpenmodus", "Ketelpomp modus", "Pannpumpsläge", "tryb pracy pompy kotła", "pumpemodus", "mode pompe chaudière", "kazan pompa modu", "modalità pompa caldaia", "režim kotlového čerpadla", "režim čerpadla kotle") +MAKE_TRANSLATION(pumpCharacter, "pumpcharacter", "boiler pump characteristic", "Charakteristik der Kesselpumpe", "karakteristiek ketelpomp", "pannpumpsegenskaper", "charakterystyka pompy kotłowej", "kjelepumpekarakteristikk", "caractéristique de la pompe de la chaudière", "kazan pompası karakteristiği", "caratteristica della pompa della caldaia", "charakteristika kotlového čerpadla", "charakteristika čerpadla kotle") +MAKE_TRANSLATION(pumpOnTemp, "pumpontemp", "pump logic temperature", "Pumpenlogiktemperatur", "pomplogica temperatuur", "Pumplogiktemperatur", "temperatura logiki pompy", "pumpelogikktemperatur", "température logique pompe", "pompa mantık sıcaklığı", "temperatura logica pompa", "teplota logiky čerpadla", "teplota logiky čerpadla") +MAKE_TRANSLATION(headertemp, "headertemp", "low loss header", "Hydr. Weiche", "open verdeler", "Fördelare", "sprzęgło hydrauliczne", "lav tap header", "bouteille de déc. hydr.", "isı bloğu gidiş suyu sıc.", "comp. idr.", "nízkostratová hlavica", "hydraulický oddělovač") +MAKE_TRANSLATION(heatblock, "heatblock", "heating block", "Wärmezelle", "Aanvoertemp. warmtecel", "Värmeblock", "blok grzewczy", "varmeblokk", "départ corps de chauffe", "Hid.denge kabı sıcaklığı", "mandata scamb. pr.", "vykurovací blok", "blok topení") -MAKE_TRANSLATION(curveOn, "curveon", "heatingcurve on", "Heizkurve an", "", "Värmekurva På", "", "", "", "", "", "vykurovacia krivka zapnutá", "topná křivka zapnutá") // TODO translate -MAKE_TRANSLATION(curveBase, "curvebase", "heatingcurve base", "Heizkurve Basis", "", "Värmekurva Bas", "", "", "", "", "", "základňa vykurovacej krivky", "základ topné křivky") // TODO translate -MAKE_TRANSLATION(curveEnd, "curveend", "heatingcurve end", "Heizkurve Ende", "", "Värmekurva Slut", "", "", "", "", "", "koniec vykurovacej krivky", "konec topné křivky") // TODO translate +MAKE_TRANSLATION(curveOn, "curveon", "heatingcurve on", "Heizkurve an", "stookkromme aan", "Värmekurva På", "krzywa grzewcza włączona", "varmekurve på", "courbe de chauffage activée", "ısıtma eğrisi açık", "curva di riscaldamento attiva", "vykurovacia krivka zapnutá", "topná křivka zapnutá") +MAKE_TRANSLATION(curveBase, "curvebase", "heatingcurve base", "Heizkurve Basis", "stookkromme basis", "Värmekurva Bas", "podstawa krzywej grzewczej", "varmekurve basis", "base de courbe de chauffage", "ısıtma eğrisi tabanı", "base curva di riscaldamento", "základňa vykurovacej krivky", "základ topné křivky") +MAKE_TRANSLATION(curveEnd, "curveend", "heatingcurve end", "Heizkurve Ende", "stookkromme einde", "Värmekurva Slut", "koniec krzywej grzewczej", "varmekurve slutt", "fin de courbe de chauffage", "ısıtma eğrisi sonu", "fine curva di riscaldamento", "koniec vykurovacej krivky", "konec topné křivky") // heatpump/compress specific -MAKE_TRANSLATION(upTimeTotal, "uptimetotal", "heatpump total uptime", "Gesamtbetriebszeit Wärmepumpe", "", "Total tid värmepump", "łączny czas pracy pompy ciepła", "", "", "", "", "celková doba prevádzky tepelného čerpadla", "celková doba provozu tepelného čerpadla") // TODO translate +MAKE_TRANSLATION(upTimeTotal, "uptimetotal", "heatpump total uptime", "Gesamtbetriebszeit Wärmepumpe", "totale bedrijfstijd warmtepomp", "Total tid värmepump", "łączny czas pracy pompy ciepła", "total driftstid varmepumpe", "temps de fonctionnement total pompe à chaleur", "toplam çalışma süresi ısı pompası", "tempo di funzionamento totale pompa di calore", "celková doba prevádzky tepelného čerpadla", "celková doba provozu tepelného čerpadla") MAKE_TRANSLATION(upTimeControl, "uptimecontrol", "total operating time heat", "Gesamtbetriebszeit Heizen", "Totale bedrijfstijd", "Total tid uppvärmning", "łączny czas generowania ciepła", "total driftstid", "durée totale de fonctionnement chauffage", "ısınma toplam işletme süresi", "Tempo di funzionamento totale riscaldamento", "celkový prevádzkový čas tepla", "celková provozní doba topení") MAKE_TRANSLATION(upTimeCompHeating, "uptimecompheating", "operating time compressor heating", "Betriebszeit Kompressor heizen", "Bedrijfstijd compressor verwarmingsbedrijf", "Total tid kompressor uppvärmning", "łączny czas ogrzewania (sprężarka)", "totaltid kompressor", "durée de fonctionnement compresseur chauffage", "ısı pompası ısınma işletme süresi", "tempo di funzionamento del compressore riscaldamento", "prevádzková doba vykurovania kompresora", "provozní doba kompresoru pro topení") MAKE_TRANSLATION(upTimeCompCooling, "uptimecompcooling", "operating time compressor cooling", "Betriebszeit Kompressor kühlen", "Bedrijfstijd compressor koelbedrijf", "Total tid kompressor kyla", "łączny czas chłodzenia (sprężarka)", "Total tid kompressor kjøling", "durée de fonctionnement compresseur refroidissement", "ısı pompası soğuma işletme süresi", "tempo di funzionamento del compressore raffreddamento", "doba prevádzky chladenia kompresora", "provozní doba kompresoru pro chlazení") @@ -456,7 +456,7 @@ MAKE_TRANSLATION(auxElecHeatNrgConsWw, "auxelecheatnrgcons", "aux elec. heater e MAKE_TRANSLATION(auxElecHeatNrgConsPool, "auxelecheatnrgconspool", "aux elec. heater energy consumption pool", "Energieverbrauch el. Zusatzheizung Pool", "Energieverbruik electrisch verwarmingselement voor zwembadbedrijf", "Energiförbrukning Eltillskott Pool", "energia pobrana przez grzałki na podgrzewanie basenu", "energiforbruk el. tilleggsvarme basseng", "consommation énergie electrique auxiliaire chauffage piscine", "ilave elektrikli ısıtıcı havuz toplam enerji tüketimi", "consumo di energia riscaldamento elettrico ausiliario piscina", "bazén spotreby energie pomocného elektrického ohrievača", "spotřeba energie pomocného el. ohřívače pro bazén") MAKE_TRANSLATION(hpCompOn, "hpcompon", "hp compressor", "WP Kompressor", "WP compressor", "VP Kompressor", "sprężarka pompy ciepła", "vp kompressor", "compresseur pompe à chaleur", "hp ısı pompası", "compressore pompa calore", "tč kompresor", "tč kompresor") -MAKE_TRANSLATION(coolingOn, "coolingon", "cooling on", "Kühlung an", "koelbedrijf", "Kyla", "chłodzenie włączone", "kjøling", "refroidissement", "soğutma", "", "chladenie", "chlazení zapnuto") // TODO translate +MAKE_TRANSLATION(coolingOn, "coolingon", "cooling on", "Kühlung an", "koelbedrijf", "Kyla", "chłodzenie włączone", "kjøling", "refroidissement", "soğutma", "", "chladenie", "chlazení zapnuto") // MAKE_TRANSLATION(hpHeatingOn, "hpheatingon", "hp heating", "WP Heizen", "WP verwarmingsbedrijf", "VP Uppvärmning", "pompa ciepła, ogrzewanie", "vp oppvarmning", "hp ısınıyor", "riscaldamento pompa calore", "vykurovanie hp", "topení hp") // MAKE_TRANSLATION(hpCoolingOn, "hpcoolingon", "hp cooling", "WP Kühlen", "WP koelbedrijf", "VP Kyla", "pompa ciepła, chłodzenie", "vp kjøling", "hp soğuyor", "raffreddamento pompa calore", "chladenie hp", "chlazení hp") // MAKE_TRANSLATION(hpWwOn, "hpdhwon", "hp", "WP", "WP", "VP Varmvatten", "pompa ciepła", "vp", "pompe à chaleur", "hp", "pompa calore", "hp", "hp") @@ -468,12 +468,12 @@ MAKE_TRANSLATION(hpBrineIn, "hpbrinein", "brine in/evaporator", "Sole in/Verdamp MAKE_TRANSLATION(hpBrineOut, "hpbrineout", "brine out/condenser", "Sole aus/Kondensator", "pekel uit/condensor", "Brine ut (kondensor)", "temperatura glikolu na wyjściu kolektora (TB1)", "Brine ut/kondensor", "sortie saumure/condenseur", "anahtar valfi", "salamoia nell uscita evaporatore", "výstup soľanky/kondenzátor", "solanka out/kondenzátor") MAKE_TRANSLATION(hpSwitchValve, "hpswitchvalve", "switch valve", "Schaltventil", "schakelklep", "Växelventil", "zawór przełączający", "skifteventil", "valve de commutation", "ısı pompası aktivitesi", "valvola commutazione pompa di calore", "prepínací ventil", "přepínací ventil") MAKE_TRANSLATION(hpActivity, "hpactivity", "compressor activity", "Kompressoraktivität", "Compressoractiviteit", "Kompressoraktivitet", "pompa ciepła, aktywność sprężarki", "kompressoraktivitet", "hp ısı pompası", "attività compressore", "činnosť kompresora", "činnost kompresoru") -MAKE_TRANSLATION(hpTargetSpd, "hptargetspd", "compressor target speed", "Kompressorsolldrehzahl", "", "", "", "", "", "", "", "kompresor cieľové otáčky", "cílová rychlost kompresoru") // TODO translate -MAKE_TRANSLATION(receiverValveVr0, "recvalve", "receiver valve VR0", "Eingangsventil VR0", "", "", "", "", "", "", "", "prijímač ventil VR0", "přijímací ventil VR0") // TODO translate -MAKE_TRANSLATION(expansionValveVr1, "expvalve", "expansion valve VR1", "Ausdehnungsventil VR1", "", "", "", "", "", "", "", "prijímač ventil VR1", "přijímací ventil VR1") // TODO translate +MAKE_TRANSLATION(hpTargetSpd, "hptargetspd", "compressor target speed", "Kompressorsolldrehzahl", "", "", "", "", "", "", "", "kompresor cieľové otáčky", "cílová rychlost kompresoru") +MAKE_TRANSLATION(receiverValveVr0, "recvalve", "receiver valve VR0", "Eingangsventil VR0", "", "", "", "", "", "", "", "prijímač ventil VR0", "přijímací ventil VR0") +MAKE_TRANSLATION(expansionValveVr1, "expvalve", "expansion valve VR1", "Ausdehnungsventil VR1", "", "", "", "", "", "", "", "prijímač ventil VR1", "přijímací ventil VR1") -MAKE_TRANSLATION(hpMaxPower, "hpmaxpower", "compressor max power", "max. Kompressorleistung", "", "Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "max výkon kompresora", "maximální výkon kompresoru") // TODO translate -MAKE_TRANSLATION(pvMaxComp, "pvmaxcomp", "pv compressor max power", "PV max. Kompressorleistung", "", "PV Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "pv max výkon kompresora", "maximální výkon PV kompresoru") // TODO translate +MAKE_TRANSLATION(hpMaxPower, "hpmaxpower", "compressor max power", "max. Kompressorleistung", "", "Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "max výkon kompresora", "maximální výkon kompresoru") +MAKE_TRANSLATION(pvMaxComp, "pvmaxcomp", "pv compressor max power", "PV max. Kompressorleistung", "", "PV Max. Kompressoreffekt", "maksymalna wydajność sprężarki", "", "", "", "", "pv max výkon kompresora", "maximální výkon PV kompresoru") MAKE_TRANSLATION(hpPower, "hppower", "compressor power output", "Kompressorleistung", "Compressorvermogen", "Kompressoreffekt", "moc wyjściowa sprężarki", "kompressoreffekt", "puissance de sortie compresseur", "ısı pompası güç çıkışı", "potenza uscita compressore", "výkon kompresora", "výstupní výkon kompresoru") MAKE_TRANSLATION(hpTc0, "hptc0", "heat carrier return (TC0)", "Kältemittelrücklauf (TC0)", "Koudemiddel retour (TC0)", "Värmebärare Retur (TC0)", "temperatura nośnika ciepła na powrocie (TC0)", "kjølemiddel retur (TC0)", "retour caloporteur (TC0)", "sıcak su dönüşü (TC0)", "ritorno del refrigerante (TC0)", "návrat nosiča tepla (TC0)", "návrat teplonosné látky (TC0)") MAKE_TRANSLATION(hpTc1, "hptc1", "heat carrier forward (TC1)", "Kältemittelvorlauf (TC1)", "Koudemiddel aanvoer (TC1)", "Värmebärare Framledning (TC1)", "temperatura nośnika ciepła pierwotna (TC1)", "kjølemiddel tur (TC1)", "avance caloporteur (TC1)", "sıcak su çıkışı (TC1)", "flusso di refrigerante (TC1)", "nosič tepla vpred (TC1)", "předání teplonosné látky (TC1)") @@ -487,8 +487,8 @@ MAKE_TRANSLATION(hpTr7, "hptr7", "refrigerant temperature gas side (condenser in MAKE_TRANSLATION(hpTl2, "hptl2", "air inlet temperature (TL2)", "Außenlufteintrittstemperatur (TL2)", "Temperatuur luchtinlaat (TL2)", "Luftintagstemperatur (TL2)", "temperatura wlotu powietrza (TL2)", "luftinntakstemperatur (TL2)", "température entrée air (TL2)", "hava giriş sıcaklığı (TL2)", "temperatura ingresso aria (TL2)", "teplota prívodu vzduchu (TL2)", "teplota vzduchu na vstupu (TL2)") MAKE_TRANSLATION(hpPl1, "hppl1", "low pressure side temperature (PL1)", "Niederdrucktemperatur (PL1)", "Temperatuur lage drukzijde (PL1)", "Temperatur Lågtryckssidan (PL1)", "temperatura po stronie niskiego ciśnienia (PL1)", "temperatur lavtrykksiden (PL1)", "température côté basse pression (PL1)", "düşük basınç tarafı sıcaklığı (PL1)", "temperatura lato bassa pressione (PL1)", "teplota na strane nízkeho tlaku (PL1)", "teplota na nízkotlaké straně (PL1)") MAKE_TRANSLATION(hpPh1, "hpph1", "high pressure side temperature (PH1)", "Hochdrucktemperatur (PH1)", "Temperatuur hoge drukzijde (PH1)", "Temperatur Högtryckssidan (PH1)", "temperatura po stronie wysokiego ciśnienia (PH1)", "Temperatur Høytrykksiden (PH1)", "température côté bhauteasse pression (PH1)", "yüksek basınç tarafı sıcaklığı (PH1)", "temperatura lato alta pressione (PH1)", "teplota na strane vysokého tlaku (PH1)", "teplota na vysokotlaké straně (PH1)") -MAKE_TRANSLATION(hpTa4, "hpta4", "drain pan temp (TA4)", "Kondensatorwanne (TA4)", "Temperatuur condensorafvoerbak (TA4)", " (TA4)", "temperatura ociekacza (TA4)", "kondenstråg temperatur (TA4)", " (TA4)", "tahliye sıcaklığı (TA4)", "temperatura condensatore (TA4)", "teplota vypúšťacej misky (TA4)", "teplota odvodňovací vany (TA4)") // TODO translate -MAKE_TRANSLATION(hpTw1, "hptw1", "reservoir temp (TW1)", "DHW Reservoir (TW1)", "(TW1)", "Varmvattentank Temperatur (TW1)", "temperatura zbiornika (TW1)", "(TW1)", "(TW1)", "(TW1)", "(TW1)", "teplota zásobníka (TW1)", "teplota v nádrži (TW1)") // TODO translate +MAKE_TRANSLATION(hpTa4, "hpta4", "drain pan temp (TA4)", "Kondensatorwanne (TA4)", "Temperatuur condensorafvoerbak (TA4)", " (TA4)", "temperatura ociekacza (TA4)", "kondenstråg temperatur (TA4)", " (TA4)", "tahliye sıcaklığı (TA4)", "temperatura condensatore (TA4)", "teplota vypúšťacej misky (TA4)", "teplota odvodňovací vany (TA4)") +MAKE_TRANSLATION(hpTw1, "hptw1", "reservoir temp (TW1)", "DHW Reservoir (TW1)", "(TW1)", "Varmvattentank Temperatur (TW1)", "temperatura zbiornika (TW1)", "(TW1)", "(TW1)", "(TW1)", "(TW1)", "teplota zásobníka (TW1)", "teplota v nádrži (TW1)") MAKE_TRANSLATION(hpInput1, "hpin1", "input 1 state", "Status Eingang 1", "Status input 1", "Status Ingång 1", "stan wejścia 1", "status inggang 1", "état entrée 1", "giriş 1 durumu", "stato ingresso 1", "stav vstupu 1", "stav vstupu 1") MAKE_TRANSLATION(hpInput2, "hpin2", "input 2 state", "Status Eingang 2", "Status input 2", "Status Ingång 2", "stan wejścia 2", "status inggang 2", "état entrée 2", "giriş 2 durumu", "stato ingresso 2", "stav vstupu 2", "stav vstupu 2") @@ -509,60 +509,60 @@ MAKE_TRANSLATION(auxHeaterOnly, "auxheateronly", "aux heater only", "nur Zusatzh MAKE_TRANSLATION(auxHeaterDelay, "auxheaterdelay", "aux heater on delay", "Zusatzheizer verzögert ein", "Bijverw. vertraagd aan", "Eltillskottfördröjning på", "opóźnienie włączenia dogrzewacza", "Tilleggsvarmer forsinket på", "Chauff app tempo marche", "ilave ısıtıcı beklemede", "ritardo riscaldatori addizionali", "oneskorenie prídavného ohrievača", "zpoždění zapnutí pomocného topení") MAKE_TRANSLATION(silentMode, "silentmode", "silent mode", "Silentmodus", "Stiller gebruik", "Tyst drift", "tryb cichy", "stille modus", "Fct silencieux", "sessiz mod", "modalità silenziosa", "tichý režim", "tichý režim") MAKE_TRANSLATION(minTempSilent, "mintempsilent", "min outside temp for silent mode", "Minimale Außentemperatur Silentmodus", "Stiller gebruik min. buitentemp", "Tyst drift min temp", "minimalna temperatura zewnętrzna dla trybu cichego", "atille modus min temp", "Fct silencieux: Temp. extérieure min.", "sessiz mod için min. dış ortam sıcaklığı", "modalità silenziosa temperatura esterna minima", "min. vonkajšia teplota pre tichý režim", "minimální venkovní teplota pro tichý režim") -MAKE_TRANSLATION(tempParMode, "tempparmode", "outside temp parallel mode", "Heizstab Parallelbetrieb", "Buitentemp. parallelbedr", "Parallelläge Utomhustemp.", "maksymalna temperatura zewnętrzna dla dogrzewacza", "", "Temp. ext. fct parallèle", "paralel mod dış ortam sıcaklığı", "modalità parallela temperatura esterna", "paralelný režim mimo teploty", "venkovní teplota pro paralelní režim") // TODO translate +MAKE_TRANSLATION(tempParMode, "tempparmode", "outside temp parallel mode", "Heizstab Parallelbetrieb", "Buitentemp. parallelbedr", "Parallelläge Utomhustemp.", "maksymalna temperatura zewnętrzna dla dogrzewacza", "", "Temp. ext. fct parallèle", "paralel mod dış ortam sıcaklığı", "modalità parallela temperatura esterna", "paralelný režim mimo teploty", "venkovní teplota pro paralelní režim") MAKE_TRANSLATION(auxHeatMixValve, "auxheatmix", "aux heater mixing valve", "Mischventil Zusatzheizer", "Bijverwarming menger", "Eltillskott Blandarventil", "mieszacz dogrzewacza", "eltilskudd blandeventil", "Chauffage auxiliaire mélangeur", "ilave ısıtıcı karışım vanası", "miscela riscaldatori addizionali", "zmiešavací ventil pomocného ohrievača", "směšovací ventil pomocného topení") MAKE_TRANSLATION(hpHystHeat, "hphystheat", "on/off hyst heat", "Schalthysterese Heizen", "Aan/uit-hysteresis in verw. bedrijf", "Hysteres Uppvärmning", "histereza wł./wył. ogrzewania", "På/av hysterese Oppvar.", "Hystérésis Marche en mode chauffage", "ısıtma gecikmesi", "isteresi di commutazione riscaldamento", "zapnutie/vypnutie hyst ohrevu", "hystereze zapnutí/vypnutí pro topení") MAKE_TRANSLATION(hpHystCool, "hphystcool", "on/off hyst cool", "Schalthysterese Kühlen", "Aan/uit-hysteresis in koelbedrijf", "Hysteres Kyla", "histereza wł./wył. chłodzenia", "hystrese kjøling", "Hystérésis Marche en mode refroidissement", "soğutma gecikmesi", "isteresi di commutazione raffreddamento", "zapnutie/vypnutie hyst chladenia", "hystereze zapnutí/vypnutí pro chlazení") MAKE_TRANSLATION(hpHystPool, "hphystpool", "on/off hyst pool", "Schalthysterese Pool", "an/uit-hysteresis in zwembadbedri", "Hysteres Pool", "histereza wł./wył. podgrzewania basenu", "hystrese basseng", "Hystérésis Marche en mode piscine", "havuz gecikmesi", "isteresi di commutazione piscina", "zapnutie/vypnutie hyst bazénu", "hystereze zapnutí/vypnutí pro bazén") MAKE_TRANSLATION(tempDiffHeat, "tempdiffheat", "temp diff TC3/TC0 heat", "Temp.diff. TC3/TC0 Heizen", "Temp.vers. TC3/TC0 verw", "Temperaturskillnad TC3/TC0 Uppvärmning", "różnica temperatur TC3/TC0 w trakcie ogrzewania", "temp. diff. TC3/TC0 oppvarm", "Delta T TC3/TC0 Chauff", "TC3-TC0 ısıtma sıcaklık farkı", "Delta T riscaldamento TC3/TC0", "teplotný rozdiel TC3/TC0 tepla", "rozdíl teplot TC3/TC0 pro topení") MAKE_TRANSLATION(tempDiffCool, "tempdiffcool", "temp diff TC3/TC0 cool", "Temp.diff. TC3/TC0 Kühlen", "Temp.vers. TC3/TC0 koel.", "Temperaturskillnad TC3/TC0 Kyla", "różnica temperatur TC3/TC0 w trakcie chłodzenia", "temp. diff. TC3/TC0 kjøling", "Delta T TC3/TC0 Refroid.", "TC3-TC0 soğutma sıcaklık farkı", "Delta T raffreddamento TC3/TC0", "teplotný rozdiel TC3/TC0 chladenie", "rozdíl teplot TC3/TC0 pro chlazení") -MAKE_TRANSLATION(silentFrom, "silentfrom", "silent mode from", "Silentmodus Start", "Start stille modus", "Tyst drift starttid", "początek trybu cichego", "stillemodus starter", "", "sessiz mod başlangıcı", "avvio della modalità silenziosa", "tichý režim od", "tichý režim od") // TODO translate -MAKE_TRANSLATION(silentTo, "silentto", "silent mode to", "Silentmodus Ende", "Einde stille modus", "Tyst drift stopptid", "koniec trybu cichego", "komfortmodus av", "", "sessiz mod bitişi", "spegnere modalità silenziosa", "tichý režim do", "tichý režim do") // TODO translate +MAKE_TRANSLATION(silentFrom, "silentfrom", "silent mode from", "Silentmodus Start", "Start stille modus", "Tyst drift starttid", "początek trybu cichego", "stillemodus starter", "", "sessiz mod başlangıcı", "avvio della modalità silenziosa", "tichý režim od", "tichý režim od") +MAKE_TRANSLATION(silentTo, "silentto", "silent mode to", "Silentmodus Ende", "Einde stille modus", "Tyst drift stopptid", "koniec trybu cichego", "komfortmodus av", "", "sessiz mod bitişi", "spegnere modalità silenziosa", "tichý režim do", "tichý režim do") MAKE_TRANSLATION(wwComfOffTemp, "comfoff", "comfort switch off", "Komfort Ausschalttemp.", "Comfort Uitschakeltemp.", "Komfort frånkopplingstemperatur", "temperatura wyłączania w trybie komfort", "eco modus utkoblingstem", "Confort Temp. d'arrêt", "konfor kapalı", "spegnimento modalità comfort", "komfortné vypnutie", "komfortní vypnutí") MAKE_TRANSLATION(wwEcoOffTemp, "ecooff", "eco switch off", "ECO Ausschalttemp.", "Eco Uitschakeltemp.", "Eko frånkopplingstemperatur", "temperatura wyłączania w trybie eko", "Øko avstengningstemp.", "Eco Temp. d'arrêt", "eko kapalı", "spegnimento modalità ECO", "eko vypínač", "eko vypnutí") MAKE_TRANSLATION(wwEcoPlusOffTemp, "ecoplusoff", "eco+ switch off", "ECO+ Ausschalttemp.", "Eco+ Uitschakeltemp.", "Eko+ frånkopplingstemperatur", "temperatura wyłączania w trybie eko+", "Øko+ avstengningstemp.", "Eco+ Temp. d'arrêt", "eko+ kapalı", "spegnimento modalità ECO+", "eko+ vypnutie", "eko+ vypnutí") -MAKE_TRANSLATION(wwComfDiffTemp, "comfdiff", "comfort diff", "Komfort Differenztemp.", "", "Komfort temperaturskillnad", "", "", "", "", "", "Komfortný rozdiel teploty", "komfortní rozdíl") // TODO translate -MAKE_TRANSLATION(wwEcoDiffTemp, "ecodiff", "eco diff", "ECO Differenztemp.", "", "Eko temperaturskillnad", "", "", "", "", "", "ECO rozdiel teploty", "eko rozdíl") // TODO translate -MAKE_TRANSLATION(wwEcoPlusDiffTemp, "ecoplusdiff", "eco+ diff", "ECO+ Differenztemp.", "", "Eko+ temperaturskillnad", "", "", "", "", "", "ECO+ rozdiel teploty", "eko+ rozdíl") // TODO translate -MAKE_TRANSLATION(wwComfStopTemp, "comfstop", "comfort stop temp", "Komfort Stopptemp.", "", "Komfort stopptemperatur", "", "", "", "", "", "komfortná stop teplota", "komfortní teplota vypnutí") // TODO translate -MAKE_TRANSLATION(wwEcoStopTemp, "ecostop", "eco stop temp", "ECO Stopptemp.", "", "Eko stopptemperatur", "", "", "", "", "", "ECO stop teplota", "eko teplota vypnutí") // TODO translate -MAKE_TRANSLATION(wwEcoPlusStopTemp, "ecoplusstop", "eco+ stop temp", "ECO+ Stopptemp.", "", "Eko+ stopptemperatur", "", "", "", "", "", "ECO+ stop teplota", "eko+ teplota vypnutí") // TODO translate +MAKE_TRANSLATION(wwComfDiffTemp, "comfdiff", "comfort diff", "Komfort Differenztemp.", "", "Komfort temperaturskillnad", "", "", "", "", "", "Komfortný rozdiel teploty", "komfortní rozdíl") +MAKE_TRANSLATION(wwEcoDiffTemp, "ecodiff", "eco diff", "ECO Differenztemp.", "", "Eko temperaturskillnad", "", "", "", "", "", "ECO rozdiel teploty", "eko rozdíl") +MAKE_TRANSLATION(wwEcoPlusDiffTemp, "ecoplusdiff", "eco+ diff", "ECO+ Differenztemp.", "", "Eko+ temperaturskillnad", "", "", "", "", "", "ECO+ rozdiel teploty", "eko+ rozdíl") +MAKE_TRANSLATION(wwComfStopTemp, "comfstop", "comfort stop temp", "Komfort Stopptemp.", "", "Komfort stopptemperatur", "", "", "", "", "", "komfortná stop teplota", "komfortní teplota vypnutí") +MAKE_TRANSLATION(wwEcoStopTemp, "ecostop", "eco stop temp", "ECO Stopptemp.", "", "Eko stopptemperatur", "", "", "", "", "", "ECO stop teplota", "eko teplota vypnutí") +MAKE_TRANSLATION(wwEcoPlusStopTemp, "ecoplusstop", "eco+ stop temp", "ECO+ Stopptemp.", "", "Eko+ stopptemperatur", "", "", "", "", "", "ECO+ stop teplota", "eko+ teplota vypnutí") -MAKE_TRANSLATION(auxHeatMode, "auxheatrmode", "aux heater mode", "Zusatzheizungsmodus", "Modus bijverwarmer", "Eltillskott Läge", "tryb pracy dogrzewacza po blokadzie z Zakładu Energetycznego", "tilleggsvarmer modus", "", "ilave ısıtıcı modu", "modalità riscaldatore addizionale", "režim pomocného ohrievača", "režim pomocného topení") // TODO translate +MAKE_TRANSLATION(auxHeatMode, "auxheatrmode", "aux heater mode", "Zusatzheizungsmodus", "Modus bijverwarmer", "Eltillskott Läge", "tryb pracy dogrzewacza po blokadzie z Zakładu Energetycznego", "tilleggsvarmer modus", "", "ilave ısıtıcı modu", "modalità riscaldatore addizionale", "režim pomocného ohrievača", "režim pomocného topení") MAKE_TRANSLATION(auxMaxLimit, "auxmaxlimit", "aux heater max limit", "Zusatzheizer max. Grenze", "Bijverwarmer grensinstelling maximaal", "Eltillskott max begränsning", "dogrzewacz, maksymalny limit", "tillegsvarme maksgrense", "ilave ısıtıcı maks limit", "limite massimo riscaldatore addizionale", "maximálny limit pomocného ohrievača", "maximální limit pomocného topení") MAKE_TRANSLATION(auxLimitStart, "auxlimitstart", "aux heater limit start", "Zusatzheizer Grenze Start", "Bijverwarmer grens voor start", "Eltillskott begränsningsstart", "dogrzewacz, początek ograniczenia", "tillegsvarme startgrense", "ilave ısıtıcı limir başlangıcı", "avvio limite massimo riscaldatore addizionale", "spustenie limitu pomocného ohrievača", "startovací limit pomocného topení") -MAKE_TRANSLATION(auxHeaterSource, "auxheatersource", "aux heater source", "Quelle Zusatzheizer", "", "", "", "", "", "", "", "pomocný zdroj tepla", "pomocný zdroj tepla") // TODO translate -MAKE_TRANSLATION(manDefrost, "mandefrost", "manual defrost", "Manuelle Enteisung", "Handmatige ontdooicyclus", "Manuell avfrostning", "ręczne odladzanie", "manuell avisning", "", "manuel buz çözme", "sbrinamento manuale", "manuálne odmrazovanie", "ruční odmrazování") // TODO translate -MAKE_TRANSLATION(pvCooling, "pvcooling", "cooling only with PV", "Kühlen nur mit PV", "Koelen alleen met solar PV", "Kyla endast med solpanel", "chłodzenie tylko z PV", "kjøling med solpanel", "", "sadece PV ile soğutma", "solo raffrescamento con solare", "Chladenie len s FV", "chlazení pouze s FV") // TODO translate -MAKE_TRANSLATION(hpCircPumpWw, "hpcircpump", "circulation pump available during dhw", "Zirkulation möglich bei WW-Bereitung", "Circulatiepomp WP beschikbaar tijdens ww", "Värmebärarpump på vid varmvattenberedning", "pompa cyrkulacji dostępna w trakcie c.w.u.", "sirkulasjonspumpe tilgjengelig under varmtvann", "", "SKS esnasında sirkülasyon pompasu uygun", "pompa di circolazione disponibile durante ACS", "obehové čerpadlo k dispozícii počas TÚV", "oběhové čerpadlo dostupné během TUV") // TODO translate -MAKE_TRANSLATION(vp_cooling, "vpcooling", "valve/pump cooling", "Ventil/Pumpe für Kühlen", "Klep koeling", "Ventil/Pump kyla", "zawór/pompa chłodzenia", "varmepumpe kjøling", "", "vana/pompa soğuyor", "valvola/pompa raffrescamento", "chladenie ventilu/čerpadla", "ventil/čerpadlo chlazení") // TODO translate -MAKE_TRANSLATION(VC0valve, "vc0valve", "VC0 valve", "VC0 Ventil", "Klep VC0", "VC0 Ventil", "zawór VC0", "vc0 ventil", "", "VC0 vana", "valvola VC0", "VC0 ventil", "ventil VC0") // TODO translate -MAKE_TRANSLATION(primePump, "primepump", "primary heatpump", "Hauptpumpe", "Hoofdpomp", "Primär Pump", "główna pompa ciepła", "primærpumpe", "", "ana ısı pompası", "pompa principale riscaldamento", "primárne tepelné čerpadlo", "primární tepelný čerpadlo") // TODO translate -MAKE_TRANSLATION(primePumpMod, "primepumpmod", "primary heatpump modulation", "Modulation Hauptpumpe", "Modulatie hoofdpomp", "Modulation Primär Pump", "wysterowanie głównej pompy ciepła", "primærpumpelast", "", "ana ısı pompası modülasyon", "pompa principale modulazione riscaldamento", "primárna modulácia tepelného čerpadla", "modulace primárního tepelného čerpadla") // TODO translate -MAKE_TRANSLATION(hp3wayValve, "hp3way", "3-way valve", "3-Wege-Ventil", "3-weg klep", "3-vägsventil", "zawór 3-drogowy pompy ciepła", "3-veisventil", "", "3 yollu vana", "valvola 3-vie", "3-cestný ventil", "3-cestný ventil") // TODO translate -MAKE_TRANSLATION(hp4wayValve, "hp4way", "4-way valve (VR4)", "4-Wege-Ventil (VR4)", "4-weg klep (VR4)", "4-vägsventil (VR4)", "zawór 4-drogowy pompy ciepła (VR4)", "4-veisventil (VR4)", "(VR4)", "4 yollu vana (VR4)", "valvola 4-vie (VR4)", "4-cestný ventil (VR4)", "4-cestný ventil (VR4)") // TODO translate -MAKE_TRANSLATION(elHeatStep1, "elheatstep1", "el. heater step 1", "El. Heizer Stufe 1", "Electrische bijverwarmer niveau 1", "Eltillskott Steg 1", "dogrzewacz poziom 1", "el-kolbe steg 1", "", "el.ısıtıcı adım 1", "riscaldatore elettrico livello 1", "krok 1 elektrického ohrievača", "elektrický ohřívač stupeň 1") // TODO translate -MAKE_TRANSLATION(elHeatStep2, "elheatstep2", "el. heater step 2", "El. Heizer Stufe 2", "Electrische bijverwarmer niveau 2", "Eltillskott Steg 2", "dogrzewacz poziom 2", "el-kolbe steg 2", "", "el.ısıtıcı adım 2", "riscaldatore elettrico livello 2", "krok 2 elektrického ohrievača", "elektrický ohřívač stupeň 2") // TODO translate -MAKE_TRANSLATION(elHeatStep3, "elheatstep3", "el. heater step 3", "El. Heizer Stufe 3", "Electrische bijverwarmer niveau 3", "Eltillskott Steg 3", "dogrzewacz poziom 3", "el-kolbe steg 3", "", "el.ısıtıcı adım 3", "riscaldatore elettrico livello 3", "krok 3 elektrického ohrievača", "elektrický ohřívač stupeň 3") // TODO translate -MAKE_TRANSLATION(wwAlternatingOper, "alternatingop", "alternating operation", "Wechselbetrieb", "Wisselbedrijf ww", "Växeldrift", "praca naprzemienna", "alternativ drift", "", "sıcak kullanım suyu alternatif işletim", "funzionamento alternato", "striedavá prevádzka", "střídavý provoz") // TODO translate -MAKE_TRANSLATION(wwAltOpPrioHeat, "altopprioheat", "prioritise heating during dhw", "Heizen bevorzugt vor WW", "Proriteit verwarming boven ww", "Varmvattenprioritet", "czas na ogrzewanie w trakcie c.w.u", "prioritert oppvarmning", "", "sıcak kullanım suyu esnasında ısıtmayı öne al", "dare la priorità al riscaldamento durante l'ACS", "Uprednostniť ohrev počas TÚV", "prioritizace vytápění během TUV") // TODO translate -MAKE_TRANSLATION(wwAltOpPrioWw, "altopprio", "prioritise dhw during heating", "bevorzugt vor Heizen", "Prioriteit ww boven verwarming", "Värmeprioritet", "czas na c.w.u w trakcie ogrzewania", "prioritert varmtvann", "", "ısıtma esnasında sıcak kullanım suyunu öne al", "dare priorità all'acqua calda durante il riscaldamento", "uprednostniť TÚV počas ohrevu", "prioritizace TUV během vytápění") // TODO translate -MAKE_TRANSLATION(hpEA0, "hpea0", "condensate reservoir heating (EA0)", "Heizung Kondensatwanne (EA0)", "", "Värme kondenstråg (EA0)", "ogrzewanie zbiornika kondensatu (EA0)", "", "", "", "", "ohrievanie zásobníka kondenzátu (EA0)", "ohřev kondenzátní nádrže (EA0)") // TODO translate -MAKE_TRANSLATION(boost, "boost", "boost mode", "Boost", "", "Boost-läge", "tryb wzmocnienia (boost)", "", "", "", "", "boost režim", "režim boost") // TODO translate -MAKE_TRANSLATION(boosttime, "boosttime", "boost time", "Boost-Dauer", "", "Boost-tid", "czas trwania wzmocnienia", "", "", "", "", "čas trvania posilnenia", "čas trvání režimu boost") // TODO translate -MAKE_TRANSLATION(hpPumpMode, "hppumpmode", "primary heatpump mode", "primärer Wärmepumpenmodus", "", "Driftläge värmebärarpump", "tryb pracy głównej pompy ciepła", "", "", "", "", "režim primárneho tepelného čerpadla", "režim primárního tepelného čerpadla") // TODO translate -MAKE_TRANSLATION(instantstart, "instantstart", "instant start", "Sofortstart", "", "Gränsvärde direktstart värme", "natychmiastowy start", "", "", "", "", "okamžité spustenie", "okamžité spuštění") // TODO translate -MAKE_TRANSLATION(heatondelay, "heatondelay", "heat-on delay", "Einschaltverzögerung Heizen", "", "Inkopplingsfördröjning värme", "opóźnienie włączania ogrzewania", "", "", "", "", "Oneskorenie zapnutia kúreni", "zpoždění zapnutí topení") // TODO translate -MAKE_TRANSLATION(heatoffdelay, "heatoffdelay", "heat-off delay", "Ausschaltverzögerung Heizen", "", "Frånkopplingsfördröjning värme", "opóźnienie włączania ogrzewania", "", "", "", "", "Oneskorenie vypnutia kúrenia", "zpoždění vypnutí topení") // TODO translate -MAKE_TRANSLATION(hpSetDiffPress, "hpsetdiffpress", "set differential pressure", "Pumpensolldruck", "", "VP Tryckskillnad", "różnica ciśnień", "", "", "", "", "nastaviť diferenčný tlak", "nastavení rozdílového tlaku") // TODO translate -MAKE_TRANSLATION(hpFan, "fan", "fan", "Lüfter", "", "Fläkt", "wentylator", "", "", "", "", "ventilátor", "ventilátor") // TODO translate -MAKE_TRANSLATION(fanSpd, "fanspd", "fan speed", "Lüfter Geschw.", "", "Fläkt", "wentylator", "", "", "", "", "ventilátor", "ventilátor") // TODO translate -MAKE_TRANSLATION(hpShutdown, "shutdown", "shutdown", "Abschalten", "", "Stäng av", "wyłączenie", "", "", "", "", "vypnutie", "vypnutí") // TODO translate -MAKE_TRANSLATION(pc0Flow, "pc0flow", "Flow PC0", "Durchfluss PC0", "", "Flöde värmebärarpump", "", "", "", "", "", "prietok PC0", "průtok PC0") // TODO translate -MAKE_TRANSLATION(pc1Flow, "pc1flow", "Flow PC1", "Durchfluss PC1", "", "Flöde cirkulationspump", "", "", "", "", "", "prietok PC1", "průtok PC1") // TODO translate -MAKE_TRANSLATION(pc1On, "pc1on", "PC1", "PC1", "", "Cirkulationspump", "", "", "", "", "", "PC1", "PC1") // TODO translate -MAKE_TRANSLATION(pc1Rate, "pc1rate", "PC1 rate", "PC1 Rate", "", "Hastighet cirkulationspump", "", "", "", "", "", "sadzba PC1", "míra PC1") // TODO translate +MAKE_TRANSLATION(auxHeaterSource, "auxheatersource", "aux heater source", "Quelle Zusatzheizer", "", "", "", "", "", "", "", "pomocný zdroj tepla", "pomocný zdroj tepla") +MAKE_TRANSLATION(manDefrost, "mandefrost", "manual defrost", "Manuelle Enteisung", "Handmatige ontdooicyclus", "Manuell avfrostning", "ręczne odladzanie", "manuell avisning", "", "manuel buz çözme", "sbrinamento manuale", "manuálne odmrazovanie", "ruční odmrazování") +MAKE_TRANSLATION(pvCooling, "pvcooling", "cooling only with PV", "Kühlen nur mit PV", "Koelen alleen met solar PV", "Kyla endast med solpanel", "chłodzenie tylko z PV", "kjøling med solpanel", "", "sadece PV ile soğutma", "solo raffrescamento con solare", "Chladenie len s FV", "chlazení pouze s FV") +MAKE_TRANSLATION(hpCircPumpWw, "hpcircpump", "circulation pump available during dhw", "Zirkulation möglich bei WW-Bereitung", "Circulatiepomp WP beschikbaar tijdens ww", "Värmebärarpump på vid varmvattenberedning", "pompa cyrkulacji dostępna w trakcie c.w.u.", "sirkulasjonspumpe tilgjengelig under varmtvann", "", "SKS esnasında sirkülasyon pompasu uygun", "pompa di circolazione disponibile durante ACS", "obehové čerpadlo k dispozícii počas TÚV", "oběhové čerpadlo dostupné během TUV") +MAKE_TRANSLATION(vp_cooling, "vpcooling", "valve/pump cooling", "Ventil/Pumpe für Kühlen", "Klep koeling", "Ventil/Pump kyla", "zawór/pompa chłodzenia", "varmepumpe kjøling", "", "vana/pompa soğuyor", "valvola/pompa raffrescamento", "chladenie ventilu/čerpadla", "ventil/čerpadlo chlazení") +MAKE_TRANSLATION(VC0valve, "vc0valve", "VC0 valve", "VC0 Ventil", "Klep VC0", "VC0 Ventil", "zawór VC0", "vc0 ventil", "", "VC0 vana", "valvola VC0", "VC0 ventil", "ventil VC0") +MAKE_TRANSLATION(primePump, "primepump", "primary heatpump", "Hauptpumpe", "Hoofdpomp", "Primär Pump", "główna pompa ciepła", "primærpumpe", "", "ana ısı pompası", "pompa principale riscaldamento", "primárne tepelné čerpadlo", "primární tepelný čerpadlo") +MAKE_TRANSLATION(primePumpMod, "primepumpmod", "primary heatpump modulation", "Modulation Hauptpumpe", "Modulatie hoofdpomp", "Modulation Primär Pump", "wysterowanie głównej pompy ciepła", "primærpumpelast", "", "ana ısı pompası modülasyon", "pompa principale modulazione riscaldamento", "primárna modulácia tepelného čerpadla", "modulace primárního tepelného čerpadla") +MAKE_TRANSLATION(hp3wayValve, "hp3way", "3-way valve", "3-Wege-Ventil", "3-weg klep", "3-vägsventil", "zawór 3-drogowy pompy ciepła", "3-veisventil", "", "3 yollu vana", "valvola 3-vie", "3-cestný ventil", "3-cestný ventil") +MAKE_TRANSLATION(hp4wayValve, "hp4way", "4-way valve (VR4)", "4-Wege-Ventil (VR4)", "4-weg klep (VR4)", "4-vägsventil (VR4)", "zawór 4-drogowy pompy ciepła (VR4)", "4-veisventil (VR4)", "(VR4)", "4 yollu vana (VR4)", "valvola 4-vie (VR4)", "4-cestný ventil (VR4)", "4-cestný ventil (VR4)") +MAKE_TRANSLATION(elHeatStep1, "elheatstep1", "el. heater step 1", "El. Heizer Stufe 1", "Electrische bijverwarmer niveau 1", "Eltillskott Steg 1", "dogrzewacz poziom 1", "el-kolbe steg 1", "", "el.ısıtıcı adım 1", "riscaldatore elettrico livello 1", "krok 1 elektrického ohrievača", "elektrický ohřívač stupeň 1") +MAKE_TRANSLATION(elHeatStep2, "elheatstep2", "el. heater step 2", "El. Heizer Stufe 2", "Electrische bijverwarmer niveau 2", "Eltillskott Steg 2", "dogrzewacz poziom 2", "el-kolbe steg 2", "", "el.ısıtıcı adım 2", "riscaldatore elettrico livello 2", "krok 2 elektrického ohrievača", "elektrický ohřívač stupeň 2") +MAKE_TRANSLATION(elHeatStep3, "elheatstep3", "el. heater step 3", "El. Heizer Stufe 3", "Electrische bijverwarmer niveau 3", "Eltillskott Steg 3", "dogrzewacz poziom 3", "el-kolbe steg 3", "", "el.ısıtıcı adım 3", "riscaldatore elettrico livello 3", "krok 3 elektrického ohrievača", "elektrický ohřívač stupeň 3") +MAKE_TRANSLATION(wwAlternatingOper, "alternatingop", "alternating operation", "Wechselbetrieb", "Wisselbedrijf ww", "Växeldrift", "praca naprzemienna", "alternativ drift", "", "sıcak kullanım suyu alternatif işletim", "funzionamento alternato", "striedavá prevádzka", "střídavý provoz") +MAKE_TRANSLATION(wwAltOpPrioHeat, "altopprioheat", "prioritise heating during dhw", "Heizen bevorzugt vor WW", "Proriteit verwarming boven ww", "Varmvattenprioritet", "czas na ogrzewanie w trakcie c.w.u", "prioritert oppvarmning", "", "sıcak kullanım suyu esnasında ısıtmayı öne al", "dare la priorità al riscaldamento durante l'ACS", "Uprednostniť ohrev počas TÚV", "prioritizace vytápění během TUV") +MAKE_TRANSLATION(wwAltOpPrioWw, "altopprio", "prioritise dhw during heating", "bevorzugt vor Heizen", "Prioriteit ww boven verwarming", "Värmeprioritet", "czas na c.w.u w trakcie ogrzewania", "prioritert varmtvann", "", "ısıtma esnasında sıcak kullanım suyunu öne al", "dare priorità all'acqua calda durante il riscaldamento", "uprednostniť TÚV počas ohrevu", "prioritizace TUV během vytápění") +MAKE_TRANSLATION(hpEA0, "hpea0", "condensate reservoir heating (EA0)", "Heizung Kondensatwanne (EA0)", "", "Värme kondenstråg (EA0)", "ogrzewanie zbiornika kondensatu (EA0)", "", "", "", "", "ohrievanie zásobníka kondenzátu (EA0)", "ohřev kondenzátní nádrže (EA0)") +MAKE_TRANSLATION(boost, "boost", "boost mode", "Boost", "", "Boost-läge", "tryb wzmocnienia (boost)", "", "", "", "", "boost režim", "režim boost") +MAKE_TRANSLATION(boosttime, "boosttime", "boost time", "Boost-Dauer", "", "Boost-tid", "czas trwania wzmocnienia", "", "", "", "", "čas trvania posilnenia", "čas trvání režimu boost") +MAKE_TRANSLATION(hpPumpMode, "hppumpmode", "primary heatpump mode", "primärer Wärmepumpenmodus", "", "Driftläge värmebärarpump", "tryb pracy głównej pompy ciepła", "", "", "", "", "režim primárneho tepelného čerpadla", "režim primárního tepelného čerpadla") +MAKE_TRANSLATION(instantstart, "instantstart", "instant start", "Sofortstart", "", "Gränsvärde direktstart värme", "natychmiastowy start", "", "", "", "", "okamžité spustenie", "okamžité spuštění") +MAKE_TRANSLATION(heatondelay, "heatondelay", "heat-on delay", "Einschaltverzögerung Heizen", "", "Inkopplingsfördröjning värme", "opóźnienie włączania ogrzewania", "", "", "", "", "Oneskorenie zapnutia kúreni", "zpoždění zapnutí topení") +MAKE_TRANSLATION(heatoffdelay, "heatoffdelay", "heat-off delay", "Ausschaltverzögerung Heizen", "", "Frånkopplingsfördröjning värme", "opóźnienie włączania ogrzewania", "", "", "", "", "Oneskorenie vypnutia kúrenia", "zpoždění vypnutí topení") +MAKE_TRANSLATION(hpSetDiffPress, "hpsetdiffpress", "set differential pressure", "Pumpensolldruck", "", "VP Tryckskillnad", "różnica ciśnień", "", "", "", "", "nastaviť diferenčný tlak", "nastavení rozdílového tlaku") +MAKE_TRANSLATION(hpFan, "fan", "fan", "Lüfter", "", "Fläkt", "wentylator", "", "", "", "", "ventilátor", "ventilátor") +MAKE_TRANSLATION(fanSpd, "fanspd", "fan speed", "Lüfter Geschw.", "", "Fläkt", "wentylator", "", "", "", "", "ventilátor", "ventilátor") +MAKE_TRANSLATION(hpShutdown, "shutdown", "shutdown", "Abschalten", "", "Stäng av", "wyłączenie", "", "", "", "", "vypnutie", "vypnutí") +MAKE_TRANSLATION(pc0Flow, "pc0flow", "Flow PC0", "Durchfluss PC0", "", "Flöde värmebärarpump", "", "", "", "", "", "prietok PC0", "průtok PC0") +MAKE_TRANSLATION(pc1Flow, "pc1flow", "Flow PC1", "Durchfluss PC1", "", "Flöde cirkulationspump", "", "", "", "", "", "prietok PC1", "průtok PC1") +MAKE_TRANSLATION(pc1On, "pc1on", "PC1", "PC1", "", "Cirkulationspump", "", "", "", "", "", "PC1", "PC1") +MAKE_TRANSLATION(pc1Rate, "pc1rate", "PC1 rate", "PC1 Rate", "", "Hastighet cirkulationspump", "", "", "", "", "", "sadzba PC1", "míra PC1") // hybrid heatpump MAKE_TRANSLATION(hybridStrategy, "hybridstrategy", "hybrid control strategy", "Hybrid-Steuerungsstrategie", "Hybride strategie", "Hybrid kontrollstrategi", "strategia sterowania hybrydowego", "hybrid kontrollstrategi", "stratégie contrôle hybride", "hibrit kontrol stratejisi", "strategia comtrollo ibrido", "hybridná stratégia riadenia", "strategie hybridního řízení") @@ -600,11 +600,11 @@ MAKE_TRANSLATION(valveReturn, "valvereturn", "return valve", "Rückflussventil", MAKE_TRANSLATION(aPumpMod, "apumpmod", "alternative hs pump modulation", "Alternative WE-Pumpenmodulation", "Alternatieve warmtebron pomp modulatie", "Alternativ Pumpmodulering Värmekälla", "modulacja pompy alternatywnego źródła ciepła", "alternativ pumpemodulering varmekilde", "modulation alternative pompe hs", "alternatif ısı kaynağı pompa modülasyonu", "pompa modulazione alternativa hs", "alternatívna modulácia čerpadla hs", "alternativní modulace čerpadla hs") MAKE_TRANSLATION(heatSource, "heatsource", "alternative heating active", "Alternativer Wärmeerzeuger aktiv", "Alternatieve warmtebron aktief", "Alternativ Värmekälla aktiv", "aktywne alternatywne źródło ciepła", "alternativ varmekilde aktiv", "chauffage alternatif actif", "alternatif ısınma devrede", "riscaldamento alternativo attivo", "alternatívne kúrenie aktívne", "alternativní vytápění aktivní") MAKE_TRANSLATION(aPump, "apump", "alternative hs pump", "Alternative WE-Pumpe", "Alternatieve warmtebron pomp", "Alternativ Pump Värmekälla", "pompy alternatywnego źródła ciepła", "alternativ pumpe varmekilde", "alternative pompe hs", "alternatif ısı kaynağı pompası", "pompa alternativa hs", "alternatívne čerpadlo hs", "alternativní čerpadlo hs") -MAKE_TRANSLATION(burner, "burner", "burner", "Brenner", "Brander", "Brännare", "palnik", "", "", "kazan", "bruciatore", "horák", "hořák") // TODO translate -MAKE_TRANSLATION(heatRequest, "heatrequest", "heat request", "Wärmeanforderung", "Warmtevraag", "Värmebehov", "zapotrzebowanie na ciepło", "varmeforespørsel", "", "ısı talebi", "richiesta calore", "požiadavka na teplo", "požadavek na teplo") // TODO translate -MAKE_TRANSLATION(blockRemain, "blockremain", "remaining blocktime", "verbleibende Sperrzeit", "Resterende bloktijd", "Återstående blockeringstid", "czas do końca blokady", "gjenstående blokkeringstid", "", "kalan blok süresi", "tempo di blocco rimanente", "zostávajúci čas blokovania", "zbývající doba blokace") // TODO translate -MAKE_TRANSLATION(blockRemainWw, "blockremaindhw", "remaining blocktime dhw", "verbleibende Sperrzeit WW", "Resterende bloktijd ww", "Återstående blockeringstid varmvatten", "czas do końca blokady c.w.u.", "gjenværende blokkeringstid bereder", "", "kalan sıcak kullanım suyu blok süresi", "tempo di blocco rimanente ACS", "zostávajúci čas blokovania TÚV", "zbývající doba blokace TUV") // TODO translate -MAKE_TRANSLATION(flueGasTemp, "fluegastemp", "flue gas temperature", "Abgastemperatur", "Rookafvoertemperatuur", "Rökgastemperatur", "temperatura spalin", "røykgasstemperatur", "", "baca gazı sıcaklığı", "temperatura gas di scarico", "teplota spalín", "teplota spalin") // TODO translate +MAKE_TRANSLATION(burner, "burner", "burner", "Brenner", "Brander", "Brännare", "palnik", "", "", "kazan", "bruciatore", "horák", "hořák") +MAKE_TRANSLATION(heatRequest, "heatrequest", "heat request", "Wärmeanforderung", "Warmtevraag", "Värmebehov", "zapotrzebowanie na ciepło", "varmeforespørsel", "", "ısı talebi", "richiesta calore", "požiadavka na teplo", "požadavek na teplo") +MAKE_TRANSLATION(blockRemain, "blockremain", "remaining blocktime", "verbleibende Sperrzeit", "Resterende bloktijd", "Återstående blockeringstid", "czas do końca blokady", "gjenstående blokkeringstid", "", "kalan blok süresi", "tempo di blocco rimanente", "zostávajúci čas blokovania", "zbývající doba blokace") +MAKE_TRANSLATION(blockRemainWw, "blockremaindhw", "remaining blocktime dhw", "verbleibende Sperrzeit WW", "Resterende bloktijd ww", "Återstående blockeringstid varmvatten", "czas do końca blokady c.w.u.", "gjenværende blokkeringstid bereder", "", "kalan sıcak kullanım suyu blok süresi", "tempo di blocco rimanente ACS", "zostávajúci čas blokovania TÚV", "zbývající doba blokace TUV") +MAKE_TRANSLATION(flueGasTemp, "fluegastemp", "flue gas temperature", "Abgastemperatur", "Rookafvoertemperatuur", "Rökgastemperatur", "temperatura spalin", "røykgasstemperatur", "", "baca gazı sıcaklığı", "temperatura gas di scarico", "teplota spalín", "teplota spalin") MAKE_TRANSLATION(vr2Config, "vr2config", "vr2 configuration", "VR2 Konfiguration", "VR2 configuratie", "VR2 Konfiguration", "konfiguracja VR2", "vr2 konfigurasjon", "configuration vr2", "vr2 ayarı", "configurazione VR2", "konfigurácia vr2", "konfigurace VR2") MAKE_TRANSLATION(ahsActivated, "ahsactivated", "alternate heat source activation", "Alt. Wärmeerzeuger aktiviert", "Altenatieve warmtebron geactiveerd", "Alternativ värmekälla aktivering", "aktywacja alternatywnego źródła ciepła", "alternativ varmekilde aktivering", "activation source chaleur alternative", "alternatif ısı kaynağı devrede", "attivazione fonte di calore alternativa", "aktivácia alternatívneho zdroja tepla", "aktivace alternativního zdroje tepla") @@ -623,37 +623,37 @@ MAKE_TRANSLATION(blockHyst, "blockhyst", "hyst. for boiler block", "Hysterese Sp MAKE_TRANSLATION(releaseWait, "releasewait", "boiler release wait time", "Wartezeit Kesselfreigabe", "Wachttijd ketel vrijgave", "Väntetid Frisläppning", "czas oczekiwania na zwolnienie kotła", "kjele frigjøringsventetid", "temps attente libération chaudière", "kazan tahliyesi bekleme süresi", "tempo di attesa sblocco caldaia", "doba čakania na uvoľnenie kotla", "doba čekání na uvolnění kotle") // energy -MAKE_TRANSLATION(nrgTotal, "nrgtotal", "total energy", "Gesamtenergie", "", "Avgiven energi totalt", "całkowita energia", "", "", "", "", "celková energia", "celková energie") // TODO translate -MAKE_TRANSLATION(nrgHeat, "nrgheat", "energy heating", "Energie Heizen", "", "Avgiven energi värme", "energia na ogrzewanie", "", "", "ısıtma enerjisi", "energia vykurovania", "energetické vykurovanie", "energie pro vytápění") // TODO translate -MAKE_TRANSLATION(nrgCool, "nrgcool", "energy cooling", "Energie Kühlen", "", "Avgiven energi kyla", "", "", "", "", "", "energia chladenia", "energie pro chlazení") // TODO translate -MAKE_TRANSLATION(nrgWw, "nrg", "energy", "Energie", "", "Avgiven energi varmvatten", "energia", "", "", "sıcak kullanım suyu enerjisi", "", "energia", "energie") // TODO translate -MAKE_TRANSLATION(nrgHeat2, "nrgheat2", "energy heating 2", "Energie Heizen 2", "", "Avgiven energi värme 2", "energia na ogrzewanie 2", "", "", "ısıtma enerjisi 2", "", "energia vykurovania 2", "energie pro vytápění 2") // TODO translate -MAKE_TRANSLATION(nrgWw2, "nrg2", "energy 2", "Energie 2", "", "", "energia 2", "", "Avgiven energi varmvatten 2", "sıcak kullanım suyu enerjisi 2", "", "energia 2", "energie 2") // TODO translate -MAKE_TRANSLATION(nomPower, "nompower", "nominal Power", "Brennerleistung", "", "Nominell effekt", "moc nominalna", "", "", "nominal güç", "", "nominálny výkon", "nominální výkon") // TODO translate -MAKE_TRANSLATION(meterTotal, "metertotal", "meter total", "Gesamtmessung", "", "Förbrukad energi totalt", "licznik całkowity", "", "", "", "", "počítadlo celkom", "počítadlo celkem") // TODO translate -MAKE_TRANSLATION(meterComp, "metercomp", "meter compressor", "Messung Kompressor", "", "Förbrukad energi kompressor", "licznik sprężarki", "", "", "", "", "počítadlo kompresor", "počítadlo kompresoru") // TODO translate -MAKE_TRANSLATION(meterEHeat, "metereheat", "meter e-heater", "Messung E-Heizer", "", "Förbrukad energi eltillskott", "licznik dogrzewacza", "", "", "", "", "počítadlo e-ohrievača", "počítadlo elektrického topení") // TODO translate -MAKE_TRANSLATION(meterHeat, "meterheat", "meter heating", "Messung Heizen", "", "Förbrukad energi värme", "licznik ogrzewania", "", "", "", "", "počítadlo kúrenia", "počítadlo vytápění") // TODO translate -MAKE_TRANSLATION(meterCool, "metercool", "meter cooling", "Messung Kühlen", "", "Förbrukad energi kyla", "", "", "", "", "", "počítadlo chladenia", "počítadlo chlazení") // TODO translate -MAKE_TRANSLATION(meterWw, "meter", "meter", "Messung", "", "", "licznik", "", "Förbrukad energi varmvatten", "", "", "počítadlo", "počítadlo") // TODO translate -MAKE_TRANSLATION(gasMeterHeat, "gasmeterheat", "gas meter heating", "Gaszähler Heizen", "", "Gasförbrukning värme", "licznik gazu na ogrzewanie", "", "", "", "", "počítadlo plynu kúrenia", "počítadlo plynu pro vytápění") // TODO translate -MAKE_TRANSLATION(gasMeterWw, "gasmeter", "gas meter", "Gaszähler", "", "Gasförbrukning varmvatten", "licznik gazu", "", "", "", "", "počítadlo plynu", "počítadlo plynu") // TODO translate -MAKE_TRANSLATION(hpCurrPower, "hpcurrpower", "compressor current power", "akt. Kompressorleistung", "", "Kompressoreffekt", "", "", "", "", "", "aktuálny výkon kompresoru", "aktuální výkon kompresoru") // TODO translate -MAKE_TRANSLATION(hpPowerLimit, "hppowerlimit", "power limit", "Leistungsgrenze", "", "Begränsning kompressoreffekt", "", "", "", "", "", "obmedzenie výkonu", "omezení výkonu") // TODO translate -MAKE_TRANSLATION(powerReduction, "powerreduction", "power reduction", "Leistungsverringerung", "", "Reducerad kompressoreffekt", "", "", "", "", "", "obmedzenie výkonu", "omezení výkonu") // TODO translate -MAKE_TRANSLATION(fuelHeat, "fuelheat", "fuel consumption heating", "Verbrauch Heizen", "", "Bränsleförbrukning värme", "", "", "", "", "", "obmedzenie výkonu", "omezení výkonu") // TODO translate -MAKE_TRANSLATION(fuelDhw, "fueldhw", "fuel consumption", "Verbrauch", "", "Bränsleförbrukning varmvatten", "", "", "", "", "", "spotreba paliva", "spotřeba paliva") // TODO translate -MAKE_TRANSLATION(elHeat, "elheat", "el. consumption heating", "el. Verbrauch Heizen", "", "Elförbrukning värme", "", "", "", "", "", "el. spotreba kúrenie", "") // TODO translate -MAKE_TRANSLATION(elDhw, "eldhw", "el. consumption", "el. Verbrauch", "", "Elförbrukning varmvatten", "", "", "", "", "", "el. spotreba", "") // TODO translate -MAKE_TRANSLATION(elGenHeat, "elgenheat", "el. generation heating", "el. Erzeugung Heizen", "", "Elgenerering värme", "", "", "", "", "", "el. generovanie kúrenia", "") // TODO translate -MAKE_TRANSLATION(elGenDhw, "elgendhw", "el generation", "el. Erzeugung", "", "Elgenerering varmvatten", "", "", "", "", "", "el. generovanie", "") // TODO translate +MAKE_TRANSLATION(nrgTotal, "nrgtotal", "total energy", "Gesamtenergie", "", "Avgiven energi totalt", "całkowita energia", "", "", "", "", "celková energia", "celková energie") +MAKE_TRANSLATION(nrgHeat, "nrgheat", "energy heating", "Energie Heizen", "", "Avgiven energi värme", "energia na ogrzewanie", "", "", "ısıtma enerjisi", "energia vykurovania", "energetické vykurovanie", "energie pro vytápění") +MAKE_TRANSLATION(nrgCool, "nrgcool", "energy cooling", "Energie Kühlen", "", "Avgiven energi kyla", "", "", "", "", "", "energia chladenia", "energie pro chlazení") +MAKE_TRANSLATION(nrgWw, "nrg", "energy", "Energie", "", "Avgiven energi varmvatten", "energia", "", "", "sıcak kullanım suyu enerjisi", "", "energia", "energie") +MAKE_TRANSLATION(nrgHeat2, "nrgheat2", "energy heating 2", "Energie Heizen 2", "", "Avgiven energi värme 2", "energia na ogrzewanie 2", "", "", "ısıtma enerjisi 2", "", "energia vykurovania 2", "energie pro vytápění 2") +MAKE_TRANSLATION(nrgWw2, "nrg2", "energy 2", "Energie 2", "", "", "energia 2", "", "Avgiven energi varmvatten 2", "sıcak kullanım suyu enerjisi 2", "", "energia 2", "energie 2") +MAKE_TRANSLATION(nomPower, "nompower", "nominal Power", "Brennerleistung", "", "Nominell effekt", "moc nominalna", "", "", "nominal güç", "", "nominálny výkon", "nominální výkon") +MAKE_TRANSLATION(meterTotal, "metertotal", "meter total", "Gesamtmessung", "", "Förbrukad energi totalt", "licznik całkowity", "", "", "", "", "počítadlo celkom", "počítadlo celkem") +MAKE_TRANSLATION(meterComp, "metercomp", "meter compressor", "Messung Kompressor", "", "Förbrukad energi kompressor", "licznik sprężarki", "", "", "", "", "počítadlo kompresor", "počítadlo kompresoru") +MAKE_TRANSLATION(meterEHeat, "metereheat", "meter e-heater", "Messung E-Heizer", "", "Förbrukad energi eltillskott", "licznik dogrzewacza", "", "", "", "", "počítadlo e-ohrievača", "počítadlo elektrického topení") +MAKE_TRANSLATION(meterHeat, "meterheat", "meter heating", "Messung Heizen", "", "Förbrukad energi värme", "licznik ogrzewania", "", "", "", "", "počítadlo kúrenia", "počítadlo vytápění") +MAKE_TRANSLATION(meterCool, "metercool", "meter cooling", "Messung Kühlen", "", "Förbrukad energi kyla", "", "", "", "", "", "počítadlo chladenia", "počítadlo chlazení") +MAKE_TRANSLATION(meterWw, "meter", "meter", "Messung", "", "", "licznik", "", "Förbrukad energi varmvatten", "", "", "počítadlo", "počítadlo") +MAKE_TRANSLATION(gasMeterHeat, "gasmeterheat", "gas meter heating", "Gaszähler Heizen", "", "Gasförbrukning värme", "licznik gazu na ogrzewanie", "", "", "", "", "počítadlo plynu kúrenia", "počítadlo plynu pro vytápění") +MAKE_TRANSLATION(gasMeterWw, "gasmeter", "gas meter", "Gaszähler", "", "Gasförbrukning varmvatten", "licznik gazu", "", "", "", "", "počítadlo plynu", "počítadlo plynu") +MAKE_TRANSLATION(hpCurrPower, "hpcurrpower", "compressor current power", "akt. Kompressorleistung", "", "Kompressoreffekt", "", "", "", "", "", "aktuálny výkon kompresoru", "aktuální výkon kompresoru") +MAKE_TRANSLATION(hpPowerLimit, "hppowerlimit", "power limit", "Leistungsgrenze", "", "Begränsning kompressoreffekt", "", "", "", "", "", "obmedzenie výkonu", "omezení výkonu") +MAKE_TRANSLATION(powerReduction, "powerreduction", "power reduction", "Leistungsverringerung", "", "Reducerad kompressoreffekt", "", "", "", "", "", "obmedzenie výkonu", "omezení výkonu") +MAKE_TRANSLATION(fuelHeat, "fuelheat", "fuel consumption heating", "Verbrauch Heizen", "", "Bränsleförbrukning värme", "", "", "", "", "", "obmedzenie výkonu", "omezení výkonu") +MAKE_TRANSLATION(fuelDhw, "fueldhw", "fuel consumption", "Verbrauch", "", "Bränsleförbrukning varmvatten", "", "", "", "", "", "spotreba paliva", "spotřeba paliva") +MAKE_TRANSLATION(elHeat, "elheat", "el. consumption heating", "el. Verbrauch Heizen", "", "Elförbrukning värme", "", "", "", "", "", "el. spotreba kúrenie", "") +MAKE_TRANSLATION(elDhw, "eldhw", "el. consumption", "el. Verbrauch", "", "Elförbrukning varmvatten", "", "", "", "", "", "el. spotreba", "") +MAKE_TRANSLATION(elGenHeat, "elgenheat", "el. generation heating", "el. Erzeugung Heizen", "", "Elgenerering värme", "", "", "", "", "", "el. generovanie kúrenia", "") +MAKE_TRANSLATION(elGenDhw, "elgendhw", "el generation", "el. Erzeugung", "", "Elgenerering varmvatten", "", "", "", "", "", "el. generovanie", "") // HIU -MAKE_TRANSLATION(netFlowTemp, "netflowtemp", "heat network flow temp", "Systemvorlauftemperatur", "Netto aanvoertemperatuur", "Temperatur fjärrvärmenät", "temp. zasilania sieci cieplnej", "", "", "ısıtma şebekesi akış derecesi", "temperatura di mandata della rete di riscaldamento", "teplota prívodu tepelnej siete", "teplota přívodu tepelné sítě") // TODO translate -// MAKE_TRANSLATION(cwFlowRate, "cwflowrate", "cold water flow rate", "Kaltwasser Durchfluss", "Stroomsnelheid koud water", "Kallvattensflöde", "przepływ zimnej wody", "", "", "soğuk su akış hızı", "portata acqua fredda", "prietok studenej vody", "průtok studené vody") // TODO translate -MAKE_TRANSLATION(keepWarmTemp, "keepwarmtemp", "keep warm temperature", "Warmhaltetemperatur", "Warmhoudtemperatuur", "", "Varmhållningstemperatur", "temperatura podtrzymywania ciepła", "", "sıcaklığı koruma derecesi", "mantenere la temperatura calda", "udržať teplú teplotu", "udržovací teplota") // TODO translate -MAKE_TRANSLATION(heatValve, "heatvalve", "heating valve", "Heizungsventil", "", "Ventil uppvärmning", "zawór ogrzewania", "", "", "", "", "vykurovací ventil", "ventil pro vytápění") // TODO translate -MAKE_TRANSLATION(wwValve, "dhwvalve", "valve", "Ventil", "", "Ventil varmvatten", "zawór", "", "", "", "", "ventil", "ventil") // TODO translate +MAKE_TRANSLATION(netFlowTemp, "netflowtemp", "heat network flow temp", "Systemvorlauftemperatur", "Netto aanvoertemperatuur", "Temperatur fjärrvärmenät", "temp. zasilania sieci cieplnej", "", "", "ısıtma şebekesi akış derecesi", "temperatura di mandata della rete di riscaldamento", "teplota prívodu tepelnej siete", "teplota přívodu tepelné sítě") +// MAKE_TRANSLATION(cwFlowRate, "cwflowrate", "cold water flow rate", "Kaltwasser Durchfluss", "Stroomsnelheid koud water", "Kallvattensflöde", "przepływ zimnej wody", "", "", "soğuk su akış hızı", "portata acqua fredda", "prietok studenej vody", "průtok studené vody") +MAKE_TRANSLATION(keepWarmTemp, "keepwarmtemp", "keep warm temperature", "Warmhaltetemperatur", "Warmhoudtemperatuur", "", "Varmhållningstemperatur", "temperatura podtrzymywania ciepła", "", "sıcaklığı koruma derecesi", "mantenere la temperatura calda", "udržať teplú teplotu", "udržovací teplota") +MAKE_TRANSLATION(heatValve, "heatvalve", "heating valve", "Heizungsventil", "", "Ventil uppvärmning", "zawór ogrzewania", "", "", "", "", "vykurovací ventil", "ventil pro vytápění") +MAKE_TRANSLATION(wwValve, "dhwvalve", "valve", "Ventil", "", "Ventil varmvatten", "zawór", "", "", "", "", "ventil", "ventil") // the following are dhw for the boiler and automatically tagged with 'dhw' MAKE_TRANSLATION(wwSelTemp, "seltemp", "selected temperature", "gewählte Temperatur", "Geselecteerd temperatuur", "Vald Temperatur", "temperatura wyższa/komfort", "valgt temperatur", "température sélectionnée", "seçili sıcaklık", "temperatura selezionata", "zvolená teplota", "nastavená teplota") @@ -682,7 +682,7 @@ MAKE_TRANSLATION(wwStorageTemp2, "storagetemp2", "storage extern temperature", " MAKE_TRANSLATION(wwActivated, "activated", "activated", "aktiviert", "geactiveerd", "Aktiverad", "system przygotowywania c.w.u.", "aktivert", "activé", "devreye girdi", "attivato", "aktivovaný", "aktivováno") MAKE_TRANSLATION(wwDisinfecting, "disinfecting", "disinfecting", "Desinfizieren", "Desinfectie", "Desinficerar", "dezynfekcja termiczna", "desinfiserer", "désinfection", "dezenfekte ediliyor", "disinfezione", "dezinfekcia", "dezinfekce") MAKE_TRANSLATION(wwDisinfectionTemp, "disinfectiontemp", "disinfection temperature", "Desinfektionstemperatur", "Desinfectietemperatuur", "Desinfektionstemperatur", "temperatura dezynfekcji termicznej", "desinfeksjonstemperatur", "température désinfection", "dezenfeksiyon sıcaklığı", "temperatura disinfezione", "teplota dezinfekcie", "dezinfekční teplota") -MAKE_TRANSLATION(wwChargePump, "chargepump", "charge pump", "Ladepumpe", "", "", "", "", "", "", "", "nabíjacie čerpadlo", "nabíjecí čerpadlo") // TODO Translate +MAKE_TRANSLATION(wwChargePump, "chargepump", "charge pump", "Ladepumpe", "", "", "", "", "", "", "", "nabíjacie čerpadlo", "nabíjecí čerpadlo") MAKE_TRANSLATION(wwCharging, "charging", "charging", "Laden", "Laden", "Värmer", "grzanie", "varmer", "chargement", "dolduruluyor", "caricamento", "nabíjanie", "nabíjení") MAKE_TRANSLATION(wwChargeOptimization, "chargeoptimization", "charge optimization", "Ladungsoptimierung", "laadoptimalisatie", "Laddningsoptimering", "optymalizacja grzania", "oppvarmingsoptimalisering", "optimisation charge", "dolum optimizasyonu", "ottimizzazione carica", "optimalizácia poplatkov", "optimalizace nabíjení") MAKE_TRANSLATION(wwRecharging, "recharging", "recharging", "Nachladen", "herladen", "Laddar om", "ponowne grzanie", "varm på nytt", "en recharge", "tekrar dolduruluyor", "in ricarica", "nabíjanie", "dobíjení") @@ -691,7 +691,7 @@ MAKE_TRANSLATION(wwActive, "active", "active", "aktiv", "Actief", "Aktiv", "akty MAKE_TRANSLATION(ww3wayValve, "3wayvalve", "3-way valve active", "3-Wege-Ventil aktiv", "3-wegklep actief", "Trevägsventil aktiv", "zawór 3-drogowy aktywny", "aktiv trevisventil", "vanne 3 voies active", "3 yollu vana", "valvola 3-vie", "3-cestný ventil aktívny", "aktivní 3-cestný ventil") MAKE_TRANSLATION(wwMixerTemp, "mixertemp", "mixer temperature", "Mischertemperatur", "Mixertemperatuur", "Blandningsventil tempertur", "temperatura mieszacza", "temperatur blandeventil", "température mélangeur", "karıştırıcı sıcaklığı", "temperatura miscelatore", "teplota mixéra", "teplota směšovače") MAKE_TRANSLATION(wwStarts, "starts", "starts", "Anzahl Starts", "Aantal starts", "Antal starter", "liczba załączeń", "antall starter", "démarrages", "başlıyor", "avvii", "Počet štartov", "Počet startů") -MAKE_TRANSLATION(wwStartsHp, "startshp", "starts hp", "Anzahl Starts WP", "", "Antal starter VP", "", "", "", "", "", "Počet spustení TČ", "počet spuštění TČ") // TODO translate +MAKE_TRANSLATION(wwStartsHp, "startshp", "starts hp", "Anzahl Starts WP", "", "Antal starter VP", "", "", "", "", "", "Počet spustení TČ", "počet spuštění TČ") MAKE_TRANSLATION(wwWorkM, "workm", "active time", "aktive Zeit", "Actieve tijd", "Aktiv Tid", "czas aktywności", "driftstid", "temps actif", "aktif zaman", "tempo attivo", "aktívny čas", "aktivní čas") MAKE_TRANSLATION(wwHystOn, "hyston", "hysteresis on temperature", "Einschalttemperaturdifferenz", "Inschakeltemperatuurverschil", "Hysteres PÅ-temperatur", "histereza załączania", "innkoblingstemperaturforskjell", "hystérésis température allumage", "çalışma sıcaklığı farkı", "differenza di temperatura di accensione", "hysterézia teploty", "hystereze zapnutí") MAKE_TRANSLATION(wwHystOff, "hystoff", "hysteresis off temperature", "Ausschalttemperaturdifferenz", "Uitschakeltemperatuurverschil", "Hysteres AV-temperatur", "histereza wyłączania", "utkoblingstemperaturforskjell", "hystérésis température extinction", "kapatma sıcaklığı farkı", "differenza di temperatura di spegnimento", "teplota hysterézie", "hystereze vypnutí") @@ -712,9 +712,9 @@ MAKE_TRANSLATION(ibaLanguage, "language", "language", "Sprache", "Taal", "Sprak" MAKE_TRANSLATION(ibaClockOffset, "clockoffset", "clock offset", "Uhrkorrektur", "Klokcorrectie", "Tidskorrigering", "korekta zegara", "tidskorrigering", "offset horloge", "saat farkı", "correzione orario", "korekcia času", "posun hodin") MAKE_TRANSLATION(ibaBuildingType, "building", "building type", "Gebäudetyp", "Type gebouw", "Byggnadstyp", "typ budynku", "bygningstype", "type bâtiment", "bina tipi", "tipo di edificio", "typ budovy", "typ budovy") MAKE_TRANSLATION(heatingPID, "heatingpid", "heating PID", "Heizungs-PID", "PID verwarming", "Uppvärmning PID", "PID ogrzewania", "oppvarmings PID", "PID chauffage", "PID ısınıyor", "PID-riscaldamento", "PID kúrenia", "PID regulace vytápění") -MAKE_TRANSLATION(pumpopt, "pumpopt", "pump optimization", "Pumpenoptimierung") // ToDo translate -MAKE_TRANSLATION(inttime, "inttime", "integral time", "Integralzeit") // ToDo translate -MAKE_TRANSLATION(inttimefloor, "inttimefloor", "integral time floor", "Integralzeit Fußbodenheizung") // ToDo translate +MAKE_TRANSLATION(pumpopt, "pumpopt", "pump optimization", "Pumpenoptimierung") +MAKE_TRANSLATION(inttime, "inttime", "integral time", "Integralzeit") +MAKE_TRANSLATION(inttimefloor, "inttimefloor", "integral time floor", "Integralzeit Fußbodenheizung") MAKE_TRANSLATION(ibaCalIntTemperature, "intoffset", "internal temperature offset", "Korrektur interner Temperatur", "Offset interne temperatuur", "Korrigering interntemperatur", "korekta temperatury w pomieszczeniu", "Korrigering interntemperatur", "offset température interne", "iç sıcaklık artışı", "scostamento della temperatura interna", "odchýlka vnútornej teploty", "kompenzace vnitřní teploty") MAKE_TRANSLATION(ibaMinExtTemperature, "minexttemp", "minimal external temperature", "Min. Außentemperatur", "Min. buitentemperatuur", "Min Extern Temperatur", "minimalna miejscowa temperatura zewnętrzna", "minimal eksterntemperatur", "température extérieure minimale", "en düşük sış sıcaklık", "temperatura esterna minima", "minimálna vonkajšia teplota", "minimální venkovní teplota") MAKE_TRANSLATION(backlight, "backlight", "key backlight", "Tastenbeleuchtung", "Toetsverlichting", "Bakgrundsbelysning", "podświetlenie klawiatury", "bakgrunnsbelysning", "rétroéclairage touches", "tuş takımı aydınlatması", "retroilluminazione dei tasti", "podsvietenie kláves", "podsvícení kláves") @@ -729,10 +729,10 @@ MAKE_TRANSLATION(autodst, "autodst", "automatic change daylight saving time", "A MAKE_TRANSLATION(preheating, "preheating", "preheating in the clock program", "Vorheizen im Zeitprogramm", "Voorverwarming in het klokprogramma", "Förvärmning i tidsprogram", "podgrzewanie w programie czasowym", "forvarming i tidsprogram", "préchauffage dans programme horloge", "saat programında ön ısıtma", "preriscaldamento nel programma orologio", "predohrev v programe hodín", "předehřev v programovaném režimu") MAKE_TRANSLATION(offtemp, "offtemp", "temperature when mode is off", "Temperatur bei AUS", "Temperatuur bij UIT", "Temperatur Avslagen", "temperatura w trybie \"wył.\"", "temperatur avslått", "température lorsque mode désactivé", "mod kapalı iken sıcaklık", "temperatura quando la modalità è disattivata", "teplota, keď je režim vypnutý", "teplota při vypnutém režimu") MAKE_TRANSLATION(mixingvalves, "mixingvalves", "mixing valves", "Mischventile", "Mengkleppen", "Blandningsventiler", "zawory mieszające", "blandeventiler", "vannes mélange", "karışım vanaları", "valvole miscela", "zmiešavacie ventily", "směšovací ventily") -MAKE_TRANSLATION(pvEnableWw, "pvenabledhw", "enable raise dhw", "aktiviere WW-Anhebung", "Verhoging WW activeren", "Höj varmvatten med solpanel", "podwyższenie c.w.u. z PV", "aktivere hevet temperatur bereder", "", "sıcak kullanım suyu yükseltmeyi etkinleştir", "abilitare aumento ACS", "povoliť zvýšenie TÚV", "povolit zvýšení TUV") // TODO translate -MAKE_TRANSLATION(pvRaiseHeat, "pvraiseheat", "raise heating with PV", "Anhebung Heizen mit PV", "Verwarmen met PV activeren", "Höj värmen med solpanel", "podwyższenie grzania z PV", "heve varmen med solpanel", "", "ısıtmayı G.E. İle yükselt", "Aumentare il riscaldamento con il solare", "zvýšiť kúrenie s FV", "zvýšení vytápění s FV") // TODO translate -MAKE_TRANSLATION(pvLowerCool, "pvlowercool", "lower cooling with PV", "Absenkung Kühlen mit PV", "Verlagen koeling met PV activeren", "Sänk kylning med solpanel", "obniżenie chłodzenia z PV", "nedre kjøling solpanel", "", "soğutmayı G.E. İle düşür", "Riduzione del raffreddamento con il solare", "nižšie chladenie s PV", "snížení chlazení s FV") // TODO translate -MAKE_TRANSLATION(hasSolar, "solar", "solar", "Solar", "", "Solpaneler", "", "", "", "", "", "solár", "solár") // TODO translate +MAKE_TRANSLATION(pvEnableWw, "pvenabledhw", "enable raise dhw", "aktiviere WW-Anhebung", "Verhoging WW activeren", "Höj varmvatten med solpanel", "podwyższenie c.w.u. z PV", "aktivere hevet temperatur bereder", "", "sıcak kullanım suyu yükseltmeyi etkinleştir", "abilitare aumento ACS", "povoliť zvýšenie TÚV", "povolit zvýšení TUV") +MAKE_TRANSLATION(pvRaiseHeat, "pvraiseheat", "raise heating with PV", "Anhebung Heizen mit PV", "Verwarmen met PV activeren", "Höj värmen med solpanel", "podwyższenie grzania z PV", "heve varmen med solpanel", "", "ısıtmayı G.E. İle yükselt", "Aumentare il riscaldamento con il solare", "zvýšiť kúrenie s FV", "zvýšení vytápění s FV") +MAKE_TRANSLATION(pvLowerCool, "pvlowercool", "lower cooling with PV", "Absenkung Kühlen mit PV", "Verlagen koeling met PV activeren", "Sänk kylning med solpanel", "obniżenie chłodzenia z PV", "nedre kjøling solpanel", "", "soğutmayı G.E. İle düşür", "Riduzione del raffreddamento con il solare", "nižšie chladenie s PV", "snížení chlazení s FV") +MAKE_TRANSLATION(hasSolar, "solar", "solar", "Solar", "", "Solpaneler", "", "", "", "", "", "solár", "solár") // thermostat dhw MAKE_TRANSLATION(wwMode, "mode", "operating mode", "Betriebsart", "Modus", "Läge", "tryb pracy", "modus", "mode", "mod", "modalità", "režim", "provozní režim") @@ -799,12 +799,12 @@ MAKE_TRANSLATION(vacreducetemp, "vacreducetemp", "vacations off/reduce switch te MAKE_TRANSLATION(vacreducemode, "vacreducemode", "vacations reduce mode", "Urlaub Absenkmodus", "Vakantie afschakelmodus", "Helg reduceringsläge", "redukcja w trakcie urlopu", "ferieavstengningsmodus", "mode réduction vacances", "tail düşürme modu", "modalita riduzione vacanze", "režim zníženia dovoleniek", "redukční režim během dovolené") MAKE_TRANSLATION(nofrostmode, "nofrostmode", "nofrost mode", "Frostschutzmodus", "Vorstbeveiligingsmodus", "Frostskyddsläge", "temperatura wiodąca dla ochrony przed zamarzaniem", "frostbeskyttelsesmodus", "mode protection gel", "donma koruması modu", "Modalità protezione antigelo", "nofrost režim", "režim proti zamrznutí") MAKE_TRANSLATION(remotetemp, "remotetemp", "room temperature from remote", "Raumtemperatur Remote", "Ruimtetemperatuur van afstandsbediening", "Rumstemperatur från fjärr", "temperatura w pomieszczeniu (z termostatu)", "romstemperatur fra fjernbetjening", "température pièce depuis télécommande", "uzaktan oda sıcaklığı", "temperatura ambiente da remoto", "izbová teplota z diaľkového ovládania", "teplota místnosti z dálkového ovladače") -MAKE_TRANSLATION(remotehum, "remotehum", "room humidity from remote", "Raumfeuchte Remote", "", "Rumsluftfuktighet från fjärr", "wilgotność w pomieszczeniu (z termostatu)", "", "", "uzaktan kumandadan oda nemi", "", "Vlhkosť v miestnosti z diaľkového ovládania", "vlhkost místnosti z dálkového ovladače") // TODO translate +MAKE_TRANSLATION(remotehum, "remotehum", "room humidity from remote", "Raumfeuchte Remote", "", "Rumsluftfuktighet från fjärr", "wilgotność w pomieszczeniu (z termostatu)", "", "", "uzaktan kumandadan oda nemi", "", "Vlhkosť v miestnosti z diaľkového ovládania", "vlhkost místnosti z dálkového ovladače") MAKE_TRANSLATION(wwHolidays, "holidays", "holiday dates", "Feiertage", "Feestdagen", "Helgdagar", "dni świąteczne", "feriedager varmtvann", "dates vacances", "tatil günleri", "feste pubbliche", "sviatočné termíny", "data pro dovolenou") MAKE_TRANSLATION(wwVacations, "vacations", "vacation dates", "Urlaubstage", "Vakantiedagen", "Semesterdatum Varmvatten", "dni urlopowe", "ferie dato varmtvann", "dates vacances", "izin günleri", "date vacanze", "termíny dovolenky", "data pro prázdniny") MAKE_TRANSLATION(holidays, "holidays", "holiday dates", "Feiertage", "Feestdagen", "Helgdatum", "święta", "helligdager", "dates vacances", "tatil günleri", "date feste pubbliche", "sviatočné termíny", "data pro dovolenou") MAKE_TRANSLATION(vacations, "vacations", "vacation dates", "Urlaubstage", "Vakantiedagen", "Semesterdatum", "urlop", "feriedager", "dates vacances", "izin günleri", "date vacanze", "termíny dovolenky", "data pro prázdniny") -MAKE_TRANSLATION(vacationmode, "vacationmode", "vacation mode", "Urlaubsmodus", "", "", "", "", "", "", "", "dovolenkový režim", "režim dovolené") // ToDo Translate +MAKE_TRANSLATION(vacationmode, "vacationmode", "vacation mode", "Urlaubsmodus", "", "", "", "", "", "", "", "dovolenkový režim", "režim dovolené") MAKE_TRANSLATION(wwprio, "dhwprio", "dhw priority", "WW-Vorrang", "Prioriteit warm water", "Prioritera Varmvatten", "priorytet dla c.w.u.", "prioroter varmtvann", "priorité ecs", "sıcak kullanım suyu önceliği", "priorita acqua calda", "Priorita TÚV", "přednost ohřevu TUV") MAKE_TRANSLATION(nofrostmode1, "nofrostmode1", "nofrost mode", "Frostschutz", "Vorstbeveiligingsmodus", "Frostskyddsläge", "ochrona przed zamarzaniem", "frostbeskyttelse", "mode protection gel", "donma koruması modu 1", "modalita protezione antigelo", "nofrost režim", "režim proti zamrznutí") MAKE_TRANSLATION(reducehours, "reducehours", "duration for nighttemp", "Dauer Nachttemp.", "Duur nachtverlaging", "Timmar Nattsänkning", "czas trwania trybu nocnego", "timer nattsenkning", "durée température nuit", "gece sıcaklığı süresi", "durata temperatura notturna", "trvanie nočnej teploty", "délka trvání noční teploty") @@ -818,25 +818,25 @@ MAKE_TRANSLATION(vacations5, "vacations5", "vacation dates 5", "Urlaubstage 5", MAKE_TRANSLATION(vacations6, "vacations6", "vacation dates 6", "Urlaubstage 6", "Vakantiedagen 6", "Semesterdatum 6", "urlop 6", "feriedager 6", "dates vacances 6", "izin günleri 6", "date vacanze 6", "termíny dovolenky 6", "data prázdnin 6") MAKE_TRANSLATION(vacations7, "vacations7", "vacation dates 7", "Urlaubstage 7", "Vakantiedagen 7", "Semesterdatum 7", "urlop 7", "feriedager 7", "dates vacances 7", "izin günleri 7", "date vacanze 7", "termíny dovolenky 7", "data prázdnin 7") MAKE_TRANSLATION(vacations8, "vacations8", "vacation dates 8", "Urlaubstage 8", "Vakantiedagen 8", "Semesterdatum 8", "urlop 8", "feriedager 8", "dates vacances 8", "izin günleri 8", "date vacanze 8", "termíny dovolenky 8", "data prázdnin 8") -MAKE_TRANSLATION(absent, "absent", "absent", "Abwesend", "", "Frånvarande", "", "", "", "", "", "chýbajúci", "chybějící") // TODO translate -MAKE_TRANSLATION(redthreshold, "redthreshold", "reduction threshold", "Absenkschwelle", "", "Tröskel för sänkning", "", "", "", "", "", "zníženie tresholdu", "práh snížení") // TODO translate -MAKE_TRANSLATION(solarinfl, "solarinfl", "solar influence", "Solareinfluß", "", "", "", "", "", "", "", "slnečný vplyv", "sluneční vliv") // TODO translate -MAKE_TRANSLATION(currsolarinfl, "currsolarinfl", "curent solar influence", "akt. Solareinfluß", "", "", "", "", "", "", "", "aktuálny slnečný vplyv", "aktuální sluneční vliv") // TODO translate +MAKE_TRANSLATION(absent, "absent", "absent", "Abwesend", "", "Frånvarande", "", "", "", "", "", "chýbajúci", "chybějící") +MAKE_TRANSLATION(redthreshold, "redthreshold", "reduction threshold", "Absenkschwelle", "", "Tröskel för sänkning", "", "", "", "", "", "zníženie tresholdu", "práh snížení") +MAKE_TRANSLATION(solarinfl, "solarinfl", "solar influence", "Solareinfluß", "", "", "", "", "", "", "", "slnečný vplyv", "sluneční vliv") +MAKE_TRANSLATION(currsolarinfl, "currsolarinfl", "curent solar influence", "akt. Solareinfluß", "", "", "", "", "", "", "", "aktuálny slnečný vplyv", "aktuální sluneční vliv") -MAKE_TRANSLATION(hpmode, "hpmode", "HP Mode", "WP-Modus", "Modus warmtepomp", "Värmepumpsläge", "tryb pracy pompy ciepła", "", "", "yüksek güç modu", "Modalità Termopompa", "Režim TČ", "režim tepelného čerpadla") // TODO translate -MAKE_TRANSLATION(dewoffset, "dewoffset", "dew point offset", "Taupunktdifferenz", "Offset dauwpunt", "Daggpunktsförskjutning", "przesunięcie punktu rosy", "", "", "çiğ noktası göreli", "differenza del punto di rugiada", "posun rosného bodu", "offset rosného bodu") // TODO translate -MAKE_TRANSLATION(roomtempdiff, "roomtempdiff", "room temp difference", "Raumtemperaturdifferenz", "Verschiltemperatuur kamertemp", "Rumstemperaturskillnad", "różnica temp. pomieszczenia", "", "", "oda sıcaklığı farkı", "differenza temperatura ambiente", "rozdiel izbovej teploty", "rozdíl teploty místnosti") // TODO translate -MAKE_TRANSLATION(hpminflowtemp, "hpminflowtemp", "HP min. flow temp.", "WP minimale Vorlauftemperatur", "Minimale aanvoertemperatuur WP", "VP min flödestemperatur", "pompa ciepła, min. temperatura przepływu", "", "yüksek güç minimum akış sıcaklığı", "temperatura minima di mandata", "VT min. teplota prietoku.", "minimální teplota přívodu tepelného čerpadla") // TODO translate +MAKE_TRANSLATION(hpmode, "hpmode", "HP Mode", "WP-Modus", "Modus warmtepomp", "Värmepumpsläge", "tryb pracy pompy ciepła", "", "", "yüksek güç modu", "Modalità Termopompa", "Režim TČ", "režim tepelného čerpadla") +MAKE_TRANSLATION(dewoffset, "dewoffset", "dew point offset", "Taupunktdifferenz", "Offset dauwpunt", "Daggpunktsförskjutning", "przesunięcie punktu rosy", "", "", "çiğ noktası göreli", "differenza del punto di rugiada", "posun rosného bodu", "offset rosného bodu") +MAKE_TRANSLATION(roomtempdiff, "roomtempdiff", "room temp difference", "Raumtemperaturdifferenz", "Verschiltemperatuur kamertemp", "Rumstemperaturskillnad", "różnica temp. pomieszczenia", "", "", "oda sıcaklığı farkı", "differenza temperatura ambiente", "rozdiel izbovej teploty", "rozdíl teploty místnosti") +MAKE_TRANSLATION(hpminflowtemp, "hpminflowtemp", "HP min. flow temp.", "WP minimale Vorlauftemperatur", "Minimale aanvoertemperatuur WP", "VP min flödestemperatur", "pompa ciepła, min. temperatura przepływu", "", "yüksek güç minimum akış sıcaklığı", "temperatura minima di mandata", "VT min. teplota prietoku.", "minimální teplota přívodu tepelného čerpadla") MAKE_TRANSLATION(hpcooling, "hpcooling", "hp cooling", "WP Kühlen", "WP koelbedrijf", "VP Kyla", "pompa ciepła, chłodzenie", "vp kjøling", "hp soğuyor", "raffreddamento pompa calore", "chladenie TČ", "chlazení tepelného čerpadla") -MAKE_TRANSLATION(coolstart, "coolstart", "cooling starttemp", "Kühlbetrieb ab", "", "Kyla starttemperatur", "", "", "", "", "", "teplota spustenia chladenia", "teplota spuštění chlazení") // TODO translate -MAKE_TRANSLATION(coolondelay, "coolondelay", "cooling on delay", "Einschaltverzögerung Kühlen", "", "Inkopplingsfördröjning Kyla", "", "", "", "", "", "oneskorenie zapnutie chladenia", "zpoždění zapnutí chlazení") // TODO translate -MAKE_TRANSLATION(cooloffdelay, "cooloffdelay", "cooling off delay", "Ausschaltverzögerung Kühlen", "", "Frånkopplingsfördröjning Kyla", "", "", "", "", "", "oneskorenie vypnutie chladenia", "zpoždění vypnutí chlazení") // TODO translate -MAKE_TRANSLATION(switchProgMode, "switchprogmode", "switch program mode", "Schaltprogrammmodus", "", "Byt programläge", "", "", "", "", "", "prepnúť režim programu", "přepínací režim programu") // TODO translate +MAKE_TRANSLATION(coolstart, "coolstart", "cooling starttemp", "Kühlbetrieb ab", "", "Kyla starttemperatur", "", "", "", "", "", "teplota spustenia chladenia", "teplota spuštění chlazení") +MAKE_TRANSLATION(coolondelay, "coolondelay", "cooling on delay", "Einschaltverzögerung Kühlen", "", "Inkopplingsfördröjning Kyla", "", "", "", "", "", "oneskorenie zapnutie chladenia", "zpoždění zapnutí chlazení") +MAKE_TRANSLATION(cooloffdelay, "cooloffdelay", "cooling off delay", "Ausschaltverzögerung Kühlen", "", "Frånkopplingsfördröjning Kyla", "", "", "", "", "", "oneskorenie vypnutie chladenia", "zpoždění vypnutí chlazení") +MAKE_TRANSLATION(switchProgMode, "switchprogmode", "switch program mode", "Schaltprogrammmodus", "", "Byt programläge", "", "", "", "", "", "prepnúť režim programu", "přepínací režim programu") // heatpump and RC100H MAKE_TRANSLATION(airHumidity, "airhumidity", "relative air humidity", "relative Luftfeuchte", "Relatieve luchtvochtigheid", "Relativ Luftfuktighet", "wilgotność względna w pomieszczeniu", "luftfuktighet", "humidité relative air", "havadaki bağıl nem", "umidità relativa aria", "relatívna vlhkosť vzduchu", "relativní vlhkost vzduchu") MAKE_TRANSLATION(dewTemperature, "dewtemperature", "dew point temperature", "Taupunkttemperatur", "Dauwpunttemperatuur", "Daggpunkt", "punkt rosy w pomieszczeniu", "duggtemperatur", "température point rosée", "çiğ noktası sıcaklığı", "temperatura del punto di rugiada", "teplota rosného bodu", "teplota rosného bodu") -MAKE_TRANSLATION(battery, "battery", "battery", "Batterie", "", "Batteri", "bateria", "", "", "", "", "batéria", "baterie") // TODO translate +MAKE_TRANSLATION(battery, "battery", "battery", "Batterie", "", "Batteri", "bateria", "", "", "", "", "batéria", "baterie") // mixer MAKE_TRANSLATION(flowSetTemp, "flowsettemp", "setpoint flow temperature", "Sollwert Vorlauftemperatur", "Streefwaarde aanvoertemperatuur", "Vald flödestemperatur", "zadana temperatura zasilania", "valgt turtemperatur", "consigne température flux", "akış sıcaklığı ayarı", "Setpoint temperatura di mandata", "požadovaná hodnota výstupnej teploty", "cílová teplota vstupní vody") @@ -845,7 +845,7 @@ MAKE_TRANSLATION(pumpStatus, "pumpstatus", "pump status (PC1)", "Pumpenstatus HK MAKE_TRANSLATION(mixerStatus, "valvestatus", "mixing valve actuator (VC1)", "Mischerventilposition (VC1)", "positie mixerklep (VC1)", "Shuntventil Status (VC1)", "siłownik zaworu mieszającego (VC1)", "shuntventil status (VC1)", "actionnement vanne mélangeur (VC1)", "karışım vanası aktüatörü (VC1)", "posizione valvola miscela (VC1)", "pohon zmiešavacieho ventilu (VC1)", "pohon směšovacího ventilu (VC1)") MAKE_TRANSLATION(flowTempVf, "flowtempvf", "flow temperature in header (T0/Vf)", "Vorlauftemperatur am Verteiler (T0/Vf)", "aanvoertemperatuur verdeler (T0/Vf)", "Flödestemperatur Fördelare (T0/Vf)", "temperatura zasilania na rozdzielaczu (T0/Vf)", "turtemperatur ved fordeleren (T0/Vf)", "température départ collecteur (T0/Vf)", "başlıkta akış sıcaklığı", "Temperatura di mandata al distributore (T0/Vf)", "teplota prívodu v zberači (T0/Vf)", "teplota přívodu v hlavici (T0/Vf)") MAKE_TRANSLATION(mixerSetTime, "valvesettime", "time to set valve", "Zeit zum einstellen des Ventils", "Inschakeltijd mengklep", "Inställningstid Shuntventil", "czas na ustawienie zaworu", "instillningstid ventil", "délai activation vanne", "vana ayar zamanı", "ritardo attivazione valvola", "čas na nastavenie ventilu", "čas pro nastavení ventilu") -MAKE_TRANSLATION(setDiffPress, "setdiffpress", "set differential pressure", "Pumpensolldruck", "", "Tryckskillnad", "różnica ciśnień", "", "", "", "", "nastaviť diferenčný tlak", "nastavení rozdílového tlaku") // TODO translate +MAKE_TRANSLATION(setDiffPress, "setdiffpress", "set differential pressure", "Pumpensolldruck", "", "Tryckskillnad", "różnica ciśnień", "", "", "", "", "nastaviť diferenčný tlak", "nastavení rozdílového tlaku") // mixer pool MAKE_TRANSLATION(poolSetTemp, "poolsettemp", "pool set temperature", "Sollwert Pooltemperatur", "Streeftemperatuur zwembad", "Pool Temperatur Börvärde", "zadana temperatura basenu", "valgt temp basseng", "température consigne piscine", "hedef havuz sıcaklığı", "temperatura nominale piscina", "nastavená teplota bazéna", "cílová teplota bazénu") @@ -893,33 +893,33 @@ MAKE_TRANSLATION(m1WorkTime, "m1worktime", "differential control working time", MAKE_TRANSLATION(energyLastHour, "energylasthour", "energy last hour", "Energie letzte Std", "Energie laatste uur", "Energi Senaste Timmen", "energia w ciągu ostatniej godziny", "energi siste time", "énergie dernière heure", "son saat enerji", "Eenergia ultima ora", "energia za poslednú hodinu", "energie za poslední hodinu") MAKE_TRANSLATION(energyTotal, "energytotal", "total energy", "Gesamtenergie", "Totale energie", "Total Energi", "energia całkowita", "total energi", "énergie totale", "toplam enerji", "energia totale", "celková energia", "celková energie") MAKE_TRANSLATION(energyToday, "energytoday", "total energy today", "Energie heute", "Energie vandaag", "Total Energi Idag", "energia całkowita dzisiaj", "total energi i dag", "énergie totale aujourd'hui", "bugün toplam enerji", "totale energia giornaliera", "celková energia dnes", "celková energie dnes") -MAKE_TRANSLATION(cyl3BottomTemp, "cyl3bottomtemp", "third cylinder bottom temperature (TS11)", "Speichertemperatur unten (TS11)", "", "Tredje Cylindertemperatur Botten (TS11)", "", "", "", "", "", "spodná teplota tretieho valca (TS11)", "") // TODO translate -MAKE_TRANSLATION(cylTopTemp, "cyltoptemp", "cylinder top temperature (TS10)", "Speichertemperatur oben (TS10)", "", "Cylindertemperatur Toppen (TS10)", "", "", "", "", "", "horná teplota valca (TS10)", "") // TODO translate -MAKE_TRANSLATION(transferPumpMod, "transferpumpmod", "transfer pump modulation", "Transferpumpenmodulation", "", "Överföringspumpmodulering", "", "", "", "", "", "modulácia prenosového čerpadla", "") // TODO translate -MAKE_TRANSLATION(transferPump, "transferpump", "transfer pump", "Transferpumpe", "", "Överföringspump", "", "", "", "", "", "prenosové čerpadlo", "oběhové čerpadlo") // TODO translate +MAKE_TRANSLATION(cyl3BottomTemp, "cyl3bottomtemp", "third cylinder bottom temperature (TS11)", "Speichertemperatur unten (TS11)", "", "Tredje Cylindertemperatur Botten (TS11)", "", "", "", "", "", "spodná teplota tretieho valca (TS11)", "") +MAKE_TRANSLATION(cylTopTemp, "cyltoptemp", "cylinder top temperature (TS10)", "Speichertemperatur oben (TS10)", "", "Cylindertemperatur Toppen (TS10)", "", "", "", "", "", "horná teplota valca (TS10)", "") +MAKE_TRANSLATION(transferPumpMod, "transferpumpmod", "transfer pump modulation", "Transferpumpenmodulation", "", "Överföringspumpmodulering", "", "", "", "", "", "modulácia prenosového čerpadla", "") +MAKE_TRANSLATION(transferPump, "transferpump", "transfer pump", "Transferpumpe", "", "Överföringspump", "", "", "", "", "", "prenosové čerpadlo", "oběhové čerpadlo") MAKE_TRANSLATION(heatAssistOn, "heatassiston", "heat assistance on", "Einschaltdiff. Rücklaufanh.") MAKE_TRANSLATION(heatAssistOff, "heatassistoff", "heat assistance off", "Ausschaltdiff. Rücklaufanh.") // solar dhw -MAKE_TRANSLATION(wwColdTemp, "coldtemp", "cold water", "Kaltwasser", "", "kallvatten", "zimna woda", "", "", "", "", "studená voda", "studená voda") // TODO translate +MAKE_TRANSLATION(wwColdTemp, "coldtemp", "cold water", "Kaltwasser", "", "kallvatten", "zimna woda", "", "", "", "", "studená voda", "studená voda") MAKE_TRANSLATION(wwTemp5, "temp5", "temperature 5", "Temperatur 5", "Temperatuur 5", "Temperatur 5", "temperatura 5", "Temperatur 5", "température 5", "sıcaklık 5", "Temperatura 5", "teplota 5", "teplota 5") MAKE_TRANSLATION(wwTemp6, "temp6", "temperature 6", "Temperatur 6", "Temperatuur 6", "Temperatur 6", "temperatura 6", "temperatur 6", "température 6", "sıcaklık 6", "Temperatura 6", "teplota 6", "teplota 6") // MAKE_TRANSLATION(wwTemp7, "temp7", "temperature 7", "Temperatur 7", "Temperatuur 7", "Temperatur 7", "temperatura 7", "Temperatur 7", "température 7", "sıcaklık 7", "Temperatura 7", "teplota 7", "teplota 7") MAKE_TRANSLATION(wwPump, "pump", "pump", "Pumpe", "Pomp", "Pump", "pompa", "pumpe", "pompe", "pompa", "Pompa", "čerpadlo", "čerpadlo") -MAKE_TRANSLATION(wwCircTc, "circtc", "circulation time controled", "zeitgesteuerte Zirkulation", "", "Tidsstyrd cirkulation", "", "", "", "", "", "riadená doba cirkulácie", "řízený čas cirkulace") // TODO translate -MAKE_TRANSLATION(errorDisp, "errordisp", "error display", "Fehleranzeige", "", "Feldisplay", "wyświetlanie błędów", "", "", "", "", "zobrazenie chyby", "zobrazení chyb") // TODO translate -MAKE_TRANSLATION(deltaTRet, "deltatret", "temp. diff. return valve", "Temperaturdifferenz Rücklaufventil", "", "Temperaturskillnad returventil", "różnica temp. zaworu powrotnego", "", "", "", "", "rozdiel teplôt spätného ventilu", "rozdíl teploty zpátečního ventilu") // TODO translate +MAKE_TRANSLATION(wwCircTc, "circtc", "circulation time controled", "zeitgesteuerte Zirkulation", "", "Tidsstyrd cirkulation", "", "", "", "", "", "riadená doba cirkulácie", "řízený čas cirkulace") +MAKE_TRANSLATION(errorDisp, "errordisp", "error display", "Fehleranzeige", "", "Feldisplay", "wyświetlanie błędów", "", "", "", "", "zobrazenie chyby", "zobrazení chyb") +MAKE_TRANSLATION(deltaTRet, "deltatret", "temp. diff. return valve", "Temperaturdifferenz Rücklaufventil", "", "Temperaturskillnad returventil", "różnica temp. zaworu powrotnego", "", "", "", "", "rozdiel teplôt spätného ventilu", "rozdíl teploty zpátečního ventilu") // solar dhw and mixer dhw MAKE_TRANSLATION(wwMinTemp, "mintemp", "minimum temperature", "minimale Temperatur", "Minimale temperatuur", "Min. Temperatur", "temperatura minimalna", "min. temperatur", "température min.", "minimum sıcaklık", "temperatura minima", "minimálna teplota", "minimální teplota") MAKE_TRANSLATION(wwRedTemp, "redtemp", "reduced temperature", "reduzierte Temperatur", "Gereduceerde temperatuur", "Reducerad Temperatur", "temperatura zredukowana", "reducert temperatur", "température réduite", "düşürülmüş sıcaklık", "temperatura ridotta", "znížená teplota", "snížená teplota") MAKE_TRANSLATION(wwDailyTemp, "dailytemp", "daily temperature", "tägl. Temperatur", "Dagelijkse temperatuur", "Daglig temperatur", "temperatura dzienna", "dagtemperatur", "température en journée", "günlük sıcaklık", "temperatura giornaliera", "denná teplota", "denní teplota") -MAKE_TRANSLATION(wwHotTemp, "hottemp", "extra hot temperature", "sehr heiße Temperatur", "", "Mycket varm temperatur", "", "", "", "", "", "extra vysoká teplota", "teplota extra horká") // TODO translate +MAKE_TRANSLATION(wwHotTemp, "hottemp", "extra hot temperature", "sehr heiße Temperatur", "", "Mycket varm temperatur", "", "", "", "", "", "extra vysoká teplota", "teplota extra horká") MAKE_TRANSLATION(wwKeepWarm, "keepwarm", "keep warm", "Warmhalten", "Warm houde", "Varmhållning", "utrzymywanie ciepła", "holde varmen", "maintenir chaleur", "ılık tut", "mantenimento calore", "udržovať v teple", "udržení tepla") MAKE_TRANSLATION(wwStatus2, "status2", "status 2", "Status 2", "Status 2", "Status 2", "status 2", "status 2", "statut 2", "durum 2", "Status 2", "stav 2", "stav 2") MAKE_TRANSLATION(wwPumpMod, "pumpmod", "pump modulation", "Pumpenmodulation", "Pompmodulatie", "Pumpmodulering", "modulacja pompy", "pumpemodulering", "modulation de pompe", "pompa modülasyonu", "modulazione pompa", "modulácia čerpadla", "modulace čerpadla") MAKE_TRANSLATION(wwFlow, "flow", "flow rate", "Volumenstrom", "Doorstroomsnelheid", "Flöde", "przepływ", "strømningshastighet", "débit", "akış hızı", "portata flusso", "prietok", "průtok") -// MAKE_TRANSLATION(wwRetValve, "retvalve", "return valve", "Rücklauf Ventil", "", "Returventil", "", "", "", "", "", "spätný ventil", "zpětný ventil") // TODO translate +// MAKE_TRANSLATION(wwRetValve, "retvalve", "return valve", "Rücklauf Ventil", "", "Returventil", "", "", "", "", "", "spätný ventil", "zpětný ventil") // extra mixer dhw MAKE_TRANSLATION(wwRequiredTemp, "requiredtemp", "required temperature", "benötigte Temperatur", "Benodigde temperatuur", "Nödvändig Temperatur", "temperatura wymagana", "nødvendig temperatur", "température requise", "gerekli sıcaklık", "temperatura richiesta", "požadovaná teplota", "požadovaná teplota") @@ -973,37 +973,37 @@ MAKE_TRANSLATION(childlock, "childlock", "child lock", "Kindersicherung") MAKE_TRANSLATION(icon, "icon", "icon", "Icon") // ventilation -MAKE_TRANSLATION(outFresh, "outfresh", "outdoor fresh air", "Außenlufttemp.", "temperatuur buitenlucht", "Utelufttemperatur", "świeże powietrze z zewnątrz", "", "", "dış ortam taze hava", "aria fresca esterna", "čerstvý vzduch vonku", "venkovní čerstvý vzduch") // TODO translate -MAKE_TRANSLATION(inFresh, "infresh", "indoor fresh air", "Zulufttemp.", "temperatuur aanvoer", "Tillufttemperatur", "nawiew", "", "", "iç ortam taze hava", "aria fresca interna", "čerstvý vzduch v interiéri", "vnitřní čerstvý vzduch") // TODO translate -MAKE_TRANSLATION(outEx, "outexhaust", "outdoor exhaust air", "Fortlufttemp.", "uitlaatemperatuur buiten", "Utgående lufttemperatur", "zużyte powietrze z wewnątrz", "", "", "dış ortam egsoz", "aria di scarico esterna", "vonkajší odpadový vzduch", "venkovní odpadní vzduch") // TODO translate -MAKE_TRANSLATION(inEx, "inexhaust", "indoor exhaust air", "Ablufttemp.", "uitlaattemperatuur binnen", "Frånlufttemperatur", "wywiew", "", "", "iç ortam egsoz", "aria di scarico interna", "vnútorný odpadový vzduch", "vnitřní odpadní vzduch") // TODO translate -MAKE_TRANSLATION(ventMode, "ventmode", "ventilation mode", "Belüftungsmodus", "ventilatiemodus", "ventilationsläge", "tryb wentylacji", "", "", "havalandırma modu", "modalità di ventilazione", "režim vetrania", "režim ventilace") // TODO translate -MAKE_TRANSLATION(ventInSpeed, "ventinspeed", "in blower speed", "Zuluftdrehzahl", "toerental aanvoerventilator", "Tilluftflöde", "prędkość wentylatora nawiewu", "", "", "iç fan hızı", "velocità aria di alimentazione", "rýchlosť ventilátora", "rychlost vnitřního ventilátoru") // TODO translate -MAKE_TRANSLATION(ventOutSpeed, "ventoutspeed", "out blower speed", "Abluftdrehzahl", "toerental afvoerventilator", "Frånluftflöde", "prędkość wentylatora wywiewu", "", "", "dış fan hızı", "velocità aria di scarico", "rýchlosť výstupného ventilátora", "rychlost venkovního ventilátoru") // TODO translate -MAKE_TRANSLATION(airquality, "airquality", "air quality (voc)", "Luftqualität (VOC)", "luchtkwaliteit (VOC)", "Luftkvalitet (VOC)", "jakość powietrza", "", "", "hava kalitesi(voc)", "qualità aria (VOC)", "kvalita vzduchu (voc)", "kvalita vzduchu (VOC)") // TODO translate +MAKE_TRANSLATION(outFresh, "outfresh", "outdoor fresh air", "Außenlufttemp.", "temperatuur buitenlucht", "Utelufttemperatur", "świeże powietrze z zewnątrz", "", "", "dış ortam taze hava", "aria fresca esterna", "čerstvý vzduch vonku", "venkovní čerstvý vzduch") +MAKE_TRANSLATION(inFresh, "infresh", "indoor fresh air", "Zulufttemp.", "temperatuur aanvoer", "Tillufttemperatur", "nawiew", "", "", "iç ortam taze hava", "aria fresca interna", "čerstvý vzduch v interiéri", "vnitřní čerstvý vzduch") +MAKE_TRANSLATION(outEx, "outexhaust", "outdoor exhaust air", "Fortlufttemp.", "uitlaatemperatuur buiten", "Utgående lufttemperatur", "zużyte powietrze z wewnątrz", "", "", "dış ortam egsoz", "aria di scarico esterna", "vonkajší odpadový vzduch", "venkovní odpadní vzduch") +MAKE_TRANSLATION(inEx, "inexhaust", "indoor exhaust air", "Ablufttemp.", "uitlaattemperatuur binnen", "Frånlufttemperatur", "wywiew", "", "", "iç ortam egsoz", "aria di scarico interna", "vnútorný odpadový vzduch", "vnitřní odpadní vzduch") +MAKE_TRANSLATION(ventMode, "ventmode", "ventilation mode", "Belüftungsmodus", "ventilatiemodus", "ventilationsläge", "tryb wentylacji", "", "", "havalandırma modu", "modalità di ventilazione", "režim vetrania", "režim ventilace") +MAKE_TRANSLATION(ventInSpeed, "ventinspeed", "in blower speed", "Zuluftdrehzahl", "toerental aanvoerventilator", "Tilluftflöde", "prędkość wentylatora nawiewu", "", "", "iç fan hızı", "velocità aria di alimentazione", "rýchlosť ventilátora", "rychlost vnitřního ventilátoru") +MAKE_TRANSLATION(ventOutSpeed, "ventoutspeed", "out blower speed", "Abluftdrehzahl", "toerental afvoerventilator", "Frånluftflöde", "prędkość wentylatora wywiewu", "", "", "dış fan hızı", "velocità aria di scarico", "rýchlosť výstupného ventilátora", "rychlost venkovního ventilátoru") +MAKE_TRANSLATION(airquality, "airquality", "air quality (voc)", "Luftqualität (VOC)", "luchtkwaliteit (VOC)", "Luftkvalitet (VOC)", "jakość powietrza", "", "", "hava kalitesi(voc)", "qualità aria (VOC)", "kvalita vzduchu (voc)", "kvalita vzduchu (VOC)") MAKE_TRANSLATION(airbypass, "bypass", "bypass", "Bypass", "Bypass", "Bypass", "obejścia", "bypass", "dérivation", "baypas", "Bypass", "obtokový", "bypassový") // EM100 -MAKE_TRANSLATION(minV, "minv", "min volt.", "min. Spannung", "", "min. spänning", "minimalne napięcie", "", "", "", "", "min. napätie", "minimální napětí") // TODO translate -MAKE_TRANSLATION(maxV, "maxv", "max volt.", "max. Spannung", "", "max. spänning", "maksymalne napięcie", "", "", "", "", "max. napätie", "maximální napětí") // TODO translate -MAKE_TRANSLATION(minT, "mint", "min temp.", "min. Temperatur", "", "min. temperatur", "minimalna temperatura", "", "", "", "", "min. tepl.", "minimální teplota") // TODO translate -MAKE_TRANSLATION(maxT, "maxt", "max temp.", "max. Temperatur", "", "max. temperatur", "maksymalna temperatura", "", "", "", "", "max. tepl.", "maximální teplota") // TODO translate -MAKE_TRANSLATION(setPoint, "setpoint", "set temp.", "Solltemperatur", "", "Börvärde", "temperatura nastawu", "", "", "", "", "pož. teplota", "nastavená teplota") // TODO translate -MAKE_TRANSLATION(setPower, "setpower", "request power", "Sollleistung", "", "Böreffekt", "zadana moc", "", "", "", "", "pož. výkon", "požadovaný výkon") // TODO translate -MAKE_TRANSLATION(dip, "dip", "dip switch", "DIP-Schalter", "", "DIP-strömställare", "przełącznik DIP", "", "", "", "", "dip prepínač", "přepínač DIP") // TODO translate -MAKE_TRANSLATION(outPower, "outpow", "output IO1", "Ausgang IO1", "", "Utgångsffekt", "wyjście IO1", "", "", "", "", "výstup IO1", "výstup IO1") // TODO translate -MAKE_TRANSLATION(input, "input", "input", "Eingang", "", "Ingång", "wejście", "", "", "", "", "vstup", "vstup") // TODO translate +MAKE_TRANSLATION(minV, "minv", "min volt.", "min. Spannung", "", "min. spänning", "minimalne napięcie", "", "", "", "", "min. napätie", "minimální napětí") +MAKE_TRANSLATION(maxV, "maxv", "max volt.", "max. Spannung", "", "max. spänning", "maksymalne napięcie", "", "", "", "", "max. napätie", "maximální napětí") +MAKE_TRANSLATION(minT, "mint", "min temp.", "min. Temperatur", "", "min. temperatur", "minimalna temperatura", "", "", "", "", "min. tepl.", "minimální teplota") +MAKE_TRANSLATION(maxT, "maxt", "max temp.", "max. Temperatur", "", "max. temperatur", "maksymalna temperatura", "", "", "", "", "max. tepl.", "maximální teplota") +MAKE_TRANSLATION(setPoint, "setpoint", "set temp.", "Solltemperatur", "", "Börvärde", "temperatura nastawu", "", "", "", "", "pož. teplota", "nastavená teplota") +MAKE_TRANSLATION(setPower, "setpower", "request power", "Sollleistung", "", "Böreffekt", "zadana moc", "", "", "", "", "pož. výkon", "požadovaný výkon") +MAKE_TRANSLATION(dip, "dip", "dip switch", "DIP-Schalter", "", "DIP-strömställare", "przełącznik DIP", "", "", "", "", "dip prepínač", "přepínač DIP") +MAKE_TRANSLATION(outPower, "outpow", "output IO1", "Ausgang IO1", "", "Utgångsffekt", "wyjście IO1", "", "", "", "", "výstup IO1", "výstup IO1") +MAKE_TRANSLATION(input, "input", "input", "Eingang", "", "Ingång", "wejście", "", "", "", "", "vstup", "vstup") /* // unknown fields to track (SM10), only for testing // **** NO TRANSLATION NEEDED **** -MAKE_TRANSLATION(data11, "data11", "unknown datafield 11", "", "", "okänt datafält 11", "nieznane pole danych 11", "", "", "", "", "neznáme dátové pole 11", "") // TODO translate -MAKE_TRANSLATION(data12, "data12", "unknown datafield 12", "", "", "okänt datafält 12", "nieznane pole danych 12", "", "", "", "", "neznáme dátové pole 12", "") // TODO translate -MAKE_TRANSLATION(data8, "data8", "unknown datafield 8", "", "", "okänt datafält 8", "nieznane pole danych 8", "", "", "", "", "neznáme dátové pole 8", "") // TODO translate -MAKE_TRANSLATION(data0, "data0", "unknown datafield 0", "", "", "okänt datafält 0", "nieznane pole danych 0", "", "", "", "", "neznáme dátové pole 0", "") // TODO translate -MAKE_TRANSLATION(data1, "data1", "unknown datafield 1", "", "", "okänt datafält 1", "nieznane pole danych 1", "", "", "", "", "neznáme dátové pole 1", "") // TODO translate -MAKE_TRANSLATION(setting3, "setting3", "unknown setting 3", "", "", "okänd inställning 3", "nieznane ustawienie 3", "", "", "", "", "neznáme dátové pole 3", "") // TODO translate -MAKE_TRANSLATION(setting4, "setting4", "unknown setting 4", "", "", "okänd inställning 4", "nieznane ustawienie 4", "", "", "", "", "neznáme dátové pole 4", "") // TODO translate +MAKE_TRANSLATION(data11, "data11", "unknown datafield 11", "", "", "okänt datafält 11", "nieznane pole danych 11", "", "", "", "", "neznáme dátové pole 11", "") +MAKE_TRANSLATION(data12, "data12", "unknown datafield 12", "", "", "okänt datafält 12", "nieznane pole danych 12", "", "", "", "", "neznáme dátové pole 12", "") +MAKE_TRANSLATION(data8, "data8", "unknown datafield 8", "", "", "okänt datafält 8", "nieznane pole danych 8", "", "", "", "", "neznáme dátové pole 8", "") +MAKE_TRANSLATION(data0, "data0", "unknown datafield 0", "", "", "okänt datafält 0", "nieznane pole danych 0", "", "", "", "", "neznáme dátové pole 0", "") +MAKE_TRANSLATION(data1, "data1", "unknown datafield 1", "", "", "okänt datafält 1", "nieznane pole danych 1", "", "", "", "", "neznáme dátové pole 1", "") +MAKE_TRANSLATION(setting3, "setting3", "unknown setting 3", "", "", "okänd inställning 3", "nieznane ustawienie 3", "", "", "", "", "neznáme dátové pole 3", "") +MAKE_TRANSLATION(setting4, "setting4", "unknown setting 4", "", "", "okänd inställning 4", "nieznane ustawienie 4", "", "", "", "", "neznáme dátové pole 4", "") */ // clang-format on From 6727c0655acb8226b622ef6cba1a4332be0ea199 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 28 Dec 2025 11:20:46 +0100 Subject: [PATCH 46/47] update dictionary --- project-words.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/project-words.txt b/project-words.txt index 332acd06c..0ac36f9f6 100644 --- a/project-words.txt +++ b/project-words.txt @@ -1446,3 +1446,4 @@ intergral vchip SPIIO SPIDQS +txpause From 263af58dc0686287cb3fa2b6c2a690552369fa4b Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 29 Dec 2025 10:37:55 +0100 Subject: [PATCH 47/47] package update --- interface/pnpm-lock.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index 74710a1ed..c15ed5094 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -2884,8 +2884,8 @@ packages: resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} engines: {node: '>=0.10.0'} - ts-api-utils@2.2.0: - resolution: {integrity: sha512-L6f5oQRAoLU1RwXz0Ab9mxsE7LtxeVB6AIR1lpkZMsOyg/JXeaxBaXa/FVCBZyNr9S9I4wkHrlZTklX+im+WMw==} + ts-api-utils@2.3.0: + resolution: {integrity: sha512-6eg3Y9SF7SsAvGzRHQvvc1skDAhwI4YQ32ui1scxD1Ccr0G5qIIbUBT3pFTKX8kmWIQClHobtUdNuaBgwdfdWg==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -3814,7 +3814,7 @@ snapshots: eslint: 9.39.2 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.2.0(typescript@5.9.3) + ts-api-utils: 2.3.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -3856,7 +3856,7 @@ snapshots: '@typescript-eslint/utils': 8.50.1(eslint@9.39.2)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.2 - ts-api-utils: 2.2.0(typescript@5.9.3) + ts-api-utils: 2.3.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -3873,7 +3873,7 @@ snapshots: minimatch: 9.0.5 semver: 7.7.3 tinyglobby: 0.2.15 - ts-api-utils: 2.2.0(typescript@5.9.3) + ts-api-utils: 2.3.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -5882,7 +5882,7 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - ts-api-utils@2.2.0(typescript@5.9.3): + ts-api-utils@2.3.0(typescript@5.9.3): dependencies: typescript: 5.9.3