Wednesday, June 14, 2017

Email Smoke Detector Using Raspberry Pi

     Many years ago I built a device that would monitor the signal wire in my home's interconnected smoke detectors, and send me an email and text message when they sounded an alert.  I used a WRT54GL Linksys router that I re-flashed to run an open-source Linux based operating system, and hardware hacked to add an SD card for added storage space, 5 GPIO pins, and two serial ports.  One of the serial ports was used as a console, and the other was used to interface with an AVR microcontroller that did the actual monitoring of the smoke detectors.  It was over engineered and unnecessarily complicated, but it worked, and it introduced me to Linux scripting and microcontroller programming.  It was probably the first electronics project that I fully engineered from start to finish, and I still look back fondly on that project.

     Recently, as I was pondering on what I could do with the various Raspberry Pis I have acquired, it occurred to me that the Pi, with all it's free GPIO pins, would be perfect to revisit and re-engineer my old smoke detector email device.  In fact, this project would take so few resources that there is no reason I can't use the same Pi for several other "smart home" type tasks.  With that in mind I designed the basic layout of this project to be modular and expandable.  I used a piece of 3/16" thick acrylic sheet and some scavenged motherboard standoffs to mount the Pi and the other circuit boards.  I drilled holes in the acrylic slightly smaller than the threads on the standoffs, and just used the standoffs to tap threads into the acrylic.  It actually worked pretty well, and made for a very stable structure.  I bought a breakout board for the Pi's GPIO pins with a ribbon cable to allow for an easy disconnect point and mounted it on a perf-board with pins to provide a test point when all the cables were connected.  I made sure to leave room on the acrylic sheet for future expansion.


     The basic concept for this project is based on the fact that when one of my smoke detectors activates, it sends 9 volts down a signal wire to let all the other smoke detectors know that they also need to sound in order to alert people in all areas of the house.  If I can detect this 9V signal then it's just a matter of writing the code to send the email.  Since this is the case, the project can be broken into two parts, hardware and software.  For the hardware side, I need to determine how to take that 9V signal and convert it into a 3.3V signal that the Pi can receive on one of it's GPIO pins (more than 3.3V could seriously damage the Pi).  On the software side I need to program the Pi to detect the level change on one of it's GPIO pins and send an email when it receives that signal.  Overall this shouldn't be too complicated.  So, let's get to building.

The Hardware

     The hardware side of things ended up being a little more complicated than I expected due to the electrical noise present on signal wire from the smoke detector.  For the sake of documentation I'll go through the failure of the initial design first, but if all you are looking for is the final solution you can skip to the end of this section.
     I started the design with the idea that all I needed to do was convert the 9V signal from the smoke detector into 3.3V for the Pi's GPIO pins.  There are several ways to convert 9V to 3.3V, but I decided to go with a simple voltage divider circuit, since all it would take are a couple of resistors that I already had lying around.  This is how it works:



For the circuit above, the following formula applies:



