// Learn about the ESP32 WiFi simulation in
// https://docs.wokwi.com/guides/esp32-wifi
#include <WiFi.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
#include <HTTPClient.h>
#include <ArduinoJson.h>
LiquidCrystal_I2C LCD = LiquidCrystal_I2C(0x27, 20, 4);
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
#define NTP_SERVER "au.pool.ntp.org"
#define UTC_OFFSET 0
#define UTC_OFFSET_DST 0
#define interruptPin GPIO_NUM_12
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const int solenoids = 5;
const int motor = 18;
//const int interruptPin = 12;
String syncedTime;
String jsonOpenTime;
String jsonShutTime;
DateTime now;
const DateTime reSyncTime = DateTime(now.year(), now.month(), now.day(), 0, 0, 0);
DateTime shutTime;
DateTime openTime;
const String duskTimeApi = "https://api.sunrisesunset.io/json?lat=-35.06042984189702&lng=138.85387414368216&timezone=UTC&date=today";
//HW interrupt for when immediate entry is required
static void IRAM_ATTR gpio_isr_handler(void* arg) {
Serial.begin(115200);
LCD.init();
LCD.backlight();
LCD.setCursor(0, 0);
LCD.clear();
LCD.println("INTERRUPT: PLEASE RESET DEVICE TO CONTINUE");
//while(true)
//{
Serial.println("PLEASE RESET");
digitalWrite(solenoids, LOW);
digitalWrite(motor, LOW);
//}
}
//Wifi connect spinner
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 syncLocalTime() {
//uses UTP time server to sync time
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
LCD.setCursor(0, 1);
LCD.println("Connection Err");
}
String AMorPM;
if (timeinfo.tm_hour > 12) {
AMorPM = "PM";
} else {
AMorPM = "AM";
}
//adjusts dateTime so time is always synced up properly
rtc.adjust(DateTime(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec));
LCD.setCursor(0, 0);
LCD.clear();
}
void button_config()
{
gpio_install_isr_service(0);
printf("configuring button\n");
gpio_reset_pin(interruptPin);
gpio_set_direction(interruptPin, GPIO_MODE_INPUT);
gpio_pullup_en(interruptPin);
gpio_set_intr_type(interruptPin, GPIO_INTR_POSEDGE);
gpio_isr_handler_add(interruptPin, gpio_isr_handler, NULL);
printf("config complete\n");
}
void syncOpenShutTime() {
LCD.print("Fetching duskTime...");
LCD.setCursor(0, 1);
//connects to internet
HTTPClient http;
http.begin(duskTimeApi);
//connects to api website
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
//if everything goes right it'll proceed
LCD.print("HTTP ");
LCD.print(httpResponseCode);
String payload = http.getString();
Serial.println();
Serial.println(payload);
//converts json data into string
//if errors deserializing check if size is too low
DynamicJsonDocument doc(2048);
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
}
//first indicates object the times are inside of
JsonObject results = doc["results"];
//then sets variables as variable name
jsonShutTime = results["dusk"].as<String>();
Serial.println(jsonShutTime);
jsonOpenTime = results["sunrise"].as<String>();
Serial.println(jsonOpenTime);
shutTime = convertToDateTime(jsonShutTime.c_str(), now);
openTime = convertToDateTime(jsonOpenTime.c_str(), now);
LCD.clear();
}
else
{
LCD.print("Connection error!");
return;
}
}
DateTime convertToDateTime(const char* timeStr, DateTime now) {
/*
**************
****SYNTAX****
**************
strdup = duplicate string
strtok = sets token variable to everything before the semicolon
atoi = conversion from char to int
free = free up unused memory
*/
// Split the time string up into hours and minutes
char* timeCopy = strdup(timeStr);
char* token = strtok(timeCopy, " :");
Serial.println(timeCopy);
int hour = atoi(token);
token = strtok(NULL, " :");
int minute = atoi(token);
token = strtok(NULL, " :");
//important so it properly converts to 24 hour
char* ampmToken = strtok(NULL, " :");
// Trim leading and trailing spaces from ampmToken
char* trimmedAmpm = strtok(ampmToken, " ");
// Handle AM/PM
bool isPM = (strcasecmp(trimmedAmpm, "PM") == 0);
if (isPM && hour != 12) {
hour += 12;
} else if (!isPM && hour == 12) {
hour = 0;
}
DateTime timeConverted(now.year(), now.month(), now.day(), hour, minute, 0); // Assuming seconds are always 0
free(timeCopy);
return timeConverted;
}
void setup() {
Serial.begin(115200);
pinMode(solenoids, OUTPUT);
pinMode(motor, OUTPUT);
button_config();
LCD.init();
LCD.backlight();
LCD.setCursor(0, 0);
LCD.print("Connecting to ");
LCD.setCursor(0, 1);
LCD.print(ssid);
WiFi.begin(ssid, password, 6);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
spinner();
}
LCD.clear();
LCD.setCursor(0,0);
LCD.println("WiFi connected with IP:");
LCD.setCursor(0,1);
LCD.println(WiFi.localIP());
delay(250);
if (!rtc.begin()) {
LCD.println("Couldn't find RTC");
abort();
}
LCD.clear();
LCD.setCursor(0, 0);
LCD.println("Online");
LCD.setCursor(0, 1);
LCD.println("Updating time...");
LCD.setCursor(0, 0);
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
syncLocalTime();
syncOpenShutTime();
LCD.setCursor(0, 0);
LCD.clear();
}
void loop() {
now = rtc.now();
LCD.setCursor(0, 0);
if(now.hour() < 10){
LCD.print('0');
}
LCD.print(now.hour(), DEC);
LCD.print(':');
if(now.minute() < 10){
LCD.print('0');
}
LCD.print(now.minute(), DEC);
LCD.print(':');
if(now.second() < 10){
LCD.print('0');
}
LCD.print(now.second(), DEC);
/*
LCD.print(" ");
LCD.print(now.hour() % shutTime.hour(), DEC);
LCD.print(':');
LCD.print(now.minute() % shutTime.minute(), DEC);
*/
LCD.setCursor(0, 1);
LCD.print(shutTime.hour(), DEC);
LCD.print(':');
if(shutTime.minute() < 10){
LCD.print('0');
}
LCD.print(shutTime.minute(), DEC);
LCD.print(':');
LCD.print(shutTime.second(), DEC);
LCD.setCursor(0, 2);
LCD.print(openTime.hour(), DEC);
LCD.print(':');
LCD.print(openTime.minute(), DEC);
LCD.print(':');
LCD.print(openTime.second(), DEC);
if(now <= reSyncTime)
{
syncLocalTime();
syncOpenShutTime();
}
if(now <= shutTime)
{
digitalWrite(solenoids, HIGH);
}
if(now >= openTime)
{
digitalWrite(solenoids, LOW);
if(now==openTime){
syncLocalTime();
syncOpenShutTime();
}
}
}