#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <freeRTOS.h>
#define TIME_SERVER_API "http://worldtimeapi.org/api/timezone/Europe/Prague"
struct Task {
void (*taskFunction)();
unsigned long interval; // Interval between task executions in milliseconds
bool immediateStart; // Flag for immediate start
unsigned long nextExecution; // Time of last execution
bool run = false;
};
Task *tasks = NULL; // Define a pointer for tasks
int numTasks = 0; // Variable to keep track of the number of tasks added
LiquidCrystal_I2C lcd(0x27, 16, 2);
unsigned int uTime;
unsigned int timeDelay;
bool update = false;
String updateLink = "";
bool restart = false;
bool loadLog = false;
void restartBoard()
{
//Serial.println("turning board off");
ESP.restart();
}
void taskFunction()
{
Serial.println("wait");
}
void loadTime()
{
Serial.println("loading Time");
}
void loadSettings()
{
Serial.println("loading settings");
HTTPClient http;
http.begin("http://script.google.com/macros/s/AKfycbxWBMwXW1kBWtNlN-kGqeoTNL52ckDwrbCG9uWzyMwddqpzwoX2E29mQOHsJ3Pdqw/exec?route=settings");
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString();
DynamicJsonDocument doc(1024);
deserializeJson(doc, payload);
JsonArray root = doc.as<JsonArray>();
update = root[0];
updateLink = root[1].as<String>();
restart = root[2];
loadLog = root [3];
Serial.println(update);
Serial.println(updateLink);
Serial.println(restart);
Serial.println(loadLog);
} else {
Serial.println("Error when loading settings." + http.errorToString(httpCode));
}
http.end();
}
void connectToWiFi() {
WiFi.begin("Wokwi-GUEST", "",6);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
}
void updateTime()
{
Serial.println("fetchigTime");
HTTPClient http;
timeDelay = millis();
http.begin(TIME_SERVER_API);
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString();
DynamicJsonDocument doc(1024);
deserializeJson(doc, payload);
uTime = doc["unixtime"].as<unsigned int>(); // Store the formatted time
} else {
Serial.println("Error fetching time and date: " + http.errorToString(httpCode));
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Date: N/A");
lcd.setCursor(0, 1);
lcd.print("Time: N/A");
}
http.end();
}
void displayTime()
{
Serial.println("updatingTime");
// Calculate time components
unsigned int accDelay = millis() - timeDelay;
uTime = uTime + (accDelay/1000) + 3600;
unsigned long seconds = uTime % 60;
unsigned long minutes = (uTime / 60) % 60;
unsigned long hours = (uTime / 3600) % 24;
unsigned long days = uTime / 86400;
// Calculate year, month, and day
unsigned long year = 1970;
unsigned long daysInYear = 365;
while (days >= daysInYear) {
if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) {
if (days >= 366) {
days -= 366;
} else {
break;
}
} else {
days -= 365;
}
year++;
daysInYear = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 366 : 365;
}
unsigned long daysInMonth;
int month;
for (month = 1; month <= 12; ++month) {
daysInMonth = 31;
if (month == 4 || month == 6 || month == 9 || month == 11) {
daysInMonth = 30;
} else if (month == 2) {
daysInMonth = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 29 : 28;
}
if (days < daysInMonth) {
break;
}
days -= daysInMonth;
}
// Construct the date and time strings
String sseconds = String(seconds);
if(seconds < 10)
{
sseconds = "0" + sseconds;
}
String sminutes = String(minutes);
if(minutes < 10)
{
sminutes = "0" + sminutes;
}
String dateString = String(year) + "-" + String(month) + "-" + String(days + 1); // Adding 1 because day is 0-indexed
String timeString = String(hours) + ":" + sminutes + ":" + sseconds;
// Display the date and time on the LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(dateString);
lcd.setCursor(0, 1);
lcd.print(timeString);
}
void setup() {
lcd.init();
lcd.backlight();
Serial.begin(115200);
Serial.println("Setup done.");
connectToWiFi();
// Add tasks to the tasks array
//addTask(restartBoard, 5000, false); // Task 1 with interval of 0ms (infinite) and immediate start
addTask(taskFunction, 100, true, true); // Task 2 with interval of 1000ms (1 second) and immediate start
addTask(updateTime, 10000, false, true); // Task 3 with interval of 10000ms (10 seconds) and immediate start
addTask(displayTime, 1000,false, true);
addTask(restartBoard, 0, true, false);;
addTask(loadSettings, 5000, false, true);
}
void loop() {
scheduler(); // Execute the scheduler function in a loop
}
void scheduler() {
// Loop through the tasks
for (int i = 0; i < numTasks; i++) {
unsigned long currentTime = micros(); // Get the current time
tasks[i]; // Reference to the current task
if(tasks[i].run)
{
if(tasks[i].nextExecution <= currentTime){
unsigned long newNextExecution = currentTime + (tasks[i].interval * 1000);
tasks[i].nextExecution = newNextExecution;
tasks[i].taskFunction();
}
}
}
}
void addTask(void (*task)(), unsigned long interval, bool immediateStart,bool run) {
// Allocate memory for a new task
Task *newTasks = (Task *)realloc(tasks, (numTasks + 1) * sizeof(Task));
if (newTasks != NULL) {
tasks = newTasks;
tasks[numTasks].taskFunction = task;
tasks[numTasks].interval = interval;
tasks[numTasks].run = run;
tasks[numTasks].immediateStart = immediateStart;
tasks[numTasks].nextExecution = 0; // Initialize lastExecution to 0
numTasks++; // Increment the number of tasks
} else {
//Serial.println("Error: Memory allocation failed.");
}
initTask(numTasks - 1);
}
void initTask(int index)
{
if(tasks[index].immediateStart == true)
{
tasks[index].nextExecution = micros();
}
else{
tasks[index].nextExecution = micros() + (tasks[index].interval * 1000);
}
}