//MULTICORE TESTING
#include <WiFi.h>
#include <Wire.h>
#include "RTClib.h"
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <Preferences.h>
#include <LiquidCrystal_I2C.h>
#define upDown 19
#define lockPin 18
#define triggerUp 5
#define triggerDown 25
LiquidCrystal_I2C LCD = LiquidCrystal_I2C(0x27, 20, 4);
Preferences pref;
bool wifiConnected = false;
String wifiPassword;
String wifiUsername; // Username for WPA2-Enterprise
String wifiIdentity; // Identity for WPA2-Enterprise
String wifiSSID;
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 0
#define UTC_OFFSET_DST 0
DateTime now;
DateTime shutTime;
DateTime openTime;
DateTime lastResync;
int timeSinceLastResync;
String syncedTime;
String jsonOpenTime;
String jsonShutTime;
SemaphoreHandle_t baton;
const String duskTimeApi = "https://api.sunrisesunset.io/json?lat=-35.06042984189702&lng=138.85387414368216&timezone=UTC&date=today";
TaskHandle_t TaskHandle_0;
TaskHandle_t Task2;
int btnState;
int btnState2;
enum doorstate
{
OPEN,
CLOSED,
CALIBRATING,
BROKEN,
UP,
DOWN,
};
doorstate dstate;
byte chicken[] = {
B00000,
B00000,
B00110,
B00111,
B01100,
B11100,
B01000,
B01000
};
byte open1[] = {
B00000,
B00000,
B00000,
B00000,
B00001,
B00010,
B00100,
B01000
};
byte open2[] = {
B00000,
B00000,
B00000,
B00000,
B11111,
B00000,
B00000,
B00000
};
byte open3[] = {
B10000,
B01000,
B00100,
B00010,
B00001,
B00000,
B00000,
B00000
};
byte open4[] = {
B00001,
B00001,
B00001,
B00001,
B00001,
B00000,
B00000,
B00000
};
uint8_t dot[] = {
B00000,
B00100,
B01110,
B11111,
B11111,
B10001,
B10001,
B11111
};
void setup()
{
LCD.init();
LCD.backlight();
LCD.setCursor(0, 0);
Serial.begin(115200);
pinMode(triggerUp, INPUT_PULLUP);
pinMode(triggerDown, INPUT_PULLUP);
pinMode(upDown, OUTPUT);
pinMode(lockPin, OUTPUT);
pref.begin("savedWifiCredentials", false);
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
abort();
}
xTaskCreate(
dostuff, // Function to implement the task
"otherThings", // Name of the task
10000, // Stack size in words
NULL, // Task input parameter
1, // Priority of the task
&TaskHandle_0 // Task handle.
);
xTaskCreate(
startUp, /* Function to implement the task */
"Connect To Internet", /* Name of the task */
10000, /* Stack size in words */
NULL, /* Task input parameter */
2, /* Priority of the task */
&TaskHandle_0 /* Task handle. */
);
}
void openingAnimation()
{
LCD.createChar(1, chicken);
LCD.createChar(2, dot);
LCD.setCursor(2, 0);
LCD.print("Door opening");
LCD.setCursor(1, 1);
LCD.print("Rise and shine!");
for (int i = 3; i < 16; i++) {
LCD.setCursor(i, 3);
LCD.print("\1");
for (int j = i + 1; j < 16; j++) {
LCD.setCursor(j, 3);
LCD.print("\2");
}
delay(200);
LCD.setCursor(i, 3);
LCD.print(" ");
}
for (int i = 3; i < 16; i++)
{
LCD.setCursor(i, 3);
LCD.print("\2");
delay(50);
}
delay(1000);
}
void closingAnimation()
{
LCD.createChar(1, open1);
LCD.createChar(2, open2);
LCD.createChar(3, open3);
LCD.createChar(4, open4);
LCD.setCursor(2, 0);
LCD.print("Door closing");
LCD.setCursor(1, 1);
LCD.print("Mind your feathers!");
LCD.setCursor(0, 2);
printLine("\1");
delay(1000);
printLine("\2");
delay(1000);
printLine("\3");
delay(1000);
printLine("\4");
delay(1000);
}
void printLine(String txt)
{
for(int i=0; i!=20; i++)
{
LCD.setCursor(i, 2);
LCD.print(txt);
LCD.setCursor(i, 3);
LCD.print(txt);
}
}
void dostuff(void * pvParameters)
{
Serial.print("time: ");
Serial.println(xPortGetCoreID());
while(true){
if(now.hour() >= shutTime.hour() && now.minute() >= shutTime.minute())
{
dstate = CLOSED;
}
else if(now.hour() >= openTime.hour() && now.minute() >= openTime.minute())
{
dstate = OPEN;
}
timeSinceLastResync = now.minute() - lastResync.minute();
//Serial.println(timeSinceLastResync);
if(timeSinceLastResync == 2)
{
resyncClocks();
dstate = CALIBRATING;
}
/*
Serial.print("Now valid ");
Serial.println(now.isValid());
Serial.print("shuttime valid ");
Serial.println(shutTime.isValid());
Serial.print("hours match ");
Serial.println(now.hour() >= shutTime.hour());
Serial.print("Minutes match ");
Serial.println( now.minute() >= shutTime.minute());
Serial.println(shutTime.minute());
Serial.println(now.minute());
*/
delay(500);
}
}
void syncOpenShutTime() {
if (WiFi.status() == WL_CONNECTED) {
Serial.print("Fetching duskTime...");
//connects to internet
WiFiClientSecure client;
client.setInsecure();
HTTPClient http;
http.begin(client, duskTimeApi);
//connects to api website
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
//if everything goes right it'll proceed
Serial.print("HTTP ");
Serial.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());
ESP.restart();
}
//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);
}
else
{
Serial.println("FATAL ERR OCCURRED");
switch(httpResponseCode)
{
case 400:
Serial.println("Bad request");
break;
case 401:
Serial.println("Unauthorized");
break;
}
}
} else {
Serial.print("Connection error!");
Serial.println("Attempting to reconnect...");
}
if(now.hour() < openTime.hour() && now.minute() < openTime.minute())
{
dstate = OPEN;
}
}
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 connectToInternet()
{
if(pref.isKey("ssid") == true)
{
Serial.println("saved SSID found!");
wifiSSID = pref.getString("ssid");
Serial.println(wifiSSID);
}
if(pref.isKey("password") == true)
{
Serial.println("saved Password found!");
wifiPassword = pref.getString("password");
}
else
{
Serial.println("Details not found...");
scanNetworks();
}
}
void resyncClocks()
{
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
//uses UTP time server to sync time
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Connection Err");
abort();
}
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));
lastResync = rtc.now();
}
void startUp(void * pvParameters)
{
Serial.println("connecting to internet:");
connectToInternet();
Serial.println("Done!");
Serial.println("Updating time...");
resyncClocks();
Serial.println("Done!");
syncOpenShutTime();
vTaskDelete(NULL);
}
void scanNetworks() {
Serial.println("Scanning for WiFi networks...");
int networkCount = WiFi.scanNetworks();
Serial.println("Scan done!");
if (networkCount == 0) {
Serial.println("No networks found.");
return;
}
Serial.print(networkCount);
Serial.println(" networks found:");
for (int i = 0; i < networkCount; ++i) {
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(") ");
switch (WiFi.encryptionType(i)) {
case WIFI_AUTH_OPEN: Serial.print("open"); break;
case WIFI_AUTH_WEP: Serial.print("WEP"); break;
case WIFI_AUTH_WPA_PSK: Serial.print("WPA"); break;
case WIFI_AUTH_WPA2_PSK: Serial.print("WPA2"); break;
case WIFI_AUTH_WPA_WPA2_PSK: Serial.print("WPA+WPA2"); break;
case WIFI_AUTH_WPA2_ENTERPRISE: Serial.print("WPA2-EAP"); break;
case WIFI_AUTH_WPA3_PSK: Serial.print("WPA3"); break;
case WIFI_AUTH_WPA2_WPA3_PSK: Serial.print("WPA2+WPA3"); break;
case WIFI_AUTH_WAPI_PSK: Serial.print("WAPI"); break;
default: Serial.print("unknown");
}
Serial.println();
delay(10);
}
selectNetwork(networkCount);
}
void selectNetwork(int networkCount) {
Serial.println("Enter the number of the network you want to connect to:");
while (true) {
if (Serial.available() > 0) {
int networkIndex = Serial.parseInt();
if (networkIndex > 0 && networkIndex <= networkCount) {
wifiSSID = WiFi.SSID(networkIndex - 1);
Serial.print("Selected network: ");
Serial.println(wifiSSID);
Serial.println("Enter the password:");
while (Serial.available()) { Serial.read(); }
while (!Serial.available());
wifiPassword = Serial.readStringUntil('\n');
Serial.print("Connecting to ");
Serial.println(wifiSSID);
connectToNetwork(wifiSSID, wifiPassword);
}
break;
}
}
}
void connectToNetwork(String ssid, String password) {
WiFi.begin(ssid.c_str(), password.c_str());
Serial.print("Connecting");
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 40) { // 10 seconds timeout
delay(250);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println();
Serial.println("Connected successfully!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
saveNetworkDetails(ssid, password, "", "");
} else {
Serial.println();
Serial.println("Connection failed. Check your password and try again.");
scanNetworks();
}
}
void connectToEnterpriseNetwork(String ssid, String username, String identity, String password) {
//TODO
}
void saveNetworkDetails(String ssid, String password, String username, String identity) {
pref.putString("savedWifiCredentials", ssid);
pref.putString("savedWifiCredentials", password);
Serial.println("Network details saved.");
}
void moveDoor(doorstate dstate)
{
Serial.print("move: ");
Serial.println(xPortGetCoreID());
btnState = digitalRead(triggerUp);
btnState2 = digitalRead(triggerDown);
digitalWrite(lockPin, HIGH);
switch(dstate){
case UP:
Serial.println("UP");
for(btnState; btnState != LOW; btnState = digitalRead(triggerUp)){
digitalWrite(upDown, HIGH);
}
break;
case DOWN:
Serial.println("DOWN");
for(btnState2; btnState2 != LOW; btnState2 = digitalRead(triggerDown))
{
digitalWrite(upDown, LOW);
}
digitalWrite(lockPin, LOW);
break;
//case default: break;
}
}
void loop()
{
LCD.setCursor(0,3);
switch(dstate)
{
case OPEN:
LCD.print("Door Open");
break;
case CLOSED:
LCD.print("Door closed");
break;
case CALIBRATING:
LCD.print("Calibrating");
break;
case UP:
openingAnimation();
break;
case DOWN:
closingAnimation();
break;
}
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("Shuts at: ");
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("Opens at: ");
LCD.print(openTime.hour(), DEC);
LCD.print(':');
LCD.print(openTime.minute(), DEC);
LCD.print(':');
LCD.print(openTime.second(), DEC);
delay(10);
}