Merge pull request #1816 from MichaelDvP/dev

This commit is contained in:
Proddy
2024-06-22 13:17:13 +01:00
committed by GitHub
6 changed files with 62 additions and 35 deletions

View File

@@ -121,7 +121,7 @@ const de: Translation = {
READONLY: 'Nur-Lese-Modus aktivieren (blockiert alle ausgehenden EMS Tx Write-Befehle)', READONLY: 'Nur-Lese-Modus aktivieren (blockiert alle ausgehenden EMS Tx Write-Befehle)',
UNDERCLOCK_CPU: 'CPU-Geschwindigkeit untertakten', UNDERCLOCK_CPU: 'CPU-Geschwindigkeit untertakten',
REMOTE_TIMEOUT: 'Timeout', REMOTE_TIMEOUT: 'Timeout',
REMOTE_TIMEOUT_EN: 'Deaktitiere Remote bei fehlender Temperatur', REMOTE_TIMEOUT_EN: 'Deaktiviere Remote bei fehlender Temperatur',
HEATINGOFF: 'Heizen ausschalten beim EMS-ESP Start', HEATINGOFF: 'Heizen ausschalten beim EMS-ESP Start',
MIN_DURATION: 'Dauer bis die Dusche erkannt wrid', MIN_DURATION: 'Dauer bis die Dusche erkannt wrid',
ENABLE_SHOWER_TIMER: 'Duschtimer aktivieren', ENABLE_SHOWER_TIMER: 'Duschtimer aktivieren',

View File

@@ -34,7 +34,7 @@ uint32_t Roomctrl::timeout_ = 0;
* set the temperature, * set the temperature,
*/ */
void Roomctrl::set_timeout(uint8_t t) { void Roomctrl::set_timeout(uint8_t t) {
timeout_ = t * 3600; timeout_ = t * 3600000; // ms
} }
void Roomctrl::set_remotetemp(const uint8_t type, const uint8_t hc, const int16_t temp) { void Roomctrl::set_remotetemp(const uint8_t type, const uint8_t hc, const int16_t temp) {
if (!type_[hc] && !type) { if (!type_[hc] && !type) {

View File

@@ -38,7 +38,6 @@ class Roomctrl {
private: private:
static constexpr uint32_t SEND_INTERVAL = 15000; // 15 sec static constexpr uint32_t SEND_INTERVAL = 15000; // 15 sec
static constexpr uint32_t TIMEOUT = 86400000; // 24 hour
static constexpr uint8_t HCS = 4; // max 4 heating circuits static constexpr uint8_t HCS = 4; // max 4 heating circuits
enum SendType : uint8_t { TEMP, HUMI }; enum SendType : uint8_t { TEMP, HUMI };

View File

@@ -37,7 +37,9 @@ void WebCustomEntityService::begin() {
// save a local pointer to the item list // save a local pointer to the item list
EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems_ = &webEntity.customEntityItems; }); EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems_ = &webEntity.customEntityItems; });
EMSESP::logger().info("Starting Custom Entity service"); EMSESP::logger().info("Starting Custom Entity service");
Mqtt::subscribe(EMSdevice::DeviceType::CUSTOM, "custom/#", nullptr); // use empty function callback char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "%s/#", F_(custom));
Mqtt::subscribe(EMSdevice::DeviceType::CUSTOM, topic, nullptr); // use empty function callback
} }
// this creates the entity file, saving it to the FS // this creates the entity file, saving it to the FS
@@ -175,7 +177,7 @@ bool WebCustomEntityService::command_setvalue(const char * value, const int8_t i
publish(); publish();
} }
char cmd[COMMAND_MAX_LENGTH]; char cmd[COMMAND_MAX_LENGTH];
snprintf(cmd, sizeof(cmd_function_p), "custom/%s", entityItem.name.c_str()); snprintf(cmd, sizeof(cmd), "%s/%s", F_(custom), entityItem.name.c_str());
EMSESP::webSchedulerService.onChange(cmd); EMSESP::webSchedulerService.onChange(cmd);
return true; return true;
} }
@@ -260,7 +262,9 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
output[F_(info)] = Helpers::translated_word(FL_(info_cmd)); output[F_(info)] = Helpers::translated_word(FL_(info_cmd));
output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd)); output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd));
for (const auto & entity : *customEntityItems_) { for (const auto & entity : *customEntityItems_) {
output[entity.name] = "custom entity"; if (entity.writeable) {
output[entity.name] = "custom entity";
}
} }
return true; return true;
} }
@@ -346,9 +350,9 @@ void WebCustomEntityService::publish_single(const CustomEntityItem & entity) {
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
if (Mqtt::publish_single2cmd()) { if (Mqtt::publish_single2cmd()) {
snprintf(topic, sizeof(topic), "%s/%s", "custom", entity.name.c_str()); snprintf(topic, sizeof(topic), "%s/%s", F_(custom), entity.name.c_str());
} else { } else {
snprintf(topic, sizeof(topic), "%s/%s", "custom_data", entity.name.c_str()); snprintf(topic, sizeof(topic), "%s_data/%s", F_(custom), entity.name.c_str());
} }
JsonDocument doc; JsonDocument doc;
@@ -386,7 +390,7 @@ void WebCustomEntityService::publish(const bool force) {
if (Mqtt::ha_enabled() && !ha_registered_) { if (Mqtt::ha_enabled() && !ha_registered_) {
JsonDocument config; JsonDocument config;
char stat_t[50]; char stat_t[50];
snprintf(stat_t, sizeof(stat_t), "%s/custom_data", Mqtt::base().c_str()); snprintf(stat_t, sizeof(stat_t), "%s/%s_data", Mqtt::base().c_str(), F_(custom));
config["stat_t"] = stat_t; config["stat_t"] = stat_t;
char val_obj[50]; char val_obj[50];
@@ -396,7 +400,7 @@ void WebCustomEntityService::publish(const bool force) {
config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}"; config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}";
char uniq_s[70]; char uniq_s[70];
snprintf(uniq_s, sizeof(uniq_s), "custom_%s", entityItem.name.c_str()); snprintf(uniq_s, sizeof(uniq_s), "%s_%s", F_(custom), entityItem.name.c_str());
config["obj_id"] = uniq_s; config["obj_id"] = uniq_s;
config["uniq_id"] = uniq_s; // same as object_id config["uniq_id"] = uniq_s; // same as object_id
@@ -406,22 +410,22 @@ void WebCustomEntityService::publish(const bool force) {
if (entityItem.writeable) { if (entityItem.writeable) {
if (entityItem.value_type == DeviceValueType::BOOL) { if (entityItem.value_type == DeviceValueType::BOOL) {
snprintf(topic, sizeof(topic), "switch/%s/custom_%s/config", Mqtt::basename().c_str(), entityItem.name.c_str()); snprintf(topic, sizeof(topic), "switch/%s/%s_%s/config", Mqtt::basename().c_str(), F_(custom), entityItem.name.c_str());
} else if (entityItem.value_type == DeviceValueType::STRING) { } else if (entityItem.value_type == DeviceValueType::STRING) {
snprintf(topic, sizeof(topic), "sensor/%s/custom_%s/config", Mqtt::basename().c_str(), entityItem.name.c_str()); snprintf(topic, sizeof(topic), "sensor/%s/%s_%s/config", Mqtt::basename().c_str(), F_(custom), entityItem.name.c_str());
} else if (Mqtt::discovery_type() == Mqtt::discoveryType::HOMEASSISTANT || Mqtt::discovery_type() == Mqtt::discoveryType::DOMOTICZ_LATEST) { } else if (Mqtt::discovery_type() == Mqtt::discoveryType::HOMEASSISTANT || Mqtt::discovery_type() == Mqtt::discoveryType::DOMOTICZ_LATEST) {
snprintf(topic, sizeof(topic), "number/%s/custom_%s/config", Mqtt::basename().c_str(), entityItem.name.c_str()); snprintf(topic, sizeof(topic), "number/%s/%s_%s/config", Mqtt::basename().c_str(), F_(custom), entityItem.name.c_str());
} else { } else {
snprintf(topic, sizeof(topic), "sensor/%s/custom_%s/config", Mqtt::basename().c_str(), entityItem.name.c_str()); snprintf(topic, sizeof(topic), "sensor/%s/%s_%s/config", Mqtt::basename().c_str(), F_(custom), entityItem.name.c_str());
} }
char command_topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char command_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(command_topic, sizeof(command_topic), "%s/custom/%s", Mqtt::basename().c_str(), entityItem.name.c_str()); snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::basename().c_str(), F_(custom), entityItem.name.c_str());
config["cmd_t"] = command_topic; config["cmd_t"] = command_topic;
} else { } else {
if (entityItem.value_type == DeviceValueType::BOOL) { if (entityItem.value_type == DeviceValueType::BOOL) {
snprintf(topic, sizeof(topic), "binary_sensor/%s/custom_%s/config", Mqtt::basename().c_str(), entityItem.name.c_str()); snprintf(topic, sizeof(topic), "binary_sensor/%s/%s_%s/config", Mqtt::basename().c_str(), F_(custom), entityItem.name.c_str());
} else { } else {
snprintf(topic, sizeof(topic), "sensor/%s/custom_%s/config", Mqtt::basename().c_str(), entityItem.name.c_str()); snprintf(topic, sizeof(topic), "sensor/%s/%s_%s/config", Mqtt::basename().c_str(), F_(custom), entityItem.name.c_str());
} }
} }
@@ -442,7 +446,7 @@ void WebCustomEntityService::publish(const bool force) {
Mqtt::add_ha_uom(config.as<JsonObject>(), entityItem.value_type, entityItem.uom); // add uom Mqtt::add_ha_uom(config.as<JsonObject>(), entityItem.value_type, entityItem.uom); // add uom
Mqtt::add_ha_sections_to_doc("custom", stat_t, config, !ha_created, val_cond); Mqtt::add_ha_sections_to_doc(F_(custom), stat_t, config, !ha_created, val_cond);
ha_created |= Mqtt::queue_ha(topic, config.as<JsonObject>()); ha_created |= Mqtt::queue_ha(topic, config.as<JsonObject>());
} }
@@ -450,7 +454,9 @@ void WebCustomEntityService::publish(const bool force) {
ha_registered_ = ha_created; ha_registered_ = ha_created;
if (output.size() > 0) { if (output.size() > 0) {
Mqtt::queue_publish("custom_data", output); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
sprintf(topic, "%s_data", F_(custom));
Mqtt::queue_publish(topic, output);
} }
// EMSESP::logger().debug("publish %d custom entities", output.size()); // EMSESP::logger().debug("publish %d custom entities", output.size());
} }
@@ -598,7 +604,7 @@ bool WebCustomEntityService::get_value(std::shared_ptr<const Telegram> telegram)
has_change = true; has_change = true;
} }
char cmd[COMMAND_MAX_LENGTH]; char cmd[COMMAND_MAX_LENGTH];
snprintf(cmd, sizeof(cmd_function_p), "custom/%s", entity.name.c_str()); snprintf(cmd, sizeof(cmd), "%s/%s", F_(custom), entity.name.c_str());
EMSESP::webSchedulerService.onChange(cmd); EMSESP::webSchedulerService.onChange(cmd);
} }
} else if (entity.value_type != DeviceValueType::STRING && telegram->type_id == entity.type_id && telegram->src == entity.device_id } else if (entity.value_type != DeviceValueType::STRING && telegram->type_id == entity.type_id && telegram->src == entity.device_id
@@ -615,7 +621,7 @@ bool WebCustomEntityService::get_value(std::shared_ptr<const Telegram> telegram)
has_change = true; has_change = true;
} }
char cmd[COMMAND_MAX_LENGTH]; char cmd[COMMAND_MAX_LENGTH];
snprintf(cmd, sizeof(cmd_function_p), "%s/%s", "custom", entity.name.c_str()); snprintf(cmd, sizeof(cmd), "%s/%s", F_(custom), entity.name.c_str());
EMSESP::webSchedulerService.onChange(cmd); EMSESP::webSchedulerService.onChange(cmd);
} }
// EMSESP::logger().debug("custom entity %s received with value %d", entity.name.c_str(), (int)entity.val); // EMSESP::logger().debug("custom entity %s received with value %d", entity.name.c_str(), (int)entity.val);

