#include #include #include #include #include #include #include #include #include // prototytpes String getDate(time_t when); String getTime(time_t when); // The MOSFET that switches the appliance #define MOSFET D1 #define MANAGER_AP "RemotePower" #define CONFIG_PORT 80 #define NTP_SERVER "1.uk.pool.ntp.org" #define DEVICE_ON HIGH #define DEVICE_OFF LOW #define DEFAULT_DELAY 10000 // 10 seconds #define www_username "admin" #define www_password "wibble" ESP8266WebServer server(CONFIG_PORT); unsigned long trigtime = 0; unsigned long trighold = 0; // track the status of our output pin bool mosfet_status = false; const unsigned int localPort = 2390; IPAddress ntpServerIP; const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets WiFiUDP udp; unsigned long ntp_lastset = 0; unsigned long ntp_lasttry = 0; void output_set(bool on) { digitalWrite(MOSFET, on?DEVICE_ON:DEVICE_OFF); mosfet_status = on; } /* compose and send an NTP time request packet */ void ntp_send() { if (ntpServerIP == INADDR_NONE) { if (WiFi.hostByName(NTP_SERVER, ntpServerIP) == 1) { if (ntpServerIP == IPAddress(1,0,0,0)) { Serial.println("DNS lookup failed for " NTP_SERVER " try again later."); ntpServerIP = INADDR_NONE; return; } Serial.print("Got NTP server " NTP_SERVER " address "); Serial.println(ntpServerIP); } else { Serial.println("DNS lookup of " NTP_SERVER " failed."); return; } } ntp_lasttry = millis(); memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: udp.beginPacket(ntpServerIP, 123); //NTP requests are to port 123 udp.write(packetBuffer, NTP_PACKET_SIZE); udp.endPacket(); Serial.println("Sending NTP request"); } /* request a time update from NTP and parse the result */ time_t ntp_fetch() { while (udp.parsePacket() > 0); // discard old udp packets ntp_send(); uint32_t beginWait = millis(); while (millis() - beginWait < 2500) { int size = udp.parsePacket(); if (size >= NTP_PACKET_SIZE) { udp.read(packetBuffer, NTP_PACKET_SIZE); // this is NTP time (seconds since Jan 1 1900): unsigned long secsSince1900 = packetBuffer[40] << 24 | packetBuffer[41] << 16 | packetBuffer[42] << 8 | packetBuffer[43]; const unsigned long seventyYears = 2208988800UL; time_t unixtime = secsSince1900 - seventyYears; ntp_lastset = millis(); Serial.print("NTP update unixtime="); Serial.println(unixtime); return unixtime; } } Serial.println("No NTP response"); return 0; } String one_button_form(String target, String action, String blurb) { String out = ""; out += "
"; out += ""; out += ""; out += "
\n"; return out; } /* HTTP page request for / */ void handleRoot() { char mtime[16]; int sec = millis() / 1000; int mi = sec / 60; int hr = mi / 60; int day = hr / 24; snprintf(mtime, 16, "%dd %02d:%02d:%02d", day, hr % 24, mi % 60, sec % 60); if (server.hasArg("action")) { String action = server.arg("action"); if (action == "on") { output_set(DEVICE_ON); trigtime = 0; } else if (action == "off") { output_set(DEVICE_OFF); trigtime = 0; } else if (action == "toggle") { output_set(!mosfet_status); trigtime = 0; } else if (action == "pulse") { if (server.hasArg("dur")) { trighold = server.arg("dur").toInt(); } else { trighold = 0; } if (trighold == 0) trighold = DEFAULT_DELAY; trigtime = millis(); output_set(DEVICE_OFF); } } String out = "\ \ Remote Power\ \ \ \

Remote Power

\

Uptime: " + (String)mtime + "

\n"; if (timeStatus() == timeSet) { time_t when = now(); out += "

Time now: " + getDate(when) + " " + getTime(when) + "

\n"; } FSInfo fs_info; if (SPIFFS.info(fs_info)) { out += "

Onboard Flash disk: - Size:"+String(fs_info.totalBytes)+" Used:"+String(fs_info.usedBytes)+"

\n"; } out += "

Powered device is "; out += mosfet_status?"ON":"OFF"; out += "("; out += digitalRead(MOSFET) == HIGH?"HIGH":"LOW"; out += ")"; if (!mosfet_status && trigtime != 0) { out += " and is due to turn back ON in "; out += (trigtime + trighold - millis() )/ 1000; out += " seconds."; } out += "

\n"; out += "
    \n"; out += "
  • Reset Configuration\n"; out += "
  • " + one_button_form("/", "on", "Turn Device ON"); out += "
  • " + one_button_form("/", "off", "Turn Device OFF"); out += "
  • " + one_button_form("/", "toggle", "Toggle Device Status"); out += "
  • " + one_button_form("/", "pulse", (String)"Turn Device OFF for " + (int)(DEFAULT_DELAY/1000) + (String)" seconds"); out += "
\n"; out += "\n\n"; server.send( 200, "text/html", out); } void handleNotFound() { String out = "File Not found\n\n"; server.send(404, "text/plain", out); } // User wants to reset config void handleReset() { if (!server.authenticate(www_username, www_password)) return server.requestAuthentication(); server.send(200, "text/plain", "Rebooting to config manager...\n\n"); WiFiManager wfm; wfm.resetSettings(); WiFi.disconnect(); ESP.reset(); delay(5000); } void returnOK() { server.send(200, "text/plain", ""); } String getTime(time_t when) { String ans; int h = hour(when); int m = minute(when); int s = second(when); if (h<10) ans += "0"; ans += String(h) + ":"; if (m<10) ans += "0"; ans += String(m) + ":"; if (s<10) ans += "0"; ans += String(s); return ans; } String getDate(time_t when) { String ans; ans += String(year(when)) + "-" + String(month(when)) + "-" + String(day(when)); return ans; } void setup() { // some serial, for debug Serial.begin(115200); // The lock mechanism pinMode(MOSFET, OUTPUT); output_set(DEVICE_ON); Serial.println("Remote Power switcher"); Serial.println("Test WiFi and enter manager mode."); WiFiManager wfm; // Only wait in config mode for 3 minutes max wfm.setConfigPortalTimeout(180); // Try to connect to the old Ap for this long wfm.setConnectTimeout(60); // okay, lets try and connect... wfm.autoConnect(MANAGER_AP); Serial.println("Entering normal operation mode."); // we have config and are running normally, setup web server server.on( "/", handleRoot ); server.on( "/reset", handleReset ); server.onNotFound( handleNotFound ); server.begin(); // advertise we exist via MDNS if (!MDNS.begin("remotepower")) { Serial.println("Error setting up MDNS responder."); } else { MDNS.addService("http", "tcp", 80); } // enable internal flash SPIFFS.begin(); Serial.println("Requesting time from network"); udp.begin(localPort); setSyncProvider(ntp_fetch); Serial.println("Remote power switch. Ready"); } void loop() { // put your main code here, to run repeatedly: server.handleClient(); // a timed off state in progress if (trigtime != 0) { if (trigtime + trighold < millis()) { trigtime = 0; output_set(DEVICE_ON); } } // has ntp failed. do we need to try again? if (ntp_lastset == 0 && ntp_lasttry + 300000 < millis()) { Serial.println("Ask Time service to try again"); setSyncProvider(ntp_fetch); } }