25 Commits

Author SHA1 Message Date
Senad Uka
79df9d05b4 weather works 2016-04-10 10:47:11 +02:00
Senad Uka
f886530f5f upgraded mongo and packages 2016-04-09 07:51:11 +02:00
974f18e067 Merge pull request #14 from senaduka/pre_production_fixes
Pre production fixes
2016-03-26 10:29:01 +01:00
Senad Uka
534497e373 Fixed filling logic 2016-03-26 07:32:53 +01:00
Senad Uka
26052a9afc Created graphs without d3 ;) 2016-03-26 07:28:43 +01:00
Senad Uka
e9e808a1bc Merge pull request #13 from senaduka/image_vise
- fixed names to match barrell*
2016-03-25 20:19:17 +01:00
4197d06819 - fixed names to match barrell*
- added more tag to images
2016-03-22 21:54:13 +01:00
Senad Uka
36d1adc626 Fixed a typo 2016-03-20 08:00:14 +01:00
Senad Uka
2317ad3e61 Some css modifications 2016-03-20 07:54:20 +01:00
b2e619c2c9 Merge pull request #12 from senaduka/ui_modifications
Ui is completely changed
2016-03-19 09:30:36 +01:00
Senad Uka
748dd19a87 Ui is completely changed 2016-03-19 09:23:59 +01:00
Senad Uka
21d364bf52 Merge pull request #11 from senaduka/improved_icon_handling_and_pump_management
Added 4 new images for opening and closing out valve while barrell is…
2016-03-19 04:33:23 +01:00
5cd8420bcf Added 4 new images for opening and closing out valve while barrell is either full or not full... also tried to add additional constraints for pump handling in means of that the pump should not be pumping if the out valve is open or opening 2016-03-18 22:26:41 +01:00
Senad Uka
24a1b81b92 Merge pull request #10 from senaduka/barrel_image_handling
Added proper barrel image handling based on input / sensor readings
2016-03-13 19:00:51 +01:00
829d6cf338 Added proper barrel image handling based on input / sensor readings 2016-03-09 00:35:26 +01:00
a8ac425832 Merge pull request #9 from senaduka/in_valve_support
In valve support
2016-03-06 21:07:56 +01:00
Senad Uka
d15bc0e5a6 problem with python syntax 2016-03-06 14:49:26 +01:00
Senad Uka
ee828c544e syntax error fix 2016-03-06 14:47:42 +01:00
Senad Uka
28e5f7f1f0 safe key getting from the response 2016-03-06 14:46:42 +01:00
Senad Uka
ed8267b6ab ignore existing config 2016-03-06 14:14:26 +01:00
Senad Uka
99fdc768fc config/init.py removed 2016-03-06 14:13:25 +01:00
Senad Uka
c47e1be364 Finished in valve support 2016-03-06 14:07:33 +01:00
Senad Uka
8d9e42c147 reformatted code 2016-03-06 13:40:53 +01:00
Senad Uka
279e0f8652 Added suport for in valve 2016-03-06 13:40:53 +01:00
2395cc6ddf Merge pull request #8 from senaduka/optimize_subscriptions
Optimized subscriptions
2016-03-06 12:05:48 +01:00
37 changed files with 728 additions and 255 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,6 @@
# configuration
controller/config/__init__.py
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

View File

@@ -10,3 +10,4 @@ notices-for-facebook-graph-api-2
1.2.0-meteor-platform-split
1.2.0-cordova-changes
1.2.0-breaking-changes
1.3.0-split-minifiers-package

View File

@@ -12,7 +12,6 @@ session # Client-side reactive dictionary for your app
jquery # Helpful client-side library
tracker # Meteor's client-side reactive programming library
standard-minifiers # JS/CSS minifiers run for production mode
es5-shim # ECMAScript 5 compatibility for older browsers.
ecmascript # Enable ECMAScript2015+ syntax in app code
@@ -24,3 +23,8 @@ selaias:meteor-simpleweather
u2622:persistent-session
percolate:synced-cron
rzymek:moment-locale-bs
peppelg:bootstrap-3-modal
fortawesome:fontawesome
mfpierre:chartist-js
standard-minifier-css
standard-minifier-js

View File

@@ -1 +1 @@
METEOR@1.2.1
METEOR@1.3.1

View File

