At some point, most everyone forgets to close their garage door when leaving for work, or wonders if they closed it before leaving for vacation.  This series of posts will cover how to easily build a system that will notify you by email, tweet, or SMS if your garage door has been left open.

Garage door SMSing

Garage Door Tweeting

What you’ll need:

At a minimum, you’ll need the following to get started:

  • Raspberry Pi model B ($35).  This is a credit card sized computer that will power the system.  Try not to spend much more than the official price – $35.  Shop at Element14 if you’re seeing higher prices.  There is also the Raspberry Pi model A, which is $10 cheaper.  It will also work, but is slightly harder to configure and does not support Ethernet.
  • 4GB or larger SD card ($6) to store the RPi’s files.
  • HDMI to HDMI -or- HDMI to DVI cable.  Initially the RPi will be connected to a keyboard, mouse, and monitor to be configured.
  • Computer monitor with HDMI input or DVI input.  This will only be needed for the initial configuration steps.
  • USB keyboard and mouse.  Again, only needed for the initial configuration steps.
  • USB hub.  Many monitors have one built in.  If not, borrow/get a powered USB hub (it should draw power from an AC outlet).  There is a list of hubs known to work with RPi on the web.  It’ll only be needed for the initial configuration.
  • Ethernet cable (if using a wired connection) -or- USB wifi adapter ($11).  The RPi will need Ethernet or Wifi connectivity to send emails/tweets/SMS.  Unless your garage is wired for Ethernet, you probably want Wifi.  I used the tiny Edimax EW-7811UN for my build and it worked well.  Newer models are now available.
  • USB power supply ($6).  The RPi draws a lot of current, so stay away from cheap ones.  If your RPi reboots or crashes a lot, your USB power supply may not be sourcing enough current.  Adafruit sells a power supply that works well.
  • USB – micro USB cable ($3).  This will connect the power supply to the RPi.  You likely already have one of these from a cell phone or other USB device.  If not, they only cost a few dollars on Amazon.com.
  • Magnetic garage door sensor ($10).  You’ll need one per garage door.  This should come with both a magnet to mount on the garage door and a sensor to mount on the door frame. Unlike window sensors, garage door sensors typically can sense the magnet from 2″ or more away. The Seco-Larm SM-226L works well.

    Magnetic sensor mounted to wooden header at top of garage door

    Magnetic sensor mounted to wooden header at top of garage door

Recommended, but not required:

  • Raspberry Pi enclosure ($10-$15).  There are many enclosures on the market that are designed specifically for RPi.  Make sure the enclosure you buy has an opening for the GPIO pins otherwise you’ll have to modify the enclosure.  Alternately, you can purchase an enclosure like the Velleman 135 x 75 x 50mm ABS Project Box and drill only the openings you need.  This is a little more work but will provide more protection for your RPi since it won’t have any unnecessary ports exposed.
    RPi in Plastic Case http://www.amazon.com/gp/product/B008TDBIDI/ref=wms_ohs_product?ie=UTF8&psc=1

    RPi in Plastic Case.  Note the GPIO opening on the right side.

    RPi in ABS Project Box

    RPi in ABS Project Box

  • Jumper wires with one female end ($5-$10).  Only two connections are required per garage door, so jumper wires work well here.
  • 2 conductor wire.  If you’re not able to position your RPi next to the garage door, you’ll need to run a wire from the magnetic sensor to your RPi.  It’s low voltage (3.3V), so thinner wire like 22 or 24 AWG is fine.
  • Multimeter.  A meter that can measure resistance will help diagnose any problems with the magnetic sensor.

You’ll also need to download the following from the Raspberry Pi web site:

Wiring up the Magnetic Sensor to the Raspberry Pi

The Raspberry Pi has numerous GPIO pins – multipurpose connections that can be inputs, outputs, or have special functionality.  The magnetic sensor should have two wires coming out of it.  When the magnet is brought close to the sensor, the two wires will behave as if they are connected together.  If your magnetic sensor has three wires, using the multimeter in resistance mode, determine which two wires go to 0 resistance when the magnet is brought close to the sensor and use only those wires.

Before you attach the magnetic sensor to the garage door, let’s test it out first.  Connect one wire of the magnetic sensor to pin 9 (ground), and the other to pin 15 (GPIO 22).  When the magnet is close to the sensor, GPIO 22 will be grounded.  When the magnet is away from the sensor, internal pull up resistors in the RPi will bring GPIO 22 up to 3.3V.

If you’re monitoring multiple garage doors, pick another ground and GPIO pin (e.g. pin 14 and 16) to connect the additional sensors to.

Double check your connections – getting it wrong could permanently damage your Raspberry Pi!

RPi GPIO Diagram 550px Wide

Setting up the Raspberry Pi

