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 # Input: dico ball + DMX on/off
pin_sun = 4 # Input: light bulb on/off
pin_pir = 0 # Output: PIR sensor
pin_door = 11 # Output: door open/closed sensor
# 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)
# function when user arrives
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 = 5 * 60 - 5 # 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:
# don't do a doorShutdown when user comes in
# or when door stays open after user left
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()