Continuing the discussion from Roku Binding Request:
Awhile back someone requested the creation of a Roku binding and my response was that Roku has a simple REST API and the HTTP binding would work. I shall post here an example of what I did to solve a little problem I had.
#Problem
At night my wife likes to go to sleep with the TV on so we put the Roku on some show and let it run all night. The TV has a timer we set to go off after an hour. But even though the TV is odd, the Roku keeps playing all night. I need a way to stop the Roku from playing all night once the TV is off.
Eventually I will create a simple sensor (probably sound) that will trigger the below when the room goes silent at night but for now I’ll just stop the Roku playing at 2 AM by sending it to the home screen.
#Finding Roku IPs
The Rokus get their IP address via DHCP so you cannot always guarantee they get the same IP every time unless you configure it to on the router. Luckily for us the Roku uses SSDP so we can discover their IPs. The following Python script uses SSDP to discover and print the serial number and URL of each Roku on your network.
#!/usr/bin/python
import sys
import socket
import re
ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \
"HOST: 239.255.255.250:1900\r\n" + \
"Man: \"ssdp:discover\"\r\n" + \
"MX: 5\r\n" + \
"ST: roku:ecp\r\n\r\n";
socket.setdefaulttimeout(10)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
sock.sendto(ssdpRequest, ("239.255.255.250", 1900))
while True:
try:
resp = sock.recv(1024)
#print(resp)
#print("Matches")
matchObj = re.match(r'.*USN: uuid:roku:ecp:([\w\d]{12}).*LOCATION: (http://.*/).*', resp, re.S)
print (matchObj.group(1) + " " + matchObj.group(2))
except socket.timeout:
break
#Items
String BedroomRokuAddress "Bedroom Roku [%s]"
String DenRokuAddress "Den Roku [%s]"
Switch RefreshRokuAddresses // used for testing
Switch S_C_BedroomRokuHome "Go Home on Bedroom Roku"
#Rules
/*
* Roku REST API (see https://sdkdocs.roku.com/display/sdkdocs/External+Control+Guide#ExternalControlGuide-3.7DIAL(DiscoveryandLaunch):
* - query/apps: Returns a map of all channels installed on the Roku box along with their app id (needed for other commands)
* - keydown/<key> : send a key down command. Supported keys include: Home, Rev, Fwd, Play, Select, Left, Right, Down, Up,
* Back, InstantReplay, Info, Backspace, Search, Enter, (Roku TVs: VolumeDown, VolumeMute, VolumeUp)
* - keyup/<key> : send the key up command
* - keypress/<key> : the same as a keydown/<key> followed by a keyup/<key>
* - launch/<app id> : launch the given channel
* - install/<app id> : closes the current channel and opens the channel store to the passed in app's page
* - query/device-info : get system info, useful to match up serial numbers to IP address
* - query/icon/<app id> : returns the png icon of the passed in app
* - input : allows custom input to apps hat support it
*
* NOTE: there is no way to determine what channel is currently running
*/
rule "Get Roku Addresses"
when
Time cron "0 0 0/1 ? * *" or
Item RefreshRokuAddresses received command
then
logInfo("Roku", "Refreshing Roku Addresses")
var String results = executeCommandLine("chmod a+x /etc/openhab/configurations/scripts/searchRokus.py", 5000)
logInfo("Roku", "chmod results: " + results)
results = executeCommandLine("/etc/openhab/configurations/scripts/searchRokus.py", 20000)
logInfo("Roku", "searchRoku.py results:\n" + results)
val rokuAddrs = results.split("\n")
rokuAddrs.forEach[addr |
val s = addr.split(" ")
switch (s.get(0)) {
case "1RE3CD071416" : BedroomRokuAddress.postUpdate(s.get(1))
case "1RE3CN071402" : DenRokuAddress.postUpdate(s.get(1))
default : logInfo("Roku", s.get(0) + " is an unknown Roku")
}
]
end
rule "Go Home on Home Roku after bed"
when
Time cron "0 0 2 ? * *" // 2 am
then
logInfo("Roku", "Sending Bedroom Roku to Home")
sendHttpGetRequest(BedroomRokuAddress+"keypress/Home")
end
If you set a static IP for your Rokus or don’t mind periodically changing your OH files when the IPs change you can skip the script and the rules and just hard code the URL for the Roku and use the HTTP binding instead of rules and the HTTP actions.
NOTE: This is moderately tested, there may be some errors above.