Skip to content

Instantly share code, notes, and snippets.

@asciidisco
Last active March 15, 2018 23:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save asciidisco/de8b625c798142433faf to your computer and use it in GitHub Desktop.
Save asciidisco/de8b625c798142433faf to your computer and use it in GitHub Desktop.
UPNP discovery
var ssdp = require('node-ssdp-lite');
var request = require('request');
var _ = require('lodash');
var parseString = require('xml2js').parseString;
var client = new ssdp();
var endpoints = {};
var locationFilter = function (msg) {
var start = msg.search('LOCATION:') + 'LOCATION:'.length;
var _temp = msg.substr(start);
var end = _temp.indexOf('\n');
return _temp.substr(0, end).replace('\r', '');
};
var newEndpoint = function (data) {
console.log('Found device:', data.address);
console.log('Name:', data.name);
console.log('Vendor:', data.vendor);
console.log('Device Type:', data.device);
console.log('Serialnumber:', data.serialnumber);
console.log('Model description:', data.model.desc);
console.log('Model name:', data.model.name);
console.log('Model no.:', data.model.no);
console.log('-----------------');
};
client.on('response', function inResponse(msg, rinfo) {
if (!endpoints[rinfo.address]) {
var info = _.clone(rinfo);
info.location = locationFilter(msg);
endpoints[rinfo.address] = info;
request(info.location, function (err, data) {
parseString(data.body, function (err, result) {
endpoints[rinfo.address].desc = result.root;
info.name = result.root.device ? result.root.device[0].friendlyName[0] : null;
info.vendor = result.root.device ? result.root.device[0].manufacturer[0] : null;
info.device = result.root.device ? result.root.device[0].deviceType[0] : null;
info.serialnumber = result.root.device && result.root.device[0].serialNumber ? result.root.device[0].serialNumber[0] : null;
info.model = {
desc: result.root.device ? result.root.device[0].modelDescription[0] : null,
name: result.root.device ? result.root.device[0].modelName[0] : null,
no: result.root.device ? result.root.device[0].modelNumber[0] : null
};
newEndpoint(info);
});
});
}
});
client.search('urn:nds-com:serviceId:SkyBrowse2');
client.search('urn:schemas-nds-com:service:SkyBrowse:2');
client.search('urn:schemas-upnp-org:device:MediaServer:1');
client.search('urn:schemas-upnp-org:service:ContentDirectory:1');
client.search('urn:schemas-upnp-org:service:ConnectionManager:1');
client.search('upnp:rootdevice1');
// Or get a list of all services on the network
client.search('ssdp:all');
client.search('ssdp:discover');
Usage:
Create a new directory & save the two files in it, then open up your CMD/Terminal, navigate to that folder & execute `npm install`, after that launch the script with `node index.js` -> if you find a Homematic/eq-3 LAN device, please post the output in the comments, that would be very helpful :)
{
"name": "upnp-scanner",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"lodash": "^2.4.1",
"node-ssdp-lite": "^0.2.0",
"request": "^2.53.0",
"xml2js": "^0.4.5"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "WTF"
}
Copy link

ghost commented Mar 15, 2018

Hi there,

My Yamaha R-N803D's LOCATION field is named Location.
I've fixed this by replacing line 10 with:

var start = msg.search(/location:/i) + 'LOCATION:'.length;

Regards,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment