diff options
| author | James Barnett <noreply@jamesbarnett.xyz> | 2018-03-31 21:00:04 +0100 |
|---|---|---|
| committer | James Barnett <noreply@jamesbarnett.xyz> | 2018-03-31 21:00:04 +0100 |
| commit | 5531f72248d0372000fe09e031e5a70fb11dafe7 (patch) | |
| tree | 1c09b1b37a583d9f73311d4f0119bfc9cc987f89 | |
| parent | f53f1d433b5d458ff0b8a5893e8127a8be3630f7 (diff) | |
| download | tplink-energy-monitor-5531f72248d0372000fe09e031e5a70fb11dafe7.tar.xz tplink-energy-monitor-5531f72248d0372000fe09e031e5a70fb11dafe7.zip | |
Add monthly usage graph
| -rw-r--r-- | public/javascripts/dash.js | 62 | ||||
| -rw-r--r-- | routes/energy-usage.js | 73 | ||||
| -rw-r--r-- | views/index.hbs | 16 |
3 files changed, 146 insertions, 5 deletions
diff --git a/public/javascripts/dash.js b/public/javascripts/dash.js index 3d02fd8..c8710db 100644 --- a/public/javascripts/dash.js +++ b/public/javascripts/dash.js @@ -7,14 +7,17 @@ var dash = { realtimeTrendLastSample: 0, dailyUsageChart: null, + monthlyUsageChart: null, init: function() { this.initRealtimeGauge(); this.initRealtimeTrendChart(); this.initDailyUsageChart(); + this.initMonthlyUsageChart(); this.startPolling(); this.getDailyUsageData(); + this.getMonthlyUsageData(); }, initRealtimeGauge: function() { @@ -113,6 +116,37 @@ var dash = { }); }, + initMonthlyUsageChart: function() { + var ctx = document.getElementById('mu-chart').getContext('2d'); + this.monthlyUsageChart = 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({ @@ -194,7 +228,33 @@ var dash = { }); dash.dailyUsageChart.update(); - } + }, + + getMonthlyUsageData: function() { + $.ajax({ + url: "/energy-usage/1/month-stats", + type: "GET", + success: function(data) { + dash.parseMonthlyUsageData(data); + }, + dataType: "json", + timeout: 4000 + }); + }, + + parseMonthlyUsageData: function(usageData) { + usageData.forEach(function(entry) { + // Months from API response are 1 based + var month = moment().month(entry.month -1); + + dash.monthlyUsageChart.data.labels.push(month.format('MMM')); + dash.monthlyUsageChart.data.datasets.forEach(function(dataset) { + dataset.data.push(entry.energy); + }); + }); + + dash.monthlyUsageChart.update(); + }, }; diff --git a/routes/energy-usage.js b/routes/energy-usage.js index 5706c75..411c0b6 100644 --- a/routes/energy-usage.js +++ b/routes/energy-usage.js @@ -44,14 +44,48 @@ router.get('/:deviceId/day-stats', function(req, res, next) { let previousMonthStats = fillMissingDays(previousPeriodStats, previousMoment); let combinedStats = previousMonthStats.concat(currentMonthStats); - res.json(trimDayStatResults(combinedStats, totalDaysRequired)); + res.json(trimStatResults(combinedStats, totalDaysRequired)); }); } else { let dayStats = fillMissingDays(currentPeriodStats, currentMoment); - res.json(trimDayStatResults(dayStats, totalDaysRequired)); + res.json(trimStatResults(dayStats, totalDaysRequired)); + } + + }); + +}); + +router.get('/:deviceId/month-stats', function(req, res, next) { + let deviceId = req.params.deviceId; + + // Get last x months + let totalMonthsRequired = 12; // TODO currently only works for up to 14 month (2 year) spans + let currentMoment = moment(); + let previousMoment = moment().subtract(totalMonthsRequired, 'months'); + + deviceManager.getDevice(deviceId).emeter.getMonthStats(currentMoment.year()).then(currentPeriodStats => { + + // Check if we also need the previous year to meet the required total number of samples + if(currentMoment.month() + 1 < totalMonthsRequired) { + + // Get previous year (assuming the totalMonthsRequired limit described above). + deviceManager.getDevice(deviceId).emeter.getMonthStats(previousMoment.year()).then(previousPeriodStats => { + + let currentYearStats = fillMissingMonths(currentPeriodStats, currentMoment); + let previousYearStats = fillMissingMonths(previousPeriodStats, previousMoment); + let combinedStats = previousYearStats.concat(currentYearStats); + + res.json(trimStatResults(combinedStats, totalMonthsRequired)); + + }); + } + else { + let monthStats = fillMissingMonths(currentPeriodStats, currentMoment); + + res.json(trimStatResults(monthStats, totalMonthsRequired)); } }); @@ -84,7 +118,40 @@ function fillMissingDays(sparseDayStats, statsMoment) { return denseDayStats; } -function trimDayStatResults(stats, maxSamples) { +function fillMissingMonths(sparseMonthStats, statsMoment) { + let denseMonthStats = []; + + let maxMonths; + // Dont fill months in months which havent happened yet + if(statsMoment.year() === moment().year()) { + maxMonths = moment().month(); + } + else { + maxMonths = 12; + } + + // Fill in any missing months up to the max amount + Array.from({length: maxMonths}, (x,i) => i + 1).forEach(m => { + + let stat = sparseMonthStats.month_list.find(i => i.month === m); + + if(stat === undefined) { + denseMonthStats.push({ + year: statsMoment.year(), + month: m, + energy: 0 + }) + } + else { + denseMonthStats.push(stat); + } + + }); + + return denseMonthStats; +} + +function trimStatResults(stats, maxSamples) { return stats.splice(stats.length - maxSamples, stats.length); } diff --git a/views/index.hbs b/views/index.hbs index ae7dac9..3a8233f 100644 --- a/views/index.hbs +++ b/views/index.hbs @@ -104,7 +104,8 @@ </div> <div class="row"> - <div class="col-md-6 col-sm-6 col-xs-12"> + + <div class="col-md-8 col-sm-8 col-xs-12"> <div class="x_panel tile"> <div class="x_title"> <h2> @@ -118,6 +119,19 @@ </div> </div> + <div class="col-md-4 col-sm-4 col-xs-12"> + <div class="x_panel tile"> + <div class="x_title"> + <h2> + <strong>Last 12 months (kWH)</strong> + </h2> + <div class="clearfix"></div> + </div> + <div class="x_content"> + <canvas id="mu-chart" height="270"></canvas> + </div> + </div> + </div> </div> |