refactor out console context menus - #510

This commit is contained in:
proddy
2020-09-23 00:19:51 +02:00
parent 6763bb2832
commit b1f10fa5ee
33 changed files with 295 additions and 489 deletions

View File

@@ -52,7 +52,7 @@ void EMSESPAPIService::emsespAPIService(AsyncWebServerRequest * request) {
String cmd = request->getParam(F_(cmd))->value(); String cmd = request->getParam(F_(cmd))->value();
// look up command in our list // look up command in our list
if (!Command::find(device_type, cmd.c_str())) { if (!Command::find_command(device_type, cmd.c_str())) {
request->send(400, "text/plain", F("Invalid cmd")); request->send(400, "text/plain", F("Invalid cmd"));
return; return;
} }

View File

@@ -77,7 +77,7 @@ void Command::add_with_json(const uint8_t device_type, const __FlashStringHelper
} }
// see if a command exists for that device type // see if a command exists for that device type
bool Command::find(const uint8_t device_type, const char * cmd) { bool Command::find_command(const uint8_t device_type, const char * cmd) {
for (const auto & cf : cmdfunctions_) { for (const auto & cf : cmdfunctions_) {
if (strcmp(cmd, uuid::read_flash_string(cf.cmd_).c_str()) == 0) { if (strcmp(cmd, uuid::read_flash_string(cf.cmd_).c_str()) == 0) {
return true; return true;
@@ -88,6 +88,10 @@ bool Command::find(const uint8_t device_type, const char * cmd) {
// output list of all commands to console for a specific DeviceType // output list of all commands to console for a specific DeviceType
void Command::show(uuid::console::Shell & shell, uint8_t device_type) { void Command::show(uuid::console::Shell & shell, uint8_t device_type) {
if (commands().empty()) {
shell.println(F("No commands"));
}
for (const auto & cf : Command::commands()) { for (const auto & cf : Command::commands()) {
if (cf.device_type_ == device_type) { if (cf.device_type_ == device_type) {
shell.printf("%s ", uuid::read_flash_string(cf.cmd_).c_str()); shell.printf("%s ", uuid::read_flash_string(cf.cmd_).c_str());
@@ -96,128 +100,71 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type) {
shell.println(); shell.println();
} }
// determines the device_type from the shell context we're in // see if a device_type is active and has associated commands
uint8_t Command::context_2_device_type(unsigned int context) { bool Command::device_has_commands(const uint8_t device_type) {
// if (context == ShellContext::MAIN) { if (device_type == EMSdevice::DeviceType::UNKNOWN) {
// return EMSdevice::DeviceType::SERVICEKEY; return false;
// }
if (context == ShellContext::BOILER) {
return EMSdevice::DeviceType::BOILER;
}
if (context == ShellContext::MIXING) {
return EMSdevice::DeviceType::MIXING;
}
if (context == ShellContext::SOLAR) {
return EMSdevice::DeviceType::SOLAR;
}
if (context == ShellContext::SYSTEM) {
return EMSdevice::DeviceType::SERVICEKEY;
}
if (context == ShellContext::THERMOSTAT) {
return EMSdevice::DeviceType::THERMOSTAT;
}
if (context == ShellContext::SENSOR) {
return EMSdevice::DeviceType::SENSOR;
} }
return EMSdevice::DeviceType::UNKNOWN; // unknown type if (device_type == EMSdevice::DeviceType::SYSTEM) {
return true; // we always have System
} }
// show command per current context if (device_type == EMSdevice::DeviceType::SENSOR) {
void Command::show(uuid::console::Shell & shell) { return true; // we always have Sensor, but should check if there are actual sensors attached!
show(shell, context_2_device_type(shell.context())); }
for (const auto & emsdevice : EMSESP::emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == device_type)) {
// device found, now see if it has any commands
for (const auto & cf : Command::commands()) {
if (cf.device_type_ == device_type) {
return true;
}
}
}
}
return false;
}
void Command::show_devices(uuid::console::Shell & shell) {
shell.printf("%s ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SYSTEM).c_str());
if (EMSESP::have_sensors()) {
shell.printf("%s ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SENSOR).c_str());
}
for (const auto & device_class : EMSFactory::device_handlers()) {
for (const auto & emsdevice : EMSESP::emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
shell.printf("%s ", EMSdevice::device_type_2_device_name(device_class.first).c_str());
}
}
}
shell.println();
} }
// output list of all commands to console // output list of all commands to console
void Command::show_all(uuid::console::Shell & shell) { void Command::show_all(uuid::console::Shell & shell) {
shell.println(F("Available commands per device: "));
// show system first // show system first
shell.printf("%s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SERVICEKEY).c_str()); shell.printf(" %s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SYSTEM).c_str());
show(shell, EMSdevice::DeviceType::SERVICEKEY); show(shell, EMSdevice::DeviceType::SYSTEM);
// show sensor
if (EMSESP::have_sensors()) {
shell.printf(" %s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SENSOR).c_str());
show(shell, EMSdevice::DeviceType::SENSOR);
}
// do this in the order of factory classes to keep a consistent order when displaying // do this in the order of factory classes to keep a consistent order when displaying
for (const auto & device_class : EMSFactory::device_handlers()) { for (const auto & device_class : EMSFactory::device_handlers()) {
for (const auto & emsdevice : EMSESP::emsdevices) { if (Command::device_has_commands(device_class.first)) {
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
shell.printf(" %s: ", EMSdevice::device_type_2_device_name(device_class.first).c_str()); shell.printf(" %s: ", EMSdevice::device_type_2_device_name(device_class.first).c_str());
show(shell, device_class.first); show(shell, device_class.first);
} }
} }
} }
}
// Add the console 'call' command to the given context
void Command::add_context_commands(unsigned int context) {
// if we're adding commands for a thermostat or mixing, then include an additional optional paramter called heating circuit
flash_string_vector params;
if ((context == ShellContext::THERMOSTAT) || (context == ShellContext::MIXING)) {
params = flash_string_vector{F_(cmd_optional), F_(data_optional), F_(hc_optional)};
} else if ((context == ShellContext::MAIN) || (context == ShellContext::SYSTEM)) {
params = flash_string_vector{F_(cmd_optional), F_(data_optional), F_(n_optional)};
} else {
params = flash_string_vector{F_(cmd_optional), F_(data_optional)};
}
EMSESPShell::commands->add_command(
context,
CommandFlags::ADMIN,
flash_string_vector{F_(call)},
params,
[&](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.empty()) {
// list options
shell.print("Available commands: ");
show(shell);
shell.println();
return;
}
// determine the device_type from the shell context
uint8_t device_type = context_2_device_type(shell.context());
// validate the command
const char * cmd = arguments[0].c_str();
if (!find(device_type, cmd)) {
shell.print(F("Unknown command. Available commands are: "));
show(shell);
shell.println();
return;
}
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
JsonObject output = doc.to<JsonObject>();
bool ok = false;
if (arguments.size() == 1) {
// no value specified, just the cmd
ok = Command::call(device_type, cmd, nullptr, -1, output);
} else if (arguments.size() == 2) {
// has a value but no id
ok = Command::call(device_type, cmd, arguments.back().c_str(), -1, output);
} else {
// use value, which could be an id or hc
ok = Command::call(device_type, cmd, arguments[1].c_str(), atoi(arguments[2].c_str()), output);
}
if (ok) {
shell.print(F("output: "));
serializeJson(doc, shell);
shell.println();
shell.println();
}
},
[&](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) -> std::vector<std::string> {
if (arguments.size() > 0) {
return {};
}
std::vector<std::string> commands;
uint8_t device_type = context_2_device_type(shell.context());
for (const auto & cf : Command::commands()) {
if (cf.device_type_ == device_type) {
commands.emplace_back(uuid::read_flash_string(cf.cmd_));
}
}
return commands;
});
}
} // namespace emsesp } // namespace emsesp

View File

@@ -61,17 +61,15 @@ class Command {
static void add(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, cmdfunction_p cb); static void add(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, cmdfunction_p cb);
static void add_with_json(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_json_p cb); static void add_with_json(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_json_p cb);
static void show_all(uuid::console::Shell & shell); static void show_all(uuid::console::Shell & shell);
static void show(uuid::console::Shell & shell); static bool find_command(const uint8_t device_type, const char * cmd);
static void add_context_commands(unsigned int context); static void show(uuid::console::Shell & shell, uint8_t device_type);
static bool find(const uint8_t device_type, const char * cmd); static void show_devices(uuid::console::Shell & shell);
static bool device_has_commands(const uint8_t device_type);
static std::vector<CmdFunction> cmdfunctions_; // list of commands static std::vector<CmdFunction> cmdfunctions_; // list of commands
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
static void show(uuid::console::Shell & shell, uint8_t device_type);
static uint8_t context_2_device_type(unsigned int context);
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -118,6 +118,15 @@ void EMSESPShell::add_console_commands() {
EMSESP::fetch_device_values(); EMSESP::fetch_device_values();
}); });
commands->add_command(ShellContext::MAIN,
CommandFlags::ADMIN,
flash_string_vector{F_(publish)},
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
shell.printfln(F("Publishing all data to MQTT"));
EMSESP::publish_all();
});
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(show)}, flash_string_vector{F_(show)},
@@ -247,6 +256,10 @@ void EMSESPShell::add_console_commands() {
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) {
shell.printfln(F_(tx_mode_fmt), settings.tx_mode); shell.printfln(F_(tx_mode_fmt), settings.tx_mode);
shell.printfln(F_(bus_id_fmt), settings.ems_bus_id); shell.printfln(F_(bus_id_fmt), settings.ems_bus_id);
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));
}); });
}); });
@@ -261,6 +274,163 @@ void EMSESPShell::add_console_commands() {
EMSESP::send_read_request(type_id, device_id); EMSESP::send_read_request(type_id, device_id);
}); });
commands->add_command(ShellContext::MAIN,
CommandFlags::ADMIN,
flash_string_vector{F_(set), F_(master), F_(thermostat)},
flash_string_vector{F_(deviceid_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) {
uint8_t 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");
});
commands->add_command(ShellContext::MAIN,
CommandFlags::ADMIN,
flash_string_vector{F_(send), F_(telegram)},
flash_string_vector{F_(data_mandatory)},
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
EMSESP::send_raw_telegram(arguments.front().c_str());
});
commands->add_command(ShellContext::MAIN,
CommandFlags::USER,
flash_string_vector{F_(watch)},
flash_string_vector{F_(watch_format_optional), F_(watchid_optional)},
[](Shell & shell, const std::vector<std::string> & arguments) {
uint16_t watch_id = WATCH_ID_NONE;
if (!arguments.empty()) {
// get raw/pretty
if (arguments[0] == read_flash_string(F_(raw))) {
emsesp::EMSESP::watch(EMSESP::WATCH_RAW); // raw
} else if (arguments[0] == read_flash_string(F_(on))) {
emsesp::EMSESP::watch(EMSESP::WATCH_ON); // on
} else if (arguments[0] == read_flash_string(F_(off))) {
emsesp::EMSESP::watch(EMSESP::WATCH_OFF); // off
} else if (emsesp::EMSESP::watch() == EMSESP::WATCH_OFF) {
shell.printfln(F_(invalid_watch));
return;
} else {
watch_id = Helpers::hextoint(arguments[0].c_str());
}
if (arguments.size() == 2) {
// get the watch_id if its set
watch_id = Helpers::hextoint(arguments[1].c_str());
}
emsesp::EMSESP::watch_id(watch_id);
}
uint8_t watch = emsesp::EMSESP::watch();
if (watch == EMSESP::WATCH_OFF) {
shell.printfln(F("Watching telegrams is off"));
return;
}
// if logging is off, the watch won't show anything, show force it back to NOTICE
if (!shell.logger().enabled(Level::NOTICE)) {
shell.log_level(Level::NOTICE);
}
if (watch == EMSESP::WATCH_ON) {
shell.printfln(F("Watching incoming telegrams, displayed in decoded format"));
} else {
shell.printfln(F("Watching incoming telegrams, displayed as raw bytes")); // WATCH_RAW
}
watch_id = emsesp::EMSESP::watch_id();
if (watch_id > 0x80) {
shell.printfln(F("Filtering only telegrams that match a telegram type of 0x%02X"), watch_id);
} else if (watch_id != WATCH_ID_NONE) {
shell.printfln(F("Filtering only telegrams that match a device ID or telegram type of 0x%02X"), watch_id);
}
});
commands->add_command(
ShellContext::MAIN,
CommandFlags::ADMIN,
flash_string_vector{F_(call)},
flash_string_vector{F_(device_type_optional), F_(cmd_optional), F_(data_optional), F_(n_optional)},
[&](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.empty()) {
Command::show_all(shell); // list options
return;
}
// validate the device_type
uint8_t device_type = EMSdevice::device_name_2_device_type(arguments[0].c_str());
if (!Command::device_has_commands(device_type)) {
shell.print(F("Invalid device. Available devices are: "));
Command::show_devices(shell);
return;
}
// validate the command
const char * cmd = arguments[1].c_str();
if (!Command::find_command(device_type, cmd)) {
shell.print(F("Unknown command. Available commands are: "));
Command::show(shell, device_type);
return;
}
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_LARGE);
JsonObject output = doc.to<JsonObject>();
bool ok = false;
if (arguments.size() == 2) {
// no value specified, just the cmd
ok = Command::call(device_type, cmd, nullptr, -1, output);
} else if (arguments.size() == 3) {
// has a value but no id
ok = Command::call(device_type, cmd, arguments.back().c_str(), -1, output);
} else {
// use value, which could be an id or hc
ok = Command::call(device_type, cmd, arguments[2].c_str(), atoi(arguments[3].c_str()), output);
}
if (ok) {
shell.print(F("output: "));
serializeJson(doc, shell);
shell.println();
shell.println();
}
},
[&](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) -> std::vector<std::string> {
if (arguments.size() == 0) {
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::SENSOR));
for (const auto & device_class : EMSFactory::device_handlers()) {
if (Command::device_has_commands(device_class.first)) {
devices_list.emplace_back(EMSdevice::device_type_2_device_name(device_class.first));
}
}
return devices_list;
} else if (arguments.size() == 1) {
std::vector<std::string> command_list;
uint8_t device_type = EMSdevice::device_name_2_device_type(arguments[0].c_str());
if (!Command::device_has_commands(device_type)) {
for (const auto & cf : Command::commands()) {
if (cf.device_type_ == device_type) {
command_list.emplace_back(uuid::read_flash_string(cf.cmd_));
}
}
return command_list;
}
}
return {};
});
/* /*
* add all the submenu contexts... * add all the submenu contexts...
*/ */
@@ -273,10 +443,6 @@ void EMSESPShell::add_console_commands() {
System::console_commands(shell, ShellContext::SYSTEM); System::console_commands(shell, ShellContext::SYSTEM);
}); });
// add all the context menus for the connected devices
// this assumes they devices have been detected and pre-registered
EMSESP::add_context_menus();
Console::load_standard_commands(ShellContext::MAIN); Console::load_standard_commands(ShellContext::MAIN);
console_commands_loaded_ = true; console_commands_loaded_ = true;
@@ -400,76 +566,6 @@ void Console::load_standard_commands(unsigned int context) {
}); });
} }
}); });
EMSESPShell::commands->add_command(context,
CommandFlags::ADMIN,
flash_string_vector{F_(send), F_(telegram)},
flash_string_vector{F_(data_mandatory)},
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
EMSESP::send_raw_telegram(arguments.front().c_str());
});
EMSESPShell::commands->add_command(context,
CommandFlags::USER,
flash_string_vector{F_(watch)},
flash_string_vector{F_(watch_format_optional), F_(watchid_optional)},
[](Shell & shell, const std::vector<std::string> & arguments) {
uint16_t watch_id = WATCH_ID_NONE;
if (!arguments.empty()) {
// get raw/pretty
if (arguments[0] == read_flash_string(F_(raw))) {
emsesp::EMSESP::watch(EMSESP::WATCH_RAW); // raw
} else if (arguments[0] == read_flash_string(F_(on))) {
emsesp::EMSESP::watch(EMSESP::WATCH_ON); // on
} else if (arguments[0] == read_flash_string(F_(off))) {
emsesp::EMSESP::watch(EMSESP::WATCH_OFF); // off
} else if (emsesp::EMSESP::watch() == EMSESP::WATCH_OFF) {
shell.printfln(F_(invalid_watch));
return;
} else {
watch_id = Helpers::hextoint(arguments[0].c_str());
}
if (arguments.size() == 2) {
// get the watch_id if its set
watch_id = Helpers::hextoint(arguments[1].c_str());
}
emsesp::EMSESP::watch_id(watch_id);
}
uint8_t watch = emsesp::EMSESP::watch();
if (watch == EMSESP::WATCH_OFF) {
shell.printfln(F("Watching telegrams is off"));
return;
}
// if logging is off, the watch won't show anything, show force it back to NOTICE
if (!shell.logger().enabled(Level::NOTICE)) {
shell.log_level(Level::NOTICE);
}
if (watch == EMSESP::WATCH_ON) {
shell.printfln(F("Watching incoming telegrams, displayed in decoded format"));
} else {
shell.printfln(F("Watching incoming telegrams, displayed as raw bytes")); // WATCH_RAW
}
watch_id = emsesp::EMSESP::watch_id();
if (watch_id > 0x80) {
shell.printfln(F("Filtering only telegrams that match a telegram type of 0x%02X"), watch_id);
} else if (watch_id != WATCH_ID_NONE) {
shell.printfln(F("Filtering only telegrams that match a device ID or telegram type of 0x%02X"), watch_id);
}
});
// load the commands (console & mqtt topics) for this specific context
// unless it's main (the root)
if (context != ShellContext::MAIN) {
Command::add_context_commands(context);
}
} }
// prompt, change per context // prompt, change per context
@@ -478,18 +574,9 @@ std::string EMSESPShell::context_text() {
case ShellContext::MAIN: case ShellContext::MAIN:
return std::string{'/'}; return std::string{'/'};
case ShellContext::BOILER:
return std::string{"/boiler"};
case ShellContext::SYSTEM: case ShellContext::SYSTEM:
return std::string{"/system"}; return std::string{"/system"};
case ShellContext::THERMOSTAT:
return std::string{"/thermostat"};
case ShellContext::SENSOR:
return std::string{"/sensor"};
default: default:
return std::string{}; return std::string{};
} }

