Update: 2023-02-12

Esp8266 Nodemcu Gaszähler Thingspeak

Auslesen des Gaszählers Elster BK-G4M mittels Reedrelais.

Die meisten mechanischen Gaszähler besitzen bereits ab Werk einen Impulsmagneten in der letzten Stelle des Rollenzählwerkes und können einfach mit einem Impulsnehmer ausgestattet werden. Ob der Gaszähler dafür geeignet ist, erkennt man an einem Aufdruck wie z.B. "1 Imp ? 0,01 m³" auf dem Typenschild.

Funktionen

Zur Anzeige vom Zähler Impuls wird die Onboard Led des Nodemcu genutzt. Die OnBoardLed des Esp 12E wird als Heartbeat-LED verwendet. Dein händisch eingegebener Zählerstand wird in einer Datei im Flash des Esp8266 gespeichert und bei jedem Neustart aus dieser eingelesen. Der Zählerstand wird, vorausgesetzt der Wert hat sich geändert, aller 4 Stunden erneut abgespeichert.

Ansicht Gaszähler im Webrowser.

Esp8266 Gaszähler.

Webinterface

Hier kannst du den aktuellen Zählerstand eingeben. Die Leds der optischen Anzeige schalten. Der Zählerstand im Browser wird aller 5 Sekunden aktualisiert. Die vergangene Zeit seit dem letzten Sendefehler wird bei aufgeklappter Eingabemaske angezeigt. Beim Klick in den Bereich der Zähleranzeige erscheint die Eingabemaske. Hier lassen sich auch beide Leds schalten.

Nodemcu Gaszähler.

Thingspeak Datenlogger

Aller 5 Minuten wird der aktuelle Stand der Gasuhr an deinen Thingspeak Account gesendet. Die Antwort von Thingspeak, ob die Übertragung erfolgreich war, wird nicht blockierend ausgewertet. Im Fehlerfall wird der Zählerstand erneut zu Thingspeak gesendet.

Thingspeak Account einrichten

Anzeige des letzten Sendefehler zu Thingspeak.

Nodemcu Gasuhr.

Da sich bei mir, als Holzheizer, der Gaszähler nur an extrem kalten Wintertagen dreht, nochmals vielen Dank an Andreas für die ausführlichen praktischen Tests und Rückmeldungen.

Esp8266 Favicon GaszählerDownload Projekt

Der Sketch zum Gasuhr auslesen übersichtlich aufgeteilt in Tabs.

Gaszaehler.ino

// ****************************************************************
// Sketch Gaszähler Modular(Tab)
// created: Jens Fleischer, 2018-03-30
// last mod: Jens Fleischer, 2023-02-12
// For more information visit: https://fipsok.de
// ****************************************************************
// Hardware: Esp8266
// D2 = GPIO4  Anschluss Reedrelais vom GPIO4 auf GND
// 10k Pullup-Widerstand von VCC auf GPIO4
// Versorgung über USB
// Software: Esp8266 Arduino Core 2.6.0 - 3.1.1
// Getestet auf: Nodemcu
/******************************************************************
  Copyright (c) 2018 Jens Fleischer. All rights reserved.

  This file is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  This file is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
*******************************************************************/
// Der WebServer Tab ist der Haupt Tab mit "setup" und "loop".
// #include <LittleFS.h> #include <ESP8266WebServer.h> müssen im Haupttab aufgerufen werden
// Die Funktionalität des ESP8266 Webservers ist erforderlich.
// Inklusive Arduino OTA-Updates (Erfordert freien Flash-Speicher )
/**************************************************************************************/

#include <ESP8266WebServer.h>                         // http://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/readme.html#server
#include <ArduinoOTA.h>                               // http://arduino-esp8266.readthedocs.io/en/latest/ota_updates/readme.html
#include <LittleFS.h>                                 // http://arduino-esp8266.readthedocs.io/en/latest/filesystem.html

const byte inputPIN = D2;                             // Reedrelais
const byte HeartbeatLed = D4;                         // OnBoardLed Esp 12E
const byte CounterLed = D0;                           // OnBoardLed NodeMcu 1.0
unsigned long value, oldvalue;
bool ledz = HIGH, ledh = LOW;                         // Merker für ZählerLed AN/Aus , Merker für HeartbeatLed AN/Aus
unsigned long lastError;                              // Zeitpunkt des letzten Fehlers

ESP8266WebServer server(80);

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.printf("\n\nSketchname: %s\nBuild: %s\t\tIDE: %d.%d.%d\n%s\n\n",
                (__FILE__), (__TIMESTAMP__), ARDUINO / 10000, ARDUINO % 10000 / 100, ARDUINO % 100 / 10 ? ARDUINO % 100 : ARDUINO % 10, ESP.getFullVersion().c_str());
  pinMode(HeartbeatLed, OUTPUT);
  pinMode(CounterLed, OUTPUT);
  digitalWrite(HeartbeatLed, HIGH);
  connectWifi();                                      // ruft die Funktion zum Verbinden mit dem Wlan auf
  webpage();                                          // ruft die Funktion zum bereitstellen einer Webseite auf
  Serial.println(LittleFS.begin() ? "LittleFS gestartet!" : "Sketch wurde mit \"FS:none\" kompilliert!\n");
  server.begin();
  Serial.println("HTTP Server gestartet!\n");
  ArduinoOTA.onStart([]() {                           // Zählerstand speichern bevor OTA Update
    save();
  });
  ArduinoOTA.begin();

  File f = LittleFS.open("/value.txt", "r");          // Zählerstand beim Neustart aus Datei lesen
  String str = f.readStringUntil('\n');
  value = str.toInt();
  oldvalue = value;
  f.close();
}

void loop() {
  static unsigned long letzterAufruf = 0;
  ArduinoOTA.handle();
  server.handleClient();
  zaehlerauslesen();  // Funktionsaufruf
  char buf[12];
  snprintf(buf, sizeof(buf), "%li.%02li", value / 100, value % 100);
  if (!thingspeak(buf)) {
    lastError = millis() / 1000;
  }
  ledh ? digitalWrite(HeartbeatLed, millis() % 500 >= 250) : digitalWrite(HeartbeatLed, HIGH);    // LED zeigt an das der Sketch läuft
  unsigned long aktuelleMillis = millis();
  if (aktuelleMillis - letzterAufruf >= 60000UL * 240 && value != oldvalue) {       // Zählerstand speichern, aller 4 Stunden, wenn der Wert sich geändert hat.
    save();
    oldvalue = value;
    letzterAufruf = aktuelleMillis;
  }
}

void zaehlerauslesen() {
  bool aktueller = 1;
  static bool vorheriger = 1;
  static unsigned long letzteMillis = 0;
  unsigned long aktuelleMillis = millis();
  if (aktuelleMillis - letzteMillis >= 1000) {        // Das Reedrelais wird einmal pro Sekunde abgefragt
    aktueller = digitalRead(inputPIN);
    if (!aktueller && aktueller != vorheriger) {
      value++;
    }
    vorheriger = aktueller;
    letzteMillis = aktuelleMillis;
  }
  !ledz ? digitalWrite(CounterLed, HIGH) : !vorheriger ? digitalWrite(CounterLed, millis() % 500 >= 250) : digitalWrite(CounterLed, HIGH);    // LED blinkt wenn Reedrelais geschlossen
}

void save() {
  File f = LittleFS.open("/value.txt", "w");
  f.printf("%li\n", value);
  f.close();
}

In diesem Tab, deine Zugangsdaten vom Netzwerk eintragen.

Connect.ino

// ****************************************************************
// Sketch Esp8266 Connect STA Modular(Tab) mit optischer Anzeige
// created: Jens Fleischer, 2018-04-08
// last mod: Jens Fleischer, 2020-12-28
// For more information visit: https://fipsok.de
// ****************************************************************
// Hardware: Esp8266
// Software: Esp8266 Arduino Core 2.4.2 - 3.1.1
// Getestet auf: Nodemcu, Wemos D1 Mini Pro, Sonoff Dual
/******************************************************************
  Copyright (c) 2018 Jens Fleischer. All rights reserved.

  This file is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  This file is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
*******************************************************************/
// Diese Version von Connect STA sollte als Tab eingebunden werden.
// #include <ESP8266WebServer.h> oder #include <ESP8266WiFi.h> muss im Haupttab aufgerufen werden
// Die Funktion "connectWifi();" muss im Setup eingebunden werden.
/**************************************************************************************/

//#define CONFIG                                // Einkommentieren wenn der ESP dem Router die IP mitteilen soll.
#define NO_SLEEP                                // Auskommentieren wenn der Nodemcu den deep sleep Modus nutzt.

const char* ssid = "Netzwerkname";              // << kann bis zu 32 Zeichen haben
const char* password = "PasswortvomNetzwerk";   // << mindestens 8 Zeichen jedoch nicht länger als 64 Zeichen

#ifdef CONFIG
IPAddress staticIP(192, 168, 178, 99);          // Statische IP des NodeMCU ESP8266
IPAddress gateway(192, 168, 178, 1);            // IP-Adresse des Router
IPAddress subnet(255, 255, 255, 0);             // Subnetzmaske des Netzwerkes
IPAddress dns(192, 168, 178, 1);                // DNS Server
#endif

void connectWifi() {                            // Funktionsaufruf "connectWifi();" muss im Setup eingebunden werden.
  byte i = 0;
  //WiFi.disconnect();                          // Nur erforderlich wenn Esp den AP Modus nicht verlassen will.
  WiFi.persistent(false);                       // Auskommentieren wenn Netzwerkname und Passwort in den Flash geschrieben werden sollen.
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
#ifdef CONFIG
  WiFi.config(staticIP, gateway, subnet, dns);
#endif
  while (WiFi.status() != WL_CONNECTED) {
#ifdef NO_SLEEP
    pinMode(LED_BUILTIN, OUTPUT);               // OnBoardLed Nodemcu, Wemos D1 Mini Pro
    digitalWrite(LED_BUILTIN, 0);
#endif
    delay(500);
    digitalWrite(LED_BUILTIN, 1);
    delay(500);
    Serial.printf(" %d sek\n", ++i);
    if (i > 9) {
      Serial.print("\nVerbindung zum AP fehlgeschlagen !\n\n");
      ESP.restart();
    }
  }
  Serial.println("\nVerbunden mit: " + WiFi.SSID());
  Serial.println("Esp8266 IP: " + WiFi.localIP().toString());
}

HTML.ino

// ****************************************************************
// Sketch Gaszähler Webinterface Modular(Tab)
// created: Jens Fleischer, 2018-04-08
// last mod: Jens Fleischer, 2023-02-12
// For more information visit: https://fipsok.de
// ****************************************************************
// Hardware: Esp8266
// Software: Esp8266 Arduino Core 2.6.0 - 3.1.1
// Getestet auf: Nodemcu
/******************************************************************
  Copyright (c) 2018 Jens Fleischer. All rights reserved.

  This file is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  This file is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
*******************************************************************/
// #include <ESP8266WebServer.h> muss im Haupttab aufgerufen werden.
// Die Funktionalität des ESP8266 Webservers ist erforderlich.
// Die Funktion "webpage();" muss im Setup eingebunden werden.
/**************************************************************************************/

void webpage() {
  server.on("/", handleRoot);
  server.on("/favicon.ico", handleIcon);
  server.on("/status", handleStatus);
  server.on("/ledh", []() {
    ledh = !ledh;
    handleStatus();
  });
  server.on("/ledz", []() {
    ledz = !ledz;
    handleStatus();
  });
}

void handleStatus() {
  if (server.arg(0).length() > 0 && server.arg(0).length() <= 7) {
    value = server.arg(0).toInt();
    save();                                      // Benutzer Eingabe in der Datei speichern
    Serial.printf("Zählerstand vom Client: %ld\n", value);
  }
  char buf[42];
  snprintf(buf, sizeof(buf), "[\"%05ld,%02ld9 m³\",\"%d\",\"%d\",\"%s\"]", value / 100, value % 100, ledh, ledz, errorTime().c_str());
  server.send(200, "application/json", buf);     // Zählerstand und Led Status an Html Seite senden
}

String errorTime() {                             // ermittelt die vergangene Zeit seit dem letztem Verbindungsfehler zu Thingspeak
  if (lastError > 0) {
    String Time = "";
    uint8_t mm = (millis() / 1000 - lastError) / 60 % 60;
    uint16_t hh = ((millis() / 1000 - lastError) / 60) / 60;
    if (hh > 240) lastError = 0;                 // nach 10 Tagen ohne Fehler, wird die Fehleranzeige zurückgesetzt
    if (hh < 10)Time += "0";
    Time += (String)hh + ":";
    if (mm < 10)Time += "0";
    Time += (String)mm;
    return Time;
  }
  return "0";
}

void handleRoot() {   // Html Webseite, der Zählerstand wird aller 5 Sekunden mittels fetch.api aktuallisiert
  String temp = "<!DOCTYPE HTML><html lang='de'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1'><title>Gaszähler</title><script>";
  temp += "addEventListener('load',()=>{let h=document.querySelector('#ledh'),z=document.querySelector('#ledz');let i=document.querySelector('input'),n=document.querySelector('#note');";
  temp += "document.querySelector('#grey').addEventListener('click',()=>t());z.addEventListener('click',()=>s('ledz'));h.addEventListener('click',()=>s('ledh'));i.addEventListener('blur',";
  temp += "()=>{!i.checkValidity()?(n.innerHTML=i.validationMessage,n.classList.add('note')):s('status',i.value)});function t(){let x=document.getElementById('no');getComputedStyle(x).";
  temp += "display==='none'?x.style.display='flex':x.style.display='none';n.innerHTML='';n.classList.remove('note');i.value=''}async function s(p='status',v){if(Number.isInteger(parseInt";
  temp += "(v)))t();let r=await fetch(p,{method:'POST',body:v});let j=await r.json();document.querySelector('span').innerHTML=j[0];j[1]=='0'?(h.innerHTML='LED Off',h.classList.add('off')):";
  temp += "(h.innerHTML='LED On',h.classList.remove('off'));j[2]=='0'?(z.innerHTML='LED Off',z.classList.add('off')):(z.innerHTML='LED On',z.classList.remove('off'));if(j[3]!='0') document.";
  temp += "querySelector('#err').innerHTML='Sendefehler vor '+j[3]+' hh:mm'}s(),setInterval(s,5000)});</script><style>body{background-color:tan;font-size:1.1em}body,#grey,#no,#black{display";
  temp += ":flex;flex-flow:column;align-items:center}#grey,#no{background-color:#c5c3c3;width:280px;height:150px;border:.3em solid #aeaeab;border-radius:.5em;box-shadow:5px 10px 5px #4e4d4d}";
  temp += "#grey{cursor:pointer}#black{background-color:black;width:14em;border-radius:.2em}#red{border:.28em solid red;position:relative;width:3.8em;height:1.5em;left:1.5em}span{color:white";
  temp += ";position:relative;left:.1em;letter-spacing:.2em;font-size:1.6em;font-weight:bold;top:4.55em;pointer-events:none;z-index:1}#no{display:none}.note{background-color:#fecdee;padding:";
  temp += ".3em;border-radius:.5em;position:relative;top:-5.5em}input,#err{height:30px;margin-top:1em}.button{background-color:#75a27e;height:40px;width:120px;font-size:16px;box-shadow:5px ";
  temp += "5px 5px #4e4d4d}.off{background-color:#cf848c}</style></head><body><span></span><div id='grey'><h1>Zählerstand</h1><div id='black'><div id='red'></div></div></div><div id='no'>";
  temp += "<input placeholder=' Zählerstand eingeben' pattern='[0-9]{1,7}' title='Nur 1 bis 7 Ziffern sind erlaubt' required><div id='err'>Zähler - Led - Heartbeat </div><div><button id='";
  temp += "ledz' class='button'></button><button id='ledh' class='button'></button></div></div><div id='note'></div></body></html>";
  server.send(200, "text/html", temp);
}

