/*
This works well with a Sears Craftsman Model 139 Garage Door Opener. However
if using it with a safety reverse you will nee=to restart the opener and Photon to resume operating IF the safety reverse is activated.
Blynk Virtual Pins
V0 Relay channel 3 Switch button
V1 Relay channel 1 Press button
V3 Door location (0,50,100)
V5 Door status (Closed,Halfway,Open)
V6 Humidity- direct from BME280
V7 Temperature- direct from BME280
V8 Wifi signal
V9 Gas sensor (MQ-2)
V10 Terminal Widget
V11 Pressure- direct from BME280
V12 Outside pressure from OpenWeatherMap.org
V13 Removed Gas sensor (MQ9). Not enough power from YWRobot
V14 Outside humidity from OpenWeatherMap.org
V15 Webhook from OpenWeather.org
V16 Outside temperature from OpenWeatherMap.org
V17 Outside wind speed and direction from OpenWeatherMap.org
V18 Door cycle count ADDED 12/17/2018
Photon Pins
D0 SCA BME280
D1 SCL BME280
D2 Relay channel 3
D3 Side switch
D4 Smoke alarm
D5 Relay channel 2
D6 Relay channel 1 (Activate Door button on Blynk)
D7 Center switch
A0 Gas sensor
EEPROM Locations
10 Sunrise Unix time from OpenWeather
50 Sunset Unix time from OpenWeather
100 Time of system.reset from loss of WiFi
*/
/*
Thingspeak Info
https://api.thingspeak.com/update
Channel ID xxxxxxxxxx
Write API key xxxxxxxxxxxx
Read API key xxxxxxxxxxx
*/
/*
OpenWeather.org Info
APIKEY = "xxxxxxxxxxxxxxxxxxxxxxxxx";// OpenWeather.org
CityID = "4924006"; //Muncie, IN
*/
#include <CE_BME280.h>
// Using blynk library v 0.5.1
#include <blynk.h>
#include <ThingSpeak.h>
#define BLYNK_PRINT Serial
#define RelayCH1 D6 // Relay channel 1 (V1)
#define RelayCH2 D5 // Relay channel 2
#define RelayCH3 D2 // Relay channel 3 (V0- lock)
#define Kidde D4 // Kidde i4618AC smoke alarm
char auth[] = "xxxxxxxxxxxxxxxxxxxxxxx"; // Top secret Blynk Auth
BlynkTimer timer;
CE_BME280 bme; // I2C
float t; // BME 280 temperature
float h; // BME 280 humidity
float p; // BME280 pressure
int g; // Gas sensor MQ2 (Combustible Gas, Smoke)
float c; // CO sensor MQ9 (Carbon Monoxide, Coal Gas, Liquefied Gas)
int w; // Wifi strength
float seaLevelhPa = 1035.7;
int DoorLocation; // Door location for history graph
float TimerStuck; // Counter for door stuck in between
float TimerLate; // Counter for door open when cold or stuck. Avoid nusiance notifications
float LateTimer; // Counter for door open during late hours. Avoid nusiance notifications
float NotifyCounter; // Counter to prevent excess notifications for door open
float NotifyLate; // Counter to prevent excess notifications for door open at night
int NotifyGas; // Counter for high gas
int LockCounter; // Counter for lock
int CountOpen; // Counter to prevent overwrite
int CountClose; // Counter to prevent overwrite
const int SideSwitch = D3; // Side (south) switch
const int CenterSwitch = D7; // Center (north) switch V4
const int GasPin = A0; // Gas sensor (MQ2)
int GasAlarm = 1800; // Gas sensor alarm level
String DoorStatus;
String ConnectStatus;
int CountConnect; // Counter for WiFi connection
int SmokeCount; // Counter to notify if smoke alarm is active
int SmokeClear; // Counter to notify 'all clear' on the smoke alarm
int LowBattery; // Counter for analogRead(r dete)ction of low smoke detector battery
int BatteryCount; // Counter for detection of low smoke detector battery
int BatteryHold; // Counter for detection of low smoke detector battery
int BatteryTime; // Counter for detection of low smoke detector battery
String SmokeText;
String WifiConnect;
String OpenWeatherData;
String OpenWeatherCopy;
String parsedata;
String winddirection;
String speedstr;
String PrintIt;
int winddegreeint;
int sunriseint; // Unix time sunrise
int sunsetint; // Unix time sunset
int startingindex;
int getparseend;
int getparsestart;
float temperature; // Outside temperature
float pressure; // Outside pressure
float windspeedfloat;
WidgetTerminal terminal(V10);
// Begin ThingSpeak stuff
TCPClient client; // Initialize the TCP client library
unsigned int ChannelNumber = xxxxxxxxxx;
const char * WriteAPIKey = "xxxxxxxxxxxxxx";
String server = "api.thingspeak.com"; // ThingSpeak Server
const char * ReadAPIKey = "xxxxxxxxxxxxxxxx";
// End ThingSpeak stuff
int NoWiFi; // To reboot Particle if no wifi
String WiFiText;
int WiFiTest;
int WiFiGet;
long DoorCount;
//
void setup() {
delay(5000); // Allow board to settle.... so they say
WiFi.setCredentials("xxxxxxx", "xxxxxx");
Blynk.begin(auth);
if (!bme.begin()) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
ThingSpeak.begin(client);
digitalWrite(RelayCH1,LOW);
digitalWrite(RelayCH2,LOW);
digitalWrite(RelayCH3,LOW);
timer.setInterval(1000, sendStatus); // Send data to Blynk once a second
timer.setInterval(60000, sendAtm); // Send data to Blynk once a minute. Send outside temperature data to Blynk.
timer.setInterval(300000, sendWebhook); // Send outside temperature data to Blynk every 5 minutes
pinMode(SideSwitch, INPUT_PULLDOWN); // Door Switches D3
pinMode(CenterSwitch, INPUT_PULLDOWN); // Door Switches D7
pinMode(RelayCH1, OUTPUT); // Relay 1 D6
pinMode(RelayCH2, OUTPUT); // Relay 2 D5
pinMode(RelayCH3, OUTPUT); // Relay 3. D2 For lock out to prevent accidental opening
pinMode(Kidde, INPUT); // Kidde smoke alarm D4
pinMode(GasPin,INPUT); // MQ2 A0
NotifyCounter = 0; // Initialize value
NotifyLate = 0; // Initialize value
NotifyGas = 0; // Initialize value
LockCounter = 0; // Initialize value
CountConnect = 0; // Initialize value
SmokeCount = 0; // Initialize value
SmokeClear = 0; // Initialize value;
LowBattery = 0; // For low battery detection on smoke alarm
BatteryCount = 0;
BatteryHold = 0;
BatteryTime = 0;
NoWiFi = 0; // Initialize value
WiFiTest = 0;
// Stick this in to get correct time when restarting. DST fun
int month = Time.month();
int day = Time.day();
int weekday = Time.weekday();
int previousSunday = day - weekday + 1;
if (month < 3 || month > 11) {
Time.zone(-5);
}else if (month > 3 && month < 11) {
Time.zone(-4);
}else if (month == 3) {
int offset = (previousSunday >= 8)? -4 : -5;
Time.zone(offset);
} else{
int offset = (previousSunday <= 0)? -4 : -5;
Time.zone(offset);
}
// Determine if power up from loss of Wifi
EEPROM.get(100, WiFiGet);
if (WiFiGet > 9){
terminal.println(Time.format(Time.now(),"%m.%d %I:%M %p Loss of WiFi. Rebooted by Particle code"));
terminal.flush();
EEPROM.put(100,0); //
}
if (WiFi.ready() == 1){
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Connected to network")); // Display restart after power loss or download
terminal.flush();
}
if (Particle.connected() == 1){
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Connected to Particle Cloud")); // Display restart after power loss or download
terminal.flush();
}
DoorCount = ThingSpeak.readLongField(ChannelNumber, 7, ReadAPIKey);
Blynk.virtualWrite(V18, DoorCount);
}
// End of Setup
BLYNK_CONNECTED() {
Blynk.syncVirtual(V10); // Terminal Widget
}
//
// Send data to Blynk
//
void myHandler(const char *event, const char *data) {
// Handle the integration response
}
void sendStatus() // Once every second
{
//
// Check door for closed status
//
if (digitalRead(SideSwitch) == LOW and digitalRead(CenterSwitch) == HIGH ) {
Blynk.setProperty(V5, "color","#23C48E");
DoorStatus = "Door Closed"; // V5
TimerStuck = millis();
DoorLocation = 0;
NotifyCounter = 0;
NotifyLate = 0;
digitalWrite(RelayCH2,LOW); // Need to keep door switch on wall operable
if (CountClose < 1) {
Blynk.setProperty(V0, "offLabel", "Locked");
Blynk.setProperty(V0, "color", "#ff0000"); //Color to red
Blynk.setProperty(V1, "offLabel", "Locked");
Blynk.setProperty(V1, "color", "#ff0000"); //Color to red
Blynk.setProperty(V1, "label", "Activate Door");
Blynk.virtualWrite(V0, 0); // Change display to locked
digitalWrite(RelayCH3,LOW);
digitalWrite(RelayCH1,LOW);
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Closed"));
terminal.flush();
CountClose = 1; // Prevent overwrite of time closed while closed
CountOpen = 0; // Allow overwrite of time opened
}
}
//
// Check door for open status
//
if (digitalRead(SideSwitch) == HIGH and digitalRead(CenterSwitch) == LOW) {
Blynk.setProperty(V5, "color","#ff0000"); // Color to green
DoorStatus = "Door Open"; // V5
TimerStuck = millis();
DoorLocation = 100;
digitalWrite(RelayCH2,LOW); // Need this to keep the manual door switch on wall operable
if (CountOpen < 1) {
Blynk.setProperty(V0, "offLabel", "Locked");
Blynk.setProperty(V0, "color", "#ff0000"); // Color to red
Blynk.setProperty(V1, "offLabel", "Locked");
Blynk.setProperty(V1, "color", "#ff0000"); // Color to red
Blynk.setProperty(V1, "label", "Activate Door");
Blynk.virtualWrite(V0, 0); // Change display to locked
digitalWrite(RelayCH3,LOW);
digitalWrite(RelayCH1,LOW);
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Open"));
terminal.flush();
CountOpen = 1;
CountClose = 0;
// Door counter
if (DoorCount == 0) {
DoorCount = ThingSpeak.readLongField(ChannelNumber, 7, ReadAPIKey);
}
DoorCount = DoorCount + 1;
Blynk.virtualWrite(V18, DoorCount);
}
}
//
// Report current status during movement
//
if (digitalRead(SideSwitch)== LOW and digitalRead(CenterSwitch)==LOW and (millis()-TimerStuck)<= 600000) {
if(DoorStatus == "Door Open") {
Blynk.setProperty(V1, "offLabel", "Closing"); // Change button to indicate direction of door movement
Blynk.setProperty(V1, "color", "#ffff00"); // Color to yellow
}
if(DoorStatus == "Door Closed") {
Blynk.setProperty(V1, "offLabel", "Opening"); // Change button to indicate direction of door movement
Blynk.setProperty(V1, "color", "#ffff00"); // Color to yellow
}
Blynk.setProperty(V5, "color","#FFFF00");
DoorStatus = "Halfway";
TimerLate = millis();
DoorLocation = 50;
Blynk.setProperty(V0, "offLabel", "Wait");
Blynk.setProperty(V0, "color", "#ffff00"); // Color to yellow
Blynk.virtualWrite(V0, 0); // Change display to locked
digitalWrite(RelayCH3,LOW); // Need to keep manual door switch on wall operable
digitalWrite(RelayCH1, LOW); // Be sure to reset relay
digitalWrite(RelayCH2,HIGH); // Need to keep manual door switch on wall operable
}
//
// Notify once and report if door is halfway open for more than 10 minutes
//
if (digitalRead(SideSwitch)== LOW and digitalRead(CenterSwitch)==LOW and NotifyCounter < 1 and (millis()-TimerStuck) > 600000) {
DoorStatus = "Door stuck- big trouble";
DoorLocation = 50;
NotifyCounter = 4 ;
Blynk.notify("Door stuck- big trouble");
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Door stuck- big trouble"));
terminal.flush();
}
//
// Notify once and report if both switches read high. Using a delay for notifications as it seems I get false positives
//
if (digitalRead(SideSwitch) == HIGH and digitalRead(CenterSwitch) == HIGH and NotifyCounter < 4) {
DoorStatus = "Switches bad- trouble";
if (millis()-TimerLate > (300000 + 300000 * NotifyCounter)){
DoorLocation = 50;
NotifyCounter = NotifyCounter + 1;
Blynk.notify("Switches bad- trouble");
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Switches bad- trouble"));
terminal.flush();
}
}
//
// End of open door test
//
// Write door location and status
//
Blynk.virtualWrite(V3,DoorLocation);
Blynk.virtualWrite(V5,DoorStatus);
//
// Counter to change from unlocked status to locked status if unlock button inadvertently pressed
//
if (DoorStatus != "Halfway" and digitalRead(RelayCH3 == HIGH)) {
LockCounter = LockCounter + 1;
if (LockCounter > 10){
digitalWrite(RelayCH3,LOW); // Need to keep manual door switch on wall operable
Blynk.virtualWrite(V0, 0); // Change display to locked
Blynk.setProperty(V0, "offLabel", "Locked");
Blynk.setProperty(V0, "color", "#ff0000"); // Color to red
Blynk.setProperty(V1, "offLabel", "Locked");
Blynk.setProperty(V1, "color", "#ff0000"); // Color to red
Blynk.setProperty(V1, "label", "Activate Door");
LockCounter = 0;
}
}
//
// Check smoke alarm status. Notify.
//
if (digitalRead(Kidde) == HIGH){
SmokeCount = SmokeCount + 1;
LowBattery = LowBattery + 1;
BatteryTime = millis();
//
// Detect low battery. Specs say a low battery will beep every 30-40 seconds
//
if (SmokeCount == 1){
BatteryHold = BatteryTime; // Start timer for low battery
}
if ((BatteryTime-BatteryHold) >= 25000 and (BatteryTime-BatteryHold) <= 45000){
BatteryCount = BatteryCount + 1;
BatteryHold = BatteryTime;
}
if (BatteryCount == 3){
Blynk.notify("Smoke alarm battery may be low !");
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Alarm battery may be low"));
terminal.flush();
}
if (SmokeCount == 5){
SmokeClear = 1;
Blynk.virtualWrite(V7,bme.readTemperature() * 9/5 + 32); // Update garage temperature
Blynk.virtualWrite(V9,analogRead(GasPin)); // Current gas/smoke reading
Blynk.notify("Smoke alarm is activated !");
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Smoke alarm activated !"));
terminal.flush();
}
if ((SmokeCount % 120) == 0){
SmokeClear = 1;
Blynk.virtualWrite(V7,bme.readTemperature() * 9/5 + 32); // Update garage temperature
Blynk.virtualWrite(V9,analogRead(GasPin)); // Current gas/smoke reading
Blynk.notify("Smoke alarm has been active for " + String((SmokeCount)/60) + " minutes !");
SmokeText = Time.format(Time.now(), "%m.%d %I:%M %p Smoke alarm active for ") + String((SmokeCount)/60) + " min" ;
terminal.println(SmokeText);
terminal.flush();
}
}
// Notify if smoke alarm stops alarming
if (digitalRead(Kidde) == LOW and SmokeClear == 1 ){
SmokeCount = 0;
SmokeClear = 0;
Blynk.virtualWrite(V7,bme.readTemperature() * 9/5 + 32); // Update garage temperature
Blynk.virtualWrite(V9,analogRead(GasPin)); // Current gas/smoke reading
Blynk.notify("Smoke alarm is clear !");
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Smoke alarm clear !"));
terminal.flush();
}
}
//
// End of void sendStatus every second
//
void sendAtm() // Once every minute
{
// Check WiFi status and reboot particle if no connection.
if (Particle.connected() == 1) {
NoWiFi = 0;
}
else {
NoWiFi = NoWiFi + 1;
}
if (NoWiFi == 3) {
WiFi.off();
}
if (NoWiFi == 4) {
WiFi.on();
WiFiTest = 1;
}
if (NoWiFi > 6) {
EEPROM.put(100,10);
NoWiFi = 0;
delay(500);
System.reset();
}
if (WiFiTest == 1 and Particle.connected() == 1 ) {
WiFiTest == 0;
Blynk.notify("WiFi was off and restarted !");
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p WiFi was off and restarted !"));
terminal.flush();
}
t = bme.readTemperature() * 9/5 + 32; // degrees F;
h = bme.readHumidity();
p = bme.readPressure()* 0.00029529983071445 + 0.9; // Convert to inches mercury and add 0.9 (seems to always be 0.9 less than airport)
g = analogRead(GasPin);
w = abs(WiFi.RSSI());
Blynk.virtualWrite(V6, h); // Current humidity
Blynk.virtualWrite(V7,t); // Current temperature
Blynk.virtualWrite(V8, w); // Wifi -1 db strong, -127 db weak. Make positive for easy charting
Blynk.virtualWrite(V9,g); // A0
Blynk.virtualWrite(V11, p); // Current pressure
Blynk.virtualWrite(V18, DoorCount);
// Connect to ThingSpeak and send data
ThingSpeak.setField(1,DoorLocation);
ThingSpeak.setField(2,g);
ThingSpeak.setField(3,h);
ThingSpeak.setField(4,t);
ThingSpeak.setField(5,p);
ThingSpeak.setField(6,w);
ThingSpeak.setField(7,DoorCount);
ThingSpeak.writeFields(ChannelNumber, WriteAPIKey);
//
// Notify if gas sensor reads high
//
if (g > GasAlarm) { // Increase from 200 to 270 to 1500 to 1800 (late June '18 vacation max)
NotifyGas = NotifyGas + 1;
}
else {
NotifyGas = 0;
}
// Notify every five minutes for 20 minutes
if ((NotifyGas % 5) == 0 and g > GasAlarm and NotifyGas < 21) {
NotifyGas = NotifyGas + 1;
Blynk.notify("Gas sensor is reading high !");
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Gas sensor high at ") + String(g));
terminal.flush();
}
// If gas is still high after 120 minutes, restart notifications
if (NotifyGas == 120) {
NotifyGas = 0;
}
// Sync time once a day and show (and store in EEPROM) sunrise/sunset time
//
if (Time.hour() == 03 and Time.minute() == 10) {
// Set todays sunrise and sunset for open door warning past sunrise. OpenWeather SR/SS changes about and hour before actual SR/SS
EEPROM.put(10, sunriseint);
EEPROM.put(50, sunsetint);
// Correct for DST
int month = Time.month();
int day = Time.day();
int weekday = Time.weekday();
int previousSunday = day - weekday + 1;
if (month < 3 || month > 11) {
Time.zone(-5);
}else if (month > 3 && month < 11) {
Time.zone(-4);
}else if (month == 3) {
int offset = (previousSunday >= 8)? -4 : -5;
Time.zone(offset);
} else{
int offset = (previousSunday <= 0)? -4 : -5;
Time.zone(offset);
}
// End of correct for DST
Particle.syncTime(); // Request time synchronization from the Particle Cloud
terminal.println(Time.format(Time.now(), "%m.%d.%y %I:%M:%S %p Updated Time"));
PrintIt = Time.format(Time.now(), "%m.%d %I:%M %p ") + "Sunrise " + Time.format(sunriseint, "%m.%d %H:%M");
terminal.println(PrintIt);
PrintIt = Time.format(Time.now(), "%m.%d %I:%M %p ") + "Sunset " + Time.format(sunsetint, "%m.%d %H:%M");
terminal.println(PrintIt);
terminal.flush();
}
//
// Reboot particle on Thursday at 2:02AM. Before etablishing sunset/sunrise-warning
//
if (Time.weekday() ==02 and Time.hour() ==02 and Time.minute() == 01) {
terminal.println(Time.format(Time.now(), "%m.%d.%y %I:%M:%S %p Reboot Particle"));
terminal.flush();
}
// Delay reboot by a minute to insure terminal print
if (Time.weekday() == 02 and Time.hour()==02 and Time.minute() == 02) {
System.reset();
}
}
//
// End of void SendAtm every minute
//
// Get data from Openweathermap.org via Webhook widget
//
void sendWebhook() // every 5 minutes to update weather data
{
Blynk.virtualWrite(V15, 1); // Activate the web hook
}
//
// End of void sendWebhook every 5 minutes to update weather data
//
BLYNK_WRITE(V0) // To open door if V0 button is pressed or reinitiate lock
{
int lockvalue = param.asInt();
if(lockvalue==1) {
digitalWrite(RelayCH3,HIGH);
Blynk.setProperty(V0, "color", "#00ff00"); // Color to green
Blynk.setProperty(V0, "onLabel", "Open");
if(digitalRead(SideSwitch) == HIGH and digitalRead(CenterSwitch) == LOW) {
Blynk.setProperty(V1, "color", "#00ff00"); // Color to green
Blynk.setProperty(V1, "offLabel", "Close");
Blynk.setProperty(V1, "label", "Press to close");
}
if (digitalRead(SideSwitch) == LOW and digitalRead(CenterSwitch) == HIGH ) {
Blynk.setProperty(V1, "color", "#00ff00"); // Color to green
Blynk.setProperty(V1, "offLabel", "Open");
Blynk.setProperty(V1, "label", "Press to open");
}
}
if(lockvalue==0) {
digitalWrite(RelayCH3,LOW);
Blynk.setProperty(V0, "color", "#ff0000"); // Color to red
Blynk.setProperty(V1, "offLabel", "Locked");
Blynk.setProperty(V1, "color", "#ff0000"); //Color to red
Blynk.setProperty(V1, "label", "Activate Door");
}
}
BLYNK_WRITE(V1) // To open door if V1 button is pressed
{
int lockvalue2 = param.asInt();
if(lockvalue2==1) {
digitalWrite(RelayCH1,HIGH);
}
}
//
// For web hook every 5 minutes
//
BLYNK_WRITE(V15)
{
OpenWeatherCopy = "";
startingindex = 0;
getparsestart = 0;
getparseend = 0;
String OpenWeatherData = param.asStr();
OpenWeatherCopy = OpenWeatherData; // for some reason using OpenWeatherData directly doesn't work
// Get outside temperature
startingindex = OpenWeatherCopy.lastIndexOf("pressure");
getparseend = OpenWeatherCopy.lastIndexOf(",",startingindex);
getparsestart = OpenWeatherCopy.lastIndexOf(":",startingindex);
parsedata = OpenWeatherCopy.substring(getparsestart + 1, getparseend);
temperature = parsedata.toFloat(); // for open door and low temperature notification
Blynk.virtualWrite(V16, parsedata); // Outside temperature from web hook
temperature = temperature + 1;
//
// Get outside pressure
startingindex = OpenWeatherCopy.lastIndexOf("humidity");
getparseend = OpenWeatherCopy.lastIndexOf(",",startingindex);
getparsestart = OpenWeatherCopy.lastIndexOf(":",startingindex);
parsedata = OpenWeatherCopy.substring(getparsestart + 1, getparseend);
pressure = parsedata.toFloat() * 0.0295301; // convert from mb to inches Hg;
Blynk.virtualWrite(V12, pressure); // Outside temperature from web hook
// Get outside humidity
startingindex = OpenWeatherCopy.lastIndexOf("temp_min");
getparseend = OpenWeatherCopy.lastIndexOf(",",startingindex);
getparsestart = OpenWeatherCopy.lastIndexOf(":",startingindex);
parsedata = OpenWeatherCopy.substring(getparsestart + 1, getparseend);
parsedata = parsedata + "%";
Blynk.virtualWrite(V14, parsedata); // Outside humidity from web hook
// Get sunrise hour and minute
startingindex = OpenWeatherCopy.lastIndexOf("sunset");
getparseend = OpenWeatherCopy.lastIndexOf(",",startingindex);
getparsestart = OpenWeatherCopy.lastIndexOf(":",startingindex);
parsedata = OpenWeatherCopy.substring(getparsestart + 1, getparseend);
sunriseint = parsedata.toInt();
// Get sunset hour and minute
startingindex = OpenWeatherCopy.lastIndexOf("name");
getparseend = OpenWeatherCopy.lastIndexOf("},",startingindex);
getparsestart = OpenWeatherCopy.lastIndexOf(":",getparseend);
parsedata = OpenWeatherCopy.substring(getparsestart + 1, getparseend);
sunsetint = parsedata.toInt();
// Get wind speed
startingindex = OpenWeatherCopy.lastIndexOf("deg");
// In case 'deg' doesn't exist
getparseend = OpenWeatherCopy.lastIndexOf(",",startingindex);
getparsestart = OpenWeatherCopy.lastIndexOf(":",startingindex);
parsedata = OpenWeatherCopy.substring(getparsestart + 1, getparseend);
windspeedfloat = parsedata.toFloat();
if (windspeedfloat >9.9) {
speedstr = String(windspeedfloat,0);
}
else {
speedstr = String(windspeedfloat, 1);
}
// Get wind degree and then convert to a direction
// Check if 'deg' is available
if (startingindex > 350 ) {
winddirection = "NA";
}
else {
// Gust is present at seemingly random times giving incorrect wind direction
// If gust is NOT present
if (OpenWeatherCopy.lastIndexOf("gust") < 0 ){
startingindex = OpenWeatherCopy.lastIndexOf("clouds");
getparseend = OpenWeatherCopy.lastIndexOf("},",startingindex);
getparsestart = OpenWeatherCopy.lastIndexOf(":",startingindex);
parsedata = OpenWeatherCopy.substring(getparsestart + 1, getparseend);
}
// If gust IS present
else
{
startingindex = OpenWeatherCopy.lastIndexOf("gust");
getparseend = OpenWeatherCopy.lastIndexOf(",",startingindex);
getparsestart = OpenWeatherCopy.lastIndexOf(":",startingindex);
parsedata = OpenWeatherCopy.substring(getparsestart + 1, getparseend);
}
winddegreeint = parsedata.toInt();
if (winddegreeint > 22.5 and winddegreeint < 67.5) {
winddirection = "NE";
}
if (winddegreeint >= 67.5 and winddegreeint < 112.5) {
winddirection = "E";
}
if (winddegreeint >= 112.5 and winddegreeint < 157.5) {
winddirection = "SE";
}
if (winddegreeint >= 157.5 and winddegreeint < 202.5) {
winddirection = "S";
}
if (winddegreeint >= 202.5 and winddegreeint < 247.5) {
winddirection = "SW";
}
if (winddegreeint >= 247.5 and winddegreeint < 292.5) {
winddirection = "W";
}
if (winddegreeint >= 292.5 and winddegreeint < 337.5) {
winddirection = "NW";
}
if ((winddegreeint >= 337.5 and winddegreeint < 361) || (winddegreeint <= 22.5)) {
winddirection = "N";
}
}
speedstr = speedstr + " " + winddirection; // String for V17
Blynk.virtualWrite(V17, speedstr);
/////////////////////////////
//
// Notify four times if door open past hours
//
// First...test for open door
//
if (digitalRead(SideSwitch) == HIGH and digitalRead(CenterSwitch) == LOW and NotifyLate < 4) {
// Compare current time vs sunrise and sunset
// Get sunrise and sunset time from EEPROM (ref line 462)
int sunup;
int sundown;
EEPROM.get(10, sunup);
EEPROM.get(50, sundown);
if ((Time.now() >= sundown || Time.now() < sunup)) {
DoorStatus = "CLOSE DOOR"; // V5
// Set timer start time
if (NotifyLate == 0) {
LateTimer = millis();
NotifyLate = 1;
}
//
// Notification if door open for more than 10 minutes if past sunset or before sunrise.
//
if (millis()-LateTimer > (300000 + 300000 * NotifyLate)) {
NotifyLate = NotifyLate + 1; //
Blynk.notify("It's late ! Close the garage door !");
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Late ! Close the door !"));
terminal.flush();
}
}
}
//
// Notify four times and report if door open for more than 10 minutes if temperature is less than 30F.
//
// First...test for open door
//
if (digitalRead(SideSwitch) == HIGH and digitalRead(CenterSwitch) == LOW and NotifyLate < 4) {
if (NotifyCounter < 4 and temperature < 30) {
DoorStatus = "CLOSE DOOR"; // V5
if (millis()-TimerLate > (600000 + 300000 * NotifyCounter)) {
NotifyCounter = NotifyCounter + 1; //
Blynk.notify("It's cold ! Close the garage door !");
terminal.println(Time.format(Time.now(), "%m.%d %I:%M %p Cold ! Close the door !"));
terminal.flush();
}
}
}
}
//
// End of BLYNK_WRITE(V15)
//
//////////////////////////////////////////////////////////////
void loop() {
Blynk.run();
timer.run();
}
Comments