Home Assistant and Node-red to automate an Android Roon display

By iainpotter, 11 June, 2021

Introduction

This probably deserves a bit of background - brace yourselves...

I have worked in the computer software industry for the last twenty-odd years, and currently work as a technical architect at Acquia. I am also a bit of a hobbyist and tinkerer, messing around with intel NUCs, raspberry pis and the like, usually something involving home automation, much to the consternation of my wife.  I've been running Home Assistant on an intel NUC (well, a pi initially, and then a NUC) for a number of years now.

I've always loved music, and have fairly eclectic tastes. I have favourite songs from just about every genre, and try not to be judgemental. I play drums, and yes, drummers ARE musicians.

Despite my love of music, I've never considered myself an audiophile, and until relatively recently my association of that term was of stuffy old men listening to jazz records on vinyl, whilst standing on their head, and listening on a setup from 1972 - because that method  "produces a pleasing timbre".

However, my opinion changed when I stumbled upon the YouTube channel of John Darko towards the end of 2020, becoming obsessed with trawling through his videos, and subsequently delving into the areas of the web where like-minded "audiophiles" live (that sounded murkier than I intended - it's mostly Facebook forums).

At this point, I'd organically collected a bunch of Sonos gear that currently fills our downstairs. It started with a couple of Sonos One speakers in around 2005, and a Spotify Premium subscription, and off I went.

Back to the recent past, and what really caught my attention was this "Roon" software that kept getting a mention in Darko's videos, and the fact that the Sonos gear was "Roon Ready" - meaning I could install the software, sign up for a trial and get tinkering.

At first, I thought Roon was just another media player with likely poor capacity for pulling track metadata, but the more it was mentioned in various places with glowing terms, the more intrigued I became - I have always been one for shiny new tech, but a relatively long career in software tells me to avoid the shiny new things in a professional capacity, so that itch gets scratched at home.

It also got me thinking about whether I was missing out in terms of the hi-res audio, and curious about whether it was worth a look.  Would I even be able to notice any difference, especially after years of playing drums?

In any case, I thought I'd sign up for a Tidal trial and give Roon a go - and despite a few teething issues (I even started a Roon community post on my problems) eventually the penny dropped and I love it.  Roon really enhances my experience of Music, and in the short time I've been using it, I've discovered a lot of music I wouldn't have otherwise.

Now I'm mucking about with DSP profiles for my Oppo PM-3 headphones, thinking about "room correction" (WHAT?!??!) etc. etc.

More people need to try this software.

In any case, this isn't a Roon review, but suffice to say, that was the start of my journey down the rabbit hole.

I've since invested in some more gear, probably what people would class as low to mid end of the spectrum rather than jumping all in. Judgemental audiophiles may baulk at my choice, but I am more than happy with my selection of Dali Oberon 5 speakers and a Cambridge Audio Evo 75 integrated amp and streamer, which currently lives in our bedroom.

One of the things that drew me to the software initially was actually the idea of being able to display what was playing on screens around the house. With my interest in home automation, I'd always liked the idea of being able to show what the Sonos speakers were playing on screens, but never really found a solution I liked.

Which pretty much sets the scene for this post.  Well done, if you got this far!

Note: from here on in, this is going to get fairly technical. So unless you're pretty comfortable working with Linux, configuring software etc. then this is probably not for you.

My setup

It's worth telling you a bit about the gear I have, the software I'm using etc.

Hardware

Intel NUC

The NUC is running Home Assistant (including the Node-red addon).  OS is Ubuntu 20.04 LTS. 8GB RAM and 512GB SSD drive.

Fierce Gaming PC

Originally bought for gaming, but now a dedicated server running Ubuntu 20.04 LTS.  This is where Roon lives.  It's also been upgraded with a 1TB SSD as the primary drive, with the original 1TB SATA repurposed just to store media.

Samsung Galaxy Tab A 10 inch

Downstairs Audio

Sonos Amp, in surround setup, running two Cambridge Audio Minx Min12 speakers front and two Sonos One speakers rear.

Two more Sonos one speakers.

One play:1

One play:5

Upstairs Audio

Cambridge Audio Evo 75

Pair Dali Oberon 5

An idea springs forth

So after a little while of mucking about with Roon, my thoughts came back to the idea of having screens around the house to show what was currently playing.

I came up with the following set of initial requirements:

  • Screens should show 'now playing' when downstairs group is playing
    • On the Samsung tablet in living room
    • On the Pi 4 in kitchen
  • Screens should be non-interactive and locked down (to avoid my wife or guests inadvertently causing me a job in terms of restoring the intended behaviour!)
  • Screens should turn off when Roon is not playing

I already knew about Fully Kiosk Browser from the Home Assistant community - many people use it on a tablet as a control panel for their home, or to display information.  So I knew that could be used to lock down the tablet. It turns out it also exposes a really handy API - more on that later!

It's also worth noting that the features I required did not come for free and I had to purchase a license; the price is negligible and more than worth it - I don't begrudge paying for software since I know first hand the effort that goes in to making it.

The tablet was the starting point.

Setting up the tablet - Fully Kiosk Browser

The first step was to install Fully Kiosk Browser on the tablet.  I then set about locking it down, to keep out meddling fingers, and configuring it to display the Roon Web Display.

1. Download Fully Kiosk Browser from the Play Store.

2. Buy a license! :)

3. Open Roon, then Settings -> Displays.  Copy or make a note of the URL, which will look something like http://<ip_address>:<port>/display

4. Open up Fully Kiosk, open the settings and go to 'Web Content Settings'.  Enter the URL from step 3 as the Start URL. This will ensure the Roon display loads when Fully Kiosk is started.

Image
Roon Start URL

5. Optional: Under 'Web Browsing Settings' I also enabled 'Load Start URL on Home Button' as an extra precaution to ensure anyone trying to bypass Fully Kiosk would fail.

6. Under 'screensaver', I ensured the screensaver would not kick in by setting the 'Screensaver Timer' to zero.  This is important, because we're not actually interacting with the tablet. For similar reasons, I also enabled 'keep screen on'.

7. Under 'Kiosk Mode' I configured 'Enable Kiosk Mode' and set a PIN under 'Kiosk Mode PIN' in order to lock down the tablet.  This ensures that only I can unlock Fully Kiosk Browser, using the PIN.

Image
Roon Kiosk Configuration

Exiting the settings dialog, you may get prompted to set Fully Kiosk Browser as your default launcher.  You should do this.  What this does is ensure that Fully Kiosk Browser is started by default whenever you start the tablet.

All being well, you should now see 'Roon' displayed on your screen.

Image
Roon Display on Samsung Tab

Back in Roon itself, I navigated to 'Settings -> Displays' again, and could see the tablet display listed.  I reconfigured the name to be 'Samsung Tab'.

In the main section of Roon, I selected my downstairs group, then configure this group to start the 'Samsung Tab' display on playback of that group.

Image
Roon Tablet Display Configuration

Job done!

If you start playback in this group, you should now see the Roon display come to life.

Image
Playing on Tablet

That takes care of having the tablet display what's playing, but we still need to figure out how to automate turning the display on or off according to playback status.

Setting up the tablet - automating the screen

Since there's no obvious way for Fully Kiosk Browser to be aware of when Roon was playing (why would there be?) I had to get a little creative here. I needed a way to get this information in the first place, and then a way to control the tablet based on the state.

I knew some things at this point

  1. Fully Kiosk allows for remote administration (in my case "remote" is limited to devices on the same network - a configuration option)
  2. The remote administration component exposes a REST API that allows us to turn the display on and off, as well as query state
  3. There is a Roon integration for Home Assistant that will talk to your Roon core and expose Roon endpoints to Home Assistant as media players, and which also includes up to date status (playing/paused/stopped)

So, Ladies and Gentlemen, welcome my old friends, Home Assistant and Node-red!

Now, I also knew...

  1. Home Assistant can call REST APIs
  2. Node-red can make use of Home Assistant - trigger logic based on state, ask Home Assistant to perform certain actions via the use of services etc.

I could use of the REST API calls in order to maintain the screen state locally as well as trigger the screen on/off behaviour as required via the Home Assistant concept of a switch.

I could determine when Roon was playing or paused via the Roon integration with Home Assistant - a change in state here becomes the trigger in Node-red for turning the screen on or off via Home Assistant and a call to the Fully Kiosk Browser API.

So the plan became:

  1. Configure the Home Assistant Roon integration
  2. Configure Fully Kiosk control from Home Assistant
  3. Configure Node-red to drive the flow

The Roon integration in Home Assistant

This is actually really straightforward, and rather than go into any detail here, I'll simply refer to the instructions.

In our case, what this gives us is the ability to know in home assistant when our Roon endpoints are playing/paused/stopped.

The node-red integration can then use this status as a starting point to drive automations - for us, this means turning the display on when music is playing, and off otherwise.

The Fully Kiosk setup in Home Assistant

Before we can have Node-red turn our display on and off, we also need to provide a mechanism for Home Assistant to be able to do this. Node-red is simply the driver for the logic - Home Assistant actually does the work of integrating with the devices.

