mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-04-02 15:06:32 +03:00
Merge branch 'dev' into core3
This commit is contained in:
@@ -842,6 +842,15 @@ bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, F_(metrics))) {
|
||||
std::string metrics = get_metrics_prometheus();
|
||||
if (!metrics.empty()) {
|
||||
output["api_data"] = metrics;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// this is for a specific sensor, return the value
|
||||
const char * attribute_s = Command::get_attribute(cmd);
|
||||
|
||||
@@ -856,6 +865,35 @@ bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int
|
||||
return false; // not found
|
||||
}
|
||||
|
||||
// generate Prometheus metrics format from analog values
|
||||
std::string AnalogSensor::get_metrics_prometheus() {
|
||||
std::string result;
|
||||
result.reserve(sensors_.size() * 140);
|
||||
char val[10];
|
||||
for (auto & sensor : sensors_) {
|
||||
result += (std::string) "# HELP emsesp_" + sensor.name() + " " + sensor.name();
|
||||
if (sensor.type() != AnalogType::DIGITAL_OUT && sensor.type() != AnalogType::DIGITAL_IN) {
|
||||
result += (std::string) ", " + EMSdevice::uom_to_string(sensor.uom());
|
||||
} else {
|
||||
result += (std::string) ", boolean";
|
||||
}
|
||||
result += (std::string) ", readable, visible";
|
||||
if (sensor.type() == AnalogType::COUNTER || sensor.type() == AnalogType::RGB || sensor.type() == AnalogType::PULSE
|
||||
|| (sensor.type() >= AnalogType::DIGITAL_OUT && sensor.type() <= AnalogType::PWM_2)
|
||||
|| (sensor.type() >= AnalogType::CNT_0 && sensor.type() <= AnalogType::CNT_2)) {
|
||||
result += (std::string) ", writable";
|
||||
}
|
||||
result += (std::string) "\n# TYPE emsesp_" + sensor.name() + " gauge\n";
|
||||
result += (std::string) "emsesp_" + sensor.name() + " ";
|
||||
if (sensor.type() != AnalogType::DIGITAL_OUT && sensor.type() != AnalogType::DIGITAL_IN) {
|
||||
result += (std::string) Helpers::render_value(val, sensor.value(), 2) + "\n";
|
||||
} else {
|
||||
result += (std::string) (sensor.value() == 0 ? "0\n" : "1\n");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// note we don't add the device and state classes here, as we do in the custom entity service
|
||||
void AnalogSensor::get_value_json(JsonObject output, const Sensor & sensor) {
|
||||
output["name"] = (const char *)sensor.name();
|
||||
|
||||
@@ -177,6 +177,7 @@ class AnalogSensor {
|
||||
bool update(uint8_t gpio, const char * name, double offset, double factor, uint8_t uom, int8_t type, bool deleted, bool is_system);
|
||||
bool get_value_info(JsonObject output, const char * cmd, const int8_t id = -1);
|
||||
void store_counters();
|
||||
std::string get_metrics_prometheus();
|
||||
static std::vector<uint8_t> exclude_types() {
|
||||
return exclude_types_;
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@ const char * EMSdevice::uom_to_string(uint8_t uom) {
|
||||
}
|
||||
}
|
||||
|
||||
const char * EMSdevice::brand_to_char() {
|
||||
std::string EMSdevice::brand_to_char() {
|
||||
if (!custom_brand().empty()) {
|
||||
return custom_brand().c_str();
|
||||
return custom_brand();
|
||||
}
|
||||
switch (brand_) {
|
||||
case EMSdevice::Brand::BOSCH:
|
||||
@@ -331,15 +331,15 @@ uint8_t EMSdevice::decode_brand(uint8_t value) {
|
||||
std::string EMSdevice::to_string() {
|
||||
// for devices that haven't been lookup yet, don't show all details
|
||||
if (product_id_ == 0) {
|
||||
return std::string(name()) + " (DeviceID:" + Helpers::hextoa(device_id_) + ")";
|
||||
return name() + " (DeviceID:" + Helpers::hextoa(device_id_) + ")";
|
||||
}
|
||||
|
||||
if (brand_ == Brand::NO_BRAND && custom_brand().empty()) {
|
||||
return std::string(name()) + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_ + ")";
|
||||
return name() + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_ + ")";
|
||||
}
|
||||
|
||||
return std::string(brand_to_char()) + " " + name() + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_)
|
||||
+ ", Version:" + version_ + ")";
|
||||
return brand_to_char() + " " + name() + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_
|
||||
+ ")";
|
||||
}
|
||||
|
||||
// returns string of EMS device version and productID
|
||||
@@ -912,7 +912,7 @@ void EMSdevice::publish_value(void * value_p) const {
|
||||
// looks up the UOM for a given key from the device value table
|
||||
std::string EMSdevice::get_value_uom(const std::string & shortname) const {
|
||||
for (const auto & dv : devicevalues_) {
|
||||
if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE)) && (dv.short_name == shortname)) {
|
||||
if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE)) && !strcmp(dv.short_name, shortname.c_str())) {
|
||||
// ignore TIME since "minutes" is already added to the string value
|
||||
if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) {
|
||||
break;
|
||||
@@ -1282,7 +1282,7 @@ void EMSdevice::setCustomizationEntity(const std::string & entity_id) {
|
||||
// set the min / max
|
||||
dv.set_custom_minmax();
|
||||
|
||||
if (Mqtt::ha_enabled() && !strcmp(dv.short_name , FL_(selRoomTemp)[0]) && (min != dv.min || max != dv.max)) {
|
||||
if (Mqtt::ha_enabled() && dv.tag <= DeviceValueTAG::TAG_HC8 && !strcmp(dv.short_name, FL_(selRoomTemp)[0]) && (min != dv.min || max != dv.max)) {
|
||||
set_climate_minmax(dv.tag, dv.min, dv.max);
|
||||
}
|
||||
|
||||
@@ -2160,7 +2160,7 @@ void EMSdevice::mqtt_ha_entity_config_create() {
|
||||
if (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) && dv.has_state(DeviceValueState::DV_ACTIVE)
|
||||
&& !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE)) {
|
||||
// create_device_config is only done once for the EMS device. It can added to any entity, so we take the first
|
||||
if (Mqtt::publish_ha_sensor_config_dv(dv, name().c_str(), std::string(brand_to_char()).c_str(), to_string_version().c_str(), false, create_device_config)) {
|
||||
if (Mqtt::publish_ha_sensor_config_dv(dv, name().c_str(), brand_to_char().c_str(), to_string_version().c_str(), false, create_device_config)) {
|
||||
dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED);
|
||||
create_device_config = false; // only create the main config once
|
||||
count++;
|
||||
|
||||
@@ -63,7 +63,7 @@ class EMSdevice {
|
||||
const char * device_type_2_device_name_translated(); // returns translated device type name
|
||||
bool has_tags(const int8_t tag) const;
|
||||
bool has_cmd(const char * cmd, const int8_t id) const;
|
||||
const char * brand_to_char();
|
||||
std::string brand_to_char();
|
||||
std::string to_string();
|
||||
std::string to_string_short();
|
||||
std::string to_string_version();
|
||||
|
||||
@@ -303,7 +303,7 @@ MAKE_ENUM(enum_comfort, FL_(hot), FL_(eco), FL_(intelligent))
|
||||
MAKE_ENUM(enum_comfort1, FL_(high_comfort), FL_(eco))
|
||||
MAKE_ENUM(enum_comfort2, FL_(eco), FL_(high_comfort))
|
||||
MAKE_ENUM(enum_flow, FL_(off), FL_(flow), FL_(bufferedflow), FL_(buffer), FL_(layeredbuffer))
|
||||
MAKE_ENUM(enum_reset, FL_(dash), FL_(maintenance), FL_(error), FL_(history), FL_(message))
|
||||
MAKE_ENUM(enum_reset, FL_(dash), FL_(maintenance), FL_(error), FL_(history), FL_(message), FL_(hp_error), FL_(burn_starts), FL_(factory))
|
||||
MAKE_ENUM(enum_maxHeat, FL_(0kW), FL_(2kW), FL_(3kW), FL_(4kW), FL_(6kW), FL_(9kW))
|
||||
MAKE_ENUM(enum_maxHeat1, FL_(0kW), FL_(3kW), FL_(6kW), FL_(9kW))
|
||||
MAKE_ENUM(enum_maxHeat2, FL_(3kW), FL_(6kW), FL_(9kW))
|
||||
|
||||
@@ -197,6 +197,9 @@ MAKE_WORD_TRANSLATION(lower, "lower", "niedriger", "lager", "lägre", "mniejszy"
|
||||
MAKE_WORD_TRANSLATION(error, "error", "Fehler", "error", "Fel", "błąd", "feil", "erreur", "Hata", "errore", "error", "chyba")
|
||||
MAKE_WORD_TRANSLATION(history, "history", "Fehlerspeicher", "geschiedenis", "historik", "historia", "historikk", "historique", "geçmiş", "storico", "história", "historie")
|
||||
MAKE_WORD_TRANSLATION(message, "message", "Meldung", "melding", "meddelande", "komunikat", "melding", "message", "mesajı", "messaggio", "správa", "zpráva")
|
||||
MAKE_WORD_TRANSLATION(hp_error, "hp error", "WP Fehler", "hp error", "hp Fel", "hp błąd", "hp feil", "hp erreur", "hp Hata", "hp errore", "hp error", "hp chyba")
|
||||
MAKE_WORD_TRANSLATION(factory, "factory", "werkseinst.", "", "", "", "", "", "", "", "", "")
|
||||
MAKE_WORD_TRANSLATION(burn_starts, "burner starts", "Brennerstarts", "", "", "", "", "", "", "", "", "")
|
||||
MAKE_WORD_TRANSLATION(na, "n/a", "n/a", "n/a", "n/a", "nd.", "n/a", "n/c", "mevcut değil", "n/a", "n/a", "n/a")
|
||||
MAKE_WORD_TRANSLATION(inverted, "inverted", "invertiert", "omgekeerd", "inverterad", "odwrócony", "invertert", "inversé", "ters", "invertito", "invertovaný", "invertovaný")
|
||||
|
||||
@@ -424,6 +427,10 @@ MAKE_TRANSLATION(pumpOnTemp, "pumpontemp", "pump logic temperature", "Pumpenlogi
|
||||
MAKE_TRANSLATION(headertemp, "headertemp", "low loss header", "Hydr. Weiche", "open verdeler", "Fördelare", "sprzęgło hydrauliczne", "lav tap header", "bouteille de déc. hydr.", "isı bloğu gidiş suyu sıc.", "comp. idr.", "nízkostratová hlavica", "hydraulický oddělovač")
|
||||
MAKE_TRANSLATION(heatblock, "heatblock", "heating block", "Wärmezelle", "Aanvoertemp. warmtecel", "Värmeblock", "blok grzewczy", "varmeblokk", "départ corps de chauffe", "Hid.denge kabı sıcaklığı", "mandata scamb. pr.", "vykurovací blok", "blok topení")
|
||||
|
||||
MAKE_TRANSLATION(pumpKickHour, "pumpkickhour", "pump kick hour", "Stunde Pumpkick")
|
||||
MAKE_TRANSLATION(pumpKickDay, "pumpkickday", "pump kick day", "Tag Pumpkick")
|
||||
MAKE_TRANSLATION(pumpKickDelay, "pumpkickdelay", "pump kick delay", "Pause vor Pumpkick")
|
||||
|
||||
MAKE_TRANSLATION(curveOn, "curveon", "heatingcurve on", "Heizkurve an", "stookkromme aan", "Värmekurva På", "krzywa grzewcza włączona", "varmekurve på", "courbe de chauffage activée", "ısıtma eğrisi açık", "curva di riscaldamento attiva", "vykurovacia krivka zapnutá", "topná křivka zapnutá")
|
||||
MAKE_TRANSLATION(curveBase, "curvebase", "heatingcurve base", "Heizkurve Basis", "stookkromme basis", "Värmekurva Bas", "podstawa krzywej grzewczej", "varmekurve basis", "base de courbe de chauffage", "ısıtma eğrisi tabanı", "base curva di riscaldamento", "základňa vykurovacej krivky", "základ topné křivky")
|
||||
MAKE_TRANSLATION(curveEnd, "curveend", "heatingcurve end", "Heizkurve Ende", "stookkromme einde", "Värmekurva Slut", "koniec krzywej grzewczej", "varmekurve slutt", "fin de courbe de chauffage", "ısıtma eğrisi sonu", "fine curva di riscaldamento", "koniec vykurovacej krivky", "konec topné křivky")
|
||||
@@ -773,6 +780,7 @@ MAKE_TRANSLATION(comforttemp, "comforttemp", "comfort temperature", "Komforttemp
|
||||
MAKE_TRANSLATION(summertemp, "summertemp", "summer temperature", "Sommertemperatur", "Zomertemperatuur", "Sommartemperatur", "temperatura przełączania lato/zima", "Sommertemperatur", "température été", "yaz sıcaklığı", "temperatura estiva", "letná teplota", "letní teplota")
|
||||
MAKE_TRANSLATION(designtemp, "designtemp", "design temperature", "Auslegungstemperatur", "Ontwerptemperatuur", "Design-temperatur", "temperatura projektowa", "designtemperatur", "température conception", "özel sıcaklık", "temperatura predefinita", "návrhová teplota", "dimenzovaná teplota")
|
||||
MAKE_TRANSLATION(offsettemp, "offsettemp", "offset temperature", "Temperaturanhebung", "Temperatuur offset", "Temperaturkorrigering", "korekta temperatury", "temperaturkorrigering", "température offset", "artış sıcaklığı", "aumento della temperatura", "offsetová teplota", "offset teploty")
|
||||
MAKE_TRANSLATION(baseflowtemp, "baseflowtemp", "base flow temperature", "Basis Vorlauftemperatur") // ToDo translate
|
||||
MAKE_TRANSLATION(minflowtemp, "minflowtemp", "min flow temperature", "min. Vorlauftemperatur", "Minimale aanvoertemperatuur", "Min. Flödestemperatur", "minimalna temperatura zasilania", "min. turtemperatur", "température min. flux", "minimun akış sıcaklığı", "temperatura minima di mandata", "min. výstupná teplota", "vytápění minimální teplota")
|
||||
MAKE_TRANSLATION(maxflowtemp, "maxflowtemp", "max flow temperature", "max. Vorlauftemperatur", "Maximale aanvoertemperatuur", "Max. Flödestemperatur", "maksymalna temperatura zasilania", "maks turtemperatur", "température max flux", "maksimum akış sıcaklığı", "temperatura massima di mandata", "maximálna teplota prívodu", "vytápění maximální teplota")
|
||||
MAKE_TRANSLATION(roominfluence, "roominfluence", "room influence", "Raumeinfluss", "Ruimteinvloed", "Rumspåverkan", "wpływ pomieszczenia", "rominnflytelse", "influence pièce", "oda etkisi", "influenza della camera", "vplyv miestnosti", "vliv prostoru")
|
||||
|
||||
@@ -1191,7 +1191,11 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8
|
||||
doc[ic_ha] = F_(iconpercent); // set icon
|
||||
}
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "power_factor";
|
||||
if (entity == FL_(airHumidity)[0] || entity == FL_(remotehum)[0]) {
|
||||
doc[dc_ha] = "humidity";
|
||||
} else if (entity == FL_(battery)[0]) {
|
||||
doc[dc_ha] = "battery";
|
||||
}
|
||||
break;
|
||||
case DeviceValueUOM::SECONDS:
|
||||
case DeviceValueUOM::MINUTES:
|
||||
@@ -1544,8 +1548,8 @@ void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const bool crea
|
||||
}
|
||||
|
||||
// add mf (manufacturer/brand), mdl (model), sw (software version) and via_device
|
||||
dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP";
|
||||
dev_json["mdl"] = model != nullptr ? model : "EMS-ESP";
|
||||
dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP";
|
||||
dev_json["mdl"] = model != nullptr ? model : "EMS-ESP";
|
||||
dev_json["sw"] = version != nullptr ? version : "v" + std::string(EMSESP_APP_VERSION);
|
||||
dev_json["via_device"] = Mqtt::basename();
|
||||
}
|
||||
|
||||
@@ -2914,7 +2914,6 @@ void System::set_valid_system_gpios() {
|
||||
// excluded:
|
||||
// GPIO3, GPIO45 - GPIO46 = strapping pins
|
||||
// GPIO26 - GPIO32 = SPI flash and PSRAM and not recommended
|
||||
// GPIO33 - GPIO37 = Octal flash/PSRAM
|
||||
// GPIO19 - GPIO20 = USB-JTAG
|
||||
// GPIO22 - GPIO25 = don't exist
|
||||
//
|
||||
@@ -2922,7 +2921,12 @@ void System::set_valid_system_gpios() {
|
||||
// GPIO11 - GPIO19 = ADC analog input only pins
|
||||
// GPIO47 - GPIO48 = valid on a Wemos S3
|
||||
// GPIO8 = used by Liligo S3 board profile for Rx
|
||||
valid_system_gpios_ = string_range_to_vector("0-48", "3, 45-46, 26-32, 33-37, 19-20, 22-25");
|
||||
if (ESP.getPsramSize() > 0) {
|
||||
// GPIO33 - GPIO37 = Octal flash/PSRAM
|
||||
valid_system_gpios_ = string_range_to_vector("0-48", "3, 45-46, 26-32, 33-37, 19-20, 22-25");
|
||||
} else {
|
||||
valid_system_gpios_ = string_range_to_vector("0-48", "3, 45-46, 26-32, 19-20, 22-25");
|
||||
}
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html
|
||||
|
||||
@@ -400,6 +400,15 @@ bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, cons
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, F_(metrics))) {
|
||||
std::string metrics = get_metrics_prometheus();
|
||||
if (!metrics.empty()) {
|
||||
output["api_data"] = metrics;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// this is for a specific sensor
|
||||
const char * attribute_s = Command::get_attribute(cmd);
|
||||
|
||||
@@ -414,6 +423,21 @@ bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, cons
|
||||
return false; // not found
|
||||
}
|
||||
|
||||
// generate Prometheus metrics format from temperature values
|
||||
std::string TemperatureSensor::get_metrics_prometheus() {
|
||||
std::string result;
|
||||
result.reserve(sensors_.size() * 120);
|
||||
char val[10];
|
||||
for (auto & sensor : sensors_) {
|
||||
result += (std::string) "# HELP emsesp_" + sensor.name() + " " + sensor.name() + ", "
|
||||
+ EMSdevice::uom_to_string(EMSESP::system_.fahrenheit() ? DeviceValueUOM::FAHRENHEIT : DeviceValueUOM::DEGREES) + ", readable, visible\n";
|
||||
result += (std::string) "# TYPE emsesp_" + sensor.name() + " gauge\n";
|
||||
result +=
|
||||
(std::string) "emsesp_" + sensor.name() + " " + Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0) + "\n";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// note we don't add the device and state classes here, as we do in the custom entity service
|
||||
void TemperatureSensor::get_value_json(JsonObject output, const Sensor & sensor) {
|
||||
output["id"] = sensor.id();
|
||||
|
||||
@@ -96,6 +96,8 @@ class TemperatureSensor {
|
||||
bool updated_values();
|
||||
bool get_value_info(JsonObject output, const char * cmd, const int8_t id = -1);
|
||||
|
||||
std::string get_metrics_prometheus();
|
||||
|
||||
// return back reference to the sensor list, used by other classes
|
||||
std::vector<Sensor, AllocatorPSRAM<Sensor>> sensors() const {
|
||||
return sensors_;
|
||||
|
||||
Reference in New Issue
Block a user