import subprocess import sys, inspect, os import wiringpi import time from datetime import datetime from time import sleep import lirc import random import mpd from pyudmx import pyudmx import talkey # HTTP Server from twisted.web import server, resource from twisted.internet import reactor class Simple(resource.Resource): isLeaf = True def render_GET(self, request): statustext = "" if inUse: statustext = "Disco in use!" else: statustext = "Ready to Disco!" html = '
%s
' % statustext return html.encode('utf-8') # GPIO pin_kugel = 2 pin_sun = 4 pin_pir = 0 pin_door = 11 # for system stuff dmxScenes = { "fadecolors":[255,255,255,255,255,192], "plain-red":[255,255,0,0,0,0], "strobe":[190,255,255,255,0,0], "nini":[120,0,255,255,0,224], "black":[0,0,0,0,0,0] } bye_sayings = [ "Goodbye!", "Bye!", "Bye bye!", "See you!", #"Ciao!", "Have a nice day!", "Thank's for using!", #"I'm off!", "Take it easy!", "I look forward to our next meeting!", "Take care!", "See you later!", "This was nice. See you!", "Peace!" ] dmxUserScenes = [ [255,255,255,255,255,192], [255,0,180,180,0,0], [255,255,0,0,0,0], [255,0,255,0,0,0], [255,0,0,255,0,0], [190,255,255,255,0,0], [120,0,255,255,0,224] ] # no strobe etc. dmxStartupScenes = [ [255,255,255,255,255,192], [255,0,180,180,0,0], [255,255,0,0,0,0], [255,0,255,0,0,0], [255,0,0,255,0,0], [120,0,255,255,0,224] ] # Set a dmx scene by name def setDmxScene(scene): # a universe of zeros cv = [0 for v in range(0, 512)] errorcode = [240,255,0,0,0,0] for index, val in enumerate(dmxScenes.get(scene,errorcode)): cv[index] = val dev.send_multi_value(1, cv) # Set random startup dmx scene def setStartupDmxScene(): # a universe of zeros cv = [0 for v in range(0, 512)] errorcode = [240,255,0,0,0,0] # get a random scene index scene = random.choice(list(enumerate(dmxStartupScenes)))[0] print(scene) for index, val in enumerate(dmxStartupScenes[scene]): cv[index] = val dev.send_multi_value(1, cv) # Switch betweeb user dmx scenes def setUserDmxScene(): # loop through scenes global dmxScene if dmxScene < len(dmxUserScenes)-1: dmxScene += 1 else: dmxScene = 0 # setup the universe cv = [0 for v in range(0, 512)] for index, val in enumerate(dmxUserScenes[dmxScene]): cv[index] = val dev.send_multi_value(1, cv) def setKugel(state): if state == 'on': wiringpi.digitalWrite(pin_kugel, 0) if state == 'off': wiringpi.digitalWrite(pin_kugel, 1) def setSun(state): if state == 'off': wiringpi.digitalWrite(pin_sun, 0) if state == 'on': wiringpi.digitalWrite(pin_sun, 1) def startMusic(playlist, single=False, shuffle=True, repeat=True): try: client.clear() # clear playlist except Exception: client.connect("localhost", 6600) client.clear() # clear playlist client.add(playlist) # add file/directory to playlist if shuffle: client.shuffle() # shuffle playlist if repeat: client.repeat(1) # set playback mode repeat else: client.repeat(0) # set playback mode repeat if single: client.repeat(0) # set playback mode repeat client.single(1) # set playback mode single else: client.single(0) # set playback mode single client.setvol(80)# set volume client.play() # play def playMusic(): try: client.play() except Exception: client.connect("localhost", 6600) client.play() def pauseMusic(): try: client.pause() except Exception: client.connect("localhost", 6600) client.pause() def stopMusic(): try: client.stop() except Exception: client.connect("localhost", 6600) client.stop() def nextSong(): try: client.next() except Exception: client.connect("localhost", 6600) client.next() def previousSong(): try: client.previous() except Exception: client.connect("localhost", 6600) client.previous() def muteMusic(): global uservolume if getMpdVolume() != 0: # if not muted setMpdVolume(0) else: setMpdVolume(uservolume) def changeVolume(change=5): global uservolume global volume newvol = uservolume + change if newvol > 100: newvol = 100 if newvol < 0: newvol = 0 try: client.setvol(newvol) except Exception: client.connect("localhost", 6600) client.setvol(newvol) uservolume = newvol volume = newvol def setMode(string): global mode global inUse mode = string if mode == "off": inUse = False def setDiscoMode(startup=False): setKugel('on') if startup: setStartupDmxScene() else: setUserDmxScene() sleep(0.3) setSun('off') setMode('disco') def getMpdVolume(): try: vol = int(client.status()['volume']) except Exception: client.connect("localhost", 6600) vol = int(client.status()['volume']) if vol != 0: #only if not muted global uservolume uservolume = vol return vol def setMpdVolume(vol): try: client.setvol(vol) except Exception: client.connect("localhost", 6600) client.setvol(vol) if vol != 0: #only if not muted global uservolume uservolume = vol return True def seek(secs): try: client.seekcur(secs) except Exception: client.connect("localhost", 6600) client.seekcur(secs) return True def getTrackInfo(): try: currentsong = client.currentsong() except Exception: client.connect("localhost", 6600) currentsong = client.currentsong() print(currentsong) volume = getMpdVolume() setMpdVolume(10) try: tts.say(currentsong['artist'] + ', ' + currentsong['title']) except Exception: tts.say('Willkommen am Discoklo!', 'de') setMpdVolume(volume) def tour(): tts.say("Hello, I'm Discobert!", "en") sleep(0.3) tts.say("Press 1 for nice electronic music", "en") sleep(0.3) tts.say("Press 2 for hard electronic music", "en") sleep(0.3) tts.say("Press 3 for HGichT", "en") sleep(0.3) tts.say("Press 4 for a good laugh", "en") sleep(0.3) tts.say("Press 5 for more music", "en") sleep(0.3) def setWorkingMode(): setSun('on') sleep(0.3) setKugel('off') setDmxScene('black') setMode('work') def startTimeoutCountdown(): global lastUsed global inUse tts.say('Timeout in') countdown = [5,4,3,2,1] #10,9,8,7,6, for sec in countdown: tts.say(str(sec)) sleep(0.5) remotesignal = lirc.nextcode() if wiringpi.digitalRead(pin_pir) == 1 or remotesignal: lastUsed = time.time() tts.say('Timeout cancelled!') inUse = True toilet = lirc.nextcode() break if not inUse: tts.say('Shutting down now.', 'en') closeService() def closeService(sleepsecs=0): setSun('off') sleep(0.3) setKugel('off') setDmxScene('black') for x in range(0, 20): changeVolume(-5) sleep(0.1) stopMusic() inUseBefore = False # Pfusch pfusch! setMode('off') sleep(sleepsecs) def initService(): startMusic('0', True) # start intro music setDiscoMode(True) global volume global defaultvolume global uservolume try: client.setvol(defaultvolume) except Exception: client.connect("localhost", 6600) client.setvol(defaultvolume) volume = defaultvolume uservolume = defaultvolume global starttime starttime = time.time() def say(text, lang="en"): originalvol = getMpdVolume() setMpdVolume(10) tts.say(text, lang) setMpdVolume(originalvol) def setOnOff(): global mode stopMusic() if mode is not 'work': setWorkingMode() else: initService() def doorShutdown(): tts.say(random.choice(bye_sayings), "en") # sleep to give user some time to close the door # (pir sensor also stays up for 2 sec) closeService(5) def bootstrap(): wiringpi.wiringPiSetup() wiringpi.pinMode(pin_kugel, 1) # set Relay Disokugel mode to OUTPUT wiringpi.pinMode(pin_door, 0) # set Circuit Door mode to INPUT wiringpi.pinMode(pin_sun, 1) # set Relay Sun mode to OUTPUT # TODO: Set pin! wiringpi.pinMode(pin_pir, 0) # set PIR Sensor mode to INPUT def timestamp(stamp=time.time()): return datetime.fromtimestamp(stamp).strftime('%Y-%m-%d %H:%M:%S') dmxScene = 0 bootstrap() dev = pyudmx.uDMXDevice() dev.open() client = mpd.MPDClient() client.connect("localhost", 6600) tts = talkey.Talkey( preferred_languages=['en'], engine_preference=['pico'], ) site = server.Site(Simple()) reactor.listenTCP(8080, site) reactor.startRunning(False) lirc.init("disco", "~/discobert/lircrc", blocking=False) starttime = time.time() # helper for doorshutdown lastUsed = time.time() # helper for timeout inUse = False # is toilet in use? inUseBefore = False # helper to check statechanges mode = "off" # can be: disco, work, off timeout = 2 * 60 - 10 # timeout since last user interaction defaultvolume = 90 # Volume when user enters the toilet volume = 90 # Global for actual volume uservolume = 90 # Global for user volume (ignores mute state) setSun('off') print(timestamp(), "Ready!") # Main event loop ... while True: sleep(0.25) pirstate = wiringpi.digitalRead(pin_pir) doorstate = wiringpi.digitalRead(pin_door) #print('pirstate: ', pirstate) #print('doorstate: ', doorstate) # 0 => door closed # 1 => door open if doorstate == 1: if (time.time() > (starttime + 15) and inUse == True): doorShutdown() if pirstate == 1: lastUsed = time.time() inUse = True else: if(time.time() > lastUsed + timeout): inUse = False remotesignal = lirc.nextcode() #print('remotesignal: ', remotesignal) if remotesignal: lastUsed = time.time() # user is active! inUse = True for code in remotesignal: print('received code:', code) if(code == "mode_disco"): setDiscoMode() if(code == "mode_work"): setWorkingMode() if(code == "mode_power"): setOnOff() if(code == "mode_music_play_1"): startMusic('1') if(code == "mode_music_play_2"): startMusic('2') if(code == "mode_music_play_3"): startMusic('3') if(code == "mode_music_play_4"): startMusic('4') if(code == "mode_music_play_5"): startMusic('5') if(code == "mode_play_fm4"): startMusic('http://185.85.29.141:8000') if(code == "mode_play_oe1"): startMusic('http://185.85.29.142:8000') if(code == "mode_music_previous"): previousSong() if(code == "mode_music_next"): nextSong() if(code == "mode_music_play"): playMusic() if(code == "mode_music_stop"): stopMusic() if(code == "mode_music_mute"): muteMusic() if(code == "mode_music_pause"): pauseMusic() if(code == "mode_music_rewind"): seek('-30') if(code == "mode_music_back"): seek('-5') if(code == "mode_music_forward"): seek('+5') if(code == "mode_music_fastforward"): seek('+30') if(code == "mode_volume_up"): changeVolume(5) if(code == "mode_volume_down"): changeVolume(-5) if(code == "mode_music_info"): getTrackInfo() if(code == "mode_record"): say("I'm sorry, I'm afraid I can't do that!") if(code == "mode_help"): tour() if(inUseBefore != inUse): print(timestamp(), "State change inUse:", inUseBefore, inUse) if inUse: initService() else: startTimeoutCountdown() inUseBefore = inUse # Webserver reactor.iterate() lirc.deinit() # Clean up lirc dev.close()