Bonjour à tous !
Après avoir vu le post sur l’utilisation de plugin-htmldisplay pour afficher sur un design un graphique, je m’en suis inspiré pour fabriquer le mien.
Ayant un système elec Enphase, j’apprécie beaucoup la présentation des puissances/énergies sur leur site :
J’entreprends de refaire ce graph chez moi :
Le code dans mon équipement plugin-htmldisplay :
<div id="controls" style="margin-bottom: 1em;">
<label><input type="radio" name="duree" value="1" checked> 24h glissant</label>
<label><input type="radio" name="duree" value="2"> Depuis 5h (veille)</label>
|
<button onclick="changerStack(-1)">−</button>
<span id="stackWidthDisplay">2</span> min
<button onclick="changerStack(1)">+</button>
</div>
<div id="container" style="height:400px;"></div>
<script>
var duree = typeof duree !== 'undefined' ? duree : 1;
var stackWidth = typeof stackWidth !== 'undefined' ? stackWidth : 2;
var stackSteps = stackSteps || [2, 5, 10, 15, 20, 30, 60];
document.querySelectorAll('input[name="duree"]').forEach(radio => {
radio.addEventListener('change', e => {
duree = parseInt(e.target.value);
chargerDonnees();
});
});
function changerStack(direction) {
const currentIndex = stackSteps.indexOf(stackWidth);
const nextIndex = currentIndex + direction;
if (nextIndex >= 0 && nextIndex < stackSteps.length) {
stackWidth = stackSteps[nextIndex];
document.getElementById('stackWidthDisplay').textContent = stackWidth;
chargerDonnees();
}
}
function chargerDonnees() {
//const duree = 1; //1 = 24h glissant, 2= depuis la veille à 5h
//const stackWidth = 2; //pour regrouper par 5min, 10 min, 15 minutes etc...
const now = new Date(); // heure locale
const endTime = now.getTime(); // maintenant, en local → timestamp (UTC millisecondes)
let startTime;
if (duree == 1) {
// Glissant 24h
startTime = new Date(now.getTime() - 24 * 60 * 60 * 1000).getTime();
} else {
// De 5h la veille jusqu'à maintenant
startTime = new Date(
now.getFullYear(),
now.getMonth(),
now.getDate() - 1, // ← veille !
5, 0, 0, 0
).getTime();
}
const puissances = {
prod: new Map(),
cons: new Map(),
exp: new Map(),
imp: new Map()
};
const arrondiXmin = timestamp => Math.floor(timestamp / (stackWidth * 60 * 1000)) * (stackWidth * 60 * 1000);
let chargements = 0;
const noms = {
5098: { map: puissances.prod, facteur: 1 },
5104: { map: puissances.cons, facteur: -1 },
5115: { map: puissances.exp, facteur: -1 },
5116: { map: puissances.imp, facteur: 1 }
};
Object.entries(noms).forEach(([cmd_id, obj]) => {
jeedom.history.get({
cmd_id: parseInt(cmd_id),
dateStart: new Date(startTime).toISOString().slice(0, 19).replace('T', ' '),
dateEnd: new Date(endTime).toISOString().slice(0, 19).replace('T', ' '),
success: function (result) {
result.data.forEach(entry => {
const t = arrondiXmin(entry[0]);
//if (t < startTime || t > endTime) return; // filtre sécurité
const val = obj.facteur * entry[1];
const list = obj.map.get(t) || [];
list.push(val);
obj.map.set(t, list);
});
chargements++;
if (chargements === 4) dessinerGraphique();
}
});
});
function dessinerGraphique() {
const allTimestamps = Array.from(
new Set([
...puissances.prod.keys(),
...puissances.cons.keys(),
...puissances.exp.keys(),
...puissances.imp.keys()
])
).sort((a, b) => a - b);
const moy = arr => arr && arr.length ? arr.reduce((a, b) => a + b, 0) / arr.length : 0;
const serie_prod = [], serie_imp = [], serie_cons = [], serie_exp = [];
allTimestamps.forEach(ts => {
serie_prod.push([ts, Math.trunc(moy(puissances.prod.get(ts)))]);
serie_imp.push([ts, Math.trunc(moy(puissances.imp.get(ts)))]);
serie_cons.push([ts, Math.trunc(moy(puissances.cons.get(ts)))]);
serie_exp.push([ts, Math.trunc(moy(puissances.exp.get(ts)))]);
});
Highcharts.setOptions({
global: {
useUTC: false
},
lang: {
months: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',
'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],
weekdays: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
shortMonths: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin',
'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.']
}
});
Highcharts.chart('container', {
chart: { type: 'column' },
title: { text: null, align: 'left' },
xAxis: {
type: 'datetime',
min: startTime,
max: endTime,
tickInterval: 60 * 60 * 1000, // 1 heure
labels: {
format: '{value:%H}h'
}
},
yAxis: {
title: { text: 'Puissance (W)' },
labels: {
formatter: function () {
return Math.abs(this.value);
}
},
stackLabels: { enabled: false }
},
tooltip: {
xDateFormat: '%H:%M',
shared: true,
formatter: function () {
const pointStart = this.x;
const pointEnd = pointStart + stackWidth * 60 * 1000; // en ms
const formatHeure = ts => Highcharts.dateFormat('%H:%M', ts);
let s = `<b>${formatHeure(pointStart)} → ${formatHeure(pointEnd)}</b><br/>`;
//let s = `<b>${Highcharts.dateFormat('%H:%M', this.x)}</b><br/>`;
this.points.forEach(point => {
const val = Math.abs(point.y);
if (val !== 0) {
s += `<span style="color:${point.series.color}">●</span> ${point.series.name}: <b>${Math.trunc(val)}</b><br/>`;
}
});
return s;
}
},
plotOptions: {
column: {
stacking: 'normal',
groupPadding: 0.1, // ≈ 90% de largeur
pointPadding: 0,
borderWidth: 0
}
},
series: [
{
name: 'Exportation',
data: serie_exp,
stack: 'Puissance',
color: '#6c7073'
},
{
name: 'Importation',
data: serie_imp,
stack: 'Puissance',
color: '#6c7073'
},
{
name: 'Production',
data: serie_prod,
stack: 'Puissance',
color: '#01b4de'
},
{
name: 'Consommation',
data: serie_cons,
stack: 'Puissance',
color: '#f37320'
},
]
});
}
}
// Initialisation après chargement
function attendreEtCharger() {
if (!document.getElementById('container')) {
setTimeout(attendreEtCharger, 100);
return;
}
chargerDonnees();
}
attendreEtCharger();
</script>
Comme vous pouvez le voir, j’ai deux commandes en haut du visuel qui permettent de modifier la durée à afficher entre deux choix (variable « duree »), et modifier la largeurs des barres parmi : 2, 5, 10, 15, 20, 30, 60 minutes (variable « stackWidth »).
Ca marche mais à chaque fois que je recharge la page ça repart vers une valeur par défaut.
Idéalement j’aimerais que mes deux informations duree et stackWidth soient lues dans les variables Jeedom et que ces variables soient réécrites à chaque fois qu’on modifie les paramètres.
J’ai demandé de l’aide à mon pote ChatGPT et Mistral mais je pense qu’il ne connaissent pas précisément les possibilités de jeedom.
Ils me propose d’utiliser des méthode jeedom.var.get() et jeedom.var.save() mais ça ne semble pas exister.
La partie du code modifiée et la proposition qui ne fonctionne pas :
let nbOK = 0;
jeedom.var.get({
name: 'graph_duree',
success: function (val) {
if (val !== null) {
duree = parseInt(val);
document.querySelector(`input[name="duree"][value="${duree}"]`).checked = true;
}
if (++nbOK === 2) chargerDonnees();
}
});
jeedom.var.get({
name: 'graph_stackWidth',
success: function (val) {
if (val !== null) {
stackWidth = parseInt(val);
}
document.getElementById('stackWidthDisplay').textContent = stackWidth;
if (++nbOK === 2) chargerDonnees();
}
});
// Ajouter les écouteurs sur les boutons radio
document.querySelectorAll('input[name="duree"]').forEach(radio => {
radio.addEventListener('change', function () {
duree = parseInt(this.value);
jeedom.var.save({ name: 'graph_duree', value: duree });
chargerDonnees();
});
});
}
function changerStack(direction) {
const index = stackSteps.indexOf(stackWidth);
const newIndex = Math.max(0, Math.min(stackSteps.length - 1, index + direction));
if (newIndex !== index) {
stackWidth = stackSteps[newIndex];
document.getElementById('stackWidthDisplay').textContent = stackWidth;
jeedom.var.save({ name: 'graph_stackWidth', value: stackWidth });
chargerDonnees();
}
}
J’aurais voulu savoir dans la communauté si quelqu’un savait comment faire pour accéder aux variables depuis du html affiché sur un design, un peu comme on connait les commande php depuis un scenario :
$scenario->setData($key, $value); : Sauvegarde une donnée (variable).
$key : clé de la valeur (int ou string).
$value : valeur à stocker (int, string, array ou object).
$scenario->getData($key); : Récupère une donnée (variable).
$key => 1 : clé de la valeur (int ou string).
Merci à tous !
PS :