Add random phrases when an optional pi camera detects motion.

Fix LED paths for more recent pi-image operating systems.

FossilOrigin-Name: 95bda0bf25a4c8760c07217545106e4a5116a2a6e01463d5189551eb83bfa0f7
This commit is contained in:
Mahlon E. Smith 2023-05-24 03:08:39 +00:00
parent 65ac4ce493
commit 74bfdfac57
9 changed files with 135 additions and 19 deletions

47
theremin/lib/theremin.rb Executable file → Normal file
View file

@ -8,6 +8,7 @@ require 'loggability'
require 'gpio'
require 'fluidsynth'
require 'open3'
require 'socket'
# A class that coordinates GPIO events and translates
@ -130,6 +131,12 @@ class Theremin
## ESpeak TTL options.
setting :espeak_flags, default: %w[ -k20 -v f5 -s 160 -a 150 ]
## Watch for camera motion?
setting :use_motion, default: false
## A list of phrases to randomly say when motion is detected.
setting :motion_messages, default: []
end
@ -163,6 +170,9 @@ class Theremin
# An IO to stream to espeak.
attr_reader :speech_io
# A TCPServer for motion IPC
attr_reader :motion_socket
# Is this Theremin currently running?
attr_reader :running
@ -181,10 +191,11 @@ class Theremin
self.chorus( self.class.chorus )
self.instrument( self.class.font_index, self.class.instrument_index )
self.speak( self.class.startup_message ) if self.class.startup_message
@threads << self.note_thread
@threads << self.gain_thread
@threads << self.motion_thread if self.class.use_motion
self.led( :green )
self.speak( self.class.startup_message ) if self.class.startup_message
self.log.warn "Waiting for interaction, or ctrl-c to exit."
@threads.map( &:join )
end
@ -196,14 +207,15 @@ class Theremin
@running = false
self.pins.each {|pin| self.class.send( pin ).unexport rescue nil }
self.synth.socket.close
self.motion_socket.close
self.speech_io.close if self.speech_io && !self.speech_io.closed?
self.led( :red )
end
#########
protected
#########
#########
protected
#########
### Measure pitch distance, and manage notes sent to the synth.
###
@ -271,6 +283,23 @@ class Theremin
end
### Watch the motion fifo, say a random phrase when motion seen.
###
def motion_thread
phrases = self.class.motion_messages
return if phrases.empty?
@motion_socket = TCPServer.new( 62877 )
return self.running_thread do
client = @motion_socket.accept
self.log.info "Camera motion detected."
client.close
self.speak( phrases.sample )
rescue IOError
end
end
### Open a pipe to espeak, and wait on input.
##
def setup_speech
@ -375,11 +404,11 @@ class Theremin
def led( color )
case color
when :red
File.open( '/sys/class/leds/led0/brightness', 'w' ){|l| l.puts(0) }
File.open( '/sys/class/leds/led1/brightness', 'w' ){|l| l.puts(1) }
File.open( '/sys/class/leds/PWR/brightness', 'w' ){|l| l.puts(1) }
File.open( '/sys/class/leds/ACT/brightness', 'w' ){|l| l.puts(0) }
when :green
File.open( '/sys/class/leds/led0/brightness', 'w' ){|l| l.puts(1) }
File.open( '/sys/class/leds/led1/brightness', 'w' ){|l| l.puts(0) }
File.open( '/sys/class/leds/PWR/brightness', 'w' ){|l| l.puts(0) }
File.open( '/sys/class/leds/ACT/brightness', 'w' ){|l| l.puts(1) }
end
end