Once you’ve purchased all the components, downloaded the software, and connected the sensor(s), here’s how to get it configured.

  1. Follow the Raspberry Pi quick start guide (there’s a link to it on the download page) to prepare the SD card and copy NOOBS onto the SD card.  In summary:
    1. Format the SD card using the SD Card Association’s formatting tool.
    2. Unzip the New Out Of Box Software zip file
      1. Windows – right click on the file and choose “Extract All”
      2. Mac – double click on the file
      3. Linux – Run “unzip <filename>” from a terminal
    3. Copy the extracted files onto the SD card you just formatted
  2. Connect the USB keyboard and mouse to the USB hub.
  3. Insert the SD card into your RPi and connect the following to your RPi:
    1. USB hub
    2. USB wifi adapter
    3. HDMI-HDMI or HDMI-DVI cable.  Connect the other end to your monitor.
    4. Finally, connect the micro-USB cable to the RPi and the power supply.  It should look similar to the picture below:
      RPi_Initial_Setup
  4. Your RPi should now boot into NOOBS and display a list of operating systems.  If your display remains blank, try pressing “2” on the keyboard to change to HDMI safe mode.
    NOOBS OS selection cropped
  5. Select Raspbian from the list if it’s not already selected.  Click “Install OS” in the top left corner.
  6. Installing the OS will take a several minutes.  Once it is completed, a dialog box will appear indicating the image was successfully applied.  click Ok to acknowledge the dialog box and the RPi will reboot into raspi-config.
    raspi-config screen
    Choose the following options in raspi-config:

    • Internationalization Options
      • Change locale – US users should uncheck en_GB.UTF-8 and select en_US.UTF-8 instead.  Make en_US.UTF-8 the default locale for the system.
      • Change Timezone – select your timezone from the list.
      • Change keyboard layout – US users should typically choose “Generic 104-key PC” keyboard with the “English (US)” layout.
    • Enable Boot to Desktop – pick “yes” at the “Should we boot straight to desktop?” dialog.
    • Press the Tab key to select Finish in the bottom-right, then press Enter.  Select “Yes” at the “Would you like to reboot now?” dialog and press Enter.
  7. The RPi will reboot into a graphical user environment.  Double click on WiFi config on the desktop.  The “wpa_gui” dialog will appear.
    1. Click the “Scan” button to search for Wifi networks.  Double click on your Wifi network.
    2. A new dialog will appear with “SSID” in the first row.  If your Wifi network has a password, enter it in the PSK field.wpa_gui dialog to add a network
    3. Click Add to close the dialog box with “SSID” in the first row.
    4. Click Close in the “Scan results” dialog box.
    5. The “wpa_gui” dialog should now show “Completed (station)” as its status.wpa_gui joined network
  8. Double click on Midori on the desktop and ensure you can browse to http://www.google.com/
  9. Close Midori and wpa_gui.

At this point, your Raspberry Pi has the Raspbian operating system installed and it can connect to the Internet.

Installing prerequisites

The next step is to update the operating system and install the software required to run the Pi Garage Alert software.

  1. Double click on “LXTerminal” on the Raspberry Pi desktop.  A terminal window will appear with the “pi@raspberrypi” prompt.  To update the system software, run the following commands.  “apt-get” manages the software on the Raspbian operating system (and many other Linux distributions), and “sudo” runs apt-get with the privileges it needs.
    sudo apt-get update
    sudo apt-get upgrade
  2. After running “sudo apt-get upgrade”, you’ll be presented with a list of packages that need to be upgraded.  Type “y” then press Enter to proceed with the upgrade.  The upgrade may take a couple minutes.
  3. Some additional software is also required – tweepy for Tweeting, twilio for sending SMS, and sleekxmpp for Jabber.  It is necessary to install this software even if you aren’t using Tweet/SMS alerts.  To install them, enter the following commands in the LXTerminal window:
    sudo apt-get install python-setuptools python-dev libffi-dev libssl-dev
    sudo pip install tweepy twilio==5.6.0 sleekxmpp dnspython pyasn1
    sudo pip install pyasn1_modules requests[security] slackclient
    sudo pip install -U requests

Installing Pi Garage Alert

We’re finally ready to install the Pi Garage Alert software.

  1. Start by downloading the software using the “git” tool:
    git clone https://github.com/rllynch/pi_garage_alert.git
  2. Now, copy the files into the correct location:
    cd pi_garage_alert
    sudo cp bin/pi_garage_alert.py /usr/local/sbin/
    sudo cp etc/pi_garage_alert_config.py /usr/local/etc/
    sudo cp init.d/pi_garage_alert /etc/init.d/
    sudo chown pi /usr/local/etc/pi_garage_alert_config.py
  3. Test out the Pi Garage Alert software by running the following command:
    sudo /usr/local/sbin/pi_garage_alert.py
  4. You should see output similar to the following in the terminal:
    pi@raspberrypi ~ $ sudo /usr/local/sbin/pi_garage_alert.py
    2013-07-27 19:37:52: ==========================================================
    2013-07-27 19:37:52: Pi Garage Alert starting
    2013-07-27 19:37:52: Configuring global settings
    2013-07-27 19:37:52: Configuring pin 15 for "Example Garage Door"
    2013-07-27 19:37:52: Initial state of "Example Garage Door" is open
    2013-07-27 19:37:56: CPU temp: 46.5, GPU temp: 46.0, Uptime: 0:50:17, Example Garage Door: open/0/4
  5. Now, try moving the magnet close to the magnetic sensor and you should see the following:
    2013-07-27 19:39:29: State of "Example Garage Door" changed to closed after 97 sec
  6. If you see a message similar to this one, everything is working correctly together.  If you do not see this, double check the wiring and make sure your garage door sensor is plugged into the pin 15 and pin 9.  You may also want to using your multimeter to test the resistance of the sensor and make sure it goes to (nearly) zero when the magnet is close to the sensor.

