From 6108d750741c4dfae4810878908a0f0c6b79d0e1 Mon Sep 17 00:00:00 2001 From: Senad Uka Date: Sun, 23 Oct 2016 15:10:20 +0200 Subject: [PATCH] saving and temperature works --- .gitignore | 1 - app/client/{alarm => }/alarm.html | 2 +- app/client/{alarm => }/alarm.js | 9 ++ app/client/alarm/alarm_settings.js | 43 ------ app/client/{alarm => }/alarm_settings.html | 16 +-- app/client/alarm_settings.js | 53 ++++++++ app/client/app.js | 24 ---- app/client/settings.js | 6 +- app/client/startup.js | 2 +- app/client/state.js | 20 +-- app/client/surveillance.js | 8 -- app/client/tabs.js | 2 +- app/common/collections.js | 4 - app/lib/zoblak.js | 44 ++++++ app/server/api.js | 15 ++ app/server/methods.js | 151 ++++++++++++++++++--- 16 files changed, 270 insertions(+), 130 deletions(-) rename app/client/{alarm => }/alarm.html (85%) rename app/client/{alarm => }/alarm.js (75%) delete mode 100644 app/client/alarm/alarm_settings.js rename app/client/{alarm => }/alarm_settings.html (67%) create mode 100644 app/client/alarm_settings.js delete mode 100644 app/common/collections.js create mode 100644 app/lib/zoblak.js diff --git a/.gitignore b/.gitignore index 08597d2..ecee633 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ dist/ downloads/ eggs/ .eggs/ -lib/ lib64/ parts/ sdist/ diff --git a/app/client/alarm/alarm.html b/app/client/alarm.html similarity index 85% rename from app/client/alarm/alarm.html rename to app/client/alarm.html index a22ee6b..569d8b5 100644 --- a/app/client/alarm/alarm.html +++ b/app/client/alarm.html @@ -4,7 +4,7 @@

Temperatura

