aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json5
-rw-r--r--package.json3
-rw-r--r--public/javascripts/dash.js66
-rw-r--r--routes/energy-usage.js71
-rw-r--r--views/index.hbs20
5 files changed, 159 insertions, 6 deletions
diff --git a/package-lock.json b/package-lock.json
index 6eba9a5..36670a2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -401,6 +401,11 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
},
+ "moment": {
+ "version": "2.22.0",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.0.tgz",
+ "integrity": "sha512-1muXCh8jb1N/gHRbn9VDUBr0GYb8A/aVcHlII9QSB68a50spqEVLIGN6KVmCOnSvJrUhC0edGgKU5ofnGXdYdg=="
+ },
"morgan": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz",
diff --git a/package.json b/package.json
index 3b857f1..6eb6e9e 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"hbs": "~4.0.1",
"http-errors": "~1.6.2",
"morgan": "~1.9.0",
- "tplink-smarthome-api": "0.22.0"
+ "tplink-smarthome-api": "0.22.0",
+ "moment": "2.22.0"
}
}
diff --git a/public/javascripts/dash.js b/public/javascripts/dash.js
index 510f804..3d02fd8 100644
--- a/public/javascripts/dash.js
+++ b/public/javascripts/dash.js
@@ -6,10 +6,15 @@ var dash = {
realtimeTrendChart: null,
realtimeTrendLastSample: 0,
+ dailyUsageChart: null,
+
init: function() {
this.initRealtimeGauge();
this.initRealtimeTrendChart();
+ this.initDailyUsageChart();
+
this.startPolling();
+ this.getDailyUsageData();
},
initRealtimeGauge: function() {
@@ -77,6 +82,37 @@ var dash = {
});
},
+ initDailyUsageChart: function() {
+ var ctx = document.getElementById('du-chart').getContext('2d');
+ this.dailyUsageChart = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ datasets: [{
+ label: "Energy (kWH)",
+ borderColor: 'rgb(255, 99, 132)',
+ backgroundColor: 'rgb(255, 99, 132)',
+ data: []
+ }]
+ },
+ options: {
+ legend: {
+ display: false
+ },
+ scales: {
+ yAxes: [{
+ ticks: {
+ beginAtZero:true
+ }
+ }]
+ },
+ maintainAspectRatio: false,
+ tooltips: {
+ intersect: false
+ },
+ }
+ });
+ },
+
realtimeTrendChartOnRefresh: function(chart) {
chart.data.datasets.forEach(function(dataset) {
dataset.data.push({
@@ -110,7 +146,7 @@ var dash = {
this.realtimeGauge.set(power);
// might switch to Vue.js if this gets tedious
- $("#rtu-power").text(power + " kW")
+ $("#rtu-power").text(power + " W")
$("#rtu-current").text(current + " A")
$("#rtu-voltage").text(voltage + " V")
@@ -134,7 +170,33 @@ var dash = {
this.realtimeTrendChart.options.plugins.streaming = false;
},
-}
+ getDailyUsageData: function() {
+ $.ajax({
+ url: "/energy-usage/1/day-stats",
+ type: "GET",
+ success: function(data) {
+ dash.parseDailyUsageData(data);
+ },
+ dataType: "json",
+ timeout: 4000
+ });
+ },
+
+ parseDailyUsageData: function(usageData) {
+ usageData.forEach(function(entry) {
+ // Months from API response are 1 based
+ var day = moment([entry.year, entry.month - 1, entry.day]);
+
+ dash.dailyUsageChart.data.labels.push(day.format('MMM D'));
+ dash.dailyUsageChart.data.datasets.forEach(function(dataset) {
+ dataset.data.push(entry.energy);
+ });
+ });
+
+ dash.dailyUsageChart.update();
+ }
+
+};
$(document).ready(function () {
diff --git a/routes/energy-usage.js b/routes/energy-usage.js
index 847248d..5706c75 100644
--- a/routes/energy-usage.js
+++ b/routes/energy-usage.js
@@ -2,16 +2,17 @@ const express = require('express');
const router = express.Router();
const deviceManager = require('../services/device-manager');
+const moment = require('moment');
router.get('/:deviceId/realtime', function(req, res, next) {
-
+
let deviceId = req.params.deviceId;
let realtimeUsage = {};
// TODO - cache results with a short TTL so we don't hammer the plug if multiple clients are requesting data
deviceManager.getDevice(deviceId).emeter.getRealtime().then(response => {
- // Voltage seems to be reported as its peak to peak voltage, not RMS.
+ // Voltage seems to be reported as its peak to peak value, not RMS.
// Show the RMS value since thats what would you expect to see.
// i.e. 220v not 310v (in the U.K)
response.voltage = response.voltage / Math.sqrt(2);
@@ -21,4 +22,70 @@ router.get('/:deviceId/realtime', function(req, res, next) {
});
+router.get('/:deviceId/day-stats', function(req, res, next) {
+
+ let deviceId = req.params.deviceId;
+
+ // Get last x days
+ let totalDaysRequired = 30; // TODO currently only works for up to 2 months spans
+ let currentMoment = moment();
+ let previousMoment = moment().subtract(totalDaysRequired, 'days');
+
+ // Month + 1 as the API months are index 1 based.
+ deviceManager.getDevice(deviceId).emeter.getDayStats(currentMoment.year(), currentMoment.month() +1).then(currentPeriodStats => {
+
+ // Check if we also need the previous month to meet the required total number of samples
+ if(currentMoment.month() !== previousMoment.month()) {
+
+ // Get previous month. This currently wont work if the previousMoment is more than 1 month before the currentMoment (see above)
+ deviceManager.getDevice(deviceId).emeter.getDayStats(previousMoment.year(), previousMoment.month() +1).then(previousPeriodStats => {
+
+ let currentMonthStats = fillMissingDays(currentPeriodStats, currentMoment);
+ let previousMonthStats = fillMissingDays(previousPeriodStats, previousMoment);
+ let combinedStats = previousMonthStats.concat(currentMonthStats);
+
+ res.json(trimDayStatResults(combinedStats, totalDaysRequired));
+
+ });
+ }
+ else {
+ let dayStats = fillMissingDays(currentPeriodStats, currentMoment);
+
+ res.json(trimDayStatResults(dayStats, totalDaysRequired));
+ }
+
+ });
+
+});
+
+function fillMissingDays(sparseDayStats, statsMoment) {
+ let denseDayStats = [];
+
+ // Fill in any missing days
+ let totalDays = statsMoment.date();
+ Array.from({length: totalDays}, (x,i) => i + 1).forEach(d => {
+
+ let stat = sparseDayStats.day_list.find(i => i.day === d);
+
+ if(stat === undefined) {
+ denseDayStats.push({
+ year: statsMoment.year(),
+ month: statsMoment.month() +1,
+ day: d,
+ energy: 0
+ })
+ }
+ else {
+ denseDayStats.push(stat);
+ }
+
+ });
+
+ return denseDayStats;
+}
+
+function trimDayStatResults(stats, maxSamples) {
+ return stats.splice(stats.length - maxSamples, stats.length);
+}
+
module.exports = router; \ No newline at end of file
diff --git a/views/index.hbs b/views/index.hbs
index 33d5549..ae7dac9 100644
--- a/views/index.hbs
+++ b/views/index.hbs
@@ -63,7 +63,7 @@
<div class="x_content">
<div class="row">
<h1 class="text-center">
- <strong id="rtu-power">- kW</strong>
+ <strong id="rtu-power">- W</strong>
</h1>
</div>
<div class="row text-center">
@@ -103,6 +103,24 @@
</div>
+ <div class="row">
+ <div class="col-md-6 col-sm-6 col-xs-12">
+ <div class="x_panel tile">
+ <div class="x_title">
+ <h2>
+ <strong>Last 30 days (kWH)</strong>
+ </h2>
+ <div class="clearfix"></div>
+ </div>
+ <div class="x_content">
+ <canvas id="du-chart" height="270"></canvas>
+ </div>
+ </div>
+ </div>
+
+
+ </div>
+
</div>
</div>
</div>