Phonos: a voice input device. part II: code
Aside from utilizing some pre-existing software, it was necessary to write a few bits of software, as well as adding an update to existing software in order to get things to work the way I wanted.
Speech Recognition with Blather
For speech recognition, Phonos is running Blather. With the Phonos project, I wanted Blather to quit after recognizing a spoken command. In hindsight, this feature wasn't really needed, but it wasn't too difficult to hack the Blather source and add a command-line flag to accomplish the desired action.
-x, --execute-once execute one command and then quit became a um… 'feature'
As part of the Blather config, it is possible for a user to set a script to run when spoken words are matched or not matched to the user defined "spoken word" commands. In my first speech recognition device, a valid match would run a basic shell script to lauch a gstreamer utility to play an "affirmative" sound. An invalid match would result in a "negative" sound file being played.
For Phonos, I wanted to expand upon the options for playing affirmative and negative audio files. To accomplish this, two directories were created: "affirmative" and "negative", and when needed, a random audio file will be played from the appropriate directory.
Python code to play a random file from a directory with a gstreamer utility
#!/usr/bin/env python import sys import os import random #assume the first arg is the path to a directory of audio files dir = sys.argv.replace(" ","\ ") print dir #get a list of the files in the directory files = os.listdir(dir) #pick a file at random random_file = random.choice(files) #join the directory and the file audio_to_play = os.path.join( dir, random_file ) #get the absolute path of the dir/random_file abs_file = os.path.abspath(audio_to_play) print abs_file #an audio command to play the file (gstreamer tools required) cmd = "gst-launch-0.10 playbin uri=file://%s" % (abs_file) #run the command os.system(cmd)
Watching the Phone Cradle
During the build, the phone cradle was connected to GPIO on the CHIP, and determining the state of the cradle was a matter of:
- setting up a GPIO pin as input
- read the GPIO's value file
- do stuff when the value changes
In this case, that stuff is "launch blather with the -x flag when the cradle is lifted"
and "kill all blather instances when the cradle goes down"
#!/usr/bin/env python import subprocess import time import os #what number gpio? num = "1019" #what is the cradle "down" value? DOWN = "0" #control looping looping = True #first cradle lift cradle_down = True #get the pin value def get_pin_value(): f = open("/sys/class/gpio/gpio"+num+"/value") val = f.read().strip() f.close() return val #what is the path to the gpio? gpio_path = "/sys/class/gpio/gpio"+num #is the pin in use? if os.path.exists(gpio_path): #unexport the pin by writing the pin number to /sys/class/gpio/export f = open("/sys/class/gpio/unexport",'w') f.write(num) f.close() #export the pin by writing the pin number to /sys/class/gpio/export f = open("/sys/class/gpio/export",'w') f.write(num) f.close() #get the initial value of the pin pin_previous_value = get_pin_value() pin_initial_value = pin_previous_value #set the direction f = open("/sys/class/gpio/gpio"+num+"/direction", "w") f.write("in") f.close() looping = True #loop and check the pin while looping: time.sleep(0.1) new_value = get_pin_value() if pin_previous_value != new_value: #the value has changed, update the previous value pin_previous_value = new_value #is the change an up or a down? print "new == DOWN", new_value,DOWN if new_value == DOWN: cradle_down = True print 'cradle down' #kill all instances of blather print "pkill -f blather" subprocess.Popen('pkill -f blather', shell=True) else: print 'cradle up' #cradle is up! if cradle_down: cradle_down = False #run blather as user chip cmd = "su - chip -c '/home/chip/Projects/blather/Blather.py -x'" print cmd subprocess.Popen(cmd, shell=True)
systemd unit-fileNot as easy as adding a line to /etc/rc.local, and quite a bit easier than writing a script for /etc/init.d/ :)
[Unit] Description=watch the phone cradle switch for changes After=network.target [Service] ExecStart=/opt/cradle.py ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure [Install] WantedBy=multi-user.target
Certainly not least
The main purpose of Phonos is to convert voice commands to MQTT commands that will control the some lights in my home. To make this process easier, I needed a simple MQTT client to publish Topics and Messages to Cronos, my MQTT broker.
#!/usr/bin/env python import sys import paho.mqtt.client as mqtt host = 'cronos' #default to testing orb topic = 'light/orb1' message = "on" #get topic and message from argv if len(sys.argv) == 3 : topic = sys.argv message = sys.argv elif len(sys.argv) == 2 : topic = sys.argv message = '' #create an MQTT client, connect, and publish mclient = mqtt.Client() mclient.connect(host, 1883, 60) mclient.publish(topic, message)
Sweet! Now I can issue commands to:
turn all lights on
./cronos-mqtt lights on
fade a single light named 'orb' on
./cronos-mqtt light/orb fade/on
fade all the lights off over 60 seconds
./cronos-mqtt lights fade/off/60
And all of the other illumination functions available to Orb lights.