This commit is contained in:
Håvard O. Nordstrand 2021-08-28 17:37:40 +02:00
parent 9c5804dc9f
commit dad14bae43
2 changed files with 111 additions and 68 deletions

View File

@ -22,21 +22,23 @@
#define WIFI_SSID "" #define WIFI_SSID ""
// Wi-Fi password (required) // Wi-Fi password (required)
#define WIFI_PASSWORD "" #define WIFI_PASSWORD ""
// Wi-Fi hostname (for DHCP, uncomment if non-default desired) // Hostname for DHCP DDNS, overrides the default (uncomment to enable)
// #define WIFI_HOSTNAME "my_host_name" // #define WIFI_HOSTNAME "my_host_name"
// Wi-Fi static IPv4 address enabled or disabled (disable for DHCPv4) // Use static IPv4 addressing, disable for DHCPv4
#define WIFI_IPV4_STATIC false #define WIFI_IPV4_STATIC true
// Wi-Fi static IPv4 address // Static IPv4 address
#define WIFI_IPV4_ADDRESS 192, 168, 1, 15 #define WIFI_IPV4_ADDRESS 192, 168, 1, 15
// Wi-Fi static IPv4 gateway address // Static IPv4 gateway address
#define WIFI_IPV4_GATEWAY 192, 168, 1, 1 #define WIFI_IPV4_GATEWAY 192, 168, 1, 1
// Wi-Fi static IPv4 subnet mask // Static IPv4 subnet mask
#define WIFI_IPV4_SUBNET_MASK 255, 255, 255, 0 #define WIFI_IPV4_SUBNET_MASK 255, 255, 255, 0
// Wi-Fi static IPv4 primary DNS server // Static IPv4 primary DNS server
#define WIFI_IPV4_DNS_1 1, 1, 1, 1 #define WIFI_IPV4_DNS_1 1, 1, 1, 1
// Wi-Fi static IPv4 secondary DNS server // Static IPv4 secondary DNS server
#define WIFI_IPV4_DNS_2 1, 0, 0, 1 #define WIFI_IPV4_DNS_2 1, 0, 0, 1
// HTTP server port // HTTP server port
#define HTTP_SERVER_PORT 80 #define HTTP_SERVER_PORT 80
// HTTP metrics endpoint // HTTP metrics endpoint
#define HTTP_METRICS_ENDPOINT "/metrics" #define HTTP_METRICS_ENDPOINT "/metrics"
// Prometheus namespace, aka metric prefix
#define PROM_NAMESPACE "iot"

View File

