Hallo,
da ich den Sketch jetzt mal wieder angepackt habe, habe ich noch gleich etwas geändert was ich schon länger mal machen wollte.
Die Anzeige der Messwerte für den Verbrauch wird jetzt mit zwei Nachkommastellen ausgegeben.
ich stelle jetzt hier nochmal den gesamten Sketch rein. Sicher wird es so sein das mit einer neuen Zählergeneration eine neu Variante innerhalb der SML Spezifikation entsteht die hier so nicht berücksichtigt ist. Dann muss ich mich halt noch mal reindenken. So kann ich mich erinnern das vor einiger Zeit ein User hier einen Zähler hatte der Kanal 1 anstelle des sonst üblichen Kanal 0 verwendet hat. Natürlich könnte man jetzt im parser genau diese Byte z.B. überspringen, damit würde es dann immer klappen.
Nun ist das Thema Stromzähler für uns Bastler sicher noch lange nicht zu Ende, letztlich wird es jedoch mit der allgemeinen Einführung von Smardmetern keinen Sinn mehr machen.
Jetzt hoffe ich noch das alles in einen Post passt 
Also hier der code
HTML Seite
<!doctype html>
<html lang="de">
<!--
Einbindung der externen Chart Lib https://www.chartjs.org
Chart.js v2.9.4
* https://www.chartjs.org
* (c) 2020 Chart.js Contributors
* Released under the MIT License
*/
-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stromzähler</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded',()=>{
document.querySelector('#btn').addEventListener('click',sendData);
var P=[];
var xachse=[];
// objekt instanz erstellen
var config1=newConfig();
// Vorenstellung
config1.data.datasets[0].label="Leistung [w]";
//config1.data.datasets[0].borderColor="red";
//config1.data.datasets[1].borderColor="blue";
var ctx1 = document.getElementById("chart-1").getContext('2d');
window.myChart1=new Chart(ctx1,config1);
function newConfig(){
var config={
type: 'line',
data: {
labels: xachse,
datasets: [{
label: 'Reihe1',
borderColor: "red",
backgroundColor:"black",
borderWidth: 1,
pointRadius:2,
data:P,
fill:false,
}
]
},
options:{
title: {
display: false,
text: 'Chart'
},
animation: {
duration: 0 // general animation time
},
scales:{
xAxes:[{
display: true,
scaleLabel: {
display: true,
labelString: 'Vergangene Minuten'
}
}],
yAxes: [{
ticks:{
//precision:0.05
},
display: true,
scaleLabel: {
display: false,
labelString: ''
}
}]
}
} // options ende
};
return config;
}
async function loadData(){
let resp = await fetch('/daten')
let obj = await resp.json();
document.getElementById("kennung").innerHTML=obj.kn;
document.getElementById("kw180").innerHTML=obj.C180+" KWh";
document.getElementById("kw181").innerHTML=obj.C181+" KWh";
document.getElementById("kw280").innerHTML=obj.C280+" KWh";
document.getElementById("P").innerHTML=obj.P+" W";
document.getElementById("logtime").value=obj.logtime;
config1.data.labels = obj.time;
config1.data.datasets[0].data = obj.PChart;
window.myChart1.update();
}
async function loadcycle(){
let resp = await fetch('/cycle')
let obj = await resp.json();
document.getElementById("kennung").innerHTML = obj.kn;
document.getElementById("kw180").innerHTML = obj.C180+" KWh";
document.getElementById("kw181").innerHTML = obj.C181+" KWh";
document.getElementById("kw280").innerHTML = obj.C280+" KWh";
document.getElementById("P").innerHTML = obj.P+" W";
config1.data.labels = obj.time;
config1.data.datasets[0].data = obj.PChart;
window.myChart1.update();
}
async function sendData(){
let data = document.querySelector('form');
let resp=await fetch('btnsend',{
method:'post',
body:new FormData(data)
});
let obj=await resp.json();
document.getElementById("logtime").value = obj.logtime;
}
loadData();
setInterval(loadcycle, 10000);
});
</script>
<style>
body {
background-color: #bdb;
display: flex;
flex-flow: column;
font-size: 1.3em;
}
.flex-container {
display: flex;
flex-direction:column;
gap:1em;
}
.flex-item {
border: 2px solid;
margin: .5em;
padding: .5em;
min-width:20em;
}
.flex-item:nth-of-type(1) {
background: #fdfcf3;
}
.flex-item:nth-of-type(2) {
background: #ffebeb;
}
/* große Viewports */
@media all and (min-width:45em) {
.flex-container {
flex-direction:row;
}
.flex-item:nth-of-type(2) {
min-width:30em
}
}
div{
width:auto
}
button{
width:5em;
height:1.5em;
font-size:1em;
}
input{
width:4.5em;
height:1em;
font-size:1em;
}
</style>
</head>
<body>
<h1>Stromzähler</h1>
<main class="flex-container">
<section class="flex-item">
<h3>Zählerstand</h3>
Zähler :<span id="kennung"></span>
<table>
<tr>
<td>Bezug gesamt (1.8.0) </td><td><span id="kw180"></span></td>
</tr>
<tr>
<td>Bezug T1 (1.8.1) </td><td><span id="kw181"></span></td>
</tr>
<tr>
<td>Einspeisung (2.8.0) </td><td><span id="kw280"></span></td>
</tr>
<tr>
<td>akt. Leistung </td><td><span id="P"></span></td>
</tr>
</table>
<form>
<p>
Log Zyklus
<input type="text" id="logtime" name="logtime">min
<button type="button" id="btn">send</button>
</p>
</form>
</section>
<section class="flex-item">
<h3> Leistung Verlauf</h3>
<div>
<canvas id="chart-1"> </canvas>
</div>
</section>
</main>
</body>
</html>
Maintab
/*
ESP8266 Wemos D1
Okt 2025 V2.0
*/
#include <SoftwareSerial.h>
#include <LittleFS.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
const char* ssid = "xxxxx";
const char* password = "yyyyy";
IPAddress staticIP(192, 168, 178, 14); // eigene IP
IPAddress gateway(192, 168, 178, 1); // Fritzbox Heimnetz
IPAddress subnet(255, 255, 255, 0);
// Server Instanz erstellen
ESP8266WebServer server(80);
//#define DEBUG 1
#ifdef DEBUG
#define printdbg(x) Serial.print(x)
#define printdbgn(x) Serial.println(x)
#else
#define printdbg(x)
#define printdbgn(x)
#endif
#define RX 13 // D7
#define TX 15 // D8
SoftwareSerial mySerial;
byte sml[420];
const byte sml_Kopf[] = {0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01}; // Startsequenz
// OBIS Code 1.8.0
const byte code180[] = {0x01, 0x00, 0x01, 0x08, 0x00, 0xff};
// OBIS CODE 1.8.1
const byte code181[] = { 0x01, 0x00, 0x01, 0x08, 0x01, 0xff};
// OBIS CODE 1.8.2
const byte code182[] = { 0x01, 0x00, 0x01, 0x08, 0x02, 0xff};
// OBIS CODE 2.8.0
const byte code280[] = { 0x01, 0x00, 0x02, 0x08, 0x00, 0xff};
// OBIS CODE 2.8.1
const byte code281[] = { 0x01, 0x00, 0x02, 0x08, 0x01, 0xff};
// OBIS CODE 2.8.2
const byte code282[] = { 0x01, 0x00, 0x02, 0x08, 0x02, 0xff};
// OBIS Code 10.7.0
const byte code107[] = { 0x01, 0x00, 0x10, 0x07, 0x00, 0xff};
// Hier eventuell zusätzliche OBIS Codes eintragen
struct d {
byte sml_octst[50];
uint32_t sml_uint32;
int32_t sml_int32;
} data;
float kw180, kw181, kw280;
long p;
long p_mittel, p_graf;
int n_mittel, n_graf;
long int ID;
char kennung[30];
uint16_t pos = 0;
uint16_t anzahl = 400;
uint32_t altzeit;
bool aktiv, wd;
// Ringpuffer
const byte maxbuffer = 100;
int logtime = 5;
byte wz = 0; // schreibzeiger
int b_wert[maxbuffer];
uint32_t b_zeit[maxbuffer];
void setup() {
// put your setup code here, to run once:
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
mySerial.begin(9600, SWSERIAL_8N1, RX, TX, false, 256);
conectWIFI();
LittleFS.begin(); // Filesystem starten
listDir("/"); // Info anzeigen
server_setup();
ArduinoOTA.onStart([]() {
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
LittleFS.end();
});
ArduinoOTA.begin();
}
void loop() {
// put your main code here, to run repeatedly:
ArduinoOTA.handle();
server.handleClient();// hier passiert sonst nichts
MDNS.update();
lesen();
wd = watchdog(aktiv);
if (logtime > 0)writebuffer(logtime * 60000UL);
digitalWrite(LED_BUILTIN, aktiv);
}//----------- Loop ende ------------
bool watchdog(bool trigger) {
static uint32_t altzeit = 0;
bool merker = false;
if (trigger != merker) {
altzeit = millis();
merker = trigger;
}
if (millis() - altzeit > 3500) {
return false;
}
else return true;
}
void lesen() {
while (mySerial.available()) {
byte b = mySerial.read();
//Serial.print(b,HEX);
altzeit = millis();
if (pos < sizeof(sml)) { // abbruck bei max
sml[pos] = b;
pos++;
aktiv = true;
}
yield();
}
// Pause erkennen
if ((millis() - altzeit > 50) && aktiv == true) {
printdbgn(F("Pause erkannt "));
//Serial.println("pause erkannt");
altzeit = 0;
aktiv = false;
anzahl = pos; // anzahl der gültigen byte
anzeige(); // anzeige und auswerten
pMittel();
reset(); // array zurück setzen und Zeiger auf 0
}
}
void pMittel() {
if (n_mittel < 100) {
p_mittel += p; // Mittelwert für numerische Anzeige
n_mittel++;
}
else {
p_mittel = p;
n_mittel = 1;
}
p_graf += p; // Mittelwert für Chart Anzeige
n_graf ++;
}
void anzeige() {
Serial.print(anzahl); Serial.println(F(" byte empfangen"));
printdump(anzahl);
// die ersten 3 byte sind ascii Zeichen
findcode(sml_Kopf, sizeof(sml_Kopf));
for (byte i = 0; i < 3; i++) {
kennung[i] = data.sml_octst[i + 2];
kennung[i + 1] = 0;
}
// der rest ergibt eine Zahl
for (byte i = 0; i < 10; i++) {
ID = ID << 8;
ID += data.sml_octst[i];
}
// hier ist eventuell zu prüfen ob der Zähler die Daten als int oder uint
// ausgibt um den vollen Zahlenumfang zu haben
// normal solle int reichen
findcode(code180, sizeof(code180));
if (data.sml_uint32 > 0 ) {
kw180 = data.sml_uint32 / 1000.0;
findcode(code181, sizeof(code181)); kw181 = data.sml_uint32 / 1000.0;
findcode(code280, sizeof(code280)); kw280 = data.sml_uint32 / 1000.0;
findcode(code107, sizeof(code107));
if (abs(data.sml_int32) < 16000) p = data.sml_int32;
}
#ifdef DEBUG
Serial.print(F("Zähler ID ")); Serial.print(kennung);
Serial.print(" "); Serial.print(ID); Serial.println();
Serial.print(F("Zählwerk A+ ")); Serial.print(kw180); Serial.println("KWh");
Serial.print(F("Zählwerk T1 A+ ")); Serial.print(kw181); Serial.println("KWh");
Serial.print(F("Zählwerk A- ")); Serial.print(kw280); Serial.println("KWh");
Serial.print(F("Wirkleistung ")); Serial.print(p); Serial.println("W");
#endif
}
void reset() {
// buffer löschen
for (uint16_t i = 0; i < sizeof(sml); i++) {
sml[i] = 0;
pos = 0;
}
}
void send_daten() {
/* alle daten senden beim laden der Seite
*/
char s[50];
int pm = 0;
if (n_mittel > 0) pm = p_mittel / n_mittel;
if (wd == true)sprintf(s, "ID %s %ld", kennung, ID);
else strcpy(s, "Keine Daten");
String buff;
buff.reserve(maxbuffer * 14 + 100);
buff = "{";
buff += "\"kn\":[\"";
buff += s;
buff += "\"],";
buff += "\"C180\":[\"";
buff += kw180;
buff += "\"],";
buff += "\"C181\":[\"";
buff += kw181;
buff += "\"],";
buff += "\"C280\":[\"";
buff += kw280;
buff += "\"],";
buff += "\"P\":[\"";
buff += pm;
buff += "\"],";
buff += "\"logtime\":[\"";
buff += logtime;
buff += "\"],";
buff += "\"PChart\"";
buff += ":";
buff += intbufferToString(b_wert);
buff += ",\"time\"";
buff += ":";
buff += timebufferToString(b_zeit);
buff += "}";
//Serial.println(buff);
server.send(200, "application/json", buff);
}
void send_cycle() {
/*alle daten senden jedoch ohne das Input feld
damt dieses nicht zyklisch überschrieben wird
Mittelwert aktualisieren und Rücksetzen
*/
char s[50];
int pm = 0;
if (n_mittel > 0) {
pm = p_mittel / n_mittel;
p_mittel = 0; // reset Mittelwert
n_mittel = 0;
}
if (wd == true)sprintf(s, "ID %s %ld", kennung, ID);
else strcpy(s, "Keine Daten");
String buff;
buff.reserve(maxbuffer * 14 + 100);
buff = "{";
buff += "\"kn\":[\"";
buff += s;
buff += "\"],";
buff += "\"C180\":[\"";
buff += kw180;
buff += "\"],";
buff += "\"C181\":[\"";
buff += kw181;
buff += "\"],";
buff += "\"C280\":[\"";
buff += kw280;
buff += "\"],";
buff += "\"P\":[\"";
buff += pm;
buff += "\"],";
buff += "\"PChart\"";
buff += ":";
buff += intbufferToString(b_wert);
buff += ",\"time\"";
buff += ":";
buff += timebufferToString(b_zeit);
buff += "}";
//Serial.println(buff);
server.send(200, "application/json", buff);
}
void get_daten() {
/* Eingabe von Form lesen
und antworten
*/
String buff;
buff.reserve( 50);
buff = server.arg(0); logtime = buff.toInt();
if (logtime < 1 ) logtime = 1;
if (logtime > 60) logtime = 60;
//Serial.print ("Daten angekommen"); Serial.println(logtime);
buff = "{";
buff += "\"logtime\":[\"";
buff += logtime;
buff += "\"]";
buff += "}";
//Serial.println(buff);
server.send(200, "application/json", buff);
}
//------------- Ringpuffer beschreiben
void writebuffer(uint32_t t) {
uint32_t static altzeit = 0;
if (millis() - altzeit >= t) {
altzeit = millis();
if (n_graf > 0) {
b_wert[wz] = p_graf / n_graf;
b_zeit[wz] = millis();
}
p_graf = 0; // reset Mittelwert für Chart Anzeige
n_graf = 0;
wz++; // schreibzeiger erhöhen
if (wz > maxbuffer - 1) wz = 0;
// for (byte i = 0; i < maxbuffer; i++) {
// Serial.print(b_temp[i]); Serial.print(" ");
// }
// Serial.println(wz);
}
}
String intbufferToString(int * arr) {
String buff;
buff.reserve(maxbuffer * 4 + 5); byte lz;
lz = wz;
buff = "[";
for (byte i = 0; i < maxbuffer; i++) {
if (b_zeit[lz] > 0) { // Eintrag enthalten
buff = buff += arr[lz];
buff = buff += ",";
}
lz++;
if (lz >= maxbuffer)lz = 0;
}
uint16_t l = buff.length();
if (l >= 2) buff.remove(l - 1);
buff = buff += "]";
//Serial.print(buff);Serial.println(l);
return buff;
}
String timebufferToString(uint32_t* arr) {
String buff ;
buff.reserve(maxbuffer * 4 + 5);
uint32_t actms = millis();
byte lz;
lz = wz;
buff = "[";
for (byte i = 0; i < maxbuffer; i++) {
if (b_zeit[lz] > 0) { // Eintrag enthalten
buff = buff += (actms - arr[lz]) / 60000UL; // Differenz in Minuten
buff = buff += ",";
}
lz++;
if (lz >= maxbuffer)lz = 0;
}
uint16_t l = buff.length();
if (l >= 2) buff.remove(l - 1);
buff = buff += "]";
//Serial.print(buff);Serial.println(l);
return buff;
}
Parser tab
void findcode(const byte *code, uint16_t anz) {
bool found = false;
bool sta = false;
bool kopfdaten = false;
unsigned int index = 0;
unsigned int startindex = 0;
unsigned int i, ii;
unsigned int n = 0;
int dazu = 0;
int64_t erg = 0;
uint64_t uerg = 0;
byte maxelm = 0;
byte elm = 0;
byte maxloop = 0;
data.sml_uint32 = 0;
data.sml_int32 = 0;
printdbgn();
// Start abfragen
if (sml[0] == 0x1B && sml[1] == 0x1B &&
sml[2] == 0x1B && sml[3] == 0x1B) sta = true;
if (!sta) return; // abbrechen Anfang falsch
for ( i = 0; i <= sizeof(sml) - anz; i++) {
if (sml[i] == code[0]) { // Anfang gefunden
found = true;
for (ii = 1; ii < anz; ii++) { // restliche prüfen
if (sml[i + ii] != code[ii]) found = false;
}
index = i + ii;
startindex = i;
if (found) { // OBIS Code stimmt
printdbg(F("code gefunden: "));
for (byte i = 0; i < anz; i++ ) {
printhex(code[i]);
}
printdbgn();
break; // for schleife verlassen
}
}
}
// hier gehts weiter
// Abfrage geht es um die Kopfdaten
int s = 0;
for (i = 0; i < anz; i++) {
s += code[i];
}
//printdbg(F("summe")); printdbgn(s);
if (s == 112) {
kopfdaten = true;
//printhex(sml[index]);
maxelm = 0;// es gab noch kein Listen-Element
elm = 1;
}
else {
kopfdaten = false;
//printhex(sml[index]);
maxelm = sml[startindex - 2] - 0x70; // Anzahl der Elemnte aus dem zugeh. Listen-Elemen
elm = 2; // das nächste Element ist 2
}
printdbg(F("start mit elm ")); printdbg( elm);
printdbg(F(" max Elemnt ")); printdbgn(maxelm);
do {
maxloop++;
if (maxloop > 30) { // Notausstieg :-)
printdbgn(F("kein Elemt erkannt"));
return;
}
// --------- 0x01 auswerten
switch (sml[index]) {
case 0x01://leres Element
printhex(sml[index]);
printdbg(F("leres erkannt "));
printdbgn(elm);
index++;
elm++;
break;
// ---------- Liste auswerten
case 0x70 ... 0x7f: // Liste
dazu = sml[index] - 0x70; // neue Elemente aus Liste
maxelm = maxelm + dazu;
printhex(sml[index]);
printdbg(F("element ")); printdbg(elm);
printdbg(F(" Liste erkannt plus ")); printdbg(dazu);
printdbg(F(" jetzt max ")); printdbgn(maxelm);
index++;
elm++;
break;
//----------- Integer auswerten
case 0x52 ... 0x59:// integer
n = sml[index] - 0x50;
for ( uint16_t i = 0; i < n; i++) {
printhex(sml[index + i]);
}
printdbg(F(" element ")); printdbgn(elm);
if (elm == maxelm - 1) {
erg = 0;
for (uint16_t i = 1; i < n; i++ ) {
erg = erg << 8;
erg += sml[index + i];
}
// Vorzeichen für int8,int16,int32 berücksichtigen
if ( n == 2 && erg > 127) erg = erg - 256;
else if (n == 3 && erg > 32768 ) erg = erg - 65536;
else if (n == 5 && erg > 2147483648 ) erg = erg - 4294967296;
// scaler berücksichtigen
if (sml[index - 1] == 0x02) erg = erg * 100;
else if (sml[index - 1] == 0x01) erg = erg * 10;
else if (sml[index - 1] == 0xff) erg = erg / 10;
else if (sml[index - 1] == 0xfe) erg = erg / 100; //*10^-2
else if (sml[index - 1] == 0xfd) erg = erg / 1000;
else if (sml[index - 1] == 0xfc) erg = erg / 10000;
else if (sml[index - 1] == 0xfb) erg = erg / 100000;//*10^-5
data.sml_int32 = erg;
printdbg(F("SML_VALUE INT ")); printdbgn(erg);
}
elm++;
index += n;
break;
// ------------unsigned Integer auswrten
case 0x62 ... 0x69:// unsigned integer
n = sml[index] - 0x60;
for (uint16_t i = 0; i < n; i++) {
printhex(sml[index + i]);
}
printdbg(F(" element ")); printdbgn(elm);
if (elm == maxelm - 1) { // hier sollte SML_VALUE sein
uerg = 0;
for (uint16_t i = 1; i < n; i++ ) {
uerg = uerg << 8;
uerg += sml[index + i];
}
if (sml[index - 1] == 0x02) uerg = uerg * 100;
else if (sml[index - 1] == 0x01) uerg = uerg * 10;
else if (sml[index - 1] == 0xff) uerg = uerg / 10;
else if (sml[index - 1] == 0xfe) uerg = uerg / 100;
else if (sml[index - 1] == 0xfd) uerg = uerg / 1000;
else if (sml[index - 1] == 0xfc) uerg = uerg / 10000;
else if (sml[index - 1] == 0xfb) uerg = uerg / 100000;
data.sml_uint32 = uerg;
printdbg(F("SML_VALUE UINT ")); printdbgn(uerg);
}
elm++;
index += n;
break;
//----------- octal String auswerten
case 0x02 ... 0x0f: // octal String
n = sml[index];
for (uint16_t i = 0; i < n; i++) {
printhex(sml[index + i]);
}
if (n > sizeof(data.sml_octst)) n = sizeof(data.sml_octst);
if ( kopfdaten == true && elm == maxelm - 3) { // Kopfdaten ID abfragen // das ist noch Q&D
printdbg(F("element ")); printdbg(elm);
printdbgn(F(" SML_ServerID "));
for (uint16_t i = 1; i < n; i++) {
//printhex(sml[index + i]);
data.sml_octst[i - 1] = sml[index + i];
}
//return;
}
else {
for (uint16_t i = 1; i < n; i++) {
//printhex(sml[index + i]);
//Serial.println(i);
data.sml_octst[i - 1] = sml[index + i];
data.sml_octst[i] = 0;
}
printdbg(F("element ")); printdbgn(elm);
}
elm++;
index += n;
break;
//----------- octal String länger 15 Zeichen
case 0x80 ...0x8f:// octalstring länger 14 Zeichen
n = (sml[index] - 0x80) * 16;
n = n + sml[index + 1];
for (uint16_t i = 0; i < n; i++) {
printhex(sml[index]);
}
printdbg(F("element ")); printdbgn(elm);
elm++;
index += n;
break;
}
} while (elm <= maxelm);
return;
}
void printdump(uint16_t n) {
for (unsigned int i = 0; i < n; i++) {
if (i % 20 == 0) printdbgn();
printhex(sml[i]);
}
printdbgn();
}
void printhex(byte wert) {
char hexstring[10];
if (wert < 16)sprintf(hexstring, "0%x ", wert);
else sprintf(hexstring, "%x ", wert);
printdbg(hexstring);
}
Webserver Tab
/*Web Server tab
*/
void server_setup() {
// --Server Handle einrichten--;
server.serveStatic("/", LittleFS, "/flexbox.html");
server.on("/daten", send_daten);
server.on("/btnsend", get_daten);
server.on("/cycle", send_cycle);
server.onNotFound(handleNotFound); // Fehler bearbeiten
server.begin();
Serial.println("HTTP server started");
}
void conectWIFI() {
byte maxzeit = 0;
WiFi.disconnect();
//WiFi.persistent(true); // daten in EEprom
WiFi.mode(WIFI_STA);
Serial.printf("Connecting to %s ", ssid);
WiFi.config(staticIP, gateway, subnet);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
maxzeit++;
if (maxzeit > 60)return;
}
WiFi.setAutoReconnect(true);
Serial.print(F(" connected...locale IP:"));
Serial.println(WiFi.localIP());
if (MDNS.begin("Stromzähler")) {
Serial.println("MDNS responder started");
}
}
// ------------ Fehler Seite
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
// --------------- Fillesystem anzeigen ---------------------
void listDir(const char *dirname) {
FSInfo fs_info;
LittleFS.info(fs_info);
float fileTotalKB = fs_info.totalBytes / 1024.0;
float fileUsedKB = fs_info.usedBytes / 1024.0;
Serial.print("\nFilesystem Total KB "); Serial.print(fileTotalKB);
Serial.print(" benutzt KB "); Serial.println(fileUsedKB);
Serial.printf("Listing directory: %s\n", dirname);
Dir root = LittleFS.openDir(dirname);
while (root.next()) {
File file = root.openFile("r");
Serial.print(root.fileName());
Serial.print('\t');
Serial.print(file.size());
Serial.println(" byte");
file.close();
}
}