mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
a6
This commit is contained in:
@@ -15,7 +15,7 @@ Note: Version 2.0 is not backward compatible with v1.0. The File system structur
|
||||
- The core is based off the great libraries from @nomis' and I adopted his general design pattens such as making everything as asynchronous as possible so that no one operation should starve another operation of it's time to execute (https://isocpp.org/wiki/faq/ctors#static-init-order).
|
||||
- All EMS devices (e.g. boiler, thermostat, solar modules etc) are derived from a factory base class and each class handles its own registering of telegram and mqtt handlers. This makes the EMS device code easier to manage and extend with new telegrams types and features.
|
||||
- Built to work with both EMS8266 and ESP32.
|
||||
- Extended MQTT to use MQTT discovery on Home Assistant, just for the thermostat
|
||||
- Extended MQTT to use MQTT discovery on Home Assistant, just for the thermostat for now.
|
||||
|
||||
### **Features**
|
||||
|
||||
@@ -124,6 +124,7 @@ thermostat
|
||||
### **Known issues, bugs and improvements currently working on**
|
||||
|
||||
```
|
||||
TODO when doing show, should we sort the ems devices?
|
||||
TODO figure out why sometimes telnet on ESP32 (and sometimes ESP8266) has slow response times. After a manual reset it seems to fix itself. Perhaps the telnet service needs to start after the wifi is up & running.
|
||||
TODO Get the ESP32 UART code working.
|
||||
TODO sometimes with tx_mode 0 there are a few CRC errors due to collision when waiting for a BRK signal.
|
||||
|
||||
@@ -58,7 +58,8 @@ Shell::~Shell() {
|
||||
|
||||
void Shell::start() {
|
||||
#ifdef EMSESP_DEBUG
|
||||
uuid::log::Logger::register_handler(this, uuid::log::Level::DEBUG); // added by proddy
|
||||
// uuid::log::Logger::register_handler(this, uuid::log::Level::DEBUG); // added by proddy
|
||||
uuid::log::Logger::register_handler(this, uuid::log::Level::INFO); // added by proddy
|
||||
#else
|
||||
uuid::log::Logger::register_handler(this, uuid::log::Level::NOTICE);
|
||||
#endif
|
||||
|
||||
@@ -76,7 +76,6 @@ void Shell::output_logs() {
|
||||
auto message = std::move(log_messages_.front());
|
||||
log_messages_.pop_front();
|
||||
|
||||
|
||||
print(uuid::log::format_timestamp_ms(message.content_->uptime_ms, 3));
|
||||
printf(F(" %c %lu: [%S] "), uuid::log::format_level_char(message.content_->level), message.id_, message.content_->name);
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ build_flags = -std=c++11 -Os -fno-exceptions
|
||||
-D ARDUINOJSON_USE_LONG_LONG=0
|
||||
-D BEARSSL_SSL_BASIC
|
||||
-D PROGMEM_WWW
|
||||
-D UUID_TELNET_HAVE_WIFICLIENT_NODELAY=0
|
||||
|
||||
libs_core =
|
||||
ArduinoJson
|
||||
@@ -44,9 +45,8 @@ libs_esp8266 =
|
||||
libs_esp32 =
|
||||
|
||||
[env]
|
||||
build_unflags = -fno-rtti ; for dynamic_cast<>
|
||||
lib_ldf_mode = chain+
|
||||
lib_compat_mode = strict
|
||||
;lib_ldf_mode = chain+
|
||||
;lib_compat_mode = strict
|
||||
extra_scripts = scripts/main_script.py
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
@@ -57,13 +57,14 @@ check_flags =
|
||||
cppcheck: --std=c++11
|
||||
clangtidy: --checks=-*,clang-analyzer-*,performance-*
|
||||
|
||||
; USB upload
|
||||
upload_protocol = esptool
|
||||
; example ports for OSX
|
||||
;upload_port = /dev/cu.wchusbserial14403
|
||||
;upload_port = /dev/cu.usbserial-1440
|
||||
;upload_port = /dev/cu.SLAB_USBtoUART
|
||||
|
||||
; OTA
|
||||
upload_protocol = esptool
|
||||
; OTA upload
|
||||
; upload_protocol = espota
|
||||
; upload_flags =
|
||||
; --port=8266
|
||||
@@ -79,7 +80,7 @@ board = esp12e
|
||||
lib_deps = ${common.libs_core} ${common.libs_esp8266}
|
||||
board_build.f_cpu = 160000000L ; 160MHz
|
||||
;board_build.ldscript = eagle.flash.4m1m.ld ; 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer
|
||||
board_build.ldscript = eagle.flash.4m2m.ld ; same as above but with 2024 KB SPIFFS
|
||||
board_build.ldscript = eagle.flash.4m2m.ld ; 1019 KB sketch, 2024 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 1028 KB OTA & buffer
|
||||
build_flags = ${common.build_flags} ${common.debug_flags} -flto -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
||||
|
||||
[env:esp32]
|
||||
|
||||
117
src/boiler.cpp
117
src/boiler.cpp
@@ -55,14 +55,14 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
|
||||
register_telegram_type(0x1C, F("UBAMaintenanceStatus"), false, std::bind(&Boiler::process_UBAMaintenanceStatus, this, _1));
|
||||
register_telegram_type(0x2A, F("MC10Status"), false, std::bind(&Boiler::process_MC10Status, this, _1));
|
||||
register_telegram_type(0x33, F("UBAParameterWW"), true, std::bind(&Boiler::process_UBAParameterWW, this, _1));
|
||||
register_telegram_type(0x14, F("UBATotalUptime"), true, std::bind(&Boiler::process_UBATotalUptime, this, _1));
|
||||
register_telegram_type(0x14, F("UBATotalUptime"), false, std::bind(&Boiler::process_UBATotalUptime, this, _1));
|
||||
register_telegram_type(0x35, F("UBAFlags"), false, std::bind(&Boiler::process_UBAFlags, this, _1));
|
||||
register_telegram_type(0x15, F("UBAMaintenanceSettings"), false, std::bind(&Boiler::process_UBAMaintenanceSettings, this, _1));
|
||||
register_telegram_type(0x16, F("UBAParameters"), true, std::bind(&Boiler::process_UBAParameters, this, _1));
|
||||
register_telegram_type(0x1A, F("UBASetPoints"), false, std::bind(&Boiler::process_UBASetPoints, this, _1));
|
||||
register_telegram_type(0xD1, F("UBAOutdoorTemp"), false, std::bind(&Boiler::process_UBAOutdoorTemp, this, _1));
|
||||
register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, std::bind(&Boiler::process_UBAMonitorFastPlus, this, _1));
|
||||
register_telegram_type(0xE5, F("UBAMonitorSlowPlus"), false, std::bind(&Boiler::process_UBAMonitorSlowPlus, this, _1));
|
||||
register_telegram_type(0xE4, F("UBAMonitorFastPlus"), true, std::bind(&Boiler::process_UBAMonitorFastPlus, this, _1));
|
||||
register_telegram_type(0xE5, F("UBAMonitorSlowPlus"), true, std::bind(&Boiler::process_UBAMonitorSlowPlus, this, _1));
|
||||
|
||||
register_telegram_type(0xE9, F("UBADHWStatus"), false, std::bind(&Boiler::process_UBADHWStatus, this, _1));
|
||||
register_telegram_type(0xE3, F("HeatPumpMonitor1"), true, std::bind(&Boiler::process_HPMonitor1, this, _1));
|
||||
@@ -82,8 +82,7 @@ void Boiler::add_context_menu() {
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(boiler)},
|
||||
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
dynamic_cast<EMSESPShell &>(shell).enter_custom_context(ShellContext::BOILER);
|
||||
console_commands();
|
||||
Boiler::console_commands(shell, ShellContext::BOILER);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -316,8 +315,11 @@ void Boiler::publish_values() {
|
||||
DEBUG_LOG(F("[DEBUG] Performing a boiler publish"));
|
||||
#endif
|
||||
|
||||
// if we have data, publish it
|
||||
if (!doc.isNull()) {
|
||||
Mqtt::publish("boiler_data", doc);
|
||||
}
|
||||
}
|
||||
|
||||
// called after a process command is called, to check values and see if we need to force an MQTT publish
|
||||
bool Boiler::updated_values() {
|
||||
@@ -330,22 +332,22 @@ void Boiler::show_values(uuid::console::Shell & shell) {
|
||||
|
||||
char buffer[10]; // used for formatting
|
||||
|
||||
print_value(shell, F("Selected flow temperature"), F_(degrees), Helpers::render_value(buffer, selFlowTemp_, 1));
|
||||
print_value(shell, F("Warm Water selected temperature"), F_(degrees), Helpers::render_value(buffer, wWSelTemp_, 1));
|
||||
print_value(shell, 2, F("Selected flow temperature"), F_(degrees), Helpers::render_value(buffer, selFlowTemp_, 1));
|
||||
print_value(shell, 2, F("Warm Water selected temperature"), F_(degrees), Helpers::render_value(buffer, wWSelTemp_, 1));
|
||||
|
||||
if (tap_water_active_ != EMS_VALUE_BOOL_NOTSET) {
|
||||
print_value(shell, F("Hot tap water"), tap_water_active_ ? "running" : "off");
|
||||
print_value(shell, 2, F("Hot tap water"), tap_water_active_ ? "running" : "off");
|
||||
}
|
||||
|
||||
if (heating_active_ != EMS_VALUE_BOOL_NOTSET) {
|
||||
print_value(shell, F("Central heating"), heating_active_ ? "active" : "off");
|
||||
print_value(shell, 2, F("Central heating"), heating_active_ ? "active" : "off");
|
||||
}
|
||||
|
||||
print_value(shell, F("Warm Water activated"), Helpers::render_value(buffer, wWActivated_, EMS_VALUE_BOOL));
|
||||
print_value(shell, F("Warm Water circulation pump available"), Helpers::render_value(buffer, wWCircPump_, EMS_VALUE_BOOL));
|
||||
print_value(shell, F("Warm Water circulation pump type"), wWCircPumpType_ ? "3-way pump" : "charge pump");
|
||||
print_value(shell, 2, F("Warm Water activated"), Helpers::render_value(buffer, wWActivated_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Warm Water circulation pump available"), Helpers::render_value(buffer, wWCircPump_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Warm Water circulation pump type"), wWCircPumpType_ ? "3-way pump" : "charge pump");
|
||||
if (wWCircPumpMode_ == 7) {
|
||||
print_value(shell, F("Warm Water circulation pump freq"), "continuous");
|
||||
print_value(shell, 2, F("Warm Water circulation pump freq"), "continuous");
|
||||
} else {
|
||||
char s[7];
|
||||
char buffer[2];
|
||||
@@ -353,64 +355,64 @@ void Boiler::show_values(uuid::console::Shell & shell) {
|
||||
buffer[1] = '\0';
|
||||
strlcpy(s, buffer, 7);
|
||||
strlcat(s, "x3min", 7);
|
||||
print_value(shell, F("Warm Water circulation pump freq"), s);
|
||||
print_value(shell, 2, F("Warm Water circulation pump freq"), s);
|
||||
}
|
||||
|
||||
if (wWComfort_ == 0x00) {
|
||||
print_value(shell, F("Warm Water comfort setting"), "Hot");
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), "Hot");
|
||||
} else if (wWComfort_ == 0xD8) {
|
||||
print_value(shell, F("Warm Water comfort setting"), "Eco");
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), "Eco");
|
||||
} else if (wWComfort_ == 0xEC) {
|
||||
print_value(shell, F("Warm Water comfort setting"), "Intelligent");
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), "Intelligent");
|
||||
}
|
||||
|
||||
print_value(shell, F("Warm Water selected temperature"), F_(degrees), Helpers::render_value(buffer, wWSelTemp_, 1));
|
||||
print_value(shell, F("Warm Water disinfection temperature"), F_(degrees), Helpers::render_value(buffer, wWDisinfectTemp_, 1));
|
||||
print_value(shell, F("Warm Water circulation active"), F_(degrees), Helpers::render_value(buffer, wWCirc_, EMS_VALUE_BOOL));
|
||||
print_value(shell, F("Warm Water set temperature"), F_(degrees), Helpers::render_value(buffer, wWSetTmp_, 1));
|
||||
print_value(shell, F("Warm Water current temperature"), F_(degrees), Helpers::render_value(buffer, wWCurTmp_, 10));
|
||||
print_value(shell, F("Warm water temperature (intern)"), F_(degrees), Helpers::render_value(buffer, wwStorageTemp1_, 10));
|
||||
print_value(shell, F("Warm water temperature (extern)"), F_(degrees), Helpers::render_value(buffer, wwStorageTemp2_, 10));
|
||||
print_value(shell, F("Warm Water current temperature (extern)"), F_(degrees), Helpers::render_value(buffer, wWCurTmp2_, 10));
|
||||
print_value(shell, F("Warm Water current tap water flow"), F("l/min"), Helpers::render_value(buffer, wWCurFlow_, 10));
|
||||
print_value(shell, F("Warm Water # starts"), Helpers::render_value(buffer, wWStarts_, 1));
|
||||
print_value(shell, 2, F("Warm Water selected temperature"), F_(degrees), Helpers::render_value(buffer, wWSelTemp_, 1));
|
||||
print_value(shell, 2, F("Warm Water disinfection temperature"), F_(degrees), Helpers::render_value(buffer, wWDisinfectTemp_, 1));
|
||||
print_value(shell, 2, F("Warm Water circulation active"), F_(degrees), Helpers::render_value(buffer, wWCirc_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Warm Water set temperature"), F_(degrees), Helpers::render_value(buffer, wWSetTmp_, 1));
|
||||
print_value(shell, 2, F("Warm Water current temperature"), F_(degrees), Helpers::render_value(buffer, wWCurTmp_, 10));
|
||||
print_value(shell, 2, F("Warm water temperature (intern)"), F_(degrees), Helpers::render_value(buffer, wwStorageTemp1_, 10));
|
||||
print_value(shell, 2, F("Warm water temperature (extern)"), F_(degrees), Helpers::render_value(buffer, wwStorageTemp2_, 10));
|
||||
print_value(shell, 2, F("Warm Water current temperature (extern)"), F_(degrees), Helpers::render_value(buffer, wWCurTmp2_, 10));
|
||||
print_value(shell, 2, F("Warm Water current tap water flow"), F("l/min"), Helpers::render_value(buffer, wWCurFlow_, 10));
|
||||
print_value(shell, 2, F("Warm Water # starts"), Helpers::render_value(buffer, wWStarts_, 1));
|
||||
if (wWWorkM_ != EMS_VALUE_ULONG_NOTSET) {
|
||||
shell.printfln(F(" Warm Water active time: %d days %d hours %d minutes"), wWWorkM_ / 1440, (wWWorkM_ % 1440) / 60, wWWorkM_ % 60);
|
||||
}
|
||||
print_value(shell, F("Warm Water 3-way valve"), Helpers::render_value(buffer, wWHeat_, EMS_VALUE_BOOL));
|
||||
print_value(shell, F("Selected flow temperature"), F_(degrees), Helpers::render_value(buffer, selFlowTemp_, 1));
|
||||
print_value(shell, F("Current flow temperature"), F_(degrees), Helpers::render_value(buffer, curFlowTemp_, 10));
|
||||
print_value(shell, F("Max boiler temperature"), F_(degrees), Helpers::render_value(buffer, boilTemp_, 10));
|
||||
print_value(shell, F("Return temperature"), F_(degrees), Helpers::render_value(buffer, retTemp_, 10));
|
||||
print_value(shell, F("Gas"), Helpers::render_value(buffer, burnGas_, EMS_VALUE_BOOL));
|
||||
print_value(shell, F("Boiler pump"), Helpers::render_value(buffer, heatPmp_, EMS_VALUE_BOOL));
|
||||
print_value(shell, F("Fan"), Helpers::render_value(buffer, fanWork_, EMS_VALUE_BOOL));
|
||||
print_value(shell, F("Ignition"), Helpers::render_value(buffer, ignWork_, EMS_VALUE_BOOL));
|
||||
print_value(shell, F("Circulation pump"), Helpers::render_value(buffer, wWCirc_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Warm Water 3-way valve"), Helpers::render_value(buffer, wWHeat_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Selected flow temperature"), F_(degrees), Helpers::render_value(buffer, selFlowTemp_, 1));
|
||||
print_value(shell, 2, F("Current flow temperature"), F_(degrees), Helpers::render_value(buffer, curFlowTemp_, 10));
|
||||
print_value(shell, 2, F("Max boiler temperature"), F_(degrees), Helpers::render_value(buffer, boilTemp_, 10));
|
||||
print_value(shell, 2, F("Return temperature"), F_(degrees), Helpers::render_value(buffer, retTemp_, 10));
|
||||
print_value(shell, 2, F("Gas"), Helpers::render_value(buffer, burnGas_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Boiler pump"), Helpers::render_value(buffer, heatPmp_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Fan"), Helpers::render_value(buffer, fanWork_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Ignition"), Helpers::render_value(buffer, ignWork_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Circulation pump"), Helpers::render_value(buffer, wWCirc_, EMS_VALUE_BOOL));
|
||||
|
||||
print_value(shell, F("Burner selected max power"), F_(percent), Helpers::render_value(buffer, selBurnPow_, 1));
|
||||
print_value(shell, F("Burner current power"), F_(percent), Helpers::render_value(buffer, curBurnPow_, 1));
|
||||
print_value(shell, F("Flame current"), F("uA"), Helpers::render_value(buffer, flameCurr_, 10));
|
||||
print_value(shell, F("System pressure"), F("bar"), Helpers::render_value(buffer, sysPress_, 10));
|
||||
if (serviceCode_ == EMS_VALUE_USHORT_NOTSET) {
|
||||
shell.printfln(F(" System service code: %s"), serviceCodeChar_);
|
||||
} else {
|
||||
print_value(shell, 2, F("Burner selected max power"), F_(percent), Helpers::render_value(buffer, selBurnPow_, 1));
|
||||
print_value(shell, 2, F("Burner current power"), F_(percent), Helpers::render_value(buffer, curBurnPow_, 1));
|
||||
print_value(shell, 2, F("Flame current"), F("uA"), Helpers::render_value(buffer, flameCurr_, 10));
|
||||
print_value(shell, 2, F("System pressure"), F("bar"), Helpers::render_value(buffer, sysPress_, 10));
|
||||
if (serviceCode_ != EMS_VALUE_USHORT_NOTSET) {
|
||||
shell.printfln(F(" System service code: %s (%d)"), serviceCodeChar_, serviceCode_);
|
||||
} else if (serviceCodeChar_[0] != '\0') {
|
||||
shell.printfln(F(" System service code: %s"), serviceCodeChar_);
|
||||
}
|
||||
|
||||
// UBAParameters
|
||||
print_value(shell, F("Heating temperature setting on the boiler"), F_(degrees), Helpers::render_value(buffer, heating_temp_, 1));
|
||||
print_value(shell, F("Boiler circuit pump modulation max power"), F_(percent), Helpers::render_value(buffer, pump_mod_max_, 1));
|
||||
print_value(shell, F("Boiler circuit pump modulation min power"), F_(percent), Helpers::render_value(buffer, pump_mod_min_, 1));
|
||||
print_value(shell, 2, F("Heating temperature setting on the boiler"), F_(degrees), Helpers::render_value(buffer, heating_temp_, 1));
|
||||
print_value(shell, 2, F("Boiler circuit pump modulation max power"), F_(percent), Helpers::render_value(buffer, pump_mod_max_, 1));
|
||||
print_value(shell, 2, F("Boiler circuit pump modulation min power"), F_(percent), Helpers::render_value(buffer, pump_mod_min_, 1));
|
||||
|
||||
// UBAMonitorSlow
|
||||
if (extTemp_ != EMS_VALUE_SHORT_NOTSET) {
|
||||
print_value(shell, F("Outside temperature"), F_(degrees), Helpers::render_value(buffer, extTemp_, 10));
|
||||
print_value(shell, 2, F("Outside temperature"), F_(degrees), Helpers::render_value(buffer, extTemp_, 10));
|
||||
}
|
||||
|
||||
print_value(shell, F("Exhaust temperature"), F_(degrees), Helpers::render_value(buffer, exhaustTemp_, 10));
|
||||
print_value(shell, F("Pump modulation"), F_(percent), Helpers::render_value(buffer, pumpMod_, 1));
|
||||
print_value(shell, F("Burner # starts"), Helpers::render_value(buffer, burnStarts_, 1));
|
||||
print_value(shell, 2, F("Exhaust temperature"), F_(degrees), Helpers::render_value(buffer, exhaustTemp_, 10));
|
||||
print_value(shell, 2, F("Pump modulation"), F_(percent), Helpers::render_value(buffer, pumpMod_, 1));
|
||||
print_value(shell, 2, F("Burner # starts"), Helpers::render_value(buffer, burnStarts_, 1));
|
||||
if (burnWorkMin_ != EMS_VALUE_ULONG_NOTSET) {
|
||||
shell.printfln(F(" Total burner operating time: %d days %d hours %d minutes"), burnWorkMin_ / 1440, (burnWorkMin_ % 1440) / 60, burnWorkMin_ % 60);
|
||||
}
|
||||
@@ -422,11 +424,11 @@ void Boiler::show_values(uuid::console::Shell & shell) {
|
||||
}
|
||||
|
||||
if (hpModulation_ != EMS_VALUE_UINT_NOTSET) {
|
||||
print_value(shell, F("Heat Pump modulation"), F_(percent), Helpers::render_value(buffer, hpModulation_, 1));
|
||||
print_value(shell, 2, F("Heat Pump modulation"), F_(percent), Helpers::render_value(buffer, hpModulation_, 1));
|
||||
}
|
||||
|
||||
if (hpSpeed_ != EMS_VALUE_UINT_NOTSET) {
|
||||
print_value(shell, F("Heat Pump speed"), F_(percent), Helpers::render_value(buffer, hpSpeed_, 1));
|
||||
print_value(shell, 2, F("Heat Pump speed"), F_(percent), Helpers::render_value(buffer, hpSpeed_, 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,6 +547,7 @@ void Boiler::process_UBAMonitorWW(std::shared_ptr<const Telegram> telegram) {
|
||||
|
||||
/*
|
||||
* UBAMonitorFastPlus - type 0xE4 - central heating monitor EMS+
|
||||
* Still to figure out are: serviceCode, retTemp, sysPress
|
||||
*/
|
||||
void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(selFlowTemp_, 6);
|
||||
@@ -562,8 +565,6 @@ void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram
|
||||
serviceCodeChar_[2] = '\0';
|
||||
}
|
||||
|
||||
// still to figure out: serviceCode, retTemp, sysPress
|
||||
|
||||
// at this point do a quick check to see if the hot water or heating is active
|
||||
check_active();
|
||||
}
|
||||
@@ -754,7 +755,7 @@ void Boiler::set_warmwater_circulation(const bool activated) {
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Boiler::console_commands() {
|
||||
void Boiler::console_commands(Shell & shell, unsigned int context) {
|
||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(read)},
|
||||
@@ -920,6 +921,10 @@ void Boiler::console_commands() {
|
||||
shell.printfln(F_(shower_alert_fmt), settings.shower_alert() ? F_(enabled) : F_(disabled));
|
||||
shell.println();
|
||||
});
|
||||
|
||||
|
||||
// enter the context
|
||||
Console::enter_custom_context(shell, context);
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -46,7 +46,7 @@ class Boiler : public EMSdevice {
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands();
|
||||
void console_commands(Shell & shell, unsigned int context);
|
||||
|
||||
uint8_t last_boilerState = 0xFF; // remember last state of heating and warm water on/off
|
||||
|
||||
@@ -82,7 +82,7 @@ class Boiler : public EMSdevice {
|
||||
uint8_t curBurnPow_ = EMS_VALUE_UINT_NOTSET; // Burner current power %
|
||||
uint16_t flameCurr_ = EMS_VALUE_USHORT_NOTSET; // Flame current in micro amps
|
||||
uint8_t sysPress_ = EMS_VALUE_UINT_NOTSET; // System pressure
|
||||
char serviceCodeChar_[3]; // 2 character status/service code
|
||||
char serviceCodeChar_[3] = {'\0'}; // 2 character status/service code
|
||||
uint16_t serviceCode_ = EMS_VALUE_USHORT_NOTSET; // error/service code
|
||||
|
||||
// UBAMonitorSlow - 0x19 on EMS1
|
||||
|
||||
@@ -21,7 +21,11 @@
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
static std::shared_ptr<Commands> commands = std::make_shared<Commands>();
|
||||
std::shared_ptr<Commands> EMSESPShell::commands = [] {
|
||||
std::shared_ptr<Commands> commands = std::make_shared<Commands>();
|
||||
return commands;
|
||||
}();
|
||||
|
||||
static std::shared_ptr<EMSESPShell> shell;
|
||||
|
||||
std::vector<bool> EMSESPStreamConsole::ptys_;
|
||||
@@ -32,11 +36,6 @@ uuid::telnet::TelnetService telnet_([](Stream & stream, const IPAddress & addr,
|
||||
});
|
||||
#endif
|
||||
|
||||
std::shared_ptr<Commands> EMSESPShell::commands = [] {
|
||||
std::shared_ptr<Commands> commands = std::make_shared<Commands>();
|
||||
return commands;
|
||||
}();
|
||||
|
||||
EMSESPShell::EMSESPShell()
|
||||
: Shell() {
|
||||
}
|
||||
@@ -125,7 +124,7 @@ void EMSESPShell::add_console_commands() {
|
||||
});
|
||||
|
||||
/*
|
||||
* add the submenu contexts...
|
||||
* add all the submenu contexts...
|
||||
*/
|
||||
|
||||
// MQTT
|
||||
@@ -133,8 +132,7 @@ void EMSESPShell::add_console_commands() {
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(mqtt)},
|
||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
dynamic_cast<EMSESPShell &>(shell).enter_custom_context(ShellContext::MQTT);
|
||||
Mqtt::console_commands();
|
||||
Mqtt::console_commands(shell, ShellContext::MQTT);
|
||||
});
|
||||
|
||||
// EMS
|
||||
@@ -142,8 +140,7 @@ void EMSESPShell::add_console_commands() {
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(ems)},
|
||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
dynamic_cast<EMSESPShell &>(shell).enter_custom_context(ShellContext::EMS);
|
||||
EMSESP::console_commands();
|
||||
EMSESP::console_commands(shell, ShellContext::EMS);
|
||||
});
|
||||
|
||||
// System
|
||||
@@ -151,15 +148,14 @@ void EMSESPShell::add_console_commands() {
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(system)},
|
||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
dynamic_cast<EMSESPShell &>(shell).enter_custom_context(ShellContext::SYSTEM);
|
||||
System::console_commands();
|
||||
System::console_commands(shell, ShellContext::SYSTEM);
|
||||
});
|
||||
|
||||
// add all the context menus for the connected devices
|
||||
// this assumes they devices have been detected and registered
|
||||
EMSESP::add_context_menu();
|
||||
// this assumes they devices have been detected and pre-registered
|
||||
EMSESP::add_context_menus();
|
||||
|
||||
enter_custom_context(ShellContext::MAIN); // add su, exit and help
|
||||
Console::load_standard_commands(ShellContext::MAIN);
|
||||
|
||||
_console_commands_loaded = true;
|
||||
}
|
||||
@@ -199,17 +195,29 @@ bool EMSESPShell::exit_context() {
|
||||
return Shell::exit_context();
|
||||
}
|
||||
|
||||
// enter a custom context (sub-menu)
|
||||
void Console::enter_custom_context(Shell & shell, unsigned int context) {
|
||||
load_standard_commands(context);
|
||||
|
||||
// don't enter context if we're already at the root
|
||||
if (context != ShellContext::MAIN) {
|
||||
shell.enter_context(context);
|
||||
}
|
||||
}
|
||||
|
||||
// each custom context has the common commands like log, help, exit, su etc
|
||||
void EMSESPShell::enter_custom_context(unsigned int context) {
|
||||
void Console::load_standard_commands(unsigned int context) {
|
||||
#ifdef EMSESP_DEBUG
|
||||
commands->add_command(context,
|
||||
EMSESPShell::commands->add_command(context,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(test)},
|
||||
flash_string_vector{F_(name_mandatory)},
|
||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { EMSESP::run_test(shell, arguments.front()); });
|
||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
EMSESP::run_test(shell, arguments.front());
|
||||
});
|
||||
#endif
|
||||
|
||||
commands->add_command(
|
||||
EMSESPShell::commands->add_command(
|
||||
context,
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(log)},
|
||||
@@ -229,7 +237,7 @@ void EMSESPShell::enter_custom_context(unsigned int context) {
|
||||
uint16_t watch_id = 0; // no watch ID set
|
||||
if ((arguments.size() == 2) && (level == uuid::log::Level::TRACE)) {
|
||||
watch_id = Helpers::hextoint(arguments[1].c_str());
|
||||
shell.printfln(("Tracing only telegrams that match a device ID/telegram type ID of 0x%02X"), watch_id);
|
||||
shell.printfln(("Tracing only telegrams that match a device ID or telegram type of 0x%02X"), watch_id);
|
||||
}
|
||||
emsesp::EMSESP::trace_watch_id(watch_id);
|
||||
}
|
||||
@@ -239,25 +247,28 @@ void EMSESPShell::enter_custom_context(unsigned int context) {
|
||||
return uuid::log::levels_lowercase();
|
||||
});
|
||||
|
||||
commands->add_command(context,
|
||||
EMSESPShell::commands->add_command(context,
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(help)},
|
||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { shell.print_all_available_commands(); });
|
||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
shell.print_all_available_commands();
|
||||
});
|
||||
|
||||
commands->add_command(context,
|
||||
EMSESPShell::commands->add_command(context,
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(exit)},
|
||||
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { shell.exit_context(); });
|
||||
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
// delete MAIN console stuff first to save memory
|
||||
EMSESPShell::commands->remove_context_commands(context);
|
||||
shell.exit_context();
|
||||
});
|
||||
|
||||
commands->add_command(context,
|
||||
EMSESPShell::commands->add_command(context,
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(su)},
|
||||
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
auto become_admin = [](Shell & shell) {
|
||||
shell.logger().log(LogLevel::NOTICE,
|
||||
LogFacility::AUTH,
|
||||
F("Admin session opened on console %s"),
|
||||
dynamic_cast<EMSESPShell &>(shell).console_name().c_str());
|
||||
shell.logger().log(LogLevel::NOTICE, LogFacility::AUTH, F("Admin session opened on console"));
|
||||
shell.add_flags(CommandFlags::ADMIN);
|
||||
};
|
||||
|
||||
@@ -272,10 +283,7 @@ void EMSESPShell::enter_custom_context(unsigned int context) {
|
||||
become_admin(shell);
|
||||
} else {
|
||||
shell.delay_until(now + INVALID_PASSWORD_DELAY_MS, [](Shell & shell) {
|
||||
shell.logger().log(LogLevel::NOTICE,
|
||||
LogFacility::AUTH,
|
||||
F("Invalid admin password on console %s"),
|
||||
dynamic_cast<EMSESPShell &>(shell).console_name().c_str());
|
||||
shell.logger().log(LogLevel::NOTICE, LogFacility::AUTH, F("Invalid admin password on console"));
|
||||
shell.println(F("su: incorrect password"));
|
||||
});
|
||||
}
|
||||
@@ -285,10 +293,8 @@ void EMSESPShell::enter_custom_context(unsigned int context) {
|
||||
});
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
commands->add_command(context,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(debug)},
|
||||
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
EMSESPShell::commands->add_command(
|
||||
context, CommandFlags::ADMIN, flash_string_vector{F_(debug)}, [&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
shell.printfln(F("%s%sEMS-ESP version %s%s"), COLOR_BRIGHT_GREEN, COLOR_BOLD_ON, Settings().app_version().c_str(), COLOR_RESET);
|
||||
Settings settings;
|
||||
settings.commit();
|
||||
@@ -296,11 +302,6 @@ void EMSESPShell::enter_custom_context(unsigned int context) {
|
||||
shell.println();
|
||||
});
|
||||
#endif
|
||||
|
||||
// don't enter context if we're at the root
|
||||
if (context != ShellContext::MAIN) {
|
||||
Shell::enter_context(context);
|
||||
}
|
||||
}
|
||||
|
||||
// prompt, change per context
|
||||
@@ -339,8 +340,6 @@ std::string EMSESPShell::prompt_suffix() {
|
||||
}
|
||||
|
||||
void EMSESPShell::end_of_transmission() {
|
||||
// delete MAIN console stuff
|
||||
commands->remove_context_commands(ShellContext::MAIN);
|
||||
invoke_command(uuid::read_flash_string(F_(exit)));
|
||||
}
|
||||
|
||||
@@ -415,7 +414,7 @@ void Console::start() {
|
||||
// note, this must be started after the network/wifi for ESP32 otherwise it'll crash
|
||||
#ifndef EMSESP_STANDALONE
|
||||
telnet_.start();
|
||||
// telnet_.default_write_timeout(1000); // in ms, socket timeout 1 second
|
||||
telnet_.default_write_timeout(1000); // in ms, socket timeout 1 second
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -428,8 +427,6 @@ void Console::loop() {
|
||||
#endif
|
||||
|
||||
Shell::loop_all();
|
||||
|
||||
// delay(0); // in EMS-ESP 1.9.5 this helped with stability
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -125,7 +125,13 @@ namespace emsesp {
|
||||
using LogLevel = ::uuid::log::Level;
|
||||
using LogFacility = ::uuid::log::Facility;
|
||||
|
||||
enum CommandFlags : uint8_t { USER = 0, ADMIN = (1 << 0), LOCAL = (1 << 1) };
|
||||
enum CommandFlags : uint8_t {
|
||||
|
||||
USER = 0,
|
||||
ADMIN = (1 << 0),
|
||||
LOCAL = (1 << 1)
|
||||
|
||||
};
|
||||
|
||||
enum ShellContext : uint8_t {
|
||||
|
||||
@@ -147,8 +153,6 @@ class EMSESPShell : virtual public uuid::console::Shell {
|
||||
static std::shared_ptr<uuid::console::Commands> commands;
|
||||
static std::shared_ptr<EMSESPShell> shell;
|
||||
|
||||
void enter_custom_context(unsigned int context);
|
||||
|
||||
protected:
|
||||
EMSESPShell();
|
||||
|
||||
@@ -191,6 +195,9 @@ class Console {
|
||||
|
||||
uuid::log::Level log_level();
|
||||
|
||||
static void enter_custom_context(Shell & shell, unsigned int context);
|
||||
static void load_standard_commands(unsigned int context);
|
||||
|
||||
private:
|
||||
static constexpr unsigned long SERIAL_CONSOLE_BAUD_RATE = 115200;
|
||||
static constexpr auto & serial_console_ = Serial;
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
{115, DeviceType::BOILER, F("Topline/GB162"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{123, DeviceType::BOILER, F("GBx72/Trendline/Cerapur/Greenstar Si/27i"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{133, DeviceType::BOILER, F("GB125/Logamatic MC110"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{115, DeviceType::BOILER, F("Topline/GB162"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{203, DeviceType::BOILER, F("Logamax U122/Cerapur"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{208, DeviceType::BOILER, F("Logamax plus/GB192/Condens GC9000"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{ 64, DeviceType::BOILER, F("BK13,BK15/Smartline/GB1x2"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
@@ -37,6 +36,7 @@
|
||||
{122, DeviceType::BOILER, F("Proline"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{170, DeviceType::BOILER, F("Logano GB212"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{172, DeviceType::BOILER, F("Enviline/Compress 6000AW"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{ 72, DeviceType::BOILER, F("MC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
|
||||
// Solar Modules - 0x30
|
||||
{ 73, DeviceType::SOLAR, F("SM10"), DeviceFlags::EMS_DEVICE_FLAG_SM10},
|
||||
@@ -60,6 +60,7 @@
|
||||
|
||||
// Controllers - 0x09 / 0x10
|
||||
{ 68, DeviceType::CONTROLLER, F("BC10/RFM20"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||
{ 89, DeviceType::CONTROLLER, F("BC"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||
{218, DeviceType::CONTROLLER, F("M200/RFM200"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x50
|
||||
{190, DeviceType::CONTROLLER, F("BC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||
{114, DeviceType::CONTROLLER, F("BC10"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||
|
||||
@@ -138,7 +138,7 @@ std::string EMSdevice::to_string() const {
|
||||
}
|
||||
|
||||
if (brand_ == Brand::NO_BRAND) {
|
||||
snprintf_P(&str[0], str.capacity() + 1, PSTR("%s (DeviceID:0x%02X ProductID:%d, Version:%s)"), name_.c_str(), device_id_, product_id_, version_.c_str());
|
||||
snprintf_P(&str[0], str.capacity() + 1, PSTR("%s (DeviceID:0x%02X, ProductID:%d, Version:%s)"), name_.c_str(), device_id_, product_id_, version_.c_str());
|
||||
} else {
|
||||
snprintf_P(&str[0],
|
||||
str.capacity() + 1,
|
||||
@@ -161,6 +161,7 @@ void EMSdevice::show_values(uuid::console::Shell & shell) {
|
||||
// for each telegram that has the fetch value set (true) do a read request
|
||||
void EMSdevice::fetch_values() {
|
||||
DEBUG_LOG(F("Fetching values for device ID 0x%02X"), device_id());
|
||||
|
||||
for (const auto & tf : telegram_functions_) {
|
||||
if (tf.fetch_) {
|
||||
read_command(tf.telegram_type_id_);
|
||||
@@ -260,13 +261,21 @@ void EMSdevice::read_command(const uint16_t type_id) {
|
||||
}
|
||||
|
||||
// prints a value to the console
|
||||
void EMSdevice::print_value(uuid::console::Shell & shell, const __FlashStringHelper * name, const __FlashStringHelper * prefix, const char * value) {
|
||||
shell.printfln(PSTR(" %s: %s%s"), uuid::read_flash_string(name).c_str(), value, uuid::read_flash_string(prefix).c_str());
|
||||
void EMSdevice::print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const __FlashStringHelper * suffix, const char * value) {
|
||||
uint8_t i = padding;
|
||||
while (i-- > 0) {
|
||||
shell.print(F(" "));
|
||||
}
|
||||
shell.printf(PSTR("%s: %s"), uuid::read_flash_string(name).c_str(), value);
|
||||
if (suffix != nullptr) {
|
||||
shell.print(uuid::read_flash_string(suffix).c_str());
|
||||
}
|
||||
shell.println();
|
||||
}
|
||||
|
||||
// prints a value to the console - no prefix
|
||||
void EMSdevice::print_value(uuid::console::Shell & shell, const __FlashStringHelper * name, const char * value) {
|
||||
shell.printfln(PSTR(" %s: %s"), uuid::read_flash_string(name).c_str(), value);
|
||||
// prints a value to the console - with no prefix
|
||||
void EMSdevice::print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const char * value) {
|
||||
print_value(shell, padding, name, nullptr, value);
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -119,8 +119,8 @@ class EMSdevice {
|
||||
|
||||
void fetch_values();
|
||||
|
||||
void print_value(uuid::console::Shell & shell, const __FlashStringHelper * name, const __FlashStringHelper * prefix, const char * value);
|
||||
void print_value(uuid::console::Shell & shell, const __FlashStringHelper * name, const char * value);
|
||||
void print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const __FlashStringHelper * prefix, const char * value);
|
||||
void print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const char * value);
|
||||
|
||||
enum Brand : uint8_t {
|
||||
NO_BRAND, // 0
|
||||
@@ -195,8 +195,7 @@ class EMSdevice {
|
||||
|
||||
uint16_t telegram_type_id_; // it's type_id
|
||||
const __FlashStringHelper * telegram_type_name_; // e.g. RC20Message
|
||||
// std::string telegram_type_name_; // e.g. RC20Message
|
||||
bool fetch_; // should this type_id be queried automatically?
|
||||
bool fetch_; // if this type_id be queried automatically
|
||||
process_function_p process_function_;
|
||||
};
|
||||
std::vector<TelegramFunction> telegram_functions_; // each EMS device has its own set of registered telegram types
|
||||
|
||||
@@ -59,14 +59,15 @@ uint8_t EMSESP::actual_master_thermostat_ = EMSESP_DEFAULT_MASTER_THERMOSTAT; /
|
||||
uint16_t EMSESP::trace_watch_id_ = 0; // for when log is TRACE
|
||||
bool EMSESP::tap_water_active_ = false; // for when Boiler states we having running warm water. used in Shower()
|
||||
bool EMSESP::ems_read_only_;
|
||||
uint32_t EMSESP::last_fetch_ = 0;
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
#include "test/test_data.h" // used with the 'test' command, under su/admin
|
||||
#endif
|
||||
|
||||
// for each associated EMS device go and request data values
|
||||
// for each associated EMS device go and request its data values
|
||||
void EMSESP::fetch_device_values() {
|
||||
fetch_device_values(0); // fetch all
|
||||
fetch_device_values(0); // 0 = fetch all
|
||||
}
|
||||
|
||||
// for a specific EMS device go and request data values
|
||||
@@ -76,7 +77,9 @@ void EMSESP::fetch_device_values(const uint8_t device_id) {
|
||||
if (emsdevice) {
|
||||
if ((device_id == 0) || emsdevice->is_device_id(device_id)) {
|
||||
emsdevice->fetch_values();
|
||||
return;
|
||||
if (device_id != 0) {
|
||||
return; // quit, we only want to return the selected device
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,6 +180,14 @@ void EMSESP::show_values(uuid::console::Shell & shell) {
|
||||
return;
|
||||
}
|
||||
|
||||
// show EMS device values
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice) {
|
||||
emsdevice->show_values(shell);
|
||||
shell.println();
|
||||
}
|
||||
}
|
||||
|
||||
// Dallas sensors (if available)
|
||||
char valuestr[8] = {0}; // for formatting temp
|
||||
if (!sensor_devices().empty()) {
|
||||
@@ -187,14 +198,6 @@ void EMSESP::show_values(uuid::console::Shell & shell) {
|
||||
shell.println();
|
||||
}
|
||||
|
||||
// show EMS device values
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice) {
|
||||
emsdevice->show_values(shell);
|
||||
shell.println();
|
||||
}
|
||||
}
|
||||
|
||||
shell.println();
|
||||
}
|
||||
|
||||
@@ -340,6 +343,7 @@ void EMSESP::process_UBADevices(std::shared_ptr<const Telegram> telegram) {
|
||||
}
|
||||
|
||||
// process the Version telegram (type 0x02), which is a common type
|
||||
// e.g. 09 0B 02 00 PP V1 V2
|
||||
void EMSESP::process_version(std::shared_ptr<const Telegram> telegram) {
|
||||
// check for valid telegram, just in case
|
||||
if (telegram->message_length < 3) {
|
||||
@@ -447,7 +451,7 @@ bool EMSESP::device_exists(const uint8_t device_id) {
|
||||
}
|
||||
|
||||
// for each device add its context menu for the console
|
||||
void EMSESP::add_context_menu() {
|
||||
void EMSESP::add_context_menus() {
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice) {
|
||||
emsdevice->add_context_menu();
|
||||
@@ -531,10 +535,10 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std::
|
||||
|
||||
// if we don't recognize the product ID report it, but don't add it.
|
||||
if (!found) {
|
||||
DEBUG_LOG(F("Cannot add device. Unknown device ID 0x%02X, product ID %d. Ignoring it."), device_id, product_id);
|
||||
logger_.notice(F("Unrecognized EMS device with device ID 0x%02X with product ID %d. Please report on GitHub."), device_id, product_id);
|
||||
return false; // not found
|
||||
} else {
|
||||
DEBUG_LOG(F("Adding new device with device ID 0x%02X, product ID %d"), device_id, product_id);
|
||||
DEBUG_LOG(F("Adding new device with device ID 0x%02X with product ID %d"), device_id, product_id);
|
||||
// go and fetch its data, including asking for the version
|
||||
send_read_request(EMSdevice::EMS_TYPE_VERSION, device_id);
|
||||
fetch_device_values(device_id);
|
||||
@@ -634,7 +638,7 @@ void EMSESP::set_ems_read_only() {
|
||||
}
|
||||
|
||||
// console commands to add
|
||||
void EMSESP::console_commands() {
|
||||
void EMSESP::console_commands(Shell & shell, unsigned int context) {
|
||||
EMSESPShell::commands->add_command(ShellContext::EMS,
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(show), F_(devices)},
|
||||
@@ -775,6 +779,9 @@ void EMSESP::console_commands() {
|
||||
shell.printfln(F_(bus_id_fmt), settings.ems_bus_id());
|
||||
shell.printfln(F_(read_only_fmt), settings.ems_read_only() ? F_(enabled) : F_(disabled));
|
||||
});
|
||||
|
||||
// enter the context
|
||||
Console::enter_custom_context(shell, context);
|
||||
}
|
||||
|
||||
// kick off the party, start all the services
|
||||
@@ -805,6 +812,13 @@ void EMSESP::loop() {
|
||||
rxservice_.loop(); // process what ever is in the rx queue
|
||||
shower_.loop(); // check for shower on/off
|
||||
sensors_.loop(); // this will also send out via MQTT
|
||||
|
||||
// force a query on the EMS devices to fetch latest data
|
||||
uint32_t currentMillis = millis();
|
||||
if ((currentMillis - last_fetch_ > EMS_FETCH_FREQUENCY)) {
|
||||
last_fetch_ = currentMillis;
|
||||
fetch_device_values();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ class EMSESP {
|
||||
static void show_devices(uuid::console::Shell & shell);
|
||||
static void show_emsbus(uuid::console::Shell & shell);
|
||||
|
||||
static void add_context_menu();
|
||||
static void add_context_menus();
|
||||
|
||||
static void incoming_telegram(uint8_t * data, const uint8_t length);
|
||||
|
||||
@@ -111,7 +111,7 @@ class EMSESP {
|
||||
return ems_read_only_;
|
||||
}
|
||||
|
||||
static void console_commands();
|
||||
static void console_commands(Shell & shell, unsigned int context);
|
||||
|
||||
static void fetch_device_values(const uint8_t device_id);
|
||||
static void fetch_device_values();
|
||||
@@ -136,6 +136,9 @@ class EMSESP {
|
||||
static RxService rxservice_;
|
||||
static TxService txservice_;
|
||||
|
||||
static constexpr uint32_t EMS_FETCH_FREQUENCY = 60000; // check every minute
|
||||
static uint32_t last_fetch_;
|
||||
|
||||
struct Device_record {
|
||||
uint8_t product_id;
|
||||
EMSdevice::DeviceType device_type;
|
||||
|
||||
@@ -65,10 +65,10 @@ void Mixing::show_values(uuid::console::Shell & shell) {
|
||||
} else {
|
||||
shell.printfln(F(" Heating Circuit #: %d"), hc_);
|
||||
}
|
||||
print_value(shell, F("Current flow temperature"), F_(degrees), Helpers::render_value(buffer, flowTemp_, 10));
|
||||
print_value(shell, F("Setpoint flow temperature"), F_(degrees), Helpers::render_value(buffer, flowSetTemp_, 1));
|
||||
print_value(shell, F("Current pump modulation"), Helpers::render_value(buffer, pumpMod_, 1));
|
||||
print_value(shell, F("Current valve status"), Helpers::render_value(buffer, status_, 1));
|
||||
print_value(shell, 2, F("Current flow temperature"), F_(degrees), Helpers::render_value(buffer, flowTemp_, 10));
|
||||
print_value(shell, 2, F("Setpoint flow temperature"), F_(degrees), Helpers::render_value(buffer, flowSetTemp_, 1));
|
||||
print_value(shell, 2, F("Current pump modulation"), Helpers::render_value(buffer, pumpMod_, 1));
|
||||
print_value(shell, 2, F("Current valve status"), Helpers::render_value(buffer, status_, 1));
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
|
||||
37
src/mqtt.cpp
37
src/mqtt.cpp
@@ -40,7 +40,7 @@ MAKE_PSTR(mqtt_enabled_fmt, "MQTT is %s")
|
||||
MAKE_PSTR(mqtt_base_fmt, "Base = %s")
|
||||
MAKE_PSTR(mqtt_qos_fmt, "QOS = %ld")
|
||||
MAKE_PSTR(mqtt_retain_fmt, "Retain Flag = %s")
|
||||
MAKE_PSTR(mqtt_format_fmt, "JSON format = %s")
|
||||
MAKE_PSTR(mqtt_format_fmt, "Format for JSON = %s")
|
||||
MAKE_PSTR(mqtt_heartbeat_fmt, "Heartbeat = %s")
|
||||
MAKE_PSTR(mqtt_publish_time_fmt, "Publish time = %d seconds")
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace emsesp {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
AsyncMqttClient Mqtt::mqttClient_;
|
||||
#endif
|
||||
|
||||
std::vector<Mqtt::MQTTFunction> Mqtt::mqtt_functions_;
|
||||
bool Mqtt::mqtt_retain_;
|
||||
uint8_t Mqtt::mqtt_qos_;
|
||||
@@ -463,17 +464,20 @@ void Mqtt::send_heartbeat() {
|
||||
|
||||
// add MQTT message to queue, payload is a JSON doc.
|
||||
// NOTE this only prints first 255 chars
|
||||
void Mqtt::queue_publish_message(const char * topic, const JsonDocument & payload, const bool retain) {
|
||||
if (strlen(topic) == 0) {
|
||||
void Mqtt::queue_publish_message(const std::string & topic, const JsonDocument & payload, const bool retain) {
|
||||
// can't have bogus topics, but empty payloads are ok
|
||||
if (topic.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
// check for empty JSON doc - we don't like those
|
||||
size_t capacity = measureJson(payload);
|
||||
if (capacity <= 3) {
|
||||
// DEBUG_LOG(("Empty JSON for topic %s. Skipping"), topic);
|
||||
// DEBUG_LOG(("Empty JSON payload for topic %s. Skipping"), topic);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
std::string payload_text;
|
||||
serializeJson(payload, payload_text);
|
||||
@@ -491,9 +495,9 @@ void Mqtt::queue_publish_message(const char * topic, const JsonDocument & payloa
|
||||
}
|
||||
|
||||
// add MQTT message to queue, payload is a string
|
||||
void Mqtt::queue_publish_message(const char * topic, const std::string & payload, const bool retain) {
|
||||
void Mqtt::queue_publish_message(const std::string & topic, const std::string & payload, const bool retain) {
|
||||
// can't have bogus topics, but empty payloads are ok
|
||||
if (strlen(topic) == 0) {
|
||||
if (topic.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -525,29 +529,29 @@ void Mqtt::queue_subscribe_message(const std::string & topic) {
|
||||
}
|
||||
|
||||
// MQTT Publish, using a specific retain flag
|
||||
void Mqtt::publish(const char * topic, const char * payload, bool retain) {
|
||||
void Mqtt::publish(const std::string & topic, const std::string & payload, bool retain) {
|
||||
queue_publish_message(topic, payload, retain);
|
||||
}
|
||||
|
||||
// Publish using the user's custom retain flag
|
||||
void Mqtt::publish(const char * topic, const char * payload) {
|
||||
void Mqtt::publish(const std::string & topic, const std::string & payload) {
|
||||
publish(topic, payload, mqtt_retain_);
|
||||
}
|
||||
|
||||
void Mqtt::publish(const char * topic, const JsonDocument & payload) {
|
||||
void Mqtt::publish(const std::string & topic, const JsonDocument & payload) {
|
||||
publish(topic, payload, mqtt_retain_);
|
||||
}
|
||||
|
||||
void Mqtt::publish(const char * topic, const JsonDocument & payload, bool retain) {
|
||||
void Mqtt::publish(const std::string & topic, const JsonDocument & payload, bool retain) {
|
||||
queue_publish_message(topic, payload, retain);
|
||||
}
|
||||
|
||||
void Mqtt::publish(const char * topic, const bool value) {
|
||||
void Mqtt::publish(const std::string & topic, const bool value) {
|
||||
queue_publish_message(topic, value ? "1" : "0", mqtt_retain_);
|
||||
}
|
||||
|
||||
// no payload
|
||||
void Mqtt::publish(const char * topic) {
|
||||
void Mqtt::publish(const std::string & topic) {
|
||||
queue_publish_message(topic, "", mqtt_retain_);
|
||||
}
|
||||
|
||||
@@ -634,10 +638,10 @@ void Mqtt::process_queue() {
|
||||
}
|
||||
|
||||
mqtt_messages_.pop_front(); // remove the message from the queue
|
||||
} // namespace emsesp
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Mqtt::console_commands() {
|
||||
void Mqtt::console_commands(Shell & shell, unsigned int context) {
|
||||
EMSESPShell::commands->add_command(
|
||||
ShellContext::MQTT,
|
||||
CommandFlags::ADMIN,
|
||||
@@ -853,6 +857,9 @@ void Mqtt::console_commands() {
|
||||
shell.printfln(F_(mqtt_publish_time_fmt), settings.mqtt_publish_time());
|
||||
shell.println();
|
||||
});
|
||||
} // namespace emsesp
|
||||
|
||||
// enter the context
|
||||
Console::enter_custom_context(shell, context);
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
20
src/mqtt.h
20
src/mqtt.h
@@ -39,6 +39,8 @@
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
using uuid::console::Shell;
|
||||
|
||||
#define EMSESP_MAX_JSON_SIZE_SMALL 200 // for smaller json docs
|
||||
#define EMSESP_MAX_JSON_SIZE_MEDIUM 800 // for smaller json docs from ems devices
|
||||
#define EMSESP_MAX_JSON_SIZE_LARGE 1500 // for large json docs from ems devices, like boiler or thermostat data
|
||||
@@ -69,16 +71,16 @@ class Mqtt {
|
||||
static void subscribe(const uint8_t device_id, const std::string & topic, mqtt_function_p cb);
|
||||
static void subscribe(const std::string & topic, mqtt_function_p cb);
|
||||
|
||||
static void publish(const char * topic, const char * payload);
|
||||
static void publish(const char * topic, const char * payload, bool retain);
|
||||
static void publish(const char * topic, const JsonDocument & payload);
|
||||
static void publish(const char * topic, const JsonDocument & payload, bool retain);
|
||||
static void publish(const char * topic, const bool value);
|
||||
static void publish(const char * topic);
|
||||
static void publish(const std::string & topic, const std::string & payload);
|
||||
static void publish(const std::string & topic, const std::string & payload, bool retain);
|
||||
static void publish(const std::string & topic, const JsonDocument & payload);
|
||||
static void publish(const std::string & topic, const JsonDocument & payload, bool retain);
|
||||
static void publish(const std::string & topic, const bool value);
|
||||
static void publish(const std::string & topic);
|
||||
|
||||
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_id);
|
||||
|
||||
static void console_commands();
|
||||
static void console_commands(Shell & shell, unsigned int context);
|
||||
|
||||
void incoming(char * topic, char * payload); // for testing
|
||||
|
||||
@@ -130,8 +132,8 @@ class Mqtt {
|
||||
|
||||
static bool mqtt_retain_;
|
||||
|
||||
static void queue_publish_message(const char * topic, const JsonDocument & payload, const bool retain);
|
||||
static void queue_publish_message(const char * topic, const std::string & payload, const bool retain);
|
||||
static void queue_publish_message(const std::string & topic, const JsonDocument & payload, const bool retain);
|
||||
static void queue_publish_message(const std::string & topic, const std::string & payload, const bool retain);
|
||||
|
||||
static void queue_subscribe_message(const std::string & topic);
|
||||
|
||||
|
||||
@@ -346,6 +346,7 @@ void Network::show_network(uuid::console::Shell & shell) {
|
||||
shell.printfln(F("WiFi: unknown"));
|
||||
break;
|
||||
}
|
||||
|
||||
shell.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -54,20 +54,20 @@ void Solar::show_values(uuid::console::Shell & shell) {
|
||||
|
||||
char buffer[10]; // used for formatting
|
||||
|
||||
print_value(shell, F("Collector temperature (TS1)"), F_(degrees), Helpers::render_value(buffer, collectorTemp_, 10));
|
||||
print_value(shell, F("Bottom temperature (TS2)"), F_(degrees), Helpers::render_value(buffer, bottomTemp_, 10));
|
||||
print_value(shell, F("Bottom temperature (TS5)"), F_(degrees), Helpers::render_value(buffer, bottomTemp2_, 10));
|
||||
print_value(shell, F("Pump modulation"), F_(percent), Helpers::render_value(buffer, pumpModulation_, 1));
|
||||
print_value(shell, F("Valve (VS2) status"), Helpers::render_value(buffer, valveStatus_, EMS_VALUE_BOOL));
|
||||
print_value(shell, F("Pump (PS1) active"), Helpers::render_value(buffer, pump_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Collector temperature (TS1)"), F_(degrees), Helpers::render_value(buffer, collectorTemp_, 10));
|
||||
print_value(shell, 2, F("Bottom temperature (TS2)"), F_(degrees), Helpers::render_value(buffer, bottomTemp_, 10));
|
||||
print_value(shell, 2, F("Bottom temperature (TS5)"), F_(degrees), Helpers::render_value(buffer, bottomTemp2_, 10));
|
||||
print_value(shell, 2, F("Pump modulation"), F_(percent), Helpers::render_value(buffer, pumpModulation_, 1));
|
||||
print_value(shell, 2, F("Valve (VS2) status"), Helpers::render_value(buffer, valveStatus_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Pump (PS1) active"), Helpers::render_value(buffer, pump_, EMS_VALUE_BOOL));
|
||||
|
||||
if (pumpWorkMin_ != EMS_VALUE_ULONG_NOTSET) {
|
||||
shell.printfln(F(" Pump working time: %d days %d hours %d minutes"), pumpWorkMin_ / 1440, (pumpWorkMin_ % 1440) / 60, pumpWorkMin_ % 60);
|
||||
}
|
||||
|
||||
print_value(shell, F("Energy last hour"), F_(wh), Helpers::render_value(buffer, energyLastHour_, 10));
|
||||
print_value(shell, F("Energy today"), F_(wh), Helpers::render_value(buffer, energyToday_, 0)); // no division
|
||||
print_value(shell, F("Energy total"), F_(kwh), Helpers::render_value(buffer, energyTotal_, 10));
|
||||
print_value(shell, 2, F("Energy last hour"), F_(wh), Helpers::render_value(buffer, energyLastHour_, 10));
|
||||
print_value(shell, 2, F("Energy today"), F_(wh), Helpers::render_value(buffer, energyToday_, 0)); // no division
|
||||
print_value(shell, 2, F("Energy total"), F_(kwh), Helpers::render_value(buffer, energyTotal_, 10));
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
|
||||
@@ -334,7 +334,7 @@ void System::show_system(uuid::console::Shell & shell) {
|
||||
}
|
||||
|
||||
// console commands to add
|
||||
void System::console_commands() {
|
||||
void System::console_commands(Shell & shell, unsigned int context) {
|
||||
EMSESPShell::commands->add_command(ShellContext::SYSTEM,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(set), F_(hostname)},
|
||||
@@ -509,7 +509,6 @@ void System::console_commands() {
|
||||
flash_string_vector{F_(show)},
|
||||
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
Network::show_network(shell);
|
||||
shell.println();
|
||||
show_system(shell);
|
||||
shell.println();
|
||||
});
|
||||
@@ -522,7 +521,7 @@ void System::console_commands() {
|
||||
shell.printfln(F_(hostname_fmt),
|
||||
settings.hostname().empty() ? uuid::read_flash_string(F_(unset)).c_str() : settings.hostname().c_str());
|
||||
|
||||
if (shell.has_flags(CommandFlags::ADMIN | CommandFlags::LOCAL)) {
|
||||
if (shell.has_flags(CommandFlags::ADMIN)) {
|
||||
shell.printfln("Wifi:");
|
||||
shell.print(" ");
|
||||
shell.printfln(F_(wifi_ssid_fmt),
|
||||
@@ -540,6 +539,9 @@ void System::console_commands() {
|
||||
shell.printfln(F_(mark_interval_fmt), settings.syslog_mark_interval());
|
||||
}
|
||||
});
|
||||
|
||||
// enter the context
|
||||
Console::enter_custom_context(shell, context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
|
||||
#include <uuid/log.h>
|
||||
|
||||
using uuid::console::Shell;
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class System {
|
||||
@@ -63,7 +65,7 @@ class System {
|
||||
|
||||
static void show_mem(const char * text);
|
||||
|
||||
static void console_commands();
|
||||
static void console_commands(Shell & shell, unsigned int context);
|
||||
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// create some fake test data
|
||||
// used with the 'test' command, under su/admin
|
||||
void EMSESP::run_test(uuid::console::Shell & shell, const std::string & command) {
|
||||
// A fake response - UBADevices(0x07) - only for testing offline
|
||||
if (command == "devices") {
|
||||
rxservice_.ems_mask(EMSbus::EMS_MASK_BUDERUS); // this is important otherwise nothing will be picked up!
|
||||
|
||||
emsdevices.push_back(EMSFactory::add(EMSdevice::DeviceType::BOILER, EMSdevice::EMS_DEVICE_ID_BOILER, 0, "", "My Boiler", 0, 0));
|
||||
|
||||
// A fake response - UBADevices(0x07)
|
||||
uint8_t t0[] = {0x08, 0x00, 0x07, 0x00, 0x0B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47};
|
||||
rxservice_.add(t0, sizeof(t0));
|
||||
|
||||
@@ -21,6 +21,20 @@ void EMSESP::run_test(uuid::console::Shell & shell, const std::string & command)
|
||||
return;
|
||||
}
|
||||
|
||||
if (command == "unknown") {
|
||||
// question: do we need to set the mask?
|
||||
std::string version("1.2.3");
|
||||
add_device(0x09, 89, version, EMSdevice::Brand::BUDERUS);
|
||||
rxservice_.loop();
|
||||
|
||||
// simulate getting version information back from an unknown device
|
||||
uint8_t u1[] = {0x09, 0x0B, 0x02, 0x00, 0x59, 0x01, 0x02, 0x56};
|
||||
rxservice_.add(u1, sizeof(u1));
|
||||
rxservice_.loop();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (command == "thermostats") {
|
||||
shell.printfln(F("Testing adding devices on the EMS bus..."));
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
register_telegram_type(EMS_TYPE_RCOutdoorTemp, F("RCOutdoorTemp"), false, std::bind(&Thermostat::process_RCOutdoorTemp, this, _1));
|
||||
register_telegram_type(EMS_TYPE_RCTime, F("RCTime"), true, std::bind(&Thermostat::process_RCTime, this, _1)); // 0x06
|
||||
|
||||
// RC10
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_RC10) {
|
||||
monitor_typeids = {0xB1};
|
||||
set_typeids = {0xB0};
|
||||
@@ -47,6 +48,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
register_telegram_type(set_typeids[i], F("RC10Set"), true, std::bind(&Thermostat::process_RC10Set, this, _1));
|
||||
}
|
||||
|
||||
// RC35
|
||||
} else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC35) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC30_1)) {
|
||||
monitor_typeids = {0x3E, 0x48, 0x52, 0x5C};
|
||||
set_typeids = {0x3D, 0x47, 0x51, 0x5B};
|
||||
@@ -56,6 +58,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
}
|
||||
register_telegram_type(EMS_TYPE_IBASettings, F("IBASettings"), true, std::bind(&Thermostat::process_IBASettings, this, _1));
|
||||
|
||||
// RC20
|
||||
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20) {
|
||||
monitor_typeids = {0x91};
|
||||
set_typeids = {0xA8};
|
||||
@@ -64,6 +67,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
register_telegram_type(set_typeids[i], F("RC20Set"), true, std::bind(&Thermostat::process_RC20Set, this, _1));
|
||||
}
|
||||
|
||||
// RC20 newer
|
||||
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20_2) {
|
||||
monitor_typeids = {0xAE};
|
||||
set_typeids = {0xAD};
|
||||
@@ -72,6 +76,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
register_telegram_type(set_typeids[i], F("RC20Set"), true, std::bind(&Thermostat::process_RC20Set_2, this, _1));
|
||||
}
|
||||
|
||||
// RC30
|
||||
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_RC30) {
|
||||
monitor_typeids = {0x41};
|
||||
set_typeids = {0xA7};
|
||||
@@ -80,11 +85,13 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
register_telegram_type(set_typeids[i], F("RC30Set"), true, std::bind(&Thermostat::process_RC30Set, this, _1));
|
||||
}
|
||||
|
||||
// EASY
|
||||
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_EASY) {
|
||||
monitor_typeids = {0x0A};
|
||||
set_typeids = {};
|
||||
register_telegram_type(monitor_typeids[0], F("EasyMonitor"), true, std::bind(&Thermostat::process_EasyMonitor, this, _1));
|
||||
|
||||
// RC300/RC100
|
||||
} else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC300) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC100)) {
|
||||
monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8};
|
||||
set_typeids = {0x02B9, 0x02BA, 0x02BB, 0x02BC};
|
||||
@@ -93,6 +100,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
register_telegram_type(set_typeids[i], F("RC300Set"), true, std::bind(&Thermostat::process_RC300Set, this, _1));
|
||||
}
|
||||
|
||||
// JUNKERS/HT3
|
||||
} else if (flags == EMSdevice::EMS_DEVICE_FLAG_JUNKERS) {
|
||||
monitor_typeids = {0x6F, 0x70, 0x71, 0x72};
|
||||
set_typeids = {0x65, 0x66, 0x67, 0x68};
|
||||
@@ -194,8 +202,7 @@ void Thermostat::add_context_menu() {
|
||||
CommandFlags::USER,
|
||||
flash_string_vector{F_(thermostat)},
|
||||
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||
dynamic_cast<EMSESPShell &>(shell).enter_custom_context(ShellContext::THERMOSTAT);
|
||||
console_commands();
|
||||
Thermostat::console_commands(shell, ShellContext::THERMOSTAT);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -326,7 +333,7 @@ bool Thermostat::updated_values() {
|
||||
}
|
||||
|
||||
return false;
|
||||
} // namespace emsesp
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
void Thermostat::publish_values() {
|
||||
@@ -337,7 +344,7 @@ void Thermostat::publish_values() {
|
||||
|
||||
DEBUG_LOG(F("Performing a thermostat publish (device ID 0x%02X)"), device_id());
|
||||
|
||||
uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits
|
||||
uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, stripping the option bits
|
||||
bool has_data = false;
|
||||
|
||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
|
||||
@@ -364,6 +371,7 @@ void Thermostat::publish_values() {
|
||||
}
|
||||
|
||||
has_data = true;
|
||||
// if the MQTT format is 'nested' then create the parent object hc<n>
|
||||
if (mqtt_format_ == Settings::MQTT_format::NESTED) {
|
||||
// create nested json for each HC
|
||||
char hc_name[10]; // hc{1-4}
|
||||
@@ -533,6 +541,10 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
// decodes the thermostat mode for the heating circuit based on the thermostat type
|
||||
// modes are off, manual, auto, day and night
|
||||
uint8_t Thermostat::HeatingCircuit::get_mode(uint8_t flags) const {
|
||||
if (mode == EMS_VALUE_UINT_NOTSET) {
|
||||
return HeatingCircuit::Mode::UNKNOWN;
|
||||
}
|
||||
|
||||
flags &= 0x0F; // strip top 4 bits
|
||||
|
||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_RC20) {
|
||||
@@ -565,7 +577,7 @@ uint8_t Thermostat::HeatingCircuit::get_mode(uint8_t flags) const {
|
||||
}
|
||||
}
|
||||
|
||||
return HeatingCircuit::Mode::OFF;
|
||||
return HeatingCircuit::Mode::UNKNOWN;
|
||||
}
|
||||
|
||||
// figures out the thermostat day/night mode depending on the thermostat type
|
||||
@@ -629,10 +641,13 @@ std::string Thermostat::mode_tostring(uint8_t mode) const {
|
||||
case HeatingCircuit::Mode::NOFROST:
|
||||
return read_flash_string(F("nofrost"));
|
||||
break;
|
||||
default:
|
||||
case HeatingCircuit::Mode::AUTO:
|
||||
return read_flash_string(F("auto"));
|
||||
break;
|
||||
default:
|
||||
case HeatingCircuit::Mode::UNKNOWN:
|
||||
return read_flash_string(F("unknown"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,16 +660,16 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
|
||||
if (datetime_.size()) {
|
||||
shell.printfln(F(" Clock: %s"), datetime_.c_str());
|
||||
if (ibaClockOffset != EMS_VALUE_UINT_NOTSET) {
|
||||
print_value(shell, F("Offset clock"), Helpers::render_value(buffer, ibaClockOffset, 1)); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
|
||||
print_value(shell, 1, F("Offset clock"), Helpers::render_value(buffer, ibaClockOffset, 1)); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits
|
||||
|
||||
if (flags == EMS_DEVICE_FLAG_RC35) {
|
||||
print_value(shell, F("Damped Outdoor temperature"), F_(degrees), Helpers::render_value(buffer, dampedoutdoortemp, 1));
|
||||
print_value(shell, F("Tempsensor 1"), F_(degrees), Helpers::render_value(buffer, tempsensor1, 10));
|
||||
print_value(shell, F("Tempsensor 2"), F_(degrees), Helpers::render_value(buffer, tempsensor2, 10));
|
||||
print_value(shell, 1, F("Damped Outdoor temperature"), F_(degrees), Helpers::render_value(buffer, dampedoutdoortemp, 1));
|
||||
print_value(shell, 1, F("Tempsensor 1"), F_(degrees), Helpers::render_value(buffer, tempsensor1, 10));
|
||||
print_value(shell, 1, F("Tempsensor 2"), F_(degrees), Helpers::render_value(buffer, tempsensor2, 10));
|
||||
}
|
||||
|
||||
for (const auto & hc : heating_circuits_) {
|
||||
@@ -677,10 +692,14 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
|
||||
break;
|
||||
}
|
||||
|
||||
print_value(shell, F("Current room temperature"), F_(degrees), Helpers::render_value(buffer, hc->curr_roomTemp, format_curr));
|
||||
print_value(shell, F("Setpoint room temperature"), F_(degrees), Helpers::render_value(buffer, hc->setpoint_roomTemp, format_setpoint));
|
||||
print_value(shell, F("Mode"), mode_tostring(hc->get_mode(flags)).c_str());
|
||||
print_value(shell, F("Mode Type"), mode_tostring(hc->get_mode_type(flags)).c_str());
|
||||
print_value(shell, 2, F("Current room temperature"), F_(degrees), Helpers::render_value(buffer, hc->curr_roomTemp, format_curr));
|
||||
print_value(shell, 2, F("Setpoint room temperature"), F_(degrees), Helpers::render_value(buffer, hc->setpoint_roomTemp, format_setpoint));
|
||||
if (hc->mode != EMS_VALUE_UINT_NOTSET) {
|
||||
print_value(shell, 2, F("Mode"), mode_tostring(hc->get_mode(flags)).c_str());
|
||||
}
|
||||
if (hc->mode_type != EMS_VALUE_UINT_NOTSET) {
|
||||
print_value(shell, 2, F("Mode Type"), mode_tostring(hc->get_mode_type(flags)).c_str());
|
||||
}
|
||||
|
||||
if ((flags == EMS_DEVICE_FLAG_RC35) || (flags == EMS_DEVICE_FLAG_RC30_1)) {
|
||||
if (hc->summer_mode) {
|
||||
@@ -689,19 +708,19 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
|
||||
shell.printfln(F(" Program is set to Holiday mode"));
|
||||
}
|
||||
|
||||
print_value(shell, F("Day temperature"), F_(degrees), Helpers::render_value(buffer, hc->daytemp, 2));
|
||||
print_value(shell, F("Night temperature"), F_(degrees), Helpers::render_value(buffer, hc->nighttemp, 2));
|
||||
print_value(shell, F("Vacation temperature"), F_(degrees), Helpers::render_value(buffer, hc->holidaytemp, 2));
|
||||
print_value(shell, 2, F("Day temperature"), F_(degrees), Helpers::render_value(buffer, hc->daytemp, 2));
|
||||
print_value(shell, 2, F("Night temperature"), F_(degrees), Helpers::render_value(buffer, hc->nighttemp, 2));
|
||||
print_value(shell, 2, F("Vacation temperature"), F_(degrees), Helpers::render_value(buffer, hc->holidaytemp, 2));
|
||||
|
||||
if (hc->offsettemp < 100) {
|
||||
print_value(shell, F("Offset temperature"), F_(degrees), Helpers::render_value(buffer, hc->offsettemp, 2));
|
||||
print_value(shell, 2, F("Offset temperature"), F_(degrees), Helpers::render_value(buffer, hc->offsettemp, 2));
|
||||
}
|
||||
print_value(shell, F("Design temperature"), F_(degrees), Helpers::render_value(buffer, hc->designtemp, 2));
|
||||
print_value(shell, 2, F("Design temperature"), F_(degrees), Helpers::render_value(buffer, hc->designtemp, 2));
|
||||
}
|
||||
|
||||
// show flow temp if we have it
|
||||
if (hc->circuitcalctemp != EMS_VALUE_UINT_NOTSET) {
|
||||
print_value(shell, F("Calculated flow temperature"), F_(degrees), Helpers::render_value(buffer, hc->circuitcalctemp, 1));
|
||||
print_value(shell, 2, F("Calculated flow temperature"), F_(degrees), Helpers::render_value(buffer, hc->circuitcalctemp, 1));
|
||||
}
|
||||
|
||||
// settings parameters
|
||||
@@ -740,11 +759,11 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
|
||||
}
|
||||
|
||||
if (ibaCalIntTemperature != EMS_VALUE_INT_NOTSET) {
|
||||
print_value(shell, F("Offset int. temperature"), F_(degrees), Helpers::render_value(buffer, ibaCalIntTemperature, 2));
|
||||
print_value(shell, 2, F("Offset int. temperature"), F_(degrees), Helpers::render_value(buffer, ibaCalIntTemperature, 2));
|
||||
}
|
||||
|
||||
if (ibaMinExtTemperature != EMS_VALUE_INT_NOTSET) {
|
||||
print_value(shell, F("Min ext. temperature"), F_(degrees), Helpers::render_value(buffer, ibaMinExtTemperature, 10)); // min ext temp for heating curve, in deg.
|
||||
print_value(shell, 2, F("Min ext. temperature"), F_(degrees), Helpers::render_value(buffer, ibaMinExtTemperature, 10)); // min ext temp for heating curve, in deg.
|
||||
}
|
||||
|
||||
if (ibaBuildingType != EMS_VALUE_UINT_NOTSET) {
|
||||
@@ -1238,7 +1257,7 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co
|
||||
}
|
||||
|
||||
// add console commands
|
||||
void Thermostat::console_commands() {
|
||||
void Thermostat::console_commands(Shell & shell, unsigned int context) {
|
||||
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
||||
CommandFlags::ADMIN,
|
||||
flash_string_vector{F_(set), F_(master)},
|
||||
@@ -1318,6 +1337,9 @@ void Thermostat::console_commands() {
|
||||
: Helpers::hextoa(buffer, settings.master_thermostat()));
|
||||
shell.println();
|
||||
});
|
||||
|
||||
// enter the context
|
||||
Console::enter_custom_context(shell, context);
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
@@ -76,7 +76,7 @@ class Thermostat : public EMSdevice {
|
||||
return set_typeid_;
|
||||
}
|
||||
|
||||
enum Mode : uint8_t { OFF, MANUAL, AUTO, DAY, NIGHT, HEAT, NOFROST, ECO, HOLIDAY, COMFORT, OFFSET, DESIGN };
|
||||
enum Mode : uint8_t { UNKNOWN, OFF, MANUAL, AUTO, DAY, NIGHT, HEAT, NOFROST, ECO, HOLIDAY, COMFORT, OFFSET, DESIGN };
|
||||
|
||||
private:
|
||||
uint8_t hc_num_;
|
||||
@@ -103,7 +103,7 @@ class Thermostat : public EMSdevice {
|
||||
private:
|
||||
static uuid::log::Logger logger_;
|
||||
|
||||
void console_commands();
|
||||
void console_commands(Shell & shell, unsigned int context);
|
||||
void init_mqtt();
|
||||
|
||||
std::string datetime_; // date and time stamp
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "2.0.0a4"
|
||||
#define EMSESP_APP_VERSION "2.0.0a6"
|
||||
|
||||
Reference in New Issue
Block a user