Hardware components | ||||||
![]() |
| × | 2 | |||
| × | 1 | ||||
| × | 2 | ||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
Software apps and online services | ||||||
![]() |
| |||||
![]() |
| |||||
![]() |
|
We don't know about you but we believe that living in a twenty first century means life without boring stuff! Clicking on buttons is old now. Would't it be nice to open your garage door with one easy phrase?! This is why we came up with an easy solution to open the garage door. This system is integrated with Alexa, so all you have to say is "Alexa trigger garage door open" or "close". This short video explains it all.
These pictures show how everything was connected to properly work, nothing fancy.
Magnetic sensors are located in specific locations so that when the garage door slides open or close, the magnet is right near the sensor in order for it to complete the circuit and send the signal through.
For convenience we have added a temperature sensor as well as humidity sensor, in case our garage catches on fire or is flooded. We have also added a second photon that lights an LED on whenever the garage door is open, and turns off the LED whenever the garage door is closed. This can be used as a reassurance that your garage door is closed and your house is safe.
Then Below is the Logs of the code and some results of Thingspeak data which is updated every 10 seconds.
// This #include statement was automatically added by the Particle IDE.
#include "PietteTech_DHT/PietteTech_DHT.h"
// Code inspired by Prof. John Macalpine
/* +-----+
* +----------| USB |----------+
* | +-----+ * |
* DHT11 V(in) -->| [ ] VIN 3V3 [ ] |<-- Relay VCC
* | [ ] GND RST [ ] |
* | [ ] TX VBAT [ ] |
* | [ ] RX [S] [R] GND [ ] |<-- Relay GND
* | [ ] WKP D7 [ ] |
* | [ ] DAC +-------+ D6 [ ] |
* Opensensor -->| [*] A5 | * | D5 [ ] |
* Closedsensor -->| [*] A4 |Photon | D4 [*] |<-- DHT111 AM2301 Sensor
* | [*] A3 | | D3 [ ] |
* | [ ] A2 +-------+ D2 [ ] |
* | [ ] A1 D1 [ ] |
* | [ ] A0 D0 [*] |<-- Garage Door Switch Relay
* | |
* \ [] [______] /
* \_______________________/
*
*
*/
const String key = "HM51Z16VGAII6IX5"; //write key
//--------------Begin DHT------------------
// Example testing sketch for various DHT humidity/temperature sensors
#define DHTPIN D4 // what pin we're connected to
// Uncomment whatever type you're using!
#define DHTTYPE DHT11 // DHT 11
// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
//declaration
void dht_wrapper(); // must be declared before the lib initialization
// Lib instantiate
PietteTech_DHT DHT(DHTPIN, DHTTYPE, dht_wrapper);
// globals
unsigned int DHTnextSampleTime; // Next time we want to start sample
bool bDHTstarted; // flag to indicate we started acquisition
int n; // counter
//---------------End DHT-------------------
unsigned int particleinterval = 100;
unsigned int particlefuncinterval = 10000;
unsigned int ubiinterval = 15000;
unsigned int dhtinterval = 5000;
int garageDoorFunction(String command);
int rssival = 0;
int doorstatus = 1;
int doorcounter = 0;
int closedsensorpin = A4;
int opensensorpin = A5;
const int open = 0;
const int closed = 1;
// Define the pins we're going to call pinMode on
int led = D6; // You'll need to wire an LED to this one to see it blink.
int led2 = D7; // This one is the built-in tiny one to the right of the USB jack
double analog1 = 0;
double analog2 = 0;
double analog1raw = 0;
double analog2raw = 0;
double garagetemp = 70;
double readtemp = 70;
double garagehumid = 0;
char publishString[40];
char doorpublishstring[40];
char doorstatusstring[40];
SYSTEM_MODE(SEMI_AUTOMATIC); //allows for control of Spark.connect() and Spark.process()
// This routine runs only once upon reset
Timer task50ms(50, dodoor);
Timer task10sec(10000,dopublish);
Timer task15sec(15000,updateThingspeak);
Timer taskdht(5000, readdht);
void setup() {
task50ms.start();
task10sec.start();
task15sec.start();
taskdht.start();
pinMode(led, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(A0, INPUT);
pinMode(A1, INPUT);
Serial1.begin(230400); // open serial over USB
//ip = {"IP:", WiFi.localIP()};
//String ip = WiFi.localIP();
Particle.function("GarageDoor", garageDoorFunction);
Particle.variable("analog1", &analog1, DOUBLE); //variables update automatically. Max 4 per particle
Particle.variable("doorcounter", doorcounter);
//Particle.variable("doorstatus", &doorstatus, INT); //variables are viewable on mobicle
Particle.variable("doorstatus", doorstatusstring, STRING); //variables are viewable on mobicle
Particle.variable("garagetemp", &garagetemp, DOUBLE); //variables are viewable on mobicle
Particle.variable("garagehumid", &garagehumid, DOUBLE); //variables are viewable on mobicle
pinMode(opensensorpin, INPUT_PULLUP);
pinMode(closedsensorpin, INPUT_PULLUP);
pinMode(D0, OUTPUT);
//Do DHTINIT
pinMode(DHTPIN, INPUT_PULLUP); //sensor needs pullup resistor.
//End DHTINIT
//-------------Begin UBIDOTS---------------
// request.hostname = "things.ubidots.com";
// request.port = 80;
// request.path = "/api/v1.6/variables/"VARIABLE_ID"/values?token="TOKEN;
//--------------End UBIDOTS----------------
}
// This wrapper is in charge of calling
// mus be defined like this for the lib work
void dht_wrapper() {
DHT.isrCallback();
}
void loop() {
if (Particle.connected() == false){
Particle.connect();
}
analog1raw = analogRead(A0);
analog1 = (analog1 *63 +analog1raw *3.3/4095)/64;
analog2raw = analogRead(A1);
analog2 = (analog2 *63 +analog2raw *3.3/4095)/64;
doDht();
}
void dopublish(){
rssival = WiFi.RSSI();
sprintf(publishString,"%d",rssival);
Particle.publish("RSSI",publishString);
}
void readdht() {
if (!bDHTstarted) { // start the sample
Serial.print("\n");
Serial.print(n);
Serial.print(": Retrieving information from sensor: ");
DHT.acquire();
bDHTstarted = true;
}
}
void dodoor() {
digitalWrite(led, !digitalRead(led)); // Turn ON the LED pins
digitalWrite(led2, !digitalRead(led2));
int opensense = digitalRead(opensensorpin);
int closedsense = digitalRead(closedsensorpin);
if (opensense == LOW) // high,0 = open door, low,1 = closed door
{
if (doorstatus == closed) //check the previous state, if closed, then generate an event
{
strcpy(doorpublishstring, "Open");
Particle.publish("ON",doorpublishstring); // Publishing Open Event for second Photon
doorcounter++;
}
doorstatus = open;
strcpy(doorstatusstring, "Open"); //update particle variable.
}
else if (closedsense == LOW)
{
if (doorstatus == open) //check the previous state, if closed, then generate an event
{
strcpy(doorpublishstring, "Closed");
Particle.publish("OFF",doorpublishstring); //Publishing Close Event for second Photon
doorcounter++;
}
doorstatus = closed;
strcpy(doorstatusstring, "Closed"); //update particle variable.
}
else
{ //if door is neither closed or open, it is in "limbo"
strcpy(doorstatusstring, "Limbo"); //update particle variable.
}
}
/*******************************************************************************
* Function Name : garageDoor
* Description : based on door status, opens or closes the door
* Input : analog 5 - digital input.
* Output : digital 1 - relay to blip and open or close the door
* Return : Value of the pin (0 or 1) in INT type
Returns a negative number on failure
*******************************************************************************/
int garageDoorFunction(String sesame)
{
if(sesame.startsWith("C"))
{
if (doorstatus == open)
{
pinMode(0, OUTPUT);
digitalWrite(0, 1);
delay(250);
digitalWrite(0, 0);
return 1;
}
}
else if (sesame.startsWith("O"))
{
if (doorstatus == closed)
{
pinMode(0, OUTPUT);
digitalWrite(0, 1);
delay(250);
digitalWrite(0, 0);
return 2;
}
}
else if (sesame.startsWith("X"))
{
if (doorstatus == closed){
return 999;
} else
return 123;
}
return -1;
}
/*******************************************************************************
* Function Name : updateThingspeak
* Description : sends variables to ts
* Input : doorstatus global variables
* Output : sends data to ts
* Return : void
*******************************************************************************/
bool updateThingspeak()
{
//delay (2000);
static int count = 0;
Serial.println(count++);
int rssival = WiFi.RSSI();
//sprintf(publishString,"%d",rssival);
//bool success = Particle.publish("RSSI",publishString);
//sprintf(publishString, "%1.4f", checkbattery());
bool success = Particle.publish("thingSpeakWrite_All", +
"{ \"1\": \"" + String(rssival) + "\"," +
"\"2\": \"" + String(garagetemp) + "\"," +
"\"3\": \"" + String(garagehumid) + "\"," +
"\"4\": \"" + String(doorstatus) + "\"," +
"\"5\": \"" + String(doorcounter) + "\"," +
//"\"6\": \"" + String(analog1) + "\"," +
//"\"7\": \"" + String(analog2) + "\"," +
"\"k\": \"" + key + "\" }", 60, PRIVATE);
return success; //if sent, then turn of the send flag, otherwise let it try again.
}
/*******************************************************************************
* Function Name : getDht
* Description : gets temp and humidity
* Input :
* Output :
* Return : void
*******************************************************************************/
void doDht() {
if (!DHT.acquiring()) { // has sample completed?
// get DHT status
int result = DHT.getStatus();
Serial.print("Read DHT sensor: ");
switch (result) {
case DHTLIB_OK:
Serial.println("OK");
garagehumid = DHT.getHumidity();
// Read temperature as Celsius
//garagetemp = DHT.getCelsius();
// Read temperature as Farenheit
garagetemp = DHT.getFahrenheit();
break;
case DHTLIB_ERROR_CHECKSUM:
Serial.println("Error\n\r\tChecksum error");
break;
case DHTLIB_ERROR_ISR_TIMEOUT:
Serial.println("Error\n\r\tISR time out error");
break;
case DHTLIB_ERROR_RESPONSE_TIMEOUT:
Serial.println("Error\n\r\tResponse time out error");
break;
case DHTLIB_ERROR_DATA_TIMEOUT:
Serial.println("Error\n\r\tData time out error");
break;
case DHTLIB_ERROR_ACQUIRING:
Serial.println("Error\n\r\tAcquiring");
break;
case DHTLIB_ERROR_DELTA:
Serial.println("Error\n\r\tDelta time to small");
break;
case DHTLIB_ERROR_NOTSTARTED:
Serial.println("Error\n\r\tNot started");
break;
default:
Serial.println("Unknown error");
break;
}
/*
Serial.print("Humidity (%): ");
Serial.println(DHT.getHumidity(), 2);
Serial.print("Temperature (oC): ");
Serial.println(DHT.getCelsius(), 2);
Serial.print("Temperature (oF): ");
Serial.println(DHT.getFahrenheit(), 2);
Serial.print("Temperature (K): ");
Serial.println(DHT.getKelvin(), 2);
Serial.print("Dew Point (oC): ");
Serial.println(DHT.getDewPoint());
Serial.print("Dew Point Slow (oC): ");
Serial.println(DHT.getDewPointSlow());
*/
n++; // increment counter
bDHTstarted = false; // reset the sample flag so we can take another
}
//Serial.println(Time.timeStr());
}
//Code For subscribing the event from first photon
int led = D7;
void setup() {
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
Particle.subscribe("ON",anything, "200040000147353138383138"); // Recieving Open Event
Particle.subscribe("OFF",anything2, "200040000147353138383138"); // Recieving Close Event
}
void anything(const char *event, const char *data)
{
digitalWrite(led, HIGH);
}
void anything2(const char *event, const char *data)
{
digitalWrite(led, LOW);
}
void loop() {
}
/*
* FILE: PietteTech_DHT.cpp
* VERSION: 0.4
* PURPOSE: Spark Interrupt driven lib for DHT sensors
* LICENSE: GPL v3 (http://www.gnu.org/licenses/gpl.html)
*
* S Piette (Piette Technologies) scott.piette@gmail.com
* January 2014 Original Spark Port
* October 2014 Added support for DHT21/22 sensors
* Improved timing, moved FP math out of ISR
* September 2016 Updated for Particle and removed dependency
* on callback_wrapper. Use of callback_wrapper
* is still for backward compatibility but not used
*
* is still for backward compatibility but not used
* ScruffR
* February 2017 Migrated for Libraries 2.0
* Fixed blocking acquireAndWait()
* and previously ignored timeout setting
*
* Based on adaptation by niesteszeck (github/niesteszeck)
* Based on original DHT11 library (http://playgroudn.adruino.cc/Main/DHT11Lib)
*
*
* With this library connect the DHT sensor to the following pins
* Spark Core: D0, D1, D2, D3, D4, A0, A1, A3, A5, A6, A7
* Particle : any Pin but D0 & A5
* See docs for more background
* https://docs.particle.io/reference/firmware/photon/#attachinterrupt-
*/
/*
Timing of DHT22 SDA signal line after MCU pulls low for 1ms
https://github.com/mtnscott/Spark_DHT/AM2302.pdf
- - - - ----- -- - - -- ------- - -
\ / \ / \ \ /
+ / + / + + /
\ / \ / \ \ /
------ ----- -- - --------
^ ^ ^ ^ ^
| Ts | Tr | Td | Te |
Ts : Start time from MCU changing SDA from Output High to Tri-State (Hi-Z)
Spec: 20-200us Tested: < 65us
Tr : DHT response to MCU controlling SDA and pulling Low and High to
start of first data bit
Spec: 150-170us Tested: 125 - 200us
Td : DHT data bit, falling edge to falling edge
Spec: '0' 70us - 85us Tested: 60 - 110us
Spec: '1' 116us - 130us Tested: 111 - 155us
Te : DHT releases SDA to Tri-State (Hi-Z)
Spec: 45-55us Not Tested
*/
#include "PietteTech_DHT.h"
#if !defined(word)
// Thanks to Paul Kourany for this word type conversion function
uint16_t word(uint8_t high, uint8_t low) {
uint16_t ret_val = low;
ret_val += (high << 8);
return ret_val;
}
#endif
/*
* NOTE: callback_wrapper is only here for backwards compatibility with v0.3 and earlier
* it is no longer used or needed
*/
PietteTech_DHT::PietteTech_DHT(uint8_t sigPin, uint8_t dht_type, void(*callback_wrapper)()) {
begin(sigPin, dht_type);
_firstreading = true;
}
/*
* NOTE: callback_wrapper is only here for backwards compatibility with v0.3 and earlier
* it is no longer used or needed
*/
void PietteTech_DHT::begin(uint8_t sigPin, uint8_t dht_type, void(*callback_wrapper)()) {
_sigPin = sigPin;
_type = dht_type;
pinMode(sigPin, OUTPUT);
digitalWrite(sigPin, HIGH);
_lastreadtime = 0;
_state = STOPPED;
_status = DHTLIB_ERROR_NOTSTARTED;
}
int PietteTech_DHT::acquire() {
// Check if sensor was read less than two seconds ago and return early
// to use last reading
unsigned long currenttime = millis();
if (!_firstreading && ((currenttime - _lastreadtime) < 2000)) {
// return last correct measurement, (this read time - last read time) < device limit
return DHTLIB_ACQUIRED;
}
if (_state == STOPPED || _state == ACQUIRED) {
/*
* Setup the initial state machine
*/
_firstreading = false;
_lastreadtime = currenttime;
_state = RESPONSE;
#if defined(DHT_DEBUG_TIMING)
/*
* Clear the debug timings array
*/
for (int i = 0; i < 41; i++) _edges[i] = 0;
_e = &_edges[0];
#endif
/*
* Set the initial values in the buffer and variables
*/
for (int i = 0; i < 5; i++) _bits[i] = 0;
_cnt = 7;
_idx = 0;
_hum = 0;
_temp = 0;
/*
* Toggle the digital output to trigger the DHT device
* to send us temperature and humidity data
*/
pinMode(_sigPin, OUTPUT);
digitalWrite(_sigPin, LOW);
if (_type == DHT11)
delay(18); // DHT11 Spec: 18ms min
else
delayMicroseconds(1500); // DHT22 Spec: 0.8-20ms, 1ms typ
pinMode(_sigPin, INPUT); // Note Hi-Z mode with pullup resistor
// will keep this high until the DHT responds.
/*
* Attach the interrupt handler to receive the data once the DHT
* starts to send us data
*/
_us = micros();
attachInterrupt(_sigPin, &PietteTech_DHT::_isrCallback, this, FALLING);
return DHTLIB_ACQUIRING;
}
else
return DHTLIB_ERROR_ACQUIRING;
}
int PietteTech_DHT::acquireAndWait(uint32_t timeout) {
acquire();
uint32_t start = millis();
while (acquiring() && (timeout == 0 || ((millis() - start) < timeout))) Particle.process();
if (acquiring())
{
_status = DHTLIB_ERROR_RESPONSE_TIMEOUT;
}
return getStatus();
}
/*
* NOTE: isrCallback is only here for backwards compatibility with v0.3 and earlier
* it is no longer used or needed
*/
void PietteTech_DHT::isrCallback() { }
void PietteTech_DHT::_isrCallback() {
unsigned long newUs = micros();
unsigned long delta = (newUs - _us);
_us = newUs;
if (delta > 6000) {
_status = DHTLIB_ERROR_ISR_TIMEOUT;
_state = STOPPED;
detachInterrupt(_sigPin);
return;
}
switch (_state) {
case RESPONSE: // Spec: 80us LOW followed by 80us HIGH
if (delta < 65) { // Spec: 20-200us to first falling edge of response
_us -= delta;
break; //do nothing, it started the response signal
} if (125 < delta && delta < 200) {
#if defined(DHT_DEBUG_TIMING)
*_e++ = delta; // record the edge -> edge time
#endif
_state = DATA;
}
else {
detachInterrupt(_sigPin);
_status = DHTLIB_ERROR_RESPONSE_TIMEOUT;
_state = STOPPED;
#if defined(DHT_DEBUG_TIMING)
*_e++ = delta; // record the edge -> edge time
#endif
}
break;
case DATA: // Spec: 50us low followed by high of 26-28us = 0, 70us = 1
if (60 < delta && delta < 155) { //valid in timing
_bits[_idx] <<= 1; // shift the data
if (delta > 110) //is a one
_bits[_idx] |= 1;
#if defined(DHT_DEBUG_TIMING)
*_e++ = delta; // record the edge -> edge time
#endif
if (_cnt == 0) { // we have completed the byte, go to next
_cnt = 7; // restart at MSB
if (++_idx == 5) { // go to next byte, if we have got 5 bytes stop.
detachInterrupt(_sigPin);
// Verify checksum
uint8_t sum = _bits[0] + _bits[1] + _bits[2] + _bits[3];
if (_bits[4] != sum) {
_status = DHTLIB_ERROR_CHECKSUM;
_state = STOPPED;
}
else {
_status = DHTLIB_OK;
_state = ACQUIRED;
_convert = true;
}
break;
}
}
else _cnt--;
}
else if (delta < 10) {
detachInterrupt(_sigPin);
_status = DHTLIB_ERROR_DELTA;
_state = STOPPED;
}
else {
detachInterrupt(_sigPin);
_status = DHTLIB_ERROR_DATA_TIMEOUT;
_state = STOPPED;
}
break;
default:
break;
}
}
void PietteTech_DHT::convert() {
// Calculate the temperature and humidity based on the sensor type
switch (_type) {
case DHT11:
_hum = _bits[0];
_temp = _bits[2];
break;
case DHT22:
case DHT21:
_hum = word(_bits[0], _bits[1]) * 0.1;
_temp = (_bits[2] & 0x80 ?
-word(_bits[2] & 0x7F, _bits[3]) :
word(_bits[2], _bits[3])) * 0.1;
break;
}
_convert = false;
}
bool PietteTech_DHT::acquiring() {
if (_state != ACQUIRED && _state != STOPPED)
return true;
return false;
}
int PietteTech_DHT::getStatus() {
return _status;
}
float PietteTech_DHT::getCelsius() {
DHT_CHECK_STATE;
return _temp;
}
float PietteTech_DHT::getHumidity() {
DHT_CHECK_STATE;
return _hum;
}
float PietteTech_DHT::getFahrenheit() {
DHT_CHECK_STATE;
return _temp * 9 / 5 + 32;
}
float PietteTech_DHT::getKelvin() {
DHT_CHECK_STATE;
return _temp + 273.15;
}
/*
* Added methods for supporting Adafruit Unified Sensor framework
*/
float PietteTech_DHT::readTemperature() {
acquireAndWait();
return getCelsius();
}
float PietteTech_DHT::readHumidity() {
acquireAndWait();
return getHumidity();
}
// delta max = 0.6544 wrt dewPoint()
// 5x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double PietteTech_DHT::getDewPoint() {
DHT_CHECK_STATE;
double a = 17.271;
double b = 237.7;
double temp_ = (a * (double)_temp) / (b + (double)_temp) + log((double)_hum / 100);
double Td = (b * temp_) / (a - temp_);
return Td;
}
// dewPoint function NOAA
// reference: http://wahiduddin.net/calc/density_algorithms.htm
double PietteTech_DHT::getDewPointSlow() {
DHT_CHECK_STATE;
double a0 = (double) 373.15 / (273.15 + (double)_temp);
double SUM = (double)-7.90298 * (a0 - 1.0);
SUM += 5.02808 * log10(a0);
SUM += -1.3816e-7 * (pow(10, (11.344*(1 - 1 / a0))) - 1);
SUM += 8.1328e-3 * (pow(10, (-3.49149*(a0 - 1))) - 1);
SUM += log10(1013.246);
double VP = pow(10, SUM - 3) * (double)_hum;
double T = log(VP / 0.61078); // temp var
return (241.88 * T) / (17.558 - T);
}
{
"event": "thingSpeakWrite_",
"url": "https://api.thingspeak.com/update",
"requestType": "POST",
"form": {
"api_key": "{{k}}",
"field1": "{{1}}",
"field2": "{{2}}",
"field3": "{{3}}",
"field4": "{{4}}",
"field5": "{{5}}",
"field6": "{{6}}",
"field7": "{{7}}",
"field8": "{{8}}",
"latitude": "{{a}}",
"longitude": "{{o}}",
"elevation": "{{e}}",
"status": "{{s}}"
},
"mydevices": true,
"noDefaults": true,
"location": true
}
Comments