diff --git a/platformio.ini b/platformio.ini index 71ddab7ca..dd88cea1d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,8 +1,8 @@ ; PlatformIO Project Configuration File for EMS-ESP [platformio] -default_envs = esp8266 -; default_envs = esp32 +; default_envs = esp8266 +default_envs = esp32 # override any settings with your own local ones in pio_local.ini extra_configs = @@ -11,27 +11,24 @@ extra_configs = [common] ; default platformio compile flags are: -fno-rtti -std=c++11 -Os -mlongcalls -mtext-section-literals -falign-functions=4 -ffunction-sections -fdata-sections -fno-exceptions -Wall -core_build_flags = -Wno-deprecated-declarations - -mtarget-align - -free - -fipa-pta - -Wreturn-type - -DCORE_DEBUG_LEVEL=0 - -DNDEBUG - -DFP_IN_IROM - -DBEARSSL_SSL_BASIC - -DVTABLES_IN_FLASH - -DPSTR_ALIGN=1 ; remove the 4-bytes alignment for PSTR() - -std=c17 - -std=c++17 - -std=gnu++17 +core_build_flags = -Wno-deprecated-declarations + -Wreturn-type + -DCORE_DEBUG_LEVEL=0 + -DNDEBUG + +esp8266_build_flags = -free + -mtarget-align + -fipa-pta + -Wreturn-type + -DFP_IN_IROM + -DBEARSSL_SSL_BASIC + -DVTABLES_IN_FLASH + -DPSTR_ALIGN=1 ; remove the 4-bytes alignment for PSTR() + -std=c17 -std=c++17 -std=gnu++17 -debug_flags = - ; -D EMSESP_DEBUG - ; -D EMSESP_UART_DEBUG - ; -D EMSESP_TEST - ; -D EMSESP_FORCE_SERIAL - ; -D ENABLE_CORS +esp32_build_flags = -DARDUINO_ARCH_ESP32=1 + -DESP32=1 + -DBOARD_HAS_PSRAM build_flags = ${common.core_build_flags} @@ -50,7 +47,17 @@ build_flags = build_unflags = -Wall -Wdeprecated-declarations - -std=gnu++11 + +esp8266_build_unflags = -std=gnu++11 + +esp32_build_unflags = + +debug_flags = + ; -D EMSESP_DEBUG + ; -D EMSESP_UART_DEBUG + ; -D EMSESP_TEST + ; -D EMSESP_FORCE_SERIAL + ; -D ENABLE_CORS [env] framework = arduino @@ -75,7 +82,8 @@ board = esp12e platform = espressif8266 board_build.filesystem = littlefs board_build.f_cpu = 160000000L -build_flags = ${common.build_flags} +build_flags = ${common.build_flags} ${common.esp8266_build_flags} +build_unflags = ${common.build_unflags} ${common.esp8266_build_unflags} ; build for GitHub Actions CI [env:esp32-ci] @@ -84,7 +92,8 @@ extra_scripts = board = esp32dev platform = espressif32 board_build.partitions = min_spiffs.csv -build_flags = ${common.build_flags} +build_flags = ${common.build_flags} ${common.esp32_build_flags} +build_unflags = ${common.build_unflags} ${common.esp32_build_unflags} [env:esp8266] extra_scripts = @@ -105,8 +114,8 @@ board_build.f_cpu = 160000000L ; 160MHz ; eagle.flash.4m1m.ld = 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer ; eagle.flash.4m2m.ld = 1019 KB sketch, 2024 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 1028 KB OTA & buffer ; board_build.ldscript = eagle.flash.4m2m.ld -build_flags = ${common.build_flags} ${common.debug_flags} -build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${common.esp8266_build_flags} ${common.debug_flags} +build_unflags = ${common.build_unflags} ${common.esp8266_build_unflags} lib_ignore = AsyncTCP @@ -116,6 +125,11 @@ extra_scripts = scripts/rename_fw.py board = esp32dev platform = espressif32 +; platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.0 +; ; toolchain-xtensa32 @ 2.80200.200226 +; ; toolchain-xtensa32 @ 5.100200.201223 +; toolchain-xtensa32 @ 2.80400.2020 ; c70ec8a-toolchain-xtensa32-linux_x86_64-2.80400.2020.tar.gz ; platform = https://github.com/platformio/platform-espressif32.git board_build.partitions = min_spiffs.csv ; https://github.com/espressif/arduino-esp32/blob/master/tools/partitions/ -build_flags = ${common.build_flags} ${common.debug_flags} +build_flags = ${common.build_flags} ${common.esp32_build_flags} ${common.debug_flags} +build_unflags = ${common.build_unflags} ${common.esp32_build_unflags} diff --git a/src/command.cpp b/src/command.cpp index 77477c16a..c33714738 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -24,11 +24,15 @@ namespace emsesp { uuid::log::Logger Command::logger_{F_(command), uuid::log::Facility::DAEMON}; +std::vector Command::cmdfunctions_; + +/* static emsesp::array cmdfunctions_(90, 255, 16); // reserve space for 90 commands emsesp::array * Command::commands() { return &cmdfunctions_; } +*/ // calls a command // id may be used to represent a heating circuit for example @@ -95,13 +99,15 @@ void Command::add(const uint8_t device_type, const __FlashStringHelper * cmd, cm return; } + /* CmdFunction cf; cf.cmd_ = cmd; cf.device_type_ = device_type; cf.cmdfunction_json_ = nullptr; // empty cf.cmdfunction_ = cb; cmdfunctions_.push(cf); - // cmdfunctions_.emplace_back(device_type, cmd, cb, nullptr); + */ + cmdfunctions_.emplace_back(device_type, cmd, cb, nullptr); // see if we need to subscribe if (Mqtt::enabled()) { @@ -116,14 +122,16 @@ void Command::add_with_json(const uint8_t device_type, const __FlashStringHelper return; } + /* CmdFunction cf; cf.cmd_ = cmd; cf.device_type_ = device_type; cf.cmdfunction_json_ = cb; cf.cmdfunction_ = nullptr; // empty cmdfunctions_.push(cf); + */ - // cmdfunctions_.emplace_back(device_type, cmd, nullptr, cb); // add command + cmdfunctions_.emplace_back(device_type, cmd, nullptr, cb); // add command } // see if a command exists for that device type diff --git a/src/command.h b/src/command.h index dda7cd9b2..a91f489fc 100644 --- a/src/command.h +++ b/src/command.h @@ -26,7 +26,7 @@ #include #include -#include "containers.h" +// #include "containers.h" #include "console.h" @@ -46,9 +46,20 @@ class Command { const __FlashStringHelper * cmd_; cmdfunction_p cmdfunction_; cmdfunction_json_p cmdfunction_json_; + + CmdFunction(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cmdfunction, cmdfunction_json_p cmdfunction_json) + : device_type_(device_type) + , cmd_(cmd) + , cmdfunction_(cmdfunction) + , cmdfunction_json_(cmdfunction_json) { + } }; - static emsesp::array * commands(); + static std::vector commands() { + return cmdfunctions_; + } + + // static emsesp::array * commands(); static bool call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id, JsonObject & json); static bool call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id); @@ -63,6 +74,8 @@ class Command { private: static uuid::log::Logger logger_; + + static std::vector cmdfunctions_; // list of commands }; } // namespace emsesp diff --git a/src/console.cpp b/src/console.cpp index 210b1f00f..7658f3ea5 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -422,7 +422,7 @@ void EMSESPShell::add_console_commands() { std::vector command_list; uint8_t device_type = EMSdevice::device_name_2_device_type(arguments[0].c_str()); if (Command::device_has_commands(device_type)) { - for (const auto & cf : *Command::commands()) { + for (const auto & cf : Command::commands()) { if (cf.device_type_ == device_type) { command_list.emplace_back(uuid::read_flash_string(cf.cmd_)); } diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index cf9c66531..187a991cb 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -2067,32 +2067,21 @@ void Thermostat::add_commands() { // register main device values, top level for all thermostats (non heating circuit) void Thermostat::register_device_values() { - /* - uint8_t model = this->model(); // Common for all thermostats - register_device_value(DeviceValueTAG::TAG_NONE, &dateTime_, DeviceValueType::TEXT,nullptr, F("dateTime"), F("Date/Time"), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_NONE, &errorCode_, DeviceValueType::TEXT,nullptr, F("errorCode"), F("Error code"), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_NONE, &lastCode_, DeviceValueType::TEXT,nullptr, F("lastCode"), F("Last error"), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_NONE, &wwTemp_, DeviceValueType::UINT,nullptr, F("wwTemp"), F("Warm water high temperature"), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_NONE, &wwTempLow_, DeviceValueType::UINT,nullptr, F("wwTempLow"), F("Warm water low temperature"), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_NONE, &wwExtra1_, DeviceValueType::UINT,nullptr, F("wwExtra1"), F("Warm water circuit 1 extra"), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_NONE, &wwExtra2_, DeviceValueType::UINT,nullptr, F("wwExtra2"), F("Warm water circuit 2 extra"), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_NONE, - &tempsensor1_, - DeviceValueType::USHORT, - FL_(div10), - F("inttemp1"), - F("Temperature sensor 1"), - DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_NONE, - &tempsensor2_, - DeviceValueType::USHORT, - FL_(div10), - F("inttemp2"), - F("Temperature sensor 2"), - DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_NONE, &dateTime_, DeviceValueType::TEXT, nullptr, F("dateTime"), F("Date/Time"), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_NONE, &errorCode_, DeviceValueType::TEXT, nullptr, F("errorCode"), F("Error code"), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_NONE, &lastCode_, DeviceValueType::TEXT, nullptr, F("lastCode"), F("Last error"), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_NONE, &wwTemp_, DeviceValueType::UINT, nullptr, F("wwTemp"), F("Warm water high temperature"), DeviceValueUOM::DEGREES); + register_device_value( + DeviceValueTAG::TAG_NONE, &wwTempLow_, DeviceValueType::UINT, nullptr, F("wwTempLow"), F("Warm water low temperature"), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_NONE, &wwExtra1_, DeviceValueType::UINT, nullptr, F("wwExtra1"), F("Warm water circuit 1 extra"), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_NONE, &wwExtra2_, DeviceValueType::UINT, nullptr, F("wwExtra2"), F("Warm water circuit 2 extra"), DeviceValueUOM::DEGREES); + register_device_value( + DeviceValueTAG::TAG_NONE, &tempsensor1_, DeviceValueType::USHORT, FL_(div10), F("inttemp1"), F("Temperature sensor 1"), DeviceValueUOM::DEGREES); + register_device_value( + DeviceValueTAG::TAG_NONE, &tempsensor2_, DeviceValueType::USHORT, FL_(div10), F("inttemp2"), F("Temperature sensor 2"), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_NONE, &ibaCalIntTemperature_, DeviceValueType::INT, @@ -2113,25 +2102,12 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_NONE, &ibaMainDisplay_, DeviceValueType::ENUM, - flash_string_vector{F("internal temperature"), - F("internal setpoint"), - F("external temperature"), - F("burner temperature"), - F("WW temperature"), - F("functioning mode"), - F("time"), - F("date"), - F("smoke temperature")}, + FL_(enum_ibaMainDisplay), F("ibaMainDisplay"), F("Display"), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_NONE, - &ibaLanguage_, - DeviceValueType::ENUM, - flash_string_vector{F("German"), F("Dutch"), F("French"), F("Italian")}, - F("ibaLanguage"), - F("Language"), - DeviceValueUOM::NONE); + register_device_value( + DeviceValueTAG::TAG_NONE, &ibaLanguage_, DeviceValueType::ENUM, FL_(enum_ibaLanguage), F("ibaLanguage"), F("Language"), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_NONE, &ibaClockOffset_, DeviceValueType::UINT, @@ -2146,7 +2122,7 @@ void Thermostat::register_device_values() { register_device_value(DeviceValueTAG::TAG_NONE, &floordrystatus_, DeviceValueType::ENUM, - flash_string_vector{F("off"), F("start"), F("heat"), F("hold"), F("cool"), F("end")}, + FL_(enum_floordrystatus), F("floordry"), F("Floor drying"), DeviceValueUOM::NONE); @@ -2157,26 +2133,20 @@ void Thermostat::register_device_values() { F("dampedtemp"), F("Damped outdoor temperature"), DeviceValueUOM::DEGREES); + register_device_value(DeviceValueTAG::TAG_NONE, + &floordrytemp_, + DeviceValueType::UINT, + nullptr, + F("floordrytemp"), + F("Floor drying temperature"), + DeviceValueUOM::DEGREES); register_device_value( - DeviceValueTAG::TAG_NONE, &floordrytemp_, DeviceValueType::UINT,nullptr, F("floordrytemp"), F("Floor drying temperature"), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_NONE, - &ibaBuildingType_, - DeviceValueType::ENUM, - flash_string_vector{F(""), F("light"), F("medium"), F("heavy")}, - F("building"), - F("Building"), - DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_NONE, - &wwMode_, - DeviceValueType::ENUM, - flash_string_vector{F("off"), F("low"), F("high"), F("auto"), F("own_prog")}, - F("wwmode"), - F("Warm water mode"), - DeviceValueUOM::NONE); + DeviceValueTAG::TAG_NONE, &ibaBuildingType_, DeviceValueType::ENUM, FL_(enum_ibaBuildingType), F("building"), F("Building"), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_NONE, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode), F("wwmode"), F("Warm water mode"), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_NONE, &wwCircMode_, DeviceValueType::ENUM, - flash_string_vector{F("off"), F("on"), F("auto"), F("own_prog")}, + FL_(enum_wwCircMode), F("wwcircmode"), F("Warm water circulation mode"), DeviceValueUOM::NONE); @@ -2191,41 +2161,30 @@ void Thermostat::register_device_values() { F("dampedtemp"), F("Damped outdoor temperature"), DeviceValueUOM::DEGREES); - register_device_value(DeviceValueTAG::TAG_NONE, - &ibaBuildingType_, - DeviceValueType::ENUM, - flash_string_vector{F("light"), F("medium"), F("heavy")}, - F("building"), - F("Building"), - DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_NONE, - &wwMode_, - DeviceValueType::ENUM, - flash_string_vector{F("off"), F("on"), F("auto")}, - F("wwmode"), - F("Warm water mode"), - DeviceValueUOM::NONE); + register_device_value( + DeviceValueTAG::TAG_NONE, &ibaBuildingType_, DeviceValueType::ENUM, FL_(enum_ibaBuildingType2), F("building"), F("Building"), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_NONE, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode2), F("wwmode"), F("Warm water mode"), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_NONE, &wwCircMode_, DeviceValueType::ENUM, - flash_string_vector{F("off"), F("on"), F("auto")}, + FL_(enum_wwCircMode2), F("wwcircmode"), F("Warm water circulation mode"), DeviceValueUOM::NONE); } - */ } // registers the values for a heating circuit void Thermostat::register_device_values_hc(std::shared_ptr hc) { - /* uint8_t model = hc->get_model(); // heating circuit uint8_t tag = DeviceValueTAG::TAG_HC1 + hc->hc_num() - 1; // different logic on how temperature values are stored, depending on model - flash_string_vector setpoint_temp_divider, curr_temp_divider; + const __FlashStringHelper * const * setpoint_temp_divider; + const __FlashStringHelper * const * curr_temp_divider; + if (model == EMS_DEVICE_FLAG_EASY) { setpoint_temp_divider = FL_(div100); curr_temp_divider = FL_(div100); @@ -2255,132 +2214,79 @@ void Thermostat::register_device_values_hc(std::shared_ptrmode, - DeviceValueType::ENUM, - flash_string_vector{F("off"), F("heat"), F("auto"), F("heat"), F("off"), F("heat"), F("auto"), F("auto"), F("auto"), F("auto")}, - F("hamode"), - nullptr, - DeviceValueUOM::NONE); + register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_hamode), F("hamode"), nullptr, DeviceValueUOM::NONE); } if (model == EMSdevice::EMS_DEVICE_FLAG_RC300 || model == EMSdevice::EMS_DEVICE_FLAG_RC100) { - register_device_value(tag, &hc->mode, DeviceValueType::ENUM, {F("manual"), F("auto")}, F("mode"), F("Mode"), DeviceValueUOM::NONE); - register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, {F("eco"), F("comfort")}, F("modetype"), F("Mode type"), DeviceValueUOM::NONE); - - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, {F("2")}, F("ecotemp"), F("Eco temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->manualtemp, DeviceValueType::UINT, {F("2")}, F("manualtemp"), F("Manual temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, {F("2")}, F("comforttemp"), F("Comfort temperature"), DeviceValueUOM::DEGREES); - - register_device_value(tag, &hc->summertemp, DeviceValueType::UINT,nullptr, F("summertemp"), F("Summer temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->designtemp, DeviceValueType::UINT,nullptr, F("designtemp"), F("Design temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->offsettemp, DeviceValueType::INT,nullptr, F("offsettemp"), F("Offset temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT,nullptr, F("minflowtemp"), F("Min flow temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT,nullptr, F("maxflowtemp"), F("Max flow temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT,nullptr, F("roominfluence"), F("Room influence"), DeviceValueUOM::NONE); - register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT,nullptr, F("nofrosttemp"), F("Nofrost temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT,nullptr, F("targetflowtemp"), F("Target flow temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, - &hc->heatingtype, - DeviceValueType::ENUM, - {F("off"), F("radiator"), F("convector"), F("floor")}, - F("heatingtype"), - F("Heating type"), - DeviceValueUOM::NONE); - register_device_value(tag, - &hc->summer_setmode, - DeviceValueType::ENUM, - flash_string_vector{F("summer"), F("auto"), F("winter")}, - F("summermode"), - F("Summer mode"), - DeviceValueUOM::NONE); - register_device_value(tag, - &hc->controlmode, - DeviceValueType::ENUM, - flash_string_vector{F("off"), F("outdoor"), F("simple"), F("MPC"), F("room"), F("power"), F("const.")}, - F("controlmode"), - F("Control mode"), - DeviceValueUOM::NONE); - register_device_value(tag, &hc->program, DeviceValueType::UINT,nullptr, F("program"), F("Program"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode), F("mode"), F("Mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype), F("modetype"), F("Mode type"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), F("ecotemp"), F("Eco temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->manualtemp, DeviceValueType::UINT, FL_(div2), F("manualtemp"), F("Manual temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), F("comforttemp"), F("Comfort temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, nullptr, F("summertemp"), F("Summer temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->designtemp, DeviceValueType::UINT, nullptr, F("designtemp"), F("Design temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->offsettemp, DeviceValueType::INT, nullptr, F("offsettemp"), F("Offset temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, F("minflowtemp"), F("Min flow temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, F("maxflowtemp"), F("Max flow temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, F("roominfluence"), F("Room influence"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, nullptr, F("nofrosttemp"), F("Nofrost temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, nullptr, F("targetflowtemp"), F("Target flow temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), F("heatingtype"), F("Heating type"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->summer_setmode, DeviceValueType::ENUM, FL_(enum_summermode), F("summermode"), F("Summer mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode), F("controlmode"), F("Control mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->program, DeviceValueType::UINT, nullptr, F("program"), F("Program"), DeviceValueUOM::NONE); } if (model == EMS_DEVICE_FLAG_RC20) { - register_device_value(tag, &hc->mode, DeviceValueType::ENUM, flash_string_vector{F("off"), F("manual"), F("auto")}, F("mode"), F("Mode"), DeviceValueUOM::NONE); - register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, flash_string_vector{F("day")}, F("modetype"), F("Mode type"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode2), F("mode"), F("Mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype2), F("modetype"), F("Mode type"), DeviceValueUOM::NONE); } if (model == EMS_DEVICE_FLAG_RC20_2) { - register_device_value(tag, &hc->mode, DeviceValueType::ENUM, flash_string_vector{F("off"), F("manual"), F("auto")}, F("mode"), F("Mode"), DeviceValueUOM::NONE); - register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, flash_string_vector{F("day")}, F("modetype"), F("Mode type"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode2), F("mode"), F("Mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype2), F("modetype"), F("Mode type"), DeviceValueUOM::NONE); register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), F("daytemp"), F("Day temperature"), DeviceValueUOM::DEGREES); register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), F("nighttemp"), F("Night temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->program, DeviceValueType::UINT,nullptr, F("program"), F("Program"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->program, DeviceValueType::UINT, nullptr, F("program"), F("Program"), DeviceValueUOM::NONE); } if (model == EMS_DEVICE_FLAG_RC35 || model == EMS_DEVICE_FLAG_RC30_1) { - register_device_value(tag, &hc->mode, DeviceValueType::ENUM, {F("night"), F("day"), F("auto")}, F("mode"), F("Mode"), DeviceValueUOM::NONE); - register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, {F("night"), F("day")}, F("modetype"), F("Mode type"), DeviceValueUOM::NONE); - register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, {F("2")}, F("daytemp"), F("Day temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, {F("2")}, F("nighttemp"), F("Night temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->designtemp, DeviceValueType::UINT,nullptr, F("designtemp"), F("Design temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->offsettemp, DeviceValueType::INT, {F("2")}, F("offsettemp"), F("Offset temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->holidaytemp, DeviceValueType::UINT, {F("2")}, F("holidaytemp"), F("Holiday temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT,nullptr, F("targetflowtemp"), F("Target flow temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->summertemp, DeviceValueType::UINT,nullptr, F("summertemp"), F("Summer temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->summermode, DeviceValueType::BOOL,nullptr, F("summermode"), F("Summer mode"), DeviceValueUOM::NONE); - register_device_value(tag, &hc->holidaymode, DeviceValueType::BOOL,nullptr, F("holidaymode"), F("Holiday mode"), DeviceValueUOM::NONE); - register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT,nullptr, F("nofrosttemp"), F("Nofrost temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT,nullptr, F("roominfluence"), F("Room influence"), DeviceValueUOM::NONE); - register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT,nullptr, F("minflowtemp"), F("Min flow temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT,nullptr, F("maxflowtemp"), F("Max flow temperature"), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->flowtempoffset, DeviceValueType::UINT,nullptr, F("flowtempoffset"), F("Flow temperature offset"), DeviceValueUOM::DEGREES); - register_device_value(tag, - &hc->heatingtype, - DeviceValueType::ENUM, - {F("off"), F("radiator"), F("convector"), F("floor")}, - F("heatingtype"), - F("Heating type"), - DeviceValueUOM::NONE); - register_device_value(tag, - &hc->reducemode, - DeviceValueType::ENUM, - flash_string_vector{F("nofrost"), F("reduce"), F("room"), F("outdoor")}, - F("reducemode"), - F("Reduce mode"), - DeviceValueUOM::NONE); - register_device_value(tag, - &hc->controlmode, - DeviceValueType::ENUM, - flash_string_vector{F("outdoor"), F("room")}, - F("controlmode"), - F("Control mode"), - DeviceValueUOM::NONE); - register_device_value(tag, &hc->program, DeviceValueType::UINT,nullptr, F("program"), F("Program"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode3), F("mode"), F("Mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype3), F("modetype"), F("Mode type"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), F("daytemp"), F("Day temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), F("nighttemp"), F("Night temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->designtemp, DeviceValueType::UINT, nullptr, F("designtemp"), F("Design temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->offsettemp, DeviceValueType::INT, FL_(div2), F("offsettemp"), F("Offset temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->holidaytemp, DeviceValueType::UINT, FL_(div2), F("holidaytemp"), F("Holiday temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, nullptr, F("targetflowtemp"), F("Target flow temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, nullptr, F("summertemp"), F("Summer temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->summermode, DeviceValueType::BOOL, nullptr, F("summermode"), F("Summer mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->holidaymode, DeviceValueType::BOOL, nullptr, F("holidaymode"), F("Holiday mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, nullptr, F("nofrosttemp"), F("Nofrost temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, nullptr, F("roominfluence"), F("Room influence"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, nullptr, F("minflowtemp"), F("Min flow temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, nullptr, F("maxflowtemp"), F("Max flow temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->flowtempoffset, DeviceValueType::UINT, nullptr, F("flowtempoffset"), F("Flow temperature offset"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->heatingtype, DeviceValueType::ENUM, FL_(enum_heatingtype), F("heatingtype"), F("Heating type"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->reducemode, DeviceValueType::ENUM, FL_(enum_reducemode), F("reducemode"), F("Reduce mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->controlmode, DeviceValueType::ENUM, FL_(enum_controlmode2), F("controlmode"), F("Control mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->program, DeviceValueType::UINT, nullptr, F("program"), F("Program"), DeviceValueUOM::NONE); } if (model == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) { - register_device_value( - tag, &hc->mode, DeviceValueType::ENUM, flash_string_vector{F("manual"), F("auto"), F("holiday")}, F("mode"), F("Mode"), DeviceValueUOM::NONE); - register_device_value(tag, - &hc->modetype, - DeviceValueType::ENUM, - flash_string_vector{F("heat"), F("eco"), F("nofrost")}, - F("modetype"), - F("Mode type"), - DeviceValueUOM::NONE); + register_device_value(tag, &hc->mode, DeviceValueType::ENUM, FL_(enum_mode4), F("mode"), F("Mode"), DeviceValueUOM::NONE); + register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype4), F("modetype"), F("Mode type"), DeviceValueUOM::NONE); register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, FL_(div2), F("heattemp"), F("Heat temperature"), DeviceValueUOM::DEGREES); register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, FL_(div2), F("ecotemp"), F("Eco temperature"), DeviceValueUOM::DEGREES); - register_device_value( - tag, &hc->nofrosttemp, DeviceValueType::INT, FL_(div2), F("nofrosttemp"), F("Nofrost temperature"), DeviceValueUOM::DEGREES); + register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, FL_(div2), F("nofrosttemp"), F("Nofrost temperature"), DeviceValueUOM::DEGREES); } - */ } } // namespace emsesp diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 73194510e..2a210b03a 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -69,6 +69,10 @@ const std::string EMSdevice::tag_to_string(uint8_t tag) { return uuid::read_flash_string(DeviceValueTAG_s[tag - 1]); // offset by 1 to account for NONE } +const std::vector EMSdevice::devicevalues() const { + return devicevalues_; +} + std::string EMSdevice::brand_to_string() const { switch (brand_) { case EMSdevice::Brand::BOSCH: @@ -260,7 +264,8 @@ std::string EMSdevice::to_string_short() const { void EMSdevice::fetch_values() { EMSESP::logger().debug(F("Fetching values for device ID 0x%02X"), device_id()); - for (const auto & tf : *telegram_functions_) { + // for (const auto & tf : *telegram_functions_) { + for (const auto & tf : telegram_functions_) { if (tf.fetch_) { read_command(tf.telegram_type_id_); } @@ -271,7 +276,8 @@ void EMSdevice::fetch_values() { void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) { EMSESP::logger().debug(F("Toggling fetch for device ID 0x%02X, telegram ID 0x%02X to %d"), device_id(), telegram_id, toggle); - for (auto & tf : *telegram_functions_) { + for (auto & tf : telegram_functions_) { + // for (auto & tf : *telegram_functions_) { if (tf.telegram_type_id_ == telegram_id) { tf.fetch_ = toggle; } @@ -280,7 +286,8 @@ void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) { // get status of automatic fetch for a telegram id bool EMSdevice::get_toggle_fetch(uint16_t telegram_id) { - for (auto & tf : *telegram_functions_) { + for (auto & tf : telegram_functions_) { + // for (auto & tf : *telegram_functions_) { if (tf.telegram_type_id_ == telegram_id) { return tf.fetch_; } @@ -292,7 +299,8 @@ bool EMSdevice::get_toggle_fetch(uint16_t telegram_id) { void EMSdevice::show_device_values(uuid::console::Shell & shell) { size_t total_s = 0; uint8_t count = 0; - for (const auto & dv : *devicevalues_) { + // for (const auto & dv : *devicevalues_) { + for (const auto & dv : devicevalues_) { size_t s = sizeof(dv); if (dv.full_name) { shell.printfln("[%s] %d", uuid::read_flash_string(dv.full_name).c_str(), s); @@ -309,12 +317,14 @@ void EMSdevice::show_device_values(uuid::console::Shell & shell) { // list all the telegram type IDs for this device void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) { - if (telegram_functions_->size() == 0) { + // if (telegram_functions_->size() == 0) { + if (telegram_functions_.size() == 0) { return; } shell.printf(F(" This %s will respond to telegram type IDs: "), device_type_name().c_str()); - for (const auto & tf : *telegram_functions_) { + for (const auto & tf : telegram_functions_) { + // for (const auto & tf : *telegram_functions_) { shell.printf(F("0x%02X "), tf.telegram_type_id_); } shell.println(); @@ -322,7 +332,8 @@ void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) { // list all the telegram type IDs for this device, outputting to a string (max size 200) char * EMSdevice::show_telegram_handlers(char * result) { - uint8_t size = telegram_functions_->size(); + // uint8_t size = telegram_functions_->size(); + uint8_t size = telegram_functions_.size(); strlcpy(result, "", 200); @@ -332,7 +343,8 @@ char * EMSdevice::show_telegram_handlers(char * result) { char str[10]; uint8_t i = 0; - for (const auto & tf : *telegram_functions_) { + // for (const auto & tf : *telegram_functions_) { + for (const auto & tf : telegram_functions_) { snprintf_P(str, sizeof(str), PSTR("0x%02X"), tf.telegram_type_id_); strlcat(result, str, 200); if (++i < size) { @@ -359,21 +371,16 @@ void EMSdevice::register_mqtt_cmd(const __FlashStringHelper * cmd, cmdfunction_p // register a call back function for a specific telegram type void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p f) { + /* TelegramFunction tf; tf.fetch_ = fetch; tf.process_function_ = f; tf.telegram_type_id_ = telegram_type_id; tf.telegram_type_name_ = telegram_type_name; telegram_functions_->push(tf); +*/ - // TelegramFunction(uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p process_function) - // : telegram_type_id_(telegram_type_id) - // , telegram_type_name_(telegram_type_name) - // , fetch_(fetch) - // , process_function_(process_function) { - // } - - // telegram_functions_.emplace_back(telegram_type_id, telegram_type_name, fetch, f); + telegram_functions_.emplace_back(telegram_type_id, telegram_type_name, fetch, f); } // add to device value library @@ -410,6 +417,8 @@ void EMSdevice::register_device_value(uint8_t tag, } // add to our library + + /* DeviceValue dv; dv.device_type = device_type_; dv.tag = tag; @@ -430,6 +439,18 @@ void EMSdevice::register_device_value(uint8_t tag, } devicevalues_->push(dv); + */ + + // count #options + uint8_t options_size = 0; + if (options != nullptr) { + uint8_t i = 0; + while (options[i++]) { + options_size++; + }; + } + + devicevalues_.emplace_back(device_type_, tag, value_p, type, options, options_size, short_name, full_name, uom); } // looks up the uom (suffix) for a given key from the device value table @@ -445,9 +466,12 @@ std::string EMSdevice::get_value_uom(const char * key) { } // find the key (p) in the name - // because the new container is not multi-threaded can't use the iterator - for (uint8_t i = 0; i < devicevalues_->size(); i++) { + // + for (const auto & dv : devicevalues_) { + /* + for (uint8_t i = 0; i < devicevalues_->size(); i++) { // because the new container is not multi-threaded can't use the iterator auto dv = (*devicevalues_)[i]; + */ if (dv.full_name != nullptr) { if (uuid::read_flash_string(dv.full_name) == p) { // ignore TIME since "minutes" is already included @@ -469,8 +493,12 @@ bool EMSdevice::generate_values_json_web(JsonObject & json) { JsonArray data = json.createNestedArray("data"); uint8_t num_elements = 0; + + for (const auto & dv : devicevalues_) { + /* for (uint8_t i = 0; i < devicevalues_->size(); i++) { auto dv = (*devicevalues_)[i]; + */ // for (const auto & dv : devicevalues()) { // ignore if full_name empty @@ -479,6 +507,8 @@ bool EMSdevice::generate_values_json_web(JsonObject & json) { if ((dv.type == DeviceValueType::BOOL) && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) { // see if we have options for the bool's if (dv.options_size == 2) { + // if (dv.options_size == 2) { + data.add(*(uint8_t *)(dv.value_p) ? dv.options[0] : dv.options[1]); } else { // see how to render the value depending on the setting @@ -502,6 +532,7 @@ bool EMSdevice::generate_values_json_web(JsonObject & json) { // handle ENUMs else if ((dv.type == DeviceValueType::ENUM) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { + // if (*(uint8_t *)(dv.value_p) < dv.options_size) { if (*(uint8_t *)(dv.value_p) < dv.options_size) { data.add(dv.options[*(uint8_t *)(dv.value_p)]); } @@ -512,7 +543,8 @@ bool EMSdevice::generate_values_json_web(JsonObject & json) { // If a divider is specified, do the division to 2 decimals places and send back as double/float // otherwise force as an integer whole // the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler - uint8_t divider = ((dv.options_size) == 1) ? Helpers::atoint(uuid::read_flash_string(dv.options[0]).c_str()) : 0; + // uint8_t divider = ((dv.options_size) == 1) ? Helpers::atoint(uuid::read_flash_string(dv.options[0]).c_str()) : 0; + uint8_t divider = (dv.options_size == 1) ? Helpers::atoint(uuid::read_flash_string(dv.options[0]).c_str()) : 0; // INT if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) { @@ -589,8 +621,12 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter uint8_t old_tag = 255; JsonObject json = root; - for (uint8_t i = 0; i < devicevalues_->size(); i++) { + for (const auto & dv : devicevalues_) { + /* + for (uint8_t i = 0; i < devicevalues_->size(); i++) { auto dv = (*devicevalues_)[i]; + */ + // for (const auto & dv : devicevalues()) { // only show if tag is either empty or matches a value, and don't show if full_name is empty unless we're outputing for mqtt payloads if (((tag_filter == DeviceValueTAG::TAG_NONE) || (tag_filter == dv.tag)) && (dv.full_name != nullptr || !verbose)) { @@ -616,6 +652,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter // handle Booleans (true, false) if ((dv.type == DeviceValueType::BOOL) && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) { // see if we have options for the bool's + // if (dv.options_size == 2) { if (dv.options_size == 2) { json[name] = *(uint8_t *)(dv.value_p) ? dv.options[0] : dv.options[1]; has_value = true; @@ -645,6 +682,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter // handle ENUMs else if ((dv.type == DeviceValueType::ENUM) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { + // if (*(uint8_t *)(dv.value_p) < dv.options_size) { if (*(uint8_t *)(dv.value_p) < dv.options_size) { json[name] = dv.options[*(uint8_t *)(dv.value_p)]; has_value = true; @@ -715,7 +753,8 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter // create the Home Assistant configs for each value as a sensor void EMSdevice::publish_mqtt_ha_sensor() { - for (const auto & dv : *devicevalues_) { + // for (const auto & dv : *devicevalues_) { + for (const auto & dv : devicevalues_) { Mqtt::register_mqtt_ha_sensor(dv.type, dv.tag, dv.full_name, device_type_, dv.short_name, dv.uom); } @@ -733,7 +772,7 @@ std::string EMSdevice::telegram_type_name(std::shared_ptr telegr return read_flash_string(F("UBADevices")); } - for (const auto & tf : *telegram_functions_) { + for (const auto & tf : telegram_functions_) { if ((tf.telegram_type_id_ == telegram->type_id) && (telegram->type_id != 0xFF)) { return uuid::read_flash_string(tf.telegram_type_name_); } @@ -745,7 +784,7 @@ std::string EMSdevice::telegram_type_name(std::shared_ptr telegr // take a telegram_type_id and call the matching handler // return true if match found bool EMSdevice::handle_telegram(std::shared_ptr telegram) { - for (const auto & tf : *telegram_functions_) { + for (const auto & tf : telegram_functions_) { if (tf.telegram_type_id_ == telegram->type_id) { // if the data block is empty, assume that this telegram is not recognized by the bus master // so remove it from the automatic fetch list diff --git a/src/emsdevice.h b/src/emsdevice.h index 793d744de..04fd2268f 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -23,7 +23,7 @@ #include #include -#include "containers.h" +// #include "containers.h" #include "emsfactory.h" #include "telegram.h" #include "mqtt.h" @@ -320,13 +320,15 @@ class EMSdevice { static constexpr uint8_t EMS_DEVICE_FLAG_JUNKERS = 10; void reserve_device_values(uint8_t elements) { - static auto dv_ = emsesp::array(elements, 255, 16); - devicevalues_ = &dv_; + devicevalues_.reserve(elements); + // static auto dv_ = emsesp::array(elements, 255, 16); + // devicevalues_ = &dv_; } void reserve_telgram_functions(uint8_t elements) { - static auto tf_ = emsesp::array(elements, 255, 16); - telegram_functions_ = &tf_; + telegram_functions_.reserve(elements); + // static auto tf_ = emsesp::array(elements, 255, 16); + // telegram_functions_ = &tf_; } private: @@ -347,8 +349,15 @@ class EMSdevice { const __FlashStringHelper * telegram_type_name_; // e.g. RC20Message bool fetch_; // if this type_id be queried automatically process_function_p process_function_; + + TelegramFunction(uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p process_function) + : telegram_type_id_(telegram_type_id) + , telegram_type_name_(telegram_type_name) + , fetch_(fetch) + , process_function_(process_function) { + } }; - emsesp::array * telegram_functions_; // each EMS device has its own set of registered telegram types + // emsesp::array * telegram_functions_; // each EMS device has its own set of registered telegram types struct DeviceValue { uint8_t device_type; // EMSdevice::DeviceType @@ -360,8 +369,37 @@ class EMSdevice { const __FlashStringHelper * short_name; // used in MQTT const __FlashStringHelper * full_name; // used in Web and Console uint8_t uom; // DeviceValueUOM::* + + DeviceValue(uint8_t device_type, + uint8_t tag, + void * value_p, + uint8_t type, + const __FlashStringHelper * const * options, + uint8_t options_size, + const __FlashStringHelper * short_name, + const __FlashStringHelper * full_name, + uint8_t uom) + : device_type(device_type) + , tag(tag) + , value_p(value_p) + , type(type) + , options(options) + , options_size(options_size) + , short_name(short_name) + , full_name(full_name) + , uom(uom) { + } }; - emsesp::array * devicevalues_; + const std::vector devicevalues() const; + + void init_devicevalues(uint8_t size) { + devicevalues_.reserve(size); + } + + std::vector telegram_functions_; // each EMS device has its own set of registered telegram types + + // emsesp::array * devicevalues_; + std::vector devicevalues_; }; } // namespace emsesp diff --git a/src/emsesp.h b/src/emsesp.h index ae777b1cc..21078f5df 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -40,7 +40,7 @@ #include "WebSettingsService.h" #include "WebAPIService.h" -#include "containers.h" +// #include "containers.h" #include "emsdevice.h" #include "emsfactory.h" #include "telegram.h" diff --git a/src/locale_EN.h b/src/locale_EN.h index 803bde3cf..7584c960a 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -138,6 +138,8 @@ MAKE_PSTR_LIST(div10, F_(10)) MAKE_PSTR_LIST(div100, F_(100)) MAKE_PSTR_LIST(div60, F_(60)) + +// boiler MAKE_PSTR_WORD(time) MAKE_PSTR_WORD(date) MAKE_PSTR_WORD(1x3min) @@ -157,8 +159,91 @@ MAKE_PSTR_WORD(buffer) MAKE_PSTR(bufferedflow, "buffered flow") MAKE_PSTR(layeredbuffer, "layered buffer") +// boiler lists MAKE_PSTR_LIST(enum_off_time_date, F_(off), F_(time), F_(date)) MAKE_PSTR_LIST(enum_freq, F_(off), F_(1x3min), F_(2x3min), F_(3x3min), F_(4x3min), F_(5x3min), F_(6x3min), F_(continuos)) MAKE_PSTR_LIST(enum_charge, F_(3wayvalve), F_(chargepump)) MAKE_PSTR_LIST(enum_comfort, F_(hot), F_(eco), F_(intelligent)) MAKE_PSTR_LIST(enum_flow, F_(off), F_(flow), F_(bufferedflow), F_(buffer), F_(layeredbuffer)) + +// thermostat +MAKE_PSTR_WORD(light) +MAKE_PSTR_WORD(medium) +MAKE_PSTR_WORD(heavy) +MAKE_PSTR_WORD(own_prog) +MAKE_PSTR(blank, "") +MAKE_PSTR_WORD(start) +MAKE_PSTR_WORD(heat) +MAKE_PSTR_WORD(hold) +MAKE_PSTR_WORD(cool) +MAKE_PSTR_WORD(end) +MAKE_PSTR_WORD(German) +MAKE_PSTR_WORD(Dutch) +MAKE_PSTR_WORD(French) +MAKE_PSTR_WORD(Italian) +MAKE_PSTR_WORD(high) +MAKE_PSTR_WORD(low) +MAKE_PSTR(internal_temperature, "internal temperature") +MAKE_PSTR(internal_setpoint, "internal setpoint") +MAKE_PSTR(external_temperature, "external temperature") +MAKE_PSTR(burner_temperature, "burner temperature") +MAKE_PSTR(WW_temperature, "WW temperature") +MAKE_PSTR(functioning_mode, "functioning mode") +MAKE_PSTR(smoke_temperature, "smoke temperature") +MAKE_PSTR_WORD(radiator) +MAKE_PSTR_WORD(convector) +MAKE_PSTR_WORD(floor) +MAKE_PSTR_WORD(summer) +MAKE_PSTR_WORD(winter) +MAKE_PSTR_WORD(outdoor) +MAKE_PSTR_WORD(MPC) +MAKE_PSTR_WORD(room) +MAKE_PSTR_WORD(power) +MAKE_PSTR_WORD(constant) +MAKE_PSTR_WORD(simple) +MAKE_PSTR_WORD(nofrost) +MAKE_PSTR_WORD(comfort) +MAKE_PSTR_WORD(manual) +MAKE_PSTR_WORD(night) +MAKE_PSTR_WORD(day) +MAKE_PSTR_WORD(holiday) +MAKE_PSTR_WORD(reduce) + +// thermostat lists +MAKE_PSTR_LIST(enum_ibaMainDisplay, + F_(internal_temperature), + F_(internal_setpoint), + F_(external_temperature), + F_(burner_temperature), + F_(WW_temperature), + F_(functioning_mode), + F_(time), + F_(date), + F_(smoke_temperature)) +MAKE_PSTR_LIST(enum_ibaLanguage, F_(German), F_(Dutch), F_(French), F_(Italian)) +MAKE_PSTR_LIST(enum_floordrystatus, F_(off), F_(start), F_(heat), F_(hold), F_(cool), F_(end)) +MAKE_PSTR_LIST(enum_ibaBuildingType, F_(blank), F_(light), F_(medium), F_(heavy)) +MAKE_PSTR_LIST(enum_wwMode, F_(off), F_(low), F_(high), F_(auto), F_(own_prog)) +MAKE_PSTR_LIST(enum_wwCircMode, F_(off), F_(on), F_(auto), F_(own_prog)) +MAKE_PSTR_LIST(enum_ibaBuildingType2, F_(light), F_(medium), F_(heavy)) +MAKE_PSTR_LIST(enum_wwMode2, F_(off), F_(on), F_(auto)) +MAKE_PSTR_LIST(enum_wwCircMode2, F_(off), F_(on), F_(auto)) +MAKE_PSTR_LIST(enum_heatingtype, F_(off), F_(radiator), F_(convector), F_(floor)) +MAKE_PSTR_LIST(enum_summermode, F_(summer), F_(auto), F_(winter)) + +MAKE_PSTR_LIST(enum_mode, F_(manual), F_(auto)) +MAKE_PSTR_LIST(enum_mode2, F_(off), F_(manual), F_(auto)) +MAKE_PSTR_LIST(enum_mode3, F_(night), F_(day), F_(auto)) +MAKE_PSTR_LIST(enum_mode4, F_(manual), F_(auto), F_(holiday)) + +MAKE_PSTR_LIST(enum_modetype, F_(eco), F_(comfort)) +MAKE_PSTR_LIST(enum_modetype2, F_(day)) +MAKE_PSTR_LIST(enum_modetype3, F_(night), F_(day)) +MAKE_PSTR_LIST(enum_modetype4, F_(heat), F_(eco), F_(nofrost)) + +MAKE_PSTR_LIST(enum_reducemode, F_(nofrost), F_(reduce), F_(room), F_(outdoor)) + +MAKE_PSTR_LIST(enum_controlmode, F_(off), F_(outdoor), F_(simple), F_(MPC), F_(room), F_(power), F_(constant)) +MAKE_PSTR_LIST(enum_controlmode2, F_(outdoor), F_(room)) + +MAKE_PSTR_LIST(enum_hamode, F_(off), F_(heat), F_(auto), F_(heat), F_(off), F_(heat), F_(auto), F_(auto), F_(auto), F_(auto)) diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 8626f1034..e4337c054 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -24,7 +24,6 @@ namespace emsesp { AsyncMqttClient * Mqtt::mqttClient_; - // static parameters we make global std::string Mqtt::hostname_; uint8_t Mqtt::mqtt_qos_; @@ -40,7 +39,8 @@ uint8_t Mqtt::dallas_format_; uint8_t Mqtt::ha_climate_format_; bool Mqtt::ha_enabled_; -static emsesp::queue mqtt_messages_ = emsesp::queue(MAX_MQTT_MESSAGES); +// static emsesp::queue mqtt_messages_ = emsesp::queue(MAX_MQTT_MESSAGES); +std::list Mqtt::mqtt_messages_; std::vector Mqtt::mqtt_subfunctions_; @@ -547,12 +547,20 @@ std::shared_ptr Mqtt::queue_message(const uint8_t operation, message = std::make_shared(operation, full_topic, payload, retain); } + // if the queue is full, make room but removing the last one + if (mqtt_messages_.size() >= MAX_MQTT_MESSAGES) { + mqtt_messages_.pop_front(); + } + mqtt_messages_.emplace_back(mqtt_message_id_++, std::move(message)); + + /* QueuedMqttMessage qmm; qmm.content_ = std::move(message); qmm.retry_count_ = 0; qmm.packet_id_ = 0; qmm.id_ = mqtt_message_id_++; mqtt_messages_.push_back(qmm); + */ return mqtt_messages_.back().content_; // this is because the message has been moved } @@ -710,7 +718,8 @@ void Mqtt::process_queue() { return; } else { // update the record - mqtt_messages_.front_p()->retry_count_++; + // mqtt_messages_.front_p()->retry_count_++; + mqtt_messages_.front().retry_count_++; LOG_DEBUG(F("Failed to publish to %s. Trying again, #%d"), message->topic.c_str(), mqtt_message.retry_count_ + 1); return; // leave on queue for next time so it gets republished } @@ -719,7 +728,8 @@ void Mqtt::process_queue() { // if we have ACK set with QOS 1 or 2, leave on queue and let the ACK process remove it // but add the packet_id so we can check it later if (mqtt_qos_ != 0) { - mqtt_messages_.front_p()->packet_id_ = packet_id; + // mqtt_messages_.front_p()->packet_id_ = packet_id; + mqtt_messages_.front().packet_id_ = packet_id; #if defined(EMSESP_DEBUG) LOG_DEBUG(F("[DEBUG] Setting packetID for ACK to %d"), packet_id); #endif diff --git a/src/mqtt.h b/src/mqtt.h index 643c2844d..810744be3 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -183,12 +183,30 @@ class Mqtt { mqtt_retain_ = mqtt_retain; } + /* struct QueuedMqttMessage { uint16_t id_; std::shared_ptr content_; uint8_t retry_count_; uint16_t packet_id_; }; + */ + + struct QueuedMqttMessage { + const uint16_t id_; + const std::shared_ptr content_; + uint8_t retry_count_; + uint16_t packet_id_; + + ~QueuedMqttMessage() = default; + QueuedMqttMessage(uint16_t id, std::shared_ptr && content) + : id_(id) + , content_(std::move(content)) { + retry_count_ = 0; + packet_id_ = 0; + } + }; + static std::list mqtt_messages_; private: static uuid::log::Logger logger_; @@ -252,7 +270,7 @@ class Mqtt { static uint8_t dallas_format_; static uint8_t ha_climate_format_; static bool ha_enabled_; -}; // namespace emsesp +}; } // namespace emsesp diff --git a/src/system.cpp b/src/system.cpp index 900034021..6195ea17f 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -273,7 +273,7 @@ void System::loop() { send_heartbeat(); } -#if defined(ESP8266) +#ifndef EMSESP_STANDALONE #if defined(EMSESP_DEBUG) static uint32_t last_memcheck_ = 0; if (currentMillis - last_memcheck_ > 5000) { // 5 seconds diff --git a/src/telegram.cpp b/src/telegram.cpp index 513a4af5e..bf6b4ef2b 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -126,11 +126,19 @@ std::string Telegram::to_string_message() const { // checks if we have an Rx telegram that needs processing void RxService::loop() { + /* while (!rx_telegrams_.empty()) { auto telegram = rx_telegrams_.pop().telegram_; (void)EMSESP::process_telegram(telegram); // further process the telegram increment_telegram_count(); // increase rx count - // rx_telegrams_.pop_front(); // remove it from the queue + } + */ + + while (!rx_telegrams_.empty()) { + auto telegram = rx_telegrams_.front().telegram_; + (void)EMSESP::process_telegram(telegram); // further process the telegram + increment_telegram_count(); // increase rx count + rx_telegrams_.pop_front(); // remove it from the queue } } @@ -217,10 +225,22 @@ void RxService::add(uint8_t * data, uint8_t length) { // if we receive a hc2.. telegram from 0x19.. match it to master_thermostat if master is 0x18 src = EMSESP::check_master_device(src, type_id, true); + // create the telegram + auto telegram = std::make_shared(operation, src, dest, type_id, offset, message_data, message_length); + + // check if queue is full, if so remove top item to make space + if (rx_telegrams_.size() >= MAX_RX_TELEGRAMS) { + rx_telegrams_.pop_front(); + } + + rx_telegrams_.emplace_back(rx_telegram_id_++, std::move(telegram)); // add to queue + + /* QueuedRxTelegram qrxt; qrxt.telegram_ = std::make_shared(operation, src, dest, type_id, offset, message_data, message_length); qrxt.id_ = rx_telegram_id_++; rx_telegrams_.push(qrxt); + */ } // start and initialize Tx @@ -264,13 +284,16 @@ void TxService::send() { return; } - // get the Telegram, also removes from queue - auto telegram = tx_telegrams_.pop(); + // auto telegram = tx_telegrams_.pop(); // get the Telegram, also removes from queue // if we're in read-only mode (tx_mode 0) forget the Tx call if (tx_mode() != 0) { - send_telegram(telegram); + // send_telegram(telegram); + send_telegram(tx_telegrams_.front()); } + + // auto telegram = tx_telegrams_.pop(); + tx_telegrams_.pop_front(); // remove the telegram from the queue } // process a Tx telegram @@ -387,6 +410,32 @@ void TxService::send_telegram(const uint8_t * data, const uint8_t length) { } } +void TxService::add(const uint8_t operation, + const uint8_t dest, + const uint16_t type_id, + const uint8_t offset, + uint8_t * message_data, + const uint8_t message_length, + const bool front) { + auto telegram = std::make_shared(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length); + +#ifdef EMSESP_DEBUG + LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); +#endif + + // if the queue is full, make room but removing the last one + if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) { + tx_telegrams_.pop_front(); + } + + if (front) { + tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false); // add to back of queue + } else { + tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // add to back of queue + } +} + +/* // builds a Tx telegram and adds to queue // given some details like the destination, type, offset and message block void TxService::add(const uint8_t operation, @@ -411,6 +460,7 @@ void TxService::add(const uint8_t operation, tx_telegrams_.push_back(qtxt); // add to back of queue } } +*/ // builds a Tx telegram and adds to queue // this is used by the retry() function to put the last failed Tx back into the queue @@ -467,19 +517,31 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt EMSESP::set_read_id(type_id); } + auto telegram = std::make_shared(operation, src, dest, type_id, offset, message_data, message_length); // operation is TX_WRITE or TX_READ + + // if the queue is full, make room but removing the last one + if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) { + tx_telegrams_.pop_front(); + } + #ifdef EMSESP_DEBUG LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); #endif + /* QueuedTxTelegram qtxt; qtxt.id_ = tx_telegram_id_++; qtxt.retry_ = false; qtxt.telegram_ = std::make_shared(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length); + */ if (front) { - tx_telegrams_.push_front(qtxt); // add to front of queue + // tx_telegrams_.push_front(qtxt); // add to front of queue + tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false); // add to back of queue + } else { - tx_telegrams_.push_back(qtxt); // add to back of queue + // tx_telegrams_.push_back(qtxt); // add to back of queue + tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // add to back of queue } } @@ -554,11 +616,20 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui Helpers::data_to_hex(data, length).c_str()); #endif + // add to the top of the queue + if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) { + tx_telegrams_.pop_back(); + } + + tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram_last_), true); + + /* QueuedTxTelegram qtxt; qtxt.id_ = tx_telegram_id_++; qtxt.retry_ = true; // this time it is a retry qtxt.telegram_ = telegram_last_; tx_telegrams_.push_front(qtxt); // add to front of queue + */ } uint16_t TxService::read_next_tx() { diff --git a/src/telegram.h b/src/telegram.h index 4a845f0fe..6a12a029d 100644 --- a/src/telegram.h +++ b/src/telegram.h @@ -32,7 +32,7 @@ #include -#include "containers.h" +// #include "containers.h" #include "helpers.h" #define MAX_RX_TELEGRAMS 10 // size of Rx queue @@ -230,6 +230,23 @@ class RxService : public EMSbus { return (q <= EMS_BUS_QUALITY_RX_THRESHOLD ? 100 : 100 - q); } + struct QueuedRxTelegram { + public: + const uint16_t id_; + const std::shared_ptr telegram_; + + ~QueuedRxTelegram() = default; + QueuedRxTelegram(uint16_t id, std::shared_ptr && telegram) + : id_(id) + , telegram_(std::move(telegram)) { + } + }; + + const std::list queue() const { + return rx_telegrams_; + } + + /* struct QueuedRxTelegram { uint16_t id_; std::shared_ptr telegram_; @@ -238,15 +255,17 @@ class RxService : public EMSbus { const emsesp::queue queue() const { return rx_telegrams_; } + */ private: static constexpr uint8_t EMS_BUS_QUALITY_RX_THRESHOLD = 5; // % threshold before reporting quality issues - uint8_t rx_telegram_id_ = 0; // queue counter - uint32_t telegram_count_ = 0; // # Rx received - uint32_t telegram_error_count_ = 0; // # Rx CRC errors - std::shared_ptr rx_telegram; // the incoming Rx telegram - emsesp::queue rx_telegrams_ = emsesp::queue(MAX_RX_TELEGRAMS); // the Rx Queue + uint8_t rx_telegram_id_ = 0; // queue counter + uint32_t telegram_count_ = 0; // # Rx received + uint32_t telegram_error_count_ = 0; // # Rx CRC errors + std::shared_ptr rx_telegram; // the incoming Rx telegram + std::list rx_telegrams_; // the Rx Queue + // emsesp::queue rx_telegrams_ = emsesp::queue(MAX_RX_TELEGRAMS); // the Rx Queue }; class TxService : public EMSbus { @@ -334,6 +353,24 @@ class TxService : public EMSbus { telegram_write_count_++; } + struct QueuedTxTelegram { + const uint16_t id_; + const std::shared_ptr telegram_; + const bool retry_; // true if its a retry + + ~QueuedTxTelegram() = default; + QueuedTxTelegram(uint16_t id, std::shared_ptr && telegram, bool retry) + : id_(id) + , telegram_(std::move(telegram)) + , retry_(retry) { + } + }; + + const std::list queue() const { + return tx_telegrams_; + } + + /* struct QueuedTxTelegram { uint16_t id_; std::shared_ptr telegram_; @@ -343,6 +380,7 @@ class TxService : public EMSbus { const emsesp::queue queue() const { return tx_telegrams_; } + */ #if defined(EMSESP_DEBUG) static constexpr uint8_t MAXIMUM_TX_RETRIES = 0; // when compiled with EMSESP_DEBUG don't retry @@ -351,7 +389,8 @@ class TxService : public EMSbus { #endif private: - emsesp::queue tx_telegrams_ = emsesp::queue(MAX_TX_TELEGRAMS); // the Tx Queue + std::list tx_telegrams_; // the Tx queue + // emsesp::queue tx_telegrams_ = emsesp::queue(MAX_TX_TELEGRAMS); // the Tx Queue uint32_t telegram_read_count_ = 0; // # Tx successful reads uint32_t telegram_write_count_ = 0; // # Tx successful writes