# sonar Sonar is an alarm clock server designed to run on a Raspberry Pi, but it could just as well work anywhere. For the alarm clock it plays a list of media files from the filesystem. By default it will use the `mplayer` command. # Usage ``` ./sonar [-listen 127.0.0.1:8000] ``` Sonar has no authentication system. It listens on localhost by default and you should put a proxy like nginx in front with HTTP Basic Auth or whatever. It will create its config on first startup. # Features It listens on an HTTP service and shows a GUI on the homepage where you can toggle the volume settings, start/stop the alarm clock playlist, and see/change the scheduled alarm times. The clock is controlled over simple RESTful API. You just post to these endpoints: * `/volume/higher`: increase volume by 5% (default) * `/volume/lower`: lower volume by 5% * `/volume/mute`: toggle mute status * `/playlist/start`: start the playlist (doesn't stop automatically!) * `/playlist/stop`: stop the playlist Example to start the playlist via `curl`: ```bash $ curl -X POST http://localhost:8000/playlist/start ``` # Screenshots ![screenshot1.png](screenshot1.png)![screenshot2.png](screenshot2.png) # How It Works The config file specifies the shell commands to run to launch your media player, volume changing commands, etc. When the playlist starts, the Go app shuffles the files in your media folder and feeds them one by one to your media player command (`mplayer` by default). To stop the playlist, it kills the current mplayer task and stops. When you save a schedule for the alarm clock, it will create and install a crontab entry for the user running the app. The cron entry hits the API server to start the playlist at the desired time, and then, an hour later, it stops it the same way. ## Crontab The schedule system installs into the user's local crontab. The cron entries just post back to the API service, like: ```cron 30 5 * * * curl -X POST http://127.0.0.1:8000/playlist/start 30 6 * * * curl -X POST http://127.0.0.1:8000/playlist/stop ``` The stop command is installed one hour after the start. The user's local crontab is **overwritten** by the one Sonar installs. To keep custom crontab entries, place them into the `crontab.in/` directory. All custom user crontabs are concatenated together ahead of Sonar's cron entries. The `000-header.cron` is the standard Debian cron header and tends to be installed on top. # Installation ## Supervisor There's an example supervisor config in the `etc/` folder. Add it to supervisor and put nginx in front with Basic Auth. # Makefile * `make setup` to fetch dependencies. * `make build` to build the binary to `bin/` * `make dist` to build a distribution for your current setup * `make run` to run it in debug mode * `make watch` to run it in debug mode, auto-reloading (sometimes flaky control over mplayer tho!) * `make pi` to build a zipped distribution for Raspberry Pi. See [Cross Compile for Raspberry Pi](#cross-compile-for-raspberry-pi) # Configuration The config file will be in your system's native location, which is `~/.config/sonar.json` on Linux environments. After running the app once, it will save its default configuration to disk. The defaults are fine for PulseAudio setups but you may want to revise it to be sure. A default config file looks like this, annotated: ```javascript { "cookieName": "session", // name of HTTP session cookie "mediaPath": "./media", // path of media files (like .mp3) to shuffle and play "mediaCommand": [ // The command to actually play the media. Use %s where the filename goes. "mplayer", "%s" ], "volUpCommand": [ "pactl", "set-sink-volume", "0", // Sink number, from `pactl list-sinks` "+5%" // 5% step ], "volDnCommand": [ "pactl", "set-sink-volume", "0", // Sink number "-5%" ], "volMuteCommand": [ "pactl", "set-sink-mute", "0", "toggle" ], "volStatusCommand": [ // How to get the volume status. The command // should output just a value like: 56% "bash", "-c", "pacmd dump-volumes | grep \"Sink 0\" | egrep -o '([0-9]+)%' | head -1" ], // scheduled alarm time by default "hour": 6, "minute": 30, "days": [ "1", "2", "3", "4", "5" ] } ``` ## ALSA Driver HOW-TO on Raspberry Pi The default config above is generated assuming a PulseAudio setup, but the current Raspbian images for Raspberry Pi prefer ALSA by default. Here are some steps to identify your sound card and edit sonar.json accordingly. ### List ALSA Devices The `alsa-utils` package provides a handful of commands you might already have pre-installed. In my use case, I had a USB audio device attached to my Raspberry Pi that shows up in ALSA as a separate hardware device: ```bash $ aplay -l **** List of PLAYBACK Hardware Devices **** card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA] Subdevices: 7/7 Subdevice #0: subdevice #0 Subdevice #1: subdevice #1 Subdevice #2: subdevice #2 Subdevice #3: subdevice #3 Subdevice #4: subdevice #4 Subdevice #5: subdevice #5 Subdevice #6: subdevice #6 card 0: ALSA [bcm2835 ALSA], device 1: bcm2835 ALSA [bcm2835 IEC958/HDMI] Subdevices: 1/1 Subdevice #0: subdevice #0 card 1: Device [USB2.0 Device], device 0: USB Audio [USB Audio] Subdevices: 1/1 Subdevice #0: subdevice #0 ``` The `aplay -l` command lists your ALSA devices. Another command to know is `alsamixer` which presents a graphical CLI program to adjust the volume and show sound card details. ### Volume Control with ALSA The `amixer` command can adjust volume settings. For simple setups you can use commands like: ```bash # Increase or decrease volume by 10% at a time, respectively $ amixer set Master 10%+ $ amixer set Master 10%- # Toggle mute on or off $ amixer set Master toggle # Get the current volume setting $ awk -F"[][]" '/dB/ { print $2 }' <(amixer sget Master) 100% ``` In my case I needed to also specify the sound card device (`-c 1`) because I'm not using the default, and my output channel is named PCM instead of Master on that device: ```bash $ amixer -c 1 set PCM 10%+ $ amixer -c 1 set PCM 10%- $ amixer -c 1 set PCM toggle $ awk -F"[][]" '/dB/ { print $2 }' <(amixer -c 1 sget PCM) ``` ### MPlayer with ALSA Devices I also needed to sort out the `mplayer` command to tell it to use my ALSA device: ```bash $ mplayer -ao alsa:device=hw=1.0 ``` ### Example ALSA Config File My sonar.json config now looks like: ```json { "cookieName": "session", "mediaPath": "/home/kirsle/Music/watts", "mediaCommand": [ "mplayer", "-ao", "alsa:device=hw=1.0", "%s" ], "volUpCommand": [ "amixer", "-c", "1", "set", "PCM", "10%+" ], "volDnCommand": [ "amixer", "-c", "1", "set", "PCM", "10%-" ], "volMuteCommand": [ "amixer", "-c", "1", "set", "PCM", "toggle" ], "volStatusCommand": [ "bash", "-c", "awk -F\"[][]\" '/dB/ { print $2 }' \u003c(amixer -c 1 sget PCM) egrep -o '([0-9]+)%' | head -1" ], "hour": 6, "minute": 30, "days": [ "1", "2", "3", "4", "5" ] } ``` ## Cross Compile for Raspberry Pi Use the `make pi` command to build a distribution for Raspberry Pi. If you get permission errors when trying to download the standard library for ARM64, make and chown the folders as a workaround: ```bash sudo mkdir /usr/lib/golang/pkg/linux_arm sudo chown kirsle:kirsle /usr/lib/golang/pkg/linux_arm make pi rsync -av sonar.pi 192.168.0.102: ``` It outputs a `sonar-pi.zip` that you can scp over and run. # License Noah Petherbridge © 2018 GPLv2.