Gaszähler an Openhab (per MQTT)

Ich möchte meinen Gaszähler, der über einen Magnetkontakt verfügt, der pro 0,01m³ einen Impuls ausgeben kann, gerne auslesen, speichern und darstellen.

Die Daten sollen per MQTT an openHAB und an eine influx-db geschickt werden.

Das passiert wieder mit einem ESP8266 den ich ja gerne für sows verwende. Auslesen kann ich diesen Magnetkontakt per Reed-Sensor der an den ESP angeschlossen wird. Ich musste ein bisschen fummeln um die richtige Position zu finden (sieht man hier vielleicht auch ein bisschen :)). Das ist bei meinem Zähler (siehe Foto) ganz rechts mit dem Reed-Kontakt nach unten gerichtet. Auf dem Bild kommt der Magnet gerade am Sensor vorbei (bei mir ca. zwischen 8 und 9).

Testaufbau ohne Gehäuse

Material

ESP8266-12F * Affiliatelink

Jumper-Kabel * Affiliatelink

KY-025 Reed-Schalter * Affiliatelink

Pinning

Code

#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <InfluxDbClient.h>

#include <NTPClient.h>
#include <WiFiUdp.h> 

#include <ESP8266WebServer.h>

#include <time.h>

// #############################################
// WLAN-Zugang
// #############################################
#define wifi_ssid "WLAN-SSID"
#define wifi_password "WLAN-PW

// #############################################
// MQTT-Server (Openhab)
// #############################################
#define mqtt_server "192.168.2.17"
#define mqtt_user "openhabian"
#define mqtt_password ""

// #############################################
// InfluxDB-Server und DB-Name
// #############################################
#define INFLUXDB_URL "http://192.168.2.18:8086"
#define INFLUXDB_DB_NAME "gaszaehler"

// #############################################
// NTP-Client
// #############################################
#define MY_NTP_SERVER "192.168.2.1"           
#define MY_TZ "CET-1CEST,M3.5.0/02,M10.5.0/03"   

time_t now;
tm tm;
String TimeStamp;

ESP8266WebServer server(80);
String htmltext;

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

int Analog_Eingang = A0; // Analogwert
int Digital_Eingang = 5; // Binärer Wert

int analog_temp = 0;
int digital_temp = 0;
float diff = 0.5;
int daily_count_gas = 0;

void setup ()
{
  pinMode (Analog_Eingang, INPUT);
  pinMode (Digital_Eingang, INPUT);
       
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  
  configTime(MY_TZ, MY_NTP_SERVER);
  
  server.on("/", handle_OnData);
  server.on("/f.css", handleCss);
  server.onNotFound(handle_NotFound);
  server.begin();
  
  Serial.println("HTTP server started");
}
  
void loop ()
{
  if (!client.connected()) {
    reconnect();
  }

  server.handleClient();

  float Analog;
  int Digital;
    
  //Aktuelle Werte werden ausgelesen, auf den Spannungswert konvertiert...
  Analog = analogRead (Analog_Eingang) * (5.0 / 1023.0); 
  Digital = digitalRead (Digital_Eingang);
    
  // Single InfluxDB instance
  InfluxDBClient influx_client(INFLUXDB_URL, INFLUXDB_DB_NAME);
  // Define data point with measurement name 'device_status`
  Point pointDevice("gaszaehler");
  // Add data
  pointDevice.addField("Analog", Analog);
  pointDevice.addField("Digital", Digital);

  // Write data
  if (checkBound(analog_temp, Analog, diff)) {
    analog_temp = Analog;
    influx_client.writePoint(pointDevice);
    client.publish("gas/analog", String(Analog).c_str(), true);
    client.publish("gas/digital", String(Digital).c_str(), true);
    client.publish("gas/tagesstand", String(Digital).c_str(), true);

    //... und an dieser Stelle ausgegeben
    Serial.print ("Analoger Spannungswert:"); Serial.print (Analog, 4);  Serial.print ("V, ");
    Serial.print ("Grenzwert:");
    
    if(Digital==1) {
        Serial.println (" erreicht");
        daily_count_gas++;
    } else {
        Serial.println (" noch nicht erreicht");
    }
  }

  time(&now);                       // read the current time
  localtime_r(&now, &tm);           // update the structure tm with the current time
/*  
  Serial.print("year:");
  Serial.print(tm.tm_year + 1900);  // years since 1900
  Serial.print("\tmonth:");
  Serial.print(tm.tm_mon + 1);      // January = 0 (!)
  Serial.print("\tday:");
  Serial.print(tm.tm_mday);         // day of month
  Serial.print("\thour:");
  Serial.print(tm.tm_hour);         // hours since midnight  0-23
  Serial.print("\tmin:");
  Serial.print(tm.tm_min);          // minutes after the hour  0-59
  Serial.print("\tsec:");
  Serial.print(tm.tm_sec);          // seconds after the minute  0-61*
  Serial.print("\twday");
  Serial.print(tm.tm_wday);         // days since Sunday 0-6
  if (tm.tm_isdst == 1)             // Daylight Saving Time flag
    Serial.print("\tDST");
  else
    Serial.print("\tstandard");
  Serial.println();
*/

  // Um Null Uhr den Zähler wieder zurück setzen!
  if (tm.tm_hour == 0 && tm.tm_min == 0 && tm.tm_sec == 0) {
    daily_count_gas = 0;
  }
  TimeStamp = String(tm.tm_mday) + "." + String(tm.tm_mon + 1) + "." + String(tm.tm_year + 1900) + " " + String(tm.tm_hour) + ":" + String(tm.tm_min) + ":" + String(tm.tm_sec);
  
  htmltext = "";
  htmltext += "<h2>Uhrzeit</h2>"; 
  htmltext += "<p><b>" + String(TimeStamp) + "</b></p>";
  htmltext += "<h2>Werte</h2>"; 
  htmltext += "<p>Analog: <b>" + String(Analog) + " V</b></p>";
  htmltext += "<p>Digital: <b>" + String(Digital) + "</b></p>";
  htmltext += "<h2>Zähler</h2>"; 
  htmltext += "<p>heute: <b>" + String(daily_count_gas * 0.01) + "m³</b></p>";
  
  delay (200);
}

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);

  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.print(WiFi.localIP());
}

