// Written by Thomas 'tjone270' Jones. // 23-12-2016 #include #include // Bootup millisecond counter const unsigned long started = millis(); // stamp initial time // Serial settings const int SERIAL_BAUDRATE = 9600; // Non-DHCP ethernet settings: // Device MAC address: DE:AD:BE:EF:FE:ED const byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip( 10, 0, 1, 150 ); // Pins const int P_RELAY = 6; const int P_ON_LED = 7; const int P_OFF_LED = 8; const int P_SW_MAN = 9; // Relay power states const char B_RELAY_ON = HIGH; const char B_RELAY_OFF = LOW; // Relay switching state boolean RELAY_STATE = false; // Manual switch const char SWITCH_MANUAL = HIGH; const char SWITCH_AUTO = LOW; char MANUAL_SWITCH_STATE; char LAST_SWITCH_STATE; // Network/web data EthernetServer server(80); String readString = String(100); String localIp; // Testing switches const boolean connectToEthernet = true; const boolean hostWebServer = true; const boolean useDHCP = false; const boolean testRelay = false; // Testing settings const int testRelayDelay = 500; // Formats an IPAddress object nicely as a string for printing String displayAddress(IPAddress address) { return String(address[0]) + "." + String(address[1]) + "." + String(address[2]) + "." + String(address[3]); } void setup() { delay(50); // allow some time (50 ms) after powerup and sketch start, for the Wiznet W5100 Reset IC to release and come out of reset. Serial.begin(SERIAL_BAUDRATE); // start serial communications while (!Serial) // wait for serial communications to connect up Serial.println(F("HTTP Web Remote Power-Point Controller.")); Serial.println(F("Given to Marc Littlejohn by Thomas Jones and Jacob Brown as a gift for Christmas 2016.")); Serial.println(); if (connectToEthernet) { Serial.println(F("Connecting to Ethernet...")); if (useDHCP) { Ethernet.begin(mac); Serial.println(F("Obtaining IP address...")); localIp = displayAddress(Ethernet.localIP()); } else { Ethernet.begin(mac, ip); // start the wiznet chip up localIp = displayAddress(ip); } if (localIp != "0.0.0.0") { Serial.println("Connected. IP: " + localIp); if (hostWebServer) { Serial.println(F("Starting TCP server...")); server.begin(); // start TCP server Serial.println(F("Started.")); } } else { Serial.println(F("Error: No address provided via DHCP.")); Serial.println(F("Please check your network connection and settings, and try again.")); while (1); } } Serial.println(F("Configuring pins...")); pinMode(P_RELAY, OUTPUT); // initialise output pins pinMode(P_ON_LED, OUTPUT); pinMode(P_OFF_LED, OUTPUT); pinMode(P_SW_MAN, INPUT_PULLUP); // initialise an input with a 10 kilo-ohm pull up resistor digitalWrite(P_OFF_LED, HIGH); digitalWrite(P_ON_LED, HIGH); Serial.println(F("Pins configured.")); Serial.println("Pin Information: \n Relay: " + String(P_RELAY) + "\n On LED: " + String(P_ON_LED) + "\n Off LED: " + String(P_OFF_LED) + "\n Manual Switch: " + String(P_SW_MAN)); MANUAL_SWITCH_STATE = digitalRead(P_SW_MAN); // detect switch position if (MANUAL_SWITCH_STATE == SWITCH_MANUAL) { Serial.println("Manual switch is in the MANUAL position."); LAST_SWITCH_STATE = SWITCH_AUTO; } else if (MANUAL_SWITCH_STATE == SWITCH_AUTO) { Serial.println("Manual switch is in the AUTO position."); LAST_SWITCH_STATE = SWITCH_MANUAL; } if (hostWebServer && connectToEthernet) { toggleRelay(false); Serial.println("Remote controller interface is running at http://" + localIp + "/"); } if (testRelay) { Serial.println(F("Testing relay mode enabled.")); Serial.println("Toggling relay every " + String(testRelayDelay) + " milliseconds..."); } const unsigned long starttime = (millis() - started); // get time since started and take away current time to get boot time Serial.println("Startup took " + String(starttime) + " milliseconds."); Serial.println(); } void loop() { MANUAL_SWITCH_STATE = digitalRead(P_SW_MAN); if (testRelay) { delay(testRelayDelay); if (RELAY_STATE) { toggleRelay(false); } else { toggleRelay(true); } } if (MANUAL_SWITCH_STATE == SWITCH_MANUAL && LAST_SWITCH_STATE == SWITCH_AUTO) { LAST_SWITCH_STATE = SWITCH_MANUAL; Serial.println(F("Manual switch engaged.")); if (RELAY_STATE == false) { toggleRelay(true); } } else if (MANUAL_SWITCH_STATE == SWITCH_AUTO && LAST_SWITCH_STATE == SWITCH_MANUAL) { Serial.println(F("Manual switch disengaged.")); LAST_SWITCH_STATE = SWITCH_AUTO; } if (useDHCP) { byte dhcpRenew = Ethernet.maintain(); // try to renew address if needed. if this wasn't done, the device would need a restart once per dhcp lease time if (dhcpRenew == 1) { Serial.println(F("Dynamic DHCP lease renewal failed.")); } else if (dhcpRenew == 2) { Serial.println(F("Dynamic DHCP lease was renewed.")); } else if (dhcpRenew == 3) { Serial.println(F("Dynamic DHCP lease rebind failed.")); } else if (dhcpRenew == 4) { Serial.println(F("Dynamic DHCP lease was rebound.")); } } EthernetClient client = server.available(); if (client) { // is there a client? Serial.println(F("Client connected to web server.")); while (client.connected()) { // is client still connected? if (client.available()) { // is client sending? char c = client.read(); // read request if (readString.length() < 100) { readString += c; // make a buffer } if (String(c) == "\n") { Serial.println("Data received from HTTP client: \n " + String(readString)); // HTTP header client.println(F("HTTP/1.1 200 OK")); // this is what the browser expects to recieve (200 OK) when a request is good client.println(F("Content-Type: text/html")); // send the document MIME type client.println(F("Connection: close")); // indicate that the web server will not support a persistant connection/will close the connection when the request is complete client.println(); // headers ALWAYS end with a carriage return // check to see if client requested relay state and send a boolean value for state if so. // note that this will not load the remainder of the webpage, this makes it act more like a queryable API. if (readString.indexOf(F("?state")) > 0) { Serial.println(F("Client queried the state of the relay.")); if (RELAY_STATE) { client.print(F("1")); } else { client.print(F("0")); } } else if (readString.indexOf(F("?manual")) > 0) { Serial.println(F("Client queried the state of the manual switch.")); if (MANUAL_SWITCH_STATE == SWITCH_AUTO) { client.print(F("AUTO")); } else if (MANUAL_SWITCH_STATE == SWITCH_MANUAL) { client.print(F("MANUAL")); } } else { // HTTP body String relaystate; String switchstate; if (RELAY_STATE) { relaystate = "on"; } else { relaystate = "off"; } if (MANUAL_SWITCH_STATE == SWITCH_AUTO) { switchstate = "auto"; } else { switchstate = "manual"; } Serial.println(F("Client requested webpage.")); client.println(F("")); client.println(F("")); client.println(F("")); client.println(F("Power-Point Controller")); client.println(F("")); client.println(F("")); client.println(F("

Power-Point Controller

")); client.println(F(" ")); client.println(F("")); client.println("

The power-point is currently " + String(relaystate) + "."); client.println("

The manual switch is currently in the " + String(switchstate) + " position."); client.println(F("")); client.println(F("")); } // give the browser time to recieve the data (10 milliseconds) delay(10); // check to see if a HTTP GET request was made to switch the relay on/off. if (MANUAL_SWITCH_STATE != SWITCH_MANUAL) { if (readString.indexOf("?relay=1") > 0) { Serial.println(F("Client toggled the relay on.")); toggleRelay(true); } else if (readString.indexOf("?relay=0") > 0) { Serial.println(F("Client toggled the relay off.")); toggleRelay(false); } } else { if (readString.indexOf("?relay") > 0) { Serial.println(F("Client attempted relay state change. Cancelled due to manual switch engaged.")); } } // stop sending data to browser and do a disconnect client.stop(); Serial.println(F("Client disconnected from web server.")); // clear request string for next connection readString = ""; } } } } } void toggleRelay(bool state) { if (state == true) { digitalWrite(P_OFF_LED, LOW); // switch pin to ground reference digitalWrite(P_RELAY, B_RELAY_ON); // switch pin to either HIGH/LOW depending on relay bias digitalWrite(P_ON_LED, HIGH); // switch pin to vcc rail RELAY_STATE = true; Serial.println(F("Relay State: ON")); } else if (state == false) { digitalWrite(P_ON_LED, LOW); // switch pin to ground reference digitalWrite(P_RELAY, B_RELAY_OFF); // switch pin to either HIGH/LOW depending on relay bias digitalWrite(P_OFF_LED, HIGH); // switch pin to vcc rail RELAY_STATE = false; Serial.println(F("Relay State: OFF")); } }