ESP32 Strom messen und an Raspy mit MQTT senden

Hallo zusammen, ich bin ziehmlicher Anfänger in Arduino möchte aber gern was bewerkstelligen. Vielleicht kann mir da jemand dabei helfen.

Ich möchte an den einzelnen Phasen in meinem Verteiler, den Strom messen. Dies funktioniert auch schon relativ genau mit einem Sketch aus dem Internet.

Im Serielen Monitor kann man die 3 Ströme und die erreichnete Gesammtleistung sehen. Ich möchte aber gern diese 4 Werte per MQTT an meinen RaspberryPi senden. Was muss ich in meinem Sketch ändern?

#include <Arduino.h>
#include <WiFi.h>

//Setup Variablen
int numberOfSamples = 9000;

const char* host = "emoncms-server.de";

//WiFi Überwachung
static bool sta_was_connected = false;

//einstellen der Spannungs- und Stromeingangspins
int inPinI1 = 34;
int inPinI2 = 35;
int inPinI3 = 39;

//Zähler für den ersten Durchlauf
int firstrun = 0;

//Leistungsberechnung
float PowerSum = 0;

//WLAN Teil
const char* ssid     = "meineSSID";
const char* password = "meinPasswort";
const char* mqttServer = "Server";
const char* mqttUsername = "Username";
const char* mqttPassword = "Passwort";
const char* mqttDeviceId = "ID";

// CT: Die Spannung hängt von Strom, Lastwiderstand und Windungen der Spule ab
#define CT_BURDEN_RESISTOR    62
#define CT_TURNS              1800
#define VOLTAGE               225

//Kalibrierungskoeffizienten
//diese müssen eingestellt werden, um die Genauigkeit zu erhöhen
//legen Sie zuerst die obigen Werte fest und kalibrieren Sie dann weiter durch Referenzmessungen
double ICAL = 1.08;

//Anpassung durch VCAL/ICAL-Optimierungen
double I_RATIO = (long double)CT_TURNS / CT_BURDEN_RESISTOR * 3.3 / 4096 * ICAL;

//Filter Variable 1
double lastFilteredI, filteredI;
double sqI, sumI;
//Stichprobe Variable 1
int lastSampleI, sampleI;

//Filter Variable 2
double lastFilteredI1, filteredI1;
double sqI1, sumI1;
//Stichprobe Variable 2
int lastSampleI1, sampleI1;

//Filter Variable 3
double lastFilteredI3, filteredI3;
double sqI3, sumI3;
//Stichprobe Variable 3
int lastSampleI3, sampleI3;

//benötigte Ergebnisse
double Irms1;
double Irms2;
double Irms3;
unsigned long timer;

//EspClass ESPm;
String url = "";

//WLAN
void WIFI_Connect()
{
  digitalWrite(2, 1);
  WiFi.disconnect();
  Serial.println("Booting Sketch...");
  WiFi.mode(WIFI_AP_STA);
  WiFi.begin(ssid, password);
  //warten auf Verbindung
  for (int i = 0; i < 25; i++)
  {
    if ( WiFi.status() != WL_CONNECTED ) {
      delay ( 250 );
      digitalWrite(2, 0);
      Serial.print ( "." );
      delay ( 250 );
      digitalWrite(2, 1);
    }
  }
  digitalWrite(2, 0);
}


void setup() {
  //setze LED als Output
  pinMode(2, OUTPUT);
  //setze Analogeingänge
  pinMode(inPinI1, INPUT);
  adcAttachPin(inPinI1);
  pinMode(inPinI2, INPUT);
  adcAttachPin(inPinI2);
  pinMode(inPinI3, INPUT);
  adcAttachPin(inPinI3);

  Serial.begin(115200);
  delay(500);
  //WLAN Teil
  WIFI_Connect();

}

