diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index c26c2890d..ffefbd0fa 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -13,6 +13,7 @@ For more details go to [emsesp.org](https://emsesp.org/). - boiler pumpkick [#2965](https://github.com/emsesp/EMS-ESP32/discussions/2965) - heatpump reset [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933) - e-mail notification using ReadyMail Client +- 2.nd freshwater module (dhw4) [#2991](https://github.com/emsesp/EMS-ESP32/issues/2991) ## Fixed diff --git a/boards/seeed_xiao_esp32c6.json b/boards/seeed_xiao_esp32c6.json index 224f0e215..a3de41d41 100644 --- a/boards/seeed_xiao_esp32c6.json +++ b/boards/seeed_xiao_esp32c6.json @@ -2,6 +2,7 @@ "build": { "core": "esp32", "extra_flags": [ + "-DNO_TLS_SUPPORT", "-DARDUINO_XIAO_ESP32C6", "-DARDUINO_USB_MODE=1", "-DARDUINO_USB_CDC_ON_BOOT=1" diff --git a/interface/eslint.config.js b/interface/eslint.config.js index 4eca2f5e5..bacff3965 100644 --- a/interface/eslint.config.js +++ b/interface/eslint.config.js @@ -1,9 +1,10 @@ // @ts-check import eslint from '@eslint/js'; import prettierConfig from 'eslint-config-prettier'; +import { defineConfig } from 'eslint/config'; import tseslint from 'typescript-eslint'; -export default tseslint.config( +export default defineConfig( eslint.configs.recommended, ...tseslint.configs.recommendedTypeChecked, prettierConfig, diff --git a/interface/package.json b/interface/package.json index 7a1ab05d6..7f821c954 100644 --- a/interface/package.json +++ b/interface/package.json @@ -49,7 +49,7 @@ "devDependencies": { "@babel/core": "^7.29.0", "@eslint/js": "^10.0.1", - "@preact/compat": "^18.3.1", + "@preact/compat": "^18.3.2", "@preact/preset-vite": "^2.10.5", "@trivago/prettier-plugin-sort-imports": "^6.0.2", "@types/node": "^25.5.0", diff --git a/lib/uuid-syslog/src/syslog.cpp b/lib/uuid-syslog/src/syslog.cpp index 024fa6665..4e0eac774 100644 --- a/lib/uuid-syslog/src/syslog.cpp +++ b/lib/uuid-syslog/src/syslog.cpp @@ -20,7 +20,7 @@ #include "../../src/core/emsesp.h" #ifndef UUID_SYSLOG_HAVE_GETTIMEOFDAY -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP8266) // time() does not return UTC on the ESP8266: https://github.com/esp8266/Arduino/issues/4637 #define UUID_SYSLOG_HAVE_GETTIMEOFDAY 1 #endif diff --git a/platformio.ini b/platformio.ini index 6182f6328..053db1a2b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -154,16 +154,10 @@ build_flags = -DBOARD_C3_MINI_V1 ; XIAO ESP32C - 512KB SRAM & 4MB Flash - https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/ -[env:c6] -framework = arduino -board_build.partitions = partitions/esp32_partition_4M.csv -board_upload.flash_size = 4MB +[env:c6_xiao_4M] +extends = espressif32_base_4M board_build.app_partition_name = app0 -platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip ; Arduino Release v3.3.0 based on ESP-IDF v5.5.0 board = seeed_xiao_esp32c6 -build_flags = - ${common.build_flags} - -DBOARD_C6 ; foundation for building and testing natively, standalone without an ESP32 ; use the `standalone` environment instead of `native` for testing diff --git a/src/ESP32React/NTPSettingsService.cpp b/src/ESP32React/NTPSettingsService.cpp index b12d69bbf..2cf67353f 100644 --- a/src/ESP32React/NTPSettingsService.cpp +++ b/src/ESP32React/NTPSettingsService.cpp @@ -52,7 +52,12 @@ void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVari tm.tm_isdst = -1; // not set by strptime, tells mktime to determine daylightsaving time_t time = mktime(&tm); struct timeval now = {.tv_sec = time, .tv_usec = {}}; +#if CONFIG_IDF_TARGET_ESP32C3 + // settimeofday and adjtime() does not work, unknown how to set time + emsesp::EMSESP::logger().warning("manual clock setting not possible"); +#else settimeofday(&now, nullptr); +#endif AsyncWebServerResponse * response = request->beginResponse(200); request->send(response); return; diff --git a/src/ESP32React/UploadFileService.cpp b/src/ESP32React/UploadFileService.cpp index 4d016dce4..53a897613 100644 --- a/src/ESP32React/UploadFileService.cpp +++ b/src/ESP32React/UploadFileService.cpp @@ -61,22 +61,27 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri if (_is_firmware) { // Check firmware header, 0xE9 magic offset 0 indicates esp bin, chip offset 12: esp32:0, S2:2, C3:5 #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 - if (len > 12 && (data[0] != 0xE9 || data[12] != 0)) { + if (len > 12 && (data[0] != ESP_IMAGE_HEADER_MAGIC || data[12] != ESP_CHIP_ID_ESP32)) { handleError(request, 503); // service unavailable return; } #elif CONFIG_IDF_TARGET_ESP32S2 - if (len > 12 && (data[0] != 0xE9 || data[12] != 2)) { + if (len > 12 && (data[0] != ESP_IMAGE_HEADER_MAGIC || data[12] != ESP_CHIP_ID_ESP32S2)) { handleError(request, 503); // service unavailable return; } #elif CONFIG_IDF_TARGET_ESP32C3 - if (len > 12 && (data[0] != 0xE9 || data[12] != 5)) { + if (len > 12 && (data[0] != ESP_IMAGE_HEADER_MAGIC || data[12] != ESP_CHIP_ID_ESP32C3)) { handleError(request, 503); // service unavailable return; } #elif CONFIG_IDF_TARGET_ESP32S3 - if (len > 12 && (data[0] != 0xE9 || data[12] != 9)) { + if (len > 12 && (data[0] != ESP_IMAGE_HEADER_MAGIC || data[12] != ESP_CHIP_ID_ESP32S3)) { + handleError(request, 503); // service unavailable + return; + } +#elif CONFIG_IDF_TARGET_ESP32C6 + if (len > 12 && (data[0] != ESP_IMAGE_HEADER_MAGIC || data[12] != ESP_CHIP_ID_ESP32C6)) { handleError(request, 503); // service unavailable return; } diff --git a/src/core/default_settings.h b/src/core/default_settings.h index 958ccf4c5..3a49273fa 100644 --- a/src/core/default_settings.h +++ b/src/core/default_settings.h @@ -285,6 +285,8 @@ enum { #define EMSESP_PLATFORM "ESP32S3" #elif CONFIG_IDF_TARGET_ESP32 || EMSESP_STANDALONE #define EMSESP_PLATFORM "ESP32" +#elif CONFIG_IDF_TARGET_ESP32C6 +#define EMSESP_PLATFORM "ESP32C6" #else #error Target CONFIG_IDF_TARGET is not supported #endif diff --git a/src/core/system.cpp b/src/core/system.cpp index 9694bb055..1f7411e7b 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -34,25 +34,6 @@ #include "../test/test.h" #endif -#ifndef EMSESP_STANDALONE -#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ -#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 -#include "../esp32/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32S2 -#include "../esp32s2/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32C3 -#include "../esp32c3/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32S3 -#include "../esp32s3/rom/rtc.h" -#else -#error Target CONFIG_IDF_TARGET is not supported -#endif -#else // ESP32 Before IDF 4.0 -#include "../rom/rtc.h" -#endif -#include -#endif - #ifndef NO_TLS_SUPPORT #define ENABLE_SMTP #define USE_ESP_SSLCLIENT @@ -63,6 +44,7 @@ #endif #ifndef EMSESP_STANDALONE +#include #include "esp_efuse.h" #endif @@ -2761,37 +2743,38 @@ bool System::command_restart(const char * value, const int8_t id) { std::string System::reset_reason(uint8_t cpu) const { #ifndef EMSESP_STANDALONE - switch (rtc_get_reset_reason(cpu)) { - case 1: + switch (esp_rom_get_reset_reason(cpu)) { + case RESET_REASON_CHIP_POWER_ON: return ("Power on reset"); - // case 2 :reset pin not on esp32 - case 3: + case 2: // not on esp32 + return ("reset pin"); + case RESET_REASON_CORE_SW: return ("Software reset"); case 4: // not on S2, C3 return ("Legacy watch dog reset"); - case 5: + case RESET_REASON_CORE_DEEP_SLEEP: return ("Deep sleep reset"); - case 6: // not on S2, C3 - return ("Reset by SDIO"); - case 7: + case 6: // RESET_REASON_CORE_SDIO: // not on S2, S3, C3 + return ("Reset by SDIO"); + case RESET_REASON_CORE_MWDT0: return ("Timer group0 watch dog reset"); - case 8: + case RESET_REASON_CORE_MWDT1: return ("Timer group1 watch dog reset"); - case 9: + case RESET_REASON_CORE_RTC_WDT: return ("RTC watch dog reset"); case 10: return ("Intrusion reset CPU"); - case 11: + case RESET_REASON_CPU0_MWDT0: return ("Timer group reset CPU"); - case 12: + case RESET_REASON_CPU0_SW: return ("Software reset CPU"); - case 13: + case RESET_REASON_CPU0_RTC_WDT: return ("RTC watch dog reset: CPU"); - case 14: // not on S2, C3 + case 14: // RESET_REASON_CPU1_CPU0: // not on S2, S3, C3 return ("APP CPU reset by PRO CPU"); - case 15: + case RESET_REASON_SYS_BROWN_OUT: return ("Brownout reset"); - case 16: + case RESET_REASON_SYS_RTC_WDT: return ("RTC watch dog reset: CPU+RTC"); default: break; @@ -3225,6 +3208,10 @@ void System::set_valid_system_gpios() { } else { valid_system_gpios_ = string_range_to_vector("0-39", "6-11, 20, 24, 28-31"); } +#elif CONFIG_IDF_TARGET_ESP32C6 + // https://docs.espressif.com/projects/esp-idf/en/v5.5.3/esp32c6/api-reference/peripherals/gpio.html + // 24-30 used for flash, 12-13 USB, 16-17 uart0 + valid_system_gpios_ = string_range_to_vector("0-30", "12-13, 16-17, 24-30"); #elif defined(EMSESP_STANDALONE) valid_system_gpios_ = string_range_to_vector("0-39"); #endif diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 889276ad7..95170fbb7 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -1759,8 +1759,12 @@ void Thermostat::process_RCTime(std::shared_ptr telegram) { ttime = mktime(tm_); // thermostat time } struct timeval newnow = {.tv_sec = ttime, .tv_usec = 0}; +#if CONFIG_IDF_TARGET_ESP32C3 + // unknown how to set time on C3 +#else settimeofday(&newnow, nullptr); LOG_INFO("ems-esp time set from thermostat"); +#endif } #endif } diff --git a/src/devices/water.cpp b/src/devices/water.cpp index 94a8c9cf2..22f198289 100644 --- a/src/devices/water.cpp +++ b/src/devices/water.cpp @@ -29,16 +29,21 @@ Water::Water(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c dhw_ = device_id - EMSdevice::EMS_DEVICE_ID_DHW1; int8_t tag = DeviceValueTAG::TAG_DHW1 + dhw_; if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) { // device_id 0x2A, DHW3 + // telegram handlers - register_telegram_type(0x07D6, "SM100wwTemperature", false, MAKE_PF_CB(process_SM100wwTemperature)); - register_telegram_type(0x07AA, "SM100wwStatus", false, MAKE_PF_CB(process_SM100wwStatus)); - register_telegram_type(0x07AB, "SM100wwCommand", false, MAKE_PF_CB(process_SM100wwCommand)); - register_telegram_type(0x07AC, "SM100wwParam1", false, MAKE_PF_CB(process_SM100wwParam2)); - register_telegram_type(0x07A5, "SM100wwCirc", true, MAKE_PF_CB(process_SM100wwCirc)); - register_telegram_type(0x07A6, "SM100wwParam", true, MAKE_PF_CB(process_SM100wwParam)); - register_telegram_type(0x07AE, "SM100wwKeepWarm", true, MAKE_PF_CB(process_SM100wwKeepWarm)); - register_telegram_type(0x07E0, "SM100wwStatus2", true, MAKE_PF_CB(process_SM100wwStatus2)); - register_telegram_type(0x07AD, "SM100ValveStatus", false, MAKE_PF_CB(process_SM100ValveStatus)); + register_telegram_type(0x07D6 + dhw_ - 2, "SM100wwTemperature", false, MAKE_PF_CB(process_SM100wwTemperature)); + register_telegram_type(0x07E0 + dhw_ - 2, "SM100wwStatus2", true, MAKE_PF_CB(process_SM100wwStatus2)); + register_telegram_type(0x07A6, "SM100wwParam", true, MAKE_PF_CB(process_SM100wwParam)); // same telegram for all circuits + if (tag == DeviceValueTAG::TAG_DHW3) { + register_telegram_type(0x07AA, "SM100wwStatus", false, MAKE_PF_CB(process_SM100wwStatus)); + register_telegram_type(0x07AC, "SM100wwParam1", false, MAKE_PF_CB(process_SM100wwParam2)); + register_telegram_type(0x07A5, "SM100wwCirc", true, MAKE_PF_CB(process_SM100wwCirc)); + register_telegram_type(0x07AE, "SM100wwKeepWarm", true, MAKE_PF_CB(process_SM100wwKeepWarm)); + register_telegram_type(0x07AD, "SM100ValveStatus", false, MAKE_PF_CB(process_SM100ValveStatus)); + register_telegram_type(0x07AB, "SM100wwCommand", false, MAKE_PF_CB(process_SM100wwCommand)); // command from thermostat + } else if (tag == DeviceValueTAG::TAG_DHW4) { + register_telegram_type(0x07C3, "SM100wwCommand", false, MAKE_PF_CB(process_SM100wwCommand)); // command from dhw3->dhw4 + } // device values... register_device_value(tag, &wwTemp_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwTemp), DeviceValueUOM::DEGREES); register_device_value(tag, &wwTemp2_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(wwStorageTemp1), DeviceValueUOM::DEGREES); @@ -100,7 +105,7 @@ Water::Water(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c } } -// SM100wwTemperature - 0x07D6 +// SM100wwTemperature - 0x07D6, dhw4: 0x07D7 // Solar Module(0x2A) -> (0x00), (0x7D6), data: 01 C1 00 00 02 5B 01 AF 01 AD 80 00 01 90 void Water::process_SM100wwTemperature(std::shared_ptr telegram) { has_update(telegram, wwTemp_, 0); // is *10 TS17 @@ -156,12 +161,10 @@ void Water::process_SM100ValveStatus(std::shared_ptr telegram) { has_update(telegram, wwRetValve_, 1); } -/* -// SM100ww? - 0x7E0, some kind of status +// SM100ww? - 0x7E0, some kind of status, dhw4: 0x7E1 // data: 00 00 46 00 00 01 06 0E 06 0E 00 00 00 00 00 03 03 03 03 // publishes single values offset 1/2(16bit), offset 5, offset 6, offset 7, offset 8, offset 9, // status2 = 03:"no heat", 06:"heat request", 08:"disinfecting", 09:"hold" -*/ void Water::process_SM100wwStatus2(std::shared_ptr telegram) { // has_update(telegram, wwFlow_, 7); // single byte, wrong see #1387 has_update(telegram, wwStatus2_, 8); @@ -170,6 +173,7 @@ void Water::process_SM100wwStatus2(std::shared_ptr telegram) { // SM100wwCommand - 0x07AB // Thermostat(0x10) -> Solar Module(0x2A), (0x7AB), data: 01 00 01 +// or dhw3 module (0x2A) -> dhw4 module(0x2B), (0x7C3), data: 01 01 00 void Water::process_SM100wwCommand(std::shared_ptr telegram) { // not implemented yet } diff --git a/src/emsesp_version.h b/src/emsesp_version.h index ed8918369..ffe1ccc12 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.8.2-dev.C11" +#define EMSESP_APP_VERSION "3.8.2-dev.C12" diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index bc59415b3..1f47d70b2 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -68,6 +68,14 @@ void EMSuart::uart_event_task(void * pvParameters) { // initialize UART driver void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t tx_gpio) { if (tx_mode_ == EMS_TXMODE_INIT) { +#if CONFIG_IDF_TARGET_ESP32C6 + uart_config_t uart_config = {.baud_rate = EMSUART_BAUD, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 0}; +#else uart_config_t uart_config = {.baud_rate = EMSUART_BAUD, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, @@ -76,6 +84,7 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t .rx_flow_ctrl_thresh = 0, .source_clk = UART_SCLK_APB, .flags = {0}}; +#endif #if defined(EMSUART_RX_INVERT) inverse_mask |= UART_SIGNAL_RXD_INV; #endif diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index f1fb188c2..106e7c052 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -506,6 +506,8 @@ void WebSettings::set_board_profile(WebSettings & settings) { settings.board_profile = "S2MINI"; #elif CONFIG_IDF_TARGET_ESP32S3 settings.board_profile = "S32S3"; // BBQKees Gateway S3 +#elif CONFIG_IDF_TARGET_ESP32C6 + settings.board_profile = "CUSTOM"; #endif // apply the new board profile setting System::load_board_profile(data, settings.board_profile.c_str());