Bianchi Rider
Published © GPL3+

Garage Door Opener and Smoke Detector With Blynk

Open, close and monitor a garage door opener with a smart phone using a Particle Photon and the Blynk application.

IntermediateShowcase (no instructions)10 hours4,298
Garage Door Opener and Smoke Detector With Blynk

Things used in this project

Hardware components

Photon
Particle Photon
×1
Relay (generic)
I used a 4 channel relay, a 3 channel will work
×1
Magnetic Switch
×2
Resistor 10k ohm
Resistor 10k ohm
×1
MQ2 Gas Sensor
×1
YuRobot Breadboard Power Supply
Need this if using the MQ2 gas sensor
×1
SparkFun Atmospheric Sensor Breakout - BME280
SparkFun Atmospheric Sensor Breakout - BME280
BME280
×1
Kidde i4618AC Smoke Alarm
Not hard wired to main, battery operated.
×1
HT7333A
Transistor for 9 volt signal from smoke detector.
×1
Resistor 1k ohm
Resistor 1k ohm
For smoke detector
×1

Software apps and online services

Blynk
Blynk
ThingSpeak API
ThingSpeak API
OpenWeather

Story

Read more

Schematics

particle_photon_garage_door_nGk3YQeEdK.fzz

Code

Magic Garage Door Code

C/C++
Any input for improvement and simplification of the code will be appreciated.
/*
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();
}

Credits

Bianchi Rider

Bianchi Rider

0 projects • 1 follower

Comments