void loop() {
  timer = millis();

  //WLAN Überwachung
  WiFi.onEvent(WiFiEvent);

  //überprüfen ob WLAN anliegt
  //automatische Neuverbindung, wenn der ESP32 keine Verbindung zum Router hat
  if (WiFi.status() != WL_CONNECTED)
  {
    WiFi.onEvent(WiFiEvent);
    WIFI_Connect();
  } else {

    //**************************************************************************
    //Phase 1
    for (int n = 0; n < numberOfSamples; n++)
    {

      //wird für den Offset benötigt
      lastSampleI = sampleI;

      //liest die Spannung- und Stromwerte
      sampleI = analogRead(inPinI1);

      //wird für den Offset benötigt
      lastFilteredI = filteredI;

      //Digitale Hochpassfilter zum Entfernen des 1,6-V-DC-Offsets
      filteredI = 0.9989 * (lastFilteredI + sampleI - lastSampleI);

      //Quadratischer Mittelwert Strom
      //1) I²
      sqI = filteredI * filteredI;
      //2) Ergebnis
      sumI += sqI;
      delay(0.00002);
    }

    //Berechnung des Effektivwertes
    //Einberechnung der Kalibrierungskoeffizienten
    Irms1 = (I_RATIO * sqrt(sumI / numberOfSamples)) - 0.16;
    if ((Irms1 < 0) || (firstrun < 2)) {
      Irms1 = 0;
    }; //setzt den negativen Strom auf Null und ignoriert die ersten 2 Berechnungen
    sumI = 0;

    Serial.println("Irms1:" + String(Irms1));

    //**************************************************************************
    //Phase 2
    for (int n = 0; n < numberOfSamples; n++)
    {

      //wird für den Offset benötigt
      lastSampleI1 = sampleI1;

      //liest die Spannung- und Stromwerte
      sampleI1 = analogRead(inPinI2);

      //wird für den Offset benötigt
      lastFilteredI1 = filteredI1;

      //Digitale Hochpassfilter zum Entfernen des 1,6-V-DC-Offsets
      filteredI1 = 0.9989 * (lastFilteredI1 + sampleI1 - lastSampleI1);

      //Quadratischer Mittelwert Strom
      //1) I²
      sqI1 = filteredI1 * filteredI1;
      //2) Ergebnis
      sumI1 += sqI1;
      delay(0.00002);
    }

    //Berechnung des Effektivwertes
    //Einberechnung der Kalibrierungskoeffizienten
    Irms2 = (I_RATIO * sqrt(sumI1 / numberOfSamples)) - 0.16;
    if ((Irms2 < 0) || (firstrun < 2)) {
      Irms2 = 0;
    }; //setzt den negativen Strom auf Null und ignoriert die ersten 2 Berechnungen
    sumI1 = 0;

    Serial.println("Irms2:" + String(Irms2));

    //**************************************************************************
    //Phase 3
    for (int n = 0; n < numberOfSamples; n++)
    {

      //wird für den Offset benötigt
      lastSampleI3 = sampleI3;

      //liest die Spannung- und Stromwerte
      sampleI3 = analogRead(inPinI3);

      //wird für den Offset benötigt
      lastFilteredI3 = filteredI3;

      //Digitale Hochpassfilter zum Entfernen des 1,6-V-DC-Offsets
      filteredI3 = 0.9989 * (lastFilteredI3 + sampleI3 - lastSampleI3);

      //Quadratischer Mittelwert Strom
      //1) I²
      sqI3 = filteredI3 * filteredI3;
      //2) Ergebnis
      sumI3 += sqI3;
      delay(0.0002);
    }

    //Berechnung des Effektivwertes
    //Einberechnung der Kalibrierungskoeffizienten
    Irms3 = (I_RATIO * sqrt(sumI3 / numberOfSamples)) - 0.16;
    if ((Irms3 < 0) || (firstrun < 2)) {
      Irms3 = 0;
    }; //setzt den negativen Strom auf Null und ignoriert die ersten 2 Berechnungen
    sumI3 = 0;
    Serial.println("Irms3:" + String(Irms3));

    Serial.println("Summe:" + String(Irms1 + Irms2 + Irms3));

    //Berechnen der Leistung
    PowerSum = ((Irms1 + Irms2 + Irms3) * VOLTAGE);

    //sendet die Daten zum Server ...
    if ((WiFi.status() == WL_CONNECTED) && (firstrun >= 2)) { //WLAN geprüft, ignoriere die ersten Daten

      //verwendet die WiFiClient, um TCP-Verbindungen aufzubauen
      WiFiClient client;
      const int httpPort = 80;
      if (!client.connect(host, httpPort)) {
        Serial.println("keine Verbindung");
        return;
      }
      //Erstellung der URI
      String url = "/emoncms/input/post.json?node=1&apikey=xxxxxxxxxxxxxxxxxxxxxx&json={";
      //url += value;
      url = url + "Phase1:" + Irms1 + ",";
      url = url + "Phase2:" + Irms2 + ",";
      url = url + "Phase3:" + Irms3 + ",";
      url = url + "PowerSum:" + PowerSum + "}";

      Serial.print("Requesting URL: ");
      Serial.println(url);

      //diese Daten zum Server senden
      client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                   "Host: " + host + "\r\n" +
                   "Connection: close\r\n\r\n");
      unsigned long timeout = millis();
      while (client.available() == 0) {
        if (millis() - timeout > 5000) {
          Serial.println(">>> Client Timeout !");
          client.stop();
          return;
        }
      }

      /*
        //Liest alle Antworten vom Server und gibt sie im "Serial" aus
        while(client.available()) {
        String line = client.readStringUntil('\r');
        Serial.print(line);
      */

    }

    if (firstrun <= 2) {
      firstrun++;
    }; //Löschen der Daten
    delay(1000);
  }//WiFi Watchdog
}

//WLAN Überwachung
void WiFiEvent(WiFiEvent_t event) {
  Serial.printf("[WiFi-event] event: %d  - ", event);
  switch (event) {
    case SYSTEM_EVENT_STA_GOT_IP:
      Serial.println("WLAN verbunden");
      Serial.print("IP-Adresse: "); Serial.println(WiFi.localIP());
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      Serial.println("WLAN Verbindung verloren");
      WiFi.begin();   // <<<<<<<<<<<  added  <<<<<<<<<<<<<<<
      ESP.restart();
      break;
    case SYSTEM_EVENT_STA_START:
      Serial.println("ESP32 starten");
      break;
    case SYSTEM_EVENT_STA_CONNECTED:
      Serial.println("ESP32 Verbunden zu AP");
      break;
    case SYSTEM_EVENT_STA_LOST_IP:
      Serial.println("ESP32 IP-Adresse verloren");
      WiFi.begin();   // <<<<<<<<<<<  added  <<<<<<<<<<<<<<<
      ESP.restart();
      break;
  }
}

Der Sketch liest die Leistung ganz bestimmt nicht. Eher die verwendete Hardware die dann vom Arduino ausgelesen wird, und die du uns mitteilen könntest.

Hallo taximan

ich benutze den ESP32-WROOM32, eine Adapterplatine und SCT013-010 (10A/1V) Splitecore-Stromsensoren

Was soll das?

Wegen der fehlenden Messung der Phasenverschiebung wird die Scheinleistung und nicht die Wirkleistung gemessen. Da die Spannung nicht gemessen wird sondern deren Wert angenommen wird, ist die Messung noch ungenauer.

Grüße Uwe

Es gibt eine automatische Funktion um den Code eines kompletten Sketches zu posten
Nur drei Schritte in 30 Sekunden:

In der Arduino-IDE

  • 1.) Drücke Strg-T um den Code automatisch formatieren zu lassen
  • 2.) Mache einen Rechtsklick mit der Maus und wähle die Option Für Forum kopieren
  • 3.) Wechsle zum Posting und drücke Strg-V um den Inhalt der Zwischenablage einzufügen
    fertig

vgs

Das ist sehr "kompakt" gefragt.
Kompakte Antwort:

Du musst eine Verbindung zum WLAN aufbauen und dann deinen
ESP32 beim MQTT-broker "einhaken"

Jetzt biste schlauer. - Nö natürlich nicht -
google ist IMMER eine fünf Minutensuche Wert.

Als erstes Suchwort "arduino" dann die Worte die näher eingrenzen was du suchst in deinem Fall MQTT demo code
https://www.google.de/search?as_q=ardunio+MQTT+demo+code
Dann sich den Demo-Code anschauen und wenn du dann eine sehr konkrete Frage zum Demo-Code hast diese Frage posten. Darauf kommen dann recht schnell antworten.

Die Frage "Was muss ich ändern" ist die indirekte Frage
enttweder für
kann mal jemand (speziell für mich) ein Arduino-MQTT-Tutorial posten"

oder
"Kann mir jemand den kompletten Code posten"
beides wird nicht passieren. Konkrete Antworten auf konkrete Fragen gibt es immer

vgs

Hallo Uwe

du hast natürlich Recht. Würde erstmal die Scheinleistung messen und später noch die Spannung über ein Trafo, um die Wirkleistung zu messen.

Das mit dem delay habe ich nur so kopiert. Kann ich ja raus nehmen.

Hallo StefanL38,

hatte schon mal ein bisschen Probiert mit MQTT. Konnte aber nur Nachrichten senden und keine Werte, desswegen habe ich mich ja hierher gewannt.
Hatte bloß gelesen man muss die Werte als float umwandel verpacken und dann versenden, aber das hat irgendwie nicht so richtig funktioniert.

#include <WiFi.h>
#include <PubSubClient.h>
#include <stdio.h>
#include <Arduino.h>

const char* ssid = "meineSSID";
const char* password =  "meinPASSWORT";
const char* mqttBroker = "meinBROKER";
const int mqttPort = 1883;
const char* mqttUser = "USER";
const char* mqttPassword = "PW";

char payload[700];
char topic[150];

int inPinI1 = 34;
int inPinI2 = 35;
int inPinI3 = 39;

// Space to store values to send
char str_Irms1[6];
char str_Irms2[6];
char str_Irms3[6];
char str_PowerSum[6];

WiFiClient espClient;
PubSubClient client(espClient);

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.println("Attempting MQTT connection...");

    // Attempt to connect
    if (client.connect(mqttUser, mqttPassword, "")) {
      Serial.println("MQTT verbunden");
    } else {
      Serial.print("Fehler, rc=");
      Serial.print(client.state());
      Serial.println(" Wiederholung in 2 Sekunden");
      // Wait 2 seconds before retrying
      delay(2000);
    }
  }
}



void setup() {

  //setze Analogeingänge
  pinMode(inPinI1, INPUT);
  adcAttachPin(inPinI1);
  pinMode(inPinI2, INPUT);
  adcAttachPin(inPinI2);
  pinMode(inPinI3, INPUT);
  adcAttachPin(inPinI3);
  Serial.begin(115200);
  WiFi.begin(ssid, password);


  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("verbinde zu WLAN ..");
  }

  Serial.println("WLAN verbunden");

  client.setServer(mqttBroker, mqttPort);
  client.setCallback(callback);



  while (!client.connected()) {
    Serial.println("verbinde zu MQTT ...");

    if (client.connect("ESP32Client", mqttUser, mqttPassword )) {

      Serial.println("MQTT verbunden");

    } else {

      Serial.print("Fehlerstatus ");
      Serial.print(client.state());
      delay(2000);

    }
  }
  //client.publish("esp/test", "Hello from ESP32");
}

void loop() {
  if (!client.connected()) {
    reconnect();

    // Subscribes for getting the value of the control variable in the temperature-box device
    char topicToSubscribe[200];
    sprintf(topicToSubscribe, "%s", ""); // Cleans the content of the char
    sprintf(topicToSubscribe, "%s%s", "/v1.6/devices/", "temperature-box");
    sprintf(topicToSubscribe, "%s/%s/lv", topicToSubscribe, "control");
    client.subscribe(topicToSubscribe);
  }

  // Values to send
  float Irms1 = 66;
  float Irms2 = 77;
  float Irms3 = 88;
  float PowerSum = 99;

  /* 4 is mininum width, 2 is precision; float value is copied onto str_Irms1*/
  dtostrf(Irms1, 4, 2, str_Irms1);
  dtostrf(Irms2, 4, 2, str_Irms2);
  dtostrf(Irms3, 4, 2, str_Irms3);
  //dtostrf(PowerSum, 4, 2, str_PowerSum);

  sprintf(topic, "%s", ""); // Cleans the topic content
  sprintf(topic, "%s%s", "/v1.6/devices/", mqttBroker);

  sprintf(payload, "%s", ""); // Cleans the payload content
  sprintf(payload, "%s {\"value\": %s", payload, str_Irms1); // Adds the value
  sprintf(payload, "%s, \"value\":{\"Irms2\": %s, \"Irms3\": %s}", payload, str_Irms2, str_Irms3); // Adds coordinates



  //sprintf(payload, "%s {\"value\": %s", payload, str_Irms2); // Adds the value
  //sprintf(payload, "%s {\"value\": %s", payload, str_Irms3); // Adds the value
  //sprintf(payload, "%s {\"value\": %s", payload, str_PowerSum); // Adds the value
  sprintf(payload, "%s } }", payload); // Closes the dictionary brackets

  client.publish(topic, payload);
  client.loop();
  delay(1000);
}

https://www.google.de/search?as_q=ardunio+MQTT+demo+code

#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <WiFiClient.h>
#include <PubSubClient.h>

#define INT_PIN1 5     // Zuordnung der GPIOs
//#define INT_PIN2 4
//#define INT_PIN3 2
//#define INT_PIN4 13
//#define INT_PIN5 12
//#define INT_PIN6 14

unsigned long impulse[6], alteZeit[6], entprellZeit[6];

Ticker Timer;
WiFiClient net;
PubSubClient client(net);

// Zugangsdaten zum WLAN:
const char* ssid = "****";
const char* password = "*****";

// Zugangsdaten zum MQTT-Broker:
const char* mqtt_server = "192.168.***.***";
const int   mqtt_port = 1883;
const char* mqtt_user = "";
const char* mqtt_password = "";


void ICACHE_RAM_ATTR interruptRoutine1() {
  handleInterrupt(0);
}
//void ICACHE_RAM_ATTR interruptRoutine2() {
//handleInterrupt(1);
//}
//void ICACHE_RAM_ATTR interruptRoutine3() {
//handleInterrupt(2);
//}
//void ICACHE_RAM_ATTR interruptRoutine4() {
// handleInterrupt(3);
//}
//void ICACHE_RAM_ATTR interruptRoutine5() {
//handleInterrupt(4);
//}
//void ICACHE_RAM_ATTR interruptRoutine6() {
//handleInterrupt(5);
//}

void handleInterrupt(int i) {
  unsigned long timeInMillis = millis();
  if ((timeInMillis - alteZeit[i]) > entprellZeit[i] || timeInMillis < alteZeit[i]) {
    impulse[i]++;
    Serial.println("Impulse Zähler " + String(i) + ": " + String(impulse[i]));
    alteZeit[i] = timeInMillis;
  }
}


void sendMqttMessage() {
  Serial.println("Sende MQTT Nachrichten");
  for (int i = 0; i < 6; i++) {
    char buffer[10];
    sprintf(buffer, "%lu", impulse[i]);
    String topic = "/SmartHome/KG/HTR/Impulszaehler_" + String(i) + "/Impulse";
    client.publish(const_cast<char*>(topic.c_str()), buffer);
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Verbindungsaufbau zum MQTT-Broker...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
      Serial.println("connected");
      client.subscribe("/SmartHome/KG/HTR/Impulszaehler/*/Entprellzeit");
    } else {
      Serial.print("fehlgeschlagen, rc=");
      Serial.print(client.state());
      Serial.println(" erneut versuchen in 5 Sekunden");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  String sTopic = String(topic);

  for (int i = 0; i < 6; i++) {
    char buffer[10];
    String topic = "/SmartHome/KG/HTR/Impulszaehler_" + String(i) + "/Entprellzeit";
    if (sTopic == topic) {
      // Workaround to get int from payload
      payload[length] = '\0';
      Serial.println("Setze Entprellzeit für Zähler " + String(i) + " auf " + String((char*)payload));
      entprellZeit[i] = String((char*)payload).toInt();
    }
  }
}

void setup() {
  pinMode(INT_PIN1, INPUT_PULLUP);
  //pinMode(INT_PIN2, INPUT_PULLUP);
  //pinMode(INT_PIN3, INPUT_PULLUP);
  //pinMode(INT_PIN4, INPUT_PULLUP);
  //pinMode(INT_PIN5, INPUT_PULLUP);
  //pinMode(INT_PIN6, INPUT_PULLUP);

  Serial.begin(115200);
  Serial.println("");
  Serial.println("Start");
  Serial.println("");
  Serial.println("Warte auf Verbindung");

  WiFi.mode(WIFI_AP_STA);                             // station  modus verbinde mit dem Router
  WiFi.begin(ssid, password); // WLAN Login daten

  // Warte auf verbindung
  int timout = 0;
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print("O");
    timout++;
    if  (timout > 20) // Wenn Anmeldung nicht möglich
    {
      Serial.println("");
      Serial.println("Wlan verbindung fehlt");
      break;
    }
  }

  if (WiFi.status() == WL_CONNECTED)
  {
    Serial.println("");
    Serial.println("Mit Wlan verbunden");
    Serial.println("IP Adresse: ");
    Serial.println(WiFi.localIP());
  }

  for (int i = 0; i < 6; i++) {
    alteZeit[i] = 0;
    entprellZeit[i] = 1000;
  }

  client.setServer(mqtt_server, mqtt_port);


  Timer.attach(15, sendMqttMessage);    // Starte den 60s Timer

  // ---------------------- Starte Interrupts ---------------------------------------------
  attachInterrupt(INT_PIN1, interruptRoutine1, FALLING);
  //attachInterrupt(INT_PIN2, interruptRoutine2, FALLING);
  //attachInterrupt(INT_PIN3, interruptRoutine3, FALLING);
  //attachInterrupt(INT_PIN4, interruptRoutine4, FALLING);
  //attachInterrupt(INT_PIN5, interruptRoutine5, FALLING);
  //attachInterrupt(INT_PIN6, interruptRoutine6, FALLING);

  reconnect();

  client.setCallback(callback);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  //server.handleClient();
}

Ich habe das mal mit einem Readkontakt für den Gaszähler gebaut, man kann den beliebig erweitern für Wasserzähler, Stromzähler

Vielleicht hilt es Dir ja.

VG Thomas