// This Example demonstrates the operation of an IoT device with artificial intelligence to control a passive water heater.
// The device is based on the principle of measuring the RMS value of the mains voltage,
// analyzing the data and deciding when to switch on the heater, for how long to run during the hours of least load on the mains.
// The device scheme includes a microcontroller of the ECP32 series, a module for measuring AC voltage from 0 to 250 volts,
// for example ZMPT101B module.
// The ZMPT101B module is combined with a simple AC/DC rectifier.
// In this case, it is not necessary to use a software algorithm for reading and averaging for RMS.
// The DC voltage value of the rectifier output is in linear dependent with input RMS and can be used easy.
// For input voltages other than sinusoidal, the correction factor must be calculated with a new calibration.
// Dont forget to include NTPClient from Library Manager
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Time stamp part
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
// Replace with your network credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
// Variables to save time
String formattedTime;
String timeStamp;
unsigned long TimeUpdPeriod = -10000; // За да сработи първия път
float HeaterOn = 0; // Време за работа на бойлера
int HeaterReady = 0;
// ENd OF Time stamp part
// RMS measurement part
int decimalPrecision = 2; // decimal places for all values shown in LED Display & Serial Monitor
int VoltageAnalogInputPin = 32; // Which pin to measure voltage Value
int HeaterContolPin = 33; // Pin to HeaterContol
float voltageSampleRead = 0; // to read the value of a sample in analog including
float voltageLastSample = 0; // to count time for each sample.
float voltageSampleSum = 0; // accumulation of sample readings
float voltageSampleCount = 0; // to count number of sample.
float RMSVoltageMean ; // analog value
float FinalRMSVoltage; // final voltage value
float AdjustRMScoeff = 12.4; // Conversion factor = Read level from GPIO/Iput voltage RMS
int VoltageTrigerLevel = 220; // Minimum voltage level to switch-On the heater.
// END of RMS measurement part
void setup() {
// Initialize Serial Monitor
Serial.begin(115200); // In order to see value in serial monitor
pinMode(VoltageAnalogInputPin, INPUT); // Define pins state
pinMode(HeaterContolPin, OUTPUT);
// Real time part connection to NTP server
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Initialize a NTPClient to get time
timeClient.begin();
// Set offset time in seconds to adjust for your timezone, for example:
// GMT +1 = 3600 GMT -1 = -3600 GMT 0 = 0
timeClient.setTimeOffset(10800); //Sofia +3 = +10800
}
void loop(){
if(millis() >= TimeUpdPeriod + 10000 ) { // every 10 second taking 1 reading of Time
if(!timeClient.update()) {
timeClient.forceUpdate();
}
// The formattedTime comes with the following format: 16:00:13 We need to extract the Hour
formattedTime = timeClient.getFormattedTime();
// Extract hour
int splitT = formattedTime.indexOf(":");
Serial.print("Time is: ");
Serial.print(formattedTime);
// Extract hour only
timeStamp = formattedTime.substring(0, splitT);
Serial.print(", Hour only is: ");
Serial.println(timeStamp);
TimeUpdPeriod = millis();
voltageLastSample = micros();
}
// Monitoring and turning on the water heater
if( timeStamp >= "13" || timeStamp <= "06" ) { // || - Logical "OR"
while (voltageSampleCount < 2000){ // Wait for 2000 samples
// while ((micros() <= voltageLastSample + 1000 ) ){ // Wait for samples for 1 millisec. (must be more than 1000)
// RMS mesurement part - get voltage of GPIO 32
if(micros() >= voltageLastSample + 1000 ) // every 1 milli second taking 1 reading
{
// voltageSampleRead = (analogRead(VoltageAnalogInputPin)/AdjustRMScoeff); //Wen we use real hardware
voltageSampleRead = (random(2700,2800)/AdjustRMScoeff); //We simulate an input between 218 and 226V for demo module
voltageSampleSum = voltageSampleSum + voltageSampleRead ; // accumulate total analog values for each sample readings
voltageSampleCount = voltageSampleCount + 1; // to move on to the next following count
voltageLastSample = micros() ; // to reset the time again so that next cycle can start again
}
}
RMSVoltageMean = voltageSampleSum/voltageSampleCount; // calculate average value of all sample readings taken
Serial.print(" The Voltage RMS value is: ");
Serial.print(RMSVoltageMean,decimalPrecision);
Serial.print(" V. Average from samples - ");
Serial.println(voltageSampleCount);
voltageSampleSum =0; // to reset accumulate sample values for the next cycle
voltageSampleCount=0; // to reset number of sample for the next cycle
// Switch Heater On or Off
if (( RMSVoltageMean > VoltageTrigerLevel || timeStamp >= "04" && timeStamp <= "06") && HeaterReady == 0 )
{
Serial.print(" Heater is On for 20 sec. Warm-up period *");
digitalWrite(HeaterContolPin, HIGH); // Start the heating
HeaterOn = millis();
while ( millis() <= HeaterOn + 20000 ) // 7200000 is 2 hours in milliseconds. 2 hours heating
{
delay(1000);
Serial.print("*");
}
Serial.println();
Serial.println(" Heater is ready. Now is Off.");
digitalWrite(HeaterContolPin, LOW); // Stop the heating
Serial.println();
HeaterReady = 1;
}
if ( HeaterReady == 1 )
{
Serial.println(" Waiting for the next power-on period / For the demo - 30 seconds");
Serial.println();
// while ( timeStamp <= "07" || timeStamp >= "22")
// {
delay(30000); // 30 seconds delay
// }
HeaterReady = 0;
}
} // End of check for 22.00-06.00 o'clock
}