View File

@@ -76,11 +76,6 @@ enum ShellContext : uint8_t {
MAIN = 0, MAIN = 0,
SYSTEM, SYSTEM,
BOILER,
THERMOSTAT,
SOLAR,
MIXING,
SENSOR
}; };

View File

@@ -84,16 +84,6 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
}); });
} }
// add submenu context
void Boiler::add_context_menu() {
EMSESPShell::commands->add_command(ShellContext::MAIN,
CommandFlags::USER,
flash_string_vector{F_(boiler)},
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
Boiler::console_commands(shell, ShellContext::BOILER);
});
}
// create the config topic for Home Assistant MQTT Discovery // create the config topic for Home Assistant MQTT Discovery
// homeassistant/sensor/ems-esp/boiler // homeassistant/sensor/ems-esp/boiler
// state is /state // state is /state
@@ -1070,25 +1060,4 @@ bool Boiler::set_warmwater_circulation(const char * value, const int8_t id) {
return true; return true;
} }
// add console commands
void Boiler::console_commands(Shell & shell, unsigned int context) {
EMSESPShell::commands->add_command(ShellContext::BOILER,
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::set_read_id(type_id);
EMSESP::send_read_request(type_id, device_id());
});
EMSESPShell::commands->add_command(ShellContext::BOILER,
CommandFlags::USER,
flash_string_vector{F_(show)},
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { show_values(shell); });
// enter the context
Console::enter_custom_context(shell, context);
}
} // namespace emsesp } // namespace emsesp

