diff --git a/.github/workflows/dev_release.yml b/.github/workflows/dev_release.yml index 78d1171e4..20629475e 100644 --- a/.github/workflows/dev_release.yml +++ b/.github/workflows/dev_release.yml @@ -43,6 +43,7 @@ jobs: run: | python -m pip install --upgrade pip pip install -U platformio + python -m pip install intelhex - name: Build the WebUI run: | diff --git a/.github/workflows/stable_release.yml b/.github/workflows/stable_release.yml index 3abfae703..b4c44c4f1 100644 --- a/.github/workflows/stable_release.yml +++ b/.github/workflows/stable_release.yml @@ -35,6 +35,7 @@ jobs: run: | python -m pip install --upgrade pip pip install -U platformio + python -m pip install intelhex - name: Build the WebUI run: | diff --git a/.github/workflows/test_release.yml b/.github/workflows/test_release.yml index 11ab624ba..ae685cf43 100644 --- a/.github/workflows/test_release.yml +++ b/.github/workflows/test_release.yml @@ -43,6 +43,7 @@ jobs: run: | python -m pip install --upgrade pip pip install -U platformio + python -m pip install intelhex - name: Build the WebUI run: | diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 9391a15a9..d5a58947c 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -19,6 +19,10 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/). - added new board profile for upcoming BBQKees E32V2.2 - set differential pressure entity in Mixer device - set set climate action cooling/heating in HA +- Internal sensors of E32V2_2 +- FW200 display options +- CR11 mode settings OFF/MANUAL depends on selTemp +- Fuse settings for BBQKees boards ## Fixed @@ -39,4 +43,5 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/). ## Changed - show console log with ISO date/time [#2533](https://github.com/emsesp/EMS-ESP32/discussions/2533) +- remove ESP32 CPU temperature - updated core libraries like AsyncTCP, AsyncWebServer and Modbus diff --git a/src/core/console.cpp b/src/core/console.cpp index d067bc649..08b400dd6 100644 --- a/src/core/console.cpp +++ b/src/core/console.cpp @@ -303,7 +303,7 @@ static void setup_commands(std::shared_ptr const & commands) { std::string board_profile = Helpers::toUpper(arguments.front()); if (!EMSESP::system_.load_board_profile(data, board_profile)) { shell.println( - "Invalid board profile (S32, E32, E32V2, E32V3, MH-ET, NODEMCU, LOLIN, OLIMEX, OLIMEXPOE, C3MINI, S2MINI, S3MINI, S32S3, CUSTOM)"); + "Invalid board profile (S32, E32, E32V2, E32V2_2, MH-ET, NODEMCU, LOLIN, OLIMEX, OLIMEXPOE, C3MINI, S2MINI, S3MINI, S32S3, CUSTOM)"); return; } diff --git a/src/core/locale_common.h b/src/core/locale_common.h index fd06c6a61..36a072937 100644 --- a/src/core/locale_common.h +++ b/src/core/locale_common.h @@ -306,7 +306,9 @@ MAKE_ENUM(enum_hpPumpMode, FL_(auto), FL_(continuous)) // thermostat lists MAKE_ENUM(enum_ibaMainDisplay, FL_(internal_temperature), FL_(internal_setpoint), FL_(external_temperature), FL_(burner_temperature), FL_(ww_temperature), FL_(functioning_mode), FL_(time), FL_(date), FL_(smoke_temperature)) +MAKE_ENUM(enum_ibaMainDisplayJ, FL_(ww_temperature), FL_(date), FL_(external_temperature)) MAKE_ENUM(enum_ibaLanguage, FL_(german), FL_(dutch), FL_(french), FL_(italian)) +MAKE_ENUM(enum_ibaLanguageJ, FL_(german), FL_(italian), FL_(french), FL_(dutch)) MAKE_ENUM(enum_ibaLanguage_RC30, FL_(german), FL_(dutch)) MAKE_ENUM(enum_floordrystatus, FL_(off), FL_(start), FL_(heat), FL_(hold), FL_(cool), FL_(end)) MAKE_ENUM(enum_ibaBuildingType, FL_(light), FL_(medium), FL_(heavy)) @@ -334,6 +336,7 @@ MAKE_ENUM(enum_mode3, FL_(night), FL_(day), FL_(auto)) // RC35, RC3 MAKE_ENUM(enum_mode4, FL_(nofrost), FL_(eco), FL_(heat), FL_(auto)) // JUNKERS MAKE_ENUM(enum_mode5, FL_(auto), FL_(off)) // CRF MAKE_ENUM(enum_mode6, FL_(nofrost), FL_(night), FL_(day)) // RC10 +MAKE_ENUM(enum_mode7, FL_(off), FL_(manual)) // CR11 MAKE_ENUM(enum_mode_ha, FL_(off), FL_(heat), FL_(auto)) // HA climate MAKE_ENUM(enum_modetype, FL_(eco), FL_(comfort)) diff --git a/src/core/system.cpp b/src/core/system.cpp index d466c000e..064fd2f7e 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -428,7 +428,7 @@ void System::reload_settings() { // See https://diyprojects.io/esp32-how-to-use-gpio-digital-io-arduino-code/#.YFpVEq9KhjG // and https://nodemcu.readthedocs.io/en/dev-esp32/modules/gpio/ bool System::is_valid_gpio(uint8_t pin, bool has_psram) { -#if CONFIG_IDF_TARGET_ESP32 || EMSESP_STANDALONE +#if CONFIG_IDF_TARGET_ESP32 || defined(EMSESP_STANDALONE) if ((pin == 1) || (pin >= 6 && pin <= 11) || (pin == 20) || (pin == 24) || (pin >= 28 && pin <= 31) || (pin > 40) || ((EMSESP::system_.PSram() > 0 || has_psram) && pin >= 16 && pin <= 17)) { #elif CONFIG_IDF_TARGET_ESP32S2 @@ -791,10 +791,7 @@ void System::system_check() { last_system_check_ = uuid::get_uptime(); #ifndef EMSESP_STANDALONE -#if defined(CONFIG_IDF_TARGET_ESP32) - uint8_t raw = temprature_sens_read(); - temperature_ = (raw - 32) / 1.8f; // convert to Celsius -#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 #if ESP_IDF_VERSION_MAJOR < 5 temp_sensor_read_celsius(&temperature_); #else @@ -1433,9 +1430,18 @@ bool System::command_service(const char * cmd, const char * value) { int n; if (!ok && Helpers::value2number(value, n)) { #ifndef EMSESP_STANDALONE - if (!strcmp(cmd, "fuse/mfg")) { // && esp_efuse_read_reg(EFUSE_BLK3, 0) == 0) { + if (!strcmp(cmd, "fuse/mfg")) { ok = esp_efuse_write_reg(EFUSE_BLK3, 0, (uint32_t)n) == ESP_OK; - LOG_INFO("fuse programed with value '%X': %s", n, ok ? "successful" : "failed"); + ok ? LOG_INFO("fuse programed with value '%X': successful", n) : LOG_ERROR("fuse programed with value '%X': failed", n); + + } + if (!strcmp(cmd, "fuse/mfgadd")) { + uint8_t reg = 0; + while (esp_efuse_read_reg(EFUSE_BLK3, reg) != 0 && reg < 7) + reg++; + ok = esp_efuse_write_reg(EFUSE_BLK3, reg, (uint32_t)n) == ESP_OK; + ok ? LOG_INFO("fuse %d programed with value '%X': successful", reg, n) : LOG_ERROR("fuse %d programed with value '%X': failed", reg, n); + return true; } #endif } @@ -1532,12 +1538,12 @@ void System::get_value_json(JsonObject output, const std::string & circuit, cons if (val.is()) { output["value"] = val.as(); output["type"] = "boolean"; - } else if (val.is() || val.is() || val.is()) { - output["value"] = val.as(); - output["type"] = "string"; - } else { + } else if (val.is() || val.is()) { output["value"] = val.as(); output["type"] = "number"; + } else { + output["value"] = val.as(); + output["type"] = "string"; } } @@ -2043,7 +2049,7 @@ bool System::ntp_connected() { } // see if its a BBQKees Gateway by checking the nvs values -String System::getBBQKeesGatewayDetails() { +String System::getBBQKeesGatewayDetails(uint8_t detail) { #ifndef EMSESP_STANDALONE /* if (!EMSESP::nvs_.isKey("mfg")) { @@ -2072,13 +2078,36 @@ String System::getBBQKeesGatewayDetails() { }; uint32_t reg; } gw; - gw.reg = esp_efuse_read_reg(EFUSE_BLK3, 0); + for (uint8_t reg = 0; reg < 8; reg++) { + gw.reg = esp_efuse_read_reg(EFUSE_BLK3, reg); + if (reg == 7 || esp_efuse_read_reg(EFUSE_BLK3, reg + 1) == 0) + break; + } const char * mfg[] = {"unknown", "BBQKees Electronics", "", "", "", "", "", ""}; const char * model[] = {"unknown", "S3", "E32V2", "E32V2.2", "S32", "E32", "", "", ""}; - - return gw.reg ? String(mfg[gw.mfg]) + " " + String(model[gw.model]) + " rev." + String(gw.rev_major) + "." + String(gw.rev_minor) + "/" - + String(2000 + gw.year) + "-" + String(gw.month) + "-" + String(gw.no) + " (fuse 0x" + String(gw.reg, 16) + ")" - : ""; + const char * board[] = {"CUSTOM", "S32S3", "E32V2", "E32V2_2", "S32", "E32", "", "", ""}; + switch (detail) { + case FUSE_VALUE::MFG: + return gw.mfg < 2 ? String(mfg[gw.mfg]) : "unknown"; + case FUSE_VALUE::MODEL: + return gw.model < 6 ? String(model[gw.model]) : "unknown"; + case FUSE_VALUE::BOARD: + return gw.model < 6 ? String(board[gw.model]) : board_profile_; + case FUSE_VALUE::REV: + return String(gw.rev_major) + "." + String(gw.rev_minor); + case FUSE_VALUE::BATCH: + return String(2000 + gw.year) + (gw.month < 10 ? "0" : "") + String(gw.month) + String(gw.no); + case FUSE_VALUE::FUSE: + return "0x" + String(gw.reg, 16); + case FUSE_VALUE::ALL: + default: + break; + } + if (!gw.reg || gw.mfg > 1 || gw.model > 5) { + return ""; + } + return String(mfg[gw.mfg]) + " " + String(model[gw.model]) + " rev." + String(gw.rev_major) + "." + String(gw.rev_minor) + "/" + String(2000 + gw.year) + + (gw.month < 10 ? "0" : "") + String(gw.month) + String(gw.no); #else return ""; #endif diff --git a/src/core/system.h b/src/core/system.h index 8431e697a..969c23959 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -68,6 +68,8 @@ enum SYSTEM_STATUS : uint8_t { SYSTEM_STATUS_RESTART_REQUESTED = 5 }; +enum FUSE_VALUE : uint8_t { ALL = 0, MFG = 1, MODEL = 2, BOARD = 3, REV = 4, BATCH = 5, FUSE = 6 }; + class System { public: void start(); @@ -121,7 +123,7 @@ class System { } #endif - String getBBQKeesGatewayDetails(); + String getBBQKeesGatewayDetails(uint8_t detail = 0); static bool uploadFirmwareURL(const char * url = nullptr); @@ -330,7 +332,7 @@ class System { test_set_all_active_ = n; } -#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 +#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 float temperature() { return temperature_; } diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 470b60627..00eb431d1 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -226,6 +226,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i register_telegram_type(0xBB, "HybridSettings", true, MAKE_PF_CB(process_HybridSettings)); register_telegram_type(0x23, "JunkersSetMixer", true, MAKE_PF_CB(process_JunkersSetMixer)); register_telegram_type(0x1D3, "JunkersDhw", true, MAKE_PF_CB(process_JunkersWW)); + register_telegram_type(0x11E, "JunkersDisp", true, MAKE_PF_CB(process_JunkersDisp)); } // register device values for common values (not heating circuit) @@ -511,7 +512,11 @@ uint8_t Thermostat::HeatingCircuit::get_mode() const { return HeatingCircuit::Mode::OFF; } } else if (model == EMSdevice::EMS_DEVICE_FLAG_CR11) { - return HeatingCircuit::Mode::MANUAL; + if (mode > 0) { + return HeatingCircuit::Mode::MANUAL; + } else { + return HeatingCircuit::Mode::OFF; + } } else if (model == EMSdevice::EMS_DEVICE_FLAG_BC400 || model == EMSdevice::EMS_DEVICE_FLAG_CR120) { if (mode_new == 0) { return HeatingCircuit::Mode::OFF; @@ -567,6 +572,8 @@ uint8_t Thermostat::HeatingCircuit::get_mode_type() const { } else if (modetype == 1) { return HeatingCircuit::Mode::DAY; } + } else if (model == EMSdevice::EMS_DEVICE_FLAG_CR11) { + return mode ? HeatingCircuit::Mode::MANUAL : HeatingCircuit::Mode::OFF; } else if (model == EMSdevice::EMS_DEVICE_FLAG_CRF) { if (modetype == 0) { return HeatingCircuit::Mode::OFF; @@ -1055,11 +1062,18 @@ void Thermostat::process_JunkersSetMixer(std::shared_ptr telegra has_update(telegram, hc->targetflowtemp, 0); } +// Thermostat(0x10) -> All(0x00), ?(0x01D3), data: 01 00 00 void Thermostat::process_JunkersWW(std::shared_ptr telegram) { auto dhw = dhw_circuit(0, true); has_bitupdate(telegram, dhw->wwCharge_, 0, 3); } +// 0x11E +void Thermostat::process_JunkersDisp(std::shared_ptr telegram) { + has_update(telegram, ibaMainDisplay_, 1); + has_update(telegram, ibaLanguage_, 3); +} + // type 0x02A5 - data from Worchester CRF200 void Thermostat::process_CRFMonitor(std::shared_ptr telegram) { auto hc = heating_circuit(telegram); @@ -1083,10 +1097,15 @@ void Thermostat::process_CR11Monitor(std::shared_ptr telegram) { return; } - has_update(telegram, hc->roomTemp, 0); // is * 10 - has_update(hc->mode, 0); // set manual for CR11 + has_update(telegram, hc->roomTemp, 0); // is * 10 + // has_update(hc->mode, 0); // set manual for CR11 has_update(telegram, hc->selTemp, 6, 1); // is * 2, force as single byte has_update(telegram, hc->targetflowtemp, 4); + if (hc->selTemp == 0) { + hc->mode = 0; + } else { + hc->mode = 1; + } add_ha_climate(hc); } @@ -2007,13 +2026,18 @@ bool Thermostat::set_calinttemp(const char * value, const int8_t id) { // 0xA5 - Set the display settings, RC30_N bool Thermostat::set_display(const char * value, const int8_t id) { uint8_t ds; - if (!Helpers::value2enum(value, ds, FL_(enum_ibaMainDisplay))) { - return false; + if (model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) { + if (Helpers::value2enum(value, ds, FL_(enum_ibaMainDisplayJ))) { + write_command(0x11E, 1, ds, 0x11E); + return true; + } + } else { + if (Helpers::value2enum(value, ds, FL_(enum_ibaMainDisplay))) { + write_command(EMS_TYPE_IBASettings, 0, ds, EMS_TYPE_IBASettings); + return true; + } } - - write_command(EMS_TYPE_IBASettings, 0, ds, EMS_TYPE_IBASettings); - - return true; + return false; } // 0xA7 - Set Screen brightness @@ -2168,7 +2192,12 @@ bool Thermostat::set_solar(const char * value, const int8_t id) { bool Thermostat::set_language(const char * value, const int8_t id) { uint8_t lg; - if (model() == EMSdevice::EMS_DEVICE_FLAG_RC30) { + if (model() == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) { + if (!Helpers::value2enum(value, lg, FL_(enum_ibaLanguageJ))) { + return false; + } + write_command(0x11E, 3, lg, 0x11E); + } else if (model() == EMSdevice::EMS_DEVICE_FLAG_RC30) { if (!Helpers::value2enum(value, lg, FL_(enum_ibaLanguage_RC30))) { return false; } @@ -2993,6 +3022,9 @@ bool Thermostat::set_mode(const char * value, const int8_t id) { case EMSdevice::EMS_DEVICE_FLAG_CRF: mode_list = FL_(enum_mode5); break; + case EMSdevice::EMS_DEVICE_FLAG_CR11: + mode_list = FL_(enum_mode7); + break; default: return false; } @@ -3077,6 +3109,15 @@ bool Thermostat::set_mode_n(const uint8_t mode, const int8_t id) { uint8_t model_ = model(); switch (model_) { + case EMSdevice::EMS_DEVICE_FLAG_CR11: + offset = 10; + if (set_mode_value) { + if (hc->selTemp > 0) { + return true; + } + set_mode_value = 50; // set selTemp to 5 degrees + } + break; case EMSdevice::EMS_DEVICE_FLAG_RC10: offset = 0; validate_typeid = 0xB1; @@ -3834,7 +3875,11 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co } else if (model == EMSdevice::EMS_DEVICE_FLAG_CR11) { offset = 10; // just seltemp write to manualtemp - + if (temperature == 0) { + hc->mode = 0; + } else { + hc->mode = 1; + } } else if (isRC300() || (model == EMSdevice::EMS_DEVICE_FLAG_RC100)) { validate_typeid = set_typeids[hc->hc()]; switch (mode) { @@ -4538,6 +4583,20 @@ void Thermostat::register_device_values() { FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &ibaMainDisplay_, + DeviceValueType::ENUM, + FL_(enum_ibaMainDisplayJ), + FL_(ibaMainDisplay), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_display)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &ibaLanguage_, + DeviceValueType::ENUM, + FL_(enum_ibaLanguageJ), + FL_(ibaLanguage), + DeviceValueUOM::NONE, + MAKE_CF_CB(set_language)); } register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hybridStrategy_, @@ -4806,7 +4865,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrtargetflowtemp, DeviceValueType::UINT8, FL_(targetflowtemp), DeviceValueUOM::DEGREES); break; case EMSdevice::EMS_DEVICE_FLAG_CR11: - register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode), FL_(mode), DeviceValueUOM::NONE); + register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode7), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT8, FL_(targetflowtemp), DeviceValueUOM::DEGREES); register_device_value( tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), FL_(heatingtype), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatingtype)); diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index 3ee85bdc2..62bbe67e9 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -458,6 +458,7 @@ class Thermostat : public EMSdevice { void process_Absent(std::shared_ptr telegram); void process_JunkersSetMixer(std::shared_ptr telegram); void process_JunkersWW(std::shared_ptr telegram); + void process_JunkersDisp(std::shared_ptr telegram); void process_RemoteTemp(std::shared_ptr telegram); void process_RemoteHumidity(std::shared_ptr telegram); void process_RemoteCorrection(std::shared_ptr telegram); diff --git a/src/emsesp_version.h b/src/emsesp_version.h index 5ff361f20..42e3d4969 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.3-dev.16" +#define EMSESP_APP_VERSION "3.7.3-dev.17" diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index a65e7d49e..f83475a1a 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -112,13 +112,13 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { // We only do this for BBQKees boards // Note 1: we never set the NVS boot value in the code - this is done on initial pre-loading // Note 2: The board profile is dynamically changed for the session, but the value in the settings file on the FS remains untouched - if (!EMSESP::system_.getBBQKeesGatewayDetails().isEmpty()) { - String nvs_boot = EMSESP::nvs_.getString("boot"); - if (!nvs_boot.isEmpty()) { + if (EMSESP::system_.getBBQKeesGatewayDetails(FUSE_VALUE::MFG).startsWith("BBQKees")) { + String bbq_board = EMSESP::system_.getBBQKeesGatewayDetails(FUSE_VALUE::BOARD); + if (!bbq_board.isEmpty()) { #if defined(EMSESP_DEBUG) - EMSESP::logger().debug("Overriding board profile with NVS boot value %s", nvs_boot.c_str()); + EMSESP::logger().info("Overriding board profile with fuse value %s", bbq_board.c_str()); #endif - settings.board_profile = nvs_boot; + settings.board_profile = bbq_board; } } diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index a5f3246b7..0431479b8 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -130,8 +130,8 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) { root["free_psram"] = ESP.getFreePsram() / 1024; } root["model"] = EMSESP::system_.getBBQKeesGatewayDetails(); -#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 - root["temperature"] = Helpers::transformNumFloat(EMSESP::system_.temperature(), 0, EMSESP::system_.fahrenheit() ? 2 : 0); // only 2 decimal places +#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 + root["temperature"] = (int)Helpers::transformNumFloat(EMSESP::system_.temperature(), 0, EMSESP::system_.fahrenheit() ? 2 : 0); // only 2 decimal places #endif // check for a factory partition first