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) {
this.isOccupied = ko.observable(params.isOccupied);
this.name = params.name;
this.timestamp = ko.observable(params.timestamp);
function SensorViewModel(sensorData) {
this.name = getName(sensorData.id);
this.readings = ko.observableArray([]);
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;
......
<h2>Edge1 Occupancy dashboard</h2>
<div data-bind="visible: sensors().length == 0">
<h3>Waiting for sensor readings</h3>
</div>
<div class="row" data-bind="foreach: sensors">
<div class="col-xs-12 col-md-4">
<sensor params="name: name, isOccupied: isOccupied, timestamp: timestamp"></sensor>
<div data-bind="with: viewModel">
<div data-bind="visible: sensors().length == 0">
<h3>Waiting for sensor readings</h3>
</div>
<div class="row" data-bind="foreach: sensors">
<div class="col-xs-12 col-md-4">
<sensor params="name: name, isOccupied: isOccupied, timestamp: timestamp"></sensor>
</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>
\ No newline at end of file
define([
"knockout",
"text!./home.html",
"components/sensor/sensorViewModel",
"queryHandlers/sensorReadingsQueryHandler",
"services/mqttListener",
"lodash",
"knockout-postbox"
"components/dashboard/dashboardViewModel",
"services/mqttListener"
], function (
ko,
homeTemplate,
SensorViewModel,
SensorReadingsQueryHandler,
MqttListener,
_
DashboardViewModel,
MqttListener
) {
function HomeViewModel(route) {
this.sensorsDict = {};
this.sensors = ko.observableArray();
this.isRefreshing = ko.observable(false);
this.queryHandler = new SensorReadingsQueryHandler();
function HomeViewModel() {
var mqttListener = new MqttListener();
mqttListener.init();
ko.postbox.subscribe("sensorUpdate", _.bind(this.onSensorUpdated, this));
}
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));
this.viewModel = new DashboardViewModel();
}
return { viewModel: HomeViewModel, template: homeTemplate };
......
......@@ -7,13 +7,12 @@
<h3>Example data</h3>
<pre>
{ "name": "Sensor 1", "isOccupied": true, "timestamp": "2017-06-17T21:10:59.948Z"}
{ "name": "Sensor 2", "isOccupied": true, "timestamp": "2017-06-17T21:10:59.948Z"}
{ "name": "Sensor 1", "isOccupied": true, "timestamp": "2017-06-17T21:11:59.948Z"}
{ "name": "Sensor 2", "isOccupied": true, "timestamp": "2017-06-17T21:11:59.948Z"}
{ "name": "Sensor 1", "isOccupied": true, "timestamp": "2017-06-17T21:12:59.948Z"}
{ "name": "Sensor 1", "isOccupied": false, "timestamp": "2017-06-17T21:13:59.948Z"}
{ "name": "Sensor 3", "isOccupied": false, "timestamp": "2017-06-17T21:13:59.948Z"}
{ "name": "Sensor 3", "isOccupied": true, "timestamp": "2017-06-17T21:13:59.949Z"}
{ "id": "Sensor 1", "isOccupied": true}
{ "id": "Sensor 2", "isOccupied": true}
{ "id": "Sensor 1", "isOccupied": true}
{ "id": "Sensor 2", "isOccupied": true}
{ "id": "Sensor 1", "isOccupied": true}
{ "id": "Sensor 1", "isOccupied": false}
{ "id": "Sensor 3", "isOccupied": false}
{ "id": "Sensor 3", "isOccupied": true}
</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() {
}
......@@ -15,12 +15,16 @@ define(["app/config", "mqtt", "lodash", "knockout", "knockout-postbox"], functio
this.client.on('message', function (topic, message) {
// message is Buffer
try{
var messegeBody = JSON.parse(message.toString());
console.debug("Mqtt message received: " + message.toString());
ko.postbox.publish("sensorUpdate", messegeBody);
console.debug("Mqtt message received: " + message.toString());
var messageBody = JSON.parse(message.toString());
if(messageBody.id === undefined || messageBody.isOccupied === undefined){
throw "InvalidMessageFormat";
}
ko.postbox.publish(events.sensorUpdate, _.merge(messageBody, { timestamp: new Date()}));
}
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