bool checkBound(float newValue, float prevValue, float maxDiff) {
  return !isnan(newValue) &&
  (newValue < prevValue - maxDiff || newValue > prevValue + maxDiff);
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "ESP01 alive");
      // ... and resubscribe
      client.subscribe("inTopic");
    } else {
        Serial.print("failed, rc=");
        Serial.print(client.state());
        Serial.println(" try again in 5 seconds");
        // Wait 5 seconds before retrying
        delay(5000);
      }
   }
}

void handle_OnData() {
  server.send(200, "text/html", SendHTML(htmltext)); 
}
void handle_OnConnect() {
  server.send(200, "text/html", SendHTML("Boot")); 
}

void handle_NotFound(){
  server.send(404, "text/plain", "Not found");
}

String SendHTML(String addtext){
  String ptr = "";
  ptr += "<!DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n";
  ptr += "<html lang='de'>\n";
  ptr += "<head>\n";
  ptr += "<title>Gaszaehler Webserver</title>\n";
  ptr += "<link rel='stylesheet' type='text/css' href='/f.css'>\n";
  ptr += "<meta content='text/html; charset=UTF-8' http-equiv='content-type'>\n";
  ptr += "</head>\n";
  ptr += "<body>\n";
  ptr += "<h1>Gaszaehler Webserver</h1>\n";
  ptr += addtext;
  ptr += "</body>\n";
  ptr += "</html>";
  
  return ptr;
}

void handleCss()
{
  String message = "";
  message += "*{font-family:sans-serif}\n";
  message += "body{margin:10px;width:300px}\n";
  message += "h1, h2{color:white;background:#8FCE00;text-align:center}\n";
  message += "h1{font-size:1.2em;margin:1px;padding:5px}\n";
  message += "h2{font-size:1.0em}\n";
  message += "h3{font-size:0.9em}\n";
  message += "a{text-decoration:none;color:dimgray;text-align:center}\n";
  message += ".small{font-size:0.6em}\n";
  message += ".value{font-size:1.8em;text-align:center;line-height:50%}\n";
  message += "footer p, .infodaten p{font-size:0.7em;color:dimgray;background:silver;";
  message += "text-align:center;margin-bottom:5px}\n";
  message += "nav{background-color:silver;margin:1px;padding:5px;font-size:0.8em}\n";
  message += "nav a{color:white;padding:10px;text-decoration:none}\n";
  message += "nav a:hover{text-decoration:underline}\n";
  message += "nav p{margin:0px;padding:0px}\n";
  message += ".btn{background-color:#C0C0C0;color:dimgray;text-decoration:none;";
  message += "border-style:solid;border-color:dimgray}\n";
  message += ".on, .off{margin-top:0;margin-bottom:0.2em;margin-left:3em;";
  message += "font-size:1.4em;background-color:#C0C0C0;";
  message += "border-style:solid;width:5em;height:1.5em;text-decoration:none;text-align:center}\n";
  message += ".on{border-color:green}\n)";
  server.send(200, "text/css", message);
}

Webserver

Zusätzlich zum senden per MQTT und in die Influx-DB gibts auch einen Webserver der die m³ pro Tag anzeigt und den aktuellen Wert. Das ist für die Einrichtung ganz nett, aber eigentlich nicht notwendig, da der Sensor ja eine Anzeige hat.

Wie immer ist der Code sehr grottig und viel zu viel. Wenn man nur die einfache Funktion braucht um einen MQTT-Status zu versenden ist viel weniger notwendig. Aber das hier ist ja auch ein Blog als mein Notizzettel 🙂

Ein Kommentar

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.