Remember the handy Fully Kiosk REST API that we talked about earlier?  We can make use of that here since there is a REST endpoint to control display on/off :)

Firstly, we need to enable Remote Administration in the Fully Kiosk Browser settings.  You should also set a password under 'Remote Admin Password'.  This will be used when communicating with the API, as well as if you choose to login and administer Fully Kiosk via it's remote admin interface.

Another setting worth configuring is 'Remote Admin from Local Network' to 'true'.

After a bit of command line tinkering, hitting the URL using cURL, and a bit of googling, I added the following into my 'secrets.yaml' file in Home Assistant.


fully_screen_on: "/usr/bin/curl -X POST 'http://<TABLET_IP>:2323/?cmd=screenOn&type=json&password=<admin_pass>'"
fully_screen_off: "/usr/bin/curl -X POST 'http://<TABLET_IP>:2323/?cmd=screenOff&type=json&password=<admin_pass>'"
fully_screen_state: '/usr/bin/curl --silent -X GET "http://<TABLET_IP>:2323/?password=<admin_pass>" |grep "Screen status" |grep "on\|off" |sed "s/<[^>]*>//g" |sed "s/Screen status//g" |sed "s/Turn on//g" |sed "s/Turn off//g"'

Once I had these commands ready to go, I could then create a switch within Home Assistant, which could call the appropriate REST endpoints to turn the display on or off, as well as keep the current state.

- platform: command_line
  switches:
    fully_kiosk_screen:
      command_on: !secret fully_screen_on
      command_off: !secret fully_screen_off
      command_state: !secret fully_screen_state
      value_template: '{{ value == "on" }}'
      friendly_name: Fully Kiosk Screen

With the switch in place, we're now ready to start integrating the Roon state with these commands using Node-red.

Node-red configuration

The final piece of the puzzle is creating a flow within Node-red.

Image
Node-red flow

The logic goes: "when we detect a change in the Roon state, check to see if it is playing. If it is, then turn on the display.  Otherwise, wait a configured amount of time, and then turn off the display".

In node-red, this is really easy.  We create a 'trigger: state' node. Unfortunately, the Roon integration does not present the concept of a group to Home Assistant, only individual endpoints.  However, since I will always use all of the downstairs speakers as a group, I only need to be concerned with the state of one device, since they will all be doing the same thing as part of the group.  So I selected the Sonos Amp as the main device for state.

Next up, we use a switch node.  This allows us to inspect the incoming state, and route our logic to one or more outputs based on the state.

Image
Switch configuration

The node is configured with three outputs.  The first will be routed when the state is 'playing', with the second routing on 'paused' and the third on 'stopped'.  In the main diagram, we can see that we don't actually distinguish between the second and third states, and route them in the same manner i.e. down the 'turn off display' route.

If the switch routes to the 'playing' output, then we pass control to a 'call service' node. This node will call Home Assistant in order to turn on the switch that we created above - in this case, this invokes the REST API call to the tablet in order to turn on the display. 

Image
Turn on display

So now, we have our display turning on when Roon is playing. Lovely!

Heading down the routes of 'stopped' and 'paused', we retrieve the value of a variable from within Home Assistant. You don't really need this, but I set up a variable in order to allow me to configure the wait time before the display turns off - I don't really want the display to flick on/off quickly if I only pause playback briefly.

This value is fed into a 'Variable timer' node.  As you can imagine, this does nothing until the elapsed time is up, before passing control to the next node.

We do a last check before turning the screen is off, just to check that 'Roon is not playing' - if we started playback within the timer window, we no longer wish to turn off the screen.

However, if Roon is still not playing after the timer expires, we issue a 'call service' command to the switch in Home Assistant, this time turning the switch off.

And...we're all done!  We now have a tablet that will turn on and off in accordance with the status of Roon.

I have posted a short YouTube video, apologies for production quality - I only have my mobile at my disposal!  Also, remember that the delay between music being paused/stopped is deliberate.  There's actually very little observable latency between the state change and node-red/home assistant issuing commands.

In my next post, coming soon, I will describe how I set up and configured a Raspberry Pi 4 to do similar, using a Pimoroni Hyperpixel display. 

In my next post, coming soon, I will describe how I set up and configured a Raspberry Pi 4 to do similar. 

Following that, as a little bonus, I will write a post about how I also configured Fully Kiosk to run as a digital photo frame when Roon is not playing - but only during the hours of 8am and 11pm.

I even built a crude frame (that you can see in the Youtube video), which does not bear close inspection, but looks much better than an exposed tablet when sitting on the shelf.  Anyone who knows me and my woodworking "skills" will tell you just what an achievement this was :)

Image
Roon Tablet Frame

Hope to see you then!