[Release] Roku Connect integration App and Roku TV Device Handler

I was typing in a brydge keyboard for my iPad Pro. A $250 piece of junk. It does that a lot. I should have gone upstairs and did this on a computer. Thanks for the info. I will fix it.

[update] I corrected the typo, and did a code review. I saw I had a bad piece of logic that I also fixed that dealt with parsing current power state of the switch. Thanks for the input. I really like this better.

This is awesome, thanks!
I'm just getting started with this and HE, so as I try to do more complex things with it, I will be back with questions :slight_smile:

I do have a question about state management and events though - currently my Roku TV will quit Plex and YouTube if it's been sitting idle long enough. Is that an event we can listen for, or poll for "idle time"?
I like the functionality of it but want to do more subtle controls like dimming lights and other visual cues that it's about to time out.

There are no events with the Roku devices. I use a redress polling feature to read the data made available in the query device state function. Different Roku devices may have different values or in the returned state. As far as I can tell, there is no idle timer to query.

Thanks. I figured that was probably the case - but hope springs eternal :slight_smile:

I guess the best way to do that would be to create my own RM rule that acts just faster than the Roku TV timeout.
Related: is there a no-op / keepalive signal option? Or if I wanted to override the TV's timeout, would I have to send a volume +1/-1 sequence?

The volume hack may be the only solution, if it even works...

1 Like

Is it possible through this integration to see if a streaming service has been paused? I’m trying to see if i can implement the ability to brighten lights when (for example) netflix is paused…

Hmmm.... not as it is now. But I can look to see if there is anything that I can see that tells me if the show is paused. I suspect the answer is no, since play/pause is just a toggle button, not a state on the TV, implemented by each app. But who knows... I will take a look. I the idea here. Turn on the lights when paused, then resume play when not paused.
But, what you can do is pause via HE through something like Alexa. To do this, create a child button for pause. Then create a rule that says when paused is pushed, turn on the lights. And when pushed again, turn the lights off. This could have sync issues, since there is no state for play pause, but it’s a start. Then using Alexa, you can create a routing “Alexa, pause theatre room TV” with the action of turning on the pause device. The child app sees the switch turn on, and send the command for the pause button, while the rule triggers to toggle the lights.

2 Likes

Or any other button controller whose events are detected by Hubitat. For example, if you have a Lutron Pro bridge, it is easy to detect a Pico remote to play/pause/vol+/vol-/mute.

Yes! It is possible. I will update my driver. The API call is:

http://x.x.x.x:8060/query/media-player

The result of which appears like:

<player error="false" state="play">
<plugin bandwidth="64181864 bps" id="61322" name="HBO Max"/>
<format audio="eac3" captions="ttml" container="dash" drm="Widevine" video="hevc_b"/>
<buffering current="1000" max="1000" target="0"/>
<new_stream speed="128000 bps"/>
<position>1729347 ms</position>
<duration>3622336 ms</duration>
<is_live>false</is_live>
<stream_segment bitrate="259000" height="0" media_sequence="431" segment_type="audio" time="1724000" width="0"/>
</player>

I was looking at this in the past for other information, but the results varied greatly by application. I think state is rather common though, as even when no app is open, state appears.
When Paused,

<player error="false" state="pause">
<plugin bandwidth="40486463 bps" id="61322" name="HBO Max"/>
<format audio="eac3" captions="ttml" container="dash" drm="Widevine" video="hevc_b"/>
<buffering current="1000" max="1000" target="0"/>
<new_stream speed="128000 bps"/>
<position>1933298 ms</position>
<duration>3622336 ms</duration>
<is_live>false</is_live>
<stream_segment bitrate="259000" height="0" media_sequence="482" segment_type="audio" time="1928000" width="0"/>
</player>

And when the app is closed, so the home screen is visible,

<player error="false" state="close"/>

So, I will add states, Play, Pause, and Close (probably try to map it to some other value)

1 Like

done. this seems to work pretty solidly for me. give it a try and let me know.

Play/Pause/Stop commands are added. As well as the standard "transportStatus" attribute.

Play button will send the play key, if the current transportStatus is not already "playing"
Pause button will send the play key, if the current transportStatus is not already "paused"
Stop button will send the back key, if the current transportStatus is not already "stopped"

The system must perform a refresh to detect the current state, and that does happen automatically after any keypress, as well as on a schedule of your defined setting for refresh interval.

When the media-player in Roku reports play, then the TV transportStatus will be playing
When the media-player in Roku reports pause, then the TV transportStatus will be paused
otherwise, the transportStatus will be stopped

1 Like

Thank you for sharing this API call. It works really well to detect play/pause. In my Node-RED integration, I poll the TV for this endpoint every 0.5s while it is on (and not at all when it off). And, thanks to you, detection of pause/play works really well as triggers for automation!

Awesome - I will try this, this evening! Thank you!

Happy to share and help out. I do plan to refine the logic in my code, to reduce refreshes, and improve predictive refresh events.For Hubitat, the xml slurper seems to impact performance if used too much, so I try to limit the heavy html response parsing. I did some of these optimizations on my hue driver and plan to do that here next.

1 Like

So, my use case is that when pause is pressed on the remote (i’m using a harmony remote), I want to activate a scene .. am I right in thinking that to achieve this I’d need to increase the refresh rate to a few seconds so that the polling interval is increased and I can then build a rule around the custom attribute that holds the state? If I increase to say 5 seconds, have you seen any issues in terms of hub performance with this?

At the moment i need to hit the poll button or refresh to trigger an update to transportStatus…

Won't be the first time I have borrowed from your code! Thank you again!!

Yes. Unfortunately, the Roku TVs do not have event notification features. This means that the only way I can determine that something has changed is to query for it. This particular version was a quick hack to get the feature out to you. My next release will move the media refresh to its own refresh cycle and it will only trigger on that cycle when an app is loaded. This means that if you are on the main screen of the Roku, the app refresh which is very light weight can run every 15 seconds. And the media state refresh can be set to something like every five seconds. Doing this, by the time you launch an application and it is usable the Roku device will have detected the app is in the media player state and the media state quarry will now be more aggressive without the adding extra burden of parsing the TV state as a whole. If my schedule works out for meI would like to have this update pushed out tonight.

1 Like

Thanks for the awesome work on this, greatly appreciated!

My update failed with HPM, It failed on the Roku TV driver. I tried to manually install it and when trying to save it failed on line 83, capability MediaTransport? FYI.

Thanks for the driver/app!

So I’ve been playing with the integration and have it triggering a scene when the status is changed to paused or stopped - awesome stuff!

Would you mind explaining the difference between the two refresh values? Which do I need just to refresh the status?

Could I also make a suggestion: the ability to increase the refresh rate based on a switch being toggled. I’d imagine my use case wouldn’t necessarily be too unique and triggering actions based on the status is something that would be valuable to those using the app. Although increasing the refresh rate makes me nervous having experienced issues with apps that are too chatty. Having the ability to increase the refresh time value based on a switch being toggled would mean that this could be increased when its more time critical e.g, in my case I have my movie scene activated but decreases back to something less frequent when its less time critical. This way there is less activity from the app when its not really needed…

Thanks!

Soon there will be three.
First refresh, described as, "Refresh the status at least every [...]" is the full device refresh. It will call the following operations:

query/device-info
Return XML data consisting of all the device information for the Roku. This is the most intensive operation, and the only operation used to determine if the TV is on or off.
(truncated sample)

query/media-player
Returns data about the media player. This is used to determine play, pause, stop state. This can also provide current position in the stream, the size of the stream (in milliseconds), and various codec details. The response if rather light weight.

query/active-app
Returns a very lightweight response of just the currently running app. When the TV is off, the current app returns to Roku (The name of the home-screen app)

query/apps
Return XML of all the installed apps. This is used to know what apps are available for installing as a child app, and what the app ID numbers are to active that app.

Second Refresh, described as, "Refresh the current application at least [...]" is for determine what the current app is, and does nothing else. This calls the function
query/active-app which as shown above is rather light weight. I set my main refresh to every 30 seconds, and my app refresh to every 5 seconds.

You can always ask, but in this case, I cannot deliver. It would run counter to the design goals. Device drivers should be simple. Any integration type logic should appear within the rules, not the device driver. Failure to keep things simple and focus strictly on control logic, results in overly complex and less adaptable solutions.

To solve achieve what you want, just create a rule in Rule Machine that calls refresh every 2 seconds, if the TV is in a Media Player state, like this:

After my next update, I will expose each of the refresh methods as commands, so you can call just the refresh for the media player. For now, this will work, and it should not be too taxing, since it will only enforce the aggressive refresh during media playback. But in addition, I will have logic for the 3rd (media player) refresh that when enabled as a separate refresh, allows the media player to refresh on its own schedule. And the refresh will only take place if the app is already active.

Thank you for bringing this up, as it exposed some more limitations in the driver that need updating.