#632 - still experimental

This commit is contained in:
proddy
2020-12-29 22:15:59 +01:00
parent fd0b74055f
commit 7c6aeb3cb9
57 changed files with 1284 additions and 833 deletions

View File

@@ -5,6 +5,51 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.2.0] December 28 2020
### Added
- function keys in editor: cursor, del, home, end. F1=help, F2=show, and other shortcuts
- SM100 pump working time and energy units
- heating curve parameters and commands for RC300
- `wwonetime` for RC300 thermostat
- expose test framework via api (#611)
- SysLog has enable/disable flag in WebUI
- Add solar configuration telegrams (#616) [thanks @hpanther]
- `log trace` shows decoded or optional raw telegrams, `watch unknown` for only unknown telegrams
- WM10 switch telegrams
- boiler information (#633), pumpmod min/max commands
- maintenance message and command
- thermostat program, reducemode, controlmode
- optional delayed start for sending tx-telegrams to prevent conflicts with KM200
- RC35 holiday setting with `+` for 'at home'
### Fixed
- mixer IPM pumpstatus
- mixer devices in HA were incorrectly named
- Prevent HA MQTT config messages for thermostat that has no 'currtemp' (#582)
- serviceCodeNumber, 3-char serviceCode, exhausttemp and heating_active for newer ems+ boilers
- prevent MQTT publish messages from sending twice
- repeated output on read commands
- heating_active for ems+
### Changed
- optimized MQTT for HA to reduce heap fragmentation issues
- change syslog settings without reboot
- HA-config split in smaller blocks
- commands `fetch` and `publish [ha]` as call
- mqtt json package sizes
- renamed the command system info (which showed settings) to `settings`
- renamed the command system report (Which dumped debug info) to `info`
- Changing settings via web restarts only selected services
- renamed pio targets (esp8266-ci and esp32-ci for GitHub CI)
- telnet default settings `log info`, timeout 60 min
- `log debug` not showing telegram names, use `log trace` or `watch on` to show the telegrams
- optimized how console and web display device data ([#632](https://github.com/proddy/EMS-ESP/issues/632))
### Removed
- old shell and python build scripts
## [2.1.0] October 31 2020
### Added
@@ -39,7 +84,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix writing to the Junkers FR120 thermostat
- support for changing summermode
- added missing `heatingtype` to thermostat data
- handle incomming ems+ read requests, ignore F7 telegrams with 3byte-id
- handle incoming ems+ read requests, ignore F7 telegrams with 3byte-id
- fix month for setting clock from NTP
### Changed

View File

@@ -1,40 +1,10 @@
# Changelog
### Added
- function keys in editor: cursor, del, home, end. F1=help, F2=show, and other shortcuts
- SM100 pump working time and energy units
- heating curve parameters and commands for RC300
- `wwonetime` for RC300 thermostat
- expose test framework via api (#611)
- SysLog has enable/disable flag in WebUI
- Add solar configuration telegrams (#616) [thanks @hpanther]
- `log trace` shows decoded telegrams, `watch unknown` for only unknown telegrams
- WM10 switch telegrams
- boiler information (#633), pumpmod min/max commands
- maintenance message and command
- thermostat program, reducemode, controlmode
- See https://github.com/proddy/EMS-ESP/issues/632
### Fixed
- mixer IPM pumpstatus
- mixer devices in HA were incorrectly named
- Prevent HA MQTT config messages for thermostat that has no 'currtemp' (#582)
- serviceCodeNumber, 3-char serviceCode, exhausttemp and heating_active for newer ems+ boilers
- prevent MQTT publish messages from sending twice
- repeated output on read commands
### Changed
- optimized MQTT for HA to reduce heap fragmentation issues
- change syslog settings without reboot
- HA-config split in smaller blocks
- commands `fetch` and `publish [ha]` as call
- mqtt json package sizes
- renamed the command system info (which showed settings) to `settings`
- renamed the command system report (Which dumped debug info) to `info`
- Changing settings via web restarts only selected services
- renamed pio targets (esp8266-ci and esp32-ci for GitHub CI)
- telnet default settings `log info`, timeout 60 min
- `log debug` not showing telegram names, use `log trace` or `watch on` to show the telegrams
- optimized how console and web display device data ([#632](https://github.com/proddy/EMS-ESP/issues/632))
### Removed
- old shell and python build scripts

View File

@@ -94,17 +94,6 @@ class SystemStatusForm extends Component<SystemStatusFormProps, SystemStatusForm
</ListItem>
</Fragment>)
}
<ListItem>
<ListItemAvatar>
<Avatar>
<BatteryUnknownIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Free System Memory"
secondary={data.free_mem + "%"}
/>
</ListItem>
<Divider variant="inset" component="li" />
<ListItem >
<ListItemAvatar>

View File

@@ -21,7 +21,7 @@ void APSettingsService::reconfigureAP() {
void APSettingsService::loop() {
unsigned long currentMillis = uuid::get_uptime();
unsigned long manageElapsed = (unsigned long)(currentMillis - _lastManaged);
unsigned long manageElapsed = (uint32_t)(currentMillis - _lastManaged);
if (manageElapsed >= MANAGE_NETWORK_DELAY) {
_lastManaged = currentMillis;
manageAP();

View File

@@ -7,7 +7,7 @@ class ESPUtils {
public:
static String defaultDeviceValue(String prefix = "") {
#ifdef ESP32
return prefix + String((unsigned long)ESP.getEfuseMac(), HEX);
return prefix + String((uint32_t)ESP.getEfuseMac(), HEX);
#elif defined(ESP8266)
return prefix + String(ESP.getChipId(), HEX);
#endif

View File

@@ -61,7 +61,7 @@ void MqttSettingsService::begin() {
}
void MqttSettingsService::loop() {
if (_reconfigureMqtt || (_disconnectedAt && (unsigned long)(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
if (_reconfigureMqtt || (_disconnectedAt && (uint32_t)(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
// reconfigure MQTT client
configureMqtt();

View File

@@ -70,7 +70,11 @@ void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVari
if (!sntp_enabled() && json.is<JsonObject>()) {
String timeUtc = json["time_utc"];
struct tm tm = {0};
char * s = strptime(timeUtc.c_str(), "%Y-%m-%dT%H:%M:%SZ", &tm);
// TODO fix strptime, which is not included in xtensa
// char * s = strptime(timeUtc.c_str(), "%Y-%m-%dT%H:%M:%SZ", &tm);
char * s = nullptr;
if (s != nullptr) {
time_t time = mktime(&tm);
struct timeval now = {.tv_sec = time};
@@ -80,6 +84,7 @@ void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVari
return;
}
}
AsyncWebServerResponse * response = request->beginResponse(400);
request->send(response);
}

View File

@@ -7,8 +7,6 @@ SystemStatus::SystemStatus(AsyncWebServer * server, SecurityManager * securityMa
}
void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
uint8_t free_mem_percent = emsesp::System::free_mem(); // added by proddy
AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_ESP_STATUS_SIZE);
JsonObject root = response->getRoot();
#ifdef ESP32
@@ -41,7 +39,6 @@ void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
#endif
root["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); // proddy added
root["free_mem"] = free_mem_percent; // proddy added
response->setLength();
request->send(response);

View File

@@ -56,7 +56,7 @@ void WiFiSettingsService::reconfigureWiFiConnection() {
void WiFiSettingsService::loop() {
unsigned long currentMillis = millis();
if (!_lastConnectionAttempt || (unsigned long)(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) {
if (!_lastConnectionAttempt || (uint32_t)(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) {
_lastConnectionAttempt = currentMillis;
manageSTA();
}

View File

@@ -30,7 +30,7 @@ namespace uuid {
namespace console {
static const char __pstr__logger_name[] __attribute__((__aligned__(sizeof(int)))) PROGMEM = "shell";
static const char __pstr__logger_name[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "shell";
const uuid::log::Logger Shell::logger_{reinterpret_cast<const __FlashStringHelper *>(__pstr__logger_name), uuid::log::Facility::LPR};
Shell::QueuedLogMessage::QueuedLogMessage(unsigned long id, std::shared_ptr<uuid::log::Message> && content)

View File

@@ -26,19 +26,19 @@ namespace uuid {
namespace log {
static constexpr const char * pstr_level_lowercase_off __attribute__((__aligned__(sizeof(int)))) PROGMEM = "off";
static constexpr const char * pstr_level_lowercase_emerg __attribute__((__aligned__(sizeof(int)))) PROGMEM = "emerg";
static constexpr const char * pstr_level_lowercase_crit __attribute__((__aligned__(sizeof(int)))) PROGMEM = "crit";
static constexpr const char * pstr_level_lowercase_alert __attribute__((__aligned__(sizeof(int)))) PROGMEM = "alert";
static constexpr const char * pstr_level_lowercase_err __attribute__((__aligned__(sizeof(int)))) PROGMEM = "err";
static constexpr const char * pstr_level_lowercase_warning __attribute__((__aligned__(sizeof(int)))) PROGMEM = "warning";
static constexpr const char * pstr_level_lowercase_notice __attribute__((__aligned__(sizeof(int)))) PROGMEM = "notice";
static constexpr const char * pstr_level_lowercase_info __attribute__((__aligned__(sizeof(int)))) PROGMEM = "info";
static constexpr const char * pstr_level_lowercase_debug __attribute__((__aligned__(sizeof(int)))) PROGMEM = "debug";
static constexpr const char * pstr_level_lowercase_trace __attribute__((__aligned__(sizeof(int)))) PROGMEM = "trace";
static constexpr const char * pstr_level_lowercase_all __attribute__((__aligned__(sizeof(int)))) PROGMEM = "all";
static constexpr const char * pstr_level_lowercase_off __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "off";
static constexpr const char * pstr_level_lowercase_emerg __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "emerg";
static constexpr const char * pstr_level_lowercase_crit __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "crit";
static constexpr const char * pstr_level_lowercase_alert __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "alert";
static constexpr const char * pstr_level_lowercase_err __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "err";
static constexpr const char * pstr_level_lowercase_warning __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "warning";
static constexpr const char * pstr_level_lowercase_notice __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "notice";
static constexpr const char * pstr_level_lowercase_info __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "info";
static constexpr const char * pstr_level_lowercase_debug __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "debug";
static constexpr const char * pstr_level_lowercase_trace __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "trace";
static constexpr const char * pstr_level_lowercase_all __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "all";
static const __FlashStringHelper * log_level_lowercase[(int)Level::ALL - (int)Level::OFF + 1] __attribute__((__aligned__(sizeof(int))))
static const __FlashStringHelper * log_level_lowercase[(int)Level::ALL - (int)Level::OFF + 1] __attribute__((__aligned__(sizeof(uint32_t))))
PROGMEM = {reinterpret_cast<const __FlashStringHelper *>(pstr_level_lowercase_off),
reinterpret_cast<const __FlashStringHelper *>(pstr_level_lowercase_emerg),
reinterpret_cast<const __FlashStringHelper *>(pstr_level_lowercase_crit),

View File

@@ -26,19 +26,19 @@ namespace uuid {
namespace log {
static constexpr const char * pstr_level_uppercase_off __attribute__((__aligned__(sizeof(int)))) PROGMEM = "OFF";
static constexpr const char * pstr_level_uppercase_emerg __attribute__((__aligned__(sizeof(int)))) PROGMEM = "EMERG";
static constexpr const char * pstr_level_uppercase_crit __attribute__((__aligned__(sizeof(int)))) PROGMEM = "CRIT";
static constexpr const char * pstr_level_uppercase_alert __attribute__((__aligned__(sizeof(int)))) PROGMEM = "ALERT";
static constexpr const char * pstr_level_uppercase_err __attribute__((__aligned__(sizeof(int)))) PROGMEM = "ERR";
static constexpr const char * pstr_level_uppercase_warning __attribute__((__aligned__(sizeof(int)))) PROGMEM = "WARNING";
static constexpr const char * pstr_level_uppercase_notice __attribute__((__aligned__(sizeof(int)))) PROGMEM = "NOTICE";
static constexpr const char * pstr_level_uppercase_info __attribute__((__aligned__(sizeof(int)))) PROGMEM = "INFO";
static constexpr const char * pstr_level_uppercase_debug __attribute__((__aligned__(sizeof(int)))) PROGMEM = "DEBUG";
static constexpr const char * pstr_level_uppercase_trace __attribute__((__aligned__(sizeof(int)))) PROGMEM = "TRACE";
static constexpr const char * pstr_level_uppercase_all __attribute__((__aligned__(sizeof(int)))) PROGMEM = "ALL";
static constexpr const char * pstr_level_uppercase_off __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "OFF";
static constexpr const char * pstr_level_uppercase_emerg __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "EMERG";
static constexpr const char * pstr_level_uppercase_crit __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "CRIT";
static constexpr const char * pstr_level_uppercase_alert __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "ALERT";
static constexpr const char * pstr_level_uppercase_err __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "ERR";
static constexpr const char * pstr_level_uppercase_warning __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "WARNING";
static constexpr const char * pstr_level_uppercase_notice __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "NOTICE";
static constexpr const char * pstr_level_uppercase_info __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "INFO";
static constexpr const char * pstr_level_uppercase_debug __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "DEBUG";
static constexpr const char * pstr_level_uppercase_trace __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "TRACE";
static constexpr const char * pstr_level_uppercase_all __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "ALL";
static const __FlashStringHelper * log_level_uppercase[(int)Level::ALL - (int)Level::OFF + 1] __attribute__((__aligned__(sizeof(int))))
static const __FlashStringHelper * log_level_uppercase[(int)Level::ALL - (int)Level::OFF + 1] __attribute__((__aligned__(sizeof(uint32_t))))
PROGMEM = {reinterpret_cast<const __FlashStringHelper *>(pstr_level_uppercase_off),
reinterpret_cast<const __FlashStringHelper *>(pstr_level_uppercase_emerg),
reinterpret_cast<const __FlashStringHelper *>(pstr_level_uppercase_crit),

View File

@@ -87,7 +87,7 @@
#include <uuid/common.h>
#include <uuid/log.h>
static const char __pstr__logger_name[] __attribute__((__aligned__(sizeof(int)))) PROGMEM = "syslog";
static const char __pstr__logger_name[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "syslog";
namespace uuid {
@@ -413,7 +413,7 @@ bool SyslogService::transmit(const QueuedLogMessage & message) {
tm.tm_hour,
tm.tm_min,
tm.tm_sec,
(unsigned long)message.time_.tv_usec);
(uint32_t)message.time_.tv_usec);
} else {
udp_.print('-');
}

View File

@@ -59,7 +59,7 @@
#endif
#endif
static const char __pstr__logger_name[] __attribute__((__aligned__(sizeof(int)))) PROGMEM = "telnet";
static const char __pstr__logger_name[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = "telnet";
namespace uuid {

View File

@@ -18,7 +18,7 @@ MAKEFLAGS+="j "
TARGET := emsesp
BUILD := build
SOURCES := src lib_standalone lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src src/devices lib/ArduinoJson/src src/test
INCLUDES := lib/ArduinoJson/src lib_standalone lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/uuid-telnet/src lib/uuid-syslog/src src/devices src
INCLUDES := lib/ArduinoJson/src lib_standalone lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/uuid-telnet/src lib/uuid-syslog/src src/devices lib src
LIBRARIES :=
CPPCHECK = cppcheck

View File

@@ -10,6 +10,22 @@ extra_configs =
pio_local.ini
[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
debug_flags =
; -D EMSESP_DEBUG
; -D EMSESP_UART_DEBUG
@@ -17,8 +33,8 @@ debug_flags =
; -D EMSESP_FORCE_SERIAL
; -D ENABLE_CORS
; 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
build_flags =
${common.core_build_flags}
${factory_settings.build_flags}
-D FT_PROJECT=1
-D FT_SECURITY=1
@@ -32,12 +48,17 @@ build_flags =
-D PROGMEM_WWW
-D CORS_ORIGIN=\"http://localhost:3000\"
build_unflags = -Wall
-Wdeprecated-declarations
-std=gnu++11
[env]
framework = arduino
monitor_speed = 115200
upload_speed = 921600
build_type = release
lib_ldf_mode = chain+
; lib_compat_mode = strict
check_tool = cppcheck, clangtidy
check_severity = high, medium
@@ -72,12 +93,20 @@ extra_scripts =
scripts/rename_fw.py
board = esp12e ; https://github.com/platformio/platform-espressif8266/tree/master/boards
platform = espressif8266 ; https://github.com/platformio/platform-espressif8266/releases
platform_packages = platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git
; toolchain-xtensa @ ~2.100100.200706
; toolchain-xtensa @ 2.40802.200502
; toolchain-xtensa @ https://github.com/earlephilhower/esp-quick-toolchain/releases/download/3.0.0-gnu12/x86_64-linux-gnu.xtensa-lx106-elf-0474ae9.200706.tar.gz
; platformio/tool-esptool @ 1.413.0
; platformio/tool-esptoolpy @ ~1.30000.0
mcspr/toolchain-xtensa @ 5.100200.201223
board_build.filesystem = littlefs
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}
lib_ignore =
AsyncTCP

View File

@@ -16,11 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WebAPIService.h"
#include "emsesp.h"
#include "command.h"
#include "emsdevice.h"
#include "system.h"
namespace emsesp {

View File

@@ -16,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WebDevicesService.h"
#include "emsesp.h"
namespace emsesp {

View File

@@ -16,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WebSettingsService.h"
#include "emsesp.h"
namespace emsesp {

View File

@@ -16,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WebStatusService.h"
#include "emsesp.h"
namespace emsesp {

View File

@@ -24,7 +24,11 @@ namespace emsesp {
uuid::log::Logger Command::logger_{F_(command), uuid::log::Facility::DAEMON};
std::vector<Command::CmdFunction> Command::cmdfunctions_;
static emsesp::array<Command::CmdFunction> cmdfunctions_(90, 255, 16); // reserve space for 90 commands
emsesp::array<Command::CmdFunction> * Command::commands() {
return &cmdfunctions_;
}
// calls a command
// id may be used to represent a heating circuit for example
@@ -85,12 +89,19 @@ bool Command::call(const uint8_t device_type, const char * cmd, const char * val
}
// add a command to the list, which does not return json
void Command::add(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, cmdfunction_p cb) {
void Command::add(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb) {
// if the command already exists for that device type don't add it
if (find_command(device_type, uuid::read_flash_string(cmd).c_str()) != nullptr) {
return;
}
cmdfunctions_.emplace_back(device_type, cmd, cb, nullptr);
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);
// see if we need to subscribe
if (Mqtt::enabled()) {
@@ -105,7 +116,14 @@ void Command::add_with_json(const uint8_t device_type, const __FlashStringHelper
return;
}
cmdfunctions_.emplace_back(device_type, cmd, nullptr, cb); // add command
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
}
// see if a command exists for that device type
@@ -132,11 +150,11 @@ Command::CmdFunction * Command::find_command(const uint8_t device_type, const ch
// output list of all commands to console for a specific DeviceType
void Command::show(uuid::console::Shell & shell, uint8_t device_type) {
if (commands().empty()) {
if (cmdfunctions_.empty()) {
shell.println(F("No commands"));
}
for (const auto & cf : Command::commands()) {
for (const auto & cf : cmdfunctions_) {
if (cf.device_type_ == device_type) {
shell.printf("%s ", uuid::read_flash_string(cf.cmd_).c_str());
}
@@ -162,7 +180,7 @@ bool Command::device_has_commands(const uint8_t device_type) {
for (const auto & emsdevice : EMSESP::emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == device_type)) {
// device found, now see if it has any commands
for (const auto & cf : Command::commands()) {
for (const auto & cf : cmdfunctions_) {
if (cf.device_type_ == device_type) {
return true;
}

View File

@@ -26,6 +26,8 @@
#include <vector>
#include <functional>
#include "containers.h"
#include "console.h"
#include <uuid/log.h>
@@ -44,22 +46,13 @@ 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 std::vector<CmdFunction> commands() {
return cmdfunctions_;
}
static emsesp::array<Command::CmdFunction> * 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);
static void add(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, cmdfunction_p cb);
static void add(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb);
static void add_with_json(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_json_p cb);
static void show_all(uuid::console::Shell & shell);
static Command::CmdFunction * find_command(const uint8_t device_type, const char * cmd);
@@ -68,8 +61,6 @@ class Command {
static void show_devices(uuid::console::Shell & shell);
static bool device_has_commands(const uint8_t device_type);
static std::vector<CmdFunction> cmdfunctions_; // list of commands
private:
static uuid::log::Logger logger_;
};

View File

@@ -422,7 +422,7 @@ void EMSESPShell::add_console_commands() {
std::vector<std::string> 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_));
}

View File

@@ -46,9 +46,11 @@ using uuid::log::Level;
// clang-format off
// strings stored 32 bit aligned on ESP8266/ESP32
#define MAKE_PSTR(string_name, string_literal) static const char __pstr__##string_name[] __attribute__((__aligned__(sizeof(int)))) PROGMEM = string_literal;
#define MAKE_PSTR(string_name, string_literal) static const char __pstr__##string_name[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = string_literal;
#define MAKE_PSTR_WORD(string_name) MAKE_PSTR(string_name, #string_name)
#define F_(string_name) FPSTR(__pstr__##string_name)
#define MAKE_PSTR_LIST(list_name, ...) static const __FlashStringHelper * const __pstr__##list_name[] PROGMEM = {__VA_ARGS__, nullptr};
#define FL_(list_name) (__pstr__##list_name)
// clang-format on
// localizations
@@ -58,7 +60,7 @@ using uuid::log::Level;
#undef LOCAL
#endif
static constexpr uint32_t INVALID_PASSWORD_DELAY_MS = 3000;
static constexpr uint32_t INVALID_PASSWORD_DELAY_MS = 2000;
namespace emsesp {

448
src/containers.h Normal file
View File

@@ -0,0 +1,448 @@
/*
* EMS-ESP - https://github.com/proddy/EMS-ESP
* Copyright 2020 Paul Derbyshire
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Lightweight queue & array
* Based ideas from https://github.com/muwerk/ustd
* Limits to max 255 entries
*/
#ifndef EMSESP_CONTAINERS_H
#define EMSESP_CONTAINERS_H
#include <Arduino.h>
#if defined EMSESP_ASSERT
#include <assert.h>
#endif
namespace emsesp {
template <typename T>
class queueIterator {
public:
queueIterator(T * values_ptr, uint8_t p)
: values_ptr_{values_ptr}
, position_{p} {
}
bool operator!=(const queueIterator<T> & other) const {
return !(*this == other);
}
bool operator==(const queueIterator<T> & other) const {
return position_ == other.position_;
}
queueIterator & operator++() {
++position_;
return *this;
}
T & operator*() const {
return *(values_ptr_ + position_);
}
private:
T * values_ptr_;
uint8_t position_;
};
template <class T>
class queue {
private:
T * que_;
uint8_t peakSize_;
uint8_t maxSize_;
uint8_t size_;
uint8_t quePtrFront_; // back
uint8_t quePtrBack_; // front
T bad_;
public:
// Constructs a queue object with the maximum number of <T> pointer entries
queue(uint8_t maxQueueSize)
: maxSize_(maxQueueSize) {
memset(&bad_, 0, sizeof(bad_));
quePtrFront_ = 0;
quePtrBack_ = 0;
size_ = 0;
peakSize_ = 0;
que_ = (T *)malloc(sizeof(T) * maxSize_);
if (que_ == nullptr)
maxSize_ = 0;
}
// Deallocate the queue structure
~queue() {
if (que_ != nullptr) {
free(que_);
que_ = nullptr;
}
}
// Push a new entry into the queue.
// true on success, false if queue is full, then the element is relaced with the front one
bool push(T ent) {
// Serial.print("quePtrFront_: ");
// Serial.print(quePtrFront_);
// Serial.print(" quePtrBack_: ");
// Serial.print(quePtrBack_);
// Serial.println();
if (size_ >= maxSize_) {
// que_[quePtrFront_] = ent;
return false;
}
que_[quePtrBack_] = ent;
quePtrBack_ = (quePtrBack_ + 1) % maxSize_;
++size_;
if (size_ > peakSize_) {
peakSize_ = size_;
}
return true;
}
bool push_back(T ent) {
return push(ent);
}
// Push a new entry into the front of queue, moving the rest down
// true on success, false if queue is full
// there are no good checks for overflow
bool push_front(T ent) {
if (size_ >= maxSize_) {
return false;
}
// Serial.print("quePtrFront_: ");
// Serial.print(quePtrFront_);
// Serial.print(" quePtrBack_: ");
// Serial.print(quePtrBack_);
// Serial.println();
for (uint8_t i = 0; i <= size_; i++) {
que_[quePtrBack_ - i + 1] = que_[quePtrBack_ - i]; // move the rest up 1
}
que_[quePtrFront_] = ent; // add the new one
quePtrBack_ = (quePtrBack_ + 1) % maxSize_;
++size_;
if (size_ > peakSize_) {
peakSize_ = size_;
}
return true;
}
T & operator[](uint8_t i) {
return que_[i + quePtrFront_];
}
// Pop the oldest entry from the queue
T pop() {
if (size_ == 0)
return bad_;
T ent = que_[quePtrFront_];
quePtrFront_ = (quePtrFront_ + 1) % maxSize_;
--size_;
return ent;
}
// alias pop_front to keep backwards compatibility with std::list/queue
T pop_front() {
return pop();
}
T front() {
return que_[quePtrFront_];
}
uint8_t front_i() {
return quePtrFront_;
}
T * front_p() {
return &que_[quePtrFront_];
}
T back() {
return que_[quePtrBack_];
}
// Set the value for <T>entry that's given back, if read from an empty
// queue is requested. By default, an entry all memset to zero is given
// back. Using this function, the value of an invalid read can be configured
void setInvalidValue(T & entryInvalidValue) {
bad_ = entryInvalidValue;
}
// returns true: queue empty, false: not empty
bool empty() {
if (size_ == 0)
return true;
else
return false;
}
// returns number of entries in the queue
uint8_t size() {
return (size_);
}
// max number of queue entries that have been in the queue
uint8_t peak() {
return (peakSize_);
}
// iterators
queueIterator<T> begin() {
return queueIterator<T>(que_, quePtrFront_);
}
queueIterator<T> end() {
return queueIterator<T>(que_, quePtrFront_ + size_);
}
queueIterator<const T> begin() const {
return queueIterator<const T>(que_, quePtrFront_);
}
queueIterator<const T> end() const {
return queueIterator<const T>(que_, quePtrFront_ + size_);
}
};
template <typename T>
class arrayIterator {
public:
arrayIterator(T * values_ptr)
: values_ptr_{values_ptr}
, position_{0} {
}
arrayIterator(T * values_ptr, size_t size_)
: values_ptr_{values_ptr}
, position_{size_} {
}
bool operator!=(const arrayIterator<T> & other) const {
return !(*this == other);
}
bool operator==(const arrayIterator<T> & other) const {
return position_ == other.position_;
}
arrayIterator & operator++() {
++position_;
return *this;
}
T & operator*() const {
return *(values_ptr_ + position_);
}
private:
T * values_ptr_;
size_t position_;
};
#define ARRAY_INIT_SIZE 16
#define ARRAY_MAX_SIZE 255 // fixed for uint8_t
#define ARRAY_INC_SIZE 16
template <typename T>
class array {
private:
T * arr_;
uint8_t startSize_;
uint8_t maxSize_;
uint8_t incSize_ = ARRAY_INC_SIZE;
uint8_t allocSize_;
uint8_t size_;
T bad_;
public:
// Constructs an array object. All allocation-hints are optional, the
// array class will allocate memory as needed during writes, if
// startSize_!=maxSize_.
// @param startSize_ The number of array entries that are allocated
// during object creation
// @param maxSize_ The maximal limit of records that will be allocated.
// If startSize_ < maxSize_, the array size_ will grow automatically as
// needed.
// @param incSize_ The number of array entries that are allocated as a
// chunk if the array needs to grow
array(uint8_t startSize_ = ARRAY_INIT_SIZE, uint8_t maxSize_ = ARRAY_MAX_SIZE, uint8_t incSize_ = ARRAY_INC_SIZE)
: startSize_(startSize_)
, maxSize_(maxSize_)
, incSize_(incSize_) {
size_ = 0;
memset(&bad_, 0, sizeof(bad_));
if (maxSize_ < startSize_)
maxSize_ = startSize_;
allocSize_ = startSize_;
arr_ = new T[allocSize_];
}
~array() {
/*! Free resources */
if (arr_ != nullptr) {
delete[] arr_;
arr_ = nullptr;
}
}
// Change the array allocation size_. the new number of array entries, corresponding memory is allocated/free'd as necessary.
bool resize(uint8_t newSize) {
uint8_t mv = newSize;
if (newSize > maxSize_) {
if (maxSize_ == allocSize_)
return false;
else
newSize = maxSize_;
}
if (newSize <= allocSize_)
return true;
T * arrn = new T[newSize];
if (arrn == nullptr)
return false;
for (uint8_t i = 0; i < mv; i++) {
arrn[i] = arr_[i];
}
delete[] arr_;
arr_ = arrn;
allocSize_ = newSize;
return true;
}
// Set the value for <T>entry that's given back,
// if read of an invalid index is requested.
// By default, an entry all memset to zero is given
// back. Using this function, the value of an invalid read can be configured.
// returns the value that is given back in case an invalid operation (e.g. read out of bounds) is tried
void setInvalidValue(T & entryInvalidValue) {
bad_ = entryInvalidValue;
}
// Append an array element after the current end of the array
// takes entry array element that is appended after the last current
// entry. The new array size_ must be smaller than maxSize_ as defined
// during array creation. New array memory is automatically allocated if
// within maxSize_ boundaries
int push(T & entry) {
if (size_ >= allocSize_) {
if (incSize_ == 0)
return -1;
if (!resize(allocSize_ + incSize_))
return -1;
}
arr_[size_] = entry;
++size_;
return size_ - 1;
}
// Assign content of array element at i for const's
T operator[](uint8_t i) const {
if (i >= allocSize_) {
if (incSize_ == 0) {
#ifdef EMSESP_ASSERT
assert(i < allocSize_);
#endif
}
if (!resize(allocSize_ + incSize_)) {
#ifdef EMSESP_ASSERT
assert(i < allocSize_);
#endif
}
}
if (i >= size_ && i <= allocSize_)
size_ = i + 1;
if (i >= allocSize_) {
return bad_;
}
return arr_[i];
}
// Assign content of array element at i
T & operator[](uint8_t i) {
if (i >= allocSize_) {
if (incSize_ == 0) {
#ifdef EMSESP_ASSERT
assert(i < allocSize_);
#endif
}
if (!resize(allocSize_ + incSize_)) {
#ifdef EMSESP_ASSERT
assert(i < allocSize_);
#endif
}
}
if (i >= size_ && i <= allocSize_)
size_ = i + 1;
if (i >= allocSize_) {
return bad_;
}
return arr_[i];
}
// true if array empty, false otherwise
bool empty() const {
if (size_ == 0)
return true;
else
return false;
}
// return number of array elements
uint8_t size() const {
return (size_);
}
// returns number of allocated entries which can be larger than the length of the array
uint8_t alloclen() const {
return (allocSize_);
}
// emplace
// template <typename... Args>
// void emplace1(Args... args) {
// add(args...);
// };
// template <class... Args>
// void emplace(Args &&... args) {
// add(T(std::forward<Args>(args)...));
// }
// iterators
arrayIterator<T> begin() {
return arrayIterator<T>(arr_);
}
arrayIterator<T> end() {
return arrayIterator<T>(arr_, size_);
}
arrayIterator<const T> begin() const {
return arrayIterator<const T>(arr_);
}
arrayIterator<const T> end() const {
return arrayIterator<const T>(arr_, size_);
}
};
} // namespace emsesp
#endif

View File

@@ -26,11 +26,11 @@ uuid::log::Logger Boiler::logger_{F_(boiler), uuid::log::Facility::CONSOLE};
Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
reserve_mem(20); // reserve some space for the telegram registries, to avoid memory fragmentation
LOG_DEBUG(F("Adding new Boiler with device ID 0x%02X"), device_id);
System::show_mem("starting boiler regs"); // TODO remove debug
reserve_telgram_functions(25); // reserve some space for the telegram registries, to avoid memory fragmentation
System::show_mem("starting boiler regs");
// the telegram handlers...
register_telegram_type(0x10, F("UBAErrorMessage1"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAErrorMessage(t); });
@@ -60,7 +60,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
EMSESP::send_read_request(0x11, device_id); // read last errorcode on start (only published on errors)
EMSESP::send_read_request(0x15, device_id); // read maintenace data on start (only published on change)
System::show_mem("after telegram type reg"); // TODO remove debug
System::show_mem("after telegram type reg");
// MQTT commands for boiler topic
register_mqtt_cmd(F("comfort"), [&](const char * value, const int8_t id) { return set_warmwater_mode(value, id); });
@@ -80,407 +80,438 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_mqtt_cmd(F("boilhystoff"), [&](const char * value, const int8_t id) { return set_hyst_off(value, id); });
register_mqtt_cmd(F("burnperiod"), [&](const char * value, const int8_t id) { return set_burn_period(value, id); });
register_mqtt_cmd(F("pumpdelay"), [&](const char * value, const int8_t id) { return set_pump_delay(value, id); });
// register_mqtt_cmd(F("reset"), [&](const char * value, const int8_t id) { return set_reset(value, id); });
register_mqtt_cmd(F("maintenance"), [&](const char * value, const int8_t id) { return set_maintenance(value, id); });
register_mqtt_cmd(F("pumpmodmax"), [&](const char * value, const int8_t id) { return set_max_pump(value, id); });
register_mqtt_cmd(F("pumpmodmin"), [&](const char * value, const int8_t id) { return set_min_pump(value, id); });
// register_mqtt_cmd(F("reset"), [&](const char * value, const int8_t id) { return set_reset(value, id); });
System::show_mem("after mqtt cmd reg"); // TODO remove debug
System::show_mem("after mqtt cmd reg");
// add values
// init_devicevalues(30); // TODO reserve mem
reserve_device_values(50);
// main - boiler_data topic
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &heatingActive_, DeviceValueType::BOOL, {}, F("heatingActive"), F("Heating active"), DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &tapwaterActive_, DeviceValueType::BOOL, {}, F("tapwaterActive"), F("Warm water/DHW active"), DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &selFlowTemp_, DeviceValueType::UINT, {}, F("selFlowTemp"), F("Selected flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &selBurnPow_, DeviceValueType::UINT, {}, F("selBurnPow"), F("Burner selected max power"), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &pumpMod_, DeviceValueType::UINT, {}, F("pumpMod"), F("Pump modulation"), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &pumpMod2_, DeviceValueType::UINT, {}, F("pumpMod2"), F("Heat pump modulation"), DeviceValueUOM::PERCENT);
register_device_value(TAG_BOILER_DATA,
&outdoorTemp_,
DeviceValueType::SHORT,
flash_string_vector{F("10")},
F("outdoorTemp"),
F("Outside temperature"),
DeviceValueTAG::TAG_BOILER_DATA, &heatingActive_, DeviceValueType::BOOL, nullptr, F("heatingActive"), F("Heating active"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&tapwaterActive_,
DeviceValueType::BOOL,
nullptr,
F("tapwaterActive"),
F("Warm water/DHW active"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&selFlowTemp_,
DeviceValueType::UINT,
nullptr,
F("selFlowTemp"),
F("Selected flow temperature"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&selBurnPow_,
DeviceValueType::UINT,
nullptr,
F("selBurnPow"),
F("Burner selected max power"),
DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &pumpMod_, DeviceValueType::UINT, nullptr, F("pumpMod"), F("Pump modulation"), DeviceValueUOM::PERCENT);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &pumpMod2_, DeviceValueType::UINT, nullptr, F("pumpMod2"), F("Heat pump modulation"), DeviceValueUOM::PERCENT);
register_device_value(TAG_BOILER_DATA, &outdoorTemp_, DeviceValueType::SHORT, FL_(div10), F("outdoorTemp"), F("Outside temperature"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&curFlowTemp_,
DeviceValueType::USHORT,
flash_string_vector{F("10")},
FL_(div10),
F("curFlowTemp"),
F("Current flow temperature"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&retTemp_,
DeviceValueType::USHORT,
flash_string_vector{F("10")},
F("retTemp"),
F("Return temperature"),
DeviceValueUOM::DEGREES);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &retTemp_, DeviceValueType::USHORT, FL_(div10), F("retTemp"), F("Return temperature"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&switchTemp_,
DeviceValueType::USHORT,
flash_string_vector{F("10")},
FL_(div10),
F("switchTemp"),
F("Mixing switch temperature"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&sysPress_,
DeviceValueType::UINT,
flash_string_vector{F("10")},
F("sysPress"),
F("System pressure"),
DeviceValueUOM::BAR);
register_device_value(TAG_BOILER_DATA,
&boilTemp_,
DeviceValueType::USHORT,
flash_string_vector{F("10")},
F("boilTemp"),
F("Max boiler temperature"),
DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA,
&exhaustTemp_,
DeviceValueType::USHORT,
flash_string_vector{F("10")},
F("exhaustTemp"),
F("Exhaust temperature"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &sysPress_, DeviceValueType::UINT, FL_(div10), F("sysPress"), F("System pressure"), DeviceValueUOM::BAR);
register_device_value(TAG_BOILER_DATA, &boilTemp_, DeviceValueType::USHORT, FL_(div10), F("boilTemp"), F("Max boiler temperature"), DeviceValueUOM::DEGREES);
register_device_value(TAG_BOILER_DATA, &exhaustTemp_, DeviceValueType::USHORT, FL_(div10), F("exhaustTemp"), F("Exhaust temperature"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &burnGas_, DeviceValueType::BOOL, {}, F("burnGas"), F("Gas"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &flameCurr_, DeviceValueType::USHORT, {F("10")}, F("flameCurr"), F("Flame current"), DeviceValueUOM::UA);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &heatPump_, DeviceValueType::BOOL, {}, F("heatPump"), F("Heat pump"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &fanWork_, DeviceValueType::BOOL, {}, F("fanWork"), F("Fan"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &ignWork_, DeviceValueType::BOOL, {}, F("ignWork"), F("Ignition"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &burnGas_, DeviceValueType::BOOL, nullptr, F("burnGas"), F("Gas"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &flameCurr_, DeviceValueType::USHORT, FL_(div10), F("flameCurr"), F("Flame current"), DeviceValueUOM::UA);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &heatPump_, DeviceValueType::BOOL, nullptr, F("heatPump"), F("Heat pump"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &fanWork_, DeviceValueType::BOOL, nullptr, F("fanWork"), F("Fan"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &ignWork_, DeviceValueType::BOOL, nullptr, F("ignWork"), F("Ignition"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&heatingActivated_,
DeviceValueType::BOOL,
nullptr,
F("heatingActivated"),
F("Heating activated"),
DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &heatingActivated_, DeviceValueType::BOOL, {}, F("heatingActivated"), F("Heating activated"), DeviceValueUOM::NONE);
DeviceValueTAG::TAG_BOILER_DATA, &heatingTemp_, DeviceValueType::UINT, nullptr, F("heatingTemp"), F("Heating temperature"), DeviceValueUOM::DEGREES);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &heatingTemp_, DeviceValueType::UINT, {}, F("heatingTemp"), F("Heating temperature"), DeviceValueUOM::DEGREES);
DeviceValueTAG::TAG_BOILER_DATA, &pumpModMax_, DeviceValueType::UINT, nullptr, F("pumpModMax"), F("Burner pump max power"), DeviceValueUOM::PERCENT);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &pumpModMax_, DeviceValueType::UINT, {}, F("pumpModMax"), F("Burner pump max power"), DeviceValueUOM::PERCENT);
DeviceValueTAG::TAG_BOILER_DATA, &pumpModMin_, DeviceValueType::UINT, nullptr, F("pumpModMin"), F("Burner pump min power"), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &pumpDelay_, DeviceValueType::UINT, nullptr, F("pumpDelay"), F("Pump delay"), DeviceValueUOM::MINUTES);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &pumpModMin_, DeviceValueType::UINT, {}, F("pumpModMin"), F("Burner pump min power"), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &pumpDelay_, DeviceValueType::UINT, {}, F("pumpDelay"), F("Pump delay"), DeviceValueUOM::MINUTES);
DeviceValueTAG::TAG_BOILER_DATA, &burnMinPeriod_, DeviceValueType::UINT, nullptr, F("burnMinPeriod"), F("Burner min period"), DeviceValueUOM::MINUTES);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &burnMinPeriod_, DeviceValueType::UINT, {}, F("burnMinPeriod"), F("Burner min period"), DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &burnMinPower_, DeviceValueType::UINT, {}, F("burnMinPower"), F("Burner min power"), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &burnMaxPower_, DeviceValueType::UINT, {}, F("burnMaxPower"), F("Burner max power"), DeviceValueUOM::PERCENT);
DeviceValueTAG::TAG_BOILER_DATA, &burnMinPower_, DeviceValueType::UINT, nullptr, F("burnMinPower"), F("Burner min power"), DeviceValueUOM::PERCENT);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &boilHystOn_, DeviceValueType::INT, {}, F("boilHystOn"), F("Hysteresis on temperature"), DeviceValueUOM::DEGREES);
DeviceValueTAG::TAG_BOILER_DATA, &burnMaxPower_, DeviceValueType::UINT, nullptr, F("burnMaxPower"), F("Burner max power"), DeviceValueUOM::PERCENT);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &boilHystOff_, DeviceValueType::INT, {}, F("boilHystOff"), F("Hysteresis off temperature"), DeviceValueUOM::DEGREES);
DeviceValueTAG::TAG_BOILER_DATA, &boilHystOn_, DeviceValueType::INT, nullptr, F("boilHystOn"), F("Hysteresis on temperature"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&boilHystOff_,
DeviceValueType::INT,
nullptr,
F("boilHystOff"),
F("Hysteresis off temperature"),
DeviceValueUOM::DEGREES);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &setFlowTemp_, DeviceValueType::UINT, {}, F("setFlowTemp"), F("Set flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &setBurnPow_, DeviceValueType::UINT, {}, F("setBurnPow"), F("Burner set power"), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &curBurnPow_, DeviceValueType::UINT, {}, F("curBurnPow"), F("Burner current power"), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &burnStarts_, DeviceValueType::ULONG, {}, F("burnStarts"), F("Burner # starts"), DeviceValueUOM::NONE);
DeviceValueTAG::TAG_BOILER_DATA, &setFlowTemp_, DeviceValueType::UINT, nullptr, F("setFlowTemp"), F("Set flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &burnWorkMin_, DeviceValueType::TIME, {}, F("burnWorkMin"), F("Total burner operating time"), DeviceValueUOM::MINUTES);
DeviceValueTAG::TAG_BOILER_DATA, &setBurnPow_, DeviceValueType::UINT, nullptr, F("setBurnPow"), F("Burner set power"), DeviceValueUOM::PERCENT);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &heatWorkMin_, DeviceValueType::TIME, {}, F("heatWorkMin"), F("Total heat operating time"), DeviceValueUOM::MINUTES);
DeviceValueTAG::TAG_BOILER_DATA, &curBurnPow_, DeviceValueType::UINT, nullptr, F("curBurnPow"), F("Burner current power"), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &burnStarts_, DeviceValueType::ULONG, nullptr, F("burnStarts"), F("Burner # starts"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&burnWorkMin_,
DeviceValueType::TIME,
nullptr,
F("burnWorkMin"),
F("Total burner operating time"),
DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&heatWorkMin_,
DeviceValueType::TIME,
nullptr,
F("heatWorkMin"),
F("Total heat operating time"),
DeviceValueUOM::MINUTES);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA, &UBAuptime_, DeviceValueType::TIME, {}, F("UBAuptime"), F("Total UBA operating time"), DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &lastCode_, DeviceValueType::TEXT, {}, F("lastCode"), F("Last error code"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &serviceCode_, DeviceValueType::TEXT, {}, F("serviceCode"), F("Service code"), DeviceValueUOM::NONE);
DeviceValueTAG::TAG_BOILER_DATA, &UBAuptime_, DeviceValueType::TIME, nullptr, F("UBAuptime"), F("Total UBA operating time"), DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &lastCode_, DeviceValueType::TEXT, nullptr, F("lastCode"), F("Last error code"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA, &serviceCode_, DeviceValueType::TEXT, nullptr, F("serviceCode"), F("Service code"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA,
&serviceCodeNumber_,
DeviceValueType::USHORT,
{},
nullptr,
F("serviceCodeNumber"),
F("Service code number"),
DeviceValueUOM::NONE);
System::show_mem("after device value reg"); // TODO remove debug
System::show_mem("after device value reg");
#ifdef EMSESP_FORCE_SERIAL
return; // TODO remove early exit
#endif
return; // TODO early exit for memory profiling on ESP8266
// ww - boiler_data_ww topic
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWSelTemp_,
DeviceValueType::UINT,
{},
nullptr,
F("wWSelTemp"),
F("Warm Water selected temperature"),
DeviceValueUOM::DEGREES);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWSetTemp_, DeviceValueType::UINT, {}, F("wWSetTemp"), F("Warm water set temperature"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWType_,
DeviceValueType::ENUM,
flash_string_vector{F("off"), F("flow"), F("buffered flow"), F("buffer"), F("layered buffer")},
F("wWType"),
F("Warm water type"),
DeviceValueUOM::NONE);
&wWSetTemp_,
DeviceValueType::UINT,
nullptr,
F("wWSetTemp"),
F("Warm water set temperature"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wWType_, DeviceValueType::ENUM, FL_(enum_flow), F("wWType"), F("Warm water type"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWComfort_,
DeviceValueType::ENUM,
flash_string_vector{F("hot"), F("eco"), F("intelligent")},
FL_(enum_comfort),
F("wWComfort"),
F("Warm water comfort"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWCircPump_,
DeviceValueType::BOOL,
{},
nullptr,
F("wWCircPump"),
F("Warm water circulation pump available"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWChargeType_,
DeviceValueType::BOOL,
flash_string_vector{F("3-way valve"), F("charge pump")},
FL_(enum_charge),
F("wWChargeType"),
F("Warm Water charging type"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWDisinfectionTemp_,
DeviceValueType::UINT,
{},
nullptr,
F("wWDisinfectionTemp"),
F("Warm Water disinfection temperature"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWCircPumpMode_,
DeviceValueType::ENUM,
flash_string_vector{F("off"), F("1x3min"), F("2x3min"), F("3x3min"), F("4x3min"), F("5x3min"), F("6x3min"), F("continuos")},
FL_(enum_freq),
F("wWCircPumpMode"),
F("Warm water circulation pump freq"),
DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWCirc_, DeviceValueType::BOOL, {}, F("wWCirc"), F("Warm Water circulation active"), DeviceValueUOM::NONE);
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWCirc_, DeviceValueType::BOOL, nullptr, F("wWCirc"), F("Warm Water circulation active"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWCurTemp_,
DeviceValueType::USHORT,
{F("10")},
FL_(div10),
F("wWCurTemp"),
F("Warm Water current temperature (intern)"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWCurTemp2_,
DeviceValueType::USHORT,
flash_string_vector{F("10")},
FL_(div10),
F("wWCurTemp2"),
F("Warm Water current temperature (extern)"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWCurFlow_,
DeviceValueType::UINT,
{F("10")},
FL_(div10),
F("wWCurFlow"),
F("Warm Water current tap water flow"),
DeviceValueUOM::LMIN);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wwStorageTemp1_,
DeviceValueType::USHORT,
flash_string_vector{F("10")},
FL_(div10),
F("wwStorageTemp1"),
F("Warm water storage temperature (intern)"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wwStorageTemp2_,
DeviceValueType::USHORT,
flash_string_vector{F("10")},
FL_(div10),
F("wwStorageTemp2"),
F("Warm water storage temperature (extern)"),
DeviceValueUOM::DEGREES);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWActivated_, DeviceValueType::BOOL, {}, F("wWActivated"), F("Warm Water activated"), DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWOneTime_, DeviceValueType::BOOL, {}, F("wWOneTime"), F("Warm Water one time charging"), DeviceValueUOM::NONE);
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWActivated_, DeviceValueType::BOOL, nullptr, F("wWActivated"), F("Warm Water activated"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWOneTime_,
DeviceValueType::BOOL,
nullptr,
F("wWOneTime"),
F("Warm Water one time charging"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWDisinfecting_,
DeviceValueType::BOOL,
{},
nullptr,
F("wWDisinfecting"),
F("Warm Water disinfecting"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wWCharging_, DeviceValueType::BOOL, {}, F("wWCharging"), F("Warm Water charging"), DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWRecharging_, DeviceValueType::BOOL, {}, F("wWRecharging"), F("Warm Water recharging"), DeviceValueUOM::NONE);
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWCharging_, DeviceValueType::BOOL, nullptr, F("wWCharging"), F("Warm Water charging"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWRecharging_,
DeviceValueType::BOOL,
nullptr,
F("wWRecharging"),
F("Warm Water recharging"),
DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWTempOK_, DeviceValueType::BOOL, {}, F("wWTempOK"), F("Warm Water temperature ok"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wWActive_, DeviceValueType::BOOL, {}, F("wWActive"), F("Warm Water active"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wWHeat_, DeviceValueType::BOOL, {}, F("wWHeat"), F("Warm Water heating"), DeviceValueUOM::NONE);
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWTempOK_, DeviceValueType::BOOL, nullptr, F("wWTempOK"), F("Warm Water temperature ok"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wWActive_, DeviceValueType::BOOL, nullptr, F("wWActive"), F("Warm Water active"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wWHeat_, DeviceValueType::BOOL, nullptr, F("wWHeat"), F("Warm Water heating"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWSetPumpPower_,
DeviceValueType::UINT,
{},
nullptr,
F("wWSetPumpPower"),
F("Warm Water pump set power"),
DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wwMixTemperature_,
DeviceValueType::USHORT,
{},
nullptr,
F("wwMixTemperature"),
F("Warm Water mix temperature"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wwBufferTemperature_,
DeviceValueType::USHORT,
{},
nullptr,
F("wwBufferTemperature"),
F("Warm Water buffer boiler temperature"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wWStarts_, DeviceValueType::ULONG, {}, F("wWStarts"), F("Warm Water # starts"), DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWStarts2_, DeviceValueType::ULONG, {}, F("wWStarts2"), F("Warm Water # starts (control)"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW, &wWWorkM_, DeviceValueType::TIME, {}, F("wWWorkM"), F("Warm Water active time"), DeviceValueUOM::MINUTES);
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWStarts_, DeviceValueType::ULONG, nullptr, F("wWStarts"), F("Warm Water # starts"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_WW,
&wWStarts2_,
DeviceValueType::ULONG,
nullptr,
F("wWStarts2"),
F("Warm Water # starts (control)"),
DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA_WW, &wWWorkM_, DeviceValueType::TIME, nullptr, F("wWWorkM"), F("Warm Water active time"), DeviceValueUOM::MINUTES);
// info - boiler_data_info topic
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&upTimeControl_,
DeviceValueType::TIME,
flash_string_vector{F("60")},
FL_(div60),
F("upTimeControl"),
F("Operating time total heat"),
DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&upTimeCompHeating_,
DeviceValueType::TIME,
flash_string_vector{F("60")},
FL_(div60),
F("upTimeCompHeating"),
F("Operating time compressor heating"),
DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&upTimeCompCooling_,
DeviceValueType::TIME,
flash_string_vector{F("60")},
FL_(div60),
F("upTimeCompCooling"),
F("Operating time compressor cooling"),
DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&upTimeCompWw_,
DeviceValueType::TIME,
flash_string_vector{F("60")},
FL_(div60),
F("upTimeCompWw"),
F("Operating time compressor warm water"),
DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&heatingStarts_,
DeviceValueType::ULONG,
{},
nullptr,
F("heatingStarts"),
F("# heating starts (control)"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&coolingStarts_,
DeviceValueType::ULONG,
{},
nullptr,
F("coolingStarts"),
F("# cooling starts (control)"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&nrgConsTotal_,
DeviceValueType::ULONG,
{},
nullptr,
F("nrgConsTotal"),
F("Total energy consumption"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&nrgConsCompTotal_,
DeviceValueType::ULONG,
{},
nullptr,
F("nrgConsCompTotal"),
F("Energy consumption compressor total"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&nrgConsCompHeating_,
DeviceValueType::ULONG,
{},
nullptr,
F("nrgConsCompHeating"),
F("Energy consumption compressor heating"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&nrgConsCompWw_,
DeviceValueType::ULONG,
{},
nullptr,
F("nrgConsCompWw"),
F("Energy consumption compressor warm water"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&nrgConsCompCooling_,
DeviceValueType::ULONG,
{},
nullptr,
F("nrgConsCompCooling"),
F("Energy consumption compressor cooling"),
DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_BOILER_DATA_INFO, &nrgSuppTotal_, DeviceValueType::ULONG, {}, F("nrgSuppTotal"), F("Total energy supplied"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&nrgSuppTotal_,
DeviceValueType::ULONG,
nullptr,
F("nrgSuppTotal"),
F("Total energy supplied"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&nrgSuppHeating_,
DeviceValueType::ULONG,
{},
nullptr,
F("nrgSuppHeating"),
F("Total energy supplied heating"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&nrgSuppWw_,
DeviceValueType::ULONG,
{},
nullptr,
F("nrgSuppWw"),
F("Total energy warm supplied warm water"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&nrgSuppCooling_,
DeviceValueType::ULONG,
{},
nullptr,
F("nrgSuppCooling"),
F("Total energy supplied cooling"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&auxElecHeatNrgConsTotal_,
DeviceValueType::ULONG,
{},
nullptr,
F("auxElecHeatNrgConsTotal"),
F("Auxiliary electrical heater energy consumption total"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&auxElecHeatNrgConsHeating_,
DeviceValueType::ULONG,
{},
nullptr,
F("auxElecHeatNrgConsHeating"),
F("Auxiliary electrical heater energy consumption heating"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&auxElecHeatNrgConsDHW_,
DeviceValueType::ULONG,
{},
nullptr,
F("auxElecHeatNrgConsDHW"),
F("Auxiliary electrical heater energy consumption DHW"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&maintenanceMessage_,
DeviceValueType::TEXT,
{},
nullptr,
F("maintenanceMessage"),
F("Maintenance message"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&maintenanceDate_,
DeviceValueType::TEXT,
{},
nullptr,
F("maintenanceDate"),
F("Maintenance set date"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&maintenanceType_,
DeviceValueType::ENUM,
flash_string_vector{F("off"), F("time"), F("date")},
FL_(enum_off_time_date),
F("maintenanceType"),
F("Scheduled maintenance"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_BOILER_DATA_INFO,
&maintenanceTime_,
DeviceValueType::UINT,
{},
nullptr,
F("maintenanceTime"),
F("Maintenance set time"),
DeviceValueUOM::NONE);
@@ -680,11 +711,12 @@ void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram
has_update(telegram->read_value(serviceCodeNumber_, 4));
// at this point do a quick check to see if the hot water or heating is active
uint8_t state = 0;
telegram->read_value(state, 11);
uint8_t state = EMS_VALUE_UINT_NOTSET;
if (telegram->read_value(state, 11)) {
boilerState_ = state & 0x01 ? 0x08 : 0;
boilerState_ |= state & 0x02 ? 0x01 : 0;
boilerState_ |= state & 0x04 ? 0x02 : 0;
}
check_active(); // do a quick check to see if the hot water or heating is active
}
@@ -870,6 +902,9 @@ void Boiler::process_UBAMaintenanceStatus(std::shared_ptr<const Telegram> telegr
// 0x10, 0x11
void Boiler::process_UBAErrorMessage(std::shared_ptr<const Telegram> telegram) {
if (telegram->offset > 0 || telegram->message_length < 9) {
return;
}
// data: displaycode(2), errornumber(2), year, month, hour, day, minute, duration(2), src-addr
if (telegram->message_data[4] & 0x80) { // valid date
@@ -896,6 +931,9 @@ void Boiler::process_UBAErrorMessage(std::shared_ptr<const Telegram> telegram) {
// 0x15
void Boiler::process_UBAMaintenanceData(std::shared_ptr<const Telegram> telegram) {
if (telegram->offset > 0 || telegram->message_length < 5) {
return;
}
// first byte: Maintenance messages (0 = none, 1 = by operating hours, 2 = by date)
telegram->read_value(maintenanceType_, 0);

View File

@@ -19,18 +19,7 @@
#ifndef EMSESP_BOILER_H
#define EMSESP_BOILER_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <uuid/log.h>
#include <string>
#include "emsdevice.h"
#include "telegram.h"
#include "emsesp.h"
#include "helpers.h"
#include "mqtt.h"
namespace emsesp {

View File

@@ -19,15 +19,7 @@
#ifndef EMSESP_CONNECT_H
#define EMSESP_CONNECT_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <uuid/log.h>
#include "emsdevice.h"
#include "telegram.h"
#include "helpers.h"
#include "mqtt.h"
#include "emsesp.h"
namespace emsesp {

View File

@@ -19,15 +19,7 @@
#ifndef EMSESP_CONTROLLER_H
#define EMSESP_CONTROLLER_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <uuid/log.h>
#include "emsdevice.h"
#include "telegram.h"
#include "helpers.h"
#include "mqtt.h"
#include "emsesp.h"
namespace emsesp {

View File

@@ -19,15 +19,7 @@
#ifndef EMSESP_GATEWAY_H
#define EMSESP_GATEWAY_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <uuid/log.h>
#include "emsdevice.h"
#include "telegram.h"
#include "helpers.h"
#include "mqtt.h"
#include "emsesp.h"
namespace emsesp {

View File

@@ -19,15 +19,7 @@
#ifndef EMSESP_GENERIC_H
#define EMSESP_GENERIC_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <uuid/log.h>
#include "emsdevice.h"
#include "telegram.h"
#include "helpers.h"
#include "mqtt.h"
#include "emsesp.h"
namespace emsesp {

View File

@@ -32,8 +32,11 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c
register_telegram_type(0x042B, F("HP1"), true, [&](std::shared_ptr<const Telegram> t) { process_HPMonitor1(t); });
register_telegram_type(0x047B, F("HP2"), true, [&](std::shared_ptr<const Telegram> t) { process_HPMonitor2(t); });
register_device_value(DeviceValueTAG::TAG_NONE, &airHumidity_, DeviceValueType::UINT, flash_string_vector{F("2")}, F("airHumidity"), F("Relative air humidity"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &dewTemperature_, DeviceValueType::UINT, {}, F("dewTemperature"), F("Dew point temperature"), DeviceValueUOM::NONE);
// device values
register_device_value(
DeviceValueTAG::TAG_NONE, &airHumidity_, DeviceValueType::UINT, FL_(div2), F("airHumidity"), F("Relative air humidity"), DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_NONE, &dewTemperature_, DeviceValueType::UINT, nullptr, F("dewTemperature"), F("Dew point temperature"), DeviceValueUOM::NONE);
}
// publish HA config

View File

@@ -19,16 +19,7 @@
#ifndef EMSESP_HEATPUMP_H
#define EMSESP_HEATPUMP_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <uuid/log.h>
#include "emsdevice.h"
#include "emsesp.h"
#include "telegram.h"
#include "helpers.h"
#include "mqtt.h"
namespace emsesp {

View File

@@ -53,6 +53,7 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
register_telegram_type(0x010C, F("IPMSetMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_IPMStatusMessage(t); });
}
}
@@ -74,10 +75,10 @@ void Mixer::register_values(const Type type, uint16_t hc) {
tag = DeviceValueTAG::TAG_WWC1 + hc - 1;
}
register_device_value(tag, &flowTemp_, DeviceValueType::USHORT, flash_string_vector{F("10")}, F("flowTemp"), F("Current flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, {}, F("flowSetTemp"), F("Setpoint flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, {}, F("pumpStatus"), F("Pump/Valve status"), DeviceValueUOM::NONE);
register_device_value(tag, &status_, DeviceValueType::INT, {}, F("status"), F("Current status"), DeviceValueUOM::NONE);
register_device_value(tag, &flowTemp_, DeviceValueType::USHORT, FL_(div10), F("flowTemp"), F("Current flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, nullptr, F("flowSetTemp"), F("Setpoint flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, F("pumpStatus"), F("Pump/Valve status"), DeviceValueUOM::NONE);
register_device_value(tag, &status_, DeviceValueType::INT, nullptr, F("status"), F("Current status"), DeviceValueUOM::NONE);
}

View File

@@ -19,16 +19,7 @@
#ifndef EMSESP_MIXER_H
#define EMSESP_MIXER_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <uuid/log.h>
#include "emsdevice.h"
#include "emsesp.h"
#include "telegram.h"
#include "helpers.h"
#include "mqtt.h"
namespace emsesp {

View File

@@ -60,37 +60,39 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
register_telegram_type(0x0101, F("ISM1Set"), false, [&](std::shared_ptr<const Telegram> t) { process_ISM1Set(t); });
}
// device values...
// special case for a device_id with 0x2A where it's not actual a solar module
if (device_id == 0x2A) {
register_device_value(DeviceValueTAG::TAG_NONE, &type_, DeviceValueType::TEXT, {}, F("type"), F("Type"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &type_, DeviceValueType::TEXT, nullptr, F("type"), F("Type"), DeviceValueUOM::NONE);
strncpy(type_, "warm water circuit", sizeof(type_));
}
register_device_value(DeviceValueTAG::TAG_NONE,
&collectorTemp_,
DeviceValueType::SHORT,
flash_string_vector{F("10")},
FL_(div10),
F("collectorTemp"),
F("Collector temperature (TS1)"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE,
&tankBottomTemp_,
DeviceValueType::SHORT,
flash_string_vector{F("10")},
FL_(div10),
F("tankBottomTemp"),
F("Bottom temperature (TS2)"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE,
&tankBottomTemp2_,
DeviceValueType::SHORT,
flash_string_vector{F("10")},
FL_(div10),
F("tankBottomTemp2"),
F("Bottom temperature (TS5)"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE,
&heatExchangerTemp_,
DeviceValueType::SHORT,
{F("10")},
FL_(div10),
F("heatExchangerTemp"),
F("Heat exchanger temperature (TS6)"),
DeviceValueUOM::DEGREES);
@@ -98,43 +100,37 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
register_device_value(DeviceValueTAG::TAG_NONE,
&tank1MaxTempCurrent_,
DeviceValueType::UINT,
{},
nullptr,
F("tank1MaxTempCurrent"),
F("Maximum Tank temperature"),
DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE,
&solarPumpModulation_,
DeviceValueType::UINT,
{},
nullptr,
F("solarPumpModulation"),
F("Solar pump modulation (PS1)"),
DeviceValueUOM::PERCENT);
register_device_value(
DeviceValueTAG::TAG_NONE, &cylinderPumpModulation_, DeviceValueType::UINT, {}, F("cylinderPumpModulation"), F("Cylinder pump modulation (PS5)"), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_NONE, &solarPump_, DeviceValueType::BOOL, {}, F("solarPump"), F("Solar pump (PS1) active"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &valveStatus_, DeviceValueType::BOOL, {}, F("valveStatus"), F("Valve status"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &tankHeated_, DeviceValueType::BOOL, {}, F("tankHeated"), F("Tank heated"), DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, {}, F("collectorShutdown"), F("Collector shutdown"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &pumpWorkMin_, DeviceValueType::TIME, {}, F("pumpWorkMin"), F("Pump working time"), DeviceValueUOM::MINUTES);
register_device_value(DeviceValueTAG::TAG_NONE,
&energyLastHour_,
DeviceValueType::ULONG,
flash_string_vector{F("10")},
F("energyLastHour"),
F("Energy last hour"),
DeviceValueUOM::WH);
register_device_value(DeviceValueTAG::TAG_NONE,
&energyTotal_,
DeviceValueType::ULONG,
flash_string_vector{F("10")},
F("energyTotal"),
F("Energy total"),
DeviceValueUOM::KWH);
register_device_value(DeviceValueTAG::TAG_NONE, &energyToday_, DeviceValueType::ULONG, {}, F("energyToday"), F("Energy today"), DeviceValueUOM::WH);
&cylinderPumpModulation_,
DeviceValueType::UINT,
nullptr,
F("cylinderPumpModulation"),
F("Cylinder pump modulation (PS5)"),
DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_NONE, &solarPump_, DeviceValueType::BOOL, nullptr, F("solarPump"), F("Solar pump (PS1) active"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &valveStatus_, DeviceValueType::BOOL, nullptr, F("valveStatus"), F("Valve status"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &tankHeated_, DeviceValueType::BOOL, nullptr, F("tankHeated"), F("Tank heated"), DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_NONE, &collectorShutdown_, DeviceValueType::BOOL, nullptr, F("collectorShutdown"), F("Collector shutdown"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &pumpWorkMin_, DeviceValueType::TIME, nullptr, F("pumpWorkMin"), F("Pump working time"), DeviceValueUOM::MINUTES);
register_device_value(
DeviceValueTAG::TAG_NONE, &energyLastHour_, DeviceValueType::ULONG, FL_(div10), F("energyLastHour"), F("Energy last hour"), DeviceValueUOM::WH);
register_device_value(DeviceValueTAG::TAG_NONE, &energyTotal_, DeviceValueType::ULONG, FL_(div10), F("energyTotal"), F("Energy total"), DeviceValueUOM::KWH);
register_device_value(DeviceValueTAG::TAG_NONE, &energyToday_, DeviceValueType::ULONG, nullptr, F("energyToday"), F("Energy today"), DeviceValueUOM::WH);
}
// publish HA config

View File

@@ -19,16 +19,7 @@
#ifndef EMSESP_SOLAR_H
#define EMSESP_SOLAR_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <uuid/log.h>
#include "emsdevice.h"
#include "emsesp.h"
#include "telegram.h"
#include "helpers.h"
#include "mqtt.h"
namespace emsesp {

View File

@@ -34,15 +34,10 @@ Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
register_telegram_type(0x9D, F("WM10SetMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_WM10SetMessage(t); });
register_telegram_type(0x1E, F("WM10TempMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_WM10TempMessage(t); });
register_device_value(DeviceValueTAG::TAG_NONE, &activated_, DeviceValueType::BOOL, {}, F("activated"), F("Activated"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE,
&flowTemp_,
DeviceValueType::USHORT,
flash_string_vector{F("10")},
F("flowTemp"),
F("Current flow temperature"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &status_, DeviceValueType::INT, {}, F("status"), F("Status"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &activated_, DeviceValueType::BOOL, nullptr, F("activated"), F("Activated"), DeviceValueUOM::NONE);
register_device_value(
DeviceValueTAG::TAG_NONE, &flowTemp_, DeviceValueType::USHORT, FL_(div10), F("flowTemp"), F("Current flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &status_, DeviceValueType::INT, nullptr, F("status"), F("Status"), DeviceValueUOM::NONE);
}
// publish HA config

View File

@@ -19,16 +19,7 @@
#ifndef EMSESP_SWITCH_H
#define EMSESP_SWITCH_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <uuid/log.h>
#include "emsdevice.h"
#include "emsesp.h"
#include "telegram.h"
#include "helpers.h"
#include "mqtt.h"
namespace emsesp {

View File

@@ -42,7 +42,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
&& ((actual_master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT) || (device_id < actual_master_thermostat)))) {
EMSESP::actual_master_thermostat(device_id);
actual_master_thermostat = device_id;
reserve_mem(25); // reserve some space for the telegram registries, to avoid memory fragmentation
reserve_telgram_functions(25); // reserve some space for the telegram registries, to avoid memory fragmentation
// common telegram handlers
register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, [&](std::shared_ptr<const Telegram> t) { process_RCOutdoorTemp(t); });
@@ -868,6 +868,10 @@ void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> telegram) {
// exit if the 15th byte (second from last) is 0x00, which I think is calculated flow setpoint temperature
// with weather controlled RC35s this value is >=5, otherwise can be zero and our setpoint temps will be incorrect
// see https://github.com/proddy/EMS-ESP/issues/373#issuecomment-627907301
if (telegram->offset > 0 || telegram->message_length < 15) {
return;
}
if (telegram->message_data[14] == 0x00) {
return;
}
@@ -890,7 +894,7 @@ void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> telegram) {
// type 0x3D (HC1), 0x47 (HC2), 0x51 (HC3), 0x5B (HC4) - Working Mode Heating - for reading the mode from the RC35 thermostat (0x10)
void Thermostat::process_RC35Set(std::shared_ptr<const Telegram> telegram) {
// check to see we have a valid type. heating: 1 radiator, 2 convectors, 3 floors, 4 room supply
if (telegram->message_data[0] == 0x00) {
if (telegram->offset == 0 && telegram->message_data[0] == 0x00) {
return;
}
@@ -935,6 +939,10 @@ void Thermostat::process_RC35Timer(std::shared_ptr<const Telegram> telegram) {
// process_RCTime - type 0x06 - date and time from a thermostat - 14 bytes long
void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
if (telegram->offset > 0 || telegram->message_length < 5) {
return;
}
if (flags() == EMS_DEVICE_FLAG_EASY) {
return; // not supported
}
@@ -975,6 +983,10 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
// 10 00 A2 00 41 32 32 03 30 00 02 00 00 00 00 00 00 02 CRC
// A 2 2 816
void Thermostat::process_RCError(std::shared_ptr<const Telegram> telegram) {
if (telegram->offset > 0 || telegram->message_length < 5) {
return;
}
char buf[4];
buf[0] = telegram->message_data[0];
buf[1] = telegram->message_data[1];
@@ -986,6 +998,10 @@ void Thermostat::process_RCError(std::shared_ptr<const Telegram> telegram) {
// 0x12 error log
void Thermostat::process_RCErrorMessage(std::shared_ptr<const Telegram> telegram) {
if (telegram->offset > 0 || telegram->message_length < 12) {
return;
}
// data: displaycode(2), errornumber(2), year, month, hour, day, minute, duration(2), src-addr
if (telegram->message_data[4] & 0x80) { // valid date
char code[3];
@@ -1011,7 +1027,7 @@ bool Thermostat::set_minexttemp(const char * value, const int8_t id) {
return false;
}
LOG_INFO(F("Setting min external temperature to %d"), mt);
LOG_INFO(F("Setting min external temperature to %d C"), mt);
if ((model() == EMS_DEVICE_FLAG_RC300) || (model() == EMS_DEVICE_FLAG_RC100)) {
write_command(0x240, 10, mt, 0x240);
} else {
@@ -1128,7 +1144,7 @@ bool Thermostat::set_control(const char * value, const int8_t id) {
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr || ctrl > 2) {
if (hc == nullptr) {
return false;
}
@@ -1238,12 +1254,20 @@ bool Thermostat::set_holiday(const char * value, const int8_t id) {
data[0] = (hd[0] - '0') * 10 + (hd[1] - '0');
data[1] = (hd[3] - '0') * 10 + (hd[4] - '0');
data[2] = (hd[7] - '0') * 100 + (hd[8] - '0') * 10 + (hd[9] - '0');
data[3] = (hd[11] - '0') * 10 + (hd[11] - '0');
data[3] = (hd[11] - '0') * 10 + (hd[12] - '0');
data[4] = (hd[14] - '0') * 10 + (hd[15] - '0');
data[5] = (hd[18] - '0') * 100 + (hd[19] - '0') * 10 + (hd[20] - '0');
LOG_INFO(F("Setting holiday for hc %d"), hc->hc_num());
if (hd[10] == '-') {
LOG_INFO(F("Setting holiday away from home for hc %d"), hc->hc_num());
write_command(timer_typeids[hc->hc_num() - 1], 87, data, 6, 0);
} else if (hd[10] == '+') {
LOG_INFO(F("Setting holiday at home for hc %d"), hc->hc_num());
write_command(timer_typeids[hc->hc_num() - 1], 93, data, 6, 0);
} else {
LOG_WARNING(F("Set holiday: Invalid"));
return false;
}
return true;
}
@@ -2004,6 +2028,7 @@ void Thermostat::add_commands() {
register_mqtt_cmd(F("clockoffset"), [&](const char * value, const int8_t id) { return set_clockoffset(value, id); });
register_mqtt_cmd(F("language"), [&](const char * value, const int8_t id) { return set_language(value, id); });
register_mqtt_cmd(F("display"), [&](const char * value, const int8_t id) { return set_display(value, id); });
break;
case EMS_DEVICE_FLAG_RC35: // RC30 and RC35
register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { return set_nighttemp(value, id); });
register_mqtt_cmd(F("daytemp"), [&](const char * value, const int8_t id) { return set_daytemp(value, id); });
@@ -2042,41 +2067,43 @@ 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, {}, F("dateTime"), F("Date/Time"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &errorCode_, DeviceValueType::TEXT, {}, F("errorCode"), F("Error code"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &lastCode_, DeviceValueType::TEXT, {}, F("lastCode"), F("Last error"), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_NONE, &wwTemp_, DeviceValueType::UINT, {}, F("wwTemp"), F("Warm water high temperature"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &wwTempLow_, DeviceValueType::UINT, {}, F("wwTempLow"), F("Warm water low temperature"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &wwExtra1_, DeviceValueType::UINT, {}, F("wwExtra1"), F("Warm water circuit 1 extra"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE, &wwExtra2_, DeviceValueType::UINT, {}, F("wwExtra2"), F("Warm water circuit 2 extra"), 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,
flash_string_vector{F("10")},
FL_(div10),
F("inttemp1"),
F("Temperature sensor 1"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE,
&tempsensor2_,
DeviceValueType::USHORT,
flash_string_vector{F("10")},
FL_(div10),
F("inttemp2"),
F("Temperature sensor 2"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE,
&ibaCalIntTemperature_,
DeviceValueType::INT,
flash_string_vector{F("2")},
FL_(div2),
F("intoffset"),
F("Offset int. temperature"),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE,
&ibaMinExtTemperature_,
DeviceValueType::INT,
{},
nullptr,
F("minexttemp"),
F("Min ext. temperature"),
DeviceValueUOM::DEGREES); // min ext temp for heating curve, in deg.
@@ -2108,7 +2135,7 @@ void Thermostat::register_device_values() {
register_device_value(DeviceValueTAG::TAG_NONE,
&ibaClockOffset_,
DeviceValueType::UINT,
{},
nullptr,
F("ibaClockOffset"),
F("Clock offset"),
DeviceValueUOM::NONE); // offset (in sec) to clock, 0xff=-1s, 0x02=2s
@@ -2126,12 +2153,12 @@ void Thermostat::register_device_values() {
register_device_value(DeviceValueTAG::TAG_NONE,
&dampedoutdoortemp2_,
DeviceValueType::SHORT,
flash_string_vector{F("10")},
FL_(div10),
F("dampedtemp"),
F("Damped outdoor temperature"),
DeviceValueUOM::DEGREES);
register_device_value(
DeviceValueTAG::TAG_NONE, &floordrytemp_, DeviceValueType::UINT, {}, F("floordrytemp"), F("Floor drying temperature"), DeviceValueUOM::DEGREES);
DeviceValueTAG::TAG_NONE, &floordrytemp_, DeviceValueType::UINT,nullptr, F("floordrytemp"), F("Floor drying temperature"), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_NONE,
&ibaBuildingType_,
DeviceValueType::ENUM,
@@ -2160,7 +2187,7 @@ void Thermostat::register_device_values() {
register_device_value(DeviceValueTAG::TAG_NONE,
&dampedoutdoortemp_,
DeviceValueType::SHORT,
{},
nullptr,
F("dampedtemp"),
F("Damped outdoor temperature"),
DeviceValueUOM::DEGREES);
@@ -2186,10 +2213,12 @@ void Thermostat::register_device_values() {
F("Warm water circulation mode"),
DeviceValueUOM::NONE);
}
*/
}
// registers the values for a heating circuit
void Thermostat::register_device_values_hc(std::shared_ptr<emsesp::Thermostat::HeatingCircuit> hc) {
/*
uint8_t model = hc->get_model();
// heating circuit
@@ -2198,14 +2227,14 @@ void Thermostat::register_device_values_hc(std::shared_ptr<emsesp::Thermostat::H
// different logic on how temperature values are stored, depending on model
flash_string_vector setpoint_temp_divider, curr_temp_divider;
if (model == EMS_DEVICE_FLAG_EASY) {
setpoint_temp_divider = flash_string_vector{F("100")};
curr_temp_divider = flash_string_vector{F("100")};
setpoint_temp_divider = FL_(div100);
curr_temp_divider = FL_(div100);
} else if (model == EMS_DEVICE_FLAG_JUNKERS) {
setpoint_temp_divider = flash_string_vector{F("10")};
curr_temp_divider = flash_string_vector{F("10")};
setpoint_temp_divider = FL_(div10);
curr_temp_divider = FL_(div10);
} else {
setpoint_temp_divider = flash_string_vector{F("2")};
curr_temp_divider = flash_string_vector{F("10")};
setpoint_temp_divider = FL_(div2);
curr_temp_divider = FL_(div10);
}
register_device_value(
tag, &hc->setpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, F("seltemp"), F("Setpoint room temperature"), DeviceValueUOM::DEGREES);
@@ -2226,7 +2255,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<emsesp::Thermostat::H
F("HA current room temperature"),
DeviceValueUOM::DEGREES);
} else if (option == Mqtt::HA_Climate_Format::ZERO) {
register_device_value(tag, &zero_value_, DeviceValueType::UINT, {}, F("hatemp"), nullptr, DeviceValueUOM::DEGREES);
register_device_value(tag, &zero_value_, DeviceValueType::UINT,nullptr, F("hatemp"), nullptr, DeviceValueUOM::DEGREES);
}
// if we're sending to HA the only valid mode types are heat, auto and off
@@ -2250,14 +2279,14 @@ void Thermostat::register_device_values_hc(std::shared_ptr<emsesp::Thermostat::H
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, {}, F("summertemp"), F("Summer temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->designtemp, DeviceValueType::UINT, {}, F("designtemp"), F("Design temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->offsettemp, DeviceValueType::INT, {}, F("offsettemp"), F("Offset temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, {}, F("minflowtemp"), F("Min flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, {}, F("maxflowtemp"), F("Max flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, {}, F("roominfluence"), F("Room influence"), DeviceValueUOM::NONE);
register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, {}, F("nofrosttemp"), F("Nofrost temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->targetflowtemp, DeviceValueType::UINT, {}, 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->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,
@@ -2279,7 +2308,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<emsesp::Thermostat::H
F("controlmode"),
F("Control mode"),
DeviceValueUOM::NONE);
register_device_value(tag, &hc->program, DeviceValueType::UINT, {}, 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_RC20) {
@@ -2290,9 +2319,9 @@ void Thermostat::register_device_values_hc(std::shared_ptr<emsesp::Thermostat::H
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->daytemp, DeviceValueType::UINT, flash_string_vector{F("2")}, F("daytemp"), F("Day temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, flash_string_vector{F("2")}, F("nighttemp"), F("Night temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->program, DeviceValueType::UINT, {}, F("program"), F("Program"), 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);
}
if (model == EMS_DEVICE_FLAG_RC35 || model == EMS_DEVICE_FLAG_RC30_1) {
@@ -2300,18 +2329,18 @@ void Thermostat::register_device_values_hc(std::shared_ptr<emsesp::Thermostat::H
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, {}, F("designtemp"), F("Design 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, {}, F("targetflowtemp"), F("Target flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, {}, F("summertemp"), F("Summer temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->summermode, DeviceValueType::BOOL, {}, F("summermode"), F("Summer mode"), DeviceValueUOM::NONE);
register_device_value(tag, &hc->holidaymode, DeviceValueType::BOOL, {}, F("holidaymode"), F("Holiday mode"), DeviceValueUOM::NONE);
register_device_value(tag, &hc->nofrosttemp, DeviceValueType::INT, {}, F("nofrosttemp"), F("Nofrost temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->roominfluence, DeviceValueType::UINT, {}, F("roominfluence"), F("Room influence"), DeviceValueUOM::NONE);
register_device_value(tag, &hc->minflowtemp, DeviceValueType::UINT, {}, F("minflowtemp"), F("Min flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->maxflowtemp, DeviceValueType::UINT, {}, F("maxflowtemp"), F("Max flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->flowtempoffset, DeviceValueType::UINT, {}, F("flowtempoffset"), F("Flow temperature offset"), 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,
@@ -2333,7 +2362,7 @@ void Thermostat::register_device_values_hc(std::shared_ptr<emsesp::Thermostat::H
F("controlmode"),
F("Control mode"),
DeviceValueUOM::NONE);
register_device_value(tag, &hc->program, DeviceValueType::UINT, {}, F("program"), F("Program"), DeviceValueUOM::NONE);
register_device_value(tag, &hc->program, DeviceValueType::UINT,nullptr, F("program"), F("Program"), DeviceValueUOM::NONE);
}
if (model == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
@@ -2346,11 +2375,12 @@ void Thermostat::register_device_values_hc(std::shared_ptr<emsesp::Thermostat::H
F("modetype"),
F("Mode type"),
DeviceValueUOM::NONE);
register_device_value(tag, &hc->daytemp, DeviceValueType::UINT, flash_string_vector{F("2")}, F("heattemp"), F("Heat temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->nighttemp, DeviceValueType::UINT, flash_string_vector{F("2")}, F("ecotemp"), F("Eco temperature"), DeviceValueUOM::DEGREES);
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, flash_string_vector{F("2")}, F("nofrosttemp"), F("Nofrost temperature"), DeviceValueUOM::DEGREES);
tag, &hc->nofrosttemp, DeviceValueType::INT, FL_(div2), F("nofrosttemp"), F("Nofrost temperature"), DeviceValueUOM::DEGREES);
}
*/
}
} // namespace emsesp

View File

@@ -19,19 +19,7 @@
#ifndef EMSESP_THERMOSTAT_H
#define EMSESP_THERMOSTAT_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <uuid/log.h>
#include "emsdevice.h"
#include "telegram.h"
#include "emsesp.h"
#include "helpers.h"
#include "mqtt.h"
#include <vector>
#include <time.h>
namespace emsesp {

View File

@@ -23,7 +23,7 @@ namespace emsesp {
// mapping of UOM, to match order in DeviceValueUOM enum emsdevice.h
// must be an int of 4 bytes, 32bit aligned
static const __FlashStringHelper * DeviceValueUOM_s[] __attribute__((__aligned__(sizeof(int)))) PROGMEM = {
static const __FlashStringHelper * DeviceValueUOM_s[] __attribute__((__aligned__(sizeof(uint32_t)))) PROGMEM = {
F_(degrees),
F_(percent),
@@ -69,10 +69,6 @@ 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::DeviceValue> EMSdevice::devicevalues() const {
return devicevalues_;
}
std::string EMSdevice::brand_to_string() const {
switch (brand_) {
case EMSdevice::Brand::BOSCH:
@@ -264,7 +260,7 @@ 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_) {
if (tf.fetch_) {
read_command(tf.telegram_type_id_);
}
@@ -275,7 +271,7 @@ 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_) {
if (tf.telegram_type_id_ == telegram_id) {
tf.fetch_ = toggle;
}
@@ -284,7 +280,7 @@ 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_) {
if (tf.telegram_type_id_ == telegram_id) {
return tf.fetch_;
}
@@ -292,15 +288,33 @@ bool EMSdevice::get_toggle_fetch(uint16_t telegram_id) {
return false;
}
// list device values
void EMSdevice::show_device_values(uuid::console::Shell & shell) {
size_t total_s = 0;
uint8_t count = 0;
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);
} else {
shell.printfln("[%s]* %d", uuid::read_flash_string(dv.short_name).c_str(), s);
}
total_s += s;
count++;
}
shell.printfln("Total size of %d elements: %d", count, total_s);
shell.println();
}
// 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) {
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_) {
shell.printf(F("0x%02X "), tf.telegram_type_id_);
}
shell.println();
@@ -308,16 +322,17 @@ 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();
strlcpy(result, "", 200);
if (telegram_functions_.size() == 0) {
if (!size) {
return result;
}
char str[10];
uint8_t i = 0;
size_t size = telegram_functions_.size();
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) {
@@ -339,12 +354,26 @@ void EMSdevice::register_mqtt_topic(const std::string & topic, mqtt_subfunction_
// add command to library
void EMSdevice::register_mqtt_cmd(const __FlashStringHelper * cmd, cmdfunction_p f) {
Command::add(device_type_, device_id_, cmd, f);
Command::add(device_type_, cmd, f);
}
// 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) {
telegram_functions_.emplace_back(telegram_type_id, telegram_type_name, fetch, 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);
}
// add to device value library
@@ -360,11 +389,10 @@ void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const __
void EMSdevice::register_device_value(uint8_t tag,
void * value_p,
uint8_t type,
const flash_string_vector & options,
const __FlashStringHelper * const * options,
const __FlashStringHelper * short_name,
const __FlashStringHelper * full_name,
uint8_t uom,
const __FlashStringHelper * icon) {
uint8_t uom) {
// init the value depending on it's type
if (type == DeviceValueType::TEXT) {
*(char *)(value_p) = {'\0'};
@@ -382,7 +410,26 @@ void EMSdevice::register_device_value(uint8_t tag,
}
// add to our library
devicevalues_.emplace_back(device_type_, tag, value_p, type, options, short_name, full_name, uom, icon);
DeviceValue dv;
dv.device_type = device_type_;
dv.tag = tag;
dv.value_p = value_p;
dv.type = type;
dv.short_name = short_name;
dv.full_name = full_name;
dv.uom = uom;
dv.options = options;
dv.options_size = 0;
// count #options
if (options != nullptr) {
uint8_t i = 0;
while (options[i++]) {
dv.options_size++;
};
}
devicevalues_->push(dv);
}
// looks up the uom (suffix) for a given key from the device value table
@@ -397,7 +444,10 @@ std::string EMSdevice::get_value_uom(const char * key) {
p++;
}
for (const auto & dv : devicevalues_) {
// 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++) {
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
@@ -419,13 +469,16 @@ 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
if (dv.full_name != nullptr) {
// 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) {
data.add(*(uint8_t *)(dv.value_p) ? dv.options[0] : dv.options[1]);
} else {
// see how to render the value depending on the setting
@@ -449,7 +502,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)]);
}
}
@@ -459,7 +512,7 @@ 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;
// INT
if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) {
@@ -536,7 +589,9 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
uint8_t old_tag = 255;
JsonObject json = root;
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)) {
bool have_tag = ((dv.tag != DeviceValueTAG::TAG_NONE) && (dv.device_type != DeviceType::BOILER));
@@ -561,7 +616,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;
} else {
@@ -590,7 +645,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;
}
@@ -601,7 +656,7 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
// 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;
// INT
if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) {
@@ -658,6 +713,17 @@ bool EMSdevice::generate_values_json(JsonObject & root, const uint8_t tag_filter
return has_value;
}
// create the Home Assistant configs for each value as a sensor
void EMSdevice::publish_mqtt_ha_sensor() {
for (const auto & dv : *devicevalues_) {
Mqtt::register_mqtt_ha_sensor(dv.type, dv.tag, dv.full_name, device_type_, dv.short_name, dv.uom);
}
// publish it
bool ok = publish_ha_config();
ha_config_done(ok); // see if it worked
}
// return the name of the telegram type
std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram> telegram) {
// see if it's one of the common ones, like Version
@@ -667,7 +733,7 @@ std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram> 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_);
}
@@ -679,7 +745,7 @@ std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram> telegr
// take a telegram_type_id and call the matching handler
// return true if match found
bool EMSdevice::handle_telegram(std::shared_ptr<const Telegram> 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
@@ -689,7 +755,10 @@ bool EMSdevice::handle_telegram(std::shared_ptr<const Telegram> telegram) {
return false;
}
if (telegram->message_length > 0) {
tf.process_function_(telegram);
}
return true;
}
}

View File

@@ -23,6 +23,7 @@
#include <vector>
#include <functional>
#include "containers.h"
#include "emsfactory.h"
#include "telegram.h"
#include "mqtt.h"
@@ -212,10 +213,13 @@ class EMSdevice {
std::string to_string_short() const;
void show_telegram_handlers(uuid::console::Shell & shell);
void show_device_values(uuid::console::Shell & shell);
char * show_telegram_handlers(char * result);
void show_mqtt_handlers(uuid::console::Shell & shell);
using process_function_p = std::function<void(std::shared_ptr<const Telegram>)>;
// using process_function_p = void (*)(std::shared_ptr<const Telegram>);
void register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p cb);
bool handle_telegram(std::shared_ptr<const Telegram> telegram);
@@ -226,11 +230,10 @@ class EMSdevice {
void register_device_value(uint8_t tag,
void * value_p,
uint8_t type,
const flash_string_vector & options,
const __FlashStringHelper * const * options,
const __FlashStringHelper * short_name,
const __FlashStringHelper * full_name,
uint8_t uom,
const __FlashStringHelper * icon = nullptr);
uint8_t uom);
void write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid);
void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid);
@@ -240,16 +243,14 @@ class EMSdevice {
void register_mqtt_topic(const std::string & topic, mqtt_subfunction_p f);
void register_mqtt_cmd(const __FlashStringHelper * cmd, cmdfunction_p f);
void publish_mqtt_ha_sensor();
std::string telegram_type_name(std::shared_ptr<const Telegram> telegram);
void fetch_values();
void toggle_fetch(uint16_t telegram_id, bool toggle);
bool get_toggle_fetch(uint16_t telegram_id);
void reserve_mem(size_t n) {
telegram_functions_.reserve(n);
}
bool ha_config_done() const {
return ha_config_done_;
}
@@ -318,41 +319,14 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICE_FLAG_RC100 = 9;
static constexpr uint8_t EMS_DEVICE_FLAG_JUNKERS = 10;
struct DeviceValue {
uint8_t device_type; // EMSdevice::DeviceType
uint8_t tag; // DeviceValueTAG::*
void * value_p; // pointer to variable of any type
uint8_t type; // DeviceValueType::*
const flash_string_vector options; // list of options for ENUM, or divider
const __FlashStringHelper * short_name; // used in MQTT
const __FlashStringHelper * full_name; // used in Web and Console
uint8_t uom; // DeviceValueUOM::*
const __FlashStringHelper * icon; // HA icon
DeviceValue(uint8_t device_type,
uint8_t tag,
void * value_p,
uint8_t type,
const flash_string_vector options,
const __FlashStringHelper * short_name,
const __FlashStringHelper * full_name,
uint8_t uom,
const __FlashStringHelper * icon)
: device_type(device_type)
, tag(tag)
, value_p(value_p)
, type(type)
, options(options)
, short_name(short_name)
, full_name(full_name)
, uom(uom)
, icon(icon) {
void reserve_device_values(uint8_t elements) {
static auto dv_ = emsesp::array<DeviceValue>(elements, 255, 16);
devicevalues_ = &dv_;
}
};
const std::vector<DeviceValue> devicevalues() const;
void init_devicevalues(uint8_t size) {
devicevalues_.reserve(size);
void reserve_telgram_functions(uint8_t elements) {
static auto tf_ = emsesp::array<TelegramFunction>(elements, 255, 16);
telegram_functions_ = &tf_;
}
private:
@@ -373,17 +347,21 @@ 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) {
}
};
std::vector<TelegramFunction> telegram_functions_; // each EMS device has its own set of registered telegram types
emsesp::array<TelegramFunction> * telegram_functions_; // each EMS device has its own set of registered telegram types
std::vector<DeviceValue> devicevalues_;
struct DeviceValue {
uint8_t device_type; // EMSdevice::DeviceType
uint8_t tag; // DeviceValueTAG::*
void * value_p; // pointer to variable of any type
uint8_t type; // DeviceValueType::*
const __FlashStringHelper * const * options; // options as a flash char array
uint8_t options_size; // # options in the char array, calculated
const __FlashStringHelper * short_name; // used in MQTT
const __FlashStringHelper * full_name; // used in Web and Console
uint8_t uom; // DeviceValueUOM::*
};
emsesp::array<DeviceValue> * devicevalues_;
};
} // namespace emsesp

View File

@@ -20,6 +20,12 @@
namespace emsesp {
#if defined(EMSESP_STANDALONE)
uint32_t heap_start = 0;
#else
uint32_t heap_start = ESP.getFreeHeap(); // get initial available heap memory
#endif
AsyncWebServer webServer(80);
#if defined(ESP32)
@@ -38,10 +44,11 @@ WebStatusService EMSESP::webStatusService = WebStatusService(&webServer, EMSES
WebDevicesService EMSESP::webDevicesService = WebDevicesService(&webServer, EMSESP::esp8266React.getSecurityManager());
WebAPIService EMSESP::webAPIService = WebAPIService(&webServer);
using DeviceFlags = emsesp::EMSdevice;
using DeviceType = emsesp::EMSdevice::DeviceType;
using DeviceFlags = EMSdevice;
using DeviceType = EMSdevice::DeviceType;
std::vector<std::unique_ptr<EMSdevice>> EMSESP::emsdevices; // array of all the detected EMS devices
std::vector<emsesp::EMSESP::Device_record> EMSESP::device_library_; // library of all our known EMS devices so far
std::vector<emsesp::EMSESP::Device_record> EMSESP::device_library_; // library of all our known EMS devices, in heap
uuid::log::Logger EMSESP::logger_{F_(emsesp), uuid::log::Facility::KERN};
@@ -410,16 +417,7 @@ void EMSESP::publish_device_values(uint8_t device_type) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
// if we're using HA and it's not already done, send the config topics first. only do this once
if (Mqtt::ha_enabled() && (!emsdevice->ha_config_done())) {
// create the configs for each value as a sensor
for (const auto & dv : emsdevice->devicevalues()) {
if (dv.device_type == device_type) {
Mqtt::register_mqtt_ha_sensor(dv.type, dv.tag, dv.full_name, device_type, dv.short_name, dv.uom, dv.icon);
}
}
// create HA device
// if this is done early, it may fail for some reason
emsdevice->ha_config_done(emsdevice->publish_ha_config());
emsdevice->publish_mqtt_ha_sensor(); // create the configs for each value as a sensor
}
// if its a boiler, generate json for each group and publish it
@@ -771,26 +769,14 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
}
shell.println();
emsdevice->show_telegram_handlers(shell);
// emsdevice->show_mqtt_handlers(shell);
shell.println();
#if defined(EMSESP_DEBUG)
// TODO debug stuff - count size of objects
size_t total_s = 0;
uint8_t count = 0;
for (const auto & dv : emsdevice->devicevalues()) {
size_t s = sizeof(dv);
if (dv.full_name) {
shell.printfln("[%s] %d", uuid::read_flash_string(dv.full_name).c_str(), s);
} else {
shell.printfln("[%s]* %d", uuid::read_flash_string(dv.short_name).c_str(), s);
}
total_s += s;
count++;
}
shell.printfln("Total size of %d elements: %d", count, total_s);
#if defined EMSESP_DEBUG
emsdevice->show_mqtt_handlers(shell);
shell.println();
emsdevice->show_device_values(shell);
#endif
shell.println();
}
}
}
@@ -1039,8 +1025,7 @@ void EMSESP::send_raw_telegram(const char * data) {
// start all the core services
// the services must be loaded in the correct order
void EMSESP::start() {
// see if we need to migrate from previous versions
if (!system_.check_upgrade()) {
// start the file system. We use LittleFS for ESP8266.
#ifdef ESP32
SPIFFS.begin(true);
#elif defined(ESP8266)
@@ -1049,23 +1034,46 @@ void EMSESP::start() {
esp8266React.begin(); // loads system settings (wifi, mqtt, etc)
webSettingsService.begin(); // load EMS-ESP specific settings
}
// Load our library of known devices into stack mem. Names are stored in Flash mem.
// device_library_.reserve(80);
system_.check_upgrade(); // do any upgrades
#if defined(EMSESP_DEBUG)
#ifndef EMSESP_STANDALONE
uint32_t tbefore = ESP.getFreeHeap();
#endif
#endif
// Load our library of known devices into stack mem. Names are stored in Flash memory
// Still it takes up about 960bytes
device_library_.reserve(80);
device_library_ = {
#include "device_library.h"
};
#if defined(EMSESP_DEBUG)
#ifndef EMSESP_STANDALONE
uint32_t tafter = ESP.getFreeHeap();
#endif
#endif
console_.start(); // telnet and serial console
mqtt_.start(); // mqtt init
system_.start(); // starts syslog, uart, sets version, initializes LED. Requires pre-loaded settings.
system_.start(heap_start); // starts syslog, uart, sets version, initializes LED. Requires pre-loaded settings.
shower_.start(); // initialize shower timer and shower alert
dallassensor_.start(); // dallas external sensors
webServer.begin(); // start web server
emsdevices.reserve(5); // reserve space for initially 5 devices to avoid mem frag issues
// emsdevices.reserve(5); // reserve space for initially 5 devices to avoid mem frag issues
LOG_INFO(F("EMS Device library loaded with %d records"), device_library_.size());
#if defined(EMSESP_DEBUG)
#ifndef EMSESP_STANDALONE
LOG_INFO(F("Used %d mem for devices"), tbefore - tafter);
System::show_mem("after start()");
#endif
#endif
}
// main loop calling all services

View File

@@ -22,9 +22,10 @@
#include <Arduino.h>
#include <vector>
#include <queue>
#include <string>
#include <ArduinoJson.h>
#include <uuid/common.h>
#include <uuid/console.h>
#include <uuid/log.h>
@@ -39,6 +40,7 @@
#include "WebSettingsService.h"
#include "WebAPIService.h"
#include "containers.h"
#include "emsdevice.h"
#include "emsfactory.h"
#include "telegram.h"

View File

@@ -355,8 +355,9 @@ double Helpers::round2(double value, const uint8_t divider) {
return (int)((value / divider) * 100 + 0.5) / 100.0;
}
bool Helpers::check_abs(const int32_t i) {
return ((i < 0 ? -i : i) != 0xFFFFFF);
// abs of a signed 32-bit integer
uint32_t Helpers::abs(const int32_t i) {
return (i < 0 ? -i : i);
}
// for booleans, use isBool true (EMS_VALUE_BOOL)
@@ -467,6 +468,4 @@ bool Helpers::value2enum(const char * v, uint8_t & value, const flash_string_vec
}
} // namespace emsesp

View File

@@ -51,6 +51,7 @@ class Helpers {
static uint32_t hextoint(const char * hex);
static uint16_t atoint(const char * value);
static bool check_abs(const int32_t i);
static uint32_t abs(const int32_t i);
static double round2(double value, const uint8_t divider);
static std::string toLower(std::string const & s);

View File

@@ -16,6 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
// common words
MAKE_PSTR_WORD(exit)
MAKE_PSTR_WORD(help)
@@ -125,3 +127,38 @@ MAKE_PSTR(new_password_prompt1, "Enter new password: ")
MAKE_PSTR(new_password_prompt2, "Retype new password: ")
MAKE_PSTR(password_prompt, "Password: ")
MAKE_PSTR(unset, "<unset>")
MAKE_PSTR_WORD(2);
MAKE_PSTR_WORD(10);
MAKE_PSTR_WORD(100);
MAKE_PSTR_WORD(60);
MAKE_PSTR_LIST(div2, F_(2))
MAKE_PSTR_LIST(div10, F_(10))
MAKE_PSTR_LIST(div100, F_(100))
MAKE_PSTR_LIST(div60, F_(60))
MAKE_PSTR_WORD(time)
MAKE_PSTR_WORD(date)
MAKE_PSTR_WORD(1x3min)
MAKE_PSTR_WORD(2x3min)
MAKE_PSTR_WORD(3x3min)
MAKE_PSTR_WORD(4x3min)
MAKE_PSTR_WORD(5x3min)
MAKE_PSTR_WORD(6x3min)
MAKE_PSTR_WORD(continuos);
MAKE_PSTR(3wayvalve, "3-way valve")
MAKE_PSTR(chargepump, "charge pump")
MAKE_PSTR_WORD(hot)
MAKE_PSTR_WORD(eco)
MAKE_PSTR_WORD(intelligent)
MAKE_PSTR_WORD(flow)
MAKE_PSTR_WORD(buffer)
MAKE_PSTR(bufferedflow, "buffered flow")
MAKE_PSTR(layeredbuffer, "layered buffer")
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))

View File

@@ -24,6 +24,7 @@ namespace emsesp {
AsyncMqttClient * Mqtt::mqttClient_;
// static parameters we make global
std::string Mqtt::hostname_;
uint8_t Mqtt::mqtt_qos_;
@@ -39,6 +40,8 @@ uint8_t Mqtt::dallas_format_;
uint8_t Mqtt::ha_climate_format_;
bool Mqtt::ha_enabled_;
static emsesp::queue<Mqtt::QueuedMqttMessage> mqtt_messages_ = emsesp::queue<Mqtt::QueuedMqttMessage>(MAX_MQTT_MESSAGES);
std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
uint16_t Mqtt::mqtt_publish_fails_ = 0;
@@ -46,7 +49,6 @@ bool Mqtt::connecting_ = false;
bool Mqtt::initialized_ = false;
uint8_t Mqtt::connectcount_ = 0;
uint16_t Mqtt::mqtt_message_id_ = 0;
std::list<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_;
char will_topic_[Mqtt::MQTT_TOPIC_MAX_SIZE]; // because MQTT library keeps only char pointer
uuid::log::Logger Mqtt::logger_{F_(mqtt), uuid::log::Facility::DAEMON};
@@ -506,17 +508,17 @@ void Mqtt::ha_status() {
doc["uniq_id"] = FJSON("status");
doc["~"] = System::hostname(); // default ems-esp
// doc["avty_t"] = FJSON("~/status");
// doc["avty_t"] = FJSON("~/status"); // commented out, as it causes errors in HA sometimes
doc["json_attr_t"] = FJSON("~/heartbeat");
doc["stat_t"] = FJSON("~/heartbeat");
doc["name"] = FJSON("EMS-ESP status");
doc["val_tpl"] = FJSON("{{value_json['status']}}");
JsonObject dev = doc.createNestedObject("dev");
dev["name"] = FJSON("EMS-ESP");
dev["name"] = F_(EMSESP); // "EMS-ESP"
dev["sw"] = EMSESP_APP_VERSION;
dev["mf"] = FJSON("proddy");
dev["mdl"] = FJSON("EMS-ESP");
dev["mdl"] = F_(EMSESP); // "EMS-ESP"
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp");
@@ -545,11 +547,12 @@ std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation,
message = std::make_shared<MqttMessage>(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
}
@@ -706,7 +709,8 @@ void Mqtt::process_queue() {
mqtt_messages_.pop_front(); // delete
return;
} else {
mqtt_messages_.front().retry_count_++;
// update the record
mqtt_messages_.front_p()->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
}
@@ -715,7 +719,7 @@ 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().packet_id_ = packet_id;
mqtt_messages_.front_p()->packet_id_ = packet_id;
#if defined(EMSESP_DEBUG)
LOG_DEBUG(F("[DEBUG] Setting packetID for ACK to %d"), packet_id);
#endif
@@ -733,15 +737,13 @@ void Mqtt::register_mqtt_ha_sensor(uint8_t type, // device v
const __FlashStringHelper * name,
const uint8_t device_type,
const __FlashStringHelper * entity,
const uint8_t uom,
const __FlashStringHelper * icon) {
const uint8_t uom) {
// ignore if name (fullname) is empty
if (name == nullptr) {
return;
}
// DynamicJsonDocument doc(EMSESP_JSON_SIZE_HA_CONFIG);
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc; // TODO see if this crashes ESP8266?
DynamicJsonDocument doc(EMSESP_JSON_SIZE_HA_CONFIG);
bool have_prefix = ((tag != DeviceValueTAG::TAG_NONE) && (device_type != EMSdevice::DeviceType::BOILER));
@@ -791,7 +793,7 @@ void Mqtt::register_mqtt_ha_sensor(uint8_t type, // device v
// look at the device value type
if (type != DeviceValueType::BOOL) {
//
// normal HA sensor
// normal HA sensor, not a boolean one
//
// topic
@@ -807,8 +809,7 @@ void Mqtt::register_mqtt_ha_sensor(uint8_t type, // device v
doc["unit_of_meas"] = EMSdevice::uom_to_string(uom);
}
// if there was no icon supplied, resort to the default one
if (icon == nullptr) {
// map the HA icon
switch (uom) {
case DeviceValueUOM::DEGREES:
doc["ic"] = F_(icontemperature);
@@ -820,9 +821,6 @@ void Mqtt::register_mqtt_ha_sensor(uint8_t type, // device v
default:
break;
}
} else {
doc["ic"] = icon; // must be prefixed with mdi:
}
} else {
//
// binary sensor

View File

@@ -38,8 +38,18 @@
using uuid::console::Shell;
// time between HA publishes
#define MQTT_HA_PUBLISH_DELAY 50
// size of queue
#if defined(EMSESP_STANDALONE)
#define MAX_MQTT_MESSAGES 70
#elif defined(ESP32)
#define MAX_MQTT_MESSAGES 100
#else
#define MAX_MQTT_MESSAGES 20
#endif
namespace emsesp {
using mqtt_subfunction_p = std::function<bool(const char * message)>;
@@ -103,8 +113,7 @@ class Mqtt {
const __FlashStringHelper * name,
const uint8_t device_type,
const __FlashStringHelper * entity,
const uint8_t uom,
const __FlashStringHelper * icon);
const uint8_t uom);
static void register_command(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb);
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);
@@ -174,37 +183,19 @@ class Mqtt {
mqtt_retain_ = mqtt_retain;
}
struct QueuedMqttMessage {
uint16_t id_;
std::shared_ptr<const MqttMessage> content_;
uint8_t retry_count_;
uint16_t packet_id_;
};
private:
static uuid::log::Logger logger_;
class QueuedMqttMessage {
public:
const uint16_t id_;
const std::shared_ptr<const MqttMessage> content_;
uint8_t retry_count_;
uint16_t packet_id_;
~QueuedMqttMessage() = default;
QueuedMqttMessage(uint16_t id, std::shared_ptr<MqttMessage> && content)
: id_(id)
, content_(std::move(content)) {
retry_count_ = 0;
packet_id_ = 0;
}
};
static std::list<QueuedMqttMessage> mqtt_messages_;
static AsyncMqttClient * mqttClient_;
static uint16_t mqtt_message_id_;
#if defined(EMSESP_STANDALONE)
static constexpr size_t MAX_MQTT_MESSAGES = 70; // size of queue
#elif defined(ESP32)
static constexpr size_t MAX_MQTT_MESSAGES = 100; // size of queue
#else
static constexpr size_t MAX_MQTT_MESSAGES = 20; // size of queue
#endif
static constexpr uint32_t MQTT_PUBLISH_WAIT = 200; // delay between sending publishes, to account for large payloads
static constexpr uint8_t MQTT_PUBLISH_MAX_RETRY = 3; // max retries for giving up on publishing
@@ -261,7 +252,7 @@ class Mqtt {
static uint8_t dallas_format_;
static uint8_t ha_climate_format_;
static bool ha_enabled_;
};
}; // namespace emsesp
} // namespace emsesp

View File

@@ -19,17 +19,8 @@
#ifndef EMSESP_SHOWER_H
#define EMSESP_SHOWER_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include "helpers.h"
#include "console.h"
#include "mqtt.h"
#include "telegram.h"
#include "emsesp.h"
#include <uuid/log.h>
namespace emsesp {
class Shower {

View File

@@ -130,17 +130,6 @@ void System::format(uuid::console::Shell & shell) {
System::restart();
}
// return free heap mem as a percentage
uint8_t System::free_mem() {
#ifndef EMSESP_STANDALONE
uint32_t free_memory = ESP.getFreeHeap();
#else
uint32_t free_memory = 1000;
#endif
return (100 * free_memory / heap_start_);
}
void System::syslog_init() {
int8_t syslog_level_;
uint32_t syslog_mark_interval_;
@@ -182,14 +171,10 @@ void System::syslog_init() {
}
// first call. Sets memory and starts up the UART Serial bridge
void System::start() {
// set the inital free mem
void System::start(uint32_t heap_start) {
// set the inital free mem, only on first boot
if (heap_start_ < 2) {
#ifndef EMSESP_STANDALONE
heap_start_ = ESP.getFreeHeap();
#else
heap_start_ = 2000;
#endif
heap_start_ = heap_start;
}
#if defined(EMSESP_DEBUG)
@@ -202,15 +187,15 @@ void System::start() {
// these commands respond to the topic "system" and take a payload like {cmd:"", data:"", id:""}
EMSESP::webSettingsService.read([&](WebSettings & settings) {
Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F_(pin), System::command_pin);
Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F_(send), System::command_send);
Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F_(publish), System::command_publish);
Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F_(fetch), System::command_fetch);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(pin), System::command_pin);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(publish), System::command_publish);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch);
Command::add_with_json(EMSdevice::DeviceType::SYSTEM, F_(info), System::command_info);
Command::add_with_json(EMSdevice::DeviceType::SYSTEM, F_(settings), System::command_settings);
#if defined(EMSESP_TEST)
Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F_(test), System::command_test);
Command::add(EMSdevice::DeviceType::SYSTEM, F_(test), System::command_test);
#endif
});
@@ -308,13 +293,12 @@ void System::show_mem(const char * note) {
static uint8_t old_heap_frag = 0;
uint32_t free_heap = ESP.getFreeHeap();
uint8_t heap_frag = ESP.getHeapFragmentation();
LOG_INFO(F("(%s) Free heap: %d%% (%lu) (~%lu), frag:%d%% (~%d)"),
LOG_INFO(F("(%s) Free heap: %lu (~%lu), frag:%d%% (~%d)"),
note,
free_mem(),
free_heap,
(uint32_t)abs(free_heap - old_free_heap),
(uint32_t)Helpers::abs(free_heap - old_free_heap),
heap_frag,
(uint8_t)abs(heap_frag - old_heap_frag));
(uint8_t)Helpers::abs(heap_frag - old_heap_frag));
old_free_heap = free_heap;
old_heap_frag = heap_frag;
#endif
@@ -329,8 +313,6 @@ void System::send_heartbeat() {
return;
}
uint32_t free_memory = free_mem();
#if defined(ESP8266)
uint8_t frag_memory = ESP.getHeapFragmentation();
#endif
@@ -352,8 +334,8 @@ void System::send_heartbeat() {
doc["mqttfails"] = Mqtt::publish_fails();
doc["txfails"] = EMSESP::txservice_.telegram_fail_count();
doc["rxfails"] = EMSESP::rxservice_.telegram_error_count();
doc["freemem"] = free_memory;
#if defined(ESP8266)
doc["freemem"] = ESP.getFreeHeap();
doc["fragmem"] = frag_memory;
#endif
if (analog_enabled_) {
@@ -508,12 +490,11 @@ void System::show_system(uuid::console::Shell & shell) {
shell.printfln(F("CPU frequency: %u MHz"), ESP.getCpuFreqMHz());
#endif
shell.printfln(F("Sketch size: %u bytes (%u bytes free)"), ESP.getSketchSize(), ESP.getFreeSketchSpace());
shell.printfln(F("Free heap: %lu bytes"), (unsigned long)ESP.getFreeHeap());
shell.printfln(F("Free mem: %d %%"), free_mem());
shell.printfln(F("Free heap: %lu bytes"), (uint32_t)ESP.getFreeHeap());
#if defined(ESP8266)
shell.printfln(F("Heap fragmentation: %u %%"), ESP.getHeapFragmentation());
shell.printfln(F("Maximum free block size: %lu bytes"), (unsigned long)ESP.getMaxFreeBlockSize());
shell.printfln(F("Free continuations stack: %lu bytes"), (unsigned long)ESP.getFreeContStack());
shell.printfln(F("Maximum free block size: %lu bytes"), (uint32_t)ESP.getMaxFreeBlockSize());
shell.printfln(F("Free continuations stack: %lu bytes"), (uint32_t)ESP.getFreeContStack());
#endif
shell.println();
@@ -734,10 +715,10 @@ void System::console_commands(Shell & shell, unsigned int context) {
Console::enter_custom_context(shell, context);
}
// upgrade from previous versions of EMS-ESP, based on SPIFFS on an ESP8266
// upgrade from previous versions of EMS-ESP
// returns true if an upgrade was done
// the logic is bit abnormal (loading both filesystems and testing) but this was the only way I could get it to work reliably
bool System::check_upgrade() {
/*
#if defined(ESP8266)
LittleFSConfig l_cfg;
l_cfg.setAutoFormat(false);
@@ -923,6 +904,8 @@ bool System::check_upgrade() {
#else
return false;
#endif
*/
return false;
}
// export all settings to JSON text
@@ -1033,8 +1016,8 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & json
node["version"] = EMSESP_APP_VERSION;
node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3);
node["freemem"] = free_mem();
#if defined(ESP8266)
node["freemem"] = ESP.getFreeHeap();
node["fragmem"] = ESP.getHeapFragmentation();
#endif

View File

@@ -39,7 +39,7 @@ namespace emsesp {
class System {
public:
void start();
void start(uint32_t heap_start);
void loop();
// commands
@@ -59,7 +59,6 @@ class System {
static bool command_test(const char * value, const int8_t id);
#endif
static uint8_t free_mem();
static void upload_status(bool in_progress);
static bool upload_status();
static void show_mem(const char * note);

View File

@@ -127,10 +127,10 @@ 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_.front().telegram_;
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
// rx_telegrams_.pop_front(); // remove it from the queue
}
}
@@ -217,25 +217,10 @@ 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<Telegram>(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
}
//
// Tx CODE starts here...
//
// empty queue, don't process
void TxService::flush_tx_queue() {
tx_telegrams_.clear();
tx_telegram_id_ = 0;
QueuedRxTelegram qrxt;
qrxt.telegram_ = std::make_shared<Telegram>(operation, src, dest, type_id, offset, message_data, message_length);
qrxt.id_ = rx_telegram_id_++;
rx_telegrams_.push(qrxt);
}
// start and initialize Tx
@@ -279,13 +264,13 @@ void TxService::send() {
return;
}
// get the Telegram, also removes from queue
auto telegram = tx_telegrams_.pop();
// if we're in read-only mode (tx_mode 0) forget the Tx call
if (tx_mode() != 0) {
send_telegram(tx_telegrams_.front());
send_telegram(telegram);
}
tx_telegrams_.pop_front(); // remove the telegram from the queue
}
// process a Tx telegram
@@ -411,21 +396,19 @@ void TxService::add(const uint8_t operation,
uint8_t * message_data,
const uint8_t message_length,
const bool front) {
auto telegram = std::make_shared<Telegram>(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();
}
QueuedTxTelegram qtxt;
qtxt.id_ = tx_telegram_id_++;
qtxt.retry_ = false;
qtxt.telegram_ = std::make_shared<Telegram>(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length);
if (front) {
tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false); // add to back of queue
tx_telegrams_.push_front(qtxt); // add to front of queue
} else {
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // add to back of queue
tx_telegrams_.push_back(qtxt); // add to back of queue
}
}
@@ -484,21 +467,19 @@ 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<Telegram>(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<Telegram>(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length);
if (front) {
tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false); // add to back of queue
tx_telegrams_.push_front(qtxt); // add to front of queue
} else {
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // add to back of queue
tx_telegrams_.push_back(qtxt); // add to back of queue
}
}
@@ -548,7 +529,7 @@ void TxService::send_raw(const char * telegram_data) {
return; // nothing to send
}
add(Telegram::Operation::TX_RAW, data, count + 1, true); // add to front of Tx queue
add(Telegram::Operation::TX_RAW, data, count + 1, true); // add to top/front of Tx queue
}
// add last Tx to tx queue and increment count
@@ -573,16 +554,15 @@ 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() {
// add to the top of the queue
// add to the top/front of the queue
uint8_t message_data[1] = {EMS_MAX_TELEGRAM_LENGTH}; // request all data, 32 bytes
add(Telegram::Operation::TX_READ, telegram_last_->dest, telegram_last_->type_id, telegram_last_->offset + 25, message_data, 1, true);
return telegram_last_->type_id;
@@ -607,7 +587,7 @@ uint16_t TxService::post_send_query() {
// when set a value with large offset before and validate on same type, we have to add offset 0, 26, 52, ...
uint8_t offset = (this->telegram_last_->type_id == post_typeid) ? ((this->telegram_last_->offset / 26) * 26) : 0;
uint8_t message_data[1] = {EMS_MAX_TELEGRAM_LENGTH}; // request all data, 32 bytes
this->add(Telegram::Operation::TX_READ, dest, post_typeid, offset, message_data, 1, true);
this->add(Telegram::Operation::TX_READ, dest, post_typeid, offset, message_data, 1, true); // add to top/front of queue
// read_request(telegram_last_post_send_query_, dest, 0); // no offset
LOG_DEBUG(F("Sending post validate read, type ID 0x%02X to dest 0x%02X"), post_typeid, dest);
set_post_send_query(0); // reset

View File

@@ -20,7 +20,6 @@
#define EMSESP_TELEGRAM_H
#include <string>
#include <list>
// UART drivers
#if defined(ESP8266)
@@ -33,8 +32,12 @@
#include <uuid/log.h>
#include "containers.h"
#include "helpers.h"
#define MAX_RX_TELEGRAMS 10 // size of Rx queue
#define MAX_TX_TELEGRAMS 30 // size of Tx queue
// default values for null values
static constexpr uint8_t EMS_VALUE_BOOL = 0xFF; // used to mark that something is a boolean
static constexpr uint8_t EMS_VALUE_BOOL_OFF = 0x00; // boolean false
@@ -200,8 +203,6 @@ class EMSbus {
};
class RxService : public EMSbus {
static constexpr size_t MAX_RX_TELEGRAMS = 10;
public:
RxService() = default;
~RxService() = default;
@@ -229,19 +230,12 @@ class RxService : public EMSbus {
return (q <= EMS_BUS_QUALITY_RX_THRESHOLD ? 100 : 100 - q);
}
class QueuedRxTelegram {
public:
const uint16_t id_;
const std::shared_ptr<const Telegram> telegram_;
~QueuedRxTelegram() = default;
QueuedRxTelegram(uint16_t id, std::shared_ptr<Telegram> && telegram)
: id_(id)
, telegram_(std::move(telegram)) {
}
struct QueuedRxTelegram {
uint16_t id_;
std::shared_ptr<const Telegram> telegram_;
};
const std::list<QueuedRxTelegram> queue() const {
const emsesp::queue<QueuedRxTelegram> queue() const {
return rx_telegrams_;
}
@@ -252,12 +246,11 @@ class RxService : public EMSbus {
uint32_t telegram_count_ = 0; // # Rx received
uint32_t telegram_error_count_ = 0; // # Rx CRC errors
std::shared_ptr<const Telegram> rx_telegram; // the incoming Rx telegram
std::list<QueuedRxTelegram> rx_telegrams_; // the Rx Queue
emsesp::queue<QueuedRxTelegram> rx_telegrams_ = emsesp::queue<QueuedRxTelegram>(MAX_RX_TELEGRAMS); // the Rx Queue
};
class TxService : public EMSbus {
public:
static constexpr size_t MAX_TX_TELEGRAMS = 30; // size of Tx queue
static constexpr uint8_t TX_WRITE_FAIL = 4; // EMS return code for fail
static constexpr uint8_t TX_WRITE_SUCCESS = 1; // EMS return code for success
@@ -277,7 +270,6 @@ class TxService : public EMSbus {
void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0);
void send_raw(const char * telegram_data);
void send_poll();
void flush_tx_queue();
void retry_tx(const uint8_t operation, const uint8_t * data, const uint8_t length);
bool is_last_tx(const uint8_t src, const uint8_t dest) const;
uint16_t post_send_query();
@@ -342,21 +334,13 @@ class TxService : public EMSbus {
telegram_write_count_++;
}
class QueuedTxTelegram {
public:
const uint16_t id_;
const std::shared_ptr<const Telegram> telegram_;
const bool retry_; // is a retry
~QueuedTxTelegram() = default;
QueuedTxTelegram(uint16_t id, std::shared_ptr<Telegram> && telegram, bool retry)
: id_(id)
, telegram_(std::move(telegram))
, retry_(retry) {
}
struct QueuedTxTelegram {
uint16_t id_;
std::shared_ptr<const Telegram> telegram_;
bool retry_; // true if its a retry
};
const std::list<QueuedTxTelegram> queue() const {
const emsesp::queue<QueuedTxTelegram> queue() const {
return tx_telegrams_;
}
@@ -367,7 +351,7 @@ class TxService : public EMSbus {
#endif
private:
std::list<QueuedTxTelegram> tx_telegrams_; // the Tx queue
emsesp::queue<QueuedTxTelegram> tx_telegrams_ = emsesp::queue<QueuedTxTelegram>(MAX_TX_TELEGRAMS); // the Tx Queue
uint32_t telegram_read_count_ = 0; // # Tx successful reads
uint32_t telegram_write_count_ = 0; // # Tx successful writes

View File

@@ -401,10 +401,11 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
if (command == "boiler") {
shell.printfln(F("Testing boiler..."));
run_test("boiler");
shell.invoke_command("show devices");
shell.invoke_command("show");
shell.invoke_command("call boiler info");
shell.invoke_command("call system publish");
shell.invoke_command("show mqtt");
// shell.invoke_command("call boiler info");
// shell.invoke_command("call system publish");
// shell.invoke_command("show mqtt");
}
if (command == "fr120") {
@@ -558,7 +559,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
uart_telegram("98 00 FF 00 01 A5 00 CF 21 2E 00 00 2E 24 03 25 03 03 01 03 25 00 C8 00 00 11 01 03"); // without CRC
uart_telegram_withCRC("98 00 FF 00 01 A6 00 CF 21 2E 00 00 2E 24 03 25 03 03 01 03 25 00 C8 00 00 11 01 03 6B"); // with CRC
EMSESP::txservice_.flush_tx_queue();
shell.loop_all();
EMSESP::show_device_values(shell);
@@ -638,8 +638,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
if (command == "tx") {
shell.printfln(F("Testing Tx..."));
EMSESP::txservice_.flush_tx_queue();
// TX queue example - Me -> Thermostat, (0x91), telegram: 0B 17 91 05 44 45 46 47 (#data=4)
uint8_t t11[] = {0x44, 0x45, 0x46, 0x47};
EMSESP::txservice_.add(Telegram::Operation::TX_RAW, 0x17, 0x91, 0x05, t11, sizeof(t11));
@@ -672,16 +670,11 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
for (uint8_t i = 0; i < 10; i++) {
EMSESP::txservice_.send(); // send it to UART
}
EMSESP::txservice_.flush_tx_queue();
}
if (command == "poll") {
shell.printfln(F("Testing Poll..."));
// check if sending works when a poll comes in, with retries
EMSESP::txservice_.flush_tx_queue();
// simulate sending a read request
// uint8_t t16[] = {0x44, 0x45, 0x46, 0x47}; // Me -> Thermostat, (0x91), telegram: 0B 17 91 05 44 45 46 47 (#data=4)
// EMSESP::txservice_.add(Telegram::Operation::TX_RAW, 0x17, 0x91, 0x05, t16, sizeof(t16));
@@ -702,8 +695,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
uint8_t t2[] = {0x21, 0x22};
EMSESP::send_write_request(0x91, 0x17, 0x00, t2, sizeof(t2), 0);
EMSESP::show_ems(shell);
EMSESP::txservice_.flush_tx_queue();
}
if (command == "cmd") {
@@ -759,10 +750,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
char boiler_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
char thermostat_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
char system_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
// test publish and adding to queue
EMSESP::txservice_.flush_tx_queue();
EMSESP::EMSESP::mqtt_.publish("boiler", "test me");
Mqtt::show_mqtt(shell); // show queue
@@ -816,7 +803,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
EMSESP::incoming_telegram(poll, 1);
EMSESP::show_ems(shell);
EMSESP::txservice_.flush_tx_queue();
}
if (command == "rx2") {

View File

@@ -21,21 +21,7 @@
#ifndef EMSESP_TEST_H
#define EMSESP_TEST_H
#include <Arduino.h>
#include <vector>
#include <string>
#include <uuid/common.h>
#include <uuid/console.h>
#include <uuid/log.h>
#include "emsdevice.h"
#include "emsfactory.h"
#include "telegram.h"
#include "mqtt.h"
#include "emsesp.h"
#include "command.h"
namespace emsesp {