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

View file

@ -4,23 +4,35 @@
---
logging:
__default__: info (color)
theremin: debug (color)
# theremin: debug (color)
# gpio: debug (color)
# See: https://pinout.xyz/
#
theremin:
# See: https://pinout.xyz/ - GPIO labels, not physical
pitch_trigger: 27
pitch_echo: 22
gain_trigger: 23
gain_echo: 24
# Fine tune range sensors
distance_max: 2
# sample_interval: 0.5
# slew: 5
# Speech
startup_message: Hello. I'm Maude the bod.
use_motion: true
motion_messages:
- Lets make beautiful music together.
- Oh yeah!
- Yes yes yes yes yessss yyyyyyyyyyyyyyyyyyyyyyyy yes!
- oooooooooooooooooooooookay!
- Let's rock.
# Alter synth sounds from defaults.
cancel_after: 3
startup_message: Hello. I'm Maude the bod. Lets make beautiful music together.
# font: /usr/share/sounds/sf2/FluidR3_GM.sf2
# glide: 1
# slew: 5
# sample_interval: 0.5
# reverb: false
# chorus: false
# font_index: 2

0
theremin/lib/gpio.rb Executable file → Normal file
View file

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

View file

5
theremin/log/run Executable file
View file

@ -0,0 +1,5 @@
#!/bin/sh
exec 2>&1
exec svlogd ./main

View file

@ -15,5 +15,7 @@ Signal.trap( "INT" ) do
theremin.stop if theremin.running
end
$stderr.sync = true
$stdout.sync = true
theremin.start