void handleIcon() {
  const static uint8_t favicon[] PROGMEM = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
                                            0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x08, 0x03, 0x00, 0x00, 0x00, 0x44, 0xA4, 0x8A,
                                            0xC6, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61,
                                            0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4D, 0x00, 0x00, 0x7A, 0x26, 0x00, 0x00, 0x80,
                                            0x84, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0x80, 0xE8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xEA,
                                            0x60, 0x00, 0x00, 0x3A, 0x98, 0x00, 0x00, 0x17, 0x70, 0x9C, 0xBA, 0x51, 0x3C, 0x00, 0x00, 0x01,
                                            0x50, 0x50, 0x4C, 0x54, 0x45, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3,
                                            0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB5, 0xAF, 0xAF, 0xBC, 0x9F, 0x9F, 0xC0, 0x93, 0x93,
                                            0xC5, 0x87, 0x87, 0xC7, 0x83, 0x83, 0xC6, 0x86, 0x86, 0xC2, 0x8F, 0x8F, 0xBC, 0x9E, 0x9E, 0xB4,
                                            0xB2, 0xB2, 0xC9, 0x7F, 0x7F, 0xDE, 0x4F, 0x4F, 0xEE, 0x27, 0x27, 0xFD, 0x04, 0x04, 0xFF, 0x00,
                                            0x00, 0xFD, 0x05, 0x05, 0xF3, 0x1D, 0x1D, 0xE2, 0x45, 0x45, 0xCF, 0x72, 0x72, 0xBA, 0xA1, 0xA1,
                                            0xB6, 0xAB, 0xAB, 0xD5, 0x62, 0x62, 0xF5, 0x18, 0x18, 0xFE, 0x02, 0x02, 0xE9, 0x33, 0x33, 0xCC,
                                            0x77, 0x77, 0xB5, 0xAE, 0xAE, 0xC7, 0x84, 0x84, 0xF6, 0x15, 0x15, 0xCB, 0x7C, 0x7C, 0xD1, 0x6D,
                                            0x6D, 0xCD, 0x77, 0x77, 0xFE, 0x03, 0x03, 0xEF, 0x24, 0x24, 0xE1, 0x46, 0x46, 0xDB, 0x55, 0x55,
                                            0xD9, 0x5A, 0x5A, 0xDD, 0x4F, 0x4F, 0xE9, 0x34, 0x34, 0xF9, 0x0D, 0x0D, 0xC3, 0x8C, 0x8C, 0xFB,
                                            0x08, 0x08, 0xD8, 0x5B, 0x5B, 0xBA, 0xA4, 0xA4, 0xB4, 0xAF, 0xAF, 0xCA, 0x7E, 0x7E, 0xE5, 0x3C,
                                            0x3C, 0xFE, 0x04, 0x04, 0xB4, 0xB1, 0xB1, 0xF2, 0x1F, 0x1F, 0xF2, 0x20, 0x20, 0xBD, 0x9A, 0x9A,
                                            0xBF, 0x96, 0x96, 0xCC, 0x78, 0x78, 0xBA, 0xA3, 0xA3, 0xCC, 0x79, 0x79, 0xF5, 0x17, 0x17, 0xC9,
                                            0x80, 0x80, 0xE6, 0x3B, 0x3B, 0xFB, 0x09, 0x09, 0xF0, 0x22, 0x22, 0xC2, 0x90, 0x90, 0xCB, 0x79,
                                            0x79, 0xC5, 0x88, 0x88, 0xBE, 0x9A, 0x9A, 0xD0, 0x6F, 0x6F, 0xD3, 0x67, 0x67, 0xD0, 0x70, 0x70,
                                            0xC6, 0x85, 0x85, 0xC2, 0x8E, 0x8E, 0xDC, 0x53, 0x53, 0xB6, 0xAD, 0xAD, 0xFC, 0x07, 0x07, 0xDC,
                                            0x54, 0x54, 0xDD, 0x51, 0x51, 0xE8, 0x35, 0x35, 0xCA, 0x7D, 0x7D, 0xD0, 0x6E, 0x6E, 0xF6, 0x16,
                                            0x16, 0xF7, 0x14, 0x14, 0xBE, 0x98, 0x98, 0xFC, 0x08, 0x08, 0xDA, 0x56, 0x56, 0xDC, 0x52, 0x52,
                                            0xDA, 0x58, 0x58, 0xD5, 0x63, 0x63, 0xD1, 0x6B, 0x6B, 0xD7, 0x5D, 0x5D, 0xB3, 0xB2, 0xB2, 0xF8,
                                            0x12, 0x12, 0xF9, 0x0E, 0x0E, 0xF5, 0x16, 0x16, 0xDF, 0x4C, 0x4C, 0xBF, 0x98, 0x98, 0xB5, 0xAD,
                                            0xAD, 0xCE, 0x74, 0x74, 0xFA, 0x0D, 0x0D, 0xEE, 0x28, 0x28, 0xE1, 0x48, 0x48, 0xCF, 0x71, 0x71,
                                            0xBD, 0x9B, 0x9B, 0xBD, 0x9C, 0x9C, 0xC2, 0x91, 0x91, 0xC7, 0x85, 0x85, 0xC0, 0x96, 0x96, 0xB9,
                                            0xA4, 0xA4, 0xFF, 0xFF, 0xFF, 0xD7, 0xC3, 0x74, 0x75, 0x00, 0x00, 0x00, 0x05, 0x74, 0x52, 0x4E,
                                            0x53, 0xF0, 0xFC, 0xE2, 0xF2, 0xEE, 0x8D, 0xB1, 0xB7, 0x7D, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4B,
                                            0x47, 0x44, 0x6F, 0x55, 0x08, 0x61, 0x81, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00,
                                            0x00, 0x03, 0x3A, 0x00, 0x00, 0x03, 0x3A, 0x01, 0x59, 0x83, 0x48, 0xD2, 0x00, 0x00, 0x00, 0x07,
                                            0x74, 0x49, 0x4D, 0x45, 0x07, 0xE7, 0x02, 0x0B, 0x07, 0x0A, 0x0B, 0x02, 0x26, 0x72, 0x7C, 0x00,
                                            0x00, 0x01, 0x29, 0x49, 0x44, 0x41, 0x54, 0x38, 0xCB, 0x63, 0x60, 0x60, 0xC5, 0x0B, 0x18, 0x19,
                                            0x48, 0x54, 0xC0, 0xC6, 0xCE, 0xC1, 0xC9, 0xC5, 0xCD, 0xC3, 0xCB, 0x87, 0x4D, 0x01, 0x1F, 0xBF,
                                            0x80, 0xA0, 0x90, 0x30, 0x04, 0x88, 0x88, 0x8A, 0x89, 0x4B, 0xA0, 0x2A, 0x90, 0x94, 0x92, 0x16,
                                            0x46, 0x05, 0x32, 0xB2, 0x72, 0xF2, 0x08, 0x05, 0x0A, 0x8A, 0xC2, 0x58, 0x80, 0x12, 0x5C, 0x81,
                                            0xB2, 0x8C, 0x30, 0x5E, 0x05, 0x2A, 0x70, 0x79, 0x55, 0x35, 0x75, 0x0D, 0x4D, 0x2D, 0x6D, 0x1D,
                                            0x54, 0x05, 0xBA, 0x30, 0xB7, 0xE9, 0xE9, 0x1B, 0x40, 0x6C, 0x34, 0x34, 0x32, 0x36, 0x41, 0x28,
                                            0x30, 0x35, 0x83, 0xCA, 0x9B, 0x5B, 0x20, 0xF9, 0xD8, 0x52, 0x16, 0xAE, 0xC0, 0x0A, 0x2A, 0x2F,
                                            0x6D, 0x8D, 0x1A, 0x48, 0x36, 0xB6, 0x76, 0x10, 0x05, 0xF6, 0x50, 0x05, 0x76, 0x38, 0x42, 0x52,
                                            0xDE, 0x01, 0x22, 0xEF, 0x88, 0x2B, 0xA8, 0x9D, 0xA0, 0x06, 0x68, 0xE2, 0x52, 0xC0, 0x0F, 0x55,
                                            0xE0, 0x0C, 0x16, 0x71, 0x91, 0x43, 0x02, 0xAE, 0x60, 0x05, 0x6E, 0x50, 0x05, 0x2E, 0x60, 0x05,
                                            0xB2, 0xC8, 0x01, 0xE5, 0x0E, 0x56, 0xE0, 0x01, 0xE5, 0x79, 0xE2, 0x52, 0x00, 0xB3, 0x42, 0x0E,
                                            0x97, 0x02, 0x2F, 0x28, 0xCF, 0x1B, 0x97, 0x02, 0x1F, 0x5F, 0x08, 0xCF, 0x0C, 0xAC, 0xC0, 0xCD,
                                            0x0F, 0x08, 0xFC, 0x51, 0x14, 0xB0, 0x06, 0x40, 0xB9, 0x81, 0x70, 0xCF, 0xF9, 0xA0, 0x2A, 0x08,
                                            0x82, 0x72, 0x83, 0x25, 0x70, 0x28, 0x90, 0x0F, 0x81, 0x45, 0x56, 0x28, 0x76, 0x05, 0xAC, 0x4A,
                                            0x30, 0x47, 0x85, 0x85, 0xB3, 0x63, 0x55, 0xC0, 0x1A, 0x81, 0x48, 0x88, 0x66, 0x62, 0x91, 0x51,
                                            0xD1, 0x31, 0xE8, 0x0A, 0x62, 0x05, 0xB0, 0xA6, 0x38, 0x84, 0x02, 0x56, 0x56, 0xFE, 0x38, 0x02,
                                            0x0A, 0x58, 0x0D, 0xBC, 0xE3, 0xD1, 0xA5, 0x13, 0x12, 0x93, 0x50, 0x32, 0x4E, 0x72, 0x8A, 0xBA,
                                            0x19, 0x2C, 0xF1, 0xA6, 0xA6, 0xA5, 0x67, 0x64, 0x62, 0xCB, 0x7A, 0x3E, 0x59, 0xD9, 0x39, 0x5C,
                                            0xBA, 0xB9, 0x79, 0xA4, 0x64, 0x5E, 0x26, 0x66, 0xBC, 0x80, 0x05, 0x00, 0x60, 0x24, 0x46, 0xAE,
                                            0xA3, 0x6F, 0x16, 0xCA, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65,
                                            0x3A, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x33, 0x2D, 0x30, 0x32, 0x2D,
                                            0x31, 0x31, 0x54, 0x30, 0x37, 0x3A, 0x31, 0x30, 0x3A, 0x31, 0x31, 0x2B, 0x30, 0x30, 0x3A, 0x30,
                                            0x30, 0xBE, 0xBE, 0x45, 0x23, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74,
                                            0x65, 0x3A, 0x6D, 0x6F, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x33, 0x2D, 0x30, 0x32,
                                            0x2D, 0x31, 0x31, 0x54, 0x30, 0x37, 0x3A, 0x31, 0x30, 0x3A, 0x31, 0x31, 0x2B, 0x30, 0x30, 0x3A,
                                            0x30, 0x30, 0xCF, 0xE3, 0xFD, 0x9F, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F,
                                            0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x6E, 0x6B, 0x73, 0x63,
                                            0x61, 0x70, 0x65, 0x2E, 0x6F, 0x72, 0x67, 0x9B, 0xEE, 0x3C, 0x1A, 0x00, 0x00, 0x00, 0x57, 0x7A,
                                            0x54, 0x58, 0x74, 0x52, 0x61, 0x77, 0x20, 0x70, 0x72, 0x6F, 0x66, 0x69, 0x6C, 0x65, 0x20, 0x74,
                                            0x79, 0x70, 0x65, 0x20, 0x69, 0x70, 0x74, 0x63, 0x00, 0x00, 0x78, 0x9C, 0xE3, 0xF2, 0x0C, 0x08,
                                            0x71, 0x56, 0x28, 0x28, 0xCA, 0x4F, 0xCB, 0xCC, 0x49, 0xE5, 0x52, 0x00, 0x03, 0x23, 0x0B, 0x2E,
                                            0x63, 0x0B, 0x13, 0x23, 0x13, 0x4B, 0x93, 0x14, 0x03, 0x13, 0x20, 0x44, 0x80, 0x34, 0xC3, 0x64,
                                            0x03, 0x23, 0xB3, 0x54, 0x20, 0xCB, 0xD8, 0xD4, 0xC8, 0xC4, 0xCC, 0xC4, 0x1C, 0xC4, 0x07, 0xCB,
                                            0x80, 0x48, 0xA0, 0x4A, 0x2E, 0x00, 0xEA, 0x17, 0x11, 0x74, 0xF2, 0x42, 0x35, 0x95, 0x00, 0x00,
                                            0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
                                           };
  server.send(200, "image/x-icon", favicon, sizeof(favicon));     // Icon an den Browser senden
}

Thingspeak.ino

// ****************************************************************
// Sketch Thingspeak Modular(Tab) (Antwort nicht blockierend)
// created: Jens Fleischer, 2018-04-08
// last mod: Jens Fleischer, 2018-05-05
// For more information visit: https://fipsok.de
// ****************************************************************
// Software: Esp8266 Arduino Core 2.4.2 -3.1.1
// Getestet auf: Nodemcu
/******************************************************************
  Copyright (c) 2018 Jens Fleischer. All rights reserved.

  This file is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  This file is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
*******************************************************************/
// Diese Version von Thingspeak sollte als Tab eingebunden werden.
// #include <ESP8266WebServer.h> oder #include <ESP8266WiFi.h> muss im Haupttab aufgerufen werden
// Der Funktionsaufruf "thingspeak();" muss in loop eingebunden sein.
/**************************************************************************************/

WiFiClient client;

bool thingspeak(const char* value) {
  static bool error = false, response = true;
  const uint16_t httpPort = 80;
  const char* host = "184.106.153.149";
  const char* APIKEY = {"Geheimer ApiKey"};                       // trage deinen ApiKey von https://thingspeak.com
  const unsigned long interval = 1000UL * 300;                    // Interval in Sekunden einstellen
  static unsigned long letzteMillis = 0 - interval / 2;           // Sendebeginn einstellen ("- interval" = sofort, "0" = nach Ablauf von Interval)
  const uint16_t timeout = 2000;                                  // Zeitraum für Fehlerrückgabe in Millisekunden einstellen
  const String path = (String)"&field1=" + value + "&field2=" + value;     // "field1 bis 8" anpassen

  /*************** Thinkspeak senden *********************/
  unsigned long aktuelleMillis = millis();
  if (aktuelleMillis - letzteMillis >= interval || error) {       // senden im Interval und erneut im Fehlerfall
    error = false;
    letzteMillis = aktuelleMillis;
    if (!client.connect(host, httpPort)) {
      Serial.println("Thingspeak Verbindung fehlgeschlagen !");
      error = true;
      return false;
    }
    else {
      client.printf("POST /update?key=%s%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", APIKEY, path.c_str(), host);
      response = 0;
      return true;
    }
  }

  /************** Thinkspeak auf Anwort prüfen *****************/
  if (!response) {
    if (millis() - letzteMillis > timeout) {
      Serial.println("Thingspeak Client Timeout !");
      error = true;
      return false;
    }
    if (client.available()) {                                     // einlesen der Antwort
      //Serial.printf("Thingspeak Antwort nach: %4ld ms\n", millis() - letzteMillis); // zeigt die Zeit bis zur Antwort --> passe den Timeout entsprechend an
      String line = client.readStringUntil('\n');
      if (line.startsWith("HTTP/1.1 200 OK")) {                   // wenn Antwort mit "HTTP/1.1 200 OK" beginnt war das Senden erfolgreich
        client.stop();
        response = true;
      }
    }
  }
  return true;
}