View File

@@ -34,7 +34,9 @@ void WebSchedulerService::begin() {
EMSESP::webSchedulerService.read([&](WebScheduler & webScheduler) { scheduleItems_ = &webScheduler.scheduleItems; }); EMSESP::webSchedulerService.read([&](WebScheduler & webScheduler) { scheduleItems_ = &webScheduler.scheduleItems; });
EMSESP::logger().info("Starting Scheduler service"); EMSESP::logger().info("Starting Scheduler service");
Mqtt::subscribe(EMSdevice::DeviceType::SCHEDULER, "scheduler/#", nullptr); // use empty function callback char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "%s/#", F_(scheduler));
Mqtt::subscribe(EMSdevice::DeviceType::SCHEDULER, topic, nullptr); // use empty function callback
} }
// this creates the scheduler file, saving it to the FS // this creates the scheduler file, saving it to the FS
@@ -261,7 +263,7 @@ void WebSchedulerService::publish(const bool force) {
if (Mqtt::ha_enabled() && !ha_registered_) { if (Mqtt::ha_enabled() && !ha_registered_) {
JsonDocument config; JsonDocument config;
char stat_t[50]; char stat_t[50];
snprintf(stat_t, sizeof(stat_t), "%s/scheduler_data", Mqtt::base().c_str()); snprintf(stat_t, sizeof(stat_t), "%s/%s_data", Mqtt::base().c_str(), F_(scheduler));
config["stat_t"] = stat_t; config["stat_t"] = stat_t;
char val_obj[50]; char val_obj[50];
@@ -271,7 +273,7 @@ void WebSchedulerService::publish(const bool force) {
config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}"; config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}";
char uniq_s[70]; char uniq_s[70];
snprintf(uniq_s, sizeof(uniq_s), "scheduler_%s", scheduleItem.name.c_str()); snprintf(uniq_s, sizeof(uniq_s), "%s_%s", F_(scheduler), scheduleItem.name.c_str());
config["obj_id"] = uniq_s; config["obj_id"] = uniq_s;
config["uniq_id"] = uniq_s; // same as object_id config["uniq_id"] = uniq_s; // same as object_id
@@ -280,8 +282,8 @@ void WebSchedulerService::publish(const bool force) {
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
char command_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.name.c_str()); snprintf(topic, sizeof(topic), "switch/%s/%s_%s/config", Mqtt::basename().c_str(), F_(scheduler), scheduleItem.name.c_str());
snprintf(command_topic, sizeof(command_topic), "%s/scheduler/%s", Mqtt::base().c_str(), scheduleItem.name.c_str()); snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::base().c_str(), F_(scheduler), scheduleItem.name.c_str());
config["cmd_t"] = command_topic; config["cmd_t"] = command_topic;
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
@@ -296,7 +298,7 @@ void WebSchedulerService::publish(const bool force) {
config["pl_off"] = Helpers::render_boolean(result, false); config["pl_off"] = Helpers::render_boolean(result, false);
} }
Mqtt::add_ha_sections_to_doc("scheduler", stat_t, config, !ha_created, val_cond); Mqtt::add_ha_sections_to_doc(F_(scheduler), stat_t, config, !ha_created, val_cond);
ha_created |= Mqtt::queue_ha(topic, config.as<JsonObject>()); ha_created |= Mqtt::queue_ha(topic, config.as<JsonObject>());
} }
@@ -304,7 +306,9 @@ void WebSchedulerService::publish(const bool force) {
} }
ha_registered_ = ha_created; ha_registered_ = ha_created;
if (doc.size() > 0) { if (doc.size() > 0) {
Mqtt::queue_publish("scheduler_data", doc.as<JsonObject>()); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "%s_data", F_(scheduler));
Mqtt::queue_publish(topic, doc.as<JsonObject>());
} }
} }
@@ -334,7 +338,7 @@ bool WebSchedulerService::command(const char * cmd, const char * data) {
JsonObject output = doc_output.to<JsonObject>(); JsonObject output = doc_output.to<JsonObject>();
// prefix "api/" to command string // prefix "api/" to command string
char command_str[100]; char command_str[COMMAND_MAX_LENGTH];
snprintf(command_str, sizeof(command_str), "/api/%s", cmd); snprintf(command_str, sizeof(command_str), "/api/%s", cmd);
uint8_t return_code = Command::process(command_str, true, input, output); // admin set uint8_t return_code = Command::process(command_str, true, input, output); // admin set
@@ -368,7 +372,8 @@ bool WebSchedulerService::command(const char * cmd, const char * data) {
bool WebSchedulerService::onChange(const char * cmd) { bool WebSchedulerService::onChange(const char * cmd) {
for (const ScheduleItem & scheduleItem : *scheduleItems_) { for (const ScheduleItem & scheduleItem : *scheduleItems_) {
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_ONCHANGE && Helpers::toLower(scheduleItem.time) == Helpers::toLower(cmd)) { if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_ONCHANGE
&& Helpers::toLower(scheduleItem.time).find(Helpers::toLower(cmd)) != std::string::npos) {
#ifdef EMESESP_DEBUG #ifdef EMESESP_DEBUG
// emsesp::EMSESP::logger().debug(scheduleItem.cmd.c_str()); // emsesp::EMSESP::logger().debug(scheduleItem.cmd.c_str());
#endif #endif

View File

@@ -371,16 +371,20 @@ int to_logic(const std::string & s) {
return -1; return -1;
} }
// number to string // number to string, remove trailing zeros
std::string to_string(double d) { std::string to_string(double d) {
if (d == static_cast<int>(d)) { std::string s = std::to_string(d);
return std::to_string(static_cast<int>(d)); while (!s.empty() && s.back() == '0') {
s.pop_back();
} }
return std::to_string(d); if (!s.empty() && s.back() == '.') {
s.pop_back();
}
return s;
} }
// RPN calculator // RPN calculator
std::string compute(const std::string & expr) { std::string calculate(const std::string & expr) {
auto expr_new = emsesp::Helpers::toLower(expr); auto expr_new = emsesp::Helpers::toLower(expr);
// emsesp::EMSESP::logger().info("calculate: %s", expr_new.c_str()); // emsesp::EMSESP::logger().info("calculate: %s", expr_new.c_str());
commands(expr_new); commands(expr_new);
@@ -554,3 +558,16 @@ std::string compute(const std::string & expr) {
} }
return stack.back(); return stack.back();
} }
// check for <expr> ? <expr1> : <expr2>
std::string compute(const std::string & expr) {
auto q = expr.find_first_of("?");
auto p = expr.find_first_of(":", q);
if (p != std::string::npos && q != std::string::npos) {
if (calculate(expr.substr(0, q))[0] == '1') {
return calculate(expr.substr(q + 1, p - q - 1));
} else {
return calculate(expr.substr(p + 1));
}
}
return calculate(expr);
}