mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
initial commit with refactored mqtt commands
This commit is contained in:
82
README.md
82
README.md
@@ -66,59 +66,49 @@ common commands available in all contexts:
|
|||||||
su
|
su
|
||||||
|
|
||||||
(from the root)
|
(from the root)
|
||||||
set
|
set
|
||||||
fetch
|
fetch
|
||||||
system (enters a context)
|
system (enters a context)
|
||||||
boiler (enters a context)
|
boiler (enters a context)
|
||||||
thermostat (enters a context)
|
thermostat (enters a context)
|
||||||
scan devices [deep]
|
scan devices [deep]
|
||||||
send telegram <"XX XX ...">
|
send telegram <"XX XX ...">
|
||||||
set bus_id <device ID>
|
set bus_id <device ID>
|
||||||
set tx_mode <n>
|
set tx_mode <n>
|
||||||
show
|
show
|
||||||
show devices
|
show devices
|
||||||
show ems
|
show ems
|
||||||
show values
|
show values
|
||||||
|
|
||||||
system
|
system
|
||||||
set
|
set
|
||||||
show
|
show
|
||||||
show mqtt
|
show mqtt
|
||||||
show users
|
show users
|
||||||
passwd
|
passwd
|
||||||
restart
|
restart
|
||||||
set wifi hostname <name>
|
set wifi hostname <name>
|
||||||
set wifi password
|
set wifi password
|
||||||
set wifi ssid <name>
|
set wifi ssid <name>
|
||||||
wifi reconnect
|
wifi reconnect
|
||||||
|
|
||||||
boiler
|
boiler
|
||||||
comfort <hot |eco | intelligent>
|
read <type ID>
|
||||||
flowtemp <degrees>
|
call [cmd] [n] (cmd's: comfort wwactivated wwtapactivated wwonetime wwcirculation flowtemp wwtemp burnmaxpower burnminpower boilhyston boilhystoff burnperiod pumpdelay)
|
||||||
wwactive <on | off>
|
|
||||||
wwcirculation <on | off>
|
|
||||||
wwonetime <on | off>
|
|
||||||
wwtemp <degrees>
|
|
||||||
read <type ID>
|
|
||||||
maxpower <%>
|
|
||||||
minpower <%>
|
|
||||||
|
|
||||||
thermostat
|
thermostat
|
||||||
set
|
set
|
||||||
set master [device ID]
|
set master [device ID]
|
||||||
mode <mode> [heating circuit]
|
read <type ID>
|
||||||
temp <degrees> [heating circuit]
|
call [cmd] [n] (cmd's: wwmode control mode holiday pause party datetime minexttemp clockoffset calinttemp display building language remotetemp temp nighttemp daytemp nofrosttemp ecotemp heattemp summertemp designtemp offsettemp holidaytemp)
|
||||||
read <type ID>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
----------
|
----------
|
||||||
### **mqtt commands**
|
### **mqtt commands**
|
||||||
|
|
||||||
commands can be written as `{"cmd": ,"data": }` or direct.
|
commands must be written as `{"cmd":<cmd> ,"data":<data>, "id":<n> }`. The `id` can be replaced with `hc` for some devices.
|
||||||
To set thermostat commands depending on heatingcircuits add `"hc": ` or nest the command. Without `"hc":` the first ative heatingcircuit is set.
|
|
||||||
These commands are equivalent:
|
|
||||||
`{"hc":2,"cmd":"daytemp","data":21}` or `{"hc":2,"daytemp":21}`or `{"hc2"{"daytemp":21}}`
|
|
||||||
In direct commands it's possible to combine commands, i.e. `{"hc1":{"daytemp":21,"nighttemp":17},"hc2":{"daytemp":20}}`
|
|
||||||
```
|
```
|
||||||
*boiler_cmd*
|
*boiler_cmd*
|
||||||
comfort <hot, eco, intelligent>
|
comfort <hot, eco, intelligent>
|
||||||
@@ -161,10 +151,7 @@ In direct commands it's possible to combine commands, i.e. `{"hc1":{"daytemp":21
|
|||||||
|
|
||||||
*cmd*
|
*cmd*
|
||||||
send <"0B XX XX ..">
|
send <"0B XX XX ..">
|
||||||
D0 <0 | 1>
|
gpio <0 | 1> <0-3> (for D0-D3)
|
||||||
D1 <0 | 1>
|
|
||||||
D2 <0 | 1>
|
|
||||||
D3 <0 | 1>
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -180,13 +167,6 @@ In direct commands it's possible to combine commands, i.e. `{"hc1":{"daytemp":21
|
|||||||
- See if it's easier to use timers instead of millis() based timers, using [polledTimeout](https://github.com/esp8266/Arduino/blob/master/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino).
|
- See if it's easier to use timers instead of millis() based timers, using [polledTimeout](https://github.com/esp8266/Arduino/blob/master/libraries/esp8266/examples/BlinkPolledTimeout/BlinkPolledTimeout.ino).
|
||||||
- Port over to ESP-IDF. The Arduino SDK is showing its limitations
|
- Port over to ESP-IDF. The Arduino SDK is showing its limitations
|
||||||
|
|
||||||
### **Features to add**
|
|
||||||
|
|
||||||
- Multi-language. German, Dutch, French
|
|
||||||
- Click on a device in the Web UI shows it's details
|
|
||||||
- Publish time can be customized per device (solar, mixing etc)
|
|
||||||
- add homeassistant mqtt discovery for Boiler as well
|
|
||||||
|
|
||||||
### **Customizing the Web UI**
|
### **Customizing the Web UI**
|
||||||
|
|
||||||
The Web is based off Rick's awesome [esp8266-react](https://github.com/rjwats/esp8266-react/) framework. These are the files that are modified:
|
The Web is based off Rick's awesome [esp8266-react](https://github.com/rjwats/esp8266-react/) framework. These are the files that are modified:
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ uint8_t OneWire::reset(void) {
|
|||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
void IRAM_ATTR OneWire::write_bit(uint8_t v) {
|
void IRAM_ATTR OneWire::write_bit(uint8_t v) {
|
||||||
#else
|
#else
|
||||||
void OneWire::write_bit(uint8_t v) {
|
void OneWire::write_bit(uint8_t v) {
|
||||||
#endif
|
#endif
|
||||||
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
||||||
volatile IO_REG_TYPE * reg IO_REG_BASE_ATTR = baseReg;
|
volatile IO_REG_TYPE * reg IO_REG_BASE_ATTR = baseReg;
|
||||||
@@ -578,4 +578,4 @@ uint16_t OneWire::crc16(const uint8_t * input, uint16_t len, uint16_t crc) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
@@ -105,10 +105,10 @@ class OneWire {
|
|||||||
|
|
||||||
// Write a bit. The bus is always left powered at the end, see
|
// Write a bit. The bus is always left powered at the end, see
|
||||||
// note in write() about that.
|
// note in write() about that.
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
void IRAM_ATTR write_bit(uint8_t v);
|
void IRAM_ATTR write_bit(uint8_t v);
|
||||||
#else
|
#else
|
||||||
void write_bit(uint8_t v);
|
void write_bit(uint8_t v);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Read a bit.
|
// Read a bit.
|
||||||
@@ -192,4 +192,4 @@ class OneWire {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
#endif // OneWire_h
|
#endif // OneWire_h
|
||||||
@@ -54,7 +54,7 @@ void NTPSettingsService::onStationModeDisconnected(const WiFiEventStationModeDis
|
|||||||
|
|
||||||
void NTPSettingsService::configureNTP() {
|
void NTPSettingsService::configureNTP() {
|
||||||
if (WiFi.isConnected() && _state.enabled) {
|
if (WiFi.isConnected() && _state.enabled) {
|
||||||
Serial.println(F("Starting NTP..."));
|
// Serial.println(F("Starting NTP..."));
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
configTzTime(_state.tzFormat.c_str(), _state.server.c_str());
|
configTzTime(_state.tzFormat.c_str(), _state.server.c_str());
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
|
|||||||
@@ -22,11 +22,6 @@ static void check(const JsonObject object, const char (&expected_data)[N]) {
|
|||||||
check(object, expected_data, expected_len);
|
check(object, expected_data, expected_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: used by the commented test
|
|
||||||
// static void check(const JsonObject object, const std::string& expected) {
|
|
||||||
// check(object, expected.data(), expected.length());
|
|
||||||
//}
|
|
||||||
|
|
||||||
TEST_CASE("serialize MsgPack object") {
|
TEST_CASE("serialize MsgPack object") {
|
||||||
DynamicJsonDocument doc(4096);
|
DynamicJsonDocument doc(4096);
|
||||||
JsonObject object = doc.to<JsonObject>();
|
JsonObject object = doc.to<JsonObject>();
|
||||||
@@ -54,23 +49,6 @@ TEST_CASE("serialize MsgPack object") {
|
|||||||
"iC\x0C\xA2iD\x0D\xA2iE\x0E\xA2iF\x0F");
|
"iC\x0C\xA2iD\x0D\xA2iE\x0E\xA2iF\x0F");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: improve performance and uncomment
|
|
||||||
// SECTION("map 32") {
|
|
||||||
// std::string expected("\xDF\x00\x01\x00\x00", 5);
|
|
||||||
//
|
|
||||||
// for (int i = 0; i < 65536; ++i) {
|
|
||||||
// char kv[16];
|
|
||||||
// sprintf(kv, "%04x", i);
|
|
||||||
// object[kv] = kv;
|
|
||||||
// expected += '\xA4';
|
|
||||||
// expected += kv;
|
|
||||||
// expected += '\xA4';
|
|
||||||
// expected += kv;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// check(object, expected);
|
|
||||||
// }
|
|
||||||
|
|
||||||
SECTION("serialized(const char*)") {
|
SECTION("serialized(const char*)") {
|
||||||
object["hello"] = serialized("\xDB\x00\x01\x00\x00", 5);
|
object["hello"] = serialized("\xDB\x00\x01\x00\x00", 5);
|
||||||
check(object, "\x81\xA5hello\xDB\x00\x01\x00\x00");
|
check(object, "\x81\xA5hello\xDB\x00\x01\x00\x00");
|
||||||
|
|||||||
@@ -10323,7 +10323,6 @@ namespace Catch {
|
|||||||
|
|
||||||
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
|
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
|
||||||
StreamingReporterBase::testGroupEnded( testGroupStats );
|
StreamingReporterBase::testGroupEnded( testGroupStats );
|
||||||
// TODO: Check testGroupStats.aborting and act accordingly.
|
|
||||||
m_xml.scopedElement( "OverallResults" )
|
m_xml.scopedElement( "OverallResults" )
|
||||||
.writeAttribute( "successes", testGroupStats.totals.assertions.passed )
|
.writeAttribute( "successes", testGroupStats.totals.assertions.passed )
|
||||||
.writeAttribute( "failures", testGroupStats.totals.assertions.failed )
|
.writeAttribute( "failures", testGroupStats.totals.assertions.failed )
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ class MsgPackDeserializer {
|
|||||||
TStringStorage stringStorage)
|
TStringStorage stringStorage)
|
||||||
: _pool(&pool), _reader(reader), _stringStorage(stringStorage) {}
|
: _pool(&pool), _reader(reader), _stringStorage(stringStorage) {}
|
||||||
|
|
||||||
// TODO: add support for filter
|
|
||||||
DeserializationError parse(VariantData &variant, AllowAllFilter,
|
DeserializationError parse(VariantData &variant, AllowAllFilter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
return parse(variant, nestingLimit);
|
return parse(variant, nestingLimit);
|
||||||
@@ -40,7 +39,6 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xe0) {
|
if ((code & 0xe0) == 0xe0) {
|
||||||
// TODO: add setNegativeInteger()
|
|
||||||
variant.setSignedInteger(static_cast<int8_t>(code));
|
variant.setSignedInteger(static_cast<int8_t>(code));
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|||||||
1
makefile
1
makefile
@@ -27,6 +27,7 @@ CXX_STANDARD := -std=c++11
|
|||||||
# Defined Symbols
|
# Defined Symbols
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_NO_LED
|
DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_NO_LED
|
||||||
|
DEFINES += -DRUN_TEST
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Sources & Files
|
# Sources & Files
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
; PlatformIO Project Configuration File for EMS-ESP
|
; PlatformIO Project Configuration File for EMS-ESP
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
; default_envs = esp8266
|
default_envs = esp8266
|
||||||
default_envs = esp32
|
; default_envs = esp32
|
||||||
|
|
||||||
# override any settings with your own local ones in pio_local.ini
|
# override any settings with your own local ones in pio_local.ini
|
||||||
extra_configs =
|
extra_configs =
|
||||||
@@ -76,7 +76,7 @@ board_build.f_cpu = 160000000L ; 160MHz
|
|||||||
; eagle.flash.4m1m.ld = 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer
|
; eagle.flash.4m1m.ld = 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer
|
||||||
; eagle.flash.4m2m.ld = 1019 KB sketch, 2024 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 1028 KB OTA & buffer
|
; eagle.flash.4m2m.ld = 1019 KB sketch, 2024 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 1028 KB OTA & buffer
|
||||||
; board_build.ldscript = eagle.flash.4m2m.ld
|
; board_build.ldscript = eagle.flash.4m2m.ld
|
||||||
build_flags = ${common.build_flags} ${common.debug_flags} -DFT_NTP=0
|
build_flags = ${common.build_flags} ${common.debug_flags} -D FT_NTP=0
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
AsyncTCP
|
AsyncTCP
|
||||||
|
|
||||||
@@ -87,4 +87,4 @@ build_type = release
|
|||||||
platform = https://github.com/platformio/platform-espressif32.git
|
platform = https://github.com/platformio/platform-espressif32.git
|
||||||
board_build.partitions = min_spiffs.csv ; https://github.com/espressif/arduino-esp32/blob/master/tools/partitions/
|
board_build.partitions = min_spiffs.csv ; https://github.com/espressif/arduino-esp32/blob/master/tools/partitions/
|
||||||
lib_deps = ${common.libs_core}
|
lib_deps = ${common.libs_core}
|
||||||
build_flags = ${common.build_flags} ${common.debug_flags} -DFT_NTP=1
|
build_flags = ${common.build_flags} ${common.debug_flags} -D FT_NTP=1
|
||||||
|
|||||||
0
scripts/build.sh
Executable file → Normal file
0
scripts/build.sh
Executable file → Normal file
@@ -91,6 +91,12 @@ void EMSESPShell::display_banner() {
|
|||||||
// turn off watch
|
// turn off watch
|
||||||
emsesp::EMSESP::watch_id(WATCH_ID_NONE);
|
emsesp::EMSESP::watch_id(WATCH_ID_NONE);
|
||||||
emsesp::EMSESP::watch(EMSESP::WATCH_OFF);
|
emsesp::EMSESP::watch(EMSESP::WATCH_OFF);
|
||||||
|
|
||||||
|
#if defined(EMSESP_STANDALONE)
|
||||||
|
#ifdef RUN_TEST
|
||||||
|
invoke_command("test"); // "test default"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// pre-loads all the console commands into the MAIN context
|
// pre-loads all the console commands into the MAIN context
|
||||||
@@ -285,11 +291,15 @@ void Console::enter_custom_context(Shell & shell, unsigned int context) {
|
|||||||
void Console::load_standard_commands(unsigned int context) {
|
void Console::load_standard_commands(unsigned int context) {
|
||||||
#ifdef EMSESP_STANDALONE
|
#ifdef EMSESP_STANDALONE
|
||||||
EMSESPShell::commands->add_command(context,
|
EMSESPShell::commands->add_command(context,
|
||||||
CommandFlags::ADMIN,
|
CommandFlags::USER,
|
||||||
flash_string_vector{F_(test)},
|
flash_string_vector{F_(test)},
|
||||||
flash_string_vector{F_(name_mandatory)},
|
flash_string_vector{F_(name_optional)},
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||||
Test::run_test(shell, arguments.front());
|
if (arguments.size() == 0) {
|
||||||
|
Test::run_test(shell, "default");
|
||||||
|
} else {
|
||||||
|
Test::run_test(shell, arguments.front());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -50,69 +50,8 @@ using uuid::log::Level;
|
|||||||
#define F_(string_name) FPSTR(__pstr__##string_name)
|
#define F_(string_name) FPSTR(__pstr__##string_name)
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// common words
|
// localizations
|
||||||
MAKE_PSTR_WORD(exit)
|
#include "locale_EN.h"
|
||||||
MAKE_PSTR_WORD(help)
|
|
||||||
MAKE_PSTR_WORD(settings)
|
|
||||||
MAKE_PSTR_WORD(log)
|
|
||||||
MAKE_PSTR_WORD(logout)
|
|
||||||
MAKE_PSTR_WORD(enabled)
|
|
||||||
MAKE_PSTR_WORD(disabled)
|
|
||||||
MAKE_PSTR_WORD(yes)
|
|
||||||
MAKE_PSTR_WORD(no)
|
|
||||||
MAKE_PSTR_WORD(set)
|
|
||||||
MAKE_PSTR_WORD(show)
|
|
||||||
MAKE_PSTR_WORD(on)
|
|
||||||
MAKE_PSTR_WORD(off)
|
|
||||||
MAKE_PSTR_WORD(su)
|
|
||||||
MAKE_PSTR_WORD(name)
|
|
||||||
MAKE_PSTR_WORD(auto)
|
|
||||||
MAKE_PSTR_WORD(scan)
|
|
||||||
MAKE_PSTR_WORD(password)
|
|
||||||
MAKE_PSTR_WORD(read)
|
|
||||||
MAKE_PSTR_WORD(version)
|
|
||||||
MAKE_PSTR_WORD(values)
|
|
||||||
MAKE_PSTR_WORD(system)
|
|
||||||
MAKE_PSTR_WORD(fetch)
|
|
||||||
MAKE_PSTR_WORD(restart)
|
|
||||||
MAKE_PSTR_WORD(format)
|
|
||||||
MAKE_PSTR_WORD(raw)
|
|
||||||
MAKE_PSTR_WORD(watch)
|
|
||||||
MAKE_PSTR_WORD(mqtt)
|
|
||||||
MAKE_PSTR_WORD(send)
|
|
||||||
MAKE_PSTR_WORD(telegram)
|
|
||||||
MAKE_PSTR_WORD(bus_id)
|
|
||||||
MAKE_PSTR_WORD(tx_mode)
|
|
||||||
MAKE_PSTR_WORD(ems)
|
|
||||||
MAKE_PSTR_WORD(devices)
|
|
||||||
|
|
||||||
MAKE_PSTR(deep_optional, "[deep]")
|
|
||||||
MAKE_PSTR(tx_mode_fmt, "Tx mode = %d")
|
|
||||||
MAKE_PSTR(bus_id_fmt, "Bus ID = %02X")
|
|
||||||
MAKE_PSTR(watchid_optional, "[ID]")
|
|
||||||
MAKE_PSTR(watch_format_mandatory, "<off | on | raw>")
|
|
||||||
MAKE_PSTR(invalid_watch, "Invalid watch type")
|
|
||||||
MAKE_PSTR(data_mandatory, "<\"XX XX ...\">")
|
|
||||||
MAKE_PSTR(percent, "%")
|
|
||||||
MAKE_PSTR(degrees, "°C")
|
|
||||||
MAKE_PSTR(degrees_mandatory, "<degrees>")
|
|
||||||
MAKE_PSTR(asterisks, "********")
|
|
||||||
MAKE_PSTR(n_mandatory, "<n>")
|
|
||||||
MAKE_PSTR(n_optional, "[n]")
|
|
||||||
MAKE_PSTR(bool_mandatory, "<on | off>")
|
|
||||||
MAKE_PSTR(typeid_mandatory, "<type ID>")
|
|
||||||
MAKE_PSTR(deviceid_mandatory, "<device ID>")
|
|
||||||
MAKE_PSTR(deviceid_optional, "[device ID]")
|
|
||||||
MAKE_PSTR(invalid_log_level, "Invalid log level")
|
|
||||||
MAKE_PSTR(port_mandatory, "<port>")
|
|
||||||
MAKE_PSTR(log_level_fmt, "Log level = %s")
|
|
||||||
MAKE_PSTR(log_level_optional, "[level]")
|
|
||||||
MAKE_PSTR(name_mandatory, "<name>")
|
|
||||||
MAKE_PSTR(name_optional, "[name]")
|
|
||||||
MAKE_PSTR(new_password_prompt1, "Enter new password: ")
|
|
||||||
MAKE_PSTR(new_password_prompt2, "Retype new password: ")
|
|
||||||
MAKE_PSTR(password_prompt, "Password: ")
|
|
||||||
MAKE_PSTR(unset, "<unset>")
|
|
||||||
|
|
||||||
#ifdef LOCAL
|
#ifdef LOCAL
|
||||||
#undef LOCAL
|
#undef LOCAL
|
||||||
|
|||||||
@@ -18,37 +18,15 @@
|
|||||||
|
|
||||||
#include "boiler.h"
|
#include "boiler.h"
|
||||||
|
|
||||||
MAKE_PSTR_WORD(boiler)
|
|
||||||
MAKE_PSTR_WORD(wwtemp)
|
|
||||||
MAKE_PSTR_WORD(flowtemp)
|
|
||||||
MAKE_PSTR_WORD(wwactive)
|
|
||||||
MAKE_PSTR_WORD(wwonetime)
|
|
||||||
MAKE_PSTR_WORD(wwcirculation)
|
|
||||||
MAKE_PSTR_WORD(comfort)
|
|
||||||
MAKE_PSTR_WORD(eco)
|
|
||||||
MAKE_PSTR_WORD(intelligent)
|
|
||||||
MAKE_PSTR_WORD(hot)
|
|
||||||
MAKE_PSTR_WORD(maxpower)
|
|
||||||
MAKE_PSTR_WORD(minpower)
|
|
||||||
|
|
||||||
MAKE_PSTR(comfort_mandatory, "<hot | eco | intelligent>")
|
|
||||||
|
|
||||||
// shower
|
|
||||||
MAKE_PSTR_WORD(shower)
|
|
||||||
MAKE_PSTR_WORD(timer)
|
|
||||||
MAKE_PSTR_WORD(alert)
|
|
||||||
MAKE_PSTR(shower_timer_fmt, "Shower Timer is %s")
|
|
||||||
MAKE_PSTR(shower_alert_fmt, "Shower Alert is %s")
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
REGISTER_FACTORY(Boiler, EMSdevice::DeviceType::BOILER)
|
REGISTER_FACTORY(Boiler, EMSdevice::DeviceType::BOILER)
|
||||||
MAKE_PSTR(logger_name, "boiler")
|
|
||||||
uuid::log::Logger Boiler::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
uuid::log::Logger Boiler::logger_{F_(boiler), uuid::log::Facility::CONSOLE};
|
||||||
|
|
||||||
Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
LOG_DEBUG(F("Registering new Boiler with device ID 0x%02X"), device_id);
|
LOG_DEBUG(F("Adding new Boiler with device ID 0x%02X"), device_id);
|
||||||
|
|
||||||
// the telegram handlers...
|
// the telegram handlers...
|
||||||
register_telegram_type(0x10, F("UBAErrorMessage1"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1));
|
register_telegram_type(0x10, F("UBAErrorMessage1"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1));
|
||||||
@@ -68,15 +46,22 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
|
|||||||
register_telegram_type(0xE3, F("UBAMonitorSlowPlus"), false, std::bind(&Boiler::process_UBAMonitorSlowPlus2, 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(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(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));
|
register_telegram_type(0xE9, F("UBADHWStatus"), false, std::bind(&Boiler::process_UBADHWStatus, this, _1));
|
||||||
|
|
||||||
// MQTT callbacks
|
// MQTT commands for boiler_cmd topic
|
||||||
register_mqtt_topic("boiler_cmd", std::bind(&Boiler::boiler_cmd, this, _1));
|
register_mqtt_cmd(F("comfort"), std::bind(&Boiler::set_warmwater_mode, this, _1, _2));
|
||||||
register_mqtt_topic("boiler_cmd_wwactivated", std::bind(&Boiler::boiler_cmd_wwactivated, this, _1));
|
register_mqtt_cmd(F("wwactivated"), std::bind(&Boiler::set_warmwater_activated, this, _1, _2));
|
||||||
register_mqtt_topic("boiler_cmd_wwonetime", std::bind(&Boiler::boiler_cmd_wwonetime, this, _1));
|
register_mqtt_cmd(F("wwtapactivated"), std::bind(&Boiler::set_tapwarmwater_activated, this, _1, _2));
|
||||||
register_mqtt_topic("boiler_cmd_wwcirculation", std::bind(&Boiler::boiler_cmd_wwcirculation, this, _1));
|
register_mqtt_cmd(F("wwonetime"), std::bind(&Boiler::set_warmwater_onetime, this, _1, _2));
|
||||||
register_mqtt_topic("boiler_cmd_wwtemp", std::bind(&Boiler::boiler_cmd_wwtemp, this, _1));
|
register_mqtt_cmd(F("wwcirculation"), std::bind(&Boiler::set_warmwater_circulation, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("flowtemp"), std::bind(&Boiler::set_flow_temp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("wwtemp"), std::bind(&Boiler::set_warmwater_temp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("burnmaxpower"), std::bind(&Boiler::set_max_power, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("burnminpower"), std::bind(&Boiler::set_min_power, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("boilhyston"), std::bind(&Boiler::set_hyst_on, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("boilhystoff"), std::bind(&Boiler::set_hyst_off, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("burnperiod"), std::bind(&Boiler::set_burn_period, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("pumpdelay"), std::bind(&Boiler::set_pump_delay, this, _1, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add submenu context
|
// add submenu context
|
||||||
@@ -86,156 +71,10 @@ void Boiler::add_context_menu() {
|
|||||||
flash_string_vector{F_(boiler)},
|
flash_string_vector{F_(boiler)},
|
||||||
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||||
Boiler::console_commands(shell, ShellContext::BOILER);
|
Boiler::console_commands(shell, ShellContext::BOILER);
|
||||||
|
add_context_commands(ShellContext::BOILER);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// boiler_cmd topic
|
|
||||||
void Boiler::boiler_cmd(const char * message) {
|
|
||||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
|
||||||
DeserializationError error = deserializeJson(doc, message);
|
|
||||||
if (error) {
|
|
||||||
LOG_DEBUG(F("MQTT error: payload %s, error %s"), message, error.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (nullptr != doc["flowtemp"]) {
|
|
||||||
uint8_t t = doc["flowtemp"];
|
|
||||||
set_flow_temp(t);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["wwtemp"]) {
|
|
||||||
uint8_t t = doc["wwtemp"];
|
|
||||||
set_warmwater_temp(t);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["boilhyston"]) {
|
|
||||||
int8_t t = doc["boilhyston"];
|
|
||||||
set_hyst_on(t);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["boilhystoff"]) {
|
|
||||||
uint8_t t = doc["boilhystoff"];
|
|
||||||
set_hyst_off(t);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["burnperiod"]) {
|
|
||||||
uint8_t t = doc["burnperiod"];
|
|
||||||
set_burn_period(t);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["burnminpower"]) {
|
|
||||||
uint8_t p = doc["burnminpower"];
|
|
||||||
set_min_power(p);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["burnmaxpower"]) {
|
|
||||||
uint8_t p = doc["burnmaxpower"];
|
|
||||||
set_max_power(p);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["pumpdelay"]) {
|
|
||||||
uint8_t t = doc["pumpdelay"];
|
|
||||||
set_pump_delay(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nullptr != doc["comfort"]) {
|
|
||||||
const char * data = doc["comfort"];
|
|
||||||
if (strcmp((char *)data, "hot") == 0) {
|
|
||||||
set_warmwater_mode(1);
|
|
||||||
} else if (strcmp((char *)data, "eco") == 0) {
|
|
||||||
set_warmwater_mode(2);
|
|
||||||
} else if (strcmp((char *)data, "intelligent") == 0) {
|
|
||||||
set_warmwater_mode(3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * command = doc["cmd"];
|
|
||||||
if (command == nullptr || doc["data"] == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// boiler ww comfort setting
|
|
||||||
if (strcmp(command, "comfort") == 0) {
|
|
||||||
const char * data = doc["data"];
|
|
||||||
if (strcmp((char *)data, "hot") == 0) {
|
|
||||||
set_warmwater_mode(1);
|
|
||||||
} else if (strcmp((char *)data, "eco") == 0) {
|
|
||||||
set_warmwater_mode(2);
|
|
||||||
} else if (strcmp((char *)data, "intelligent") == 0) {
|
|
||||||
set_warmwater_mode(3);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// boiler flowtemp setting
|
|
||||||
if (strcmp(command, "flowtemp") == 0) {
|
|
||||||
uint8_t t = doc["data"];
|
|
||||||
set_flow_temp(t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "wwtemp") == 0) {
|
|
||||||
uint8_t t = doc["data"];
|
|
||||||
set_warmwater_temp(t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// boiler max power setting
|
|
||||||
if (strcmp(command, "burnmaxpower") == 0) {
|
|
||||||
uint8_t p = doc["data"];
|
|
||||||
set_max_power(p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// boiler min power setting
|
|
||||||
if (strcmp(command, "burnminpower") == 0) {
|
|
||||||
uint8_t p = doc["data"];
|
|
||||||
set_min_power(p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "boilhyston") == 0) {
|
|
||||||
int8_t t = doc["data"];
|
|
||||||
set_hyst_on(t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "boilhystoff") == 0) {
|
|
||||||
uint8_t t = doc["data"];
|
|
||||||
set_hyst_off(t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "burnperiod") == 0) {
|
|
||||||
uint8_t t = doc["data"];
|
|
||||||
set_burn_period(t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "pumpdelay") == 0) {
|
|
||||||
uint8_t t = doc["data"];
|
|
||||||
set_pump_delay(t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Boiler::boiler_cmd_wwactivated(const char * message) {
|
|
||||||
if ((message[0] == '1' || strcmp(message, "on") == 0) || (strcmp(message, "auto") == 0)) {
|
|
||||||
set_warmwater_activated(true);
|
|
||||||
} else if (message[0] == '0' || strcmp(message, "off") == 0) {
|
|
||||||
set_warmwater_activated(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Boiler::boiler_cmd_wwonetime(const char * message) {
|
|
||||||
if (message[0] == '1' || strcmp(message, "on") == 0) {
|
|
||||||
set_warmwater_onetime(true);
|
|
||||||
} else if (message[0] == '0' || strcmp(message, "off") == 0) {
|
|
||||||
set_warmwater_onetime(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Boiler::boiler_cmd_wwcirculation(const char * message) {
|
|
||||||
if (message[0] == '1' || strcmp(message, "on") == 0) {
|
|
||||||
set_warmwater_circulation(true);
|
|
||||||
} else if (message[0] == '0' || strcmp(message, "off") == 0) {
|
|
||||||
set_warmwater_circulation(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Boiler::boiler_cmd_wwtemp(const char * message) {
|
|
||||||
uint8_t t = atoi((char *)message);
|
|
||||||
if (t) {
|
|
||||||
set_warmwater_temp(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Boiler::device_info(JsonArray & root) {
|
void Boiler::device_info(JsonArray & root) {
|
||||||
JsonObject dataElement;
|
JsonObject dataElement;
|
||||||
|
|
||||||
@@ -295,16 +134,16 @@ void Boiler::publish_values() {
|
|||||||
if (Helpers::hasValue(pumpMod2_)) {
|
if (Helpers::hasValue(pumpMod2_)) {
|
||||||
doc["pumpMod2"] = pumpMod2_;
|
doc["pumpMod2"] = pumpMod2_;
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWCircPump_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWCircPump_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWCircPump"] = Helpers::render_value(s, wWCircPump_, EMS_VALUE_BOOL);
|
doc["wWCircPump"] = Helpers::render_value(s, wWCircPump_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWCircPumpType_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWCircPumpType_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWCiPuType"] = wWCircPumpType_ ? "valve" : "pump";
|
doc["wWCiPuType"] = wWCircPumpType_ ? "valve" : "pump";
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWCircPumpMode_)) {
|
if (Helpers::hasValue(wWCircPumpMode_)) {
|
||||||
doc["wWCiPuMode"] = wWCircPumpMode_;
|
doc["wWCiPuMode"] = wWCircPumpMode_;
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWCirc_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWCirc_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWCirc"] = Helpers::render_value(s, wWCirc_, EMS_VALUE_BOOL);
|
doc["wWCirc"] = Helpers::render_value(s, wWCirc_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(extTemp_)) {
|
if (Helpers::hasValue(extTemp_)) {
|
||||||
@@ -340,43 +179,43 @@ void Boiler::publish_values() {
|
|||||||
if (Helpers::hasValue(exhaustTemp_)) {
|
if (Helpers::hasValue(exhaustTemp_)) {
|
||||||
doc["exhaustTemp"] = (float)exhaustTemp_ / 10;
|
doc["exhaustTemp"] = (float)exhaustTemp_ / 10;
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWActivated_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWActivated_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWActivated"] = Helpers::render_value(s, wWActivated_, EMS_VALUE_BOOL);
|
doc["wWActivated"] = Helpers::render_value(s, wWActivated_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWOneTime_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWOneTime_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWOnetime"] = Helpers::render_value(s, wWOneTime_, EMS_VALUE_BOOL);
|
doc["wWOnetime"] = Helpers::render_value(s, wWOneTime_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWDesinfecting_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWDesinfecting_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWDesinfecting"] = Helpers::render_value(s, wWDesinfecting_, EMS_VALUE_BOOL);
|
doc["wWDesinfecting"] = Helpers::render_value(s, wWDesinfecting_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWReadiness_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWReadiness_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWReady"] = Helpers::render_value(s, wWReadiness_, EMS_VALUE_BOOL);
|
doc["wWReady"] = Helpers::render_value(s, wWReadiness_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWRecharging_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWRecharging_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWRecharge"] = Helpers::render_value(s, wWRecharging_, EMS_VALUE_BOOL);
|
doc["wWRecharge"] = Helpers::render_value(s, wWRecharging_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWTemperatureOK_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWTemperatureOK_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWTempOK"] = Helpers::render_value(s, wWTemperatureOK_, EMS_VALUE_BOOL);
|
doc["wWTempOK"] = Helpers::render_value(s, wWTemperatureOK_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWCirc_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWCirc_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWCirc"] = Helpers::render_value(s, wWCirc_, EMS_VALUE_BOOL);
|
doc["wWCirc"] = Helpers::render_value(s, wWCirc_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(burnGas_, VALUE_BOOL)) {
|
if (Helpers::hasValue(burnGas_, EMS_VALUE_BOOL)) {
|
||||||
doc["burnGas"] = Helpers::render_value(s, burnGas_, EMS_VALUE_BOOL);
|
doc["burnGas"] = Helpers::render_value(s, burnGas_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(flameCurr_)) {
|
if (Helpers::hasValue(flameCurr_)) {
|
||||||
doc["flameCurr"] = (float)(int16_t)flameCurr_ / 10;
|
doc["flameCurr"] = (float)(int16_t)flameCurr_ / 10;
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(heatPmp_, VALUE_BOOL)) {
|
if (Helpers::hasValue(heatPmp_, EMS_VALUE_BOOL)) {
|
||||||
doc["heatPump"] = Helpers::render_value(s, heatPmp_, EMS_VALUE_BOOL);
|
doc["heatPump"] = Helpers::render_value(s, heatPmp_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(fanWork_, VALUE_BOOL)) {
|
if (Helpers::hasValue(fanWork_, EMS_VALUE_BOOL)) {
|
||||||
doc["fanWork"] = Helpers::render_value(s, fanWork_, EMS_VALUE_BOOL);
|
doc["fanWork"] = Helpers::render_value(s, fanWork_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(ignWork_, VALUE_BOOL)) {
|
if (Helpers::hasValue(ignWork_, EMS_VALUE_BOOL)) {
|
||||||
doc["ignWork"] = Helpers::render_value(s, ignWork_, EMS_VALUE_BOOL);
|
doc["ignWork"] = Helpers::render_value(s, ignWork_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(wWHeat_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWHeat_, EMS_VALUE_BOOL)) {
|
||||||
doc["wWHeat"] = Helpers::render_value(s, wWHeat_, EMS_VALUE_BOOL);
|
doc["wWHeat"] = Helpers::render_value(s, wWHeat_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
if (Helpers::hasValue(heating_temp_)) {
|
if (Helpers::hasValue(heating_temp_)) {
|
||||||
@@ -450,16 +289,16 @@ bool Boiler::updated_values() {
|
|||||||
void Boiler::show_values(uuid::console::Shell & shell) {
|
void Boiler::show_values(uuid::console::Shell & shell) {
|
||||||
EMSdevice::show_values(shell); // for showing the header
|
EMSdevice::show_values(shell); // for showing the header
|
||||||
|
|
||||||
if (Helpers::hasValue(tap_water_active_, VALUE_BOOL)) {
|
if (Helpers::hasValue(tap_water_active_, EMS_VALUE_BOOL)) {
|
||||||
print_value(shell, 2, F("Hot tap water"), tap_water_active_ ? F("running") : F("off"));
|
print_value(shell, 2, F("Hot tap water"), tap_water_active_ ? F("running") : F("off"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Helpers::hasValue(heating_active_, VALUE_BOOL)) {
|
if (Helpers::hasValue(heating_active_, EMS_VALUE_BOOL)) {
|
||||||
print_value(shell, 2, F("Central heating"), heating_active_ ? F("active") : F("off"));
|
print_value(shell, 2, F("Central heating"), heating_active_ ? F("active") : F("off"));
|
||||||
}
|
}
|
||||||
|
|
||||||
print_value(shell, 2, F("Warm Water activated"), wWActivated_, nullptr, EMS_VALUE_BOOL);
|
print_value(shell, 2, F("Warm Water activated"), wWActivated_, nullptr, EMS_VALUE_BOOL);
|
||||||
if (Helpers::hasValue(wWCircPumpType_, VALUE_BOOL)) {
|
if (Helpers::hasValue(wWCircPumpType_, 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 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);
|
print_value(shell, 2, F("Warm Water circulation pump available"), wWCircPump_, nullptr, EMS_VALUE_BOOL);
|
||||||
@@ -557,6 +396,8 @@ void Boiler::show_values(uuid::console::Shell & shell) {
|
|||||||
if (Helpers::hasValue(UBAuptime_)) {
|
if (Helpers::hasValue(UBAuptime_)) {
|
||||||
shell.printfln(F(" Total UBA working time: %d days %d hours %d minutes"), UBAuptime_ / 1440, (UBAuptime_ % 1440) / 60, UBAuptime_ % 60);
|
shell.printfln(F(" Total UBA working time: %d days %d hours %d minutes"), UBAuptime_ / 1440, (UBAuptime_ % 1440) / 60, UBAuptime_ % 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shell.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -579,7 +420,7 @@ void Boiler::check_active() {
|
|||||||
|
|
||||||
// see if the heating or hot tap water has changed, if so send
|
// see if the heating or hot tap water has changed, if so send
|
||||||
// last_boilerActive stores heating in bit 1 and tap water in bit 2
|
// last_boilerActive stores heating in bit 1 and tap water in bit 2
|
||||||
if (Helpers::hasValue(tap_water_active_, VALUE_BOOL) && Helpers::hasValue(heating_active_, VALUE_BOOL)) {
|
if (Helpers::hasValue(tap_water_active_, EMS_VALUE_BOOL) && Helpers::hasValue(heating_active_, EMS_VALUE_BOOL)) {
|
||||||
uint8_t latest_boilerState = (tap_water_active_ << 1) + heating_active_;
|
uint8_t latest_boilerState = (tap_water_active_ << 1) + heating_active_;
|
||||||
if (latest_boilerState != last_boilerState) {
|
if (latest_boilerState != last_boilerState) {
|
||||||
last_boilerState = latest_boilerState;
|
last_boilerState = latest_boilerState;
|
||||||
@@ -650,12 +491,12 @@ void Boiler::process_UBATotalUptime(std::shared_ptr<const Telegram> telegram) {
|
|||||||
*/
|
*/
|
||||||
void Boiler::process_UBAParameters(std::shared_ptr<const Telegram> telegram) {
|
void Boiler::process_UBAParameters(std::shared_ptr<const Telegram> telegram) {
|
||||||
telegram->read_value(heating_temp_, 1);
|
telegram->read_value(heating_temp_, 1);
|
||||||
telegram->read_value(burnPowermax_,2);
|
telegram->read_value(burnPowermax_, 2);
|
||||||
telegram->read_value(burnPowermin_,3);
|
telegram->read_value(burnPowermin_, 3);
|
||||||
telegram->read_value(boilTemp_off_,4);
|
telegram->read_value(boilTemp_off_, 4);
|
||||||
telegram->read_value(boilTemp_on_,5);
|
telegram->read_value(boilTemp_on_, 5);
|
||||||
telegram->read_value(burnPeriod_,6);
|
telegram->read_value(burnPeriod_, 6);
|
||||||
telegram->read_value(pumpDelay_,8);
|
telegram->read_value(pumpDelay_, 8);
|
||||||
telegram->read_value(pump_mod_max_, 9);
|
telegram->read_value(pump_mod_max_, 9);
|
||||||
telegram->read_value(pump_mod_min_, 10);
|
telegram->read_value(pump_mod_min_, 10);
|
||||||
}
|
}
|
||||||
@@ -804,7 +645,7 @@ void Boiler::process_UBAMaintenanceStatus(std::shared_ptr<const Telegram> telegr
|
|||||||
// 0x10, 0x11, 0x12
|
// 0x10, 0x11, 0x12
|
||||||
// not yet implemented
|
// not yet implemented
|
||||||
void Boiler::process_UBAErrorMessage(std::shared_ptr<const Telegram> telegram) {
|
void Boiler::process_UBAErrorMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
// data: displaycode(2), errornumner(2), year, month, hour, day, minute, duration(2), src-addr
|
// data: displaycode(2), errornumber(2), year, month, hour, day, minute, duration(2), src-addr
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
@@ -818,67 +659,113 @@ void Boiler::process_UBAMaintenanceData(std::shared_ptr<const Telegram> telegram
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Commands
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
// Set the warm water temperature 0x33
|
// Set the warm water temperature 0x33
|
||||||
void Boiler::set_warmwater_temp(const uint8_t temperature) {
|
void Boiler::set_warmwater_temp(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler warm water temperature to %d C"), temperature);
|
uint8_t v = 0;
|
||||||
write_command(EMS_TYPE_UBAParameterWW, 2, temperature);
|
if (!Helpers::value2number(value, v)) {
|
||||||
write_command(EMS_TYPE_UBAFlags, 3, temperature); // for i9000, see #397
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting boiler warm water temperature to %d C"), v);
|
||||||
|
write_command(EMS_TYPE_UBAParameterWW, 2, v);
|
||||||
|
write_command(EMS_TYPE_UBAFlags, 3, v); // for i9000, see #397
|
||||||
}
|
}
|
||||||
|
|
||||||
// flow temp
|
// flow temp
|
||||||
void Boiler::set_flow_temp(const uint8_t temperature) {
|
void Boiler::set_flow_temp(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler flow temperature to %d C"), temperature);
|
uint8_t v = 0;
|
||||||
write_command(EMS_TYPE_UBASetPoints, 0, temperature);
|
if (!Helpers::value2number(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting boiler flow temperature to %d C"), v);
|
||||||
|
write_command(EMS_TYPE_UBASetPoints, 0, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set min boiler output
|
// set min boiler output
|
||||||
void Boiler::set_min_power(const uint8_t power) {
|
void Boiler::set_min_power(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler min power to "), power);
|
uint8_t v = 0;
|
||||||
write_command(EMS_TYPE_UBAParameters, 3, power);
|
if (!Helpers::value2number(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG_INFO(F("Setting boiler min power to "), v);
|
||||||
|
write_command(EMS_TYPE_UBAParameters, 3, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set max temp
|
// set max temp
|
||||||
void Boiler::set_max_power(const uint8_t power) {
|
void Boiler::set_max_power(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler max power to %d C"), power);
|
uint8_t v = 0;
|
||||||
write_command(EMS_TYPE_UBAParameters, 2, power);
|
if (!Helpers::value2number(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting boiler max power to %d C"), v);
|
||||||
|
write_command(EMS_TYPE_UBAParameters, 2, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set oiler on hysteresis
|
// set oiler on hysteresis
|
||||||
void Boiler::set_hyst_on(const uint8_t temp) {
|
void Boiler::set_hyst_on(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler hysteresis on to %d C"), temp);
|
uint8_t v = 0;
|
||||||
write_command(EMS_TYPE_UBAParameters, 5, temp);
|
if (!Helpers::value2number(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting boiler hysteresis on to %d C"), v);
|
||||||
|
write_command(EMS_TYPE_UBAParameters, 5, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set boiler off hysteresis
|
// set boiler off hysteresis
|
||||||
void Boiler::set_hyst_off(const uint8_t temp) {
|
void Boiler::set_hyst_off(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler hysteresis off to %d C"), temp);
|
uint8_t v = 0;
|
||||||
write_command(EMS_TYPE_UBAParameters, 4, temp);
|
if (!Helpers::value2number(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting boiler hysteresis off to %d C"), v);
|
||||||
|
write_command(EMS_TYPE_UBAParameters, 4, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set min burner period
|
// set min burner period
|
||||||
void Boiler::set_burn_period(const uint8_t t) {
|
void Boiler::set_burn_period(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting burner min. period to %d min"), t);
|
uint8_t v = 0;
|
||||||
write_command(EMS_TYPE_UBAParameters, 6, t);
|
if (!Helpers::value2number(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting burner min. period to %d min"), v);
|
||||||
|
write_command(EMS_TYPE_UBAParameters, 6, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set pump delay
|
// set pump delay
|
||||||
void Boiler::set_pump_delay(const uint8_t t) {
|
void Boiler::set_pump_delay(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler pump delay to %d min"), t);
|
uint8_t v = 0;
|
||||||
write_command(EMS_TYPE_UBAParameters, 8, t);
|
if (!Helpers::value2number(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting boiler pump delay to %d min"), v);
|
||||||
|
write_command(EMS_TYPE_UBAParameters, 8, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1=hot, 2=eco, 3=intelligent
|
|
||||||
// note some boilers do not have this setting, than it's done by thermostat
|
// note some boilers do not have this setting, than it's done by thermostat
|
||||||
// on a RC35 it's by EMSESP::send_write_request(0x37, 0x10, 2, &set, 1, 0); (set is 1,2,3)
|
// on a RC35 it's by EMSESP::send_write_request(0x37, 0x10, 2, &set, 1, 0); (set is 1,2,3) 1=hot, 2=eco, 3=intelligent
|
||||||
void Boiler::set_warmwater_mode(const uint8_t comfort) {
|
void Boiler::set_warmwater_mode(const char * value, const int8_t id) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
uint8_t set;
|
uint8_t set;
|
||||||
if (comfort == 1) {
|
if (strcmp(value, "hot") == 0) {
|
||||||
LOG_INFO(F("Setting boiler warm water to Hot"));
|
LOG_INFO(F("Setting boiler warm water to Hot"));
|
||||||
set = 0x00;
|
set = 0x00;
|
||||||
} else if (comfort == 2) {
|
} else if (strcmp(value, "eco") == 0) {
|
||||||
LOG_INFO(F("Setting boiler warm water to Eco"));
|
LOG_INFO(F("Setting boiler warm water to Eco"));
|
||||||
set = 0xD8;
|
set = 0xD8;
|
||||||
} else if (comfort == 3) {
|
} else if (strcmp(value, "intelligent") == 0) {
|
||||||
LOG_INFO(F("Setting boiler warm water to Intelligent"));
|
LOG_INFO(F("Setting boiler warm water to Intelligent"));
|
||||||
set = 0xEC;
|
set = 0xEC;
|
||||||
} else {
|
} else {
|
||||||
@@ -888,24 +775,33 @@ void Boiler::set_warmwater_mode(const uint8_t comfort) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// turn on/off warm water
|
// turn on/off warm water
|
||||||
void Boiler::set_warmwater_activated(const bool activated) {
|
void Boiler::set_warmwater_activated(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler warm water %s"), activated ? "on" : "off");
|
bool v = false;
|
||||||
uint8_t value;
|
if (!Helpers::value2bool(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting boiler warm water %s"), v ? "on" : "off");
|
||||||
|
|
||||||
// https://github.com/proddy/EMS-ESP/issues/268
|
// https://github.com/proddy/EMS-ESP/issues/268
|
||||||
|
uint8_t n;
|
||||||
if (EMSbus::is_ht3()) {
|
if (EMSbus::is_ht3()) {
|
||||||
value = (activated ? 0x08 : 0x00); // 0x08 is on, 0x00 is off
|
n = (v ? 0x08 : 0x00); // 0x08 is on, 0x00 is off
|
||||||
} else {
|
} else {
|
||||||
value = (activated ? 0xFF : 0x00); // 0xFF is on, 0x00 is off
|
n = (v ? 0xFF : 0x00); // 0xFF is on, 0x00 is off
|
||||||
}
|
}
|
||||||
write_command(EMS_TYPE_UBAParameterWW, 1, value);
|
write_command(EMS_TYPE_UBAParameterWW, 1, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate / De-activate the Warm Tap Water
|
// Activate / De-activate the Warm Tap Water
|
||||||
// true = on, false = off
|
|
||||||
// Note: Using the type 0x1D to put the boiler into Test mode. This may be shown on the boiler with a flashing 'T'
|
// Note: Using the type 0x1D to put the boiler into Test mode. This may be shown on the boiler with a flashing 'T'
|
||||||
void Boiler::set_tapwarmwater_activated(const bool activated) {
|
void Boiler::set_tapwarmwater_activated(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler warm tap water %s"), activated ? "on" : "off");
|
bool v = false;
|
||||||
|
if (!Helpers::value2bool(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting tap warm tap water %s"), v ? "on" : "off");
|
||||||
uint8_t message_data[EMS_MAX_TELEGRAM_MESSAGE_LENGTH];
|
uint8_t message_data[EMS_MAX_TELEGRAM_MESSAGE_LENGTH];
|
||||||
for (uint8_t i = 0; i < sizeof(message_data); i++) {
|
for (uint8_t i = 0; i < sizeof(message_data); i++) {
|
||||||
message_data[i] = 0x00;
|
message_data[i] = 0x00;
|
||||||
@@ -914,7 +810,7 @@ void Boiler::set_tapwarmwater_activated(const bool activated) {
|
|||||||
// we use the special test mode 0x1D for this. Setting the first data to 5A puts the system into test mode and
|
// we use the special test mode 0x1D for this. Setting the first data to 5A puts the system into test mode and
|
||||||
// a setting of 0x00 puts it back into normal operating mode
|
// a setting of 0x00 puts it back into normal operating mode
|
||||||
// when in test mode we're able to mess around with the 3-way valve settings
|
// when in test mode we're able to mess around with the 3-way valve settings
|
||||||
if (!activated) {
|
if (!v) {
|
||||||
// on
|
// on
|
||||||
message_data[0] = 0x5A; // test mode on
|
message_data[0] = 0x5A; // test mode on
|
||||||
message_data[1] = 0x00; // burner output 0%
|
message_data[1] = 0x00; // burner output 0%
|
||||||
@@ -932,16 +828,26 @@ void Boiler::set_tapwarmwater_activated(const bool activated) {
|
|||||||
// Activate / De-activate One Time warm water 0x35
|
// Activate / De-activate One Time warm water 0x35
|
||||||
// true = on, false = off
|
// true = on, false = off
|
||||||
// See also https://github.com/proddy/EMS-ESP/issues/341#issuecomment-596245458 for Junkers
|
// See also https://github.com/proddy/EMS-ESP/issues/341#issuecomment-596245458 for Junkers
|
||||||
void Boiler::set_warmwater_onetime(const bool activated) {
|
void Boiler::set_warmwater_onetime(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler warm water OneTime loading %s"), activated ? "on" : "off");
|
bool v = false;
|
||||||
write_command(EMS_TYPE_UBAFlags, 0, (activated ? 0x22 : 0x02));
|
if (!Helpers::value2bool(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting boiler warm water OneTime loading %s"), v ? "on" : "off");
|
||||||
|
write_command(EMS_TYPE_UBAFlags, 0, (v ? 0x22 : 0x02));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate / De-activate circulation of warm water 0x35
|
// Activate / De-activate circulation of warm water 0x35
|
||||||
// true = on, false = off
|
// true = on, false = off
|
||||||
void Boiler::set_warmwater_circulation(const bool activated) {
|
void Boiler::set_warmwater_circulation(const char * value, const int8_t id) {
|
||||||
LOG_INFO(F("Setting boiler warm water circulation %s"), activated ? "on" : "off");
|
bool v = false;
|
||||||
write_command(EMS_TYPE_UBAFlags, 1, (activated ? 0x22 : 0x02));
|
if (!Helpers::value2bool(value, v)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(F("Setting boiler warm water circulation %s"), v ? "on" : "off");
|
||||||
|
write_command(EMS_TYPE_UBAFlags, 1, (v ? 0x22 : 0x02));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add console commands
|
// add console commands
|
||||||
@@ -955,115 +861,6 @@ void Boiler::console_commands(Shell & shell, unsigned int context) {
|
|||||||
EMSESP::send_read_request(type_id, device_id());
|
EMSESP::send_read_request(type_id, device_id());
|
||||||
});
|
});
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(wwtemp)},
|
|
||||||
flash_string_vector{F_(degrees_mandatory)},
|
|
||||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
|
||||||
set_warmwater_temp(Helpers::atoint(arguments.front().c_str()));
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(flowtemp)},
|
|
||||||
flash_string_vector{F_(degrees_mandatory)},
|
|
||||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
|
||||||
set_flow_temp(Helpers::atoint(arguments.front().c_str()));
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(maxpower)},
|
|
||||||
flash_string_vector{F_(n_mandatory)},
|
|
||||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
|
||||||
set_max_power(Helpers::atoint(arguments.front().c_str()));
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(minpower)},
|
|
||||||
flash_string_vector{F_(n_mandatory)},
|
|
||||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
|
||||||
set_min_power(Helpers::atoint(arguments.front().c_str()));
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(
|
|
||||||
ShellContext::BOILER,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(wwactive)},
|
|
||||||
flash_string_vector{F_(bool_mandatory)},
|
|
||||||
[=](Shell & shell, const std::vector<std::string> & arguments) {
|
|
||||||
if (arguments[0] == read_flash_string(F_(on))) {
|
|
||||||
set_warmwater_activated(true);
|
|
||||||
} else if (arguments[0] == read_flash_string(F_(off))) {
|
|
||||||
set_warmwater_activated(false);
|
|
||||||
} else {
|
|
||||||
shell.println(F("Must be on or off"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
|
||||||
return std::vector<std::string>{read_flash_string(F_(on)), read_flash_string(F_(off))};
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(
|
|
||||||
ShellContext::BOILER,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(wwonetime)},
|
|
||||||
flash_string_vector{F_(bool_mandatory)},
|
|
||||||
[=](Shell & shell, const std::vector<std::string> & arguments) {
|
|
||||||
if (arguments[0] == read_flash_string(F_(on))) {
|
|
||||||
set_warmwater_onetime(true);
|
|
||||||
} else if (arguments[0] == read_flash_string(F_(off))) {
|
|
||||||
set_warmwater_onetime(false);
|
|
||||||
} else {
|
|
||||||
shell.println(F("Must be on or off"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
|
||||||
return std::vector<std::string>{read_flash_string(F_(on)), read_flash_string(F_(off))};
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(
|
|
||||||
ShellContext::BOILER,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(wwcirculation)},
|
|
||||||
flash_string_vector{F_(bool_mandatory)},
|
|
||||||
[=](Shell & shell, const std::vector<std::string> & arguments) {
|
|
||||||
if (arguments[0] == read_flash_string(F_(on))) {
|
|
||||||
set_warmwater_circulation(true);
|
|
||||||
} else if (arguments[0] == read_flash_string(F_(off))) {
|
|
||||||
set_warmwater_circulation(false);
|
|
||||||
} else {
|
|
||||||
shell.println(F("Must be on or off"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
|
||||||
return std::vector<std::string>{read_flash_string(F_(on)), read_flash_string(F_(off))};
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(
|
|
||||||
ShellContext::BOILER,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(comfort)},
|
|
||||||
flash_string_vector{F_(comfort_mandatory)},
|
|
||||||
[=](Shell & shell, const std::vector<std::string> & arguments) {
|
|
||||||
if (arguments[0] == read_flash_string(F_(hot))) {
|
|
||||||
set_warmwater_mode(1);
|
|
||||||
} else if (arguments[0] == read_flash_string(F_(eco))) {
|
|
||||||
set_warmwater_mode(2);
|
|
||||||
} else if (arguments[0] == read_flash_string(F_(intelligent))) {
|
|
||||||
set_warmwater_mode(3);
|
|
||||||
} else {
|
|
||||||
shell.println(F("Invalid value. Must be hot, eco or intelligent"));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
|
||||||
return std::vector<std::string>{read_flash_string(F_(hot)), read_flash_string(F_(eco)), read_flash_string(F_(intelligent))};
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
||||||
CommandFlags::USER,
|
CommandFlags::USER,
|
||||||
flash_string_vector{F_(show)},
|
flash_string_vector{F_(show)},
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class Boiler : public EMSdevice {
|
|||||||
uint8_t burnPowermin_ = EMS_VALUE_UINT_NOTSET;
|
uint8_t burnPowermin_ = EMS_VALUE_UINT_NOTSET;
|
||||||
uint8_t burnPowermax_ = EMS_VALUE_UINT_NOTSET;
|
uint8_t burnPowermax_ = EMS_VALUE_UINT_NOTSET;
|
||||||
int8_t boilTemp_off_ = EMS_VALUE_INT_NOTSET;
|
int8_t boilTemp_off_ = EMS_VALUE_INT_NOTSET;
|
||||||
int8_t boilTemp_on_ = EMS_VALUE_UINT_NOTSET;
|
int8_t boilTemp_on_ = EMS_VALUE_INT_NOTSET;
|
||||||
uint8_t burnPeriod_ = EMS_VALUE_UINT_NOTSET;
|
uint8_t burnPeriod_ = EMS_VALUE_UINT_NOTSET;
|
||||||
uint8_t pumpDelay_ = EMS_VALUE_UINT_NOTSET;
|
uint8_t pumpDelay_ = EMS_VALUE_UINT_NOTSET;
|
||||||
|
|
||||||
@@ -160,27 +160,20 @@ class Boiler : public EMSdevice {
|
|||||||
|
|
||||||
void check_active();
|
void check_active();
|
||||||
|
|
||||||
void set_warmwater_temp(const uint8_t temperature);
|
// commands
|
||||||
void set_flow_temp(const uint8_t temperature);
|
void set_warmwater_mode(const char * value, const int8_t id);
|
||||||
void set_warmwater_mode(const uint8_t comfort);
|
void set_warmwater_activated(const char * value, const int8_t id);
|
||||||
void set_warmwater_activated(const bool activated);
|
void set_tapwarmwater_activated(const char * value, const int8_t id);
|
||||||
void set_tapwarmwater_activated(const bool activated);
|
void set_warmwater_onetime(const char * value, const int8_t id);
|
||||||
void set_warmwater_onetime(const bool activated);
|
void set_warmwater_circulation(const char * value, const int8_t id);
|
||||||
void set_warmwater_circulation(const bool activated);
|
void set_warmwater_temp(const char * value, const int8_t id);
|
||||||
void set_min_power(const uint8_t power);
|
void set_flow_temp(const char * value, const int8_t id);
|
||||||
void set_max_power(const uint8_t power);
|
void set_min_power(const char * value, const int8_t id);
|
||||||
void set_hyst_on(const uint8_t temp);
|
void set_max_power(const char * value, const int8_t id);
|
||||||
void set_hyst_off(const uint8_t temp);
|
void set_hyst_on(const char * value, const int8_t id);
|
||||||
void set_burn_period(const uint8_t t);
|
void set_hyst_off(const char * value, const int8_t id);
|
||||||
void set_pump_delay(const uint8_t t);
|
void set_burn_period(const char * value, const int8_t id);
|
||||||
|
void set_pump_delay(const char * value, const int8_t id);
|
||||||
|
|
||||||
// mqtt callbacks
|
|
||||||
void boiler_cmd(const char * message);
|
|
||||||
void boiler_cmd_wwactivated(const char * message);
|
|
||||||
void boiler_cmd_wwonetime(const char * message);
|
|
||||||
void boiler_cmd_wwcirculation(const char * message);
|
|
||||||
void boiler_cmd_wwtemp(const char * message);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -22,16 +22,10 @@ namespace emsesp {
|
|||||||
|
|
||||||
REGISTER_FACTORY(Connect, EMSdevice::DeviceType::CONNECT);
|
REGISTER_FACTORY(Connect, EMSdevice::DeviceType::CONNECT);
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "connect")
|
uuid::log::Logger Connect::logger_{F_(connect), uuid::log::Facility::CONSOLE};
|
||||||
uuid::log::Logger Connect::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
|
||||||
|
|
||||||
Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
// telegram handlers
|
|
||||||
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
|
|
||||||
|
|
||||||
// MQTT callbacks
|
|
||||||
// register_mqtt_topic("topic", std::bind(&Connect::cmd, this, _1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connect::device_info(JsonArray & root) {
|
void Connect::device_info(JsonArray & root) {
|
||||||
@@ -42,7 +36,7 @@ void Connect::add_context_menu() {
|
|||||||
|
|
||||||
// display all values into the shell console
|
// display all values into the shell console
|
||||||
void Connect::show_values(uuid::console::Shell & shell) {
|
void Connect::show_values(uuid::console::Shell & shell) {
|
||||||
EMSdevice::show_values(shell); // always call this to show header
|
// EMSdevice::show_values(shell); // always call this to show header
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish values via MQTT
|
// publish values via MQTT
|
||||||
|
|||||||
@@ -18,22 +18,14 @@
|
|||||||
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
|
|
||||||
// MAKE_PSTR_WORD(controller)
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
REGISTER_FACTORY(Controller, EMSdevice::DeviceType::CONTROLLER);
|
REGISTER_FACTORY(Controller, EMSdevice::DeviceType::CONTROLLER);
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "controller")
|
uuid::log::Logger Controller::logger_{F_(controller), uuid::log::Facility::CONSOLE};
|
||||||
uuid::log::Logger Controller::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
|
||||||
|
|
||||||
Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
// telegram handlers
|
|
||||||
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
|
|
||||||
|
|
||||||
// MQTT callbacks
|
|
||||||
// register_mqtt_topic("topic", std::bind(&Controller::cmd, this, _1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::add_context_menu() {
|
void Controller::add_context_menu() {
|
||||||
@@ -44,7 +36,7 @@ void Controller::device_info(JsonArray & root) {
|
|||||||
|
|
||||||
// display all values into the shell console
|
// display all values into the shell console
|
||||||
void Controller::show_values(uuid::console::Shell & shell) {
|
void Controller::show_values(uuid::console::Shell & shell) {
|
||||||
EMSdevice::show_values(shell); // always call this to show header
|
// EMSdevice::show_values(shell); // always call this to show header
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish values via MQTT
|
// publish values via MQTT
|
||||||
|
|||||||
@@ -18,22 +18,14 @@
|
|||||||
|
|
||||||
#include "gateway.h"
|
#include "gateway.h"
|
||||||
|
|
||||||
// MAKE_PSTR_WORD(gateway)
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
REGISTER_FACTORY(Gateway, EMSdevice::DeviceType::GATEWAY);
|
REGISTER_FACTORY(Gateway, EMSdevice::DeviceType::GATEWAY);
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "gateway")
|
uuid::log::Logger Gateway::logger_{F_(gateway), uuid::log::Facility::CONSOLE};
|
||||||
uuid::log::Logger Gateway::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
|
||||||
|
|
||||||
Gateway::Gateway(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
Gateway::Gateway(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
// telegram handlers
|
|
||||||
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
|
|
||||||
|
|
||||||
// MQTT callbacks
|
|
||||||
// register_mqtt_topic("topic", std::bind(&Gateway::cmd, this, _1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gateway::add_context_menu() {
|
void Gateway::add_context_menu() {
|
||||||
|
|||||||
@@ -18,32 +18,19 @@
|
|||||||
|
|
||||||
#include "heatpump.h"
|
#include "heatpump.h"
|
||||||
|
|
||||||
// MAKE_PSTR_WORD(heatpump)
|
|
||||||
|
|
||||||
/*
|
|
||||||
example telegrams 0x32B, 0x37B
|
|
||||||
"38 10 FF 00 03 7B 08 24 00 4B",
|
|
||||||
"38 10 FF 00 03 2B 00 C7 07 C3 01",
|
|
||||||
"38 10 FF 00 03 2B 00 D1 08 2A 01",
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
REGISTER_FACTORY(Heatpump, EMSdevice::DeviceType::HEATPUMP);
|
REGISTER_FACTORY(Heatpump, EMSdevice::DeviceType::HEATPUMP);
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "heatpump")
|
uuid::log::Logger Heatpump::logger_{F_(heatpump), uuid::log::Facility::CONSOLE};
|
||||||
uuid::log::Logger Heatpump::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
|
||||||
|
|
||||||
Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
LOG_DEBUG(F("Registering new Heat Pump module with device ID 0x%02X"), device_id);
|
LOG_DEBUG(F("Adding new Heat Pump module with device ID 0x%02X"), device_id);
|
||||||
|
|
||||||
// telegram handlers
|
// telegram handlers
|
||||||
register_telegram_type(0x047B, F("HP1"), true, std::bind(&Heatpump::process_HPMonitor1, this, _1));
|
register_telegram_type(0x047B, F("HP1"), true, std::bind(&Heatpump::process_HPMonitor1, this, _1));
|
||||||
register_telegram_type(0x042B, F("HP2"), true, std::bind(&Heatpump::process_HPMonitor2, this, _1));
|
register_telegram_type(0x042B, F("HP2"), true, std::bind(&Heatpump::process_HPMonitor2, this, _1));
|
||||||
|
|
||||||
// MQTT callbacks
|
|
||||||
// register_mqtt_topic("topic", std::bind(&Heatpump::cmd, this, _1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// context submenu
|
// context submenu
|
||||||
@@ -55,7 +42,7 @@ void Heatpump::device_info(JsonArray & root) {
|
|||||||
|
|
||||||
// display all values into the shell console
|
// display all values into the shell console
|
||||||
void Heatpump::show_values(uuid::console::Shell & shell) {
|
void Heatpump::show_values(uuid::console::Shell & shell) {
|
||||||
EMSdevice::show_values(shell); // always call this to show header
|
// EMSdevice::show_values(shell); // always call this to show header
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish values via MQTT
|
// publish values via MQTT
|
||||||
|
|||||||
@@ -22,12 +22,11 @@ namespace emsesp {
|
|||||||
|
|
||||||
REGISTER_FACTORY(Mixing, EMSdevice::DeviceType::MIXING);
|
REGISTER_FACTORY(Mixing, EMSdevice::DeviceType::MIXING);
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "mixing")
|
uuid::log::Logger Mixing::logger_{F_(mixing), uuid::log::Facility::CONSOLE};
|
||||||
uuid::log::Logger Mixing::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
|
||||||
|
|
||||||
Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
LOG_DEBUG(F("Registering new Mixing module with device ID 0x%02X"), device_id);
|
LOG_DEBUG(F("Adding new Mixing module with device ID 0x%02X"), device_id);
|
||||||
|
|
||||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) {
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) {
|
||||||
if (device_id <= 0x27) {
|
if (device_id <= 0x27) {
|
||||||
@@ -48,9 +47,6 @@ Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
|
|||||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
|
||||||
register_telegram_type(0x010C, F("IPMSetMessage"), false, std::bind(&Mixing::process_IPMStatusMessage, this, _1));
|
register_telegram_type(0x010C, F("IPMSetMessage"), false, std::bind(&Mixing::process_IPMStatusMessage, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MQTT callbacks
|
|
||||||
// register_mqtt_topic("topic", std::bind(&Mixing::cmd, this, _1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add context submenu
|
// add context submenu
|
||||||
@@ -72,7 +68,6 @@ void Mixing::device_info(JsonArray & root) {
|
|||||||
render_value_json(root, "", F("Setpoint flow temperature"), flowSetTemp_, F_(degrees));
|
render_value_json(root, "", F("Setpoint flow temperature"), flowSetTemp_, F_(degrees));
|
||||||
render_value_json(root, "", F("Current pump modulation"), pumpMod_, F_(percent));
|
render_value_json(root, "", F("Current pump modulation"), pumpMod_, F_(percent));
|
||||||
render_value_json(root, "", F("Current valve status"), status_, nullptr);
|
render_value_json(root, "", F("Current valve status"), status_, nullptr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check to see if values have been updated
|
// check to see if values have been updated
|
||||||
@@ -101,6 +96,8 @@ void Mixing::show_values(uuid::console::Shell & shell) {
|
|||||||
print_value(shell, 4, F("Setpoint flow temperature"), flowSetTemp_, F_(degrees));
|
print_value(shell, 4, F("Setpoint flow temperature"), flowSetTemp_, F_(degrees));
|
||||||
print_value(shell, 4, F("Current pump modulation"), pumpMod_, F_(percent));
|
print_value(shell, 4, F("Current pump modulation"), pumpMod_, F_(percent));
|
||||||
print_value(shell, 4, F("Current valve status"), status_, nullptr);
|
print_value(shell, 4, F("Current valve status"), status_, nullptr);
|
||||||
|
|
||||||
|
shell.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish values via MQTT
|
// publish values via MQTT
|
||||||
|
|||||||
@@ -18,19 +18,15 @@
|
|||||||
|
|
||||||
#include "solar.h"
|
#include "solar.h"
|
||||||
|
|
||||||
MAKE_PSTR(kwh, "kWh")
|
|
||||||
MAKE_PSTR(wh, "Wh")
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
REGISTER_FACTORY(Solar, EMSdevice::DeviceType::SOLAR);
|
REGISTER_FACTORY(Solar, EMSdevice::DeviceType::SOLAR);
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "solar")
|
uuid::log::Logger Solar::logger_{F_(solar), uuid::log::Facility::CONSOLE};
|
||||||
uuid::log::Logger Solar::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
|
||||||
|
|
||||||
Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
LOG_DEBUG(F("Registering new Solar module with device ID 0x%02X"), device_id);
|
LOG_DEBUG(F("Adding new Solar module with device ID 0x%02X"), device_id);
|
||||||
|
|
||||||
// telegram handlers
|
// telegram handlers
|
||||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
|
||||||
@@ -49,9 +45,6 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
|
|||||||
register_telegram_type(0x0103, F("ISM1StatusMessage"), true, std::bind(&Solar::process_ISM1StatusMessage, this, _1));
|
register_telegram_type(0x0103, F("ISM1StatusMessage"), true, std::bind(&Solar::process_ISM1StatusMessage, this, _1));
|
||||||
register_telegram_type(0x0101, F("ISM1Set"), false, std::bind(&Solar::process_ISM1Set, this, _1));
|
register_telegram_type(0x0101, F("ISM1Set"), false, std::bind(&Solar::process_ISM1Set, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MQTT callbacks
|
|
||||||
// register_mqtt_topic("topic", std::bind(&Solar::cmd, this, _1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// context submenu
|
// context submenu
|
||||||
@@ -105,6 +98,8 @@ void Solar::show_values(uuid::console::Shell & shell) {
|
|||||||
print_value(shell, 2, F("Energy last hour"), energyLastHour_, F_(wh), 10);
|
print_value(shell, 2, F("Energy last hour"), energyLastHour_, F_(wh), 10);
|
||||||
print_value(shell, 2, F("Energy today"), energyToday_, F_(wh));
|
print_value(shell, 2, F("Energy today"), energyToday_, F_(wh));
|
||||||
print_value(shell, 2, F("Energy total"), energyTotal_, F_(kwh), 10);
|
print_value(shell, 2, F("Energy total"), energyTotal_, F_(kwh), 10);
|
||||||
|
|
||||||
|
shell.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish values via MQTT
|
// publish values via MQTT
|
||||||
@@ -129,11 +124,11 @@ void Solar::publish_values() {
|
|||||||
doc["pumpmodulation"] = pumpModulation_;
|
doc["pumpmodulation"] = pumpModulation_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Helpers::hasValue(pump_, VALUE_BOOL)) {
|
if (Helpers::hasValue(pump_, EMS_VALUE_BOOL)) {
|
||||||
doc["pump"] = Helpers::render_value(s, pump_, EMS_VALUE_BOOL);
|
doc["pump"] = Helpers::render_value(s, pump_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Helpers::hasValue(valveStatus_, VALUE_BOOL)) {
|
if (Helpers::hasValue(valveStatus_, EMS_VALUE_BOOL)) {
|
||||||
doc["valvestatus"] = Helpers::render_value(s, valveStatus_, EMS_VALUE_BOOL);
|
doc["valvestatus"] = Helpers::render_value(s, valveStatus_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,11 +136,11 @@ void Solar::publish_values() {
|
|||||||
doc["pumpWorkMin"] = (float)pumpWorkMin_;
|
doc["pumpWorkMin"] = (float)pumpWorkMin_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Helpers::hasValue(tankHeated_, VALUE_BOOL)) {
|
if (Helpers::hasValue(tankHeated_, EMS_VALUE_BOOL)) {
|
||||||
doc["tankHeated"] = Helpers::render_value(s, tankHeated_, EMS_VALUE_BOOL);
|
doc["tankHeated"] = Helpers::render_value(s, tankHeated_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Helpers::hasValue(collectorOnOff_, VALUE_BOOL)) {
|
if (Helpers::hasValue(collectorOnOff_, EMS_VALUE_BOOL)) {
|
||||||
doc["collectorOnOff"] = Helpers::render_value(s, collectorOnOff_, EMS_VALUE_BOOL);
|
doc["collectorOnOff"] = Helpers::render_value(s, collectorOnOff_, EMS_VALUE_BOOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,22 +18,14 @@
|
|||||||
|
|
||||||
#include "switch.h"
|
#include "switch.h"
|
||||||
|
|
||||||
// MAKE_PSTR_WORD(switch)
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
REGISTER_FACTORY(Switch, EMSdevice::DeviceType::SWITCH);
|
REGISTER_FACTORY(Switch, EMSdevice::DeviceType::SWITCH);
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "switch")
|
uuid::log::Logger Switch::logger_{F_(switch), uuid::log::Facility::CONSOLE};
|
||||||
uuid::log::Logger Switch::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
|
||||||
|
|
||||||
Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
// telegram handlers
|
|
||||||
// register_telegram_type(EMS_TYPE_XX, "XX", false, std::bind(&Controller::process_XX, this, _1));
|
|
||||||
|
|
||||||
// MQTT callbacks
|
|
||||||
// register_mqtt_topic("topic", std::bind(&Switch::cmd, this, _1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Switch::add_context_menu() {
|
void Switch::add_context_menu() {
|
||||||
@@ -44,7 +36,7 @@ void Switch::device_info(JsonArray & root) {
|
|||||||
|
|
||||||
// display all values into the shell console
|
// display all values into the shell console
|
||||||
void Switch::show_values(uuid::console::Shell & shell) {
|
void Switch::show_values(uuid::console::Shell & shell) {
|
||||||
EMSdevice::show_values(shell); // always call this to show header
|
// EMSdevice::show_values(shell); // always call this to show header
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish values via MQTT
|
// publish values via MQTT
|
||||||
|
|||||||
@@ -18,22 +18,11 @@
|
|||||||
|
|
||||||
#include "thermostat.h"
|
#include "thermostat.h"
|
||||||
|
|
||||||
MAKE_PSTR_WORD(thermostat)
|
|
||||||
MAKE_PSTR_WORD(master)
|
|
||||||
MAKE_PSTR_WORD(temp)
|
|
||||||
MAKE_PSTR_WORD(mode)
|
|
||||||
MAKE_PSTR_WORD(wwmode)
|
|
||||||
|
|
||||||
MAKE_PSTR(hc_optional, "[heating circuit]")
|
|
||||||
MAKE_PSTR(mode_mandatory, "<mode>")
|
|
||||||
MAKE_PSTR(mode_optional, "[mode]")
|
|
||||||
MAKE_PSTR(master_thermostat_fmt, "Master Thermostat device ID = %s")
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
REGISTER_FACTORY(Thermostat, EMSdevice::DeviceType::THERMOSTAT);
|
REGISTER_FACTORY(Thermostat, EMSdevice::DeviceType::THERMOSTAT);
|
||||||
MAKE_PSTR(logger_name, "thermostat")
|
|
||||||
uuid::log::Logger Thermostat::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
uuid::log::Logger Thermostat::logger_{F_(thermostat), uuid::log::Facility::CONSOLE};
|
||||||
|
|
||||||
Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
|
||||||
@@ -138,18 +127,17 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
uint8_t actual_master_thermostat = EMSESP::actual_master_thermostat(); // what we're actually using
|
uint8_t actual_master_thermostat = EMSESP::actual_master_thermostat(); // what we're actually using
|
||||||
uint8_t num_devices = EMSESP::count_devices(EMSdevice::DeviceType::THERMOSTAT) + 1; // including this thermostat
|
uint8_t num_devices = EMSESP::count_devices(EMSdevice::DeviceType::THERMOSTAT) + 1; // including this thermostat
|
||||||
|
|
||||||
// if we're on auto mode, register this thermostat if it has a device id of 0x10 or 0x17
|
// if we're on auto mode, register this thermostat if it has a device id of 0x10, 0x17 or 0x18
|
||||||
// or if its the master thermostat we defined
|
// or if its the master thermostat we defined
|
||||||
// see https://github.com/proddy/EMS-ESP/issues/362#issuecomment-629628161
|
// see https://github.com/proddy/EMS-ESP/issues/362#issuecomment-629628161
|
||||||
if (((num_devices == 1) && (actual_master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT)) || (master_thermostat == device_id)) {
|
if (((num_devices == 1) && (actual_master_thermostat == EMSESP_DEFAULT_MASTER_THERMOSTAT)) || (master_thermostat == device_id)) {
|
||||||
EMSESP::actual_master_thermostat(device_id);
|
EMSESP::actual_master_thermostat(device_id);
|
||||||
LOG_DEBUG(F("Registering new thermostat with device ID 0x%02X (as master)"), device_id);
|
LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X (as master)"), device_id);
|
||||||
init_mqtt();
|
init_mqtt();
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG(F("Registering new thermostat with device ID 0x%02X"), device_id);
|
LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X"), device_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// for the thermostat, go a query all the heating circuits. This is only done once. The automatic fetch will from now on
|
// for the thermostat, go a query all the heating circuits. This is only done once. The automatic fetch will from now on
|
||||||
// only update the active heating circuits
|
// only update the active heating circuits
|
||||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
@@ -160,14 +148,6 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for the master thermostat initialize the MQTT subscribes
|
|
||||||
// these will be prefixed with hostname
|
|
||||||
void Thermostat::init_mqtt() {
|
|
||||||
register_mqtt_topic("thermostat_cmd", std::bind(&Thermostat::thermostat_cmd, this, _1)); // generic commands
|
|
||||||
register_mqtt_topic("thermostat_cmd_temp", std::bind(&Thermostat::thermostat_cmd_temp, this, _1));
|
|
||||||
register_mqtt_topic("thermostat_cmd_mode", std::bind(&Thermostat::thermostat_cmd_mode, this, _1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare data for Web UI
|
// prepare data for Web UI
|
||||||
void Thermostat::device_info(JsonArray & root) {
|
void Thermostat::device_info(JsonArray & root) {
|
||||||
uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits
|
uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits
|
||||||
@@ -205,14 +185,18 @@ void Thermostat::device_info(JsonArray & root) {
|
|||||||
dataElement = root.createNestedObject();
|
dataElement = root.createNestedObject();
|
||||||
std::string mode_str(15, '\0');
|
std::string mode_str(15, '\0');
|
||||||
snprintf_P(&mode_str[0], mode_str.capacity() + 1, PSTR("%sMode"), hc_str.c_str());
|
snprintf_P(&mode_str[0], mode_str.capacity() + 1, PSTR("%sMode"), hc_str.c_str());
|
||||||
dataElement["name"] = mode_str;
|
dataElement["name"] = mode_str;
|
||||||
std::string modetype_str(20, '\0');
|
std::string modetype_str(20, '\0');
|
||||||
if (Helpers::hasValue(hc->summer_mode) && hc->summer_mode) {
|
if (Helpers::hasValue(hc->summer_mode) && hc->summer_mode) {
|
||||||
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - summer"), mode_tostring(hc->get_mode(flags)).c_str());
|
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - summer"), mode_tostring(hc->get_mode(flags)).c_str());
|
||||||
} else if (Helpers::hasValue(hc->holiday_mode) && hc->holiday_mode) {
|
} else if (Helpers::hasValue(hc->holiday_mode) && hc->holiday_mode) {
|
||||||
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - holiday"), mode_tostring(hc->get_mode(flags)).c_str());
|
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - holiday"), mode_tostring(hc->get_mode(flags)).c_str());
|
||||||
} else if (Helpers::hasValue(hc->mode_type)) {
|
} else if (Helpers::hasValue(hc->mode_type)) {
|
||||||
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - %s"), mode_tostring(hc->get_mode(flags)).c_str(), mode_tostring(hc->get_mode_type(flags)).c_str());
|
snprintf_P(&modetype_str[0],
|
||||||
|
modetype_str.capacity() + 1,
|
||||||
|
PSTR("%s - %s"),
|
||||||
|
mode_tostring(hc->get_mode(flags)).c_str(),
|
||||||
|
mode_tostring(hc->get_mode_type(flags)).c_str());
|
||||||
} else {
|
} else {
|
||||||
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, mode_tostring(hc->get_mode(flags)).c_str());
|
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, mode_tostring(hc->get_mode(flags)).c_str());
|
||||||
}
|
}
|
||||||
@@ -221,8 +205,9 @@ void Thermostat::device_info(JsonArray & root) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// only add the menu for the master thermostat
|
// context menu "thermostat"
|
||||||
void Thermostat::add_context_menu() {
|
void Thermostat::add_context_menu() {
|
||||||
|
// only add it once, to prevent conflicts when there are multiple thermostats
|
||||||
if (device_id() != EMSESP::actual_master_thermostat()) {
|
if (device_id() != EMSESP::actual_master_thermostat()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -232,318 +217,10 @@ void Thermostat::add_context_menu() {
|
|||||||
flash_string_vector{F_(thermostat)},
|
flash_string_vector{F_(thermostat)},
|
||||||
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||||
Thermostat::console_commands(shell, ShellContext::THERMOSTAT);
|
Thermostat::console_commands(shell, ShellContext::THERMOSTAT);
|
||||||
|
add_context_commands(ShellContext::THERMOSTAT);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// general MQTT command for controlling thermostat
|
|
||||||
// e.g. { "hc": 1, "cmd":"daytemp", "data": 20 }
|
|
||||||
// or { "hc": 1, "daytemp": 20 } or { "hc2": { "daytemp":20 }}
|
|
||||||
void Thermostat::thermostat_cmd(const char * message) {
|
|
||||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
|
||||||
DeserializationError error = deserializeJson(doc, message);
|
|
||||||
if (error) {
|
|
||||||
LOG_DEBUG(F("MQTT error: payload %s, error %s"), message, error.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for nested commands like {"hc2":{"temp":21}}
|
|
||||||
for (const auto & hc : heating_circuits_) {
|
|
||||||
char hc_name[6], s[3]; // hc{1-4}
|
|
||||||
strlcpy(hc_name, "hc", 6);
|
|
||||||
uint8_t hc_num = hc->hc_num();
|
|
||||||
strlcat(hc_name, Helpers::itoa(s, hc_num), 6);
|
|
||||||
if (nullptr != doc[hc_name]["mode"]) {
|
|
||||||
std::string mode = doc[hc_name]["mode"];
|
|
||||||
set_mode(mode, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["temp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::AUTO, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["nighttemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::NIGHT, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["daytemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::DAY, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["nofrosttemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::NOFROST, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["ecotemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::ECO, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["heattemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::HEAT, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["summertemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::SUMMER, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["designtemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::DESIGN, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["offsettemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::OFFSET, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["holidaytemp"]) { //
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::HOLIDAY, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc[hc_name]["remotetemp"]) {
|
|
||||||
if (f > 100 || f < 0) {
|
|
||||||
Roomctrl::set_remotetemp(hc_num - 1, EMS_VALUE_SHORT_NOTSET);
|
|
||||||
} else {
|
|
||||||
Roomctrl::set_remotetemp(hc_num - 1, (int16_t)(f * 10));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nullptr != doc[hc_name]["control"]) {
|
|
||||||
uint8_t ctrl = doc[hc_name]["control"];
|
|
||||||
set_control(ctrl, hc_num);
|
|
||||||
}
|
|
||||||
if (nullptr != doc[hc_name]["pause"]) {
|
|
||||||
uint8_t p = doc[hc_name]["pause"];
|
|
||||||
set_pause(p, hc_num);
|
|
||||||
}
|
|
||||||
if (nullptr != doc[hc_name]["party"]) {
|
|
||||||
uint8_t p = doc[hc_name]["party"];
|
|
||||||
set_party(p, hc_num);
|
|
||||||
}
|
|
||||||
if (nullptr != doc[hc_name]["holiday"]) {
|
|
||||||
std::string holiday = doc[hc_name]["holiday"];
|
|
||||||
set_holiday(holiday.c_str(), hc_num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// commands without heatingcircuit
|
|
||||||
if (nullptr != doc["wwmode"]) {
|
|
||||||
std::string mode = doc["wwmode"];
|
|
||||||
set_ww_mode(mode);
|
|
||||||
}
|
|
||||||
if (float ct = doc["calinttemp"]) {
|
|
||||||
set_settings_calinttemp((int8_t)(ct * 10));
|
|
||||||
}
|
|
||||||
if (nullptr != doc["minexttemp"]) {
|
|
||||||
int8_t mt = doc["minexttemp"];
|
|
||||||
set_settings_minexttemp(mt);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["building"]) {
|
|
||||||
std::string bds = doc["building"];
|
|
||||||
uint8_t bd = doc["building"];
|
|
||||||
if (strcmp(bds.c_str(), "light") == 0) {
|
|
||||||
bd = 0;
|
|
||||||
} else if (strcmp(bds.c_str(), "medium") == 0) {
|
|
||||||
bd = 1;
|
|
||||||
} else if (strcmp(bds.c_str(), "heavy") == 0) {
|
|
||||||
bd = 2;
|
|
||||||
}
|
|
||||||
set_settings_building(bd);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["language"]) {
|
|
||||||
uint8_t lg = doc["language"];
|
|
||||||
set_settings_language(lg);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["display"]) {
|
|
||||||
uint8_t dp = doc["display"];
|
|
||||||
set_settings_display(dp);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["clockoffset"]) {
|
|
||||||
int8_t co = doc["clockoffset"];
|
|
||||||
set_settings_clockoffset(co);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get heating circuit if it exists
|
|
||||||
uint8_t hc_num = doc["hc"] | AUTO_HEATING_CIRCUIT;
|
|
||||||
|
|
||||||
// check for unnested commands like {"temp":21} or {"hc":2,"temp":21,"mode":"auto"}
|
|
||||||
if (nullptr != doc["mode"]) {
|
|
||||||
std::string mode = doc["mode"];
|
|
||||||
set_mode(mode, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["temp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::AUTO, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["nighttemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::NIGHT, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["daytemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::DAY, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["nofrosttemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::NOFROST, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["ecotemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::ECO, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["heattemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::HEAT, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["summertemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::SUMMER, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["designtemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::DESIGN, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["offsettemp"]) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::OFFSET, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["holidaytemp"]) { //
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::HOLIDAY, hc_num);
|
|
||||||
}
|
|
||||||
if (float f = doc["remotetemp"]) {
|
|
||||||
if (f > 100 || f < 0) {
|
|
||||||
Roomctrl::set_remotetemp(hc_num - 1, EMS_VALUE_SHORT_NOTSET);
|
|
||||||
} else {
|
|
||||||
Roomctrl::set_remotetemp(hc_num - 1, (int16_t)(f * 10));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nullptr != doc["control"]) {
|
|
||||||
uint8_t ctrl = doc["control"];
|
|
||||||
set_control(ctrl, hc_num);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["pause"]) {
|
|
||||||
uint8_t p = doc["pause"];
|
|
||||||
set_pause(p, hc_num);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["party"]) {
|
|
||||||
uint8_t p = doc["party"];
|
|
||||||
set_party(p, hc_num);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["holiday"]) {
|
|
||||||
std::string holiday = doc["holiday"];
|
|
||||||
set_holiday(holiday.c_str(), hc_num);
|
|
||||||
}
|
|
||||||
if (nullptr != doc["date"]) {
|
|
||||||
std::string date = doc["date"];
|
|
||||||
set_datetime(date.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for commands like {"hc":2,"cmd":"temp","data":21}
|
|
||||||
const char * command = doc["cmd"];
|
|
||||||
if (command == nullptr || doc["data"] == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// ok, we have command and data
|
|
||||||
if (strcmp(command, "temp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::AUTO, hc_num);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "mode") == 0) {
|
|
||||||
std::string mode = doc["data"];
|
|
||||||
if (mode.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
set_mode(mode, hc_num);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "nighttemp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::NIGHT, hc_num);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "daytemp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::DAY, hc_num);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "holidaytemp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::HOLIDAY, hc_num);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "ecotemp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::ECO, hc_num);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "heattemp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::HEAT, hc_num);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "nofrosttemp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::NOFROST, hc_num);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "summertemp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::SUMMER, hc_num);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "designtemp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::DESIGN, hc_num);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "offsettemp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f) {
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::OFFSET, hc_num);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "remotetemp") == 0) {
|
|
||||||
float f = doc["data"];
|
|
||||||
if (f > 100 || f < 0) {
|
|
||||||
Roomctrl::set_remotetemp(hc_num - 1, EMS_VALUE_SHORT_NOTSET);
|
|
||||||
} else {
|
|
||||||
Roomctrl::set_remotetemp(hc_num - 1, (int16_t)(f * 10));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "control") == 0) {
|
|
||||||
uint8_t ctrl = doc["data"];
|
|
||||||
set_control(ctrl, hc_num);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "pause") == 0) {
|
|
||||||
uint8_t p = doc["data"];
|
|
||||||
set_pause(p, hc_num);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "party") == 0) {
|
|
||||||
uint8_t p = doc["data"];
|
|
||||||
set_party(p, hc_num);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "holiday") == 0) {
|
|
||||||
std::string holiday = doc["data"];
|
|
||||||
set_holiday(holiday.c_str(), hc_num);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (strcmp(command, "date") == 0) {
|
|
||||||
std::string date = doc["data"];
|
|
||||||
set_datetime(date.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thermostat::thermostat_cmd_temp(const char * message) {
|
|
||||||
float f = strtof((char *)message, 0);
|
|
||||||
set_temperature(f, HeatingCircuit::Mode::AUTO, AUTO_HEATING_CIRCUIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// message payload holds the text name of the mode e.g. "auto"
|
|
||||||
void Thermostat::thermostat_cmd_mode(const char * message) {
|
|
||||||
std::string s(message);
|
|
||||||
set_mode(s, AUTO_HEATING_CIRCUIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this function is called post the telegram handler function has been executed
|
// this function is called post the telegram handler function has been executed
|
||||||
// we check if any of the thermostat values have changed and then republish if necessary
|
// we check if any of the thermostat values have changed and then republish if necessary
|
||||||
bool Thermostat::updated_values() {
|
bool Thermostat::updated_values() {
|
||||||
@@ -761,12 +438,14 @@ void Thermostat::publish_values() {
|
|||||||
// returns the heating circuit object based on the hc number
|
// returns the heating circuit object based on the hc number
|
||||||
// of nullptr if it doesn't exist yet
|
// of nullptr if it doesn't exist yet
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(const uint8_t hc_num) {
|
std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(const uint8_t hc_num) {
|
||||||
|
// if hc_num is 0 then return the first existing hc in the list
|
||||||
if (hc_num == 0) {
|
if (hc_num == 0) {
|
||||||
// return first existing hc
|
|
||||||
for (const auto & heating_circuit : heating_circuits_) {
|
for (const auto & heating_circuit : heating_circuits_) {
|
||||||
return heating_circuit;
|
return heating_circuit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// otherwise find a match
|
||||||
for (const auto & heating_circuit : heating_circuits_) {
|
for (const auto & heating_circuit : heating_circuits_) {
|
||||||
if (heating_circuit->hc_num() == hc_num) {
|
if (heating_circuit->hc_num() == hc_num) {
|
||||||
return heating_circuit;
|
return heating_circuit;
|
||||||
@@ -1161,6 +840,8 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
|
|||||||
print_value(shell, 4, F("Target flow temperature"), hc->targetflowtemp, F_(degrees));
|
print_value(shell, 4, F("Target flow temperature"), hc->targetflowtemp, F_(degrees));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shell.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0xA8 - for reading the mode from the RC20 thermostat (0x17)
|
// 0xA8 - for reading the mode from the RC20 thermostat (0x17)
|
||||||
@@ -1360,8 +1041,7 @@ void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> telegram) {
|
|||||||
|
|
||||||
// type 0x3D (HC1), 0x47 (HC2), 0x51 (HC3), 0x5B (HC4) - Working Mode Heating - for reading the mode from the RC35 thermostat (0x10)
|
// type 0x3D (HC1), 0x47 (HC2), 0x51 (HC3), 0x5B (HC4) - Working Mode Heating - for reading the mode from the RC35 thermostat (0x10)
|
||||||
void Thermostat::process_RC35Set(std::shared_ptr<const Telegram> telegram) {
|
void Thermostat::process_RC35Set(std::shared_ptr<const Telegram> telegram) {
|
||||||
// check to see we have a valid type
|
// check to see we have a valid type. heating: 1 radiator, 2 convectors, 3 floors, 4 room supply
|
||||||
// heating: 1 radiator, 2 convectors, 3 floors, 4 room supply
|
|
||||||
if (telegram->message_data[0] == 0x00) {
|
if (telegram->message_data[0] == 0x00) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1389,7 +1069,7 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (telegram->message_data[7] & 0x0C) { // date and time not valid
|
if (telegram->message_data[7] & 0x0C) { // date and time not valid
|
||||||
set_datetime("NTP"); // set from NTP
|
set_datetime("ntp", -1); // set from NTP
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (datetime_.empty()) {
|
if (datetime_.empty()) {
|
||||||
@@ -1415,8 +1095,69 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add 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)},
|
||||||
|
flash_string_vector{F_(deviceid_optional)},
|
||||||
|
[](Shell & shell, const std::vector<std::string> & arguments) {
|
||||||
|
uint8_t value;
|
||||||
|
if (arguments.empty()) {
|
||||||
|
value = EMSESP_DEFAULT_MASTER_THERMOSTAT;
|
||||||
|
} else {
|
||||||
|
value = Helpers::hextoint(arguments.front().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSESP::emsespSettingsService.update(
|
||||||
|
[&](EMSESPSettings & settings) {
|
||||||
|
settings.master_thermostat = value;
|
||||||
|
EMSESP::actual_master_thermostat(value); // set the internal value too
|
||||||
|
char buffer[5];
|
||||||
|
shell.printfln(F_(master_thermostat_fmt),
|
||||||
|
!value ? uuid::read_flash_string(F_(auto)).c_str() : Helpers::hextoa(buffer, value));
|
||||||
|
return StateUpdateResult::CHANGED;
|
||||||
|
},
|
||||||
|
"local");
|
||||||
|
});
|
||||||
|
|
||||||
|
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
||||||
|
CommandFlags::ADMIN,
|
||||||
|
flash_string_vector{F_(read)},
|
||||||
|
flash_string_vector{F_(typeid_mandatory)},
|
||||||
|
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
||||||
|
uint16_t type_id = Helpers::hextoint(arguments.front().c_str());
|
||||||
|
EMSESP::send_read_request(type_id, device_id());
|
||||||
|
});
|
||||||
|
|
||||||
|
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
||||||
|
CommandFlags::USER,
|
||||||
|
flash_string_vector{F_(show)},
|
||||||
|
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { show_values(shell); });
|
||||||
|
|
||||||
|
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
||||||
|
CommandFlags::USER,
|
||||||
|
flash_string_vector{F_(set)},
|
||||||
|
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||||
|
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) {
|
||||||
|
char buffer[4];
|
||||||
|
shell.printfln(F_(master_thermostat_fmt),
|
||||||
|
settings.master_thermostat == 0 ? uuid::read_flash_string(F_(auto)).c_str()
|
||||||
|
: Helpers::hextoa(buffer, settings.master_thermostat));
|
||||||
|
shell.println();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// enter the context
|
||||||
|
Console::enter_custom_context(shell, context);
|
||||||
|
}
|
||||||
|
|
||||||
// 0xA5 - Set minimum external temperature
|
// 0xA5 - Set minimum external temperature
|
||||||
void Thermostat::set_settings_minexttemp(const int8_t mt) {
|
void Thermostat::set_settings_minexttemp(const char * value, const int8_t id) {
|
||||||
|
int8_t mt = 0;
|
||||||
|
if (!Helpers::value2number(value, mt)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) {
|
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) {
|
||||||
LOG_INFO(F("Setting min external temperature to %d"), mt);
|
LOG_INFO(F("Setting min external temperature to %d"), mt);
|
||||||
write_command(EMS_TYPE_IBASettings, 5, mt);
|
write_command(EMS_TYPE_IBASettings, 5, mt);
|
||||||
@@ -1424,14 +1165,25 @@ void Thermostat::set_settings_minexttemp(const int8_t mt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0xA5 - Clock offset
|
// 0xA5 - Clock offset
|
||||||
void Thermostat::set_settings_clockoffset(const int8_t co) {
|
void Thermostat::set_settings_clockoffset(const char * value, const int8_t id) {
|
||||||
|
int8_t co = 0;
|
||||||
|
if (!Helpers::value2number(value, co)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
||||||
LOG_INFO(F("Setting clock offset to %d"), co);
|
LOG_INFO(F("Setting clock offset to %d"), co);
|
||||||
write_command(EMS_TYPE_IBASettings, 12, co);
|
write_command(EMS_TYPE_IBASettings, 12, co);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0xA5 - Calibrate internal temperature
|
// 0xA5 - Calibrate internal temperature
|
||||||
void Thermostat::set_settings_calinttemp(const int8_t ct) {
|
void Thermostat::set_settings_calinttemp(const char * value, const int8_t id) {
|
||||||
|
int8_t ct = 0;
|
||||||
|
if (!Helpers::value2number(value, ct)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Michael - does this value need to be multiple by 10?
|
||||||
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) {
|
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) {
|
||||||
LOG_INFO(F("Calibrating internal temperature to %d.%d"), ct / 10, ct < 0 ? -ct % 10 : ct % 10);
|
LOG_INFO(F("Calibrating internal temperature to %d.%d"), ct / 10, ct < 0 ? -ct % 10 : ct % 10);
|
||||||
write_command(EMS_TYPE_IBASettings, 2, ct);
|
write_command(EMS_TYPE_IBASettings, 2, ct);
|
||||||
@@ -1439,15 +1191,50 @@ void Thermostat::set_settings_calinttemp(const int8_t ct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0xA5 - Set the display settings
|
// 0xA5 - Set the display settings
|
||||||
void Thermostat::set_settings_display(const uint8_t ds) {
|
void Thermostat::set_settings_display(const char * value, const int8_t id) {
|
||||||
|
uint8_t ds = 0;
|
||||||
|
if (!Helpers::value2number(value, ds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
||||||
LOG_INFO(F("Setting display to %d"), ds);
|
LOG_INFO(F("Setting display to %d"), ds);
|
||||||
write_command(EMS_TYPE_IBASettings, 0, ds);
|
write_command(EMS_TYPE_IBASettings, 0, ds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_remotetemp(const char * value, const int8_t id) {
|
||||||
|
float f = 0;
|
||||||
|
if (!Helpers::value2float(value, f)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id;
|
||||||
|
|
||||||
|
if (f > 100 || f < 0) {
|
||||||
|
Roomctrl::set_remotetemp(hc_num - 1, EMS_VALUE_SHORT_NOTSET);
|
||||||
|
} else {
|
||||||
|
Roomctrl::set_remotetemp(hc_num - 1, (int16_t)(f * 10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 0xA5 - Set the building settings
|
// 0xA5 - Set the building settings
|
||||||
void Thermostat::set_settings_building(const uint8_t bg) {
|
void Thermostat::set_settings_building(const char * value, const int8_t id) {
|
||||||
|
std::string bd;
|
||||||
|
if (!Helpers::value2string(value, bd)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bg = 0;
|
||||||
|
if (bd == "light") {
|
||||||
|
bg = 0;
|
||||||
|
} else if (bd == "medium") {
|
||||||
|
bg = 1;
|
||||||
|
} else if (bd == "heavy") {
|
||||||
|
bg = 2;
|
||||||
|
} else {
|
||||||
|
return; // invalid
|
||||||
|
}
|
||||||
|
|
||||||
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) {
|
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) {
|
||||||
LOG_INFO(F("Setting building to %d"), bg);
|
LOG_INFO(F("Setting building to %d"), bg);
|
||||||
write_command(EMS_TYPE_IBASettings, 6, bg);
|
write_command(EMS_TYPE_IBASettings, 6, bg);
|
||||||
@@ -1455,7 +1242,11 @@ void Thermostat::set_settings_building(const uint8_t bg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0xA5 Set the language settings
|
// 0xA5 Set the language settings
|
||||||
void Thermostat::set_settings_language(const uint8_t lg) {
|
void Thermostat::set_settings_language(const char * value, const int8_t id) {
|
||||||
|
uint8_t lg = 0;
|
||||||
|
if (!Helpers::value2number(value, lg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
||||||
LOG_INFO(F("Setting language to %d"), lg);
|
LOG_INFO(F("Setting language to %d"), lg);
|
||||||
write_command(EMS_TYPE_IBASettings, 1, lg);
|
write_command(EMS_TYPE_IBASettings, 1, lg);
|
||||||
@@ -1463,16 +1254,25 @@ void Thermostat::set_settings_language(const uint8_t lg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the control-mode for hc 0-off, 1-RC20, 2-RC3x
|
// Set the control-mode for hc 0-off, 1-RC20, 2-RC3x
|
||||||
void Thermostat::set_control(const uint8_t ctrl, const uint8_t hc_num) {
|
void Thermostat::set_control(const char * value, const int8_t id) {
|
||||||
|
uint8_t ctrl = 0;
|
||||||
|
if (!Helpers::value2number(value, ctrl)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id;
|
||||||
|
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
LOG_WARNING(F("Set control: Heating Circuit %d not found or activated"), hc_num);
|
LOG_WARNING(F("Set control: Heating Circuit %d not found or activated"), hc_num);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctrl > 2) {
|
if (ctrl > 2) {
|
||||||
LOG_WARNING(F("Set control: Invalid control mode: %d"), ctrl);
|
LOG_WARNING(F("Set control: Invalid control mode: %d"), ctrl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
||||||
LOG_INFO(F("Setting circuit-control for hc%d to %d"), hc_num, ctrl);
|
LOG_INFO(F("Setting circuit-control for hc%d to %d"), hc_num, ctrl);
|
||||||
write_command(set_typeids[hc->hc_num() - 1], 26, ctrl);
|
write_command(set_typeids[hc->hc_num() - 1], 26, ctrl);
|
||||||
@@ -1482,23 +1282,37 @@ void Thermostat::set_control(const uint8_t ctrl, const uint8_t hc_num) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sets the thermostat ww working mode, where mode is a string
|
// sets the thermostat ww working mode, where mode is a string
|
||||||
void Thermostat::set_ww_mode(const std::string & mode) {
|
void Thermostat::set_wwmode(const char * value, const int8_t id) {
|
||||||
if (strcasecmp("off", mode.c_str()) == 0) {
|
std::string v;
|
||||||
LOG_INFO(F("Setting thermostat warm water mode to %s"), mode.c_str());
|
if (!Helpers::value2string(value, v)) {
|
||||||
write_command(EMS_TYPE_wwSettings, 2, 0);
|
return;
|
||||||
} else if (strcasecmp("on", mode.c_str()) == 0) {
|
}
|
||||||
LOG_INFO(F("Setting thermostat warm water mode to %s"), mode.c_str());
|
|
||||||
write_command(EMS_TYPE_wwSettings, 2, 1);
|
uint8_t set = 0xFF; // some dummy value
|
||||||
} else if (strcasecmp("auto", mode.c_str()) == 0) {
|
if (v == "off") {
|
||||||
LOG_INFO(F("Setting thermostat warm water mode to %s"), mode.c_str());
|
set = 0;
|
||||||
write_command(EMS_TYPE_wwSettings, 2, 2);
|
} else if (v == "on") {
|
||||||
|
set = 1;
|
||||||
|
} else if (v == "auto") {
|
||||||
|
set = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set != 0xFF) {
|
||||||
|
LOG_INFO(F("Setting thermostat warm water mode to %s"), v.c_str());
|
||||||
|
write_command(EMS_TYPE_wwSettings, 2, set);
|
||||||
} else {
|
} else {
|
||||||
LOG_WARNING(F("Set thermostat warm water mode: Invalid mode: %s"), mode.c_str());
|
LOG_WARNING(F("Set thermostat warm water mode: Invalid mode: %s"), v.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the holiday as string dd.mm.yyyy-dd.mm.yyyy
|
// set the holiday as string dd.mm.yyyy-dd.mm.yyyy
|
||||||
void Thermostat::set_holiday(const char * hd, const uint8_t hc_num) {
|
void Thermostat::set_holiday(const char * value, const int8_t id) {
|
||||||
|
std::string hd;
|
||||||
|
if (!Helpers::value2string(value, hd)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id;
|
||||||
|
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
LOG_WARNING(F("Set holiday: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id());
|
LOG_WARNING(F("Set holiday: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id());
|
||||||
@@ -1520,7 +1334,13 @@ void Thermostat::set_holiday(const char * hd, const uint8_t hc_num) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set pause in hours
|
// set pause in hours
|
||||||
void Thermostat::set_pause(const uint8_t hrs, const uint8_t hc_num) {
|
void Thermostat::set_pause(const char * value, const int8_t id) {
|
||||||
|
uint8_t hrs = 0;
|
||||||
|
if (!Helpers::value2number(value, hrs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id;
|
||||||
|
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
LOG_WARNING(F("Set pause: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id());
|
LOG_WARNING(F("Set pause: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id());
|
||||||
@@ -1535,7 +1355,13 @@ void Thermostat::set_pause(const uint8_t hrs, const uint8_t hc_num) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set partymode in hours
|
// set partymode in hours
|
||||||
void Thermostat::set_party(const uint8_t hrs, const uint8_t hc_num) {
|
void Thermostat::set_party(const char * value, const int8_t id) {
|
||||||
|
uint8_t hrs = 0;
|
||||||
|
if (!Helpers::value2number(value, hrs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id;
|
||||||
|
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
LOG_WARNING(F("Set party: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id());
|
LOG_WARNING(F("Set party: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id());
|
||||||
@@ -1551,11 +1377,17 @@ void Thermostat::set_party(const uint8_t hrs, const uint8_t hc_num) {
|
|||||||
|
|
||||||
// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst or "NTP" for setting to internet-time
|
// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst or "NTP" for setting to internet-time
|
||||||
// dw - day of week (0..6), dst- summertime (0/1)
|
// dw - day of week (0..6), dst- summertime (0/1)
|
||||||
void Thermostat::set_datetime(const char * dt) {
|
// id is ignored
|
||||||
|
void Thermostat::set_datetime(const char * value, const int8_t id) {
|
||||||
|
std::string dt;
|
||||||
|
if (!Helpers::value2string(value, dt)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t data[9];
|
uint8_t data[9];
|
||||||
if (strcmp(dt,"NTP") == 0) {
|
if (dt == "ntp") {
|
||||||
time_t now = time(nullptr);
|
time_t now = time(nullptr);
|
||||||
tm * tm_ = localtime(&now);
|
tm * tm_ = localtime(&now);
|
||||||
if (tm_->tm_year < 110) { // no NTP time
|
if (tm_->tm_year < 110) { // no NTP time
|
||||||
LOG_WARNING(F("No NTP time. Cannot set RCtime"));
|
LOG_WARNING(F("No NTP time. Cannot set RCtime"));
|
||||||
return;
|
return;
|
||||||
@@ -1590,34 +1422,43 @@ void Thermostat::set_datetime(const char * dt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sets the thermostat working mode, where mode is a string
|
// sets the thermostat working mode, where mode is a string
|
||||||
void Thermostat::set_mode(const std::string & mode, const uint8_t hc_num) {
|
// converts string mode to HeatingCircuit::Mode
|
||||||
|
void Thermostat::set_mode(const char * value, const int8_t id) {
|
||||||
|
std::string mode;
|
||||||
|
if (!Helpers::value2string(value, mode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id;
|
||||||
|
|
||||||
if (mode_tostring(HeatingCircuit::Mode::OFF) == mode) {
|
if (mode_tostring(HeatingCircuit::Mode::OFF) == mode) {
|
||||||
set_mode(HeatingCircuit::Mode::OFF, hc_num);
|
set_mode_n(HeatingCircuit::Mode::OFF, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::MANUAL) == mode) {
|
} else if (mode_tostring(HeatingCircuit::Mode::MANUAL) == mode) {
|
||||||
set_mode(HeatingCircuit::Mode::MANUAL, hc_num);
|
set_mode_n(HeatingCircuit::Mode::MANUAL, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::AUTO) == mode) {
|
} else if (mode_tostring(HeatingCircuit::Mode::AUTO) == mode) {
|
||||||
set_mode(HeatingCircuit::Mode::AUTO, hc_num);
|
set_mode_n(HeatingCircuit::Mode::AUTO, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::DAY) == mode) {
|
} else if (mode_tostring(HeatingCircuit::Mode::DAY) == mode) {
|
||||||
set_mode(HeatingCircuit::Mode::DAY, hc_num);
|
set_mode_n(HeatingCircuit::Mode::DAY, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::NIGHT) == mode) {
|
} else if (mode_tostring(HeatingCircuit::Mode::NIGHT) == mode) {
|
||||||
set_mode(HeatingCircuit::Mode::NIGHT, hc_num);
|
set_mode_n(HeatingCircuit::Mode::NIGHT, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::HEAT) == mode) {
|
} else if (mode_tostring(HeatingCircuit::Mode::HEAT) == mode) {
|
||||||
set_mode(HeatingCircuit::Mode::HEAT, hc_num);
|
set_mode_n(HeatingCircuit::Mode::HEAT, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::NOFROST) == mode) {
|
} else if (mode_tostring(HeatingCircuit::Mode::NOFROST) == mode) {
|
||||||
set_mode(HeatingCircuit::Mode::NOFROST, hc_num);
|
set_mode_n(HeatingCircuit::Mode::NOFROST, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::ECO) == mode) {
|
} else if (mode_tostring(HeatingCircuit::Mode::ECO) == mode) {
|
||||||
set_mode(HeatingCircuit::Mode::ECO, hc_num);
|
set_mode_n(HeatingCircuit::Mode::ECO, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) {
|
} else if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) {
|
||||||
set_mode(HeatingCircuit::Mode::HOLIDAY, hc_num);
|
set_mode_n(HeatingCircuit::Mode::HOLIDAY, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::COMFORT) == mode) {
|
} else if (mode_tostring(HeatingCircuit::Mode::COMFORT) == mode) {
|
||||||
set_mode(HeatingCircuit::Mode::COMFORT, hc_num);
|
set_mode_n(HeatingCircuit::Mode::COMFORT, hc_num);
|
||||||
} else {
|
} else {
|
||||||
LOG_WARNING(F("Invalid mode %s. Cannot set"), mode.c_str());
|
LOG_WARNING(F("Invalid mode %s. Cannot set"), mode.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the thermostat working mode
|
// Set the thermostat working mode
|
||||||
void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) {
|
// mode is HeatingCircuit::Mode
|
||||||
|
void Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) {
|
||||||
if (can_write()) {
|
if (can_write()) {
|
||||||
LOG_WARNING(F("Write not supported for this model Thermostat"));
|
LOG_WARNING(F("Write not supported for this model Thermostat"));
|
||||||
return;
|
return;
|
||||||
@@ -1893,109 +1734,93 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add console commands
|
// for HA specifically when receiving over MQTT
|
||||||
void Thermostat::console_commands(Shell & shell, unsigned int context) {
|
void Thermostat::thermostat_cmd_temp(const char * message) {
|
||||||
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
float f = strtof((char *)message, 0);
|
||||||
CommandFlags::ADMIN,
|
set_temperature(f, HeatingCircuit::Mode::AUTO, AUTO_HEATING_CIRCUIT);
|
||||||
flash_string_vector{F_(set), F_(master)},
|
|
||||||
flash_string_vector{F_(deviceid_optional)},
|
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments) {
|
|
||||||
uint8_t value;
|
|
||||||
if (arguments.empty()) {
|
|
||||||
value = EMSESP_DEFAULT_MASTER_THERMOSTAT;
|
|
||||||
} else {
|
|
||||||
value = Helpers::hextoint(arguments.front().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSESP::emsespSettingsService.update(
|
|
||||||
[&](EMSESPSettings & settings) {
|
|
||||||
settings.master_thermostat = value;
|
|
||||||
EMSESP::actual_master_thermostat(value); // set the internal value too
|
|
||||||
char buffer[5];
|
|
||||||
shell.printfln(F_(master_thermostat_fmt),
|
|
||||||
!value ? uuid::read_flash_string(F_(auto)).c_str() : Helpers::hextoa(buffer, value));
|
|
||||||
return StateUpdateResult::CHANGED;
|
|
||||||
},
|
|
||||||
"local");
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(read)},
|
|
||||||
flash_string_vector{F_(typeid_mandatory)},
|
|
||||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
|
||||||
uint16_t type_id = Helpers::hextoint(arguments.front().c_str());
|
|
||||||
EMSESP::send_read_request(type_id, device_id());
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(temp)},
|
|
||||||
flash_string_vector{F_(degrees_mandatory), F_(hc_optional), F_(mode_optional)},
|
|
||||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
|
||||||
uint8_t hc = (arguments.size() >= 2) ? arguments[1].at(0) - '0' : AUTO_HEATING_CIRCUIT;
|
|
||||||
if ((arguments.size() == 3)) {
|
|
||||||
set_temperature(atof(arguments.front().c_str()), arguments.back().c_str(), hc);
|
|
||||||
} else if (arguments[1].at(0) >= 'A') {
|
|
||||||
set_temperature(atof(arguments.front().c_str()), arguments.back().c_str(), AUTO_HEATING_CIRCUIT);
|
|
||||||
} else {
|
|
||||||
set_temperature(atof(arguments.front().c_str()), HeatingCircuit::Mode::AUTO, hc);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(
|
|
||||||
ShellContext::THERMOSTAT,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(mode)},
|
|
||||||
flash_string_vector{F_(mode_mandatory), F_(hc_optional)},
|
|
||||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
|
||||||
uint8_t hc = (arguments.size() == 2) ? arguments[1].at(0) - '0' : AUTO_HEATING_CIRCUIT;
|
|
||||||
set_mode(arguments.front(), hc);
|
|
||||||
},
|
|
||||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
|
||||||
return std::vector<std::string>{read_flash_string(F("off")),
|
|
||||||
read_flash_string(F("manual")),
|
|
||||||
read_flash_string(F("day")),
|
|
||||||
read_flash_string(F("night")),
|
|
||||||
read_flash_string(F("eco")),
|
|
||||||
read_flash_string(F("comfort")),
|
|
||||||
read_flash_string(F("heat")),
|
|
||||||
read_flash_string(F("nofrost")),
|
|
||||||
read_flash_string(F("auto"))
|
|
||||||
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(
|
|
||||||
ShellContext::THERMOSTAT,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(wwmode)},
|
|
||||||
flash_string_vector{F_(mode_mandatory)},
|
|
||||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) { set_ww_mode(arguments.front()); },
|
|
||||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
|
||||||
return std::vector<std::string>{read_flash_string(F("off")), read_flash_string(F("on")), read_flash_string(F("auto"))};
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
|
||||||
CommandFlags::USER,
|
|
||||||
flash_string_vector{F_(show)},
|
|
||||||
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { show_values(shell); });
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
|
||||||
CommandFlags::USER,
|
|
||||||
flash_string_vector{F_(set)},
|
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
|
||||||
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) {
|
|
||||||
char buffer[4];
|
|
||||||
shell.printfln(F_(master_thermostat_fmt),
|
|
||||||
settings.master_thermostat == 0 ? uuid::read_flash_string(F_(auto)).c_str()
|
|
||||||
: Helpers::hextoa(buffer, settings.master_thermostat));
|
|
||||||
shell.println();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// enter the context
|
|
||||||
Console::enter_custom_context(shell, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for HA specifically when receiving over MQTT
|
||||||
|
// message payload holds the text name of the mode e.g. "auto"
|
||||||
|
void Thermostat::thermostat_cmd_mode(const char * message) {
|
||||||
|
set_mode(message, AUTO_HEATING_CIRCUIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_temperature_value(const char * value, const uint8_t id, const uint8_t mode) {
|
||||||
|
float f = 0;
|
||||||
|
uint8_t hc_num = (id == -1) ? DEFAULT_HEATING_CIRCUIT : id;
|
||||||
|
if (Helpers::value2float(value, f)) {
|
||||||
|
set_temperature(f, mode, hc_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_temp(const char * value, const int8_t id) {
|
||||||
|
set_temperature_value(value, id, HeatingCircuit::Mode::AUTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_nighttemp(const char * value, const int8_t id) {
|
||||||
|
set_temperature_value(value, id, HeatingCircuit::Mode::NIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_daytemp(const char * value, const int8_t id) {
|
||||||
|
set_temperature_value(value, id, HeatingCircuit::Mode::DAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_nofrosttemp(const char * value, const int8_t id) {
|
||||||
|
set_temperature_value(value, id, HeatingCircuit::Mode::NOFROST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_ecotemp(const char * value, const int8_t id) {
|
||||||
|
set_temperature_value(value, id, HeatingCircuit::Mode::ECO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_heattemp(const char * value, const int8_t id) {
|
||||||
|
set_temperature_value(value, id, HeatingCircuit::Mode::HEAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_summertemp(const char * value, const int8_t id) {
|
||||||
|
set_temperature_value(value, id, HeatingCircuit::Mode::SUMMER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_designtemp(const char * value, const int8_t id) {
|
||||||
|
set_temperature_value(value, id, HeatingCircuit::Mode::DESIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_offsettemp(const char * value, const int8_t id) {
|
||||||
|
set_temperature_value(value, id, HeatingCircuit::Mode::OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thermostat::set_holidaytemp(const char * value, const int8_t id) {
|
||||||
|
set_temperature_value(value, id, HeatingCircuit::Mode::HOLIDAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// commands for MQTT and Console
|
||||||
|
void Thermostat::init_mqtt() {
|
||||||
|
register_mqtt_cmd(F("wwmode"), std::bind(&Thermostat::set_wwmode, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("control"), std::bind(&Thermostat::set_control, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("mode"), std::bind(&Thermostat::set_mode, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("holiday"), std::bind(&Thermostat::set_holiday, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("pause"), std::bind(&Thermostat::set_pause, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("party"), std::bind(&Thermostat::set_party, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("datetime"), std::bind(&Thermostat::set_datetime, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("minexttemp"), std::bind(&Thermostat::set_settings_minexttemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("clockoffset"), std::bind(&Thermostat::set_settings_clockoffset, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("calinttemp"), std::bind(&Thermostat::set_settings_calinttemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("display"), std::bind(&Thermostat::set_settings_display, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("building"), std::bind(&Thermostat::set_settings_building, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("language"), std::bind(&Thermostat::set_settings_language, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("remotetemp"), std::bind(&Thermostat::set_remotetemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("temp"), std::bind(&Thermostat::set_temp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("nighttemp"), std::bind(&Thermostat::set_nighttemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("daytemp"), std::bind(&Thermostat::set_daytemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("nofrosttemp"), std::bind(&Thermostat::set_nofrosttemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("ecotemp"), std::bind(&Thermostat::set_ecotemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("heattemp"), std::bind(&Thermostat::set_heattemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("summertemp"), std::bind(&Thermostat::set_summertemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("designtemp"), std::bind(&Thermostat::set_designtemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("offsettemp"), std::bind(&Thermostat::set_offsettemp, this, _1, _2));
|
||||||
|
register_mqtt_cmd(F("holidaytemp"), std::bind(&Thermostat::set_holidaytemp, this, _1, _2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
@@ -220,55 +220,61 @@ class Thermostat : public EMSdevice {
|
|||||||
void process_IBASettings(std::shared_ptr<const Telegram> telegram);
|
void process_IBASettings(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_RCTime(std::shared_ptr<const Telegram> telegram);
|
void process_RCTime(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_RC35wwSettings(std::shared_ptr<const Telegram> telegram);
|
void process_RC35wwSettings(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
void process_RC35Monitor(std::shared_ptr<const Telegram> telegram);
|
void process_RC35Monitor(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_RC35Set(std::shared_ptr<const Telegram> telegram);
|
void process_RC35Set(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
void process_RC30Monitor(std::shared_ptr<const Telegram> telegram);
|
void process_RC30Monitor(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_RC30Set(std::shared_ptr<const Telegram> telegram);
|
void process_RC30Set(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
void process_RC20Monitor(std::shared_ptr<const Telegram> telegram);
|
void process_RC20Monitor(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_RC20Set(std::shared_ptr<const Telegram> telegram);
|
void process_RC20Set(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_RC20Remote(std::shared_ptr<const Telegram> telegram);
|
void process_RC20Remote(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
void process_RC20Monitor_2(std::shared_ptr<const Telegram> telegram);
|
void process_RC20Monitor_2(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_RC20Set_2(std::shared_ptr<const Telegram> telegram);
|
void process_RC20Set_2(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
void process_RC10Monitor(std::shared_ptr<const Telegram> telegram);
|
void process_RC10Monitor(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_RC10Set(std::shared_ptr<const Telegram> telegram);
|
void process_RC10Set(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
void process_RC300Monitor(std::shared_ptr<const Telegram> telegram);
|
void process_RC300Monitor(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_RC300Set(std::shared_ptr<const Telegram> telegram);
|
void process_RC300Set(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
void process_JunkersMonitor(std::shared_ptr<const Telegram> telegram);
|
void process_JunkersMonitor(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_JunkersSet(std::shared_ptr<const Telegram> telegram);
|
void process_JunkersSet(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
void process_EasyMonitor(std::shared_ptr<const Telegram> telegram);
|
void process_EasyMonitor(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
void process_RC300WWmode(std::shared_ptr<const Telegram> telegram);
|
void process_RC300WWmode(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
// set functions
|
// internal helper functions
|
||||||
void set_settings_minexttemp(const int8_t mt);
|
void set_mode_n(const uint8_t mode, const uint8_t hc_num);
|
||||||
void set_settings_calinttemp(const int8_t ct);
|
void set_temperature_value(const char * value, const uint8_t hc, const uint8_t mode);
|
||||||
void set_settings_clockoffset(const int8_t co);
|
|
||||||
void set_settings_display(const uint8_t ds);
|
|
||||||
void set_settings_building(const uint8_t bg);
|
|
||||||
void set_settings_language(const uint8_t lg);
|
|
||||||
void set_control(const uint8_t ctrl, const uint8_t hc_num);
|
|
||||||
void set_ww_mode(const std::string & mode);
|
|
||||||
void set_holiday(const char * hd, const uint8_t hc_num);
|
|
||||||
void set_datetime(const char * dt);
|
|
||||||
void set_pause(const uint8_t hrs, const uint8_t hc_num);
|
|
||||||
void set_party(const uint8_t hrs, const uint8_t hc_num);
|
|
||||||
void set_mode(const uint8_t mode, const uint8_t hc_num);
|
|
||||||
void set_mode(const std::string & mode, const uint8_t hc_num);
|
|
||||||
void set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num);
|
void set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num);
|
||||||
void set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num);
|
void set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num);
|
||||||
|
|
||||||
// MQTT functions
|
// for HA specifically. MQTT functions.
|
||||||
void thermostat_cmd(const char * message);
|
|
||||||
void thermostat_cmd_temp(const char * message);
|
void thermostat_cmd_temp(const char * message);
|
||||||
void thermostat_cmd_mode(const char * message);
|
void thermostat_cmd_mode(const char * message);
|
||||||
|
|
||||||
|
// set functions - these use the id/hc
|
||||||
|
void set_mode(const char * value, const int8_t id);
|
||||||
|
void set_control(const char * value, const int8_t id);
|
||||||
|
void set_holiday(const char * value, const int8_t id);
|
||||||
|
void set_pause(const char * value, const int8_t id);
|
||||||
|
void set_party(const char * value, const int8_t id);
|
||||||
|
void set_temp(const char * value, const int8_t id);
|
||||||
|
void set_nighttemp(const char * value, const int8_t id);
|
||||||
|
void set_daytemp(const char * value, const int8_t id);
|
||||||
|
void set_nofrosttemp(const char * value, const int8_t id);
|
||||||
|
void set_ecotemp(const char * value, const int8_t id);
|
||||||
|
void set_heattemp(const char * value, const int8_t id);
|
||||||
|
void set_summertemp(const char * value, const int8_t id);
|
||||||
|
void set_designtemp(const char * value, const int8_t id);
|
||||||
|
void set_offsettemp(const char * value, const int8_t id);
|
||||||
|
void set_holidaytemp(const char * value, const int8_t id);
|
||||||
|
void set_remotetemp(const char * value, const int8_t id);
|
||||||
|
|
||||||
|
// set functions - these don't use the id/hc
|
||||||
|
void set_wwmode(const char * value, const int8_t id);
|
||||||
|
void set_datetime(const char * value, const int8_t id);
|
||||||
|
void set_settings_minexttemp(const char * value, const int8_t id);
|
||||||
|
void set_settings_clockoffset(const char * value, const int8_t id);
|
||||||
|
void set_settings_calinttemp(const char * value, const int8_t id);
|
||||||
|
void set_settings_display(const char * value, const int8_t id);
|
||||||
|
void set_settings_building(const char * value, const int8_t id);
|
||||||
|
void set_settings_language(const char * value, const int8_t id);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -20,11 +20,9 @@
|
|||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
#include "mqtt.h" // for the mqtt_function_p
|
#include "mqtt.h" // for the mqtt_function_p
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "emsdevice")
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
uuid::log::Logger EMSdevice::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
uuid::log::Logger EMSdevice::logger_{F_(emsesp), uuid::log::Facility::CONSOLE};
|
||||||
|
|
||||||
std::string EMSdevice::brand_to_string() const {
|
std::string EMSdevice::brand_to_string() const {
|
||||||
switch (brand_) {
|
switch (brand_) {
|
||||||
@@ -55,6 +53,35 @@ std::string EMSdevice::brand_to_string() const {
|
|||||||
return std::string{};
|
return std::string{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns the name of the MQTT topic to use for a specific device
|
||||||
|
std::string EMSdevice::device_type_topic_name(const uint8_t device_type) {
|
||||||
|
switch (device_type) {
|
||||||
|
case DeviceType::BOILER:
|
||||||
|
return read_flash_string(F("boiler"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceType::THERMOSTAT:
|
||||||
|
return read_flash_string(F("thermostat"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceType::HEATPUMP:
|
||||||
|
return read_flash_string(F("heatpump"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceType::SOLAR:
|
||||||
|
return read_flash_string(F("solar"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceType::MIXING:
|
||||||
|
return read_flash_string(F("mixing"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return std::string{};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string EMSdevice::device_type_name() const {
|
std::string EMSdevice::device_type_name() const {
|
||||||
switch (device_type_) {
|
switch (device_type_) {
|
||||||
case DeviceType::BOILER:
|
case DeviceType::BOILER:
|
||||||
@@ -206,12 +233,17 @@ void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) {
|
|||||||
|
|
||||||
// list all the mqtt handlers for this device
|
// list all the mqtt handlers for this device
|
||||||
void EMSdevice::show_mqtt_handlers(uuid::console::Shell & shell) {
|
void EMSdevice::show_mqtt_handlers(uuid::console::Shell & shell) {
|
||||||
Mqtt::show_topic_handlers(shell, this->device_id_);
|
Mqtt::show_topic_handlers(shell, this->device_type_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EMSdevice::register_mqtt_topic(const std::string & topic, mqtt_subfunction_p f) {
|
void EMSdevice::register_mqtt_topic(const std::string & topic, mqtt_subfunction_p f) {
|
||||||
LOG_DEBUG(F("Registering MQTT topic %s for device ID %02X"), topic.c_str(), this->device_id_);
|
LOG_DEBUG(F("Registering MQTT topic %s for device ID %02X and type %s"), topic.c_str(), this->device_id_, this->device_type_name().c_str());
|
||||||
Mqtt::subscribe(this->device_id_, topic, f);
|
Mqtt::subscribe(this->device_type_, topic, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EMSdevice::register_mqtt_cmd(const __FlashStringHelper * cmd, mqtt_cmdfunction_p f) {
|
||||||
|
LOG_DEBUG(F("Registering MQTT cmd %s for device type %s"), uuid::read_flash_string(cmd).c_str(), this->device_type_name().c_str());
|
||||||
|
Mqtt::add_command(this->device_type_, cmd, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSdevice::TelegramFunction::TelegramFunction(uint16_t telegram_type_id,
|
EMSdevice::TelegramFunction::TelegramFunction(uint16_t telegram_type_id,
|
||||||
@@ -239,7 +271,7 @@ std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram> telegr
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const auto & tf : telegram_functions_) {
|
for (const auto & tf : telegram_functions_) {
|
||||||
if ((tf.telegram_type_id_ == telegram->type_id) && ((telegram->type_id & 0x0F0) != 0xF0)) {
|
if ((tf.telegram_type_id_ == telegram->type_id) && ((telegram->type_id & 0xF0) != 0xF0)) {
|
||||||
return uuid::read_flash_string(tf.telegram_type_name_);
|
return uuid::read_flash_string(tf.telegram_type_name_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -295,6 +327,7 @@ void EMSdevice::print_value(uuid::console::Shell & shell, uint8_t padding, const
|
|||||||
print_value(shell, padding, name, uuid::read_flash_string(value).c_str());
|
print_value(shell, padding, name, uuid::read_flash_string(value).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// print string value, value is not in flash
|
||||||
void EMSdevice::print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const char * value) {
|
void EMSdevice::print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const char * value) {
|
||||||
uint8_t i = padding;
|
uint8_t i = padding;
|
||||||
while (i-- > 0) {
|
while (i-- > 0) {
|
||||||
@@ -304,4 +337,52 @@ void EMSdevice::print_value(uuid::console::Shell & shell, uint8_t padding, const
|
|||||||
shell.printfln(PSTR("%s: %s"), uuid::read_flash_string(name).c_str(), value);
|
shell.printfln(PSTR("%s: %s"), uuid::read_flash_string(name).c_str(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// given a context, automatically add the commands taken them from the MQTT registry for "<device_type>_cmd" topics
|
||||||
|
void EMSdevice::add_context_commands(unsigned int context) {
|
||||||
|
EMSESPShell::commands->add_command(
|
||||||
|
context,
|
||||||
|
CommandFlags::ADMIN,
|
||||||
|
flash_string_vector{F_(call)},
|
||||||
|
flash_string_vector{F_(cmd_optional), F_(data_optional), F_(id_optional)},
|
||||||
|
[&](Shell & shell, const std::vector<std::string> & arguments) {
|
||||||
|
uint8_t device_type_ = device_type();
|
||||||
|
if (arguments.empty()) {
|
||||||
|
// list options
|
||||||
|
shell.print("Available commands:");
|
||||||
|
for (const auto & cf : Mqtt::commands()) {
|
||||||
|
if (cf.device_type_ == device_type_) {
|
||||||
|
shell.printf(" %s", uuid::read_flash_string(cf.cmd_).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shell.println();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * cmd = arguments[0].c_str();
|
||||||
|
if (arguments.size() == 1) {
|
||||||
|
// no value specified
|
||||||
|
Mqtt::call_command(device_type_, cmd, nullptr, -1);
|
||||||
|
} else if (arguments.size() == 2) {
|
||||||
|
// has a value but no id
|
||||||
|
Mqtt::call_command(device_type_, cmd, arguments.back().c_str(), -1);
|
||||||
|
} else {
|
||||||
|
// use value, which could be an id or hc
|
||||||
|
Mqtt::call_command(device_type_, cmd, arguments[1].c_str(), atoi(arguments[2].c_str()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) -> std::vector<std::string> {
|
||||||
|
if (arguments.size() > 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::vector<std::string> commands;
|
||||||
|
for (const auto & cf : Mqtt::commands()) {
|
||||||
|
if (cf.device_type_ == device_type()) {
|
||||||
|
commands.emplace_back(uuid::read_flash_string(cf.cmd_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return commands;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -47,11 +47,22 @@ class EMSdevice {
|
|||||||
|
|
||||||
virtual ~EMSdevice() = default; // destructor of base class must always be virtual because it's a polymorphic class
|
virtual ~EMSdevice() = default; // destructor of base class must always be virtual because it's a polymorphic class
|
||||||
|
|
||||||
|
/*
|
||||||
|
// https://github.com/proddy/EMS-ESP/issues/434#issuecomment-667840531
|
||||||
|
inline uint8_t device_id(uint8_t hc = 0) const {
|
||||||
|
if (((device_id_ & 0x7F) >= 0x18) && ((device_id_ & 0x7F) <= 0x1B)) {
|
||||||
|
return ((device_id_ & 0x80) + 0x18 + hc);
|
||||||
|
}
|
||||||
|
return device_id_;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
inline uint8_t device_id() const {
|
inline uint8_t device_id() const {
|
||||||
return device_id_;
|
return device_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string device_type_name() const;
|
std::string device_type_name() const;
|
||||||
|
static std::string device_type_topic_name(const uint8_t device_type);
|
||||||
|
|
||||||
inline uint8_t product_id() const {
|
inline uint8_t product_id() const {
|
||||||
return product_id_;
|
return product_id_;
|
||||||
@@ -129,7 +140,10 @@ class EMSdevice {
|
|||||||
|
|
||||||
void read_command(const uint16_t type_id);
|
void read_command(const uint16_t type_id);
|
||||||
|
|
||||||
|
void add_context_commands(unsigned int context);
|
||||||
|
|
||||||
void register_mqtt_topic(const std::string & topic, mqtt_subfunction_p f);
|
void register_mqtt_topic(const std::string & topic, mqtt_subfunction_p f);
|
||||||
|
void register_mqtt_cmd(const __FlashStringHelper * cmd, mqtt_cmdfunction_p f);
|
||||||
|
|
||||||
// virtual functions overrules by derived classes
|
// virtual functions overrules by derived classes
|
||||||
virtual void show_values(uuid::console::Shell & shell) = 0;
|
virtual void show_values(uuid::console::Shell & shell) = 0;
|
||||||
@@ -222,7 +236,7 @@ class EMSdevice {
|
|||||||
|
|
||||||
enum DeviceType : uint8_t {
|
enum DeviceType : uint8_t {
|
||||||
UNKNOWN = 0,
|
UNKNOWN = 0,
|
||||||
SERVICEKEY,
|
SERVICEKEY, // us
|
||||||
BOILER,
|
BOILER,
|
||||||
THERMOSTAT,
|
THERMOSTAT,
|
||||||
MIXING,
|
MIXING,
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "emsesp")
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
using DeviceFlags = emsesp::EMSdevice;
|
using DeviceFlags = emsesp::EMSdevice;
|
||||||
@@ -45,7 +43,7 @@ EMSESPDevicesService EMSESP::emsespDevicesService = EMSESPDevicesService(&webSer
|
|||||||
std::vector<std::unique_ptr<EMSdevice>> EMSESP::emsdevices; // array of all the detected EMS devices
|
std::vector<std::unique_ptr<EMSdevice>> EMSESP::emsdevices; // array of all the detected EMS devices
|
||||||
std::vector<emsesp::EMSESP::Device_record> EMSESP::device_library_; // libary of all our known EMS devices so far
|
std::vector<emsesp::EMSESP::Device_record> EMSESP::device_library_; // libary of all our known EMS devices so far
|
||||||
|
|
||||||
uuid::log::Logger EMSESP::logger_{FPSTR(__pstr__logger_name), uuid::log::Facility::KERN};
|
uuid::log::Logger EMSESP::logger_{F_(emsesp), uuid::log::Facility::KERN};
|
||||||
|
|
||||||
// The services
|
// The services
|
||||||
RxService EMSESP::rxservice_; // incoming Telegram Rx handler
|
RxService EMSESP::rxservice_; // incoming Telegram Rx handler
|
||||||
@@ -242,7 +240,6 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) {
|
|||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
|
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
|
||||||
emsdevice->show_values(shell);
|
emsdevice->show_values(shell);
|
||||||
shell.println();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -758,17 +755,14 @@ void EMSESP::start() {
|
|||||||
|
|
||||||
esp8266React.begin(); // loads system settings (wifi, mqtt, etc)
|
esp8266React.begin(); // loads system settings (wifi, mqtt, etc)
|
||||||
emsespSettingsService.begin(); // load EMS-ESP specific settings
|
emsespSettingsService.begin(); // load EMS-ESP specific settings
|
||||||
|
|
||||||
// system_.check_upgrade(); // see if we need to migrate from previous versions
|
// system_.check_upgrade(); // see if we need to migrate from previous versions
|
||||||
|
mqtt_.start(); // mqtt init
|
||||||
console_.start(); // telnet and serial console
|
console_.start(); // telnet and serial console
|
||||||
system_.start(); // starts syslog, uart, sets version, initializes LED. Requires pre-loaded settings.
|
system_.start(); // starts syslog, uart, sets version, initializes LED. Requires pre-loaded settings.
|
||||||
mqtt_.start(); // mqtt init
|
|
||||||
shower_.start(); // initialize shower timer and shower alert
|
shower_.start(); // initialize shower timer and shower alert
|
||||||
txservice_.start(); // sets bus ID, sends out request for EMS devices
|
txservice_.start(); // sets bus ID, sends out request for EMS devices
|
||||||
sensors_.start(); // dallas external sensors
|
sensors_.start(); // dallas external sensors
|
||||||
|
webServer.begin(); // start web server
|
||||||
webServer.begin(); // start web server
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// main loop calling all services
|
// main loop calling all services
|
||||||
@@ -777,9 +771,11 @@ void EMSESP::loop() {
|
|||||||
|
|
||||||
// if we're doing an OTA upload, skip MQTT and EMS
|
// if we're doing an OTA upload, skip MQTT and EMS
|
||||||
if (system_.upload_status()) {
|
if (system_.upload_status()) {
|
||||||
|
/*
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
delay(10); // slow down OTA update to avoid getting killed by task watchdog (task_wdt)
|
delay(10); // slow down OTA update to avoid getting killed by task watchdog (task_wdt)
|
||||||
#endif
|
#endif
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,7 +792,9 @@ void EMSESP::loop() {
|
|||||||
fetch_device_values();
|
fetch_device_values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ESP8266)
|
||||||
delay(1);
|
delay(1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "telegram.h" // for EMS_VALUE_* settings
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
@@ -329,9 +328,9 @@ bool Helpers::check_abs(const int32_t i) {
|
|||||||
return ((i < 0 ? -i : i) != 0xFFFFFF);
|
return ((i < 0 ? -i : i) != 0xFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
// for booleans, use isBool true (VALUE_BOOL)
|
// for booleans, use isBool true (EMS_VALUE_BOOL)
|
||||||
bool Helpers::hasValue(const uint8_t v, bool isBool) {
|
bool Helpers::hasValue(const uint8_t v, const uint8_t isBool) {
|
||||||
if (isBool) {
|
if (isBool == EMS_VALUE_BOOL) {
|
||||||
return (v != EMS_VALUE_BOOL_NOTSET);
|
return (v != EMS_VALUE_BOOL_NOTSET);
|
||||||
}
|
}
|
||||||
return (v != EMS_VALUE_UINT_NOTSET);
|
return (v != EMS_VALUE_UINT_NOTSET);
|
||||||
@@ -354,4 +353,61 @@ bool Helpers::hasValue(const uint32_t v) {
|
|||||||
return (v != EMS_VALUE_ULONG_NOTSET);
|
return (v != EMS_VALUE_ULONG_NOTSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checks if we can convert a char string to an int value
|
||||||
|
bool Helpers::value2number(const char * v, int value) {
|
||||||
|
if ((v == nullptr) || (strlen(v) == 0)) {
|
||||||
|
value = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = atoi((char *)v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks if we can convert a char string to a float value
|
||||||
|
bool Helpers::value2float(const char * v, float value) {
|
||||||
|
if ((v == nullptr) || (strlen(v) == 0)) {
|
||||||
|
value = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = atof((char *)v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/313970/how-to-convert-stdstring-to-lower-case
|
||||||
|
std::string Helpers::toLower(std::string const & s) {
|
||||||
|
std::string lc = s;
|
||||||
|
std::transform(lc.begin(), lc.end(), lc.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||||
|
return lc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks if we can convert a chat string to an int value
|
||||||
|
bool Helpers::value2string(const char * v, std::string & value) {
|
||||||
|
if ((v == nullptr) || (strlen(v) == 0)) {
|
||||||
|
value = {};
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = toLower(v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks to see if a string (usually a command or payload cmd) looks like a boolean
|
||||||
|
// on, off, true, false, 1, 0
|
||||||
|
bool Helpers::value2bool(const char * v, uint8_t value) {
|
||||||
|
if ((v == nullptr) || (strlen(v) == 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((strncmp(v, "on", 2) == 0) || (strncmp(v, "1", 1) == 0) || (strncmp(v, "true", 4) == 0)) {
|
||||||
|
value = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((strncmp(v, "off", 3) == 0) || (strncmp(v, "0", 1) == 0) || (strncmp(v, "false", 5) == 0)) {
|
||||||
|
value = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <uuid/common.h>
|
#include <uuid/common.h>
|
||||||
|
|
||||||
|
#include "telegram.h" // for EMS_VALUE_* settings
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
class Helpers {
|
class Helpers {
|
||||||
@@ -48,11 +50,18 @@ class Helpers {
|
|||||||
static char * ultostr(char * ptr, uint32_t value, const uint8_t base);
|
static char * ultostr(char * ptr, uint32_t value, const uint8_t base);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool hasValue(const uint8_t v, bool isBool = false); // use isBool=true for bool's
|
static bool hasValue(const uint8_t v, const uint8_t isBool = 0);
|
||||||
static bool hasValue(const int8_t v);
|
static bool hasValue(const int8_t v);
|
||||||
static bool hasValue(const int16_t v);
|
static bool hasValue(const int16_t v);
|
||||||
static bool hasValue(const uint16_t v);
|
static bool hasValue(const uint16_t v);
|
||||||
static bool hasValue(const uint32_t v);
|
static bool hasValue(const uint32_t v);
|
||||||
|
|
||||||
|
static std::string toLower(std::string const & s);
|
||||||
|
|
||||||
|
static bool value2number(const char * v, int value);
|
||||||
|
static bool value2float(const char * v, float value);
|
||||||
|
static bool value2bool(const char * v, uint8_t value);
|
||||||
|
static bool value2string(const char * v, std::string & value);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
117
src/locale_EN.h
Normal file
117
src/locale_EN.h
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||||
|
* Copyright 2019 Paul Derbyshire
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// common words
|
||||||
|
MAKE_PSTR_WORD(exit)
|
||||||
|
MAKE_PSTR_WORD(help)
|
||||||
|
MAKE_PSTR_WORD(settings)
|
||||||
|
MAKE_PSTR_WORD(log)
|
||||||
|
MAKE_PSTR_WORD(logout)
|
||||||
|
MAKE_PSTR_WORD(enabled)
|
||||||
|
MAKE_PSTR_WORD(disabled)
|
||||||
|
MAKE_PSTR_WORD(set)
|
||||||
|
MAKE_PSTR_WORD(show)
|
||||||
|
MAKE_PSTR_WORD(on)
|
||||||
|
MAKE_PSTR_WORD(off)
|
||||||
|
MAKE_PSTR_WORD(su)
|
||||||
|
MAKE_PSTR_WORD(name)
|
||||||
|
MAKE_PSTR_WORD(auto)
|
||||||
|
MAKE_PSTR_WORD(scan)
|
||||||
|
MAKE_PSTR_WORD(password)
|
||||||
|
MAKE_PSTR_WORD(read)
|
||||||
|
MAKE_PSTR_WORD(version)
|
||||||
|
MAKE_PSTR_WORD(values)
|
||||||
|
MAKE_PSTR_WORD(system)
|
||||||
|
MAKE_PSTR_WORD(fetch)
|
||||||
|
MAKE_PSTR_WORD(restart)
|
||||||
|
MAKE_PSTR_WORD(format)
|
||||||
|
MAKE_PSTR_WORD(raw)
|
||||||
|
MAKE_PSTR_WORD(watch)
|
||||||
|
MAKE_PSTR_WORD(send)
|
||||||
|
MAKE_PSTR_WORD(telegram)
|
||||||
|
MAKE_PSTR_WORD(bus_id)
|
||||||
|
MAKE_PSTR_WORD(tx_mode)
|
||||||
|
MAKE_PSTR_WORD(ems)
|
||||||
|
MAKE_PSTR_WORD(devices)
|
||||||
|
MAKE_PSTR_WORD(shower)
|
||||||
|
MAKE_PSTR_WORD(mqtt)
|
||||||
|
MAKE_PSTR_WORD(emsesp)
|
||||||
|
MAKE_PSTR_WORD(connected)
|
||||||
|
MAKE_PSTR_WORD(disconnected)
|
||||||
|
MAKE_PSTR_WORD(passwd)
|
||||||
|
MAKE_PSTR_WORD(hostname)
|
||||||
|
MAKE_PSTR_WORD(wifi)
|
||||||
|
MAKE_PSTR_WORD(reconnect)
|
||||||
|
MAKE_PSTR_WORD(ssid)
|
||||||
|
MAKE_PSTR_WORD(heartbeat)
|
||||||
|
MAKE_PSTR_WORD(users)
|
||||||
|
MAKE_PSTR_WORD(master)
|
||||||
|
MAKE_PSTR_WORD(test)
|
||||||
|
MAKE_PSTR_WORD(call)
|
||||||
|
|
||||||
|
// devices
|
||||||
|
MAKE_PSTR_WORD(boiler)
|
||||||
|
MAKE_PSTR_WORD(thermostat)
|
||||||
|
MAKE_PSTR_WORD(switch)
|
||||||
|
MAKE_PSTR_WORD(solar)
|
||||||
|
MAKE_PSTR_WORD(mixing)
|
||||||
|
MAKE_PSTR_WORD(gateway)
|
||||||
|
MAKE_PSTR_WORD(controller)
|
||||||
|
MAKE_PSTR_WORD(connect)
|
||||||
|
MAKE_PSTR_WORD(heatpump)
|
||||||
|
|
||||||
|
// dallas sensors
|
||||||
|
MAKE_PSTR_WORD(sensors)
|
||||||
|
|
||||||
|
MAKE_PSTR(kwh, "kWh")
|
||||||
|
MAKE_PSTR(wh, "Wh")
|
||||||
|
MAKE_PSTR(hc_optional, "[heating circuit]")
|
||||||
|
MAKE_PSTR(master_thermostat_fmt, "Master Thermostat device ID = %s")
|
||||||
|
MAKE_PSTR(host_fmt, "Host = %s")
|
||||||
|
MAKE_PSTR(hostname_fmt, "WiFi Hostname = %s")
|
||||||
|
MAKE_PSTR(mark_interval_fmt, "Mark interval = %lus");
|
||||||
|
MAKE_PSTR(wifi_ssid_fmt, "WiFi SSID = %s");
|
||||||
|
MAKE_PSTR(wifi_password_fmt, "WiFi Password = %S")
|
||||||
|
MAKE_PSTR(system_heartbeat_fmt, "Heartbeat is %s")
|
||||||
|
MAKE_PSTR(cmd_optional, "[cmd]")
|
||||||
|
MAKE_PSTR(deep_optional, "[deep]")
|
||||||
|
MAKE_PSTR(tx_mode_fmt, "Tx mode = %d")
|
||||||
|
MAKE_PSTR(bus_id_fmt, "Bus ID = %02X")
|
||||||
|
MAKE_PSTR(watchid_optional, "[ID]")
|
||||||
|
MAKE_PSTR(watch_format_mandatory, "<off | on | raw>")
|
||||||
|
MAKE_PSTR(invalid_watch, "Invalid watch type")
|
||||||
|
MAKE_PSTR(data_mandatory, "<\"XX XX ...\">")
|
||||||
|
MAKE_PSTR(percent, "%")
|
||||||
|
MAKE_PSTR(degrees, "°C")
|
||||||
|
MAKE_PSTR(asterisks, "********")
|
||||||
|
MAKE_PSTR(n_mandatory, "<n>")
|
||||||
|
MAKE_PSTR(n_optional, "[n]")
|
||||||
|
MAKE_PSTR(data_optional, "[data]")
|
||||||
|
MAKE_PSTR(id_optional, "[id]")
|
||||||
|
MAKE_PSTR(typeid_mandatory, "<type ID>")
|
||||||
|
MAKE_PSTR(deviceid_mandatory, "<device ID>")
|
||||||
|
MAKE_PSTR(deviceid_optional, "[device ID]")
|
||||||
|
MAKE_PSTR(invalid_log_level, "Invalid log level")
|
||||||
|
MAKE_PSTR(log_level_fmt, "Log level = %s")
|
||||||
|
MAKE_PSTR(log_level_optional, "[level]")
|
||||||
|
MAKE_PSTR(name_mandatory, "<name>")
|
||||||
|
MAKE_PSTR(name_optional, "[name]")
|
||||||
|
MAKE_PSTR(new_password_prompt1, "Enter new password: ")
|
||||||
|
MAKE_PSTR(new_password_prompt2, "Retype new password: ")
|
||||||
|
MAKE_PSTR(password_prompt, "Password: ")
|
||||||
|
MAKE_PSTR(unset, "<unset>")
|
||||||
181
src/mqtt.cpp
181
src/mqtt.cpp
@@ -20,12 +20,6 @@
|
|||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
MAKE_PSTR_WORD(connected)
|
|
||||||
MAKE_PSTR_WORD(disconnected)
|
|
||||||
MAKE_PSTR(system_heartbeat_fmt, "Heartbeat is %s")
|
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "mqtt")
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
AsyncMqttClient * Mqtt::mqttClient_;
|
AsyncMqttClient * Mqtt::mqttClient_;
|
||||||
@@ -35,14 +29,16 @@ std::string Mqtt::hostname_;
|
|||||||
uint8_t Mqtt::mqtt_qos_;
|
uint8_t Mqtt::mqtt_qos_;
|
||||||
uint16_t Mqtt::publish_time_;
|
uint16_t Mqtt::publish_time_;
|
||||||
|
|
||||||
std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
|
std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
|
||||||
|
std::vector<Mqtt::MQTTCmdFunction> Mqtt::mqtt_cmdfunctions_;
|
||||||
|
|
||||||
uint16_t Mqtt::mqtt_publish_fails_ = 0;
|
uint16_t Mqtt::mqtt_publish_fails_ = 0;
|
||||||
size_t Mqtt::maximum_mqtt_messages_ = Mqtt::MAX_MQTT_MESSAGES;
|
size_t Mqtt::maximum_mqtt_messages_ = Mqtt::MAX_MQTT_MESSAGES;
|
||||||
uint16_t Mqtt::mqtt_message_id_ = 0;
|
uint16_t Mqtt::mqtt_message_id_ = 0;
|
||||||
std::deque<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_;
|
std::deque<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_;
|
||||||
char will_topic_[Mqtt::MQTT_TOPIC_MAX_SIZE]; // because MQTT library keeps only char pointer
|
char will_topic_[Mqtt::MQTT_TOPIC_MAX_SIZE]; // because MQTT library keeps only char pointer
|
||||||
|
|
||||||
uuid::log::Logger Mqtt::logger_{F_(logger_name), uuid::log::Facility::DAEMON};
|
uuid::log::Logger Mqtt::logger_{F_(mqtt), uuid::log::Facility::DAEMON};
|
||||||
|
|
||||||
Mqtt::QueuedMqttMessage::QueuedMqttMessage(uint16_t id, std::shared_ptr<MqttMessage> && content)
|
Mqtt::QueuedMqttMessage::QueuedMqttMessage(uint16_t id, std::shared_ptr<MqttMessage> && content)
|
||||||
: id_(id)
|
: id_(id)
|
||||||
@@ -58,34 +54,65 @@ MqttMessage::MqttMessage(const uint8_t operation, const std::string & topic, con
|
|||||||
, retain(retain) {
|
, retain(retain) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Mqtt::MQTTSubFunction::MQTTSubFunction(const uint8_t device_id, const std::string && topic, mqtt_subfunction_p mqtt_subfunction)
|
Mqtt::MQTTSubFunction::MQTTSubFunction(const uint8_t device_type, const std::string && topic, const std::string && full_topic, mqtt_subfunction_p mqtt_subfunction)
|
||||||
: device_id_(device_id)
|
: device_type_(device_type)
|
||||||
, topic_(topic)
|
, topic_(topic)
|
||||||
|
, full_topic_(full_topic)
|
||||||
, mqtt_subfunction_(mqtt_subfunction) {
|
, mqtt_subfunction_(mqtt_subfunction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Mqtt::MQTTCmdFunction::MQTTCmdFunction(const uint8_t device_type, const __FlashStringHelper * cmd, mqtt_cmdfunction_p mqtt_cmdfunction)
|
||||||
|
: device_type_(device_type)
|
||||||
|
, cmd_(cmd)
|
||||||
|
, mqtt_cmdfunction_(mqtt_cmdfunction) {
|
||||||
|
}
|
||||||
|
|
||||||
// subscribe to an MQTT topic, and store the associated callback function
|
// subscribe to an MQTT topic, and store the associated callback function
|
||||||
void Mqtt::subscribe(const uint8_t device_id, const std::string & topic, mqtt_subfunction_p cb) {
|
// only if it already hasn't been added
|
||||||
auto message = queue_subscribe_message(topic); // add subscription to queue. The hostname will automatically be appended
|
void Mqtt::subscribe(const uint8_t device_type, const std::string & topic, mqtt_subfunction_p cb) {
|
||||||
|
|
||||||
if (message == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the message will contain the full topic, with the hostname prefixed
|
|
||||||
// check if we already have the topic subscribed, if so don't add it again
|
// check if we already have the topic subscribed, if so don't add it again
|
||||||
bool exists = false;
|
|
||||||
if (!mqtt_subfunctions_.empty()) {
|
if (!mqtt_subfunctions_.empty()) {
|
||||||
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
||||||
if ((mqtt_subfunction.device_id_ == device_id) && (strcmp(mqtt_subfunction.topic_.c_str(), message->topic.c_str()) == 0)) {
|
if ((mqtt_subfunction.device_type_ == device_type) && (strcmp(mqtt_subfunction.topic_.c_str(), topic.c_str()) == 0)) {
|
||||||
exists = true;
|
return; // it exists, exit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!exists) {
|
// add to MQTT queue as a subscribe operation
|
||||||
mqtt_subfunctions_.emplace_back(device_id, std::move(message->topic), cb); // register a call back function for a specific telegram type
|
auto message = queue_subscribe_message(topic);
|
||||||
|
|
||||||
|
// register in our libary with the callback function.
|
||||||
|
// We store both the original topic and the fully-qualified
|
||||||
|
mqtt_subfunctions_.emplace_back(device_type, std::move(topic), std::move(message->topic), cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// adds a command and callback function for a specific device
|
||||||
|
void Mqtt::add_command(const uint8_t device_type, const __FlashStringHelper * cmd, mqtt_cmdfunction_p cb) {
|
||||||
|
// subscribe to the command topic if it doesn't exist yet
|
||||||
|
// create the cmd topic for a device like "<device_type>_cmd" e.g. "boiler_cmd"
|
||||||
|
// unless its a system MQTT command
|
||||||
|
std::string cmd_topic(40, '\0');
|
||||||
|
if (device_type == EMSdevice::DeviceType::SERVICEKEY) {
|
||||||
|
cmd_topic = "system"; // hard-coded system
|
||||||
|
} else {
|
||||||
|
snprintf_P(&cmd_topic[0], 40, PSTR("%s_cmd"), EMSdevice::device_type_topic_name(device_type).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool exists = false;
|
||||||
|
if (!mqtt_subfunctions_.empty()) {
|
||||||
|
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
||||||
|
if ((mqtt_subfunction.device_type_ == device_type) && (strcmp(mqtt_subfunction.topic_.c_str(), cmd_topic.c_str()) == 0)) {
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!exists) {
|
||||||
|
Mqtt::subscribe(device_type, cmd_topic, nullptr); // use an empty function handler to signal this is a command function
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the function to our list
|
||||||
|
mqtt_cmdfunctions_.emplace_back(device_type, cmd, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscribe to an MQTT topic, and store the associated callback function. For generic functions not tied to a specific device
|
// subscribe to an MQTT topic, and store the associated callback function. For generic functions not tied to a specific device
|
||||||
@@ -142,7 +169,20 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) {
|
|||||||
// show subscriptions
|
// show subscriptions
|
||||||
shell.printfln(F("MQTT subscriptions:"));
|
shell.printfln(F("MQTT subscriptions:"));
|
||||||
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
||||||
shell.printfln(F(" %s"), mqtt_subfunction.topic_.c_str());
|
shell.printfln(F(" %s"), mqtt_subfunction.full_topic_.c_str());
|
||||||
|
}
|
||||||
|
shell.println();
|
||||||
|
|
||||||
|
// show command handlers
|
||||||
|
shell.printfln(F("MQTT commands:"));
|
||||||
|
for (const auto & mqtt_cmdfunction : mqtt_cmdfunctions_) {
|
||||||
|
if (mqtt_cmdfunction.device_type_ == EMSdevice::DeviceType::SERVICEKEY) {
|
||||||
|
shell.printfln(F(" on topic: system, cmd: %s"), uuid::read_flash_string(mqtt_cmdfunction.cmd_).c_str()); // hardcoded topic is system
|
||||||
|
} else {
|
||||||
|
shell.printfln(F(" on topic: %s_cmd, cmd: %s"),
|
||||||
|
EMSdevice::device_type_topic_name(mqtt_cmdfunction.device_type_).c_str(),
|
||||||
|
uuid::read_flash_string(mqtt_cmdfunction.cmd_).c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
shell.println();
|
shell.println();
|
||||||
|
|
||||||
@@ -190,6 +230,31 @@ void Mqtt::incoming(char * topic, char * payload) {
|
|||||||
on_message(topic, payload, strlen(payload));
|
on_message(topic, payload, strlen(payload));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calls a command, context is the device_type
|
||||||
|
// id may be used to represent a heating circuit for example
|
||||||
|
bool Mqtt::call_command(const uint8_t device_type, const char * cmd, const char * value, const int8_t id) {
|
||||||
|
#ifdef EMSESP_DEBUG
|
||||||
|
if (id == -1) {
|
||||||
|
LOG_DEBUG(F("calling command %s, value %s, id is default"), cmd, value);
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(F("calling command %s, value %s, id is %d"), cmd, value, id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!mqtt_cmdfunctions_.empty()) {
|
||||||
|
for (const auto & cf : mqtt_cmdfunctions_) {
|
||||||
|
if (cf.device_type_ == device_type) {
|
||||||
|
const char * cf_cmd = uuid::read_flash_string(cf.cmd_).c_str();
|
||||||
|
if (strcmp(cf_cmd, cmd) == 0) {
|
||||||
|
(cf.mqtt_cmdfunction_)(value, id); // call function, data needs to be a string and can be null
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// received an MQTT message that we subscribed too
|
// received an MQTT message that we subscribed too
|
||||||
void Mqtt::on_message(char * topic, char * payload, size_t len) {
|
void Mqtt::on_message(char * topic, char * payload, size_t len) {
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
@@ -199,33 +264,65 @@ void Mqtt::on_message(char * topic, char * payload, size_t len) {
|
|||||||
// convert payload to a null-terminated char string
|
// convert payload to a null-terminated char string
|
||||||
char message[len + 2];
|
char message[len + 2];
|
||||||
strlcpy(message, payload, len + 1);
|
strlcpy(message, payload, len + 1);
|
||||||
|
|
||||||
|
#ifdef EMSESP_DEBUG
|
||||||
LOG_DEBUG(F("[DEBUG] Received %s => %s (length %d)"), topic, message, len);
|
LOG_DEBUG(F("[DEBUG] Received %s => %s (length %d)"), topic, message, len);
|
||||||
|
#endif
|
||||||
|
|
||||||
// see if we have this topic in our subscription list, then call its callback handler
|
// see if we have this topic in our subscription list, then call its callback handler
|
||||||
// note: this will pick the first topic that matches, so for multiple devices of the same type it's gonna fail. Not sure if this is going to be an issue?
|
|
||||||
for (const auto & mf : mqtt_subfunctions_) {
|
for (const auto & mf : mqtt_subfunctions_) {
|
||||||
if (strcmp(topic, mf.topic_.c_str()) == 0) {
|
if (strcmp(topic, mf.full_topic_.c_str()) == 0) {
|
||||||
(mf.mqtt_subfunction_)(message);
|
if (mf.mqtt_subfunction_) {
|
||||||
return;
|
(mf.mqtt_subfunction_)(message); // matching function, call it
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// empty function. It's a command then. Find the command from the json and call it directly.
|
||||||
|
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
||||||
|
DeserializationError error = deserializeJson(doc, message);
|
||||||
|
if (error) {
|
||||||
|
LOG_ERROR(F("MQTT error: payload %s, error %s"), message, error.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * command = doc["cmd"];
|
||||||
|
if (command == nullptr) {
|
||||||
|
LOG_ERROR(F("MQTT error: invalid payload cmd format. message=%s"), message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for hc and id
|
||||||
|
int8_t n = -1; // no value
|
||||||
|
if (doc.containsKey("hc")) {
|
||||||
|
n = doc["hc"];
|
||||||
|
} else if (doc.containsKey("id")) {
|
||||||
|
n = doc["id"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!call_command(mf.device_type_, command, doc["data"], n)) {
|
||||||
|
// if we got here we didn't find a matching command
|
||||||
|
LOG_ERROR(F("MQTT error: no matching cmd: %s"), command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we got here we didn't find a topic match
|
// if we got here we didn't find a topic match
|
||||||
LOG_DEBUG(F("No responding handler found for topic %s"), topic);
|
LOG_ERROR(F("No MQTT handler found for topic %s and payload %s"), topic, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// print all the topics related to a specific device_id
|
// print all the topics related to a specific device type
|
||||||
void Mqtt::show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_id) {
|
void Mqtt::show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type) {
|
||||||
if (std::count_if(mqtt_subfunctions_.cbegin(),
|
if (std::count_if(mqtt_subfunctions_.cbegin(),
|
||||||
mqtt_subfunctions_.cend(),
|
mqtt_subfunctions_.cend(),
|
||||||
[=](MQTTSubFunction const & mqtt_subfunction) { return device_id == mqtt_subfunction.device_id_; })
|
[=](MQTTSubFunction const & mqtt_subfunction) { return device_type == mqtt_subfunction.device_type_; })
|
||||||
== 0) {
|
== 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
shell.print(F(" Subscribed MQTT topics: "));
|
shell.print(F(" Subscribed MQTT topics: "));
|
||||||
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
||||||
if (mqtt_subfunction.device_id_ == device_id) {
|
if (mqtt_subfunction.device_type_ == device_type) {
|
||||||
shell.printf(F("%s "), mqtt_subfunction.topic_.c_str());
|
shell.printf(F("%s "), mqtt_subfunction.topic_.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,8 +394,13 @@ void Mqtt::start() {
|
|||||||
mqttClient_->setWill(will_topic, 1, true, "offline"); // with qos 1, retain true
|
mqttClient_->setWill(will_topic, 1, true, "offline"); // with qos 1, retain true
|
||||||
|
|
||||||
mqttClient_->onMessage([this](char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
mqttClient_->onMessage([this](char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||||
|
// receiving mqtt
|
||||||
on_message(topic, payload, len);
|
on_message(topic, payload, len);
|
||||||
mqttClient_->onPublish([this](uint16_t packetId) { on_publish(packetId); });
|
});
|
||||||
|
|
||||||
|
mqttClient_->onPublish([this](uint16_t packetId) {
|
||||||
|
// publish
|
||||||
|
on_publish(packetId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,15 +430,18 @@ void Mqtt::on_connect() {
|
|||||||
resubscribe(); // in case this is a reconnect, re-subscribe again to all MQTT topics
|
resubscribe(); // in case this is a reconnect, re-subscribe again to all MQTT topics
|
||||||
|
|
||||||
// add the system MQTT subscriptions, only if its a fresh start with no previous subscriptions
|
// add the system MQTT subscriptions, only if its a fresh start with no previous subscriptions
|
||||||
|
// these commands respond to the topic "system" and take a payload like {cmd:"", data:"", id:""}
|
||||||
if (mqtt_subfunctions_.empty()) {
|
if (mqtt_subfunctions_.empty()) {
|
||||||
Mqtt::subscribe("cmd", System::mqtt_commands);
|
add_command(EMSdevice::DeviceType::SERVICEKEY, F("gpio"), System::mqtt_command_gpio);
|
||||||
|
add_command(EMSdevice::DeviceType::SERVICEKEY, F("send"), System::mqtt_command_send);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("MQTT connected"));
|
LOG_INFO(F("MQTT connected"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add sub or pub task to the queue. When the message is created, the topic will have
|
// add sub or pub task to the queue.
|
||||||
// automatically the hostname prefixed.
|
// a fully-qualified topic is created by prefixing the hostname, unless it's HA
|
||||||
|
// returns a pointer to the message created
|
||||||
std::shared_ptr<const MqttMessage>
|
std::shared_ptr<const MqttMessage>
|
||||||
Mqtt::queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, const bool retain, bool no_prefix) {
|
Mqtt::queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, const bool retain, bool no_prefix) {
|
||||||
if (topic.empty()) {
|
if (topic.empty()) {
|
||||||
|
|||||||
43
src/mqtt.h
43
src/mqtt.h
@@ -44,6 +44,8 @@ using uuid::console::Shell;
|
|||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
using mqtt_subfunction_p = std::function<void(const char * message)>;
|
using mqtt_subfunction_p = std::function<void(const char * message)>;
|
||||||
|
using mqtt_cmdfunction_p = std::function<void(const char * data, const int8_t id)>;
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1`
|
using namespace std::placeholders; // for `_1`
|
||||||
|
|
||||||
struct MqttMessage {
|
struct MqttMessage {
|
||||||
@@ -68,20 +70,24 @@ class Mqtt {
|
|||||||
|
|
||||||
static constexpr uint8_t MQTT_TOPIC_MAX_SIZE = 100;
|
static constexpr uint8_t MQTT_TOPIC_MAX_SIZE = 100;
|
||||||
|
|
||||||
static void subscribe(const uint8_t device_id, const std::string & topic, mqtt_subfunction_p cb);
|
static void subscribe(const uint8_t device_type, const std::string & topic, mqtt_subfunction_p cb);
|
||||||
static void subscribe(const std::string & topic, mqtt_subfunction_p cb);
|
static void subscribe(const std::string & topic, mqtt_subfunction_p cb);
|
||||||
static void resubscribe();
|
static void resubscribe();
|
||||||
|
|
||||||
|
static void add_command(const uint8_t device_type, const __FlashStringHelper * cmd, mqtt_cmdfunction_p cb);
|
||||||
|
|
||||||
static void publish(const std::string & topic, const std::string & payload, bool retain = false);
|
static void publish(const std::string & topic, const std::string & payload, bool retain = false);
|
||||||
static void publish(const std::string & topic, const JsonDocument & payload, bool retain = false);
|
static void publish(const std::string & topic, const JsonDocument & payload, bool retain = false);
|
||||||
static void publish(const std::string & topic, const bool value);
|
static void publish(const std::string & topic, const bool value);
|
||||||
static void publish(const std::string & topic);
|
static void publish(const std::string & topic);
|
||||||
|
|
||||||
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_id);
|
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);
|
||||||
static void show_mqtt(uuid::console::Shell & shell);
|
static void show_mqtt(uuid::console::Shell & shell);
|
||||||
|
|
||||||
static void on_connect();
|
static void on_connect();
|
||||||
|
|
||||||
|
static bool call_command(const uint8_t device_type, const char * cmd, const char * value, const int8_t id);
|
||||||
|
|
||||||
void disconnect() {
|
void disconnect() {
|
||||||
mqttClient_->disconnect();
|
mqttClient_->disconnect();
|
||||||
}
|
}
|
||||||
@@ -102,6 +108,20 @@ class Mqtt {
|
|||||||
|
|
||||||
static std::string hostname_;
|
static std::string hostname_;
|
||||||
|
|
||||||
|
class MQTTCmdFunction {
|
||||||
|
public:
|
||||||
|
MQTTCmdFunction(const uint8_t device_type, const __FlashStringHelper * cmd, mqtt_cmdfunction_p mqtt_cmdfunction);
|
||||||
|
~MQTTCmdFunction() = default;
|
||||||
|
|
||||||
|
const uint8_t device_type_;
|
||||||
|
const __FlashStringHelper * cmd_;
|
||||||
|
mqtt_cmdfunction_p mqtt_cmdfunction_;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<MQTTCmdFunction> commands() {
|
||||||
|
return mqtt_cmdfunctions_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uuid::log::Logger logger_;
|
static uuid::log::Logger logger_;
|
||||||
|
|
||||||
@@ -127,29 +147,32 @@ class Mqtt {
|
|||||||
static constexpr uint32_t MQTT_PUBLISH_WAIT = 200; // delay between sending publishes, to account for large payloads
|
static constexpr uint32_t MQTT_PUBLISH_WAIT = 200; // delay between sending publishes, to account for large payloads
|
||||||
static constexpr uint8_t MQTT_PUBLISH_MAX_RETRY = 3; // max retries for giving up on publishing
|
static constexpr uint8_t MQTT_PUBLISH_MAX_RETRY = 3; // max retries for giving up on publishing
|
||||||
|
|
||||||
static std::shared_ptr<const MqttMessage> queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, const bool retain, bool no_prefix = false);
|
static std::shared_ptr<const MqttMessage>
|
||||||
|
queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, const bool retain, bool no_prefix = false);
|
||||||
static std::shared_ptr<const MqttMessage> queue_publish_message(const std::string & topic, const std::string & payload, const bool retain);
|
static std::shared_ptr<const MqttMessage> queue_publish_message(const std::string & topic, const std::string & payload, const bool retain);
|
||||||
static std::shared_ptr<const MqttMessage> queue_subscribe_message(const std::string & topic);
|
static std::shared_ptr<const MqttMessage> queue_subscribe_message(const std::string & topic);
|
||||||
|
|
||||||
void on_publish(uint16_t packetId);
|
void on_publish(uint16_t packetId);
|
||||||
void on_message(char * topic, char * payload, size_t len);
|
void on_message(char * topic, char * payload, size_t len);
|
||||||
void process_queue();
|
void process_queue();
|
||||||
void process_all_queue();
|
void process_all_queue();
|
||||||
|
|
||||||
static uint16_t mqtt_publish_fails_;
|
static uint16_t mqtt_publish_fails_;
|
||||||
|
|
||||||
// function handlers for MQTT subscriptions
|
// function handlers for MQTT subscriptions
|
||||||
class MQTTSubFunction {
|
class MQTTSubFunction {
|
||||||
public:
|
public:
|
||||||
MQTTSubFunction(const uint8_t device_id, const std::string && topic, mqtt_subfunction_p mqtt_subfunction);
|
MQTTSubFunction(const uint8_t device_type, const std::string && topic, const std::string && full_topic, mqtt_subfunction_p mqtt_subfunction);
|
||||||
~MQTTSubFunction() = default;
|
~MQTTSubFunction() = default;
|
||||||
|
|
||||||
const uint8_t device_id_; // which device ID owns this
|
const uint8_t device_type_; // which device type, from DeviceType::
|
||||||
const std::string topic_;
|
const std::string topic_;
|
||||||
mqtt_subfunction_p mqtt_subfunction_;
|
const std::string full_topic_; // the fully qualified topic name, usually with the hostname prefixed
|
||||||
|
mqtt_subfunction_p mqtt_subfunction_; // can be empty
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<MQTTSubFunction> mqtt_subfunctions_; // list of mqtt subscribe callbacks for all devices
|
static std::vector<MQTTSubFunction> mqtt_subfunctions_; // list of mqtt subscribe callbacks for all devices
|
||||||
|
static std::vector<MQTTCmdFunction> mqtt_cmdfunctions_; // list of commands
|
||||||
|
|
||||||
uint32_t last_mqtt_poll_ = 0;
|
uint32_t last_mqtt_poll_ = 0;
|
||||||
uint32_t last_publish_ = 0;
|
uint32_t last_publish_ = 0;
|
||||||
|
|||||||
@@ -16,13 +16,11 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// code written by nomis - https://github.com/nomis
|
// code originally written by nomis - https://github.com/nomis
|
||||||
|
|
||||||
#include "sensors.h"
|
#include "sensors.h"
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "sensors")
|
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#define YIELD
|
#define YIELD
|
||||||
#else
|
#else
|
||||||
@@ -31,7 +29,7 @@ MAKE_PSTR(logger_name, "sensors")
|
|||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
uuid::log::Logger Sensors::logger_{F_(logger_name), uuid::log::Facility::DAEMON};
|
uuid::log::Logger Sensors::logger_{F_(sensors), uuid::log::Facility::DAEMON};
|
||||||
|
|
||||||
void Sensors::start() {
|
void Sensors::start() {
|
||||||
// copy over values from MQTT so we don't keep on quering the filesystem
|
// copy over values from MQTT so we don't keep on quering the filesystem
|
||||||
@@ -206,7 +204,7 @@ float Sensors::get_temperature_c(const uint8_t addr[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t raw = (raw_value *625) / 100; // round to 0.01
|
uint32_t raw = (raw_value * 625) / 100; // round to 0.01
|
||||||
return (float)raw / 100;
|
return (float)raw / 100;
|
||||||
#else
|
#else
|
||||||
return NAN;
|
return NAN;
|
||||||
@@ -303,4 +301,4 @@ void Sensors::publish_values() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// code written by nomis - https://github.com/nomis
|
// code originally written by nomis - https://github.com/nomis
|
||||||
|
|
||||||
#ifndef EMSESP_SENSORS_H
|
#ifndef EMSESP_SENSORS_H
|
||||||
#define EMSESP_SENSORS_H
|
#define EMSESP_SENSORS_H
|
||||||
@@ -87,10 +87,10 @@ class Sensors {
|
|||||||
static constexpr uint8_t TYPE_DS1822 = 0x22;
|
static constexpr uint8_t TYPE_DS1822 = 0x22;
|
||||||
static constexpr uint8_t TYPE_DS1825 = 0x3B;
|
static constexpr uint8_t TYPE_DS1825 = 0x3B;
|
||||||
|
|
||||||
static constexpr uint32_t READ_INTERVAL_MS = 5000; // 5 seconds
|
static constexpr uint32_t READ_INTERVAL_MS = 5000; // 5 seconds
|
||||||
static constexpr uint32_t CONVERSION_MS = 1000; // 1 seconds
|
static constexpr uint32_t CONVERSION_MS = 1000; // 1 seconds
|
||||||
static constexpr uint32_t READ_TIMEOUT_MS = 2000; // 2 seconds
|
static constexpr uint32_t READ_TIMEOUT_MS = 2000; // 2 seconds
|
||||||
static constexpr uint32_t SCAN_TIMEOUT_MS = 3000; // 3 seconds
|
static constexpr uint32_t SCAN_TIMEOUT_MS = 3000; // 3 seconds
|
||||||
|
|
||||||
static constexpr uint8_t CMD_CONVERT_TEMP = 0x44;
|
static constexpr uint8_t CMD_CONVERT_TEMP = 0x44;
|
||||||
static constexpr uint8_t CMD_READ_SCRATCHPAD = 0xBE;
|
static constexpr uint8_t CMD_READ_SCRATCHPAD = 0xBE;
|
||||||
@@ -112,9 +112,8 @@ class Sensors {
|
|||||||
|
|
||||||
uint8_t mqtt_format_;
|
uint8_t mqtt_format_;
|
||||||
uint8_t retrycnt_ = 0;
|
uint8_t retrycnt_ = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -18,11 +18,9 @@
|
|||||||
|
|
||||||
#include "shower.h"
|
#include "shower.h"
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "shower")
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
uuid::log::Logger Shower::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
uuid::log::Logger Shower::logger_{F_(shower), uuid::log::Facility::CONSOLE};
|
||||||
|
|
||||||
void Shower::start() {
|
void Shower::start() {
|
||||||
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) {
|
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) {
|
||||||
|
|||||||
122
src/system.cpp
122
src/system.cpp
@@ -21,25 +21,9 @@
|
|||||||
|
|
||||||
#include "version.h" // firmware version of EMS-ESP
|
#include "version.h" // firmware version of EMS-ESP
|
||||||
|
|
||||||
MAKE_PSTR_WORD(passwd)
|
|
||||||
MAKE_PSTR_WORD(hostname)
|
|
||||||
MAKE_PSTR_WORD(wifi)
|
|
||||||
MAKE_PSTR_WORD(reconnect)
|
|
||||||
MAKE_PSTR_WORD(ssid)
|
|
||||||
MAKE_PSTR_WORD(heartbeat)
|
|
||||||
MAKE_PSTR_WORD(users)
|
|
||||||
|
|
||||||
MAKE_PSTR(host_fmt, "Host = %s")
|
|
||||||
MAKE_PSTR(hostname_fmt, "WiFi Hostname = %s")
|
|
||||||
MAKE_PSTR(mark_interval_fmt, "Mark interval = %lus");
|
|
||||||
MAKE_PSTR(wifi_ssid_fmt, "WiFi SSID = %s");
|
|
||||||
MAKE_PSTR(wifi_password_fmt, "WiFi Password = %S")
|
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "system")
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
uuid::log::Logger System::logger_{F_(logger_name), uuid::log::Facility::KERN};
|
uuid::log::Logger System::logger_{F_(system), uuid::log::Facility::KERN};
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
uuid::syslog::SyslogService System::syslog_;
|
uuid::syslog::SyslogService System::syslog_;
|
||||||
@@ -50,94 +34,28 @@ uint32_t System::heap_start_ = 0;
|
|||||||
int System::reset_counter_ = 0;
|
int System::reset_counter_ = 0;
|
||||||
bool System::upload_status_ = false;
|
bool System::upload_status_ = false;
|
||||||
|
|
||||||
// handle generic system related MQTT commands
|
// send on/off to a gpio pin
|
||||||
void System::mqtt_commands(const char * message) {
|
// value: true = HIGH, false = LOW
|
||||||
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
|
void System::mqtt_command_gpio(const char * value, const int8_t id) {
|
||||||
DeserializationError error = deserializeJson(doc, message);
|
|
||||||
if (error) {
|
|
||||||
LOG_DEBUG(F("MQTT error: payload %s, error %s"), message, error.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doc["send"] != nullptr) {
|
|
||||||
const char * data = doc["send"];
|
|
||||||
EMSESP::send_raw_telegram(data);
|
|
||||||
LOG_INFO(F("Sending raw: %s"), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
const uint8_t d0_ = 16;
|
const uint8_t pins[] = {16, 5, 4, 0};
|
||||||
const uint8_t d1_ = 5;
|
|
||||||
const uint8_t d2_ = 4;
|
|
||||||
const uint8_t d3_ = 0;
|
|
||||||
#elif defined(ESP32)
|
#elif defined(ESP32)
|
||||||
const uint8_t d0_ = 26;
|
const uint8_t pins[] = {26, 22, 21, 17};
|
||||||
const uint8_t d1_ = 22;
|
#else
|
||||||
const uint8_t d2_ = 21;
|
const uint8_t pins[] = {0, 1, 2, 3};
|
||||||
const uint8_t d3_ = 17;
|
|
||||||
#endif
|
#endif
|
||||||
|
bool v = false;
|
||||||
#ifndef EMSESP_STANDALONE
|
if (Helpers::value2bool(value, v)) {
|
||||||
if (doc["D0"] != nullptr) {
|
uint8_t gpio = pins[id]; // D0 - D3
|
||||||
const int8_t set = doc["D0"];
|
pinMode(gpio, OUTPUT);
|
||||||
pinMode(d0_, OUTPUT);
|
digitalWrite(gpio, v);
|
||||||
if (set == 1) {
|
LOG_INFO(F("Port D%d set to %s"), id, v ? "HIGH" : "LOW");
|
||||||
digitalWrite(d0_, HIGH);
|
|
||||||
} else if (set == 0) {
|
|
||||||
digitalWrite(d0_, LOW);
|
|
||||||
}
|
|
||||||
LOG_INFO(F("Port D0 set to %d"), set);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (doc["D1"] != nullptr) {
|
// send raw
|
||||||
const int8_t set = doc["D1"];
|
void System::mqtt_command_send(const char * value, const int8_t id) {
|
||||||
pinMode(d1_, OUTPUT);
|
EMSESP::send_raw_telegram(value); // ignore id
|
||||||
if (set == 1) {
|
|
||||||
digitalWrite(d1_, HIGH);
|
|
||||||
} else if (set == 0) {
|
|
||||||
digitalWrite(d1_, LOW);
|
|
||||||
}
|
|
||||||
LOG_INFO(F("Port D1 set to %d"), set);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doc["D2"] != nullptr) {
|
|
||||||
const int8_t set = doc["D2"];
|
|
||||||
pinMode(d2_, OUTPUT);
|
|
||||||
if (set == 1) {
|
|
||||||
digitalWrite(d2_, HIGH);
|
|
||||||
} else if (set == 0) {
|
|
||||||
digitalWrite(d2_, LOW);
|
|
||||||
}
|
|
||||||
LOG_INFO(F("Port D2 set to %d"), set);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doc["D3"] != nullptr) {
|
|
||||||
const int8_t set = doc["D3"];
|
|
||||||
pinMode(d3_, OUTPUT);
|
|
||||||
if (set == 1) {
|
|
||||||
digitalWrite(d3_, HIGH);
|
|
||||||
} else if (set == 0) {
|
|
||||||
digitalWrite(d3_, LOW);
|
|
||||||
}
|
|
||||||
LOG_INFO(F("Port D3 set to %d"), set);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char * command = doc["cmd"];
|
|
||||||
if (command == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send raw command
|
|
||||||
if (strcmp(command, "send") == 0) {
|
|
||||||
const char * data = doc["data"];
|
|
||||||
if (data == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
EMSESP::send_raw_telegram(data);
|
|
||||||
LOG_INFO(F("Sending raw: %s"), data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// restart EMS-ESP
|
// restart EMS-ESP
|
||||||
@@ -646,9 +564,10 @@ void System::console_commands(Shell & shell, unsigned int context) {
|
|||||||
|
|
||||||
// upgrade from previous versions of EMS-ESP
|
// upgrade from previous versions of EMS-ESP
|
||||||
void System::check_upgrade() {
|
void System::check_upgrade() {
|
||||||
|
/*
|
||||||
// check for v1.9. It uses SPIFFS and only on the ESP8266
|
// check for v1.9. It uses SPIFFS and only on the ESP8266
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
Serial.begin(115200); // TODO remove, just for debugging
|
Serial.begin(115200);
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
@@ -771,6 +690,7 @@ void System::check_upgrade() {
|
|||||||
},
|
},
|
||||||
"local");
|
"local");
|
||||||
#endif
|
#endif
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ class System {
|
|||||||
static void format(uuid::console::Shell & shell);
|
static void format(uuid::console::Shell & shell);
|
||||||
|
|
||||||
static void console_commands(Shell & shell, unsigned int context);
|
static void console_commands(Shell & shell, unsigned int context);
|
||||||
static void mqtt_commands(const char * message);
|
|
||||||
|
static void mqtt_command_gpio(const char * value, const int8_t id);
|
||||||
|
static void mqtt_command_send(const char * value, const int8_t id);
|
||||||
|
|
||||||
static uint8_t free_mem();
|
static uint8_t free_mem();
|
||||||
static void upload_status(bool in_progress);
|
static void upload_status(bool in_progress);
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
#include "telegram.h"
|
#include "telegram.h"
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
|
|
||||||
MAKE_PSTR(logger_name, "telegram")
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
// CRC lookup table with poly 12 for faster checking
|
// CRC lookup table with poly 12 for faster checking
|
||||||
@@ -45,7 +43,7 @@ uint8_t EMSbus::ems_bus_id_ = EMSESP_DEFAULT_EMS_BUS_ID;
|
|||||||
uint8_t EMSbus::tx_mode_ = EMSESP_DEFAULT_TX_MODE;
|
uint8_t EMSbus::tx_mode_ = EMSESP_DEFAULT_TX_MODE;
|
||||||
uint8_t EMSbus::tx_state_ = Telegram::Operation::NONE;
|
uint8_t EMSbus::tx_state_ = Telegram::Operation::NONE;
|
||||||
|
|
||||||
uuid::log::Logger EMSbus::logger_{F_(logger_name), uuid::log::Facility::CONSOLE};
|
uuid::log::Logger EMSbus::logger_{F_(telegram), uuid::log::Facility::CONSOLE};
|
||||||
|
|
||||||
// Calculates CRC checksum using lookup table for speed
|
// Calculates CRC checksum using lookup table for speed
|
||||||
// length excludes the last byte (which mainly is the CRC)
|
// length excludes the last byte (which mainly is the CRC)
|
||||||
@@ -572,11 +570,13 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EMSESP_DENUG
|
||||||
LOG_DEBUG(F("[DEBUG] Last Tx %s operation failed. Retry #%d. sent message: %s, received: %s"),
|
LOG_DEBUG(F("[DEBUG] Last Tx %s operation failed. Retry #%d. sent message: %s, received: %s"),
|
||||||
(operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"),
|
(operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"),
|
||||||
retry_count_,
|
retry_count_,
|
||||||
telegram_last_->to_string().c_str(),
|
telegram_last_->to_string().c_str(),
|
||||||
Helpers::data_to_hex(data, length).c_str());
|
Helpers::data_to_hex(data, length).c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
// add to the top of the queue
|
// add to the top of the queue
|
||||||
if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) {
|
if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) {
|
||||||
|
|||||||
@@ -38,9 +38,9 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
// default values for null values
|
// default values for null values
|
||||||
static constexpr uint8_t VALUE_BOOL = true; // is a boolean
|
static constexpr uint8_t EMS_VALUE_BOOL = 0xFF; // used to mark that something is a boolean
|
||||||
static constexpr uint8_t EMS_VALUE_BOOL = 0xFF; // is a boolean
|
static constexpr uint8_t EMS_VALUE_BOOL_OFF = 0x00; // boolean false
|
||||||
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_ON = 0x01; // boolean true. 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_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 uint8_t EMS_VALUE_UINT_NOTSET = 0xFF; // for 8-bit unsigned ints/bytes
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#if defined(EMSESP_STANDALONE)
|
#if defined(EMSESP_STANDALONE)
|
||||||
|
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
@@ -26,6 +27,14 @@ namespace emsesp {
|
|||||||
// create some fake test data
|
// create some fake test data
|
||||||
// used with the 'test' command, under su/admin
|
// used with the 'test' command, under su/admin
|
||||||
void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
||||||
|
if (command == "default") {
|
||||||
|
run_test(shell, "mqtt"); // add the default test case here
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.empty()) {
|
||||||
|
run_test(shell, "default");
|
||||||
|
}
|
||||||
|
|
||||||
if (command == "render") {
|
if (command == "render") {
|
||||||
uint8_t test1 = 12;
|
uint8_t test1 = 12;
|
||||||
int8_t test2 = -12;
|
int8_t test2 = -12;
|
||||||
@@ -129,7 +138,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
|||||||
rx_telegram({0x08, 0x00, 0x07, 0x00, 0x0B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
rx_telegram({0x08, 0x00, 0x07, 0x00, 0x0B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command == "boiler2") {
|
if (command == "boiler") {
|
||||||
// question: do we need to set the mask?
|
// question: do we need to set the mask?
|
||||||
std::string version("1.2.3");
|
std::string version("1.2.3");
|
||||||
EMSESP::add_device(0x08, 123, version, EMSdevice::Brand::BUDERUS); // Nefit Trendline
|
EMSESP::add_device(0x08, 123, version, EMSdevice::Brand::BUDERUS); // Nefit Trendline
|
||||||
@@ -180,7 +189,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (command == "thermostat") {
|
if (command == "thermostat") {
|
||||||
shell.printfln(F("Testing adding devices on the EMS bus..."));
|
shell.printfln(F("Testing adding a thermostat to the EMS bus..."));
|
||||||
|
|
||||||
// create some fake devices
|
// create some fake devices
|
||||||
std::string version("1.2.3");
|
std::string version("1.2.3");
|
||||||
@@ -245,7 +254,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
|||||||
// see https://github.com/proddy/EMS-ESP/issues/390
|
// see https://github.com/proddy/EMS-ESP/issues/390
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
uart_telegram_withCRC("90 48 FF 04 01 A6 5C");
|
uart_telegram_withCRC("90 48 FF 04 01 A6 5C");
|
||||||
uart_telegram_withCRC("90 48 FF 00 01 A6 4C");
|
uart_telegram_withCRC("90 48 FF 00 01 A6 4C");
|
||||||
uart_telegram_withCRC("90 48 FF 08 01 A7 6D");
|
uart_telegram_withCRC("90 48 FF 08 01 A7 6D");
|
||||||
@@ -283,7 +291,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
|||||||
uart_telegram_withCRC("C8 90 FF 00 02 01 A6 D0");
|
uart_telegram_withCRC("C8 90 FF 00 02 01 A6 D0");
|
||||||
|
|
||||||
// uart_telegram_withCRC("10 00 FF 00 01 A5 00 D7 21 00 00 00 00 30 01 84 01 01 03 01 84 01 F1 00 00 11 01 00 08 63 00");
|
// uart_telegram_withCRC("10 00 FF 00 01 A5 00 D7 21 00 00 00 00 30 01 84 01 01 03 01 84 01 F1 00 00 11 01 00 08 63 00");
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uart_telegram_withCRC("C8 90 F7 02 01 FF 01 A6 BA");
|
uart_telegram_withCRC("C8 90 F7 02 01 FF 01 A6 BA");
|
||||||
@@ -473,49 +480,115 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
|||||||
EMSESP::txservice_.flush_tx_queue();
|
EMSESP::txservice_.flush_tx_queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command == "mqtt1") {
|
if (command == "mqtt") {
|
||||||
shell.printfln(F("Testing MQTT..."));
|
shell.printfln(F("Testing MQTT..."));
|
||||||
|
|
||||||
// MQTT test
|
// simulate an on connect
|
||||||
EMSESP::txservice_.flush_tx_queue();
|
Mqtt::on_connect();
|
||||||
EMSESP::EMSESP::mqtt_.publish("boiler_cmd", "test me");
|
|
||||||
// EMSESP::mqtt_.show_queue();
|
// add a boiler
|
||||||
// simulate an incoming mqtt msg
|
// question: do we need to set the mask?
|
||||||
|
std::string version("1.2.3");
|
||||||
|
EMSESP::add_device(0x08, 123, version, EMSdevice::Brand::BUDERUS); // Nefit Trendline
|
||||||
|
|
||||||
|
// add a thermostat
|
||||||
|
EMSESP::add_device(0x18, 157, version, EMSdevice::Brand::BOSCH); // Bosch CR100 - https://github.com/proddy/EMS-ESP/issues/355
|
||||||
|
EMSESP::rxservice_.loop();
|
||||||
|
|
||||||
|
// RCPLUSStatusMessage_HC1(0x01A5)
|
||||||
|
uart_telegram({0x98, 0x00, 0xFF, 0x00, 0x01, 0xA5, 0x00, 0xCF, 0x21, 0x2E, 0x00, 0x00, 0x2E, 0x24,
|
||||||
|
0x03, 0x25, 0x03, 0x03, 0x01, 0x03, 0x25, 0x00, 0xC8, 0x00, 0x00, 0x11, 0x01, 0x03});
|
||||||
|
uart_telegram("98 00 FF 00 01 A5 00 CF 21 2E 00 00 2E 24 03 25 03 03 01 03 25 00 C8 00 00 11 01 03"); // without CRC
|
||||||
|
uart_telegram_withCRC("98 00 FF 00 01 A5 00 CF 21 2E 00 00 2E 24 03 25 03 03 01 03 25 00 C8 00 00 11 01 03 13"); // with CRC
|
||||||
|
|
||||||
|
EMSESP::rxservice_.loop();
|
||||||
|
shell.loop_all();
|
||||||
|
|
||||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
char payload[100];
|
char payload[100];
|
||||||
|
|
||||||
strcpy(topic, "boiler_cmd");
|
// test publish and adding to queue
|
||||||
|
EMSESP::txservice_.flush_tx_queue();
|
||||||
|
EMSESP::EMSESP::mqtt_.publish("boiler_cmd", "test me");
|
||||||
|
Mqtt::show_mqtt(shell);
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/boiler_cmd");
|
||||||
strcpy(payload, "12345");
|
strcpy(payload, "12345");
|
||||||
EMSESP::mqtt_.incoming(topic, payload);
|
EMSESP::mqtt_.incoming(topic, payload); // invalid format
|
||||||
EMSESP::mqtt_.incoming(payload, payload); // should report error
|
EMSESP::mqtt_.incoming(payload, payload); // no matching topic
|
||||||
|
|
||||||
strcpy(topic, "thermostat_cmd_mode");
|
strcpy(topic, "ems-esp/boiler_cmd");
|
||||||
strcpy(payload, "auto");
|
strcpy(payload, "{\"cmd\":\"garbage\",\"data\":22.52}");
|
||||||
|
EMSESP::mqtt_.incoming(topic, payload); // should report error
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/boiler_cmd");
|
||||||
|
strcpy(payload, "{\"cmd\":\"comfort\",\"data\":\"eco\"}");
|
||||||
EMSESP::mqtt_.incoming(topic, payload);
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
strcpy(topic, "thermostat_cmd_temp");
|
strcpy(topic, "ems-esp/boiler_cmd");
|
||||||
strcpy(payload, "20");
|
strcpy(payload, "{\"cmd\":\"wwactivated\",\"data\":\"1\"}");
|
||||||
EMSESP::mqtt_.incoming(topic, payload);
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
strcpy(topic, "thermostat_cmd");
|
strcpy(topic, "ems-esp/boiler_cmd");
|
||||||
|
strcpy(payload, "{\"cmd\":\"wwactivated\",\"data\":1}");
|
||||||
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/boiler_cmd");
|
||||||
|
strcpy(payload, "{\"cmd\":\"flowtemp\",\"data\":55}");
|
||||||
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/system");
|
||||||
|
strcpy(payload, "{\"cmd\":\"send\",\"data\":\"01 02 03 04 05\"}");
|
||||||
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/system");
|
||||||
|
strcpy(payload, "{\"cmd\":\"gpio\",\"id\":1,\"data\":\"1\"}");
|
||||||
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/thermostat_cmd");
|
||||||
|
strcpy(payload, "{\"cmd\":\"wwmode\",\"data\":\"auto\"}");
|
||||||
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/thermostat_cmd");
|
||||||
|
strcpy(payload, "{\"cmd\":\"control\",\"data\":\"1\"}");
|
||||||
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/thermostat_cmd");
|
||||||
|
strcpy(payload, "{\"cmd\":\"control\",\"data\":1}");
|
||||||
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/thermostat_cmd");
|
||||||
|
strcpy(payload, "{\"cmd\":\"mode\",\"data\":\"auto\",\"id\":2}"); // with id
|
||||||
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/thermostat_cmd");
|
||||||
|
strcpy(payload, "{\"cmd\":\"mode\",\"data\":\"auto\",\"hc\":2}"); // with hc
|
||||||
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
|
strcpy(topic, "ems-esp/thermostat_cmd");
|
||||||
strcpy(payload, "{\"cmd\":\"temp\",\"data\":22.52}");
|
strcpy(payload, "{\"cmd\":\"temp\",\"data\":22.52}");
|
||||||
EMSESP::mqtt_.incoming(topic, payload);
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
strcpy(topic, "boiler_cmd_wwtemp");
|
strcpy(topic, "ems-esp/thermostat_cmd");
|
||||||
strcpy(payload, "66");
|
strcpy(payload, "{\"cmd\":\"temp\",\"data\":22.52}");
|
||||||
EMSESP::mqtt_.incoming(topic, payload);
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
strcpy(topic, "thermostat_cmd");
|
strcpy(topic, "ems-esp/thermostat_cmd");
|
||||||
strcpy(payload, "{\"cmd\":\"temp\",\"hc\":2,\"data\":22}");
|
strcpy(payload, "{\"cmd\":\"temp\",\"id\":2,\"data\":22}");
|
||||||
EMSESP::mqtt_.incoming(topic, payload);
|
|
||||||
|
|
||||||
strcpy(topic, "home/ems-esp/cmd");
|
|
||||||
strcpy(payload, "restart");
|
|
||||||
EMSESP::mqtt_.incoming(topic, payload);
|
EMSESP::mqtt_.incoming(topic, payload);
|
||||||
|
|
||||||
// EMSESP::txservice_.show_tx_queue();
|
// EMSESP::txservice_.show_tx_queue();
|
||||||
|
// EMSESP::publish_all_values();
|
||||||
|
|
||||||
EMSESP::publish_all_values();
|
EMSESP::add_context_menus(); // need to add this as it happens later in the code
|
||||||
|
shell.invoke_command("su");
|
||||||
|
shell.invoke_command("thermostat");
|
||||||
|
shell.invoke_command("help");
|
||||||
|
shell.invoke_command("call");
|
||||||
|
shell.invoke_command("call wwmode");
|
||||||
|
shell.invoke_command("call mode auto 2");
|
||||||
|
|
||||||
|
shell.loop_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command == "poll2") {
|
if (command == "poll2") {
|
||||||
@@ -542,12 +615,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
|||||||
uart_telegram({0x21, 0x0B, 0xFF, 0x00});
|
uart_telegram({0x21, 0x0B, 0xFF, 0x00});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command == "mqtt2") {
|
|
||||||
for (uint8_t i = 0; i < 30; i++) {
|
|
||||||
Mqtt::subscribe("topic", dummy_mqtt_commands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// testing the UART tx command, without a queue
|
// testing the UART tx command, without a queue
|
||||||
if (command == "tx2") {
|
if (command == "tx2") {
|
||||||
uint8_t t[] = {0x0B, 0x88, 0x18, 0x00, 0x20, 0xD4}; // including CRC
|
uint8_t t[] = {0x0B, 0x88, 0x18, 0x00, 0x20, 0xD4}; // including CRC
|
||||||
@@ -686,9 +753,6 @@ void Test::uart_telegram(const char * rx_data) {
|
|||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
|
||||||
void Test::dummy_mqtt_commands(const char * message) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
#include "mqtt.h"
|
#include "mqtt.h"
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
|
|
||||||
MAKE_PSTR_WORD(test)
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "2.0.0b11"
|
#define EMSESP_APP_VERSION "2.0.0b12"
|
||||||
|
|||||||
Reference in New Issue
Block a user