mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-03-13 21:26:32 +03:00
add prometheus metrics for analog/scheduler/custom #2962
This commit is contained in:
@@ -9,7 +9,7 @@ For more details go to [emsesp.org](https://emsesp.org/).
|
|||||||
- comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935)
|
- comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935)
|
||||||
- customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784)
|
- customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784)
|
||||||
- set model for ems-esp devices temperature, analog, etc. [#2958](https://github.com/emsesp/EMS-ESP32/discussions/2958)
|
- set model for ems-esp devices temperature, analog, etc. [#2958](https://github.com/emsesp/EMS-ESP32/discussions/2958)
|
||||||
- prometheus metrics for temperaturesensors [#2962](https://github.com/emsesp/EMS-ESP32/issues/2962)
|
- prometheus metrics for temperature/analog/scheduler/custom [#2962](https://github.com/emsesp/EMS-ESP32/issues/2962)
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
|||||||
@@ -852,6 +852,15 @@ bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int
|
|||||||
return true;
|
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
|
// this is for a specific sensor, return the value
|
||||||
const char * attribute_s = Command::get_attribute(cmd);
|
const char * attribute_s = Command::get_attribute(cmd);
|
||||||
|
|
||||||
@@ -866,6 +875,35 @@ bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int
|
|||||||
return false; // not found
|
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
|
// 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) {
|
void AnalogSensor::get_value_json(JsonObject output, const Sensor & sensor) {
|
||||||
output["name"] = (const char *)sensor.name();
|
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 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);
|
bool get_value_info(JsonObject output, const char * cmd, const int8_t id = -1);
|
||||||
void store_counters();
|
void store_counters();
|
||||||
|
std::string get_metrics_prometheus();
|
||||||
static std::vector<uint8_t> exclude_types() {
|
static std::vector<uint8_t> exclude_types() {
|
||||||
return exclude_types_;
|
return exclude_types_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.8.2-dev.6"
|
#define EMSESP_APP_VERSION "3.8.2-dev.7"
|
||||||
|
|||||||
@@ -343,6 +343,15 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(cmd, F_(metrics))) {
|
||||||
|
std::string metrics = get_metrics_prometheus();
|
||||||
|
if (!metrics.empty()) {
|
||||||
|
output["api_data"] = metrics;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// specific value info
|
// specific value info
|
||||||
const char * attribute_s = Command::get_attribute(cmd);
|
const char * attribute_s = Command::get_attribute(cmd);
|
||||||
for (auto const & entity : *customEntityItems_) {
|
for (auto const & entity : *customEntityItems_) {
|
||||||
@@ -354,6 +363,54 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
|||||||
return false; // not found
|
return false; // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate Prometheus metrics format from custom entities
|
||||||
|
std::string WebCustomEntityService::get_metrics_prometheus() {
|
||||||
|
std::string result;
|
||||||
|
result.reserve(customEntityItems_->size() * 140);
|
||||||
|
char val[10];
|
||||||
|
for (CustomEntityItem & entity : *customEntityItems_) {
|
||||||
|
if (entity.hide || entity.name[0] == '\0') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result += (std::string) "# HELP emsesp_" + entity.name + " " + entity.name;
|
||||||
|
if (entity.uom != 0) {
|
||||||
|
result += (std::string) ", " + EMSdevice::uom_to_string(entity.uom);
|
||||||
|
}
|
||||||
|
result += (std::string) ", readable, visible" + (entity.writeable ? ", writable\n" : "\n");
|
||||||
|
result += (std::string) "# TYPE emsesp_" + entity.name + " gauge\n";
|
||||||
|
result += (std::string) "emsesp_" + entity.name + " ";
|
||||||
|
switch (entity.value_type) {
|
||||||
|
case DeviceValueType::BOOL:
|
||||||
|
result += (std::string)(entity.value == 0 ? "0" : "1");
|
||||||
|
break;
|
||||||
|
case DeviceValueType::INT8:
|
||||||
|
result += (std::string)Helpers::render_value(val, entity.factor * (int8_t)entity.value, 2);
|
||||||
|
break;
|
||||||
|
case DeviceValueType::UINT8:
|
||||||
|
result += (std::string)Helpers::render_value(val, entity.factor * (uint8_t)entity.value, 2);
|
||||||
|
break;
|
||||||
|
case DeviceValueType::INT16:
|
||||||
|
result += (std::string)Helpers::render_value(val, entity.factor * (int16_t)entity.value, 2);
|
||||||
|
break;
|
||||||
|
case DeviceValueType::UINT16:
|
||||||
|
result += (std::string)Helpers::render_value(val, entity.factor * (uint16_t)entity.value, 2);
|
||||||
|
break;
|
||||||
|
case DeviceValueType::UINT24:
|
||||||
|
case DeviceValueType::TIME:
|
||||||
|
case DeviceValueType::UINT32:
|
||||||
|
result += (std::string)Helpers::render_value(val, entity.factor * entity.value, 2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (entity.data.length() > 0) {
|
||||||
|
result += entity.data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result += (std::string) "\n";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// build the json for specific entity
|
// build the json for specific entity
|
||||||
void WebCustomEntityService::get_value_json(JsonObject output, CustomEntityItem const & entity) {
|
void WebCustomEntityService::get_value_json(JsonObject output, CustomEntityItem const & entity) {
|
||||||
output["name"] = (const char *)entity.name;
|
output["name"] = (const char *)entity.name;
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ class WebCustomEntityService : public StatefulService<WebCustomEntity> {
|
|||||||
void show_values(JsonObject output);
|
void show_values(JsonObject output);
|
||||||
void generate_value_web(JsonObject output, const bool is_dashboard = false);
|
void generate_value_web(JsonObject output, const bool is_dashboard = false);
|
||||||
|
|
||||||
|
std::string get_metrics_prometheus();
|
||||||
|
|
||||||
uint8_t count_entities();
|
uint8_t count_entities();
|
||||||
void ha_reset() {
|
void ha_reset() {
|
||||||
ha_configdone_ = false;
|
ha_configdone_ = false;
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ StateUpdateResult WebScheduler::update(JsonObject root, WebScheduler & webSchedu
|
|||||||
if (webScheduler.scheduleItems.back().name[0] != '\0') {
|
if (webScheduler.scheduleItems.back().name[0] != '\0') {
|
||||||
char key[sizeof(webScheduler.scheduleItems.back().name) + 2];
|
char key[sizeof(webScheduler.scheduleItems.back().name) + 2];
|
||||||
snprintf(key, sizeof(key), "s:%s", webScheduler.scheduleItems.back().name);
|
snprintf(key, sizeof(key), "s:%s", webScheduler.scheduleItems.back().name);
|
||||||
if (EMSESP::nvs_.isKey(key)) {
|
if (EMSESP::nvs_.isKey(key) && webScheduler.scheduleItems.back().flags != SCHEDULEFLAG_SCHEDULE_IMMEDIATE) {
|
||||||
webScheduler.scheduleItems.back().active = EMSESP::nvs_.getBool(key);
|
webScheduler.scheduleItems.back().active = EMSESP::nvs_.getBool(key);
|
||||||
}
|
}
|
||||||
Command::add(
|
Command::add(
|
||||||
@@ -138,20 +138,11 @@ bool WebSchedulerService::command_setvalue(const char * value, const int8_t id,
|
|||||||
publish();
|
publish();
|
||||||
}
|
}
|
||||||
// save new state to nvs #2946
|
// save new state to nvs #2946
|
||||||
char key[sizeof(scheduleItem.name) + 2];
|
if (scheduleItem.flags != SCHEDULEFLAG_SCHEDULE_IMMEDIATE) {
|
||||||
snprintf(key, sizeof(key), "s:%s", scheduleItem.name);
|
char key[sizeof(scheduleItem.name) + 2];
|
||||||
EMSESP::nvs_.putBool(key, scheduleItem.active);
|
snprintf(key, sizeof(key), "s:%s", scheduleItem.name);
|
||||||
/* save to filesystem
|
EMSESP::nvs_.putBool(key, scheduleItem.active);
|
||||||
EMSESP::webSchedulerService.update([&](WebScheduler & webSchedule) {
|
}
|
||||||
for (auto si : webSchedule.scheduleItems) {
|
|
||||||
if (!strcmp(si.name, scheduleItem.name)) {
|
|
||||||
si.active = scheduleItem.active;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return StateUpdateResult::CHANGED;
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,6 +175,15 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(cmd, F_(metrics))) {
|
||||||
|
std::string metrics = get_metrics_prometheus();
|
||||||
|
if (!metrics.empty()) {
|
||||||
|
output["api_data"] = metrics;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const char * attribute_s = Command::get_attribute(cmd);
|
const char * attribute_s = Command::get_attribute(cmd);
|
||||||
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
||||||
if (Helpers::toLower(scheduleItem.name) == cmd) {
|
if (Helpers::toLower(scheduleItem.name) == cmd) {
|
||||||
@@ -195,6 +195,21 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
|||||||
return false; // not found
|
return false; // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate Prometheus metrics format from scheduler values
|
||||||
|
std::string WebSchedulerService::get_metrics_prometheus() {
|
||||||
|
std::string result;
|
||||||
|
result.reserve(scheduleItems_->size() * 140);
|
||||||
|
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
||||||
|
if (scheduleItem.name[0] == '\0') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result += (std::string) "# HELP emsesp_" + scheduleItem.name + " " + scheduleItem.name + ", boolean, readable, visible, writable\n";
|
||||||
|
result += (std::string) "# TYPE emsesp_" + scheduleItem.name + " gauge\n";
|
||||||
|
result += (std::string) "emsesp_" + scheduleItem.name + " " + (scheduleItem.active ? "1\n" : "0\n");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// build the json for specific entity
|
// build the json for specific entity
|
||||||
void WebSchedulerService::get_value_json(JsonObject output, const ScheduleItem & scheduleItem) {
|
void WebSchedulerService::get_value_json(JsonObject output, const ScheduleItem & scheduleItem) {
|
||||||
output["name"] = (const char *)scheduleItem.name;
|
output["name"] = (const char *)scheduleItem.name;
|
||||||
@@ -483,6 +498,10 @@ void WebSchedulerService::loop() {
|
|||||||
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_IMMEDIATE) {
|
if (scheduleItem.active && scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_IMMEDIATE) {
|
||||||
command(scheduleItem.name, scheduleItem.cmd.c_str(), compute(scheduleItem.value.c_str()));
|
command(scheduleItem.name, scheduleItem.cmd.c_str(), compute(scheduleItem.value.c_str()));
|
||||||
scheduleItem.active = false;
|
scheduleItem.active = false;
|
||||||
|
publish_single(scheduleItem.name, false);
|
||||||
|
if (EMSESP::mqtt_.get_publish_onchange(0)) {
|
||||||
|
publish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ class WebSchedulerService : public StatefulService<WebScheduler> {
|
|||||||
uint8_t count_entities(bool cmd_only = false);
|
uint8_t count_entities(bool cmd_only = false);
|
||||||
bool onChange(const char * cmd);
|
bool onChange(const char * cmd);
|
||||||
|
|
||||||
|
std::string get_metrics_prometheus();
|
||||||
|
|
||||||
std::string raw_value;
|
std::string raw_value;
|
||||||
std::string computed_value;
|
std::string computed_value;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user