@@ -1,88 +1,95 @@
accounts-base@1.2.2
accounts-password@1.1.4
accounts-base@1.2.5
accounts-password@1.1.7
allow-deny@1.0.3
amplify@1.0.0
autoupdate@1.2.4
babel-compiler@5.8.24_1
babel-runtime@0.1.4
base64@1.0.4
binary-heap@1.0.4
blaze@2.1.3
blaze-html-templates@1.0.1
blaze-tools@1.0.4
boilerplate-generator@1.0.4
caching-compiler@1.0.0
caching-html-compiler@1.0.2
callback-hook@1.0.4
check@1.1.0
coffeescript@1.0.11
ddp@1.2.2
ddp-client@1.2.1
ddp-common@1.2.2
ddp-rate-limiter@1.0.0
ddp-server@1.2.2
deps@1.0.9
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
handlebars@1.0.4
hot-code-push@1.0.0
html-tools@1.0.5
htmljs@1.0.5
http@1.1.1
huttonr:bootstrap3@3.3.6_6
huttonr:bootstrap3-assets@3.3.6_2
id-map@1.0.4
jquery@1.11.4
json@1.0.3
launch-screen@1.0.4
less@2.5.1
livedata@1.0.15
localstorage@1.0.5
logging@1.0.8
meteor@1.1.10
meteor-base@1.0.1
minifiers@1.1.7
minimongo@1.0.10
mobile-experience@1.0.1
mobile-status-bar@1.0.6
momentjs:moment@2.11.2
mongo@1.1.3
mongo-id@1.0.1
nimble:restivus@0.8.7
autoupdate@1.2.7
babel-compiler@6.6.1
babel-runtime@0.1.7
base64@1.0.7
binary-heap@1.0.7
blaze@2.1.6
blaze-html-templates@1.0.3
blaze-tools@1.0.7
boilerplate-generator@1.0.7
caching-compiler@1.0.3
caching-html-compiler@1.0.5
callback-hook@1.0.7
check@1.1.3
coffeescript@1.0.16
ddp@1.2.4
ddp-client@1.2.4
ddp-common@1.2.4
ddp-rate-limiter@1.0.3
ddp-server@1.2.5
deps@1.0.11
diff-sequence@1.0.4
ecmascript@0.4.2
ecmascript-runtime@0.2.9
ejson@1.0.10
email@1.0.11
es5-shim@4.5.9
fastclick@1.0.10
fortawesome:fontawesome@4.5.0
fourseven:scss@3.4.1
geojson-utils@1.0.7
hot-code-push@1.0.3
html-tools@1.0.8
htmljs@1.0.8
http@1.1.4
huttonr:bootstrap3@3.3.6_10
huttonr:bootstrap3-assets@3.3.6_3
id-map@1.0.6
jquery@1.11.7
launch-screen@1.0.10
less@2.5.7
livedata@1.0.17
localstorage@1.0.8
logging@1.0.11
meteor@1.1.13
meteor-base@1.0.3
mfpierre:chartist-js@1.6.1
minifier-css@1.1.10
minifier-js@1.1.10
minimongo@1.0.13
mobile-experience@1.0.3
mobile-status-bar@1.0.11
modules@0.5.2
modules-runtime@0.6.2
momentjs:moment@2.12.0
mongo@1.1.6
mongo-id@1.0.3
nimble:restivus@0.8.10
npm-bcrypt@0.7.8_2
npm-mongo@1.4.39_1
observe-sequence@1.0.7
ordered-dict@1.0.4
percolate:synced-cron@1.3.0
promise@0.5.1
random@1.0.5
rate-limit@1.0.0
reactive-dict@1.1.3
reactive-var@1.0.6
reload@1.1.4
retry@1.0.4
routepolicy@1.0.6
npm-mongo@1.4.42
observe-sequence@1.0.10
ordered-dict@1.0.6
peppelg:bootstrap-3-modal@1.0.4
percolate:synced-cron@1.3.2
promise@0.6.6
random@1.0.8
rate-limit@1.0.3
reactive-dict@1.1.6
reactive-var@1.0.8
reload@1.1.7
retry@1.0.6
routepolicy@1.0.9
rzymek:moment-locale-bs@2.9.0
selaias:meteor-simpleweather@0.6.8
service-configuration@1.0.5
session@1.1.1
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
tracker@1.0.9
selaias:meteor-simpleweather@0.7.0
service-configuration@1.0.8
session@1.1.4
sha@1.0.6
simple:json-routes@2.1.0
spacebars@1.0.10
spacebars-compiler@1.0.10
srp@1.0.7
standard-minifier-css@1.0.5
standard-minifier-js@1.0.5
templating@1.1.8
templating-tools@1.0.3
tracker@1.0.12
u2622:persistent-session@0.4.4
ui@1.0.8
underscore@1.0.4
url@1.0.5
webapp@1.2.3
webapp-hashing@1.0.5
ui@1.0.10
underscore@1.0.7
url@1.0.8
webapp@1.2.7
webapp-hashing@1.0.8

View File

@@ -2,12 +2,20 @@
padding: 40px 15px;
text-align: center;
}
.controller_selection {
padding-top: 10px;
}
#bucket_image {
width: 60%;
@media all and (orientation: portrait) {
#bucket_image {
width: 90%;
cursor: pointer;
}
}
@media all and (orientation: landscape) {
#bucket_image {
width: 40%;
cursor: pointer;
}
}

View File

