MQTT Thermometer mit UI
Projektbeschreibung
Dieser Code ist für ein ESP8266-basiertes IoT-Gerät, das Temperatur- und Feuchtigkeitswerte mit einem HTU21D-Sensor misst und die Daten über MQTT an einen Server sendet. Zusätzlich wird eine Weboberfläche bereitgestellt, die zur Konfiguration des Geräts dient, einschließlich Sensorname und Offset-Korrekturen für Temperatur und Feuchtigkeit. Das Gerät verbindet sich mit einem WLAN-Netzwerk, misst die Umgebungsbedingungen und sendet die Daten regelmäßig an den konfigurierten MQTT-Server.
Funktionsweise
- Temperatur- und Feuchtigkeitsmessung: Der HTU21D-Sensor misst die Temperatur und Luftfeuchtigkeit. Die Werte werden mit Offset-Werten, die konfigurierbar sind, korrigiert.
- MQTT-Kommunikation: Das Gerät stellt eine Verbindung zu einem MQTT-Broker her und veröffentlicht die gemessenen Temperatur- und Feuchtigkeitsdaten.
- Weboberfläche: Eine Weboberfläche wird bereitgestellt, um den Gerätenamen (Sensorname) und Offset-Werte für Temperatur und Feuchtigkeit zu konfigurieren. Außerdem zeigt sie die Live-Daten der aktuellen Messungen an.
Anschlüsse
- ESP8266 Pin D1 (SCL): Mit dem SCL-Pin des HTU21D verbunden.
- ESP8266 Pin D2 (SDA): Mit dem SDA-Pin des HTU21D verbunden.
- HTU21D GND: Mit GND des ESP8266 verbunden.
- HTU21D VCC: Mit 3.3V des ESP8266 verbunden.
Voraussetzungen
- ESP8266 Development Board (z. B. NodeMCU oder Wemos D1 Mini)
- HTU21D Sensor
- MQTT-Server (z. B. Mosquitto auf einem Raspberry Pi oder einem öffentlichen MQTT-Broker)
- WLAN-Netzwerk zur Verbindung des ESP8266 mit dem Internet
Einrichtung
- Bibliotheken installieren: Stellen Sie sicher, dass die folgenden Bibliotheken installiert sind:
ESP8266WiFi.h
: Für die WLAN-Konnektivität des ESP8266.PubSubClient.h
: Für die Kommunikation mit dem MQTT-Broker.Adafruit_HTU21DF.h
: Für die Temperatur- und Feuchtigkeitssensoren.EEPROM.h
: Zum Speichern und Abrufen von Geräteeinstellungen.ESP8266WebServer.h
: Zum Bereitstellen der Weboberfläche.
- WLAN- und MQTT-Einstellungen anpassen: Ändern Sie die WLAN-SSID, das Passwort, den MQTT-Server und die Anmeldedaten direkt im Code.
- Upload und Nutzung:
- Laden Sie den Code auf den ESP8266 hoch.
- Nach dem Start verbindet sich das Gerät mit Ihrem WLAN und ist über dessen IP-Adresse erreichbar (im seriellen Monitor sichtbar).
- Rufen Sie die IP-Adresse im Browser auf, um die Weboberfläche für Live-Daten und Gerätekonfiguration zu sehen.
Kurzbeschreibung zur Veröffentlichung
„ESP8266 IoT-Temperatur- und Feuchtigkeitssensor mit MQTT und Weboberfläche“
Dieses Projekt verwendet einen ESP8266-Controller mit einem HTU21D-Sensor zur Messung von Temperatur und Luftfeuchtigkeit. Die gemessenen Werte werden über einen MQTT-Broker an einen Server gesendet. Eine intuitive Weboberfläche ermöglicht es, den Sensor zu konfigurieren und die aktuellen Messwerte einzusehen.
#include
#include
#include
#include
#include
#include
// Struktur zur Verwaltung der EEPROM-Daten
struct EEPROMData {
float temperature_offset;
float humidity_offset;
char sensor_name[32];
};
EEPROMData eepromData;
Adafruit_HTU21DF htu = Adafruit_HTU21DF();
WiFiClient espClient;
PubSubClient client(espClient);
ESP8266WebServer server(80);
// WiFi und MQTT Zugangsdaten
const char* ssid = "WLAN SSID"; // hier Dein WLAN Name eintragen
const char* password = "WLAN Passwort"; // hier Dein WLAN Passwort eintragen
const char* mqtt_server = "192.168.x.xx"; // hier die IP des MQTT-Servers eintragen
const int mqtt_port = 1885; // hier den Port des MQTT-Servers eintragen
const char* mqtt_user = "MQTT-User"; // hier den Benutzer vom MQTT-Servers eintragen
const char* mqtt_password = "MQTT-Passwort"; // hier das Passwort vom MQTT-Servers eintragen
// Standardwerte
const EEPROMData defaultData = {
0.0, // Temperatur Offset - dieser Wert kann über das Web-UI angepasst
0.0, // Luftfeuchtigkeit Offset - dieser Wert kann über das Web-UI angepasst werden
"Temperatursensor" // Sensorname - dieser kann über das Web-UI angepasst werden
};
String sanitizedSensorName;
String sanitizeSensorName(const char* name) {
String sanitized = "";
for (int i = 0; i < strlen(name); i++) {
char c = name[i];
if (isalnum(c) || c == '_') {
sanitized += c;
} else if (c == ' ') {
sanitized += '_';
} else {
sanitized += '_';
}
}
return sanitized;
}
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Verbinde mit ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi verbunden");
Serial.print("IP-Adresse: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
while (!client.connected()) {
Serial.print("Versuche MQTT-Verbindung herzustellen...");
if (client.connect("HTU21DClient", mqtt_user, mqtt_password)) {
Serial.println("verbunden");
publishIPAddress();
} else {
Serial.print("fehlgeschlagen, rc=");
Serial.print(client.state());
Serial.println(" Versuche es in 5 Sekunden erneut");
delay(5000);
}
}
}
void handleLiveValues() {
float temperature = readTemperature() + eepromData.temperature_offset;
float humidity = readHumidity() + eepromData.humidity_offset;
String json = "{";
json += "\"temperature\":" + String(temperature, 2) + ",";
json += "\"humidity\":" + String(humidity, 2);
json += "}";
server.send(200, "application/json", json);
}
void handleSetOffsets() {
bool changed = false;
if (server.hasArg("temp_offset")) {
eepromData.temperature_offset = server.arg("temp_offset").toFloat();
Serial.print("Temperatur-Offset gesetzt: ");
Serial.println(eepromData.temperature_offset);
changed = true;
}
if (server.hasArg("hum_offset")) {
eepromData.humidity_offset = server.arg("hum_offset").toFloat();
Serial.print("Feuchtigkeits-Offset gesetzt: ");
Serial.println(eepromData.humidity_offset);
changed = true;
}
if (changed) {
EEPROM.put(0, eepromData);
EEPROM.commit();
}
server.sendHeader("Location", "/");
server.send(303);
}
float readTemperature() {
float temp = htu.readTemperature();
if (isnan(temp)) {
Serial.println("Fehler beim Lesen der Temperatur!");
return 0.0;
}
return temp;
}
float readHumidity() {
float hum = htu.readHumidity();
if (isnan(hum)) {
Serial.println("Fehler beim Lesen der Feuchtigkeit!");
return 0.0;
}
return hum;
}
void publishIPAddress() {
if (client.connected()) {
String ip = WiFi.localIP().toString();
String ipTopic = sanitizedSensorName + "/Info/ip";
client.publish(ipTopic.c_str(), ip.c_str());
Serial.println("IP-Adresse veröffentlicht: " + ip);
}
}
void setup() {
Serial.begin(9600);
Wire.begin(D2, D1);
EEPROM.begin(sizeof(EEPROMData));
EEPROM.get(0, eepromData);
bool eepromValid = validateEEPROMData(eepromData);
if (!eepromValid) {
Serial.println("Ungültige EEPROM-Daten gefunden. Setze auf Standardwerte.");
eepromData = defaultData;
EEPROM.put(0, eepromData);
EEPROM.commit();
}
eepromData.sensor_name[sizeof(eepromData.sensor_name) - 1] = '\0';
sanitizedSensorName = sanitizeSensorName(eepromData.sensor_name);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
server.on("/", handleRoot);
server.on("/set_name", handleSetName);
server.on("/set_offsets", handleSetOffsets);
server.on("/live_values", handleLiveValues);
server.begin();
if (!htu.begin()) {
Serial.println("HTU21D Sensor konnte nicht gefunden werden!");
while (1);
}
reconnect();
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
server.handleClient();
static unsigned long lastSensorRead = 0;
unsigned long currentMillis = millis();
if (currentMillis - lastSensorRead >= 2000) {
lastSensorRead = currentMillis;
float temperature = readTemperature() + eepromData.temperature_offset;
float humidity = readHumidity() + eepromData.humidity_offset;
publishSensorData(temperature, humidity);
}
}
void publishSensorData(float temperature, float humidity) {
if (client.connected()) {
String tempStr = String(temperature, 2);
String humStr = String(humidity, 2);
String tempTopic = sanitizedSensorName + "/temperature";
String humTopic = sanitizedSensorName + "/humidity";
client.publish(tempTopic.c_str(), tempStr.c_str());
client.publish(humTopic.c_str(), humStr.c_str());
Serial.println("Sensordaten veröffentlicht: " + tempStr + " °C, " + humStr + " %");
}
}
bool validateEEPROMData(const EEPROMData& data) {
if (data.temperature_offset < -50.0 || data.temperature_offset > 100.0) return false;
if (data.humidity_offset < -100.0 || data.humidity_offset > 100.0) return false;
for (int i = 0; i < sizeof(data.sensor_name); i++) {
if (isPrintable(data.sensor_name[i])) {
return true;
}
}
return false;
}
void handleRoot() {
String html = "";
html += "" + String(eepromData.sensor_name) + "
";
html += "Temperatur: ...
";
html += "Feuchtigkeit: ...
";
html += "";
html += "";
html += "";
html += "";
server.send(200, "text/html", html);
}
void handleSetName() {
if (server.hasArg("sensor_name")) {
String newSensorName = server.arg("sensor_name");
newSensorName.toCharArray(eepromData.sensor_name, sizeof(eepromData.sensor_name));
eepromData.sensor_name[sizeof(eepromData.sensor_name) - 1] = '\0';
EEPROM.put(0, eepromData);
EEPROM.commit();
sanitizedSensorName = sanitizeSensorName(eepromData.sensor_name);
Serial.print("Sensorname gesetzt: ");
Serial.println(eepromData.sensor_name);
Serial.print("Sanitierter Sensorname: ");
Serial.println(sanitizedSensorName);
if (client.connected()) {
publishIPAddress();
}
}
server.sendHeader("Location", "/");
server.send(303);
}