#include #include #include #include #include #include "time.h" // --- 1. YOUR NETWORK CREDENTIALS --- const char* ssid = "xxxx"; const char* password = "xxxx"; // --- 2. CONFIGURATION --- const int servoPin = 18; const int lockHour = 22; // 10 PM const int lockMin = 0; const long gmtOffset_sec = -18000; const int daylightOffset_sec = 3600; int posIdle = 35; int posPress = 28; // --- 3. VARIABLES --- Servo myServo; bool alreadyLockedToday = false; bool bootTestPerformed = false; unsigned long bootTime = 0; void setup() { Serial.begin(115200); myServo.attach(servoPin); myServo.write(posIdle); bootTime = millis(); // Connect WiFi WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } // --- FULL OTA CONFIGURATION --- ArduinoOTA.setHostname("fob-lock-box"); ArduinoOTA.setPassword("airtime"); ArduinoOTA.onStart([]() { String type = (ArduinoOTA.getCommand() == U_FLASH) ? "sketch" : "filesystem"; Serial.println("Start updating " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); ArduinoOTA.begin(); // ------------------------------ configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org"); Serial.println("\ncurrent program - keyfob202601"); Serial.println("\nReady! IP address: " + WiFi.localIP().toString()); } void loop() { ArduinoOTA.handle(); // This MUST run constantly to listen for updates // Power-Cycle Test (20 seconds after boot) if (!bootTestPerformed && (millis() - bootTime > 20000)) { Serial.println(">>> 20 Second Boot Test!"); lockTruck(); bootTestPerformed = true; } // Nightly Timer struct tm timeinfo; if(getLocalTime(&timeinfo)) { if (timeinfo.tm_hour == lockHour && timeinfo.tm_min == lockMin) { if (!alreadyLockedToday) { lockTruck(); alreadyLockedToday = true; } } if (timeinfo.tm_hour == 0) alreadyLockedToday = false; } delay(10); // Short delay to keep the loop snappy for OTA } void lockTruck() { myServo.write(posPress); delay(1000); myServo.write(posIdle); Serial.println("Action complete."); }