Created
December 13, 2015 17:29
-
-
Save kntyskw/40d144e47ed0067e125b to your computer and use it in GitHub Desktop.
UPnP-MQTT Gateway connecting via SORACOM Beam to AWS IoT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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