Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
EnTerr
Level 9

Re: FInd box on LAN

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...
0 Kudos
squirreltown
Level 9

Re: FInd box on LAN

Yes, it is not the most efficient  - it works by attrition. Typical run, find roku# -   2,2,1,2,3,1,3,4.  So, it finds them eventually, because it's looping . No clue why it picks one or the other in the first place - perhaps the most recent roku broadcast? 
It's only been a day but no hiccups so far with 4 rokus.
Kinetics Screensavers
0 Kudos
EnTerr
Level 9

Re: FInd box on LAN

"squirreltown" wrote:
Yes, it is not the most efficient  - it works by attrition. Typical run, find roku# -   2,2,1,2,3,1,3,4.  So, it finds them eventually, because it's looping . No clue why it picks one or the other in the first place - perhaps the most recent roku broadcast? 
It's only been a day but no hiccups so far with 4 rokus.

Ah... when there are 4 players listening, the likelihood of all 4 datagrams being lost is very low. Say if probability of loss is 5%, then for a "quadruple whammy" to happen it will take upwards of 100,000 calls.

But allow me to demonstrate - unplug all but 1 Rokus and try running in a loop again, it should hiccup within 100 tries.
Or unplug all Rokus and it should hiccup on the 1st try Smiley Happy
0 Kudos
EnTerr
Level 9

Re: FInd box on LAN

"squirreltown" wrote:
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...

This will be the simplest option, i think. Here, i wrote you this:

function discover_my_server_ip() as String:
port = createObject("roMessagePort")
for each hash in createObject("roDeviceInfo").getIpAddrs().items():
octets = hash.value.split(".")
xfers = { }
for i = 1 to 254:
octets[3] = i.toStr()
url = "http://" + octets.join(".") + "/path/unique/to/squirreltown"
req = createObject("roUrlTransfer")
xfers[req.getIdentity().toStr()] = req
req.setUrl(url)
req.setMessagePort(port)
req.asyncHead()
next
while not xfers.isEmpty():
msg = port.waitMessage(0)
if type(msg) = "roUrlEvent":
if msg.getResponseCode() = 200 then return msg.GetTargetIpAddress()
xfers.delete(msg.GetSourceIdentity().toStr())
end if
end while
next
return ""
end function

Change "/path/unique/to/squirreltown" to some URL that's unique to your server and try it out. If the server is on the network, it finds it almost instantly. If not, it may take a while until all probes fail.
0 Kudos
squirreltown
Level 9

Re: FInd box on LAN

@belltown  @EnTerr
I've taken EnTerr's ECP solution and made it into a nice system where you send it some text and flies it across the Roku screen. 
As for finding the Pi from the Roku,  I now have a python file on the Pi broadcasting a UDP message every second. - "piip:<ipaddress>". An SDK socket function on the Roku receives this fine.
So i've solved the problem two ways, and am still going for the third.
I'm still not able to see the Pi with belltown's UPnP code. I've changed 
"ST: roku:ecp"  to "ST:ssdp:all"

And it finds all my Rokus, 2 NAS and DSL modem. I've noticed that if take the Pi python file and send an "M-SEARCH" formated message instead of my own, Wireshark will list the protocol as SSDP instead of UDP, but belltown's code still won't see it. I'm wondering what it is  I'm not sending. Why can't my Pi be a grown-up box?
Kinetics Screensavers
0 Kudos
belltown
Level 7

Re: FInd box on LAN

What is the Pi sending, and how is it sending it, in order to respond to an M-SEARCH request that your Roku sends?
https://github.com/belltown/
0 Kudos
belltown
Level 7

Re: FInd box on LAN

Here's a little Python 3 program that you can run on your Pi to respond to M-SEARCH requests from a Roku. As it's written right now, it impersonates a Roku device, but you can change the "ST" field to something else, and make sure the Roku code searches for the same value.

import socket
import struct

MSEARCH_RESPONSE = ('HTTP/1.1 200 OK\r\n'
                   'Cache-Control: max-age=3600\r\n'
                   'ST: roku:ecp\r\n'
                   'USN: uuid:roku:ecp:H0A0AP999999\r\n'
                   'Ext:\r\n'
                   'Server: Roku UPnP/1.0 MiniUPnPd/1.4\r\n'
                   'Location: http://{ipAddr}:8060/\r\n'
                   '\r\n')

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', 1900))
addMembershipData = struct.pack('4sl', socket.inet_aton('239.255.255.250'), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, addMembershipData)

while True:
   data, addr = sock.recvfrom(4096)
   if data.startswith(b'M-SEARCH'):
       response = str.encode(MSEARCH_RESPONSE.format(ipAddr=addr[0]))
       sock.sendto(response, addr)
https://github.com/belltown/
0 Kudos
EnTerr
Level 9

Re: FInd box on LAN

I have only one question and that is "why?"
Above I gave code that will instantly find the normal web server, does not need extra service to run and does not rely on multicast (support for which is wonky in many home routers). Why do we keep beating the SSDP horse?
0 Kudos
belltown
Level 7

Re: FInd box on LAN

It's just another way to beat a dead horse, or skin a dead cat.

I've done it both ways (subnet scan and SSDP). Granted, SSDP, being connectionless, is flaky, so when doing an SSDP discovery, I'll usually send out several M-SEARCH requests. At least one will almost always succeed.

One issue with your subnet scan method is that it assumes your local network is configured to use a 24-bit subnet id (8-bit host id). That may be common for most home networks, but it's by no means guaranteed. Ideally, you'd have to figure out the subnet mask somehow and use that determine how many possible hosts to scan. That's a lot more network traffic if you've configured a 16-bit subnet id for, example.
https://github.com/belltown/
0 Kudos
EnTerr
Level 9

Re: FInd box on LAN

"belltown" wrote:
One issue with your subnet scan method is that it assumes your local network is configured to use a 24-bit subnet id (8-bit host id). That may be common for most home networks, but it's by no means guaranteed. Ideally, you'd have to figure out the subnet mask somehow and use that determine how many possible hosts to scan. That's a lot more network traffic if you've configured a 16-bit subnet id for, example.

The subnet mask is not related - but yes, i assumed that the 2 hosts share the first 3 octets. The odds of that in SOHO network are so high that i'd take such bet any day of the year that's not 2/29  Smiley Happy. I just won't try my hooliganism to scan >254 hosts. I had the code that maintained pool of pending async requests (Roku survives up to 500 simultaneous or so) but stripped it for simplicity of the example; i had better reason for it before.
0 Kudos