// Learn about the ESP32 WiFi simulation in
// https://docs.wokwi.com/guides/esp32-wifi
#include <WiFi.h>
#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>
#include <SPI.h>
#include <TimeLib.h>
#include <OneButton.h>
/* Relay Config */
int Relay_1 = 16;
int Relay_2 = 17;
int Relay_3 = 25;
int Relay_4 = 26;
int Relay_5 = 27;
int Relay_6 = 32;
int Relay_7 = 33;
LiquidCrystal_I2C lcd(0x27, 20, 4);
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 25200
#define UTC_OFFSET_DST 0
#define OnSign "#"
#define OffSign "X"
// change this to match your SD shield or module;
// WeMos Micro SD Shield V1.0.0: D8
// LOLIN Micro SD Shield V1.2.0: D4 (Default)
const int chipSelect = 5; //D5
File dataFile;
RTC_DS1307 rtc;
/* Variable Setting */
const int ProgLimit = 30;
const int maxstep = 10;
DateTime WorkTime;
DateTime BegTime;
time_t begtimeu,curtimeu,difftimeu;
int curstep = 0;
int workmin = 9999;
int workmode = 0; // 0 = MMM:SS 1 = HHH:MM:SS
boolean Relay_1_status;
boolean Relay_2_status;
boolean Relay_3_status;
boolean Relay_4_status;
boolean Relay_5_status;
boolean Relay_6_status;
boolean Relay_7_status;
String Relay_1_name = "P1";
String Relay_2_name = "P2";
String Relay_3_name = "P3";
String Relay_4_name = "V1";
String Relay_5_name = "V2";
String Relay_6_name = "V3";
String Relay_7_name = "V4";
String Work_Code_Array[maxstep] = {
"", "P1t16c1", "P2t5", "P3t14c1", "V1t12", "V2t16c2", "P3t5:P2t5", "P1t16c1", "", "P3t5:V1t5:P2t2:P1t5:P3t5:P2t5:P1t10:P3t5:P2t5"
};
String work[maxstep][ProgLimit];
int i,j;
int cursec, curprog, runningprog = 0;
int CurProgress = 0;
#define BUTTON_PIN 34
/*
OneButton btn = OneButton(
BUTTON_PIN, // Input pin for the button
true, // Button is active LOW
true // Enable internal pull-up resistor
);
*/
OneButton btn(BUTTON_PIN, true);
// -------------- Declare end here -------------------------
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
InitWifi();
delay(1000);
InitRelay();
delay(1000);
//InitSD();
//delay(1000);
InitRTC();
delay(1000);
InitButton();
delay(1000);
lcd.clear();
Serial.println();
MakingTab();
CurProgress = 1;
}
void loop() {
btn.tick(); // check the status of the button
if (CurProgress == 1) // Wait for start
{
// Show wait for start
PrintClock();
lcd.setCursor(0, 2);
lcd.print(" PRESS BUTTON to .. ");
lcd.setCursor(0, 3);
lcd.print(" START ");
}
else if (CurProgress == 2) // start
{
// stamp start time
PrintClock();
printRTC();
}
else if (CurProgress == 3) // end
{
// show complete
Serial.println("Complete");
CurProgress = 1;
}
else if (CurProgress == 4) // emergency
{
// show emergency stop
Serial.println("emergency stop");
CurProgress = 1;
}
delay(5);
}
// ------------------------- user function start here ----------------
void InitWifi()
{
lcd.setCursor(0, 0);
lcd.print("Connecting to ");
lcd.setCursor(0, 1);
lcd.print("WiFi ");
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
spinner();
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
lcd.clear();
lcd.setCursor(0, 0);
lcd.println("Online");
lcd.setCursor(0, 1);
lcd.println("Updating time...");
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
}
void spinner() {
static int8_t counter = 0;
const char* glyphs = "\xa1\xa5\xdb";
lcd.setCursor(15, 1);
lcd.print(glyphs[counter++]);
if (counter == strlen(glyphs)) {
counter = 0;
}
}
void InitRelay()
{
Serial.println("\n --> Initial Relay");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Initial Relay ");
pinMode(Relay_1, OUTPUT);
pinMode(Relay_2, OUTPUT);
pinMode(Relay_3, OUTPUT);
pinMode(Relay_4, OUTPUT);
pinMode(Relay_5, OUTPUT);
pinMode(Relay_6, OUTPUT);
pinMode(Relay_7, OUTPUT);
delay(500);
Relay_1_status = LOW;
Relay_2_status = LOW;
Relay_3_status = LOW;
Relay_4_status = LOW;
Relay_5_status = LOW;
Relay_6_status = LOW;
Relay_7_status = LOW;
digitalWrite(Relay_1, Relay_1_status);
digitalWrite(Relay_2, Relay_2_status);
digitalWrite(Relay_3, Relay_3_status);
digitalWrite(Relay_4, Relay_4_status);
digitalWrite(Relay_5, Relay_5_status);
digitalWrite(Relay_6, Relay_6_status);
digitalWrite(Relay_7, Relay_7_status);
delay(500);
}
void InitSD()
{
Serial.println("\n --> Initializing MicroSD Card Module");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Initial MicroSD ");
// See if the card is present and can be initialized
//Serial.println("Initializing SD card --> ");
while(1)
{
if (SD.begin(chipSelect)) break;
Serial.println("Failed to initialize, or card not present. Trying again...");
lcd.setCursor(0, 2);
//lcd.print(" ");
lcd.print("Failed to initialize");
lcd.setCursor(0, 3);
//lcd.print(" ");
lcd.print(" Trying Again ");
delay(2000);
}
Serial.println("\n --> Initializing SD card --> Card Initialized.");
// เปิดไฟล์เพื่ออ่าน
//Read_Config_File("/config.txt");
}
void InitRTC()
{
lcd.setCursor(0, 0);
lcd.print(" Initial RTC ");
// SETUP RTC MODULE
if (! rtc.begin()) {
Serial.println("RTC module is NOT found");
Serial.flush();
lcd.setCursor(0, 2);
//lcd.print(" ");
lcd.print("Failed to initialize");
while (1);
}
// automatically sets the RTC to the date & time on PC this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// manually sets the RTC with an explicit date & time, for example to set
// January 21, 2021 at 3am you would call:
// rtc.adjust(DateTime(2021, 1, 21, 3, 0, 0));
}
void InitButton()
{
Serial.println("\n --> Initial Emergency Button");
pinMode(BUTTON_PIN, INPUT);
//btn.setPressMs(3000);
btn.setDebounceTicks(60);
btn.setClickTicks(800);
// Single Click event attachment
btn.attachClick(singleclick);
// Double Click event attachment
btn.attachDoubleClick(doubleclick);
// Long Click button event attachment
btn.attachLongPressStop(longclick);
}
void MakingTab()
{
//Serial.println("Clear work table....");
//ClearWork()
Serial.println("Making time table....");
for (i=0;i<maxstep;i++)
{
if (Work_Code_Array[i] != "")
{
Serial.println(Work_Code_Array[i]);
cursec = 0;
curprog = 0;
MakeTimeTab(Work_Code_Array[i],i);
}
}
/*
// display table
for (i=0;i<maxstep;i++)
{
if (work[i][0] != "")
{
for (j=0;j<ProgLimit;j++)
{
if (work[i][j] != "")
{
Serial.print(i);
Serial.println(work[i][j]);
}
}
}
}
*/
}
void ClearWork()
{
for (i=0;i<maxstep;i++)
Work_Code_Array[i] != "";
}
void PrintClock() {
DateTime now = ThaiTime(rtc.now());
lcd.setCursor(0, 0);
lcd.print(now.day());
lcd.print('/');
lcd.print(now.month());
lcd.print('/');
lcd.print(now.year()+543);
lcd.print(" ");
if (now.hour() < 10)
lcd.print('0');
lcd.print(now.hour());
lcd.print(':');
if (now.minute() < 10)
lcd.print('0');
lcd.print(now.minute());
lcd.print(':');
if (now.second() < 10)
lcd.print('0');
lcd.print(now.second());
}
void printRTC() {
DateTime now = ThaiTime(rtc.now());
String oneconwork,oneconcode;
curtimeu = now.unixtime();
difftimeu = curtimeu - begtimeu;
int dhour = difftimeu / (60*60);
int dminute = (difftimeu - (dhour*60*60)) / 60;
int dsecond = (difftimeu - (dhour*60*60)) - (dminute*60);
lcd.setCursor(0, 1);
if (dhour < 10)
lcd.print("00");
if ((dhour < 100) && (dhour > 9))
lcd.print('0');
lcd.print(dhour);
lcd.print(':');
if (dminute < 10)
lcd.print('0');
lcd.print(dminute);
lcd.print(':');
if (dsecond < 10)
lcd.print('0');
lcd.print(dsecond);
if (workmode == 0) // minute mode
{
oneconwork = work[dminute][runningprog];
oneconcode = Work_Code_Array[dminute];
}
else // hour mode
{
oneconwork = work[dhour][runningprog];
oneconcode = Work_Code_Array[dhour];
}
// check time table
//Serial.print(dispmin);
//Serial.print(" work[dispmin][runningprog] ");
//Serial.println(work[dispmin][runningprog]);
if (oneconwork != "")
{
lcd.setCursor(10, 1);
lcd.print(addtail(oneconcode.substring(0,9)));
int Length = oneconwork.length();
String Data_0 = oneconwork.substring(0,2);
String Data_1 = oneconwork.substring(3,Length);
int Time_0 = Data_1.toInt();
if (workmode == 0 && Time_0 == dsecond) // minute mode
{
firerelay(Data_0);
runningprog = runningprog+1;
}
else if(workmode == 1 && Time_0 == dminute) // hour mode
{
firerelay(Data_0);
runningprog = runningprog+1;
}
}
else
{
lcd.setCursor(10, 1);
lcd.print(" ");
runningprog = 0;
}
// check the last program of all work done
if (workmode == 0 && dminute >= maxstep && dsecond >= 0)
{
CurProgress = 3;
lcd.setCursor(0, 1);
lcd.print(" END ");
}
if (workmode == 1 && dhour >= maxstep && dminute >= 0)
{
CurProgress = 3;
lcd.setCursor(0, 1);
lcd.print(" END ");
}
}
void PrintWorkingTime(int datediff)
{
}
void firerelay(String channal)
{
if (channal == Relay_1_name)
{
Relay_1_status = !Relay_1_status;
digitalWrite(Relay_1,Relay_1_status);
lcd.setCursor(4, 2);
lcd.print(showstatus(Relay_1_status));
}
else if (channal == Relay_2_name)
{
Relay_2_status = !Relay_2_status;
digitalWrite(Relay_2,Relay_2_status);
lcd.setCursor(12, 2);
lcd.print(showstatus(Relay_2_status));
}
else if (channal == Relay_3_name)
{
Relay_3_status = !Relay_3_status;
digitalWrite(Relay_3,Relay_3_status);
lcd.setCursor(19, 2);
lcd.print(showstatus(Relay_3_status));
}
else if (channal == Relay_4_name)
{
Relay_4_status = !Relay_4_status;
digitalWrite(Relay_4,Relay_4_status);
lcd.setCursor(3, 3);
lcd.print(showstatus(Relay_4_status));
}
else if (channal == Relay_5_name)
{
Relay_5_status = !Relay_5_status;
digitalWrite(Relay_5,Relay_5_status);
lcd.setCursor(8, 3);
lcd.print(showstatus(Relay_5_status));
}
else if (channal == Relay_6_name)
{
Relay_6_status = !Relay_6_status;
digitalWrite(Relay_6,Relay_6_status);
lcd.setCursor(15, 3);
lcd.print(showstatus(Relay_6_status));
}
else if (channal == Relay_7_name)
{
Relay_7_status = !Relay_7_status;
digitalWrite(Relay_7,Relay_7_status);
lcd.setCursor(20, 3);
lcd.print(showstatus(Relay_7_status));
}
}
String showstatus(boolean stat)
{
if (stat)
return OnSign;
else
return OffSign;
}
String addtail(String ori)
{
//int Length = ori.length();
while (ori.length() < 9)
{
ori = ori+ " ";
}
return ori;
}
void MakeTimeTab(String workcode,int curfirst)
{
int i,j;
int index_0 = workcode.indexOf(':');
if (index_0 == -1) // it has only 1 program
{
int index_2 = workcode.indexOf('c');
if (index_2 == -1) // it has only on and off
{
int index_1 = workcode.indexOf('t');
int Length = workcode.length();
String Data_0 = workcode.substring(0, index_1);
String Data_1 = workcode.substring(index_1+1, Length);
int Time_0 = Data_1.toInt();
work[curfirst][curprog] = Data_0+":"+String(cursec);
curprog = curprog+1;
cursec = cursec+Time_0;
work[curfirst][curprog] = Data_0+":"+String(cursec);
}
else // it has toggle
{
//Serial.println("Toggle");
int index_1 = workcode.indexOf('t');
int index_2 = workcode.indexOf('c');
int Length = workcode.length();
String Data_0 = workcode.substring(0, index_1);
String Data_1 = workcode.substring(index_1+1, index_2);
String Data_2 = workcode.substring(index_2+1, Length);
int Time_0 = Data_1.toInt();
int Time_1 = Data_2.toInt();
int toggle = Time_0 / Time_1;
for (i=0;i<toggle;i++)
{
work[curfirst][curprog] = Data_0+":"+String(cursec+(Time_1*i));
curprog = curprog+1;
}
cursec = cursec+Time_0;
}
}
else // it has more than 1 program
{
int index_0 = workcode.indexOf(':');
String Part_0 = workcode.substring(0, index_0);
int Length = workcode.length();
String Part_1 = workcode.substring(index_0+1, Length);
MakeTimeTab(Part_0,curfirst); //first part
curprog=curprog+1;
cursec=cursec+1; // add gap between another ch.
MakeTimeTab(Part_1,curfirst); // rest part
}
}
void singleclick()
{
Serial.println("Clicked!");
if (CurProgress == 1)
{
CurProgress = 2;
ShowDefaultStatus();
BegTime = ThaiTime(rtc.now()); //---- Stamp Start DateTime
begtimeu = BegTime.unixtime();
Serial.print("begtimeu-");
Serial.print(day(begtimeu));
Serial.print('/');
Serial.print(month(begtimeu));
Serial.print('/');
Serial.print(year(begtimeu));
Serial.print(' ');
Serial.print(hour(begtimeu));
Serial.print(':');
Serial.print(minute(begtimeu));
Serial.print(':');
Serial.println(second(begtimeu));
}
}
void doubleclick()
{
Serial.println("Double Clicked!");
}
void longclick()
{
Serial.println("Long Clicked! inc ase emergency stop");
if (CurProgress == 2)
{
InitRelay();
CurProgress = 4;
lcd.setCursor(0, 1);
lcd.print(" ");
}
}
void multiClick1(){
Serial.println("multiClick1");
Serial.println(btn.getNumberClicks());
if(btn.getNumberClicks()==3){
Serial.println("multiClick1");
}
}
DateTime ThaiTime(DateTime now)
{
// calculate a date which is 0 days, 7 hours, 0 minutes, 0 seconds into the future
return (now + TimeSpan(0,7,0,0));
}
void ShowDefaultStatus()
{
// Show start status
lcd.clear();
lcd.setCursor(0, 2);
lcd.print("P1: X P2: X P3: X");
lcd.setCursor(0, 3);
lcd.print("V1:X V2:X V3:X V4:X");
}