At this point, the RPi can sense the state of the garage door, but it is not sending emails/tweets/SMSes yet.  Part 2 discusses how to configure these alerts.

 
  • Pingback: Making Your Garage Door Email, Tweet, or SMS: Part 2 - Richard L. Lynch()

  • disqus_Oz8s6oUKmX

    Great Article. Not having a lot of electronic knowledge I was really worried before I found your article. Thanks for the help in getting it all setup and configured.

  • Rick

    Everything was working fine and now some days the garage door monitor does not send a message to my twilio account and other days it does. Any ideas? I tried unplugging it and plugging it back in and that worked once but didn’t work the second time I tried it.

    • I’d start by checking the log file /var/log/pi_garage_alert.log for any hints. Every 10 minutes it should log the garage door state. If there’s a gap in the log when you weren’t getting alerts or an error message, that could indicate a problem with pi_garage_alert.py.

      If you don’t see a gap in the log when you weren’t getting alerts, I’d suspect a connectivity problem or perhaps the power supply is going bad. From the RPi, open a terminal and run command “ifconfig wlan0”. One of the lines will say “inet addr:” followed by an IP address (four numbers separated by periods, often times starts with 192.168). This is the IP address of the RPi. You can remotely control the RPi from other computers in your house using this address.

      When you see it not working, go to another computer on your home network and from a terminal run command “ping RPI_IP_ADDRESS”. If it says “request timeout” or “destination host unreachable” then there’s a connectivity problem. The RPi may be too far/borderline too far from your wireless router, or its power supply may be failing and not able to deliver enough current at 5V to maintain the Wifi connection.

      • Rick

        Richard Thank You! sorry for the delay in responding, I see the notification until just now. I think it might be a problem with the DHCP assigning random IP addresses. I have a D-Link 605L using DHCP but it allows me to reserve IP addresses. I reserved an IP address for the RPi but I didn’t reboot the RPi yet. I will follow your instructions and check the IP. This may be a dumb question but when say you “ping RPI_IP_ADDRESS” I should type, ping 192.168.1.114 (or whatever the IP address is) I assume.

        • Right, “ping 192.168.1.114” is the correct syntax. At the end, it’ll print statistics on how many packets were lost, so you may want to let it run for a while. If you’re on Windows, you can add -n to specify how many pings to send, e.g. “ping -n 600 192.168.1.114” will send 600 pings which should take about ten minutes. OSX/Linux don’t need -n and will ping until you press ctrl-c.

  • Fernando Gómez

    Hi, I’m a newbie in python language and wanted to ask how it could do to
    a photo shoot when the magnetic opens. I have written a small program
    that does what but not how to include it in pi_garage_alert or
    pi_garage_alert_config. The program is as follows:

    #! /bin/sh
    # /etc/init.d/puerta

    ### BEGIN INIT INFO
    # Provides: puerta
    # Required-Start: $all
    # Required-Stop: $remote_fs $syslog
    # Default-Start: 2 3 4 5
    # Default-Stop: 0 1 6
    # Short-Description: Script Arranque Puerta cargando intentofoto.py
    # Description: Script Arranque Puerta cargando intentofoto.py
    ### END INIT INFO

    case “$1” in
    start)
    echo “Arrancando puerta”
    /usr/bin/python /home/pi/python/intentofoto.py
    ;;
    stop)
    echo “Deteniendo puerta”

    ;;
    *)
    echo “Modo de uso: /etc/init.d/puerta {start|stop}”
    exit 1
    ;;
    esac

    exit 0

    #########################################

    And “intentofoto.py:

    #!/usr/bin/python
    import time
    import os
    import sys
    import re
    import subprocess
    import datetime

    # capture image

    SnapImage = “/home/pi/fotos puerta/” + datetime.datetime.now().strftime(“%d-%m-%Y_%H:%M:%S”) + “.jpg”
    subprocess.call([“/usr/bin/wget”,”-O”,SnapImage,”http://melanoma69.no-ip.biz:9000/?action=snapshot”])
    time.sleep(1)

    SnapImage = “/home/pi/fotos puerta/” + datetime.datetime.now().strftime(“%d-%m-%Y_%H:%M:%S”) + “.jpg”
    subprocess.call([“/usr/bin/wget”,”-O”,SnapImage,”http://melanoma69.no-ip.biz:9000/?action=snapshot”])
    time.sleep(1)

    ##############################################

    If you could give me a simple answer would greatly appreciate it, I’m studying python and still not get it right …

    Sorry for my English

    Thank you very much and greetings from Spain.

    • Fernando,

      The most python way to do it would be to add your intentofoto.py to pi_garage_alert.py as a function (e.g. def intento_foto(): followed by your code), then call the function right after this line of pi_garage_alert.py:

      self.logger.info(“State of “%s” changed to %s after %.0f sec”, name, state, time_in_state)

      If you want to keep it a separate file, you can do an os.system call in the same location, and call your Python script.

      If you don’t need photos of the door closed, you should also check if the “state” variable is equal to “open”.

      Rich

  • Fernando Gómez

    My messages are not displayed… anybody knows??

  • Fernando Gómez

    Richard much appreciate your help!!! I would make another query.

    No where I have to change “state” to “open”

    Greetings from Spain

  • Yes, you could do something like this to only take photos when the door opens:

    if state == ‘open’:
    intento_foto()

    There’s a good example of attaching files to emails at this stackoverflow page.

  • pete

    Noob to GPIO stuff here.

    I’ve installed everything, control of the garage door opener works fine. The sensor part is the issue.

    I actually bought a Honeywell Ademco 958 instead of the one spec’d here. It sounds, and looks, identical. Possible this is the issue.

    However, what, exactly, am I sensing? Let’s say I use pins 9 (ground) and 15 (GPIO). Should pin 15 go to 0 and stay there when closed, and go to 1 and stay there when the magnet is more than 3″ away? Because this doesn’t happen, both are sort of random.

    This is true even if I manually hold the wires directly to the PI pins.

    I have called “gpio mode 15 in” first, do I need to do this every time? Doesn’t seem to help. Any other calls I need to make before “gpio read 15”?

    Thanks, and awesome project.

    pete

    • Hi Pete,

      Most magnetic sensors work like a switch – when the magnet is near, it’ll connect the GPIO to ground, 0V. If the magnet is not nearby, the switch will be open and the GPIO will be floating (it’ll appear to the RPi like nothing is connected). However, the RPi is configured by pi_garage_alert.py with a pull up resistor that’ll make it 3.3V when the GPIO is floating. If you’re getting random readings with “gpio read #”, the pull up is probably not configured.

      I’d start by measuring the resistance of the Ademco 958 with a multimeter in resistance mode first. Ideally you want a sensor that goes to 0 resistance when the magnet is nearby, and has a large/infinite resistance when the magnet is not nearby. If it’s the other way around, you can tweak pi_garage_alert.py to deal with that.

      If you then connect it to the RPi and use the gpio utility, you can make it an input, “gpio mode # in”, then enable the pull up with “gpio mode # up” (replace # with the pin number). You should then be able to check the status of the sensor with “gpio readall” or “gpio read #”. Watch out for the pin numbering – gpio by default using the wiringpi numbering scheme which is different than the order of the physical pins. For instance physical pin 15 is wiringpi pin 3, so you’d do “gpio mode 3 in”.

      So, you can do that for debugging, but once it’s all set, when you run pi_garage_alert.py, it should configure the GPIO as an input with a pull up resistor for you.

      Rich

      • pete

        Thanks for the detailed answer, but so far no joy.

        I spliced my female cables onto the ends of the 24″ leads coming from the sensor and attached the multimeter to the two cables. I measure 0.L (infinity) when the magnet is not near the sensor, and it goes rapidly to 0.0 when I move the magnet to the sensor. So all appears well there.

        Then I attach the cables to pins 14 and 16 (wiringpi numbering), and read 16 every 3 seconds, as follows (this is tcsh, not bash):

        while (1)
        sleep 3
        gpio mode 16 in; gpio mode 16 up; gpio read 16
        end

        and it always returns 1, regardless of whether the magnet is near the sensor or not.

        Same thing when I moved to 23/24 (with 24 ground).

        I must be doing something wrong here….

        • pete

          23/*25*, the ground is 25 not 24. This is an error in my reply, not my wiring.

          • pete

            And, I was being foolish. I was using “physical” numbers, not GPIO OR wiringpi. All is well now.

      • Matthew Foglia

        yes, this is my exact issue –

        would either of you know how to tweak pi_garage_alert.py to work with an inverted sensor scheme as you described?

        • Sure, the code that reads the sensor is in the get_garage_door_state function around line 435. You can change the “if GPIO.input(pin):” to “if not GPIO.input(pin):” to invert the input.

  • Chuck Murison

    Love it. Parts are coming in and I hope to have this up and running this weekend. Mind if I reblog this with a link back to you?

    • As long as you’re only reblogging a short excerpt that should be fine.

      Rich

  • stuart

    Question.
    When I submit the command ‘sudo pip install twillo’ it comes up with :
    Could not find any downloads that satisfy the requirement twillo. No distributions at all found for twillo.
    So, I kept going through the steps and received another issue when I submitted the following command ‘sudo /usr/local/sbin/pi_garage_alert.py’ the following error come up:
    Traceback(most recent call last): File “/usr/local/sbin/pi_garage_alert.py”, line 46, in import httplib2
    ImportError: No module name httplib2
    Any ideas?

    • stuart

      nevermind, I think I misspelled twilio.

  • stuart

    I found my issue. I made a typo error spelling twilit.

  • JamesTX10

    This is my first Pi project and I have it working except for the log. There is no log file in /var/log/pi_garage_alert.log Any ideas on getting the log working?

  • stuart

    did you try and run the program yet?

    • JamesTX10

      Yes and it runs fine. I get the emails as expected just no log.

      • jerryasmith

        Same issue for me, no logs.

        • Hmm.. a couple questions – is the log file empty, or does it not even exist? Are you running pi_garage_alert.py with sudo?

          • jerryasmith

            Yeah, it’s very weird. The script is run with sudo using the default pi login. There is no log file at all – I eventually decided to create it manually, but that file is not populated when the script runs.

  • stuart

    Look in your .py file where your garage information (name, state, time..etc).

    There should be a line above Email settings that read:

    LOG_FILENAME = “/var/log/pi_garage_alert.log”

    make sure it there.

  • mike novack

    No log file for me either. I get the messages on the screen indicating the status of the doors (2 in my case) working great. There is no log file generated in the specified location with the specified name. Does this file need to exist before it can be added to?

    Still working on getting email via gmail working. Everywhere I look on the net says the port for gmail smtp is 465. Is the 587 shown in your docs correct?

    Thanks.

    • Instead of running pi_garage_alert.py from the command line, try installing it as a service with “sudo update-rc.d pi_garage_alert defaults” then starting the service with “sudo service pi_garage_alert start”. The log should then show up and be populated.

      I’m using [smtp.gmail.com]:587 as the relay host and it works for me. 465 is a non-standard port, but gmail supports it so it may work as well.

      • mike novack

        The log file finally started showing up when I ran it as a service as you suggested. Not sure why it would not show up when run from the command line. Still haven’t got the gmail working but finally gave up on it and signed up for a Twilio account. $1 a month and less than a penny/text message … works great. Thanks.

  • jay six

    I have a question would this work with open and close switch. Instead of a magnet. Let’s say if my garage is close the switch is close and when its open the switch is open.

    • Yes, it should work fine with a mechanical switch as well.

      • jay six

        Thanks you it works works great. For those having trouble with gmail check if your gmail accont is set to 2 way versification. If it does i won’t work. You have to enable less secure up setting on gmail.

        How d you run run your screen on start up without logging in?

  • Woki Home

    how to make it work for Raspberry Pi 2 Model B please

  • Pepper

    Hi Richard, first thx for all !! Is amazing and exiting to try this at home 🙂 But have a big problem about send email.. have this message on simulation : 2016-05-20 21:09:30,101 ERROR Exception sending email: can you help my? thx!!

  • Pepper

    after next hours of search, i was view : – the thread about email canot working, i dont know why is the problem and the next as the twitter thread canot working about instructions cause the link was down !! and twitter was a new policie so python dont working.. no solution about twitter or email?? plz… thx for all anyway, but know all no working on this page !

  • Jarod Zoubek

    Using SSMTP instead of Postfix, but when I go to test sending an email from the alert program it give me a . What is wrong? Sends email from smtp in terminal just fine.

  • Somebody Else

    I’m using this with an alarm system to notify me (i.e. alarm connected via relay to RPi). When there’s a fire alarm, the signal alternates on/off until disarmed. Is there a way to limit the number of notifications? Maybe add a loop with a ‘wait x’ command in python after, say, five emails? Where would I add this (what file, and before/after which line? I’m a n00b when it comes to python, but I think I could figure it out with a little help. This program works FANTASTICALLY after writing a script to copy over the resolv.conf file for postfix at boot. Alarm goes off, I get text and email. For those having issues with postfix, check your /var/spool/postfix/etc/resolv.conf file and see if the DNS info matches your /etc/resolv.conf file. It seems that if postfix loads before your ethernet connects, the dns info doesnt get copied over and postfix won’t work. I added a script to copy the resolv.conf file over at boot and added it in my bash.rc file and that fixed the issue. Anyhow, any ideas on adding a loop with a wait command? … Bueller?

    • Chris

      I had the issue with email not sending after a reboot, and /var/spool/postfix/etc/resolv.conf not having name server entries.
      My fix was to tell my Raspberry Pi to wait for the network before booting. I did this by:
      1) sudo raspi-config
      2) Option 4 – Wait for Network at Boot.
      3) Choose Yes.
      Hope that helps.

  • Pepper

    I am very disappointed , no help from the designer . I am a beginner and I still have the same problem !! If this project can not function, it is not necessary to confuse + 4 hours of working time for NOTHING

  • Firdosh Nogama Diakus

    Hi can someone please confirm if this project and code will run on the Pi 3B?

    • Yes, it should run fine on a RPi 3. You’ll notice the 26 pin header described in the post has been expanded to 40 pins in recent RPi models. The function of the top 26 pins is unchanged so you can ignore the 14 new pins on the bottom, or alternately, refer to http://elinux.org/RPi_Low-level_peripherals#Model_A.2B.2C_B.2B_and_B2 for the new pinout.

      • Matthew Foglia

        Thanks Richard! I was actually able to get it working by just switching the ‘open’ and ‘close’ states in the first part of the //main functionality// part.

        great script – i really appreciate your sharing it and getting me off to a good start with RPi.

        • Matthew Foglia

          the main issue was the difference between (BOARD) and (BCI) pins – I reconciled that and everything worked out.

  • Ryan

    Terrific program, thanks for creating & sharing! I had this working nicely for a while. Not sure if related but I moved the system to a pi2 and I think that’s around the same time I started having trouble with it. When the door is open it seems to oscillate readings very frequently (example from log below.) When I do a manual/one-off check of the pin state using a different python program it consistently reads false as expected. Because it never stays open for the alert duration, I don’t get alerted. I can’t figure out why pi_garage_alert is seeing these flaps:

    2016-10-30 15:55:06,405 INFO State of “Garage Door” changed to open after 4 sec
    2016-10-30 15:55:11,412 INFO State of “Garage Door” changed to closed after 5 sec
    2016-10-30 15:55:16,418 INFO State of “Garage Door” changed to open after 5 sec
    2016-10-30 15:55:21,425 INFO State of “Garage Door” changed to closed after 5 sec
    2016-10-30 15:55:26,432 INFO State of “Garage Door” changed to open after 5 sec
    2016-10-30 15:55:31,438 INFO State of “Garage Door” changed to closed after 5 sec
    2016-10-30 15:55:36,445 INFO State of “Garage Door” changed to open after 5 sec
    2016-10-30 15:55:42,453 INFO State of “Garage Door” changed to closed after 6 sec
    2016-10-30 15:55:47,460 INFO State of “Garage Door” changed to open after 5 sec

    • Ryan

      Although I wouldn’t think it should be required, it seems that by adding a GPIO.setup before the GPIO.input in the get_garage_door_state() function corrects it. Line 435 added:
      GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

      • Yeah, that’s really weird. From the log it does sound like the pull up isn’t working and the GPIO is floating between states, but the pull up should have been configured in initialization when it logged that it was configuring pins. I’ll keep the workaround in mind in case there are any other reports of this issue. Glad you got it working again and thanks for posting the workaround.

  • Raspberry Pi

    The parts list specifies Raspberry Pi model B.
    Is that necessary? or, can others be used?

    • Any Raspberry Pi model will work, but the RPi 2 B and RPi 3 B will be the easiest since they have plenty of USB ports. RPi A+ will also work, but it only has one USB port which will require you to use a USB hub during setup. RPi Zero should also work, but may require soldering a 40 pin header to it.

  • Raspberry Pi

    Perfect. Thanks!

  • Michel Le Noir

    Hi Richard,
    Thank you for the nice program and tutorial. Works pretty well on my RPi3 except that I get “Garage Door: open/0/4” whatever I do with the pin 9 – pin 15 connexion.
    I double (quadruple) checked it but still have it “open” even with a direct female-female jumper connexion between both pins.
    Any idea ? Thanks in advance.
    Michel

    • Michel Le Noir

      Actually, it works when I do a “gpio read 3”. It seems physical pin 15, aka GPIO 22, must be addressed as wiring pi 3…
      Why make it simple when it is so fun to complicate…
      But can you tell me which pin does your program really work with?
      Thanks so much
      Michel

      • The program will use whichever pins are specified in the config file. The pins should be specified by physical pin numbers, so, 15 in your example.

        • Michel Le Noir

          It’s actually a problem of pin state instability, quite the same Ryan described a few months ago: Program reading alternatively “changed to open” and “changed to closed” every few seconds.
          Tried the solution found by Ryan (adding line “GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)”)
          Now the program reads constantly “open/0/xx” every xx seconds no matter pins 9-15 beeing connected or not…

          • Michel Le Noir

            Problem solved: it was just that #*@# jumper wire that was defective! It’s crazy how an unsuspected hardware problem can spoil any logical reasonning…

  • Matt

    Great program, thanks a lot.

    Had an issue installing per script on Raspbian Jessie recently. Found out the issue was with Twilio 6.0 which is a recent update. Fixed it by changing to the following:

    sudo pip install tweepy twilio==5.6.0 sleekxmpp dnspython pyasn1

  • I think this is related to the problem Matt discovered and found the fix for in one of the comments below – Twilio 6.0 causes problems for Raspbian and tends to leave Python/pip in a pretty bad state. I’ve updated the post with the fix Matt described to use the older version of Twilio.

    I’m not able to reproduce that exact error, but I think the following commands may repair your system – they repaired my system after I tried installing Twilio 6.0 on a fresh Raspbian install. If not, reinstalling Raspbian and installing Twilio 5.6.0 (see the updated instructions on this post) will fix the issue.

    sudo easy_install pyparsing
    sudo easy_install -U pip
    pip install -U twilio==5.6.0

    Rich

  • RC123

    Hi just bought a new Raspberry Pi 3. I followed the instructions and the O.S. choice was Raspbian PIXEL full desktop version. When I run the command to test the Pi Garage Alert software, I get the following error messages:
    pi@raspberrypi:~/pi_garage_alert $ sudo /usr/local/sbin/pi_garage_alert.py
    Traceback (most recent call last):
    File “/usr/local/sbin/pi_garage_alert.py”, line 59, in
    from slackclient import SlackClient
    File “/usr/local/lib/python2.7/dist-packages/slackclient/__init__.py”, line 1, in
    from slackclient._client import SlackClient # noqa
    File “/usr/local/lib/python2.7/dist-packages/slackclient/_client.py”, line 6, in
    from slackclient._server import Server
    File “/usr/local/lib/python2.7/dist-packages/slackclient/_server.py”, line 2, in
    from requests.packages.urllib3.util.url import parse_url
    ImportError: cannot import name parse_url
    =================
    Does anybody have any suggestions to fix this? I tried re-formatting the SD card and re-did everything and got the same result. Thanks for any help you can offer.

    • Try issuing the following command – it should fix this problem:

      sudo pip install -U requests

      • Rick

        Thank You!

        sudo pip install -U requests

        worked perfectly!

  • DRPhoto

    Thanks for the effort in putting this together. i have followed the tutorial and have the following errors:

    ——————
    pi@raspberrypi:~ $ sudo pip install tweepy twilio==5.6.0 sleekxmpp dnspython pyasnl
    Downloading/unpacking tweepy
    Downloading tweepy-3.5.0-py2.py3-none-any.whl
    Downloading/unpacking twilio==5.6.0
    Downloading twilio-5.6.0.tar.gz (194kB): 194kB downloaded
    Running setup.py (path:/tmp/pip-build-XQjat6/twilio/setup.py) egg_info for package twilio

    Downloading/unpacking sleekxmpp
    Downloading sleekxmpp-1.3.3.tar.gz (845kB): 845kB downloaded
    Running setup.py (path:/tmp/pip-build-XQjat6/sleekxmpp/setup.py) egg_info for package sleekxmpp

    Downloading/unpacking dnspython
    Downloading dnspython-1.15.0-py2.py3-none-any.whl (177kB): 177kB downloaded
    Downloading/unpacking pyasnl

    Could not find any downloads that satisfy the requirement pyasnl
    Cleaning up…
    No distributions at all found for pyasnl
    Storing debug log for failure in /root/.pip/pip.log
    pi@raspberrypi:~ $
    ———————————–

    appears that the PYASNL package is not available anymore????

    i tried to continue anyway and got the following when testing:

    ———————————–
    pi@raspberrypi:~/Downloads/pi_garage_alert $ sudo /usr/local/sbin/pi_garage_alert.py
    Traceback (most recent call last):
    File “/usr/local/sbin/pi_garage_alert.py”, line 52, in
    import tweepy
    ImportError: No module named tweepy
    pi@raspberrypi:
    ———————————–

    which is interesting due to tweepy being installed as per the above copy/paste.

    any help appreciated 🙂

    • DRPhoto

      to anyone else who has ran into the same issues, i have used apt to do the install of the following packages
      pyasnl = python-pyasn1 (thats a 1 not a lower case L)
      tweepy = python-tweepy

      then i needed to get httplib2 (which in apt is python-httplib2)

      then:
      sleekxmpp = python-sleekxmpp

      then i try again to run the test script and it mentions i am missing “resolver”

      i have tried to install the particular versions i can search for with resolver and none have worked. i have tried apt and also pip, but no packages satisfy the requirements (apparently its line 56)

      pi@raspberrypi:~/Downloads/pi_garage_alert $ sudo /usr/local/sbin/pi_garage_alert.py
      Traceback (most recent call last):
      File “/usr/local/sbin/pi_garage_alert.py”, line 56, in
      from sleekxmpp.xmlstream import resolver, cert
      ImportError: cannot import name resolver
      pi@raspberrypi:~/Downloads/pi_garage_alert $

      • Odd – I just did a fresh install of Raspbian from NOOBS v2.4.4, installed all the pi_garage_alert dependencies, and there were no errors. python-pyasn1 was also installed by default in Raspbian:

        pi@rpi-misc1:~ $ dpkg-query -l python-pyasn1
        Desired=Unknown/Install/Remove/Purge/Hold
        | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
        |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
        ||/ Name Version Architecture Description
        +++-================================-=====================-=====================-======================================================================
        ii python-pyasn1 0.1.9-2 all ASN.1 library for Python (Python 2 module)

        pi@rpi-misc1:~ $ sudo apt-get install python-setuptools python-dev libffi-dev libssl-dev
        Reading package lists… Done
        Building dependency tree
        Reading state information… Done
        python-dev is already the newest version (2.7.13-2).
        python-dev set to manually installed.
        python-setuptools is already the newest version (33.1.1-1).
        python-setuptools set to manually installed.
        The following additional packages will be installed:
        libssl-doc
        The following NEW packages will be installed:
        libffi-dev libssl-dev libssl-doc
        0 upgraded, 3 newly installed, 0 to remove and 1 not upgraded.
        Need to get 2,986 kB of archives.
        After this operation, 10.1 MB of additional disk space will be used.
        Do you want to continue? [Y/n] y
        Get:1 http://mirrordirector.raspbian.org/raspbian stretch/main armhf libffi-dev armhf 3.2.1-6 [159 kB]
        Get:2 http://mirrordirector.raspbian.org/raspbian stretch/main armhf libssl-dev armhf 1.1.0f-3 [1,369 kB]
        Get:3 http://mirrordirector.raspbian.org/raspbian stretch/main armhf libssl-doc all 1.1.0f-3 [1,457 kB]
        Fetched 2,986 kB in 0s (3,122 kB/s)
        Selecting previously unselected package libffi-dev:armhf.
        (Reading database … 122747 files and directories currently installed.)
        Preparing to unpack …/libffi-dev_3.2.1-6_armhf.deb …
        Unpacking libffi-dev:armhf (3.2.1-6) …
        Selecting previously unselected package libssl-dev:armhf.
        Preparing to unpack …/libssl-dev_1.1.0f-3_armhf.deb …
        Unpacking libssl-dev:armhf (1.1.0f-3) …
        Selecting previously unselected package libssl-doc.
        Preparing to unpack …/libssl-doc_1.1.0f-3_all.deb …
        Unpacking libssl-doc (1.1.0f-3) …
        Processing triggers for install-info (6.3.0.dfsg.1-1+b1) …
        Setting up libssl-dev:armhf (1.1.0f-3) …
        Setting up libffi-dev:armhf (3.2.1-6) …
        Processing triggers for man-db (2.7.6.1-2) …
        Setting up libssl-doc (1.1.0f-3) …

        pi@rpi-misc1:~ $ sudo pip install tweepy twilio==5.6.0 sleekxmpp dnspython pyasn1
        Collecting tweepy
        Downloading tweepy-3.5.0-py2.py3-none-any.whl
        Collecting twilio==5.6.0
        Downloading https://www.piwheels.hostedpi.com/simple/twilio/twilio-5.6.0-py2.py3-none-any.whl (262kB)
        100% |████████████████████████████████| 266kB 485kB/s
        Collecting sleekxmpp
        Downloading sleekxmpp-1.3.3.tar.gz (845kB)
        100% |████████████████████████████████| 849kB 241kB/s
        Collecting dnspython
        Downloading dnspython-1.15.0-py2.py3-none-any.whl (177kB)
        100% |████████████████████████████████| 184kB 971kB/s
        Requirement already satisfied: pyasn1 in /usr/lib/python2.7/dist-packages
        Requirement already satisfied: six>=1.7.3 in /usr/lib/python2.7/dist-packages (from tweepy)
        Requirement already satisfied: requests>=2.4.3 in /usr/lib/python2.7/dist-packages (from tweepy)
        Requirement already satisfied: requests-oauthlib>=0.4.1 in /usr/lib/python2.7/dist-packages (from tweepy)
        Collecting pysocks (from twilio==5.6.0)
        Downloading PySocks-1.6.7.tar.gz (282kB)
        100% |████████████████████████████████| 286kB 634kB/s
        Collecting pytz (from twilio==5.6.0)
        Downloading pytz-2017.2-py2.py3-none-any.whl (484kB)
        100% |████████████████████████████████| 491kB 439kB/s
        Collecting httplib2>=0.7 (from twilio==5.6.0)
        Downloading httplib2-0.10.3.tar.gz (204kB)
        100% |████████████████████████████████| 204kB 841kB/s
        Requirement already satisfied: oauthlib>=0.6.2 in /usr/lib/python2.7/dist-packages (from requests-oauthlib>=0.4.1->tweepy)
        Building wheels for collected packages: sleekxmpp, pysocks, httplib2
        Running setup.py bdist_wheel for sleekxmpp … done
        Stored in directory: /root/.cache/pip/wheels/3d/fd/c3/66abcf67ba5c4a609449824f6b4741fa53655ee4df862aa03c
        Running setup.py bdist_wheel for pysocks … done
        Stored in directory: /root/.cache/pip/wheels/8a/24/d0/6c9c780e6d7fbd5cc6ffaa83b926ffc186886a5bad16078bc7
        Running setup.py bdist_wheel for httplib2 … done
        Stored in directory: /root/.cache/pip/wheels/ca/ac/5f/749651f7925b231103f5316cacca82a487810c22d30f011c0c
        Successfully built sleekxmpp pysocks httplib2
        Installing collected packages: tweepy, pysocks, pytz, httplib2, twilio, sleekxmpp, dnspython
        Successfully installed dnspython-1.15.0 httplib2-0.10.3 pysocks-1.6.7 pytz-2017.2 sleekxmpp-1.3.3 tweepy-3.5.0 twilio-5.6.0

        pi@rpi-misc1:~ $ sudo pip install pyasn1_modules requests[security] slackclient
        Collecting pyasn1_modules
        Downloading pyasn1_modules-0.1.4-py2.py3-none-any.whl (60kB)
        100% |████████████████████████████████| 61kB 955kB/s
        Requirement already satisfied: requests[security] in /usr/lib/python2.7/dist-packages
        Collecting slackclient
        Downloading https://www.piwheels.hostedpi.com/simple/slackclient/slackclient-1.0.9-py2.py3-none-any.whl
        Collecting pyasn1=0.3.4 (from pyasn1_modules)
        Downloading pyasn1-0.3.6-py2.py3-none-any.whl (63kB)
        100% |████████████████████████████████| 71kB 1.3MB/s
        Requirement already satisfied: pyOpenSSL>=0.14 in /usr/lib/python2.7/dist-packages (from requests[security])
        Requirement already satisfied: cryptography>=1.3.4 in /usr/lib/python2.7/dist-packages (from requests[security])
        Requirement already satisfied: idna>=2.0.0 in /usr/lib/python2.7/dist-packages (from requests[security])
        Requirement already satisfied: six=1.10 in /usr/lib/python2.7/dist-packages (from slackclient)
        Collecting websocket-client=0.35 (from slackclient)
        Downloading websocket_client-0.44.0-py2.py3-none-any.whl (199kB)
        100% |████████████████████████████████| 204kB 848kB/s
        Installing collected packages: pyasn1, pyasn1-modules, websocket-client, slackclient
        Found existing installation: pyasn1 0.1.9
        Not uninstalling pyasn1 at /usr/lib/python2.7/dist-packages, outside environment /usr
        Successfully installed pyasn1-0.3.6 pyasn1-modules-0.1.4 slackclient-1.0.9 websocket-client-0.44.0

        pi@rpi-misc1:~ $ sudo pip install -U requests
        Collecting requests
        Downloading requests-2.18.4-py2.py3-none-any.whl (88kB)
        100% |████████████████████████████████| 92kB 1.2MB/s
        Collecting urllib3=1.21.1 (from requests)
        Downloading urllib3-1.22-py2.py3-none-any.whl (132kB)
        100% |████████████████████████████████| 133kB 1.1MB/s
        Collecting idna=2.5 (from requests)
        Downloading idna-2.6-py2.py3-none-any.whl (56kB)
        100% |████████████████████████████████| 61kB 1.3MB/s
        Collecting chardet=3.0.2 (from requests)
        Downloading chardet-3.0.4-py2.py3-none-any.whl (133kB)
        100% |████████████████████████████████| 143kB 1.2MB/s
        Collecting certifi>=2017.4.17 (from requests)
        Downloading certifi-2017.7.27.1-py2.py3-none-any.whl (349kB)
        100% |████████████████████████████████| 358kB 531kB/s
        Installing collected packages: urllib3, idna, chardet, certifi, requests
        Found existing installation: urllib3 1.19.1
        Not uninstalling urllib3 at /usr/lib/python2.7/dist-packages, outside environment /usr
        Found existing installation: idna 2.2
        Not uninstalling idna at /usr/lib/python2.7/dist-packages, outside environment /usr
        Found existing installation: chardet 2.3.0
        Not uninstalling chardet at /usr/lib/python2.7/dist-packages, outside environment /usr
        Found existing installation: requests 2.12.4
        Not uninstalling requests at /usr/lib/python2.7/dist-packages, outside environment /usr
        Successfully installed certifi-2017.7.27.1 chardet-3.0.4 idna-2.6 requests-2.18.4 urllib3-1.22