#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <WiFiClientSecure.h>
// ================= WiFi =================
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// ============ Google Apps Script ============
const char* SCRIPT_URL =
"https://script.google.com/macros/s/AKfycbxX9SU3DP1m9vcRi5rDnqEwG_OatYU3EWXHGgpUSkxh53KIXRwtOupyYdVM_UolxP5y/exec";
// ============ Retry & Timing Settings ============
const int MAX_RETRIES = 5;
const int retryDelayMs = 1000;
// Deep sleep time: 24 hours in microseconds
#define uS_TO_S_FACTOR 1000000ULL
#define TIME_TO_SLEEP_S 60 //(24ULL * 60ULL * 60ULL) // 24 hours
#define TIME_TO_SLEEP_US (TIME_TO_SLEEP_S * uS_TO_S_FACTOR)
// Optional: keep track of boot count (useful for debugging)
RTC_DATA_ATTR int bootCount = 0;
// ================= Setup =================
void setup()
{
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
Serial.print("Wakeup cause: ");
Serial.println(cause);
Serial.begin(115200);
delay(100); // give serial a moment
bootCount++;
Serial.println("\n----------------------------------");
Serial.printf("Boot number: %d\n", bootCount);
Serial.println("----------------------------------");
// Connect to WiFi
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20)
{
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() != WL_CONNECTED)
{
Serial.println("\nWiFi connection failed → going back to sleep");
goToDeepSleep();
return; // not reached
}
Serial.println("\nWiFi connected");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
// Generate payload
StaticJsonDocument<256> doc;
doc["rmsACVoltage"] = random(100, 200);
doc["ChargingVoltage"] = random(10, 20);
doc["BatteryVoltage"] = random(12, 18);
String payload;
serializeJson(doc, payload);
Serial.println("\nPayload:");
Serial.println(payload);
// ---------- POST + optional GET logic ----------
bool success = sendDataWithRedirect(payload);
if (!success)
{
Serial.println("Data send failed after retries.");
}
// Done → sleep again
goToDeepSleep();
}
// ================= Deep Sleep Helper =================
void goToDeepSleep()
{
Serial.println("Going to deep sleep for 1 minute...");
Serial.flush(); // make sure message gets out
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP_US);
esp_deep_sleep_start(); // → never returns
}
// ================= Send data (POST → 302 → GET) =================
bool sendDataWithRedirect(const String &payload)
{
int postTries = 0;
String redirectUrl = "";
bool gotRedirect = false;
while (!gotRedirect && postTries < MAX_RETRIES)
{
WiFiClientSecure client;
client.setInsecure();
client.setTimeout(15000);
HTTPClient http;
if (!http.begin(client, SCRIPT_URL))
{
postTries++;
Serial.println("HTTP begin failed. Retry " + String(postTries));
delay(retryDelayMs);
continue;
}
http.addHeader("Content-Type", "application/json");
const char* headerKeys[] = {"Location"};
http.collectHeaders(headerKeys, 1);
http.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS);
int httpCode = http.POST(payload);
if (httpCode == 302)
{
redirectUrl = http.header("Location");
if (redirectUrl.length() > 5)
{
gotRedirect = true;
Serial.println("Redirect received: " + redirectUrl);
http.end();
break;
}
}
postTries++;
Serial.printf("POST failed (code %d). Retry %d/%d\n", httpCode, postTries, MAX_RETRIES);
http.end();
delay(retryDelayMs);
}
if (!gotRedirect)
{
Serial.println("No valid redirect after max retries.");
return false;
}
// GET phase
int getTries = 0;
while (getTries < MAX_RETRIES)
{
WiFiClientSecure client;
client.setInsecure();
client.setTimeout(15000);
HTTPClient httpGet;
if (!httpGet.begin(client, redirectUrl))
{
getTries++;
delay(retryDelayMs);
continue;
}
int getCode = httpGet.GET();
if (getCode == 200)
{
Serial.println("GET successful:");
Serial.println(httpGet.getString());
httpGet.end();
return true;
}
Serial.printf("GET failed (code %d). Retry %d\n", getCode, getTries + 1);
httpGet.end();
getTries++;
delay(retryDelayMs);
}
Serial.println("GET failed after max retries.");
return false;
}
// ================= Loop =================
// (empty – everything happens in setup + deep sleep)
void loop()
{
// Never reached when using deep sleep
}