36 Kommentare - Kommentar eintragen
B.Röhl ❘ 14.09.2023
Sehr schön beschrieben.
Nur es funktioniert nicht.
Haufen Fehlermeldungen.
Na ein Versuch wars wert. Dennoch vielen dank

Antwort:
Ohne die Fehlermeldungen ist keine Hilfe möglich.

Gruß Fips
Konrad ✪ ✪ ✪ 12.03.2023
Hi nochmal nach fast 2 Jahren,

Habe das Auslesen aus diesem Projekt mit der ESP8266 Zeitschaltuhr kombiniert, die ich direkt an die Gasheizung gekoppelt habe (Brauchte dazu aber meinen Kollegen Elektromeister wegen der 230 V Sache, der mir das aber in einer halben Stunde für lau gemacht hat). Bei mir ist das machbar, da ich Gas NICHT für warmes Wasser für Dusche, etc. benutze.

Fazit: Ich konnte den Gasverbrauch in den letzten 2 Jahren massiv um mehr als 30 % reduzieren, Tendenz weiter fallend! Vielen, vielen Dank Fips!

Wie gesagt: Projekt läuft schon seit mehr als 2 Jahre ohne Schwierigkeiten. Auch die Datenauslese mache ich immer noch wie oben beschrieben mit einer Datei, die ich ein mal im Jahr nach der Winterheizperiode auslese, zwecks Dokumentation.

Beide Projekte sind "best projects ever" bei mir.

Danke Fips

Antwort:
Bitte Konrad