{{#with last_reading}} -
{{temperatureValue}}°C
+
{{ all_temperatures }}
{{pretty_time created_at}}
{{/with}} diff --git a/app/client/alarm/alarm.js b/app/client/alarm.js similarity index 75% rename from app/client/alarm/alarm.js rename to app/client/alarm.js index 805d5c5..e43f56d 100644 --- a/app/client/alarm/alarm.js +++ b/app/client/alarm.js @@ -27,6 +27,15 @@ Template.alarm.helpers({ last_reading: last_sensor_reading, pretty_time: function(time) { return moment(time).format("DD.MM.YYYY, HH:mm") + }, + all_temperatures: function() { + var result=""; + var temperatures = last_sensor_reading().temperatures; + + for(var i in temperatures) { + result += '' + parseFloat(temperatures[i]).toFixed(1) + ' °C '; + } + return result; } }); diff --git a/app/client/alarm/alarm_settings.js b/app/client/alarm/alarm_settings.js deleted file mode 100644 index 6b7118d..0000000 --- a/app/client/alarm/alarm_settings.js +++ /dev/null @@ -1,43 +0,0 @@ - -Template.settings.helpers({ - timeSelected: function(time) { - var config = controller_state().config; - return config.automaticTimeOfDay == time; - }, - - dayChecked: function(day) { - var config = controller_state().config; - var days = config.automaticDaysOfWeek || []; - return days.includes(day) - }, - - manualInflowChecked: function(day) { - var config = controller_state().config; - return config.manualInflow; - } - - -}); - -Template.settings.events({ - 'click #save_settings': function() { - var instance = Template.instance(); - selectedTime = instance.$('#time_of_day').val(); - selectedDays = []; - instance.$('.day_checkbox').each(function() { - if (this.checked) { - selectedDays.push(instance.$(this).val()); - } - }); - var manualInflow = instance.$('#manual_inflow').is(':checked'); - console.log("MI ", manualInflow); - var controller_id = Session.get('controller_id'); - Meteor.call('saveControllerConfig', controller_id, selectedTime, selectedDays, manualInflow); - } -}); - -Template.sensorData.helpers({ - created_at_formatted: function() { - return moment(this.created_at).format("DD.MM.YYYY, HH:mm") - } -}); diff --git a/app/client/alarm/alarm_settings.html b/app/client/alarm_settings.html similarity index 67% rename from app/client/alarm/alarm_settings.html rename to app/client/alarm_settings.html index f6706ad..36d8b2d 100644 --- a/app/client/alarm/alarm_settings.html +++ b/app/client/alarm_settings.html @@ -17,25 +17,25 @@ ako je temperatura niža od - °C + °C ako je temperatura viša od - °C + °C ako se Zoblak Alarm Kutija ne javi - minuta + minuta ako se bar jedan mobitel ne javi - minuta + minuta
@@ -46,27 +46,27 @@ 1. - + 2. - + 3. - + 4. - + diff --git a/app/client/alarm_settings.js b/app/client/alarm_settings.js new file mode 100644 index 0000000..a1f2da9 --- /dev/null +++ b/app/client/alarm_settings.js @@ -0,0 +1,53 @@ +controller_state = function() { + var controller = Session.get('controller_id'); + var result = {} + if (controller) { + result = ControllerState.findOne({ + controller_id: controller + }); + } + + if (!result) { + result = {} + }; + return result; +}; + +config = function() { + return Meteor.zoblak.client.controller_state().config; +} + + +Template.alarm_settings.helpers({ + config: function(property) { + + console.log('asking for property', property); + console.log('config is', config()); + var result = config()[property]; + console.log('returning', result); + return result; + } +}); + +Template.alarm_settings.events({ + 'click #save_settings': function() { + var controller_id = Meteor.zoblak.client.controller_state().controller_id; + var instance = Template.instance(); + var minTemperature = instance.$('#min_temperature').val(); + var maxTemperature = instance.$('#max_temperature').val(); + var timeoutBox = instance.$('#timeout_box').val(); + var timeoutPhone = instance.$('#timeout_phone').val(); + var sms1 = instance.$('#sms1').val(); + var sms2 = instance.$('#sms2').val(); + var sms3 = instance.$('#sms3').val(); + var sms4 = instance.$('#sms4').val(); + + Meteor.call('saveAlarmSettings', controller_id, minTemperature, maxTemperature, timeoutBox, timeoutPhone, [sms1, sms2, sms3, sms4]); + } +}); + +Template.sensorData.helpers({ + created_at_formatted: function() { + return moment(this.created_at).format("DD.MM.YYYY, HH:mm") + } +}); diff --git a/app/client/app.js b/app/client/app.js index 77bfb8c..a54400f 100644 --- a/app/client/app.js +++ b/app/client/app.js @@ -6,27 +6,3 @@ Template.body.helpers({ return Session.get("templateName"); } }); - -controller_state = function() { - var controller = Session.get('controller_id'); - var result = {} - if (controller) { - result = ControllerState.findOne({ - controller_id: controller - }); - } - - if (!result) { - result = {} - }; - return result; -}; - -accessible = function(feature) { - var controller = controller_state(); - - console.log('cotnroller ', controller); - if (!controller.features) return false; - - return controller.features[feature] === true; -} diff --git a/app/client/settings.js b/app/client/settings.js index 6b7118d..20f7298 100644 --- a/app/client/settings.js +++ b/app/client/settings.js @@ -1,18 +1,18 @@ Template.settings.helpers({ timeSelected: function(time) { - var config = controller_state().config; + var config = Meteor.zoblak.client.controller_state().config; return config.automaticTimeOfDay == time; }, dayChecked: function(day) { - var config = controller_state().config; + var config = Meteor.zoblak.client.controller_state().config; var days = config.automaticDaysOfWeek || []; return days.includes(day) }, manualInflowChecked: function(day) { - var config = controller_state().config; + var config = Meteor.zoblak.client.controller_state().config; return config.manualInflow; } diff --git a/app/client/startup.js b/app/client/startup.js index 862d092..8610e56 100644 --- a/app/client/startup.js +++ b/app/client/startup.js @@ -8,7 +8,7 @@ Tracker.autorun(function() { }); Router.route('/', function() { - if (accessible('start')) { + if (Meteor.zoblak.client.accessible('start')) { Session.set('templateName', 'start'); } else { Session.set('templateName', 'no_access') diff --git a/app/client/state.js b/app/client/state.js index dceeee7..01ec4db 100644 --- a/app/client/state.js +++ b/app/client/state.js @@ -1,11 +1,3 @@ -function controller_state() { - var controllerId = Session.get('controller_id'); - result = ControllerState.findOne({}); - if (!result) { - result = {} - }; - return result; -}; function sensor_data_collection() { var controllerId = Session.get('controller_id'); @@ -44,7 +36,7 @@ Template.state.helpers({ bucket_image: function() { var sensor = last_sensor_reading(); - var stateObject = controller_state(); + var stateObject = Meteor.zoblak.client.controller_state(); if (sensor) { if (parseInt(sensor.tankFull) === 0 && stateObject.state.in_valve === 'open' && stateObject.state.out_valve === 'closed') return "/images/barrellFillingUp.png"; else if (parseInt(sensor.tankFull) === 1 && (stateObject.state.out_valve === 'closed')) return "/images/barrellFull.png"; @@ -74,7 +66,7 @@ Template.state.helpers({ }, water_now_button_class: function() { - var stateObject = controller_state(); + var stateObject = Meteor.zoblak.client.controller_state(); if (stateObject.state && (stateObject.state.out_valve === 'open' || stateObject.state.out_valve === 'opening')) { return 'hidden btn btn-success'; } else { @@ -82,7 +74,7 @@ Template.state.helpers({ } }, stop_button_class: function() { - var stateObject = controller_state(); + var stateObject = Meteor.zoblak.client.controller_state(); if (stateObject.state && (stateObject.state.out_valve === 'closed' || stateObject.state.out_valve === 'closing')) { return 'hidden btn btn-success'; } else { @@ -91,7 +83,7 @@ Template.state.helpers({ }, start_inflow_button_class: function() { - var stateObject = controller_state(); + var stateObject = Meteor.zoblak.client.controller_state(); if(stateObject.config && stateObject.config.manualInflow && stateObject.state.out_valve === 'closed' && ( stateObject.state.in_valve === 'closed' || stateObject.state.in_valve === 'closing')) { return 'btn btn-danger' } else { @@ -100,7 +92,7 @@ Template.state.helpers({ }, stop_inflow_button_class: function() { - var stateObject = controller_state(); + var stateObject = Meteor.zoblak.client.controller_state(); if(stateObject.config && stateObject.config.manualInflow && stateObject.state.out_valve === 'closed' && ( stateObject.state.in_valve === 'open' || stateObject.state.in_valve === 'opening')) { return 'btn btn-danger' } else { @@ -159,7 +151,7 @@ Template.state.events({ }, 'click #bucket_image': function() { - Modal.show('state_details', controller_state()); + Modal.show('state_details', Meteor.zoblak.client.controller_state()); } }); diff --git a/app/client/surveillance.js b/app/client/surveillance.js index d61bd35..9e3ab25 100644 --- a/app/client/surveillance.js +++ b/app/client/surveillance.js @@ -1,11 +1,3 @@ -function controller_state() { - var controllerId = Session.get('controller_id'); - result = ControllerState.findOne({}); - if (!result) { - result = {} - }; - return result; -}; function picture() { var controllerId = Session.get('controller_id'); diff --git a/app/client/tabs.js b/app/client/tabs.js index 199fca6..e29df30 100644 --- a/app/client/tabs.js +++ b/app/client/tabs.js @@ -15,7 +15,7 @@ Template.tabs.helpers({ return Session.get('controller_id'); }, - accessible: accessible + accessible: Meteor.zoblak.client.accessible }); Template.tabs.events({ diff --git a/app/common/collections.js b/app/common/collections.js deleted file mode 100644 index 84c7465..0000000 --- a/app/common/collections.js +++ /dev/null @@ -1,4 +0,0 @@ - -SensorData = new Mongo.Collection("sensorData"); -ControllerState = new Mongo.Collection("controller_states"); -Picture = new Mongo.Collection("pictures"); diff --git a/app/lib/zoblak.js b/app/lib/zoblak.js new file mode 100644 index 0000000..7f966b2 --- /dev/null +++ b/app/lib/zoblak.js @@ -0,0 +1,44 @@ +SensorData = new Mongo.Collection("sensorData"); +ControllerState = new Mongo.Collection("controller_states"); +Picture = new Mongo.Collection("pictures"); + + +Meteor.zoblak = {} +Meteor.zoblak.client = { + controller_state: function() { + result = ControllerState.findOne({}); + if (!result) { + result = {} + }; + return result; + }, + + config: function() { + Meteor.zoblak.client.controller_state().config + }, + + accessible: function(feature) { + var controller = Meteor.zoblak.client.controller_state(); + + console.log('cotnroller ', controller); + if (!controller.features) return false; + + return controller.features[feature] === true; + } +} + +Meteor.zoblak.server = { + controller_state: function(controller_id) { + var result = {} + if (controller_id) { + result = ControllerState.findOne({ + controller_id: controller_id + }); + } + + if (!result) { + result = {} + }; + return result; + } +} diff --git a/app/server/api.js b/app/server/api.js index f34d63a..4b174d8 100644 --- a/app/server/api.js +++ b/app/server/api.js @@ -13,6 +13,7 @@ Api.addRoute('sensorData', { var sensorObject = { temperatureValue: parseFloat(this.bodyParams.temperatureValue), humidityValue: parseFloat(this.bodyParams.humidityValue), + temperatures: this.bodyParams.temperatures, tankLevel0: this.bodyParams.tankLevel0, tankLevel1: this.bodyParams.tankLevel1, tankLevel2: this.bodyParams.tankLevel2, @@ -96,6 +97,20 @@ reactToSensorData = function(nextSensorReading) { } } +Api.addRoute('alarm/:id/stop', { + authRequired: false +}, { + post: function() { + var state = Meteor.zoblak.server.controller_state(controller_id); + ControllerState.update(state._id, { + '$set': { + 'state.alarmTriggered': false, + 'state.alarmStopped': new Date() + } + }); + } +}); + Api.addRoute('state/:id', { authRequired: false }, { diff --git a/app/server/methods.js b/app/server/methods.js index 4459f77..ac3f77f 100644 --- a/app/server/methods.js +++ b/app/server/methods.js @@ -1,19 +1,6 @@ -function controller_state(controller_id) { - var result = {} - if (controller_id) { - result = ControllerState.findOne({ - controller_id: controller_id - }); - } - - if (!result) { - result = {} - }; - return result; -}; function setOutValveTo(controller_id, nextState) { - var state = controller_state(controller_id); + var state = Meteor.zoblak.server.controller_state(controller_id); ControllerState.update(state._id, { '$set': { 'state.out_valve': nextState, @@ -33,7 +20,7 @@ function setOutValveTo(controller_id, nextState) { } function setInValveTo(controller_id, nextState) { - var state = controller_state(controller_id); + var state = Meteor.zoblak.server.controller_state(controller_id); ControllerState.update(state._id, { '$set': { 'state.in_valve': nextState, @@ -53,7 +40,7 @@ function setInValveTo(controller_id, nextState) { } function requestNewPicture(controller_id) { - var state = controller_state(controller_id); + var state = Meteor.zoblak.server.controller_state(controller_id); ControllerState.update(state._id, { '$set': { 'state.picture_requested': 'true', @@ -64,7 +51,7 @@ function requestNewPicture(controller_id) { }; function openInValve(controller_id) { - var state = controller_state(controller_id); + var state = Meteor.zoblak.server.controller_state(controller_id); var config = state.config; if (config.manualInflow) { setInValveTo(controller_id, 'opening'); @@ -73,7 +60,7 @@ function openInValve(controller_id) { } function closeInValve(controller_id) { - var state = controller_state(controller_id); + var state = Meteor.zoblak.server.controller_state(controller_id); var config = state.config; if (config.manualInflow) { setInValveTo(controller_id, 'closing'); @@ -87,7 +74,7 @@ function closeInValve(controller_id) { function openOutValve(controller_id) { setOutValveTo(controller_id, 'opening'); setInValveTo(controller_id, 'closing'); - var state = controller_state(controller_id); + var state = Meteor.zoblak.server.controller_state(controller_id); var config = state.config; var jobName = "Close out valve " + state.controller_id + " after draining"; console.log("Opening valve ", controller_id, jobName); @@ -108,7 +95,7 @@ function openOutValve(controller_id) { } function closeOutValve(controller_id) { - var state = controller_state(controller_id); + var state = Meteor.zoblak.server.controller_state(controller_id); var jobName = "Close out valve " + state.controller_id + " after draining"; console.log("Closing valve ", controller_id, jobName); @@ -127,7 +114,7 @@ function clearLog() { } function saveControllerConfig(controller_id, time, days, manualInflow) { - var state = controller_state(controller_id); + var state = Meteor.zoblak.server.controller_state(controller_id); ControllerState.update(state._id, { '$set': { 'config.automaticTimeOfDay': time, @@ -157,6 +144,125 @@ function saveControllerConfig(controller_id, time, days, manualInflow) { }); } +function saveAlarmSettings(controller_id, minTemperature, maxTemperature, timeoutBox, timeoutPhone, smsNumbers) { + var state = Meteor.zoblak.server.controller_state(controller_id); + ControllerState.update(state._id, { + '$set': { + 'config.minTemperature': parseFloat(minTemperature), + 'config.maxTemperature': parseFloat(maxTemperature), + 'config.timeoutBox': parseInt(timeoutBox), + 'config.timeoutPhone': parseInt(timeoutPhone), + 'config.smsNumbers': smsNumbers, + 'config.sms1': smsNumbers[0], + 'config.sms2': smsNumbers[1], + 'config.sms3': smsNumbers[2], + 'config.sms4': smsNumbers[3] + } + }); + var jobName = "automatic_alarm_" + controller_id; + + SyncedCron.remove(jobName); + SyncedCron.add({ + name: jobName, + schedule: function(parser) { + return parser.text('every 30 seconds'); + }, + job: function() { + reactToAlarmData(controller_id); + } + }); +} + +function reactToAlarmData(controller_id) { + var reading = last_sensor_reading(controller_id); + var state = Meteor.zoblak.server.controller_state(controller_id); + var config = state.config; + + var minTemperature = function(temperatures) { + // if it gets a lot colder than absolute zero we will + // we will have more problems than the bug in this code + if(size(temperatures) <= 0) return -1000; + var minimal = parseFloat(temperatures[0]); + for (var i in temperatures) { + if (parseFloat(temperatures[i]) < minimal) { + minimal = parseFloat(temperatures[i]); + } + } + return minimal; + } + + var maxTemperature = function(temperatures) { + // obviously - hell is not supported in this version + if(size(temperatures) <= 0) return 1000; + var maximal = parseFloat(temperatures[0]); + for (var i in temperatures) { + if (parseFloat(temperatures[i]) > maximal) { + maximal = parseFloat(temperatures[i]); + } + } + return maximal; + } + + var tooCold = config.minTemperature && (minTemperature(reading.temperatures) < config.minTemperature); + + var tooHot = config.maxTemperature && (maxTemperature(reading.temperatures) > config.maxTemperature); + + var minutesSinceLastBoxContact = state.lastBoxContact ? moment(state.lastBoxContact).diff(moment(new Date()), 'minutes') : -1; + var boxSilent = config.timeoutBox && minutesSinceLastBoxContact > config.timeoutBox; + + var minutesSinceLastPhoneContact = state.lastPhoneContact ? moment(state.lastPhoneContact).diff(moment(new Date()), 'minutes') : -1; + var phoneSilent = config.timeoutPhone && minutesSinceLastPhoneContact > config.timeoutPhone; + + if (tooCold || tooHot || boxSilent || phoneSilent) { + soundTheAlarm(tooCold, tooHot, boxSilent, phoneSilent); + } +} + +function soundTheAlarm(tooCold, tooHot, boxSilent, phoneSilent) { + var state = Meteor.zoblak.server.controller_state(controller_id); + var reason = { + tooHot: tooHot, + tooCold: tooCold, + boxSilent: boxSilent, + phoneSilent: phoneSilent + }; + + if (!state.state.alarmTriggered) { + ControllerState.update(state._id, { + '$set': { + 'state.alarmTriggered': true, + 'state.alarmStarted': new Date(), + 'state.alarmStopped': null, + 'state.alarmReasons': reason + } + }); + if (boxSilent || phoneSilent) { + sendAlarmingSms(reason, state.config.smsNumbers) + } + } +} + +function sendAlarmingSms(reason, numbers) { + for (var i in numbers) { + var number = numbers[i]; + twilio = Twilio('AC10d7ed0bf54c1be4b1cd7133130e63f4', 'e133d3f02a69b79e93ad9ca1d73517d1'); + twilio.sendSms({ + to: number, // Any number Twilio can deliver to + from: '+43676800104260', // A number you bought from Twilio and can use for outbound communication + body: 'Zoblak alarm! Pokrenite aplikaciju! HITNO!' // body of the SMS message + }, function(err, responseData) { //this function is executed when a response is received from Twilio + if (!err) { // "err" is an error received during the request, if any + // "responseData" is a JavaScript object containing data received from Twilio. + // A sample response from sending an SMS message is here (click "JSON" to see how the data appears in JavaScript): + // http://www.twilio.com/docs/api/rest/sending-sms#example-1 + console.log(responseData.from); // outputs "+14506667788" + console.log(responseData.body); // outputs "word to your mother." + } + }); + } +} + + function last_sensor_reading(controller_id) { var result = null; @@ -186,5 +292,6 @@ Meteor.methods({ closeInValve: closeInValve, clearLog: clearLog, saveControllerConfig: saveControllerConfig, - requestNewPicture: requestNewPicture + requestNewPicture: requestNewPicture, + saveAlarmSettings: saveAlarmSettings });