Remote DC power control with a WeMos D1 mini master
authorBuildTools <unconfigured@null.spigotmc.org>
Mon, 13 Mar 2017 16:16:40 +0000 (16:16 +0000)
committerBuildTools <unconfigured@null.spigotmc.org>
Mon, 13 Mar 2017 16:16:40 +0000 (16:16 +0000)
remote_power.fzz [new file with mode: 0644]
remote_power.ino [new file with mode: 0644]

diff --git a/remote_power.fzz b/remote_power.fzz
new file mode 100644 (file)
index 0000000..4b0871a
Binary files /dev/null and b/remote_power.fzz differ
diff --git a/remote_power.ino b/remote_power.ino
new file mode 100644 (file)
index 0000000..04a4039
--- /dev/null
@@ -0,0 +1,339 @@
+
+#include <TimeLib.h>
+#include <Time.h>
+#include <ESP8266WiFi.h>
+#include <WiFiUdp.h>
+#include <DNSServer.h>
+#include <ESP8266WebServer.h>
+#include <WiFiManager.h>
+#include <ESP8266mDNS.h>
+#include <FS.h>
+
+// 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 += "<form action=\"" + target + "\" method=\"POST\">";
+  out += "<input type=hidden name=action value=\"" + action + "\">";
+  out += "<input type=submit name=button value=\"" + blurb + "\">";
+  out += "</form>\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 = "<html>\
+  <head>\
+    <title>Remote Power</title>\
+    <style>\
+      body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; }\
+    </style>\
+  </head>\
+  <body>\
+    <h1>Remote Power</h1>\
+    <p>Uptime: " + (String)mtime + "</p>\n";
+
+  if (timeStatus() == timeSet) {
+    time_t when = now();
+    out += "<p>Time now: " + getDate(when) + " " + getTime(when) + "</p>\n";
+  }
+
+  FSInfo fs_info;
+  if (SPIFFS.info(fs_info)) {
+    out += "<p>Onboard Flash disk: - Size:"+String(fs_info.totalBytes)+" Used:"+String(fs_info.usedBytes)+"</p>\n";
+  }
+
+  out += "<p>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 += "</p>\n";
+
+  out += "<ul>\n";
+  out += "<li><a href=\"/reset\">Reset Configuration</a>\n";
+  out += "<li>" + one_button_form("/", "on", "Turn Device ON");
+  out += "<li>" + one_button_form("/", "off", "Turn Device OFF");
+  out += "<li>" + one_button_form("/", "toggle", "Toggle Device Status");
+  out += "<li>" + one_button_form("/", "pulse", (String)"Turn Device OFF for " + (int)(DEFAULT_DELAY/1000) + (String)" seconds");
+  
+    
+  out += "</ul>\n";
+  out += "</body>\n</html>\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);
+  }
+
+}