#include <Wire.h>
#include <WiFi.h>
#include <RTClib.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include <AsyncWebSocket.h>
#include <SPIFFS.h>
#include <FS.h>
#include <Arduino.h>
#include "TimeInterval.h"
#include "Relay.h"
#include "WifiCredentials.h"
RTC_DS3231 rtc;
const char* ssid = "your-ssid";
const char* password = "your-password";
AsyncWebServer server(80);
Relay relay(0, "RelayName", rtc);
WifiCredentials wifiCredentials;
void setup() {
Serial.begin(115200);
// Initialize SPIFFS
if (!SPIFFS.begin(true)) {
Serial.println("Error mounting SPIFFS");
return;
}
// Initialize RTC
Wire.begin();
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC lost power, let's set the time!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
loadWiFiCredentialsJSON("/wifiConfig.json", wifiCredentials);
// Connect to Wi-Fi
WiFi.begin(wifiCredentials.ssid.c_str(), wifiCredentials.password.c_str());
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Initialize server
server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(200, "text/plain", "Hello, ESP32!");
});
server.on("/configWiFi", HTTP_GET, [](AsyncWebServerRequest * request) {
// Send the HTML content directly from SPIFFS
request->send(SPIFFS, "/configWiFi.html", "text/html");
});
// Endpoint to scan available WiFi networks
server.on("/scanNetworks", HTTP_GET, [](AsyncWebServerRequest * request) {
// Scan for available networks
int numNetworks = WiFi.scanNetworks();
// Create a JSON object to store the network information
DynamicJsonDocument jsonDoc(JSON_ARRAY_SIZE(numNetworks));
JsonObject networks = jsonDoc.to<JsonObject>();
// Add each network to the JSON object
for (int i = 0; i < numNetworks; ++i) {
networks[String(i)]["ssid"] = WiFi.SSID(i);
networks[String(i)]["rssi"] = WiFi.RSSI(i);
networks[String(i)]["encryptionType"] = WiFi.encryptionType(i);
}
// Send the JSON response
String jsonStr;
serializeJson(jsonDoc, jsonStr);
request->send(200, "application/json", jsonStr);
});
// Endpoint to receive and save WiFi credentials
server.on("/saveWiFi", HTTP_POST, [&wifiCredentials](AsyncWebServerRequest * request) {
// Extract WiFi credentials from request parameters
String newSsid = request->getParam("ssid")->value();
String newPass = request->getParam("password")->value();
// Save WiFi credentials
wifiCredentials.ssid = newSsid.c_str();
wifiCredentials.password = newPass.c_str();
// Restart ESP32 in STA mode
saveWiFiCredentialsJSON("/wifiCredentials.json", wifiCredentials);
restartInStationMode();
request->send(200, "text/plain", "WiFi credentials saved. ESP32 will restart in STA mode.");
});
server.on("/turnOn", HTTP_GET, [](AsyncWebServerRequest * request) {
relay.turnOn();
request->send(200, "text/plain", "Relay turned ON");
});
server.on("/turnOff", HTTP_GET, [](AsyncWebServerRequest * request) {
relay.turnOff();
request->send(200, "text/plain", "Relay turned OFF");
});
server.on("/changeMode", HTTP_GET, [](AsyncWebServerRequest * request) {
String modeParam = request->getParam("mode")->value();
if (modeParam.equalsIgnoreCase("auto")) {
relay.setMode(Relay::AUTO);
request->send(200, "text/plain", "Relay mode set to AUTO");
} else if (modeParam.equalsIgnoreCase("manual")) {
relay.setMode(Relay::MANUAL);
request->send(200, "text/plain", "Relay mode set to MANUAL");
} else {
request->send(400, "text/plain", "Invalid mode parameter");
}
});
server.on("/configureIntervals", HTTP_POST, [rtc](AsyncWebServerRequest * request) {
// Extract JSON data from the request
String jsonStr = request->getParam("plain")->value();
// Allocate a buffer to store the JSON payload
DynamicJsonDocument jsonDoc(1024);
// Parse the JSON payload
DeserializationError error = deserializeJson(jsonDoc, jsonStr);
if (error) {
Serial.print("JSON parse error: ");
Serial.println(error.c_str());
request->send(400, "text/plain", "Failed to parse JSON");
return;
}
// Update relay intervals from the JSON payload
for (int i = 0; i < 3; ++i) {
JsonObject interval = jsonDoc["intervals"][i];
std::vector<int> days;
for (JsonVariant day : interval["days"].as<JsonArray>()) {
days.push_back(day.as<int>());
}
relay.setIntervals(i, interval["startHour"],
interval["startMinute"],
interval["endHour"],
interval["endMinute"],
days
);
}
request->send(200, "text/plain", "Intervals configured successfully");
});
// Load Relay configuration from a JSON file
loadRelayFromJson("/relayConfig.json", relay);
Serial.println("Loaded Relay Configuration:");
Serial.print("Pin: ");
Serial.println(relay.pin);
Serial.print("State: ");
Serial.println((relay.state == Relay::ON) ? "ON" : "OFF");
Serial.print("Mode: ");
Serial.println((relay.modeStr == Relay::AUTO) ? "AUTO" : "MANUAL");
Serial.print("Name: ");
Serial.println(relay.nameStr);
Serial.println("Intervals:");
for (int i = 0; i < 3; ++i) {
Serial.print("Interval ");
Serial.print(i + 1);
Serial.print(": ");
Serial.print("Start: ");
Serial.print(relay.intervals[i].startHour);
Serial.print(":");
Serial.print(relay.intervals[i].startMinute);
Serial.print(", End: ");
Serial.print(relay.intervals[i].endHour);
Serial.print(":");
Serial.print(relay.intervals[i].endMinute);
Serial.print(", Days: ");
for (int day : relay.intervals[i].daysOfWeek) {
Serial.print(day);
Serial.print(" ");
}
Serial.println();
}
server.begin();
}
void loop() {
// Handle other tasks
//relay.update();
}
void saveRelayToJson(const char* filename, const Relay& relay) {
DynamicJsonDocument doc(1024);
JsonObject relayJson = doc.to<JsonObject>();
relay.toJson(relayJson);
File file = SPIFFS.open(filename, "w");
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
if (serializeJson(doc, file) == 0) {
Serial.println("Failed to write to file");
}
file.close();
}
void loadRelayFromJson(const char* filename, Relay& relay) {
File file = SPIFFS.open(filename, "r");
if (!file) {
Serial.println("Failed to open file for reading");
return;
}
const size_t bufferSize = JSON_OBJECT_SIZE(4) + 3 * JSON_OBJECT_SIZE(5) + 200;
DynamicJsonDocument doc(bufferSize);
DeserializationError error = deserializeJson(doc, file);
if (error) {
Serial.print("JSON parse error: ");
Serial.println(error.c_str());
file.close();
return;
}
relay.pin = doc["pin"];
relay.state = (doc["state"] == "ON") ? Relay::ON : Relay::OFF;
relay.modeStr = (doc["mode"] == "AUTO") ? Relay::AUTO : Relay::MANUAL;
relay.nameStr = doc["name"];
JsonArray intervalsArray = doc["intervals"];
for (int i = 0; i < 3; ++i) {
JsonObject interval = doc["intervals"][i];
std::vector<int> days;
for (JsonVariant day : interval["days"].as<JsonArray>()) {
days.push_back(day.as<int>());
}
relay.setIntervals(i, interval["startHour"],
interval["startMinute"],
interval["endHour"],
interval["endMinute"],
days
);
}
file.close();
}
void saveWiFiCredentialsJSON(const char* filename, const WifiCredentials& wifiCredentials) {
// Create a JSON object
DynamicJsonDocument doc(256); // Adjust the size based on your needs
JsonObject credentials = doc.to<JsonObject>();
wifiCredentials.toJson(credentials);
// Open the file in write mode
File file = SPIFFS.open(filename, "w");
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
// Write the JSON string to the file
if (serializeJson(doc, file) == 0) {
Serial.println("Failed to write to file");
}
// Close the file
file.close();
}
void loadWiFiCredentialsJSON(const char* filename, WifiCredentials& wifiCredentials) {
File file = SPIFFS.open(filename, "r");
if (!file) {
Serial.println("Failed to open file for reading");
return;
}
const size_t bufferSize = JSON_OBJECT_SIZE(4) + 3 * JSON_OBJECT_SIZE(5) + 200;
DynamicJsonDocument doc(bufferSize);
DeserializationError error = deserializeJson(doc, file);
if (error) {
Serial.print("JSON parse error: ");
Serial.println(error.c_str());
file.close();
return;
}
wifiCredentials.ssid = doc["ssid"].as<String>();
wifiCredentials.password = doc["password"].as<String>();
file.close();
}
void restartInStationMode() {
Serial.println("Restarting in Station Mode...");
// Disconnect from the current WiFi network, if connected
WiFi.disconnect(true);
// Wait a moment to ensure the disconnect completes
delay(1000);
// Start WiFi in station mode
WiFi.mode(WIFI_STA);
// Begin connecting to the saved WiFi network
WiFi.begin();
Serial.println("Restart complete.");
}