Gruß Fips
Klaus ❘ 04.01.2023
Hallo Fips,
kaum hat man eine Frage gestellt und dabei das Problem geschildert fällt einem auch schon die Lösung ein.
Ich habe also den Webbrowser und das Interface unter der lokalen IP-Adresse (192.168.xx.yy) des ESP8266 gefunden. Auch die Einstellung des aktuellen Zählerstandes geht.
Ursache meiner Verwirrung war, daß ich an eine -von außen zugängliche, quasi öffentliche - Internetadresse gedacht hatte.
Also alles ok.
Grüße Klaus


Antwort:
Schön, das du es selbst......

Gruß Fips
Klaus ❘ 04.01.2023
Hallo Fips,
dein Projekt hat mich ermutigt auch mal etwas mehr als Spielerei mit Arduino zu probieren. Gasuhr auslesen und jederzeit mit dem Webbrowser zu kontrollieren erschien mir sehr sinnvoll.
Kurz, ich habe den Aufbau und die Anmeldung bei Thingspeak gemacht und es scheint alles zu laufen.
Meldung im Seriellen Monitor:
10:00:49.223 -> Verbunden mit: xxxxxx
10:00:49.256 -> Esp8266 IP: 192.168.178.47
10:00:49.289 -> SPIFFS gestartet!
10:00:49.289 -> HTTP Server gestartet!
10:00:49.289 ->
Auch erscheinen bei Thingspeak die Grafiken und Werte unter Private View. Aber das Webinterface mit der Anzeige "Zählerstand" und "Zählerstand eingeben" habe ich bisher nicht zu sehen gekriegt. Ich weiß einfach nicht wie ich es aufrufen soll/könnte. Wahrscheinlich ganz einfach - kannst du mir die URL dafür nennen?
Danke schon mal vorab
Gruß Klaus

Antwort:
Ja, es ist ganz einfach.

Gruß Fips
Helmut ✪ ✪ ✪ 17.10.2022
Moin,
ich hatte dir heute morgen einen Kommentar geschrieben, in dem ich davon ausgegangen war, dass der Befehl server.begin() an der falschen Stelle steht. Das stimmt so nicht, da hat mein Board wohl gesponnen, mit einem anderen läuft es so wie im Originalcode.
Also alles gut und noch mal vielen Dank.
Gruß Helmut

Antwort:
Bitte.

Gruß Fips
Helmut ✪ ✪ ✪ 17.10.2022
Moin,
ich habe mir deine Quellen kopiert und an meinen Zähler angepasst. Leider habe ich die entsprechende Serverseite über den Browser wg. Timeout nicht öffnen können.
Nachdem ich diese Stelle in "GasZaehler.ino" im setup() korrigiert(?) hatte, funktionierte es!

vorher:
Connect();
homepage();
..
server.begin();

nachher:
Connect();
server.begin();
homepage();

Vielen Dank für den Quellcode
Gruß Helmut


Antwort:
Hauptsache es Funktioniert.

Gruß Fips
Burkhard ✪ ✪ ✪ 20.09.2022
Hallo fipsok
hast du inzwischen auch mal die mqtt Anbindung programmiert?
Ich würde die mqtt Daten dann direkt in Homeassitant auslesen können..

Antwort:
Mit MQTT habe ich noch nie gearbeitet.

Gruß Fips
Jens ✪ ✪ ✪ 07.09.2022
Erst einmal vielen Dank für deine super spannenden Projekte. Ich beschäfte mich bereits seit einigen Wochen mit der Materie und konnte durch deine sehr strukturierten Projekte bereits viel lernen.

Hättest du vielleicht eine Empfehlung für einen Reedsensor für mich?

Antwort:
Es muss ein "Schließer" sein.

Gruß Fips
Hans ✪ ✪ ✪ 03.09.2022
Moin,
wirklich klasse. Tolle Umsetzung und gut lesbarer Code. Mir gefällt besonders, dass man keine weiteren Geräte/Server wie auf anderen Seiten benötigt.

Ich habe versucht Thingspeak per https aufzurufen und dazu zig Lösungen (sha1, WifiSecureClient, SSL) ausprobiert. Laufe aber in einen Timeout.

Haben Sie evtl. schon eine https-Verbindung aufgebaut?

Gruß Hans

Antwort:
Nein, das habe ich noch nicht probiert.

Gruß Fips
Frank ❘ 02.09.2022
Hallo,
ich bin noch Anfänger, was das Arduino/Esp programmieren angeht. Diese Projekt find ich aber sehr gut, und hab eine Frage.
Bisher hatte ich zum programmieren immer nur eine .Ino die aufgemacht habe, und programmiert habe in der Arduino Umgebung. Wie geht das hier mit den vier .ino? Muss ich die alle aneinander reihen?
Danke und Gruss

Antwort:
Auf der Startseite oben links gibt es die Erklärung dazu.
Klick auf "Tab Information Einblenden", zeigt es dir.

Gruß Fips
Kommentar eintragen

*