What I learnt using docker as a beginner

Running my own server setup with docker, I ran into some issues over time. To not forget what I did and maybe to help others here is what I found.

It is a gathering of simple things I now try to include in all my docker setups, as they make life with docker easier. For some this might be obvious things. If you have additional thoughts, I am happy to hear of them.

Do not mix your hosts file system with your docker mounts

It might be a tempting idea to store config files of your container within your regular /etc or logs to /var/log. However you easily get lost to know which file is used by whom. Log files may get merged with others and so on. Hence have your own directory in which you store your docker stuff. It also makes backups, git use etc. easier.

Use git - a lot

You should use git to version everything you do on docker. Starting with your dockerfiles, to configuration files for services. Especially building a new container needs a lot of testing. Things might go forth and back, hence a history and versioning is utterly helpful.

Keep ENTRYPOINT and CMD separate

Use the entrypoint for something that needs to be done before each start of the service, like correcting permissions, update small things, etc. Keep the command separated from this (hence do not put the service start command in the entrypoint) so you can override it easily.

Use dumb-init in your own Dockerfiles

It is a small package you can easily install and easily add to your image. It simply puts a tiny init system into the container to properly start and stop your service. You can read more on the dumb-init github page. A lot of images out there ignore this. It is not per se harmful, but a lot of services get killed instead of properly shut down.

Prosody container example:

ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["bash", "-c", "/usr/local/sbin/entrypoint.sh && exec prosodyctl start"]

Learn about IPv6, iptables and internal docker networks

Docker takes over iptables when running a container, be sure to understand what is happening. Especially take a look on internal networks, as they can easily secure database container and other backend services.

For IPv6 better still use NAT. I didn’t like that in the beginning as well, however you run into so many troubles (like dynamic prefixes, limited IPv6 configuration options, etc.), that it is just way easier to use NAT again. Sadly docker does not support NAT on IPv6, for that use https://github.com/robbertkl/docker-ipv6nat. It is a simple binary to run in the background, that fills the gap.

Make sure your container runs with the correct user:group

Especially when using bind-mounts, make sure your use proper UID:GID combinations. I have created the users on my host machine that will be used inside the container and pass the UID:GID into the container. This ensures, that files stored on the host will not by accident be accessible by other processes due to UID overlap.

Again a prosody example on debian for your Dockerfile

ARG uid=1001
ARG gid=1002

# Add user and group before install, for correct file permission
RUN addgroup --gid $gid prosody \
    && adduser --system --disabled-login --disabled-password --home /var/lib/prosody --uid $uid --gid $gid prosody

Use docker logging

It is tempting to just mount a folder and store logfiles. However when using images, e.g. from hub.docker it can be quite difficult to correctly map this and often leads into some sort of chaos.

I actually like the webserver approach to just link the logfiles to /dev/stdout and /dev/stderr

RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log

With that you can use the regular docker logs command and use configuration options to divert it to whatever log facility you are using.

Make sure your container are in the right timezone

A lot of images nowadays use the TZ=<timezone> as an environment variable in the container to control the timezone. You should set this always and use it in your own Dockerfiles

RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime

Nothing is more confusing than log files with non matching timestamps.

If you need to build from source use multi-stage builds

Instead of bloating your production image with build-tools and sources, use multi-stage builds.

With that you can create a build image, run it and use the build results in a regular image:

Shortened example for coturn

### 1. stage: create build image
FROM debian:stable-slim AS coturn-build

# Install build dependencies
[...]

# Clone Coturn
WORKDIR /usr/local/src
RUN git clone https://github.com/coturn/coturn.git

# Build Coturn
WORKDIR /usr/local/src/coturn
RUN ./configure
RUN make


### 2. stage: create production image
FROM debian:stable-slim AS coturn
[...]

# Copy out of build environment
COPY --from=coturn-build /usr/local/src/coturn/bin/ /usr/local/bin/
COPY --from=coturn-build /usr/local/src/coturn/man/ /usr/local/man/
COPY --from=coturn-build /usr/local/src/coturn/sqlite/turndb /usr/local/var/lib/coturn/turndb
COPY --from=coturn-build /usr/local/src/coturn/turndb /usr/local/turndb

# Install missing software
[...]

Make sure your services start in order

A lot of errors come up when services that depend on each other just start in random order. Sometimes you are lucky and it works, sometimes you get an error. Within docker-compose you can use the depends_on directive. If you have for some reason separate setups, you can use the following bit within your entrypoint:

/bin/bash -c " \
  while ! nc -z mariadb 3306; \
  do \
    echo 'Waiting for MariaDB'; \
    sleep 5; \
  done; \
  echo 'Connected!';"
Full article view to comment or share...

Parsing config files in bash using awk

Ever so often I get to some sort of complex bash script and find, that a configuration or ini file would make sense, to control the script and make it more flexible. However bash does not bring nice libraries to parse config files, e.g. like python.

In essence two things are needed to write a config file parser:

  1. good trim of the config option, as you can have
    • <option>=<value>
    • <option> = <value>
    • <option> =<value>
    • and so on…
  2. structured way to move the config to usable variables within bash.

So what is the solution

First lets take a look on how to analyze a config file line. It is normally setup like: <option><delimiter><value>

To parse this, we need to separate the option and value by the delimiter. For this awk is perfect to use as it can seperate a line with a field separator in parts and store each in a variable.

Additionally we can eliminate spaces around the delimiter to make the config parser more robust. However we need to do that left and right of the delimiter, to only trim the leading and trailing spaces of each side. Just eliminating spaces in the whole string would delete spaces in configurations as well. Using the delimiter = this would look like the following for the left side (for right side change $1 to $2).

awk -F'[=]' '{gsub("^\\s+|\\s+$", "", $1); print $1}' <<< $line

So what does this do?

  • -F[=] sets the delimiter to =
  • gsub("^\\s+|\\s+$", "", $1); starting starting from the first letter (^) replace 1 or more spaces at beginning and end (\\s+|\\s+$) with an empty string (""). $1 use the left part of the delimiter for the gsub command
  • print $1 as awk automatically splits with the delimiter, print the first part (left side of the config line)
  • <<< $line is the feeded line of our config. Within bash you can easily loop through a file line by line with the read command.

Now that we have the basics, we can write a parser function with it.

An example within a script:

#!/bin/bash

declare -A settings_map

function read_config () {
    while IFS= read -r line; do
        case "$line" in
            ""|\#*)
                # do nothing on comments and empty lines
                ;;
            *)
                # parse config name and value in array
                settings_map[$(awk -F'[=]' '{gsub("^\\s+|\\s+$", "", $1); print $1}' <<< $line)]=$(awk -F'[=]' '{gsub("^\\s+|\\s+$", "", $2);print $2}' <<< $line)
                ;;
        esac
    done < $1
    echo ${settings_map[*]}
}

# call fuction with the config file to parse
read_config parser-test.conf

# show that it is working and picking "option" from the array
echo ${settings_map[option]}

This would read a config file like this (or with some spaces around the =):

# parser-test.conf
# Use option=value
#
type=value_type
option = value_option

test =value_test
spaces    = value space

It reads line by line, remove leading and trailing spaces on the left and right site of the config line, then store it into the settings_map array. The array can be used within the rest of the bash script.

Important: This function uses a globally declared array. Handing back an array from a function is not trivial. You could create and return a string, then initialize an array afterwards. However I feel that to be a bit cumberstone and not adding to the functionality.

Full article view to comment or share...

Deactivate bluetooth on startup

For some reason my laptop thinks bluetooth is the technology to go and activates it on startup of Linux Mint/Ubuntu.

Searching the internet you will find a lot of answers for this problem, that quite brutally kill the bluetooth service or block devices. All not very elegant.

So what is the solution

Most laptops use tlp for power management. If you don’t you should check it out. With that it is quite easy. Uncomment and edit in /etc/tlp.conf:

DEVICES_TO_DISABLE_ON_STARTUP="bluetooth"

You can also edit tlp to remember the last state when powering down. But for me deactivating bluetooth was all enough.

Full article view to comment or share...

Open Source Wifi Speaker based on IKEA Symfonisk - Part II: Software / OS

After finishing the hardware in part I of this little tutorial, we need to set up the operating system to run our speakers. Of course it should be open source software.

There are multiple solutions out there to do multiroom streaming, however the slimserver or squeezserver eco system looks the easiest for me right now. It seems to support everything I am looking for:

  • Central streaming server with lightweight clients for playback
  • Multiroom and sync features
  • Extensible with plugins
  • Internet radio
  • Streaming services, like Spotify or Tidal
  • Open source

Most of the features are actually done in the server and are pretty easy to set up. I am running the server in a docker on my NAS, where it also has access to my local music library.

This part however is focusing on the player and have that as slim and robust as possible. I checked a setup on HifiberryOS, Rasbian, etc.. However was convinced to start with piCorePlayer as a clever solution based on tinycore Linux.

The advantage of piCorePlayer / tinycore Linux is, that it runs completely in RAM. Hence you can unplug the speaker without too much worries about the SD card in the raspi. Also the system is very small. I use now only a 1GB SD card, which is not even used 10% (Sadly you can not buy such small cards anymore ;-)). I could have used piCore (the barebone tinycore Linux for raspis), however then I would need to do a lot of work that has already been done by the piCorePlayer team.

So now we only need to extend the piCorePlayer with specialties of our setup:

Step 1: Prepare Richard Taylor’s LADSPA plugins

As tinycore is loading everything into RAM on boot, the system is build out of different extensions, which are pretty much zips with the files for that extension. All loaded extensions get merged into one filesystem in RAM on which the system is running. Most things are already prepackaged and can be downloaded as an extension, however within the repositories, I could not find the LADSPA plugins of Richard as a prepared extension. However creating such extension is not too complicated.

Download Plugins (Author published source code under GPL-v3.0)

If you want to compile the plugins yourself, it makes it easier to use a piCore setup on the Raspberry.

Step 2: Get piCorePlayer and install it to the SD card of your speaker

Get the latest piCorePlayer here and write it to your SD card.

Next you need to add your wifi information to have it log in automatically. For that, mount the just created SD card. It should have two partitions, a PCP_BOOT (probably mmcblk0p1) and PCP_ROOT (probably mmcblk0p2) partition. Create a wpa_supplicant.conf in the root of the PCP_BOOT partition and fill in the relevant fields (country, SSID, password). There is also a sample file which you can just copy, rename and edit. This is also explained here.

Next you need to resize the root partition to use the free space on the SD card. On my systems (Linux Mint), I can easily to this with gparted (right click on partition to resize). Otherwise you can do it in the piCorePlayer GUI after booting. However to do it right away is easier, as we want to copy Richard Taylors plugins as well. The plugins from Step 1, will now be added to the piCorePlayer by copying them to the PCP_ROOT storage

cp rt-plugins-0.0.6.tcz /mnt/mmcblk0p2/tce/optional/
cp rt-plugins-0.0.6.tcz.md5.txt /mnt/mmcblk0p2/tce/optional/
echo "rt-plugins-0.0.6.tcz" >> /mnt/mmcblk0p2/tce/onboot.lst

The last line adds the extension to the boot list, so they will be loaded and available in the file system after boot. Now the piCorePlayer is ready to boot and to run the speaker.

Step 3: Configure piCorePlayer

You need to do some basic configuration of piCorePlayer to run it with the speaker. For that use a browser to access the piCorePlayer web interface under the IP of our speaker. First activate the advanced mode on the tab of the bottom of the Main Page. During the configuration you will have a few reboots. I would do each one of them, to be thorough.

If you haven’t extended the filesystem yet, you need to do it now (Main Page -> Resize FS) and probably still need to copy the plugin

After that update the player under Main Page -> Full Update. Update the extension under Main Page -> Update. Check for possible hotfixes under Main Page -> HotFix.

Then head to the Squeezelite Settings page and set Amp2 as audio output device. After saving and possible reboot, use the Card control button and deactivate the raspis internal audio device down at the bottom. Only after that squeezelite will start. Back on the Squeezelite Settings page you have to enter the name of this player and the IP of the LMS server. Finally on the Tweaks page enable the ALSA 10 band Equalizer. Probably another reboot is helpful and our basic configuration is complete.

The speaker now will be working, however it will sound weird. You still need to activate the crossover and probably use the equalizer.

Step 4: Activate crossover, mono downmix and equalizer settings

For the crossover you need to connect to the player console via SSH. After login you need to edit the /etc/asound.conf file. Vi is installed in the system. You will find a pre-generated configuration from piCorePlayer. Edit this to match the following:

# default - Generated by piCorePlayer
pcm.!default {
  type plug
  slave.pcm "plugequal"
}

ctl.!default {
  type hw
  card 0
}

pcm.pcpinput {
  type plug
  slave.pcm "hw:1,0"
}

#---ALSA EQ Below--------
ctl.equal {
  type equal;
  controls "/home/tc/.alsaequal.bin"
  library "/usr/local/lib/ladspa/caps.so"
}

pcm.plugequal {
  type equal;
  slave.pcm "plug:crossover";
  controls "/home/tc/.alsaequal.bin"
  library "/usr/local/lib/ladspa/caps.so"
}

pcm.equal {
  type plug;
  slave.pcm plugequal;
}

#--- Speaker crossover below-----
pcm.crossover {
  type ladspa
  slave.pcm "amp2"
  path "/usr/local/lib/ladspa"
  channels 6
  plugins
  {
    0 {
       label RTlr4lowpass # lowpass left output to channel 2
       policy none
       input.bindings.0 "Input"
       output.bindings.2 "Output"
       input { controls [ 3000 ] }
      }
    1 {                                                    
       label RTlr4lowpass # lowpass right output to channel 3
       policy none                       
       input.bindings.1 "Input"                            
       output.bindings.3 "Output"                           
       input { controls [ 3000 ] }       
      }                                       
    2 {                                                     
       label RTlr4hipass # highpass left output to channel 4
       policy none                       
       input.bindings.0 "Input"                             
       output.bindings.4 "Output"                           
       input { controls [ 3000 ] }                         
      }                                       
    3 {                                                     
       label RTlr4hipass # highpass right output to channel 5
       policy none                                         
       input.bindings.1 "Input"                            
       output.bindings.5 "Output"                           
       input { controls [ 3000 ] }                          
      }                                  
  }                                                         
}                                

# --- Output device and mono downmix below -----                                                            
pcm.amp2 {                                                  
  type plug                                                 
  slave {                                                   
    pcm "t-table"                
    channels 6                                              
    rate "unchanged"                                       
  }                                                         
}                               
                                 
pcm.t-table {                                               
  type route                                               
  slave {                                                  
    pcm "hw:0,0"                                            
    channels 2                                              
  }                              
  ttable {                       
    2.0 0.5 # Mix both stereo low (main) to mono            
    3.0 0.5                                                 
    4.1 0.5 # Mix both stereo high (tweeter) to mono        
    5.1 0.5                                                
  }                                                         
}                                                  
                                               
pcm.plughw.slave.rate = "unchanged";

So what is this doing? Basically it tells ALSA to use a chain of filters for the default device and then send it to the hardware:

  • pcm.!default: redirect the default device to plugequal
  • pcm.plugequal/pcm.equal: this is the ALSA equalizer and first step in our chain. We will configure it later. We can use this to influence the sound of our speaker
  • pcm.crossover: here we use Richard Taylor’s plugins to split our stereo signal in 4 channels. The highpass ones above 3000Hz and the lowpass below that
  • pcm.amp2/pcm.t-table: this is the hardware device for playback (hw:0,0), the table does the mono downmix for high- and lowpass channels

After this, we get 2 mono signals, one above 3000Hz, one below, each left and right of the stereo signal downmixed. These are then put to the tweeter and mid-range speaker. Having the equalizer in the chain, we additionally have the opportunity to tune the sound of our speaker. This will impact all sound being send to the speaker.

Save the file and get back to the command line. Next you need to set the equalizer

Step 5: Setting the equalizer

The ALSA equalizer is set via the command line.

export TERM=xterm
sudo alsamixer -D equal

The first line will prevent the error Error opening terminal: xterm-256color.

You will get a nice looking console equalizer, in which you can tune the sound of the speaker (left/right, up/down arrow keys). Now this is complicated, as sound is something very personal. Hence my settings might not be the right ones for you. I advise to come back later when you play some music and tune this to your taste (I am happy to hear of any settings). Changes to the equalizer are audible right away.

Here are my settings (observe the numbers on the bottom)

Equalizer

As you can see, I did not change too much. As far as I know, within an equalizer the less is better.

IMPORTANT step: We now edited some files on the player, to make that survive the next reboot, we need to backup our config. Go back to the piCorePlayer web interface to the Main Page and click the Backup button. Now the settings will survive possible reboots.

Step 5: Add controls to the front buttons

To make our buttons on the front work during playback, we need another extension.

Head to Main Page -> Extensions and click on the Available tab. Under the Available extensions select pcp-sbpd.tcz and click load. This installs all necessary plugins to monitor the raspi pins.

Next - via SSH - create the file /home/tc/sbpd-script.sh with the following content (please adjust the -A and -P to your LMS server instance and port. You can try auto discovery by removing both flags as well):

#!/bin/sh

# start pigpiod daemon
sudo pigpiod -t 0

# give the daemon a moment to start up before issuing the sbpd command
sleep 1

# load uinput module, then set the permission to group writable, so you don't need to run sbpd with root
sudo modprobe uinput
sudo chmod g+w /dev/uinput

# issue the sbpd command
sbpd -s -d -A 192.168.2.9 -P 9000 b,11,PLAY,2,0 b,10,VOL-,2,0 b,9,VOL+,2,0

After saving the file, make it executable chmod +x /home/tc/sbpd-script.sh This script basically starts the GPIO monitoring. The last line defines the GPIOs to watch. here it is 9, 10 and 11 (each right after the b,). If you remember the table out of the hardware wiring for the buttons this is SW_Mute, SW_Down, SW_Up. If you changed the pins used on the raspi, then you will need to adapt it here.

If you are interested in the whole syntax given there or to add a long press event, use sbpd --help on the command line to get the details.

Now the script needs to be launched at startup. In the web interface go to Tweaksand add /home/tc/sbpd-script.sh as User command #1 and click Save.

Now finally go back to the Main Page and hit Backup one last time. One last reboot and your speaker should be ready to rock…

Addendum: Changing crossover frequency and equalizer

The selected crossover frequency and equalizer settings are based on my personal taste. It might be that there are better options. Overall, this is not a high audiophile level of speaker, hence do not expect too much. If you want to fiddle with that, the following commands might help a bit.

The crossover frequency is set in /etc/asound.conf. I guess you can spot the 3000. ;-). The frequencies for each filter should match, otherwise it sounds quite weird, but feel free to play around with it. Just beware, that forcing a speaker into frequencies it was not build for is stressful for it and might even break it. Hence not change your tweeter into a sub-woofer and vice versa.

Calling the equalizer: export TERM=xterm sudo alsamixer -D equal

Relaod ALSA after changes (reboot is always better): alsactl kill rescan

Reduce the volume directly on the speaker to 70% (otherwise the next command is very loud): amixer sset Digital 70%

Produce a pink noise speaker test sound (for frequency measurements): speaker-test -c2 -tpink

Full article view to comment or share...

Open Source Wifi Speaker based on IKEA Symfonisk - Part I: Hardware

For years I had Sonos speakers back at home to play my music and stream internet radio, spotify, etc. With the announcement of Sonos to not support older devices, it became clear, that again perfectly fine hardware will become useless, just because of software decisions. For long I was annoyed with samba v1 on the speakers, which couldn’t be updated due to limited space inside the flash memory. For adding Alexa and other new features apparently there was always space.

Hence I thought to build a speaker that is build with standard components (can be repaired if broken) and uses open source software. However if you look into the internet, there is tons of howtos on how to build your own speaker and speaker casing, even some awesome builds into old radios etc. I wanted to have the small devices with good sound like I had with my Sonos (not audiophile high def super sound). The importance for me was design, to have a device that fits nicely into the living room (high WAF).

So basically I need to rebuild a Sonos speaker. However these are quite expensive to just tinker with. But lately IKEA got the Symfonisk speakers for 99€. Hence I got one and rebuild it into a complete open source Wifi enabled speaker.

This is probably not the cheapest way of getting a wifi speaker, but the result was worth it for me. If you sum up the costs you are in the range of a small Sonos speaker, however with the huge advantage of being free from a single vendor and having a maintainable device.

What did I use (For some parts there are other options, e.g. the amp or power supply, but “This is my design”). The links below are just for informational purposes, feel free to use your own supplier.

I measured the setup in terms of power consumption. It uses roughly 2,5W in standby. Compared with Sonos, that is quite good.

You personally need some really basic soldering expertise and good common sense (“Don’t eat from the yellow snow”, “Don’t touch live wires”). I glued most of the parts into the chassis, however the raspi can be unscrewed.

DISCLAIMER: I am not a technician or expert on this, and learned a lot by doing this project. If you rebuild this, you do it on your own risk.

If you found any errors, I am happy to hear of them. If you try this guide, start off by building it outside of the case to verify correct wiring and function of each part.

Step 1: Disassembly

First you need to completely disassemble the Symfonisk speaker. A good guide you will find here: Hacking the Sonos Ikea Symfonisk Into a High Quality Speaker Amp That guide is basically doing the reverse: Using the Sonos parts for a regular speaker. Also a good project and probably good to sell off the Sonos components. However goal of this tutorial is to get independent of a single supplier. After the disassembly you pretty much will have a lot of Sonos spare parts and en empty housing for the speaker. For the build we will only use/reuse the following, so make sure you do not damage them in disassembly:

  • Housing/Chassis
  • Front part with both drivers
  • Wiring towards the speakers
  • Power plug and cable on the back (not the wiring inside)
  • Buttons on front with electronics and the flex cable towards mainboard
  • Screws, etc.

Step 2: Power supply

I used a DIN-rail power supply, as they are very compact. The speakers inside the Symfonisk are a 4Ohm mid range and a 8Ohm Tweeter. Hifiberry recommends a 18V 60W ~3A power supply, if you connect the Amp2 to 4-8Ohm speakers.

Finding a 18V power supply in compact form was quite a hassle. The Mean Well HDR-60-15 actually is in the 15V category, but can be tuned to deliver up to 18V. Mean Well even has open housing power supplies, which are a few € cheaper, however they are not as compact as this one. The power supply has a little screw next to the outputs to increase voltage output. It is quite clearly marked. You can turn it fully for the 18V.

Alternatively you can use an external power supply (Like old notebook supply), however then you will need new plug and wiring at the backside.

Step 3: Add the Raspberry Pi and Hifiberry Amp2

The regular raspi zero W does not have the pin header soldered on, that is why I went for the zero WH. If you happen to have a W only, the only thing to do is to solder the header on and test it (German).

The Amp2 is just placed on top of the raspi:

Amp2 on Raspberry

On the picture you can see I used a regular plug to power the Amp2 with raspi, mainly for testing.

Step 4: Wiring the power supply

Make sure you use proper cables for the power supply, I used >1mm diameter full copper and used the original plug from the backside of the Symfonisk and soldered new cables on towards the power supply. +/- does not matter here, as it is AC.

The Amp2 powers the raspi, so you only need to connect the Amp2 to the power supply. Here it is important to correctly wire +/- with the Amp2 as the output is DC. The power supply has two outputs, it does not matter which to use.

Step 5: Extend Raspberry Pi ports

As the SD cards in raspis easily get damaged, I decided I want to extend the sd card slot and make it accessible from the outside when the housing is closed. Also I want to extend one USB port to the back of the housing to possibly add some hdd or to connect a usb network adapter (should I not use wifi anymore). You could build in the network adapter and glue it on the old port, however I felt this to be more flexible. This is pretty straight forward, as you just connect the USB port plug and the SD-card extender on the raspi.

Step 6: Connect the Sonos buttons

The Symfonisk has pretty little buttons and LEDs on the front and it would be nice to be able to still use them. The parts you pulled out in the disassembly (+ the cable):

Amp2 on Raspberry

The rubber parts are not needed for now, but we need to check the electronics. You have 4 LEDs and 3 buttons on it, all wired to a FPC 10 pin, 0,5mm connector. With the adapter linked above you can actually use the original cable and solder on some cables to connect it to the raspi.

Amp2 on Raspberry

On the adapter you can see the lines of the cable in 1-10. With a multimeter you can figure out what it connects to on the button electronics board (or use my table below). We also need to map them to raspi pins to use them later on. The Amp2 uses HW pins 3, 5, 7, 12, 35, 38 and 40. Also 27 and 28 are off limits for the eeprom.

Please be careful: HW pins are not the GPIO numbers. See chart below, HW pins in the middle. Nr. 1 ist the squared one on the raspi and Amp2 board.

Amp2 on Raspberry

To pull everything together, I did the following mapping for the buttons and LEDs for the adapter and raspi connection:

CABLE/ADAPTER FUNCTION HW-PIN GPIO EXPLANATION
1 SW_Mute 23 11 play/pause button
2 SW_Mute 23 11 just use one
3 Green LED 16 23
4 Red LED 18 24
5 GND 20 GND just use one
6 Amber LED 22 25
7 GND 20 GND just use one
8 White LED 15 22
9 SW_UP 21 9 volume up button
10 SW_DW 19 10 volume down button

When you solder everything together you get something like this.

Amp2 on Raspberry

You can now connect the Button panel with the original flexcable to this.

Step 7: Wire the speakers

Polarity is key in here, hence make sure you connect it correctly. The speakers and the Amp2 are marked with +/-.

I used the Sonos wiring, but you can of course create new ones. On the Sonos wiring, the big plugs are the + (this is also marked on the speakers) Yes, you see correctly, I am using one stereo channel for of the Amp2 for the mid range and one channel for the tweeter speaker. No hardware crossover, we will need to do that later on with ALSA.

Now everything is ready. If you want to do some tests you should be able to. However be careful with live wires!

Step 8: Fit everything into the chassis

Now everything needs to go into the chassis. I mainly glued everything into it, but made sure, I can unscrew the raspi for possible maintenance. To hold it in place I used spacers which are then glued to the chassis.

Amp2 on Raspberry

You can see the original speaker wiring in the foam, the red and white wires go to the power supply. In the back you see the red white again, which is the wiring from the power supply to the plug on the back of the chassis. The SD-card extension is leaving the raspi on the left, the USB port is the thick cable in the front.

The spacers are stepped, left 1cm, on the right 2cm. The chassis is not even in the back, hence you need this to fit. Only these parts are glued and the raspi is screwed on.

After adding the power supply you get something like this

Amp2 on Raspberry

The bottom of the picture is also the bottom of the speaker. Hence if you close the chassis, the big speaker will be on the right.

In the middle you can see the power plug and the extended port glued to the back. From the back you can then access one USB port and the SD-card of the raspi.

Amp2 on Raspberry

If you connect the buttons and soldered adapter from step 6 you get the following

Amp2 on Raspberry

Hardware should be done now and we close up everything. If you have, you can glue a bit of padding to the cables and things inside. It is a speaker, so everything will be vibrating.

Now you have a Wifi enabled speaker build with freely available parts, maintainable and good looking. Next step is to make it smart, which is basically choosing the right software. See next -> Open Source Wifi Speaker based on IKEA Symfonisk – Part II: Software / OS

Full article view to comment or share...