Since I am trying to convert 9V to 3.3V, all I need to do is find two resistors in my collection that will make V(out) about 1/3 of V(in).  A little bit of math tells us that R1 needs to be about twice the value of R2.  I settled on an 8.2 kohm resistor for R1 and a 3.9 kohm for R2, since that is what I had readily available.  I built the circuit on a breadboard and tested it with a 9 volt battery.  The battery measured 9.7V across it's terminals, and I measured 3.1V for V(out), which is enough to pull the GPIO pin to high.  A little more math said that at 9V even V(out) would be 2.9V, and according to the following website, the voltage really only needs to be >2V in order to pull the input pin to high  (http://www.mosaic-industries.com/embedded-systems/microcontroller-projects/raspberry-pi/gpio-pin-electrical-specifications)  I thought I had a quick and easy solution, but once I had everything soldered and connected, I was surprised to find that the Pi was sending out multiple false alarms.  It seems that the signal wire for the smoke detector circuit was picking up electrical noise and that was translating into false alarms.  I tried to smooth it out with capacitors, but to no avail.  I decided it was probably better this way, being forced to isolate the smoke detector circuit from the Pis circuitry would protect both the Pi and the smoke detectors, so I went about trying to find the best way to do it.

  I thought about using a relay to isolate the Pi from the noisy electrical system, but there is not enough current on the signal wire to power a relay.  A transistor would probably be just as susceptible to the noise as the Pi, so that solution was out as well.  I brainstormed and researched for days trying to find a solution to this problem, until finally I came across the website of Dr Edward Cheung (http://www.edcheung.com/).  He is a very fascinating man, and I recommend taking the time to look at his web page if you have a chance, but what was of particular interest to me was a project he did in 2004 where he tied the signal wire from his interconnected smoke detectors to his homemade home automation system (http://www.edcheung.com/automa/smoke_det.htm).  In order to do this he used an optoisolator to act as the relay between the smoke detector system and his home automation system.  An optoisolator, also referred to as a photocoupler or an optical coupler, activates a light source, typically an LED, when voltage is applied across one half of the circuit.  A receiver coupled with a transistor on the other side of the circuit detects this light and closes the circuit on that side of the optoisolator.  This electrically isolates the two sides of the circuit. That was exactly the solution I had been searching for (Thank you Dr Cheung).  With this new found idea I quickly ordered some optoisolators and sketched out a circuit design.  I settled on a PC817 for the optoisolator due to it's low cost and quick/free shipping from Amazon.  Here is the datasheet if anyone is interested: http://www.farnell.com/datasheets/73758.pdf   And here is the final circuit:
When it was finally put together it worked perfectly.  A couple of notes regarding the design, I got the idea of using redundant resistors on the smoke detector side of the circuit from Dr Cheung's website as well.  The idea is that if one of the resistors failed it would not interfere with the smoke detector's operation, so the value of R1 and R2 had to be such that just one resistor would be enough to allow for proper operation of the smoke detector, and the sum of both resistors would not be too high as to prevent the optoisolator from sensing the current.  I expected to do some trial and error here, but it turned out that my first try with 680 ohms worked perfectly with one or both resistors.  R3 is just a pull-up resistor to keep the GPIO high until the circuit is closed and it is pulled low by the ground.  The switch on the Pi side of the circuit is to allow me to test multiple iterations of my script without having to set off the smoke detectors every time (my dog hates the sound).  Basically closing the switch simulates the optoisolator closing the circuit due to the smoke detector's activation.


When it came to actually building the circuit on a circuit board instead of the breadboard, I wanted to use a socket for the optoisolator in case I ever needed to change it out.  Unfortunately the only sockets I had lying around were for 16-pin microcontrollers, which were 4 times too big.  I decided to turn this inconvenience into opportunity, and wired the circuit board up to accommodate 4 optoisolators wired to four different GPIO pins.  This way if I ever decide to monitor any other systems with this same Pi, the circuitry is already built.

The Software

While there are many ways I could have approached the software side of this project, I have always wanted to learn to program in Python, so that is what I did.  A couple of Google searches and YouTube tutorials later I was ready to start.  Since this is not a Python tutorial I will just paste the code below.  If anyone would like to use the code to do a similar project of your own please feel free to copy it.  If you republish it, all I ask is to give me credit, and possibly post a link to this blog.  If you are having problems getting the code to work for your own project, please feel free to leave questions in the comments and I will do my best to answer them.  First I am listing the modules that I will be using, as well as providing a link to the Python documentation for each module.

time (used to allow the sleep command to pause the script)
datetime (used to timestamp emails and events)
RPi.GPIO (used manipulate, set, and read GPIO pins on the Raspberry Pi)
email (used to format email messages)
smtplib (used to send email messages)
https://docs.python.org/3.5/library/smtplib.html


And here's the code (obviously email addresses and passwords have been removed):


 #!/usr/bin/env python  
   
 import RPi.GPIO as GPIO # Used to interact with GPIO pins  
 import time # Used for sleep and to timestamp the email  
 from email.mime.text import MIMEText # Used to compose email  
 import smtplib # Used to send email  
   
 # Create a function to run when pin state changes  
 # When this function is called, all it does is send an email  
 # based on the state of the pin  
 def send_alert(channel):  
   
   # Set variables  
   gmail_user = 'address@gmail.com'  
   gmail_pass = 'password'  
   sent_from = gmail_user  
   send_to = 'address1@gmail.com, address2@gmail.com'  
   
   # Create Timestamp  
   timestamp = time.strftime("%m-%d-%y %H:%M:%S")  
   
   # if statement to determine which email msg to send  
   # If the pin is low then the alarm is sounding  
   # Boolean vale of pin when high is true, low is false  
   if GPIO.input(12):  
     subject = 'Smoke Detector Stopped ' + timestamp  
     body = 'Sorry to interrupt you again, but your smoke detector has stopped sounding. It is possible that there is no fire, but it is also possible that the fire has shorted out part or all of your elecrical system. Thank you for your time. \n\n   Sincerly,\n Pi-Server'  
   else:  
     subject = 'Your House May be on Fire ' + timestamp  
     body = 'Sorry to interrupt you, but it seems that your smoke detector is sounding. It is possible that your house is on fire. Thank you for your time. \n\n   Sincerly,\n Pi-Server'  
   
   # Compose the email  
   msg = MIMEText(body)  
   msg['From'] = sent_from  
   msg['To'] = send_to  
   msg['Subject'] = subject  
   
   # Send the email  
   try:   
     server = smtplib.SMTP_SSL('smtp.gmail.com', 465)  
     server.ehlo()  
     server.login(gmail_user, gmail_pass)  
     server.sendmail(sent_from, send_to, msg.as_string())  
     server.close()  
   
     if GPIO.input(12):  
       print 'All-clear email sent!'  
     else:  
       print 'Alert email sent!'  
   except:   
     print 'Something went wrong sending email...'  
   
   
 # Beginning of Program  
   
 GPIO.setmode(GPIO.BCM) # Set's GPIO pins to BCM GPIO numbering  
 INPUT_PIN = 12 # Set's the variable representing the input pin to 12  
 GPIO.setup(INPUT_PIN, GPIO.IN) # Sets the input pin to be an input  
   
 # Wait for the input to change states, run the function send_alert when it does  
 GPIO.add_event_detect(INPUT_PIN, GPIO.BOTH, callback=send_alert, bouncetime=2000)  
   
   
 # Endless loop to keep the program running  
 var = 1  
 while var == 1:  
   print 'smoke detector is being monitored'  
   time.sleep(60)  
   
   

A couple of quick notes here.  In the example above I have only sent the alert to two email addresses.  It is also possible to send a text message using email.  For Verizon, you use the full 10-digit phone number followed by @vtext.com  The advantage of using text message is that it tends to get pushed to your phone faster, since most email just polls the server periodically.  The limitation of using text messages, at least with Verizon, is that to send it from email you are limited to 140 characters including the addresses.  Since I am already sending this to two email addresses, adding two more text message addresses to the message pushes the total over 140 characters, and the message doesn't go through.  The solution to this is simple, I just need to create a second email message that only sends a short message via text.  This is not difficult, I just haven't done it yet.

Whether you've written your own script or used mine above, don't forget to make your file executable:

chmod +x filename.py

If you want to be able to run the script using only the filename without referencing the location then copy the file to /usr/bin, although this is not really necessary in this case since I will just be running the script automatically on boot.

cp /home/pi/filename.py /usr/bin/filename.py

Finally, I want to make the script run when the Pi boots so that I don't have to log in and run the script every time the power flickers.  There are several ways to do this, but the method I used was to edit the /etc/rc.local file.  Use whatever text editor you like, I prefer Vim.

sudo vim /etc/rc.local

Add the following line under the comments, but before the "exit 0"

sudo /home/pi/filename.py &

Don't forget the ampersand at the end to tell the script to run as a separate process.  Since the script is an endless loop, if you leave off the ampersand the Pi could get hung up in the loop and never finish booting.  Also note that this script must be run as root due to accessing the GPIO pins, hence the "sudo".

And that's it.  Connect all the wires, reboot the Pi, and now the Pi is monitoring the smoke detectors.


So What Next?

At the time of writing this blog I have had this project done for about a month.  It has been running 24/7 and tested periodically with both the smoke detectors and the test switch.  No problems so far, and only one false alarm that happened during a lightning storm.  I'm planning on putting this project along with my file server and network equipment on a UPS, so that should stop any power fluctuations from causing false alarms.

So what other uses can I come up with for this Pi?  I'm up for suggestions.  I'm considering a temperature and humidity sensor in the shop, because heat and moisture are bad for both woodworking and electronics.  I'm even considering putting wireless contact sensors on the windows and doors so that the Pi can act as a home security system.

Currently, I'm building a system to allow the Pi to control water flow to a hose bib so I can schedule the sprinklers hooked up to that faucet.  It combines a little plumbing with a little electronics and results in a fairly interesting project.  As soon as I get it up and running I'll post an overview for anyone interested in building something similar.  Until then, stay safe and keep building.

5 comments:

  1. Thank you for your excellent write up of this useful project. I found your page by following the link on Dr Edward Cheung's page.

    The explanation behind the choice of resistor values was particularly helpful to me and filled in the missing piece of the jigsaw, because I have only recently started to understand opto-isolators.

    I am in the middle of building a similar smart smoke alarm, but it will be connected to an ESP8266 instead of a Pi.

    I'm planning to connect this to a mains powered Kiddie smoke alarm (interconnect signal is still 9v DC), which will be wired into the lighting circuit of my home. If the alarm activates I can have the ESP8266 alert a home automation server, such as OpenHAB.

    The idea is to power the ESP8266 from said lighting circuit using a tiny AC-DC converter I bought, which provides a 3.3v DC output and will be located near the alarm and the ESP8266. It should be exciting trying to avoid the irony of my project actually causing a fire!

    ReplyDelete
    Replies
    1. Thanks. I'm glad you found this useful. Good luck on your project. It sounds like you have a good design. Just be sure to allow some airflow around the inverter/voltage regulator because they all emit some heat by design.

      Delete
  2. You could integrate this into something like Domoticz and use that for scripting and alerting. I use Domoticz and have a relay on the pi to control my garage opener and light as well as to control the zwave devices I have.

    ReplyDelete
  3. Thanks for the suggestion. Domoticz looks interesting. I'm actually working on writing a web interface front end of my own. I'm sure it won't be as feature rich as Domoticz, but for me it's more about learning and understanding than it is about the finished product.

    ReplyDelete
  4. Thanks for this! It's right on time. I just tossed the alarm system circuit board for my house, replacing it with a Raspberry Pi. I'm now monitoring my door and window sensors and was wondering how to get the smoke detectors' signal to the Pi.

    I understand that the optoisolator isolates the two circuits, but not sure how it reduces noise. I would think the noise on the alarm signal would translate to noisy flashes of light in the optoisolator and therefore to noise on the circuit involving the GPIO.

    ReplyDelete