mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-09 09:19:51 +03:00
Merge branch 'v2' of https://github.com/proddy/EMS-ESP into v2
This commit is contained in:
117
README.md
117
README.md
@@ -1,70 +1,61 @@
|
||||
# EMS-ESP version 2.0 (alpha)
|
||||
|
||||
*Warning: this is still in early stages of it's development. Not all features have been fully tested. Use at your own risk!*
|
||||
|
||||
Note: Version 2.0 is not backward compatible with v1.0. The File system structure is different. When coming from version 1.9.x its best if you first erase the flash on the ESP and upload using USB. `esptool.py erase_flash` will clean the flash and `esptool.py -p COM6 -b 921600 write_flash 0x00000 firmware.bin` is an example of how to upload the firmware over USB.
|
||||
*Warning: this is still in development and not all features have been fully tested.*
|
||||
|
||||
---
|
||||
|
||||
## Major changes since version 1.9.x
|
||||
## **New Features in v2**
|
||||
|
||||
### **Design & coding principles**
|
||||
|
||||
- The code can be built and run without an ESP microcontroller, which is useful when testing and simulating handling of the different telegrams and devices. Make sure you have GNU make and g++ installed and use 'make' to build the image and execute the file `emsesp` (on linux).
|
||||
- I used C++11 containers where I could (std::string, std::deque, std::list, std::multimap etc).
|
||||
- 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 for now.
|
||||
|
||||
### **Features**
|
||||
|
||||
- A web interface built using React and TypeScript to be secure and cross-browser compatible. Each restful endpoint is protected and issues a JWT which is then sent using Bearer Authentication. Implements a Web captive portal. On first installs EMS-ESP starts an Access Point where system settings can be configured. Note, this is still in a separate repo and pending a merge into this project.
|
||||
- A new web interface using React and TypeScript that's now secure as each URL endpoint is protected by issuing a JWT which is then sent using Bearer Authentication. Using a Captive Portal in AP mode or connecting to a local wifi network.
|
||||
|
||||
- A new console. Like in version 1.9 it works with both Serial and Telnet but a lot more intuitive, behaving similar to a Linux-style shell. It supports multiple connections and any commands that effect the behavior of EMS-ESP are secure behind an admin password. You can use TAB to auto-complete commands, ctrl-L, ctrl-U and the other typical console type shortcuts. ctrl-D to exit the current menu. Some other important commands:
|
||||
- A new console. Like in version 1.9 it works with both Serial and Telnet but with a rich set of commands and more intuitive with behavior similar to a Linux-style shell. It supports multiple connections and commands that alter the settings or interact directly with EMS devices are secure behind an admin password. A full list of commands is below, here are the key ones:
|
||||
* `help` lists the commands and keywords
|
||||
* some commands take you into a new context, a bit like a sub-menu. e.g. `system`, `mqtt`, `thermostat`. Use `help` to show which commands this context has and `exit` or CTRL-D to get back to the root.
|
||||
* To change a setting use the `set` command. Typing `set` shows the current settings.
|
||||
* `show` shows the data specific to the context you're in.
|
||||
* `show` shows the data specific to the which context you're in.
|
||||
* `su` to switch to Admin which enables more commands such as most of the `set` commands. The default password is "neo" which can be changed with `passwd` from the system menu. When in Admin mode the command prompt switches from `$` to `#`.
|
||||
* `log` sets the logging. `log off` disables logging. Use `log trace` to see the telegram traffic and `log debug` for very verbose logging. To watch a specific telegram ID or device ID use `log trace [full|raw| [id]`.
|
||||
* `log` sets the logging level. `log off` disables logging. Use `log debug` for debugging commands and actions.
|
||||
* `watch` from the ems context, will output the incoming Rx telegrams to the console. You can also show these in its 'raw' data format and also watch a particular ID.
|
||||
* CTRL-D to exit, CTRL-U to remove line, TAB to auto-complete
|
||||
|
||||
- There is no "serial mode" anymore like with version 1.9. When the Wifi cannot connect to the SSID it will automatically enter a "safe" mode where the Serial console is activated automatically (baud 115200). Note Serial is always available on the ESP32 because it has multiple UARTs.
|
||||
|
||||
- There is no "serial mode" anymore like with version 1.9. When the Wifi cannot connect to the SSID it will automatically enter a "safe" mode where the Serial console is activated, baud 115200. Note Serial is always available on the ESP32 because it has multiple UARTs.
|
||||
- The onboard LED behaves like in 1.9. A solid LED means good connection and EMS data is coming in. A slow pulse means either the WiFi or the EMS bus is not connected yet. A very fast pulse is when the system is booting up and configuring itself, which typically takes 5 seconds.
|
||||
|
||||
- LED behaves like in 1.9. A solid LED means good connection and EMS data is coming in. A slow pulse means either the WiFi or the EMS bus is not connected. A very fast pulse is when the system is booting up and configuring itself.
|
||||
- Built to work with both EMS8266 and ESP32
|
||||
|
||||
### Uploading the firmware
|
||||
- Extended MQTT to use MQTT discovery on Home Assistant.
|
||||
|
||||
- If you don't have Python 3.8:
|
||||
- first install it (https://www.python.org/downloads/)
|
||||
- install `esptool` using the command `pip install esptool`
|
||||
- also for OTA updates later, download `espota` from https://github.com/esp8266/Arduino/blob/master/tools/espota.py
|
||||
- For debugging there is an offline mode where the code can be compiled and executed standalone without uploading to an ESP controller. Use `make` (based off GNUMakefile).
|
||||
|
||||
- Grab the firmware binary from https://github.com/proddy/EMS-ESP/releases/tag/travis-v2-build
|
||||
- Using direct to USB: `esptool.py -p <COM PORT> -b 921600 write_flash 0x00000 <firmware.bin>`
|
||||
- Using OTA (Over The Air): `espota.py --debug --progress --port 8266 --auth neo -i <ip address> -f <firmware.bin>`
|
||||
|
||||
### Setting up for the first time:
|
||||
## **Uploading the firmware**
|
||||
|
||||
- connect the ESP8266/ESP32 via USB and enter via the serial/com port with baud 115200
|
||||
- If you're not using PlatformIO, use the command-line and Python. You can download Python from https://www.python.org/downloads/. Make sure you also get:
|
||||
- `esptool`, install using the command `pip install esptool`
|
||||
- and for OTA updates later, `espota` from https://github.com/esp8266/Arduino/blob/master/tools/espota.py
|
||||
|
||||
- Grab the latest firmware binary from https://github.com/proddy/EMS-ESP/releases/tag/travis-v2-build
|
||||
- Uploading directly via USB: `esptool.py -p <COM PORT> -b 921600 write_flash 0x00000 <firmware.bin>`
|
||||
- Uploading over WiFi: `espota.py --debug --progress --port 8266 --auth neo -i <IP address> -f <firmware.bin>`
|
||||
|
||||
## **Setting EMS-ESP up for the first time**
|
||||
|
||||
- connect the ESP8266/ESP32 via USB. If you're coming from version 1.9 all the settings will be erased. If you want a full clean system do a `esptool.py erase_flash` first
|
||||
- enter USB via the serial/com/tty port with baud 115200, with something like putty
|
||||
- type `su` and use the default password *neo*
|
||||
- type `system` to go to the system sub-menu (which we call a context)
|
||||
- type `system` to go to the system sub-menu/context
|
||||
- type `help` if you want see the available commands
|
||||
- type `set` to see the current settings
|
||||
- use `set wifi` to change the SSID and password. Remember TAB auto-completes the command
|
||||
- use `set wifi ssid` to change the SSID and password. Remember TAB auto-completes commands if you're not sure of the next parameter.
|
||||
- CTRL-D to get back to the root
|
||||
- use `mqtt` to enter the MQTT menu. Same approach using the `set` command to set the MQTT IP and any credentials. CTRL-D to get back to the root.
|
||||
- use `ems` to change to the EMS BUS tx mode if you find Tx is not working.
|
||||
- reboot and next time use the Telnet via WiFi to connect as the serial mode will be disabled.
|
||||
- use `mqtt` to enter the MQTT context. Using the same approach, use `help` and `set` command to set the MQTT IP and any credentials. Then CTRL-D to get back to the root.
|
||||
- reboot and next time use the Telnet via WiFi to connect as the serial mode will be disabled. The EMS-ESP should have a solid LED or a slow pulsing LED.
|
||||
- Telnet to the IP to get back into the console.
|
||||
- If Tx is not working you will see errors show up in red. Use `ems` to change to the EMS context and `set` to see the default values. Try different `tx_mode` settings. 1 is default for EMS 1.0. EMS 2.0 is 2 and HT3/Bosch/Junkers is 3. Then a `refresh` to see if it's working. There is no need to reboot.
|
||||
- `show` to show all values.
|
||||
|
||||
### Debugging
|
||||
- Turn on logging with either `log all` or `log debug`
|
||||
- Error messages are shown in the color red
|
||||
- type `show` from the main root to see if any data has come in
|
||||
- if not, go to the `ems` context and type `show` which will display some EMS bus stats
|
||||
- use the `refresh` command to fetch new data from the EMS bus
|
||||
- use `scan devices` or `scan devices deep` to locate devices on the EMS bus. If any are unknown please report back to the project so we can update our EMS device library.
|
||||
|
||||
# List of console commands
|
||||
## **List of console commands**
|
||||
|
||||
```
|
||||
common commands available in all contexts:
|
||||
@@ -72,10 +63,11 @@ common commands available in all contexts:
|
||||
help
|
||||
log [level]
|
||||
su
|
||||
set
|
||||
show
|
||||
|
||||
(top root level)
|
||||
refresh
|
||||
show
|
||||
show version
|
||||
ems (enters a context)
|
||||
mqtt (enters a context)
|
||||
@@ -86,12 +78,10 @@ common commands available in all contexts:
|
||||
ems
|
||||
scan devices [deep]
|
||||
send telegram <"XX XX ...">
|
||||
set
|
||||
set bus_id <device ID>
|
||||
set read_only <on | off>
|
||||
set tx_mode <n>
|
||||
refresh
|
||||
show
|
||||
show devices
|
||||
show emsbus
|
||||
show values
|
||||
@@ -100,7 +90,6 @@ ems
|
||||
mqtt
|
||||
publish
|
||||
reconnect
|
||||
set
|
||||
set base <name>
|
||||
set enabled <on | off>
|
||||
set heartbeat <on | off>
|
||||
@@ -110,21 +99,17 @@ mqtt
|
||||
set publish_time <seconds>
|
||||
set qos <n>
|
||||
set username [name]
|
||||
show
|
||||
|
||||
system
|
||||
format
|
||||
passwd
|
||||
restart
|
||||
set
|
||||
set syslog host [IP address]
|
||||
set syslog level [level]
|
||||
set syslog mark [seconds]
|
||||
set wifi hostname <name>
|
||||
set wifi password
|
||||
set wifi ssid <name>
|
||||
show
|
||||
test <name>
|
||||
wifi disconnect
|
||||
wifi reconnect
|
||||
wifi scan
|
||||
@@ -137,37 +122,27 @@ boiler
|
||||
change wwonetime <on | off>
|
||||
change wwtemp <degrees>
|
||||
read <type ID>
|
||||
set
|
||||
set shower alert <on | off>
|
||||
set shower timer <on | off>
|
||||
show
|
||||
|
||||
thermostat
|
||||
change mode <mode> [heating circuit]
|
||||
change temp <degrees> [heating circuit]
|
||||
read <type ID>
|
||||
set
|
||||
set master [device ID]
|
||||
show
|
||||
```
|
||||
|
||||
----------
|
||||
|
||||
### **Known issues, bugs and improvements currently being worked on**
|
||||
### **Basic Design Principles**
|
||||
|
||||
```
|
||||
TODO Optimized ESP8266 and ESP32 UART code (via Michael)
|
||||
TODO merge in the web code which has the Captive AP and better wifi reconnect logic. Use IPV6 and NTP from lwip2
|
||||
```
|
||||
- The core services like telnet, logging and shell are based off the libraries from @nomis. I also 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, mixing units 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 we can extend with new telegrams types and features.
|
||||
|
||||
### **To tidy up in code later**
|
||||
### **Things to tidy up in code later**
|
||||
|
||||
```
|
||||
TODO replace vectors of class objects with shared pointers and use emplace_back since it instantiates during construction. It may have a performance gain.
|
||||
TODO make more use of comparison operators in the Telegram class e.g. the compare like "friend inline bool operator==(const Telegram & lhs, const Telegram & rhs)"
|
||||
TODO replace read_value with C++ Templates per data type
|
||||
TODO exit from serial should be prevented? Because you never can really exit, just close it.
|
||||
TODO add real unit tests using platformio's test bed (https://docs.platformio.org/en/latest/plus/pio-remote.html)
|
||||
TODO See if it's easier to use timers instead of millis() based timers, using https://github.com/esp8266/Arduino/blob/master/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino
|
||||
```
|
||||
- Replace vectors of class objects with shared pointers and use emplace_back since it instantiates during construction. It may have a performance gain.
|
||||
- Make more use of comparison operators in the Telegram class e.g. the compare like "friend inline bool operator==(const Telegram & lhs, const Telegram & rhs)"
|
||||
- Add real unit tests using platformio's test bed (https://docs.platformio.org/en/latest/plus/pio-remote.html)
|
||||
- See if it's easier to use timers instead of millis() based timers, using https://github.com/esp8266/Arduino/blob/master/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino
|
||||
|
||||
|
||||
@@ -410,7 +410,7 @@ void Console::start() {
|
||||
shell = std::make_shared<EMSESPStreamConsole>(serial_console_, true);
|
||||
shell->maximum_log_messages(100); // default is 50
|
||||
shell->start();
|
||||
shell->log_level(uuid::log::Level::DEBUG); // order is: err, warning, notice, info, trace, debug, all
|
||||
shell->log_level(uuid::log::Level::DEBUG); // order is: err, warning, notice, info, debug, trace, all
|
||||
|
||||
#if defined(EMSESP_STANDALONE)
|
||||
shell->add_flags(CommandFlags::ADMIN);
|
||||
|
||||
@@ -63,15 +63,12 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
|
||||
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(0xE3, F("UBAMonitorSlowPlus"), false, std::bind(&Boiler::process_UBAMonitorSlowPlus2, 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(0xE9, F("UBADHWStatus"), false, std::bind(&Boiler::process_UBADHWStatus, this, _1));
|
||||
|
||||
// HeatPump specific
|
||||
register_telegram_type(0xE3, F("HeatPumpMonitor1"), false, std::bind(&Boiler::process_HPMonitor1, this, _1));
|
||||
register_telegram_type(0xE5, F("HeatPumpMonitor2"), false, std::bind(&Boiler::process_HPMonitor2, this, _1));
|
||||
|
||||
// MQTT callbacks
|
||||
register_mqtt_topic("boiler_cmd", std::bind(&Boiler::boiler_cmd, this, _1));
|
||||
register_mqtt_topic("boiler_cmd_wwactivated", std::bind(&Boiler::boiler_cmd_wwactivated, this, _1));
|
||||
@@ -195,6 +192,9 @@ void Boiler::publish_values() {
|
||||
if (Helpers::hasValue(pumpMod_)) {
|
||||
doc["pumpMod"] = pumpMod_;
|
||||
}
|
||||
if (Helpers::hasValue(pumpMod2_)) {
|
||||
doc["pumpMod2"] = pumpMod2_;
|
||||
}
|
||||
if (Helpers::hasValue(wWCircPump_, true)) {
|
||||
doc["wWCircPump"] = Helpers::render_value(s, wWCircPump_, EMS_VALUE_BOOL);
|
||||
}
|
||||
@@ -312,15 +312,6 @@ void Boiler::publish_values() {
|
||||
doc["serviceCodeNumber"] = serviceCode_;
|
||||
}
|
||||
|
||||
// heatpump specific
|
||||
if (Helpers::hasValue(hpModulation_)) {
|
||||
doc["pumpmodulation"] = hpModulation_;
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(hpSpeed_)) {
|
||||
doc["pumpspeed"] = hpSpeed_;
|
||||
}
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
LOG_DEBUG(F("[DEBUG] Performing a boiler publish"));
|
||||
#endif
|
||||
@@ -340,21 +331,19 @@ bool Boiler::updated_values() {
|
||||
void Boiler::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // for showing the header
|
||||
|
||||
char buffer[10]; // used for formatting
|
||||
|
||||
if (Helpers::hasValue(tap_water_active_, true)) {
|
||||
print_value(shell, 2, F("Hot tap water"), tap_water_active_ ? "running" : "off");
|
||||
print_value(shell, 2, F("Hot tap water"), tap_water_active_ ? F("running") : F("off"));
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(heating_active_, true)) {
|
||||
print_value(shell, 2, F("Central heating"), heating_active_ ? "active" : "off");
|
||||
print_value(shell, 2, F("Central heating"), heating_active_ ? F("active") : F("off"));
|
||||
}
|
||||
|
||||
print_value(shell, 2, F("Warm Water activated"), Helpers::render_value(buffer, wWActivated_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Warm Water charging type"), wWCircPumpType_ ? "3-way valve" : "charge pump");
|
||||
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 activated"), wWActivated_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Warm Water charging type"), wWCircPumpType_ ? F("3-way valve") : F("charge pump"));
|
||||
print_value(shell, 2, F("Warm Water circulation pump available"), wWCircPump_, nullptr, EMS_VALUE_BOOL);
|
||||
if (wWCircPumpMode_ == 7) {
|
||||
print_value(shell, 2, F("Warm Water circulation pump freq"), "continuous");
|
||||
print_value(shell, 2, F("Warm Water circulation pump freq"), F("continuous"));
|
||||
} else {
|
||||
char s[7];
|
||||
char buffer[2];
|
||||
@@ -362,67 +351,67 @@ void Boiler::show_values(uuid::console::Shell & shell) {
|
||||
buffer[1] = '\0';
|
||||
strlcpy(s, buffer, 7);
|
||||
strlcat(s, "x3min", 7);
|
||||
print_value(shell, 2, F("Warm Water circulation pump freq"), s);
|
||||
print_value(shell, 2, F("Warm Water circulation pump freq"), FPSTR(s)); // TODO check
|
||||
}
|
||||
print_value(shell, 2, F("Warm Water circulation active"), Helpers::render_value(buffer, wWCirc_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Warm Water circulation active"), wWCirc_, nullptr, EMS_VALUE_BOOL);
|
||||
|
||||
if (wWComfort_ == 0x00) {
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), "Hot");
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), F("Hot"));
|
||||
} else if (wWComfort_ == 0xD8) {
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), "Eco");
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), F("Eco"));
|
||||
} else if (wWComfort_ == 0xEC) {
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), "Intelligent");
|
||||
print_value(shell, 2, F("Warm Water comfort setting"), F("Intelligent"));
|
||||
}
|
||||
|
||||
print_value(shell, 2, F("Warm water mix temperature"), F_(degrees), Helpers::render_value(buffer, wwMixTemperature_, 10));
|
||||
print_value(shell, 2, F("Warm water buffer boiler temperature"), F_(degrees), Helpers::render_value(buffer, wwBufferBoilerTemperature_, 10));
|
||||
|
||||
print_value(shell, 2, F("Warm Water disinfection temperature"), F_(degrees), Helpers::render_value(buffer, wWDisinfectTemp_, 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 set temperature"), F_(degrees), Helpers::render_value(buffer, wWSetTmp_, 1));
|
||||
print_value(shell, 2, F("Warm Water current temperature (intern)"), F_(degrees), Helpers::render_value(buffer, wWCurTmp_, 10));
|
||||
print_value(shell, 2, F("Warm water storage temperature (intern)"), F_(degrees), Helpers::render_value(buffer, wwStorageTemp1_, 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 storage temperature (extern)"), F_(degrees), Helpers::render_value(buffer, wwStorageTemp2_, 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));
|
||||
print_value(shell, 2, F("Warm water mix temperature"), wwMixTemperature_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm water buffer boiler temperature"), wwBufferBoilerTemperature_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm Water disinfection temperature"), wWDisinfectTemp_, F_(degrees), 1);
|
||||
print_value(shell, 2, F("Warm Water selected temperature"), wWSelTemp_, F_(degrees), 1);
|
||||
print_value(shell, 2, F("Warm Water set temperature"), wWSetTmp_, F_(degrees), 1);
|
||||
print_value(shell, 2, F("Warm Water current temperature (intern)"), wWCurTmp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm water storage temperature (intern)"), wwStorageTemp1_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm Water current temperature (extern)"), wWCurTmp2_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm water storage temperature (extern)"), wwStorageTemp2_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Warm Water current tap water flow"), wWCurFlow_, F("l/min"), 10);
|
||||
print_value(shell, 2, F("Warm Water # starts"), wWStarts_, nullptr, 1);
|
||||
if (Helpers::hasValue(wWWorkM_)) {
|
||||
shell.printfln(F(" Warm Water active time: %d days %d hours %d minutes"), wWWorkM_ / 1440, (wWWorkM_ % 1440) / 60, wWWorkM_ % 60);
|
||||
}
|
||||
print_value(shell, 2, F("Warm Water charging"), Helpers::render_value(buffer, wWHeat_, EMS_VALUE_BOOL));
|
||||
print_value(shell, 2, F("Warm Water disinfecting"), Helpers::render_value(buffer, wWDesinfecting_, 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("Warm Water charging"), wWHeat_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Warm Water disinfecting"), wWDesinfecting_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Selected flow temperature"), selFlowTemp_, F_(degrees), 1);
|
||||
print_value(shell, 2, F("Current flow temperature"), curFlowTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Max boiler temperature"), boilTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Return temperature"), retTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Gas"), burnGas_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Boiler pump"), heatPmp_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Fan"), fanWork_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Ignition"), ignWork_, nullptr, EMS_VALUE_BOOL);
|
||||
|
||||
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));
|
||||
print_value(shell, 2, F("Burner selected max power"), selBurnPow_, F_(percent), 1);
|
||||
print_value(shell, 2, F("Burner current power"), curBurnPow_, F_(percent), 1);
|
||||
print_value(shell, 2, F("Flame current"), flameCurr_, F("uA"), 10);
|
||||
print_value(shell, 2, F("System pressure"), sysPress_, F("bar"), 10);
|
||||
if (Helpers::hasValue(serviceCode_)) {
|
||||
shell.printfln(F(" System service code: %s (%d)"), serviceCodeChar_, serviceCode_);
|
||||
} else if (serviceCodeChar_[0] != '\0') {
|
||||
shell.printfln(F(" System service code: %s"), serviceCodeChar_);
|
||||
print_value(shell, 2, F("System service code"), FPSTR(serviceCodeChar_)); // TODO check
|
||||
}
|
||||
|
||||
// UBAParameters
|
||||
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));
|
||||
print_value(shell, 2, F("Heating temperature setting on the boiler"), heating_temp_, F_(degrees), 1);
|
||||
print_value(shell, 2, F("Boiler circuit pump modulation max power"), pump_mod_max_, F_(percent), 1);
|
||||
print_value(shell, 2, F("Boiler circuit pump modulation min power"), pump_mod_min_, F_(percent), 1);
|
||||
|
||||
// UBAMonitorSlow
|
||||
if (Helpers::hasValue(extTemp_)) {
|
||||
print_value(shell, 2, F("Outside temperature"), F_(degrees), Helpers::render_value(buffer, extTemp_, 10));
|
||||
print_value(shell, 2, F("Outside temperature"), extTemp_, F_(degrees), 10);
|
||||
}
|
||||
|
||||
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));
|
||||
print_value(shell, 2, F("Exhaust temperature"), exhaustTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Pump modulation"), pumpMod_, F_(percent), 1);
|
||||
print_value(shell, 2, F("Pump modulation2"), pumpMod2_, F_(percent), 1);
|
||||
print_value(shell, 2, F("Burner # starts"), burnStarts_, nullptr, 1);
|
||||
if (Helpers::hasValue(burnWorkMin_)) {
|
||||
shell.printfln(F(" Total burner operating time: %d days %d hours %d minutes"), burnWorkMin_ / 1440, (burnWorkMin_ % 1440) / 60, burnWorkMin_ % 60);
|
||||
}
|
||||
@@ -432,14 +421,6 @@ void Boiler::show_values(uuid::console::Shell & shell) {
|
||||
if (Helpers::hasValue(UBAuptime_)) {
|
||||
shell.printfln(F(" Total UBA working time: %d days %d hours %d minutes"), UBAuptime_ / 1440, (UBAuptime_ % 1440) / 60, UBAuptime_ % 60);
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(hpModulation_)) {
|
||||
print_value(shell, 2, F("Heat Pump modulation"), F_(percent), Helpers::render_value(buffer, hpModulation_, 1));
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(hpSpeed_)) {
|
||||
print_value(shell, 2, F("Heat Pump speed"), F_(percent), Helpers::render_value(buffer, hpSpeed_, 1));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -597,6 +578,13 @@ void Boiler::process_UBAMonitorSlow(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(heatWorkMin_, 19);
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAMonitorSlowPlus2 - type 0xE3
|
||||
*/
|
||||
void Boiler::process_UBAMonitorSlowPlus2(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(pumpMod2_, 13);
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAMonitorSlowPlus - type 0xE5 - central heating monitor EMS+
|
||||
*/
|
||||
@@ -608,21 +596,7 @@ void Boiler::process_UBAMonitorSlowPlus(std::shared_ptr<const Telegram> telegram
|
||||
telegram->read_value(burnStarts_, 10);
|
||||
telegram->read_value(burnWorkMin_, 13);
|
||||
telegram->read_value(heatWorkMin_, 19);
|
||||
telegram->read_value(pumpMod_, 25); // or is it switchTemp ?
|
||||
}
|
||||
|
||||
/*
|
||||
* Type 0xE3 - HeatPump Monitor 1
|
||||
*/
|
||||
void Boiler::process_HPMonitor1(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(hpModulation_, 13);
|
||||
}
|
||||
|
||||
/*
|
||||
* Type 0xE5 - HeatPump Monitor 2
|
||||
*/
|
||||
void Boiler::process_HPMonitor2(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(hpSpeed_, 25);
|
||||
telegram->read_value(pumpMod_, 25);
|
||||
}
|
||||
|
||||
// 0xE9 - DHW Status
|
||||
|
||||
@@ -123,9 +123,7 @@ class Boiler : public EMSdevice {
|
||||
uint8_t tap_water_active_ = EMS_VALUE_BOOL_NOTSET; // Hot tap water is on/off
|
||||
uint8_t heating_active_ = EMS_VALUE_BOOL_NOTSET; // Central heating is on/off
|
||||
|
||||
// heatpump boilers
|
||||
uint8_t hpModulation_ = EMS_VALUE_UINT_NOTSET; // heatpump modulation in %
|
||||
uint8_t hpSpeed_ = EMS_VALUE_UINT_NOTSET; // speed 0-100 %
|
||||
uint8_t pumpMod2_ = EMS_VALUE_UINT_NOTSET; // heatpump modulation from 0xE3 (heatpumps)
|
||||
|
||||
void process_UBAParameterWW(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMonitorFast(std::shared_ptr<const Telegram> telegram);
|
||||
@@ -135,6 +133,8 @@ class Boiler : public EMSdevice {
|
||||
void process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMonitorSlow(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMonitorSlowPlus(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAMonitorSlowPlus2(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_UBAOutdoorTemp(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBASetPoints(std::shared_ptr<const Telegram> telegram);
|
||||
void process_UBAFlags(std::shared_ptr<const Telegram> telegram);
|
||||
@@ -144,8 +144,6 @@ class Boiler : public EMSdevice {
|
||||
void process_UBAErrorMessage(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void process_UBADHWStatus(std::shared_ptr<const Telegram> telegram);
|
||||
void process_HPMonitor1(std::shared_ptr<const Telegram> telegram);
|
||||
void process_HPMonitor2(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
void check_active();
|
||||
|
||||
|
||||
@@ -70,17 +70,15 @@ void Mixing::show_values(uuid::console::Shell & shell) {
|
||||
return; // don't have any values yet
|
||||
}
|
||||
|
||||
char buffer[10]; // used for formatting
|
||||
|
||||
if (type_ == Type::WWC) {
|
||||
shell.printfln(F(" Warm Water Circuit #: %d"), hc_);
|
||||
print_value(shell, 2, F("Warm Water Circuit"), hc_, nullptr, 1);
|
||||
} else {
|
||||
shell.printfln(F(" Heating Circuit #: %d"), hc_);
|
||||
print_value(shell, 2, F("Heating Circuit"), hc_, nullptr, 1);
|
||||
}
|
||||
print_value(shell, 4, F("Current flow temperature"), F_(degrees), Helpers::render_value(buffer, flowTemp_, 10));
|
||||
print_value(shell, 4, F("Setpoint flow temperature"), F_(degrees), Helpers::render_value(buffer, flowSetTemp_, 1));
|
||||
print_value(shell, 4, F("Current pump modulation"), Helpers::render_value(buffer, pumpMod_, 1));
|
||||
print_value(shell, 4, F("Current valve status"), Helpers::render_value(buffer, status_, 1));
|
||||
print_value(shell, 4, F("Current flow temperature"), flowTemp_, F_(degrees), 10);
|
||||
print_value(shell, 4, F("Setpoint flow temperature"), flowSetTemp_, F_(degrees), 1);
|
||||
print_value(shell, 4, F("Current pump modulation"), pumpMod_, F_(percent), 1);
|
||||
print_value(shell, 4, F("Current valve status"), status_, nullptr, 1);
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
|
||||
@@ -56,22 +56,20 @@ void Solar::add_context_menu() {
|
||||
void Solar::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // always call this to show header
|
||||
|
||||
char buffer[10]; // used for formatting
|
||||
|
||||
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));
|
||||
print_value(shell, 2, F("Collector temperature (TS1)"), collectorTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Bottom temperature (TS2)"), bottomTemp_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Bottom temperature (TS5)"), bottomTemp2_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Pump modulation"), pumpModulation_, F_(percent), 1);
|
||||
print_value(shell, 2, F("Valve (VS2) status"), valveStatus_, nullptr, EMS_VALUE_BOOL);
|
||||
print_value(shell, 2, F("Pump (PS1) active"), pump_, nullptr, EMS_VALUE_BOOL);
|
||||
|
||||
if (Helpers::hasValue(pumpWorkMin_)) {
|
||||
shell.printfln(F(" Pump working time: %d days %d hours %d minutes"), pumpWorkMin_ / 1440, (pumpWorkMin_ % 1440) / 60, pumpWorkMin_ % 60);
|
||||
}
|
||||
|
||||
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));
|
||||
print_value(shell, 2, F("Energy last hour"), energyLastHour_, F_(wh), 10);
|
||||
print_value(shell, 2, F("Energy today"), energyToday_, F_(wh), 0);
|
||||
print_value(shell, 2, F("Energy total"), energyTotal_, F_(kwh), 10);
|
||||
}
|
||||
|
||||
// publish values via MQTT
|
||||
|
||||
@@ -804,20 +804,19 @@ std::string Thermostat::mode_tostring(uint8_t mode) const {
|
||||
void Thermostat::show_values(uuid::console::Shell & shell) {
|
||||
EMSdevice::show_values(shell); // always call this to show header
|
||||
|
||||
char buffer[10]; // for formatting only
|
||||
uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits
|
||||
|
||||
if (datetime_.size()) {
|
||||
shell.printfln(F(" Clock: %s"), datetime_.c_str());
|
||||
if (Helpers::hasValue(ibaClockOffset_) && flags == EMS_DEVICE_FLAG_RC30_1) {
|
||||
print_value(shell, 2, F("Offset clock"), Helpers::render_value(buffer, ibaClockOffset_, 1)); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
|
||||
print_value(shell, 2, F("Offset clock"), ibaClockOffset_, nullptr, 1); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
|
||||
}
|
||||
}
|
||||
|
||||
if (flags == EMS_DEVICE_FLAG_RC35) {
|
||||
print_value(shell, 2, F("Damped Outdoor temperature"), F_(degrees), Helpers::render_value(buffer, dampedoutdoortemp_, 1));
|
||||
print_value(shell, 2, F("Temp sensor 1"), F_(degrees), Helpers::render_value(buffer, tempsensor1_, 10));
|
||||
print_value(shell, 2, F("Temp sensor 2"), F_(degrees), Helpers::render_value(buffer, tempsensor2_, 10));
|
||||
print_value(shell, 2, F("Damped Outdoor temperature"), dampedoutdoortemp_, F_(degrees), 1);
|
||||
print_value(shell, 2, F("Temp sensor 1"), tempsensor1_, F_(degrees), 10);
|
||||
print_value(shell, 2, F("Temp sensor 2"), tempsensor2_, F_(degrees), 10);
|
||||
}
|
||||
if (flags == EMS_DEVICE_FLAG_RC30_1) {
|
||||
// settings parameters
|
||||
@@ -857,11 +856,11 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
|
||||
}
|
||||
if (flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1) {
|
||||
if (Helpers::hasValue(ibaCalIntTemperature_)) {
|
||||
print_value(shell, 2, F("Offset int. temperature"), F_(degrees), Helpers::render_value(buffer, ibaCalIntTemperature_, 2));
|
||||
print_value(shell, 2, F("Offset int. temperature"), ibaCalIntTemperature_, F_(degrees), 2);
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(ibaMinExtTemperature_)) {
|
||||
print_value(shell, 2, F("Min ext. temperature"), F_(degrees), Helpers::render_value(buffer, ibaMinExtTemperature_, 0)); // min ext temp for heating curve, in deg.
|
||||
print_value(shell, 2, F("Min ext. temperature"), ibaMinExtTemperature_, F_(degrees), 0); // min ext temp for heating curve, in deg.
|
||||
}
|
||||
|
||||
if (Helpers::hasValue(ibaBuildingType_)) {
|
||||
@@ -895,8 +894,8 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
|
||||
break;
|
||||
}
|
||||
|
||||
print_value(shell, 4, F("Current room temperature"), F_(degrees), Helpers::render_value(buffer, hc->curr_roomTemp, format_curr));
|
||||
print_value(shell, 4, F("Setpoint room temperature"), F_(degrees), Helpers::render_value(buffer, hc->setpoint_roomTemp, format_setpoint));
|
||||
print_value(shell, 4, F("Current room temperature"), hc->curr_roomTemp, F_(degrees), format_curr);
|
||||
print_value(shell, 4, F("Setpoint room temperature"), hc->setpoint_roomTemp, F_(degrees), format_setpoint);
|
||||
if (Helpers::hasValue(hc->mode)) {
|
||||
print_value(shell, 4, F("Mode"), mode_tostring(hc->get_mode(flags)).c_str());
|
||||
}
|
||||
@@ -911,18 +910,18 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
|
||||
shell.printfln(F(" Program is set to Holiday mode"));
|
||||
}
|
||||
|
||||
print_value(shell, 4, F("Day temperature"), F_(degrees), Helpers::render_value(buffer, hc->daytemp, 2));
|
||||
print_value(shell, 4, F("Night temperature"), F_(degrees), Helpers::render_value(buffer, hc->nighttemp, 2));
|
||||
print_value(shell, 4, F("Holiday temperature"), F_(degrees), Helpers::render_value(buffer, hc->holidaytemp, 2));
|
||||
print_value(shell, 4, F("Day temperature"), hc->daytemp, F_(degrees), 2);
|
||||
print_value(shell, 4, F("Night temperature"), hc->nighttemp, F_(degrees), 2);
|
||||
print_value(shell, 4, F("Holiday temperature"), hc->holidaytemp, F_(degrees), 2);
|
||||
|
||||
print_value(shell, 4, F("Offset temperature"), F_(degrees), Helpers::render_value(buffer, hc->offsettemp, 2));
|
||||
print_value(shell, 4, F("Design temperature"), F_(degrees), Helpers::render_value(buffer, hc->designtemp, 0));
|
||||
print_value(shell, 4, F("Summer temperature"), F_(degrees), Helpers::render_value(buffer, hc->summertemp, 0));
|
||||
print_value(shell, 4, F("Offset temperature"), hc->offsettemp, F_(degrees), 2);
|
||||
print_value(shell, 4, F("Design temperature"), hc->designtemp, F_(degrees), 0);
|
||||
print_value(shell, 4, F("Summer temperature"), hc->summertemp, F_(degrees), 0);
|
||||
}
|
||||
|
||||
// show flow temp if we have it
|
||||
if (Helpers::hasValue(hc->circuitcalctemp)) {
|
||||
print_value(shell, 4, F("Calculated flow temperature"), F_(degrees), Helpers::render_value(buffer, hc->circuitcalctemp, 1));
|
||||
print_value(shell, 4, F("Calculated flow temperature"), hc->circuitcalctemp, F_(degrees), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,22 +279,18 @@ void EMSdevice::read_command(const uint16_t type_id) {
|
||||
EMSESP::send_read_request(type_id, device_id());
|
||||
}
|
||||
|
||||
// prints a value to the console
|
||||
void EMSdevice::print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const __FlashStringHelper * suffix, const char * value) {
|
||||
// prints a string value to the console
|
||||
void EMSdevice::print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const __FlashStringHelper * value) {
|
||||
print_value(shell, padding, name, uuid::read_flash_string(value).c_str());
|
||||
}
|
||||
|
||||
void EMSdevice::print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, 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 - 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);
|
||||
shell.printfln(PSTR("%s: %s"), uuid::read_flash_string(name).c_str(), value);
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -120,8 +120,30 @@ class EMSdevice {
|
||||
void fetch_values();
|
||||
void toggle_fetch(uint16_t telegram_id, bool toggle);
|
||||
|
||||
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);
|
||||
template <typename Value>
|
||||
static void
|
||||
print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, Value & value, const __FlashStringHelper * suffix, const uint8_t p) {
|
||||
char buffer[15];
|
||||
if (Helpers::render_value(buffer, value, p) == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t i = padding;
|
||||
while (i-- > 0) {
|
||||
shell.print(F(" "));
|
||||
}
|
||||
|
||||
shell.printf(PSTR("%s: %s"), uuid::read_flash_string(name).c_str(), buffer);
|
||||
|
||||
if (suffix != nullptr) {
|
||||
shell.println(uuid::read_flash_string(suffix).c_str());
|
||||
} else {
|
||||
shell.println();
|
||||
}
|
||||
}
|
||||
|
||||
static void print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const __FlashStringHelper * value);
|
||||
static void print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const char * value);
|
||||
|
||||
enum Brand : uint8_t {
|
||||
NO_BRAND, // 0
|
||||
|
||||
@@ -32,8 +32,45 @@ char * Helpers::hextoa(char * result, const uint8_t value) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef EMSESP_STANDALONE
|
||||
char * Helpers::ultostr(char * ptr, uint32_t value, const uint8_t base) {
|
||||
unsigned long t = 0, res = 0;
|
||||
unsigned long tmp = value;
|
||||
int count = 0;
|
||||
|
||||
if (NULL == ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tmp == 0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
while (tmp > 0) {
|
||||
tmp = tmp / base;
|
||||
count++;
|
||||
}
|
||||
|
||||
ptr += count;
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
do {
|
||||
res = value - base * (t = value / base);
|
||||
if (res < 10) {
|
||||
*--ptr = '0' + res;
|
||||
} else if ((res >= 10) && (res < 16)) {
|
||||
*--ptr = 'A' - 10 + res;
|
||||
}
|
||||
} while ((value = t) != 0);
|
||||
|
||||
return (ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* itoa for 2 byte integers
|
||||
* itoa for 2 byte signed (short) integers
|
||||
* written by Lukás Chmela, Released under GPLv3. http://www.strudel.org.uk/itoa/ version 0.4
|
||||
*/
|
||||
char * Helpers::itoa(char * result, int16_t value, const uint8_t base) {
|
||||
@@ -56,12 +93,14 @@ char * Helpers::itoa(char * result, int16_t value, const uint8_t base) {
|
||||
if (tmp_value < 0) {
|
||||
*ptr++ = '-';
|
||||
}
|
||||
|
||||
*ptr-- = '\0';
|
||||
while (ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr-- = *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -92,7 +131,7 @@ char * Helpers::render_value(char * result, uint8_t value, uint8_t format) {
|
||||
if (value == EMS_VALUE_BOOL_OFF) {
|
||||
strlcpy(result, "off", 5);
|
||||
} else if (value == EMS_VALUE_BOOL_NOTSET) {
|
||||
strlcpy(result, "?", 5);
|
||||
return nullptr;
|
||||
} else {
|
||||
strlcpy(result, "on", 5); // assume on. could have value 0x01 or 0xFF
|
||||
}
|
||||
@@ -100,8 +139,7 @@ char * Helpers::render_value(char * result, uint8_t value, uint8_t format) {
|
||||
}
|
||||
|
||||
if (value == EMS_VALUE_UINT_NOTSET) {
|
||||
strlcpy(result, "?", 5);
|
||||
return (result);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char s2[5] = {0};
|
||||
@@ -153,8 +191,7 @@ char * Helpers::render_value(char * result, const int16_t value, const uint8_t f
|
||||
|
||||
// remove errors or invalid values, 0x7D00 and higher
|
||||
if ((value == EMS_VALUE_SHORT_NOTSET) || (value == EMS_VALUE_SHORT_INVALID) || (value == EMS_VALUE_USHORT_NOTSET)) {
|
||||
strlcpy(result, "?", 10);
|
||||
return result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// just print it if mo conversion required
|
||||
@@ -196,8 +233,7 @@ char * Helpers::render_value(char * result, const uint16_t value, const uint8_t
|
||||
result[0] = '\0';
|
||||
|
||||
if ((value == EMS_VALUE_USHORT_NOTSET) || (value == EMS_VALUE_USHORT_INVALID)) {
|
||||
strlcpy(result, "?", 10);
|
||||
return result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (render_value(result, (int16_t)value, format)); // use same code, force it to a signed int
|
||||
@@ -209,8 +245,7 @@ char * Helpers::render_value(char * result, const int8_t value, const uint8_t fo
|
||||
result[0] = '\0';
|
||||
|
||||
if (value == EMS_VALUE_INT_NOTSET) {
|
||||
strlcpy(result, "?", 10);
|
||||
return result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (render_value(result, (int16_t)value, format)); // use same code, force it to a signed int
|
||||
@@ -222,8 +257,7 @@ char * Helpers::render_value(char * result, const uint32_t value, const uint8_t
|
||||
result[0] = '\0';
|
||||
|
||||
if ((value == EMS_VALUE_ULONG_NOTSET) || (value == EMS_VALUE_ULONG_INVALID)) {
|
||||
strlcpy(result, "?", 10);
|
||||
return (result);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char s[20] = {0};
|
||||
@@ -238,7 +272,13 @@ char * Helpers::render_value(char * result, const uint32_t value, const uint8_t
|
||||
}
|
||||
|
||||
#else
|
||||
strncat(result, itoa(s, value / format, 10), 20);
|
||||
if (format <= 1) {
|
||||
strlcat(result, ultostr(s, value, 10), 20);
|
||||
} else {
|
||||
strncat(result, ultostr(s, value / format, 10), 20);
|
||||
strlcat(result, ".", 20);
|
||||
strncat(result, ultostr(s, value % format, 10), 20);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
@@ -264,7 +304,6 @@ std::string Helpers::data_to_hex(const uint8_t * data, const uint8_t length) {
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
// takes a hex string and convert it to an unsigned 32bit number (max 8 hex digits)
|
||||
// works with only positive numbers
|
||||
uint32_t Helpers::hextoint(const char * hex) {
|
||||
@@ -331,5 +370,4 @@ bool Helpers::hasValue(const uint32_t v) {
|
||||
return (v != EMS_VALUE_ULONG_NOTSET);
|
||||
}
|
||||
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -44,6 +44,10 @@ class Helpers {
|
||||
static bool check_abs(const int32_t i);
|
||||
static double round2(double value);
|
||||
|
||||
#ifdef EMSESP_STANDALONE
|
||||
static char * ultostr(char * ptr, uint32_t value, const uint8_t base);
|
||||
#endif
|
||||
|
||||
static bool hasValue(const uint8_t v, bool isBool = false); // use isBool=true for bool's
|
||||
static bool hasValue(const int8_t v);
|
||||
static bool hasValue(const int16_t v);
|
||||
|
||||
@@ -25,6 +25,62 @@ namespace emsesp {
|
||||
// create some fake test data
|
||||
// used with the 'test' command, under su/admin
|
||||
void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
||||
if (command == "render") {
|
||||
/*
|
||||
static constexpr uint8_t EMS_VALUE_BOOL = 0xFF; // boolean
|
||||
static constexpr uint8_t EMS_VALUE_BOOL_OFF = 0x00; // boolean false. True can be 0x01 or 0xFF sometimes.
|
||||
|
||||
static constexpr uint8_t EMS_VALUE_BOOL_NOTSET = 0xFE; // random number for booleans, that's not 0, 1 or FF
|
||||
static constexpr uint8_t EMS_VALUE_UINT_NOTSET = 0xFF; // for 8-bit unsigned ints/bytes
|
||||
static constexpr int8_t EMS_VALUE_INT_NOTSET = 0x7F; // for signed 8-bit ints/bytes
|
||||
static constexpr int16_t EMS_VALUE_SHORT_NOTSET = 0x8300; // -32000: for 2-byte signed shorts
|
||||
static constexpr uint16_t EMS_VALUE_USHORT_NOTSET = 0x7D00; // 32000: for 2-byte unsigned shorts
|
||||
static constexpr uint16_t EMS_VALUE_USHORT_INVALID = 0x8000;
|
||||
static constexpr int16_t EMS_VALUE_SHORT_INVALID = 0x8000;
|
||||
static constexpr uint32_t EMS_VALUE_ULONG_NOTSET = 0xFFFFFFFF; // for 3-byte and 4-byte longs
|
||||
static constexpr uint32_t EMS_VALUE_ULONG_INVALID = 0x80000000;
|
||||
*/
|
||||
|
||||
uint8_t test1 = 12;
|
||||
int8_t test2 = -12;
|
||||
uint16_t test3 = 456;
|
||||
int16_t test4 = -456;
|
||||
uint8_t test5 = 1; // bool = on
|
||||
uint32_t test6 = 305419896;
|
||||
float test7 = 89.43;
|
||||
|
||||
uint8_t test1u = EMS_VALUE_UINT_NOTSET;
|
||||
int8_t test2u = EMS_VALUE_INT_NOTSET;
|
||||
uint16_t test3u = EMS_VALUE_USHORT_NOTSET;
|
||||
int16_t test4u = EMS_VALUE_USHORT_NOTSET;
|
||||
uint8_t test5u = EMS_VALUE_BOOL_NOTSET;
|
||||
uint32_t test6u = EMS_VALUE_ULONG_NOTSET;
|
||||
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature1"), test1, F_(degrees), 1); // 12
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature2"), test2, F_(degrees), 1); // -12
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature3"), test3, F_(degrees), 10); // 45.6
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature4"), test4, F_(degrees), 10); // -45.6
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature5"), test5, nullptr, EMS_VALUE_BOOL); // on
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature6"), test6, F_(degrees), 1); //
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature7"), test7, F_(degrees), 2); // 89.43
|
||||
EMSdevice::print_value(shell, 2, F("Warm Water comfort setting"), F("Intelligent"));
|
||||
char s[100];
|
||||
strcpy(s, "Not very intelligent");
|
||||
EMSdevice::print_value(shell, 2, F("Warm Water comfort setting2"), s);
|
||||
|
||||
shell.println();
|
||||
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature1u"), test1u, F_(degrees), 1);
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature2u"), test2u, F_(degrees), 1);
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature3u"), test3u, F_(degrees), 10);
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature4u"), test4u, F_(degrees), 10);
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature5u"), test5u, F_(degrees), EMS_VALUE_BOOL);
|
||||
EMSdevice::print_value(shell, 2, F("Selected flow temperature6u"), test6u, F_(degrees), 100);
|
||||
|
||||
shell.loop_all();
|
||||
return;
|
||||
}
|
||||
|
||||
if (command == "devices") {
|
||||
EMSESP::rxservice_.ems_mask(EMSbus::EMS_MASK_BUDERUS); // this is important otherwise nothing will be picked up!
|
||||
|
||||
@@ -101,6 +157,17 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
||||
// B0 0B FF 00 02 62 00 44 02 7A 80 00 80 00 80 00 80 00 80 00 80 00 00 7C 80 00 80 00 80 00 80
|
||||
rx_telegram({0xB0, 0x0B, 0xFF, 00, 0x02, 0x62, 00, 0x44, 0x02, 0x7A, 0x80, 00, 0x80, 0x00, 0x80, 00,
|
||||
0x80, 00, 0x80, 00, 0x80, 00, 00, 0x7C, 0x80, 00, 0x80, 00, 0x80, 00, 0x80});
|
||||
EMSESP::show_values(shell);
|
||||
|
||||
rx_telegram({0xB0, 0x0B, 0xFF, 0x00, 0x02, 0x62, 0x01, 0x44, 0x03, 0x30, 0x80, 00, 0x80, 00, 0x80, 00,
|
||||
0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 0x33});
|
||||
EMSESP::show_values(shell);
|
||||
|
||||
rx_telegram({0xB0, 00, 0xFF, 0x18, 02, 0x62, 0x80, 00, 0xB8});
|
||||
EMSESP::show_values(shell);
|
||||
|
||||
EMSESP::send_raw_telegram("B0 00 FF 18 02 62 80 00 B8");
|
||||
EMSESP::show_values(shell);
|
||||
}
|
||||
|
||||
if (command == "cr100") {
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "2.0.0a20"
|
||||
#define EMSESP_APP_VERSION "2.0.0a21"
|
||||
|
||||
Reference in New Issue
Block a user