mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
add mqtt base, fix mixer, fix masterthermostat, dallas fails, fix mult. roomctrl.
This commit is contained in:
@@ -9,11 +9,15 @@ See https://github.com/proddy/EMS-ESP/issues/632
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- telegrams matched to masterthermostat 0x18
|
- telegrams matched to masterthermostat 0x18
|
||||||
|
- multible roomcontrollers
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- split `show values` in smaller packages (edited)
|
- split `show values` in smaller packages (edited)
|
||||||
- extended length of IP/hostname from 32 to 48 chars (#676)
|
- extended length of IP/hostname from 32 to 48 chars (#676)
|
||||||
- check flowsensor for `tap_water_active`
|
- check flowsensor for `tap_water_active`
|
||||||
|
- mqtt prefixed with `Base`
|
||||||
|
- count Dallas sensor fails
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import SaveIcon from '@material-ui/icons/Save';
|
|||||||
import MenuItem from '@material-ui/core/MenuItem';
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
|
||||||
import { RestFormProps, FormActions, FormButton, BlockFormControlLabel, PasswordValidator } from '../components';
|
import { RestFormProps, FormActions, FormButton, BlockFormControlLabel, PasswordValidator } from '../components';
|
||||||
import { isIP, isHostname, or } from '../validators';
|
import { isIP, isHostname, or, isPath } from '../validators';
|
||||||
|
|
||||||
import { MqttSettings } from './types';
|
import { MqttSettings } from './types';
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
ValidatorForm.addValidationRule('isIPOrHostname', or(isIP, isHostname));
|
ValidatorForm.addValidationRule('isIPOrHostname', or(isIP, isHostname));
|
||||||
|
ValidatorForm.addValidationRule('isPath', isPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -55,6 +56,17 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
|
|||||||
onChange={handleValueChange('port')}
|
onChange={handleValueChange('port')}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
/>
|
/>
|
||||||
|
<TextValidator
|
||||||
|
validators={['required', 'isPath']}
|
||||||
|
errorMessages={['Base is required', "Not a valid Path"]}
|
||||||
|
name="base"
|
||||||
|
label="Base"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.base}
|
||||||
|
onChange={handleValueChange('base')}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
name="username"
|
name="username"
|
||||||
label="Username"
|
label="Username"
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export interface MqttSettings {
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
host: string;
|
host: string;
|
||||||
port: number;
|
port: number;
|
||||||
|
base: string;
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
client_id: string;
|
client_id: string;
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ export { default as isHostname } from './isHostname';
|
|||||||
export { default as isIP } from './isIP';
|
export { default as isIP } from './isIP';
|
||||||
export { default as optional } from './optional';
|
export { default as optional } from './optional';
|
||||||
export { default as or } from './or';
|
export { default as or } from './or';
|
||||||
|
export { default as isPath } from './isPath';
|
||||||
6
interface/src/validators/isPath.ts
Normal file
6
interface/src/validators/isPath.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
const pathLengthRegex = /^[^.]{0,108}$/
|
||||||
|
const pathPatternRegex = /^([a-zA-Z0-9_][a-zA-Z0-9/_-]*[a-zA-Z0-9_])$/
|
||||||
|
|
||||||
|
export default function isPath(path: string) {
|
||||||
|
return pathLengthRegex.test(path) && pathPatternRegex.test(path);
|
||||||
|
}
|
||||||
@@ -167,6 +167,7 @@ void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
|
|||||||
root["enabled"] = settings.enabled;
|
root["enabled"] = settings.enabled;
|
||||||
root["host"] = settings.host;
|
root["host"] = settings.host;
|
||||||
root["port"] = settings.port;
|
root["port"] = settings.port;
|
||||||
|
root["base"] = settings.base;
|
||||||
root["username"] = settings.username;
|
root["username"] = settings.username;
|
||||||
root["password"] = settings.password;
|
root["password"] = settings.password;
|
||||||
root["client_id"] = settings.clientId;
|
root["client_id"] = settings.clientId;
|
||||||
@@ -195,6 +196,7 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
|
|||||||
newSettings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED;
|
newSettings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED;
|
||||||
newSettings.host = root["host"] | FACTORY_MQTT_HOST;
|
newSettings.host = root["host"] | FACTORY_MQTT_HOST;
|
||||||
newSettings.port = root["port"] | FACTORY_MQTT_PORT;
|
newSettings.port = root["port"] | FACTORY_MQTT_PORT;
|
||||||
|
newSettings.base = root["base"] | FACTORY_MQTT_BASE;
|
||||||
newSettings.username = root["username"] | FACTORY_MQTT_USERNAME;
|
newSettings.username = root["username"] | FACTORY_MQTT_USERNAME;
|
||||||
newSettings.password = root["password"] | FACTORY_MQTT_PASSWORD;
|
newSettings.password = root["password"] | FACTORY_MQTT_PASSWORD;
|
||||||
newSettings.clientId = root["client_id"] | FACTORY_MQTT_CLIENT_ID;
|
newSettings.clientId = root["client_id"] | FACTORY_MQTT_CLIENT_ID;
|
||||||
|
|||||||
@@ -29,6 +29,10 @@
|
|||||||
#define FACTORY_MQTT_PORT 1883
|
#define FACTORY_MQTT_PORT 1883
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef FACTORY_MQTT_BASE
|
||||||
|
#define FACTORY_MQTT_BASE "ems-esp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FACTORY_MQTT_USERNAME
|
#ifndef FACTORY_MQTT_USERNAME
|
||||||
#define FACTORY_MQTT_USERNAME ""
|
#define FACTORY_MQTT_USERNAME ""
|
||||||
#endif
|
#endif
|
||||||
@@ -73,6 +77,7 @@ class MqttSettings {
|
|||||||
bool enabled;
|
bool enabled;
|
||||||
String host;
|
String host;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
|
String base;
|
||||||
|
|
||||||
// username and password
|
// username and password
|
||||||
String username;
|
String username;
|
||||||
|
|||||||
@@ -125,14 +125,18 @@ void DallasSensor::loop() {
|
|||||||
sensors_.back().read = true;
|
sensors_.back().read = true;
|
||||||
changed_ = true;
|
changed_ = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
sensorfails_++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
sensorfails_++;
|
||||||
LOG_ERROR(F("Unknown dallas sensor %s"), Sensor(addr).to_string().c_str());
|
LOG_ERROR(F("Unknown dallas sensor %s"), Sensor(addr).to_string().c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
sensorfails_++;
|
||||||
LOG_ERROR(F("Invalid dallas sensor %s"), Sensor(addr).to_string().c_str());
|
LOG_ERROR(F("Invalid dallas sensor %s"), Sensor(addr).to_string().c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ class DallasSensor {
|
|||||||
|
|
||||||
const std::vector<Sensor> sensors() const;
|
const std::vector<Sensor> sensors() const;
|
||||||
|
|
||||||
|
uint32_t fails() {
|
||||||
|
return sensorfails_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint8_t MAX_SENSORS = 20;
|
static constexpr uint8_t MAX_SENSORS = 20;
|
||||||
|
|
||||||
@@ -115,6 +119,7 @@ class DallasSensor {
|
|||||||
uint8_t dallas_gpio_ = 0;
|
uint8_t dallas_gpio_ = 0;
|
||||||
bool parasite_ = false;
|
bool parasite_ = false;
|
||||||
bool changed_ = false;
|
bool changed_ = false;
|
||||||
|
uint32_t sensorfails_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -190,8 +190,8 @@ bool Boiler::publish_ha_config() {
|
|||||||
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
|
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
|
||||||
doc["uniq_id"] = F_(boiler);
|
doc["uniq_id"] = F_(boiler);
|
||||||
|
|
||||||
char stat_t[50];
|
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/boiler_data"), System::hostname().c_str());
|
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/boiler_data"), Mqtt::base().c_str());
|
||||||
doc["stat_t"] = stat_t;
|
doc["stat_t"] = stat_t;
|
||||||
|
|
||||||
doc["name"] = FJSON("Service Code");
|
doc["name"] = FJSON("Service Code");
|
||||||
@@ -204,8 +204,8 @@ bool Boiler::publish_ha_config() {
|
|||||||
JsonArray ids = dev.createNestedArray("ids");
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
ids.add("ems-esp-boiler");
|
ids.add("ems-esp-boiler");
|
||||||
|
|
||||||
char topic[100];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/boiler/config"), System::hostname().c_str());
|
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/boiler/config"), Mqtt::base().c_str());
|
||||||
Mqtt::publish_ha(topic,
|
Mqtt::publish_ha(topic,
|
||||||
doc.as<JsonObject>()); // publish the config payload with retain flag
|
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
|
// read the service code / installation status as appears on the display
|
||||||
if ((telegram->message_length > 18) && (telegram->offset == 0)) {
|
if ((telegram->message_length > 18) && (telegram->offset == 0)) {
|
||||||
|
serviceCode_[0] = (serviceCode_[0] == '~') ? 0xF0 : serviceCode_[0];
|
||||||
has_update(telegram->read_value(serviceCode_[0], 18));
|
has_update(telegram->read_value(serviceCode_[0], 18));
|
||||||
|
serviceCode_[0] = (serviceCode_[0] == 0xF0) ? '~' : serviceCode_[0];
|
||||||
has_update(telegram->read_value(serviceCode_[1], 19));
|
has_update(telegram->read_value(serviceCode_[1], 19));
|
||||||
serviceCode_[2] = '\0'; // null terminate string
|
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
|
// read 3 char service code / installation status as appears on the display
|
||||||
if ((telegram->message_length > 3) && (telegram->offset == 0)) {
|
if ((telegram->message_length > 3) && (telegram->offset == 0)) {
|
||||||
|
serviceCode_[0] = (serviceCode_[0] == '~') ? 0xF0 : serviceCode_[0];
|
||||||
has_update(telegram->read_value(serviceCode_[0], 1));
|
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_[1], 2));
|
||||||
has_update(telegram->read_value(serviceCode_[2], 3));
|
has_update(telegram->read_value(serviceCode_[2], 3));
|
||||||
serviceCode_[3] = '\0';
|
serviceCode_[3] = '\0';
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ bool Heatpump::publish_ha_config() {
|
|||||||
doc["uniq_id"] = F_(heatpump);
|
doc["uniq_id"] = F_(heatpump);
|
||||||
doc["ic"] = F_(iconvalve);
|
doc["ic"] = F_(iconvalve);
|
||||||
|
|
||||||
char stat_t[50];
|
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/heatpump_data"), System::hostname().c_str());
|
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/heatpump_data"), Mqtt::base().c_str());
|
||||||
doc["stat_t"] = stat_t;
|
doc["stat_t"] = stat_t;
|
||||||
|
|
||||||
doc["name"] = FJSON("Humidity");
|
doc["name"] = FJSON("Humidity");
|
||||||
@@ -58,8 +58,8 @@ bool Heatpump::publish_ha_config() {
|
|||||||
JsonArray ids = dev.createNestedArray("ids");
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
ids.add("ems-esp-heatpump");
|
ids.add("ems-esp-heatpump");
|
||||||
|
|
||||||
char topic[100];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/heatpump/config"), System::hostname().c_str());
|
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
|
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -49,33 +49,25 @@ Mixer::Mixer(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
|
|||||||
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
|
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
|
||||||
register_telegram_type(0x010C, F("IPMSetMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_IPMStatusMessage(t); });
|
register_telegram_type(0x010C, F("IPMSetMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_IPMStatusMessage(t); });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// register the device values and set hc_ and type_
|
||||||
// register values, depending on type (hc or wwc)
|
if (device_id <= 0x27) {
|
||||||
void Mixer::register_values(const Type type, uint16_t hc) {
|
type_ = Type::HC;
|
||||||
if (type == Type::NONE) {
|
hc_ = device_id - 0x20 + 1;
|
||||||
return; // already done
|
uint8_t tag = TAG_HC1 + hc_ - 1;
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
} else {
|
|
||||||
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, &flowSetTemp_, DeviceValueType::UINT, nullptr, F("flowSetTemp"), F("Setpoint flow temperature"), DeviceValueUOM::DEGREES);
|
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 {
|
||||||
|
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, &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, &status_, DeviceValueType::INT, nullptr, F("status"), F("Current status"), DeviceValueUOM::NONE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// publish HA config
|
// publish HA config
|
||||||
bool Mixer::publish_ha_config() {
|
bool Mixer::publish_ha_config() {
|
||||||
@@ -90,8 +82,8 @@ bool Mixer::publish_ha_config() {
|
|||||||
snprintf_P(uniq_id, sizeof(uniq_id), PSTR("Mixer%02X"), device_id() - 0x20 + 1);
|
snprintf_P(uniq_id, sizeof(uniq_id), PSTR("Mixer%02X"), device_id() - 0x20 + 1);
|
||||||
doc["uniq_id"] = uniq_id;
|
doc["uniq_id"] = uniq_id;
|
||||||
|
|
||||||
char stat_t[50];
|
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/mixer_data"), System::hostname().c_str());
|
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/mixer_data"), Mqtt::base().c_str());
|
||||||
doc["stat_t"] = stat_t;
|
doc["stat_t"] = stat_t;
|
||||||
|
|
||||||
char name[20];
|
char name[20];
|
||||||
@@ -108,11 +100,11 @@ bool Mixer::publish_ha_config() {
|
|||||||
ids.add("ems-esp-mixer");
|
ids.add("ems-esp-mixer");
|
||||||
|
|
||||||
// determine the topic, if its HC and WWC. This is determined by the incoming telegram types.
|
// 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) {
|
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 {
|
} 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
|
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
|
// 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
|
// 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) {
|
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(flowTemp_, 3)); // is * 10
|
||||||
has_update(telegram->read_value(flowSetTemp_, 5));
|
has_update(telegram->read_value(flowSetTemp_, 5));
|
||||||
has_update(telegram->read_bitvalue(pumpStatus_, 0, 0));
|
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
|
// 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
|
// 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) {
|
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_value(flowTemp_, 0)); // is * 10
|
||||||
has_update(telegram->read_bitvalue(pumpStatus_, 2, 0));
|
has_update(telegram->read_bitvalue(pumpStatus_, 2, 0));
|
||||||
has_update(telegram->read_value(status_, 11)); // temp status
|
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
|
// 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
|
// A1 00 FF 00 00 0C 02 04 00 01 1D 00 82
|
||||||
void Mixer::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
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
|
// check if circuit is active, 0-off, 1-unmixed, 2-mixed
|
||||||
uint8_t ismixed = 0;
|
uint8_t ismixed = 0;
|
||||||
telegram->read_value(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
|
// 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
|
// 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
|
// 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_value(flowTemp_, 1)); // is * 10
|
||||||
has_update(telegram->read_bitvalue(pumpStatus_, 3, 2)); // is 0 or 0x64 (100%), check only bit 2
|
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
|
// Mixer on a MM10 - 0xAA
|
||||||
// e.g. Thermostat -> Mixer Module, type 0xAA, telegram: 10 21 AA 00 FF 0C 0A 11 0A 32 xx
|
// 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) {
|
void Mixer::process_MMConfigMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
register_values(Type::HC, device_id() - 0x20);
|
|
||||||
// pos 0: active FF = on
|
// pos 0: active FF = on
|
||||||
// pos 1: valve runtime 0C = 120 sec in units of 10 sec
|
// 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
|
// Mixer on a MM10 - 0xAC
|
||||||
// e.g. Thermostat -> Mixer Module, type 0xAC, telegram: 10 21 AC 00 1E 64 01 AB
|
// 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) {
|
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 0: flowtemp setpoint 1E = 30°C
|
||||||
// pos 1: position in %
|
// pos 1: position in %
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ class Mixer : public EMSdevice {
|
|||||||
int8_t status_;
|
int8_t status_;
|
||||||
uint8_t flowSetTemp_;
|
uint8_t flowSetTemp_;
|
||||||
|
|
||||||
void register_values(const Type type, const uint16_t hc);
|
|
||||||
Type type_ = Type::NONE;
|
Type type_ = Type::NONE;
|
||||||
uint16_t hc_ = EMS_VALUE_USHORT_NOTSET;
|
uint16_t hc_ = EMS_VALUE_USHORT_NOTSET;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ bool Solar::publish_ha_config() {
|
|||||||
doc["name"] = FJSON("Solar Status");
|
doc["name"] = FJSON("Solar Status");
|
||||||
doc["uniq_id"] = F_(solar);
|
doc["uniq_id"] = F_(solar);
|
||||||
|
|
||||||
char stat_t[50];
|
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/solar_data"), System::hostname().c_str());
|
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/solar_data"), Mqtt::base().c_str());
|
||||||
doc["stat_t"] = stat_t;
|
doc["stat_t"] = stat_t;
|
||||||
|
|
||||||
doc["val_tpl"] = FJSON("{{value_json.solarPump}}");
|
doc["val_tpl"] = FJSON("{{value_json.solarPump}}");
|
||||||
@@ -108,8 +108,8 @@ bool Solar::publish_ha_config() {
|
|||||||
JsonArray ids = dev.createNestedArray("ids");
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
ids.add("ems-esp-solar");
|
ids.add("ems-esp-solar");
|
||||||
|
|
||||||
char topic[100];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/solar/config"), System::hostname().c_str());
|
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
|
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ bool Switch::publish_ha_config() {
|
|||||||
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
|
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
|
||||||
doc["uniq_id"] = F_(switch);
|
doc["uniq_id"] = F_(switch);
|
||||||
|
|
||||||
char stat_t[50];
|
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/switch_data"), System::hostname().c_str());
|
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/switch_data"), Mqtt::base().c_str());
|
||||||
doc["stat_t"] = stat_t;
|
doc["stat_t"] = stat_t;
|
||||||
|
|
||||||
doc["name"] = FJSON("Type");
|
doc["name"] = FJSON("Type");
|
||||||
@@ -63,8 +63,8 @@ bool Switch::publish_ha_config() {
|
|||||||
JsonArray ids = dev.createNestedArray("ids");
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
ids.add("ems-esp-switch");
|
ids.add("ems-esp-switch");
|
||||||
|
|
||||||
char topic[100];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/switch/config"), System::hostname().c_str());
|
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
|
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -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)
|
// reserve some memory for the heating circuits (max 4 to start with)
|
||||||
heating_circuits_.reserve(4);
|
heating_circuits_.reserve(4);
|
||||||
|
|
||||||
|
strlcpy(status_, "offline", sizeof(status_));
|
||||||
|
|
||||||
if (actual_master_thermostat != device_id) {
|
if (actual_master_thermostat != device_id) {
|
||||||
LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X"), 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
|
return; // don't fetch data if more than 1 thermostat
|
||||||
}
|
}
|
||||||
|
|
||||||
strlcpy(status_, "offline", sizeof(status_));
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// this next section is only for the master thermostat....
|
// this next section is only for the master thermostat....
|
||||||
//
|
//
|
||||||
LOG_DEBUG(F("Adding new thermostat with device ID 0x%02X (as master)"), device_id);
|
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();
|
add_commands();
|
||||||
|
|
||||||
// only for for the master-thermostat, go a query all the heating circuits. This is only done once.
|
// 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;
|
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
|
||||||
doc["uniq_id"] = F_(thermostat);
|
doc["uniq_id"] = F_(thermostat);
|
||||||
|
|
||||||
char stat_t[50];
|
char stat_t[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/thermostat_data"), System::hostname().c_str());
|
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/thermostat_data"), Mqtt::base().c_str());
|
||||||
doc["stat_t"] = stat_t;
|
doc["stat_t"] = stat_t;
|
||||||
|
|
||||||
doc["name"] = FJSON("Thermostat Status");
|
doc["name"] = FJSON("Thermostat Status");
|
||||||
@@ -197,8 +198,8 @@ bool Thermostat::publish_ha_config() {
|
|||||||
JsonArray ids = dev.createNestedArray("ids");
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
ids.add("ems-esp-thermostat");
|
ids.add("ems-esp-thermostat");
|
||||||
|
|
||||||
char topic[100];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/thermostat/config"), System::hostname().c_str());
|
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
|
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||||
|
|
||||||
return true;
|
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
|
// 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
|
// 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) {
|
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
|
// look through the Monitor and Set arrays to see if there is a match
|
||||||
uint8_t hc_num = 0;
|
uint8_t hc_num = 0;
|
||||||
bool toggle_ = false;
|
bool toggle_ = false;
|
||||||
@@ -362,7 +364,7 @@ void Thermostat::register_mqtt_ha_config_hc(uint8_t hc_num) {
|
|||||||
doc["uniq_id"] = str2;
|
doc["uniq_id"] = str2;
|
||||||
doc["mode_cmd_t"] = str3;
|
doc["mode_cmd_t"] = str3;
|
||||||
doc["temp_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["mode_stat_t"] = FJSON("~/thermostat_data");
|
||||||
doc["temp_stat_t"] = FJSON("~/thermostat_data");
|
doc["temp_stat_t"] = FJSON("~/thermostat_data");
|
||||||
doc["curr_temp_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");
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
ids.add("ems-esp-thermostat");
|
ids.add("ems-esp-thermostat");
|
||||||
|
|
||||||
char topic[100];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/climate/%s/thermostat_hc%d/config"), System::hostname().c_str(), hc_num);
|
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
|
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
|
// 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, &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"),
|
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
|
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
|
// RC300 and RC100
|
||||||
@@ -2109,9 +2108,12 @@ void Thermostat::register_device_values() {
|
|||||||
|
|
||||||
// RC30 and RC35
|
// RC30 and RC35
|
||||||
if (model == EMS_DEVICE_FLAG_RC35 || model == EMS_DEVICE_FLAG_RC30_1) {
|
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, &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, &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, &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, &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);
|
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->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);
|
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
|
// 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
|
// we create special values called hatemp and hamode, which have empty fullnames so not shown in the web or console
|
||||||
if (Mqtt::ha_enabled()) {
|
if (Mqtt::ha_enabled()) {
|
||||||
|
|||||||
@@ -441,10 +441,12 @@ void EMSESP::publish_device_values(uint8_t device_type) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((device_type != DeviceType::THERMOSTAT) || (emsdevice->device_id() == EMSESP::actual_master_thermostat())) {
|
||||||
// for all other devices add the values to the json, without verbose mode
|
// for all other devices add the values to the json, without verbose mode
|
||||||
has_value |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE);
|
has_value |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if there is nothing to publish, exit
|
// if there is nothing to publish, exit
|
||||||
if (!has_value) {
|
if (!has_value) {
|
||||||
@@ -862,18 +864,19 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std::
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::add_with_json(device_type, F_(info), [device_type](const char * value, const int8_t id, JsonObject & json) { return command_info(device_type, json); });
|
Command::add_with_json(device_type, F_(info), [device_type](const char * value, const int8_t id, JsonObject & json) { return command_info(device_type, json, id); });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// export all values to info command
|
// export all values to info command
|
||||||
// value and id are ignored
|
// value and id are ignored
|
||||||
bool EMSESP::command_info(uint8_t device_type, JsonObject & json) {
|
bool EMSESP::command_info(uint8_t device_type, JsonObject & json, const int8_t id) {
|
||||||
bool has_value = false;
|
bool has_value = false;
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if (emsdevice && (emsdevice->device_type() == device_type)) {
|
if (emsdevice && (emsdevice->device_type() == device_type) &&
|
||||||
has_value |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, true); // verbose mode
|
((device_type != DeviceType::THERMOSTAT) || (emsdevice->device_id() == EMSESP::actual_master_thermostat()))) {
|
||||||
|
has_value |= emsdevice->generate_values_json(json, DeviceValueTAG::TAG_NONE, (id != 0)); // verbose mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,6 +127,10 @@ class EMSESP {
|
|||||||
return (!(dallassensor_.sensors().empty()));
|
return (!(dallassensor_.sensors().empty()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t sensor_fails() {
|
||||||
|
return dallassensor_.fails();
|
||||||
|
}
|
||||||
|
|
||||||
enum Watch : uint8_t { WATCH_OFF, WATCH_ON, WATCH_RAW, WATCH_UNKNOWN };
|
enum Watch : uint8_t { WATCH_OFF, WATCH_ON, WATCH_RAW, WATCH_UNKNOWN };
|
||||||
static void watch_id(uint16_t id);
|
static void watch_id(uint16_t id);
|
||||||
static uint16_t watch_id() {
|
static uint16_t watch_id() {
|
||||||
@@ -204,7 +208,7 @@ class EMSESP {
|
|||||||
static void process_version(std::shared_ptr<const Telegram> telegram);
|
static void process_version(std::shared_ptr<const Telegram> telegram);
|
||||||
static void publish_response(std::shared_ptr<const Telegram> telegram);
|
static void publish_response(std::shared_ptr<const Telegram> telegram);
|
||||||
static void publish_all_loop();
|
static void publish_all_loop();
|
||||||
static bool command_info(uint8_t device_type, JsonObject & json);
|
static bool command_info(uint8_t device_type, JsonObject & json, const int8_t id);
|
||||||
|
|
||||||
static constexpr uint32_t EMS_FETCH_FREQUENCY = 60000; // check every minute
|
static constexpr uint32_t EMS_FETCH_FREQUENCY = 60000; // check every minute
|
||||||
static uint32_t last_fetch_;
|
static uint32_t last_fetch_;
|
||||||
|
|||||||
38
src/mqtt.cpp
38
src/mqtt.cpp
@@ -25,7 +25,7 @@ namespace emsesp {
|
|||||||
AsyncMqttClient * Mqtt::mqttClient_;
|
AsyncMqttClient * Mqtt::mqttClient_;
|
||||||
|
|
||||||
// static parameters we make global
|
// static parameters we make global
|
||||||
std::string Mqtt::hostname_;
|
std::string Mqtt::mqtt_base_;
|
||||||
uint8_t Mqtt::mqtt_qos_;
|
uint8_t Mqtt::mqtt_qos_;
|
||||||
bool Mqtt::mqtt_retain_;
|
bool Mqtt::mqtt_retain_;
|
||||||
uint32_t Mqtt::publish_time_boiler_;
|
uint32_t Mqtt::publish_time_boiler_;
|
||||||
@@ -339,12 +339,10 @@ void Mqtt::reset_mqtt() {
|
|||||||
void Mqtt::start() {
|
void Mqtt::start() {
|
||||||
mqttClient_ = EMSESP::esp8266React.getMqttClient();
|
mqttClient_ = EMSESP::esp8266React.getMqttClient();
|
||||||
|
|
||||||
// get the hostname, which we'll use to prefix to all topics
|
|
||||||
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) { hostname_ = networkSettings.hostname.c_str(); });
|
|
||||||
|
|
||||||
// fetch MQTT settings, to see if MQTT is enabled
|
// fetch MQTT settings, to see if MQTT is enabled
|
||||||
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & mqttSettings) {
|
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & mqttSettings) {
|
||||||
mqtt_enabled_ = mqttSettings.enabled;
|
mqtt_enabled_ = mqttSettings.enabled;
|
||||||
|
mqtt_base_ = mqttSettings.base.c_str();
|
||||||
if (!mqtt_enabled_) {
|
if (!mqtt_enabled_) {
|
||||||
return; // quit, not using MQTT
|
return; // quit, not using MQTT
|
||||||
}
|
}
|
||||||
@@ -377,11 +375,9 @@ void Mqtt::start() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// create will_topic with the hostname prefixed. It has to be static because asyncmqttclient destroys the reference
|
// create will_topic with the base prefixed. It has to be static because asyncmqttclient destroys the reference
|
||||||
static char will_topic[MQTT_TOPIC_MAX_SIZE];
|
static char will_topic[MQTT_TOPIC_MAX_SIZE];
|
||||||
strlcpy(will_topic, hostname_.c_str(), MQTT_TOPIC_MAX_SIZE);
|
snprintf_P(will_topic, MQTT_TOPIC_MAX_SIZE, PSTR("%s/status"), mqtt_base_.c_str());
|
||||||
strlcat(will_topic, "/", MQTT_TOPIC_MAX_SIZE);
|
|
||||||
strlcat(will_topic, "status", MQTT_TOPIC_MAX_SIZE);
|
|
||||||
mqttClient_->setWill(will_topic, 1, true, "offline"); // with qos 1, retain true
|
mqttClient_->setWill(will_topic, 1, true, "offline"); // with qos 1, retain true
|
||||||
|
|
||||||
mqttClient_->onMessage([this](char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
mqttClient_->onMessage([this](char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||||
@@ -512,7 +508,7 @@ void Mqtt::ha_status() {
|
|||||||
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
|
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
|
||||||
|
|
||||||
doc["uniq_id"] = FJSON("ems-esp-system");
|
doc["uniq_id"] = FJSON("ems-esp-system");
|
||||||
doc["~"] = System::hostname(); // default ems-esp
|
doc["~"] = mqtt_base_; // default ems-esp
|
||||||
// doc["avty_t"] = FJSON("~/status"); // commented out, as it causes errors in HA sometimes
|
// doc["avty_t"] = FJSON("~/status"); // commented out, as it causes errors in HA sometimes
|
||||||
// doc["json_attr_t"] = FJSON("~/heartbeat"); // store also as HA attributes
|
// doc["json_attr_t"] = FJSON("~/heartbeat"); // store also as HA attributes
|
||||||
doc["stat_t"] = FJSON("~/heartbeat");
|
doc["stat_t"] = FJSON("~/heartbeat");
|
||||||
@@ -527,8 +523,8 @@ void Mqtt::ha_status() {
|
|||||||
JsonArray ids = dev.createNestedArray("ids");
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
ids.add("ems-esp-system");
|
ids.add("ems-esp-system");
|
||||||
|
|
||||||
char topic[100];
|
char topic[MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/system/config"), System::hostname().c_str());
|
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/system/config"), mqtt_base_.c_str());
|
||||||
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
|
||||||
|
|
||||||
// create the sensors
|
// create the sensors
|
||||||
@@ -545,22 +541,22 @@ void Mqtt::ha_status() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add sub or pub task to the queue.
|
// add sub or pub task to the queue.
|
||||||
// a fully-qualified topic is created by prefixing the hostname, unless it's HA
|
// a fully-qualified topic is created by prefixing the base, unless it's HA
|
||||||
// returns a pointer to the message created
|
// returns a pointer to the message created
|
||||||
std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, bool retain) {
|
std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, bool retain) {
|
||||||
if (topic.empty()) {
|
if (topic.empty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// take the topic and prefix the hostname, unless its for HA
|
// take the topic and prefix the base, unless its for HA
|
||||||
std::shared_ptr<MqttMessage> message;
|
std::shared_ptr<MqttMessage> message;
|
||||||
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, payload, retain);
|
message = std::make_shared<MqttMessage>(operation, topic, payload, retain);
|
||||||
} else {
|
} else {
|
||||||
// prefix the hostname
|
// prefix the base
|
||||||
std::string full_topic(100, '\0');
|
std::string full_topic(MQTT_TOPIC_MAX_SIZE, '\0');
|
||||||
snprintf_P(&full_topic[0], full_topic.capacity() + 1, PSTR("%s/%s"), hostname_.c_str(), topic.c_str());
|
snprintf_P(&full_topic[0], full_topic.capacity() + 1, PSTR("%s/%s"), mqtt_base_.c_str(), topic.c_str());
|
||||||
message = std::make_shared<MqttMessage>(operation, full_topic, payload, retain);
|
message = std::make_shared<MqttMessage>(operation, full_topic, payload, retain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -795,11 +791,11 @@ void Mqtt::publish_mqtt_ha_sensor(uint8_t type, // EMSdevice
|
|||||||
// if its a boiler we use the tag
|
// if its a boiler we use the tag
|
||||||
char stat_t[MQTT_TOPIC_MAX_SIZE];
|
char stat_t[MQTT_TOPIC_MAX_SIZE];
|
||||||
if (device_type == EMSdevice::DeviceType::BOILER) {
|
if (device_type == EMSdevice::DeviceType::BOILER) {
|
||||||
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/%s"), hostname_.c_str(), EMSdevice::tag_to_string(tag).c_str());
|
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/%s"), mqtt_base_.c_str(), EMSdevice::tag_to_string(tag).c_str());
|
||||||
} else if (device_type == EMSdevice::DeviceType::SYSTEM) {
|
} else if (device_type == EMSdevice::DeviceType::SYSTEM) {
|
||||||
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/heartbeat"), hostname_.c_str());
|
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/heartbeat"), mqtt_base_.c_str());
|
||||||
} else {
|
} else {
|
||||||
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/%s_data"), hostname_.c_str(), device_name);
|
snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/%s_data"), mqtt_base_.c_str(), device_name);
|
||||||
}
|
}
|
||||||
doc["stat_t"] = stat_t;
|
doc["stat_t"] = stat_t;
|
||||||
|
|
||||||
@@ -823,7 +819,7 @@ void Mqtt::publish_mqtt_ha_sensor(uint8_t type, // EMSdevice
|
|||||||
// look at the device value type
|
// look at the device value type
|
||||||
if (type == DeviceValueType::BOOL) {
|
if (type == DeviceValueType::BOOL) {
|
||||||
// binary sensor
|
// binary sensor
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/binary_sensor/%s/%s/config"), System::hostname().c_str(), uniq.c_str()); // topic
|
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/binary_sensor/%s/%s/config"), mqtt_base_.c_str(), uniq.c_str()); // topic
|
||||||
|
|
||||||
// how to render boolean
|
// how to render boolean
|
||||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||||
@@ -833,7 +829,7 @@ void Mqtt::publish_mqtt_ha_sensor(uint8_t type, // EMSdevice
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// normal HA sensor, not a boolean one
|
// normal HA sensor, not a boolean one
|
||||||
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/%s/config"), System::hostname().c_str(), uniq.c_str()); // topic
|
snprintf_P(topic, sizeof(topic), PSTR("homeassistant/sensor/%s/%s/config"), mqtt_base_.c_str(), uniq.c_str()); // topic
|
||||||
|
|
||||||
// unit of measure and map the HA icon
|
// unit of measure and map the HA icon
|
||||||
if (uom != DeviceValueUOM::NONE) {
|
if (uom != DeviceValueUOM::NONE) {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class Mqtt {
|
|||||||
enum Dallas_Format : uint8_t { SENSORID = 1, NUMBER };
|
enum Dallas_Format : uint8_t { SENSORID = 1, NUMBER };
|
||||||
enum HA_Climate_Format : uint8_t { CURRENT = 1, SETPOINT, ZERO };
|
enum HA_Climate_Format : uint8_t { CURRENT = 1, SETPOINT, ZERO };
|
||||||
|
|
||||||
static constexpr uint8_t MQTT_TOPIC_MAX_SIZE = 128; // note this should really match the user setting in mqttSettings.maxTopicLength
|
static constexpr uint8_t MQTT_TOPIC_MAX_SIZE = FACTORY_MQTT_MAX_TOPIC_LENGTH; // note this should really match the user setting in mqttSettings.maxTopicLength
|
||||||
|
|
||||||
static void on_connect();
|
static void on_connect();
|
||||||
|
|
||||||
@@ -138,6 +138,10 @@ class Mqtt {
|
|||||||
return mqtt_enabled_;
|
return mqtt_enabled_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string base() {
|
||||||
|
return mqtt_base_;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t publish_fails() {
|
static uint32_t publish_fails() {
|
||||||
return mqtt_publish_fails_;
|
return mqtt_publish_fails_;
|
||||||
}
|
}
|
||||||
@@ -249,7 +253,7 @@ class Mqtt {
|
|||||||
static uint8_t connectcount_;
|
static uint8_t connectcount_;
|
||||||
|
|
||||||
// settings, copied over
|
// settings, copied over
|
||||||
static std::string hostname_;
|
static std::string mqtt_base_;
|
||||||
static uint8_t mqtt_qos_;
|
static uint8_t mqtt_qos_;
|
||||||
static bool mqtt_retain_;
|
static bool mqtt_retain_;
|
||||||
static uint32_t publish_time_;
|
static uint32_t publish_time_;
|
||||||
|
|||||||
@@ -20,35 +20,42 @@
|
|||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
static uint32_t rc_time_ = 0;
|
// init statics
|
||||||
static int16_t remotetemp[4] = {EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET};
|
bool Roomctrl::switch_off_[HCS] = {false, false, false, false};
|
||||||
|
uint32_t Roomctrl::rc_time_[HCS] = {0, 0, 0, 0};
|
||||||
|
int16_t Roomctrl::remotetemp_[HCS] = {EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the temperature,
|
* set the temperature,
|
||||||
*/
|
*/
|
||||||
void Roomctrl::set_remotetemp(const uint8_t hc, const int16_t temp) {
|
void Roomctrl::set_remotetemp(const uint8_t hc, const int16_t temp) {
|
||||||
if (hc > 3) {
|
if (hc >= HCS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
remotetemp[hc] = temp;
|
if (remotetemp_[hc] != EMS_VALUE_SHORT_NOTSET && temp == EMS_VALUE_SHORT_NOTSET) {
|
||||||
|
switch_off_[hc] = true;
|
||||||
|
}
|
||||||
|
remotetemp_[hc] = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if remote control is active send the temperature every minute
|
* if remote control is active send the temperature every minute
|
||||||
*/
|
*/
|
||||||
void Roomctrl::send(const uint8_t addr) {
|
void Roomctrl::send(const uint8_t addr) {
|
||||||
uint8_t hc_ = addr - ADDR;
|
uint8_t hc = addr - ADDR;
|
||||||
// check address, reply only on addresses 0x18..0x1B
|
// check address, reply only on addresses 0x18..0x1B
|
||||||
if (hc_ > 3) {
|
if (hc >= HCS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// no reply if the temperature is not set
|
// no reply if the temperature is not set
|
||||||
if (remotetemp[hc_] == EMS_VALUE_SHORT_NOTSET) {
|
if (remotetemp_[hc] == EMS_VALUE_SHORT_NOTSET && !switch_off_[hc]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (uuid::get_uptime() - rc_time_ > SEND_INTERVAL) { // send every minute
|
|
||||||
rc_time_ = uuid::get_uptime(); // use EMS-ESP's millis() to prevent overhead
|
if (uuid::get_uptime() - rc_time_[hc] > SEND_INTERVAL) { // send every minute
|
||||||
|
rc_time_[hc] = uuid::get_uptime(); // use EMS-ESP's millis() to prevent overhead
|
||||||
temperature(addr, 0x00); // send to all
|
temperature(addr, 0x00); // send to all
|
||||||
|
switch_off_[hc] = false;
|
||||||
} else {
|
} else {
|
||||||
// acknowledge every poll, otherwise the master shows error A22-816
|
// acknowledge every poll, otherwise the master shows error A22-816
|
||||||
EMSuart::send_poll(addr);
|
EMSuart::send_poll(addr);
|
||||||
@@ -59,14 +66,14 @@ void Roomctrl::send(const uint8_t addr) {
|
|||||||
* check if there is a message for the remote room controller
|
* check if there is a message for the remote room controller
|
||||||
*/
|
*/
|
||||||
void Roomctrl::check(const uint8_t addr, const uint8_t * data) {
|
void Roomctrl::check(const uint8_t addr, const uint8_t * data) {
|
||||||
uint8_t hc_ = (addr & 0x7F) - ADDR;
|
uint8_t hc = (addr & 0x7F) - ADDR;
|
||||||
|
|
||||||
// check address, reply only on addresses 0x18..0x1B
|
// check address, reply only on addresses 0x18..0x1B
|
||||||
if (hc_ > 3) {
|
if (hc >= HCS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// no reply if the temperature is not set
|
// no reply if the temperature is not set
|
||||||
if (remotetemp[hc_] == EMS_VALUE_SHORT_NOTSET) {
|
if (remotetemp_[hc] == EMS_VALUE_SHORT_NOTSET) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// reply to writes with write nack byte
|
// reply to writes with write nack byte
|
||||||
@@ -78,7 +85,7 @@ void Roomctrl::check(const uint8_t addr, const uint8_t * data) {
|
|||||||
// empty message back if temperature not set or unknown message type
|
// empty message back if temperature not set or unknown message type
|
||||||
if (data[2] == 0x02) {
|
if (data[2] == 0x02) {
|
||||||
version(addr, data[0]);
|
version(addr, data[0]);
|
||||||
} else if (remotetemp[hc_] == EMS_VALUE_SHORT_NOTSET) {
|
} else if (remotetemp_[hc] == EMS_VALUE_SHORT_NOTSET) {
|
||||||
unknown(addr, data[0], data[2], data[3]);
|
unknown(addr, data[0], data[2], data[3]);
|
||||||
} else if (data[2] == 0xAF && data[3] == 0) {
|
} else if (data[2] == 0xAF && data[3] == 0) {
|
||||||
temperature(addr, data[0]);
|
temperature(addr, data[0]);
|
||||||
@@ -121,13 +128,13 @@ void Roomctrl::unknown(uint8_t addr, uint8_t dst, uint8_t type, uint8_t offset)
|
|||||||
*/
|
*/
|
||||||
void Roomctrl::temperature(uint8_t addr, uint8_t dst) {
|
void Roomctrl::temperature(uint8_t addr, uint8_t dst) {
|
||||||
uint8_t data[10];
|
uint8_t data[10];
|
||||||
uint8_t hc_ = addr - ADDR;
|
uint8_t hc = addr - ADDR;
|
||||||
data[0] = addr;
|
data[0] = addr;
|
||||||
data[1] = dst;
|
data[1] = dst;
|
||||||
data[2] = 0xAF;
|
data[2] = 0xAF;
|
||||||
data[3] = 0;
|
data[3] = 0;
|
||||||
data[4] = (uint8_t)(remotetemp[hc_] >> 8);
|
data[4] = (uint8_t)(remotetemp_[hc] >> 8);
|
||||||
data[5] = (uint8_t)(remotetemp[hc_] & 0xFF);
|
data[5] = (uint8_t)(remotetemp_[hc] & 0xFF);
|
||||||
data[6] = 0;
|
data[6] = 0;
|
||||||
data[7] = EMSbus::calculate_crc(data, 7); // apppend CRC
|
data[7] = EMSbus::calculate_crc(data, 7); // apppend CRC
|
||||||
EMSuart::transmit(data, 8);
|
EMSuart::transmit(data, 8);
|
||||||
|
|||||||
@@ -32,11 +32,17 @@ class Roomctrl {
|
|||||||
private:
|
private:
|
||||||
static constexpr uint8_t ADDR = 0x18;
|
static constexpr uint8_t ADDR = 0x18;
|
||||||
static constexpr uint32_t SEND_INTERVAL = 60000; // 1 minute
|
static constexpr uint32_t SEND_INTERVAL = 60000; // 1 minute
|
||||||
|
static constexpr uint8_t HCS = 4; // max 4 heating circuits
|
||||||
|
|
||||||
static void version(uint8_t addr, uint8_t dst);
|
static void version(uint8_t addr, uint8_t dst);
|
||||||
static void unknown(uint8_t addr, uint8_t dst, uint8_t type, uint8_t offset);
|
static void unknown(uint8_t addr, uint8_t dst, uint8_t type, uint8_t offset);
|
||||||
static void temperature(uint8_t addr, uint8_t dst);
|
static void temperature(uint8_t addr, uint8_t dst);
|
||||||
static void nack_write();
|
static void nack_write();
|
||||||
|
|
||||||
|
static bool switch_off_[HCS];
|
||||||
|
static uint32_t rc_time_[HCS];
|
||||||
|
static int16_t remotetemp_[HCS];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -401,6 +401,7 @@ void System::send_heartbeat() {
|
|||||||
doc["txread"] = EMSESP::txservice_.telegram_read_count();
|
doc["txread"] = EMSESP::txservice_.telegram_read_count();
|
||||||
doc["txwrite"] = EMSESP::txservice_.telegram_write_count();
|
doc["txwrite"] = EMSESP::txservice_.telegram_write_count();
|
||||||
doc["txfails"] = EMSESP::txservice_.telegram_fail_count();
|
doc["txfails"] = EMSESP::txservice_.telegram_fail_count();
|
||||||
|
doc["dallasfails"] = EMSESP::sensor_fails();
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
doc["freemem"] = ESP.getFreeHeap();
|
doc["freemem"] = ESP.getFreeHeap();
|
||||||
#endif
|
#endif
|
||||||
@@ -1079,6 +1080,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & json
|
|||||||
node["tx line quality"] = EMSESP::txservice_.quality();
|
node["tx line quality"] = EMSESP::txservice_.quality();
|
||||||
node["#MQTT publish fails"] = Mqtt::publish_fails();
|
node["#MQTT publish fails"] = Mqtt::publish_fails();
|
||||||
node["#dallas sensors"] = EMSESP::sensor_devices().size();
|
node["#dallas sensors"] = EMSESP::sensor_devices().size();
|
||||||
|
node["#dallas fails"] = EMSESP::sensor_fails();
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArray devices2 = json.createNestedArray("Devices");
|
JsonArray devices2 = json.createNestedArray("Devices");
|
||||||
|
|||||||
Reference in New Issue
Block a user