Roon extension - http APIs

So I did a brand new Roon install on another box and worked like a charm… My home install keeps crashing after the update.

@Tech_Whisky_Lab

Stop the extension and remove the config.json file from the directory that you cloned this repo into. Then start the extension and use a Roon client to enable the extension.

That file is automatically generated when you pair the extension to a core server. It may have gotten messed up somehow.

(As a side note - you really should not be running Node.JS as “root”. It runs perfectly fine as a standard user and that is much safer.)

I caught that one after reading a bit about nodejs and services.
That did it. Thanks.

@Mike_Plugge and @St0g1e code together would make a killer Roon-Web :blush:

To be fair - my project would not have happened without @St0g1e. I learned more about the API from his code than from anything else.

1 Like

I was just giving this a look and wanted to try it out. I was looking into the APIs and this as a faster way to control Roon because the iOS app takes too long to start & connect.

I wrote a quick Dockerfile to make it easier to test and run this and just submitted a PR with it :slight_smile:

Hi @Tech_Whisky_Lab and @Mike_Plugge

I created the projects to test the APIs and later the web socket functionalities.
The Player and browser are just an examples on how to connect to the controllers.

I have zero knowledge on UI stuff and to be honest, the one we have on the project was created by @crieke (I hope I have not forgotten to thank you for this). Thank you for helping, Christopher.

Mike, I really like your professional looking UI and glad that others are using it.

I’ll keep finding a way on how to add functionalities with the available APIs and hopefully Mike or others can add more good looking clients to their project.

Bastian

1 Like

Hi @Patrick_Lang,

Thank you for the PR. I see that it does not conflict with my code and will merge shortly.

bastian

Thanks @St0g1e!

You are really good at figuring out the Roon API and I have learned more from your code than anything else. So I hope you keep playing!

@St0g1e, many thanks for the example code.

I have it working and I am trying to add a new API call to put an output into standby. I have added the following to your example as follows:

— roonAPI.js —

exports.standby = function(req, res) {
core.services.RoonApiTransport.standby(zones[req.query[‘output’]], {});

res.send({
“status”: “success”
})
};

— routes.js —
app.get(’/roonAPI/standby’, apis.standby);

— call made to http server —
http://localhost:3001/roonAPI/standby?output=1701ed7165c2cb977ddeb8f537f3ed49cdca

Did I miss something?

Many thanks again!

Hi @cg321,

I think you are working off of the https://github.com/st0g1e/roon-extension-http-api (http extension).

If you are, You also need to update the routes.js to have call recognized.

I was looking at roon’s Lab transport extension and they also have toggle_standby to get the output out of standby mode.

May I know what the standby is used for?

You can create a pull request or I can also add these functionalities if you want to.

Thanks for looking at the code,
Bastian

Hi @St0g1e, yeah I updated the routes.js as well:

— routes.js —
app.get(’/roonAPI/standby’, apis.standby);

I am guessing standby allows an output (my DAC) to be put in standby mode. I want to be able to turn it off as part of my home theatre scripts.

Chris

Hi @ben and @danny,

I have a quick question on the transport apis, for the following:

  • get_zones, and
  • get_outputs

I always get empty list when invoking these APIs.

Here are my call:

exports.listZones = function(req, res) {
res.send({
“zones”: core.services.RoonApiTransport.get_zones()
})
};

exports.listOutputs = function(req, res) {
res.send({
“outputs”: core.services.RoonApiTransport.get_outputs()
})
};

I was helping Chris (@cg321) where he wants to set an output to standby. And looking at the transport apis, this information can only be found from the Output list.

Please let me know if i’m doing anything wrong.

thank you,
bastian

Neither of those functions actually returns a value. They expect to take a callback argument that will be called with the result of the API called when it finally returns. In general everything in the JS Roon API library works this way, because we don’t want anything to be blocking on messages sent over the network.

I would try something like this:

exports.listZones = function(req, res) {
    core.services.RoonApiTransport.get_zones((iserror, body) => {
        if (!iserror) {
            res.send({
                “zones”: body.zones
            })
        }
    })
};

exports.listOutputs = function(req, res) {
    core.services.RoonApiTransport.get_outputs((iserror, body) => {
        if (!iserror) {
            res.send({
                “outputs”: body.outputs
            })
        }
    })
};

You could probably get away with res.send(body), because the names you’re using for the zones/outputs properties happen to be the same as the ones in the body objects returned by the Roon API library.

I also don’t know what you want to do in case of an error, I would recommend at least some sort of logging but don’t know enough about your app to say what that might look like.

I believe we also use that (iserror, body) pattern everywhere in the JS library, so I’d keep that in mind too.

Hopefully this helps, let me know if you have any other questions.

Hi @ben,

Thank you very much for your reply.

However, after I tried your method, both apis returns:

  • InvalidRequest for iserror, and
  • the body is undefined.

I’m writing some apis to be called by http and have not implemented error catching yet.
The rest of the code is in: https://github.com/st0g1e/roon-extension-http-api

Thank you,
Bastian

This turns out to be a bug in the Roon API code. I’ve pushed a fix internally, which will be out with our next stable build, whenever that is.

You could probably work around the bug by modifying our Javascript API to send an empty (or not empty) JSON body with the get_outputs/get_zones requests, but I’d rather just wait for the next Roon build.

Also, the way your extension works now, by getting a subscription to the zones and having a local copy that is sent when someone asks, is what we recommend in general. You can also get a complete list of outputs by looking at the zones list, so I would implement your list outputs endpoint that way also.

Hi Ben,

Thank you for your update.

I’m helping Chris (@cg321) to add standby and toggle standby apis.
However, I can’t get the source_control information on the output. Is there anything I should do to have these information show when calling get_zones?

May I know the reason why having a local copy is better than calling the get_zones when we need it? This way, we are maintaining 2 copies of the zone list, and it gets updates constantly when a track is playing In at least one of the zone. My guess would be because the call is expensive, is it correct?

Regards,
Bastian

The answer here is that the source_controls field on the output objects is only for “external” source controls implemented in the API. It just doesn’t appear if there are no external source controls, so I think that is why you aren’t seeing it. You can omit the control_key from the standby/toggle/convenience switch API calls, that’ll make them apply to every control associated with the output.

I was thinking of the fact that the call requires an extra network round trip, but I guess in practice most of the time that’s very quick. I think in your position I would probably wait for the next stable build to fix the get_zones/get_outputs calls and then switch to those.

Hi Ben,

Thank you for your explanation.
I think for the http implementation I will call the get_zones directly but keep local list for the websocket repository.

Bastian

Hi,

I made some mods to the HTTPAPI (htmls and js) to have a now playing screen on my tv that is connected to the Roon player (Raspberry pi/hifiberry digi connected to Devialet) it does not contain the start/stop/next/etc button, because they are not used on the tv. It just needs to give info on now playing.
it looks like

So what are my questions.

  • the cover image is not of the best quality, even if i have high quality images in the library, and i am picking up the high quality image in the js (zone.now_playing.image_key) is this due to the “television factor” which is a 4K tele.

  • i am moving from jRiver to Roon, and what i would love to do in my screen is split out the credits (which i had in my jRiver Database as well) by person on the screen, so not as shown in the images with slashes but each credit on a seperate line.

  • is there any way to get more of the database info into the api ?

thanks for the help

Raf