/* This application will run on a Arduino with a WizArd compatible ethernet shield. The Arduino will server up a jQuery enhanced website using webduino for switching on and off relays The relays can be connected to any number of applications. Most Specific it was intended for remote automation of utility main's power for home automation. You will need the webduino library in your Arduino /library folder to compile; built in Arduino 1.5.4 and webduino 1.7 (you will need to restart IDE to load) https://github.com/sirleech/Webduino The application also has functionality for Push Button, which is essentially a pulse rather then a latch of a relay, this is useful for hooking up to items that need turned on and off with a time delay on the power button. This code assumes the use of a 2x2 or 1x4 optio-isolator relay module. for a max of 7 relays (I am out of memory in default code to add more) Any use of high voltage or damage to your hardware is not my fault. I assume no risk or responsibility for the quality of this code. To enable auth look below and change the settings accordingly. you will need to base 64 encode your creds. Currently I am not saving the Port Name to EEPROM, if you have suggestions on how to accomplish this quickly let me know, I just haven’t done it yet.. until then you can edit the relayUse array below change 'Undefined' To your port name after reboot, Port1,Port2... etc. To use this, enter the following USLs into your browser. Replace "host" with the IP address assigned to the Arduino. (variables below) http://host/ These URLs brings up a display of the values READ on digital pins This is done with a call to defaultCmd. http://host/webpower This URL also brings up a display of the values READ on digital pins But it's done as a form, by the "formCmd" function, and the digital pins are shown as radio buttons you can change. When you click the "Submit" button, it does a POST that sets the digital pins, re-reads them, and re-displays the form. http://host/settings This URL will assign the pins to relays, by default all relays are disabled this pin to relay information is stored on your Arduino EEPROM Note: 255 is the default and that means the Item is not active. */ #define WEBDUINO_FAIL_MESSAGE "

Request Failed

" #define WEBDUINO_SERVER_HEADER "Server: Switch/" #define WEBDUINO_AUTH_REALM "Switch" #define WEBDUINO_SERIAL_DEBUGGING 0 #define PREFIX "" #include "SPI.h" #include "Ethernet.h" #include "WebServer.h" #include /* CHANGE THIS TO MATCH YOUR HOST NETWORK. Most home networks are in * the 192.168.0.XXX or 192.168.1.XXX subrange. Pick an address * that's not in use and isn't going to be automatically allocated by * DHCP from your router. */ static uint8_t ip[] = {192,168,1,222}; static uint8_t gateway[] = {192,168,1,1}; static uint8_t subnet[] = {255,255,255,0}; static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; /* The following should be updated as required * The relayUse array human object names for the Relay Function */ String relayUse[] = {"Undefined","Undefined","Undefined","Undefined","Undefined","Undefined","Undefined"}; //defaults for pin names. EEPROM write not emplimented for this yet. boolean invertOO = true; //if your using different hardware setup or relay boards your HIGH might be ON or OFF(or NO/NC) just switch this (global settings) #define THEME "b" //options a-e see http://jquerymobile.com/demos/1.2.1/docs/pages/pages-themes.html //the following variables are normally not changed proceed undocumented // const int PulseTime = 500; // time in miliseconds for pulse high width:global setting WebServer webserver(PREFIX, 80); // port webserver will listen on HTTP default is port 80 const char* AUTHENTICATION = "YWRtaW46YWRtaW4="; //admin:admin Base64-encoded boolean AUTHENABLED = false; //use Auth on Switching and settings Page #define MAXrelay 7 //the upper limit of PINS that will be used (memory constraints) int TotalRelay = 9; boolean relayAtBoot = LOW; // for high or low state at boot of code, typically not changed as invert deals boolean HardwareControl = true; // enable hardware buttons for ON off #define AnalogONpin A0 //pin for analog on button #define AnalogOFFpin A1 //pin for analog off button boolean AnalogEnabled = false; // enable printing the output of analog pins to the root webpage used for reading device LED woth optioresistor for "on off" status etc.. #define Analog1Pin A2 //pin for analog reading #define Analog2Pin A3 //pin for analog reading #define Analog1UpperValue 900 //the upper value for analog reading after this point will flip to "on" vs off #define Analog2UpperValue 900 //the upper value for analog reading after this point will flip to "on" vs off boolean Analog1 = false; //false = off boolean Analog2 = false; //false = off unsigned long previousMillis = 0; P(htmlHead) = "" "PowerSwitch" "" "" "" "" "" "" "
" "
SwitchStatus
SwitchPower
" "
"; P(htmlFooter) = "
Remote Switch
";// add footer information P(endrefresh)=""; // the following are system variables static uint8_t relayPinAddressStart = 255; //default pis status for EEPROM static uint8_t relayTypeAddressStart = 0; //default pin type for EEPROM uint8_t relayPin[] = {9,8,7,6,5,4,3}; //the default pins to relay (stored in EEPROM after you change in web) uint8_t relayType[] = {0,0,0,0,0,0,0}; //the default pin type relay-0 or PWM-1 (stored in EEPROM after you change in web) uint8_t aio = 1; uint8_t aif = 1; P(analog1ON) = "Analog Sensor 1 ON"; P(analog2ON) = "Analog Sensor 2 ON"; P(formStart) = "
"; P(formEnd) = ""; P(spacer) = "
"; template // no-cost stream operator as described at http://arduiniana.org/libraries/streaming/ inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; } void outputPins(WebServer &server, WebServer::ConnectionType type, bool addControls = false) //main web routine { server.httpSuccess(); server.printP(htmlHead); if (addControls) { server.printP(formStart); } for (int i = 1; i <= MAXrelay; ++i) { if (relayPin[i-1] >= 0 && relayPin[i-1] <= 53) { if (relayType[i-1] == 0) { String displayName; if (relayUse[i-1].equalsIgnoreCase("Undefined")){ displayName = String("Relay-" + String(i,DEC) + " "); } else { displayName = String(relayUse[i-1] + " "); } displayPins(server, relayPin[i-1], relayType[i-1], displayName, addControls); } else if (relayType[i-1] == 1) { String displayName; if (relayUse[i-1].equalsIgnoreCase("Undefined")){ displayName = String("PulseRelay-" + String(i,DEC) + " "); } else { displayName = String(relayUse[i-1] + "* "); } displayPins(server, relayPin[i-1], relayType[i-1], displayName, addControls); } } } //display analog controls if (AnalogEnabled && Analog1 ) { server.printP(analog1ON); } if (AnalogEnabled && Analog2 ) { server.printP(analog2ON); } server << "

"; if (addControls) { server.printP(formEnd); } else { server.printP(endrefresh); } server.printP(htmlFooter); } void settingsPage(WebServer &server, WebServer::ConnectionType type) //settings only page { if(!server.checkCredentials(AUTHENTICATION) && AUTHENABLED) { server.httpUnauthorized(); //not authenticated } else //authenticated { server.httpSuccess(); server.printP(htmlHead); server << "
"; char pinName[4]; for (int i = 1; i <= MAXrelay; ++i) { server << "
"; pinName[0] = 'e'; itoa(i, pinName + 1, 10); server.radioButton(pinName, "0", "Latched Relay(LR)", !relayType[i-1]); server << " "; server.radioButton(pinName, "1", "Pulse Relay(PR)", relayType[i-1]); server << "
"; } server << "
"; server.printP(htmlFooter); } } void settingsCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) //settings post handler { if (type == WebServer::POST) { bool repeat; char name[MAXrelay*3], value[MAXrelay*3]; do { repeat = server.readPOSTparam(name, MAXrelay*3, value, MAXrelay*3); int pin = strtoul(name + 1, NULL, 10); int val = strtoul(value, NULL, 10); String valueString = String(value); if (name[0] == 'h') //pinNumber { if (EEPROM.read(relayPinAddressStart+pin-1) == val) { //do nothing no change in value } else { if (relayPin[pin-1] > 0 && relayPin[pin-1] <=53) { digitalWrite(relayPin[pin-1], LOW); //make sure pin is off before overwritting it } relayPin[pin-1] = val; EEPROM.write(relayPinAddressStart+pin-1,val); } } if (name[0] == 'e') //relay type { if (EEPROM.read(relayTypeAddressStart+pin-1) == val) { //do nothing no change in value } else { relayType[pin-1] = val; EEPROM.write(relayTypeAddressStart+pin-1,val); } } if (name[0] == 'u') //relay common name { relayUse[pin-1] = valueString; } } while (repeat); server.httpSeeOther(PREFIX "/settings"); } else settingsPage(server, type); } void switchCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) // generic post handler and pin writer { if (type == WebServer::POST) { bool repeat; char name[MAXrelay], value[MAXrelay]; do { repeat = server.readPOSTparam(name, MAXrelay, value, MAXrelay); if (name[0] == 'd') { int pin = strtoul(name + 1, NULL, 10); int val = strtoul(value, NULL, 10); int pinindex = -1; for( int a = 0; a"; } else if (type == 1) { //latch relay server.radioButton(pinName, "1", "Switch", val); server << ""; } } else { if (type == 0) { //normal relay if (invertOO){ server << (!val ? "Off" : "On"); } else { server << (val ? "On" : "Off"); } } else if (type == 1) { //latch relay - recomended that you monitor the analog sensor here and use to print status server << "n/a"; //if (AnalogEnabled && Analog1 ) {server.printP(analog1ON);} } } server << "
"; } void setup() { Serial.begin(9600); // set pins 0-9 for digital input for (int i = 2; i <= TotalRelay; ++i) { pinMode(i, OUTPUT); } //Initialize pins - this should be changed if other then UNO for (int i = 2; i <= TotalRelay; ++i) { if (invertOO){ digitalWrite(i, !relayAtBoot); } else { digitalWrite(i, relayAtBoot); } } //start web Ethernet.begin(mac, ip); webserver.begin(); webserver.setDefaultCommand(&defaultCmd); webserver.addCommand("switch", &switchCmd); webserver.addCommand("settings", &settingsCmd); Serial.print("server address "); Serial.println(Ethernet.localIP()); //debug to serial if server is 0.0.0.0 web boot failed check sheld connections for (int i = 0; i < sizeof(relayPin); i++){ relayPin[i] = EEPROM.read(relayPinAddressStart + i); } for (int i = 0; i < sizeof(relayType); i++){ relayType[i] = EEPROM.read(relayTypeAddressStart + i); } if (HardwareControl) { digitalWrite(AnalogONpin, LOW); digitalWrite(AnalogOFFpin, LOW); } if (AnalogEnabled) { digitalWrite(Analog1Pin, INPUT); digitalWrite(Analog2Pin, INPUT); } } void loop() { // process incoming connections one at a time forever webserver.processConnection(); //physical on/off control if (HardwareControl) { int aon = analogRead(AnalogONpin); int aoff = analogRead(AnalogOFFpin); if (aon > 1015){; //Turn On relays incrementally if (relayPin[aio-1] > 0 && relayPin[aio-1] <= 53){ if (invertOO){ digitalWrite(relayPin[aio-1], LOW); } else { digitalWrite(relayPin[aio-1], HIGH); } delay(400); //cheap antibounce aif = aio; //keep them synched if (aio == sizeof(relayPin)){aio=1;} else { aio++;} } } if (aoff > 1015){; //if long delay press power down all relays if(previousMillis > 8) //3 second press of button (400 second delay below*8) bug here for over 8 relays { Serial.println("do"); previousMillis = 0; for (int i = 0; i < sizeof(relayPin); i++){ { if (invertOO){ digitalWrite(relayPin[aif-1], HIGH); } else { digitalWrite(relayPin[aif-1], LOW); } aif=1;aio=1; //reset hardware switching } } } else { previousMillis++;} //Turn Off relays incrementally if (relayPin[aif-1] > 0 && relayPin[aif-1] <= 53){ if (invertOO){ digitalWrite(relayPin[aif-1], HIGH); } else { digitalWrite(relayPin[aif-1], LOW); } delay(400); //cheap antibounce aio= aif; //keep them synched if (aif == sizeof(relayPin)){aif=1;previousMillis = 0;} else { aif--;} } if(aif<1){aif=1;} } } //analog reading if (AnalogEnabled) { int a1 = analogRead(Analog1Pin); int a2 = analogRead(Analog2Pin); //Serial.println(a1 + ":" + a2); //debug print for tuning the AnalogUpperValue settings if (a1 > Analog1UpperValue){;Analog1 = true;}else {Analog1 = false;} if (a2 > Analog2UpperValue){;Analog2 = true;}else {Analog2 = false;} } }