Skip to content

Instantly share code, notes, and snippets.

@kntyskw
Created December 13, 2015 17:29
Show Gist options
  • Save kntyskw/40d144e47ed0067e125b to your computer and use it in GitHub Desktop.
Save kntyskw/40d144e47ed0067e125b to your computer and use it in GitHub Desktop.
UPnP-MQTT Gateway connecting via SORACOM Beam to AWS IoT
var ssdp = require('node-upnp-ssdp');
var UPnPDeviceClient = require('upnp-device-client');
var mqtt = require('mqtt');
var clientId = 'kenta-upnp-gateway';
var mqttOptions = { clientId: clientId };
var mqttEndpoint = 'mqtt://beam.soracom.io';
var mqttClient = mqtt.connect(mqttEndpoint, mqttOptions);
var topicUpdateAccepted = '$aws/things/' + clientId + '/shadow/update/accepted';
var topicUpdateDelta = '$aws/things/' + clientId + '/shadow/update/delta';
var topicDevicesRoot = '$aws/things/' + clientId + '/devices';
var devices = {};
var addOrUpdateDevice = function(info){
var udn = info.usn.split('::')[0];
if (!devices[udn]){
var client = new UPnPDeviceClient(info.location);
client.getDeviceDescription(function(err, device){
if (!err){
console.log('UPnP: Device ' + device.friendlyName + ' found');
device.client = client;
device.online = true;
publish(createDevicePresense(udn, device));
devices[udn] = device;
} else {
console.error('UPnP: ' + err);
}
});
} else {
publish(createDevicePresense(udn, {online: true}));
}
};
var createDevicePresense = function(udn, device){
var presense = {
devices: {}
};
presense.devices[udn] = {};
for (var key in device){
if (key !== 'client'){
presense.devices[udn][key] = device[key];
}
}
return presense;
};
var removeDevice = function(info){
var udn = info.usn.split('::')[0];
var device = devices[udn];
if (device){
console.log('UPnP: Device ' + device.friendlyName + ' gets offline');
delete devices[udn];
publish(createDevicePresense(udn, {online: false}));
}
};
var publish = function(state){
var event = {
state: {
reported: state
}
};
mqttClient.publish('$aws/things/kenta-upnp-gateway/shadow/update', JSON.stringify(event));
};
var getContextFromTopic = function(topic){
var path = topic.substring(topicDevicesRoot.length + 1);
var elems = path.split('/');
var context = {
udn: elems[0],
service: elems[1],
action: elems[2]
};
console.log(context);
return context;
};
var executeAction = function(context, args){
if (devices[context.udn]){
var client = devices[context.udn].client;
client.callAction(context.service, context.action, args, function(err, result) {
if (!err){
console.log(result);
} else {
console.error(err);
}
});
} else {
console.error("No such device found");
}
};
ssdp.on('DeviceFound', addOrUpdateDevice);
ssdp.on('DeviceAvailable:upnp:rootdevice', addOrUpdateDevice);
ssdp.on('DeviceUnavailable:upnp:rootdevice', removeDevice);
ssdp.on('DeviceError', console.error);
ssdp.mSearch('upnp:rootdevice');
mqttClient.on('connect', function () {
mqttClient.subscribe([topicUpdateDelta, topicUpdateAccepted, topicDevicesRoot + '/#']);
});
mqttClient.on('message', function (topic, buffer) {
if (topic === topicUpdateAccepted){
console.log('MQTT: Device shadow update accepted by AWS IoT');
} else if (topic === topicUpdateDelta){
console.log('MQTT: Delta is received from AWS IoT');
var delta = JSON.parse(buffer.toString());
console.log(delta);
} else if (topic.indexOf(topicDevicesRoot) === 0){
console.log('MQTT: Message to a device received');
executeAction(getContextFromTopic(topic), JSON.parse(buffer.toString()));
} else {
console.error('MQTT: Unknown message received on topic ' + topic);
console.error(buffer.toString());
}
});
mqttClient.on('error', console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment