diff --git a/device/components/grove-flow-sensor-analog.js b/device/components/grove-flow-sensor-analog.js new file mode 100644 index 0000000..ec638b1 --- /dev/null +++ b/device/components/grove-flow-sensor-analog.js @@ -0,0 +1,44 @@ +var GroveSensor = require("./grove-sensor.js"); + +// NOTE: We set this as an ANALOG signal not DIGITAL!!! +AnalogFlowSensor = function(pin, freq, multiplier) { + GroveSensor.call(this, { pin : pin, freq: freq }); + this.flowMultiplier = multiplier; + this.flowCount = 0; + this.isLow = false; + + this.within([0,100], this.lowTrigger); + this.within([900,1023], this.highTrigger); +}; + + +AnalogFlowSensor.prototype = Object.create(GroveSensor.prototype, { + isFlowing: { + value: function() { + if (this.flowCount>0) return true; + else return false; + } + }, + read: { + value: function() { + var _fc = this.flowCount; + this.flowCount = 0; + return _fc * this.flowMultiplier; + } + }, + lowTrigger: { + value: function() { + this.isLow = true; + } + }, + highTrigger: { + value: function() { + if (this.isLow) { + this.flowCount++; + } + this.isLow = false; + } + } +}); + +exports = module.exports = AnalogFlowSensor; diff --git a/device/components/grove-flow-sensor.js b/device/components/grove-flow-sensor.js index 9419d14..52ba643 100644 --- a/device/components/grove-flow-sensor.js +++ b/device/components/grove-flow-sensor.js @@ -1,22 +1,37 @@ var GroveSensor = require("./grove-sensor.js"); -FlowSensor = function(pin) { - GroveSensor.call(this, { pin : pin, type: "digital" }); -}; +FlowSensor = function(pin, freq, multiplier) { + GroveSensor.call(this, { pin : pin, type: "digital", freq: freq }); + this.flowMultiplier = multiplier; + this.flowCount = 0; + this.last = 0; -FlowSensor.prototype = Object.create(GroveSensor.prototype); -FlowSensor.prototype.flowCount = 0; -FlowSensor.prototype.isFlowing = function () { - if (this.flowCount>0) return true; - else return false; -} -FlowSensor.prototype.incrementFlowCount = function () { - this.flowCount++; + this.on("change", this.processChange); }; -FlowSensor.prototype.read = function () { - var _fc = this.flowCount; - this.flowCount = 0; - return _fc; -} + + +FlowSensor.prototype = Object.create(GroveSensor.prototype, { + isFlowing: { + value: function() { + if (this.flowCount>0) return true; + else return false; + } + }, + read: { + value: function() { + var _fc = this.flowCount; + this.flowCount = 0; + return _fc * this.flowMultiplier; + } + }, + processChange: { + value: function() { + if (this.last === 0 && this.value === 1) { + this.flowCount++; + } + this.last = this.value; + } + } +}); exports = module.exports = FlowSensor; diff --git a/device/components/grove-lcd.js b/device/components/grove-lcd.js index 10e4518..5a9a793 100644 --- a/device/components/grove-lcd.js +++ b/device/components/grove-lcd.js @@ -1,10 +1,25 @@ var five = require("johnny-five"); +var vsprintf = require('sprintf-js').vsprintf; +var pad = require('pad'); -GroveLCD = function(messages) { +GroveLCD = function(config) { five.LCD.call(this, { controller: "JHD1313M1" }); - this.messages = messages; + this.messages = null; + this.autoscroll.lines = []; + this.autoscroll.linepos = []; + this.autoscroll.wait = []; + this.interval = { + autoscroll: null, + messages: null + }; + this.timer = {}; + this.autoscroll.position = 0; + this.currentMessage = 0; + this.kegdata = {}; + + this.updateConfig(config, false); }; GroveLCD.prototype = Object.create(five.LCD.prototype, { @@ -28,20 +43,94 @@ GroveLCD.prototype = Object.create(five.LCD.prototype, { ).cursor(0, 0).print(line1).cursor(1,0).print(line2); } }, - displayRandomMessage: { - value: function () { - try { - var randColor = [ - Math.floor(Math.random() * 255), - Math.floor(Math.random() * 255), - Math.floor(Math.random() * 255), - ] - var randMessage = Math.floor(Math.random() * this.messages.length); - this.printRGB(randColor,this.messages[randMessage].line1,this.messages[randMessage].line2); - } catch (e) { - console.log("Error printing..."); + startAutoScroll: { + value: function() { + this.timer.scroll = setInterval(this.printContinousScrolling, this.interval.autoscroll, this); + this.timer.message = setInterval(this.displayBeerMessage, this.interval.messages, this); + this.displayBeerMessage(this); + } + }, + printContinousScrolling: { + value: function (lcd) { + if (lcd.autoscroll.lines.length < 1) { + return; + } + for (var i=0; i < lcd.autoscroll.lines.length; i++) { + if (lcd.autoscroll.lines[i].length > 16) { // scroll if length of overall line greater than 16 characters + + if (lcd.autoscroll.linepos[i] == null) { + lcd.autoscroll.linepos[i] = 0; + } + + if (lcd.autoscroll.linepos[i] == 0 || lcd.autoscroll.linepos[i] + 16 >= lcd.autoscroll.lines[i].length) { + lcd.autoscroll.wait[i] = (lcd.autoscroll.wait[i] == null) ? 1 : lcd.autoscroll.wait[i] + 1; + if (lcd.autoscroll.wait[i] >= 4) { + lcd.autoscroll.linepos[i] = (lcd.autoscroll.linepos[i] > 0) ? 0 : 1; + lcd.autoscroll.wait[i] = null; + } + } else { + lcd.autoscroll.linepos[i]++; + } + + lcd.cursor(i,0).print(lcd.autoscroll.lines[i].substring(lcd.autoscroll.linepos[i], lcd.autoscroll.linepos[i] + 16)); + } + else { + lcd.cursor(i,0).print(pad(lcd.autoscroll.lines[i],16)); + } + } + } + }, + updateConfig: { + value: function(config, reset) { + this.messages = config.messages; + this.interval.autoscroll = config.intervals.autoScroll; + this.interval.messages = config.intervals.rotateMessages; + + if (reset) { + // reset auto-scroll + clearTimeout(this.timer.scroll); + clearTimeout(this.timer.message); + this.autoscroll.position = 0; + this.startAutoScroll(); } } + }, + updateKegData: { + value: function(data) { + this.kegdata = data; + } + }, + displayBeerMessage: { + value: function (lcd) { + // only display messages if we have beer info to display + if (! ('usage' in lcd.kegdata)) { + return + } + + // calculate beer usage data to display + lcd.kegdata.used = Math.round(((lcd.kegdata.size - lcd.kegdata.usage) / lcd.kegdata.size) * 100); + lcd.kegdata.left = Math.round((lcd.kegdata.size - lcd.kegdata.usage) * 100) / 100; + + //substitute in needed variables + var line1vars = []; + var line2vars = []; + for (var i=0; i < lcd.messages[lcd.currentMessage].line1vars.length; i++) { + line1vars[i] = lcd.kegdata[lcd.messages[lcd.currentMessage].line1vars[i]]; + } + + for (var i=0; i < lcd.messages[lcd.currentMessage].line2vars.length; i++) { + line2vars[i] = lcd.kegdata[lcd.messages[lcd.currentMessage].line2vars[i]]; + } + + lcd.autoscroll.lines[0] = vsprintf(lcd.messages[lcd.currentMessage].line1, line1vars); + lcd.autoscroll.lines[1] = vsprintf(lcd.messages[lcd.currentMessage].line2, line2vars); + lcd.autoscroll.linepos = []; + lcd.autoscroll.wait = []; + lcd.bgColor(lcd.messages[lcd.currentMessage].color); + + // increment next line to display + lcd.currentMessage = (lcd.currentMessage + 1 >= lcd.messages.length) ? 0 : ++lcd.currentMessage; + } } }); diff --git a/device/components/grove-sound-sensor.js b/device/components/grove-sound-sensor.js index b522e3c..3870bde 100644 --- a/device/components/grove-sound-sensor.js +++ b/device/components/grove-sound-sensor.js @@ -1,7 +1,8 @@ var GroveSensor = require("./grove-sensor.js"); +var DEFAULT_READ_INTERVAL = 1000; -SoundSensor = function(pin) { - GroveSensor.call(this, { pin: pin }); +SoundSensor = function(pin, freq) { + GroveSensor.call(this, { pin : pin, freq: freq }); }; SoundSensor.prototype = Object.create(GroveSensor.prototype, { @@ -12,7 +13,7 @@ SoundSensor.prototype = Object.create(GroveSensor.prototype, { value: false }, readInterval: { - value: 500 + value: DEFAULT_READ_INTERVAL }, read: { value: function() { diff --git a/device/components/grove-temp-sensor.js b/device/components/grove-temp-sensor.js index 5cb8dad..af38d20 100644 --- a/device/components/grove-temp-sensor.js +++ b/device/components/grove-temp-sensor.js @@ -1,7 +1,7 @@ var GroveSensor = require("./grove-sensor.js"); -TempSensor = function(pin) { - GroveSensor.call(this, { pin : pin }); +TempSensor = function(pin, freq) { + GroveSensor.call(this, { pin : pin, freq: freq }); }; TempSensor.prototype = Object.create(GroveSensor.prototype, { diff --git a/device/components/grove-ultrasonic-ranger.js b/device/components/grove-ultrasonic-ranger.js index 5d80238..55feb59 100644 --- a/device/components/grove-ultrasonic-ranger.js +++ b/device/components/grove-ultrasonic-ranger.js @@ -1,9 +1,26 @@ -var GroveSensor = require("./grove-sensor.js"); +var five = require("johnny-five"); +var DEFAULT_READ_INTERVAL = 1000; -UltrasonicRanger = function(pin) { - GroveSensor.call(this, { pin : pin, type: "digital" }); + +UltrasonicRanger = function(pin, freq) { + five.Proximity.call(this, { + controller: "HCSR04", + pin: pin, + freq: freq + }); }; -UltrasonicRanger.prototype = Object.create(GroveSensor.prototype, {}); +UltrasonicRanger.prototype = Object.create(five.Proximity.prototype, { + readInterval: { + value: DEFAULT_READ_INTERVAL + }, + read: { + value: function() { + return this.lastProximity; + } + } + }); + +UltrasonicRanger.prototype.lastProximity = 0; exports = module.exports = UltrasonicRanger; diff --git a/device/device.json b/device/device.json index 978dd9a..23020bb 100644 --- a/device/device.json +++ b/device/device.json @@ -1,40 +1,58 @@ { - "deviceId": "SBS003", - "location": "San Francisco", - "short": "SFO", - "region": "us-east-1", - "intervals": { - "rotateMessages": 10000, - "publish": 1020 - }, - "topic": "sbs", - "logTopic": "logs", - "certs": { - "privateKey": "/opt/sbs/cert/private.pem.key", - "certificate": "/opt/sbs/cert/certificate.pem.crt", - "caCert": "/opt/sbs/cert/root.pem.crt" - }, - "components": { - "leds": { - "blue": 2, - "green": 5, - "red": 6 - }, - "sensors": { - "Sound": "A0", - "Temperature": "A1", - "Flow": 3, - "Proximity": 4 - } - }, - "api": { - "endpoint": "", - "apiKey": "" - }, - "messages": [ - {"line1":"I :heart: beer!","line2":"How about you?"}, - {"line1":"Step right up...","line2":"and grab a beer!"}, - {"line1":"What a beautiful","line2":"day for a beer!"}, - {"line1":"HEY! YOU!","line2":"Want a beer?"} - ] -} + "thingName": "sbs", + "location": "Vancouver", + "short": "YVR", + "region": "us-east-1", + "intervals": { + "rotateMessages": 30000, + "autoScroll": 400, + "topic": 1020, + "shadow": 300000 + }, + "topicName": "simpleBeerEdisonTopic", + "logTopic": "simpleBeerEdisonTopicLogs", + "certs": { + "privateKey": "/opt/sbs/cert/private.pem.key", + "certificate": "/opt/sbs/cert/certificate.pem.crt", + "caCert": "/opt/sbs/cert/root.pem.crt" + }, + "components": { + "leds": { + "blue": 2, + "green": 5, + "red": 6 + }, + "sensors": { + "Sound": { + "pin": "A0" + }, + "Temperature": { + "pin": "A1" + }, + "Flow": { + "pin": "A2", + "freq": 1, + "multiplier": 3.2715 + }, + "Proximity": { + "pin": 4 + } + } + }, + "messages": [ + { + "line1": "Beer: %s, from %s brewery", + "line1vars": ["name", "brewery"], + "line2": "Description: %s", + "line2vars": ["desc"], + "color": "#f442ce" + }, + { + "line1": "Beer is at %2.0f%% used.", + "line1vars": ["used"], + "line2": "Only %.2f liters left!", + "line2vars": ["left"], + "color": "#f2a7e2" + } + ] +} \ No newline at end of file diff --git a/device/package.json b/device/package.json index 3b87a0a..9f3f8f5 100644 --- a/device/package.json +++ b/device/package.json @@ -15,9 +15,12 @@ "crypto-js": "^3.1.6", "edison-io": "^0.9.4", "forever": "^0.15.2", - "johnny-five": "^0.9.56", + "johnny-five": "^0.11.6", "restler": "^3.4.0", "sleep": "^3.0.1", - "th02js": "0.0.2" + "th02js": "0.0.2", + "semaphore": "1.1.0", + "sprintf-js": "1.1.1", + "pad": "1.1.0" } } diff --git a/device/sbs-simulator.js b/device/sbs-simulator.js index dd5fa1c..7f39aac 100644 --- a/device/sbs-simulator.js +++ b/device/sbs-simulator.js @@ -21,13 +21,14 @@ const commandLineArgs = require('command-line-args'); const optionDefinitions = [ { name: 'verbose', alias: 'v', type: Boolean, defaultValue: false }, { name: 'region', alias: 'r', type: String, defaultValue: config.region }, - { name: 'unitid', alias: 'u', type: String, defaultValue: config.deviceId } + { name: 'unitid', alias: 'u', type: String, defaultValue: config.thingName }, + { name: 'topicName', alias: 't', type: String, defaultValue: config.topicName } ]; const options = commandLineArgs(optionDefinitions); var data = []; try { - var device = awsIot.device({ + var device = awsIot.thingShadow({ keyPath: "cert/private.pem.key", certPath: "cert/certificate.pem.crt", caPath: "cert/root.pem.crt", @@ -35,7 +36,7 @@ try { region: options.region }); - var topic = "test/"+options.unitid; + var topic = options.topicName + "/" + options.unitid; var messages = [ {"line1":"I :heart: beer!","line2":"How about you?"}, @@ -56,8 +57,7 @@ try { "data": data } data = []; - console.log("Payload: ", "eyAidGVzdCI6ICJ0ZXN0IiB9"); - return "eyAidGVzdCI6ICJ0ZXN0IiB9"; + return JSON.stringify(payload); } // Generates a random flow count every 10 iterations. @@ -107,7 +107,11 @@ try { populateData('Temperature', temp); populateData('Humidity', humidity); populateData('Sound', sound); - device.publish(topic, generatePayload()); + var payload = generatePayload(); + console.log(topic,payload); + device.publish(topic, payload,{ qos: 0, retain: false }, (err)=>{ + if(err) console.log("err:" , err) + }); } // Sets only a random value for the Sound sensor. @@ -117,17 +121,44 @@ try { populateData('Temperature', 14); populateData('Humidity', 55); populateData('Sound', sound); - device.publish(topic, generatePayload()); + device.publish(topic, generatePayload(),{},(err)=>{ + console.log(err) + }); } // Connect to AWS IoT and setup Intervals console.log("Connecting to AWS IoT..."); device.on("connect", function() { - console.log("Connected to AWS IoT."); - setInterval(consistent, 1000); - setInterval(function() { - console.log("Message: ",messages[Math.floor(Math.random()*4)]); - },10000); + console.log("registering...") + device.register( options.unitid, {}, function() { + console.log("registered"); + var sbsState = { + "state":{ + "desired": { + "data": { + "temp": 10, + "humidity": 43 + }, + "color":[100,150,155], + "full":"simpleBeerEdison", + "short":"edison" + } + } + }; + var clientTokenUpdate = device.update( options.unitid, sbsState ); + if (clientTokenUpdate === null) + { + console.log('update shadow failed, operation still in progress'); + }else{ + console.log("token:",clientTokenUpdate) + console.log("Connected to AWS IoT."); + setInterval(run, 1000); + setInterval(function() { + console.log("Message: ",messages[Math.floor(Math.random()*4)]); + },10000); + } + }); + }); } catch (e) { diff --git a/device/sbs.js b/device/sbs.js index 3874b37..bbc86b4 100644 --- a/device/sbs.js +++ b/device/sbs.js @@ -18,21 +18,29 @@ var LCDScreen = require("./components/grove-lcd.js"); var TempSensor = require("./components/grove-temp-sensor.js"); var SoundSensor = require("./components/grove-sound-sensor.js"); var FlowSensor = require("./components/grove-flow-sensor.js"); +var AnalogFlowSensor = require("./components/grove-flow-sensor-analog.js"); var UltrasonicRanger = require("./components/grove-ultrasonic-ranger.js"); var awsIot = require("aws-iot-device-sdk"); var Edison = require("edison-io"); var os = require('os'); var sleep = require('sleep'); var async = require('async'); +var shadowAccess = require('semaphore')(1); +var configUpdate = require('semaphore')(1); var config = require("./device.json"); var ifaces = os.networkInterfaces(); var bus = 6; +var defaultFreq = 25; +var defaultMultiplier = 2.25; +var kegdata = {}; +var components = null; +var lcd = null; const commandLineArgs = require('command-line-args') const optionDefinitions = [ { name: 'verbose', alias: 'v', type: Boolean, defaultValue: false }, { name: 'region', alias: 'r', type: String, defaultValue: config.region }, - { name: 'unitid', alias: 'u', type: String, defaultValue: config.deviceId } + { name: 'unitid', alias: 'u', type: String, defaultValue: config.thingName } ] const options = commandLineArgs(optionDefinitions) @@ -48,22 +56,27 @@ if (options.verbose) { }); } -var PUBLISH_INTERVAL = config.intervals.publish; -var ROTATE_MESSAGE_INTERVAL = config.intervals.rotateMessages; +var PUBLISH_TOPIC = config.intervals.topic; +var PUBLISH_SHADOW = config.intervals.shadow; var unitID = options.unitid; -var device = awsIot.thingShadow({ - keyPath: config.certs.privateKey, - certPath: config.certs.certificate, - caPath: config.certs.caCert, - clientId: options.unitid, - region: options.region -}); +var device = awsIot.thingShadow( + { + keyPath: config.certs.privateKey, + certPath: config.certs.certificate, + caPath: config.certs.caCert, + clientId: options.unitid, + region: options.region + }, + { + operationTimeout: 30000 // 30 seconds + } +); var logs = []; var data = []; -var topic = config.topic+"/"+unitID; +var topic = config.topicName +"/"+unitID; var logtopic = config.logTopic+"/"+unitID; var colors = { "green": [ 0, 255, 0 ], @@ -72,23 +85,41 @@ var colors = { "blue": [ 0, 0, 255 ], } -try { - var components = { - "leds": { - "blue": new five.Led(config.components.leds.blue), - "green": new five.Led(config.components.leds.green), - "red": new five.Led(config.components.leds.red) - }, - "lcd": new LCDScreen(config.messages), - "sensors": { - "Sound": new SoundSensor(config.components.sensors.Sound, board), - "Temperature": new TempSensor(config.components.sensors.Temperature), - "Flow": new FlowSensor(config.components.sensors.Flow), - "Proximity": new UltrasonicRanger(config.components.sensors.Proximity) +function initLCD() { + lcd = new LCDScreen(config); +} + +function initSensors(callback) { + configUpdate.take(function() { + try { + components = { + "leds": { + "blue": new five.Led(config.components.leds.blue), + "green": new five.Led(config.components.leds.green), + "red": new five.Led(config.components.leds.red) + }, + "lcd": lcd, + "sensors": { + "Sound": new SoundSensor( + config.components.sensors.Sound.pin, + ('freq' in config.components.sensors.Sound) ? config.components.sensors.Sound.freq : defaultFreq + ), + "Temperature": new TempSensor( + config.components.sensors.Temperature.pin, + ('freq' in config.components.sensors.Temperature) ? config.components.sensors.Temperature.freq : defaultFreq + ), + "Flow": new AnalogFlowSensor( + config.components.sensors.Flow.pin, + ('freq' in config.components.sensors.Flow) ? config.components.sensors.Flow.freq : defaultFreq, + ('multiplier' in config.components.sensors.Flow) ? config.components.sensors.Flow.multiplier : defaultMultiplier + ) + } + } + } catch (e) { + log('ErrorInit',e); } - } -} catch (e) { - log('ErrorInit',e); + callback(); + }); } function log(type, message) { @@ -128,66 +159,135 @@ function initReaders() { }) } }); - callback(); }, function(err) { log("Init","Complete"); }); } + +function recurseUpdate(initial, update){ + for(prop in initial){ + if({}.hasOwnProperty.call(initial, prop) && {}.hasOwnProperty.call(update, prop)){ + if(typeof initial[prop] === 'object' && typeof update[prop] === 'object'){ + recurseUpdate(initial[prop], update[prop]); + } + else{ + initial[prop] = update[prop]; + } + } + } +} + +function updateFromShadow(shadow, isDelta) { + var updateShadow = false; + update = (isDelta) ? shadow.state : shadow.state.desired; + + if (update == null) { // we can ignore message if we have no desired object and its not an update + return; + } + + if ('kegdata' in update) { + if (Object.keys(kegdata).length == 0) { // deal wth empty initial kegdata + kegdata = update.kegdata; + } + else { + recurseUpdate(kegdata, update.kegdata); + } + lcd.updateKegData(kegdata); + updateShadow = true; + } + + if ('config' in update) { + recurseUpdate(config, update.config); + lcd.updateConfig(config, true); + updateShadow = true; + } + if (updateShadow) { + shadowAccess.take(function() { + var sbsState = { + "state" : { + "reported": { + "kegdata": kegdata, + "config": config + } + } + }; + device.update( options.unitid, sbsState ); + }); + } +} -function startupRoutine() { +function startupRoutine(callback) { /* Setup the components */ - var clientTokenUpdate; + var token; try { log(options.unitid+"init",JSON.stringify(options)); - components.lcd.useChar("heart"); + lcd.useChar("heart"); board.pinMode("A0", five.Pin.INPUT); log("Board",ifaces); - components.lcd.printRGB(colors.blue,"SBS 5.0 Starting","IP:"+ifaces.wlan0[0].address); + lcd.printRGB(colors.blue,"SBS 5.0 Starting","IP:"+ifaces.wlan0[0].address); sleep.sleep(3); - components.lcd.printRGB(colors.blue,"Location set to",config.location); + lcd.printRGB(colors.blue,"Location set to",config.location); sleep.sleep(3); - components.lcd.printRGB(colors.red,"Connecting...","to AWS IoT"); + lcd.printRGB(colors.red,"Connecting...","to AWS IoT"); log("AWS IoT","Connecting to AWS IoT..."); - components.leds.red.blink(100); + try { device.on("connect", function() { - device.register( options.unitid, function() { - var sbsState = { - "desired": { - "data": { - "temp": components.sensors['Temperature'].read(), - "humidity": 43 + device.register(options.unitid, { enableVersioning: false }, function() { // disable versioning for device shadow updating, as we also have lambda updating shadow + + shadowAccess.take(function() { + token = device.get(options.unitid); + }); + + shadowAccess.take(function() { + var sbsState = { + "state" : { + "reported": { + "device": { + "config": config + }, + } } - } - }; - var clientTokenUpdate = device.update( options.unitid, sbsState ); - if (clientTokenUpdate === null) - { - console.log('update shadow failed, operation still in progress'); - } + }; + token = device.update( options.unitid, sbsState ); + }); }); log("AWS IoT","Connected to AWS IoT..."); - components.leds.red.stop().off(); - components.lcd.printRGB(colors.green,"Connected!","TO AWS IoT"); + lcd.printRGB(colors.green,"Connected!","TO AWS IoT"); }); device.on('status', function(thingName, stat, clientToken, stateObject) { - console.log('received '+stat+' on '+thingName+': '+ + console.log('received ' + stat + ' on ' + thingName + ' with token ' + clientToken + ': ' + JSON.stringify(stateObject)); + updateFromShadow(stateObject, false); + shadowAccess.leave(); + + // On initial start we wait until device shadow over-ride config is read before initalizing sensors + if (! configUpdate.available()) { + configUpdate.leave(); + } + }); device.on('delta', function(thingName, stateObject) { console.log('received delta on '+thingName+': '+ JSON.stringify(stateObject)); + updateFromShadow(stateObject, true); }); device.on('timeout', function(thingName, clientToken) { console.log('received timeout on '+thingName+ ' with token: '+ clientToken); + shadowAccess.leave(); + }); + + device.on('error', + function(error) { + console.log('recieved error: ' + error); }); } catch (e) { @@ -196,48 +296,62 @@ function startupRoutine() { } catch (e) { log('Error',e); } + callback(); } -board.on("ready", function() { - - startupRoutine(); - - components.sensors.Flow.on("change", function() { - //log("Flow", this.flowCount); - this.incrementFlowCount(); - components.leds.blue.on(); - }); - - this.loop(ROTATE_MESSAGE_INTERVAL, function() { - try { - components.lcd.displayRandomMessage(); - } catch (e) { - log("ErrorInBoot",e); - } - }); +// +// MAIN +// - initReaders(); - this.loop(PUBLISH_INTERVAL, function() { - try { - for (var i = 0, len = logs.length; i < len; i++) { - device.publish(logtopic, JSON.stringify(logs[i])); +board.on("ready", function() { + initLCD(); + lcd.startAutoScroll(); + configUpdate.take(function() { + async.parallel([startupRoutine, initSensors], function() { + initReaders(); + board.loop(PUBLISH_TOPIC, function() { + try { + for (var i = 0, len = logs.length; i < len; i++) { + device.publish(logtopic, JSON.stringify(logs[i])); + if (options.verbose) { + board.info('PublishLog', JSON.stringify(logs[i])); + } + } + logs = []; + } catch (e) { if (options.verbose) { - board.info('PublishLog', JSON.stringify(logs[i])); + board.info('ErrorLog','Error publishing log.' + e); } } - logs = []; - } catch (e) { - if (options.verbose) { - board.info('ErrorLog','Error publishing log.' + e); + components.leds.green.on(); + components.leds.blue.off(); + device.publish(topic, generatePayload()); + setTimeout(function() { + components.leds.green.off(); + }, 100); + }); + board.loop(PUBLISH_SHADOW, function () { + var sensordata = {}; + for (var sensor in components.sensors) { + sensordata[sensor] = components.sensors[sensor].read() } - } - components.leds.green.on(); - components.leds.blue.off(); - device.publish(topic, generatePayload()); - setTimeout(function() { - components.leds.green.off(); - }, 100); - }); + sensordata.Humidity = 43; // Hack - hard-coded for now until humidity sensor can be made to work + kegdata.sensors = sensordata + shadowAccess.take(function () { + var sbsState = { + "state": { + "reported": { + "kegdata": { + "sensors": kegdata.sensors + } + } + } + }; + device.update(options.unitid, sbsState); + }); + }); + }); + }); });