Roon Command Line Control

I have published a set of Bash and Python scripts I use to control Roon via the command line on Unix/Linux/Mac or anywhere Bash/Python/SSH are supported. These scripts use SSH to execute commands on a system with the Python Roon API installed (roonapi · PyPI). The Python Roon API then sends commands to the Roon Core via the Roon API. This release of the Roon Command Line tools includes a patch to the Python Roon API which enables searches of the Roon library based on substrings. Using such searches it is possible to retrieve, for example, all playlists that contain the word “Best” or all albums with titles containing the words “Greatest Hits”.

Most of this functionality can be accomplished via the Roon Remote GUI. The command line tools provided here are not intended to provide new functionality but rather to provide a useful subset of functionality accessible via the command line. So, if you are not a command line sort of person and do not spend a lot of time in terminal windows then this project may be of no interest to you. However, I find it useful since I do spend a lot of time in terminal windows and issuing a command like “roon -a Donovan” to play songs by artist “Donovan” is a lot easier than switching windows to the Roon Remote and searching for Donovan then pressing play. YMMV.

Another area in which command line control of Roon is useful is automation. Any system of automation that can utilize SSH can be used to automate Roon with these command line tools. For example, Apple Shortcuts can be configured to use SSH and execute a command on a remote system. Thus Siri or any form of automatic control can be implemented to run a Shortcut which plays an artist, album, playlist, genre, or starts/pauses/etc Roon. I don’t know Android as well but if there is an automated way to run SSH commands then something similar could be done with Android phones. The Roon Command Line project can be used for automating control of Roon via voice, shortcut execution, cron jobs, etc.

The project is new and there are plenty of areas for improvement/extension. The current release includes support for playback of albums, artists, genres, playlists, Radio Paradise, and tags with zone selection for each. In addition, commands to play|pause|stop|next|previous|shuffle|unshuffle|repeat|unrepeat|mute|unmute can be issued by zone and searches can be performed by exact match or substring.

In order to run the Roon Command Line tools, you will need some familiarity with SSH setup/configuration as Public Key authentication is used to provide SSH access. Further, the command line tools require the installation of the Python Roon API which uses pip and Python3 so a system running Python3 and pip is required. If these requirements are satisfied the installation and configuration of the Roon Command Line tools is automated to some extent.

Releases can be downloaded at https://gitlab.com/doctorfree/RoonCommandLine/-/releases

See the README at https://gitlab.com/doctorfree/RoonCommandLine for an Installation and Usage overview.

10 Likes

The links you give don’t work - on a hunch I changed gitlab to github, and found your project. :slight_smile:

Thanks Brian, the project on Gitlab was set to Private. My mirror of the project on Github is public. I changed the settings on the Repo so it is now Public on Gitlab. The links should now work ok. Let me know if you have any problem.

Thanks a bunch for this, really appreciate you taking the time to put this together.

1 Like

Thanks so much for this. When I read what you’d put together, I immediately got several ideas of things I could do with a command line controller for Roon.

Full disclosure: Although I’ve been working professionally in programming for longer than I’d like to admit, I’ve been on the Microsoft side of things, and that means I’m fairly new to Git/Bash/Python… but all is not lost. I’ve dabbled in all of the above, and you can still teach this old dog new tricks. :slight_smile:

I managed to get this cloned from GitLab and running in Windows Subsystem for Linux. The installation seemed to go as outlined in the README, but I’m not sure what I’ve done wrong because when I run list_zones, I get the output below and nothing else:

snoker@SN-THREADRIPPER:~/RoonCommandLine$ list_zones
2021-04-12 11:43:31,871 INFO roonapi – Connecting to Roon server 192.168.4.175:9100
2021-04-12 11:43:31,879 INFO roonapi – Connection with roon websockets (re)created.
2021-04-12 11:43:31,879 INFO roonapi – Confirming previous registration with Roon…
2021-04-12 11:43:31,897 INFO roonapi – Registered to Roon server SN-MUSIC

If I run any other “list” command, I get a “list index out of range error” similar to this:
Traceback (most recent call last):
File “list_artists.py”, line 47, in
output_id = [
IndexError: list index out of range

Keeping in mind that it’s more than likely a newbie mistake on my end, do you have any suggestions?

Thanks for trying this out Shawn. I have not run the Roon Command Line tools in a Windows Subsystem for Linux so it will be interesting to see if this works. I will try to help. There are a couple of areas I suspect users will initially stumble over. One is the setup for public key authentication in SSH. Did you get this setup correctly? Can you ssh from your Windows Subsystem for Linux to the system running the Python Roon API package without the need for entering credentials?

The other area that may be causing problems is the installation of the Python Roon API package and its ability to communicate with your Roon Core. To debug problems I have found it useful to SSH in to the system running the Python Roon API package and run commands by hand there. For example, rather than running the list_zones command, SSH in as the configured user, cd to the appropriate directory, and run “python list_zones.py -z YOUR_ZONE_NAME”.

Another area I expect will be problematic is the configuration settings. Some defaults are provided but these will no doubt need to be modified. There are two primary configuration files, both on the system where the Python Roon API was installed. These are the files “$HOME/.pyroonconf” and “$HOME/RoonCommandLine/roon_api.ini”. Make sure these two configuration files have valid entries. For example, in roon_api.ini verify that the DefaultZone setting is valid for your setup. By default, the DefaultZone is set to “Living Room”. If you do not have a Roon Zone named “Living Room” then this is going to cause problems. I tried to dynamically configure as best I could but really all I have done thus far is set the IP addresses and a few other variables. Setting the default artist and album and zone and so on is still left to you. If you provide me with the contents of these two configuration files I can maybe help you set them up.

I am happy to assist but I also realize this is not as easy as it should be right now. Helping you will help me to make it easier in future releases.

1 Like

I am excited to try this in my system, looking to better integrate my control system with the audio playback. Do you know if this will work with an Elac Discovery. The Elac unit is running the Roon Essentials v1.7 (it has not been updated to 1.8 yet).

Hi, sorry, no I do not know if this will work with an Elac Discovery or with v1.7. But I would be interested to find out. Let me know how it goes. I will try to help if you run into problems.

Ronald,
Thank you for the pointers. With that information I was able to get almost all of this working. I’ll summarize here what I did in order to help you or anyone who is interested do the same.

For the record, my Roon Core is a Windows Server 2019 machine, but all of the work I’ve done is on a Windows 10 20H2 (19042.867) machine, running Windows Subsystem for Linux (Ubuntu 20.04.2 LTS).

You mentioned the default settings in roon_api.ini. I had found this file before I posted the first time and I did need to change the IP address and the Default Zone. The IP address that it had grabbed and inserted in there was for a VirtualBox adapter. I would imagine that most users won’t be running VMs on their machines, so you probably don’t need to account for that.

I was oblivious to the .pyroonconf file, so the ROON_ZONE value in there was incorrect, and I changed that after you mentioned it.

At this point, I was able to follow your directions and run the python commands. For example, “python list_zones.py -z MY_ZONE” returned my zone name. This was encouraging.

From there, I set out to get the public key authentication in SSH working. I had already generated a key pair when I cloned from Git, so I Googled and found the steps that I needed. I tried

ssh-copy-id @destination-IP

but I got a “connection refused” message.

I Googled some more and discovered that the ssh service wasn’t running on the destination machine. (How silly.) I ran

sudo service ssh start

to start it.

I tried the
ssh-copy-id @destination-IP

command again, and this time I got Permimssion denied (publickey)

This time more Googling led me to the following steps. I’m not sure why this worked, or even if it’s a good security practice, but since I reverted the config change at the end, it seems safe enough to me.

sudo nano /etc/ssh/sshd_config
Change this line: PasswordAuthentication no
To PasswordAuthentication yes
Save / Exit

ssh-copy-id @my.IP

This time it succeeded.

Then I reverted my changes to sshd_config so that the line read

PasswordAuthentication no

At this point I was able to SSH in to the system running the Python Roon API package and I could run the roon commands and most of them worked for me.

For example,

  • roon -l zones lists all my active zones
  • roon -g Pop/Rock plays the genre Pop/Rock
  • roon -p “Billy Joel” plays the Billy Joel playlist
  • roon -a Blondie plays tracks by Blondie
  • roon -A Autoamerican plays the album Autoamerican
  • roon -c All of the controls work

Most of the scripts are working! The only ones that are giving me trouble are the lists. For example, I have playlists called Pete Townsend, Peter Frampton, and Peter Gabriel. If I run this command:

roon -l playlists -s Pete

I would expect it to list those three. Instead, I get this error:

Traceback (most recent call last):
File “list_playlists.py”, line 54, in
playlists = roonapi.list_media(output_id, [“Playlists”, searchterm])
AttributeError: ‘RoonApi’ object has no attribute ‘list_media’

I get the same error if I use a search string that’s an exact match for a playlist name. Similar attempts to use roon -l to lists artists or albums result in the same error on line 54.

I know this was an extremely long post that will likely interest very few, but if it helps a few folks, it was worth it.

For now, I’m off and running because my first goal is to use automation to kick off playlists, and that’s accomplished. I appreciate your help, Ronald, and I hope you find my feedback useful. I can continue to provide information if you need it.

1 Like

Excellent progress Shawn. The most glaring weakness in this project right now is the difficulty in the initial setup. I want to make it as easy as possible and your work and feedback will help with that. So, thanks!

It looks like Roon Core IP discovery did not work in your setup. Unfortunately I cannot easily debug this as I do not have a similar environment. I wish I did, i would love to play with the Windows Subsystem for Linux. Probably I would experiment with PowerShell as a command line interface but that is for another day. For now, I am going to table the Core IP discovery issue and focus on your other remaining problems.

I’ll add a “Troubleshooting” section to the README with some of what you have done and an overview of what I feel are the most likely areas to look at, like .pyroonconf and roon_api.ini. I should also add some info on how to setup public key authentication in SSH. Documenting your experience and solution will help.

Then there is the problem you are seeing with listing Roon library media. At first glance this looks like my patch to the Python Roon API module did not get applied properly. This could be due to missing commands in your environment. Do you have the patch command? I expect this is the issue. I can check for its existence and issue a warning or something if that is in fact the problem.

Or, it could be a problem with locating the Python/Pip User Base folder. I use the command ‘python -m site --user-site’ to retrieve this from Python then parse that with awk. If that doesn’t find it then I use the command:
python -c ‘import site; print(site.getsitepackages())’ | tr -d ‘[],’)
to retrieve a list of folders Python uses for site packages. If either of these commands is failing to retrieve the Python site package folder that contains the Python Roon API module, or if your Linux subsystem does not have the necessary commands then the patch will fail. The patch is applied in the discovered folder, for example $HOME/.local/lib/python3.8/site-packages/roonapi/ and creates files with a .orig suffix as backups.

I don’t want to overload you. As you have discovered, the roon command line tools still mostly work even if the list feature is not working. However, some of the other features fall back on listing if their initial search fails to find specified media. For example, partial matches on substrings will not work to play an artist or album. Try something like “roon -a Tull” which, on my system will play songs by Jethro Tull. This would not work if listing did not work. So, you are probably broken in more ways than you at first thought.

I can help you get the patch applied or supply you with an already patched Python Roon API module if necessary.

I very much appreciate your trying this out and your excellent work getting it setup in the Windows Subsystem for Linux. And your clear feedback. Good job!

1 Like

I have added the patched Python Roon API files to the Roon Command Line repository, making it possible to simply copy these files to the appropriate location rather than applying a patch. This may not help you as it may not be the case that the patch failed in your install but it may help others. I have also added a README there to provide some instructions on how to locate the Python Roon API site-packages module and where to copy these files.

See patches/roonapi · master · Ron Record / RoonCommandLine · GitLab

1 Like

First of all, you were correct that all of the listing functionality was broken for me, but you were also correct that I didn’t have the patched files. I finally got a chance to download those today, and now everything is working! Thank you so much for putting the patch files out there.

I went back through my notes, and I did consider that the patch had failed and made an attempt to apply the patch manually, which obviously failed as well. If I remember correctly (unfortunately my notes weren’t as careful as I wish they would have been), I ended up trying these commands:

$ cd $HOME/Python3 # Or wherever your Pip roonapi module is installed
$ patch -b -p0 < $HOME/src/RoonCommandLine/patches/roonapi-listmedia.patch

Clearly whatever I did was incorrect because today I grabbed your two patched files, ran this to find the correct path:

$ python -m site --user-site

which returned one of the paths you suggested was likely:

$HOME/Python3/lib/python3.8/site-packages/roonapi/

I copied the patched roonapi.py and roonapisocket.py files there and now everything is working as expected.

I took a peek at get_core_ip.py to see if I could be of any help as far as the Roon Core IP discovery goes, and I see that it’s grabbing a collection of servers (IPs, I assume) from the Roon API and looping through them until it hits one that gets the authorization response. Unfortunately I don’t have any idea how the Roon API comes up with that servers collection. I took a peek at the API as well, but that was well over my head.

In any case, the PC I tried this on is probably an edge case with 4 enabled ethernet adapters (two are virtual). The one that discovery tried to use was a virtual one. I would guess that the discovery works for most use cases. In fact, when I get a chance, I’ll try all of this on a more typical laptop.

Thanks again for all of your help.

1 Like

See Roon Command Line Control version 2 for announcement of a new release of RoonCommandLine which includes support for Debian and RPM format installation, automated Mac OS X installation, and greatly improved automated installation and configuration.

Just saw this. I’m the current maintainer of the Python roon library.

Your description of the discovery process is pretty accurate. The library sends a discovery packet, and then looks through the responses looking for a core that gets authorised. Strangely some roon controller clients respond to the discovery packet - so even a network with a single core will get multiple responses.

I can imagine that the code doesn’t work well in a complex network environment.

It is possible to directly specify the IP address of the roon core to the Python library if needed, although I don’t know if the library would communicate via the correct Ethernet port even them!

Seems like a nice extension. Unfortunatly it does not install on a Raspberry Pi running Raspbian

@Ron_Witkamp can you provide any details of your RoonCommandLine installation failure on Raspbian? I can install without error on a Raspberry Pi running Raspbian Bullseye. I have received no other reports of installation failures on a Raspberry Pi.

If you can get me any additional info I may be able to assist you, either here or open an issue at Issues · Ron Record / RoonCommandLine · GitLab

Are you using the latest Debian installation package for RoonCommandLine at RoonCommandLine Version 2.0.3 release 2 · Ron Record / RoonCommandLine · GitLab ?

Thanks for reporting this problem. I hope we can get it resolved quickly and easily.

1 Like

@Ronald_Record I’m running Raspbian Buster on a Raspberry Pi 3B. This is a Raspberry running my Domoticz home-automation software.

I’m running into these errors:

pi@domoticz:~ $ sudo apt install ./RoonCommandLine_2.0.2-3.deb
Reading package lists… Error!
E: Sub-process Popen returned an error code (2)
E: Encountered a section with no Package: header
E: Problem with MergeList /home/pi/RoonCommandLine_2.0.2-3.deb
E: The package lists or status file could not be parsed or opened.
pi@domoticz:~ $

and with dpkg:

pi@domoticz:~ $ sudo dpkg -i ./RoonCommandLine_2.0.2-3.deb
dpkg-deb: error: ‘./RoonCommandLine_2.0.2-3.deb’ is not a Debian format archive
dpkg: error processing archive ./RoonCommandLine_2.0.2-3.deb (–install):
dpkg-deb --control subprocess returned error exit status 2
Errors were encountered while processing:
./RoonCommandLine_2.0.2-3.deb
pi@domoticz:~ $

Same errors after upgrading to Bullseye

I’m afraid the problem was on my side, sorry! Something went wrong with downloading the .deb file. I’ve got it working now!

1 Like

@Ron_Witkamp good to hear. Let me know how it goes, if you encounter problems with RoonCommandLine in your setup, what additional features you might like, or if you have any suggestions/comments. One of the principle goals of RoonCommandLine was to enable integration of Roon with home automation. I would be interested to hear of any progress you might make in this area.