View File

@@ -42,12 +42,10 @@ class Boiler : public EMSdevice {
virtual void publish_values(); virtual void publish_values();
virtual void device_info_web(JsonArray & root); virtual void device_info_web(JsonArray & root);
virtual bool updated_values(); virtual bool updated_values();
virtual void add_context_menu();
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void console_commands(Shell & shell, unsigned int context);
void register_mqtt_ha_config(); void register_mqtt_ha_config();
void check_active(); void check_active();
bool export_values(JsonObject & doc); bool export_values(JsonObject & doc);

View File

@@ -31,9 +31,6 @@ Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, con
void Connect::device_info_web(JsonArray & root) { void Connect::device_info_web(JsonArray & root) {
} }
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
@@ -48,8 +45,4 @@ bool Connect::updated_values() {
return false; return false;
} }
// add console commands
void Connect::console_commands() {
}
} // namespace emsesp } // namespace emsesp

View File

@@ -39,12 +39,9 @@ class Connect : public EMSdevice {
virtual void publish_values(); virtual void publish_values();
virtual void device_info_web(JsonArray & root); virtual void device_info_web(JsonArray & root);
virtual bool updated_values(); virtual bool updated_values();
virtual void add_context_menu();
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void console_commands();
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -28,9 +28,6 @@ Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_i
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
} }
void Controller::add_context_menu() {
}
void Controller::device_info_web(JsonArray & root) { void Controller::device_info_web(JsonArray & root) {
} }
@@ -48,8 +45,4 @@ bool Controller::updated_values() {
return false; return false;
} }
// add console commands
void Controller::console_commands() {
}
} // namespace emsesp } // namespace emsesp

View File

@@ -39,12 +39,10 @@ class Controller : public EMSdevice {
virtual void publish_values(); virtual void publish_values();
virtual void device_info_web(JsonArray & root); virtual void device_info_web(JsonArray & root);
virtual bool updated_values(); virtual bool updated_values();
virtual void add_context_menu();
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void console_commands();
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -28,9 +28,6 @@ Gateway::Gateway(uint8_t device_type, uint8_t device_id, uint8_t product_id, con
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
} }
void Gateway::add_context_menu() {
}
void Gateway::device_info_web(JsonArray & root) { void Gateway::device_info_web(JsonArray & root) {
} }
@@ -48,8 +45,4 @@ bool Gateway::updated_values() {
return false; return false;
} }
// add console commands
void Gateway::console_commands() {
}
} // namespace emsesp } // namespace emsesp

View File

@@ -39,12 +39,10 @@ class Gateway : public EMSdevice {
virtual void publish_values(); virtual void publish_values();
virtual void device_info_web(JsonArray & root); virtual void device_info_web(JsonArray & root);
virtual bool updated_values(); virtual bool updated_values();
virtual void add_context_menu();
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void console_commands();
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -33,10 +33,6 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c
register_telegram_type(0x042B, F("HP2"), true, [&](std::shared_ptr<const Telegram> t) { process_HPMonitor2(t); }); register_telegram_type(0x042B, F("HP2"), true, [&](std::shared_ptr<const Telegram> t) { process_HPMonitor2(t); });
} }
// context submenu
void Heatpump::add_context_menu() {
}
void Heatpump::device_info_web(JsonArray & root) { void Heatpump::device_info_web(JsonArray & root) {
} }
@@ -54,10 +50,6 @@ bool Heatpump::updated_values() {
return false; return false;
} }
// add console commands
void Heatpump::console_commands() {
}
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"

View File

@@ -39,13 +39,10 @@ class Heatpump : public EMSdevice {
virtual void publish_values(); virtual void publish_values();
virtual void device_info_web(JsonArray & root); virtual void device_info_web(JsonArray & root);
virtual bool updated_values(); virtual bool updated_values();
virtual void add_context_menu();
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void console_commands();
void process_HPMonitor1(std::shared_ptr<const Telegram> telegram); void process_HPMonitor1(std::shared_ptr<const Telegram> telegram);
void process_HPMonitor2(std::shared_ptr<const Telegram> telegram); void process_HPMonitor2(std::shared_ptr<const Telegram> telegram);
}; };

View File

