add mqtt base, fix mixer, fix masterthermostat, dallas fails, fix mult. roomctrl.

This commit is contained in:
MichaelDvP
2021-01-25 11:53:01 +01:00
parent 993607d657
commit 3f9995340c
23 changed files with 192 additions and 136 deletions

View File

@@ -190,8 +190,8 @@ bool Boiler::publish_ha_config() {
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
doc["uniq_id"] = F_(boiler);
char stat_t[50];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/boiler_data"), System::hostname().c_str());
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/boiler_data"), Mqtt::base().c_str());
doc["stat_t"] = stat_t;
doc["name"] = FJSON("Service Code");
@@ -204,8 +204,8 @@ bool Boiler::publish_ha_config() {
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp-boiler");
char topic[100];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/boiler/config"), System::hostname().c_str());
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/boiler/config"), Mqtt::base().c_str());
Mqtt::publish_ha(topic,
doc.as<JsonObject>()); // publish the config payload with retain flag
@@ -304,7 +304,9 @@ void Boiler::process_UBAMonitorFast(std::shared_ptr<const Telegram> telegram) {
// read the service code / installation status as appears on the display
if ((telegram->message_length > 18) && (telegram->offset == 0)) {
serviceCode_[0] = (serviceCode_[0] == '~') ? 0xF0 : serviceCode_[0];
has_update(telegram->read_value(serviceCode_[0], 18));
serviceCode_[0] = (serviceCode_[0] == 0xF0) ? '~' : serviceCode_[0];
has_update(telegram->read_value(serviceCode_[1], 19));
serviceCode_[2] = '\0'; // null terminate string
}
@@ -386,7 +388,9 @@ void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram
// read 3 char service code / installation status as appears on the display
if ((telegram->message_length > 3) && (telegram->offset == 0)) {
serviceCode_[0] = (serviceCode_[0] == '~') ? 0xF0 : serviceCode_[0];
has_update(telegram->read_value(serviceCode_[0], 1));
serviceCode_[0] = (serviceCode_[0] == 0xF0) ? '~' : serviceCode_[0];
has_update(telegram->read_value(serviceCode_[1], 2));
has_update(telegram->read_value(serviceCode_[2], 3));
serviceCode_[3] = '\0';

View File

@@ -43,8 +43,8 @@ bool Heatpump::publish_ha_config() {
doc["uniq_id"] = F_(heatpump);
doc["ic"] = F_(iconvalve);
char stat_t[50];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/heatpump_data"), System::hostname().c_str());
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/heatpump_data"), Mqtt::base().c_str());
doc["stat_t"] = stat_t;
doc["name"] = FJSON("Humidity");
@@ -58,8 +58,8 @@ bool Heatpump::publish_ha_config() {
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp-heatpump");
char topic[100];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/heatpump/config"), System::hostname().c_str());
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/heatpump/config"), Mqtt::base().c_str());
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
return true;

View File

@@ -49,34 +49,26 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
register_telegram_type(0x010C, F("IPMSetMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_IPMStatusMessage(t); });
}
}
// register values, depending on type (hc or wwc)
void Mixer::register_values(const Type type, uint16_t hc) {
if (type == Type::NONE) {
return; // already done
}
// store the heating circuit and type
hc_ = hc + 1;
type_ = type;
// with hc<n> or wwc<n>
uint8_t tag = TAG_NONE;
if (type_ == Type::HC) {
tag = TAG_HC1 + hc - 1;
// register the device values and set hc_ and type_
if (device_id <= 0x27) {
type_ = Type::HC;
hc_ = device_id - 0x20 + 1;
uint8_t tag = TAG_HC1 + hc_ - 1;
register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, nullptr, F("flowSetTemp"), F("Setpoint flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &flowTemp_, DeviceValueType::USHORT, FL_(div10), F("flowTemp"), F("Current flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, F("pumpStatus"), F("Pump status"), DeviceValueUOM::NONE);
register_device_value(tag, &status_, DeviceValueType::INT, nullptr, F("status"), F("Valve status"), DeviceValueUOM::PERCENT);
} else {
tag = TAG_WWC1 + hc - 1;
type_ = Type::WWC;
hc_ = device_id - 0x28 + 1;
uint8_t tag = TAG_WWC1 + hc_ - 1;
register_device_value(tag, &flowTemp_, DeviceValueType::USHORT, FL_(div10), F("flowTemp"), F("Current flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, F("pumpStatus"), F("Pump/Valve status"), DeviceValueUOM::NONE);
register_device_value(tag, &status_, DeviceValueType::INT, nullptr, F("status"), F("Current status"), DeviceValueUOM::NONE);
}
register_device_value(tag, &flowTemp_, DeviceValueType::USHORT, FL_(div10), F("flowTemp"), F("Current flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &flowSetTemp_, DeviceValueType::UINT, nullptr, F("flowSetTemp"), F("Setpoint flow temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &pumpStatus_, DeviceValueType::BOOL, nullptr, F("pumpStatus"), F("Pump/Valve status"), DeviceValueUOM::NONE);
register_device_value(tag, &status_, DeviceValueType::INT, nullptr, F("status"), F("Current status"), DeviceValueUOM::NONE);
}
// publish HA config
bool Mixer::publish_ha_config() {
// if we don't have valid values for this HC don't add it ever again
@@ -90,8 +82,8 @@ bool Mixer::publish_ha_config() {
snprintf_P(uniq_id, sizeof(uniq_id), PSTR("Mixer%02X"), device_id() - 0x20 + 1);
doc["uniq_id"] = uniq_id;
char stat_t[50];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/mixer_data"), System::hostname().c_str());
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/mixer_data"), Mqtt::base().c_str());
doc["stat_t"] = stat_t;
char name[20];
@@ -108,11 +100,11 @@ bool Mixer::publish_ha_config() {
ids.add("ems-esp-mixer");
// determine the topic, if its HC and WWC. This is determined by the incoming telegram types.
std::string topic(100, '\0');
std::string topic(Mqtt::MQTT_TOPIC_MAX_SIZE, '\0');
if (type_ == Type::HC) {
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/sensor/%s/mixer_hc%d/config"), System::hostname().c_str(), hc_);
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/sensor/%s/mixer_hc%d/config"), Mqtt::base().c_str(), hc_);
} else {
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/sensor/%s/mixer_wwc%d/config"), System::hostname().c_str(), hc_); // WWC
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/sensor/%s/mixer_wwc%d/config"), Mqtt::base().c_str(), hc_); // WWC
}
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
@@ -124,7 +116,6 @@ bool Mixer::publish_ha_config() {
// e.g. A0 00 FF 00 01 D7 00 00 00 80 00 00 00 00 03 C5
// A0 0B FF 00 01 D7 00 00 00 80 00 00 00 00 03 80
void Mixer::process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram) {
register_values(Type::HC, telegram->type_id - 0x02D7);
has_update(telegram->read_value(flowTemp_, 3)); // is * 10
has_update(telegram->read_value(flowSetTemp_, 5));
has_update(telegram->read_bitvalue(pumpStatus_, 0, 0));
@@ -135,7 +126,6 @@ void Mixer::process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> teleg
// e.g. A9 00 FF 00 02 32 02 6C 00 3C 00 3C 3C 46 02 03 03 00 3C // on 0x28
// A8 00 FF 00 02 31 02 35 00 3C 00 3C 3C 46 02 03 03 00 3C // in 0x29
void Mixer::process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram) {
register_values(Type::WWC, telegram->type_id - 0x0331);
has_update(telegram->read_value(flowTemp_, 0)); // is * 10
has_update(telegram->read_bitvalue(pumpStatus_, 2, 0));
has_update(telegram->read_value(status_, 11)); // temp status
@@ -145,8 +135,6 @@ void Mixer::process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> tele
// e.g. A0 00 FF 00 00 0C 01 00 00 00 00 00 54
// A1 00 FF 00 00 0C 02 04 00 01 1D 00 82
void Mixer::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
register_values(Type::HC, device_id() - 0x20);
// check if circuit is active, 0-off, 1-unmixed, 2-mixed
uint8_t ismixed = 0;
telegram->read_value(ismixed, 0);
@@ -171,7 +159,6 @@ void Mixer::process_MMStatusMessage(std::shared_ptr<const Telegram> telegram) {
// the heating circuit is determine by which device_id it is, 0x20 - 0x23
// 0x21 is position 2. 0x20 is typically reserved for the WM10 switch module
// see https://github.com/proddy/EMS-ESP/issues/270 and https://github.com/proddy/EMS-ESP/issues/386#issuecomment-629610918
register_values(Type::HC, device_id() - 0x20);
has_update(telegram->read_value(flowTemp_, 1)); // is * 10
has_update(telegram->read_bitvalue(pumpStatus_, 3, 2)); // is 0 or 0x64 (100%), check only bit 2
@@ -185,7 +172,6 @@ void Mixer::process_MMStatusMessage(std::shared_ptr<const Telegram> telegram) {
// Mixer on a MM10 - 0xAA
// e.g. Thermostat -> Mixer Module, type 0xAA, telegram: 10 21 AA 00 FF 0C 0A 11 0A 32 xx
void Mixer::process_MMConfigMessage(std::shared_ptr<const Telegram> telegram) {
register_values(Type::HC, device_id() - 0x20);
// pos 0: active FF = on
// pos 1: valve runtime 0C = 120 sec in units of 10 sec
}
@@ -193,7 +179,6 @@ void Mixer::process_MMConfigMessage(std::shared_ptr<const Telegram> telegram) {
// Mixer on a MM10 - 0xAC
// e.g. Thermostat -> Mixer Module, type 0xAC, telegram: 10 21 AC 00 1E 64 01 AB
void Mixer::process_MMSetMessage(std::shared_ptr<const Telegram> telegram) {
register_values(Type::HC, device_id() - 0x20);
// pos 0: flowtemp setpoint 1E = 30°C
// pos 1: position in %
}

View File

@@ -51,7 +51,6 @@ class Mixer : public EMSdevice {
int8_t status_;
uint8_t flowSetTemp_;
void register_values(const Type type, const uint16_t hc);
Type type_ = Type::NONE;
uint16_t hc_ = EMS_VALUE_USHORT_NOTSET;
};

View File

@@ -95,8 +95,8 @@ bool Solar::publish_ha_config() {
doc["name"] = FJSON("Solar Status");
doc["uniq_id"] = F_(solar);
char stat_t[50];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/solar_data"), System::hostname().c_str());
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/solar_data"), Mqtt::base().c_str());
doc["stat_t"] = stat_t;
doc["val_tpl"] = FJSON("{{value_json.solarPump}}");
@@ -108,8 +108,8 @@ bool Solar::publish_ha_config() {
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp-solar");
char topic[100];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/solar/config"), System::hostname().c_str());
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/solar/config"), Mqtt::base().c_str());
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
return true;

View File

@@ -49,8 +49,8 @@ bool Switch::publish_ha_config() {
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
doc["uniq_id"] = F_(switch);
char stat_t[50];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/switch_data"), System::hostname().c_str());
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/switch_data"), Mqtt::base().c_str());
doc["stat_t"] = stat_t;
doc["name"] = FJSON("Type");
@@ -63,8 +63,8 @@ bool Switch::publish_ha_config() {
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp-switch");
char topic[100];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/switch/config"), System::hostname().c_str());
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/switch/config"), Mqtt::base().c_str());
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
return true;

View File

@@ -151,23 +151,24 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
}
}
// register device values for common values (not heating circuit)
register_device_values();
// reserve some memory for the heating circuits (max 4 to start with)
heating_circuits_.reserve(4);
strlcpy(status_, "offline", sizeof(status_));
if (actual_master_thermostat != device_id) {
LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X"), device_id);
return; // don't fetch data if more than 1 thermostat
}
strlcpy(status_, "offline", sizeof(status_));
//
// this next section is only for the master thermostat....
//
LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X (as master)"), device_id);
// register device values for common values (not heating circuit)
register_device_values();
add_commands();
// only for for the master-thermostat, go a query all the heating circuits. This is only done once.
@@ -183,8 +184,8 @@ bool Thermostat::publish_ha_config() {
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
doc["uniq_id"] = F_(thermostat);
char stat_t[50];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/thermostat_data"), System::hostname().c_str());
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/thermostat_data"), Mqtt::base().c_str());
doc["stat_t"] = stat_t;
doc["name"] = FJSON("Thermostat Status");
@@ -197,8 +198,8 @@ bool Thermostat::publish_ha_config() {
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp-thermostat");
char topic[100];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/thermostat/config"), System::hostname().c_str());
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/thermostat/config"), Mqtt::base().c_str());
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
return true;
@@ -230,6 +231,7 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(const ui
// returns pointer to the HeatingCircuit or nullptr if it can't be found
// if its a new one, the object will be created and also the fetch flags set
std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::shared_ptr<const Telegram> telegram) {
// look through the Monitor and Set arrays to see if there is a match
uint8_t hc_num = 0;
bool toggle_ = false;
@@ -362,7 +364,7 @@ void Thermostat::register_mqtt_ha_config_hc(uint8_t hc_num) {
doc["uniq_id"] = str2;
doc["mode_cmd_t"] = str3;
doc["temp_cmd_t"] = str3;
doc["~"] = System::hostname(); // ems-esp
doc["~"] = Mqtt::base(); // ems-esp
doc["mode_stat_t"] = FJSON("~/thermostat_data");
doc["temp_stat_t"] = FJSON("~/thermostat_data");
doc["curr_temp_t"] = FJSON("~/thermostat_data");
@@ -397,8 +399,8 @@ void Thermostat::register_mqtt_ha_config_hc(uint8_t hc_num) {
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp-thermostat");
char topic[100];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/climate/%s/thermostat_hc%d/config"), System::hostname().c_str(), hc_num);
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/climate/%s/thermostat_hc%d/config"), Mqtt::base().c_str(), hc_num);
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
// enable the a special "thermostat_hc<n>" topic to take both mode strings and floats for each of the heating circuits
@@ -2088,9 +2090,6 @@ void Thermostat::register_device_values() {
register_device_value(TAG_NONE, &ibaLanguage_, DeviceValueType::ENUM, FL_(enum_ibaLanguage), F("ibaLanguage"), F("Language"), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &ibaClockOffset_, DeviceValueType::UINT, nullptr, F("ibaClockOffset"), F("Clock offset"),
DeviceValueUOM::NONE); // offset (in sec) to clock, 0xff=-1s, 0x02=2s
register_device_value(TAG_NONE, &ibaCalIntTemperature_, DeviceValueType::INT, FL_(div2), F("intoffset"), F("Offset int. temperature"), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &ibaMinExtTemperature_, DeviceValueType::INT, nullptr, F("minexttemp"), F("Min ext. temperature"),
DeviceValueUOM::DEGREES); // min ext temp for heating curve, in deg.
}
// RC300 and RC100
@@ -2109,9 +2108,12 @@ void Thermostat::register_device_values() {
// RC30 and RC35
if (model == EMS_DEVICE_FLAG_RC35 || model == EMS_DEVICE_FLAG_RC30_1) {
register_device_value(TAG_NONE, &ibaCalIntTemperature_, DeviceValueType::INT, FL_(div2), F("intoffset"), F("Offset int. temperature"), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &ibaMinExtTemperature_, DeviceValueType::INT, nullptr, F("minexttemp"), F("Min ext. temperature"),
DeviceValueUOM::DEGREES); // min ext temp for heating curve, in deg.
register_device_value(TAG_NONE, &tempsensor1_, DeviceValueType::USHORT, FL_(div10), F("inttemp1"), F("Temperature sensor 1"), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &tempsensor2_, DeviceValueType::USHORT, FL_(div10), F("inttemp2"), F("Temperature sensor 2"), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &dampedoutdoortemp_, DeviceValueType::SHORT, nullptr, F("dampedtemp"), F("Damped outdoor temperature"), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &dampedoutdoortemp_, DeviceValueType::INT, nullptr, F("dampedtemp"), F("Damped outdoor temperature"), DeviceValueUOM::DEGREES);
register_device_value(TAG_NONE, &ibaBuildingType_, DeviceValueType::ENUM, FL_(enum_ibaBuildingType2), F("building"), F("Building"), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &wwMode_, DeviceValueType::ENUM, FL_(enum_wwMode2), F("wwmode"), F("Warm water mode"), DeviceValueUOM::NONE);
register_device_value(TAG_NONE, &wwCircMode_, DeviceValueType::ENUM, FL_(enum_wwCircMode2), F("wwcircmode"), F("Warm water circulation mode"), DeviceValueUOM::NONE);
@@ -2142,6 +2144,10 @@ void Thermostat::register_device_values_hc(std::shared_ptr<emsesp::Thermostat::H
register_device_value(tag, &hc->setpoint_roomTemp, DeviceValueType::SHORT, setpoint_temp_divider, F("seltemp"), F("Setpoint room temperature"), DeviceValueUOM::DEGREES);
register_device_value(tag, &hc->curr_roomTemp, DeviceValueType::SHORT, curr_temp_divider, F("currtemp"), F("Current room temperature"), DeviceValueUOM::DEGREES);
if (device_id() != EMSESP::actual_master_thermostat()) {
return;
}
// special handling for Home Assistant
// we create special values called hatemp and hamode, which have empty fullnames so not shown in the web or console
if (Mqtt::ha_enabled()) {