Commit cd4c9bb3 by Martin Kotula

Moved sensor logic into sensor view model. refactored dashboard viewmodel

parent 96aa8745
define({
sensorUpdate: "sensorUpdate"
});
\ No newline at end of file
define({
"Sensor 1": {
name: "Chill room"
}
});
\ No newline at end of file
define([
"app/events",
"knockout",
"components/sensor/sensorViewModel",
"lodash",
"knockout-postbox"
], function (
events,
ko,
SensorViewModel,
_
) {
function DashboardViewModel() {
this.sensorsDict = {};
this.sensors = ko.observableArray();
ko.postbox.subscribe(events.sensorUpdate, _.bind(this.onSensorUpdated, this));
}
DashboardViewModel.prototype.addSensor = function (key, sensorData) {
if (!this.sensorsDict[key]) {
var sensorViewModel = new SensorViewModel(sensorData);
this.sensorsDict[key] = sensorViewModel;
this.sensors.push(sensorViewModel);
}
};
DashboardViewModel.prototype.updateSensor = function (key, sensorData) {
var sensorViewModel = this.sensorsDict[key];
if (sensorViewModel) {
sensorViewModel.update(sensorData);
}
};
DashboardViewModel.prototype.onSensorUpdated = function(data){
var key = data.id;
if(this.sensorsDict[key]){
this.updateSensor(key, data);
} else {
this.addSensor(key, data);
}
} ;
return DashboardViewModel;
});
\ No newline at end of file
define(['knockout'], function(ko) { define(['knockout', "app/sensors.config", "lodash"], function(ko, sensorsConfig, _) {
function SensorViewModel(params) { function SensorViewModel(sensorData) {
this.isOccupied = ko.observable(params.isOccupied); this.name = getName(sensorData.id);
this.name = params.name; this.readings = ko.observableArray([]);
this.timestamp = ko.observable(params.timestamp);
this.update(sensorData);
this.isOccupied = ko.computed(_.bind(function () {
var lastReading = _.last(this.readings());
if(!lastReading)
return undefined;
return lastReading.isOccupied;
}, this));
}
SensorViewModel.prototype.update = function(sensorData){
this.readings.push(_.pick(sensorData, ["isOccupied", "timestamp"]));
this.timestamp = ko.observable(sensorData.timestamp);
};
function getName(id){
return (sensorsConfig[id] && sensorsConfig[id].name) || id;
} }
return SensorViewModel; return SensorViewModel;
......
<h2>Edge1 Occupancy dashboard</h2> <h2>Edge1 Occupancy dashboard</h2>
<div data-bind="with: viewModel">
<div data-bind="visible: sensors().length == 0"> <div data-bind="visible: sensors().length == 0">
<h3>Waiting for sensor readings</h3> <h3>Waiting for sensor readings</h3>
</div> </div>
<div class="row" data-bind="foreach: sensors"> <div class="row" data-bind="foreach: sensors">
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<sensor params="name: name, isOccupied: isOccupied, timestamp: timestamp"></sensor> <sensor params="name: name, isOccupied: isOccupied, timestamp: timestamp"></sensor>
</div>
</div> </div>
</div>
<button type="button" class="btn btn-default btn-lg" data-bind="click: refresh, disable: isRefreshing">
<span class="glyphicon glyphicon-refresh" aria-hidden="true"></span> Refresh
</button>
<div data-bind="visible: isRefreshing">
Refreshing...
</div> </div>
\ No newline at end of file
define([ define([
"knockout",
"text!./home.html", "text!./home.html",
"components/sensor/sensorViewModel", "components/dashboard/dashboardViewModel",
"queryHandlers/sensorReadingsQueryHandler", "services/mqttListener"
"services/mqttListener",
"lodash",
"knockout-postbox"
], function ( ], function (
ko,
homeTemplate, homeTemplate,
SensorViewModel, DashboardViewModel,
SensorReadingsQueryHandler, MqttListener
MqttListener,
_
) { ) {
function HomeViewModel(route) { function HomeViewModel() {
this.sensorsDict = {};
this.sensors = ko.observableArray();
this.isRefreshing = ko.observable(false);
this.queryHandler = new SensorReadingsQueryHandler();
var mqttListener = new MqttListener(); var mqttListener = new MqttListener();
mqttListener.init(); mqttListener.init();
ko.postbox.subscribe("sensorUpdate", _.bind(this.onSensorUpdated, this)); this.viewModel = new DashboardViewModel();
}
HomeViewModel.prototype.addSensor = function (key, sensorData) {
if (!this.sensorsDict[key]) {
var viewModel = new SensorViewModel(sensorData);
this.sensorsDict[key] = viewModel;
this.sensors.push(viewModel);
}
}
HomeViewModel.prototype.updateSensor = function (key, sensorData) {
var viewModel = this.sensorsDict[key];
if (viewModel) {
viewModel.isOccupied(sensorData.isOccupied);
viewModel.timestamp(sensorData.timestamp);
}
}
HomeViewModel.prototype.onSensorUpdated = function(data){
var key = data.name;
if(this.sensorsDict[key]){
this.updateSensor(key, data);
} else {
this.addSensor(key, data);
}
}
HomeViewModel.prototype.refresh = function () {
this.isRefreshing(true);
this.queryHandler.handle().then(_.bind(function(data) {
var sensorsGroupedByName = _.groupBy(data, "name");
_.each(sensorsGroupedByName, _.bind(function(sensorReadings, key){
var latestReading = _.orderBy(sensorReadings, "timestamp").pop();
if(this.sensorsDict[key]){
this.updateSensor(key, latestReading);
} else {
this.addSensor(key, latestReading);
}
}, this));
this.isRefreshing(false);
}, this));
} }
return { viewModel: HomeViewModel, template: homeTemplate }; return { viewModel: HomeViewModel, template: homeTemplate };
......
...@@ -7,13 +7,12 @@ ...@@ -7,13 +7,12 @@
<h3>Example data</h3> <h3>Example data</h3>
<pre> <pre>
{ "name": "Sensor 1", "isOccupied": true, "timestamp": "2017-06-17T21:10:59.948Z"} { "id": "Sensor 1", "isOccupied": true}
{ "name": "Sensor 2", "isOccupied": true, "timestamp": "2017-06-17T21:10:59.948Z"} { "id": "Sensor 2", "isOccupied": true}
{ "name": "Sensor 1", "isOccupied": true, "timestamp": "2017-06-17T21:11:59.948Z"} { "id": "Sensor 1", "isOccupied": true}
{ "name": "Sensor 2", "isOccupied": true, "timestamp": "2017-06-17T21:11:59.948Z"} { "id": "Sensor 2", "isOccupied": true}
{ "name": "Sensor 1", "isOccupied": true, "timestamp": "2017-06-17T21:12:59.948Z"} { "id": "Sensor 1", "isOccupied": true}
{ "name": "Sensor 1", "isOccupied": false, "timestamp": "2017-06-17T21:13:59.948Z"} { "id": "Sensor 1", "isOccupied": false}
{ "name": "Sensor 3", "isOccupied": false, "timestamp": "2017-06-17T21:13:59.948Z"} { "id": "Sensor 3", "isOccupied": false}
{ "name": "Sensor 3", "isOccupied": true, "timestamp": "2017-06-17T21:13:59.949Z"} { "id": "Sensor 3", "isOccupied": true}
</pre> </pre>
\ No newline at end of file
define(["jquery"], function($) {
function SensorReadingsQueryHandler() {
}
SensorReadingsQueryHandler.prototype.handle = function(){
return $.ajax('/mockData.json');
}
return SensorReadingsQueryHandler;
});
\ No newline at end of file
define(["app/config", "mqtt", "lodash", "knockout", "knockout-postbox"], function(config, mqtt, _, ko) { define(["app/config", "app/events", "mqtt", "lodash", "knockout", "knockout-postbox"], function(config, events, mqtt, _, ko) {
function MqttListener() { function MqttListener() {
} }
...@@ -15,12 +15,16 @@ define(["app/config", "mqtt", "lodash", "knockout", "knockout-postbox"], functio ...@@ -15,12 +15,16 @@ define(["app/config", "mqtt", "lodash", "knockout", "knockout-postbox"], functio
this.client.on('message', function (topic, message) { this.client.on('message', function (topic, message) {
// message is Buffer // message is Buffer
try{ try{
var messegeBody = JSON.parse(message.toString()); console.debug("Mqtt message received: " + message.toString());
console.debug("Mqtt message received: " + message.toString()); var messageBody = JSON.parse(message.toString());
ko.postbox.publish("sensorUpdate", messegeBody); if(messageBody.id === undefined || messageBody.isOccupied === undefined){
throw "InvalidMessageFormat";
}
ko.postbox.publish(events.sensorUpdate, _.merge(messageBody, { timestamp: new Date()}));
} }
catch(e){ catch(e){
console.error("Failed to parse message into JSON: [" + message.toString() + "]"); console.error("Failed to parse message into JSON: [" + message.toString() + "]: " + e);
} }
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment