This commit is contained in:
MichaelDvP
2024-10-10 09:34:18 +02:00
37 changed files with 1321 additions and 1165 deletions

View File

@@ -39,10 +39,6 @@ static inline EMSESPShell & to_shell(Shell & shell) {
return static_cast<EMSESPShell &>(shell);
}
static inline EMSESP & to_app(Shell & shell) {
return to_shell(shell).emsesp_;
}
#define NO_ARGUMENTS \
std::vector<std::string> { \
}
@@ -67,7 +63,7 @@ static std::vector<std::string> log_level_autocomplete(Shell & shell, const std:
return uuid::log::levels_lowercase();
}
static void setup_commands(std::shared_ptr<Commands> & commands) {
static void setup_commands(std::shared_ptr<Commands> const & commands) {
// exit, help, log
commands->add_command(ShellContext::MAIN, CommandFlags::USER, {F_(exit)}, EMSESPShell::main_exit_function);
commands->add_command(ShellContext::MAIN, CommandFlags::USER, {F_(help)}, EMSESPShell::main_help_function);
@@ -81,35 +77,35 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
CommandFlags::USER,
{F_(show)},
{F_(show_commands)},
[=](Shell & shell, const std::vector<std::string> & arguments) {
[](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.empty()) {
to_app(shell).system_.show_system(shell);
EMSESP::system_.show_system(shell);
return;
}
auto command = arguments.front();
auto const & command = arguments.front();
if (command == F_(commands)) {
Command::show_all(shell);
} else if (command == F_(system)) {
to_app(shell).system_.show_system(shell);
EMSESP::system_.show_system(shell);
} else if (command == F_(users) && (shell.has_flags(CommandFlags::ADMIN))) {
to_app(shell).system_.show_users(shell); // admin only
EMSESP::system_.show_users(shell); // admin only
} else if (command == F_(devices)) {
to_app(shell).show_devices(shell);
EMSESP::show_devices(shell);
} else if (command == F_(log)) {
to_app(shell).webLogService.show(shell);
EMSESP::webLogService.show(shell);
} else if (command == F_(ems)) {
to_app(shell).show_ems(shell);
EMSESP::show_ems(shell);
} else if (command == F_(values)) {
to_app(shell).show_device_values(shell);
to_app(shell).show_sensor_values(shell);
EMSESP::show_device_values(shell);
EMSESP::show_sensor_values(shell);
} else if (command == F_(mqtt)) {
Mqtt::show_mqtt(shell);
} else {
shell.printfln("Unknown show command");
}
},
[](Shell & shell, const std::vector<std::string> & current_arguments, const std::string & next_argument) -> std::vector<std::string> {
[](Shell const & shell, const std::vector<std::string> & current_arguments, const std::string & next_argument) -> std::vector<std::string> {
return std::vector<std::string>{"system", "users", "devices", "log", "ems", "values", "mqtt", "commands"};
});
@@ -154,7 +150,7 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
if (completed) {
uint64_t now = uuid::get_uptime_ms();
to_app(shell).esp8266React.getSecuritySettingsService()->read([&](SecuritySettings & securitySettings) {
EMSESP::esp8266React.getSecuritySettingsService()->read([&](SecuritySettings & securitySettings) {
if (!password.empty() && (securitySettings.jwtSecret.equals(password.c_str()))) {
become_admin(shell);
} else {
@@ -178,7 +174,7 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
shell.enter_password(F_(new_password_prompt2), [password1](Shell & shell, bool completed, const std::string & password2) {
if (completed) {
if (password1 == password2) {
to_app(shell).esp8266React.getSecuritySettingsService()->update([&](SecuritySettings & securitySettings) {
EMSESP::esp8266React.getSecuritySettingsService()->update([&](SecuritySettings & securitySettings) {
securitySettings.jwtSecret = password2.c_str();
return StateUpdateResult::CHANGED;
});
@@ -198,16 +194,16 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
{F_(partitionname_optional)},
[](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.size()) {
to_app(shell).system_.system_restart(arguments.front().c_str());
EMSESP::system_.system_restart(arguments.front().c_str());
} else {
to_app(shell).system_.system_restart();
EMSESP::system_.system_restart();
}
});
commands->add_command(ShellContext::MAIN,
CommandFlags::ADMIN,
string_vector{F_(wifi), F_(reconnect)},
[](Shell & shell, const std::vector<std::string> & arguments) { to_app(shell).system_.wifi_reconnect(); });
[](Shell & shell, const std::vector<std::string> & arguments) { EMSESP::system_.wifi_reconnect(); });
//
// SET commands
@@ -221,13 +217,13 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
shell.enter_password(F_(new_password_prompt2), [password1](Shell & shell, bool completed, const std::string & password2) {
if (completed) {
if (password1 == password2) {
to_app(shell).esp8266React.getNetworkSettingsService()->updateWithoutPropagation(
EMSESP::esp8266React.getNetworkSettingsService()->updateWithoutPropagation(
[&](NetworkSettings & networkSettings) {
networkSettings.password = password2.c_str();
return StateUpdateResult::CHANGED;
});
shell.println("WiFi password updated. Reconnecting...");
to_app(shell).system_.wifi_reconnect();
EMSESP::system_.wifi_reconnect();
} else {
shell.println("Passwords do not match");
}
@@ -245,7 +241,7 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
shell.println("The network connection will be reset...");
Shell::loop_all();
delay(1000); // wait a second
to_app(shell).esp8266React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) {
EMSESP::esp8266React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) {
networkSettings.hostname = arguments.front().c_str();
return StateUpdateResult::CHANGED;
});
@@ -256,12 +252,12 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
string_vector{F_(set), F_(wifi), F_(ssid)},
{F_(name_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) {
to_app(shell).esp8266React.getNetworkSettingsService()->updateWithoutPropagation([&](NetworkSettings & networkSettings) {
EMSESP::esp8266React.getNetworkSettingsService()->updateWithoutPropagation([&](NetworkSettings & networkSettings) {
networkSettings.ssid = arguments.front().c_str();
return StateUpdateResult::CHANGED;
});
shell.println("WiFi ssid updated. Reconnecting...");
to_app(shell).system_.wifi_reconnect();
EMSESP::system_.wifi_reconnect();
});
@@ -273,12 +269,12 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
[](Shell & shell, const std::vector<std::string> & arguments) {
std::vector<int8_t> data; // led, dallas, rx, tx, button, phy_type, eth_power, eth_phy_addr, eth_clock_mode
std::string board_profile = Helpers::toUpper(arguments.front());
if (!to_app(shell).system_.load_board_profile(data, board_profile)) {
if (!EMSESP::system_.load_board_profile(data, board_profile)) {
shell.println("Invalid board profile (S32, E32, E32V2, MH-ET, NODEMCU, LOLIN, OLIMEX, OLIMEXPOE, C3MINI, S2MINI, S3MINI, S32S3, CUSTOM)");
return;
}
to_app(shell).webSettingsService.update([&](WebSettings & settings) {
EMSESP::webSettingsService.update([&](WebSettings & settings) {
settings.board_profile = board_profile.c_str();
settings.led_gpio = data[0];
settings.dallas_gpio = data[1];
@@ -292,7 +288,7 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
return StateUpdateResult::CHANGED;
});
shell.printfln("Loaded board profile %s", board_profile.c_str());
to_app(shell).system_.network_init(true);
EMSESP::system_.network_init(true);
});
commands->add_command(
@@ -303,7 +299,7 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
[](Shell & shell, const std::vector<std::string> & arguments) {
uint8_t device_id = Helpers::hextoint(arguments.front().c_str());
if ((device_id == 0x0B) || (device_id == 0x0D) || (device_id == 0x0A) || (device_id == 0x0F) || (device_id == 0x12)) {
to_app(shell).webSettingsService.update([&](WebSettings & settings) {
EMSESP::webSettingsService.update([&](WebSettings & settings) {
settings.ems_bus_id = device_id;
shell.printfln(F_(bus_id_fmt), settings.ems_bus_id);
return StateUpdateResult::CHANGED;
@@ -323,12 +319,12 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
[](Shell & shell, const std::vector<std::string> & arguments) {
uint8_t tx_mode = std::strtol(arguments[0].c_str(), nullptr, 10);
// save the tx_mode
to_app(shell).webSettingsService.update([&](WebSettings & settings) {
EMSESP::webSettingsService.update([&](WebSettings & settings) {
settings.tx_mode = tx_mode;
shell.printfln(F_(tx_mode_fmt), settings.tx_mode);
return StateUpdateResult::CHANGED;
});
to_app(shell).uart_init();
EMSESP::uart_init();
});
commands->add_command(ShellContext::MAIN,
@@ -339,17 +335,17 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
if (arguments.back() == "enable" || arguments.back() == "disable") {
bool enable = arguments.back() == "enable";
if (arguments.front() == "mqtt") {
to_app(shell).esp8266React.getMqttSettingsService()->update([&](MqttSettings & Settings) {
EMSESP::esp8266React.getMqttSettingsService()->update([&](MqttSettings & Settings) {
Settings.enabled = enable;
return StateUpdateResult::CHANGED;
});
} else if (arguments.front() == "ntp") {
to_app(shell).esp8266React.getNTPSettingsService()->update([&](NTPSettings & Settings) {
EMSESP::esp8266React.getNTPSettingsService()->update([&](NTPSettings & Settings) {
Settings.enabled = enable;
return StateUpdateResult::CHANGED;
});
} else if (arguments.front() == "ap") {
to_app(shell).esp8266React.getAPSettingsService()->update([&](APSettings & Settings) {
EMSESP::esp8266React.getAPSettingsService()->update([&](APSettings & Settings) {
Settings.provisionMode = enable ? 0 : 2;
return StateUpdateResult::CHANGED;
});
@@ -368,17 +364,17 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
//
commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, {F_(scan)}, {F_(deep_optional)}, [](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.size() == 0) {
to_app(shell).scan_devices();
if (arguments.empty()) {
EMSESP::scan_devices();
} else {
shell.printfln("Performing a deep scan...");
to_app(shell).clear_all_devices();
EMSESP::clear_all_devices();
// device IDs taken from device_library.h
// send the read command with Version command
const std::vector<uint8_t> Device_Ids = {0x02, 0x08, 0x09, 0x10, 0x11, 0x12, 0x15, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x20, 0x21, 0x22, 0x23,
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x30, 0x38, 0x40, 0x41, 0x48, 0x50, 0x51, 0x60};
for (const uint8_t device_id : Device_Ids) {
to_app(shell).send_read_request(EMSdevice::EMS_TYPE_VERSION, device_id);
EMSESP::send_read_request(EMSdevice::EMS_TYPE_VERSION, device_id);
}
}
});
@@ -390,7 +386,7 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
[=](Shell & shell, const std::vector<std::string> & arguments) {
uint8_t device_id = Helpers::hextoint(arguments.front().c_str());
if (!to_app(shell).valid_device(device_id)) {
if (!EMSESP::valid_device(device_id)) {
shell.printfln("Invalid deviceID");
return;
}
@@ -399,14 +395,14 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
if (arguments.size() == 4) {
uint16_t offset = Helpers::hextoint(arguments[2].c_str());
uint8_t length = Helpers::hextoint(arguments.back().c_str());
to_app(shell).send_read_request(type_id, device_id, offset, length, true);
EMSESP::send_read_request(type_id, device_id, offset, length, true);
} else if (arguments.size() == 3) {
uint16_t offset = Helpers::hextoint(arguments.back().c_str());
to_app(shell).send_read_request(type_id, device_id, offset, 0, true);
EMSESP::send_read_request(type_id, device_id, offset, 0, true);
} else {
to_app(shell).send_read_request(type_id, device_id, 0, 0, true);
EMSESP::send_read_request(type_id, device_id, 0, 0, true);
}
to_app(shell).set_read_id(type_id);
EMSESP::set_read_id(type_id);
});
commands->add_command(ShellContext::MAIN,
@@ -419,22 +415,21 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
// only use english commands, not the translations
if (!arguments.empty()) {
// get raw/pretty
if (arguments[0] == (F_(raw))) {
to_app(shell).watch(to_app(shell).WATCH_RAW); // raw
if (arguments[0] == F_(raw)) {
EMSESP::watch(EMSESP::WATCH_RAW); // raw
} else if (arguments[0] == (FL_(on)[0])) {
to_app(shell).watch(to_app(shell).WATCH_ON); // on
EMSESP::watch(EMSESP::WATCH_ON); // on
} else if (arguments[0] == (FL_(off)[0])) {
to_app(shell).watch(to_app(shell).WATCH_OFF); // off
EMSESP::watch(EMSESP::WATCH_OFF); // off
} else if (arguments[0] == (FL_(unknown)[0])) {
to_app(shell).watch(to_app(shell).WATCH_UNKNOWN); // unknown
EMSESP::watch(EMSESP::WATCH_UNKNOWN); // unknown
watch_id = WATCH_ID_NONE;
} else {
watch_id = Helpers::hextoint(arguments[0].c_str());
if (watch_id > 0
&& ((to_app(shell).watch() == to_app(shell).WATCH_OFF) || (to_app(shell).watch() == to_app(shell).WATCH_UNKNOWN))) {
to_app(shell).watch(to_app(shell).WATCH_ON); // on
if (watch_id > 0 && ((EMSESP::watch() == EMSESP::WATCH_OFF) || (EMSESP::watch() == EMSESP::WATCH_UNKNOWN))) {
EMSESP::watch(EMSESP::WATCH_ON); // on
} else if (watch_id == 0) {
to_app(shell).watch(to_app(shell).WATCH_OFF); // off
EMSESP::watch(EMSESP::WATCH_OFF); // off
return;
}
}
@@ -444,14 +439,14 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
watch_id = Helpers::hextoint(arguments[1].c_str());
}
to_app(shell).watch_id(watch_id);
EMSESP::watch_id(watch_id);
} else {
shell.printfln("Invalid: use watch raw|on|off|unknown|id [id]");
return;
}
uint8_t watch = to_app(shell).watch();
if (watch == to_app(shell).WATCH_OFF) {
uint8_t watch = EMSESP::watch();
if (watch == EMSESP::WATCH_OFF) {
shell.printfln("Watching telegrams is off");
return;
}
@@ -462,15 +457,15 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
shell.printfln("Setting log level to Notice");
}
if (watch == to_app(shell).WATCH_ON) {
if (watch == EMSESP::WATCH_ON) {
shell.printfln("Watching incoming telegrams, displayed in decoded format");
} else if (watch == to_app(shell).WATCH_RAW) {
} else if (watch == EMSESP::WATCH_RAW) {
shell.printfln("Watching incoming telegrams, displayed as raw bytes"); // WATCH_RAW
} else {
shell.printfln("Watching unknown telegrams"); // WATCH_UNKNOWN
}
watch_id = to_app(shell).watch_id();
watch_id = EMSESP::watch_id();
if (watch_id > 0x80) {
shell.printfln("Filtering only telegrams that match a telegram type of 0x%02X", watch_id);
} else if (watch_id != WATCH_ID_NONE) {
@@ -571,7 +566,7 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
}
},
[](Shell & shell, const std::vector<std::string> & current_arguments, const std::string & next_argument) -> std::vector<std::string> {
if (current_arguments.size() == 0) {
if (current_arguments.empty()) {
std::vector<std::string> devices_list;
devices_list.emplace_back(EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SYSTEM));
devices_list.emplace_back(EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::TEMPERATURESENSOR));
@@ -600,7 +595,7 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
}
std::shared_ptr<Commands> EMSESPShell::commands_ = [] {
std::shared_ptr<Commands> commands = std::make_shared<Commands>();
auto commands = std::make_shared<Commands>();
setup_commands(commands);
return commands;
}();

View File

@@ -24,40 +24,40 @@
*/
// Boilers - 0x08
{ 8, DeviceType::BOILER, "CS5800i/CS6800i/WLW176i", DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP},
{ 8, DeviceType::BOILER, "CS*800i, Logatherm WLW*", DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP},
{ 12, DeviceType::BOILER, "C1200W", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 64, DeviceType::BOILER, "BK13/BK15/Smartline/GB1x2", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 72, DeviceType::BOILER, "GB125/GB135/MC10", DeviceFlags::EMS_DEVICE_FLAG_EMS},
{ 64, DeviceType::BOILER, "BK13/BK15, Smartline, GB1*2", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 72, DeviceType::BOILER, "Logano GB1*5, Logamatic MC10", DeviceFlags::EMS_DEVICE_FLAG_EMS},
{ 81, DeviceType::BOILER, "Cascade CM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 84, DeviceType::BOILER, "Logamax Plus GB022", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 95, DeviceType::BOILER, "Condens 2500/5000W/Logamax/Logomatic/Cerapur Top/Greenstar/Generic HT3", DeviceFlags::EMS_DEVICE_FLAG_HT3},
{115, DeviceType::BOILER, "Topline/GB162", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 95, DeviceType::BOILER, "Condens 2500/5000W, Logamax/Logomatic, Cerapur Top, Greenstar, Generic HT3", DeviceFlags::EMS_DEVICE_FLAG_HT3},
{115, DeviceType::BOILER, "Topline, GB162", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{121, DeviceType::BOILER, "Cascade MCM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{122, DeviceType::BOILER, "Proline", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{123, DeviceType::BOILER, "GBx72/Trendline/Cerapur/Greenstar Si", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{123, DeviceType::BOILER, "GB*72, Trendline, Cerapur, Greenstar Si", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{131, DeviceType::BOILER, "GB212", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{132, DeviceType::BOILER, "GC7000F", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{133, DeviceType::BOILER, "Logano GB125/KB195i/Logamatic MC110", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{133, DeviceType::BOILER, "Logano GB125/KB195i, Logamatic MC110", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{154, DeviceType::BOILER, "Greenstar 30Ri Compact", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{167, DeviceType::BOILER, "Cerapur Aero", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{168, DeviceType::BOILER, "Hybrid Heatpump", DeviceFlags::EMS_DEVICE_FLAG_HYBRID},
{170, DeviceType::BOILER, "Logano GB212", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{172, DeviceType::BOILER, "Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i", DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP},
{172, DeviceType::BOILER, "Enviline, Compress 6000AW, Hybrid 3000-7000iAW, SupraEco/Geo 5xx, WLW196i/WSW196i", DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP},
{173, DeviceType::BOILER, "Geo 5xx", DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP},
{195, DeviceType::BOILER, "Condens 5000i/Greenstar 8000/GC9800IW/GB192i.2", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{203, DeviceType::BOILER, "Logamax U122/Cerapur", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{195, DeviceType::BOILER, "Condens 5000i, Greenstar 8000/GC9800IW, GB192i*2", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{203, DeviceType::BOILER, "Logamax U122, Cerapur", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{206, DeviceType::BOILER, "Ecomline Excellent", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{208, DeviceType::BOILER, "Logamax Plus/GB192/Condens GC9000/Greenstar ErP", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{208, DeviceType::BOILER, "Logamax Plus, GB192, Condens GC9000, Greenstar ErP", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{210, DeviceType::BOILER, "Cascade MC400", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{211, DeviceType::BOILER, "EasyControl Adapter", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{219, DeviceType::BOILER, "Greenstar HIU/Logamax kompakt WS170", DeviceFlags::EMS_DEVICE_FLAG_HIU},
{234, DeviceType::BOILER, "Logamax Plus GB122/Condense 2300", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{219, DeviceType::BOILER, "Greenstar HIU, Logamax kompakt WS170", DeviceFlags::EMS_DEVICE_FLAG_HIU},
{234, DeviceType::BOILER, "Logamax Plus GB122, Condense 2300, Junkers Cerapur GC2200W", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Controllers - 0x09 / 0x10 / 0x50
{ 68, DeviceType::CONTROLLER, "BC10/RFM20", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{ 68, DeviceType::CONTROLLER, "BC10, RFM20", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{ 81, DeviceType::CONTROLLER, "CM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 84, DeviceType::CONTROLLER, "GB022", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 89, DeviceType::CONTROLLER, "BC10 GB142", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{ 89, DeviceType::CONTROLLER, "BC10, GB142", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{ 95, DeviceType::CONTROLLER, "HT3", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{114, DeviceType::CONTROLLER, "BC10", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{121, DeviceType::CONTROLLER, "MCM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
@@ -77,35 +77,35 @@
{241, DeviceType::CONTROLLER, "Condens 5000i", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
// Thermostat - not currently supporting write operations, like the Easy/100 types - 0x18
{202, DeviceType::THERMOSTAT, "Logamatic TC100/Moduline Easy", DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
{203, DeviceType::THERMOSTAT, "EasyControl/CT200", DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
{202, DeviceType::THERMOSTAT, "Logamatic TC100, Moduline Easy", DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
{203, DeviceType::THERMOSTAT, "EasyControl, CT200", DeviceFlags::EMS_DEVICE_FLAG_EASY | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
// Thermostat - Buderus/Nefit/Bosch specific - 0x17 / 0x10 / 0x18 / 0x19-0x1B for hc2-4 / 0x38
{ 4, DeviceType::THERMOSTAT, "UI800/BC400", DeviceFlags::EMS_DEVICE_FLAG_BC400}, // 0x10
{ 4, DeviceType::THERMOSTAT, "UI800, BC400", DeviceFlags::EMS_DEVICE_FLAG_BC400}, // 0x10
{ 65, DeviceType::THERMOSTAT, "RC10", DeviceFlags::EMS_DEVICE_FLAG_RC20_N},// 0x17
{ 67, DeviceType::THERMOSTAT, "RC30", DeviceFlags::EMS_DEVICE_FLAG_RC30_N},// 0x10 - based on RC35
{ 77, DeviceType::THERMOSTAT, "RC20/Moduline 300", DeviceFlags::EMS_DEVICE_FLAG_RC20},// 0x17
{ 77, DeviceType::THERMOSTAT, "RC20, Moduline 300", DeviceFlags::EMS_DEVICE_FLAG_RC20},// 0x17
{ 78, DeviceType::THERMOSTAT, "Moduline 400", DeviceFlags::EMS_DEVICE_FLAG_RC30}, // 0x10
{ 79, DeviceType::THERMOSTAT, "RC10/Moduline 100", DeviceFlags::EMS_DEVICE_FLAG_RC10},// 0x17
{ 79, DeviceType::THERMOSTAT, "RC10, Moduline 100", DeviceFlags::EMS_DEVICE_FLAG_RC10},// 0x17
{ 80, DeviceType::THERMOSTAT, "Moduline 200", DeviceFlags::EMS_DEVICE_FLAG_RC10}, // 0x17
{ 86, DeviceType::THERMOSTAT, "RC35", DeviceFlags::EMS_DEVICE_FLAG_RC35}, // 0x10
{ 90, DeviceType::THERMOSTAT, "RC10/Moduline 100", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17
{ 90, DeviceType::THERMOSTAT, "RC10, Moduline 100", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17
{ 93, DeviceType::THERMOSTAT, "RC20RF", DeviceFlags::EMS_DEVICE_FLAG_RC20}, // 0x19
{ 94, DeviceType::THERMOSTAT, "RFM20 Remote", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x18
{151, DeviceType::THERMOSTAT, "RC25", DeviceFlags::EMS_DEVICE_FLAG_RC25}, // 0x17
{157, DeviceType::THERMOSTAT, "RC200/CW100/CR120/CR50", DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18,, CR120 v22 is FLAG_BC400
{158, DeviceType::THERMOSTAT, "RC300/RC310/Moduline 3000/1010H/CW400/Sense II/HPC410", DeviceFlags::EMS_DEVICE_FLAG_RC300}, // 0x10
{165, DeviceType::THERMOSTAT, "RC100/CR10/Moduline 1000/1010", DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18, 0x38
{157, DeviceType::THERMOSTAT, "RC200, CW100, CR120, CR50", DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18,, CR120 v22 is FLAG_BC400
{158, DeviceType::THERMOSTAT, "RC3*0, Moduline 3000/1010H, CW400, Sense II, HPC410", DeviceFlags::EMS_DEVICE_FLAG_RC300}, // 0x10
{165, DeviceType::THERMOSTAT, "RC100, CR10, Moduline 1000/1010", DeviceFlags::EMS_DEVICE_FLAG_RC100}, // 0x18, 0x38
{172, DeviceType::THERMOSTAT, "Rego 2000/3000", DeviceFlags::EMS_DEVICE_FLAG_R3000}, // 0x10
{215, DeviceType::THERMOSTAT, "Comfort RF", DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18
{216, DeviceType::THERMOSTAT, "CRF200S", DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18
{246, DeviceType::THERMOSTAT, "Comfort+2RF", DeviceFlags::EMS_DEVICE_FLAG_CRF | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE}, // 0x18
{253, DeviceType::THERMOSTAT, "Rego 3000/UI800/WSW196i/BC400", DeviceFlags::EMS_DEVICE_FLAG_BC400}, // 0x10
{253, DeviceType::THERMOSTAT, "Rego 3000, UI800, Logatherm WLW186i/WSW196i, Logamatic BC400", DeviceFlags::EMS_DEVICE_FLAG_BC400}, // 0x10
// Thermostat - Sieger - 0x10 / 0x17
{ 66, DeviceType::THERMOSTAT, "ES72/RC20", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17 or remote
{ 66, DeviceType::THERMOSTAT, "ES72, RC20", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17 or remote
{ 76, DeviceType::THERMOSTAT, "ES73", DeviceFlags::EMS_DEVICE_FLAG_RC30_N}, // 0x10
{113, DeviceType::THERMOSTAT, "ES72/RC20", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17
{113, DeviceType::THERMOSTAT, "ES72, RC20", DeviceFlags::EMS_DEVICE_FLAG_RC20_N}, // 0x17
{156, DeviceType::THERMOSTAT, "ES79", DeviceFlags::EMS_DEVICE_FLAG_RC35}, // 0x10
// Thermostat - Junkers - 0x10
@@ -122,17 +122,17 @@
{192, DeviceType::THERMOSTAT, "FW120", DeviceFlags::EMS_DEVICE_FLAG_JUNKERS},
// Thermostat remote - 0x38
{ 3, DeviceType::THERMOSTAT, "RT800/RC220", DeviceFlags::EMS_DEVICE_FLAG_RC100H},
{ 3, DeviceType::THERMOSTAT, "RT800, RC220", DeviceFlags::EMS_DEVICE_FLAG_RC100H},
{200, DeviceType::THERMOSTAT, "RC100H", DeviceFlags::EMS_DEVICE_FLAG_RC100H},
{249, DeviceType::THERMOSTAT, "TR120RF/CR20RF", DeviceFlags::EMS_DEVICE_FLAG_RC100H},
{249, DeviceType::THERMOSTAT, "TR120RF, CR20RF", DeviceFlags::EMS_DEVICE_FLAG_RC100H},
// Solar Modules - 0x30 (for solar), 0x2A, 0x41 (for ww)
{ 73, DeviceType::SOLAR, "SM10", DeviceFlags::EMS_DEVICE_FLAG_SM10},
{101, DeviceType::SOLAR, "ISM1", DeviceFlags::EMS_DEVICE_FLAG_ISM},
{103, DeviceType::SOLAR, "ISM2", DeviceFlags::EMS_DEVICE_FLAG_ISM},
{162, DeviceType::SOLAR, "SM50", DeviceFlags::EMS_DEVICE_FLAG_SM100},
{163, DeviceType::SOLAR, "SM100/MS100", DeviceFlags::EMS_DEVICE_FLAG_SM100},
{164, DeviceType::SOLAR, "SM200/MS200", DeviceFlags::EMS_DEVICE_FLAG_SM100},
{163, DeviceType::SOLAR, "SM100, MS100", DeviceFlags::EMS_DEVICE_FLAG_SM100},
{164, DeviceType::SOLAR, "SM200, MS200", DeviceFlags::EMS_DEVICE_FLAG_SM100},
// Mixer Modules - 0x20-0x27 for HC, 0x28-0x29 for WWC and 0x11 for the MP100
{ 69, DeviceType::MIXER, "MM10", DeviceFlags::EMS_DEVICE_FLAG_MM10},
@@ -163,7 +163,7 @@
{206, DeviceType::CONNECT, "Easy Connect", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Wireless sensor base - 0x50
{218, DeviceType::CONNECT, "M200/RFM200", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{218, DeviceType::CONNECT, "M200, RFM200", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{236, DeviceType::CONNECT, "Wireless sensor base", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{238, DeviceType::CONNECT, "Wireless sensor base", DeviceFlags::EMS_DEVICE_FLAG_NONE},
@@ -171,7 +171,7 @@
{ 71, DeviceType::SWITCH, "WM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// EM10/100 extension module, pump module - 0x15
{ 243, DeviceType::EXTENSION, "EM10/EM100", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 243, DeviceType::EXTENSION, "EM10, EM100", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Wireless outdoor sensor T1RF - 0x16
{ 220, DeviceType::EXTENSION, "T1RF", DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x16
@@ -180,8 +180,8 @@
{ 74, DeviceType::ALERT, "EM10", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Gateways - 0x48
{189, DeviceType::GATEWAY, "KM200/MB LAN 2", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{252, DeviceType::GATEWAY, "K30RF/MX300", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{189, DeviceType::GATEWAY, "KM200, MB LAN 2", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{252, DeviceType::GATEWAY, "K30RF, MX300", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Generic - 0x40 or other with no product-id and no version
{0, DeviceType::GENERIC, "unknown", DeviceFlags::EMS_DEVICE_FLAG_NONE}

View File

@@ -95,7 +95,8 @@ void Mqtt::subscribe(const uint8_t device_type, const std::string & topic, mqtt_
// register in our libary with the callback function.
// We store the original topic string without base
mqtt_subfunctions_.emplace_back(device_type, std::move(topic), std::move(cb));
// removed std::move(topic) in 3.7.0-dev.43
mqtt_subfunctions_.emplace_back(device_type, topic, cb);
if (!enabled() || !connected()) {
return;
@@ -135,7 +136,7 @@ void Mqtt::loop() {
uint32_t currentMillis = uuid::get_uptime();
// send heartbeat
if ((currentMillis - last_publish_heartbeat_ > publish_time_heartbeat_)) {
if (currentMillis - last_publish_heartbeat_ > publish_time_heartbeat_) {
last_publish_heartbeat_ = currentMillis;
EMSESP::system_.send_heartbeat(); // send heartbeat
}
@@ -265,7 +266,8 @@ void Mqtt::on_message(const char * topic, const uint8_t * payload, size_t len) {
JsonDocument input_doc;
JsonDocument output_doc;
JsonObject input, output;
JsonObject input;
JsonObject output;
// convert payload into a json doc
// if the payload doesn't not contain the key 'value' or 'data', treat the whole payload as the 'value'
@@ -524,8 +526,6 @@ void Mqtt::on_connect() {
// publish to the last will topic (see Mqtt::start() function) to say we're alive
queue_publish_retain("status", "online", false); // with retain off
// mqtt_publish_fails_ = 0; // reset fail count to 0
}
// Home Assistant Discovery - the main master Device called EMS-ESP

View File

@@ -256,7 +256,8 @@ class Mqtt {
const std::string topic_; // short topic name
mqtt_sub_function_p mqtt_subfunction_; // can be empty
MQTTSubFunction(uint8_t device_type, const std::string && topic, mqtt_sub_function_p mqtt_subfunction)
// replaced &&topic with &topic in 3.7.0-dev.43, so we prevent the std:move later
MQTTSubFunction(uint8_t device_type, const std::string & topic, mqtt_sub_function_p mqtt_subfunction)
: device_type_(device_type)
, topic_(topic)
, mqtt_subfunction_(mqtt_subfunction) {
@@ -265,7 +266,6 @@ class Mqtt {
static std::vector<MQTTSubFunction> mqtt_subfunctions_; // list of mqtt subscribe callbacks for all devices
// uint32_t last_mqtt_poll_ = 0;
uint32_t last_publish_boiler_ = 0;
uint32_t last_publish_thermostat_ = 0;
uint32_t last_publish_solar_ = 0;

View File

@@ -8,19 +8,12 @@
// https://ideone.com/VocUTq
//
// License:
// If you use this code in binary / compiled / un-commented (removing all text comments) form,
// you can use it under CC0 license.
//
// But if you use this code as source code / readable text, since main content of this code is
// their notes, I recommend you to indicate notices which conform CC-BY-SA. For example,
//
// --- ---
// YOUR-CONTENT uses the following materials.
// This code uses the following materials.
// (1) Wikipedia article [Shunting-yard algorithm](https://en.wikipedia.org/wiki/Shunting-yard_algorithm),
// which is released under the [Creative Commons Attribution-Share-Alike License 3.0](https://creativecommons.org/licenses/by-sa/3.0/).
// (2) [Implementation notes for unary operators in Shunting-Yard algorithm](https://stackoverflow.com/a/5240912) by Austin Taylor
// which is released under the [Creative Commons Attribution-Share-Alike License 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
// --- ---
//
// copy from https://gist.github.com/t-mat/b9f681b7591cdae712f6
// modified MDvP, 06.2024
//
@@ -75,7 +68,7 @@ std::deque<Token> exprToTokens(const std::string & expr) {
++p;
}
const auto s = std::string(b, p);
tokens.push_back(Token{Token::Type::String, s, -3});
tokens.emplace_back(Token::Type::String, s, -3);
if (*p == '\0') {
--p;
}
@@ -85,7 +78,7 @@ std::deque<Token> exprToTokens(const std::string & expr) {
++p;
}
const auto s = std::string(b, p);
tokens.push_back(Token{Token::Type::String, s, -2});
tokens.emplace_back(Token::Type::String, s, -2);
--p;
} else if (*p == '"') {
++p;
@@ -94,7 +87,7 @@ std::deque<Token> exprToTokens(const std::string & expr) {
++p;
}
const auto s = std::string(b, p);
tokens.push_back(Token{Token::Type::String, s, -3});
tokens.emplace_back(Token::Type::String, s, -3);
if (*p == '\0') {
--p;
}
@@ -105,7 +98,7 @@ std::deque<Token> exprToTokens(const std::string & expr) {
++p;
}
const auto s = std::string(b, p);
tokens.push_back(Token{Token::Type::String, s, -3});
tokens.emplace_back(Token::Type::String, s, -3);
if (*p == '\0') {
--p;
}
@@ -115,7 +108,7 @@ std::deque<Token> exprToTokens(const std::string & expr) {
++p;
}
const auto s = std::string(b, p);
tokens.push_back(Token{Token::Type::Number, s, -4});
tokens.emplace_back(Token::Type::Number, s, -4);
--p;
} else {
Token::Type token = Token::Type::Operator;
@@ -214,7 +207,7 @@ std::deque<Token> exprToTokens(const std::string & expr) {
break;
}
const auto s = std::string(1, c);
tokens.push_back(Token{token, s, precedence, rightAssociative});
tokens.emplace_back(token, s, precedence, rightAssociative);
}
}
@@ -227,7 +220,7 @@ std::deque<Token> shuntingYard(const std::deque<Token> & tokens) {
std::vector<Token> stack;
// While there are tokens to be read:
for (auto token : tokens) {
for (auto const & token : tokens) {
// Read a token
switch (token.type) {
case Token::Type::Number:
@@ -302,7 +295,6 @@ std::deque<Token> shuntingYard(const std::deque<Token> & tokens) {
case Token::Type::Unknown:
default:
return {};
break;
}
}
@@ -355,7 +347,8 @@ std::string commands(std::string & expr, bool quotes = true) {
if (strstr(cmd, "/value") == nullptr) {
strlcat(cmd, "/value", sizeof(cmd) - 6);
}
JsonDocument doc_out, doc_in;
JsonDocument doc_out;
JsonDocument doc_in;
JsonObject output = doc_out.to<JsonObject>();
JsonObject input = doc_in.to<JsonObject>();
std::string cmd_s = "api/" + std::string(cmd);
@@ -589,7 +582,6 @@ std::string calculate(const std::string & expr) {
result += s;
}
return result;
// return stack.back();
}
// check for multiple instances of <cond> ? <expr1> : <expr2>

View File

@@ -243,7 +243,7 @@ void RxService::add_empty(const uint8_t src, const uint8_t dest, const uint16_t
// send out request to EMS bus for all devices
void TxService::start() {
// grab the bus ID and tx_mode
EMSESP::webSettingsService.read([&](WebSettings & settings) {
EMSESP::webSettingsService.read([&](WebSettings const & settings) {
ems_bus_id(settings.ems_bus_id);
tx_mode(settings.tx_mode);
});
@@ -418,30 +418,6 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
tx_state(telegram->operation); // tx now in a wait state
}
/*
// send an array of bytes as a telegram
// we need to calculate the CRC and append it before sending
// this function is fire-and-forget. there are no checks or post-send validations
void TxService::send_telegram(const uint8_t * data, const uint8_t length) {
uint8_t telegram_raw[EMS_MAX_TELEGRAM_LENGTH];
for (uint8_t i = 0; i < length; i++) {
telegram_raw[i] = data[i];
}
telegram_raw[length] = calculate_crc(telegram_raw, length); // append CRC
tx_state(Telegram::Operation::NONE); // no post validation needed
// send the telegram to the UART Tx
uint16_t status = EMSuart::transmit(telegram_raw, length);
if (status == EMS_TX_STATUS_ERR) {
LOG_ERROR("Failed to transmit Tx via UART.");
increment_telegram_fail_count(); // another Tx fail
}
}
*/
void TxService::add(const uint8_t operation,
const uint8_t dest,
const uint16_t type_id,
@@ -547,10 +523,8 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt
LOG_DEBUG("New Tx [#%d] telegram, length %d", tx_telegram_id_, message_length);
if (front && (operation != Telegram::Operation::TX_RAW || EMSESP::response_id() == 0)) {
// tx_telegrams_.push_front(qtxt); // add to front of queue
tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false, validate_id); // add to front of queue
} else {
// tx_telegrams_.push_back(qtxt); // add to back of queue
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false, validate_id); // add to back of queue
}
if (validate_id != 0) {

View File

@@ -285,7 +285,8 @@ class RxService : public EMSbus {
const std::shared_ptr<const Telegram> telegram_;
~QueuedRxTelegram() = default;
QueuedRxTelegram(uint16_t id, std::shared_ptr<Telegram> && telegram)
// removed && from telegram in 3.7.0-dev.43
QueuedRxTelegram(uint16_t id, std::shared_ptr<Telegram> telegram)
: id_(id)
, telegram_(std::move(telegram)) {
}
@@ -414,7 +415,8 @@ class TxService : public EMSbus {
const uint16_t validateid_;
~QueuedTxTelegram() = default;
QueuedTxTelegram(uint16_t id, std::shared_ptr<Telegram> && telegram, bool retry, uint16_t validateid)
// replaced && im std::shared_ptr<Telegram> telegram in 3.7.0-dev.43
QueuedTxTelegram(uint16_t id, std::shared_ptr<Telegram> telegram, bool retry, uint16_t validateid)
: id_(id)
, telegram_(std::move(telegram))
, retry_(retry)

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.7.0-dev.42"
#define EMSESP_APP_VERSION "3.7.0-dev.43"

View File

@@ -255,7 +255,7 @@ bool WebStatusService::exportData(JsonObject root, std::string & type) {
} else if (type == "entities") {
System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root);
} else if (type == "allvalues") {
root.clear(); // don't need the "type" key
root.clear(); // don't need the "type" key added to the output
allvalues(root);
} else {
return false;