Vues et periodes comme VRM, et un panneau Batterie enfin lisible
Trois demandes du proprietaire apres usage reel. 1. SELECTEUR DE VUE. Variable « vue » en haut du tableau, dans l'esprit de VRM : Vue generale / Consommation / Reseau / Batterie / Chargeur VE. La valeur de chaque option est directement une alternative d'expression reguliere, consommee par la transformation filterFieldsByName des deux graphiques — d'ou le separateur « | ». Un seul jeu de requetes, cinq lectures. 2. PAS ADAPTATIF. L'histogramme d'energie suit desormais la periode choisie : l'heure jusqu'a 4 jours, le jour jusqu'a 70, le mois au-dela. Sans cela « 30 derniers jours » rendait 720 barres illisibles. C'est ce que fait VRM en passant de l'heure au jour puis au mois. 3. PANNEAU BATTERIE ILLISIBLE — un defaut que j'avais cree. Cinq valeurs dans huit colonnes : Grafana reduisait le texte jusqu'a l'illisible. Porte a dix colonnes avec une taille imposee, plutot que de laisser l'ajustement automatique decider. Reseau et Charges CA resserres en consequence. Ajout lie a la panne en cours : panneau « Ce que le BMS impose » — limite de courant de charge, alarme de tension de cellule, desequilibre, etat de sante. C'est ce qu'il faudra regarder cet apres-midi. Sa fenetre de lecture est de 48 h, deliberement differente des 6 h du reste : un etat d'alarme ne devient jamais indisponible, il se publie, donc sa derniere valeur EST la valeur courante meme vieille de dix heures. A l'inverse du courant reseau, dont le capteur disparait et laisse un chiffre qui ment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
This commit is contained in:
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
"uid": "evcs-nuit",
|
"uid": "evcs-nuit",
|
||||||
"title": "La nuit",
|
"title": "La nuit",
|
||||||
"description": "Ce que le bilan exigeait, contre ce que la batterie a reellement fait. C'est la question qui a demande une nuit d'archeologie le 03/09 et qui tient maintenant en un coup d'oeil.",
|
"description": "Ce que le bilan exigeait, contre ce que la batterie a reellement fait. C'est la question qui a demande une nuit d'archeologie le 03/09 et qui tient maintenant en un coup d'oeil.",
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
"uid": "evcs-prevision",
|
"uid": "evcs-prevision",
|
||||||
"title": "Prevision contre reel",
|
"title": "Prevision contre reel",
|
||||||
"description": "Le total de la prevision tombe juste ; sa FORME non. Sur les trois jours verifies le 04/09, la production arrive plus tot que prevu et l'apres-midi est sur-promis d'un facteur 2 a 3 apres 16 h. Ce tableau existe pour instruire cette question sur des semaines, pas sur trois jours.",
|
"description": "Le total de la prevision tombe juste ; sa FORME non. Sur les trois jours verifies le 04/09, la production arrive plus tot que prevu et l'apres-midi est sur-promis d'un facteur 2 a 3 apres 16 h. Ce tableau existe pour instruire cette question sur des semaines, pas sur trois jours.",
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
"uid": "evcs-solaire",
|
"uid": "evcs-solaire",
|
||||||
"title": "Le solaire",
|
"title": "Le solaire",
|
||||||
"description": "La production mesuree n'est jamais la production disponible : sans injection, le MPPT ne produit que ce que le systeme peut absorber. Ces panneaux montrent l'ecart entre les deux.",
|
"description": "La production mesuree n'est jamais la production disponible : sans injection, le MPPT ne produit que ce que le systeme peut absorber. Ces panneaux montrent l'ecart entre les deux.",
|
||||||
|
|||||||
@@ -1,4 +1,50 @@
|
|||||||
{
|
{
|
||||||
|
"templating": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "vue",
|
||||||
|
"label": "Vue",
|
||||||
|
"type": "custom",
|
||||||
|
"hide": 0,
|
||||||
|
"skipUrlSync": false,
|
||||||
|
"query": "Vue generale : Solaire|Reseau|Batterie|Maison|Voiture,Consommation : Maison|Voiture,Reseau : Reseau|Maison,Batterie : Batterie|Solaire|Maison,Chargeur VE : Voiture|Solaire",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"selected": true,
|
||||||
|
"text": "Vue generale",
|
||||||
|
"value": "Solaire|Reseau|Batterie|Maison|Voiture"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selected": false,
|
||||||
|
"text": "Consommation",
|
||||||
|
"value": "Maison|Voiture"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selected": false,
|
||||||
|
"text": "Reseau",
|
||||||
|
"value": "Reseau|Maison"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selected": false,
|
||||||
|
"text": "Batterie",
|
||||||
|
"value": "Batterie|Solaire|Maison"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selected": false,
|
||||||
|
"text": "Chargeur VE",
|
||||||
|
"value": "Voiture|Solaire"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"current": {
|
||||||
|
"selected": true,
|
||||||
|
"text": "Vue generale",
|
||||||
|
"value": "Solaire|Reseau|Batterie|Maison|Voiture"
|
||||||
|
},
|
||||||
|
"multi": false,
|
||||||
|
"includeAll": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"uid": "evcs-systeme",
|
"uid": "evcs-systeme",
|
||||||
"title": "Le systeme",
|
"title": "Le systeme",
|
||||||
"description": "Replique locale de la vue generale VRM. La console Victron est hebergee dans le cloud : elle disparait quand une coupure d'orage emporte Internet. Tout ce qui est affiche ici est lu sur le reseau local.",
|
"description": "Replique locale de la vue generale VRM. La console Victron est hebergee dans le cloud : elle disparait quand une coupure d'orage emporte Internet. Tout ce qui est affiche ici est lu sur le reseau local.",
|
||||||
@@ -93,7 +139,7 @@
|
|||||||
"gridPos": {
|
"gridPos": {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"w": 6,
|
"w": 5,
|
||||||
"h": 5
|
"h": 5
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
@@ -208,9 +254,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"gridPos": {
|
"gridPos": {
|
||||||
"x": 6,
|
"x": 5,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"w": 5,
|
"w": 4,
|
||||||
"h": 5
|
"h": 5
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
@@ -333,9 +379,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"gridPos": {
|
"gridPos": {
|
||||||
"x": 11,
|
"x": 9,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"w": 8,
|
"w": 10,
|
||||||
"h": 5
|
"h": 5
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
@@ -476,6 +522,10 @@
|
|||||||
"justifyMode": "center",
|
"justifyMode": "center",
|
||||||
"percentChangeColorMode": "standard",
|
"percentChangeColorMode": "standard",
|
||||||
"noValue": "—",
|
"noValue": "—",
|
||||||
|
"text": {
|
||||||
|
"valueSize": 26,
|
||||||
|
"titleSize": 11
|
||||||
|
},
|
||||||
"wideLayout": true
|
"wideLayout": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -633,7 +683,7 @@
|
|||||||
"gridPos": {
|
"gridPos": {
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 5,
|
"y": 5,
|
||||||
"w": 6,
|
"w": 5,
|
||||||
"h": 8
|
"h": 8
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
@@ -724,9 +774,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"gridPos": {
|
"gridPos": {
|
||||||
"x": 6,
|
"x": 5,
|
||||||
"y": 5,
|
"y": 5,
|
||||||
"w": 18,
|
"w": 13,
|
||||||
"h": 8
|
"h": 8
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
@@ -850,6 +900,148 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "stat",
|
||||||
|
"title": "Ce que le BMS impose",
|
||||||
|
"description": "« Charge max » est la limite que le BMS impose au systeme entier. Le 04/09 elle est tombee de 150 a 20 A en trois minutes, des 76 % de charge, au moment ou l'alarme de tension de cellule s'est declenchee — le parc n'etait alors qu'a 50,76 V pour 53,2 V autorises. Ce n'est pas le parc qui sature, c'est une cellule.",
|
||||||
|
"datasource": {
|
||||||
|
"type": "influxdb",
|
||||||
|
"uid": "evcs-influx"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"datasource": {
|
||||||
|
"type": "influxdb",
|
||||||
|
"uid": "evcs-influx"
|
||||||
|
},
|
||||||
|
"query": "from(bucket: \"evcs\")\n |> range(start: -48h)\n |> filter(fn: (r) => r._measurement == \"A\" and r.entity_id == \"airtria_8_us2000c_maximum_allowed_charge_current\" and r._field == \"value\")\n |> last()\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"Charge max\"})"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "B",
|
||||||
|
"datasource": {
|
||||||
|
"type": "influxdb",
|
||||||
|
"uid": "evcs-influx"
|
||||||
|
},
|
||||||
|
"query": "from(bucket: \"evcs\")\n |> range(start: -48h)\n |> filter(fn: (r) => r._measurement == \"sensor.airtria_8_us2000c_tension_de_cellule_elevee\" and r._field == \"state\")\n |> last()\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"Tension cellule\"})"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "C",
|
||||||
|
"datasource": {
|
||||||
|
"type": "influxdb",
|
||||||
|
"uid": "evcs-influx"
|
||||||
|
},
|
||||||
|
"query": "from(bucket: \"evcs\")\n |> range(start: -48h)\n |> filter(fn: (r) => r._measurement == \"sensor.airtria_8_us2000c_cell_imbalance\" and r._field == \"state\")\n |> last()\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"Desequilibre\"})"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "D",
|
||||||
|
"datasource": {
|
||||||
|
"type": "influxdb",
|
||||||
|
"uid": "evcs-influx"
|
||||||
|
},
|
||||||
|
"query": "from(bucket: \"evcs\")\n |> range(start: -48h)\n |> filter(fn: (r) => r._measurement == \"%\" and r.entity_id == \"airtria_8_us2000c_state_of_health\" and r._field == \"value\")\n |> last()\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"Sante\"})"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gridPos": {
|
||||||
|
"x": 18,
|
||||||
|
"y": 5,
|
||||||
|
"w": 6,
|
||||||
|
"h": 8
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "text",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"type": "value",
|
||||||
|
"options": {
|
||||||
|
"no_alarm": {
|
||||||
|
"text": "OK",
|
||||||
|
"color": "green",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"text": "AVERTISSEMENT",
|
||||||
|
"color": "orange",
|
||||||
|
"index": 1
|
||||||
|
},
|
||||||
|
"alarm": {
|
||||||
|
"text": "ALARME",
|
||||||
|
"color": "red",
|
||||||
|
"index": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Charge max"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "unit",
|
||||||
|
"value": "amp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "decimals",
|
||||||
|
"value": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Sante"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "unit",
|
||||||
|
"value": "percent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "decimals",
|
||||||
|
"value": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"lastNotNull"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"orientation": "horizontal",
|
||||||
|
"textMode": "auto",
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "center",
|
||||||
|
"percentChangeColorMode": "standard",
|
||||||
|
"noValue": "—",
|
||||||
|
"text": {
|
||||||
|
"valueSize": 24,
|
||||||
|
"titleSize": 11
|
||||||
|
},
|
||||||
|
"wideLayout": true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "timeseries",
|
"type": "timeseries",
|
||||||
"title": "Les flux",
|
"title": "Les flux",
|
||||||
@@ -985,12 +1177,22 @@
|
|||||||
"mode": "multi",
|
"mode": "multi",
|
||||||
"sort": "desc"
|
"sort": "desc"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "filterFieldsByName",
|
||||||
|
"options": {
|
||||||
|
"include": {
|
||||||
|
"pattern": "^(time|Heure|$vue)$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "barchart",
|
"type": "barchart",
|
||||||
"title": "Energie heure par heure",
|
"title": "Energie par periode",
|
||||||
"description": "Obtenue en integrant la puissance, PAS en lisant les compteurs kWh du GX : ceux-ci se remettent a zero sans le signaler (verifie le 04/09, -373 kWh enregistres sur une heure cote Home Assistant).",
|
"description": "Le pas suit la periode choisie : l'heure jusqu'a 4 jours, le jour jusqu'a 70, le mois au-dela. Obtenue en integrant la puissance, PAS en lisant les compteurs kWh du GX : ceux-ci se remettent a zero sans le signaler (verifie le 04/09, -373 kWh enregistres sur une heure cote Home Assistant).",
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "grafana-postgresql-datasource",
|
"type": "grafana-postgresql-datasource",
|
||||||
"uid": "evcs-pg"
|
"uid": "evcs-pg"
|
||||||
@@ -1005,7 +1207,7 @@
|
|||||||
"format": "table",
|
"format": "table",
|
||||||
"rawQuery": true,
|
"rawQuery": true,
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"rawSql": "WITH axe AS (\n SELECT generate_series(date_trunc('minute', $__timeFrom()::timestamptz),\n date_trunc('minute', $__timeTo()::timestamptz),\n interval '1 minute') AS t\n),\nreleve AS (\n SELECT date_trunc('minute', ts) AS t,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_pv_power_system') AS Solaire,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_grid_power_l1') AS Reseau,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_consumption_power_l1') AS Maison,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_evcs_ac_power') AS Voiture\n FROM mesure WHERE $__timeFilter(ts) GROUP BY 1\n),\npar_minute AS (\n SELECT axe.t, releve.Solaire, releve.Reseau, releve.Maison, releve.Voiture\n FROM axe LEFT JOIN releve USING (t)\n),\npaliers AS (\n SELECT t, Solaire, Reseau, Maison, Voiture,\n count(Solaire) OVER (ORDER BY t) AS g_Solaire,\n count(Reseau) OVER (ORDER BY t) AS g_Reseau,\n count(Maison) OVER (ORDER BY t) AS g_Maison,\n count(Voiture) OVER (ORDER BY t) AS g_Voiture\n FROM par_minute\n),\nreport AS (\n SELECT t,\n first_value(Solaire) OVER (PARTITION BY g_Solaire ORDER BY t) AS Solaire,\n first_value(Reseau) OVER (PARTITION BY g_Reseau ORDER BY t) AS Reseau,\n first_value(Maison) OVER (PARTITION BY g_Maison ORDER BY t) AS Maison,\n first_value(Voiture) OVER (PARTITION BY g_Voiture ORDER BY t) AS Voiture\n FROM paliers\n)\nSELECT to_char(t, 'DD/MM HH24') AS \"Heure\",\n round((avg(Solaire) * count(Solaire) / 60.0 / 1000.0)::numeric, 2) AS \"Solaire\",\n round((avg(Reseau) * count(Reseau) / 60.0 / 1000.0)::numeric, 2) AS \"Reseau\",\n round((avg(Maison) * count(Maison) / 60.0 / 1000.0)::numeric, 2) AS \"Maison\",\n round((avg(Voiture) * count(Voiture) / 60.0 / 1000.0)::numeric, 2) AS \"Voiture\"\nFROM report\nGROUP BY date_trunc('hour', t), to_char(t, 'DD/MM HH24')\nHAVING count(Solaire) > 0 OR count(Reseau) > 0 OR count(Maison) > 0 OR count(Voiture) > 0\nORDER BY date_trunc('hour', t)"
|
"rawSql": "WITH bornes AS (\n SELECT $__timeFrom()::timestamptz AS d, $__timeTo()::timestamptz AS f\n),\n-- Le pas s'adapte a la plage choisie. Sans cela, « 30 derniers jours » rend\n-- 720 barres illisibles — c'est exactement ce que fait VRM en passant de\n-- l'heure au jour puis au mois.\npas AS (\n SELECT CASE WHEN f - d > interval '70 days' THEN 'month'\n WHEN f - d > interval '4 days' THEN 'day'\n ELSE 'hour' END AS unite,\n CASE WHEN f - d > interval '70 days' THEN 'MM/YYYY'\n WHEN f - d > interval '4 days' THEN 'DD/MM'\n ELSE 'DD/MM HH24' END AS forme\n FROM bornes\n),\naxe AS (\n SELECT generate_series(date_trunc('minute', (SELECT d FROM bornes)),\n date_trunc('minute', (SELECT f FROM bornes)),\n interval '1 minute') AS t\n),\nreleve AS (\n SELECT date_trunc('minute', ts) AS t,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_pv_power_system') AS Solaire,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_grid_power_l1') AS Reseau,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_consumption_power_l1') AS Maison,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_evcs_ac_power') AS Voiture\n FROM mesure WHERE $__timeFilter(ts) GROUP BY 1\n),\npar_minute AS (\n SELECT axe.t, releve.Solaire, releve.Reseau, releve.Maison, releve.Voiture\n FROM axe LEFT JOIN releve USING (t)\n),\npaliers AS (\n SELECT t, Solaire, Reseau, Maison, Voiture,\n count(Solaire) OVER (ORDER BY t) AS g_Solaire,\n count(Reseau) OVER (ORDER BY t) AS g_Reseau,\n count(Maison) OVER (ORDER BY t) AS g_Maison,\n count(Voiture) OVER (ORDER BY t) AS g_Voiture\n FROM par_minute\n),\nreport AS (\n SELECT t,\n first_value(Solaire) OVER (PARTITION BY g_Solaire ORDER BY t) AS Solaire,\n first_value(Reseau) OVER (PARTITION BY g_Reseau ORDER BY t) AS Reseau,\n first_value(Maison) OVER (PARTITION BY g_Maison ORDER BY t) AS Maison,\n first_value(Voiture) OVER (PARTITION BY g_Voiture ORDER BY t) AS Voiture\n FROM paliers\n)\nSELECT to_char(date_trunc(pas.unite, t), pas.forme) AS \"Heure\",\n round((avg(Solaire) * count(Solaire) / 60.0 / 1000.0)::numeric, 2) AS \"Solaire\",\n round((avg(Reseau) * count(Reseau) / 60.0 / 1000.0)::numeric, 2) AS \"Reseau\",\n round((avg(Maison) * count(Maison) / 60.0 / 1000.0)::numeric, 2) AS \"Maison\",\n round((avg(Voiture) * count(Voiture) / 60.0 / 1000.0)::numeric, 2) AS \"Voiture\"\nFROM report, pas\nGROUP BY date_trunc(pas.unite, t), pas.forme\nHAVING count(Solaire) > 0 OR count(Reseau) > 0 OR count(Maison) > 0 OR count(Voiture) > 0\nORDER BY date_trunc(pas.unite, t)"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"gridPos": {
|
"gridPos": {
|
||||||
@@ -1045,7 +1247,17 @@
|
|||||||
"mode": "multi",
|
"mode": "multi",
|
||||||
"sort": "none"
|
"sort": "none"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "filterFieldsByName",
|
||||||
|
"options": {
|
||||||
|
"include": {
|
||||||
|
"pattern": "^(time|Heure|$vue)$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
"uid": "evcs-telephone",
|
"uid": "evcs-telephone",
|
||||||
"title": "Sur le telephone",
|
"title": "Sur le telephone",
|
||||||
"description": "Une colonne, pensee pour un ecran de telephone. Repond a une seule question : est-ce que la nuit qui vient va bien se passer ?",
|
"description": "Une colonne, pensee pour un ecran de telephone. Repond a une seule question : est-ce que la nuit qui vient va bien se passer ?",
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ def ts(title, targets, ds, x, y, w, h, unit="", desc="", extra=None, legend="bot
|
|||||||
p[k] = v
|
p[k] = v
|
||||||
return p
|
return p
|
||||||
|
|
||||||
def stat(title, targets, ds, x, y, w, h, desc="", overrides=None, texte="auto"):
|
def stat(title, targets, ds, x, y, w, h, desc="", overrides=None, texte="auto",
|
||||||
|
taille=None, mappings=None):
|
||||||
"""Grands chiffres. Sur telephone, Grafana empile TOUS les panneaux en
|
"""Grands chiffres. Sur telephone, Grafana empile TOUS les panneaux en
|
||||||
pleine largeur sous ~770 px : mettre plusieurs valeurs dans UN panneau est
|
pleine largeur sous ~770 px : mettre plusieurs valeurs dans UN panneau est
|
||||||
donc le seul moyen de les garder cote a cote et de limiter le defilement."""
|
donc le seul moyen de les garder cote a cote et de limiter le defilement."""
|
||||||
@@ -84,7 +85,7 @@ def stat(title, targets, ds, x, y, w, h, desc="", overrides=None, texte="auto"):
|
|||||||
"color": {"mode": "thresholds"},
|
"color": {"mode": "thresholds"},
|
||||||
"thresholds": {"mode": "absolute",
|
"thresholds": {"mode": "absolute",
|
||||||
"steps": [{"color": "text", "value": None}]},
|
"steps": [{"color": "text", "value": None}]},
|
||||||
"mappings": []}, "overrides": overrides or []},
|
"mappings": mappings or []}, "overrides": overrides or []},
|
||||||
"options": {"reduceOptions": {"calcs": ["lastNotNull"],
|
"options": {"reduceOptions": {"calcs": ["lastNotNull"],
|
||||||
"fields": "", "values": False},
|
"fields": "", "values": False},
|
||||||
"orientation": "horizontal", "textMode": texte,
|
"orientation": "horizontal", "textMode": texte,
|
||||||
@@ -92,6 +93,7 @@ def stat(title, targets, ds, x, y, w, h, desc="", overrides=None, texte="auto"):
|
|||||||
"justifyMode": "center",
|
"justifyMode": "center",
|
||||||
"percentChangeColorMode": "standard",
|
"percentChangeColorMode": "standard",
|
||||||
"noValue": "—",
|
"noValue": "—",
|
||||||
|
**({"text": taille} if taille else {}),
|
||||||
"wideLayout": True}}
|
"wideLayout": True}}
|
||||||
|
|
||||||
|
|
||||||
@@ -136,8 +138,9 @@ def barchart(title, targets, ds, x, y, w, h, unit="", desc=""):
|
|||||||
"showLegend": True},
|
"showLegend": True},
|
||||||
"tooltip": {"mode": "multi", "sort": "none"}}}
|
"tooltip": {"mode": "multi", "sort": "none"}}}
|
||||||
|
|
||||||
def dashboard(uid, title, desc, panels, refresh="1m", frm="now-24h"):
|
def dashboard(uid, title, desc, panels, refresh="1m", frm="now-24h", variables=None):
|
||||||
return {
|
return {
|
||||||
|
"templating": {"list": variables or []},
|
||||||
"uid": uid, "title": title, "description": desc,
|
"uid": uid, "title": title, "description": desc,
|
||||||
"tags": ["evcs"], "timezone": "Europe/Paris", "editable": True,
|
"tags": ["evcs"], "timezone": "Europe/Paris", "editable": True,
|
||||||
"schemaVersion": 39, "version": 1, "refresh": refresh,
|
"schemaVersion": 39, "version": 1, "refresh": refresh,
|
||||||
@@ -614,7 +617,7 @@ telephone = dashboard("evcs-telephone", "Sur le telephone", (
|
|||||||
# variation de -373 kWh sur une heure. Integrer la puissance ignore
|
# variation de -373 kWh sur une heure. Integrer la puissance ignore
|
||||||
# completement ce probleme.
|
# completement ce probleme.
|
||||||
|
|
||||||
def flux_dernier(refid, mesure, entite, libelle, champ="value"):
|
def flux_dernier(refid, mesure, entite, libelle, champ="value", fenetre="6h"):
|
||||||
"""Derniere valeur connue d'une entite, renommee pour l'affichage."""
|
"""Derniere valeur connue d'une entite, renommee pour l'affichage."""
|
||||||
# Fenetre de 6 HEURES : un compromis, et il merite d'etre explique.
|
# Fenetre de 6 HEURES : un compromis, et il merite d'etre explique.
|
||||||
#
|
#
|
||||||
@@ -645,7 +648,7 @@ def flux_dernier(refid, mesure, entite, libelle, champ="value"):
|
|||||||
# constante. `last()` reste peu couteux sur une fenetre large.
|
# constante. `last()` reste peu couteux sur une fenetre large.
|
||||||
return flux(refid,
|
return flux(refid,
|
||||||
f'from(bucket: "evcs")\n'
|
f'from(bucket: "evcs")\n'
|
||||||
f' |> range(start: -6h)\n'
|
f' |> range(start: -{fenetre})\n'
|
||||||
f' |> filter(fn: (r) => r._measurement == "{mesure}"'
|
f' |> filter(fn: (r) => r._measurement == "{mesure}"'
|
||||||
f' and r.entity_id == "{entite}" and r._field == "{champ}")\n'
|
f' and r.entity_id == "{entite}" and r._field == "{champ}")\n'
|
||||||
f' |> last()\n'
|
f' |> last()\n'
|
||||||
@@ -678,9 +681,24 @@ ENERGIE_CLES = [
|
|||||||
# D'ou l'axe des minutes COMPLET par `generate_series`, la valeur reportee
|
# D'ou l'axe des minutes COMPLET par `generate_series`, la valeur reportee
|
||||||
# depuis le dernier point connu, puis la moyenne. Chaque heure pese alors ses
|
# depuis le dernier point connu, puis la moyenne. Chaque heure pese alors ses
|
||||||
# soixante minutes, qu'il y ait eu une mesure ou non.
|
# soixante minutes, qu'il y ait eu une mesure ou non.
|
||||||
ENERGIE_SQL = """WITH axe AS (
|
ENERGIE_SQL = """WITH bornes AS (
|
||||||
SELECT generate_series(date_trunc('minute', $__timeFrom()::timestamptz),
|
SELECT $__timeFrom()::timestamptz AS d, $__timeTo()::timestamptz AS f
|
||||||
date_trunc('minute', $__timeTo()::timestamptz),
|
),
|
||||||
|
-- Le pas s'adapte a la plage choisie. Sans cela, « 30 derniers jours » rend
|
||||||
|
-- 720 barres illisibles — c'est exactement ce que fait VRM en passant de
|
||||||
|
-- l'heure au jour puis au mois.
|
||||||
|
pas AS (
|
||||||
|
SELECT CASE WHEN f - d > interval '70 days' THEN 'month'
|
||||||
|
WHEN f - d > interval '4 days' THEN 'day'
|
||||||
|
ELSE 'hour' END AS unite,
|
||||||
|
CASE WHEN f - d > interval '70 days' THEN 'MM/YYYY'
|
||||||
|
WHEN f - d > interval '4 days' THEN 'DD/MM'
|
||||||
|
ELSE 'DD/MM HH24' END AS forme
|
||||||
|
FROM bornes
|
||||||
|
),
|
||||||
|
axe AS (
|
||||||
|
SELECT generate_series(date_trunc('minute', (SELECT d FROM bornes)),
|
||||||
|
date_trunc('minute', (SELECT f FROM bornes)),
|
||||||
interval '1 minute') AS t
|
interval '1 minute') AS t
|
||||||
),
|
),
|
||||||
releve AS (
|
releve AS (
|
||||||
@@ -705,22 +723,15 @@ report AS (
|
|||||||
for _, n in ENERGIE_CLES) + """
|
for _, n in ENERGIE_CLES) + """
|
||||||
FROM paliers
|
FROM paliers
|
||||||
)
|
)
|
||||||
SELECT to_char(t, 'DD/MM HH24') AS "Heure",
|
SELECT to_char(date_trunc(pas.unite, t), pas.forme) AS "Heure",
|
||||||
""" + ",\n".join(
|
""" + ",\n".join(
|
||||||
# Energie REELLEMENT accumulee : puissance moyenne x duree observee.
|
# Energie REELLEMENT accumulee : puissance moyenne x duree observee.
|
||||||
# Pas la moyenne seule, qui comptait 22 minutes comme 60 et annoncait
|
|
||||||
# 5,13 kWh de reseau a 01 h le 04/09 — le service n'avait demarre qu'a
|
|
||||||
# 01:37. Pas non plus un rejet des heures incompletes, qui laissait
|
|
||||||
# toujours vide l'heure EN COURS, celle qu'on regarde le plus.
|
|
||||||
# Contrepartie assumee : une heure passee amputee par un arret du service
|
|
||||||
# sous-estime — mais un tel arret est journalise et apparait en marqueur
|
|
||||||
# sur le graphique.
|
|
||||||
f' round((avg({n}) * count({n}) / 60.0 / 1000.0)::numeric, 2) AS "{n}"'
|
f' round((avg({n}) * count({n}) / 60.0 / 1000.0)::numeric, 2) AS "{n}"'
|
||||||
for _, n in ENERGIE_CLES) + """
|
for _, n in ENERGIE_CLES) + """
|
||||||
FROM report
|
FROM report, pas
|
||||||
GROUP BY date_trunc('hour', t), to_char(t, 'DD/MM HH24')
|
GROUP BY date_trunc(pas.unite, t), pas.forme
|
||||||
HAVING """ + " OR ".join(f"count({n}) > 0" for _, n in ENERGIE_CLES) + """
|
HAVING """ + " OR ".join(f"count({n}) > 0" for _, n in ENERGIE_CLES) + """
|
||||||
ORDER BY date_trunc('hour', t)"""
|
ORDER BY date_trunc(pas.unite, t)"""
|
||||||
|
|
||||||
# Detail par tracker. Les quatre entrees du RS 450/200 et le MPPT1 ne suivent
|
# Detail par tracker. Les quatre entrees du RS 450/200 et le MPPT1 ne suivent
|
||||||
# pas la meme convention de nommage : deux branches, reunies puis pivotees.
|
# pas la meme convention de nommage : deux branches, reunies puis pivotees.
|
||||||
@@ -757,17 +768,39 @@ def col(nom, unite, largeur=None, dec=0):
|
|||||||
props.append({"id": "custom.width", "value": largeur})
|
props.append({"id": "custom.width", "value": largeur})
|
||||||
return sur(nom, props)
|
return sur(nom, props)
|
||||||
|
|
||||||
|
|
||||||
|
# Selecteur de vue, dans l'esprit de VRM : la meme representation, restreinte
|
||||||
|
# aux grandeurs qui interessent. La valeur de chaque option est directement une
|
||||||
|
# alternative d'expression reguliere, consommee par la transformation
|
||||||
|
# « filterFieldsByName » des panneaux — d'ou le separateur « | ».
|
||||||
|
_VUES = [
|
||||||
|
("Vue generale", "Solaire|Reseau|Batterie|Maison|Voiture"),
|
||||||
|
("Consommation", "Maison|Voiture"),
|
||||||
|
("Reseau", "Reseau|Maison"),
|
||||||
|
("Batterie", "Batterie|Solaire|Maison"),
|
||||||
|
("Chargeur VE", "Voiture|Solaire"),
|
||||||
|
]
|
||||||
|
VARIABLE_VUE = {
|
||||||
|
"name": "vue", "label": "Vue", "type": "custom", "hide": 0, "skipUrlSync": False,
|
||||||
|
"query": ",".join(f"{t} : {v}" for t, v in _VUES),
|
||||||
|
"options": [{"selected": i == 0, "text": t, "value": v} for i, (t, v) in enumerate(_VUES)],
|
||||||
|
"current": {"selected": True, "text": _VUES[0][0], "value": _VUES[0][1]},
|
||||||
|
"multi": False, "includeAll": False,
|
||||||
|
}
|
||||||
|
FILTRE_VUE = [{"id": "filterFieldsByName",
|
||||||
|
"options": {"include": {"pattern": "^(time|Heure|$vue)$"}}}]
|
||||||
|
|
||||||
systeme = dashboard("evcs-systeme", "Le systeme", (
|
systeme = dashboard("evcs-systeme", "Le systeme", (
|
||||||
"Replique locale de la vue generale VRM. La console Victron est hebergee "
|
"Replique locale de la vue generale VRM. La console Victron est hebergee "
|
||||||
"dans le cloud : elle disparait quand une coupure d'orage emporte "
|
"dans le cloud : elle disparait quand une coupure d'orage emporte "
|
||||||
"Internet. Tout ce qui est affiche ici est lu sur le reseau local."),
|
"Internet. Tout ce qui est affiche ici est lu sur le reseau local."),
|
||||||
frm="now-24h", refresh="30s", panels=[
|
frm="now-24h", refresh="30s", variables=[VARIABLE_VUE], panels=[
|
||||||
|
|
||||||
stat("Reseau", [
|
stat("Reseau", [
|
||||||
flux_dernier("A", "W", "victron_grid_power_l1", "Puissance"),
|
flux_dernier("A", "W", "victron_grid_power_l1", "Puissance"),
|
||||||
flux_dernier("B", "V", "airtria_mpii_v1_input_voltage_l1", "Tension"),
|
flux_dernier("B", "V", "airtria_mpii_v1_input_voltage_l1", "Tension"),
|
||||||
flux_dernier("C", "A", "gx_device_grid_current_l1", "Courant")],
|
flux_dernier("C", "A", "gx_device_grid_current_l1", "Courant")],
|
||||||
IN, 0, 0, 6, 5,
|
IN, 0, 0, 5, 5,
|
||||||
"Positif : le reseau alimente la maison. Le contacteur EDF est pilote par "
|
"Positif : le reseau alimente la maison. Le contacteur EDF est pilote par "
|
||||||
"le workflow d'hysteresis, pas depuis ici.",
|
"le workflow d'hysteresis, pas depuis ici.",
|
||||||
overrides=[col("Puissance", "watt"), col("Tension", "volt"), col("Courant", "amp", dec=1)]),
|
overrides=[col("Puissance", "watt"), col("Tension", "volt"), col("Courant", "amp", dec=1)]),
|
||||||
@@ -775,7 +808,7 @@ systeme = dashboard("evcs-systeme", "Le systeme", (
|
|||||||
stat("Charges CA", [
|
stat("Charges CA", [
|
||||||
flux_dernier("A", "W", "victron_consumption_power_l1", "Consommation"),
|
flux_dernier("A", "W", "victron_consumption_power_l1", "Consommation"),
|
||||||
flux_dernier("B", "Hz", "airtria_mpii_v1_output_frequency_l1", "Frequence")],
|
flux_dernier("B", "Hz", "airtria_mpii_v1_output_frequency_l1", "Frequence")],
|
||||||
IN, 6, 0, 5, 5,
|
IN, 5, 0, 4, 5,
|
||||||
"Ce que la maison consomme, voiture comprise.",
|
"Ce que la maison consomme, voiture comprise.",
|
||||||
overrides=[col("Consommation", "watt"), col("Frequence", "hertz", dec=1)]),
|
overrides=[col("Consommation", "watt"), col("Frequence", "hertz", dec=1)]),
|
||||||
|
|
||||||
@@ -785,7 +818,7 @@ systeme = dashboard("evcs-systeme", "Le systeme", (
|
|||||||
flux_dernier("C", "V", "victron_battery_voltage", "Tension"),
|
flux_dernier("C", "V", "victron_battery_voltage", "Tension"),
|
||||||
flux_dernier("D", "A", "victron_battery_current", "Courant"),
|
flux_dernier("D", "A", "victron_battery_current", "Courant"),
|
||||||
flux_dernier("E", "°C", "victron_battery_temperature", "Temperature")],
|
flux_dernier("E", "°C", "victron_battery_temperature", "Temperature")],
|
||||||
IN, 11, 0, 8, 5,
|
IN, 9, 0, 10, 5,
|
||||||
"Puissance positive : la batterie se charge. Sept modules actifs sur huit, "
|
"Puissance positive : la batterie se charge. Sept modules actifs sur huit, "
|
||||||
"un pack bloquant la charge vers 94 %.",
|
"un pack bloquant la charge vers 94 %.",
|
||||||
overrides=[
|
overrides=[
|
||||||
@@ -793,7 +826,11 @@ systeme = dashboard("evcs-systeme", "Le systeme", (
|
|||||||
{"id": "thresholds", "value": seuils(
|
{"id": "thresholds", "value": seuils(
|
||||||
("red", None), ("orange", 25), ("yellow", 40), ("green", 60))}]),
|
("red", None), ("orange", 25), ("yellow", 40), ("green", 60))}]),
|
||||||
col("Puissance", "watt"), col("Tension", "volt", dec=2),
|
col("Puissance", "watt"), col("Tension", "volt", dec=2),
|
||||||
col("Courant", "amp", dec=1), col("Temperature", "celsius")]),
|
col("Courant", "amp", dec=1), col("Temperature", "celsius")],
|
||||||
|
# Cinq valeurs dans huit colonnes : Grafana reduisait le texte jusqu'a
|
||||||
|
# l'illisible. Dix colonnes et une taille imposee, plutot que de laisser
|
||||||
|
# l'ajustement automatique decider.
|
||||||
|
taille={"valueSize": 26, "titleSize": 11}),
|
||||||
|
|
||||||
stat("Chargeur VE", [
|
stat("Chargeur VE", [
|
||||||
flux_dernier("A", "W", "victron_evcs_ac_power", "Puissance"),
|
flux_dernier("A", "W", "victron_evcs_ac_power", "Puissance"),
|
||||||
@@ -808,14 +845,14 @@ systeme = dashboard("evcs-systeme", "Le systeme", (
|
|||||||
stat("Chargeur PV", [
|
stat("Chargeur PV", [
|
||||||
flux_dernier("A", "W", "victron_pv_power_system", "Production"),
|
flux_dernier("A", "W", "victron_pv_power_system", "Production"),
|
||||||
flux_dernier("B", "W", "victron_pv_power_10m_avg", "Moyenne 10 min")],
|
flux_dernier("B", "W", "victron_pv_power_10m_avg", "Moyenne 10 min")],
|
||||||
IN, 0, 5, 6, 8,
|
IN, 0, 5, 5, 8,
|
||||||
"Rappel qui vaut pour toute lecture de cette valeur : sans injection, la "
|
"Rappel qui vaut pour toute lecture de cette valeur : sans injection, la "
|
||||||
"production MESUREE vaut min(ressource, consommation + absorption "
|
"production MESUREE vaut min(ressource, consommation + absorption "
|
||||||
"batterie). Basse ne veut pas dire mauvais temps.",
|
"batterie). Basse ne veut pas dire mauvais temps.",
|
||||||
overrides=[col("Production", "watt"), col("Moyenne 10 min", "watt")]),
|
overrides=[col("Production", "watt"), col("Moyenne 10 min", "watt")]),
|
||||||
|
|
||||||
dict(table("Detail par tracker", [flux("A", TRACKERS_FLUX)],
|
dict(table("Detail par tracker", [flux("A", TRACKERS_FLUX)],
|
||||||
IN, 6, 5, 18, 8,
|
IN, 5, 5, 13, 8,
|
||||||
"Les 52 panneaux en quatre plans : sud-est 40 degres, trois chaines sud "
|
"Les 52 panneaux en quatre plans : sud-est 40 degres, trois chaines sud "
|
||||||
"35 degres, ouest 45 degres. Le suiveur de trois panneaux ne publie pas "
|
"35 degres, ouest 45 degres. Le suiveur de trois panneaux ne publie pas "
|
||||||
"de mode de fonctionnement et n'apparait donc pas ici.",
|
"de mode de fonctionnement et n'apparait donc pas ici.",
|
||||||
@@ -835,6 +872,41 @@ systeme = dashboard("evcs-systeme", "Le systeme", (
|
|||||||
transformations=[{"id": "organize", "options": {
|
transformations=[{"id": "organize", "options": {
|
||||||
"indexByName": {"tracker": 0, "V": 1, "A": 2, "W": 3}}}]),
|
"indexByName": {"tracker": 0, "V": 1, "A": 2, "W": 3}}}]),
|
||||||
|
|
||||||
|
stat("Ce que le BMS impose", [
|
||||||
|
# Fenetre de 48 h pour ce panneau, et c'est deliberement different du
|
||||||
|
# reste. Un etat d'alarme ne devient jamais « indisponible » : il se
|
||||||
|
# publie. Sa derniere valeur EST donc la valeur courante, meme vieille de
|
||||||
|
# dix heures — a l'inverse du courant reseau, dont le capteur disparait et
|
||||||
|
# laisse derriere lui un chiffre qui ment.
|
||||||
|
flux_dernier("A", "A", "airtria_8_us2000c_maximum_allowed_charge_current", "Charge max", fenetre="48h"),
|
||||||
|
flux("B", 'from(bucket: "evcs")\n'
|
||||||
|
' |> range(start: -48h)\n'
|
||||||
|
' |> filter(fn: (r) => r._measurement == "sensor.airtria_8_us2000c_tension_de_cellule_elevee"'
|
||||||
|
' and r._field == "state")\n'
|
||||||
|
' |> last()\n'
|
||||||
|
' |> keep(columns: ["_time", "_value"])\n'
|
||||||
|
' |> rename(columns: {_value: "Tension cellule"})'),
|
||||||
|
flux("C", 'from(bucket: "evcs")\n'
|
||||||
|
' |> range(start: -48h)\n'
|
||||||
|
' |> filter(fn: (r) => r._measurement == "sensor.airtria_8_us2000c_cell_imbalance"'
|
||||||
|
' and r._field == "state")\n'
|
||||||
|
' |> last()\n'
|
||||||
|
' |> keep(columns: ["_time", "_value"])\n'
|
||||||
|
' |> rename(columns: {_value: "Desequilibre"})'),
|
||||||
|
flux_dernier("D", "%", "airtria_8_us2000c_state_of_health", "Sante", fenetre="48h")],
|
||||||
|
IN, 18, 5, 6, 8,
|
||||||
|
"« Charge max » est la limite que le BMS impose au systeme entier. Le "
|
||||||
|
"04/09 elle est tombee de 150 a 20 A en trois minutes, des 76 % de charge, "
|
||||||
|
"au moment ou l'alarme de tension de cellule s'est declenchee — le parc "
|
||||||
|
"n'etait alors qu'a 50,76 V pour 53,2 V autorises. Ce n'est pas le parc "
|
||||||
|
"qui sature, c'est une cellule.",
|
||||||
|
overrides=[col("Charge max", "amp"), col("Sante", "percent")],
|
||||||
|
taille={"valueSize": 24, "titleSize": 11},
|
||||||
|
mappings=[{"type": "value", "options": {
|
||||||
|
"no_alarm": {"text": "OK", "color": "green", "index": 0},
|
||||||
|
"warning": {"text": "AVERTISSEMENT", "color": "orange", "index": 1},
|
||||||
|
"alarm": {"text": "ALARME", "color": "red", "index": 2}}}]),
|
||||||
|
|
||||||
ts("Les flux", [
|
ts("Les flux", [
|
||||||
sql_grandeurs("A", [
|
sql_grandeurs("A", [
|
||||||
('sensor.victron_pv_power_system', 'Solaire'),
|
('sensor.victron_pv_power_system', 'Solaire'),
|
||||||
@@ -852,13 +924,17 @@ systeme = dashboard("evcs-systeme", "Le systeme", (
|
|||||||
sur("Batterie", [{"id": "color", "value": {"mode": "fixed", "fixedColor": "blue"}}]),
|
sur("Batterie", [{"id": "color", "value": {"mode": "fixed", "fixedColor": "blue"}}]),
|
||||||
sur("Maison", [{"id": "color", "value": {"mode": "fixed", "fixedColor": "text"}},
|
sur("Maison", [{"id": "color", "value": {"mode": "fixed", "fixedColor": "text"}},
|
||||||
{"id": "custom.fillOpacity", "value": 0}]),
|
{"id": "custom.fillOpacity", "value": 0}]),
|
||||||
sur("Voiture", [{"id": "color", "value": {"mode": "fixed", "fixedColor": "green"}}])]}),
|
sur("Voiture", [{"id": "color", "value": {"mode": "fixed", "fixedColor": "green"}}])],
|
||||||
|
"transformations": FILTRE_VUE}),
|
||||||
|
|
||||||
barchart("Energie heure par heure", [sql("A", ENERGIE_SQL, fmt="table")],
|
dict(barchart("Energie par periode", [sql("A", ENERGIE_SQL, fmt="table")],
|
||||||
PG, 0, 22, 24, 9, "kwatth",
|
PG, 0, 22, 24, 9, "kwatth",
|
||||||
"Obtenue en integrant la puissance, PAS en lisant les compteurs kWh du "
|
"Le pas suit la periode choisie : l'heure jusqu'a 4 jours, le jour "
|
||||||
"GX : ceux-ci se remettent a zero sans le signaler (verifie le 04/09, "
|
"jusqu'a 70, le mois au-dela. Obtenue en integrant la puissance, PAS en "
|
||||||
"-373 kWh enregistres sur une heure cote Home Assistant)."),
|
"lisant les compteurs kWh du GX : ceux-ci se remettent a zero sans le "
|
||||||
|
"signaler (verifie le 04/09, -373 kWh enregistres sur une heure cote "
|
||||||
|
"Home Assistant)."),
|
||||||
|
transformations=FILTRE_VUE),
|
||||||
])
|
])
|
||||||
|
|
||||||
base = pathlib.Path('deploy/historisation/grafana/dashboards')
|
base = pathlib.Path('deploy/historisation/grafana/dashboards')
|
||||||
|
|||||||
Reference in New Issue
Block a user