Menzelenerheide 26

46519 Alpen

Michael Arthen

Ihr Ansprechpartner

0176/34048100

immer für Sie erreichbar

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

  1. Temperatur- und Feuchtigkeitsmessung: Der HTU21D-Sensor misst die Temperatur und Luftfeuchtigkeit. Die Werte werden mit Offset-Werten, die konfigurierbar sind, korrigiert.
  2. MQTT-Kommunikation: Das Gerät stellt eine Verbindung zu einem MQTT-Broker her und veröffentlicht die gemessenen Temperatur- und Feuchtigkeitsdaten.
  3. 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

  1. 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.
  2. WLAN- und MQTT-Einstellungen anpassen: Ändern Sie die WLAN-SSID, das Passwort, den MQTT-Server und die Anmeldedaten direkt im Code.
  3. 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 <Wire.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <EEPROM.h>
#include <Adafruit_HTU21DF.h>
#include <ESP8266WebServer.h>

// 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 = "<!DOCTYPE html><html><head><meta charset='UTF-8'><style>"
                "body { text-align: center; font-family: Arial, sans-serif; } "
                "form { border-top: 1px solid #ccc; margin-top: 20px; padding-top: 20px; }"
                "</style></head><body>";
  html += "<h1>" + String(eepromData.sensor_name) + "</h1>";
  html += "<p>Temperatur: <span id='temperature'>...</span></p>";
  html += "<p>Feuchtigkeit: <span id='humidity'>...</span></p>";
  html += "<form action='/set_name' method='get'>";
  html += "<p>Sensorname: </p><input type='text' name='sensor_name' value='" + String(eepromData.sensor_name) + "'>";
  html += "<br><br><input type='submit' value='Speichern'>";
  html += "</form>";
  html += "<form action='/set_offsets' method='get'>";
  html += "<p>Temperatur-Offset: " + String(eepromData.temperature_offset) + " &deg;C</p><input type='text' name='temp_offset' value='" + String(eepromData.temperature_offset) + "'>";
  html += "<p>Feuchtigkeits-Offset: " + String(eepromData.humidity_offset) + " %</p><input type='text' name='hum_offset' value='" + String(eepromData.humidity_offset) + "'>";
  html += "<br><br><input type='submit' value='Speichern'>";
  html += "</form>";
  html += "";
  html += "<script>var rocket_beacon_data = {"ajax_url":"https:\/\/ma-multiservice.de\/wp-admin\/admin-ajax.php","nonce":"80bc8a2764","url":"https:\/\/ma-multiservice.de\/mqtt-thermometer","is_mobile":false,"width_threshold":1600,"height_threshold":700,"delay":500,"debug":null,"status":{"atf":true,"lrc":true},"elements":"img, video, picture, p, main, div, li, svg, section, header, span","lrc_threshold":1800}</script><script data-name="wpr-wpr-beacon" src='https://ma-multiservice.de/wp-content/plugins/wp-rocket/assets/js/wpr-beacon.min.js' async></script><script src="https://ma-multiservice.de/wp-content/cache/min/1/e695075621d3f91415cb5cc141d8c1c7.js" data-minify="1"></script></body></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);
}

				
			
Nach oben scrollen