Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * Chicken Coop Door/Light controller for ESP8266 board.
- * Copyright 2016, Ioan Ghip <ioanghip (at) gmail (dot) com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
- #include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
- #include <WiFiClient.h>
- #include <ESP8266WebServer.h>
- #include <ESP8266HTTPClient.h>
- #include <TinyGPS++.h> //https://github.com/mikalhart/TinyGPSPlus
- #include <SoftwareSerial.h>
- #include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
- #include <TimeLord.h> //https://github.com/probonopd/TimeLord
- #include <TimeLib.h> //https://github.com/PaulStoffregen/Time
- #include <TimeAlarms.h> //https://github.com/PaulStoffregen/TimeAlarms
- #include <EEPROM.h> //http://playground.arduino.cc/Code/EEPROMWriteAnything
- #include <Arduino.h>
- // we don't need to send message to serial if not connected to a computer. Comment the following line if not debuging
- #define __DEBUG__
- #if defined (__DEBUG__)
- #define DEBUG_begin(val) Serial.begin(val)
- #define DEBUG_print(val) Serial.print(val)
- #define DEBUG_println(val) Serial.println(val)
- #else
- #define DEBUG_begin(val)
- #define DEBUG_print(val)
- #define DEBUG_println(val)
- #endif
- #define COOP_VERSION "5"
- const String HTTP_HEAD_COOP = "<!DOCTYPE html><html lang=\"en\"><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/><title>Chicken Coop</title>";
- const String HTTP_STYLE_COOP = "<style>div,input{padding:5px;font-size:1em;} input{width:95%;} body{text-align: center;} button{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;} input[type=\"submit\"]{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;}</style>";
- const String HTTP_HEAD_END_COOP = "</head><body><div style='font-family: verdana; text-align: left; display: inline-block;'><h1>Chicken Coop</h1>";
- const String HTTP_END_COOP = "</div></body></html>";
- const String HTTP_BUTTON_COOP = "<p><form action=\"{ACT}\" method=\"get\"><button>{TXT}</button></form></p>";
- const String HTTP_FORM_SAVE_COOP = "<p><form action=\"/SAVE\" method=\"get\"><p><input type=\"text\" name=\"timezone\" value=\"{TZ}\" onkeypress='return (event.charCode >= 48 && event.charCode <= 57) || (event.charCode == 45)'></input></p><input type=\"hidden\" name=\"v\" value=\"{VER}\"><p><input style=button type=\"submit\" value=\"Save settings\"></p></form></p>";
- const String HTTP_LINK_RESET_COOP = "<p><a href=\"/RESET\" onclick=\"return confirm('Are you sure?');\">Change WiFi configuration</a></p>";
- const String HTTP_LINK_CONFIG_COOP = "<p><a href=\"/CONFIG\">Time zone</a></p>";
- const String HTTP_BEGIN_COOP = HTTP_HEAD_COOP + HTTP_STYLE_COOP + HTTP_HEAD_END_COOP;
- const String GOOGLE_DYNDNS_USERNAME = "doesnt work";
- const String GOOGLE_DYNDNS_PASSWORD = "doesnt work yet";
- const String GOOGLE_DYNDNS_DOMAIN = "coop.marginallyhandy.com";
- const String GOOGLE_DYNDNS = "http://" + GOOGLE_DYNDNS_USERNAME + ":" + GOOGLE_DYNDNS_PASSWORD + "@domains.google.com/nic/update?hostname=" + GOOGLE_DYNDNS_DOMAIN + "&myip={IP}";
- int door_relay1 = 2; // gpo2 - d4
- int light_relay = 14; // gop14 - d5
- int door_open_button = 12; // gpo12 - d6
- int door_close_button = 5; // gpo5 - d1
- // what is our longitude (west values negative) and latitude (south values negative)
- float latitude = 44.9308; // the value is going to be replaced by the GPS
- float longitude = -123.0289; // the value is going to be replaced by the GPS
- int timezone = -8; // get this from the user
- // we will syncronize the time with an GPS connected tot pin gpo13 -> gps TX, gpo15 -> gpx RX
- static const int RXPin = 13; // gpo13 - d7
- static const int TXPin = 15; // gpo15 - d8
- static const uint32_t GPSBaud = 38400;
- SoftwareSerial SerialGPS = SoftwareSerial(RXPin, TXPin);
- TinyGPSPlus gps;
- // TimeLord library for calculating sunset / sunrise times
- TimeLord sunrisesunset;
- // what TimeLord lib returns will be stored here:
- byte todaySunRiseHour;
- byte todaySunRiseMinute;
- byte todaySunSetHour;
- byte todaySunSetMinute;
- boolean isDoorOpen = true;
- /* Set these to your desired credentials. */
- const char *ssid = "ChickenCoop";
- const char *password = "12345678";
- ESP8266WebServer webServer(80);
- void setup()
- {
- pinMode(door_relay1, OUTPUT);
- pinMode(light_relay, OUTPUT);
- digitalWrite(door_relay1, LOW);
- digitalWrite(light_relay, LOW);
- // init serial for time sync with the GPS
- SerialGPS.begin(GPSBaud);
- // init serial for debugging
- DEBUG_begin(115200);
- DEBUG_print("Chicken Coop v");
- DEBUG_println(COOP_VERSION);
- // init the eeprom
- EEPROM.begin(512);
- String ip;
- if (isAPFlag())
- {
- /* You can remove the password parameter if you want the AP to be open. */
- WiFi.softAP(ssid, password);
- DEBUG_print("AP Mode, IP address: ");
- }
- else
- {
- //WiFiManager: Local intialization. Once its business is done, there is no need to keep it around
- WiFiManager wifi;
- //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
- wifi.setAPCallback(configModeCallback);
- if (!wifi.autoConnect("ChickenCoop"))
- {
- DEBUG_println("failed to connect and hit timeout");
- //reset and try again, or maybe put it to deep sleep
- ESP.reset();
- Alarm.delay(1000);
- }
- //if you get here you have connected to the WiFi
- DEBUG_print("WiFi Mode, IP address: ");
- }
- DEBUG_println(WiFi.localIP());
- // Store IP on Google Dynamic DNS - doesn't work yet
- //dynDNS();
- // Match the request for the web server
- webServer.on("/", mainPage);
- webServer.on("/ACT=OPEN", openDoor);
- webServer.on("/ACT=CLOSE", closeDoor);
- webServer.on("/ACT=LON", lightOn);
- webServer.on("/ACT=LOFF", lightOff);
- webServer.on("/SAVE", []()
- {
- int ltz = (int)webServer.arg("timezone").toInt();
- if ((ltz > -13) || (ltz < 15))
- {
- timezone = ltz;
- // save the new Time Zone value in eeprom
- writeTZ(timezone);
- }
- mainPage();
- });
- webServer.on("/RESET", resetToAPPage);
- webServer.on("/CONFIG", configPage);
- webServer.on("/AP", doAP);
- webServer.on("/WIFI", doWiFi);
- // Start the web server
- webServer.begin();
- getTimeZone(); // retrieve timezone from eprom
- setTheClock(); // wait for GPS fix and then set the date/time
- // create the alarms
- // schedule alarms for today, do it once now
- Alarm.timerOnce(60, setAllAlarmsForTheDay);
- // every hour, sync the clock
- Alarm.timerRepeat(60 * 60, setTheClock);
- // recalculate times and schedule alarms for the day. Do it around middle of the night
- Alarm.alarmRepeat(1, 30, 0, setAllAlarmsForTheDay);
- }
- void loop()
- {
- webServer.handleClient();
- Alarm.delay(0);
- }
- String makeButton(String action, String text)
- {
- String btn = HTTP_BUTTON_COOP;
- btn.replace("{ACT}", action);
- btn.replace("{TXT}", text);
- return btn;
- }
- void mainPage()
- {
- String page = HTTP_BEGIN_COOP;
- page += "Coop time is: " + String(hour()) + ":" + String(niceMinuteSecond(minute())) + ", " + String(day()) + "/" + String(month()) + "/" + String(year()) + "<br>";
- page += "Door open today: " + String(todaySunRiseHour) + ":" + String(niceMinuteSecond(todaySunRiseMinute)) + "<br>";
- page += "Door close today: " + String(todaySunSetHour + 1) + ":" + String(niceMinuteSecond(todaySunSetMinute)) + "<br>";
- webServer.on("/ACT=OPEN", openDoor);
- webServer.on("/ACT=CLOSE", closeDoor);
- webServer.on("/ACT=LON", lightOn);
- webServer.on("/ACT=LOFF", lightOff);
- if (isDoorOpen)
- {
- page += makeButton("/ACT=CLOSE", "Close door");
- }
- else
- {
- page += makeButton("/ACT=OPEN", "Open door");
- }
- if (isLightOn())
- {
- page += makeButton("/ACT=LOFF", "Light off");
- }
- else
- {
- page += makeButton("/ACT=LON", "Light on");
- }
- page += HTTP_LINK_CONFIG_COOP;
- // bottom of the html page
- page += HTTP_END_COOP;
- webServer.send(200, "text/html", page);
- }
- void resetToAPPage()
- {
- String page = HTTP_BEGIN_COOP;
- page += "Do you want to run as AP or<br>do you want to connect to a WiFi network?";
- page += makeButton("/AP", "Make AP");
- page += makeButton("/WIFI", "Connect to WiFi");
- page += HTTP_END_COOP;
- webServer.send(200, "text/html", page);
- }
- void doAP()
- {
- setAPFlag();
- String page = HTTP_BEGIN_COOP;
- page += "Creating AP and rebooting...";
- page += HTTP_END_COOP;
- webServer.send(200, "text/html", page);
- WiFiManager wifi;
- DEBUG_println(wifi.getConfigPortalSSID());
- wifi.resetSettings();
- ESP.reset();
- Alarm.delay(5000);
- }
- void doWiFi()
- {
- unsetAPFlag();
- String page = HTTP_BEGIN_COOP;
- page += "Creating WiFi and rebooting...";
- page += HTTP_END_COOP;
- WiFiManager wifi;
- DEBUG_println(wifi.getConfigPortalSSID());
- wifi.resetSettings();
- ESP.reset();
- Alarm.delay(5000);
- }
- void configPage()
- {
- String page = HTTP_BEGIN_COOP;
- // ask the user to select time zone
- page += "Please enter your Time Zone (-12..14): <br>";
- page += HTTP_FORM_SAVE_COOP;
- page.replace("{TZ}", String(timezone));
- page.replace("{VER}", COOP_VERSION);
- page += HTTP_LINK_RESET_COOP;
- // bottom of the html page
- page += HTTP_END_COOP;
- webServer.send(200, "text/html", page);
- }
- void configModeCallback(WiFiManager *myWiFiManager)
- {
- DEBUG_println("Entered config mode");
- DEBUG_println(WiFi.softAPIP());
- }
- boolean syncTimeWithGPS()
- {
- // Dispatch incoming characters
- while (SerialGPS.available() > 0)
- gps.encode(SerialGPS.read());
- if (gps.date.isUpdated() && gps.time.isUpdated() && gps.location.isUpdated() && gps.location.isValid())
- {
- latitude = gps.location.lat();
- longitude = gps.location.lng();
- setTime(gps.time.hour(), gps.time.minute(), gps.time.second(), gps.date.day(), gps.date.month(), gps.date.year());
- adjustTime(timezone * SECS_PER_HOUR);
- showDateTime();
- return true;
- }
- else
- return false;
- }
- void lightOn()
- {
- digitalWrite(light_relay, HIGH);
- mainPage();
- }
- void lightOff()
- {
- digitalWrite(light_relay, LOW);
- mainPage();
- }
- void openDoor()
- {
- DEBUG_println("Opening door...");
- showDateTime();
- digitalWrite(door_relay1, LOW);
- isDoorOpen = true;
- mainPage();
- }
- void closeDoor()
- {
- DEBUG_println("Closing door...");
- showDateTime();
- digitalWrite(door_relay1, HIGH);
- isDoorOpen = false;
- mainPage();
- }
- boolean isLightOn()
- {
- return digitalRead(light_relay) == HIGH;
- }
- void setAllAlarmsForTheDay()
- {
- calculateTodaysSunriseSunset();
- // creating two of each just to make sure
- showATime(todaySunRiseHour, todaySunRiseMinute);
- Alarm.alarmOnce(todaySunRiseHour, todaySunRiseMinute, 0, openDoor);
- Alarm.alarmOnce(todaySunRiseHour + 1, todaySunRiseMinute, 0, openDoor);
- showATime(todaySunSetHour + 1, todaySunSetMinute);
- Alarm.alarmOnce(todaySunSetHour + 1, todaySunSetMinute, 0, closeDoor);
- Alarm.alarmOnce(todaySunSetHour + 2, todaySunSetMinute, 0, closeDoor);
- // create the alarm to turn the light on before sunset
- Alarm.alarmOnce(todaySunSetHour, todaySunSetMinute, 0, lightOn);
- // ...and off after door closing
- Alarm.alarmOnce(todaySunSetHour + 2, todaySunSetMinute, 0, lightOff);
- }
- void getTimeZone()
- {
- timezone = readTZ();
- if ((timezone < -12) || (timezone > 14))
- {
- DEBUG_println(timezone);
- DEBUG_println("Time Zone not set, using default -8 (PST)");
- writeTZ(-8);
- }
- else
- {
- DEBUG_print("Time Zone found: ");
- DEBUG_println(timezone);
- }
- }
- void setTheClock()
- {
- DEBUG_println("Please wait, syncing the clock with GPS...");
- while (!syncTimeWithGPS())
- {
- delay(10);
- }
- }
- void showDateTime()
- {
- // digital clock display of the time
- DEBUG_print(hour());
- DEBUG_print(":");
- DEBUG_print(niceMinuteSecond(minute()));
- DEBUG_print(":");
- DEBUG_print(niceMinuteSecond(second()));
- DEBUG_print(" ");
- DEBUG_print(day());
- DEBUG_print("/");
- DEBUG_print(month());
- DEBUG_print("/");
- DEBUG_print(year());
- DEBUG_println();
- }
- void showATime(int h, int m)
- {
- DEBUG_print(h);
- DEBUG_print(":");
- DEBUG_println(niceMinuteSecond(m));
- }
- void calculateTodaysSunriseSunset()
- {
- //Time Lord constants
- //tl_second=0, tl_minute=1, tl_hour=2, tl_day=3, tl_month=4, tl_year=5
- sunrisesunset.TimeZone(timezone * 60);
- sunrisesunset.Position(latitude, longitude);
- byte rise[] = { 0, 0, 12, (byte)day(), (byte)month(), (byte)year() };
- byte set[] = { 0, 0, 12, (byte)day(), (byte)month(), (byte)year() };
- sunrisesunset.SunRise(rise);
- todaySunRiseHour = rise[tl_hour];
- todaySunRiseMinute = rise[tl_minute];
- sunrisesunset.SunSet(set);
- todaySunSetHour = set[tl_hour];
- todaySunSetMinute = set[tl_minute];
- }
- template <class T> int EEPROM_writeAnything(int ee, const T& value);
- template <class T> int EEPROM_readAnything(int ee, T& value);
- // Read TimeZone from EEPROM
- int readTZ()
- {
- int tz;
- EEPROM_readAnything(0, tz);
- DEBUG_print("Found TZ: ");
- DEBUG_println(tz);
- return tz;
- }
- // Write TimeZone from EEPROM
- void writeTZ(int tz)
- {
- DEBUG_print("New TZ: ");
- DEBUG_println(tz);
- EEPROM_writeAnything(0, tz);
- }
- void setAPFlag()
- {
- EEPROM_writeAnything(20, true);
- }
- void unsetAPFlag()
- {
- EEPROM_writeAnything(20, false);
- }
- boolean isAPFlag()
- {
- boolean ap;
- EEPROM_readAnything(20, ap);
- return ap;
- }
- template <class T> int EEPROM_writeAnything(int ee, const T& value)
- {
- const byte* p = (const byte*)(const void*)&value;
- unsigned int i;
- for (i = 0; i < sizeof(value); i++)
- EEPROM.write(ee++, *p++);
- EEPROM.commit();
- return i;
- }
- template <class T> int EEPROM_readAnything(int ee, T& value)
- {
- byte* p = (byte*)(void*)&value;
- unsigned int i;
- for (i = 0; i < sizeof(value); i++)
- *p++ = EEPROM.read(ee++);
- return i;
- }
- void dynDNS()
- {
- // put the IP on a DYNDNS for easy access
- HTTPClient http;
- String dyndns = GOOGLE_DYNDNS;
- dyndns.replace("{IP}", WiFi.localIP().toString());
- http.begin(dyndns); //HTTP
- int httpCode = http.GET();
- if (httpCode == HTTP_CODE_OK)
- {
- String payload = http.getString();
- DEBUG_println(payload);
- }
- }
- String niceMinuteSecond(int m)
- {
- char sz[4];
- sprintf(sz, "%02d", m);
- return String(sz);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement