/* * * */ #define WEBDUINO_FAVICON_DATA "" #include #include #include #include #include #include #include #include "EEPROM_IO.h" /*********************************************************************************/ /* Pin definitions */ #define METER_PULSE 2 #define STATUS_LED 7 #define FDOOR_STRIKE 8 #define FDOOR_CLOSED 9 #define GDOOR1_ACTIVATE 3 #define GDOOR1_OPEN 0 #define GDOOR1_CLOSED 1 #define GDOOR2_ACTIVATE 6 #define GDOOR2_OPEN 4 #define GDOOR2_CLOSED 5 /*********************************************************************************/ /* Typedefs/datastructures */ struct st_config { byte configVersion; byte mac[6]; byte def_ip[4]; byte def_netmask[4]; byte def_gateway[4]; byte ntpServer[4]; unsigned int UTC_offset; byte notifyHost[4]; unsigned int notifyPort; byte frontdoor_holdtime; byte garagedoor_nightgracetime; byte dawn; byte dusk; }; struct st_door { byte openSensePin; byte closedSensePin; byte controlPin; boolean open; boolean closed; boolean last_open; boolean last_closed; boolean controlActive; time_t controlTime; time_t openTime; }; /*********************************************************************************/ /* Variable declarations */ #define BUF1_SIZE 64 #define BUF2_SIZE 16 byte buf1[BUF1_SIZE]; byte buf2[BUF2_SIZE]; time_t time; time_t blinkTime = 0; struct st_config config = { // Config version. Set to 0 to debug (doesn't read from eeprom) 7, //0, // Ethernet MAC address 0x00, 0xA5, 0xCB, 0x28, 0xF4, 0xCC, // "Production" //0x00, 0xA5, 0xCB, 0x28, 0xF4, 0xCD, // "Testing" 10, 113, 1, 160, // Default IP if no DHCP 255, 255, 255, 0, // Default Netmask if no DHCP 10, 113, 1, 254, // Default GW if no DHCP 10, 113, 1, 1, // NTP Server 1300, // UTC offset 10, 113, 1, 255, // Host to send UDP status packets to 8888, // Port to send UDP status packets to 10, // Seconds to leave front door unlocked 1, // Minutes to leave garage doors open at night 7, // "Dawn" Hour - auto close before this. 21 // "Dusk" Hour - auto close after this. }; struct st_door frontDoor; struct st_door garageDoor1; struct st_door garageDoor2; EthernetUDP NTPSocket; time_t lastNTPtime = 0; //Server telnetServer(23); WebServer httpServer("", 80); /*********************************************************************************/ /* Utility functions */ /* const char* mac_to_str(const uint8_t* macAddr) { static char buf[32]; sprintf(buf, "%x:%x:%x:%x:%x:%x\0", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]); return buf; } const char* ip_to_str(const uint8_t* ipAddr) { static char buf[16]; sprintf(buf, "%d.%d.%d.%d\0", ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]); return buf; } */ /*********************************************************************************/ /* NTP/Time functions */ // send an NTP request to the time server at the given address void sendNTPpacket() { // Packet buffer byte pb[48]; // set all bytes in the buffer to 0 memset(pb, 0, sizeof(pb)); // Initialize values needed to form NTP request pb[0] = 0b11100011; // LI, Version, Mode pb[1] = 0; // Stratum, or type of clock pb[2] = 6; // Polling Interval pb[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion pb[12] = 49; pb[13] = 0x4E; pb[14] = 49; pb[15] = 52; // all NTP fields have been given values, now // we send a packet requesting a timestamp: NTPSocket.beginPacket(config.ntpServer, 123); NTPSocket.write(pb, sizeof(pb)); NTPSocket.endPacket(); } void parseNTPresponse() { byte pb[48]; unsigned long ntp_time = 0; float ntp_time_frac; // read the packet into the buffer NTPSocket.read(pb, sizeof(pb)); // NTP contains four timestamps with an integer part and a fraction part // we only use the integer part here for (int i=40; i<44; i++) ntp_time = ntp_time << 8 | pb[i]; // part of the fractional part // could be 4 bytes but this is more precise than the 1307 RTC // which has a precision of ONE second // in fact one byte is sufficient for 1307 ntp_time_frac = ((long)pb[44] * 256 + pb[45]) / 65536.0; // convert NTP to UNIX time, differs seventy years = 2208988800 seconds // NTP starts Jan 1, 1900 // Unix time starts on Jan 1 1970. ntp_time -= 2208988800UL; // Adjust timezone and DST... ntp_time += (config.UTC_offset * 3600L) / 100L; // Notice the L for long calculations!! if (ntp_time_frac > 0.4) ntp_time++; // adjust fractional part, see above setTime(ntp_time); lastNTPtime = now(); } /*********************************************************************************/ /* HTTP Handler function */ void httpHandler(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) { /* for a GET or HEAD, send the standard "it's all OK headers" */ server.httpSuccess("text/html; charset=iso-8859-1", "Content-Encoding: gzip\r\n"); /* we don't output the body for a HEAD request */ if (type == WebServer::GET) { /* store the HTML in program memory using the P macro - See index.html for content, encode_html.sh for getting this data */ P(message) = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc5, 0x56, 0x5b, 0x8f, 0x9b, 0x38, 0x14, 0x7e, 0xcf, 0xaf, 0xb0, 0xd4, 0x59, 0x99, 0xa8, 0x01, 0x02, 0x53, 0xfa, 0x40, 0x08, 0x2f, 0x53, 0xed, 0x4a, 0xab, 0x55, 0xbb, 0x52, 0x2f, 0xef, 0x06, 0x1b, 0xf0, 0x04, 0x6c, 0x6a, 0x9b, 0xcc, 0x44, 0xd1, 0xfc, 0xf7, 0x3d, 0x36, 0x24, 0x43, 0x67, 0x32, 0xea, 0x54, 0xfb, 0x50, 0x25, 0x0a, 0xe6, 0x3b, 0xdf, 0xb9, 0xfa, 0x9c, 0xa3, 0x64, 0x8d, 0xe9, 0xda, 0x3c, 0x6b, 0x18, 0xa1, 0x79, 0x66, 0xb8, 0x69, 0x59, 0xfe, 0x41, 0x4a, 0x85, 0x6e, 0xa4, 0x30, 0x4a, 0xb6, 0x59, 0x38, 0x62, 0x8b, 0xac, 0x63, 0x86, 0x20, 0x4e, 0xb7, 0x78, 0xcf, 0xd9, 0x5d, 0x2f, 0x95, 0xc1, 0x48, 0x90, 0x8e, 0xcd, 0xdf, 0x4b, 0xd0, 0x61, 0xc2, 0x6c, 0xf1, 0x1d, 0xa7, 0xa6, 0xd9, 0x46, 0xef, 0xd7, 0x1b, 0xc4, 0x05, 0x37, 0x9c, 0xb4, 0xbe, 0x2e, 0x49, 0xcb, 0xb6, 0x51, 0x00, 0x50, 0x47, 0xee, 0x79, 0x37, 0x74, 0x73, 0x68, 0xd0, 0x4c, 0xb9, 0x77, 0x52, 0x00, 0xb4, 0xde, 0x60, 0x70, 0xa8, 0xcd, 0xc1, 0x3a, 0x2e, 0x24, 0x3d, 0xa0, 0x63, 0x41, 0xca, 0x5d, 0xad, 0xe4, 0x20, 0xa8, 0x5f, 0xca, 0x56, 0xaa, 0xf4, 0x4d, 0x51, 0x14, 0x9b, 0x0a, 0x1c, 0xfa, 0x15, 0xe9, 0x78, 0x7b, 0x48, 0xf1, 0x37, 0xa6, 0x28, 0x11, 0x04, 0xaf, 0x34, 0x11, 0xda, 0x07, 0x83, 0xbc, 0x7a, 0x58, 0x34, 0x31, 0x3a, 0xb6, 0x5c, 0x30, 0xbf, 0x61, 0xbc, 0x6e, 0x4c, 0x9a, 0xac, 0xff, 0xd8, 0x00, 0x7a, 0xfd, 0x04, 0xb5, 0x60, 0xd0, 0x93, 0x9a, 0xa1, 0xa3, 0x61, 0xf7, 0xc6, 0x27, 0x2d, 0xaf, 0x45, 0x5a, 0x42, 0x32, 0x4c, 0x59, 0x91, 0x3d, 0x29, 0x46, 0x7d, 0x63, 0xe3, 0x5b, 0x05, 0x54, 0x16, 0x83, 0x31, 0x52, 0x5c, 0x62, 0x77, 0x44, 0xd5, 0x5c, 0xf8, 0x2d, 0xab, 0x4c, 0x4a, 0x06, 0x23, 0x4f, 0x80, 0x72, 0x9e, 0x1c, 0x02, 0x06, 0x4f, 0xfa, 0x3d, 0xa1, 0x94, 0x8b, 0xda, 0x2f, 0x24, 0xbc, 0x77, 0x69, 0xd2, 0xdf, 0x5b, 0xe9, 0xa3, 0xfd, 0x73, 0xd8, 0x20, 0x70, 0x55, 0x4d, 0xe3, 0xf5, 0x7a, 0x24, 0x0d, 0xa2, 0x95, 0xe5, 0x8e, 0x51, 0xa8, 0x19, 0x6b, 0x57, 0x81, 0xec, 0x99, 0x98, 0x8e, 0x65, 0x2b, 0xf5, 0x19, 0xd7, 0x86, 0x18, 0xe6, 0xce, 0x97, 0xaa, 0x48, 0x12, 0xfb, 0xd9, 0x4c, 0x61, 0xa4, 0xd7, 0x60, 0xba, 0x90, 0x8a, 0xc2, 0x6d, 0x28, 0x42, 0xf9, 0xa0, 0xd3, 0x77, 0xa3, 0xb3, 0x99, 0x2b, 0x74, 0xdc, 0x73, 0xcd, 0x0b, 0xde, 0x72, 0x73, 0x48, 0x1b, 0x4e, 0x29, 0x13, 0xcf, 0xc2, 0xb9, 0xe4, 0x2a, 0x49, 0x2a, 0xcb, 0x3b, 0xc7, 0x79, 0x89, 0x53, 0x25, 0x89, 0x2b, 0xf7, 0x63, 0x02, 0x17, 0x2d, 0x55, 0x96, 0x95, 0x85, 0x53, 0x87, 0x64, 0xba, 0x54, 0xbc, 0x37, 0xc8, 0x1c, 0x7a, 0x68, 0x47, 0x7b, 0x23, 0xe1, 0x2d, 0xd9, 0x93, 0x11, 0xc5, 0x48, 0xab, 0x72, 0x8b, 0x1b, 0x63, 0xfa, 0x34, 0x0c, 0x4b, 0x49, 0x59, 0x70, 0xfb, 0x7d, 0x60, 0xea, 0x10, 0x94, 0xb2, 0x0b, 0xc7, 0xa3, 0x1f, 0x05, 0x49, 0x10, 0x07, 0x1d, 0x17, 0xc1, 0xad, 0xc6, 0x39, 0x18, 0x76, 0xaa, 0x3f, 0xb3, 0x9c, 0x2f, 0xae, 0x3c, 0x2a, 0xcb, 0xa1, 0x83, 0x8b, 0x5f, 0x06, 0x0a, 0x26, 0xe8, 0xe0, 0x55, 0x83, 0x28, 0x0d, 0x97, 0xc2, 0x5b, 0xa2, 0xe3, 0x02, 0xa1, 0x2b, 0x0f, 0xbf, 0xa9, 0x28, 0xc1, 0x4b, 0x48, 0x89, 0x97, 0xbb, 0x99, 0xf8, 0x78, 0x15, 0xf4, 0x52, 0x1b, 0x0f, 0x53, 0x89, 0x57, 0xe8, 0x58, 0x29, 0x68, 0x65, 0x0a, 0x83, 0x97, 0xa2, 0xe8, 0x61, 0xb9, 0x81, 0xef, 0xa4, 0x5d, 0xd3, 0xe8, 0x15, 0xea, 0x35, 0x51, 0xd0, 0xbc, 0x56, 0x3f, 0x7a, 0x6e, 0x20, 0xfe, 0x25, 0x03, 0xf1, 0xdc, 0xc0, 0xd0, 0x53, 0xe8, 0x9e, 0xcf, 0xd0, 0x42, 0x83, 0xf6, 0x00, 0xb1, 0xe8, 0xc9, 0xc6, 0x13, 0xe1, 0x98, 0x6f, 0x50, 0x33, 0xf3, 0xf7, 0xe7, 0x4f, 0x1f, 0x3d, 0x7c, 0xab, 0xa5, 0x00, 0xcb, 0x67, 0x8f, 0xc0, 0x25, 0x23, 0xc9, 0xd2, 0x18, 0x29, 0x1b, 0x07, 0xcd, 0x18, 0x3b, 0x76, 0x58, 0xa1, 0x3d, 0x69, 0x4f, 0xac, 0x31, 0x7e, 0x8c, 0xde, 0x22, 0x90, 0x2c, 0x03, 0x62, 0x8c, 0xf2, 0x70, 0xd9, 0x12, 0xad, 0xb1, 0xe3, 0x81, 0x00, 0xbb, 0x1e, 0xc1, 0x2e, 0x56, 0x84, 0x1e, 0xa6, 0xa7, 0x66, 0xe6, 0x0b, 0xef, 0x98, 0x1c, 0x8c, 0x37, 0x8f, 0x71, 0x85, 0xa2, 0xf5, 0x7a, 0xed, 0x38, 0x96, 0xe9, 0x3a, 0xe8, 0x74, 0xd1, 0xa1, 0x5b, 0x80, 0x8b, 0xcc, 0x6e, 0x1b, 0x78, 0x50, 0xbe, 0x47, 0xce, 0xd3, 0xd6, 0x2e, 0x05, 0x00, 0x9a, 0x38, 0x8f, 0x12, 0xf4, 0x2f, 0x51, 0x3b, 0xf4, 0x0f, 0x11, 0x0c, 0xf8, 0xb1, 0x45, 0xaf, 0x9f, 0x2c, 0x4b, 0x00, 0x16, 0x99, 0x5b, 0x12, 0x93, 0xfa, 0x0f, 0x8b, 0xc3, 0xca, 0x94, 0xfd, 0x81, 0x55, 0x6b, 0x3d, 0xc0, 0x36, 0xad, 0xa8, 0x9c, 0x98, 0x8f, 0x73, 0x9a, 0x7f, 0x82, 0x11, 0xc9, 0x42, 0x60, 0x40, 0x2b, 0x1a, 0xfa, 0x54, 0x61, 0x98, 0x14, 0x66, 0xe3, 0x96, 0x7f, 0x9d, 0x86, 0xef, 0x65, 0xad, 0xf2, 0xb9, 0x9b, 0x1b, 0x37, 0x65, 0x3f, 0xa8, 0x84, 0x63, 0x7c, 0x63, 0x90, 0xb0, 0xcf, 0x5b, 0xdd, 0x13, 0xb1, 0xbd, 0xce, 0x67, 0x05, 0x19, 0x37, 0x53, 0x9e, 0x71, 0xd1, 0x0f, 0xd3, 0x64, 0x4c, 0xcb, 0x6a, 0x94, 0x9f, 0x77, 0x97, 0x73, 0x4b, 0xec, 0x45, 0x0d, 0x30, 0x3c, 0x7f, 0xda, 0x06, 0x47, 0xb6, 0x5a, 0x18, 0x85, 0xf9, 0xcb, 0x4e, 0xcf, 0x21, 0x43, 0xe3, 0xbf, 0xb6, 0x34, 0xcf, 0xd2, 0x05, 0xdd, 0xdf, 0x92, 0xaf, 0x1d, 0xd6, 0x53, 0xc2, 0x7f, 0xb9, 0x89, 0x72, 0x19, 0xa3, 0xe8, 0xd5, 0x39, 0xc7, 0xff, 0x23, 0xe7, 0xf8, 0x37, 0xe5, 0x1c, 0x5f, 0xcc, 0x39, 0x7e, 0x21, 0xe7, 0xf0, 0x34, 0x0a, 0x4e, 0x04, 0x8f, 0x69, 0xe4, 0x42, 0xf7, 0x47, 0x64, 0xf1, 0x1f, 0x55, 0xc9, 0x65, 0xbc, 0x90, 0x08, 0x00, 0x00, }; server.writeP(message, sizeof(message)); } } void jsonHandler(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) { /* for a GET or HEAD, send the standard "it's all OK headers" */ server.httpSuccess("application/json"); /* we don't output the body for a HEAD request */ if (type == WebServer::GET) { /* store the HTML in program memory using the P macro */ server.write("{\"fdo\":\""); server.write(((frontDoor.open)?"open":"state")); server.write("\", \"fdc\":\""); server.write(((frontDoor.closed)?"closed":"state")); server.write("\", \"fdu\":\""); server.write(((frontDoor.controlActive)?"unlocked":"locked")); server.write("\", \"gd1o\":\""); server.write(((garageDoor1.open)?"open":"state")); server.write("\", \"gd1c\":\""); server.write(((garageDoor1.closed)?"closed":"state")); server.write("\", \"gd2o\":\""); server.write(((garageDoor2.open)?"open":"state")); server.write("\", \"gd2c\":\""); server.write(((garageDoor2.closed)?"closed":"state")); server.write("\"}"); } } void doHandler(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) { if (type == WebServer::POST) { bool repeat; // char name[16], value[16]; do { repeat = server.readPOSTparam((char*)buf2, BUF2_SIZE, (char*)buf1, BUF1_SIZE); if ((strcmp((const char*)buf2, "frontdoor") == 0)) toggleDoorControl(&frontDoor); if ((strcmp((const char*)buf2, "garagedoor1") == 0)) toggleDoorControl(&garageDoor1); if ((strcmp((const char*)buf2, "garagedoor2") == 0)) toggleDoorControl(&garageDoor2); } while (repeat); server.httpSuccess(); server.write("OK"); return; } server.httpSeeOther("/"); return; } void configHandler(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) { /* for a GET or HEAD, send the standard "it's all OK headers" */ server.httpSuccess("text/html; charset=iso-8859-1", "Content-Encoding: gzip\r\n"); /* we don't output the body for a HEAD request */ if (type == WebServer::GET) { P(message) = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x85, 0x54, 0xdb, 0x6e, 0xdb, 0x30, 0x0c, 0x7d, 0xd7, 0x57, 0x70, 0x68, 0x07, 0x39, 0x58, 0x7d, 0x4d, 0xb3, 0x76, 0xca, 0x05, 0xe8, 0x12, 0xb4, 0xd8, 0xb0, 0xa5, 0x05, 0xda, 0xed, 0x5d, 0xb1, 0xe5, 0x58, 0x8d, 0x2f, 0x99, 0x24, 0x27, 0x35, 0x82, 0xfe, 0xfb, 0x28, 0x3b, 0x69, 0xb3, 0x15, 0xc3, 0x0c, 0x18, 0xb2, 0x0e, 0x0f, 0x0f, 0x49, 0x91, 0xf2, 0x28, 0x33, 0x45, 0x3e, 0x19, 0x65, 0x82, 0x27, 0x93, 0x91, 0x91, 0x26, 0x17, 0x93, 0x59, 0x55, 0x29, 0x98, 0x56, 0xa5, 0x51, 0x55, 0x3e, 0xf2, 0x3b, 0x8c, 0x8c, 0x0a, 0x61, 0x38, 0xc8, 0x64, 0x4c, 0x37, 0x52, 0x6c, 0xd7, 0x95, 0x32, 0x14, 0x4a, 0x5e, 0x88, 0xe3, 0x7d, 0x8c, 0x3e, 0xa2, 0x34, 0x63, 0xba, 0x95, 0x89, 0xc9, 0xc6, 0xe1, 0xc7, 0x60, 0x08, 0xb2, 0x94, 0x46, 0xf2, 0xdc, 0xd5, 0x31, 0xcf, 0xc5, 0x38, 0xf4, 0x10, 0x2a, 0xf8, 0x93, 0x2c, 0xea, 0xe2, 0x18, 0xaa, 0xb5, 0x50, 0xed, 0x9e, 0x2f, 0x10, 0x0a, 0x86, 0x14, 0x03, 0x6a, 0xd3, 0xd8, 0xc0, 0x8b, 0x2a, 0x69, 0x60, 0xb7, 0xe0, 0xf1, 0x6a, 0xa9, 0xaa, 0xba, 0x4c, 0xdc, 0xb8, 0xca, 0x2b, 0xc5, 0x4e, 0x16, 0x8b, 0xc5, 0x30, 0xc5, 0x80, 0x6e, 0xca, 0x0b, 0x99, 0x37, 0x8c, 0xfe, 0x14, 0x2a, 0xe1, 0x25, 0xa7, 0x67, 0x9a, 0x97, 0xda, 0x45, 0x41, 0x99, 0x3e, 0x93, 0x2c, 0x82, 0x5d, 0x2e, 0x4b, 0xe1, 0x66, 0x42, 0x2e, 0x33, 0xc3, 0x06, 0xc1, 0xfb, 0x21, 0xa2, 0xfd, 0xbf, 0x50, 0x0b, 0x7a, 0x6b, 0xbe, 0x14, 0xb0, 0x33, 0xe2, 0xc9, 0xb8, 0x3c, 0x97, 0xcb, 0x92, 0xc5, 0x58, 0x8c, 0x50, 0x68, 0x1a, 0xf9, 0xfb, 0x64, 0x46, 0x3a, 0x56, 0x72, 0x6d, 0xc0, 0x34, 0x6b, 0xac, 0xdc, 0x52, 0xfd, 0x47, 0xbe, 0xe1, 0x1d, 0x4a, 0x41, 0xab, 0x78, 0x4c, 0x33, 0x63, 0xd6, 0xcc, 0xf7, 0xe3, 0x2a, 0x11, 0xde, 0xe3, 0xaf, 0x5a, 0xa8, 0xc6, 0x8b, 0xab, 0xc2, 0xef, 0x3e, 0xdd, 0xd0, 0x1b, 0x78, 0x91, 0x57, 0xc8, 0xd2, 0x7b, 0xd4, 0x74, 0x82, 0xc2, 0xad, 0xeb, 0xff, 0x94, 0x27, 0xe4, 0xd4, 0x49, 0xaa, 0xb8, 0x2e, 0x30, 0xa3, 0x9e, 0xa7, 0xb0, 0x59, 0x8d, 0x93, 0xd6, 0x65, 0x6c, 0x64, 0x55, 0x3a, 0x3d, 0xd8, 0x41, 0xbd, 0x4e, 0xb8, 0x11, 0x4e, 0x6f, 0x08, 0xcf, 0xbd, 0x21, 0x39, 0x98, 0x5e, 0x60, 0xd8, 0x11, 0x80, 0x53, 0x6f, 0x29, 0x8c, 0x43, 0x31, 0xb3, 0x32, 0x95, 0x4b, 0x1f, 0x37, 0xf4, 0x0c, 0x5e, 0x54, 0x90, 0xc8, 0x3b, 0x1e, 0x32, 0x1d, 0x7a, 0xb2, 0x6f, 0x26, 0xed, 0x79, 0x76, 0x42, 0x3a, 0xf3, 0x10, 0xad, 0x56, 0xdf, 0xf7, 0xf7, 0x6a, 0x5f, 0xef, 0x6f, 0xe7, 0x0e, 0xfd, 0x87, 0x92, 0x65, 0x59, 0x9e, 0xe0, 0x71, 0xd6, 0x82, 0x47, 0x9c, 0x95, 0x68, 0xce, 0x60, 0xc3, 0xf3, 0x57, 0x5e, 0x17, 0x95, 0xc2, 0x07, 0x40, 0x5b, 0xcf, 0xe3, 0xc6, 0x28, 0x87, 0x22, 0xa3, 0x16, 0xb4, 0x63, 0x0e, 0xf7, 0xc4, 0x43, 0x02, 0x76, 0x6d, 0x5b, 0x73, 0x38, 0x41, 0xbf, 0x1d, 0x62, 0x32, 0xb2, 0x13, 0x83, 0x4b, 0x22, 0x37, 0x10, 0xe7, 0x5c, 0xeb, 0xb1, 0x6d, 0x2c, 0x02, 0x59, 0x7f, 0x32, 0x6d, 0x4b, 0xaf, 0x15, 0xb7, 0x49, 0xa0, 0x43, 0x1f, 0xe1, 0xb5, 0x12, 0x76, 0xae, 0xf7, 0xf5, 0x5a, 0x1d, 0x44, 0xec, 0x82, 0x02, 0xb8, 0xbc, 0x73, 0x5d, 0xd2, 0xb9, 0x01, 0x4e, 0x98, 0x46, 0x3f, 0x06, 0x17, 0x84, 0x3c, 0xc8, 0x42, 0xc0, 0xbc, 0xda, 0x32, 0x88, 0x22, 0xbf, 0xef, 0x47, 0x41, 0x18, 0x41, 0xd4, 0x67, 0xc1, 0x05, 0x8b, 0x3e, 0x91, 0x6f, 0x5c, 0x1b, 0x98, 0x3f, 0xdc, 0xbd, 0x35, 0x86, 0xe8, 0xfa, 0xfd, 0x6a, 0x0a, 0x57, 0x49, 0xa2, 0x84, 0xd6, 0x0c, 0x82, 0x80, 0x5d, 0x0d, 0xd8, 0xf4, 0x33, 0x8b, 0x2e, 0xd9, 0xf5, 0x39, 0x9b, 0x4e, 0x09, 0x99, 0x89, 0x94, 0xd7, 0xb9, 0x81, 0x2f, 0x77, 0x2d, 0x8d, 0x41, 0x18, 0x78, 0x61, 0xd8, 0xf7, 0x42, 0x0f, 0x6f, 0xd4, 0x8b, 0x75, 0x2e, 0x4c, 0xc1, 0xf5, 0x0a, 0x43, 0x0c, 0x70, 0xa2, 0xf6, 0xef, 0xab, 0xf9, 0x06, 0xfb, 0xbe, 0xe5, 0xcd, 0x91, 0x73, 0x34, 0x38, 0x27, 0x04, 0x93, 0x82, 0x7b, 0xa1, 0x36, 0xe2, 0x0f, 0x59, 0xf2, 0xe3, 0x61, 0x0a, 0xb7, 0x69, 0xaa, 0x85, 0x41, 0xb8, 0x1f, 0x04, 0x84, 0xdc, 0x1b, 0x6e, 0x6a, 0xfd, 0x96, 0x8b, 0x51, 0x0e, 0xb6, 0x3b, 0xbc, 0xf4, 0x0c, 0x2e, 0xf1, 0x21, 0xe4, 0x5a, 0xe1, 0xf1, 0x41, 0xfb, 0xe7, 0xa8, 0xcb, 0xbc, 0x8a, 0x57, 0x60, 0xf0, 0x80, 0xac, 0x1f, 0x38, 0x5a, 0xc4, 0xba, 0x47, 0xc8, 0x0d, 0x57, 0xf6, 0x82, 0xb5, 0x9c, 0xa5, 0xe2, 0xb1, 0x38, 0x50, 0xc0, 0xc1, 0xeb, 0x50, 0x1b, 0x81, 0xa4, 0x19, 0xdf, 0xe2, 0xf1, 0xe2, 0x39, 0x61, 0x0a, 0xb3, 0xba, 0xad, 0x2e, 0xb4, 0xdf, 0xae, 0x6b, 0x1b, 0xb2, 0x6f, 0xac, 0xdf, 0xfe, 0xb2, 0xc8, 0x6f, 0x42, 0x23, 0x41, 0x60, 0xba, 0x04, 0x00, 0x00, }; server.writeP(message, sizeof(message)); } } void configGetHandler(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) { /* for a GET or HEAD, send the standard "it's all OK headers" */ server.httpSuccess("text/plain"); /* we don't output the body for a HEAD request */ if (type == WebServer::GET) { sprintf((char*)buf1, "Config Version: %d\n\n\0", config.configVersion); server.print((char*)buf1); sprintf((char*)buf1, "Time Now: %d/%d/%d %02d:%02d:%02d\n\0", day(time), month(time), year(time), hour(time), minute(time), second(time)); server.print((char*)buf1); sprintf((char*)buf1, "Last NTP: %d/%d/%d %02d:%02d:%02d\n\n\0", day(lastNTPtime), month(lastNTPtime), year(lastNTPtime), hour(lastNTPtime), minute(lastNTPtime), second(lastNTPtime)); server.print((char*)buf1); sprintf((char*)buf1, "MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n\n\0", config.mac[0], config.mac[1], config.mac[2], config.mac[3], config.mac[4], config.mac[5]); server.print((char*)buf1); sprintf((char*)buf1, "Default IP Addr: %d.%d.%d.%d\n\0", config.def_ip[0], config.def_ip[1], config.def_ip[2], config.def_ip[3]); server.print((char*)buf1); sprintf((char*)buf1, "Default Netmask: %d.%d.%d.%d\n\0", config.def_netmask[0], config.def_netmask[1], config.def_netmask[2], config.def_netmask[3]); server.print((char*)buf1); sprintf((char*)buf1, "Default Gateway: %d.%d.%d.%d\n\n\0", config.def_gateway[0], config.def_gateway[1], config.def_gateway[2], config.def_gateway[3]); server.print((char*)buf1); sprintf((char*)buf1, "NTP Server: %d.%d.%d.%d\n\0", config.ntpServer[0], config.ntpServer[1], config.ntpServer[2], config.ntpServer[3]); server.print((char*)buf1); sprintf((char*)buf1, "UTC Offset: %d\n\n\0", config.UTC_offset); server.print((char*)buf1); sprintf((char*)buf1, "Status Server: %d.%d.%d.%d\n\0", config.notifyHost[0], config.notifyHost[1], config.notifyHost[2], config.notifyHost[3]); server.print((char*)buf1); sprintf((char*)buf1, "Status Port: %d\n\n\0", config.notifyPort); server.print((char*)buf1); sprintf((char*)buf1, "Front Door unlock time: %d (secs)\n\n\0", config.frontdoor_holdtime); server.print((char*)buf1); sprintf((char*)buf1, "Garage Door grace time: %d (minutes)\n\0", config.garagedoor_nightgracetime); server.print((char*)buf1); sprintf((char*)buf1, "Dawn: %02d:00\n\0", config.dawn); server.print((char*)buf1); sprintf((char*)buf1, "Dusk: %02d:00\n\n\0", config.dusk); server.print((char*)buf1); sprintf((char*)buf1, "Bytes Free: %d\n\n\0", freeMemory()); server.print((char*)buf1); } } void configSetHandler(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) { if (type == WebServer::POST) { bool repeat; do { repeat = server.readPOSTparam((char*)buf2, BUF2_SIZE, (char*)buf1, BUF1_SIZE); } while (repeat); server.httpSuccess(); server.write("OK"); return; } server.httpSeeOther("/"); return; } /*void debugHandler(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) { server.httpSuccess("text/plain"); if (type == WebServer::GET) { sprintf((char*)buf1, "Time Now: %d/%d/%d %02d:%02d:%02d\n\0", day(time), month(time), year(time), hour(time), minute(time), second(time)); server.print((char*)buf1); sprintf((char*)buf1, "Last NTP: %d/%d/%d %02d:%02d:%02d\n\nPacket:\n\0", day(lastNTPtime), month(lastNTPtime), year(lastNTPtime), hour(lastNTPtime), minute(lastNTPtime), second(lastNTPtime)); server.print((char*)buf1); for (int i = 0; i < 48; i++) { sprintf((char*)buf1, "%02X \0", pb[i]); server.print((char*)buf1); } } } */ /*********************************************************************************/ /* Miscellaneous functions */ void setupDoor (struct st_door *door, byte cp, byte csp, byte osp) { door->controlPin = cp; door->closedSensePin = csp; door->openSensePin = osp; door->controlActive = false; pinMode(door->controlPin, OUTPUT); pinMode(door->closedSensePin, INPUT); digitalWrite(door->closedSensePin, HIGH); if (door->openSensePin != 255) { pinMode(door->openSensePin, INPUT); digitalWrite(door->openSensePin, HIGH); } } boolean readDoorState (struct st_door *door) { door->last_closed = door->closed; door->closed = !digitalRead(door->closedSensePin); door->last_open = door->open; if (door->openSensePin != 255) { door->open = !digitalRead(door->openSensePin); } else { door->open = !door->closed; } if (!door->last_open && door->open) door->openTime = time; if ((door->last_open != door->open) || (door->last_closed != door->closed)) return true; return false; } void toggleDoorControl(struct st_door *door) { if (!door->controlActive) { digitalWrite(door->controlPin, HIGH); door->controlTime = time; } else { digitalWrite(door->controlPin, LOW); } door->controlActive = !door->controlActive; } void deToggleDoorCheck(struct st_door *door, byte controlHoldTime) { if (door->controlActive && ((time - door->controlTime) >= controlHoldTime) ) toggleDoorControl(door); } void garageDoorNightCheck(struct st_door *door) { if ( lastNTPtime > 0 && !door->controlActive && door->open && ((hour(time) >= config.dusk) || (hour(time) < config.dawn)) && ((time - door->openTime) >= (config.garagedoor_nightgracetime * 60)) ) toggleDoorControl(door); } /*********************************************************************************/ /* Setup function */ void setup() { byte eepromVersion; eepromRead(0, eepromVersion); if (config.configVersion > eepromVersion) eepromWrite(0, config); if (config.configVersion > 0) eepromRead(0, config); if(Ethernet.begin(config.mac) == 0) { Ethernet.begin(config.mac, config.def_ip, config.def_gateway, config.def_netmask); } // Udp.begin(config.notifyPort); NTPSocket.begin(123); httpServer.setDefaultCommand(&httpHandler); httpServer.addCommand("json", &jsonHandler); httpServer.addCommand("do", &doHandler); httpServer.addCommand("config", &configHandler); httpServer.addCommand("config/get", &configGetHandler); httpServer.addCommand("config/set", &configSetHandler); // httpServer.addCommand("debug", &debugHandler); httpServer.begin(); setupDoor(&frontDoor, FDOOR_STRIKE, FDOOR_CLOSED, 255); setupDoor(&garageDoor1, GDOOR1_ACTIVATE, GDOOR1_CLOSED, GDOOR1_OPEN); setupDoor(&garageDoor2, GDOOR2_ACTIVATE, GDOOR2_CLOSED, GDOOR2_OPEN); pinMode(STATUS_LED, OUTPUT); sendNTPpacket(); } /*********************************************************************************/ /* MAIN PROGRAM */ void loop() { time = now(); if ((time - lastNTPtime) >= 600) sendNTPpacket(); if (NTPSocket.parsePacket() >= 46) parseNTPresponse(); readDoorState(&frontDoor); readDoorState(&garageDoor1); readDoorState(&garageDoor2); deToggleDoorCheck(&frontDoor, config.frontdoor_holdtime); deToggleDoorCheck(&garageDoor1, 1); deToggleDoorCheck(&garageDoor2, 1); garageDoorNightCheck(&garageDoor1); garageDoorNightCheck(&garageDoor2); httpServer.processConnection(); /* Toggle Status LED so we know things are OK */ if (time != blinkTime) { blinkTime = time; digitalWrite(STATUS_LED, HIGH); delay(80); digitalWrite(STATUS_LED, LOW); } }