Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ client.state(function(err,state) {

if (state===1) {
// WeMo if on, turn it off
client.off();
client.switchOff();
} else {
// WeMo is off, turn it on
client.on();
client.switchOn();
}
});
```
Expand All @@ -48,10 +48,10 @@ Discovers WeMo power sockets on your local network.

## Client API

### client.on(cb)
### client.switchOn(cb)
Attempts to turn the WeMo on. `cb` will be passed an error if this failed, or if the device is already on.

### client.off(cb)
### client.switchOff(cb)
Attempts to turn the WeMo off. `cb` will be passed an error if this failed, or if the device is already off.

### client.state(cb)
Expand Down
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var WeMo = require('./lib/WeMo');

exports.discover = require('./lib/Discoverer');
exports.discoverer = require('./lib/Discoverer');

exports.createClient = function(config) {
return new WeMo(config);
Expand Down
112 changes: 67 additions & 45 deletions lib/Discoverer.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,75 @@
var dgram = require('dgram');
var async = require('async');
var EventEmitter = require('events').EventEmitter;
var request = require('request');
var SSDP = require('ssdp');
var SSDP = require('node-ssdp').Client;
var url = require('url');
var xml = require('libxml-to-js');
var util = require('util');
var xml = require('xml2js');

module.exports = function(cb) {
module.exports = Discoverer;
util.inherits(Discoverer,EventEmitter);

var client = new SSDP;
var found = [];
function Discoverer() {
EventEmitter.call(this);

this.client = new SSDP();
this.found = {};

this.client.on('response', handleUDPResponse.bind(this));

function handleUDPResponse (headers, statusCode, rinfo) {
// Ignore devices that don't match the WeMo LOCATION pattern
if (!headers.LOCATION || !/^(?:.*)setup[.]xml$/.test(headers.LOCATION))
return;

// Ensure headers to get unique identifier
if (!headers.ST || !headers.USN)
return;

var handleUDPResponse = function(msg, rinfo) {

var regex = new RegExp('location: (.*?)\\r\\n','i')
var location = regex.exec(msg.toString());
var wemo = location && location[1] || undefined;

if (wemo && found.indexOf(wemo)===-1) {
found.push(wemo);
}
};

var handleSearchResults = function(){
async.map(found,wemoFinder,function(err,results) {
cb(results.filter(function(item,index,arr) {
return item;
}));
});
};

client.on('response',handleUDPResponse);
client.search('ssdp:all');
setTimeout(handleSearchResults,2000);
};

function wemoFinder(wemo,cb) {

request(wemo,function(e,r,b) {

xml(b, function (error, result) {
if (error) {
return cb(error);
}
else if (/WeMo Switch/g.test(b)) {
return cb (null,{location:url.parse(wemo),info:result});
} else {
return cb(true);
var idRegex = new RegExp('^(uuid:.+)::' + headers.ST + '$');
var match = headers.USN.match(idRegex);
// Cannot extract identifier from USN
if (!match)
return;

var identifier = match[1];
if (this.found[identifier]) {
if (this.found[identifier].location.hostname == rinfo.address)
return;
console.log('ip changed', identifier);
// Wemo has changed IP address since last discovery
this.found[identifier].location = url.parse(headers.LOCATION);
this.emit('ipchange', { identifier: identifier, ip: this.found[identifier].location });
return;
}
});

var discoveryData = {
identifier: identifier,
location: url.parse(headers.LOCATION)
};
this.found[identifier] = discoveryData;
if (!this.found[identifier].info)
getDescription.bind(this)(identifier);
}

function getDescription(identifier) {
request(this.found[identifier].location.href, function (e, r, b) {
if (!b)
return;
xml.Parser({ explicitRoot: false, explicitArray: false })
.parseString(b, function (error, result) {
if (error)
return;
var valid = [/WeMo Switch/g, /WeMo Insight/g, /WeMo LightSwitch/g, /CoffeeMaker/g];
if (valid.some(function(pattern) { return pattern.test(b); })) {
this.found[identifier].info = result;
this.emit('discovered', this.found[identifier]);
}
}.bind(this));
}.bind(this));
}
}

});
};
Discoverer.prototype.discover = function () {
this.client.search('urn:Belkin:service:basicevent:1');
}
Loading