Plays an audio file on loop until a timer runs out and that's all it does. Package includes 3dprint for the case and code to run everything on a Raspberry Pi Zero W. Controls are via a single large dial/button or via web app. This could (should?) have been done on an Arduino, but Fred can't tell the difference. Shhhhh.
Directions below may have gaps. If so, oops! Good luck.
Lullablock is built on top of a Raspberry Pi Zero WH.
- Raspberry Pi Zero WH (Zero W with Headers)
- Adafruit I2S 3W Stereo Speaker Bonnet for Raspberry Pi - Mini Kit
- Stereo Enclosed Speaker Set - 3W 4 Ohm
- ky040 Rotary Encoder, from Cylewet
- Power supply
- Terminal blocks and/or wire as needed
- Case using supplied 3D print files or your own design
- Handful of nylon M2.5 screws and hex nuts
- Handful of nylon 6-32 thumbscrews and hex nuts
Start by assembling the Speaker Bonnet and attaching it to your RPI Zero. you will also need to build a case, or use the 3d printing files provided in this package to print one.
Then you're ready to:
- Base: screw the RPI to the base using M2.5 screws and nuts.
- Body: attach rotary encoder to the top of the body using the nut and washer that it comes with. Attach speakers to the sides using M2.5 screws and nuts.
- Attach all wires between the rotary encoder and the RPI, as well as between the speakers and the speaker bonnet. I used jumpers and soldered terminals but you can also solder wires directly. The Speaker Bonnet includes a prototyping area, so you will be connecting to that with the following:
- ROTARY ENCODER CLK -> GPIO Pin 12
- ROTARY ENCODER DT -> GPIO Pin 13
- ROTARY ENCODER SW -> GPIO Pin 16
- ROTARY ENCODER Plus Sign -> 5V
- ROTARY ENCODER GND -> Ground
- Connect power cable to RPI.
- Glue 6-32 nylon hex nuts into the receptacles on the bottom of the Body.
- Assemble body and base! Use 6-32 Nylon Thumb Screws, 1/4" Long, to secure it closed.
- Infill: rotary knobs have slight variarions, so depending on which one you use you may need to devise your own infill piece that connects the 3d printed dial cover (knob) to the metal stem of the rotary encoder. The infill piece fits over the metal stem, which then slots into the hole on the bottom of the dial. Friction should hold everything in place but you can glue it as well if you like.
- Raspbian Buster Lite
- Python 3.7
- I2S DAC per Adafruit
- Pygame provides audio control
- Flask provides the web app framework
- NGINX provides the webserver
- Gunicorn3
Add the following to /boot/config.txt
based on these instructions:
# enable rotary encoder
dtoverlay=rotary-encoder,pin_a=12,pin_b=13,relative_axis=1
dtoverlay=gpio-key,gpio=16,keycode=28,label="ENTER"
dtoverlay=hifiberry-dac
dtoverlay=i2s-mmap
Copy rotarylistener.service.example
to /etc/systemd/system/rotarylistener.service
. From there you can:
- Start with
sudo systemctl start rotarylistener.service
- Stop with
sudo systemctl stop rotarylistener.service
- Check with
systemctl status rotarylistener.service
- Tail logs for the service by using:
journalctl -f -u rotarylistener.service
Enable NGINX by copying lullablock.service.example
to /etc/nginx/sites-available/
and then symlink that file to /etc/nginx/sites-available/lullablock
with sudo ln -s /etc/nginx/sites-available/lullablock /etc/nginx/sites-enabled/lullablock
- Test config file with
sudo nginx -t
- Restart the server
sudo systemctl restart nginx
Set up the worker by copying lullablock.service.example
to /etc/systemd/system/lullablock.service
- Start with
sudo systemctl start lullablock
Fair warning: no effort has been made to secure this device, so make sure your RPI has a good password. Lullablock does not need to connect to the outside world for anything, so you can also wall it off from the open internet without impeding functionality.
Lullablock plays an audio file on loop until a timer runs out. Physical and digital interfaces are provided to change the timer duration and volume. Setting a new audio track will require connecting via the app/web interface.
Lullablock has a set of timer durations, by default 90, 45, 15, and 0 minutes (these can be changed in settings.py
). Pressing the big dial will advance through these timers. For instance, if Lullablock is off, pressing the dial will turn on the sound and begin counting down to 90 minutes. At the end of the timer it will shut off. Tap a second time and the timer will be reduced to 45 minutes, again and it will be 15 miniutes, one more time and Lullablock will tiurn off.
Turning the dial will decrease or increase the volume based on the direction of rotation. Technically, this happens by sending API calls for each increment of rotation so you will find that there's a small delay between spinning the dial and hearing the change. This is a bad way to implement the dial controls but... I couldn't figure out a better way to do it and maintain state. Ooops.
Find your device on the network and load that in a browser, such as the one on your phone. For instance, my Lullablock uses the hostname lullablock.local and can be found at http://lullablock.local. Once the page loads you will have the ability to turn volume up and down by tapping the - and + icons. The |‾|_|‾|_|‾|_| graphic is a representation of the countdown to silence. Click it to start the timer.
To change the audio that plays on loop, upload new audio files to static/audio
. The files must be WAV or MP3 format. In the app you can change the track by clicking on the trackname in the upper left corner of the screen and then clicking on the track you would like to play. For instance, you might edit together your own loop of cafe chatter from the BBC or crickets or something. 🦗