Tuesday, June 20, 2017

(#25) My IoT Garage Door Closer

Problem with a 'p'

There's a big problem with leaving your garage door open at night.

And the problem is that the thieves never take the stuff you want them to take. 

Do they grab the box of outdated college text books from 1985? 
No. 

Do they grab the mostly-empty can of Oldham Tudor Earth Tone brown paint you bought in 1995 when that color was in vogue? 
No. 



How about the bicycle pump that still works, sort of? No. The really-broken-but-I-can-fix-it lawn chair? Nope.


Then there's a big problem with big problems (in my head) and that's that I tend to avoid the cost-effective and highly reliable solutions out there and pursue a DIY approach.

And there's a big problem with a dearth of clip-art about leaving your garage door open at night. So instead of a nice picture of a wide-open garage door, I'm using a picture of what I can only surmise is a puzzled burglar who came completely equipped with a big bag of break-in tools only to find a house, well lit with windows and doors wide open.



Admiral Gial Ackbar's warning seems appropriate.


I'm not naming names...


So, someone in our house tends to leave the garage door open. And that's a problem. We've already got the sensors installed to detect the open door. All we need to do is provide a means to close it.

The 'net has dozens of posts on how to build a garage door closer with a Raspberry Pi and a relay and I stole one approach from here. Thank you Andrew https://github.com/andrewshilliday/garage-door-controller

My Raspberry Pi 2B controller is wired like this:


5V power to the relay comes from an old, USB charger cable.

Python Relay Control

The python code to control the relay is simple

import RPi.GPIO as GPIO
from time import sleep


class Relay(object):

   def __init__(self):
       print 'Creating and initializing relay class'
       GPIO.setwarnings(False)
       GPIO.setmode(GPIO.BCM)

       # I've wired door 1 to relay 1 to GPIO pin 23
       # door 2 is relay 2 on GPIO pin 24
       # sleep 0.25 seconds between relay trigger low/high to simulate button press

       self.door1_pin_number = 23
       self.door2_pin_number = 24
       self.latch_time = 0.25

       # Set relay pins as output
       GPIO.setup(self.door1_pin_number, GPIO.OUT, initial=GPIO.HIGH)
       GPIO.setup(self.door2_pin_number, GPIO.OUT, initial=GPIO.HIGH)

   def trigger(self, door_id=1):
       if door_id == 1:
           pin_number = self.door1_pin_number
       else:
           pin_number = self.door2_pin_number

       print 'Relay Trigger invoked on pin number', pin_number
       GPIO.output(pin_number, GPIO.LOW)
       sleep(self.latch_time)
       GPIO.output(pin_number, GPIO.HIGH)

   def cleanup(self):
       print 'Cleaning up relay'
       GPIO.output(self.door1_pin_number, GPIO.HIGH)
       GPIO.output(self.door2_pin_number, GPIO.HIGH)
       GPIO.cleanup(self.door1_pin_number)
       GPIO.cleanup(self.door2_pin_number)


Passing MQTT Messages (AGAIN!)


My Home Automation approach is based on systems passing JSON messages over MQTT. That means it's time to define the JSON messages that'll control our controller.

The Command Packet:
{  
   "topic":"GDCTL/COMMAND",
   "datetime":"2017-06-20T20:09:49",
   "doorID":1,
   "command":"close"
}

Valid commands are “open”, “close” and “trigger”. The first two do what you'd expect, except if an open door receives and open command – it's ignored. Likewise, a close command to a closed door is ignored. I added the “trigger” command to just activate the relay regardless of the state.

Every five seconds or so, the Status Packet is published:
{  
   "topic":"GDCTL/STATUS",
   "datetime":"2017-06-20T20:09:49"
   "door":{  
      "door_id":1
      "state":"OPENED",
      "state_datetime":"2017-06-20T20:09:1",
      "last_command":"OPEN",
      "last_command_datetime":"2017-06-20T19:51:35",
   },
   "system":{  
      "uptime":"23:40:32.84",
      "cpu_temp":92.5,
      "ssid":"ESSID411",
      "camera_present":true
   },
}

The first datetime is the current date / time of packet creation. Valid door states are 'Unknown', 'Opened', 'Closed' and 'In-Motion'.

The system object simply sends back some information about the RPi that I'll find useful.


If you look at older blog posts you may notice that there are some changes afoot in my design. Over the years now of accumulated MQTT usage, I've concluded that I want the MQTT topic to be part of the payload. I'll spare you the arguments for/against I've had with myself. But, I want the topic to be part of the payload.

You can see in my older MQTT messages, the topic is outside the JSON payload. I've changed my mind on that too now – the entire MQTT packet payload is a JSON formatted messages and the topic is part of the message.


No comments :

Post a Comment