@@ -60,19 +60,6 @@ Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
}); });
} }
// add context submenu
void Mixing::add_context_menu() {
// TODO support for multiple mixing units from a single menu, similar to set master with thermostat
/*
EMSESPShell::commands->add_command(ShellContext::MAIN,
CommandFlags::USER,
flash_string_vector{F_(mixing)},
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
Mixing::console_commands(shell, ShellContext::MIXING);
});
*/
}
// output json to web UI // output json to web UI
void Mixing::device_info_web(JsonArray & root) { void Mixing::device_info_web(JsonArray & root) {
if (type_ == Type::NONE) { if (type_ == Type::NONE) {
@@ -102,27 +89,6 @@ bool Mixing::updated_values() {
return false; return false;
} }
// add console commands
void Mixing::console_commands(Shell & shell, unsigned int context) {
EMSESPShell::commands->add_command(ShellContext::MIXING,
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::set_read_id(type_id);
EMSESP::send_read_request(type_id, device_id());
});
EMSESPShell::commands->add_command(ShellContext::MIXING,
CommandFlags::USER,
flash_string_vector{F_(show)},
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { show_values(shell); });
// enter the context
Console::enter_custom_context(shell, context);
}
// display all values into the shell console // display all values into the shell console
void Mixing::show_values(uuid::console::Shell & shell) { void Mixing::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

View File

@@ -40,12 +40,10 @@ class Mixing : public EMSdevice {
virtual void publish_values(); virtual void publish_values();
virtual void device_info_web(JsonArray & root); virtual void device_info_web(JsonArray & root);
virtual bool updated_values(); virtual bool updated_values();
virtual void add_context_menu();
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void console_commands(Shell & shell, unsigned int context);
bool export_values(JsonObject & doc); bool export_values(JsonObject & doc);
bool command_info(const char * value, const int8_t id, JsonObject & output); bool command_info(const char * value, const int8_t id, JsonObject & output);

View File

@@ -58,19 +58,6 @@ bool Solar::command_info(const char * value, const int8_t id, JsonObject & outpu
return (export_values(output)); return (export_values(output));
} }
// context submenu
void Solar::add_context_menu() {
// TODO support for multiple solar units from a single menu, similar to set master with thermostat
/*
EMSESPShell::commands->add_command(ShellContext::MAIN,
CommandFlags::USER,
flash_string_vector{F_(solar)},
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
Solar::console_commands(shell, ShellContext::SOLAR);
});
*/
}
// print to web // print to web
void Solar::device_info_web(JsonArray & root) { void Solar::device_info_web(JsonArray & root) {
render_value_json(root, "", F("Collector temperature (TS1)"), collectorTemp_, F_(degrees), 10); render_value_json(root, "", F("Collector temperature (TS1)"), collectorTemp_, F_(degrees), 10);
@@ -206,27 +193,6 @@ bool Solar::updated_values() {
return false; return false;
} }
// add console commands
void Solar::console_commands(Shell & shell, unsigned int context) {
EMSESPShell::commands->add_command(ShellContext::SOLAR,
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::set_read_id(type_id);
EMSESP::send_read_request(type_id, device_id());
});
EMSESPShell::commands->add_command(ShellContext::SOLAR,
CommandFlags::USER,
flash_string_vector{F_(show)},
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { show_values(shell); });
// enter the context
Console::enter_custom_context(shell, context);
}
// SM10Monitor - type 0x97 // SM10Monitor - type 0x97
void Solar::process_SM10Monitor(std::shared_ptr<const Telegram> telegram) { void Solar::process_SM10Monitor(std::shared_ptr<const Telegram> telegram) {
changed_ |= telegram->read_value(collectorTemp_, 2); // collector temp from SM10, is *10 changed_ |= telegram->read_value(collectorTemp_, 2); // collector temp from SM10, is *10

View File

@@ -40,12 +40,10 @@ class Solar : public EMSdevice {
virtual void publish_values(); virtual void publish_values();
virtual void device_info_web(JsonArray & root); virtual void device_info_web(JsonArray & root);
virtual bool updated_values(); virtual bool updated_values();
virtual void add_context_menu();
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void console_commands(Shell & shell, unsigned int context);
bool export_values(JsonObject & doc); bool export_values(JsonObject & doc);
bool command_info(const char * value, const int8_t id, JsonObject & output); bool command_info(const char * value, const int8_t id, JsonObject & output);

View File

@@ -28,9 +28,6 @@ Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) { : EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
} }
void Switch::add_context_menu() {
}
void Switch::device_info_web(JsonArray & root) { void Switch::device_info_web(JsonArray & root) {
} }
@@ -48,8 +45,4 @@ bool Switch::updated_values() {
return false; return false;
} }
// add console commands
void Switch::console_commands() {
}
} // namespace emsesp } // namespace emsesp

View File

@@ -39,12 +39,10 @@ class Switch : public EMSdevice {
virtual void publish_values(); virtual void publish_values();
virtual void device_info_web(JsonArray & root); virtual void device_info_web(JsonArray & root);
virtual bool updated_values(); virtual bool updated_values();
virtual void add_context_menu();
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void console_commands();
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -219,21 +219,6 @@ void Thermostat::device_info_web(JsonArray & root) {
} }
} }
// context menu "thermostat"
void Thermostat::add_context_menu() {
// only add it once, to prevent conflicts when there are multiple thermostats
if (this->device_id() != EMSESP::actual_master_thermostat()) {
return;
}
EMSESPShell::commands->add_command(ShellContext::MAIN,
CommandFlags::USER,
flash_string_vector{F_(thermostat)},
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
Thermostat::console_commands(shell, ShellContext::THERMOSTAT);
});
}
// 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() {
@@ -1167,58 +1152,6 @@ 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_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) {
uint8_t 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::set_read_id(type_id);
EMSESP::send_read_request(type_id, this->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
bool Thermostat::set_minexttemp(const char * value, const int8_t id) { bool Thermostat::set_minexttemp(const char * value, const int8_t id) {
int mt = 0; int mt = 0;

View File

@@ -101,12 +101,10 @@ class Thermostat : public EMSdevice {
virtual void publish_values(); virtual void publish_values();
virtual void device_info_web(JsonArray & root); virtual void device_info_web(JsonArray & root);
virtual bool updated_values(); virtual bool updated_values();
virtual void add_context_menu();
private: private:
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void console_commands(Shell & shell, unsigned int context);
void add_commands(); void add_commands();
bool export_values(uint8_t mqtt_format, JsonObject & doc); bool export_values(uint8_t mqtt_format, JsonObject & doc);

View File

@@ -55,7 +55,7 @@ std::string EMSdevice::brand_to_string() const {
// returns the name of the MQTT topic to use for a specific device // returns the name of the MQTT topic to use for a specific device
std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) { std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) {
switch (device_type) { switch (device_type) {
case DeviceType::SERVICEKEY: case DeviceType::SYSTEM:
return read_flash_string(F("system")); return read_flash_string(F("system"));
break; break;
@@ -79,6 +79,18 @@ std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) {
return read_flash_string(F("mixing")); return read_flash_string(F("mixing"));
break; break;
case DeviceType::SENSOR:
return read_flash_string(F("sensor"));
break;
case DeviceType::CONTROLLER:
return read_flash_string(F("controller"));
break;
case DeviceType::SWITCH:
return read_flash_string(F("switch"));
break;
default: default:
return std::string{}; return std::string{};
break; break;
@@ -96,7 +108,7 @@ uint8_t EMSdevice::device_name_2_device_type(const char * topic) {
} }
if (strcmp(topic, "system") == 0) { if (strcmp(topic, "system") == 0) {
return DeviceType::SERVICEKEY; return DeviceType::SYSTEM;
} }
if (strcmp(topic, "heatpump") == 0) { if (strcmp(topic, "heatpump") == 0) {

View File

@@ -137,7 +137,6 @@ class EMSdevice {
virtual void show_values(uuid::console::Shell & shell) = 0; virtual void show_values(uuid::console::Shell & shell) = 0;
virtual void publish_values() = 0; virtual void publish_values() = 0;
virtual bool updated_values() = 0; virtual bool updated_values() = 0;
virtual void add_context_menu() = 0;
virtual void device_info_web(JsonArray & root) = 0; virtual void device_info_web(JsonArray & root) = 0;
std::string telegram_type_name(std::shared_ptr<const Telegram> telegram); std::string telegram_type_name(std::shared_ptr<const Telegram> telegram);
@@ -228,7 +227,7 @@ class EMSdevice {
}; };
enum DeviceType : uint8_t { enum DeviceType : uint8_t {
SERVICEKEY = 0, // this is us (EMS-ESP) SYSTEM = 0, // this is us (EMS-ESP)
SENSOR, // for internal dallas sensors SENSOR, // for internal dallas sensors
BOILER, BOILER,
THERMOSTAT, THERMOSTAT,
@@ -279,7 +278,7 @@ class EMSdevice {
private: private:
uint8_t unique_id_; uint8_t unique_id_;
uint8_t device_type_ = DeviceType::SERVICEKEY; uint8_t device_type_ = DeviceType::SYSTEM;
uint8_t device_id_ = 0; uint8_t device_id_ = 0;
uint8_t product_id_ = 0; uint8_t product_id_ = 0;
std::string version_; std::string version_;

View File

@@ -276,7 +276,7 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) {
// show Dallas temperature sensors // show Dallas temperature sensors
void EMSESP::show_sensor_values(uuid::console::Shell & shell) { void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
if (sensor_devices().empty()) { if (!have_sensors()) {
return; return;
} }
@@ -288,6 +288,17 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
shell.println(); shell.println();
} }
// MQTT publish everything, immediately
void EMSESP::publish_all() {
publish_device_values(EMSdevice::DeviceType::BOILER);
publish_device_values(EMSdevice::DeviceType::THERMOSTAT);
publish_device_values(EMSdevice::DeviceType::SOLAR);
publish_device_values(EMSdevice::DeviceType::MIXING);
publish_other_values();
publish_sensor_values(true);
system_.send_heartbeat();
}
void EMSESP::publish_device_values(uint8_t device_type) { void EMSESP::publish_device_values(uint8_t device_type) {
if (Mqtt::connected()) { if (Mqtt::connected()) {
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
@@ -432,7 +443,9 @@ std::string EMSESP::pretty_telegram(std::shared_ptr<const Telegram> telegram) {
* e.g. 08 00 07 00 0B 80 00 00 00 00 00 00 00 00 00 00 00 * e.g. 08 00 07 00 0B 80 00 00 00 00 00 00 00 00 00 00 00
* Junkers has 15 bytes of data * Junkers has 15 bytes of data
* each byte is a bitmask for which devices are active * each byte is a bitmask for which devices are active
* byte 1 = range 0x08 - 0x0F, byte 2=0x10 - 0x17 etc... * byte 1 = 0x08 - 0x0F, byte 2 = 0x10 - 0x17, etc...
* e.g. in example above 1st byte = x0B = b1011 so we have device ids 0x08, 0x09, 0x011
* and 2nd byte = x80 = b1000 b0000 = device id 0x17
*/ */
void EMSESP::process_UBADevices(std::shared_ptr<const Telegram> telegram) { void EMSESP::process_UBADevices(std::shared_ptr<const Telegram> telegram) {
// exit it length is incorrect (must be 13 or 15 bytes long) // exit it length is incorrect (must be 13 or 15 bytes long)
@@ -589,15 +602,6 @@ bool EMSESP::device_exists(const uint8_t device_id) {
return false; // not found return false; // not found
} }
// for each device add its context menu for the console
void EMSESP::add_context_menus() {
for (const auto & emsdevice : emsdevices) {
if (emsdevice) {
emsdevice->add_context_menu();
}
}
}
// for each associated EMS device go and get its system information // for each associated EMS device go and get its system information
void EMSESP::show_devices(uuid::console::Shell & shell) { void EMSESP::show_devices(uuid::console::Shell & shell) {
if (emsdevices.empty()) { if (emsdevices.empty()) {
@@ -609,7 +613,7 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
shell.printfln(F("These EMS devices are currently active:")); shell.printfln(F("These EMS devices are currently active:"));
shell.println(); shell.println();
// for all device objects from emsdevice.h (UNKNOWN, SERVICEKEY, BOILER, THERMOSTAT, MIXING, SOLAR, HEATPUMP, GATEWAY, SWITCH, CONTROLLER, CONNECT) // for all device objects from emsdevice.h (UNKNOWN, SYSTEM, BOILER, THERMOSTAT, MIXING, SOLAR, HEATPUMP, GATEWAY, SWITCH, CONTROLLER, CONNECT)
// so we keep a consistent order // so we keep a consistent order
for (const auto & device_class : EMSFactory::device_handlers()) { for (const auto & device_class : EMSFactory::device_handlers()) {
// shell.printf(F("[factory ID: %d] "), device_class.first); // shell.printf(F("[factory ID: %d] "), device_class.first);

View File

@@ -64,6 +64,7 @@ class EMSESP {
static void publish_device_values(uint8_t device_type); static void publish_device_values(uint8_t device_type);
static void publish_other_values(); static void publish_other_values();
static void publish_sensor_values(const bool force = false); static void publish_sensor_values(const bool force = false);
static void publish_all();
#ifdef EMSESP_STANDALONE #ifdef EMSESP_STANDALONE
static void run_test(uuid::console::Shell & shell, const std::string & command); // only for testing static void run_test(uuid::console::Shell & shell, const std::string & command); // only for testing
@@ -102,8 +103,6 @@ class EMSESP {
static void show_devices(uuid::console::Shell & shell); static void show_devices(uuid::console::Shell & shell);
static void show_ems(uuid::console::Shell & shell); static void show_ems(uuid::console::Shell & shell);
static void add_context_menus();
static void init_tx(); static void init_tx();
static void incoming_telegram(uint8_t * data, const uint8_t length); static void incoming_telegram(uint8_t * data, const uint8_t length);
@@ -112,6 +111,10 @@ class EMSESP {
return sensor_.devices(); return sensor_.devices();
} }
static bool have_sensors() {
return (!(sensor_.devices().empty()));
}
enum Watch : uint8_t { WATCH_OFF, WATCH_ON, WATCH_RAW }; enum Watch : uint8_t { WATCH_OFF, WATCH_ON, WATCH_RAW };
static void watch_id(uint16_t id); static void watch_id(uint16_t id);
static uint16_t watch_id() { static uint16_t watch_id() {

View File

@@ -62,6 +62,7 @@ MAKE_PSTR_WORD(heartbeat)
MAKE_PSTR_WORD(users) MAKE_PSTR_WORD(users)
MAKE_PSTR_WORD(master) MAKE_PSTR_WORD(master)
MAKE_PSTR_WORD(pin) MAKE_PSTR_WORD(pin)
MAKE_PSTR_WORD(publish)
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
MAKE_PSTR_WORD(test) MAKE_PSTR_WORD(test)
@@ -117,6 +118,7 @@ MAKE_PSTR(n_optional, "[n]")
MAKE_PSTR(data_optional, "[data]") MAKE_PSTR(data_optional, "[data]")
MAKE_PSTR(typeid_mandatory, "<type ID>") MAKE_PSTR(typeid_mandatory, "<type ID>")
MAKE_PSTR(deviceid_mandatory, "<device ID>") MAKE_PSTR(deviceid_mandatory, "<device ID>")
MAKE_PSTR(device_type_optional, "[device]")
MAKE_PSTR(invalid_log_level, "Invalid log level") MAKE_PSTR(invalid_log_level, "Invalid log level")
MAKE_PSTR(log_level_fmt, "Log level = %s") MAKE_PSTR(log_level_fmt, "Log level = %s")
MAKE_PSTR(log_level_optional, "[level]") MAKE_PSTR(log_level_optional, "[level]")

View File

@@ -100,9 +100,7 @@ void Mqtt::resubscribe() {
} }
} }
// Main MQTT loop // Main MQTT loop - sends out top item on publish queue
// Checks for connection, establishes a connection if not
// sends out top item on publish queue
void Mqtt::loop() { void Mqtt::loop() {
// exit if MQTT is not enabled or if there is no WIFI // exit if MQTT is not enabled or if there is no WIFI
if (!connected()) { if (!connected()) {
@@ -116,26 +114,32 @@ void Mqtt::loop() {
last_publish_boiler_ = currentMillis; last_publish_boiler_ = currentMillis;
EMSESP::publish_device_values(EMSdevice::DeviceType::BOILER); EMSESP::publish_device_values(EMSdevice::DeviceType::BOILER);
} }
if (publish_time_thermostat_ && (currentMillis - last_publish_thermostat_ > publish_time_thermostat_)) { if (publish_time_thermostat_ && (currentMillis - last_publish_thermostat_ > publish_time_thermostat_)) {
last_publish_thermostat_ = currentMillis; last_publish_thermostat_ = currentMillis;
EMSESP::publish_device_values(EMSdevice::DeviceType::THERMOSTAT); EMSESP::publish_device_values(EMSdevice::DeviceType::THERMOSTAT);
} }
if (publish_time_solar_ && (currentMillis - last_publish_solar_ > publish_time_solar_)) { if (publish_time_solar_ && (currentMillis - last_publish_solar_ > publish_time_solar_)) {
last_publish_solar_ = currentMillis; last_publish_solar_ = currentMillis;
EMSESP::publish_device_values(EMSdevice::DeviceType::SOLAR); EMSESP::publish_device_values(EMSdevice::DeviceType::SOLAR);
} }
if (publish_time_mixing_ && (currentMillis - last_publish_mixing_ > publish_time_mixing_)) { if (publish_time_mixing_ && (currentMillis - last_publish_mixing_ > publish_time_mixing_)) {
last_publish_mixing_ = currentMillis; last_publish_mixing_ = currentMillis;
EMSESP::publish_device_values(EMSdevice::DeviceType::MIXING); EMSESP::publish_device_values(EMSdevice::DeviceType::MIXING);
} }
if (publish_time_other_ && (currentMillis - last_publish_other_ > publish_time_other_)) { if (publish_time_other_ && (currentMillis - last_publish_other_ > publish_time_other_)) {
last_publish_other_ = currentMillis; last_publish_other_ = currentMillis;
EMSESP::publish_other_values(); EMSESP::publish_other_values();
} }
if (currentMillis - last_publish_sensor_ > publish_time_sensor_) { if (currentMillis - last_publish_sensor_ > publish_time_sensor_) {
last_publish_sensor_ = currentMillis; last_publish_sensor_ = currentMillis;
EMSESP::publish_sensor_values(publish_time_sensor_ != 0); EMSESP::publish_sensor_values(publish_time_sensor_ != 0);
} }
// publish top item from MQTT queue to stop flooding // publish top item from MQTT queue to stop flooding
if ((uint32_t)(currentMillis - last_mqtt_poll_) > MQTT_PUBLISH_WAIT) { if ((uint32_t)(currentMillis - last_mqtt_poll_) > MQTT_PUBLISH_WAIT) {
last_mqtt_poll_ = currentMillis; last_mqtt_poll_ = currentMillis;
@@ -316,7 +320,7 @@ void Mqtt::on_publish(uint16_t packetId) {
} }
if (mqtt_message.packet_id_ != packetId) { if (mqtt_message.packet_id_ != packetId) {
LOG_DEBUG(F("Mismatch, expecting PID %d, got %d"), mqtt_message.packet_id_, packetId); LOG_ERROR(F("Mismatch, expecting PID %d, got %d"), mqtt_message.packet_id_, packetId);
mqtt_publish_fails_++; // increment error count mqtt_publish_fails_++; // increment error count
} }
@@ -470,13 +474,14 @@ std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation,
if ((strncmp(topic.c_str(), "homeassistant/", 13) == 0)) { if ((strncmp(topic.c_str(), "homeassistant/", 13) == 0)) {
// leave topic as it is // leave topic as it is
// message = std::make_shared<MqttMessage>(operation, topic, std::move(payload), retain); // message = std::make_shared<MqttMessage>(operation, topic, std::move(payload), retain);
message = std::make_shared<MqttMessage>(operation, topic, payload, retain); message = std::make_shared<MqttMessage>(operation, topic, std::move(payload), retain);
} else { } else {
// prefix the hostname // prefix the hostname
std::string full_topic(50, '\0'); std::string full_topic(50, '\0');
snprintf_P(&full_topic[0], full_topic.capacity() + 1, PSTR("%s/%s"), Mqtt::hostname_.c_str(), topic.c_str()); snprintf_P(&full_topic[0], full_topic.capacity() + 1, PSTR("%s/%s"), Mqtt::hostname_.c_str(), topic.c_str());
message = std::make_shared<MqttMessage>(operation, full_topic, payload, retain); // message = std::make_shared<MqttMessage>(operation, full_topic, std::move(payload), retain);
message = std::make_shared<MqttMessage>(operation, full_topic, std::move(payload), retain);
} }
// if the queue is full, make room but removing the last one // if the queue is full, make room but removing the last one

View File

@@ -55,8 +55,8 @@ struct MqttMessage {
const std::string payload; const std::string payload;
const bool retain; const bool retain;
// MqttMessage(const uint8_t operation, const std::string & topic, const std::string && payload, bool retain) // MqttMessage(const uint8_t operation, const std::string & topic, const std::string & payload, bool retain)
MqttMessage(const uint8_t operation, const std::string & topic, const std::string & payload, bool retain) MqttMessage(const uint8_t operation, const std::string & topic, const std::string && payload, bool retain)
: operation(operation) : operation(operation)
, topic(topic) , topic(topic)
, payload(payload) , payload(payload)

View File

@@ -62,8 +62,6 @@ class Shower {
static constexpr uint32_t SHOWER_COLDSHOT_DURATION = 10; // in seconds. 10 seconds for cold water before turning back hot water static constexpr uint32_t SHOWER_COLDSHOT_DURATION = 10; // in seconds. 10 seconds for cold water before turning back hot water
static constexpr uint32_t SHOWER_MAX_DURATION = 420000; // in ms. 7 minutes, before trigger a shot of cold water static constexpr uint32_t SHOWER_MAX_DURATION = 420000; // in ms. 7 minutes, before trigger a shot of cold water
void console_commands();
void publish_values(); void publish_values();
void shower_alert_start(); void shower_alert_start();
void shower_alert_stop(); void shower_alert_stop();

View File

@@ -157,9 +157,9 @@ void System::start() {
// these commands respond to the topic "system" and take a payload like {cmd:"", data:"", id:""} // these commands respond to the topic "system" and take a payload like {cmd:"", data:"", id:""}
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) {
Command::add(EMSdevice::DeviceType::SERVICEKEY, settings.ems_bus_id, F("pin"), System::command_pin); Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F("pin"), System::command_pin);
Command::add(EMSdevice::DeviceType::SERVICEKEY, settings.ems_bus_id, F("send"), System::command_send); Command::add(EMSdevice::DeviceType::SYSTEM, settings.ems_bus_id, F("send"), System::command_send);
Command::add_with_json(EMSdevice::DeviceType::SERVICEKEY, F("info"), System::command_info); Command::add_with_json(EMSdevice::DeviceType::SYSTEM, F("info"), System::command_info);
}); });
EMSESP::init_tx(); // start UART EMSESP::init_tx(); // start UART
@@ -523,7 +523,7 @@ void System::console_commands(Shell & shell, unsigned int context) {
EMSESPShell::commands->add_command(ShellContext::SYSTEM, EMSESPShell::commands->add_command(ShellContext::SYSTEM,
CommandFlags::USER, CommandFlags::USER,
flash_string_vector{F_(show)}, flash_string_vector{F_(show), F_(system)},
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { [=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
show_system(shell); show_system(shell);
shell.println(); shell.println();

View File

@@ -206,8 +206,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
0x03, 0x25, 0x03, 0x03, 0x01, 0x03, 0x25, 0x00, 0xC8, 0x00, 0x00, 0x11, 0x01, 0x03}); 0x03, 0x25, 0x03, 0x03, 0x01, 0x03, 0x25, 0x00, 0xC8, 0x00, 0x00, 0x11, 0x01, 0x03});
shell.invoke_command("show"); shell.invoke_command("show");
// shell.invoke_command("system");
// shell.invoke_command("show mqtt");
} }
if (command == "thermostat") { if (command == "thermostat") {
@@ -409,11 +407,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
shell.loop_all(); shell.loop_all();
EMSESP::show_device_values(shell); EMSESP::show_device_values(shell);
shell.invoke_command("thermostat"); shell.invoke_command("call thermostat mode auto");
shell.loop_all();
// shell.invoke_command("set temp 20");
shell.invoke_command("set mode auto");
shell.loop_all(); shell.loop_all();
EMSESP::show_ems(shell); EMSESP::show_ems(shell);
@@ -576,12 +570,9 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
return StateUpdateResult::CHANGED; return StateUpdateResult::CHANGED;
}); });
EMSESP::add_context_menus(); // need to add this as it happens later in the code
shell.invoke_command("su"); shell.invoke_command("su");
shell.invoke_command("system");
shell.invoke_command("call"); shell.invoke_command("call");
shell.invoke_command("call info"); shell.invoke_command("call system info");
shell.invoke_command("exit");
char system_topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char system_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
strcpy(system_topic, "ems-esp/system"); strcpy(system_topic, "ems-esp/system");
@@ -595,24 +586,14 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
uart_telegram({0x90, 0x00, 0xFF, 0x00, 0x00, 0x70, 0x00, 0xCF, 0x22, 0x2F, 0x10, 0x00, 0x2E, 0x24, uart_telegram({0x90, 0x00, 0xFF, 0x00, 0x00, 0x70, 0x00, 0xCF, 0x22, 0x2F, 0x10, 0x00, 0x2E, 0x24,
0x03, 0x25, 0x03, 0x03, 0x01, 0x03, 0x25, 0x00, 0xC8, 0x00, 0x00, 0x11, 0x01, 0x03}); // HC2 0x03, 0x25, 0x03, 0x03, 0x01, 0x03, 0x25, 0x00, 0xC8, 0x00, 0x00, 0x11, 0x01, 0x03}); // HC2
uart_telegram({0x90, 0x00, 0xFF, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); // HC3 uart_telegram({0x90, 0x00, 0xFF, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); // HC3
EMSESP::add_context_menus(); // need to add this as it happens later in the code
shell.invoke_command("thermostat");
shell.invoke_command("show");
shell.invoke_command("call");
shell.invoke_command("call info");
shell.invoke_command("exit");
shell.invoke_command("show mqtt");
} }
if (command == "pin") { if (command == "pin") {
shell.printfln(F("Testing pin...")); shell.printfln(F("Testing pin..."));
EMSESP::add_context_menus(); // need to add this as it happens later in the code
shell.invoke_command("su"); shell.invoke_command("su");
shell.invoke_command("system"); shell.invoke_command("call system pin");
shell.invoke_command("help"); shell.invoke_command("call system pin 1 true");
shell.invoke_command("pin");
shell.invoke_command("pin 1 true");
} }
if (command == "mqtt") { if (command == "mqtt") {
@@ -678,14 +659,12 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
// 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("su");
shell.invoke_command("thermostat");
shell.invoke_command("help"); shell.invoke_command("help");
shell.invoke_command("call"); shell.invoke_command("call");
shell.invoke_command("call wwmode"); shell.invoke_command("call thermostat wwmode");
shell.invoke_command("call mode auto 2"); shell.invoke_command("call thermostat mode auto 2");
shell.invoke_command("call temp 22.56"); shell.invoke_command("call thermostat temp 22.56");
Mqtt::resubscribe(); Mqtt::resubscribe();
Mqtt::show_mqtt(shell); // show queue Mqtt::show_mqtt(shell); // show queue
@@ -745,7 +724,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
// check for error "[emsesp] No telegram type handler found for ID 0x255 (src 0x20, dest 0x00)" // check for error "[emsesp] No telegram type handler found for ID 0x255 (src 0x20, dest 0x00)"
rx_telegram({0xA0, 0x00, 0xFF, 0x00, 0x01, 0x55, 0x00, 0x1A}); rx_telegram({0xA0, 0x00, 0xFF, 0x00, 0x01, 0x55, 0x00, 0x1A});
EMSESP::add_context_menus(); // need to add this as it happens later in the code
} }
// finally dump to console // finally dump to console