improvements to reduce heap and fragmentation

This commit is contained in:
proddy
2020-08-12 23:20:21 +02:00
parent eef86cc9f9
commit d01d2aad98
13 changed files with 261 additions and 220 deletions

View File

@@ -29,39 +29,39 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
LOG_DEBUG(F("Adding new Boiler with device ID 0x%02X"), device_id);
// the telegram handlers...
register_telegram_type(0x10, F("UBAErrorMessage1"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1));
register_telegram_type(0x11, F("UBAErrorMessage2"), false, std::bind(&Boiler::process_UBAErrorMessage, this, _1));
register_telegram_type(0x18, F("UBAMonitorFast"), false, std::bind(&Boiler::process_UBAMonitorFast, this, _1));
register_telegram_type(0x19, F("UBAMonitorSlow"), true, std::bind(&Boiler::process_UBAMonitorSlow, this, _1));
register_telegram_type(0x34, F("UBAMonitorWW"), false, std::bind(&Boiler::process_UBAMonitorWW, this, _1));
register_telegram_type(0x1C, F("UBAMaintenanceStatus"), false, std::bind(&Boiler::process_UBAMaintenanceStatus, this, _1));
register_telegram_type(0x2A, F("MC10Status"), false, std::bind(&Boiler::process_MC10Status, this, _1));
register_telegram_type(0x33, F("UBAParameterWW"), true, std::bind(&Boiler::process_UBAParameterWW, this, _1));
register_telegram_type(0x14, F("UBATotalUptime"), false, std::bind(&Boiler::process_UBATotalUptime, this, _1));
register_telegram_type(0x35, F("UBAFlags"), false, std::bind(&Boiler::process_UBAFlags, this, _1));
register_telegram_type(0x15, F("UBAMaintenanceData"), false, std::bind(&Boiler::process_UBAMaintenanceData, this, _1));
register_telegram_type(0x16, F("UBAParameters"), true, std::bind(&Boiler::process_UBAParameters, this, _1));
register_telegram_type(0x1A, F("UBASetPoints"), false, std::bind(&Boiler::process_UBASetPoints, this, _1));
register_telegram_type(0xD1, F("UBAOutdoorTemp"), false, std::bind(&Boiler::process_UBAOutdoorTemp, this, _1));
register_telegram_type(0xE3, F("UBAMonitorSlowPlus"), false, std::bind(&Boiler::process_UBAMonitorSlowPlus2, this, _1));
register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, std::bind(&Boiler::process_UBAMonitorFastPlus, this, _1));
register_telegram_type(0xE5, F("UBAMonitorSlowPlus"), false, std::bind(&Boiler::process_UBAMonitorSlowPlus, this, _1));
register_telegram_type(0xE9, F("UBADHWStatus"), false, std::bind(&Boiler::process_UBADHWStatus, this, _1));
register_telegram_type(0x10, F("UBAErrorMessage1"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAErrorMessage(t); });
register_telegram_type(0x11, F("UBAErrorMessage2"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAErrorMessage(t); });
register_telegram_type(0x18, F("UBAMonitorFast"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorFast(t); });
register_telegram_type(0x19, F("UBAMonitorSlow"), true, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorSlow(t); });
register_telegram_type(0x34, F("UBAMonitorWW"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorWW(t); });
register_telegram_type(0x1C, F("UBAMaintenanceStatus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMaintenanceStatus(t); });
register_telegram_type(0x2A, F("MC10Status"), false, [&](std::shared_ptr<const Telegram> t) { process_MC10Status(t); });
register_telegram_type(0x33, F("UBAParameterWW"), true, [&](std::shared_ptr<const Telegram> t) { process_UBAParameterWW(t); });
register_telegram_type(0x14, F("UBATotalUptime"), false, [&](std::shared_ptr<const Telegram> t) { process_UBATotalUptime(t); });
register_telegram_type(0x35, F("UBAFlags"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAFlags(t); });
register_telegram_type(0x15, F("UBAMaintenanceData"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMaintenanceData(t); });
register_telegram_type(0x16, F("UBAParameters"), true, [&](std::shared_ptr<const Telegram> t) { process_UBAParameters(t); });
register_telegram_type(0x1A, F("UBASetPoints"), false, [&](std::shared_ptr<const Telegram> t) { process_UBASetPoints(t); });
register_telegram_type(0xD1, F("UBAOutdoorTemp"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAOutdoorTemp(t); });
register_telegram_type(0xE3, F("UBAMonitorSlowPlus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorSlowPlus2(t); });
register_telegram_type(0xE4, F("UBAMonitorFastPlus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorFastPlus(t); });
register_telegram_type(0xE5, F("UBAMonitorSlowPlus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBAMonitorSlowPlus(t); });
register_telegram_type(0xE9, F("UBADHWStatus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBADHWStatus(t); });
// MQTT commands for boiler_cmd topic
register_mqtt_cmd(F("comfort"), std::bind(&Boiler::set_warmwater_mode, this, _1, _2));
register_mqtt_cmd(F("wwactivated"), std::bind(&Boiler::set_warmwater_activated, this, _1, _2));
register_mqtt_cmd(F("wwtapactivated"), std::bind(&Boiler::set_tapwarmwater_activated, this, _1, _2));
register_mqtt_cmd(F("wwonetime"), std::bind(&Boiler::set_warmwater_onetime, this, _1, _2));
register_mqtt_cmd(F("wwcirculation"), std::bind(&Boiler::set_warmwater_circulation, this, _1, _2));
register_mqtt_cmd(F("flowtemp"), std::bind(&Boiler::set_flow_temp, this, _1, _2));
register_mqtt_cmd(F("wwtemp"), std::bind(&Boiler::set_warmwater_temp, this, _1, _2));
register_mqtt_cmd(F("burnmaxpower"), std::bind(&Boiler::set_max_power, this, _1, _2));
register_mqtt_cmd(F("burnminpower"), std::bind(&Boiler::set_min_power, this, _1, _2));
register_mqtt_cmd(F("boilhyston"), std::bind(&Boiler::set_hyst_on, this, _1, _2));
register_mqtt_cmd(F("boilhystoff"), std::bind(&Boiler::set_hyst_off, this, _1, _2));
register_mqtt_cmd(F("burnperiod"), std::bind(&Boiler::set_burn_period, this, _1, _2));
register_mqtt_cmd(F("pumpdelay"), std::bind(&Boiler::set_pump_delay, this, _1, _2));
register_mqtt_cmd(F("comfort"), [&](const char * value, const int8_t id) { set_warmwater_mode(value, id); });
register_mqtt_cmd(F("wwactivated"), [&](const char * value, const int8_t id) { set_warmwater_activated(value, id); });
register_mqtt_cmd(F("wwtapactivated"), [&](const char * value, const int8_t id) { set_tapwarmwater_activated(value, id); });
register_mqtt_cmd(F("wwonetime"), [&](const char * value, const int8_t id) { set_warmwater_onetime(value, id); });
register_mqtt_cmd(F("wwcirculation"), [&](const char * value, const int8_t id) { set_warmwater_circulation(value, id); });
register_mqtt_cmd(F("flowtemp"), [&](const char * value, const int8_t id) { set_flow_temp(value, id); });
register_mqtt_cmd(F("wwtemp"), [&](const char * value, const int8_t id) { set_warmwater_temp(value, id); });
register_mqtt_cmd(F("burnmaxpower"), [&](const char * value, const int8_t id) { set_max_power(value, id); });
register_mqtt_cmd(F("burnminpower"), [&](const char * value, const int8_t id) { set_min_power(value, id); });
register_mqtt_cmd(F("boilhyston"), [&](const char * value, const int8_t id) { set_hyst_on(value, id); });
register_mqtt_cmd(F("boilhystoff"), [&](const char * value, const int8_t id) { set_hyst_off(value, id); });
register_mqtt_cmd(F("burnperiod"), [&](const char * value, const int8_t id) { set_burn_period(value, id); });
register_mqtt_cmd(F("pumpdelay"), [&](const char * value, const int8_t id) { set_pump_delay(value, id); });
}
// add submenu context
@@ -99,8 +99,9 @@ void Boiler::device_info(JsonArray & root) {
// publish values via MQTT
void Boiler::publish_values() {
const size_t capacity = JSON_OBJECT_SIZE(56); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/
DynamicJsonDocument doc(capacity);
// const size_t capacity = JSON_OBJECT_SIZE(56); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/
// DynamicJsonDocument doc(capacity);
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
char s[10]; // for formatting strings
@@ -862,7 +863,7 @@ void Boiler::console_commands(Shell & shell, unsigned int context) {
flash_string_vector{F_(typeid_mandatory)},
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
uint16_t type_id = Helpers::hextoint(arguments.front().c_str());
EMSESP::send_read_request(type_id, device_id());
EMSESP::send_read_request(type_id, get_device_id());
});
EMSESPShell::commands->add_command(ShellContext::BOILER,

View File

@@ -29,8 +29,8 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c
LOG_DEBUG(F("Adding new Heat Pump module with device ID 0x%02X"), device_id);
// telegram handlers
register_telegram_type(0x047B, F("HP1"), true, std::bind(&Heatpump::process_HPMonitor1, this, _1));
register_telegram_type(0x042B, F("HP2"), true, std::bind(&Heatpump::process_HPMonitor2, this, _1));
register_telegram_type(0x047B, F("HP1"), true, [&](std::shared_ptr<const Telegram> t) { process_HPMonitor1(t); });
register_telegram_type(0x042B, F("HP2"), true, [&](std::shared_ptr<const Telegram> t) { process_HPMonitor2(t); });
}
// context submenu

View File

@@ -31,21 +31,27 @@ Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const
if (flags == EMSdevice::EMS_DEVICE_FLAG_MMPLUS) {
if (device_id <= 0x27) {
// telegram handlers 0x20 - 0x27 for HC
register_telegram_type(device_id - 0x20 + 0x02D7, F("MMPLUSStatusMessage_HC"), true, std::bind(&Mixing::process_MMPLUSStatusMessage_HC, this, _1));
register_telegram_type(device_id - 0x20 + 0x02D7, F("MMPLUSStatusMessage_HC"), true, [&](std::shared_ptr<const Telegram> t) {
process_MMPLUSStatusMessage_HC(t);
});
} else {
// telegram handlers for warm water/DHW 0x28, 0x29
register_telegram_type(device_id - 0x28 + 0x0331, F("MMPLUSStatusMessage_WWC"), true, std::bind(&Mixing::process_MMPLUSStatusMessage_WWC, this, _1));
register_telegram_type(device_id - 0x28 + 0x0331, F("MMPLUSStatusMessage_WWC"), true, [&](std::shared_ptr<const Telegram> t) {
process_MMPLUSStatusMessage_WWC(t);
});
}
}
// EMS 1.0
if (flags == EMSdevice::EMS_DEVICE_FLAG_MM10) {
register_telegram_type(0x00AA, F("MMConfigMessage"), false, std::bind(&Mixing::process_MMConfigMessage, this, _1));
register_telegram_type(0x00AB, F("MMStatusMessage"), true, std::bind(&Mixing::process_MMStatusMessage, this, _1));
register_telegram_type(0x00AC, F("MMSetMessage"), false, std::bind(&Mixing::process_MMSetMessage, this, _1));
register_telegram_type(0x00AA, F("MMConfigMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_MMConfigMessage(t); });
register_telegram_type(0x00AB, F("MMStatusMessage"), true, [&](std::shared_ptr<const Telegram> t) { process_MMStatusMessage(t); });
register_telegram_type(0x00AC, F("MMSetMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_MMSetMessage(t); });
}
// HT3
if (flags == EMSdevice::EMS_DEVICE_FLAG_IPM) {
register_telegram_type(0x010C, F("IPMSetMessage"), false, std::bind(&Mixing::process_IPMStatusMessage, this, _1));
register_telegram_type(0x010C, F("IPMSetMessage"), false, [&](std::shared_ptr<const Telegram> t) { process_IPMStatusMessage(t); });
}
}
@@ -64,6 +70,7 @@ void Mixing::device_info(JsonArray & root) {
} else {
render_value_json(root, "", F("Heating Circuit"), hc_, nullptr);
}
render_value_json(root, "", F("Current flow temperature"), flowTemp_, F_(degrees), 10);
render_value_json(root, "", F("Setpoint flow temperature"), flowSetTemp_, F_(degrees));
render_value_json(root, "", F("Current pump modulation"), pumpMod_, F_(percent));
@@ -92,6 +99,7 @@ void Mixing::show_values(uuid::console::Shell & shell) {
} else {
print_value(shell, 2, F("Heating Circuit"), hc_, nullptr);
}
print_value(shell, 4, F("Current flow temperature"), flowTemp_, F_(degrees), 10);
print_value(shell, 4, F("Setpoint flow temperature"), flowSetTemp_, F_(degrees));
print_value(shell, 4, F("Current pump modulation"), pumpMod_, F_(percent));
@@ -136,7 +144,7 @@ void Mixing::publish_values() {
char topic[30];
char s[3]; // for formatting strings
strlcpy(topic, "mixing_data", 30);
strlcat(topic, Helpers::itoa(s, device_id() - 0x20 + 1), 30); // append hc to topic
strlcat(topic, Helpers::itoa(s, get_device_id() - 0x20 + 1), 30); // append hc to topic
Mqtt::publish(topic, doc);
}
@@ -168,7 +176,7 @@ void Mixing::process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> tel
// A1 00 FF 00 00 0C 02 04 00 01 1D 00 82
void Mixing::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
type_ = Type::HC;
hc_ = device_id() - 0x20 + 1;
hc_ = get_device_id() - 0x20 + 1;
uint8_t ismixed = 0;
telegram->read_value(ismixed, 0); // check if circuit is active, 0-off, 1-unmixed, 2-mixed
if (ismixed == 0) {
@@ -195,7 +203,7 @@ void Mixing::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
hc_ = device_id() - 0x20 + 1;
hc_ = get_device_id() - 0x20 + 1;
telegram->read_value(flowTemp_, 1); // is * 10
telegram->read_value(pumpMod_, 3);
telegram->read_value(flowSetTemp_, 0);
@@ -207,7 +215,7 @@ void Mixing::process_MMStatusMessage(std::shared_ptr<const Telegram> telegram) {
// Mixing on a MM10 - 0xAA
// e.g. Thermostat -> Mixing Module, type 0xAA, telegram: 10 21 AA 00 FF 0C 0A 11 0A 32 xx
void Mixing::process_MMConfigMessage(std::shared_ptr<const Telegram> telegram) {
hc_ = device_id() - 0x20 + 1;
hc_ = get_device_id() - 0x20 + 1;
// pos 0: active FF = on
// pos 1: valve runtime 0C = 120 sec in units of 10 sec
}
@@ -215,7 +223,7 @@ void Mixing::process_MMConfigMessage(std::shared_ptr<const Telegram> telegram) {
// Mixing on a MM10 - 0xAC
// e.g. Thermostat -> Mixing Module, type 0xAC, telegram: 10 21 AC 00 1E 64 01 AB
void Mixing::process_MMSetMessage(std::shared_ptr<const Telegram> telegram) {
hc_ = device_id() - 0x20 + 1;
hc_ = get_device_id() - 0x20 + 1;
// pos 0: flowtemp setpoint 1E = 30°C
// pos 1: position in %
}

View File

@@ -30,20 +30,22 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s
// telegram handlers
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM10) {
register_telegram_type(0x0097, F("SM10Monitor"), true, std::bind(&Solar::process_SM10Monitor, this, _1));
register_telegram_type(0x0097, F("SM10Monitor"), true, [&](std::shared_ptr<const Telegram> t) { process_SM10Monitor(t); });
}
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) {
register_telegram_type(0x0362, F("SM100Monitor"), true, std::bind(&Solar::process_SM100Monitor, this, _1));
register_telegram_type(0x0363, F("SM100Monitor2"), true, std::bind(&Solar::process_SM100Monitor2, this, _1));
register_telegram_type(0x0366, F("SM100Config"), true, std::bind(&Solar::process_SM100Config, this, _1));
register_telegram_type(0x0364, F("SM100Status"), false, std::bind(&Solar::process_SM100Status, this, _1));
register_telegram_type(0x036A, F("SM100Status2"), false, std::bind(&Solar::process_SM100Status2, this, _1));
register_telegram_type(0x038E, F("SM100Energy"), true, std::bind(&Solar::process_SM100Energy, this, _1));
if (flags == EMSdevice::EMS_DEVICE_FLAG_SM100) {
register_telegram_type(0x0362, F("SM100Monitor"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Monitor(t); });
register_telegram_type(0x0363, F("SM100Monitor2"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Monitor2(t); });
register_telegram_type(0x0366, F("SM100Config"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Config(t); });
register_telegram_type(0x0364, F("SM100Status"), false, [&](std::shared_ptr<const Telegram> t) { process_SM100Status(t); });
register_telegram_type(0x036A, F("SM100Status2"), false, [&](std::shared_ptr<const Telegram> t) { process_SM100Status2(t); });
register_telegram_type(0x038E, F("SM100Energy"), true, [&](std::shared_ptr<const Telegram> t) { process_SM100Energy(t); });
}
if (flags == EMSdevice::EMS_DEVICE_FLAG_ISM) {
register_telegram_type(0x0103, F("ISM1StatusMessage"), true, std::bind(&Solar::process_ISM1StatusMessage, this, _1));
register_telegram_type(0x0101, F("ISM1Set"), false, std::bind(&Solar::process_ISM1Set, this, _1));
register_telegram_type(0x0103, F("ISM1StatusMessage"), true, [&](std::shared_ptr<const Telegram> t) { process_ISM1StatusMessage(t); });
register_telegram_type(0x0101, F("ISM1Set"), false, [&](std::shared_ptr<const Telegram> t) { process_ISM1Set(t); });
}
}
@@ -106,7 +108,7 @@ void Solar::show_values(uuid::console::Shell & shell) {
// publish values via MQTT
void Solar::publish_values() {
DynamicJsonDocument doc(EMSESP_MAX_JSON_SIZE_MEDIUM);
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
char s[10]; // for formatting strings

View File

@@ -24,6 +24,8 @@ namespace emsesp {
uuid::log::Logger EMSdevice::logger_{F_(emsesp), uuid::log::Facility::CONSOLE};
std::vector<EMSdevice::TelegramFunction> EMSdevice::telegram_functions_;
std::string EMSdevice::brand_to_string() const {
switch (brand_) {
case EMSdevice::Brand::BOSCH:
@@ -198,7 +200,7 @@ void EMSdevice::show_values(uuid::console::Shell & shell) {
// for each telegram that has the fetch value set (true) do a read request
void EMSdevice::fetch_values() {
LOG_DEBUG(F("Fetching values for device ID 0x%02X"), device_id());
LOG_DEBUG(F("Fetching values for device ID 0x%02X"), get_device_id());
for (const auto & tf : telegram_functions_) {
if (tf.fetch_) {
@@ -209,7 +211,7 @@ void EMSdevice::fetch_values() {
// toggle on/off automatic fetch for a telegram id
void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) {
LOG_DEBUG(F("Toggling fetch for device ID 0x%02X, telegram ID 0x%02X to %d"), device_id(), telegram_id, toggle);
LOG_DEBUG(F("Toggling fetch for device ID 0x%02X, telegram ID 0x%02X to %d"), get_device_id(), telegram_id, toggle);
for (auto & tf : telegram_functions_) {
if (tf.telegram_type_id_ == telegram_id) {
@@ -243,22 +245,12 @@ void EMSdevice::register_mqtt_topic(const std::string & topic, mqtt_subfunction_
void EMSdevice::register_mqtt_cmd(const __FlashStringHelper * cmd, mqtt_cmdfunction_p f) {
LOG_DEBUG(F("Registering MQTT cmd %s for device type %s"), uuid::read_flash_string(cmd).c_str(), this->device_type_name().c_str());
Mqtt::add_command(this->device_type_, cmd, f);
}
EMSdevice::TelegramFunction::TelegramFunction(uint16_t telegram_type_id,
const __FlashStringHelper * telegram_type_name,
bool fetch,
process_function_p process_function)
: telegram_type_id_(telegram_type_id)
, telegram_type_name_(telegram_type_name)
, fetch_(fetch)
, process_function_(process_function) {
Mqtt::add_command(this->device_type_, this->device_id_, cmd, f);
}
// register a call back function for a specific telegram type
void EMSdevice::register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p f) {
telegram_functions_.emplace_back(telegram_type_id, std::move(telegram_type_name), fetch, std::move(f));
telegram_functions_.emplace_back(telegram_type_id, telegram_type_name, fetch, f);
}
// return the name of the telegram type
@@ -302,24 +294,22 @@ bool EMSdevice::handle_telegram(std::shared_ptr<const Telegram> telegram) {
// send Tx write with a data block
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid) {
EMSESP::send_write_request(type_id, device_id(), offset, message_data, message_length, validate_typeid);
EMSESP::send_write_request(type_id, this->get_device_id(), offset, message_data, message_length, validate_typeid);
}
// send Tx write with a single value
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid) {
uint8_t message_data[1];
message_data[0] = value;
EMSESP::send_write_request(type_id, device_id(), offset, message_data, 1, validate_typeid);
EMSESP::send_write_request(type_id, this->get_device_id(), offset, value, validate_typeid);
}
// send Tx write with a single value, with no post validation
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value) {
write_command(type_id, offset, value, 0);
EMSESP::send_write_request(type_id, this->get_device_id(), offset, value, 0);
}
// send Tx read command to the device
void EMSdevice::read_command(const uint16_t type_id) {
EMSESP::send_read_request(type_id, device_id());
EMSESP::send_read_request(type_id, get_device_id());
}
// prints a string value to the console

View File

@@ -30,10 +30,10 @@
namespace emsesp {
using namespace std::placeholders; // for `_1`
class EMSdevice {
public:
static constexpr uint8_t EMS_DEVICES_MAX_TELEGRAMS = 20;
// device_type defines which derived class to use, e.g. BOILER, THERMOSTAT etc..
EMSdevice(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
: device_type_(device_type)
@@ -47,17 +47,7 @@ class EMSdevice {
virtual ~EMSdevice() = default; // destructor of base class must always be virtual because it's a polymorphic class
/*
// https://github.com/proddy/EMS-ESP/issues/434#issuecomment-667840531
inline uint8_t device_id(uint8_t hc = 0) const {
if (((device_id_ & 0x7F) >= 0x18) && ((device_id_ & 0x7F) <= 0x1B)) {
return ((device_id_ & 0x80) + 0x18 + hc);
}
return device_id_;
}
*/
inline uint8_t device_id() const {
inline uint8_t get_device_id() const {
return device_id_;
}
@@ -157,6 +147,10 @@ class EMSdevice {
void fetch_values();
void toggle_fetch(uint16_t telegram_id, bool toggle);
static void reserve_mem(size_t n) {
telegram_functions_.reserve(n);
}
// prints a ems device value to the console, handling the correct rendering of the type
// padding is # white space
// name is the name of the parameter
@@ -296,17 +290,21 @@ class EMSdevice {
static uuid::log::Logger logger_;
class TelegramFunction {
public:
TelegramFunction(uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p process_function);
~TelegramFunction() = default;
struct TelegramFunction {
uint16_t telegram_type_id_; // it's type_id
const __FlashStringHelper * telegram_type_name_; // e.g. RC20Message
bool fetch_; // if this type_id be queried automatically
process_function_p process_function_;
process_function_p process_function_;
TelegramFunction(uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p process_function)
: telegram_type_id_(telegram_type_id)
, telegram_type_name_(telegram_type_name)
, fetch_(fetch)
, process_function_(process_function) {
}
};
std::vector<TelegramFunction> telegram_functions_; // each EMS device has its own set of registered telegram types
static std::vector<TelegramFunction> telegram_functions_; // each EMS device has its own set of registered telegram types
};
} // namespace emsesp

View File

@@ -20,9 +20,6 @@
namespace emsesp {
using DeviceFlags = emsesp::EMSdevice;
using DeviceType = emsesp::EMSdevice::DeviceType;
AsyncWebServer webServer(80);
#if defined(ESP32)
@@ -40,6 +37,8 @@ EMSESPSettingsService EMSESP::emsespSettingsService = EMSESPSettingsService(&web
EMSESPStatusService EMSESP::emsespStatusService = EMSESPStatusService(&webServer, EMSESP::esp8266React.getSecurityManager());
EMSESPDevicesService EMSESP::emsespDevicesService = EMSESPDevicesService(&webServer, EMSESP::esp8266React.getSecurityManager());
using DeviceFlags = emsesp::EMSdevice;
using DeviceType = emsesp::EMSdevice::DeviceType;
std::vector<std::unique_ptr<EMSdevice>> EMSESP::emsdevices; // array of all the detected EMS devices
std::vector<emsesp::EMSESP::Device_record> EMSESP::device_library_; // libary of all our known EMS devices so far
@@ -77,6 +76,11 @@ void EMSESP::fetch_device_values(const uint8_t device_id) {
}
}
// clears list of recognized devices
void EMSESP::clear_all_devices() {
emsdevices.clear(); // or use empty to release memory too
}
// return number of devices of a known type
uint8_t EMSESP::count_devices(const uint8_t device_type) {
uint8_t count = 0;
@@ -88,6 +92,33 @@ uint8_t EMSESP::count_devices(const uint8_t device_type) {
return count;
}
// scans for new devices
void EMSESP::scan_devices() {
EMSESP::clear_all_devices();
EMSESP::send_read_request(EMSdevice::EMS_TYPE_UBADevices, EMSdevice::EMS_DEVICE_ID_BOILER);
}
/**
* if thermostat master is 0x18 it handles only ww and hc1, hc2..hc4 handled by devices 0x19..0x1B
* we send to right device and match all reads to 0x18
*/
uint8_t EMSESP::check_master_device(const uint8_t device_id, const uint16_t type_id, const bool read) {
uint16_t mon_id[4] = {0x02A5, 0x02A6, 0x02A7, 0x02A8};
uint16_t set_id[4] = {0x02B9, 0x02BA, 0x02BB, 0x02BC};
if (actual_master_thermostat_ == 0x18) {
for (uint8_t i = 0; i < 4; i++) {
if (type_id == mon_id[i] || type_id == set_id[i]) {
if (read) {
return 0x18;
} else {
return 0x18 + i;
}
}
}
}
return device_id;
}
void EMSESP::actual_master_thermostat(const uint8_t device_id) {
actual_master_thermostat_ = device_id;
}
@@ -215,11 +246,7 @@ void EMSESP::show_ems(uuid::console::Shell & shell) {
} else if ((it.telegram_->operation) == Telegram::Operation::TX_WRITE) {
op = read_flash_string(F("WRITE"));
}
shell.printfln(F(" [%02d%c] %s %s"),
it.id_,
((it.retry_) ? '*' : ' '),
op.c_str(),
pretty_telegram(it.telegram_).c_str());
shell.printfln(F(" [%02d%c] %s %s"), it.id_, ((it.retry_) ? '*' : ' '), op.c_str(), pretty_telegram(it.telegram_).c_str());
}
}
@@ -541,7 +568,7 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
for (const auto & emsdevice : emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
shell.printf(F("%s: %s"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str());
if ((emsdevice->device_type() == EMSdevice::DeviceType::THERMOSTAT) && (emsdevice->device_id() == actual_master_thermostat())) {
if ((emsdevice->device_type() == EMSdevice::DeviceType::THERMOSTAT) && (emsdevice->get_device_id() == actual_master_thermostat())) {
shell.printf(F(" ** master device **"));
}
shell.println();
@@ -561,6 +588,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std::
return false;
}
// first check to see if we already have it, if so update the record
for (const auto & emsdevice : emsdevices) {
if (emsdevice) {
@@ -585,6 +613,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std::
}
}
// look up the rest of the details using the product_id and create the new device object
Device_record * device_p = nullptr;
for (auto & device : device_library_) {
@@ -636,6 +665,17 @@ void EMSESP::send_write_request(const uint16_t type_id,
txservice_.set_post_send_query(validate_typeid); // store which type_id to send Tx read after a write
}
void EMSESP::send_write_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t value) {
send_write_request(type_id, dest, offset, value, 0);
}
// send Tx write with a single value
void EMSESP::send_write_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid) {
uint8_t message_data[1];
message_data[0] = value;
EMSESP::send_write_request(type_id, dest, offset, message_data, 1, validate_typeid);
}
// this is main entry point when data is received on the Rx line, via emsuart library
// we check if its a complete telegram or just a single byte (which could be a poll or a return status)
// the CRC check is not done here, only when it's added to the Rx queue with add()
@@ -735,9 +775,11 @@ void EMSESP::send_raw_telegram(const char * data) {
txservice_.send_raw(data);
}
// kick off the party, start all the services
// start all the core services
// the services must be loaded in the correct order
void EMSESP::start() {
// Load our library of known devices
// Load our library of known devices. Names are stored in Flash mem.
device_library_.reserve(100);
device_library_ = {
#include "device_library.h"
};
@@ -758,6 +800,12 @@ void EMSESP::start() {
txservice_.start(); // sets bus ID, sends out request for EMS devices
sensors_.start(); // dallas external sensors
webServer.begin(); // start web server
// reserve some space for the telegram registries, to avoid memory fragmentation
EMSdevice::reserve_mem(EMSdevice::EMS_DEVICES_MAX_TELEGRAMS); // space for 20 telegram handlers
emsdevices.reserve(5); // reserve space for initially 5 devices
LOG_INFO("EMS Device library loaded with %d records", device_library_.size());
}
// main loop calling all services

View File

@@ -78,6 +78,9 @@ class EMSESP {
uint8_t * message_data,
const uint8_t message_length,
const uint16_t validate_typeid);
static void send_write_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t value);
static void send_write_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid);
static void send_raw_telegram(const char * data);
static bool device_exists(const uint8_t device_id);
@@ -87,6 +90,7 @@ class EMSESP {
static uint8_t actual_master_thermostat();
static void actual_master_thermostat(const uint8_t device_id);
static uint8_t check_master_device(const uint8_t device_id, const uint16_t type_id, const bool read);
static void show_device_values(uuid::console::Shell & shell);
static void show_sensor_values(uuid::console::Shell & shell);
@@ -134,6 +138,8 @@ class EMSESP {
static void fetch_device_values(const uint8_t device_id = 0);
static bool add_device(const uint8_t device_id, const uint8_t product_id, std::string & version, const uint8_t brand);
static void scan_devices();
static void clear_all_devices();
static std::vector<std::unique_ptr<EMSdevice>> emsdevices;

View File

@@ -28,6 +28,7 @@ AsyncMqttClient * Mqtt::mqttClient_;
std::string Mqtt::hostname_;
uint8_t Mqtt::mqtt_qos_;
uint16_t Mqtt::publish_time_;
uint8_t Mqtt::bus_id_;
std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
std::vector<Mqtt::MQTTCmdFunction> Mqtt::mqtt_cmdfunctions_;
@@ -35,38 +36,11 @@ std::vector<Mqtt::MQTTCmdFunction> Mqtt::mqtt_cmdfunctions_;
uint16_t Mqtt::mqtt_publish_fails_ = 0;
size_t Mqtt::maximum_mqtt_messages_ = Mqtt::MAX_MQTT_MESSAGES;
uint16_t Mqtt::mqtt_message_id_ = 0;
std::deque<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_;
std::list<Mqtt::QueuedMqttMessage> Mqtt::mqtt_messages_;
char will_topic_[Mqtt::MQTT_TOPIC_MAX_SIZE]; // because MQTT library keeps only char pointer
uuid::log::Logger Mqtt::logger_{F_(mqtt), uuid::log::Facility::DAEMON};
Mqtt::QueuedMqttMessage::QueuedMqttMessage(uint16_t id, std::shared_ptr<MqttMessage> && content)
: id_(id)
, content_(std::move(content)) {
retry_count_ = 0;
packet_id_ = 0;
}
MqttMessage::MqttMessage(const uint8_t operation, const std::string & topic, const std::string && payload, bool retain)
: operation(operation)
, topic(topic)
, payload(std::move(payload))
, retain(retain) {
}
Mqtt::MQTTSubFunction::MQTTSubFunction(const uint8_t device_type, const std::string && topic, const std::string && full_topic, mqtt_subfunction_p mqtt_subfunction)
: device_type_(device_type)
, topic_(topic)
, full_topic_(full_topic)
, mqtt_subfunction_(mqtt_subfunction) {
}
Mqtt::MQTTCmdFunction::MQTTCmdFunction(const uint8_t device_type, const __FlashStringHelper * cmd, mqtt_cmdfunction_p mqtt_cmdfunction)
: device_type_(device_type)
, cmd_(cmd)
, mqtt_cmdfunction_(mqtt_cmdfunction) {
}
// subscribe to an MQTT topic, and store the associated callback function
// only if it already hasn't been added
void Mqtt::subscribe(const uint8_t device_type, const std::string & topic, mqtt_subfunction_p cb) {
@@ -88,10 +62,11 @@ void Mqtt::subscribe(const uint8_t device_type, const std::string & topic, mqtt_
}
// adds a command and callback function for a specific device
void Mqtt::add_command(const uint8_t device_type, const __FlashStringHelper * cmd, mqtt_cmdfunction_p cb) {
void Mqtt::add_command(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, mqtt_cmdfunction_p cb) {
// subscribe to the command topic if it doesn't exist yet
// create the cmd topic for a device like "<device_type>_cmd" e.g. "boiler_cmd"
// unless its a system MQTT command, then its system_cmd
std::string cmd_topic(40, '\0');
if (device_type == EMSdevice::DeviceType::SERVICEKEY) {
cmd_topic = MQTT_SYSTEM_CMD; // hard-coded system
@@ -111,8 +86,7 @@ void Mqtt::add_command(const uint8_t device_type, const __FlashStringHelper * cm
Mqtt::subscribe(device_type, cmd_topic, nullptr); // use an empty function handler to signal this is a command function
}
// add the function to our list
mqtt_cmdfunctions_.emplace_back(device_type, std::move(cmd), std::move(cb));
mqtt_cmdfunctions_.emplace_back(device_type, device_id, cmd, cb);
}
// subscribe to an MQTT topic, and store the associated callback function. For generic functions not tied to a specific device
@@ -366,6 +340,8 @@ void Mqtt::start() {
mqtt_qos_ = mqttSettings.mqtt_qos;
});
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { bus_id_ = settings.ems_bus_id; });
mqttClient_->onConnect([this](bool sessionPresent) { on_connect(); });
mqttClient_->onDisconnect([this](AsyncMqttClientDisconnectReason reason) {
@@ -402,6 +378,10 @@ void Mqtt::start() {
// publish
on_publish(packetId);
});
// create space for command buffer, to avoid heap memory fragmentation
mqtt_cmdfunctions_.reserve(40); // current count with boiler+thermostat is 37
mqtt_subfunctions_.reserve(10);
}
void Mqtt::set_publish_time(uint16_t publish_time) {
@@ -432,8 +412,8 @@ void Mqtt::on_connect() {
// add the system MQTT subscriptions, only if its a fresh start with no previous subscriptions
// these commands respond to the topic "system_cmd" and take a payload like {cmd:"", data:"", id:""}
if (mqtt_subfunctions_.empty()) {
add_command(EMSdevice::DeviceType::SERVICEKEY, F("pin"), System::mqtt_command_pin);
add_command(EMSdevice::DeviceType::SERVICEKEY, F("send"), System::mqtt_command_send);
add_command(EMSdevice::DeviceType::SERVICEKEY, bus_id_, F("pin"), System::mqtt_command_pin);
add_command(EMSdevice::DeviceType::SERVICEKEY, bus_id_, F("send"), System::mqtt_command_send);
}
LOG_INFO(F("MQTT connected"));

View File

@@ -24,7 +24,7 @@
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <functional>
#include <AsyncMqttClient.h>
@@ -46,16 +46,20 @@ namespace emsesp {
using mqtt_subfunction_p = std::function<void(const char * message)>;
using mqtt_cmdfunction_p = std::function<void(const char * data, const int8_t id)>;
using namespace std::placeholders; // for `_1`
struct MqttMessage {
MqttMessage(const uint8_t operation, const std::string & topic, const std::string && payload, bool retain);
~MqttMessage() = default;
const uint8_t operation;
const std::string topic;
const std::string payload;
const bool retain;
MqttMessage(const uint8_t operation, const std::string & topic, const std::string && payload, bool retain)
: operation(operation)
, topic(topic)
, payload(std::move(payload))
, retain(retain) {
}
};
class Mqtt {
@@ -74,7 +78,7 @@ class Mqtt {
static void subscribe(const std::string & topic, mqtt_subfunction_p cb);
static void resubscribe();
static void add_command(const uint8_t device_type, const __FlashStringHelper * cmd, mqtt_cmdfunction_p cb);
static void add_command(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, mqtt_cmdfunction_p cb);
static void publish(const std::string & topic, const std::string & payload, bool retain = false);
static void publish(const std::string & topic, const JsonDocument & payload, bool retain = false);
@@ -106,16 +110,18 @@ class Mqtt {
mqtt_publish_fails_ = 0;
}
static std::string hostname_;
class MQTTCmdFunction {
public:
MQTTCmdFunction(const uint8_t device_type, const __FlashStringHelper * cmd, mqtt_cmdfunction_p mqtt_cmdfunction);
~MQTTCmdFunction() = default;
const uint8_t device_type_;
struct MQTTCmdFunction {
uint8_t device_type_;
uint8_t device_id_;
const __FlashStringHelper * cmd_;
mqtt_cmdfunction_p mqtt_cmdfunction_;
MQTTCmdFunction(uint8_t device_type, uint8_t device_id, const __FlashStringHelper * cmd, mqtt_cmdfunction_p mqtt_cmdfunction)
: device_type_(device_type)
, device_id_(device_id)
, cmd_(cmd)
, mqtt_cmdfunction_(mqtt_cmdfunction) {
}
};
static std::vector<MQTTCmdFunction> commands() {
@@ -127,15 +133,20 @@ class Mqtt {
class QueuedMqttMessage {
public:
QueuedMqttMessage(uint16_t id, std::shared_ptr<MqttMessage> && content);
~QueuedMqttMessage() = default;
const uint16_t id_;
const std::shared_ptr<const MqttMessage> content_;
uint8_t retry_count_;
uint16_t packet_id_;
~QueuedMqttMessage() = default;
QueuedMqttMessage(uint16_t id, std::shared_ptr<MqttMessage> && content)
: id_(id)
, content_(std::move(content)) {
retry_count_ = 0;
packet_id_ = 0;
}
};
static std::deque<QueuedMqttMessage> mqtt_messages_;
static std::list<QueuedMqttMessage> mqtt_messages_;
static AsyncMqttClient * mqttClient_;
@@ -143,7 +154,7 @@ class Mqtt {
static uint16_t mqtt_message_id_;
static bool mqtt_retain_;
static constexpr size_t MAX_MQTT_MESSAGES = 30; // size of queue
static constexpr size_t MAX_MQTT_MESSAGES = 20; // size of queue
static constexpr uint32_t MQTT_PUBLISH_WAIT = 200; // delay between sending publishes, to account for large payloads
static constexpr uint8_t MQTT_PUBLISH_MAX_RETRY = 3; // max retries for giving up on publishing
@@ -159,15 +170,18 @@ class Mqtt {
static uint16_t mqtt_publish_fails_;
// function handlers for MQTT subscriptions
class MQTTSubFunction {
public:
MQTTSubFunction(const uint8_t device_type, const std::string && topic, const std::string && full_topic, mqtt_subfunction_p mqtt_subfunction);
~MQTTSubFunction() = default;
const uint8_t device_type_; // which device type, from DeviceType::
struct MQTTSubFunction {
uint8_t device_type_; // which device type, from DeviceType::
const std::string topic_;
const std::string full_topic_; // the fully qualified topic name, usually with the hostname prefixed
mqtt_subfunction_p mqtt_subfunction_; // can be empty
MQTTSubFunction(uint8_t device_type, const std::string && topic, const std::string && full_topic, mqtt_subfunction_p mqtt_subfunction)
: device_type_(device_type)
, topic_(topic)
, full_topic_(full_topic)
, mqtt_subfunction_(mqtt_subfunction) {
}
};
static std::vector<MQTTSubFunction> mqtt_subfunctions_; // list of mqtt subscribe callbacks for all devices
@@ -177,8 +191,10 @@ class Mqtt {
uint32_t last_publish_ = 0;
// settings, copied over
static uint8_t mqtt_qos_;
static uint16_t publish_time_;
static std::string hostname_;
static uint8_t mqtt_qos_;
static uint16_t publish_time_;
static uint8_t bus_id_;
};
} // namespace emsesp

View File

@@ -127,11 +127,6 @@ std::string Telegram::to_string_message() const {
return Helpers::data_to_hex(this->message_data, this->message_length);
}
RxService::QueuedRxTelegram::QueuedRxTelegram(uint16_t id, std::shared_ptr<Telegram> && telegram)
: id_(id)
, telegram_(std::move(telegram)) {
}
// empty queue, don't process them
void RxService::flush_rx_queue() {
rx_telegrams_.clear();
@@ -143,12 +138,9 @@ void RxService::flush_rx_queue() {
void RxService::loop() {
while (!rx_telegrams_.empty()) {
auto telegram = rx_telegrams_.front().telegram_;
(void)EMSESP::process_telegram(telegram); // further process the telegram
increment_telegram_count(); // increase count
rx_telegrams_.pop_front(); // remove it from the queue
increment_telegram_count(); // increase count
rx_telegrams_.pop_front(); // remove it from the queue
}
}
@@ -221,11 +213,15 @@ void RxService::add(uint8_t * data, uint8_t length) {
LOG_DEBUG(F("[DEBUG] New Rx [#%d] telegram, message length %d"), rx_telegram_id_, message_length);
#endif
// if we don't have a type_id or empty data block, exit
if ((type_id == 0) || (message_length == 0)) {
// if we don't have a type_id exit,
// do not exit on empty message, it is checked for toggle fetch
if (type_id == 0) {
return;
}
// if we receive a hc2.. telegram from 0x19.. match it to master_thermostat if master is 0x18
src = EMSESP::check_master_device(src, type_id, true);
// create the telegram
auto telegram = std::make_shared<Telegram>(Telegram::Operation::RX, src, dest, type_id, offset, message_data, message_length);
@@ -241,12 +237,6 @@ void RxService::add(uint8_t * data, uint8_t length) {
// Tx CODE starts here...
//
TxService::QueuedTxTelegram::QueuedTxTelegram(uint16_t id, std::shared_ptr<Telegram> && telegram, bool retry)
: id_(id)
, telegram_(std::move(telegram))
, retry_(retry) {
}
// empty queue, don't process
void TxService::flush_tx_queue() {
tx_telegrams_.clear();
@@ -295,16 +285,12 @@ void TxService::send() {
}
// if we're in read-only mode (tx_mode 0) forget the Tx call
if (tx_mode() == 0) {
tx_telegrams_.pop_front();
return;
if (tx_mode() != 0) {
send_telegram(tx_telegrams_.front());
}
// send next telegram in the queue (which is actually a list!)
send_telegram(tx_telegrams_.front());
// remove the telegram from the queue
tx_telegrams_.pop_front();
tx_telegrams_.pop_front(); // remove the telegram from the queue
}
// process a Tx telegram
@@ -324,6 +310,10 @@ void TxService::send_telegram(const QueuedTxTelegram & tx_telegram) {
// dest - for READ the MSB must be set
// fix the READ or WRITE depending on the operation
uint8_t dest = telegram->dest;
// check if we have to manipulate the id for thermostats > 0x18
dest = EMSESP::check_master_device(dest, telegram->type_id, false);
if (telegram->operation == Telegram::Operation::TX_READ) {
dest |= 0x80; // read has 8th bit set for the destination
}
@@ -570,7 +560,7 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui
return;
}
#ifdef EMSESP_DENUG
#ifdef EMSESP_DEBUG
LOG_DEBUG(F("[DEBUG] Last Tx %s operation failed. Retry #%d. sent message: %s, received: %s"),
(operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"),
retry_count_,

View File

@@ -20,9 +20,7 @@
#define EMSESP_TELEGRAM_H
#include <string>
#include <deque>
#include <memory> // for unique ptrs
#include <vector>
#include <list>
// UART drivers
#if defined(ESP8266)
@@ -197,7 +195,7 @@ class EMSbus {
class RxService : public EMSbus {
public:
static constexpr size_t MAX_RX_TELEGRAMS = 20;
static constexpr size_t MAX_RX_TELEGRAMS = 10;
RxService() = default;
~RxService() = default;
@@ -226,31 +224,32 @@ class RxService : public EMSbus {
class QueuedRxTelegram {
public:
QueuedRxTelegram(uint16_t id, std::shared_ptr<Telegram> && telegram);
~QueuedRxTelegram() = default;
uint16_t id_; // sequential identifier
const uint16_t id_;
const std::shared_ptr<const Telegram> telegram_;
~QueuedRxTelegram() = default;
QueuedRxTelegram(uint16_t id, std::shared_ptr<Telegram> && telegram)
: id_(id)
, telegram_(std::move(telegram)) {
}
};
const std::deque<QueuedRxTelegram> queue() const {
const std::list<QueuedRxTelegram> queue() const {
return rx_telegrams_;
}
private:
uint32_t last_rx_check_ = 0;
uint8_t rx_telegram_id_ = 0; // queue counter
uint32_t last_rx_check_ = 0;
uint8_t rx_telegram_id_ = 0; // queue counter
uint16_t telegram_count_ = 0; // # Rx received
uint16_t telegram_error_count_ = 0; // # Rx CRC errors
std::deque<QueuedRxTelegram> rx_telegrams_;
std::list<QueuedRxTelegram> rx_telegrams_;
};
class TxService : public EMSbus {
public:
static constexpr size_t MAX_TX_TELEGRAMS = 30; // size of Tx queue
static constexpr size_t MAX_TX_TELEGRAMS = 20; // size of Tx queue
static constexpr uint8_t TX_WRITE_FAIL = 4;
static constexpr uint8_t TX_WRITE_SUCCESS = 1;
@@ -336,26 +335,29 @@ class TxService : public EMSbus {
class QueuedTxTelegram {
public:
QueuedTxTelegram(uint16_t id, std::shared_ptr<Telegram> && telegram, bool retry);
~QueuedTxTelegram() = default;
uint16_t id_; // sequential identifier
const uint16_t id_;
const std::shared_ptr<const Telegram> telegram_;
bool retry_; // is a retry
const bool retry_; // is a retry
~QueuedTxTelegram() = default;
QueuedTxTelegram(uint16_t id, std::shared_ptr<Telegram> && telegram, bool retry)
: id_(id)
, telegram_(std::move(telegram))
, retry_(retry) {
}
};
const std::deque<QueuedTxTelegram> queue() const {
const std::list<QueuedTxTelegram> queue() const {
return tx_telegrams_;
}
static constexpr uint8_t MAXIMUM_TX_RETRIES = 3;
private:
uint8_t tx_telegram_id_ = 0; // queue counter
uint8_t tx_telegram_id_ = 0; // queue counter
uint32_t last_tx_check_ = 0;
uint32_t last_tx_check_ = 0;
std::deque<QueuedTxTelegram> tx_telegrams_;
std::list<QueuedTxTelegram> tx_telegrams_;
uint16_t telegram_read_count_ = 0; // # Tx successful reads
uint16_t telegram_write_count_ = 0; // # Tx successful writes

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "2.0.0b12-1"
#define EMSESP_APP_VERSION "2.0.0b12-2"