#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "RTClib.h"
#include <EEPROM.h>
#include "ZMPT101B.h"
#include <SPI.h>
#include <LoRa.h>
#include <ArduinoJson.h>
#define ss 5
#define rst 25
#define dio0 33
#define EEPROM_SIZE 512
#define PinI 27
#define RelayPin 2
#define UpBtn 12
#define DownBtn 14
bool Screen = true,U=false,D=false,Send=false;
bool Log=false;
int LogTime;
int LastSave =0;
float I=0,V=0;
double P=0;
String Date,Time;
int indx=0, Logindx;
String PowerState;
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
RTC_DS1307 RTC;
DateTime now;
hw_timer_t *My_timer = NULL;
void IRAM_ATTR onTimer(){
Screen=!Screen;
}
void IRAM_ATTR Up() {
if(U){
U=false;
LogTime=millis();
if(!Log){
Logindx=indx-1;
Log=true;
display.clearDisplay();
}else{
if(Logindx==127){
Logindx=1;
}else{
if(Logindx!=indx-1){
Logindx++;
}
}
}
}
}
void IRAM_ATTR Down() {
if(D){
D=false;
LogTime=millis();
if(!Log){
Logindx=indx-1;
Log=true;
display.clearDisplay();
}else{
if(Logindx<0){
Logindx=127;
}else{
Logindx--;
}
}
Serial.println(Logindx);
}
}
void setup() {
Serial.begin(115200);
EEPROM.begin(EEPROM_SIZE);
pinMode(UpBtn, INPUT_PULLUP);
pinMode(DownBtn, INPUT_PULLUP);
pinMode(RelayPin, OUTPUT);
attachInterrupt(UpBtn, Up, FALLING);
attachInterrupt(DownBtn, Down, FALLING);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x64
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
indx=EEPROM.read(511);
SplashScreen();
if (!RTC.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
LoRa.setPins(ss, rst, dio0);
if (!LoRa.begin(433E6)) {
Serial.println("Starting LoRa failed!");
while (1);
}
delay(1000);
My_timer = timerBegin(0, 80, true);
timerAttachInterrupt(My_timer, &onTimer, true);
timerAlarmWrite(My_timer, 1000000, true);
timerAlarmEnable(My_timer);
}
void loop() {
I=getCurrent();
V=getVoltage();
P=P*I;
now = RTC.now();
Date=GetDate();
Time=GetTime();
if(!Log){
if(Screen){
SplashScreen1();
}else{
SplashScreen2();
}
}else{
LogScreen(Logindx);
}
U=true;
D=true;
if(millis()-LogTime>5000){
Log=false;
}
if(now.minute()%6==0){
if(Send){
for(int i=5;i>=0;i--){
int k=indx-i;
if(k<0){
k=128+k;
}
Serial.print(EEPROM.read(k*4));
Serial.print(":");
Serial.print(EEPROM.read(k*4+1));
Serial.print(" P=");
Serial.print((float)(EEPROM.read(k*4+2)*256+EEPROM.read(k*4+3))/1000);
Serial.println(" KWh");
}
Send=false;
}
}else{
Send=true;
}
if(P>5){
digitalWrite(RelayPin,LOW);
}
}
int getVoltage(){
// double VMax=0;
// for(int i=0;i<100;i++){
// int temp=analogRead(26);
// if(VMax<temp){
// VMax=temp;
// }
// delay(1);
// }
// double Scale1 = 2 / 4095;
// double Scale2 = 220.4 / 2;
// VMax = VMax * 220.4;
// double VeffD = VMax / sqrt(2);
// int v = (((VeffD - 420.76) * Scale1) * Scale2) + 210.2;
//Uncomment this part when sensor is connected
int v=map(analogRead(26),0,4096,150,260);
if(v<220){
PowerState="Voltage Low";
digitalWrite(RelayPin,LOW);
}else if(v>240){
PowerState ="Voltage High";
digitalWrite(RelayPin,LOW);
}else{
PowerState="Voltage Normal";
digitalWrite(RelayPin,HIGH);
}
return v;
}
float getCurrent(){
float result;
int readValue; // value read from the sensor
int maxValue = 0; // store max value here
int minValue = 4096; // store min value here ESP32 ADC resolution
int mVperAmp = 66;
uint32_t start_time = millis();
while((millis()-start_time) < 100){
readValue = analogRead(PinI);
if (readValue > maxValue){
maxValue = readValue;
}
if (readValue < minValue){
minValue = readValue;
}
}
result = ((maxValue - 2.5) * 3.3)/4096.0;
//result = ((maxValue - minValue) * 3.3)/4096.0;
float VRMS = (result/2.0) *0.707; //root 2 is 0.707
float AmpsRMS = ((VRMS * 1000)/mVperAmp); //0.3 is the error I got for my sensor
return AmpsRMS;
}
void SplashScreen(){
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(50, 4);
display.println("Smart");
display.setCursor(14, 20);
display.println("Electricity Meter");
display.setCursor(4, 36);
display.println("Made By");
display.setCursor(44, 52);
display.println("IntelliMeters");
display.display();
}
void SplashScreen1(){
display.clearDisplay();
display.setCursor(8, 4);
display.println(Date+" "+Time);
display.setCursor(4, 26);
display.println("V: "+ String(V,0)+" v I: "+String((float)I)+" A");
display.setCursor(4, 36);
display.println(" ");
display.setCursor(22, 48);
display.println(PowerState);
display.display();
}
void SplashScreen2(){
display.clearDisplay();
display.setCursor(8, 4);
display.println(Date+" "+Time);
display.setCursor(8, 26);
display.println("Power Consumption");
display.setCursor(32, 48);
display.println(String((float)I*V/1000)+" KWh");
//display.setCursor(28, 52);
//display.println(PowerState);
display.display();
}
void LogScreen(int i){
display.clearDisplay();
display.setCursor(24, 4);
display.println("Meter Log");
display.setCursor(8, 20);
display.println("Power Consumption");
display.setCursor(28, 36);
display.println(String((float)(EEPROM.read(i*4+2)*256+EEPROM.read(i*4+3))/1000)+" KWh");
display.setCursor(4, 52);
display.print("Time:");
if(EEPROM.read(i*4)<10){
display.print("0");
}
display.print(String(EEPROM.read(i*4)));
display.print(":");
if(EEPROM.read(i*4+1)<10){
display.print("0");
}
display.print(String(EEPROM.read(i*4+1)));
display.print(" Index:"+ String(i));
display.display();
}
String GetTime(){
String str="";
if (now.hour() < 10){
str+="0";
}
str+=String(now.hour())+":";
if (now.minute() < 10)
str+="0";
str+=String(now.minute());
if(abs(LastSave-now.minute())>1){
LastSave=now.minute();
P=V*I;
SaveLog(now.hour(),now.minute(),(int)P/256,(int)P%256);
SendData();
}
return str;
}
void SendData(){
StaticJsonDocument<200> doc;
doc["Time"] = String(now.hour())+":"+String(now.minute());
doc["Power"] = V*I;
String jsonString;
serializeJson(doc, jsonString);
LoRa.beginPacket();
LoRa.print(jsonString);
LoRa.endPacket();
}
String GetDate(){
String str="";
if (now.day() < 10){
str+="0";
}
str+=String(now.day())+"/";
if (now.month() < 10)
str+="0";
str+=String(now.month())+"/";;
if (now.year() < 10)
str+="0";
str+=String(now.year());
return str;
}
void SaveLog(int hr, int mn, int p1, int p2){
int i=indx;
i=i*4;
EEPROM.write(i,hr);
EEPROM.write(i+1,mn);
EEPROM.write(i+2,p1);
EEPROM.write(i+3,p2);
EEPROM.write(511,indx);
EEPROM.commit();
Serial.println("Save at " + String(i) + " "+String(hr)+":"+String(mn)+" P="+String((float)(p1*256+p2)/1000)+" KWh");
indx++;
if(indx>126){
indx=0;
}
}