mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-09 17:29:50 +03:00
Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev2
This commit is contained in:
@@ -49,7 +49,7 @@
|
||||
{208, DeviceType::BOILER, "Logamax Plus/GB192/Condens GC9000/Greenstar ErP", DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{210, DeviceType::BOILER, "Cascade MC400", DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{211, DeviceType::BOILER, "EasyControl Adapter", DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
{219, DeviceType::BOILER, "Greenstar HIU", DeviceFlags::EMS_DEVICE_FLAG_HIU},
|
||||
{219, DeviceType::BOILER, "Greenstar HIU/Logamax kompakt WS170", DeviceFlags::EMS_DEVICE_FLAG_HIU},
|
||||
{234, DeviceType::BOILER, "Logamax Plus GB122/Condense 2300", DeviceFlags::EMS_DEVICE_FLAG_NONE},
|
||||
|
||||
// Controllers - 0x09 / 0x10 / 0x50
|
||||
|
||||
@@ -941,14 +941,15 @@ void EMSdevice::generate_values_web(JsonObject & output) {
|
||||
}
|
||||
}
|
||||
// handle INTs
|
||||
// add min and max values and steps, as integer values
|
||||
else {
|
||||
// add step if it's not 1
|
||||
if (dv.numeric_operator > 0) {
|
||||
obj["s"] = (float)1 / dv.numeric_operator;
|
||||
} else if (dv.numeric_operator < 0) {
|
||||
obj["s"] = (float)(-1) * dv.numeric_operator;
|
||||
}
|
||||
|
||||
// add min and max values, if available
|
||||
int16_t dv_set_min;
|
||||
uint32_t dv_set_max;
|
||||
if (dv.get_min_max(dv_set_min, dv_set_max)) {
|
||||
|
||||
@@ -716,7 +716,6 @@ std::string EMSESP::pretty_telegram(std::shared_ptr<const Telegram> telegram) {
|
||||
uint8_t offset = telegram->offset;
|
||||
|
||||
// find name for src and dest by looking up known devices
|
||||
|
||||
std::string src_name("");
|
||||
std::string dest_name("");
|
||||
std::string type_name("");
|
||||
|
||||
@@ -205,11 +205,11 @@ MAKE_NOTRANSLATION(L3, "L3")
|
||||
MAKE_NOTRANSLATION(L4, "L4")
|
||||
|
||||
// templates - this are not translated and will be saved under options_single
|
||||
MAKE_NOTRANSLATION(tpl_datetime, "< NTP | dd.mm.yyyy-hh:mm:ss-day(0-6)-dst(0/1) >")
|
||||
MAKE_NOTRANSLATION(tpl_datetime, "NTP | dd.mm.yyyy-hh:mm:ss-day(0-6)-dst(0/1)")
|
||||
MAKE_NOTRANSLATION(tpl_switchtime, "<nn> [ not_set | day hh:mm on|off ]")
|
||||
MAKE_NOTRANSLATION(tpl_switchtime1, "<nn> [ not_set | day hh:mm Tn ]")
|
||||
MAKE_NOTRANSLATION(tpl_holidays, "< dd.mm.yyyy-dd.mm.yyyy >")
|
||||
MAKE_NOTRANSLATION(tpl_date, "< dd.mm.yyyy >")
|
||||
MAKE_NOTRANSLATION(tpl_holidays, "dd.mm.yyyy-dd.mm.yyyy")
|
||||
MAKE_NOTRANSLATION(tpl_date, "dd.mm.yyyy")
|
||||
MAKE_NOTRANSLATION(tpl_input, "<inv>[<evu1><evu2><evu3><comp><aux><cool><heat><dhw><pv>]")
|
||||
MAKE_NOTRANSLATION(tpl_input4, "<inv>[<comp><aux><cool><heat><dhw><pv>]")
|
||||
|
||||
|
||||
12
src/mqtt.cpp
12
src/mqtt.cpp
@@ -532,7 +532,7 @@ void Mqtt::ha_status() {
|
||||
doc["obj_id"] = uniq;
|
||||
|
||||
doc["stat_t"] = mqtt_basename_ + "/status";
|
||||
doc["name"] = "system status";
|
||||
doc["name"] = "System status";
|
||||
doc["pl_on"] = "online";
|
||||
doc["pl_off"] = "offline";
|
||||
doc["stat_cla"] = "measurement";
|
||||
@@ -855,14 +855,11 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
|
||||
case DeviceValueType::UINT:
|
||||
case DeviceValueType::SHORT:
|
||||
case DeviceValueType::USHORT:
|
||||
// case DeviceValueType::ULONG:
|
||||
if (discovery_type() == discoveryType::HOMEASSISTANT) {
|
||||
// Home Assistant
|
||||
// number - https://www.home-assistant.io/integrations/number.mqtt
|
||||
snprintf(topic, sizeof(topic), "number/%s", config_topic);
|
||||
} else {
|
||||
// Domoticz
|
||||
// Does not support number, use sensor
|
||||
// Domoticz does not support number, use sensor
|
||||
snprintf(topic, sizeof(topic), "sensor/%s", config_topic);
|
||||
}
|
||||
break;
|
||||
@@ -1126,9 +1123,8 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
|
||||
}
|
||||
|
||||
// add category "diagnostic" for system entities
|
||||
if (device_type == EMSdevice::DeviceType::SYSTEM) {
|
||||
doc["ent_cat"] = "diagnostic";
|
||||
}
|
||||
// config for writeable entities, like switches. diagnostic for read only sensors.
|
||||
doc["ent_cat"] = (has_cmd) ? "config" : "diagnostic";
|
||||
|
||||
// add the dev json object to the end
|
||||
doc["dev"] = dev_json;
|
||||
|
||||
@@ -101,15 +101,16 @@ void Shower::loop() {
|
||||
if (duration_ > SHOWER_MIN_DURATION) {
|
||||
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
||||
|
||||
// char s[50];
|
||||
// snprintf(s, 50, "%02u:%02u:%02u", (uint8_t)(duration_ / 3600000UL), (uint8_t)(duration_ / 60000UL), (uint8_t)((duration_ / 1000UL) % 60));
|
||||
// duration in seconds
|
||||
doc["duration"] = (duration_ / 1000UL); // seconds
|
||||
time_t now = time(nullptr);
|
||||
time_t now = time(nullptr);
|
||||
// if NTP enabled, publish timestamp
|
||||
if (now > 1576800000) { // year 2020
|
||||
tm * tm_ = localtime(&now);
|
||||
// doc["timestamp_s"] = now; // if needed, in seconds
|
||||
tm * tm_ = localtime(&now);
|
||||
char dt[25];
|
||||
strftime(dt, sizeof(dt), "%FT%T%z", tm_);
|
||||
doc["time"] = dt;
|
||||
doc["timestamp"] = dt;
|
||||
}
|
||||
Mqtt::queue_publish("shower_data", doc.as<JsonObject>());
|
||||
LOG_INFO("finished with duration %lu seconds", duration_ / 1000UL);
|
||||
@@ -180,7 +181,7 @@ void Shower::set_shower_state(bool state, bool force) {
|
||||
char stat_t[50];
|
||||
|
||||
//
|
||||
// shower_active topic
|
||||
// shower active
|
||||
//
|
||||
doc["name"] = "Shower Active";
|
||||
|
||||
@@ -217,7 +218,7 @@ void Shower::set_shower_state(bool state, bool force) {
|
||||
ha_configdone_ = Mqtt::queue_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||
|
||||
//
|
||||
// shower_duaration topic
|
||||
// shower duaration
|
||||
//
|
||||
doc.clear();
|
||||
|
||||
@@ -244,6 +245,32 @@ void Shower::set_shower_state(bool state, bool force) {
|
||||
|
||||
snprintf(topic, sizeof(topic), "sensor/%s/shower_duration/config", Mqtt::basename().c_str());
|
||||
Mqtt::queue_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||
|
||||
//
|
||||
// shower timestamp
|
||||
//
|
||||
doc.clear();
|
||||
|
||||
snprintf(str, sizeof(str), "%s_shower_timestamp", Mqtt::basename().c_str());
|
||||
|
||||
doc["uniq_id"] = str;
|
||||
doc["object_id"] = str;
|
||||
|
||||
snprintf(stat_t, sizeof(stat_t), "%s/shower_data", Mqtt::basename().c_str());
|
||||
doc["stat_t"] = stat_t;
|
||||
|
||||
doc["name"] = "Shower Timestamp";
|
||||
doc["val_tpl"] = "{{value_json.timestamp if value_json.timestamp is defined else 0}}";
|
||||
doc["ent_cat"] = "diagnostic";
|
||||
|
||||
JsonObject dev3 = doc.createNestedObject("dev");
|
||||
JsonArray ids3 = dev3.createNestedArray("ids");
|
||||
ids3.add(Mqtt::basename());
|
||||
|
||||
Mqtt::add_avty_to_doc(stat_t, doc.as<JsonObject>(), "value_json.timestamp is defined"); // add "availability" section
|
||||
|
||||
snprintf(topic, sizeof(topic), "sensor/%s/shower_timestamp/config", Mqtt::basename().c_str());
|
||||
Mqtt::queue_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ class Shower {
|
||||
|
||||
static constexpr uint32_t SHOWER_PAUSE_TIME = 15000; // in ms. 15 seconds, max time if water is switched off & on during a shower
|
||||
static constexpr uint32_t SHOWER_MIN_DURATION = 120000; // in ms. 2 minutes, before recognizing its a shower
|
||||
static constexpr uint32_t SHOWER_OFFSET_TIME = 5000; // in ms. 5 seconds grace time, to calibrate actual time under the shower
|
||||
// static constexpr uint32_t SHOWER_MIN_DURATION = 5000; // for testing in ms. 5 seconds
|
||||
|
||||
static constexpr uint32_t SHOWER_OFFSET_TIME = 5000; // in ms. 5 seconds grace time, to calibrate actual time under the shower
|
||||
|
||||
void shower_alert_start();
|
||||
void shower_alert_stop();
|
||||
|
||||
@@ -113,7 +113,8 @@ class Telegram {
|
||||
return (val != value);
|
||||
}
|
||||
|
||||
// read a value from a telegram. We always store the value, regardless if its garbage
|
||||
// read a value from a telegram if its not out of bounds.
|
||||
// Then we update the value, regardless if its garbage
|
||||
template <typename Value>
|
||||
// assuming negative numbers are stored as 2's-complement
|
||||
// https://medium.com/@LeeJulija/how-integers-are-stored-in-memory-using-twos-complement-5ba04d61a56c
|
||||
@@ -124,6 +125,20 @@ class Telegram {
|
||||
uint8_t num_bytes = (!s) ? sizeof(Value) : s;
|
||||
// check for out of bounds, if so don't modify the value
|
||||
auto msg_size = (index - this->offset + num_bytes - 1);
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
// Serial.print(" index: ");
|
||||
// Serial.print(index);
|
||||
// Serial.print(" offset: ");
|
||||
// Serial.print(offset);
|
||||
// Serial.print(" index: ");
|
||||
// Serial.print(" message_length: ");
|
||||
// Serial.print(this->message_length);
|
||||
// Serial.print(" msg_size: ");
|
||||
// Serial.print(msg_size);
|
||||
// Serial.println();
|
||||
#endif
|
||||
|
||||
if ((index < this->offset) || (msg_size >= this->message_length) || (msg_size > EMS_MAX_TELEGRAM_MESSAGE_LENGTH)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -576,7 +576,7 @@ TemperatureSensor::Sensor::Sensor(const uint8_t addr[])
|
||||
(unsigned int)(internal_id_ >> 48) & 0xFF,
|
||||
(unsigned int)(internal_id_ >> 32) & 0xFFFF,
|
||||
(unsigned int)(internal_id_ >> 16) & 0xFFFF,
|
||||
(unsigned int)(internal_id_)&0xFFFF);
|
||||
(unsigned int)(internal_id_) & 0xFFFF);
|
||||
id_ = std::string(id_s);
|
||||
name_ = std::string{}; // name (alias) is empty
|
||||
offset_ = 0; // 0 degrees offset
|
||||
|
||||
@@ -74,6 +74,18 @@ bool Test::run_test(const char * command, int8_t id) {
|
||||
//
|
||||
#ifdef EMSESP_STANDALONE
|
||||
|
||||
if (strcmp(command, "heat_exchange") == 0) {
|
||||
EMSESP::logger().info("Testing heating exchange...");
|
||||
|
||||
add_device(0x08, 219); // Greenstar HIU/Logamax kompakt WS170
|
||||
|
||||
// [emsesp] boiler(0x08) -W-> Me(0x0B), UBAMonitorFastPlus(0xE4), data: 00 01 35 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 80 00 (offset 6)
|
||||
uart_telegram({0x08, 0x00, 0xE4, 0x00, //
|
||||
00, 01, 0x35, 00, 00, 00, 00, 00, 00, 00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 0x80, 00});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcmp(command, "2thermostats") == 0) {
|
||||
EMSESP::logger().info("Testing with multiple thermostats...");
|
||||
|
||||
@@ -493,16 +505,24 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
shell.printfln("Testing RC310...");
|
||||
run_test("310");
|
||||
shell.invoke_command("show devices");
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
shell.invoke_command("call system publish");
|
||||
shell.invoke_command("show mqtt");
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (command == "heat_exchange") {
|
||||
shell.printfln("Testing heat exchange...");
|
||||
run_test("heat_exchange");
|
||||
shell.invoke_command("show devices");
|
||||
shell.invoke_command("show values");
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (command == "2thermostats") {
|
||||
shell.printfln("Testing multiple thermostats...");
|
||||
run_test("2thermostats");
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
shell.invoke_command("show devices");
|
||||
ok = true;
|
||||
}
|
||||
@@ -571,7 +591,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
|
||||
run_test("boiler");
|
||||
shell.invoke_command("show devices");
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
shell.invoke_command("call boiler info");
|
||||
shell.invoke_command("call system publish");
|
||||
|
||||
@@ -610,7 +630,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
// HC1
|
||||
uart_telegram({0x90, 0x00, 0xFF, 0x00, 0x00, 0x6F, 0x01, 0x02, 0x00, 0xCF, 0x00, 0xE6});
|
||||
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
shell.invoke_command("show devices");
|
||||
ok = true;
|
||||
}
|
||||
@@ -653,7 +673,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
uart_telegram(
|
||||
{0x08, 0x0B, 0xC2, 0, 0x08, 0xAC, 00, 0x10, 0x31, 0x48, 0x30, 0x31, 0x15, 0x80, 0x95, 0x0B, 0x0E, 0x10, 0x38, 00, 0x7F, 0xFF, 0xFF, 0xFF});
|
||||
|
||||
// shell.invoke_command("show");
|
||||
// shell.invoke_command("show values");
|
||||
|
||||
ok = true;
|
||||
}
|
||||
@@ -686,12 +706,12 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
// Mqtt::nested_format(0);
|
||||
|
||||
emsesp::EMSESP::temperaturesensor_.test();
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
shell.invoke_command("call system publish");
|
||||
|
||||
// rename
|
||||
EMSESP::temperaturesensor_.update("01-0203-0405-0607", "testtemperature", 2);
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
shell.invoke_command("call system publish");
|
||||
ok = true;
|
||||
}
|
||||
@@ -704,14 +724,14 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
// Mqtt::nested_format(0);
|
||||
|
||||
emsesp::EMSESP::analogsensor_.test();
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
// shell.invoke_command("call system publish");
|
||||
// shell.invoke_command("show mqtt");
|
||||
|
||||
// rename
|
||||
// bool update(uint8_t id, const std::string & name, int16_t offset, float factor, uint8_t uom, uint8_t type);
|
||||
EMSESP::analogsensor_.update(36, "analogtest", 2, 0.7, 17, 1);
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
// shell.invoke_command("call system publish");
|
||||
ok = true;
|
||||
}
|
||||
@@ -1174,7 +1194,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
shell.printfln("Testing adding a thermostat FW120...");
|
||||
|
||||
run_test("thermostat");
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
shell.invoke_command("call system publish");
|
||||
|
||||
EMSESP::mqtt_.incoming("ems-esp/thermostat_hc1", "heat");
|
||||
@@ -1243,7 +1263,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
|
||||
uart_telegram("30 00 FF 0A 02 6A 03"); // SM100 pump off 0
|
||||
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -1676,7 +1696,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
// check for error "No telegram type handler found for ID 0x255 (src 0x20)"
|
||||
uart_telegram({0xA0, 0x00, 0xFF, 0x00, 0x01, 0x55, 0x00, 0x1A});
|
||||
|
||||
shell.invoke_command("show");
|
||||
shell.invoke_command("show values");
|
||||
shell.invoke_command("call mixer info");
|
||||
shell.invoke_command("call system publish");
|
||||
shell.invoke_command("show mqtt");
|
||||
|
||||
@@ -56,6 +56,8 @@ namespace emsesp {
|
||||
// #define EMSESP_DEBUG_DEFAULT "memory"
|
||||
// #define EMSESP_DEBUG_DEFAULT "coldshot"
|
||||
// #define EMSESP_DEBUG_DEFAULT "custom_entities"
|
||||
// #define EMSESP_DEBUG_DEFAULT "heat_exchange"
|
||||
|
||||
|
||||
class Test {
|
||||
public:
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.6.3-dev.2i"
|
||||
#define EMSESP_APP_VERSION "3.6.3-dev.3a"
|
||||
|
||||
Reference in New Issue
Block a user