Hi, I have a problem with spikes in my measurement. I am using ESP32 T-CALL TTGO (SIM800L) and EmonLib. I am using standart CT Sensor (YHDC SCT-013).
a screenshot to the measurement:
I am attaching my code also (It send the data via mqtt):
/*
* Project SM_Photon
* Description:
* Author:
* Date:16.09.2021
*/
// Please select the corresponding model
#define SIM800L_IP5306_VERSION_20190610
#define TINY_GSM_MODEM_SIM800
#include <ArduinoJson.h>
#include <Wire.h>
#include <TinyGsmClient.h>
#include "EmonLib.h"
#include <vector>
#include <sstream>
#include <locale>
#include <iomanip>
#include <map>
#include <string>
#include <cstdio>
#include <algorithm>
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
// Set serial for AT commands
#define SerialAT Serial1
#define TINY_GSM_DEBUG SerialMon
// Your GPRS credentials, if any
const char apn[] = "internet.vivacom.bg"; // APN (example: internet.vodafone.pt) use https://wiki.apnchanger.org
const char gprsUser[] = "";
const char gprsPass[] = "";
// SIM card PIN (leave empty, if not defined)
const char simPIN[] = "";
// set GSM PIN, if any
#define GSM_PIN ""
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
#include <PubSubClient.h>
TinyGsmClient client(modem);
PubSubClient mqtt(client);
// TTGO T-Call pins
#define MODEM_RST 5
#define MODEM_PWKEY 4
#define MODEM_POWER_ON 23
#define MODEM_TX 27
#define MODEM_RX 26
#define I2C_SDA 21
#define I2C_SCL 22
uint32_t lastReconnectAttempt = 0;
// I2C for SIM800 (to keep it running when powered from battery)
TwoWire I2CPower = TwoWire(0);
TwoWire I2CBME = TwoWire(1);
#define IP5306_ADDR 0x75
#define IP5306_REG_SYS_CTL0 0x00
bool setPowerBoostKeepOn(int en){
I2CPower.beginTransmission(IP5306_ADDR);
I2CPower.write(IP5306_REG_SYS_CTL0);
if (en) {
I2CPower.write(0x37); // Set bit1: 1 enable 0 disable boost keep on
} else {
I2CPower.write(0x35); // 0x37 is default reg value
}
return I2CPower.endTransmission() == 0;
}
// MQTT details
const char* broker = "159.89.103.242"; // Public IP address or domain name
const char* mqttUsername = "REPLACE_WITH_YOUR_MQTT_USER"; // MQTT username
const char* mqttPassword = "REPLACE_WITH_YOUR_MQTT_PASS"; // MQTT password
char auth[] = "ag1p2OnHsvHusY3-ZsOYAjuOgTsMXyxS";
// variable for storing the potentiometer value
int potValue = 0;
int ver = 3;
EnergyMonitor emon1;
EnergyMonitor emon2;
EnergyMonitor emon3;
float blynkPublish;
float accumulatePow;
int nextPeriod;
float average;
long interval = 2000;
long previousMillis = 0;
float hourBegining;
float hourConsumption;
float dayBegining;
float dayConsumption;
float monthBegining;
float monthConsumption;
float currPriceH;
float currPriceD;
float currPriceM;
float currPrice;
long currentMillisSend = 0;
long previousMillisSend = 0;
long intervalSend = 5000;
long intervalSendBlynk = 60000;
long previousMillisSendBlynk = 0;
int reportFreq;
int currMin;
int currHour;
int currDay;
int currMonth;
int blynkGridButton;
int16_t currYear;
int16_t prevYear;
uint8_t prevMin;
uint8_t prevDay;
uint8_t prevHour;
uint8_t prevMonth;
#define NUMSAMPLES 5
float tenSec[NUMSAMPLES];
float sixty[60];
float fifteen[15];
float avTenSec = 0;
std::map<String, float>powerMap;
int trigger = 0;
char data[80];
double Irms1;
double Irms2;
double Irms3;
int j;
String stampRecieved;
StaticJsonDocument<200>parser;
const char* deviceID = "sm-0002";
const char* authStr = "/auth";
String blynkAuth = String(deviceID)+String(authStr);
const char* blynkAuthChar = blynkAuth.c_str();
const char* timestampStr = "/timestamp";
String timestampReceived = String(deviceID)+String(timestampStr);
const char* timestampRe = timestampReceived.c_str();
const char* initChr = "init/";
String initStr = String(initChr)+String(deviceID);
const char* initial = initStr.c_str();
const char* dashCh = "dash/";
const char* currP = "/currpower/currpower";
String pingDev = String(dashCh)+String(deviceID)+String(currP);
const char* ping = pingDev.c_str();
const char* dataChar = "data/";
const char* fifteenToChar = "/fifteen";
String dataSend = String(dataChar)+String(deviceID)+String(fifteenToChar);
const char* sendFifteen = dataSend.c_str();
const char* er = "error/check/";
String error = String(er)+String(deviceID);
const char* errorSendDash = error.c_str();
const char* blh = "blynkHourConsumption/";
String blynkh = String(blh)+String(deviceID);
const char* blynkHourCons = blynkh.c_str();
const char* bld = "blynkDayConsumption/";
String blynkd = String(bld)+String(deviceID);
const char* blynkDayCons = blynkd.c_str();
const char* blM = "blynkMonthConsumption/";
String blynkm = String(blM)+String(deviceID);
const char* blynkMonthCons = blynkm.c_str();
const char* blPh = "blynkHourPrice/";
String blynkPh = String(blPh)+String(deviceID);
const char* blynkPriceHour = blynkPh.c_str();
const char* blPd = "blynkDayPrice/";
String blynkPd = String(blPd)+String(deviceID);
const char* blynkPriceDay = blynkPd.c_str();
const char* blPm = "blynkMonthPrice/";
String blynkPm = String(blPm)+String(deviceID);
const char* blynkPriceMonth = blynkPm.c_str();
const char* blynkPrice = "blynkPrice/";
String blynkP = String(blynkPrice)+String(deviceID);
const char* blynkCurrPrice = blynkP.c_str();
const char* powtoBl = "blynkPower/";
String blynkPow = String(powtoBl)+String(deviceID);
const char* currPowerToBlynk = blynkPow.c_str();
String authToken;
String subscribeTopic = "meter/ibexIn";
//BlynkTimer timer;
// recieve message
void mqttCallback(char* topic, byte* message, unsigned int len) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String p = "";
for (int i=0;i<len;i++)
{
p += (char)message[i];
}
Serial.println();
if (String(topic) == subscribeTopic)
{
currPrice = p.toFloat();
Serial.println(currPrice);
}
//test topic
if (String(topic) == "RED")
{
mqtt.publish("size_plusOnemin", "ECHO ECHO");
}
if (String(topic) == String(deviceID)+"/timestamp")
{
stampRecieved = String(p);
DeserializationError error = deserializeJson(parser, stampRecieved);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
String strValue = parser["time"];;
float powValue = parser["pow"];
mqtt.publish("parserPow", (char*) strValue.c_str());
std::map<String,float>::iterator it;
it = powerMap.find(strValue);
if (it != powerMap.end())
{
powerMap.erase (it);
trigger = 1;
}
else {
//Particle.publish("empty","empty");
}
}
}
boolean mqttConnect() {
SerialMon.print("Connecting to ");
SerialMon.print(broker);
// Connect to MQTT Broker without username and password
//boolean status = mqtt.connect("GsmClientN");
// Or, if you want to authenticate MQTT:
boolean status = mqtt.connect(deviceID);
if (status == false) {
SerialMon.println(" fail");
ESP.restart();
return false;
}
SerialMon.println(" success");
mqtt.subscribe("meter/ibexIn");
mqtt.subscribe(blynkAuthChar);
mqtt.subscribe(timestampRe);
mqtt.subscribe("RED");
mqtt.publish(initial,deviceID);
return mqtt.connected();
}
void setup() {
SerialMon.begin(115200);
delay(10);
// Keep power when running from battery
bool isOk = setPowerBoostKeepOn(1);
SerialMon.println(String("IP5306 KeepOn ") + (isOk ? "OK" : "FAIL"));
// Set modem reset, enable, power pins
pinMode(MODEM_PWKEY, OUTPUT);
pinMode(MODEM_RST, OUTPUT);
pinMode(MODEM_POWER_ON, OUTPUT);
digitalWrite(MODEM_PWKEY, LOW);
digitalWrite(MODEM_RST, HIGH);
digitalWrite(MODEM_POWER_ON, HIGH);
SerialMon.println("Wait...");
// Set GSM module baud rate and UART pins
SerialAT.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
delay(6000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println("Initializing modem...");
modem.restart();
// modem.init();
String modemInfo = modem.getModemInfo();
SerialMon.print("Modem Info: ");
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN if needed
if ( GSM_PIN && modem.getSimStatus() != 3 ) {
modem.simUnlock(GSM_PIN);
}
SerialMon.print("Connecting to APN: ");
SerialMon.print(apn);
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
SerialMon.println(" fail");
ESP.restart();
}
else {
SerialMon.println(" OK");
}
if (modem.isGprsConnected()) {
SerialMon.println("GPRS connected");
}
// MQTT Broker setup
mqtt.setServer(broker, 1883);
mqtt.setCallback(mqttCallback);
emon1.current(33, 90.9); //22 ohm 90.9
emon2.current(32, 90.9);
emon3.current(34, 90.9);
analogReadResolution(ADC_BITS);
if (!mqtt.connected()) {
SerialMon.println("=== MQTT NOT CONNECTED ===");
// Reconnect every 10 seconds
uint32_t t = millis();
if (t - lastReconnectAttempt > 10000L) {
lastReconnectAttempt = t;
if (mqttConnect()) {
lastReconnectAttempt = 0;
}
}
delay(100);
return;
}
timeConvert();
// currHour = Time.hour(Time.now());
// currDay = Time.day(Time.now());
// currMonth = Time.month(Time.now());
prevHour = currHour;
prevDay = currDay;
prevMonth = currMonth;
powerMap.clear();
}
void blynkUpdate()
{
char blynkPub[8];
dtostrf(blynkPublish, 1, 2, blynkPub);
mqtt.publish(ping,blynkPub);
//Serial.println(blynkPublish);
}
void measure()
{
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval)
{
Irms1 = emon1.calcIrms(1480);
Irms2 = emon2.calcIrms(1480);
Irms3 = emon3.calcIrms(1480);
double Irms = Irms1 + Irms2 + Irms3;
double power = Irms*230;
tenSec[j] = power;
j++;
if (j > 4)
{
for (int k=0; k < 5; k++)
{
//if (client.isConnected())
average += tenSec[k];
}
average /= 5;
//avTenSec = average/360; //Wh
blynkPublish = average/1000; //kW
//accumulatePow = accumulatePow + avTenSec;
average = 0;
j = 0;
}
previousMillis = currentMillis;
}
}
void timeConvert (){
String time = modem.getGSMDateTime(DATE_FULL);
int splitT = time.indexOf(",");
int splitY = time.indexOf("/");
String timeStamp = time.substring(splitT+1, time.length());
String timeStampY = time.substring(splitY, 0);
currYear = timeStampY.toInt();
String currHourStr = timeStamp.substring(0,2);
currHour = currHourStr.toInt();
int splitM = timeStamp.indexOf(":");
String timeStampM = timeStamp.substring(splitM+1, timeStamp.length());
String currMinString = timeStampM.substring(0,2);
currMin = currMinString.toInt();
String timeStampMonth = time.substring(splitY+1, time.length());
String currMonthString = timeStampMonth.substring(0,2);
currMonth = currMonthString.toInt();
int splitDay = timeStampMonth.indexOf("/");
String timeStampDay = timeStampMonth.substring(splitDay+1, timeStampMonth.length());
String currDayString = timeStampDay.substring(0,2);
currDay = currDayString.toInt();
//delay(2000);
}
String test(struct tm t)
{
t = {0};
t.tm_year = (currYear+2000) - 1900;
t.tm_mon = currMonth - 1;
t.tm_mday = currDay;
t.tm_hour = currHour;
t.tm_min = currMin;
t.tm_sec = 00;
time_t timeSinceEpoch = mktime(&t);
int test = int(timeSinceEpoch);
String timestamp = String(test);
return timestamp;
}
struct timestampPower {
void myFunc()
{
for (std::map<String, float>::iterator it = powerMap.begin(); it != powerMap.end(); ++it)
{
String timeSt = "\"timestamp\": " + String((*it).first);
String powerSt = "\"power\": " + String((*it).second);
String jObj = timeSt +','+ powerSt;
String payload = "{ \"payload\": {" + jObj + "}}";
payload.toCharArray(data, (payload.length() + 1));
mqtt.publish(sendFifteen, data);
}
}
void checkDb(){
if(!powerMap.empty())
{
String mapKey = (--powerMap.end())->first;
float mapValue = (--powerMap.end())->second;
String timeSt = "\"timestamp\": " + mapKey;
String powerSt = "\"power\": " + String(mapValue);
String jObj = timeSt +','+ powerSt;
String payload = "{ \"payload\": {" + jObj + "}}";
payload.toCharArray(data, (payload.length() + 1));
mqtt.publish(errorSendDash, data);
}
}
}tp;
void loop() {
timeConvert();
if (!mqtt.connected()) {
SerialMon.println("=== MQTT NOT CONNECTED ===");
// Reconnect every 10 seconds
uint32_t t = millis();
if (t - lastReconnectAttempt > 10000L) {
lastReconnectAttempt = t;
if (mqttConnect()) {
lastReconnectAttempt = 0;
}
}
delay(100);
return;
}
unsigned long currentMillisSend = millis();
if(currentMillisSend - previousMillisSend > intervalSend)
{
if (trigger == 1 && powerMap.size() > 0)
{
tp.checkDb();
trigger = 0;
}
previousMillisSend = currentMillisSend;
}
measure();
if(currentMillisSend - previousMillisSendBlynk > intervalSendBlynk)
{
// Serial.print(currYear);
// Serial.print(currMonth);
// Serial.print(currDay);
// Serial.print(currHour);
Serial.print(currMin);
blynkUpdate();
previousMillisSendBlynk = currentMillisSend;
}
if (currMin != prevMin)
{
accumulatePow = accumulatePow + blynkPublish;
hourConsumption = (accumulatePow - hourBegining)/60;
Serial.print(currMin);
char hourConsumptionBlynk[8];
dtostrf(hourConsumption, 1, 2, hourConsumptionBlynk);
mqtt.publish(blynkHourCons, hourConsumptionBlynk);
dayConsumption = (accumulatePow - dayBegining )/60;
char dayConsumptionBlynk[8];
dtostrf(dayConsumption, 1, 2, dayConsumptionBlynk);
mqtt.publish(blynkDayCons, dayConsumptionBlynk);
monthConsumption = (accumulatePow - monthBegining)/60;
char monthConsumptionBlynk[8];
dtostrf(monthConsumption, 1, 2, monthConsumptionBlynk);
mqtt.publish(blynkMonthCons, monthConsumptionBlynk);
currPriceH = (hourConsumption*currPrice)/1000;
char hourPriceBlynk[8];
dtostrf(currPriceH, 1, 2, hourPriceBlynk);
mqtt.publish(blynkPriceHour, hourPriceBlynk);
currPriceD = (dayConsumption*currPrice)/1000;
char dayPriceBlynk[8];
dtostrf(currPriceD, 1, 2, dayPriceBlynk);
mqtt.publish(blynkPriceDay, dayPriceBlynk);
currPriceM = (monthConsumption*currPrice)/1000;
char monthPriceBlynk[8];
dtostrf(currPriceM, 1, 2, monthPriceBlynk);
mqtt.publish(blynkPriceMonth, monthPriceBlynk);
char currentBlynkPrice[8];
dtostrf(currPrice, 1, 2, currentBlynkPrice);
mqtt.publish(blynkCurrPrice, currentBlynkPrice);
char powerToBlynk[8];
dtostrf(blynkPublish, 1, 2, powerToBlynk);
mqtt.publish(currPowerToBlynk, powerToBlynk);
if (currMin == 0)
{
sixty[59] = blynkPublish;
}
else
{
sixty[currMin-1] = blynkPublish;
}
if (currMin % 3 == 0 && currMin != 0)
{
float averageM = 0;
nextPeriod = currMin + 1;
int countValues = 0;
for (int l = currMin - 3; l < currMin; l++)
{
if (sixty[l] != 0)
{
countValues++;
}
averageM += sixty[l];
}
averageM /= countValues;
struct tm t0;
String timestamp = test(t0);
if (!isnan(averageM) && !isinf(averageM))
{
powerMap.insert(std::pair<String, float>(timestamp,averageM));
tp.myFunc();
}
}
else if (currMin == 0)
{
float averageM = 0;
int countValues = 0;
for (int l = 57; l < 60; l++)
{
if (sixty[l] != 0)
{
countValues++;
}
averageM += sixty[l];
}
averageM /= countValues;
struct tm t0;
String timestamp = test(t0);
if (!isnan(averageM) && !isinf(averageM))
{
powerMap.insert(std::pair<String, float>(timestamp,averageM));
tp.myFunc();
}
}
if (currMin == nextPeriod)
{
int err_size = powerMap.size();
String err_string = String(err_size);
mqtt.publish("boron", (char*) err_string.c_str());
if (err_size > 100)
{
powerMap.clear();
}
tp.checkDb();
trigger = 1;
}
prevMin = currMin;
}
if (currHour != prevHour)
{
// mqtt.publish("meter/trigger", "ibexTrigg");
hourBegining = accumulatePow;
currPriceH = 0;
prevHour = currHour;
}
if (prevDay != currDay)
{
dayBegining = accumulatePow;
currPriceD = 0;
prevDay = currDay;
}
if (prevMonth != currMonth)
{
monthBegining = accumulatePow;
currPriceM = 0;
prevMonth = currMonth;
}
mqtt.loop();
}