some hopeful memory optimizations to reduce defrag

This commit is contained in:
proddy
2020-10-04 20:22:10 +02:00
parent 85a59a174c
commit a15bc21f50
9 changed files with 84 additions and 73 deletions

View File

@@ -30,6 +30,7 @@ class FSPersistence {
DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize); DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize);
DeserializationError error = deserializeJson(jsonDocument, settingsFile); DeserializationError error = deserializeJson(jsonDocument, settingsFile);
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) { if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
jsonDocument.shrinkToFit(); // added by proddy
JsonObject jsonObject = jsonDocument.as<JsonObject>(); JsonObject jsonObject = jsonDocument.as<JsonObject>();
// debug added by Proddy // debug added by Proddy

View File

@@ -152,8 +152,8 @@ void Mixing::register_mqtt_ha_config(const char * topic) {
doc["uniq_id"] = F("mixing"); doc["uniq_id"] = F("mixing");
doc["ic"] = F("mdi:home-thermometer-outline"); doc["ic"] = F("mdi:home-thermometer-outline");
std::string stat_t(50, '\0'); char stat_t[50];
snprintf_P(&stat_t[0], stat_t.capacity() + 1, PSTR("%s/%s"), System::hostname().c_str(), topic); snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/%s"), System::hostname().c_str(), topic);
doc["stat_t"] = stat_t; doc["stat_t"] = stat_t;
doc["val_tpl"] = F("{{value_json.pumpStatus}}"); doc["val_tpl"] = F("{{value_json.pumpStatus}}");

View File

@@ -60,30 +60,28 @@ bool Solar::command_info(const char * value, const int8_t id, JsonObject & outpu
// print to web // print to web
void Solar::device_info_web(JsonArray & root) { void Solar::device_info_web(JsonArray & root) {
render_value_json(root, "", F("Collector temperature (TS1)"), collectorTemp_, F_(degrees), 10); render_value_json(root, "", F_(collectorTemp), collectorTemp_, F_(degrees), 10);
render_value_json(root, "", F("Tank bottom temperature (TS2)"), tankBottomTemp_, F_(degrees), 10); render_value_json(root, "", F_(tankBottomTemp), tankBottomTemp_, F_(degrees), 10);
render_value_json(root, "", F("Tank bottom temperature (TS5)"), tankBottomTemp2_, F_(degrees), 10); render_value_json(root, "", F_(tankBottomTemp2), tankBottomTemp2_, F_(degrees), 10);
render_value_json(root, "", F("Heat exchanger temperature (TS6)"), heatExchangerTemp_, F_(degrees), 10); render_value_json(root, "", F_(heatExchangerTemp), heatExchangerTemp_, F_(degrees), 10);
render_value_json(root, "", F("Solar pump modulation (PS1)"), solarPumpModulation_, F_(percent)); render_value_json(root, "", F_(solarPumpModulation), solarPumpModulation_, F_(percent));
render_value_json(root, "", F("Cylinder pump modulation (PS5)"), cylinderPumpModulation_, F_(percent)); render_value_json(root, "", F_(cylinderPumpModulation), cylinderPumpModulation_, F_(percent));
render_value_json(root, "", F("Valve (VS2) status"), valveStatus_, nullptr, EMS_VALUE_BOOL); render_value_json(root, "", F_(valveStatus), valveStatus_, nullptr, EMS_VALUE_BOOL);
render_value_json(root, "", F("Solar Pump (PS1) active"), solarPump_, nullptr, EMS_VALUE_BOOL); render_value_json(root, "", F_(solarPump), solarPump_, nullptr, EMS_VALUE_BOOL);
render_value_json(root, "", F_(tankHeated), tankHeated_, nullptr, EMS_VALUE_BOOL);
render_value_json(root, "", F_(collectorShutdown), collectorShutdown_, nullptr, EMS_VALUE_BOOL);
render_value_json(root, "", F_(energyLastHour), energyLastHour_, F_(wh), 10);
render_value_json(root, "", F_(energyToday), energyToday_, F_(wh));
render_value_json(root, "", F_(energyTotal), energyTotal_, F_(kwh), 10);
if (Helpers::hasValue(pumpWorkMin_)) { if (Helpers::hasValue(pumpWorkMin_)) {
JsonObject dataElement; JsonObject dataElement;
dataElement = root.createNestedObject(); dataElement = root.createNestedObject();
dataElement["name"] = F("Pump working time"); dataElement["name"] = F_(pumpWorkMin);
std::string time_str(60, '\0'); char time_str[60];
snprintf_P(&time_str[0], time_str.capacity() + 1, PSTR("%d days %d hours %d minutes"), pumpWorkMin_ / 1440, (pumpWorkMin_ % 1440) / 60, pumpWorkMin_ % 60); snprintf_P(time_str, sizeof(time_str), PSTR("%d days %d hours %d minutes"), pumpWorkMin_ / 1440, (pumpWorkMin_ % 1440) / 60, pumpWorkMin_ % 60);
dataElement["value"] = time_str; dataElement["value"] = time_str;
} }
render_value_json(root, "", F("Tank Heated"), tankHeated_, nullptr, EMS_VALUE_BOOL);
render_value_json(root, "", F("Collector shutdown"), collectorShutdown_, nullptr, EMS_VALUE_BOOL);
render_value_json(root, "", F("Energy last hour"), energyLastHour_, F_(wh), 10);
render_value_json(root, "", F("Energy today"), energyToday_, F_(wh));
render_value_json(root, "", F("Energy total"), energyTotal_, F_(kwh), 10);
} }
// display all values into the shell console // display all values into the shell console
@@ -112,7 +110,11 @@ void Solar::show_values(uuid::console::Shell & shell) {
print_value_json(shell, F("energyTotal"), F_(energyTotal), F_(kwh), output); print_value_json(shell, F("energyTotal"), F_(energyTotal), F_(kwh), output);
if (Helpers::hasValue(pumpWorkMin_)) { if (Helpers::hasValue(pumpWorkMin_)) {
shell.printfln(F(" Pump working time: %d days %d hours %d minutes"), pumpWorkMin_ / 1440, (pumpWorkMin_ % 1440) / 60, pumpWorkMin_ % 60); shell.printfln(F(" %s: %d days %d hours %d minutes"),
uuid::read_flash_string(F_(pumpWorkMin)).c_str(),
pumpWorkMin_ / 1440,
(pumpWorkMin_ % 1440) / 60,
pumpWorkMin_ % 60);
} }
} }
@@ -134,13 +136,13 @@ void Solar::publish_values() {
void Solar::register_mqtt_ha_config() { void Solar::register_mqtt_ha_config() {
// Create the Master device // Create the Master device
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
doc["name"] = F("EMS-ESP"); doc["name"] = "EMS-ESP";
doc["uniq_id"] = F("solar"); doc["uniq_id"] = "solar";
doc["ic"] = F("mdi:home-thermometer-outline"); doc["ic"] = "mdi:home-thermometer-outline";
doc["stat_t"] = F("ems-esp/solar_data"); doc["stat_t"] = "ems-esp/solar_data";
doc["val_tpl"] = F("{{value_json.solarPump}}"); doc["val_tpl"] = "{{value_json.solarPump}}";
JsonObject dev = doc.createNestedObject("dev"); JsonObject dev = doc.createNestedObject("dev");
dev["name"] = F("EMS-ESP Solar"); dev["name"] = "EMS-ESP Solar";
dev["sw"] = EMSESP_APP_VERSION; dev["sw"] = EMSESP_APP_VERSION;
dev["mf"] = this->brand_to_string(); dev["mf"] = this->brand_to_string();
dev["mdl"] = this->name(); dev["mdl"] = this->name();

View File

@@ -193,8 +193,8 @@ void Thermostat::device_info_web(JsonArray & root) {
} }
// create prefix with heating circuit number // create prefix with heating circuit number
std::string hc_str(5, '\0'); char hc_str[5];
snprintf_P(&hc_str[0], hc_str.capacity() + 1, PSTR("hc%d: "), hc->hc_num()); snprintf_P(hc_str, sizeof(hc_str), PSTR("hc%d: "), hc->hc_num());
render_value_json(root, hc_str, F_(currtemp), hc->curr_roomTemp, F_(degrees), format_curr); render_value_json(root, hc_str, F_(currtemp), hc->curr_roomTemp, F_(degrees), format_curr);
render_value_json(root, hc_str, F_(seltemp), hc->setpoint_roomTemp, F_(degrees), format_setpoint); render_value_json(root, hc_str, F_(seltemp), hc->setpoint_roomTemp, F_(degrees), format_setpoint);
@@ -202,23 +202,23 @@ void Thermostat::device_info_web(JsonArray & root) {
JsonObject dataElement; JsonObject dataElement;
dataElement = root.createNestedObject(); dataElement = root.createNestedObject();
std::string mode_str(15, '\0'); char mode_str[15];
snprintf_P(&mode_str[0], mode_str.capacity() + 1, PSTR("%sMode"), hc_str.c_str()); snprintf_P(mode_str, sizeof(mode_str), PSTR("%sMode"), hc_str);
dataElement["name"] = mode_str; dataElement["name"] = mode_str;
std::string modetype_str(20, '\0'); char modetype_str[20];
if (Helpers::hasValue(hc->summer_mode) && hc->summer_mode) { if (Helpers::hasValue(hc->summer_mode) && hc->summer_mode) {
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - summer"), mode_tostring(hc->get_mode(flags)).c_str()); snprintf_P(modetype_str, sizeof(modetype_str), PSTR("%s - summer"), mode_tostring(hc->get_mode(flags)).c_str());
} else if (Helpers::hasValue(hc->holiday_mode) && hc->holiday_mode) { } else if (Helpers::hasValue(hc->holiday_mode) && hc->holiday_mode) {
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - holiday"), mode_tostring(hc->get_mode(flags)).c_str()); snprintf_P(modetype_str, sizeof(modetype_str), PSTR("%s - holiday"), mode_tostring(hc->get_mode(flags)).c_str());
} else if (Helpers::hasValue(hc->mode_type)) { } else if (Helpers::hasValue(hc->mode_type)) {
snprintf_P(&modetype_str[0], snprintf_P(modetype_str,
modetype_str.capacity() + 1, sizeof(modetype_str),
PSTR("%s - %s"), PSTR("%s - %s"),
mode_tostring(hc->get_mode(flags)).c_str(), mode_tostring(hc->get_mode(flags)).c_str(),
mode_tostring(hc->get_mode_type(flags)).c_str()); mode_tostring(hc->get_mode_type(flags)).c_str());
} else { } else {
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, mode_tostring(hc->get_mode(flags)).c_str()); snprintf_P(modetype_str, sizeof(modetype_str), mode_tostring(hc->get_mode(flags)).c_str());
} }
dataElement["value"] = modetype_str; dataElement["value"] = modetype_str;
} }
@@ -716,12 +716,12 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
void Thermostat::register_mqtt_ha_config(uint8_t hc_num) { void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc;
std::string str1(40, '\0'); char str1[40];
snprintf_P(&str1[0], str1.capacity() + 1, PSTR("Thermostat hc%d"), hc_num); snprintf_P(str1, sizeof(str1), PSTR("Thermostat hc%d"), hc_num);
doc["name"] = str1; doc["name"] = str1;
std::string str2(40, '\0'); char str2[40];
snprintf_P(&str2[0], str2.capacity() + 1, PSTR("thermostat_hc%d"), hc_num); snprintf_P(str2, sizeof(str2), PSTR("thermostat_hc%d"), hc_num);
doc["uniq_id"] = str2; doc["uniq_id"] = str2;
doc["~"] = F("ems-esp"); doc["~"] = F("ems-esp");
@@ -731,16 +731,16 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
doc["temp_stat_t"] = F("~/thermostat_data"); doc["temp_stat_t"] = F("~/thermostat_data");
doc["curr_temp_t"] = F("~/thermostat_data"); doc["curr_temp_t"] = F("~/thermostat_data");
std::string mode_str(30, '\0'); char mode_str[30];
snprintf_P(&mode_str[0], 30, PSTR("{{value_json.hc%d.mode}}"), hc_num); snprintf_P(mode_str, sizeof(mode_str), PSTR("{{value_json.hc%d.mode}}"), hc_num);
doc["mode_stat_tpl"] = mode_str; doc["mode_stat_tpl"] = mode_str;
std::string seltemp_str(30, '\0'); char seltemp_str[30];
snprintf_P(&seltemp_str[0], 30, PSTR("{{value_json.hc%d.seltemp}}"), hc_num); snprintf_P(seltemp_str, sizeof(seltemp_str), PSTR("{{value_json.hc%d.seltemp}}"), hc_num);
doc["temp_stat_tpl"] = seltemp_str; doc["temp_stat_tpl"] = seltemp_str;
std::string currtemp_str(30, '\0'); char currtemp_str[30];
snprintf_P(&currtemp_str[0], 30, PSTR("{{value_json.hc%d.currtemp}}"), hc_num); snprintf_P(currtemp_str, sizeof(currtemp_str), PSTR("{{value_json.hc%d.currtemp}}"), hc_num);
doc["curr_temp_tpl"] = currtemp_str; doc["curr_temp_tpl"] = currtemp_str;
doc["min_temp"] = F("5"); doc["min_temp"] = F("5");

View File

@@ -208,16 +208,16 @@ class EMSdevice {
// append suffix to end // append suffix to end
if (suffix != nullptr) { if (suffix != nullptr) {
std::string text(20, '\0'); char text[20];
snprintf_P(&text[0], text.capacity() + 1, PSTR("%s%s"), buffer, uuid::read_flash_string(suffix).c_str()); snprintf_P(text, sizeof(text), PSTR("%s%s"), buffer, uuid::read_flash_string(suffix).c_str());
dataElement["value"] = text; dataElement["value"] = text;
} else { } else {
dataElement["value"] = buffer; dataElement["value"] = buffer;
} }
// add prefix to name // add prefix to name
std::string text2(100, '\0'); char text2[100];
snprintf_P(&text2[0], text2.capacity() + 1, PSTR("%s%s"), prefix.c_str(), uuid::read_flash_string(name).c_str()); snprintf_P(text2, sizeof(text2), PSTR("%s%s"), prefix.c_str(), uuid::read_flash_string(name).c_str());
dataElement["name"] = text2; dataElement["name"] = text2;
} }

View File

@@ -521,7 +521,6 @@ std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation,
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"), hostname_.c_str(), topic.c_str());
message = std::make_shared<MqttMessage>(operation, full_topic, std::move(payload), retain); message = std::make_shared<MqttMessage>(operation, full_topic, std::move(payload), retain);
} }
// TODO use && and resize() to fix mem defrag issues
// if the queue is full, make room but removing the last one // if the queue is full, make room but removing the last one
if (mqtt_messages_.size() >= maximum_mqtt_messages_) { if (mqtt_messages_.size() >= maximum_mqtt_messages_) {
@@ -687,17 +686,20 @@ void Mqtt::process_queue() {
// HA config for a binary_sensor // HA config for a binary_sensor
void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, const uint8_t device_type, const char * entity) { void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, const uint8_t device_type, const char * entity) {
return; // TODO remove
if (mqtt_format() != Format::HA) { if (mqtt_format() != Format::HA) {
return; return;
} }
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
doc["name"] = name; doc["name"] = name;
doc["uniq_id"] = entity; doc["uniq_id"] = entity;
std::string state_t(50, '\0'); char state_t[50];
snprintf_P(&state_t[0], state_t.capacity() + 1, PSTR("%s/%s"), hostname_.c_str(), entity); snprintf_P(state_t, sizeof(state_t), PSTR("%s/%s"), hostname_.c_str(), entity);
doc["stat_t"] = state_t; doc["stat_t"] = state_t;
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) {
@@ -715,8 +717,8 @@ void Mqtt::register_mqtt_ha_binary_sensor(const __FlashStringHelper * name, cons
JsonObject dev = doc.createNestedObject(F("dev")); JsonObject dev = doc.createNestedObject(F("dev"));
JsonArray ids = dev.createNestedArray(F("ids")); JsonArray ids = dev.createNestedArray(F("ids"));
std::string ha_device(40, '\0'); char ha_device[40];
snprintf_P(&ha_device[0], ha_device.capacity() + 1, PSTR("ems-esp-%s"), EMSdevice::device_type_2_device_name(device_type).c_str()); snprintf_P(ha_device, sizeof(ha_device), PSTR("ems-esp-%s"), EMSdevice::device_type_2_device_name(device_type).c_str());
ids.add(ha_device); ids.add(ha_device);
std::string topic(100, '\0'); std::string topic(100, '\0');
@@ -737,14 +739,14 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix,
return; return;
} }
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_MEDIUM> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
std::string device_name = EMSdevice::device_type_2_device_name(device_type); std::string device_name = EMSdevice::device_type_2_device_name(device_type);
char new_entity[20]; char new_entity[20];
// add prefix to entity if its specified // add prefix to entity if its specified
if (prefix != nullptr) { if (prefix != nullptr) {
snprintf_P(&new_entity[0], 20, PSTR("%s.%s"), prefix, entity); snprintf_P(new_entity, sizeof(new_entity), PSTR("%s.%s"), prefix, entity);
} else { } else {
strcpy(new_entity, entity); strcpy(new_entity, entity);
} }
@@ -761,12 +763,12 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix,
doc["unit_of_meas"] = uom; doc["unit_of_meas"] = uom;
} }
std::string state_t(50, '\0'); char state_t[50];
snprintf_P(&state_t[0], state_t.capacity() + 1, PSTR("%s/%s_data"), hostname_.c_str(), device_name.c_str()); snprintf_P(state_t, sizeof(state_t), PSTR("%s/%s_data"), hostname_.c_str(), device_name.c_str());
doc["stat_t"] = state_t; doc["stat_t"] = state_t;
std::string tpl(50, '\0'); char tpl[50];
snprintf_P(&tpl[0], tpl.capacity() + 1, PSTR("{{value_json.%s}}"), new_entity); snprintf_P(tpl, sizeof(tpl), PSTR("{{value_json.%s}}"), new_entity);
doc["val_tpl"] = tpl; doc["val_tpl"] = tpl;
if (icon != nullptr) { if (icon != nullptr) {
@@ -775,8 +777,8 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix,
JsonObject dev = doc.createNestedObject(F("dev")); JsonObject dev = doc.createNestedObject(F("dev"));
JsonArray ids = dev.createNestedArray(F("ids")); JsonArray ids = dev.createNestedArray(F("ids"));
std::string ha_device(40, '\0'); char ha_device[40];
snprintf_P(&ha_device[0], ha_device.capacity() + 1, PSTR("ems-esp-%s"), device_name.c_str()); snprintf_P(ha_device, sizeof(ha_device), PSTR("ems-esp-%s"), device_name.c_str());
ids.add(ha_device); ids.add(ha_device);
std::string topic(100, '\0'); std::string topic(100, '\0');

View File

@@ -81,7 +81,7 @@ class Mqtt {
enum Operation { PUBLISH, SUBSCRIBE }; enum Operation { PUBLISH, SUBSCRIBE };
enum Format : uint8_t { NONE = 0, SINGLE, NESTED, HA }; enum Format : uint8_t { NONE = 0, SINGLE, NESTED, HA, CUSTOM };
static constexpr uint8_t MQTT_TOPIC_MAX_SIZE = 100; static constexpr uint8_t MQTT_TOPIC_MAX_SIZE = 100;

View File

@@ -57,7 +57,7 @@ void Shower::loop() {
// first check to see if hot water has been on long enough to be recognized as a Shower/Bath // first check to see if hot water has been on long enough to be recognized as a Shower/Bath
if (!shower_on_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) { if (!shower_on_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) {
shower_on_ = true; shower_on_ = true;
Mqtt::publish(F("shower_active"), (bool)true); Mqtt::publish("shower_active", (bool)true);
LOG_DEBUG(F("[Shower] hot water still running, starting shower timer")); LOG_DEBUG(F("[Shower] hot water still running, starting shower timer"));
} }
// check if the shower has been on too long // check if the shower has been on too long

View File

@@ -248,6 +248,12 @@ void System::send_heartbeat() {
return; return;
} }
uint32_t free_memory = free_mem();
#if defined(ESP8266)
uint8_t frag_memory = ESP.getHeapFragmentation();
#endif
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc; StaticJsonDocument<EMSESP_MAX_JSON_SIZE_SMALL> doc;
uint8_t ems_status = EMSESP::bus_status(); uint8_t ems_status = EMSESP::bus_status();
@@ -262,16 +268,16 @@ void System::send_heartbeat() {
doc["rssid"] = rssid; doc["rssid"] = rssid;
doc["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); doc["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3);
doc["uptime_sec"] = uuid::get_uptime_sec(); doc["uptime_sec"] = uuid::get_uptime_sec();
doc["freemem"] = free_mem();
doc["mqttpublishfails"] = Mqtt::publish_fails(); doc["mqttpublishfails"] = Mqtt::publish_fails();
doc["txfails"] = EMSESP::txservice_.telegram_fail_count(); doc["txfails"] = EMSESP::txservice_.telegram_fail_count();
doc["rxfails"] = EMSESP::rxservice_.telegram_error_count(); doc["rxfails"] = EMSESP::rxservice_.telegram_error_count();
doc["freemem"] = free_memory;
#if defined(ESP8266)
doc["fragmentation"] = frag_memory;
#endif
if (analog_enabled_) { if (analog_enabled_) {
doc["adc"] = analog_; doc["adc"] = analog_;
} }
#if defined(ESP8266)
doc["fragmentation"] = ESP.getHeapFragmentation();
#endif
Mqtt::publish_retain(F("heartbeat"), doc.as<JsonObject>(), false); // send to MQTT with retain off. This will add to MQTT queue. Mqtt::publish_retain(F("heartbeat"), doc.as<JsonObject>(), false); // send to MQTT with retain off. This will add to MQTT queue.
} }