You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

426 regels
9.9 KiB

  1. import subprocess
  2. import sys, inspect, os
  3. import wiringpi
  4. import time
  5. from datetime import datetime
  6. from time import sleep
  7. import lirc
  8. import random
  9. import mpd
  10. from pyudmx import pyudmx
  11. import talkey
  12. # GPIO
  13. pin_kugel = 2
  14. pin_sun = 4
  15. pin_pir = 0
  16. pin_door = 11
  17. dmxScenes = {
  18. "fadecolors":[255,255,255,255,255,192],
  19. "plain-red":[255,255,0,0,0,0],
  20. "strobe":[190,255,255,255,0,0],
  21. "nini":[120,0,255,255,0,224],
  22. "black":[0,0,0,0,0,0]
  23. }
  24. bye_sayings = [
  25. "Goodbye!",
  26. "Bye!",
  27. "Bye bye!",
  28. "See you!",
  29. #"Ciao!",
  30. "Have a nice day!",
  31. "Thank's for using!",
  32. #"I'm off!",
  33. "Take it easy!",
  34. "I look forward to our next meeting!",
  35. "Take care!",
  36. "Catch you later!",
  37. "Peace!"
  38. ]
  39. dmxUserScenes = [
  40. [255,255,255,255,255,192],
  41. [255,0,180,180,0,0],
  42. [255,255,0,0,0,0],
  43. [255,0,255,0,0,0],
  44. [255,0,0,255,0,0],
  45. [190,255,255,255,0,0],
  46. [120,0,255,255,0,224]
  47. ]
  48. def setDmxScene(scene):
  49. cv = [0 for v in range(0, 512)]
  50. errorcode = [240,255,0,0,0,0]
  51. for index, val in enumerate(dmxScenes.get(scene,errorcode)):
  52. cv[index] = val
  53. dev.send_multi_value(1, cv)
  54. def setUserDmxScene():
  55. global dmxScene
  56. if dmxScene < len(dmxUserScenes)-1:
  57. dmxScene += 1
  58. else:
  59. dmxScene = 0
  60. cv = [0 for v in range(0, 512)]
  61. for index, val in enumerate(dmxUserScenes[dmxScene]):
  62. cv[index] = val
  63. dev.send_multi_value(1, cv)
  64. def setKugel(state):
  65. if state == 'on':
  66. wiringpi.digitalWrite(pin_kugel, 0)
  67. if state == 'off':
  68. wiringpi.digitalWrite(pin_kugel, 1)
  69. def setSun(state):
  70. if state == 'off':
  71. wiringpi.digitalWrite(pin_sun, 0)
  72. if state == 'on':
  73. wiringpi.digitalWrite(pin_sun, 1)
  74. def startMusic(playlist, single=False, shuffle=True, repeat=True):
  75. try:
  76. client.clear() # clear playlist
  77. except Exception:
  78. client.connect("localhost", 6600)
  79. client.clear() # clear playlist
  80. client.add(playlist) # add file/directory to playlist
  81. if shuffle:
  82. client.shuffle() # shuffle playlist
  83. if repeat:
  84. client.repeat(1) # set playback mode repeat
  85. else:
  86. client.repeat(0) # set playback mode repeat
  87. if single:
  88. client.repeat(0) # set playback mode repeat
  89. client.single(1) # set playback mode single
  90. else:
  91. client.single(0) # set playback mode single
  92. client.setvol(80)# set volume
  93. client.play() # play
  94. def stopMusic():
  95. try:
  96. client.stop()
  97. except Exception:
  98. client.connect("localhost", 6600)
  99. client.stop()
  100. def muteMusic():
  101. global uservolume
  102. if getMpdVolume() != 0: # if not muted
  103. setMpdVolume(0)
  104. else:
  105. setMpdVolume(uservolume)
  106. def changeVolume(change=5):
  107. global uservolume
  108. global volume
  109. newvol = uservolume + change
  110. if newvol > 100:
  111. newvol = 100
  112. if newvol < 0:
  113. newvol = 0
  114. try:
  115. client.setvol(newvol)
  116. except Exception:
  117. client.connect("localhost", 6600)
  118. client.setvol(newvol)
  119. uservolume = newvol
  120. volume = newvol
  121. def setMode(string):
  122. global mode
  123. global inUse
  124. mode = string
  125. if mode == "off":
  126. inUse = False
  127. def setDiscoMode():
  128. setKugel('on')
  129. setDmxScene('fadecolors')
  130. setUserDmxScene()
  131. sleep(0.3)
  132. setSun('off')
  133. setMode('disco')
  134. def getMpdVolume():
  135. try:
  136. vol = int(client.status()['volume'])
  137. except Exception:
  138. client.connect("localhost", 6600)
  139. vol = int(client.status()['volume'])
  140. if vol != 0: #only if not muted
  141. global uservolume
  142. uservolume = vol
  143. return vol
  144. def setMpdVolume(vol):
  145. try:
  146. client.setvol(vol)
  147. except Exception:
  148. client.connect("localhost", 6600)
  149. client.setvol(vol)
  150. if vol != 0: #only if not muted
  151. global uservolume
  152. uservolume = vol
  153. return True
  154. def getTrackInfo():
  155. try:
  156. currentsong = client.currentsong()
  157. except Exception:
  158. client.connect("localhost", 6600)
  159. currentsong = client.currentsong()
  160. print(currentsong)
  161. volume = getMpdVolume()
  162. setMpdVolume(10)
  163. try:
  164. tts.say(currentsong['artist'] + ', ' + currentsong['title'])
  165. except Exception:
  166. tts.say('Willkommen am Discoklo!', 'de')
  167. setMpdVolume(volume)
  168. def tour():
  169. tts.say("Welcome! To the world of tomorrow!", "en")
  170. sleep(0.3)
  171. tts.say("Press 1 for nice electronic music", "en")
  172. sleep(0.3)
  173. tts.say("Press 2 for hard electronic music", "en")
  174. sleep(0.3)
  175. tts.say("Press 3 for HGichT", "en")
  176. sleep(0.3)
  177. tts.say("Press 4 for a good laugh", "en")
  178. sleep(0.3)
  179. tts.say("Press 5 for more music", "en")
  180. sleep(0.3)
  181. def setWorkingMode():
  182. setSun('on')
  183. sleep(0.3)
  184. setKugel('off')
  185. setDmxScene('black')
  186. setMode('work')
  187. def startTimeoutCountdown():
  188. global lastUsed
  189. global inUse
  190. tts.say('Timeout in')
  191. countdown = [5,4,3,2,1] #10,9,8,7,6,
  192. for sec in countdown:
  193. tts.say(str(sec))
  194. sleep(0.5)
  195. remotesignal = lirc.nextcode()
  196. if wiringpi.digitalRead(pin_pir) == 1 or remotesignal:
  197. lastUsed = time.time()
  198. tts.say('Timeout cancelled!')
  199. inUse = True
  200. toilet = lirc.nextcode()
  201. break
  202. if not inUse:
  203. tts.say('Shutting down now.', 'en')
  204. closeService()
  205. def closeService(sleepsecs=0):
  206. setSun('off')
  207. sleep(0.3)
  208. setKugel('off')
  209. setDmxScene('black')
  210. for x in range(0, 20):
  211. changeVolume(-5)
  212. sleep(0.1)
  213. stopMusic()
  214. setMode('off')
  215. sleep(sleepsecs)
  216. def initService():
  217. startMusic('0', True) # start intro music
  218. setDiscoMode()
  219. global volume
  220. global defaultvolume
  221. global uservolume
  222. try:
  223. client.setvol(defaultvolume)
  224. except Exception:
  225. client.connect("localhost", 6600)
  226. client.setvol(defaultvolume)
  227. volume = defaultvolume
  228. uservolume = defaultvolume
  229. global starttime
  230. starttime = time.time()
  231. def say(text, lang="en"):
  232. originalvol = getMpdVolume()
  233. setMpdVolume(10)
  234. tts.say(text, lang)
  235. setMpdVolume(originalvol)
  236. def setOnOff():
  237. global mode
  238. stopMusic()
  239. if mode is not 'work':
  240. setWorkingMode()
  241. else:
  242. initService()
  243. def doorShutdown():
  244. tts.say(random.choice(bye_sayings), "en")
  245. # sleep to give user some time to close the door
  246. # (pir sensor also stays up for 2 sec)
  247. closeService(5)
  248. def bootstrap():
  249. wiringpi.wiringPiSetup()
  250. wiringpi.pinMode(pin_kugel, 1) # set Relay Disokugel mode to OUTPUT
  251. wiringpi.pinMode(pin_door, 0) # set Circuit Door mode to INPUT
  252. wiringpi.pinMode(pin_sun, 1) # set Relay Sun mode to OUTPUT # TODO: Set pin!
  253. wiringpi.pinMode(pin_pir, 0) # set PIR Sensor mode to INPUT
  254. def timestamp(stamp=time.time()):
  255. return datetime.fromtimestamp(stamp).strftime('%Y-%m-%d %H:%M:%S')
  256. dmxScene = 0
  257. bootstrap()
  258. dev = pyudmx.uDMXDevice()
  259. dev.open()
  260. client = mpd.MPDClient()
  261. client.connect("localhost", 6600)
  262. tts = talkey.Talkey(
  263. preferred_languages=['en'],
  264. engine_preference=['pico'],
  265. )
  266. lirc.init("disco", "~/discobert/lircrc", blocking=False)
  267. starttime = time.time() # helper for doorshutdown
  268. lastUsed = time.time() # helper for timeout
  269. inUse = False # is toilet in use?
  270. inUseBefore = False # helper to check statechanges
  271. mode = "off" # can be: disco, work, off
  272. timeout = 2 * 60 - 10 # timeout since last user interaction
  273. defaultvolume = 90 # Volume when user enters the toilet
  274. volume = 90 # Global for actual volume
  275. uservolume = 90 # Global for user volume (ignores mute state)
  276. setSun('off')
  277. print(timestamp(), "Ready!")
  278. # Main event loop ...
  279. while True:
  280. sleep(0.25)
  281. pirstate = wiringpi.digitalRead(pin_pir)
  282. doorstate = wiringpi.digitalRead(pin_door)
  283. #print('pirstate: ', pirstate)
  284. # 0 => door closed
  285. # 1 => door open
  286. if doorstate == 1:
  287. if (time.time() > (starttime + 15) and inUse == True):
  288. doorShutdown()
  289. inUseBefore = False # Pfusch pfusch!
  290. if pirstate == 1:
  291. lastUsed = time.time()
  292. inUse = True
  293. else:
  294. if(time.time() > lastUsed + timeout):
  295. inUse = False
  296. remotesignal = lirc.nextcode()
  297. if remotesignal:
  298. lastUsed = time.time() # user is active!
  299. inUse = True
  300. for code in remotesignal:
  301. print('received code:', code)
  302. if(code == "mode_disco"):
  303. setDiscoMode()
  304. if(code == "mode_work"):
  305. setWorkingMode()
  306. if(code == "mode_power"):
  307. setOnOff()
  308. #if(code == "mode_dmx_next"):
  309. if(code == "mode_music_play_1"):
  310. startMusic('1')
  311. if(code == "mode_music_play_2"):
  312. startMusic('2')
  313. if(code == "mode_music_play_3"):
  314. startMusic('3')
  315. if(code == "mode_music_play_4"):
  316. startMusic('4')
  317. if(code == "mode_music_play_5"):
  318. startMusic('5')
  319. if(code == "mode_play_fm4"):
  320. startMusic('http://185.85.29.141:8000')
  321. if(code == "mode_play_oe1"):
  322. startMusic('http://185.85.29.142:8000')
  323. if(code == "mode_music_stop"):
  324. stopMusic()
  325. if(code == "mode_music_mute"):
  326. muteMusic()
  327. if(code == "mode_volume_up"):
  328. changeVolume(5)
  329. if(code == "mode_volume_down"):
  330. changeVolume(-5)
  331. if(code == "mode_music_info"):
  332. getTrackInfo()
  333. if(code == "mode_record"):
  334. say("I'm sorry, I'm afraid I can't do that!")
  335. if(code == "mode_home"):
  336. tour()
  337. if(inUseBefore != inUse):
  338. print(timestamp(), "State change inUse:", inUseBefore, inUse)
  339. if inUse:
  340. initService()
  341. else:
  342. startTimeoutCountdown()
  343. inUseBefore = inUse
  344. lirc.deinit() # Clean up lirc
  345. dev.close()