UNPKG

homespun-grovepi

Version:

This is a Node.js module that reads sensors residing on a [Raspberry Pi](https://www.raspberrypi.org) and a [GrovePi+ Shield](http://www.dexterindustries.com/shop/grovepi-board/) and transcodes them to [TSRP](http://thethingsystem.com/dev/Thing-Sensor-Rep

233 lines (195 loc) 8.02 kB
/* ___ usage: en_US ___ usage: node homespun.js [options] file options: -h, --help display this message -c, --config name configuration name description: homespun will monitor any sensors connected to your GrovePi and generate TSRP messages for node-homework ___ usage ___ */ var r2c, requestID, runloop, tsrp , cadence = require('cadence/redux') , crypto = require('crypto') , dgram = require('dgram') , fs = require('fs') , underscore = require('underscore') , util = require('util') , uuid = require('node-uuid') , GrovePi = require('node-grovepi').GrovePi require('cadence/loops') GrovePi.sensors.TemperatureDigital = {} underscore.keys(GrovePi.sensors.DHTDigital.VERSION).forEach(function (moduleType) { GrovePi.sensors.TemperatureDigital[moduleType] = function (pin) { GrovePi.sensors.DHTDigital.apply(this, [ pin , GrovePi.sensors.DHTDigital.VERSION[moduleType] , GrovePi.sensors.DHTDigital.CELSIUS ]) } GrovePi.sensors.TemperatureDigital[moduleType].prototype = new GrovePi.sensors.DHTDigital() }) r2c = { lowP : function (v) { return (!v) } , highP : function (v) { return (!!v) } , maxP : function (v) { return (v >= 1023) } , cm : function (v) { return (v / 100.0) } , pct : function (v) { return (v / 1024.0) } , epsilon : function (v) { return ((v * 4.95) / 1023.0) } , v : function (v) { return v } , 'v[0]' : function (v) { return v[0] } , 'v[1]' : function (v) { return v[1] } , 'v[1]%' : function (v) { if (v[1] < 1) return 0.0 if (v[1] >= 100) return 1.0 return (v[1] / 100.0) } , pH : function (v) { return (7 - 1000 * (v - 372) * 4.95 / (59.16 * 1023)) } , resistpct : function (v) { if (v < 1) return 0.0 v = (1023 - v) * (10 / v) if (v >= 100) return 1.0 return (v / 100.0) } , uv : function (v) { return ((v * 4980) / (1023 * 200)) } } requestID = 1 runloop = cadence(function (async, sensor) { var suffix , bootTime = new Date().getTime() , properties = {} , root = GrovePi.sensors sensor.type.split('.').forEach(function (component) { root = root[component] }) sensor.sensor = new root(sensor.pin) suffix = '/device/sensor/grovepi/' + sensor.sensorTag sensor.template = { path : '/api/v1/thing/reporting' , requestID : '1' , things : { } } underscore.keys(sensor.properties).forEach(function (key) { properties[key] = sensor.properties[key][0] }) sensor.template.things[suffix] = { prototype : { device : { name : sensor.sensorType || 'Grove sensor' , maker : sensor.sensorMaker || 'Dexter Industries / Seeed Studio' , model : { number : sensor.modelNumber } } , name : true , status : [ 'present', 'absent', 'recent' ] , properties : properties } , instances : [ { name : sensor.name , status : 'present' , unit : { serial : sensor.udn , udn : sensor.udn } , info : { } , uptime : 0 } ] } async(function () { setTimeout(async(), 5 * 1000) }, function () { var data , value = sensor.sensor.read() if ((Buffer.isBuffer(value)) && (value.length === 1)) value = value[0] sensor.template.requestID = requestID++ sensor.template.things[suffix].instances[0].info = {} underscore.keys(sensor.properties).forEach(function (key) { var f = r2c[sensor.properties[key][1]] if (!!f) sensor.template.things[suffix].instances[0].info[key] = f(value) }) sensor.template.things[suffix].instances[0].uptime = new Date().getTime() - bootTime data = new Buffer(JSON.stringify(sensor.template)) tsrp.send(data, 0, data.length, 22601, '224.0.9.1', async()) }, function (bytes) {/* jshint unused: false */ })() }) require('arguable/executable')(module, cadence(function (async, options) { var config, name, path , logger = require('prolific').createLogger('homespun') if (options.params.help) return console.log(options._usage.message) if (options.params.config) { name = options.argv[0] path = options.argv[1] } else { path = options.argv[0] } if (!path) path = __dirname + '/config.json' async(function () { fs.readFile(path, 'utf8', async()) }, function (body) { var i , json = JSON.parse(body) , keys = underscore.keys(json) if (keys.length === 0) throw new Error('empty configuration file') if (!name) name = underscore.keys(json)[0] config = json[name] if (!config) throw new Error('configuration name \"' + name + '\" is undefined') i = 0 config.sensors.forEach(function (sensor) { var root = GrovePi.sensors if ((!sensor.name) || (!sensor.type) || (isNaN(sensor.pin)) || (!sensor.properties) || (!sensor.sensorType) || (!sensor.sensorTag) || (!sensor.modelNumber)) { console.log(util.inspect(sensor, { depth : null })) throw new Error('incomplete specification for sensor #' + i) } sensor.type.split('.').forEach(function (component) { if (!root[component]) { console.log(util.inspect(sensor, { depth : null })) throw new Error('invalid type for sensor #' + i) } root = root[component] }) if (typeof sensor.properties !== 'object') { console.log(util.inspect(sensor, { depth : null })) throw new Error('invalid properties for sensor #' + i) } underscore.keys(sensor.properties).forEach(function (key) { var property = sensor.properties[key] if ((!util.isArray(property)) || (!r2c[property[1]])) { console.log(util.inspect(sensor, { depth : null })) throw new Error('invalid property ' + key + ' for sensor #' + i) } }) i++ if (!!sensor.udn) return async(function () { crypto.randomBytes(16, async()) }, function (bytes) { sensor.udn = uuid.v4(bytes) fs.writeFile(path, JSON.stringify(json, null, 2), async()) }) }) }, function () { tsrp = dgram.createSocket('udp4') tsrp.bind(0, async()) }, function () { tsrp.addMembership('224.0.9.1'); tsrp.setMulticastLoopback(true) tsrp.setMulticastTTL(10) }, function () { var initP, loop , board = new GrovePi.board({ debug : true , onError : function (err) { throw err } , onInit : function (/* firstP */) { initP = true } }) board.init() loop = async(function () { if (!!initP) return [ loop ] setTimeout(async(), 100) })() logger.info('initialized', { version : board.version() }) config.sensors.forEach(function (sensor) { runloop(sensor, function (err) { if (!!err) logger.error('initialize', { sensor : sensor.name, message : err.message }) }) }) }) }))