peter-murray / node-hue-api

Node.js Library for interacting with the Philips Hue Bridge and Lights
Apache License 2.0
1.19k stars 145 forks source link

Respect location ssdp header #52

Closed achingbrain closed 9 years ago

achingbrain commented 9 years ago

I'm writing a proxy for my hue bridge that augments it with a new non-hue networked lights - when doing discovery of hue bridges, they respond with a location header which is a URL to a description document. That document contains useful information like bridge serial number and the URLBase property.

Right now node-hue-api does a ssdp search for bridges, then requests /description.xml from port 80 of the hosts that respond to the search in order to get the bridge id - this happens to follow the hue implementation but doesn't seems to be in the spirit of the protocol - it should follow the location header instead.

So, for example, the ssdp search node-hue-api generates is:

M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: ssdp:discover
MX: 10
ST: urn:schemas-upnp-org:device:Basic:1

The response is then:

HTTP/1.1 200 OK
ST: urn:schemas-upnp-org:device:Basic:1
USN: uuid:07a50742-5a89-4b27-9a9e-374df1191a61::urn:schemas-upnp-org:device:Basic:1
LOCATION: http://192.168.1.67:64764
CACHE-CONTROL: max-age=100
DATE: Sat, 18 Jul 2015 11:43:43 GMT
SERVER: FreeRTOS/7.4.2 UPnP/1.0 IpBridge/1.8.0
EXT: 

The next request from node-hue-api should be to http://192.168.1.67:64764, instead it's to http://192.168.1.67/description.xml

I think this is because when makes the request to the host and then has the path to /description.xml hard coded.

As a shameless plug I've written an ssdp implementation that automagically goes off, fetches and parses the contents of the location header for you - might solve the problem..

peter-murray commented 9 years ago

I am respecting the location header being returned. The search data being returned to me from my bridge has a value of http://192.168.2.150:80/description.xml for the LOCATION value.

The point of the code that you indicate as hard coded is a direct link to the description.xml file, but is not used in the lookup from the SSDP lookups.

I had looked at your library in the past, but I wanted this library to be a small as possible, and your SSDP library includes a lot of extra dependencies that I did not want to pull in for an edge case bridge lookup that over 95% of users of the library would not need. When Hue released an update to finding of the bridges, they now have a broker service, which is the preferred discovery method.

achingbrain commented 9 years ago

I'm not sure that it is respecting the location header. Take a look at this gist.

If you run server.js, it'll open two http servers - one on port 80, one on 8080 and set up a dgram socket to respond to bridge search requests.

The dgram socket responds with LOCATION: http://localhost:8080/foo.xml in the message, so if node-hue-api respects the location header, it should make a request to port 8080 and request /foo.xml.

search.js contains the upnp example search code from the node-hue-api readme. When I run it I see:

$ sudo node server.js
Socket listening
Responding to bridge search request
Responded to bridge search request
Got request for /description.xml on port 80
$ node search.js
Hue Bridges Found: [{"id":"WRONG PORT!","ipaddress":"localhost"}]

So it's requesting http://localhost:80/description.xml even though the LOCATION header in the search response is http://localhost:8080/foo.xml.

peter-murray commented 9 years ago

Thanks for that, the penny finally dropped. I had checked that the LOCATION was being returned in the SSDP results, but of course you were right, as after that I defaulted to pulling the discovery xml via an API call, thereby not actually following the URL.

I have switched the code to issue a simplified HTTP GET on the LOCATION that is returned, which has no change on my bridge, as it is returning the http://192.168.2.150:80/description.xml value for me.

This has been released in version 1.1.1 of the library.