Improve initial code, but my sensor seems to be broken

This commit is contained in:
Håvard O. Nordstrand 2020-06-27 19:50:42 +02:00
parent e599b110e2
commit 45ae85594b
3 changed files with 160 additions and 102 deletions

View File

@ -1,22 +1,27 @@
# prometheus-arduino-dht-exporter # prometheus-esp8266-dht-exporter
A Prometheus exporter for IoT temperature and humidity measurements, using an Arduino with a Wi-Fi module and a DHT (temperature + humidity) sensor. A Prometheus exporter for IoT temperature and humidity measurements, using an ESP8266 (Arduino-compatible) with a Wi-Fi module and a DHT (temperature + humidity) sensor.
## Hardware ## Hardware
Arduino-compatible board: [WEMOS D1 Mini](https://wiki.wemos.cc/products:d1:d1_mini) (ESP8266) ESP8266 board: [WEMOS D1 Mini](https://wiki.wemos.cc/products:d1:d1_mini) (ESP8266)
DHT sensor: [Wemos DHT Shield](https://wiki.wemos.cc/products:retired:dht_shield_v1.0.0) (DHT11) DHT sensor: [Wemos DHT Shield](https://wiki.wemos.cc/products:retired:dht_shield_v1.0.0) (DHT11)
## Requirements ## Requirements
- [Arduino IDE](https://www.arduino.cc/en/Main/Software) (download) - [Arduino IDE](https://www.arduino.cc/en/Main/Software)
- [esp8266 library for Arduino](https://github.com/esp8266/Arduino#installing-with-boards-manager) (see instructions) - Download and install.
- [Adafruit DHT sensor library](https://github.com/adafruit/DHT-sensor-library) (install using the library manager, including all dependencies) - [esp8266 library for Arduino](https://github.com/esp8266/Arduino#installing-with-boards-manager)
- See the instructions on the page.
- [Adafruit DHT sensor library](https://github.com/adafruit/DHT-sensor-library)
- Install using the library manager, including all dependencies.
## Building ## Building
This uses the Arduino IDE.
1. Copy `config.default.h` to `config.h` and fill inn the details. 1. Copy `config.default.h` to `config.h` and fill inn the details.
1. Set the correct board settings in Arduino IDE: 1. Set the correct settings for the board.
- WEMOS D1 Mini uses board "WeMoS D1 R2 & mini", CPU frequency 160MHz and upload speed 821 600. - WEMOS D1 Mini uses board "WeMoS D1 R2 & mini".
1. Build and upload in Arduino IDE. 1. Build and upload using the Arduino IDE.

View File

@ -1,21 +1,24 @@
#pragma once #pragma once
// Debug mode is enabled if not zero // Debug mode is enabled if not zero
#define DEBUG 0 #define DEBUG_MODE 0
// DHT sensor type: DHT11, DHT21 or DHT22 // DHT sensor type: DHT11, DHT21 or DHT22
#define DHT_TYPE DHT11 #define DHT_TYPE DHT11
// DHT pin // DHT pin
#define DHT_PIN D4 #define DHT_PIN D4
// HTTP server port
#define HTTP_SERVER_PORT 80
// HTTP metrics endpoint
#define HTTP_METRICS_ENDPOINT "/metrics"
// Temperature offset in degrees Celsius // Temperature offset in degrees Celsius
#define TEMPERATURE_CORRECTION_OFFSET 0 #define TEMPERATURE_CORRECTION_OFFSET 0
// Humidity offset in percent // Humidity offset in percent
#define HUMIDITY_CORRECTION_OFFSET 0 #define HUMIDITY_CORRECTION_OFFSET 0
// How long to cache the sensor results // How long to cache the sensor results
#define READ_INTERVAL 2000 #define READ_INTERVAL 2000
// Retry up to this many times to read the snsor correctly before returning before returning error // How many times to try to read the sensor before returning an error
#define READ_RETRY_COUNT 5 #define READ_TRY_COUNT 5
// WiFi SSID (required) // WiFi SSID (required)
const char *WIFI_SSID = ""; #define WIFI_SSID ""
// WiFi password (required) // WiFi password (required)
const char *WIFI_PASSWORD = ""; #define WIFI_PASSWORD ""

View File

@ -5,113 +5,163 @@
#include "config.h" #include "config.h"
enum LogLevel {
DEBUG,
INFO,
ERROR,
};
void setup_dht_sensor();
void setup_wifi();
void setup_http_server();
void handle_http_home_client();
void handle_http_metrics_client();
void read_sensors(boolean force=false);
bool read_sensor(float (*function)(), float *value);
void log(char const *message, LogLevel level=LogLevel::INFO);
DHT dht_sensor(DHT_PIN, DHT_TYPE); DHT dht_sensor(DHT_PIN, DHT_TYPE);
ESP8266WebServer web_server(80); ESP8266WebServer http_server(HTTP_SERVER_PORT);
float humidity, temperature; float humidity, temperature;
char str_humidity[10], str_temperature[10]; char str_humidity[10], str_temperature[10];
unsigned long previousReadTime = 0; unsigned long previousReadTime = 0;
void setup_wifi();
void setup_dht();
void setup_web();
void read_sensors(boolean force=false);
void read_sensor(const char *name, float (*function)(), const char *str_format, char *str_result, size_t len_result, float &result);
void log(const char *message, boolean error=false);
void setup(void) { void setup(void) {
Serial.begin(9600); Serial.begin(9600);
log("Starting setup ..."); setup_dht_sensor();
setup_wifi(); setup_wifi();
setup_dht(); setup_http_server();
setup_web(); }
log("Started setup");
void setup_dht_sensor() {
log("Setting up DHT sensor ...");
dht_sensor.begin();
// Test read
read_sensors(true);
log("DHT sensor ready.");
} }
void setup_wifi() { void setup_wifi() {
char message[100]; char message[100];
snprintf(message, 100, "SSID: %s", WIFI_SSID); snprintf(message, 100, "Using Wi-Fi SSID \"%s\".", WIFI_SSID);
log(message); log(message);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD); log("Wi-Fi connecting ...");
log("WiFi connecting ..."); WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) { while (WiFi.status() != WL_CONNECTED) {
delay(500); log("Wi-Fi waiting ...", LogLevel::DEBUG);
} delay(500);
const IPAddress &ipaddr = WiFi.localIP(); }
snprintf(message, 100, "IP address: %d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); const IPAddress &ipaddr = WiFi.localIP();
log(message); log("Wi-Fi connected.");
log("Started WiFi"); snprintf(message, 100, "IPv4 address: %d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
log(message);
} }
void setup_dht() { void setup_http_server() {
dht_sensor.begin(); http_server.on("/", HTTPMethod::HTTP_GET, handle_http_home_client);
// Initial read http_server.on(HTTP_METRICS_ENDPOINT, HTTPMethod::HTTP_GET, handle_http_metrics_client);
read_sensors(true); http_server.begin();
log("Started DHT sensor"); log("HTTP server started.");
}
void setup_web() {
web_server.on("/", [] {
read_sensors();
char response[100];
snprintf(response, 100, "Temperature: %s\nHumidity: %s", str_temperature, str_humidity);
web_server.send(200, "text/plain", response);
});
web_server.begin();
log("Started web server");
} }
void loop(void) { void loop(void) {
web_server.handleClient(); http_server.handleClient();
}
void handle_http_home_client() {
static char const *response =
"Prometheus ESP8266 DHT Exporter by HON95.\n"
"\n"
"Project: https://github.com/HON95/prometheus-esp8266-dht-exporter\n"
"\n"
"Usage: " HTTP_METRICS_ENDPOINT "\n";
http_server.send(200, "text/plain", response);
}
void handle_http_metrics_client() {
read_sensors();
char response[100];
snprintf(response, 100, "Temperature: %s\nHumidity: %s", str_temperature, str_humidity);
http_server.send(200, "text/plain", response);
} }
void read_sensors(boolean force) { void read_sensors(boolean force) {
unsigned long currentTime = millis(); // TODO remove caching, the library already does it
if (!force && currentTime - previousReadTime < READ_INTERVAL) { unsigned long currentTime = millis();
// Use cached values if (!force && currentTime - previousReadTime < READ_INTERVAL) {
return; log("Sensors were recently read, will not read again yet.", LogLevel::DEBUG);
} return;
previousReadTime = currentTime; }
previousReadTime = currentTime;
// Read temperature as degrees Celsius and force read read_humidity_sensor();
read_sensor("temperature", []() { read_temperature_sensor();
return dht_sensor.readTemperature(false, true) + TEMPERATURE_CORRECTION_OFFSET; // TODO float hic = dht.computeHeatIndex(t, h, false);
}, "%.0f\u00B0C", str_temperature, 10, temperature);
// Read humidity and force read
read_sensor("humidity", []() {
return dht_sensor.readHumidity(true) + HUMIDITY_CORRECTION_OFFSET;
}, "%.0f%%", str_humidity, 10, humidity);
} }
void read_sensor(const char *name, float (*function)(), const char *str_format, char *str_result, size_t len_result, float &result) { void read_humidity_sensor() {
char message[100]; log("Reading humidity sensor ...", LogLevel::DEBUG);
result = function(); bool result = read_sensor([] {
for (int i = 0; isnan(result) && i < READ_RETRY_COUNT; i++) { return dht_sensor.readHumidity();
#if DEBUG != 0 }, &humidity);
snprintf(message, 100, "Re-reading failed %s ...", name); if (result) {
log(message, true); humidity += HUMIDITY_CORRECTION_OFFSET;
#endif snprintf(str_humidity, 10, "%.0f%%", humidity);
result = function(); } else {
} snprintf(str_humidity, 10, "ERROR");
if (!isnan(humidity)) { log("Failed to read humidity sensor.", LogLevel::ERROR);
snprintf(str_result, len_result, str_format, result); }
} else {
strcpy(str_result, "ERROR");
snprintf(message, 100, "Failed to read %s!", name);
log(message, true);
}
} }
void log(const char *message, boolean error) { void read_temperature_sensor() {
float seconds = millis() / 1000.0; log("Reading temperature sensor ...", LogLevel::DEBUG);
char level[10]; bool result = read_sensor([] {
if (!error) { return dht_sensor.readTemperature(false);
strcpy(level, "INFO"); }, &temperature);
} else { if (result) {
strcpy(level, "ERROR"); temperature += TEMPERATURE_CORRECTION_OFFSET;
} snprintf(str_temperature, 10, "%.0f\u00B0C", temperature);
char record[150]; } else {
snprintf(record, 150, "[%10.3f] [%-5s] %s", seconds, level, message); snprintf(str_temperature, 10, "ERROR");
Serial.println(record); log("Failed to read temperature sensor.", LogLevel::ERROR);
}
}
bool read_sensor(float (*function)(), float *value) {
bool success = false;
for (int i = 0; i < READ_TRY_COUNT; i++) {
*value = function();
if (!isnan(*value)) {
success = true;
break;
}
log("Failed to read sensor.", LogLevel::DEBUG);
}
return success;
}
void log(char const *message, LogLevel level) {
if (DEBUG_MODE == 0 && level == LogLevel::DEBUG) {
return;
}
// Will overflow after a while
float seconds = millis() / 1000.0;
char str_level[10];
switch (level) {
case DEBUG:
strcpy(str_level, "DEBUG");
break;
case INFO:
strcpy(str_level, "INFO");
break;
case ERROR:
strcpy(str_level, "ERROR");
break;
default:
break;
}
char record[150];
snprintf(record, 150, "[%10.3f] [%-5s] %s", seconds, str_level, message);
Serial.println(record);
} }