PageRenderTime 118ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/tot.py

https://gitlab.com/tighek/Toad-ToT
Python | 417 lines | 363 code | 45 blank | 9 comment | 104 complexity | 95b8ec6dbe3ae02b6d61b99038ae304a MD5 | raw file
  1. #!/usr/bin/python
  2. #
  3. # Trunk or Treat Automation
  4. # Copyright 2015 Tighe Kuykendall
  5. # All rights reserved under the Apache 2.0 License
  6. #
  7. # See http://github.com/tighek/toad-tot
  8. #
  9. import RPi.GPIO as GPIO
  10. import time
  11. import random
  12. import sys
  13. import optparse
  14. import config as cfg
  15. import socket
  16. import select
  17. import pygame
  18. def setup_action():
  19. GPIO.setmode(GPIO.BCM)
  20. GPIO.setwarnings(False)
  21. if cfg.tubes:
  22. for tube_name, tube_value in cfg.tubes.iteritems():
  23. GPIO.setup(tube_value, GPIO.OUT, initial=GPIO.HIGH)
  24. if cfg.sprayers:
  25. for sprayer_name, sprayer_value in cfg.sprayers.iteritems():
  26. GPIO.setup(sprayer_value, GPIO.OUT, initial=GPIO.HIGH)
  27. pygame.mixer.init()
  28. return
  29. def setup_sensor():
  30. GPIO.setmode(GPIO.BCM)
  31. GPIO.setwarnings(False)
  32. if cfg.doors:
  33. for door_name, door_value in cfg.doors.iteritems():
  34. GPIO.setup(door_value, GPIO.IN, pull_up_down = GPIO.PUD_UP)
  35. if cfg.buttons:
  36. for button_name, button_value in cfg.buttons.iteritems():
  37. GPIO.setup(button_value, GPIO.IN, pull_up_down = GPIO.PUD_UP)
  38. return
  39. def sensor_send(item):
  40. sensor_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  41. sensor_client.connect((cfg.ACTION_IP, cfg.ACTION_PORT))
  42. sensor_client.send(item)
  43. sensor_client.close()
  44. return
  45. def fire_tube(tb):
  46. global run_mode
  47. if run_mode == "local" or run_mode == "action":
  48. print ("Mode: " + run_mode + " Fire Candy %s" % tb)
  49. GPIO.output(cfg.tubes.get(tb), 0)
  50. time.sleep(config.VALVE_OPEN_TIME)
  51. GPIO.output(cfg.tubes.get(tb), 1)
  52. sound_play("success")
  53. elif run_mode == "sensor":
  54. print ("Mode: " + run_mode + "Fire Candy %s" % tb)
  55. sensor_send(tb)
  56. return
  57. def spray_water(tb):
  58. global run_mode
  59. if run_mode == "local" or run_mode == "action":
  60. print ("Mode: " + run_mode + "Fire Water %s" % tb)
  61. GPIO.output(cfg.sprayers.get(tb), 0)
  62. time.sleep(config.VALVE_OPEN_TIME)
  63. GPIO.output(cfg.sprayers.get(tb), 1)
  64. sound_play("fail")
  65. elif run_mode == "sensor":
  66. print ("Mode: " + run_mode + "Fire Water %s" % tb)
  67. sensor_send(tb)
  68. return
  69. def sound_pygame(sound):
  70. pygame.mixer.music.load(sound)
  71. pygame.mixer.music.play()
  72. while pygame.mixer.music.get_busy() == True:
  73. continue
  74. return
  75. def sound_play(type):
  76. if type == "reset":
  77. sound_pygame(cfg.SOUND_RESET)
  78. elif type == "fail":
  79. sound_pygame(cfg.SOUND_FAIL)
  80. elif type == "success":
  81. sound_pygame(cfg.SOUND_SUCCESS)
  82. elif type == "reload":
  83. sound_pygame(cfg.SOUND_RELOAD)
  84. return
  85. def randomize_tubes():
  86. rand_water = random.sample(range(1, 8), 2)
  87. w1 = rand_water[0]
  88. w2 = rand_water[1]
  89. rand_candy = list(range(1, 8))
  90. rand_candy.remove(w1)
  91. rand_candy.remove(w2)
  92. print ("Water Tubes: %s" % rand_water)
  93. print ("Candy Tubes: %s" % rand_candy)
  94. time.sleep(1)
  95. return rand_water, rand_candy
  96. def fire_candy():
  97. global candy_tube
  98. global candy_tube_only
  99. global candy_count
  100. global water_count
  101. if candy_tube_only == 1 and candy_tube < num_tubes:
  102. tot_candy_metrics = open('tot_candy_metrics', 'a')
  103. tot_candy_metrics.write('1')
  104. tot_candy_metrics.close()
  105. candy_count = 0
  106. fire_tube("tube"+str(candy_tube))
  107. candy_tube += 1
  108. elif candy_tube_only == 1 and candy_tube == num_tubes:
  109. tot_candy_metrics = open('tot_candy_metrics', 'a')
  110. tot_candy_metrics.write('1')
  111. tot_candy_metrics.close()
  112. candy_count = 0
  113. fire_tube("tube"+str(candy_tube))
  114. sound_play(reload)
  115. candy_tube = 1
  116. elif 1 <= candy_tube <= num_tubes-1 and candy_count < 2:
  117. tot_candy_metrics = open('tot_candy_metrics', 'a')
  118. tot_candy_metrics.write('1')
  119. tot_candy_metrics.close()
  120. candy_count += 1
  121. fire_tube("tube"+str(candy_tube))
  122. candy_tube += 1
  123. elif candy_tube == num_tubes and candy_count < 2:
  124. tot_candy_metrics = open('tot_candy_metrics', 'a')
  125. tot_candy_metrics.write('1')
  126. tot_candy_metrics.close()
  127. candy_count += 1
  128. fire_tube("tube"+str(candy_tube))
  129. sound_play(reload)
  130. candy_tube = 1
  131. water_count = 0
  132. else:
  133. candy_count = 0
  134. fire_water()
  135. time.sleep(.2)
  136. return
  137. def fire_water():
  138. global water_spray_only
  139. global water_tube
  140. global water_count
  141. if water_spray_only == 1:
  142. tot_water_metrics = open('tot_water_metrics', 'a')
  143. tot_water_metrics.write('1')
  144. tot_water_metrics.close()
  145. spray_water("spray"+str(water_tube))
  146. water_tube = 1
  147. elif water_tube == 1 and water_count <= 2:
  148. tot_water_metrics = open('tot_water_metrics', 'a')
  149. tot_water_metrics.write('1')
  150. tot_water_metrics.close()
  151. water_count += 1
  152. spray_water("spray"+str(water_tube))
  153. water_tube = 1
  154. else:
  155. water_count = 0
  156. fire_candy()
  157. time.sleep(.2)
  158. return
  159. def reset_counters():
  160. global water_count
  161. global candy_count
  162. global water_tube
  163. global candy_tube
  164. water_count = 0
  165. candy_count = 0
  166. water_tube = 1
  167. candy_tube = 1
  168. return
  169. def test_action():
  170. if cfg.tubes:
  171. for tube_name, tube_value in cfg.tubes.iteritems():
  172. fire_tube(tube_name)
  173. if cfg.sprayers:
  174. for sprayer_name, sprayer_value in cfg.sprayers.iteritems():
  175. spray_water(sprayer_name)
  176. return
  177. def startup():
  178. global run_mode
  179. if run_mode == "local":
  180. print ("Setup Local Mode")
  181. setup_sensor()
  182. setup_action()
  183. if cfg.FIRE_ON_STARTUP == 1:
  184. test_action()
  185. elif run_mode == "action":
  186. print ("Setup Action Mode")
  187. setup_action()
  188. if cfg.FIRE_ON_STARTUP == 1:
  189. test_action()
  190. elif run_mode == "sensor":
  191. print ("Setup Sensor Mode")
  192. setup_sensor()
  193. return
  194. def sensomatic():
  195. global water_spray_only
  196. global candy_tube_only
  197. global water_count
  198. global water
  199. global candy
  200. lockout_timer = 0
  201. while True:
  202. if GPIO.input(cfg.buttons.get('water_only')) == False and GPIO.input(cfg.buttons.get('candy_only')) == False:
  203. if lockout_timer == 0:
  204. sound_play(reload)
  205. lockout_timer += 1
  206. time.sleep(.5)
  207. elif lockout_timer == 20:
  208. lockout_timer = 0
  209. time.sleep(.5)
  210. else:
  211. lockout_timer += 1
  212. time.sleep(.5)
  213. if GPIO.input(cfg.buttons.get('water_only')) == False:
  214. water_spray_only = 1
  215. elif GPIO.input(cfg.buttons.get('water_only')) == True:
  216. water_spray_only = 0
  217. if GPIO.input(cfg.buttons.get('candy_only')) == False:
  218. candy_tube_only = 1
  219. elif GPIO.input(cfg.buttons.get('candy_only')) == True:
  220. candy_tube_only = 0
  221. if GPIO.input(cfg.doors.get('door1')) == True:
  222. print ("Door1 Open")
  223. if water_spray_only == 1:
  224. water_count = 0
  225. fire_water()
  226. elif candy_tube_only == 1 or 1 in candy:
  227. fire_candy()
  228. elif 1 in water:
  229. fire_water()
  230. time.sleep(cfg.TUBE_DELAY)
  231. elif GPIO.input(cfg.doors.get('door2')) == True:
  232. if water_spray_only == 1:
  233. water_count = 0
  234. fire_water()
  235. elif candy_tube_only == 1 or 2 in candy:
  236. fire_candy()
  237. elif 2 in water:
  238. fire_water()
  239. time.sleep(cfg.TUBE_DELAY)
  240. elif GPIO.input(cfg.doors.get('door3')) == True:
  241. if water_spray_only == 1:
  242. water_count = 0
  243. fire_water()
  244. elif candy_tube_only == 1 or 3 in candy:
  245. fire_candy()
  246. elif 3 in water:
  247. fire_water()
  248. time.sleep(cfg.TUBE_DELAY)
  249. elif GPIO.input(cfg.doors.get('door4')) == True:
  250. if water_spray_only == 1:
  251. water_count = 0
  252. fire_water()
  253. elif candy_tube_only == 1 or 4 in candy:
  254. fire_candy()
  255. elif 4 in water:
  256. fire_water()
  257. time.sleep(cfg.TUBE_DELAY)
  258. elif GPIO.input(cfg.doors.get('door5')) == True:
  259. if water_spray_only == 1:
  260. water_count = 0
  261. fire_water()
  262. elif candy_tube_only == 1 or 5 in candy:
  263. fire_candy()
  264. elif 5 in water:
  265. fire_water()
  266. time.sleep(cfg.TUBE_DELAY)
  267. elif GPIO.input(cfg.doors.get('door6')) == True:
  268. if water_spray_only == 1:
  269. water_count = 0
  270. fire_water()
  271. elif candy_tube_only == 1 or 6 in candy:
  272. fire_candy()
  273. elif 6 in water:
  274. fire_water()
  275. time.sleep(cfg.TUBE_DELAY)
  276. elif GPIO.input(cfg.doors.get('door7')) == True:
  277. if water_spray_only == 1:
  278. water_count = 0
  279. fire_water()
  280. elif candy_tube_only == 1 or 7 in candy:
  281. fire_candy()
  282. elif 7 in water:
  283. fire_water()
  284. time.sleep(cfg.TUBE_DELAY)
  285. elif GPIO.input(cfg.buttons.get('reset')) == False:
  286. reset_counters()
  287. water, candy = randomize_tubes()
  288. return
  289. def action_server():
  290. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  291. s.bind((cfg.ACTION_IP, cfg.ACTION_PORT))
  292. print ("Listening on port {h} {p}...".format(h=cfg.ACTION_IP, p=cfg.ACTION_PORT))
  293. s.listen(5)
  294. while True:
  295. try:
  296. client, addr = s.accept()
  297. ready = select.select([client, ], [], [], 1)
  298. if ready[0]:
  299. data = client.recv(500)
  300. action_server_process(data)
  301. if not data:
  302. sys.stdout.write('.')
  303. sys.stdout.flush()
  304. except KeyboardInterrupt:
  305. print ()
  306. print ("Stop.")
  307. break
  308. except socket.error, msg:
  309. print ("Socket error! %s" % msg)
  310. break
  311. client.close()
  312. print ("end of action server")
  313. return
  314. def action_server_process(value):
  315. if value in cfg.tubes:
  316. fire_tube(value)
  317. elif value in cfg.sprayers:
  318. spray_water(value)
  319. return
  320. if __name__ == "__main__":
  321. global num_tubes
  322. num_tubes = len(cfg.tubes)
  323. global num_doors
  324. num_doors = len(cfg.doors)
  325. global num_sprayers
  326. num_sprayers = len(cfg.sprayers)
  327. global num_buttons
  328. num_buttons = len(cfg.buttons)
  329. global water_spray_only
  330. water_spray_only = 0
  331. global candy_tube_only
  332. candy_tube_only = 0
  333. global water_count
  334. water_count = 0
  335. global candy_count
  336. candy_count = 0
  337. global water_tube
  338. water_tube = 1
  339. global candy_tube
  340. candy_tube = 1
  341. global run_mode
  342. run_mode = "local"
  343. try:
  344. parser = optparse.OptionParser()
  345. parser.add_option('-l', '--local', action="store_const", const="local", dest="run_mode", default="local", help="Run in Local Mode")
  346. parser.add_option('-s', '--sensor', action="store_const", const="sensor", dest="run_mode", help="Run in Sensor Mode")
  347. parser.add_option('-a', '--action', action="store_const", const="action", dest="run_mode", help="Run in Action Mode")
  348. (options, args) = parser.parse_args()
  349. if options.run_mode:
  350. run_mode = options.run_mode
  351. print ("Startup Routine")
  352. startup()
  353. if run_mode == "local" or not run_mode:
  354. print ("Running in mode: " + options.run_mode)
  355. water, candy = randomize_tubes()
  356. sensomatic()
  357. elif run_mode == "sensor":
  358. print ("Running in mode: " + options.run_mode)
  359. water, candy = randomize_tubes()
  360. sensomatic()
  361. elif run_mode == "action":
  362. print ("Running in mode: " + options.run_mode)
  363. action_server()
  364. else:
  365. print ("Whoops, something went wrong!")
  366. except Exception, err:
  367. print ("Exception:", str(err))
  368. import traceback, sys
  369. print ('-'*60)
  370. traceback.print_exc(file=sys.stdout)
  371. print ('-'*60)
  372. # End