ESP32 - take the average of receiving values

Hi,

situation:
I have a device at my house electricity meter which is sending the actual power consumption (watts) via mqtt to the mqtt broker. There are maybe one measuring every 3 seconds. Sometimes one measurement does not work and the gap between 2 measurements become a little bit bigger like 6 seconds.

These messages are received by a esp32. at the moment, I just display the momentary value at a display.
But I don't want to see the live value. I want to take the average of let's say one minute and display the average power consumption of the last minute at my display. (so the display will only change once a minute)

To achieve this, I have to count the number of received messages and I have to sum up them to make the calculation: sum of every received value divided through count of all messages I received in this minute.

Can anyone show me an example how to do that? It sound's pretty easy but I am not able to do it by myown. :frowning:
I don't know how to count the messages and I also don't know how to sum up all messages received in a certain amount of time.

please help :slight_smile:

Start by posting your current sketch using code tags when you do

Your post was MOVED to its current location as it is more suitable.

Could you also take a few moments to Learn How To Use The Forum.

This fellow has made a rolling average filter. You can use this library or you can look at his code and then write your own. moving average filter

Oh, I'd write the code just as you described it on your op.

1 Like

oh, that sounds interesting. I will try that and give feedback if it works or if I need some more help.

Hi,

now I tried the example of the moving average filter. THe example works well.
But in my code, it does not work at the moment. I do not know why. every loop, my float value "verbrauch" is changing but the fir output always is just 0.

#include <WiFi.h>
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include <PubSubClient.h>
#include <ArduinoFritzApi.h>
#include <MovingAverageFilter.h>

const char *ssid     = "ssid";
const char *password = "password";


const char* fritz_user     = "userxy";
const char* fritz_password = "password";
const char* fritz_ip       = "192.168.178.1"; // ip or fritz.local

const char* fritz_ain      = "116570483787";
/* 
 * The actor identification number (ain) can be fount in the fritzbox  
 * web interface or is found on a label on the device
 * 
 */
MovingAverageFilter movingAverageFilter(50);

FritzApi fritz(fritz_user, fritz_password, fritz_ip);

const char* mqtt_server = "192.168.178.44";

String temp = "";  //temporär
String zaehler = "0";
float input = 0;
float output = 0;
float einsparung = 0;
float solar = 0;
float verbrauchkorr = 0;
float verbrauch = 0;

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


void setup() {
  
  Serial.begin(9600);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

    reconnect();
 // Initialize Fritzbox stuff;
  try {
    fritz.init();
  } catch (int e) {
    Serial.println("Could not connect to fritzbox: " + String(e));
  }
  Serial.println("Fritz connected");
}


void setup_wifi() {

  delay(10);
 //wifi
  WiFi.begin(ssid, password);

  Serial.print("Connecting.");
  while ( WiFi.status() != WL_CONNECTED ) {
    delay(500);
    Serial.print(".");
    Serial.println("Connecting to WiFi..");
  }
  Serial.println("Connected to the WiFi network");
}

void callback(char* topic, byte* payload, unsigned int length) {
   String sTopic = String(topic);
        Serial.print("topic empfangen: ");
           Serial.println(String(topic));

 if (sTopic == "strom/smartmeter/sensor/1/obis/1-0:16.7.0/255/value"){

temp = "";

    for (int i = 0; i < length; i++) {
    temp += ((char)payload[i]);  }
    zaehler = temp;
    Serial.println(zaehler);    

  }

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
  //  uint32_t chipid=ESP.getChipId();
    char clientid[25];
   snprintf(clientid,25,"WIFI-Display-%08X","12345"); //this adds the mac address to the client for a unique id
    Serial.print("Client ID: ");
 //   Serial.println(clientid);
    if (client.connect(clientid)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      //client.publish("Say", "-t 'hello world'");
      // ... and resubscribe
      client.subscribe("strom/smartmeter/sensor/1/obis/1-0:16.7.0/255/value");

    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void loop() {

client.loop();

float solar = fritz.getSwitchPower(fritz_ain);
float verbrauch = zaehler.toFloat();

Serial.print("Zähleranzeige: ");
Serial.println(verbrauch);
Serial.print ("Solarertrag: ");
Serial.println (solar);

float verbrauchkorr = ((verbrauch)+(solar));
Serial.print("Zähleranzeige + Solar: ");
Serial.println(verbrauchkorr);

if ((verbrauch) <= 0) {
float einsparung = verbrauchkorr;
Serial.print("Einsparung: ");
Serial.println(einsparung);
}
else {
float einsparung = solar;
Serial.print("Einsparung: ");
Serial.println(einsparung);
}

  // declare input and output variables
  float input = einsparung; // without a real input, looking at the step respons (input at unity, 1)
//  float output = 0;

    Serial.println("Now calling fir...");
    output = movingAverageFilter.process(input); // here we call the fir routine with the input. The value 'fir' spits out is stored in the output variable.
    Serial.print("fir presented the following value= ");
    Serial.println(output); // just for debugging or to understand what it does, print the output value  
}  




topic empfangen: strom/smartmeter/sensor/1/obis/1-0:16.7.0/255/value
-193
Zähleranzeige: -193.00
Solarertrag: 465.17
Zähleranzeige + Solar: 272.17
Einsparung: 272.17
Now calling fir...
fir presented the following value= 0.00

float verbrauch = 0;
float verbrauch = zaehler.toFloat();

You have more than one variable named verbrauch in your code. One with global scope and one declared in loop() whose scope is limited to that function

How does the compiler know which one to use when doing the calculations ?

Remove the float type specifier where you use verbrauch in loop() so that the global version is always used

oh, thank you very much. now it seems to work onw, after i removed the "float" parts at every variable in the loop part. But it only works until 20 loops. although I have declared 50

MovingAverageFilter movingAverageFilter(50);

after 20 loops, the value did not change anymore. after 50 loops, it starts again adapting to another 20 loops.
does it only work with 20?

oh, i have found out that in the MovingAverageFilter.h file a maximum of 20 is defined. I try to raise the number in that file.

changing the MovingAverageFilter.h file to 50 is working now. But you can't change it up to 100. I tried 100 too but then it does not work anymore.

Thank you for your help and suggestions.

You might want to use a library that allows you to specify the length of the filter as a compile-time constant, e.g. Arduino Filters: SimpleMovingAverage.ino
For your use application, you could use

SMA<100, float, float> average {0};
...
output = average(input);

There are no limitations on the length of the filter (apart from the available memory, of course).