Cleanup web server prometheus integration (#1192)

This commit is contained in:
Otto Winter 2020-07-27 12:07:05 +02:00
parent f39bf9c1e5
commit e898345ff1
No known key found for this signature in database
GPG key ID: 48ED2DDB96D7682C
10 changed files with 106 additions and 125 deletions

View file

@ -0,0 +1,22 @@
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_ID
from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID
from esphome.components import web_server_base
AUTO_LOAD = ['web_server_base']
prometheus_ns = cg.esphome_ns.namespace('prometheus')
PrometheusHandler = prometheus_ns.class_('PrometheusHandler', cg.Component)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(PrometheusHandler),
cv.GenerateID(CONF_WEB_SERVER_BASE_ID): cv.use_id(web_server_base.WebServerBase),
}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
paren = yield cg.get_variable(config[CONF_WEB_SERVER_BASE_ID])
var = cg.new_Pvariable(config[CONF_ID], paren)
yield cg.register_component(var, config)

View file

@ -1,23 +1,11 @@
#include "web_server.h" #include "prometheus_handler.h"
#include "web_server_prometheus.h"
#include "esphome/core/log.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/util.h"
#include "esphome/components/json/json_util.h"
#include "StreamString.h"
#include <cstdlib>
#ifdef USE_LOGGER
#include <esphome/components/logger/logger.h>
#endif
namespace esphome { namespace esphome {
namespace web_server { namespace prometheus {
void WebServerPrometheus::handle_request(AsyncWebServerRequest *request) { void PrometheusHandler::handleRequest(AsyncWebServerRequest *req) {
AsyncResponseStream *stream = request->beginResponseStream("text/plain"); AsyncResponseStream *stream = req->beginResponseStream("text/plain");
#ifdef USE_SENSOR #ifdef USE_SENSOR
this->sensor_type_(stream); this->sensor_type_(stream);
@ -55,16 +43,16 @@ void WebServerPrometheus::handle_request(AsyncWebServerRequest *request) {
this->switch_row_(stream, obj); this->switch_row_(stream, obj);
#endif #endif
request->send(stream); req->send(stream);
} }
// Type-specific implementation // Type-specific implementation
#ifdef USE_SENSOR #ifdef USE_SENSOR
void WebServerPrometheus::sensor_type_(AsyncResponseStream *stream) { void PrometheusHandler::sensor_type_(AsyncResponseStream *stream) {
stream->print(F("#TYPE esphome_sensor_value GAUGE\n")); stream->print(F("#TYPE esphome_sensor_value GAUGE\n"));
stream->print(F("#TYPE esphome_sensor_failed GAUGE\n")); stream->print(F("#TYPE esphome_sensor_failed GAUGE\n"));
} }
void WebServerPrometheus::sensor_row_(AsyncResponseStream *stream, sensor::Sensor *obj) { void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor *obj) {
if (obj->is_internal()) if (obj->is_internal())
return; return;
if (!isnan(obj->state)) { if (!isnan(obj->state)) {
@ -97,14 +85,14 @@ void WebServerPrometheus::sensor_row_(AsyncResponseStream *stream, sensor::Senso
// Type-specific implementation // Type-specific implementation
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
void WebServerPrometheus::binary_sensor_type_(AsyncResponseStream *stream) { void PrometheusHandler::binary_sensor_type_(AsyncResponseStream *stream) {
stream->print(F("#TYPE esphome_binary_sensor_value GAUGE\n")); stream->print(F("#TYPE esphome_binary_sensor_value GAUGE\n"));
stream->print(F("#TYPE esphome_binary_sensor_failed GAUGE\n")); stream->print(F("#TYPE esphome_binary_sensor_failed GAUGE\n"));
} }
void WebServerPrometheus::binary_sensor_row_(AsyncResponseStream *stream, binary_sensor::BinarySensor *obj) { void PrometheusHandler::binary_sensor_row_(AsyncResponseStream *stream, binary_sensor::BinarySensor *obj) {
if (obj->is_internal()) if (obj->is_internal())
return; return;
if (!isnan(obj->state)) { if (obj->has_state()) {
// We have a valid value, output this value // We have a valid value, output this value
stream->print(F("esphome_binary_sensor_failed{id=\"")); stream->print(F("esphome_binary_sensor_failed{id=\""));
stream->print(obj->get_object_id().c_str()); stream->print(obj->get_object_id().c_str());
@ -131,68 +119,58 @@ void WebServerPrometheus::binary_sensor_row_(AsyncResponseStream *stream, binary
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
void WebServerPrometheus::fan_type_(AsyncResponseStream *stream) { void PrometheusHandler::fan_type_(AsyncResponseStream *stream) {
stream->print(F("#TYPE esphome_fan_value GAUGE\n")); stream->print(F("#TYPE esphome_fan_value GAUGE\n"));
stream->print(F("#TYPE esphome_fan_failed GAUGE\n")); stream->print(F("#TYPE esphome_fan_failed GAUGE\n"));
stream->print(F("#TYPE esphome_fan_speed GAUGE\n")); stream->print(F("#TYPE esphome_fan_speed GAUGE\n"));
stream->print(F("#TYPE esphome_fan_oscillation GAUGE\n")); stream->print(F("#TYPE esphome_fan_oscillation GAUGE\n"));
} }
void WebServerPrometheus::fan_row_(AsyncResponseStream *stream, fan::FanState *obj) { void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::FanState *obj) {
if (obj->is_internal()) if (obj->is_internal())
return; return;
if (!isnan(obj->state)) { stream->print(F("esphome_fan_failed{id=\""));
// We have a valid value, output this value stream->print(obj->get_object_id().c_str());
stream->print(F("esphome_fan_failed{id=\"")); stream->print(F("\",name=\""));
stream->print(obj->get_object_id().c_str()); stream->print(obj->get_name().c_str());
stream->print(F("\",name=\"")); stream->print(F("\"} 0\n"));
stream->print(obj->get_name().c_str()); // Data itself
stream->print(F("\"} 0\n")); stream->print(F("esphome_fan_value{id=\""));
// Data itself stream->print(obj->get_object_id().c_str());
stream->print(F("esphome_fan_value{id=\"")); stream->print(F("\",name=\""));
stream->print(obj->get_name().c_str());
stream->print(F("\"} "));
stream->print(obj->state);
stream->print('\n');
// Speed if available
if (obj->get_traits().supports_speed()) {
stream->print(F("esphome_fan_speed{id=\""));
stream->print(obj->get_object_id().c_str()); stream->print(obj->get_object_id().c_str());
stream->print(F("\",name=\"")); stream->print(F("\",name=\""));
stream->print(obj->get_name().c_str()); stream->print(obj->get_name().c_str());
stream->print(F("\"} ")); stream->print(F("\"} "));
stream->print(obj->state); stream->print(obj->speed);
stream->print('\n'); stream->print('\n');
// Speed if available }
if (obj->get_traits().supports_speed()) { // Oscillation if available
stream->print(F("esphome_fan_speed{id=\"")); if (obj->get_traits().supports_oscillation()) {
stream->print(obj->get_object_id().c_str()); stream->print(F("esphome_fan_oscillation{id=\""));
stream->print(F("\",name=\""));
stream->print(obj->get_name().c_str());
stream->print(F("\"} "));
stream->print(obj->speed);
stream->print('\n');
}
// Oscillation if available
if (obj->get_traits().supports_oscillation()) {
stream->print(F("esphome_fan_oscillation{id=\""));
stream->print(obj->get_object_id().c_str());
stream->print(F("\",name=\""));
stream->print(obj->get_name().c_str());
stream->print(F("\"} "));
stream->print(obj->oscillating);
stream->print('\n');
}
} else {
// Invalid state
stream->print(F("esphome_fan_failed{id=\""));
stream->print(obj->get_object_id().c_str()); stream->print(obj->get_object_id().c_str());
stream->print(F("\",name=\"")); stream->print(F("\",name=\""));
stream->print(obj->get_name().c_str()); stream->print(obj->get_name().c_str());
stream->print(F("\"} 1\n")); stream->print(F("\"} "));
stream->print(obj->oscillating);
stream->print('\n');
} }
} }
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
void WebServerPrometheus::light_type_(AsyncResponseStream *stream) { void PrometheusHandler::light_type_(AsyncResponseStream *stream) {
stream->print(F("#TYPE esphome_light_state GAUGE\n")); stream->print(F("#TYPE esphome_light_state GAUGE\n"));
stream->print(F("#TYPE esphome_light_color GAUGE\n")); stream->print(F("#TYPE esphome_light_color GAUGE\n"));
stream->print(F("#TYPE esphome_light_effect_active GAUGE\n")); stream->print(F("#TYPE esphome_light_effect_active GAUGE\n"));
} }
void WebServerPrometheus::light_row_(AsyncResponseStream *stream, light::LightState *obj) { void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightState *obj) {
if (obj->is_internal()) if (obj->is_internal())
return; return;
// State // State
@ -264,11 +242,11 @@ void WebServerPrometheus::light_row_(AsyncResponseStream *stream, light::LightSt
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
void WebServerPrometheus::cover_type_(AsyncResponseStream *stream) { void PrometheusHandler::cover_type_(AsyncResponseStream *stream) {
stream->print(F("#TYPE esphome_cover_value GAUGE\n")); stream->print(F("#TYPE esphome_cover_value GAUGE\n"));
stream->print(F("#TYPE esphome_cover_failed GAUGE\n")); stream->print(F("#TYPE esphome_cover_failed GAUGE\n"));
} }
void WebServerPrometheus::cover_row_(AsyncResponseStream *stream, cover::Cover *obj) { void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *obj) {
if (obj->is_internal()) if (obj->is_internal())
return; return;
if (!isnan(obj->position)) { if (!isnan(obj->position)) {
@ -307,38 +285,28 @@ void WebServerPrometheus::cover_row_(AsyncResponseStream *stream, cover::Cover *
#endif #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
void WebServerPrometheus::switch_type_(AsyncResponseStream *stream) { void PrometheusHandler::switch_type_(AsyncResponseStream *stream) {
stream->print(F("#TYPE esphome_switch_value GAUGE\n")); stream->print(F("#TYPE esphome_switch_value GAUGE\n"));
stream->print(F("#TYPE esphome_switch_failed GAUGE\n")); stream->print(F("#TYPE esphome_switch_failed GAUGE\n"));
} }
void WebServerPrometheus::switch_row_(AsyncResponseStream *stream, switch_::Switch *obj) { void PrometheusHandler::switch_row_(AsyncResponseStream *stream, switch_::Switch *obj) {
if (obj->is_internal()) if (obj->is_internal())
return; return;
if (!isnan(obj->state)) { stream->print(F("esphome_switch_failed{id=\""));
// We have a valid value, output this value stream->print(obj->get_object_id().c_str());
stream->print(F("esphome_switch_failed{id=\"")); stream->print(F("\",name=\""));
stream->print(obj->get_object_id().c_str()); stream->print(obj->get_name().c_str());
stream->print(F("\",name=\"")); stream->print(F("\"} 0\n"));
stream->print(obj->get_name().c_str()); // Data itself
stream->print(F("\"} 0\n")); stream->print(F("esphome_switch_value{id=\""));
// Data itself stream->print(obj->get_object_id().c_str());
stream->print(F("esphome_switch_value{id=\"")); stream->print(F("\",name=\""));
stream->print(obj->get_object_id().c_str()); stream->print(obj->get_name().c_str());
stream->print(F("\",name=\"")); stream->print(F("\"} "));
stream->print(obj->get_name().c_str()); stream->print(obj->state);
stream->print(F("\"} ")); stream->print('\n');
stream->print(obj->state);
stream->print('\n');
} else {
// Invalid state
stream->print(F("esphome_switch_failed{id=\""));
stream->print(obj->get_object_id().c_str());
stream->print(F("\",name=\""));
stream->print(obj->get_name().c_str());
stream->print(F("\"} 1\n"));
}
} }
#endif #endif
} // namespace web_server } // namespace prometheus
} // namespace esphome } // namespace esphome

View file

@ -1,17 +1,31 @@
#pragma once #pragma once
#include "esphome/core/component.h"
#include "esphome/core/controller.h"
#include "esphome/components/web_server_base/web_server_base.h" #include "esphome/components/web_server_base/web_server_base.h"
#include "esphome/core/controller.h"
#include "esphome/core/component.h"
namespace esphome { namespace esphome {
namespace web_server { namespace prometheus {
class WebServerPrometheus { class PrometheusHandler : public AsyncWebHandler, public Component {
public: public:
WebServerPrometheus(){}; PrometheusHandler(web_server_base::WebServerBase *base) : base_(base) {}
/// Handle an prometheus metrics request under '/metrics'.
void handle_request(AsyncWebServerRequest *request); bool canHandle(AsyncWebServerRequest *request) override {
if (request->method() == HTTP_GET) {
if (request->url() == "/metrics")
return true;
}
return false;
}
void handleRequest(AsyncWebServerRequest *req) override;
void setup() override {
this->base_->init();
this->base_->add_handler(this);
}
protected: protected:
#ifdef USE_SENSOR #ifdef USE_SENSOR
@ -55,7 +69,9 @@ class WebServerPrometheus {
/// Return the switch Values state as prometheus data point /// Return the switch Values state as prometheus data point
void switch_row_(AsyncResponseStream *stream, switch_::Switch *obj); void switch_row_(AsyncResponseStream *stream, switch_::Switch *obj);
#endif #endif
web_server_base::WebServerBase *base_;
}; };
} // namespace web_server } // namespace prometheus
} // namespace esphome } // namespace esphome

View file

@ -4,7 +4,7 @@ from esphome.components import web_server_base
from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID
from esphome.const import ( from esphome.const import (
CONF_CSS_INCLUDE, CONF_CSS_URL, CONF_ID, CONF_JS_INCLUDE, CONF_JS_URL, CONF_PORT, CONF_CSS_INCLUDE, CONF_CSS_URL, CONF_ID, CONF_JS_INCLUDE, CONF_JS_URL, CONF_PORT,
CONF_AUTH, CONF_USERNAME, CONF_PASSWORD, CONF_PROMETHEUS) CONF_AUTH, CONF_USERNAME, CONF_PASSWORD)
from esphome.core import coroutine_with_priority from esphome.core import coroutine_with_priority
AUTO_LOAD = ['json', 'web_server_base'] AUTO_LOAD = ['json', 'web_server_base']
@ -19,7 +19,6 @@ CONFIG_SCHEMA = cv.Schema({
cv.Optional(CONF_CSS_INCLUDE): cv.file_, cv.Optional(CONF_CSS_INCLUDE): cv.file_,
cv.Optional(CONF_JS_URL, default="https://esphome.io/_static/webserver-v1.min.js"): cv.string, cv.Optional(CONF_JS_URL, default="https://esphome.io/_static/webserver-v1.min.js"): cv.string,
cv.Optional(CONF_JS_INCLUDE): cv.file_, cv.Optional(CONF_JS_INCLUDE): cv.file_,
cv.Optional(CONF_PROMETHEUS, default=False): cv.boolean,
cv.Optional(CONF_AUTH): cv.Schema({ cv.Optional(CONF_AUTH): cv.Schema({
cv.Required(CONF_USERNAME): cv.string_strict, cv.Required(CONF_USERNAME): cv.string_strict,
cv.Required(CONF_PASSWORD): cv.string_strict, cv.Required(CONF_PASSWORD): cv.string_strict,
@ -50,5 +49,3 @@ def to_code(config):
cg.add_define('WEBSERVER_JS_INCLUDE') cg.add_define('WEBSERVER_JS_INCLUDE')
with open(config[CONF_JS_INCLUDE], "r") as myfile: with open(config[CONF_JS_INCLUDE], "r") as myfile:
cg.add(var.set_js_include(myfile.read())) cg.add(var.set_js_include(myfile.read()))
if config[CONF_PROMETHEUS]:
cg.add_define('WEBSERVER_PROMETHEUS')

View file

@ -572,11 +572,6 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) {
if (request->url() == "/") if (request->url() == "/")
return true; return true;
#ifdef WEBSERVER_PROMETHEUS
if (request->url() == "/metrics")
return true;
#endif
#ifdef WEBSERVER_CSS_INCLUDE #ifdef WEBSERVER_CSS_INCLUDE
if (request->url() == "/0.css") if (request->url() == "/0.css")
return true; return true;
@ -637,13 +632,6 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) {
return; return;
} }
#ifdef WEBSERVER_PROMETHEUS
if (request->url() == "/metrics") {
this->prometheus.handle_request(request);
return;
}
#endif
#ifdef WEBSERVER_CSS_INCLUDE #ifdef WEBSERVER_CSS_INCLUDE
if (request->url() == "/0.css") { if (request->url() == "/0.css") {
this->handle_css_request(request); this->handle_css_request(request);

View file

@ -3,9 +3,6 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/controller.h" #include "esphome/core/controller.h"
#include "esphome/components/web_server_base/web_server_base.h" #include "esphome/components/web_server_base/web_server_base.h"
#ifdef WEBSERVER_PROMETHEUS
#include "esphome/components/web_server/web_server_prometheus.h"
#endif
#include <vector> #include <vector>
@ -173,10 +170,6 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
const char *css_include_{nullptr}; const char *css_include_{nullptr};
const char *js_url_{nullptr}; const char *js_url_{nullptr};
const char *js_include_{nullptr}; const char *js_include_{nullptr};
#ifdef WEBSERVER_PROMETHEUS
WebServerPrometheus prometheus;
#endif
}; };
} // namespace web_server } // namespace web_server

View file

@ -384,7 +384,6 @@ CONF_POWER_SAVE_MODE = 'power_save_mode'
CONF_POWER_SUPPLY = 'power_supply' CONF_POWER_SUPPLY = 'power_supply'
CONF_PRESSURE = 'pressure' CONF_PRESSURE = 'pressure'
CONF_PRIORITY = 'priority' CONF_PRIORITY = 'priority'
CONF_PROMETHEUS = 'prometheus'
CONF_PROTOCOL = 'protocol' CONF_PROTOCOL = 'protocol'
CONF_PULL_MODE = 'pull_mode' CONF_PULL_MODE = 'pull_mode'
CONF_PULSE_LENGTH = 'pulse_length' CONF_PULSE_LENGTH = 'pulse_length'

View file

@ -93,11 +93,11 @@ def main():
get_output('clang-tidy-7', '-version') get_output('clang-tidy-7', '-version')
except: except:
print(""" print("""
Oops. It looks like clang-tidy is not installed. Oops. It looks like clang-tidy is not installed.
Please check you can run "clang-tidy-7 -version" in your terminal and install Please check you can run "clang-tidy-7 -version" in your terminal and install
clang-tidy (v7) if necessary. clang-tidy (v7) if necessary.
Note you can also upload your code as a pull request on GitHub and see the CI check Note you can also upload your code as a pull request on GitHub and see the CI check
output to apply clang-tidy. output to apply clang-tidy.
""") """)

View file

@ -166,7 +166,6 @@ web_server:
port: 8080 port: 8080
css_url: https://esphome.io/_static/webserver-v1.min.css css_url: https://esphome.io/_static/webserver-v1.min.css
js_url: https://esphome.io/_static/webserver-v1.min.js js_url: https://esphome.io/_static/webserver-v1.min.js
prometheus: true
power_supply: power_supply:
id: 'atx_power_supply' id: 'atx_power_supply'

View file

@ -210,7 +210,6 @@ logger:
esp8266_store_log_strings_in_flash: false esp8266_store_log_strings_in_flash: false
web_server: web_server:
prometheus: true
deep_sleep: deep_sleep:
run_duration: 20s run_duration: 20s