@@ -1,88 +1,103 @@
<template name="settings">
<div class="col-md-3 col-md-offset-4">
<h1>Automatsko zaljevanje: </h1>
<select name="time_of_day" id="time_of_day">
<option value="00:00" selected={{ timeSelected "00:00" }}>00:00</option>
<option value="00:30" selected={{ timeSelected "00:30" }}>00:30</option>
<option value="01:00" selected={{ timeSelected "01:00" }}>01:00</option>
<option value="01:30" selected={{ timeSelected "01:30" }}>01:30</option>
<option value="02:00" selected={{ timeSelected "02:00" }}>02:00</option>
<option value="02:30" selected={{ timeSelected "02:30" }}>02:30</option>
<option value="03:00" selected={{ timeSelected "03:00" }}>03:00</option>
<option value="03:30" selected={{ timeSelected "03:30" }}>03:30</option>
<option value="04:00" selected={{ timeSelected "04:00" }}>04:00</option>
<option value="04:30" selected={{ timeSelected "04:30" }}>04:30</option>
<option value="05:00" selected={{ timeSelected "05:00" }}>05:00</option>
<option value="05:30" selected={{ timeSelected "05:30" }}>05:30</option>
<option value="06:00" selected={{ timeSelected "06:00" }}>06:00</option>
<option value="06:30" selected={{ timeSelected "06:30" }}>06:30</option>
<option value="07:00" selected={{ timeSelected "07:00" }}>07:00</option>
<option value="07:30" selected={{ timeSelected "07:30" }}>07:30</option>
<option value="08:00" selected={{ timeSelected "08:00" }}>08:00</option>
<option value="08:30" selected={{ timeSelected "08:30" }}>08:30</option>
<option value="09:00" selected={{ timeSelected "09:00" }}>09:00</option>
<option value="09:30" selected={{ timeSelected "09:30" }}>09:30</option>
<option value="10:00" selected={{ timeSelected "10:00" }}>10:00</option>
<option value="10:30" selected={{ timeSelected "10:30" }}>10:30</option>
<option value="11:00" selected={{ timeSelected "11:00" }}>11:00</option>
<option value="11:30" selected={{ timeSelected "11:30" }}>11:30</option>
<option value="12:00" selected={{ timeSelected "12:00" }}>12:00</option>
<option value="12:30" selected={{ timeSelected "12:30" }}>12:30</option>
<option value="13:00" selected={{ timeSelected "13:00" }}>13:00</option>
<option value="13:30" selected={{ timeSelected "13:30" }}>13:30</option>
<option value="14:00" selected={{ timeSelected "14:00" }}>14:00</option>
<option value="14:30" selected={{ timeSelected "14:30" }}>14:30</option>
<option value="15:00" selected={{ timeSelected "15:00" }}>15:00</option>
<option value="15:30" selected={{ timeSelected "15:30" }}>15:30</option>
<option value="16:00" selected={{ timeSelected "16:00" }}>16:00</option>
<option value="16:30" selected={{ timeSelected "16:30" }}>16:30</option>
<option value="17:00" selected={{ timeSelected "17:00" }}>17:00</option>
<option value="17:30" selected={{ timeSelected "17:30" }}>17:30</option>
<option value="18:00" selected={{ timeSelected "18:00" }}>18:00</option>
<option value="18:30" selected={{ timeSelected "18:30" }}>18:30</option>
<option value="19:00" selected={{ timeSelected "19:00" }}>19:00</option>
<option value="19:30" selected={{ timeSelected "19:30" }}>19:30</option>
<option value="20:00" selected={{ timeSelected "20:00" }}>20:00</option>
<option value="20:30" selected={{ timeSelected "20:30" }}>20:30</option>
<option value="21:00" selected={{ timeSelected "21:00" }}>21:00</option>
<option value="21:30" selected={{ timeSelected "21:30" }}>21:30</option>
<option value="22:00" selected={{ timeSelected "22:00" }}>22:00</option>
<option value="22:30" selected={{ timeSelected "22:30" }}>22:30</option>
<option value="23:00" selected={{ timeSelected "23:00" }}>23:00</option>
<option value="23:30" selected={{ timeSelected "23:30" }}>23:30</option>
</select>
<div>
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<input type="checkbox" id="day_1" name="day_1" value="2" class="day_checkbox" checked="{{ dayChecked '2' }}" />
<label for="day_1">Ponedjeljak</label>
</div>
<div>
<input type="checkbox" id="day_2" name="day_2" value="3" class="day_checkbox" checked="{{ dayChecked '3' }}" />
<label for="day_2">Utorak</label>
</div>
<div>
<input type="checkbox" id="day_3" name="day_3" value="4" class="day_checkbox" checked="{{ dayChecked '4' }}" />
<label for="day_3">Srijeda</label>
</div>
<div>
<input type="checkbox" id="day_4" name="day_4" value="5" class="day_checkbox" checked="{{ dayChecked '5' }}" />
<label for="day_4">Četvrtak</label>
</div>
<div>
<input type="checkbox" id="day_5" name="day_5" value="6" class="day_checkbox" checked="{{ dayChecked '6' }}" />
<label for="day_5">Petak</label>
</div>
<div>
<input type="checkbox" id="day_6" name="day_6" value="7" class="day_checkbox" checked="{{ dayChecked '7' }}" />
<label for="day_6">Subota</label>
</div>
<div>
<input type="checkbox" id="day_7" name="day_7" value="1" class="day_checkbox" checked="{{ dayChecked '1' }}" />
<label for="day_7">Nedjelja</label>
</div>
<div class="modal-header">
<h4 class="modal-title">Automatsko zaljevanje</h4>
</div>
<div>
<button id="save_settings" name="save_settings">Zapamti</button>
<div class="modal-body">
<div class="form-group">
<select name="time_of_day" id="time_of_day" class="form-control">
<option value="00:00" selected={{ timeSelected "00:00" }}>00:00</option>
<option value="00:30" selected={{ timeSelected "00:30" }}>00:30</option>
<option value="01:00" selected={{ timeSelected "01:00" }}>01:00</option>
<option value="01:30" selected={{ timeSelected "01:30" }}>01:30</option>
<option value="02:00" selected={{ timeSelected "02:00" }}>02:00</option>
<option value="02:30" selected={{ timeSelected "02:30" }}>02:30</option>
<option value="03:00" selected={{ timeSelected "03:00" }}>03:00</option>
<option value="03:30" selected={{ timeSelected "03:30" }}>03:30</option>
<option value="04:00" selected={{ timeSelected "04:00" }}>04:00</option>
<option value="04:30" selected={{ timeSelected "04:30" }}>04:30</option>
<option value="05:00" selected={{ timeSelected "05:00" }}>05:00</option>
<option value="05:30" selected={{ timeSelected "05:30" }}>05:30</option>
<option value="06:00" selected={{ timeSelected "06:00" }}>06:00</option>
<option value="06:30" selected={{ timeSelected "06:30" }}>06:30</option>
<option value="07:00" selected={{ timeSelected "07:00" }}>07:00</option>
<option value="07:30" selected={{ timeSelected "07:30" }}>07:30</option>
<option value="08:00" selected={{ timeSelected "08:00" }}>08:00</option>
<option value="08:30" selected={{ timeSelected "08:30" }}>08:30</option>
<option value="09:00" selected={{ timeSelected "09:00" }}>09:00</option>
<option value="09:30" selected={{ timeSelected "09:30" }}>09:30</option>
<option value="10:00" selected={{ timeSelected "10:00" }}>10:00</option>
<option value="10:30" selected={{ timeSelected "10:30" }}>10:30</option>
<option value="11:00" selected={{ timeSelected "11:00" }}>11:00</option>
<option value="11:30" selected={{ timeSelected "11:30" }}>11:30</option>
<option value="12:00" selected={{ timeSelected "12:00" }}>12:00</option>
<option value="12:30" selected={{ timeSelected "12:30" }}>12:30</option>
<option value="13:00" selected={{ timeSelected "13:00" }}>13:00</option>
<option value="13:30" selected={{ timeSelected "13:30" }}>13:30</option>
<option value="14:00" selected={{ timeSelected "14:00" }}>14:00</option>
<option value="14:30" selected={{ timeSelected "14:30" }}>14:30</option>
<option value="15:00" selected={{ timeSelected "15:00" }}>15:00</option>
<option value="15:30" selected={{ timeSelected "15:30" }}>15:30</option>
<option value="16:00" selected={{ timeSelected "16:00" }}>16:00</option>
<option value="16:30" selected={{ timeSelected "16:30" }}>16:30</option>
<option value="17:00" selected={{ timeSelected "17:00" }}>17:00</option>
<option value="17:30" selected={{ timeSelected "17:30" }}>17:30</option>
<option value="18:00" selected={{ timeSelected "18:00" }}>18:00</option>
<option value="18:30" selected={{ timeSelected "18:30" }}>18:30</option>
<option value="19:00" selected={{ timeSelected "19:00" }}>19:00</option>
<option value="19:30" selected={{ timeSelected "19:30" }}>19:30</option>
<option value="20:00" selected={{ timeSelected "20:00" }}>20:00</option>
<option value="20:30" selected={{ timeSelected "20:30" }}>20:30</option>
<option value="21:00" selected={{ timeSelected "21:00" }}>21:00</option>
<option value="21:30" selected={{ timeSelected "21:30" }}>21:30</option>
<option value="22:00" selected={{ timeSelected "22:00" }}>22:00</option>
<option value="22:30" selected={{ timeSelected "22:30" }}>22:30</option>
<option value="23:00" selected={{ timeSelected "23:00" }}>23:00</option>
<option value="23:30" selected={{ timeSelected "23:30" }}>23:30</option>
</select>
</div>
<div class="form-group">
<div>
<input type="checkbox" id="day_1" name="day_1" value="2" class="day_checkbox form_control" checked="{{ dayChecked '2' }}" />
<label for="day_1">Ponedjeljak</label>
</div>
<div>
<input type="checkbox" id="day_2" name="day_2" value="3" class="day_checkbox form_control" checked="{{ dayChecked '3' }}" />
<label for="day_2">Utorak</label>
</div>
<div>
<input type="checkbox" id="day_3" name="day_3" value="4" class="day_checkbox form_control" checked="{{ dayChecked '4' }}" />
<label for="day_3">Srijeda</label>
</div>
<div>
<input type="checkbox" id="day_4" name="day_4" value="5" class="day_checkbox form_control" checked="{{ dayChecked '5' }}" />
<label for="day_4">Četvrtak</label>
</div>
<div>
<input type="checkbox" id="day_5" name="day_5" value="6" class="day_checkbox form_control" checked="{{ dayChecked '6' }}" />
<label for="day_5">Petak</label>
</div>
<div>
<input type="checkbox" id="day_6" name="day_6" value="7" class="day_checkbox form_control" checked="{{ dayChecked '7' }}" />
<label for="day_6">Subota</label>
</div>
<div>
<input type="checkbox" id="day_7" name="day_7" value="1" class="day_checkbox form_control" checked="{{ dayChecked '1' }}" />
<label for="day_7">Nedjelja</label>
</div>
</div>
</div>
<div class="modal-footer">
<button id="save_settings" class="btn btn-default" name="save_settings" data-dismiss="modal">Zapamti</button>
</div>
</div>
</div>
</div>

