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.
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.
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
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?
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).