#pragma once #include #include #include "esphome.h" // Forward declare the global variables/pointers defined in main.cpp extern template_::TemplateSensor *local_cellar_temp; extern template_::TemplateSensor *local_cellar_humi; extern template_::TemplateSensor *local_cellar_dp; extern template_::TemplateSensor *local_cellar_out_temp; extern template_::TemplateSensor *local_cellar_out_humi; extern template_::TemplateSensor *local_cellar_out_dp; extern template_::TemplateSensor *local_fan_status; extern template_::TemplateSensor *local_mold_critical; extern template_::TemplateSensor *local_fan_would_activate; extern template_::TemplateSensor *local_mold_threshold; extern template_::TemplateSensor *local_shelly_online; extern globals::GlobalsComponent *prometheus_connected; inline void fetch_prometheus() { WiFiClient client; if (!client.connect("prometheus.haumdaucher.de", 80)) { prometheus_connected->value() = false; ESP_LOGW("taupi", "Failed to connect to Prometheus over HTTP"); return; } // Send HTTP/1.0 request to avoid chunked transfer encoding! client.println("GET /api/v1/query?query=%7B__name__%3D~%22taupi_.*%7Cup%22%2Cjob%3D%22taupi-fan%22%7D HTTP/1.0"); client.println("Host: prometheus.haumdaucher.de"); client.println("Authorization: Basic bW9yaXR6OlZhZWo2UXVpZXF1NHZvMGphZVJh"); client.println("Connection: close"); client.println(); // Read headers bool headers_ended = false; std::string body = ""; while (client.connected() || client.available()) { if (client.available()) { if (!headers_ended) { String line = client.readStringUntil('\n'); if (line == "\r" || line == "") { headers_ended = true; } } else { String data = client.readString(); body += data.c_str(); } } } client.stop(); if (body.length() == 0) { prometheus_connected->value() = false; ESP_LOGW("taupi", "Empty response body from Prometheus"); return; } prometheus_connected->value() = true; // Parse body using ArduinoJson 7 JsonDocument doc; DeserializationError error = deserializeJson(doc, body); if (!error) { JsonObject root = doc.as(); JsonObject data = root["data"]; JsonArray result = data["result"]; for (JsonObject item : result) { JsonObject metric = item["metric"]; std::string name = metric["__name__"].as(); JsonArray value = item["value"]; if (value.size() >= 2) { std::string val_str = value[1].as(); float val = atof(val_str.c_str()); if (name == "taupi_temperature_celsius_innen") local_cellar_temp->publish_state(val); else if (name == "taupi_humidity_percent_innen") local_cellar_humi->publish_state(val); else if (name == "taupi_dewpoint_celsius_innen") local_cellar_dp->publish_state(val); else if (name == "taupi_temperature_celsius_aussen") local_cellar_out_temp->publish_state(val); else if (name == "taupi_humidity_percent_aussen") local_cellar_out_humi->publish_state(val); else if (name == "taupi_dewpoint_celsius_aussen") local_cellar_out_dp->publish_state(val); else if (name == "taupi_relay_status") local_fan_status->publish_state(val); else if (name == "taupi_is_critical") local_mold_critical->publish_state(val); else if (name == "taupi_would_fan_activate") local_fan_would_activate->publish_state(val); else if (name == "taupi_critical_humidity_threshold_percent") local_mold_threshold->publish_state(val); else if (name == "up") { std::string job = metric["job"].as(); if (job == "taupi-fan") { local_shelly_online->publish_state(val); } } } } ESP_LOGD("taupi", "Successfully parsed Taupi metrics from Prometheus"); } else { ESP_LOGW("taupi", "JSON parsing failed: %s", error.c_str()); } }