@ -1,11 +1,12 @@
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
#include <WiFiClient.h>
#include <DHTesp.h> #include <DHTesp.h>
#include "config.h" #include "config.h"
#include "version.h" #include "version.h"
#define EXPLODE4(arr) (arr[0], arr[1], arr[2], arr[3])
enum LogLevel { enum LogLevel {
DEBUG, DEBUG,
INFO, INFO,
@ -28,78 +29,90 @@ float humidity, temperature, heat_index;
uint32_t previous_read_time = 0; uint32_t previous_read_time = 0;
void setup(void) { void setup(void) {
char message[128];
Serial.begin(9600); Serial.begin(9600);
setup_dht_sensor(); setup_dht_sensor();
setup_wifi(); setup_wifi();
setup_http_server(); setup_http_server();
snprintf(message, 128, "Namespace: %s", PROM_NAMESPACE);
log(message);
log("Setup done");
} }
void setup_dht_sensor() { void setup_dht_sensor() {
log("Setting up DHT sensor ..."); log("Setting up DHT sensor");
dht_sensor.setup(DHT_PIN, DHTesp::DHT_TYPE); dht_sensor.setup(DHT_PIN, DHTesp::DHT_TYPE);
delay(dht_sensor.getMinimumSamplingPeriod()); delay(dht_sensor.getMinimumSamplingPeriod());
// Test read // Test read
read_sensors(true); read_sensors(true);
log("DHT sensor ready."); log("DHT sensor ready");
} }
void setup_wifi() { void setup_wifi() {
WiFi.mode(WIFI_STA);
char message[128]; char message[128];
log("Setting up Wi-Fi");
snprintf(message, 128, "Wi-Fi SSID: %s", WIFI_SSID); snprintf(message, 128, "Wi-Fi SSID: %s", WIFI_SSID);
log(message); log(message);
snprintf(message, 128, "MAC address: %s", WiFi.macAddress().c_str());
log(message);
snprintf(message, 128, "Initial hostname: %s", WiFi.hostname().c_str());
log(message);
if (WIFI_IPV4_STATIC) { WiFi.mode(WIFI_STA);
IPAddress address(WIFI_IPV4_ADDRESS);
IPAddress subnet(WIFI_IPV4_SUBNET_MASK); #if WIFI_IPV4_STATIC == true
IPAddress gateway(WIFI_IPV4_GATEWAY); log("Using static IPv4 adressing");
IPAddress dns1(WIFI_IPV4_DNS_1); IPAddress static_address(WIFI_IPV4_ADDRESS);
IPAddress dns2(WIFI_IPV4_DNS_2); IPAddress static_subnet(WIFI_IPV4_SUBNET_MASK);
snprintf(message, 128, "Static IPv4 address: %d.%d.%d.%d", address[0], address[1], address[2], address[3]); IPAddress static_gateway(WIFI_IPV4_GATEWAY);
log(message); IPAddress static_dns1(WIFI_IPV4_DNS_1);
snprintf(message, 128, "Static IPv4 subnet mask: %d.%d.%d.%d", subnet[0], subnet[1], subnet[2], subnet[3]); IPAddress static_dns2(WIFI_IPV4_DNS_2);
log(message); if (!WiFi.config(static_address, static_gateway, static_subnet, static_dns1, static_dns2)) {
snprintf(message, 128, "Static IPv4 gateway: %d.%d.%d.%d", gateway[0], gateway[1], gateway[2], gateway[3]); log("Failed to configure static addressing", LogLevel::ERROR);
log(message);
snprintf(message, 128, "Static IPv4 primary DNS server: %d.%d.%d.%d", dns1[0], dns1[1], dns1[2], dns1[3]);
log(message);
snprintf(message, 128, "Static IPv4 secondary DNS server: %d.%d.%d.%d", dns2[0], dns2[1], dns2[2], dns2[3]);
log(message);
if (!WiFi.config(address, gateway, subnet, dns1, dns2)) {
log("Failed to configure Wi-Fi.", LogLevel::ERROR);
} }
}
log("Wi-Fi connecting ...");
#ifdef WIFI_HOSTNAME
snprintf(message, 128, "Initial hostname: %s", WiFi.hostname().c_str());
log(message);
log("Requesting hostname " WIFI_HOSTNAME);
if (!WiFi.hostname(WIFI_HOSTNAME)) {
log("Hostname request failed");
} else {
log("Hostname request succeeded");
}
snprintf(message, 128, "New hostname: %s", WiFi.hostname().c_str());
log(message);
#endif #endif
#ifdef WIFI_HOSTNAME
log("Requesting hostname: " WIFI_HOSTNAME);
if (!WiFi.hostname(WIFI_HOSTNAME)) {
log("Hostname changed");
} else {
log("Failed to change hostname (too long?)");
}
#endif
WiFi.begin(WIFI_SSID, WIFI_PASSWORD); WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) { while (WiFi.status() != WL_CONNECTED) {
log("Wi-Fi waiting ...", LogLevel::DEBUG); log("Wi-Fi connection not ready, waiting", LogLevel::DEBUG);
delay(500); delay(500);
} }
const IPAddress &address = WiFi.localIP();
log("Wi-Fi connected."); log("Wi-Fi connected.");
snprintf(message, 128, "IPv4 address: %d.%d.%d.%d", address[0], address[1], address[2], address[3]); snprintf(message, 128, "SSID: %s", WiFi.SSID().c_str());
log(message);
snprintf(message, 128, "BSSID: %s", WiFi.BSSIDstr().c_str());
log(message);
snprintf(message, 128, "Hostname: %s", WiFi.hostname().c_str());
log(message);
snprintf(message, 128, "IPv4 address: %s", WiFi.localIP().toString().c_str());
log(message);
snprintf(message, 128, "IPv4 subnet mask: %s", WiFi.subnetMask().toString().c_str());
log(message);
snprintf(message, 128, "IPv4 gateway: %s", WiFi.gatewayIP().toString().c_str());
log(message);
snprintf(message, 128, "Primary DNS server: %s", WiFi.dnsIP(0).toString().c_str());
log(message);
snprintf(message, 128, "Secondary DNS server: %s", WiFi.dnsIP(1).toString().c_str());
log(message); log(message);
} }
void setup_http_server() { void setup_http_server() {
http_server.on("/", HTTPMethod::HTTP_GET, handle_http_home_client); char message[128];
http_server.on(HTTP_METRICS_ENDPOINT, HTTPMethod::HTTP_GET, handle_http_metrics_client); http_server.on("/", HTTPMethod::HTTP_GET, handle_http_root);
http_server.on(HTTP_METRICS_ENDPOINT, HTTPMethod::HTTP_GET, handle_http_metrics);
http_server.onNotFound(handle_http_not_found);
http_server.begin(); http_server.begin();
log("HTTP server started."); log("HTTP server started.");
char message[128];
snprintf(message, 128, "Metrics endpoint: %s", HTTP_METRICS_ENDPOINT); snprintf(message, 128, "Metrics endpoint: %s", HTTP_METRICS_ENDPOINT);
log(message); log(message);
} }
@ -108,7 +121,8 @@ void loop(void) {
http_server.handleClient(); http_server.handleClient();
} }
void handle_http_home_client() { void handle_http_root() {
log_request();
static size_t const BUFSIZE = 256; static size_t const BUFSIZE = 256;
static char const *response_template = static char const *response_template =
"Prometheus ESP8266 DHT Exporter by HON95.\n" "Prometheus ESP8266 DHT Exporter by HON95.\n"
@ -121,25 +135,26 @@ void handle_http_home_client() {
http_server.send(200, "text/plain; charset=utf-8", response); http_server.send(200, "text/plain; charset=utf-8", response);
} }
void handle_http_metrics_client() { void handle_http_metrics() {
log_request();
static size_t const BUFSIZE = 1024; static size_t const BUFSIZE = 1024;
static char const *response_template = static char const *response_template =
"# HELP iot_info Metadata about the device.\n" "# HELP " PROM_NAMESPACE "_info Metadata about the device.\n"
"# TYPE iot_info gauge\n" "# TYPE " PROM_NAMESPACE "_info gauge\n"
"# UNIT iot_info \n" "# UNIT " PROM_NAMESPACE "_info \n"
"iot_info{version=\"%s\",board=\"%s\",sensor=\"%s\"} 1\n" PROM_NAMESPACE "_info{version=\"%s\",board=\"%s\",sensor=\"%s\"} 1\n"
"# HELP iot_air_humidity_percent Air humidity.\n" "# HELP " PROM_NAMESPACE "_air_humidity_percent Air humidity.\n"
"# TYPE iot_air_humidity_percent gauge\n" "# TYPE " PROM_NAMESPACE "_air_humidity_percent gauge\n"
"# UNIT iot_air_humidity_percent %%\n" "# UNIT " PROM_NAMESPACE "_air_humidity_percent %%\n"
"iot_air_humidity_percent %f\n" PROM_NAMESPACE "_air_humidity_percent %f\n"
"# HELP iot_air_temperature_celsius Air temperature.\n" "# HELP " PROM_NAMESPACE "_air_temperature_celsius Air temperature.\n"
"# TYPE iot_air_temperature_celsius gauge\n" "# TYPE " PROM_NAMESPACE "_air_temperature_celsius gauge\n"
"# UNIT iot_air_temperature_celsius \u00B0C\n" "# UNIT " PROM_NAMESPACE "_air_temperature_celsius \u00B0C\n"
"iot_air_temperature_celsius %f\n" PROM_NAMESPACE "_air_temperature_celsius %f\n"
"# HELP iot_air_heat_index_celsius Apparent air temperature, based on temperature and humidity.\n" "# HELP " PROM_NAMESPACE "_air_heat_index_celsius Apparent air temperature, based on temperature and humidity.\n"
"# TYPE iot_air_heat_index_celsius gauge\n" "# TYPE " PROM_NAMESPACE "_air_heat_index_celsius gauge\n"
"# UNIT iot_air_heat_index_celsius \u00B0C\n" "# UNIT " PROM_NAMESPACE "_air_heat_index_celsius \u00B0C\n"
"iot_air_heat_index_celsius %f\n"; PROM_NAMESPACE "_air_heat_index_celsius %f\n";
read_sensors(); read_sensors();
if (isnan(humidity) || isnan(temperature) || isnan(heat_index)) { if (isnan(humidity) || isnan(temperature) || isnan(heat_index)) {
@ -152,6 +167,11 @@ void handle_http_metrics_client() {
http_server.send(200, "text/plain; charset=utf-8", response); http_server.send(200, "text/plain; charset=utf-8", response);
} }
void handle_http_not_found() {
log_request();
http_server.send(404, "text/plain; charset=utf-8", "Not found.");
}
void read_sensors(boolean force) { void read_sensors(boolean force) {
uint32_t min_interval = max(dht_sensor.getMinimumSamplingPeriod(), READ_INTERVAL); uint32_t min_interval = max(dht_sensor.getMinimumSamplingPeriod(), READ_INTERVAL);
uint32_t current_time = millis(); uint32_t current_time = millis();
@ -211,6 +231,27 @@ bool read_sensor(float (*function)(), float *value) {
return success; return success;
} }
void log_request() {
char message[128];
char method_name[16];
get_http_method_name(method_name, 16, http_server.method());
snprintf(message, 128, "Request: client=%s:%u method=%s path=%s",
http_server.client().remoteIP().toString().c_str(), http_server.client().remotePort(), method_name, http_server.uri().c_str());
log(message, LogLevel::INFO);
}
void get_http_method_name(char *name, size_t name_length, HTTPMethod method) {
switch (method) {
case HTTP_ANY:
snprintf(name, name_length, "ANY");
break;
default:
snprintf(name, name_length, "UNKNOWN");
break;
//, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS }
}
}
void log(char const *message, LogLevel level) { void log(char const *message, LogLevel level) {
if (DEBUG_MODE == 0 && level == LogLevel::DEBUG) { if (DEBUG_MODE == 0 && level == LogLevel::DEBUG) {
return; return;