View File

@@ -1,5 +1,5 @@
<template name="start">
<div class="col-lg-12 text-center">
<div class="col-lg-12 text-center form">
{{>state}}
</div>
</template>

View File

@@ -1,17 +0,0 @@
var options = {
location: 40.7127+','+ 74.0059, // New York
unit: 'c',
success: function(weather) {
html = '<h2><i class="sw icon-'+weather.code+'"></i> '
html += weather.temp+'&deg;'+weather.units.temp+'</h2>';
html += '<ul><li>'+weather.city+', '+weather.region +'</li>';
html += '<li class="currently">'+weather.currently+'</li>';
$("#weather").html(html);
},
error: function(error) {
$("#weather").html('<p>'+error+'</p>');
}
}
Weather.options = options

View File

@@ -1,24 +1,19 @@
<template name="state">
<div class="col-md-3 col-md-offset-4">
<div>&nbsp;</div>
<div class="col-md-12">
{{#with controller_state}}
<h1>{{controller_id}}</h1>
<img src="{{ bucket_image }}" class="img-responsive center-block" id="bucket_image" /> {{#with last_sensor_reading}}
<div>
<strong>{{ temperatureValue }} °C, {{ humidityValue }} % </strong>
<img src="{{ bucket_image }}" class="img-responsive center-block" id="bucket_image" />
<div class="text-center">
{{controller_id}}:
{{#with last_sensor_reading}} <strong> {{ temperatureValue }} °C, {{ humidityValue }} % </strong> {{/with}}
</div>
<div>
<div class="text-center">
Automatsko zalijevanje:<br /> <strong>{{ pretty_days config.automaticDaysOfWeek }} {{ pretty_time config.automaticDaysOfWeek config.automaticTimeOfDay }}</strong> <button id="run_settings" class="btn btn-default"> <i class="fa fa-wrench"></i> </button>
</div>
{{/with}}
<div>Otpusni ventil: {{pretty_valve state.out_valve }}</div>
<div>Zadnja komunikacija: {{ last_communication_time }}</div>
{{/with}}
<div>
<button id="water_now" class="{{ water_now_button_class }}">Zalij sada</button>
<button id="stop_water_now" class="{{ stop_button_class }}">Prekini zalijevanje</button>
</div>
</div>
<div class="col-md-1">
</div>
</template>

View File

@@ -1,7 +1,6 @@
function controller_state() {
var controllerId = Session.get('controller_id');
result = ControllerState.findOne({});
console.log("jupiii", result);
if (!result) {
result = {}
};
@@ -45,39 +44,64 @@ Template.state.helpers({
bucket_image: function() {
var sensor = last_sensor_reading();
if (sensor && sensor.tankFull === "1") {
return "/images/barell_full.png";
} else {
return "/images/barell_draining.png";
}
var stateObject = 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";
else if (parseInt(sensor.tankFull) === 1 && (stateObject.state.out_valve === 'opening')) return "/images/barrellStartWateringFull.png";
else if (parseInt(sensor.tankFull) === 1 && (stateObject.state.out_valve === 'open')) return "/images/barrellWateringFull.png";
else if (parseInt(sensor.tankFull) === 1 && (stateObject.state.out_valve === 'closing')) return "/images/barrellStopWateringFull.png";
else if (parseInt(sensor.tankFull) === 0 && (stateObject.state.out_valve === 'closed')) return "/images/barrellNotFull.png";
else if (parseInt(sensor.tankFull) === 0 && (stateObject.state.out_valve === 'opening')) return "/images/barrellStartWateringNotFull.png";
else if (parseInt(sensor.tankFull) === 0 && (stateObject.state.out_valve === 'open')) return "/images/barrellWateringNotFull.png"
else if (parseInt(sensor.tankFull) === 0 && (stateObject.state.out_valve === 'closing')) return "/images/barrellStopWateringNotFull.png"
else return "/images/statusAmber.png";
} else return "/images/statusRed.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';
return 'hidden btn btn-success';
} else {
return '';
return 'btn btn-success';
}
},
stop_button_class: function() {
var stateObject = controller_state();
if (stateObject.state && (stateObject.state.out_valve === 'closed' || stateObject.state.out_valve === 'closing')) {
return 'hidden';
return 'hidden btn btn-success';
} else {
return '';
return 'btn btn-success';
}
},
pretty_days: function(daysInNumbers) {
var days = ["Nedjelja", "Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota"];
if (!daysInNumbers || daysInNumbers.length == 0) {
return "Nikad"
}
else if (daysInNumbers.length == 7) {
return "Svaki dan"
} else {
return daysInNumbers.map(function(number) {
return days[number -1 ];
}).join(", ");
}
},
pretty_time: function(daysInNumbers, time) {
if (!daysInNumbers || daysInNumbers.length == 0) {
return ""
} else {
return " u " + time;
}
}
});
Template.state.events({
'click #water_now': function() {
var controller_id = Session.get('controller_id');
@@ -87,6 +111,14 @@ Template.state.events({
'click #stop_water_now': function() {
var controller_id = Session.get('controller_id');
Meteor.call('closeOutValve', controller_id)
},
'click #run_settings': function() {
Modal.show('settings');
},
'click #bucket_image': function() {
Modal.show('state_details', controller_state());
}
});

View File

@@ -0,0 +1,44 @@
<template name="state_details">
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Detalji</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12 chart">
<div><strong>Otpusni ventil:</strong> {{pretty_valve state.out_valve }}</div>
<div><strong>Ulazni ventil/pumpa:</strong> {{pretty_valve state.in_valve }}</div>
<div><strong>Zadnja komunikacija: {{ last_communication_time }}</strong>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 chart">
<h3>Temperatura:</h3>
<div id="temperature_graph">
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 chart">
<h3>Vlažnost:</h3>
<div id="humidity_graph">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button id="close_details" class="btn btn-default" name="close_details" data-dismiss="modal">Zatvori</button>
</div>
</div>
</div>
</div>
</template>

108
app/client/state_details.js Normal file
View File

@@ -0,0 +1,108 @@
Template.state_details.helpers({
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";
},
last_communication_time: function() {
return moment(this.time).fromNow();
}
});
Template.state_details.events({});
Template.state_details.rendered = function() {
this.node = this.find('#temperature_graph'); // our d3 code goes here
var yScale = d3.scale.linear()
.domain([0, 4])
.range([10, 60]);
var xScale = d3.scale.linear()
.domain([0, self.duration])
.range([0, $(self.timelineWrapper).width()])
};
function sensor_data_collection() {
var controllerId = Session.get('controller_id');
return SensorData.find({
controllerId: controllerId
}, {
sort: {
created_at: -1
}
});
}
Template.state_details.rendered = function() {
var self = this;
/*
* add point when new temperature is added
*/
setTimeout(function() {
self.autorun(function() {
sensor_data_collection().observe({
added: function(reading) {
buildTemperatureGraph();
buildHumidityGraph()
}
});
});
}, 1000);
}
/*
* Function to draw the graph
*/
function buildTemperatureGraph() {
var sensorReadings = sensor_data_collection();
console.log("Added: ", sensorReadings.count());
var times = sensorReadings.map(function(reading) {
return moment(reading.created_at).format("HH:mm:ss");
});
var values = sensorReadings.map(function(reading) {
return reading.temperatureValue;
});
return new Chartist.Line('#temperature_graph', {
labels: times,
series: [values]
}, {
fullWidth: true,
chartPadding: {
right: 40
}
});
}
/*
* Function to draw the graph
*/
function buildHumidityGraph() {
var sensorReadings = sensor_data_collection();
console.log("Added: ", sensorReadings.count());
var times = sensorReadings.map(function(reading) {
return moment(reading.created_at).format("HH:mm:ss");
});
var values = sensorReadings.map(function(reading) {
return reading.humidityValue;
});
return new Chartist.Line('#humidity_graph', {
labels: times,
series: [values]
}, {
fullWidth: true,
chartPadding: {
right: 40
}
});
}

View File

@@ -4,7 +4,6 @@
<li role="presentation" class="{{ class_for 'start' }}"><a href="#">Stanje</a></li>
<li role="presentation" class="{{ class_for 'weather' }}"><a href="#">Vrijeme</a></li>
<li role="presentation" class="{{ class_for 'log' }}"><a href="#">Novosti</a></li>
<li role="presentation" class="{{ class_for 'settings' }}"><a href="#">Podešavanje</a></li>
<li role="presentation" class="controller_selection"> <input type="number" id="controller" name="controller" value="{{ selected_controller }}" min="1" max="99999"> <button id="switch" name="switch">Prebaci</button>
</li>
</ul>

9
app/client/weather.html Normal file
View File

@@ -0,0 +1,9 @@
<template name="weather">
<div>&nbsp;</div>
<div class="col-md-12">
<div class="text-center">
{{>simpleWeather}}
</div>
</div>
</template>

39
app/client/weather.js Normal file
View File

@@ -0,0 +1,39 @@
var options = {
location: 44.0123 + ',' + 18.19455, // New Visoko
unit: 'c',
success: function(weather) {
html = "<h2><i class='sw icon-" + weather.code + "'></i>";
html += weather.temp + '&deg;' + weather.units.temp + '</h2>';
html += '<ul><li>' + weather.city + ', ' + weather.region + '</li>';
html += "<li class='currently'>" + weather.currently + '</li>';
html += '<hr />';
for (var i = 0; i < 5; i++) {
var forecast = weather.forecast[i];
html += '<div>';
html += "<h2><i class='sw icon-" + forecast.code + "'></i>";
html += forecast.high + '&deg;' + weather.units.temp + '</h2>';
html += "<li class='currently'>" + daysInBosnian[forecast.day] + ': ' + forecast.text + '</li>';
html += "</div>";
}
$('#weather').html(html);
},
error: function(error) {
$('#weather').html('<p>' + error + '</p>');
}
}
var daysInBosnian = {
'Sun': 'Nedjelja',
'Mon': 'Ponedjeljak',
'Tue': 'Utorak',
'Wed': 'Srijeda',
'Thu': 'Četvrtak',
'Fri': 'Petak',
'Sat': 'Subota'
};
Weather.options = options

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -9,7 +9,7 @@ Api.addRoute('sensorData', {
authRequired: false
}, {
post: function() {
console.log("Body params", this.bodyParams);
reactToSensorData(this.bodyParams);
SensorData.insert({
temperatureValue: parseFloat(this.bodyParams.temperatureValue),
humidityValue: parseFloat(this.bodyParams.humidityValue),
@@ -23,16 +23,48 @@ Api.addRoute('sensorData', {
});
function reactToSensorData(nextSensorReading) {
var controllerId = nextSensorReading.controllerId;
var state = stateOrDefault(controllerId).state;
console.log(nextSensorReading , state);
var shouldStartPumping = (!state.in_valve || state.in_valve === 'closed' || state.in_valve === 'closing') && ((parseInt(nextSensorReading.tankFull) === 0) && (state.out_valve === 'closed' || state.out_valve === 'closing'));
var shouldStopPumping = (state.in_valve === 'open' || state.in_valve === 'opening') && (parseInt(nextSensorReading.tankFull) === 1 || state.out_valve === 'open' || state.out_valve === 'opening');
if (shouldStartPumping) {
ControllerState.update({
controller_id: controllerId
}, {
'$set': {
'state.in_valve': 'opening',
'time': new Date(),
'set_by': 'server'
}
});
} else if (shouldStopPumping) {
ControllerState.update({
controller_id: controllerId
}, {
'$set': {
'state.in_valve': 'closing',
'time': new Date(),
'set_by': 'server'
}
});
}
}
Api.addRoute('state/:id', {
authRequired: false
}, {
post: function() {
console.log("Body params", this.bodyParams);
console.log("setting state", this.bodyParams);
return ControllerState.update({
controller_id: this.urlParams.id
}, {
'$set': {
'state.out_valve': this.bodyParams.out_valve,
'state.in_valve': this.bodyParams.in_valve,
'time': new Date(),
'set_by': 'client'
}
@@ -43,6 +75,7 @@ Api.addRoute('state/:id', {
}
});
function stateOrDefault(id) {
var stateEntry = ControllerState.findOne({
controller_id: id,
@@ -52,13 +85,13 @@ function stateOrDefault(id) {
stateEntry = ControllerState.insert({
controller_id: id,
state: {
out_valve: 'closed'
out_valve: 'closed',
in_valve: 'closed'
},
time: new Date(),
config: {
draining_period_amount: 5,
draining_period_amount: 60,
draining_period_unit: 'minutes'
},
set_by: 'server'
});
@@ -68,3 +101,6 @@ function stateOrDefault(id) {
});
return stateEntry;
}
Meteor.sharedFunctions = Meteor.sharedFunctions || {};
Meteor.sharedFunctions.reactToSensorData = reactToSensorData;

View File

@@ -40,7 +40,9 @@ function openOutValve(controller_id) {
closeOutValve(controller_id);
}
});
console.log("Finished adding cron ", controller_id);
console.log(Meteor.sharedFunctions);
Meteor.sharedFunctions.reactToSensorData(last_sensor_reading(controller_id));
}
function closeOutValve(controller_id) {
@@ -51,6 +53,10 @@ function closeOutValve(controller_id) {
SyncedCron.remove(jobName);
setOutValveTo(controller_id, 'closing');
console.log("Finished clearing cron ", controller_id);
console.log(Meteor.sharedFunctions);
Meteor.sharedFunctions.reactToSensorData(last_sensor_reading(controller_id));
}
function clearLog() {
@@ -88,6 +94,28 @@ function saveControllerConfig(controller_id, time, days) {
});
}
function last_sensor_reading(controller_id) {
var result = null;
if (controller_id) {
result = SensorData.find({
controllerId: controller_id
}, {
sort: {
created_at: -1
},
limit: 1
});
}
if (result && result.count() > 0) {
return result.fetch()[0];
} else {
return {}
}
}
Meteor.methods({
openOutValve: openOutValve,
closeOutValve: closeOutValve,

View File

@@ -5,26 +5,28 @@ if (Meteor.isServer) {
});
// Global API configuration
var Api = new Restivus({
useDefaultAuth: true,
prettyJson: true
});
Api.addRoute('sensorData', {
authRequired: false
}, {
post: function() {
SensorData.insert({
temperatureValue: parseFloat(this.bodyParams.temperatureValue),
humidityValue: parseFloat(this.bodyParams.humidityValue),
tankFull: this.bodyParams.tankFull,
owner: this.bodyParams.owner,
created_at: new Date()
});
return [];
}
});
// Api.addRoute('sensorData', {
// authRequired: false
// }, {
// post: function() {
// SensorData.insert({
// temperatureValue: parseFloat(this.bodyParams.temperatureValue),
// humidityValue: parseFloat(this.bodyParams.humidityValue),
// tankFull: this.bodyParams.tankFull,
// owner: this.bodyParams.owner,
// created_at: new Date()
// });
// return [];
// }
// });
}

View File

@@ -3,7 +3,8 @@
GPIO_PIN_DHT = 4 # BCM
SENSORDATA_URL = 'http://tfm.meteor.com/api/v1.0/sensorData'
GPIO_PIN_TANKFULL = 20 # BCM
GPIO_PIN_VALVE = 21 # BCM
GPIO_PIN_OUT_VALVE = 21 # BCM
GPIO_PIN_IN_VALVE = 18 # BCM
API_BASE_URL = 'http://tfm.meteor.com/api/v1.0'
CONTROLLER_ID = '120' # every controller must have a different one
STATE_FILE = '/var/run/controller_state'

View File

@@ -7,29 +7,56 @@ class Changer(object):
self.local_state = local_state
self.remote_state = remote_state
GPIO.setmode(GPIO.BCM) # Broadcom pin-numbering scheme
GPIO.setup(config.GPIO_PIN_VALVE, GPIO.OUT)
self.states = {
'opening': self.open_valve,
'closing': self.close_valve,
'open': self.open_valve,
'closed': self.close_valve
GPIO.setup(config.GPIO_PIN_OUT_VALVE, GPIO.OUT)
GPIO.setup(config.GPIO_PIN_IN_VALVE, GPIO.OUT)
self.out_valve_states = {
'opening': self.open_out_valve,
'closing': self.close_out_valve,
'open': self.open_out_valve,
'closed': self.close_out_valve
}
self.in_valve_states = {
'opening': self.open_in_valve,
'closing': self.close_in_valve,
'open': self.open_in_valve,
'closed': self.close_in_valve
}
def safe_remote_state(self, key):
if key in ['out_valve', 'in_valve']:
return self.remote_state.get(key, 'closed')
else:
return self.remote_state.get(key,'');
def process_change(self):
self.validate_states()
change = self.states.get(self.remote_state['out_valve'], None )
if change is not None:
change()
out_valve_change = self.out_valve_states.get(self.safe_remote_state('out_valve'), None )
if out_valve_change is not None:
out_valve_change()
in_valve_change = self.in_valve_states.get(self.safe_remote_state('in_valve'), None )
if in_valve_change is not None:
in_valve_change()
return self.local_state
def open_valve(self):
GPIO.output(config.GPIO_PIN_VALVE, GPIO.HIGH)
def open_in_valve(self):
GPIO.output(config.GPIO_PIN_IN_VALVE, GPIO.HIGH)
self.local_state['in_valve'] = 'open'
def close_in_valve(self):
GPIO.output(config.GPIO_PIN_IN_VALVE, GPIO.LOW)
self.local_state['in_valve'] = 'closed'
def open_out_valve(self):
GPIO.output(config.GPIO_PIN_OUT_VALVE, GPIO.HIGH)
self.local_state['out_valve'] = 'open'
def close_valve(self):
GPIO.output(config.GPIO_PIN_VALVE, GPIO.LOW)
def close_out_valve(self):
GPIO.output(config.GPIO_PIN_OUT_VALVE, GPIO.LOW)
self.local_state['out_valve'] = 'closed'
def validate_states(self):

132
misc/kalkulator.html Normal file
View File

@@ -0,0 +1,132 @@
<html>
<head>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
</head>
<body>
<div class="jumbotron">
<img src="http://zoblak.com/wp-content/uploads/2016/02/zoblak-1.png" /> <br />
Zoblak Agrar Plus se isplati za 2 mjeseci. U periodu od 3 godine ostvaruje uštedu u novcu od 3000.00 KM, te uštedu u vremenu od 800 sati za ovaj konkretan slučaj.
</div>
<div class="container-fluid">
<div class="row">
<div class="col-md-6">
<p>Na troškove goriva mjesečno trošite 600 KM. Na rad potreban za zalijevanje trošite mjesečno 45 sati što uz zadanu satnicu iznosi 3000 KM. Zajedno to je 3600 KM troška na zalijevanje. </p>
<p>Okvirna cijena Zoblak Agrar Plus za navedeni broj ventila i pumpi iznosi 2500 KM</p>
<p class="bg-primary">NAPOMENA: finalna cijena može biti
niža ili viša i poznata je nakon izrade projekta).</p>
</div>
<div class="col-md-6 col-sm-6">
<form method="post">
<div class="form-group ">
<label class="control-label " for="number">
Vaša udaljenost od polja u km
</label>
<input class="form-control ulazni-parametar" id="udaljenost" type="number" min="1" max="200" step="0.1" value="5" />
</div>
<div class="form-group ">
<label class="control-label " for="number1">
Prosjecna potro&scaron;nja automobila na 100 km
</label>
<input class="form-control ulazni-parametar" id="potrosnja" type="number" min="2" max="5" value="7" step="0.1" />
</div>
<div class="form-group ">
<label class="control-label " for="select">
Koliko često treba zaljevati kulturu?
</label>
<select class="select form-control" id="frekvencija_zalijevanja">
<option value="1">
Svaki dan
</option>
<option value="2">
Jednom u dva dana
</option>
<option value="3">
Jednom u tri dana
</option>
<option value="4">
Jednom u četiri dana
</option>
</select>
</div>
<div class="form-group ">
<label class="control-label " for="number2">
Koliko vremena traje put prema polju (u oba smijera) i jedan ciklus zalijevanja? U satima.
</label>
<input class="form-control ulazni-parametar" id="vrijeme" type="number" min="2" max="10" value="1.5" step="0.5"/>
</div>
<div class="form-group ">
<label class="control-label " for="number3">
Satnica osobe koja zalijeva u KM
</label>
<input class="form-control ulazni-parametar" id="satnica" type="number" min="5" max="100" value="20" step="5" />
</div>
<div class="form-group ">
<label class="control-label " for="number3">
Trajanje sezone u mjesecima
</label>
<input class="form-control ulazni-parametar" id="sezona" type="number" min="1" max="12" value="4" step="1" />
</div>
<div class="form-group ">
<label class="control-label " for="number3">
Broj ventila i pumpi koje Zoblak kontroliše
</label>
<input class="form-control ulazni-parametar" id="broj_ventila" type="number" min="2" max="50" value="2" step="1"/>
</div>
<div class="form-group ">
<label class="control-label " for="number3">
Na koliko godina/sezona se projekcija vrši
</label>
<input class="form-control ulazni-parametar" id="broj_sezona" type="number" min="1" max="10" value="1" step="1"/>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
function iskalkulisi() {
// ulazi
var udaljenost = parseFloat($('#udaljenost').val());
var potrosnja = parseFloat($('#potrosnja').val());
var frekvencija = parseInt($'#frekvencija_zalijevanja').val());
var vrijeme = parseFloat($('#vrijeme').val());
var satnica = parseFloat($('#satnica').val());
var sezona = parseInt($'#sezona').val());
var ventili = parseInt($'#broj_ventila').val());
var brojSezona = parseInt($'#broj_sezona').val());
var bazaCijeneZoblaka = 1400;
var bazaCijeneVentila = 150;
var godisnjeOdrzavanjeZoblaka = 200;
// rezultati
var zalijevanjaMjesecno = Math.ceil(30 / frekvencija);
var satiMjesecno = Math.ceil(vrijeme) * zalijevanjaMjesecno;
var plata = satiMjesecno * satnica;
var iznosGoriva = Math.ceil((potrosnja / 100) * (udaljenost * 2) * zalijevanjaMjesecno);
var ukupnoTroskovaMjesecno = iznosGoriva + plata;
var trosakZoblaka = bazaCijeneZoblaka + ((ventili - 2) * bazaCijeneVentila);
var satiUProjekciji = satiMjesecno * sezona * brojSezona;
var novcaUProjekciji = ukupnoTroskovaMjesecno * sezona * brojSezona;
var iznosUstede =
};
$(document).ready(function(){
});
</script>
</body>
</html>