Advertisement
Guest User

Untitled

a guest
Jul 18th, 2019
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.14 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. import RPi.GPIO as GPIO
  4. from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
  5. import time
  6. import signal
  7. import sys
  8. from lib import send_mail
  9.  
  10. ###############
  11. # Global Vars #
  12. ###############
  13.  
  14. XMLRPC_IP = "0.0.0.0"
  15. XMLRPC_PORT = 9000
  16.  
  17. RELAY_PIN = 37
  18. RESET_BTN = 35
  19.  
  20. # Keeps track of the last time a button was pressed
  21. last_reset_button_press_at = 0.0
  22.  
  23. # Keeps track of the last time the relay was flipped
  24. last_relay_flip_at = 0.0
  25.  
  26. last_alert = ''
  27. last_alert_at = 0.0
  28.  
  29. ##############
  30. # Setup Pins #
  31. ##############
  32.  
  33. GPIO.setmode(GPIO.BOARD)
  34.  
  35. GPIO.setup(RELAY_PIN, GPIO.OUT)
  36. GPIO.setup(RESET_BTN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  37.  
  38. #######################
  39. # Kill Signal Handler #
  40. #######################
  41.  
  42. def signal_handler(*_):
  43. GPIO.cleanup()
  44. print("\nExiting...")
  45. sys.exit()
  46.  
  47. signal.signal(signal.SIGINT, signal_handler)
  48. signal.signal(signal.SIGTERM, signal_handler)
  49.  
  50. #########################
  51. # Set to Low as Default #
  52. #########################
  53.  
  54. GPIO.output(RELAY_PIN, GPIO.LOW)
  55.  
  56. #############
  57. # Functions #
  58. #############
  59.  
  60. # Makes sure the button is being released - not pressed
  61. # Due to a bug in the GPIO library, a GPIO.FALLING appears the same as
  62. # GPIO.BOTH. This means the callback will be called when the button is
  63. # being released (as it should), and sometimes when the button is being
  64. # pressed. This results in 2 calls per button press. This decorator
  65. # waits 5ms and checks the input's state, to see if it's currently pressed
  66. # or released. This eliminates false positives
  67. def ensure_press(func):
  68. def wrapper(*args, **kwargs):
  69. global last_reset_button_press_at
  70.  
  71. channel = args[0]
  72.  
  73. # Wait before checking state of pin
  74. time.sleep(0.005)
  75.  
  76. if GPIO.input(channel):
  77. return
  78.  
  79. if (time.time() - last_reset_button_press_at) > 1.0:
  80. last_reset_button_press_at = time.time()
  81.  
  82. return func(*args, **kwargs)
  83.  
  84. return wrapper
  85.  
  86. def water_detected(location):
  87. global last_alert
  88. global last_alert_at
  89. global last_relay_flip_at
  90.  
  91. # If the reset button was recently pressed, ignore alerts
  92. # There's some sort of bug where sensors trigger when reset button is pressed
  93. if (time.time() - last_reset_button_press_at) < 2.0:
  94. return True
  95.  
  96. # If the relay was recently flipped, ignore alerts
  97. # There's some sort of bug where sensors trigger when relay is flipped
  98. if (time.time() - last_relay_flip_at) < 2.0:
  99. return True
  100.  
  101.  
  102. # If the alert we are seeing is the same as the last one we got, and
  103. # it's been less than 5 minutes since the last alert, ignore it
  104. # Makes sure it doesn't send us dozens of alerts per minute for the
  105. # same incident
  106. if last_alert == location and time.time() - last_alert_at < 300:
  107. return True
  108.  
  109. print("Water detected at %s" % location)
  110.  
  111. GPIO.output(RELAY_PIN, GPIO.HIGH)
  112. last_relay_flip_at = time.time()
  113.  
  114. last_alert = location
  115. last_alert_at = time.time()
  116.  
  117. # Send email
  118. recipients = 'my@email.com, some_other@email.com'
  119. subject = 'Water Leak Detected'
  120. body = 'Water detected at %s' % location
  121. credentials = {"gmail_username": "some_account@gmail.com",
  122. "gmail_password": ""}
  123.  
  124. send_mail(recipients=recipients,
  125. subject=subject,
  126. body=body,
  127. credentials=credentials)
  128.  
  129.  
  130. return True
  131.  
  132. @ensure_press
  133. def reset_btn_pressed(channel):
  134. global last_alert
  135. global last_alert_at
  136.  
  137. print("Reset button pressed - resetting relay to allow water flow")
  138.  
  139. GPIO.output(RELAY_PIN, GPIO.LOW)
  140.  
  141. last_alert = ''
  142. last_alert_at = 0.0
  143.  
  144. ########
  145. # Main #
  146. ########
  147.  
  148. # XMLRPC Server
  149. print("Running XMLRPC server on %s:%s..." % (XMLRPC_IP, XMLRPC_PORT))
  150.  
  151. # Restrict to a particular path
  152. class RequestHandler(SimpleXMLRPCRequestHandler):
  153. rpc_paths = ('/RPC2',)
  154.  
  155. # Create server
  156. server = SimpleXMLRPCServer((XMLRPC_IP, XMLRPC_PORT),
  157. requestHandler=RequestHandler)
  158.  
  159. # Register my functions
  160. server.register_function(water_detected)
  161.  
  162. # Setup reset button handler
  163. GPIO.add_event_detect(RESET_BTN, GPIO.FALLING, callback=reset_btn_pressed, bouncetime=300)
  164.  
  165. # Run the server
  166. server.serve_forever()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement