diff --git a/lib/framework/FSPersistence.h b/lib/framework/FSPersistence.h index 09be212ea..390be5ce1 100644 --- a/lib/framework/FSPersistence.h +++ b/lib/framework/FSPersistence.h @@ -30,6 +30,7 @@ class FSPersistence { DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize); DeserializationError error = deserializeJson(jsonDocument, settingsFile); if (error == DeserializationError::Ok && jsonDocument.is()) { + jsonDocument.shrinkToFit(); // added by proddy JsonObject jsonObject = jsonDocument.as(); // debug added by Proddy diff --git a/src/devices/mixing.cpp b/src/devices/mixing.cpp index 5033adb86..21a4a8440 100644 --- a/src/devices/mixing.cpp +++ b/src/devices/mixing.cpp @@ -152,8 +152,8 @@ void Mixing::register_mqtt_ha_config(const char * topic) { doc["uniq_id"] = F("mixing"); doc["ic"] = F("mdi:home-thermometer-outline"); - std::string stat_t(50, '\0'); - snprintf_P(&stat_t[0], stat_t.capacity() + 1, PSTR("%s/%s"), System::hostname().c_str(), topic); + char stat_t[50]; + snprintf_P(stat_t, sizeof(stat_t), PSTR("%s/%s"), System::hostname().c_str(), topic); doc["stat_t"] = stat_t; doc["val_tpl"] = F("{{value_json.pumpStatus}}"); diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index 0920b6ee6..0c14594b5 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -60,30 +60,28 @@ bool Solar::command_info(const char * value, const int8_t id, JsonObject & outpu // print to web void Solar::device_info_web(JsonArray & root) { - render_value_json(root, "", F("Collector temperature (TS1)"), collectorTemp_, F_(degrees), 10); - render_value_json(root, "", F("Tank bottom temperature (TS2)"), tankBottomTemp_, F_(degrees), 10); - render_value_json(root, "", F("Tank bottom temperature (TS5)"), tankBottomTemp2_, F_(degrees), 10); - render_value_json(root, "", F("Heat exchanger temperature (TS6)"), heatExchangerTemp_, F_(degrees), 10); - render_value_json(root, "", F("Solar pump modulation (PS1)"), solarPumpModulation_, F_(percent)); - render_value_json(root, "", F("Cylinder pump modulation (PS5)"), cylinderPumpModulation_, F_(percent)); - render_value_json(root, "", F("Valve (VS2) status"), valveStatus_, nullptr, EMS_VALUE_BOOL); - render_value_json(root, "", F("Solar Pump (PS1) active"), solarPump_, nullptr, EMS_VALUE_BOOL); + render_value_json(root, "", F_(collectorTemp), collectorTemp_, F_(degrees), 10); + render_value_json(root, "", F_(tankBottomTemp), tankBottomTemp_, F_(degrees), 10); + render_value_json(root, "", F_(tankBottomTemp2), tankBottomTemp2_, F_(degrees), 10); + render_value_json(root, "", F_(heatExchangerTemp), heatExchangerTemp_, F_(degrees), 10); + render_value_json(root, "", F_(solarPumpModulation), solarPumpModulation_, F_(percent)); + render_value_json(root, "", F_(cylinderPumpModulation), cylinderPumpModulation_, F_(percent)); + render_value_json(root, "", F_(valveStatus), valveStatus_, 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_)) { JsonObject dataElement; dataElement = root.createNestedObject(); - dataElement["name"] = F("Pump working time"); - std::string time_str(60, '\0'); - snprintf_P(&time_str[0], time_str.capacity() + 1, PSTR("%d days %d hours %d minutes"), pumpWorkMin_ / 1440, (pumpWorkMin_ % 1440) / 60, pumpWorkMin_ % 60); + dataElement["name"] = F_(pumpWorkMin); + char time_str[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; } - - 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 @@ -112,7 +110,11 @@ void Solar::show_values(uuid::console::Shell & shell) { print_value_json(shell, F("energyTotal"), F_(energyTotal), F_(kwh), output); 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() { // Create the Master device StaticJsonDocument doc; - doc["name"] = F("EMS-ESP"); - doc["uniq_id"] = F("solar"); - doc["ic"] = F("mdi:home-thermometer-outline"); - doc["stat_t"] = F("ems-esp/solar_data"); - doc["val_tpl"] = F("{{value_json.solarPump}}"); + doc["name"] = "EMS-ESP"; + doc["uniq_id"] = "solar"; + doc["ic"] = "mdi:home-thermometer-outline"; + doc["stat_t"] = "ems-esp/solar_data"; + doc["val_tpl"] = "{{value_json.solarPump}}"; JsonObject dev = doc.createNestedObject("dev"); - dev["name"] = F("EMS-ESP Solar"); + dev["name"] = "EMS-ESP Solar"; dev["sw"] = EMSESP_APP_VERSION; dev["mf"] = this->brand_to_string(); dev["mdl"] = this->name(); diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 91adac305..33a4b75ed 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -193,8 +193,8 @@ void Thermostat::device_info_web(JsonArray & root) { } // create prefix with heating circuit number - std::string hc_str(5, '\0'); - snprintf_P(&hc_str[0], hc_str.capacity() + 1, PSTR("hc%d: "), hc->hc_num()); + char hc_str[5]; + 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_(seltemp), hc->setpoint_roomTemp, F_(degrees), format_setpoint); @@ -202,23 +202,23 @@ void Thermostat::device_info_web(JsonArray & root) { JsonObject dataElement; dataElement = root.createNestedObject(); - std::string mode_str(15, '\0'); - snprintf_P(&mode_str[0], mode_str.capacity() + 1, PSTR("%sMode"), hc_str.c_str()); + char mode_str[15]; + snprintf_P(mode_str, sizeof(mode_str), PSTR("%sMode"), hc_str); dataElement["name"] = mode_str; - std::string modetype_str(20, '\0'); + char modetype_str[20]; 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) { - 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)) { - snprintf_P(&modetype_str[0], - modetype_str.capacity() + 1, + snprintf_P(modetype_str, + sizeof(modetype_str), PSTR("%s - %s"), mode_tostring(hc->get_mode(flags)).c_str(), mode_tostring(hc->get_mode_type(flags)).c_str()); } 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; } @@ -353,8 +353,8 @@ bool Thermostat::export_values_main(JsonObject & rootThermostat) { rootThermostat["time"] = datetime_.c_str(); } - if (model == EMSdevice::EMS_DEVICE_FLAG_RC30_1) { - // Display + if (model == EMSdevice::EMS_DEVICE_FLAG_RC30_1) { + // Display if (Helpers::hasValue(ibaMainDisplay_)) { if (ibaMainDisplay_ == 0) { rootThermostat["display"] = F("internal temperature"); @@ -716,12 +716,12 @@ std::shared_ptr Thermostat::heating_circuit(std::sha void Thermostat::register_mqtt_ha_config(uint8_t hc_num) { StaticJsonDocument doc; - std::string str1(40, '\0'); - snprintf_P(&str1[0], str1.capacity() + 1, PSTR("Thermostat hc%d"), hc_num); + char str1[40]; + snprintf_P(str1, sizeof(str1), PSTR("Thermostat hc%d"), hc_num); doc["name"] = str1; - std::string str2(40, '\0'); - snprintf_P(&str2[0], str2.capacity() + 1, PSTR("thermostat_hc%d"), hc_num); + char str2[40]; + snprintf_P(str2, sizeof(str2), PSTR("thermostat_hc%d"), hc_num); doc["uniq_id"] = str2; 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["curr_temp_t"] = F("~/thermostat_data"); - std::string mode_str(30, '\0'); - snprintf_P(&mode_str[0], 30, PSTR("{{value_json.hc%d.mode}}"), hc_num); + char mode_str[30]; + snprintf_P(mode_str, sizeof(mode_str), PSTR("{{value_json.hc%d.mode}}"), hc_num); doc["mode_stat_tpl"] = mode_str; - std::string seltemp_str(30, '\0'); - snprintf_P(&seltemp_str[0], 30, PSTR("{{value_json.hc%d.seltemp}}"), hc_num); + char seltemp_str[30]; + snprintf_P(seltemp_str, sizeof(seltemp_str), PSTR("{{value_json.hc%d.seltemp}}"), hc_num); doc["temp_stat_tpl"] = seltemp_str; - std::string currtemp_str(30, '\0'); - snprintf_P(&currtemp_str[0], 30, PSTR("{{value_json.hc%d.currtemp}}"), hc_num); + char currtemp_str[30]; + snprintf_P(currtemp_str, sizeof(currtemp_str), PSTR("{{value_json.hc%d.currtemp}}"), hc_num); doc["curr_temp_tpl"] = currtemp_str; doc["min_temp"] = F("5"); diff --git a/src/emsdevice.h b/src/emsdevice.h index 65160f817..e6dcc6cf7 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -208,16 +208,16 @@ class EMSdevice { // append suffix to end if (suffix != nullptr) { - std::string text(20, '\0'); - snprintf_P(&text[0], text.capacity() + 1, PSTR("%s%s"), buffer, uuid::read_flash_string(suffix).c_str()); + char text[20]; + snprintf_P(text, sizeof(text), PSTR("%s%s"), buffer, uuid::read_flash_string(suffix).c_str()); dataElement["value"] = text; } else { dataElement["value"] = buffer; } // add prefix to name - std::string text2(100, '\0'); - snprintf_P(&text2[0], text2.capacity() + 1, PSTR("%s%s"), prefix.c_str(), uuid::read_flash_string(name).c_str()); + char text2[100]; + snprintf_P(text2, sizeof(text2), PSTR("%s%s"), prefix.c_str(), uuid::read_flash_string(name).c_str()); dataElement["name"] = text2; } diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 4f6c75be9..9eee365ec 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -521,7 +521,6 @@ std::shared_ptr 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()); message = std::make_shared(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 (mqtt_messages_.size() >= maximum_mqtt_messages_) { @@ -687,17 +686,20 @@ void Mqtt::process_queue() { // HA config for a binary_sensor 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) { return; } - StaticJsonDocument doc; + StaticJsonDocument doc; doc["name"] = name; doc["uniq_id"] = entity; - std::string state_t(50, '\0'); - snprintf_P(&state_t[0], state_t.capacity() + 1, PSTR("%s/%s"), hostname_.c_str(), entity); + char state_t[50]; + snprintf_P(state_t, sizeof(state_t), PSTR("%s/%s"), hostname_.c_str(), entity); doc["stat_t"] = state_t; 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")); JsonArray ids = dev.createNestedArray(F("ids")); - std::string ha_device(40, '\0'); - snprintf_P(&ha_device[0], ha_device.capacity() + 1, PSTR("ems-esp-%s"), EMSdevice::device_type_2_device_name(device_type).c_str()); + char ha_device[40]; + 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); std::string topic(100, '\0'); @@ -737,14 +739,14 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix, return; } - StaticJsonDocument doc; + StaticJsonDocument doc; std::string device_name = EMSdevice::device_type_2_device_name(device_type); char new_entity[20]; // add prefix to entity if its specified 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 { strcpy(new_entity, entity); } @@ -761,12 +763,12 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix, doc["unit_of_meas"] = uom; } - std::string state_t(50, '\0'); - snprintf_P(&state_t[0], state_t.capacity() + 1, PSTR("%s/%s_data"), hostname_.c_str(), device_name.c_str()); + char state_t[50]; + snprintf_P(state_t, sizeof(state_t), PSTR("%s/%s_data"), hostname_.c_str(), device_name.c_str()); doc["stat_t"] = state_t; - std::string tpl(50, '\0'); - snprintf_P(&tpl[0], tpl.capacity() + 1, PSTR("{{value_json.%s}}"), new_entity); + char tpl[50]; + snprintf_P(tpl, sizeof(tpl), PSTR("{{value_json.%s}}"), new_entity); doc["val_tpl"] = tpl; if (icon != nullptr) { @@ -775,8 +777,8 @@ void Mqtt::register_mqtt_ha_sensor(const char * prefix, JsonObject dev = doc.createNestedObject(F("dev")); JsonArray ids = dev.createNestedArray(F("ids")); - std::string ha_device(40, '\0'); - snprintf_P(&ha_device[0], ha_device.capacity() + 1, PSTR("ems-esp-%s"), device_name.c_str()); + char ha_device[40]; + snprintf_P(ha_device, sizeof(ha_device), PSTR("ems-esp-%s"), device_name.c_str()); ids.add(ha_device); std::string topic(100, '\0'); diff --git a/src/mqtt.h b/src/mqtt.h index 2ddbb07e2..03b9ffaee 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -81,7 +81,7 @@ class Mqtt { 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; diff --git a/src/shower.cpp b/src/shower.cpp index da34fddf9..70f34039d 100644 --- a/src/shower.cpp +++ b/src/shower.cpp @@ -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 if (!shower_on_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) { 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")); } // check if the shower has been on too long diff --git a/src/system.cpp b/src/system.cpp index 1109729c9..39e005b27 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -248,6 +248,12 @@ void System::send_heartbeat() { return; } + uint32_t free_memory = free_mem(); + +#if defined(ESP8266) + uint8_t frag_memory = ESP.getHeapFragmentation(); +#endif + StaticJsonDocument doc; uint8_t ems_status = EMSESP::bus_status(); @@ -262,16 +268,16 @@ void System::send_heartbeat() { doc["rssid"] = rssid; doc["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); doc["uptime_sec"] = uuid::get_uptime_sec(); - doc["freemem"] = free_mem(); doc["mqttpublishfails"] = Mqtt::publish_fails(); doc["txfails"] = EMSESP::txservice_.telegram_fail_count(); doc["rxfails"] = EMSESP::rxservice_.telegram_error_count(); + doc["freemem"] = free_memory; +#if defined(ESP8266) + doc["fragmentation"] = frag_memory; +#endif if (analog_enabled_) { doc["adc"] = analog_; } -#if defined(ESP8266) - doc["fragmentation"] = ESP.getHeapFragmentation(); -#endif Mqtt::publish_retain(F("heartbeat"), doc.as(), false); // send to MQTT with retain off. This will add to MQTT queue. }