Results 1 to 2 of 2

Thread: Garage Door Monitor via SMS

  1. #1
    Join Date
    May 2008
    Location
    TN
    Posts
    853
    Images
    99
    Rep Power
    78

    Garage Door Monitor via SMS

    We bought a new house last year and I had a garage for the first time in my life. While I absolutely love it, I have had a problem with leaving the garage door open. Thus was born this project, a garage door monitor that works over SMS. I also like to call it an experiment with the worlds slowest serial protocol.

    I knew that I wanted to be able to check the door to see if I had left it open as well as close it when I needed to. I have an Android powered smart phone and toyed with the idea of writing a custom Android application to meet my needs but that would limit the platforms that would work with the system. Around the time that I started laying out the project Google Voice opened up to everyone. There's my solution!

    I signed up for a local Google Voice account and got a phone number assigned. This was free and looked like it would do exactly what I needed. Next I searched the web to see who had written code for GV. I found the API for Google Voice and tossed around writing a custom application when I came across a Python module for Google Voice. Once again, all things complex are made easy with python.

    I grabbed the module and wrote a simple wrapper to check the GV SMS messages every couple of minutes. The code looks at incoming messages and sees if the sender is on an "approved" list. This is to keep my friends from driving me insane with a randomly closing door. If the number is on an approved list then it checks the incoming text for a valid command. If the command is valid then it will send a command to the door controller over a serial port via an XBEE explorer. The Python server code is based on this example:
    http://sphinxdoc.github.com/pygooglevoice/examples.html
    Here is the full Python code:
    Code:
    # 
    #SMS test via Google Voice 
    # 
     
    from googlevoice import Voice 
    import sys 
    import BeautifulSoup 
    import re 
    import time 
    import logging 
    import serial 
     
     
     
    ser = serial.Serial('/dev/ttyUSB1', 9600, timeout = 3) 
     
    LOG_FILENAME = 'debug.txt' 
    logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG) 
     
     
    timeThreshold = 120   #  Time in seconds to poll the server 
     
    startTime = time.time() 
    voice = Voice() 
    
    print "SMS Portal Service Started" 
     
     
    def readUsers() : 
        f = open('users.txt', 'r') 
        users = f.readlines()     
        f.close() 
        return users 
     
    def addUser(user) : 
        f = open('users.txt', 'a')     
        f.write("+1" + user + ":\n")     
        f.close() 
         
     
    def ready() : 
        logging.debug("_______________  Started at " + time.strftime('%X %x %Z')) 
        print "Ready" 
         
     
    def extractsms(htmlsms) : 
        """ 
        extractsms  --  extract SMS messages from BeautifulSoup tree of Google Voice SMS HTML. 
     
        Output is a list of dictionaries, one per message. 
        """ 
        msgitems = []                                        # accum message items here 
        #    Extract all conversations by searching for a DIV with an ID at top level. 
        tree = BeautifulSoup.BeautifulSoup(htmlsms)            # parse HTML into tree 
        conversations = tree.findAll("div",attrs={"id" : True},recursive=False) 
        for conversation in conversations : 
            #    For each conversation, extract each row, which is one SMS message. 
            rows = conversation.findAll(attrs={"class" : "gc-message-sms-row"}) 
            for row in rows :                                # for all rows 
                #    For each row, which is one message, extract all the fields. 
                msgitem = {"id" : conversation["id"]}        # tag this message with conversation ID 
                spans = row.findAll("span",attrs={"class" : True}, recursive=False) 
                for span in spans :                            # for all spans in row 
                    cl = span["class"].replace('gc-message-sms-', '') 
                    msgitem[cl] = (" ".join(span.findAll(text=True))).strip()    # put text in dict 
                msgitems.append(msgitem)                    # add msg dictionary to list 
        return msgitems 
         
     
    def parseMsg(message) : 
        try : 
            serOut = '' 
            ser.flush() 
            message = message.lower()
            print message 
            splitMessage = message.split(" ") 
     
            if splitMessage[0] == "status" : 
                serOut = "s"         
     
            if splitMessage[0] == "open" : 
                serOut = "o" 
         
            if splitMessage[0] == "close" : 
                serOut = "c" 
     
            if splitMessage[0] == "adc" : 
                serOut = "v"     
     
            if splitMessage[0] == "?" : 
                return "Commands: status, open, close, adc, add #, remove #"  # Don't send anything out the port 
     
            if splitMessage[0] == "add" : 
                number = splitMessage[1] 
                addUser(number) 
                return number + " added" 
             
             
            if serOut : 
                ser.write(serOut)             
                serialData = ser.readline() 
                if not serialData : 
                    serialData = "Timeout" 
             
            if not serOut : 
                serialData = "Not Found" + "'" + message + "'" 
     
            return serialData 
    
        except : 
            return "Bad command or unable to address serial port" 
             
             
         
    def checkMsg(login, password) : 
        voice.login(login, password)     
        voice.sms() 
        returned = '' 
        if extractsms(voice.sms.html) :     
            for msg in extractsms(voice.sms.html):     
                number = str(msg['from'])                 
                user = msg['from']+ '\n'                         
                if user in readUsers():    
                 
                    logging.debug('Message from approved user: ' + msg['from'] + 'at ' + time.strftime('%X %x %Z')) 
                    logging.debug('Message: ' + str(msg['text'])) 
                     
                     
                    incomingCommand = msg['text']                 
                    #print incomingCommand 
                    returned = parseMsg(incomingCommand) 
                    logging.debug("From Garage: " + returned +"\n\n")  # The \n's are for a few buffer lines                 
     
     
                    voice.send_sms(number, returned) 
                    for message in voice.sms().messages:        # delete all of the old messages 
                        message.delete() 
                        time.sleep(1) 
                     
                         
        else :         
            pass 
        voice.logout() 
                     
     
    def deleteMsg(login, password) : 
        numMessages = 0 
        voice.login(login, password)     
        voice.sms() 
        print "Deleting old messages" 
        for message in voice.sms().messages:        # delete all of the old messages 
            numMessages = numMessages + 1 
            message.delete() 
            time.sleep(1) 
        logging.debug(str(numMessages) + " messages emptied\n\n") 
        print "Deleted " + str(numMessages) + " messages" 
     
     
    ready() 
    deleteMsg('loginName', 'password') 
     
    while 1 : 
        if time.time() - startTime > timeThreshold : 
            startTime = time.time()     
            try : 
                checkMsg('loginName', 'password')     
            except : 
                logging.debug('***********  Server Error at ' + time.strftime('%X %x %Z')) 
     
        else : 
            pass
    The server talks to the hardware controller over and XBEE radio. The hardware controller is in the garage and just consists of an Arduino connected to a garage door opener that I bought off of eBay. I opened the garage door opener and soldered two wires across the button. I connected those to a relay that is controlled by the Arduino. When the Arduino receives a valid command over the XBEE then it will check the door state by reading a photo-sensor attached to the side of the door. It will then open or close the garage door as needed. It's important to note that I used an XBEE Explorer Regulated in the controller so that it will take care of all of the regulation and step up or down the voltage as needed. The circuit is really simple and is built on a prototyping sheield for an Arduino. Here is the code that runs on the Arduino:
    Code:
    //  Controls a garage door via an XBEE
    //  replay pin attaches to a relay wired to the door opener
    //  Yellow LED lights when the door is activated
    
    //  Low on Door means closed
    
    // Pin definitions
    int doorSensor = 4;
    int doorRelay = 13;
    int greenLED = 12;
    int yellowLED = 11;
    int buzzer = 9;
    
    // State definitions
    int open = 0;
    int closed = 1;
    int incomingByte = 0;
    int doorThreshold = 800;
    
    
    void setup() 
    { 
      pinMode(doorSensor, INPUT);
      digitalWrite(doorSensor, HIGH);
      pinMode(doorRelay, OUTPUT);
      pinMode(greenLED, OUTPUT);
      pinMode(yellowLED, OUTPUT);
      pinMode(buzzer, OUTPUT);  
      Serial.begin(9600);   
      Serial.println("Garage online"); 
      if(readDoor() == open) {
        toggleDoor();    
      }  
    } 
    
    
    int readDoor() {
      int i;
      i = analogRead(doorSensor);
      Serial.println(i);
      if (i< doorThreshold){
        return closed;
      }
        
      else { return open;}
      
    }
    
    int checkDoor() {
      delay(30000);
      return readDoor();
    }
      
    void sendError() {
      Serial.println("error");
    }
    
    
    
    int toggleDoor() {
      digitalWrite(yellowLED, HIGH);
      digitalWrite(doorRelay, HIGH);
      delay(100);  // time to hold down button
      digitalWrite(doorRelay, LOW);
      digitalWrite(yellowLED, LOW);
        
    }
    
    
    
    void loop() 
    { 
      int i = 0;
      int doorState = 0;
      doorState = readDoor();
      
      if (Serial.available() > 0) {
        incomingByte = Serial.read();
        Serial.println(incomingByte, BYTE); //Echo
        switch(incomingByte) {      
          
          
          
          
          
          case 'o' :        
            if (readDoor() == closed) {          
              toggleDoor();
              if (checkDoor() != open) {sendError();}
              else {Serial.println("ok");}
            }            
            break;
            
          case 'c' :
            if (readDoor() == open) {          
              toggleDoor();
              if (checkDoor() != closed) {sendError();}
              else {Serial.println("ok");}
            }
            break;
            
          case 's' :
            doorState = readDoor();
              if (doorState == closed) {
                Serial.println("closed");
              }
              else  { Serial.println("open"); }
              break;
        
        }       
           
    
      }
      
      
    }
    Here is the controller. You can see the XBEE at the top and well as the relay and drive transistor on the shield.



    This is a view of the door sensor. It mounts on the side of the box and detects whether the door is open or closed. It's connected to an A/D port on the Arduino.


    Finally, here is the schematic. It's drawn as if you are using just an ATMEGA8 rather than a full Arduino.



    Overall, this project was a resounding success. I can check the state of the door at any time from anywhere that I have cell service. Plus I can now say that I can send a text to my garage and it will do something. Sweet! Now if I just explain to my wife why it was required...
    Last edited by jes1510; 12-23-2010 at 11:40 PM.
    "If A is a success in life, then A equals x plus y plus z. Work is x; y is play; and z is keeping your mouth shut."
    -
    Einstein

    Don't be a HelpVampire

  2. #2
    Join Date
    Dec 2007
    Location
    Whidbey Island, WA
    Posts
    1,718
    Images
    456
    Rep Power
    102

    Re: Garage Door Monitor via SMS

    Now I'm going to have to build a garage just so I can use your really cool project.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. News/Announcement Huge Garage Sale at Trossen Robotics
    By Alex in forum Garage Sale
    Replies: 1
    Last Post: 02-26-2010, 05:09 PM
  2. Garage sale??
    By Hellfire in forum Garage Sale
    Replies: 5
    Last Post: 01-20-2009, 06:15 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •