Adding Optical Input to a Bluesound Powernode (N150)

The Bluesound Powernode N150 is an IoT “super integrated” HiFi amplifier. This device is combination Streamer, DAC, Preamp and Power Amplifier. Utilizing the mobile and desktop apps one can directly stream Spotify, Amazon Music, TuneIn Radio etc.

One of the biggest downsides of this device is the lack of inputs besides the built-in streaming functionality (an issue mostly solved in newer, more expensive Powernode models). Luckily, there is a USB port in the back but unfortunately out-of-the-box this USB port only really supports a bluetooth dongle. It does not support a USB DAC or other peripherals, that is, without modification.

Internally the Powernode utilizes an ARM board running Linux and some custom Perl scripts. This means with root access and some modifications we can get other USB devices working with the available port.

In my case I used a StarTech 7.1 USB External Sound card (ICUSBAUDIO7D). These are pretty generic, I believe most of these 7.1 USB sound cards utilize the same C-Media CM6206 chipset. With some adjustments other cards will likely work as well.

The first step is getting root on the device. One method is described here https://rot256.dev/post/bluesound-powernode/. There a definitely other methods to root this device, but I have found that one to be pretty reliable. Once root access is acquired, it is helpful to set up persistent access. This can be achieved by adding SSH keys to the Powernode at /var/data/authorized_keys. This is helpfully already symlinked to /root/.ssh/authorized_keys.

That /var/data path is an important one. The root filesystem is by default mounted read-only. When a firmware update is applied, the root filesystem is overwritten. The manufacturer uses /var/data as non-volatile storage for settings, volume states etc.

When firmware updates are applied, our modifications will be lost. If you plan to update your firmware, be sure to keep copies of these modification somewhere you can easily re-apply them. Note: at the top of the sovi_info.xml file that we will be modifying there is a “git” version number and “rootfs” date that are updated for every new firmware. These will also need to be updated in your modified files to work properly (and avoid issues with the update process).

Now that we have pivoted from our initial access to the persistent SSH session the rest of the work becomes easier. The primary file that needs modification is /etc/sovi_info.xml. This file appears to be where the manufacturer customizes the BluOS firmware to match the feature sets of their various products (and 3 party products they license the firmware to). In our case, for optical input, we are going to need to add a <capture> device entry.

First we need to grab a copy of the current sovi.info.xml. To do this I used scp to pull the file to my local machine:

scp root@192.168.1.92:/etc/sovi_info.xml sovi_info.xml

Now add the capture device to the config file. This should go right after the <bt>bluez</bt> line:

<capture>
	<device id="input0" name="{OPTICAL_INPUT}"
		type="spdif"
		hw="hw:1,0" format="S16_LE" channels="2" rate="48000"/>
</capture>

This modification is creating an input labeled “Optical Input” which maps to alsa audio card 1 device 0 (audio card 0 will be the internal audio device where streams and things are played). We set the SPDIF word length to 16 bit and sample rate to 48khz. Note: These SPDIF settings are now statically set, meaning the source must always output with these settings as well. In my case I manually configured the SPDIF output on Windows.

During experimentation I found one other issue. By default when the driver loads for the StarTech USB sound card, the “PCM Capture” toggle is set to “Mic”. For the optical input to work, this needs to be set to “IEC958 IN”. Changing this in ALSA mixer isn’t hard, but every time the device rebooted, I would need to SSH in and manually correct this.

To fix this, we also need to add an ALSA state file to sovi_info.xml. We’ll add this right below the existing <state file… line

<state file="asound.state.startech" card="1"/>

Don’t worry about the asound.state.startech file itself, we will generate that later.

To do any modifications of the root filesystem, we need to first remount it read/write. This is easily enough done by SSHing into the Powernode and running:

mount -o remount,rw /dev/root /

Next we need to upload the modified sovi_info.xml. On the host we run:

scp sovi_info.xml root@192.168.1.92:/etc/sovi_info.xml

Now we need to configure that asound state file. With the USB soundcard plugged in we want to manually configure the “PCM Capture” to “IEC958 IN”.

amixer -c ICUSBAUDIO7D set 'PCM Capture Source' 'IEC958 In'

Now save the state:

alsactl --file /etc/asound/asound.state.startech store

We should now be able to reboot and test the Optical Input:

reboot

As previously stated, set your source output to 16bit/48khz and obviously make sure the Toslink is plugged in ūüėČ Then play the test audio of your choice.

Jump in the BluOS app, select the Powernode, and you should be able to see and select the “Optical Input” from the hamburger menu.

If you did everything right, the music should be playing!

Modification Backup/Restore for Firmware Updates

As stated above, the rootfs is overwritten during updates. Luckily the changes to /var/data are retained. Therefore the USB DAC mods will be lost (/etc/sovi_info.xml and /etc/asound/asound.state.startech will be gone) but our root access should remain (/var/data/authorized_keys should be retained). Keeping a local copy of both of our USB DAC mod files handy is a good idea.

After an update one simply needs to update some values in sovi_info.xml before recopying the files to the Powernode. After the update is complete SSH back into the Powernode and grab the new values:

cat /etc/sovi_info.xml

From there copy the values from <git></git> and <rootfs></rootfs> and update them in our modified sovi_info.xml

Then simply reupload the files with scp and reboot the Powernode. As of this posting, this method has worked. In the future with other updates, that may not remain true!

Adding support for the Nexx WT3020 in OpenWRT Barrier Breaker

Recently I have been playing with mesh networking. ¬†I’ve spent some time with the great folks over at¬†BuffaloMesh. ¬†They showed me the Commotion Wireless¬†firmware and that has become my main focus. ¬†This firmware is a great little tool based on OpenWRT. ¬†The Commotion organization has developed their own, more user-friendly UI and integrated many tools designed specifically for mesh networking.

A few weeks ago a purchased one of these little guys:

wt3020_smaller
NEXX WT3020

Unfortunately support for the Nexx WT3020 wasn’t added until very recently and therefore is only supported in¬†OpenWRT Chaos Calmer. ¬†Since Commotion only moved over to OpenWRT Barrier Breaker earlier this year, I was disappointed to find out I wouldn’t be able to directly compile Commotion for this device.

Luckily this last week I had some extra free time and decided to backport support of this device from the current OpenWRT trunk to Barrier Breaker.

The process started by locating the patch used to add support for this device to OpenWRT.  I found that changeset here.  At first I tried using this patch directly against a freshly downloaded copy of Barrier Breaker.  The bad news was that the patch command reported back multiple errors.  The good news was that some of the files patched without issue.

At this point I manually attempted to apply the patches.  It appears that Chaos Calmer has change the structure of the directories that hold device-specific code(thanks for the tip Roger).  Once I located all the files, I manually patch them(basically copy and pasting parts out of the patch file and properly placing the new lines into the source)

From there I ran a build. ¬†I ran into a couple compile errors because of my fat fingers. ¬†After those issues were corrected I was presented with a shiny, new .bin file. ¬†I find the easiest way to flash this thing is just setup a HTTP server on my dev box, SSH into the router, wget the file from the server and then use mtd to flash the firmware. ¬†Normally I would use the “sysupgrade” command to flash the firmware but I received an error stating this device isn’t sysupgrade compatible. ¬†At some point I’ll need to figure out what to tweak to add sysupgrade support.

After mtd completed the device rebooted and BOOM! Working OpenWRT Barrier Breaker on my WT3020.

Sweet success

After that I realized I still didn’t have a working .patch file, since I had manually patched everything. ¬†After doing some reading, I learned about making patches with “quilt”. ¬†Essentially I downloaded a fresh, unpatched copy of Barrier Breaker. ¬†I was then able to use quilt to run a diff between the modified and unmodified copies of the repo. ¬†This produced a .patch file which I have uploaded to my github repo. ¬†I verified the patched worked by using quilt to apply the .patch to the virgin copy of Barrier Breaker. ¬†I then ran a build using the fresh patch. ¬†I ran into one strange glitch where the build errored out part way through. ¬†But after restarting the build a second time it compiled without issue.

One this I wanted to make sure of, was that the device specific code I had applied also functioned properly.  One of the easiest ways I could thing to do this was testing the LED functionality.  One of the files in the patch included device specific LED settings.  To make sure the LED was being addressed properly I simply needed to go into the OpenWRT LED settings and make sure they responded appropriately.  I did this by setting a 1 second on/of delay.

IMG_3671
Blinking blue LEDs makes it faster

Next I will need to compile Commotion against this patch and verify functionality. ¬†I’ll be sure to make a new post and link it here once that process is complete.