diff --git a/app/.meteor/packages b/app/.meteor/packages
index 3acc393..f9a45b9 100644
--- a/app/.meteor/packages
+++ b/app/.meteor/packages
@@ -25,3 +25,4 @@ momentjs:moment
selaias:meteor-simpleweather
u2622:persistent-session
percolate:synced-cron
+rzymek:moment-locale-bs
diff --git a/app/.meteor/versions b/app/.meteor/versions
index e6cf2c9..fe6158d 100644
--- a/app/.meteor/versions
+++ b/app/.meteor/versions
@@ -1,4 +1,5 @@
accounts-base@1.2.2
+accounts-password@1.1.4
amplify@1.0.0
autopublish@1.0.4
autoupdate@1.2.4
@@ -25,6 +26,7 @@ diff-sequence@1.0.1
ecmascript@0.1.6
ecmascript-runtime@0.2.6
ejson@1.0.7
+email@1.0.8
es5-shim@4.1.14
fastclick@1.0.7
geojson-utils@1.0.4
@@ -33,8 +35,8 @@ hot-code-push@1.0.0
html-tools@1.0.5
htmljs@1.0.5
http@1.1.1
-huttonr:bootstrap3@3.3.5_10
-huttonr:bootstrap3-assets@3.3.5_6
+huttonr:bootstrap3@3.3.6_6
+huttonr:bootstrap3-assets@3.3.6_2
id-map@1.0.4
insecure@1.0.4
jquery@1.11.4
@@ -50,10 +52,11 @@ minifiers@1.1.7
minimongo@1.0.10
mobile-experience@1.0.1
mobile-status-bar@1.0.6
-momentjs:moment@2.10.6
+momentjs:moment@2.11.2
mongo@1.1.3
mongo-id@1.0.1
-nimble:restivus@0.8.4
+nimble:restivus@0.8.7
+npm-bcrypt@0.7.8_2
npm-mongo@1.4.39_1
observe-sequence@1.0.7
ordered-dict@1.0.4
@@ -66,12 +69,15 @@ reactive-var@1.0.6
reload@1.1.4
retry@1.0.4
routepolicy@1.0.6
+rzymek:moment-locale-bs@2.9.0
selaias:meteor-simpleweather@0.6.8
service-configuration@1.0.5
session@1.1.1
-simple:json-routes@1.0.4
+sha@1.0.4
+simple:json-routes@2.0.1
spacebars@1.0.7
spacebars-compiler@1.0.7
+srp@1.0.4
standard-minifiers@1.0.2
templating@1.1.5
templating-tools@1.0.0
diff --git a/app/client/app.html b/app/client/app.html
index 62dbde6..c9acb5a 100644
--- a/app/client/app.html
+++ b/app/client/app.html
@@ -4,6 +4,7 @@
+
@@ -14,7 +15,7 @@
{{> Template.dynamic template=template_name }}
-
+
diff --git a/app/client/app.less b/app/client/app.less
index 2f32c35..86e3a66 100644
--- a/app/client/app.less
+++ b/app/client/app.less
@@ -6,3 +6,8 @@
.controller_selection {
padding-top: 10px;
}
+
+
+#bucket_image {
+ width: 30%;
+}
diff --git a/app/client/log.js b/app/client/log.js
index add5112..e204342 100644
--- a/app/client/log.js
+++ b/app/client/log.js
@@ -1,12 +1,16 @@
+function sensor_data_collection() {
+ var controllerId = Session.get('controller_id');
+ return SensorData.find({
+ controllerId: controllerId
+ }, {
+ sort: {
+ created_at: -1
+ }
+ });
+}
+
Template.log.helpers({
- sensorDataCollection: function() {
- var controllerId = Session.get('controller_id');
- return SensorData.find({ controllerId: controllerId }, {
- sort: {
- created_at: -1
- }
- });
- }
+ sensorDataCollection: sensor_data_collection
});
Template.log.events({
diff --git a/app/client/settings.html b/app/client/settings.html
new file mode 100644
index 0000000..a49c7fd
--- /dev/null
+++ b/app/client/settings.html
@@ -0,0 +1,89 @@
+
+
+
+
diff --git a/app/client/settings.js b/app/client/settings.js
new file mode 100644
index 0000000..a20a04a
--- /dev/null
+++ b/app/client/settings.js
@@ -0,0 +1,50 @@
+function controller_state() {
+ var controller = Session.get('controller_id');
+ var result = {}
+ if (controller) {
+ result = ControllerState.findOne({
+ controller_id: controller
+ });
+ }
+
+ if (!result) {
+ result = {}
+ };
+ return result;
+};
+
+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)
+ },
+
+
+});
+
+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 controller_id = Session.get('controller_id');
+ Meteor.call('saveControllerConfig', controller_id, selectedTime, selectedDays);
+ }
+});
+
+Template.sensorData.helpers({
+ created_at_formatted: function() {
+ return moment(this.created_at).format("DD.MM.YYYY, HH:mm")
+ }
+});
diff --git a/app/client/state.html b/app/client/state.html
index ca32d42..2aacea9 100644
--- a/app/client/state.html
+++ b/app/client/state.html
@@ -1,18 +1,24 @@
+
+ {{#with controller_state}}
+
{{controller_id}}
+

{{#with last_sensor_reading}}
+
+ {{ temperatureValue }} °C, {{ humidityValue }} %
+
+
-
Controller state
-
-{{#with controller_state}}
-
Controller broj: {{controller_id}}
-
Otpusni ventil: {{pretty_valve state.out_valve }}
-
Stanje postavio: {{ set_by }}
-
Zadnja komunikacija: {{time}}
-{{/with}}
-
-
-
-
-
-
+
+ {{/with}}
+
Otpusni ventil: {{pretty_valve state.out_valve }}
+
Zadnja komunikacija: {{ last_communication_time }}
+ {{/with}}
+
+
+
+
+
+
+
diff --git a/app/client/state.js b/app/client/state.js
index 9b0088f..17b9edb 100644
--- a/app/client/state.js
+++ b/app/client/state.js
@@ -1,58 +1,96 @@
-if (Meteor.isClient) {
+function controller_state() {
+ var controller = Session.get('controller_id');
+ var result = {}
+ if (controller) {
+ result = ControllerState.findOne({
+ controller_id: controller
+ });
+ }
- function controller_state() {
- var controller = Session.get('controller_id');
- var result = {}
- if (controller) {
- result = ControllerState.findOne({
- controller_id: controller
- });
- }
-
- if (!result) {
- result = {}
- };
- return result;
+ if (!result) {
+ result = {}
};
+ return result;
+};
- Template.state.helpers({
- controller_state: controller_state,
- pretty_valve: function(state) {
- if (state === 'open') return "Otvoren";
- if (state === 'opening') return "Otvara se";
- if (state === 'closing') return "Zatvara se";
- if (state === 'closed') return "Zatvoren";
- },
-
- water_now_button_class: function () {
- var stateObject = controller_state();
- if (stateObject.state && ( stateObject.state.out_valve === 'open' || stateObject.state.out_valve === 'opening' )) {
- return 'hidden';
- } else {
- return '';
- }
- },
- stop_button_class: function () {
- var stateObject = controller_state();
- if (stateObject.state && ( stateObject.state.out_valve === 'closed' || stateObject.state.out_valve === 'closing' )) {
- return 'hidden';
- } else {
- return '';
- }
+function sensor_data_collection() {
+ var controllerId = Session.get('controller_id');
+ return SensorData.find({
+ controllerId: controllerId
+ }, {
+ sort: {
+ created_at: -1
}
-
- });
-
- Template.state.events({
- 'click #water_now': function() {
- var controller_id = Session.get('controller_id');
- Meteor.call('openOutValve',controller_id )
- },
-
- 'click #stop_water_now': function() {
- var controller_id = Session.get('controller_id');
- Meteor.call('closeOutValve',controller_id )
- }
-
});
}
+
+function last_sensor_reading() {
+ var controller = Session.get('controller_id');
+ var result = null;
+ if (controller) {
+ result = sensor_data_collection();
+ }
+ if (result && result.count() > 0) {
+ return result.fetch()[0];
+ } else {
+ return {}
+ }
+}
+
+
+Template.state.helpers({
+ controller_state: controller_state,
+ pretty_valve: function(state) {
+ if (state === 'open') return "Otvoren";
+ if (state === 'opening') return "Otvara se";
+ if (state === 'closing') return "Zatvara se";
+ if (state === 'closed') return "Zatvoren";
+ },
+
+ bucket_image: function() {
+ var sensor = last_sensor_reading();
+ if (sensor && sensor.tankFull === "1") {
+ return "/images/barell_full.png";
+ } else {
+ return "/images/barell_draining.png";
+ }
+ },
+
+ last_sensor_reading: last_sensor_reading,
+
+ last_communication_time: function() {
+ return moment(controller_state().time).fromNow();
+ },
+
+
+ water_now_button_class: function() {
+ var stateObject = controller_state();
+ if (stateObject.state && (stateObject.state.out_valve === 'open' || stateObject.state.out_valve === 'opening')) {
+ return 'hidden';
+ } else {
+ return '';
+ }
+ },
+ stop_button_class: function() {
+ var stateObject = controller_state();
+ if (stateObject.state && (stateObject.state.out_valve === 'closed' || stateObject.state.out_valve === 'closing')) {
+ return 'hidden';
+ } else {
+ return '';
+ }
+ }
+
+});
+
+Template.state.events({
+ 'click #water_now': function() {
+ var controller_id = Session.get('controller_id');
+ Meteor.call('openOutValve', controller_id)
+ },
+
+ 'click #stop_water_now': function() {
+ var controller_id = Session.get('controller_id');
+ Meteor.call('closeOutValve', controller_id)
+ }
+
+});
diff --git a/app/client/tabs.html b/app/client/tabs.html
index 2ecc58e..d285cff 100644
--- a/app/client/tabs.html
+++ b/app/client/tabs.html
@@ -1,8 +1,10 @@
+
diff --git a/app/client/tabs.js b/app/client/tabs.js
index f42c1d6..0de0d4b 100644
--- a/app/client/tabs.js
+++ b/app/client/tabs.js
@@ -1,39 +1,38 @@
-if (Meteor.isClient) {
+Template.tabs.helpers({
+ class_for: function(tab_name) {
+ var templateName = Session.get('templateName');
- Template.tabs.helpers({
- class_for: function(tab_name) {
- var templateName = Session.get('templateName');
-
- if (templateName === tab_name) {
- return tab_name + ' active';
- } else if (templateName === 'display' && tab_name === 'news') {
- return tab_name + ' active'
- } else {
- return tab_name;
- }
- },
-
- selected_controller: function() {
- return Session.get('controller_id');
- },
- });
-
- Template.tabs.events({
- 'click .start': function() {
- Session.set('templateName', 'start');
- },
- 'click .weather': function() {
- Session.set('templateName', 'weather');
- },
- 'click .log': function() {
- Session.set('templateName', 'log');
- },
-
- 'click #switch': function() {
- var instance = Template.instance();
- controller_id = instance.$('#controller').val();
- Session.setPersistent('controller_id', controller_id);
+ if (templateName === tab_name) {
+ return tab_name + ' active';
+ } else if (templateName === 'display' && tab_name === 'news') {
+ return tab_name + ' active'
+ } else {
+ return tab_name;
}
- });
+ },
-}
+ selected_controller: function() {
+ return Session.get('controller_id');
+ },
+});
+
+Template.tabs.events({
+ 'click .start': function() {
+ Session.set('templateName', 'start');
+ },
+ 'click .weather': function() {
+ Session.set('templateName', 'weather');
+ },
+ 'click .log': function() {
+ Session.set('templateName', 'log');
+ },
+ 'click .settings': function() {
+ Session.set('templateName', 'settings');
+ },
+
+ 'click #switch': function() {
+ var instance = Template.instance();
+ controller_id = instance.$('#controller').val();
+ Session.setPersistent('controller_id', controller_id);
+ }
+});
diff --git a/app/public/images/barell_draining.png b/app/public/images/barell_draining.png
new file mode 100644
index 0000000..f1efa87
Binary files /dev/null and b/app/public/images/barell_draining.png differ
diff --git a/app/public/images/barell_full.png b/app/public/images/barell_full.png
new file mode 100644
index 0000000..a78c0d4
Binary files /dev/null and b/app/public/images/barell_full.png differ
diff --git a/app/server/methods.js b/app/server/methods.js
index add245e..cf991ea 100644
--- a/app/server/methods.js
+++ b/app/server/methods.js
@@ -47,7 +47,7 @@ function closeOutValve(controller_id) {
var state = controller_state(controller_id);
var jobName = "Close out valve " + state.controller_id + " after draining";
- console.log("Closing valve ", controller_id, jobName);
+ console.log("Closing valve ", controller_id, jobName);
SyncedCron.remove(jobName);
setOutValveTo(controller_id, 'closing');
console.log("Finished clearing cron ", controller_id);
@@ -58,8 +58,39 @@ function clearLog() {
SensorData.remove({});
}
+function saveControllerConfig(controller_id, time, days) {
+ var state = controller_state(controller_id);
+ ControllerState.update(state._id, {
+ '$set': {
+ 'config.automaticTimeOfDay': time,
+ 'config.automaticDaysOfWeek': days
+ }
+ });
+ var jobName = "automatic_" + controller_id;
+ var times = time.split(":");
+ var hours = parseInt(times[0]);
+ var minutes = parseInt(times[1]);
+
+ SyncedCron.remove(jobName);
+ SyncedCron.add({
+ name: jobName,
+ schedule: function(parser) {
+
+ var period = parser.recur();
+ for (var i = 0; i < days.length; i++) {
+ period = period.and().on(parseInt(days[i])).dayOfWeek().on(hours).hour().on(minutes).minute();
+ }
+ return period;
+ },
+ job: function() {
+ openOutValve(controller_id);
+ }
+ });
+}
+
Meteor.methods({
openOutValve: openOutValve,
closeOutValve: closeOutValve,
- clearLog: clearLog
+ clearLog: clearLog,
+ saveControllerConfig: saveControllerConfig
});