From 0380fe1fffbb3bc320dff9511716f7260bfb4ea6 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 4 Mar 2023 14:10:32 +0100 Subject: [PATCH] mqtt/commands for scheduler --- interface/src/i18n/de/index.ts | 36 ++--- interface/src/i18n/en/index.ts | 2 +- interface/src/i18n/fr/index.ts | 2 +- interface/src/i18n/nl/index.ts | 2 +- interface/src/i18n/no/index.ts | 2 +- interface/src/i18n/pl/index.ts | 2 +- interface/src/i18n/sv/index.ts | 2 +- interface/src/i18n/tr/index.ts | 2 +- interface/src/project/SettingsScheduler.tsx | 2 +- src/analogsensor.cpp | 3 +- src/command.cpp | 46 ++++++- src/emsdevice.cpp | 13 +- src/emsdevice.h | 1 + src/emsesp.cpp | 4 +- src/locale_common.h | 1 + src/locale_translations.h | 1 + src/mqtt.cpp | 1 + src/web/WebSchedulerService.cpp | 138 ++++++++++++++++++++ src/web/WebSchedulerService.h | 4 + 19 files changed, 225 insertions(+), 39 deletions(-) diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index cf62347e8..73a54d5b3 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -14,8 +14,6 @@ const de: Translation = { SU_PASSWORD: 'su Passwort', DASHBOARD: 'Kontrollzentrum', SETTINGS_OF: '{0} Einstellungen', - APPLY_CHANGES: 'Apply Changes ({0})', // TODO translate - UPDATE: 'Update', // TODO translate HELP_OF: '{0} Hilfe', LOGGED_IN: 'Eingeloggt als {name}', PLEASE_SIGNIN: 'Bitte einloggen, um fortzufahren', @@ -32,11 +30,11 @@ const de: Translation = { REFRESH: 'Aktualisieren', EXPORT: 'Exportieren', DEVICE_DETAILS: 'Geräte Details', - BRAND: 'Marke', ID_OF: '{0} ID', DEVICE: 'Geräte', PRODUCT: 'Produkt', VERSION: 'Version', + BRAND: 'Marke', ENTITY_NAME: 'Entitätsname', VALUE: '{{Wert|wert}}', SHOW_FAV: 'nur Favoriten anzeigen', @@ -48,6 +46,8 @@ const de: Translation = { CANCEL: 'Abbrechen', RESET: 'Zurücksetzen', SEND: 'Senden', + APPLY_CHANGES: 'Apply Changes ({0})', // TODO translate + UPDATE: 'Update', // TODO translate REMOVE: 'Entfernen', PROBLEM_UPDATING: 'Problem beim Aktualisieren', PROBLEM_LOADING: 'Problem beim Laden', @@ -208,7 +208,7 @@ const de: Translation = { COMPACT: 'Kompakte Darstellung', ENABLE_OTA: 'OTA Updates verwenden', DOWNLOAD_CUSTOMIZATION_TEXT: 'Herunterladen der individuellen Entitätsanpassungen', - DOWNLOAD_SCHEDULE_TEXT: 'Download Scheduler Events', // TODO translate + DOWNLOAD_SCHEDULE_TEXT: 'Herunterladen geplanter Befehle', DOWNLOAD_SETTINGS_TEXT: 'Herunterladen der Anwendungseinstellungen. Vorsicht beim Teilen der Einstellungen, da sie Passwörter und andere sensitive Einstellungen enthalten', UPLOAD_TEXT: 'Hochladen von neuer Firmware (.bin), Geräte- oder Entitätseinstellungen (.json), zur optionalen Validitätsprüfung zuerst die (.md5) Datei hochladen', UPLOADING: 'Hochladen', @@ -305,20 +305,20 @@ const de: Translation = { ENTITY: 'Entität', MIN: 'min', MAX: 'max', - BLOCK_NAVIGATE_1: 'You have unsaved changes', // TODO translate - BLOCK_NAVIGATE_2: 'If you navigate to a different page, your unsaved changes will be lost. Are you sure you want to leave this page?', // TODO translate - STAY: 'Stay', // TODO translate - LEAVE: 'Leave', // TODO translate - SCHEDULER: 'Scheduler', // TODO translate - SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP', // TODO translate - SCHEDULE: 'Schedule', // TODO translate - TIME: 'Time', // TODO translate - TIMER: 'Timer', // TODO translate - WEEKLY: 'Weekly', // TODO translate - SCHEDULE_SAVED: 'Schedule updated', // TODO translate - SCHEDULE_TIMER_1: 'on startup', // TODO translate - SCHEDULE_TIMER_2: 'every minute', // TODO translate - SCHEDULE_TIMER_3: 'every hour' // TODO translate + BLOCK_NAVIGATE_1: 'Sie haben ungesicherte Änderungen', + BLOCK_NAVIGATE_2: 'Beim verlassen der Seite verlieren Sie ungesicherte Einstellungen. Wollen Sie die Seite wirklich verlassen?', + STAY: 'Bleiben', + LEAVE: 'Verlassen', + SCHEDULER: 'Planer', + SCHEDULER_HELP_1: 'Fügen Sie eigene, geplante Befehle zur Automatisierung hinzu. Vergeben Sie einen Entitätsnamen um die Aktivierung über API/Mqtt zu steuern', + SCHEDULE: 'Zeitplan', + TIME: 'Zeit', + TIMER: 'Timer', + WEEKLY: 'Wöchentlich', + SCHEDULE_SAVED: 'Plan gespeichert', + SCHEDULE_TIMER_1: 'beim Start', + SCHEDULE_TIMER_2: 'jede Minute', + SCHEDULE_TIMER_3: 'jede Stunde' }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index dc0abb8ea..6daa59ad8 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -310,7 +310,7 @@ const en: Translation = { STAY: 'Stay', LEAVE: 'Leave', SCHEDULER: 'Scheduler', - SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP', + SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', SCHEDULE: 'Schedule', TIME: 'Time', TIMER: 'Timer', diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index 29e7e9fbf..001b8d880 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -310,7 +310,7 @@ const fr: Translation = { STAY: 'Stay', // TODO translate LEAVE: 'Leave', // TODO translate SCHEDULER: 'Scheduler', // TODO translate - SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP', // TODO translate + SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate SCHEDULE: 'Schedule', // TODO translate TIME: 'Time', // TODO translate TIMER: 'Timer', // TODO translate diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index c23d8eecf..e24c33c63 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -310,7 +310,7 @@ const nl: Translation = { STAY: 'Stay', // TODO translate LEAVE: 'Leave', // TODO translate SCHEDULER: 'Scheduler', // TODO translate - SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP', // TODO translate + SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate SCHEDULE: 'Schedule', // TODO translate TIME: 'Time', // TODO translate TIMER: 'Timer', // TODO translate diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index bef50fca9..aeee08059 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -310,7 +310,7 @@ const no: Translation = { STAY: 'Stay', // TODO translate LEAVE: 'Leave', // TODO translate SCHEDULER: 'Scheduler', // TODO translate - SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP', // TODO translate + SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate SCHEDULE: 'Schedule', // TODO translate TIME: 'Time', // TODO translate TIMER: 'Timer', // TODO translate diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index 325eac75f..b963a93ef 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -310,7 +310,7 @@ const pl: BaseTranslation = { STAY: 'Stay', // TODO translate LEAVE: 'Leave', // TODO translate SCHEDULER: 'Scheduler', // TODO translate - SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP', // TODO translate + SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate SCHEDULE: 'Schedule', // TODO translate SCHEDULE: 'Schedule', // TODO translate TIME: 'Time', // TODO translate TIMER: 'Timer', // TODO translate diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index 3eca024b2..23ecddf6c 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -310,7 +310,7 @@ const sv: Translation = { STAY: 'Stay', // TODO translate LEAVE: 'Leave', // TODO translate SCHEDULER: 'Scheduler', // TODO translate - SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP', // TODO translate + SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate SCHEDULE: 'Schedule', // TODO translate TIME: 'Time', // TODO translate TIMER: 'Timer', // TODO translate diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index f17a234b9..35ea50a16 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -310,7 +310,7 @@ const tr: Translation = { STAY: 'Stay', // TODO translate LEAVE: 'Leave', // TODO translate SCHEDULER: 'Scheduler', // TODO translate - SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP.', // TODO translate + SCHEDULER_HELP_1: 'Add custom scheduled commands to automate EMS-ESP. Add entity name to control activation by api/mqtt', // TODO translate SCHEDULE: 'Schedule', // TODO translate TIME: 'Time', // TODO translate TIMER: 'Timer', // TODO translate diff --git a/interface/src/project/SettingsScheduler.tsx b/interface/src/project/SettingsScheduler.tsx index e6a37e41c..ddf0e740c 100644 --- a/interface/src/project/SettingsScheduler.tsx +++ b/interface/src/project/SettingsScheduler.tsx @@ -464,7 +464,7 @@ const SettingsScheduler: FC = () => { )} ()) { + const char * d = data.as(); + if (strlen(d)) { + char * device_end = strchr(d, '/'); + if (device_end != nullptr) { + char device_s[15] = {'\0'}; + const char * device_p = device_s; + const char * data_p = nullptr; + strlcpy(device_s, d, device_end - d + 1); + data_p = device_end + 1; + int8_t id_d = -1; + data_p = parse_command_string(data_p, id_d); + char data_s[50]; + strcpy(data_s, data_p); + strcat(data_s, "/value"); + uint8_t device_type = EMSdevice::device_name_2_device_type(device_p); + if (CommandRet::OK == Command::call(device_type, data_s, "", true, id_d, output)) { + if (output.containsKey("api_data")) { + data = output["api_data"]; + } + } + output.clear(); + } + } + } + // call the command based on the type uint8_t return_code = CommandRet::ERROR; if (data.is()) { @@ -204,11 +231,13 @@ const char * Command::parse_command_string(const char * command, int8_t & id) { id = command[2] - '0'; command += 3; } else if (!strncmp(lowerCmd, "wwc", 3) && command[3] == '1' && command[4] == '0') { - id = DeviceValueTAG::TAG_WWC10 - DeviceValueTAG::TAG_HC1 + 1; //18; } else if (!strncmp(lowerCmd, "wwc", 3) && command[3] >= '1' && command[3] <= '9') { - id = command[3] - '0' + 8; + id = DeviceValueTAG::TAG_WWC10 - DeviceValueTAG::TAG_HC1 + 1; //18; + command += 5; + } else if (!strncmp(lowerCmd, "wwc", 3) && command[3] >= '1' && command[3] <= '9') { + id = command[3] - '1' + DeviceValueTAG::TAG_WWC1 - DeviceValueTAG::TAG_HC1 + 1; //9; command += 4; } else if (!strncmp(lowerCmd, "id", 2) && command[2] == '1' && command[3] >= '0' && command[3] <= '9') { - id = command[3] - '1' + DeviceValueTAG::TAG_WWC1 - DeviceValueTAG::TAG_HC1 + 1; //9; + id = command[3] - '0' + 10; command += 4; } else if (!strncmp(lowerCmd, "id", 2) && command[2] >= '1' && command[2] <= '9') { id = command[2] - '0'; @@ -499,6 +528,10 @@ bool Command::device_has_commands(const uint8_t device_type) { return true; // we always have System } + if (device_type == EMSdevice::DeviceType::SCHEDULER) { + return EMSESP::webSchedulerService.has_commands(); + } + if (device_type == EMSdevice::DeviceType::DALLASSENSOR) { return (EMSESP::dallassensor_.have_sensors()); } @@ -555,6 +588,13 @@ void Command::show_all(uuid::console::Shell & shell) { shell.print(COLOR_RESET); show(shell, EMSdevice::DeviceType::SYSTEM, true); + // show scheduler + shell.print(COLOR_BOLD_ON); + shell.print(COLOR_YELLOW); + shell.printf(" %s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SCHEDULER)); + shell.print(COLOR_RESET); + show(shell, EMSdevice::DeviceType::SCHEDULER, true); + // show sensors if (EMSESP::dallassensor_.have_sensors()) { shell.print(COLOR_BOLD_ON); diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index c0ff3d32a..b3797bb0a 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -105,6 +105,8 @@ const char * EMSdevice::device_type_2_device_name(const uint8_t device_type) { switch (device_type) { case DeviceType::SYSTEM: return F_(system); + case DeviceType::SCHEDULER: + return F_(scheduler); case DeviceType::BOILER: return F_(boiler); case DeviceType::THERMOSTAT: @@ -194,6 +196,9 @@ uint8_t EMSdevice::device_name_2_device_type(const char * topic) { if (!strcmp(lowtopic, F_(system))) { return DeviceType::SYSTEM; } + if (!strcmp(lowtopic, F_(scheduler))) { + return DeviceType::SCHEDULER; + } if (!strcmp(lowtopic, F_(heatpump))) { return DeviceType::HEATPUMP; } @@ -225,10 +230,6 @@ uint8_t EMSdevice::device_name_2_device_type(const char * topic) { return DeviceType::HEATSOURCE; } - if (!strcmp(lowtopic, F_(heatsource))) { - return DeviceType::HEATSOURCE; - } - return DeviceType::UNKNOWN; } @@ -550,10 +551,6 @@ void EMSdevice::add_device_value(uint8_t tag, // to b return; } - if (ignore) { - return; - } - // add the device entity devicevalues_.emplace_back( device_type_, tag, value_p, type, options, options_single, numeric_operator, short_name, fullname, custom_fullname, uom, has_cmd, min, max, state); diff --git a/src/emsdevice.h b/src/emsdevice.h index bdd3c31bc..e2c1a8ad4 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -322,6 +322,7 @@ class EMSdevice { SYSTEM = 0, // this is us (EMS-ESP) DALLASSENSOR, // for internal dallas sensors ANALOGSENSOR, // for internal analog sensors + SCHEDULER, BOILER, THERMOSTAT, MIXER, diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 67638c456..2272db1e6 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -478,7 +478,8 @@ void EMSESP::publish_all(bool force) { publish_device_values(EMSdevice::DeviceType::THERMOSTAT); publish_device_values(EMSdevice::DeviceType::SOLAR); publish_device_values(EMSdevice::DeviceType::MIXER); - publish_other_values(); // switch and heat pump, ... + publish_other_values(); // switch and heat pump, ... + webSchedulerService.publish(); publish_sensor_values(true); // includes dallas and analog sensors system_.send_heartbeat(); } @@ -510,6 +511,7 @@ void EMSESP::publish_all_loop() { break; case 5: publish_other_values(); // switch and heat pump + webSchedulerService.publish(true); break; case 6: publish_sensor_values(true, true); diff --git a/src/locale_common.h b/src/locale_common.h index 3218abd63..051bd50f2 100644 --- a/src/locale_common.h +++ b/src/locale_common.h @@ -97,6 +97,7 @@ MAKE_WORD(dallassensor) MAKE_WORD(alert) MAKE_WORD(pump) MAKE_WORD(heatsource) +MAKE_WORD(scheduler) // brands MAKE_WORD_CUSTOM(bosch, "Bosch") diff --git a/src/locale_translations.h b/src/locale_translations.h index 60737f3b4..0d2b9bbec 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -61,6 +61,7 @@ MAKE_TRANSLATION(restart_cmd, "restart EMS-ESP", "Neustart", "", "", "", "", "", MAKE_TRANSLATION(watch_cmd, "watch incoming telegrams", "Watch auf eingehende Telegramme", "", "", "", "", "", "Gelen telegramları ") MAKE_TRANSLATION(publish_cmd, "publish all to MQTT", "Publiziere MQTT", "", "", "", "", "", "Hepsini MQTTye gönder") MAKE_TRANSLATION(system_info_cmd, "show system status", "Zeige System-Status", "", "", "", "", "", "Sistem Durumunu Göster") +MAKE_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplan", "", "", "", "", "", "") // tags MAKE_TRANSLATION(tag_boiler_data_ww, "dhw", "WW", "dhw", "VV", "CWU", "dhw", "ecs", "SKS") diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 2430b1c04..446ec9f24 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -182,6 +182,7 @@ void Mqtt::loop() { if (publish_time_other_ && (currentMillis - last_publish_other_ > publish_time_other_)) { last_publish_other_ = (currentMillis / publish_time_other_) * publish_time_other_; EMSESP::publish_other_values(); // switch and heatpump + EMSESP::webSchedulerService.publish(); } else if (publish_time_sensor_ && (currentMillis - last_publish_sensor_ > publish_time_sensor_)) { diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index 28c0effa8..52306e0a9 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -64,6 +64,9 @@ StateUpdateResult WebScheduler::update(JsonObject & root, WebScheduler & webSche Serial.println(COLOR_RESET); #endif + for (ScheduleItem & scheduleItem : webScheduler.scheduleItems) { + Command::erase_command(EMSdevice::DeviceType::SCHEDULER, scheduleItem.description.c_str()); + } webScheduler.scheduleItems.clear(); if (root["schedule"].is()) { @@ -84,11 +87,146 @@ StateUpdateResult WebScheduler::update(JsonObject & root, WebScheduler & webSche si.retry_cnt = 0xFF; // no starup retries webScheduler.scheduleItems.push_back(si); // add to list + if (!webScheduler.scheduleItems.back().description.empty()) { + Command::add( + EMSdevice::DeviceType::SCHEDULER, + webScheduler.scheduleItems.back().description.c_str(), + [webScheduler](const char * value, const int8_t id) { + return EMSESP::webSchedulerService.command_setvalue(value, webScheduler.scheduleItems.back().description); + }, + FL_(schedule_cmd), + CommandFlag::ADMIN_ONLY); + } } } + EMSESP::webSchedulerService.publish(true); return StateUpdateResult::CHANGED; } +// set active by api command +bool WebSchedulerService::command_setvalue(const char * value, const std::string name) { + bool v; + if (!Helpers::value2bool(value, v)) { + return false; + } + EMSESP::webSchedulerService.read([&](WebScheduler & webScheduler) { scheduleItems = &webScheduler.scheduleItems; }); + for (ScheduleItem & scheduleItem : *scheduleItems) { + if (scheduleItem.description == name) { + if (scheduleItem.active == v) { + return true; + } + scheduleItem.active = v; + publish_single(name.c_str(), v); + if (EMSESP::mqtt_.get_publish_onchange(0)) { + publish(); + } + return true; + } + } + return false; +} + +void WebSchedulerService::publish_single(const char * name, const bool state) { + if (!Mqtt::publish_single() || name == nullptr || name[0] == '\0') { + return; + } + char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + if (Mqtt::publish_single2cmd()) { + snprintf(topic, sizeof(topic), "%s/%s", F_(scheduler), name); + } else { + snprintf(topic, sizeof(topic), "%s%s/%s", F_(scheduler), "_data", name); + } + char payload[12]; + Mqtt::queue_publish(topic, Helpers::render_boolean(payload, state)); +} + +// publish to Mqtt +void WebSchedulerService::publish(const bool force) { + EMSESP::webSchedulerService.read([&](WebScheduler & webScheduler) { scheduleItems = &webScheduler.scheduleItems; }); + if (scheduleItems->size() == 0) { + return; + } + if (Mqtt::publish_single() && force) { + for (const ScheduleItem & scheduleItem : *scheduleItems) { + publish_single(scheduleItem.description.c_str(), scheduleItem.active); + } + } + + DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE); + for (const ScheduleItem & scheduleItem : *scheduleItems) { + if (!scheduleItem.description.empty() && !doc.containsKey(scheduleItem.description)) { + if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { + doc[scheduleItem.description] = scheduleItem.active; + } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { + doc[scheduleItem.description] = scheduleItem.active ? 1 : 0; + } else { + char result[12]; + doc[scheduleItem.description] = Helpers::render_boolean(result, scheduleItem.active); + } + + // create HA config + if (Mqtt::ha_enabled() && force) { + StaticJsonDocument config; + char stat_t[50]; + snprintf(stat_t, sizeof(stat_t), "%s/scheduler_data", Mqtt::base().c_str()); + config["stat_t"] = stat_t; + + char val_obj[50]; + char val_cond[65]; + snprintf(val_obj, sizeof(val_obj), "value_json['%s']", scheduleItem.description.c_str()); + snprintf(val_cond, sizeof(val_cond), "%s is defined", val_obj); + config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}"; + + char uniq_s[70]; + snprintf(uniq_s, sizeof(uniq_s), "scheduler_%s", scheduleItem.description.c_str()); + + config["obj_id"] = uniq_s; + config["uniq_id"] = uniq_s; // same as object_id + config["name"] = scheduleItem.description.c_str(); + + char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + char command_topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + snprintf(topic, sizeof(topic), "switch/%s/scheduler_%s/config", Mqtt::basename().c_str(), scheduleItem.description.c_str()); + snprintf(command_topic, sizeof(command_topic), "%s/scheduler/%s", Mqtt::basename().c_str(), scheduleItem.description.c_str()); + config["cmd_t"] = command_topic; + if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { + config["pl_on"] = true; + config["pl_off"] = false; + } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { + config["pl_on"] = 1; + config["pl_off"] = 0; + } else { + char result[12]; + config["pl_on"] = Helpers::render_boolean(result, true); + config["pl_off"] = Helpers::render_boolean(result, false); + } + + JsonObject dev = config.createNestedObject("dev"); + JsonArray ids = dev.createNestedArray("ids"); + ids.add("ems-esp"); + + // add "availability" section + Mqtt::add_avty_to_doc(stat_t, config.as(), val_cond); + Mqtt::queue_ha(topic, config.as()); + } + } + } + Mqtt::queue_publish("scheduler_data", doc.as()); +} + +bool WebSchedulerService::has_commands() { + EMSESP::webSchedulerService.read([&](WebScheduler & webScheduler) { scheduleItems = &webScheduler.scheduleItems; }); + if (scheduleItems->size() == 0) { + return false; + } + for (const ScheduleItem & scheduleItem : *scheduleItems) { + if (!scheduleItem.description.empty()) { + return true; + } + } + return false; +} + // execute scheduled command bool WebSchedulerService::command(const char * cmd, const char * data) { StaticJsonDocument doc_input; diff --git a/src/web/WebSchedulerService.h b/src/web/WebSchedulerService.h index b822768ac..696ea8d99 100644 --- a/src/web/WebSchedulerService.h +++ b/src/web/WebSchedulerService.h @@ -54,6 +54,10 @@ class WebSchedulerService : public StatefulService { void begin(); void loop(); + void publish_single(const char * name, const bool state); + void publish(const bool force = false); + bool has_commands(); + bool command_setvalue(const char * value, const std::string name); private: bool command(const char * cmd, const char * data);