Module lib.plugins.electricmeter.htmlpage
Web page of electric meter
Expand source code
# Distributed under Pycameresp License
# Copyright (c) 2023 Remi BERTHOLET
''' Web page of electric meter '''
page = b"""
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<canvas id="line-chart"></canvas>
<span id="legend"></span>
<script>
var STEP = %d;
var DAY_SELECTED = '%s';
var DATE = '%s';
var CHART_TYPE = '%s';
var chart = null;
function pad(num, size)
{
num = parseInt(num);
num = num.toString();
while (num.length < size)
{
num = "0" + num;
}
return num;
}
function capitalize(string)
{
return string.charAt(0).toUpperCase() + string.slice(1);
}
class Cost
{
constructor(name, currency, color)
{
this.total_cost = 0;
this.total_pulses = 0;
this.currency = currency;
this.name = name;
this.color = color;
this.pulses = [];
this.costs = [];
}
}
class Costs
{
constructor(datas)
{
this.costs = new Map();
this.datas = datas;
this.labels = [];
this.step_pulses = 0;
for (let i = 0; i < this.datas.rates.length; i++)
{
var rate = this.datas.rates[i];
if (!this.costs.has(rate.rate))
{
this.costs.set(rate.rate, new Cost(rate.rate, rate.currency, rate.color));
}
}
}
add_step(minute, pulses)
{
var rate = null;
minute *= 60;
for (let i = 0; i < this.datas.rates.length; i++)
{
rate = this.datas.rates[i];
if (minute >= rate.start_time && minute <= rate.end_time)
{
rate = this.datas.rates[i];
break;
}
}
for (var [name, cost] of this.costs)
{
if (cost.name === rate.rate)
{
var current_cost = (rate.price / 1000.) * pulses
if (STEP <= 15)
{
cost.pulses.push(pulses);
}
else
{
cost.pulses.push((pulses/1000.).toFixed(2));
}
cost.costs.push(current_cost.toFixed(2));
cost.total_cost += current_cost;
cost.total_pulses += pulses;
}
else
{
cost.pulses.push(0);
cost.costs.push(0);
}
}
}
parse_step(minute, pulses)
{
this.step_pulses += pulses;
if ((minute + 1)%%STEP == 0)
{
var time = pad((minute+1)/60, 2) + ":" + pad((minute+1)%%60, 2);
this.labels.push(time);
this.add_step(minute, this.step_pulses);
this.step_pulses = 0;
}
}
parse()
{
for (let minute = 0; minute < this.datas.pulses.length; minute++)
{
this.parse_step(minute, this.datas.pulses[minute]);
}
}
get_data_set()
{
var result = [];
var data = null;
var unit = "";
for (var [name, cost] of this.costs)
{
if (CHART_TYPE === "price")
{
unit = cost.currency;
data = cost.costs;
}
else
{
if (STEP <= 15)
{
unit = "Wh";
}
else
{
unit = "kWh";
}
data = cost.pulses;
}
result.push(
{
data: data,
label: cost.name + " (" + unit + ")",
backgroundColor: cost.color,
fill: false,
pointRadius:1,
borderWidth:0
});
}
return result;
}
get_labels()
{
return this.labels;
}
get_legend()
{
var legend = "<br>";
var result = capitalize(DATE) + ' : ';
var total = 0;
var currency = "";
if (CHART_TYPE === "price")
{
for (var [name, cost] of this.costs)
{
total += cost.total_cost;
currency = cost.currency;
legend += "<li>" + cost.name + " : " + cost.total_cost.toFixed(2) + " " + cost.currency + "</li>";
}
result += total.toFixed(2) + currency;
}
else
{
for (var [name, cost] of this.costs)
{
total += cost.total_pulses;
legend += "<li>" + cost.name + " : " + (cost.total_pulses / 1000).toFixed(2) + " kWh </li>";
}
result += (total/1000).toFixed(2) + " kWh";
}
document.getElementById("legend").innerHTML="<ul>" + capitalize(legend) + "</ul>";
return result;
}
}
function show_chart(datas)
{
var costs = new Costs(datas);
costs.parse();
if (!(chart === null))
{
chart.destroy();
chart = null;
}
costs.get_legend();
chart = new Chart(document.getElementById("line-chart"),
{
type: 'bar',
data:
{
labels: costs.get_labels(),
datasets: costs.get_data_set()
},
options:
{
responsive: true,
animation:
{
duration: 0
},
plugins:
{
legend:
{
position: 'top',
},
title:
{
display: true,
text: costs.get_legend()
}
},
scales:
{
x:
{
stacked: true,
}
}
}
});
}
async function download_datas()
{
const response = await fetch('/pulses_rates?day='+DAY_SELECTED);
var data = await response.json();
show_chart(data);
}
download_datas();
const d = new Date();
var currentDate = d.getFullYear() + "-" + pad(d.getMonth()+1,2) + "-" + pad(d.getDate(),2);
if (DAY_SELECTED === currentDate)
{
setInterval(download_datas, 5000);
}
</script>
"""