4 #include <ESP8266WiFi.h>
7 #include <ESP8266WebServer.h>
8 #include <WiFiManager.h>
9 #include <ESP8266mDNS.h>
13 String getDate(time_t when);
14 String getTime(time_t when);
16 // The MOSFET that switches the appliance
19 #define MANAGER_AP "RemotePower"
20 #define CONFIG_PORT 80
21 #define NTP_SERVER "1.uk.pool.ntp.org"
23 #define DEVICE_ON HIGH
24 #define DEVICE_OFF LOW
25 #define DEFAULT_DELAY 10000 // 10 seconds
28 #define www_username "admin"
29 #define www_password "wibble"
31 ESP8266WebServer server(CONFIG_PORT);
33 unsigned long trigtime = 0;
34 unsigned long trighold = 0;
36 // track the status of our output pin
37 bool mosfet_status = false;
39 const unsigned int localPort = 2390;
40 IPAddress ntpServerIP;
42 const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
44 byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
48 unsigned long ntp_lastset = 0;
49 unsigned long ntp_lasttry = 0;
53 void output_set(bool on)
55 digitalWrite(MOSFET, on?DEVICE_ON:DEVICE_OFF);
59 /* compose and send an NTP time request packet */
62 if (ntpServerIP == INADDR_NONE) {
63 if (WiFi.hostByName(NTP_SERVER, ntpServerIP) == 1) {
64 if (ntpServerIP == IPAddress(1,0,0,0)) {
65 Serial.println("DNS lookup failed for " NTP_SERVER " try again later.");
66 ntpServerIP = INADDR_NONE;
69 Serial.print("Got NTP server " NTP_SERVER " address ");
70 Serial.println(ntpServerIP);
72 Serial.println("DNS lookup of " NTP_SERVER " failed.");
77 ntp_lasttry = millis();
78 memset(packetBuffer, 0, NTP_PACKET_SIZE);
79 // Initialize values needed to form NTP request
80 // (see URL above for details on the packets)
81 packetBuffer[0] = 0b11100011; // LI, Version, Mode
82 packetBuffer[1] = 0; // Stratum, or type of clock
83 packetBuffer[2] = 6; // Polling Interval
84 packetBuffer[3] = 0xEC; // Peer Clock Precision
85 // 8 bytes of zero for Root Delay & Root Dispersion
86 packetBuffer[12] = 49;
87 packetBuffer[13] = 0x4E;
88 packetBuffer[14] = 49;
89 packetBuffer[15] = 52;
91 // all NTP fields have been given values, now
92 // you can send a packet requesting a timestamp:
93 udp.beginPacket(ntpServerIP, 123); //NTP requests are to port 123
94 udp.write(packetBuffer, NTP_PACKET_SIZE);
97 Serial.println("Sending NTP request");
100 /* request a time update from NTP and parse the result */
103 while (udp.parsePacket() > 0); // discard old udp packets
106 uint32_t beginWait = millis();
108 while (millis() - beginWait < 2500) {
109 int size = udp.parsePacket();
110 if (size >= NTP_PACKET_SIZE) {
111 udp.read(packetBuffer, NTP_PACKET_SIZE);
113 // this is NTP time (seconds since Jan 1 1900):
114 unsigned long secsSince1900 = packetBuffer[40] << 24 | packetBuffer[41] << 16 | packetBuffer[42] << 8 | packetBuffer[43];
115 const unsigned long seventyYears = 2208988800UL;
116 time_t unixtime = secsSince1900 - seventyYears;
118 ntp_lastset = millis();
119 Serial.print("NTP update unixtime=");
120 Serial.println(unixtime);
124 Serial.println("No NTP response");
129 String one_button_form(String target, String action, String blurb)
132 out += "<form action=\"" + target + "\" method=\"POST\">";
133 out += "<input type=hidden name=action value=\"" + action + "\">";
134 out += "<input type=submit name=button value=\"" + blurb + "\">";
141 /* HTTP page request for / */
145 int sec = millis() / 1000;
150 snprintf(mtime, 16, "%dd %02d:%02d:%02d", day, hr % 24, mi % 60, sec % 60);
152 if (server.hasArg("action")) {
153 String action = server.arg("action");
155 if (action == "on") {
156 output_set(DEVICE_ON);
159 if (action == "off") {
160 output_set(DEVICE_OFF);
163 if (action == "toggle") {
164 output_set(!mosfet_status);
167 if (action == "pulse") {
168 if (server.hasArg("dur")) {
169 trighold = server.arg("dur").toInt();
173 if (trighold == 0) trighold = DEFAULT_DELAY;
175 output_set(DEVICE_OFF);
179 String out = "<html>\
181 <title>Remote Power</title>\
183 body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; }\
187 <h1>Remote Power</h1>\
188 <p>Uptime: " + (String)mtime + "</p>\n";
190 if (timeStatus() == timeSet) {
192 out += "<p>Time now: " + getDate(when) + " " + getTime(when) + "</p>\n";
196 if (SPIFFS.info(fs_info)) {
197 out += "<p>Onboard Flash disk: - Size:"+String(fs_info.totalBytes)+" Used:"+String(fs_info.usedBytes)+"</p>\n";
200 out += "<p>Powered device is ";
201 out += mosfet_status?"ON":"OFF";
203 out += digitalRead(MOSFET) == HIGH?"HIGH":"LOW";
206 if (!mosfet_status && trigtime != 0) {
207 out += " and is due to turn back ON in ";
208 out += (trigtime + trighold - millis() )/ 1000;
215 out += "<li><a href=\"/reset\">Reset Configuration</a>\n";
216 out += "<li>" + one_button_form("/", "on", "Turn Device ON");
217 out += "<li>" + one_button_form("/", "off", "Turn Device OFF");
218 out += "<li>" + one_button_form("/", "toggle", "Toggle Device Status");
219 out += "<li>" + one_button_form("/", "pulse", (String)"Turn Device OFF for " + (int)(DEFAULT_DELAY/1000) + (String)" seconds");
223 out += "</body>\n</html>\n";
225 server.send( 200, "text/html", out);
228 void handleNotFound() {
229 String out = "File Not found\n\n";
230 server.send(404, "text/plain", out);
233 // User wants to reset config
235 if (!server.authenticate(www_username, www_password))
236 return server.requestAuthentication();
238 server.send(200, "text/plain", "Rebooting to config manager...\n\n");
248 server.send(200, "text/plain", "");
251 String getTime(time_t when)
255 int m = minute(when);
256 int s = second(when);
258 if (h<10) ans += "0";
259 ans += String(h) + ":";
260 if (m<10) ans += "0";
261 ans += String(m) + ":";
262 if (s<10) ans += "0";
268 String getDate(time_t when)
272 ans += String(year(when)) + "-" + String(month(when)) + "-" + String(day(when));
278 // some serial, for debug
279 Serial.begin(115200);
281 // The lock mechanism
282 pinMode(MOSFET, OUTPUT);
283 output_set(DEVICE_ON);
285 Serial.println("Remote Power switcher");
286 Serial.println("Test WiFi and enter manager mode.");
289 // Only wait in config mode for 3 minutes max
290 wfm.setConfigPortalTimeout(180);
291 // Try to connect to the old Ap for this long
292 wfm.setConnectTimeout(60);
293 // okay, lets try and connect...
294 wfm.autoConnect(MANAGER_AP);
296 Serial.println("Entering normal operation mode.");
298 // we have config and are running normally, setup web server
299 server.on( "/", handleRoot );
300 server.on( "/reset", handleReset );
301 server.onNotFound( handleNotFound );
304 // advertise we exist via MDNS
305 if (!MDNS.begin("remotepower")) {
306 Serial.println("Error setting up MDNS responder.");
308 MDNS.addService("http", "tcp", 80);
311 // enable internal flash
314 Serial.println("Requesting time from network");
315 udp.begin(localPort);
316 setSyncProvider(ntp_fetch);
318 Serial.println("Remote power switch. Ready");
322 // put your main code here, to run repeatedly:
323 server.handleClient();
325 // a timed off state in progress
327 if (trigtime + trighold < millis()) {
329 output_set(DEVICE_ON);
333 // has ntp failed. do we need to try again?
334 if (ntp_lastset == 0 && ntp_lasttry + 300000 < millis()) {
335 Serial.println("Ask Time service to try again");
336 setSyncProvider(ntp_fetch);