Advertisement
Guest User

My code

a guest
Jan 23rd, 2017
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.32 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. # GARAGE DOOR SMS BUTLER
  4. # Written by Akira Fist, August 2014
  5. #
  6. # Most Raspberry Pi garage door remotes had open ports, or other features I wasn't too fond of.
  7. # So I created my own that contains much more security, logging of who opens the garage, video capture, garage status and more.
  8. #
  9. # Features:
  10. #
  11. # - 100% secure garage door operation, with access control lists. Only authorized family members can open.
  12. # - Ability to monitor or control garage anywhere in the world from a controlled website, with no open router ports
  13. # - Full video capture of who's coming into the garage, uploaded security to a website for later perusal
  14. # - Ability to remotely stop or kill the process in case of malfunction or abuse
  15. # - Email notifications when a family member arrives or leaves the house
  16. # - Cheap SMS solution (3/4 a cent per text), with no GSM card purchases or any cell contracts
  17. # - Standard Linux code, easily setup on a new Pi, and quickly portable to other platforms like BeagleBone or whatever
  18. # future Linux technology arrives. Basically, I wanted the ability to restore this system on a fresh device within 30 minutes or less
  19. #
  20.  
  21. import RPi.GPIO as GPIO
  22. import MySQLdb
  23. import datetime
  24. import time
  25. import os
  26. import smtplib
  27. from ftplib import FTP
  28. from email.MIMEMultipart import MIMEMultipart
  29. from email.MIMEText import MIMEText
  30. from email.MIMEImage import MIMEImage
  31. from contextlib import closing
  32. from twilio.rest import TwilioRestClient
  33.  
  34. # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  35. # VARIABLES
  36. # CHANGE THESE TO YOUR OWN SETTINGS!
  37. # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  38.  
  39. # Insert your own account's SID and auth_token from Twilio's account page
  40. twilio_account_sid = "AC0fbcd3bc0d7cc012eadb60befea6ab7f"
  41. twilio_auth_token = "8023ed8a72c3331c8a1836332c82ac52"
  42. # The phone number you purchased from Twilio
  43. sTwilioNumber = "+12048189506"
  44. # Gmail information - for informing homeowner that garage activity happened
  45. recipients = ['']
  46. sGmailAddress = ""
  47. sGmailLogin = ""
  48. sGmailPassword = ""
  49. sFTPUserName = "WebsiteFTPUsername"
  50. sFTPPassword = "WebsiteFTPPassword"
  51. sFTPHost = "MyWebsite.com"
  52.  
  53. iNumOpenings = 0
  54. iStatusEnabled = 1
  55. iAuthorizedUser_Count = 0
  56. iSID_Count = 0
  57.  
  58. sLastCommand = "Startup sequence initiated at {0}. No open requests, yet".format(time.strftime("%x %X"))
  59. sAuthorized = ""
  60. sSid = ""
  61. sSMSSender = ""
  62. # Added cleanup command as I was having trouble with an error telling me that the pins were already in use
  63. GPIO.cleanup()
  64. GPIO_PIN = 23
  65. # Added Pins 4 and 17 as variables
  66. GPIO_FOUR = 4
  67. GPIO_ONESEVEN = 17
  68. GPIO.setmode(GPIO.BCM)
  69. GPIO.setup(GPIO_PIN, GPIO.OUT)
  70. #Set pins 4 and 17 as outputs
  71. GPIO.setup(GPIO_FOUR, GPIO.OUT)
  72. GPIO.setup(GPIO_ONESEVEN, GPIO.OUT)
  73.  
  74. # Unfortunately, you can't delete SMS messages from Twilio's list.
  75. # So we store previously processed SIDs into the database.
  76. lstSids = list()
  77. lstAuthorized = list() # authorized phone numbers, that can open the garage
  78.  
  79. # Connect to local MySQL database
  80. con = MySQLdb.connect('localhost', 'garage', 'garagepassword', 'GarageDoor')
  81. # Twilio client which will be fetching messages from their server
  82. TwilioClient = TwilioRestClient(twilio_account_sid, twilio_auth_token)
  83.  
  84.  
  85. # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  86. # FUNCTIONS
  87. # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  88.  
  89. # This function sends an SMS message, wrapped in some error handling
  90. def SendSMS(sMsg):
  91. try:
  92. sms = TwilioClient.sms.messages.create(body="{0}".format(sMsg),to="{0}".format(sSMSSender),from_="{0}".format(sTwilioNumber))
  93. except:
  94. print "Error inside function SendSMS"
  95. pass
  96.  
  97. # Once the garage door has begun opening, I want a video of who's coming in. And then, upload the video to my website so I can see it remotely
  98. #I disabled this in my in my project as I didnt have a use for it
  99. def TakeVideoAndUpload():
  100. try:
  101. sVideoFile = "Vid.{0}.h264".format(time.strftime("%m-%d-%Y.%I.%M.%S"))
  102. # Give 10 seconds to garage to raise up
  103. time.sleep(10)
  104. # Now take 60 seconds of video, to see who's coming inside
  105. sVideoCommand = "raspivid -w 640 -h 480 -o /home/pi/movies/{0} -t 60000".format(sVideoFile)
  106. os.system(sVideoCommand)
  107. ftp = FTP(sFTPHost,sFTPUserName,sFTPPassword)
  108. ftp.storbinary("stor {0}".format(sVideoFile), open("/home/pi/movies/{0}".format(sVideoFile),'rb'),blocksize=1024)
  109. # It uploaded ok, so delete the video file to avoid clogging up SD card space
  110. os.system("sudo rm /home/pi/movies/{0}".format(sVideoFile))
  111. except:
  112. print "Error inside function TakeVideoAndUpload"
  113. pass
  114.  
  115. # When doing a STATUS on the Garage SMS Butler, it will capture a screen shot of the garage, so I can see if it's open or closed, from anywhere in the world
  116. def TakePictureAndUpload():
  117. try:
  118. os.system("raspistill -w 640 -h 480 -o /home/pi/pictures/garagepic.jpg")
  119. ftp = FTP(sFTPHost,sFTPUserName,sFTPPassword)
  120. ftp.storbinary("stor garagepic.jpg", open("/home/pi/pictures/garagepic.jpg",'rb'),blocksize=1024)
  121. except:
  122. print "Error inside function TakePictureAndUpload"
  123. pass
  124.  
  125. # Send a signal to the relay
  126. #Removed the picture taking functionality and changed the error message didnt change function name as it was called in other places
  127. def OpenGarageDoor():
  128. try:
  129. GPIO.output(GPIO_PIN, GPIO.HIGH)
  130. time.sleep(0.5)
  131. GPIO.output(GPIO_PIN, GPIO.LOW)
  132. except:
  133. print "Error inside function twothree"
  134. pass
  135.  
  136. #Set pin four to high for point five seconds
  137. def four():
  138. try:
  139. GPIO.output(GPIO_FOUR, GPIO.HIGH)
  140. time.sleep(0.5)
  141. GPIO.output(GPIO_FOUR, GPIO.LOW)
  142. except:
  143. print "Error inside function four"
  144. pass
  145.  
  146. def oneseven():
  147. try:
  148. GPIO.output(GPIO_ONESEVEN, GPIO.HIGH)
  149. time.sleep(0.5)
  150. GPIO.output(GPIO_ONESEVEN, GPIO.LOW)
  151. except:
  152. print "Error inside function oneseven"
  153. pass
  154.  
  155.  
  156.  
  157. # Email the home owner with any status updates
  158. def SendGmailToHomeOwner(sMsg):
  159. try:
  160. connect = server = smtplib.SMTP('smtp.gmail.com:587')
  161. starttls = server.starttls()
  162. login = server.login(sGmailLogin,sGmailPassword)
  163. msg = MIMEMultipart()
  164. msg['Subject'] = "GARAGE: {0}".format(sMsg)
  165. msg['From'] = sGmailAddress
  166. msg['To'] = ", ".join(recipients)
  167. sendit = server.sendmail(sGmailAddress, recipients, msg.as_string())
  168. server.quit()
  169. except:
  170. print "Error inside function SendGmailToHomeOwner"
  171. pass
  172.  
  173.  
  174. try:
  175. # Store authorized phone numbers in a List, so we don't waste SQL resources repeatedly querying tables
  176. with closing(con.cursor()) as authorized_cursor:
  177. authorized_users = authorized_cursor.execute("select sPhone from Authorized")
  178. auth_rows = authorized_cursor.fetchall()
  179. for auth_row in auth_rows:
  180. for auth_col in auth_row:
  181. iAuthorizedUser_Count = iAuthorizedUser_Count + 1
  182. lstAuthorized.append(auth_col)
  183.  
  184. # Store previous Twilio SMS SID ID's in a List, again, so we don't waste SQL resources repeatedly querying tables
  185. with closing(con.cursor()) as sid_cursor:
  186. sid_rows = sid_cursor.execute("select sSid from Door")
  187. sid_rows = sid_cursor.fetchall()
  188. for sid_row in sid_rows:
  189. for sid_col in sid_row:
  190. iSID_Count = iSID_Count + 1
  191. lstSids.append(sid_col)
  192.  
  193. print "{0} Service loaded, found {1} authorized users, {2} previous SMS messages".format(time.strftime("%x %X"),iAuthorizedUser_Count,iSID_Count)
  194. SendGmailToHomeOwner("{0} Service loaded, found {1} authorized users, {2} previous SMS messages".format(time.strftime("%x %X"),iAuthorizedUser_Count,iSID_Count))
  195. except:
  196. print "{0} Error while loading service, bailing!".format(time.strftime("%x %X"))
  197. if con: con.close() # Not critical since we're bailing, but let's be nice to MySQL
  198. exit(2)
  199.  
  200.  
  201. # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  202. # MAIN GARAGE LOOP
  203. #
  204. # Continuously scan Twilio's incoming SMS list
  205. # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  206.  
  207. while (True):
  208.  
  209. # The TRY block is critical. If we cannot connect to the database, then we could possibly open the garage dozens of times.
  210. # If we can't contact Twilio, again, we could open the garage excessively. Ideally, if any error at all occurs, we need
  211. # to completely bail, and ideally contact the home owner that this application stopped working.
  212. try:
  213.  
  214. # Only process messages from today (Twilio uses UTC)
  215. messages = TwilioClient.messages.list(date_sent=datetime.datetime.utcnow())
  216.  
  217. for p in messages:
  218. sSMSSender = p.from_
  219.  
  220. # Only processed fully received messages, otherwise we get duplicates
  221. if p.status == "received":
  222. if p.sid not in lstSids: # Is it a unique SMS SID ID from Twilio's list?
  223. # Insert this new SID ID into database and List, to avoid double processing
  224. lstSids.append(p.sid)
  225. try:
  226. with closing(con.cursor()) as insert_sid_cursor:
  227. insert_sid_cursor = insert_sid_cursor.execute("insert into Door(sSid) values('{0}')".format(p.sid))
  228. con.commit()
  229. except:
  230. print "Error while inserting SID record to database"
  231. pass
  232.  
  233. if p.from_ in lstAuthorized: # Is this phone number authorized to open garage door?
  234. if p.body.lower() == "kill":
  235. print "{0} Received KILL command from phone number {1} - bailing now!".format(time.strftime("%x %X"), sSMSSender)
  236. SendSMS("Received KILL command from you. Bailing to terminal now!")
  237. SendGmailToHomeOwner("Received KILL command from phone number {0}. Exiting application!".format(sSMSSender))
  238. exit(3)
  239.  
  240. if p.body.lower() == "disable":
  241. iStatusEnabled = 0
  242. print "{0} Received STOP command from phone number {1}, now disabled. Send START to restart".format(time.strftime("%x %X"), sSMSSender)
  243. SendSMS("Received STOP command from you. Send START to restart")
  244. SendGmailToHomeOwner("Received STOP command from phone number {0}. Send START to restart".format(sSMSSender))
  245.  
  246. if p.body.lower() == "enable":
  247. iStatusEnabled = 1
  248. print "{0} Received START command from phone number {1}. Service is now enabled".format(time.strftime("%x %X"), sSMSSender)
  249. SendSMS("Received START command from you. Service is now enabled")
  250. SendGmailToHomeOwner("Received START command from phone number {0}. Service is now enabled".format(sSMSSender))
  251.  
  252. if p.body.lower() == "status":
  253. if iStatusEnabled == 1:
  254. TakePictureAndUpload()
  255. print "{0} Status requested from {1}, replied".format(time.strftime("%x %X"), sSMSSender)
  256. SendSMS("ENABLED. Status reply: {0}".format(sLastCommand))
  257. else:
  258. print "{0} SERVICE DISABLED! Status requested from {1}, replied".format(time.strftime("%x %X"), sSMSSender)
  259. SendSMS("SERVICE DISABLED! Status reply: {0}".format(sLastCommand))
  260. # Changed the text required to run the function "opengaragedoor" to something that made more sense for my project
  261. if p.body.lower() in ("twothree"):
  262. if iStatusEnabled == 1:
  263. iNumOpenings = iNumOpenings + 1
  264. # OPEN GARAGE DOOR HERE
  265. SendSMS("Pin 23 set to high for .5 seconds")
  266. print "{0} SMS response sent to authorized user {1}".format(time.strftime("%x %X"), sSMSSender)
  267. OpenGarageDoor()
  268. else:
  269. print "{0} request received from {1} but SERVICE IS DISABLED!".format(time.strftime("%x %X"), sSMSSender)
  270.  
  271. #added a if statement for the text four that would run the finction that I created
  272. if p.body.lower() in ("four"):
  273. if iStatusEnabled == 1:
  274. iNumOpenings = iNumOpenings + 1
  275. SendSMS("Pin four set to high for .5 seconds")
  276. print "{0} SMS response sent to authorized user {1}".format(time.strftime("%x %X"), sSMSSender)
  277. four()
  278. else:
  279. print "error in four"
  280. # added a if statement for the text oneseven that would run the fuction oneseven that I created
  281. if p.body.lower() in ("oneseven"):
  282. if iStatusEnabled == 1:
  283. iNumOpenings = iNumOpenings + 1
  284. SendSMS("Pin 17 set to high for .5 seconds")
  285. print "{0} SMS response sent to authorized user {1}".format(time.strftime("%x %X"), sSMSSender)
  286. oneseven()
  287. else:
  288. print "error in one seven"
  289.  
  290. else: # This phone number is not authorized. Report possible intrusion to home owner
  291. print "{0} Unauthorized user tried to access system: {1}".format(time.strftime("%x %X"), sSMSSender)
  292. SendGmailToHomeOwner("Unauthorized phone tried opening garage: {0}".format(sSMSSender))
  293. print "{0} Email sent to home owner".format(time.strftime("%x %X"))
  294.  
  295. except KeyboardInterrupt:
  296. SendGmailToHomeOwner("Application closed via keyboard interrupt (somebody closed the app)")
  297. GPIO.cleanup() # clean up GPIO on CTRL+C exit
  298. exit(4)
  299.  
  300. except:
  301. print "Error occurred, bailing to terminal"
  302. SendGmailToHomeOwner("Error occurred, bailing to terminal")
  303. GPIO.cleanup()
  304. exit(1)
  305.  
  306. GPIO.cleanup()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement