I want to write a roku function that will find a device on my LAN. It’s a RaspberryPi, which interestingly has the same first-half of the MAC address as all other pi’s -B8:27:EB.
I haven’t worked with these parts of the SDK, so I’m looking for a basic description of the components needed to do that. Thanks.
I think you’ll need to know its IP address.
Bummer. How does a media player find a server? The pi is setup as a webserver. The Roku is set up to enter the I.P. manually now. Sure would be nice…
If you install some kind of UPnP software on the Pi that can respond to SSDP M-SEARCH requests, then I can post some code I have that discovers the IP addresses of other Rokus on the network that can easily be adapted to find your Pi(s) on the network.
Thank you. I’ll look into making that happen and get back. Pi-world is pretty big, there must be something out there.
even easier - tell your router to always give the same IP to that MAC address, a feature often called “DHCP reservations”
“EnTerr” wrote:
even easier - tell your router to always give the same IP to that MAC address, a feature often called “DHCP reservations”
Yes, well I do that at home, I want to make it more portable.
“squirreltown” wrote:
I want to write a roku function that will find a device on my LAN. It’s a RaspberryPi, which interestingly has the same first-half of the MAC address as all other pi’s -B8:27:EB.
This will let you know why https://en.wikipedia.org/wiki/MAC_addre … ss_details
Don’t think you can use it though, there is no B/S API to query ARP cache.
“squirreltown” wrote:
Yes, well I do that at home, I want to make it more portable.
What’s the reason to want to know RasPi’s IP from a Roku - are there particular services running on it?
If so, you might be able to discover that in a hacky way - say if there is web server, you can have some code that scans the network for your guy on port 80, knowing what to expect there.
As was inevitable, I’ve built a thing that is too complex, uses too much bandwidth, and is too artsy to be a screensaver so I’ve decided it’s an installation. The Pi is a web server, holds all the files and does Imagemagick processing. So anything I can do to make it slicker while demonstrating it seems worth the effort. I think I will try @belltown 's way first, but what you describe sounds like second choice for sure, If I get there I’ll ask again about how I might go about that.
Thanks both of you for answering, I appreciate it.
Awesome, thank you.
“squirreltown” wrote:
As was inevitable, I’ve built a thing that is too complex, uses too much bandwidth, and is too artsy to be a screensaver so I’ve decided it’s an installation. The Pi is a web server, holds all the files and does Imagemagick processing. So anything I can do to make it slicker while demonstrating it seems worth the effort. I think I will try @belltown 's way first, but what you describe sounds like second choice for sure, If I get there I’ll ask again about how I might go about that.
I see… well here is a 3rd option- you can have RaspberryPi discover your Roku via SSDP (a few lines in Python, say) and then notify your channel about its own IP address via ECP /launch or /input. That way you won’t have to find and implement UPnP server on R-Pi, something which (put understatedly) is an overkill
Ok, so I made it work this way. Python file on Pi is setup as a looping service, sends the Pi i.p. to any roku device via ECP/input. The only issue is that the Python socket function that actually finds the roku ip seems to randomly find the boxes. i have 4 rokus, and it will find all of them within a few seconds, but it’s random, if I had a large network it would be an issue. I’m going to try the more complex way but this looked like fruit i could reach.
Would something like this combined with belltown’s code be useful? I was going to go through the Python code I have (fauxmo) that allows Alexa (Amazon Echo) to discover my Dockstar to see how it works, but then I stumbled upon that code. I haven’t tried it, but seems like it should work for SSDP discovery.
-JT
“renojim” wrote:
Would something like this combined with belltown’s code be useful? I was going to go through the Python code I have (fauxmo) that allows Alexa (Amazon Echo) to discover my Dockstar to see how it works, but then I stumbled upon that code. I haven’t tried it, but seems like it should work for SSDP discovery.-JT
Hey thanks, that looks interesting too. I’m just learning python, and obviously the great thing about non-Brightscript languages is you can find enough examples in the wild to cobble together whatever you are trying to build.
Deploying yet another UPnP server so that one box can find another? We are so wielding a microscope to hammer a nail here.
“squirreltown” wrote:
The only issue is that the Python socket function that actually finds the roku ip seems to randomly find the boxes.
Hmm, how exactly does this fn “actually find” the Roku IPs? I vaguely suspect something barbaric going on :twisted:
EnTerr:Hmm, how exactly does this fn “actually find” the Roku IPs? I vaguely suspect something barbaric going on :twisted:
Since you are going to read this, mind telling me why it doesn’t work with python3? ![]()
import requests
import curses
import socket
import string
import urllib
DISCOVER_GROUP = ('239.255.255.250', 1900)
DISCOVER_MESSAGE = '''\
M-SEARCH * HTTP/1.1\r\n\
Host: %s:%s\r\n\
Man: "ssdp:discover"\r\n\
ST: roku:ecp\r\n\r\n\
''' % DISCOVER_GROUP
def find_roku():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(DISCOVER_MESSAGE, DISCOVER_GROUP)
data = s.recv(1024)
s.close()
return data
def get_ip_address():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
return s.getsockname()[0]
def keypress(url, key):
request_url = url + key
requests.post(request_url)
class HTTPResponse(object):
def __init__(self, response_text):
response = response_text.split('\r\n')
status_line = response[0].split()
self.http_version = status_line[0]
self.status_code = status_line[1]
self.status = status_line[2]
self.headers = {}
for line in response[1:]:
line = line.split()
if len(line) == 2:
header_name = line[0][:-1]
header_value = line[1]
self.headers[header_name.lower()] = header_value.lower()
def main():
value = get_ip_address()
print ('Searching for a Roku device...')
while True:
response_text = find_roku()
response = HTTPResponse(response_text)
url=response.headers['location']
print ('Found Roku@'+url[7:-6])
send = 'input?ip='+value
keypress(url, send)
if __name__ == '__main__':
main()
“squirreltown” wrote:
...Since you are going to read this, mind telling me why it doesn’t work with python3?
Not bad actually, where did you get the code?
Re Python 3 - no clue, i haven’t moved to Py3k and just go with what comes in OSX (2.7). Generally code is compatible with minor tweaks though (e.g. py2 “print foo” → py3 add parentheses “print(foo)”)
For posterity here is something i whipped today being presumptuous you did not have the SSDP discovery code:
#!/usr/bin/python
def get_ecp_urls():
import socket, re
from time import time
# send a SSDP M-SEARCH looking for a Roku
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
MCAST_GRP = '239.255.255.250' # local network ssdp multicast address
qry = 'M-SEARCH * HTTP/1.1|HOST: %s:1900|MAN: "ssdp:discover"|ST: roku:ecp||' % MCAST_GRP
qry = qry.replace('|','\r\n')
sock.sendto(qry, (MCAST_GRP, 1900))
rokus = set()
sock.settimeout(0.1)
clk = time()
while time() < clk + 1: # wait for a whopping second to hear back
try:
dat, ip = sock.recvfrom(1024)
rokus.update(re.findall('\r\nLOCATION:\s*(.*)\r\n', dat, re.I))
except socket.timeout: pass
except socket.error, err: print "SSDP ERROR:", err
return sorted(rokus)
# demo run
print(get_ecp_urls())
“EnTerr” wrote:
Not bad actually, where did you get the code?
One example for the network stuff, another for grabbing the local ip and I re-wrote main(). The roku returns it’s serial # in the response.headers so it’s easy to keep track that way if needed.
Note that since IP (and thus UDP, thus HTTPU, thus SSDP) is by definition a best-effort delivery protocol, sometimes you won’t hear back from one Roku or another. It’s a fact of life.
In the code i wrote that will result in that Roku IP not showing in the list of results (i wait 1000ms to collect all responses). The drop rate is not particularly high - e.g. on my home WiFi is <10% with 3 Rokus:
n_fails = 0
for i in range(1, 100):
rokus = get_ecp_urls()
n_fails += 3 - len(rokus)
print i, 'runs,', 100 * n_fails // (3*i), '% failure rate'
$ python oo.py
1 runs, 0 % failure rate
2 runs, 0 % failure rate
3 runs, 0 % failure rate
4 runs, 0 % failure rate
5 runs, 13 % failure rate
6 runs, 22 % failure rate
7 runs, 19 % failure rate
8 runs, 16 % failure rate
9 runs, 14 % failure rate
10 runs, 13 % failure rate
11 runs, 12 % failure rate
12 runs, 11 % failure rate
13 runs, 10 % failure rate
14 runs, 9 % failure rate
15 runs, 8 % failure rate
16 runs, 8 % failure rate
17 runs, 9 % failure rate
18 runs, 9 % failure rate
...
However, since the code you used waits forever for a response, in some cases (e.g. no Roku or lost reply) it will never return, just “hanging” there. Plus, since it waits for the 1st response only and ignores the rest - we end up with a race fondition and you may never hear from some slower Roku on WiFi since a faster, wired one will preempt it. Yes, network programming is hairy…
