Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
1045 lines
49 KiB
JSON
1045 lines
49 KiB
JSON
{
|
|
"templating": {
|
|
"list": []
|
|
},
|
|
"uid": "evcs-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.",
|
|
"tags": [
|
|
"evcs"
|
|
],
|
|
"timezone": "Europe/Paris",
|
|
"editable": true,
|
|
"schemaVersion": 39,
|
|
"version": 1,
|
|
"refresh": "1m",
|
|
"time": {
|
|
"from": "now-24h",
|
|
"to": "now"
|
|
},
|
|
"timepicker": {
|
|
"refresh_intervals": [
|
|
"30s",
|
|
"1m",
|
|
"5m",
|
|
"15m",
|
|
"1h"
|
|
]
|
|
},
|
|
"annotations": {
|
|
"list": [
|
|
{
|
|
"builtIn": 1,
|
|
"datasource": {
|
|
"type": "grafana",
|
|
"uid": "-- Grafana --"
|
|
},
|
|
"enable": true,
|
|
"hide": true,
|
|
"name": "Annotations & Alerts",
|
|
"iconColor": "rgba(0, 211, 255, 1)",
|
|
"type": "dashboard"
|
|
},
|
|
{
|
|
"name": "Evenements",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"enable": false,
|
|
"iconColor": "semi-dark-orange",
|
|
"hide": false,
|
|
"target": {
|
|
"format": "table",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "SELECT ts AS time, resume AS text, genre || ',' || coalesce(source,'?') AS tags FROM evenement WHERE $__timeFilter(ts) AND genre <> 'bilan' ORDER BY 1"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"panels": [
|
|
{
|
|
"type": "timeseries",
|
|
"title": "Couverture de la nuit",
|
|
"description": "SOC requis = ce qu'il faut MAINTENANT pour tenir jusqu'au croisement PV/conso. Il decroit avec la nuit qui se consomme. Quand la courbe reelle passe dessous, la batterie ne passera pas la nuit sans reseau.",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "time_series",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "SELECT ts AS time,\n soc_pct AS \"SOC reel\",\n soc_requis_pct AS \"SOC requis (bilan)\"\nFROM bilan\nWHERE $__timeFilter(ts)\nORDER BY 1"
|
|
},
|
|
{
|
|
"refId": "B",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "time_series",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "SELECT ts AS time, valeur AS \"Cible du matin\"\nFROM mesure\nWHERE cle = 'input_number.victron_evcs_night_target_soc'\n AND $__timeFilter(ts)\nORDER BY 1"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 0,
|
|
"w": 16,
|
|
"h": 9
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "percent",
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"custom": {
|
|
"lineWidth": 2,
|
|
"fillOpacity": 8,
|
|
"showPoints": "never",
|
|
"spanNulls": true,
|
|
"axisBorderShow": false,
|
|
"gradientMode": "opacity"
|
|
},
|
|
"min": 0,
|
|
"max": 100
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "SOC reel"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "green"
|
|
}
|
|
},
|
|
{
|
|
"id": "custom.lineWidth",
|
|
"value": 3
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "SOC requis (bilan)"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "orange"
|
|
}
|
|
},
|
|
{
|
|
"id": "custom.fillOpacity",
|
|
"value": 0
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Cible du matin"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "purple"
|
|
}
|
|
},
|
|
{
|
|
"id": "custom.fillOpacity",
|
|
"value": 0
|
|
},
|
|
{
|
|
"id": "custom.lineStyle",
|
|
"value": {
|
|
"fill": "dash",
|
|
"dash": [
|
|
8,
|
|
6
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"displayMode": "list",
|
|
"placement": "bottom",
|
|
"showLegend": true,
|
|
"calcs": []
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "timeseries",
|
|
"title": "Marge (reel moins requis)",
|
|
"description": "Sous zero, il manque de l'energie pour finir la nuit. La nuit du 02-03/09 est restee negative de bout en bout, et personne ne le voyait.",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "time_series",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "SELECT ts AS time, soc_pct - soc_requis_pct AS \"Marge\"\nFROM bilan\nWHERE $__timeFilter(ts) AND soc_requis_pct IS NOT NULL\nORDER BY 1"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 16,
|
|
"y": 0,
|
|
"w": 8,
|
|
"h": 9
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "percent",
|
|
"color": {
|
|
"mode": "thresholds"
|
|
},
|
|
"custom": {
|
|
"lineWidth": 2,
|
|
"fillOpacity": 25,
|
|
"showPoints": "never",
|
|
"gradientMode": "scheme",
|
|
"spanNulls": true,
|
|
"thresholdsStyle": {
|
|
"mode": "line"
|
|
}
|
|
},
|
|
"thresholds": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{
|
|
"color": "red",
|
|
"value": null
|
|
},
|
|
{
|
|
"color": "green",
|
|
"value": 0
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"overrides": []
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"showLegend": false
|
|
},
|
|
"tooltip": {
|
|
"mode": "single",
|
|
"sort": "none"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "state-timeline",
|
|
"title": "Ce que le controleur a decide",
|
|
"description": "Une ligne par CHANGEMENT de decision, pas une toutes les 30 s. La session reseau de nuit doit s'engager UNE fois et se relacher a la fermeture de la fenetre : plusieurs bascules = un oscillateur.",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "table",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "SELECT ts AS time,\n source_mode AS \"Source\",\n etat AS \"Etat\",\n CASE WHEN session_engagee THEN 'engagee' ELSE '-' END AS \"Session reseau\",\n CASE WHEN takeover_reseau THEN 'demande' ELSE '-' END AS \"Reprise reseau\"\nFROM decision\nWHERE $__timeFilter(ts)\nORDER BY 1"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 9,
|
|
"w": 24,
|
|
"h": 7
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "continuous-GrYlRd"
|
|
},
|
|
"custom": {
|
|
"lineWidth": 0,
|
|
"fillOpacity": 80,
|
|
"insertNulls": false,
|
|
"spanNulls": true
|
|
},
|
|
"mappings": [
|
|
{
|
|
"type": "value",
|
|
"options": {
|
|
"-": {
|
|
"color": "dark-blue",
|
|
"index": 0
|
|
},
|
|
"engagee": {
|
|
"color": "orange",
|
|
"index": 1
|
|
},
|
|
"demande": {
|
|
"color": "semi-dark-orange",
|
|
"index": 2
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"overrides": []
|
|
},
|
|
"options": {
|
|
"showValue": "auto",
|
|
"mergeValues": true,
|
|
"alignValue": "left",
|
|
"rowHeight": 0.85,
|
|
"legend": {
|
|
"displayMode": "list",
|
|
"placement": "bottom",
|
|
"showLegend": false
|
|
},
|
|
"tooltip": {
|
|
"mode": "single"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "timeseries",
|
|
"title": "Les puissances de la nuit",
|
|
"description": "Batterie positive = elle se charge. Contacteur ferme avec un import qui ne couvre pas la maison = la batterie paie quand meme : c'est le defaut du 04/09 (consigne retombee a 50 W en pleine session).",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "time_series",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "WITH par_minute AS (\n SELECT date_trunc('minute', ts) AS t,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_grid_power_l1') AS Reseau,\n (array_agg(valeur ORDER BY ts DESC) FILTER (WHERE cle = 'sensor.victron_grid_power_l1'))[1] AS d_Reseau,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_battery_power') AS Batterie,\n (array_agg(valeur ORDER BY ts DESC) FILTER (WHERE cle = 'sensor.victron_battery_power'))[1] AS d_Batterie,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_consumption_power_l1') AS Maison,\n (array_agg(valeur ORDER BY ts DESC) FILTER (WHERE cle = 'sensor.victron_consumption_power_l1'))[1] AS d_Maison,\n avg(valeur) FILTER (WHERE cle = 'sensor.victron_evcs_ac_power') AS Voiture,\n (array_agg(valeur ORDER BY ts DESC) FILTER (WHERE cle = 'sensor.victron_evcs_ac_power'))[1] AS d_Voiture\n FROM mesure WHERE $__timeFilter(ts) GROUP BY 1\n),\npaliers AS (\n SELECT t,\n Reseau, count(d_Reseau) OVER (ORDER BY t) AS g_Reseau,\n Batterie, count(d_Batterie) OVER (ORDER BY t) AS g_Batterie,\n Maison, count(d_Maison) OVER (ORDER BY t) AS g_Maison,\n Voiture, count(d_Voiture) OVER (ORDER BY t) AS g_Voiture,\n d_Reseau,\n d_Batterie,\n d_Maison,\n d_Voiture\n FROM par_minute\n),\nreport AS (\n SELECT t,\n coalesce(Reseau, first_value(d_Reseau) OVER (PARTITION BY g_Reseau ORDER BY t)) AS Reseau,\n coalesce(Batterie, first_value(d_Batterie) OVER (PARTITION BY g_Batterie ORDER BY t)) AS Batterie,\n coalesce(Maison, first_value(d_Maison) OVER (PARTITION BY g_Maison ORDER BY t)) AS Maison,\n coalesce(Voiture, first_value(d_Voiture) OVER (PARTITION BY g_Voiture ORDER BY t)) AS Voiture\n FROM paliers\n)\nSELECT t AS time,\n Reseau AS \"Reseau\",\n Batterie AS \"Batterie\",\n Maison AS \"Maison\",\n Voiture AS \"Voiture\"\nFROM report ORDER BY t"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 16,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "watt",
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"custom": {
|
|
"lineWidth": 2,
|
|
"fillOpacity": 8,
|
|
"showPoints": "never",
|
|
"spanNulls": true,
|
|
"axisBorderShow": false,
|
|
"gradientMode": "opacity"
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Reseau"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "red"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Batterie"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "green"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Maison"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "text"
|
|
}
|
|
},
|
|
{
|
|
"id": "custom.fillOpacity",
|
|
"value": 0
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Voiture"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "blue"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"displayMode": "list",
|
|
"placement": "bottom",
|
|
"showLegend": true,
|
|
"calcs": []
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "timeseries",
|
|
"title": "Ce qu'il reste a couvrir",
|
|
"description": "\"Manque de stockage\" non nul = meme pleine, la batterie actuelle ne passe pas. C'est le signal de dimensionnement pour l'extension prevue cet hiver, pas une erreur.",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "time_series",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "SELECT ts AS time,\n energie_a_couvrir_kwh AS \"A couvrir d'ici le croisement\",\n reseau_energie_kwh AS \"Dont reseau necessaire\",\n manque_stockage_kwh AS \"Manque de stockage\"\nFROM bilan\nWHERE $__timeFilter(ts)\nORDER BY 1"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 12,
|
|
"y": 16,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "kwatth",
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"custom": {
|
|
"lineWidth": 2,
|
|
"fillOpacity": 12,
|
|
"showPoints": "never",
|
|
"spanNulls": true,
|
|
"gradientMode": "opacity"
|
|
}
|
|
},
|
|
"overrides": []
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"displayMode": "list",
|
|
"placement": "bottom",
|
|
"showLegend": true,
|
|
"calcs": []
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "table",
|
|
"title": "Journal des evenements",
|
|
"description": "Une courbe sans ses evenements ne s'interprete pas. Ces lignes apparaissent aussi en marqueurs verticaux sur tous les graphiques.",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "table",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "SELECT ts AS \"Quand\", genre AS \"Genre\", source AS \"Par\",\n resume AS \"Ce qui s'est passe\"\nFROM evenement\nWHERE $__timeFilter(ts)\nORDER BY ts DESC"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 24,
|
|
"w": 24,
|
|
"h": 8
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"custom": {
|
|
"align": "left",
|
|
"cellOptions": {
|
|
"type": "auto"
|
|
},
|
|
"filterable": true
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Quand"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 190
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Genre"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 140
|
|
},
|
|
{
|
|
"id": "custom.cellOptions",
|
|
"value": {
|
|
"type": "color-text"
|
|
}
|
|
},
|
|
{
|
|
"id": "mappings",
|
|
"value": [
|
|
{
|
|
"type": "value",
|
|
"options": {
|
|
"deploiement": {
|
|
"color": "blue",
|
|
"index": 0
|
|
},
|
|
"incident": {
|
|
"color": "red",
|
|
"index": 1
|
|
},
|
|
"intervention": {
|
|
"color": "orange",
|
|
"index": 2
|
|
},
|
|
"systeme": {
|
|
"color": "purple",
|
|
"index": 3
|
|
},
|
|
"reseau": {
|
|
"color": "yellow",
|
|
"index": 4
|
|
},
|
|
"vehicule": {
|
|
"color": "green",
|
|
"index": 5
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Par"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "custom.width",
|
|
"value": 130
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"showHeader": true,
|
|
"cellHeight": "sm",
|
|
"footer": {
|
|
"show": false
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "xychart",
|
|
"title": "Soiree contre nuit : le nuage des nuits",
|
|
"description": "Un point = une nuit. En abscisse ce que la maison a consomme de 18:00 a 21:30 (la cuisine), en ordonnee de 21:30 a 09:00, voiture exclue. La droite orange est la regression sur toutes les nuits ; le gros point rouge est CE SOIR, place sur la droite : une prevision, pas une mesure. 1 point de SOC = 0,30 kWh sur le parc actuel.",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 32,
|
|
"w": 14,
|
|
"h": 11
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "table",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "WITH pts AS (\n SELECT cle, ts, valeur,\n least(coalesce(lead(ts) OVER (PARTITION BY cle ORDER BY ts), now()), ts + interval '1 hour') AS fin\n FROM mesure\n WHERE cle IN ('sensor.victron_consumption_power_l1', 'sensor.victron_evcs_ac_power',\n 'sensor.victron_grid_power_l1', 'sensor.victron_pv_power_system')\n AND ts > now() - interval '40 days'\n),\njours AS (\n SELECT d::date AS j,\n (d::date + time '18:00') AT TIME ZONE 'Europe/Paris' AS s0,\n (d::date + time '21:30') AT TIME ZONE 'Europe/Paris' AS n0,\n (d::date + 1 + time '01:24') AT TIME ZONE 'Europe/Paris' AS hc,\n (d::date + 1 + time '09:00') AT TIME ZONE 'Europe/Paris' AS n1\n FROM generate_series(current_date - 35, current_date, interval '1 day') d\n),\ne AS (\n SELECT j.j,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n0) - greatest(p.ts, j.s0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.s0 AND p.ts < j.n0) AS c_soir,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n0) - greatest(p.ts, j.s0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.s0 AND p.ts < j.n0) AS v_soir,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.hc) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.n0 AND p.ts < j.hc) AS c_hc,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.hc) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.n0 AND p.ts < j.hc) AS v_hc,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.n0 AND p.ts < j.n1) AS c_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.n0 AND p.ts < j.n1) AS v_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_grid_power_l1' AND p.fin > j.n0 AND p.ts < j.n1) AS r_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_pv_power_system' AND p.fin > j.n0 AND p.ts < j.n1) AS pv_nuit\n FROM jours j JOIN pts p ON p.fin > j.s0 AND p.ts < j.n1\n GROUP BY j.j\n),\nnuits AS (\n SELECT j.j, j.n0, j.n1,\n round(((coalesce(c_soir,0) - coalesce(v_soir,0)) / 3.6e6)::numeric, 2) AS soiree_kwh,\n round(((coalesce(c_hc,0) - coalesce(v_hc,0)) / 3.6e6)::numeric, 2) AS maison_hc_kwh,\n round(((coalesce(c_nuit,0) - coalesce(v_nuit,0)) / 3.6e6)::numeric, 2) AS maison_nuit_kwh,\n round((coalesce(v_nuit,0) / 3.6e6)::numeric, 2) AS voiture_kwh,\n round((coalesce(r_nuit,0) / 3.6e6)::numeric, 2) AS reseau_kwh,\n round((coalesce(pv_nuit,0) / 3.6e6)::numeric, 2) AS pv_avant_9h_kwh,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.n0 AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_2130,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.hc AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_0124,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.n1 AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_9h\n FROM jours j JOIN e ON e.j = j.j\n WHERE j.n1 <= now() AND j.j >= date '2026-09-04'\n)\nSELECT soiree_kwh AS \"Soiree\", maison_nuit_kwh AS \"Nuit sans voiture\" FROM nuits WHERE voiture_kwh < 0.5 ORDER BY 1"
|
|
},
|
|
{
|
|
"refId": "B",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "table",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "WITH pts AS (\n SELECT cle, ts, valeur,\n least(coalesce(lead(ts) OVER (PARTITION BY cle ORDER BY ts), now()), ts + interval '1 hour') AS fin\n FROM mesure\n WHERE cle IN ('sensor.victron_consumption_power_l1', 'sensor.victron_evcs_ac_power',\n 'sensor.victron_grid_power_l1', 'sensor.victron_pv_power_system')\n AND ts > now() - interval '40 days'\n),\njours AS (\n SELECT d::date AS j,\n (d::date + time '18:00') AT TIME ZONE 'Europe/Paris' AS s0,\n (d::date + time '21:30') AT TIME ZONE 'Europe/Paris' AS n0,\n (d::date + 1 + time '01:24') AT TIME ZONE 'Europe/Paris' AS hc,\n (d::date + 1 + time '09:00') AT TIME ZONE 'Europe/Paris' AS n1\n FROM generate_series(current_date - 35, current_date, interval '1 day') d\n),\ne AS (\n SELECT j.j,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n0) - greatest(p.ts, j.s0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.s0 AND p.ts < j.n0) AS c_soir,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n0) - greatest(p.ts, j.s0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.s0 AND p.ts < j.n0) AS v_soir,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.hc) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.n0 AND p.ts < j.hc) AS c_hc,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.hc) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.n0 AND p.ts < j.hc) AS v_hc,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.n0 AND p.ts < j.n1) AS c_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.n0 AND p.ts < j.n1) AS v_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_grid_power_l1' AND p.fin > j.n0 AND p.ts < j.n1) AS r_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_pv_power_system' AND p.fin > j.n0 AND p.ts < j.n1) AS pv_nuit\n FROM jours j JOIN pts p ON p.fin > j.s0 AND p.ts < j.n1\n GROUP BY j.j\n),\nnuits AS (\n SELECT j.j, j.n0, j.n1,\n round(((coalesce(c_soir,0) - coalesce(v_soir,0)) / 3.6e6)::numeric, 2) AS soiree_kwh,\n round(((coalesce(c_hc,0) - coalesce(v_hc,0)) / 3.6e6)::numeric, 2) AS maison_hc_kwh,\n round(((coalesce(c_nuit,0) - coalesce(v_nuit,0)) / 3.6e6)::numeric, 2) AS maison_nuit_kwh,\n round((coalesce(v_nuit,0) / 3.6e6)::numeric, 2) AS voiture_kwh,\n round((coalesce(r_nuit,0) / 3.6e6)::numeric, 2) AS reseau_kwh,\n round((coalesce(pv_nuit,0) / 3.6e6)::numeric, 2) AS pv_avant_9h_kwh,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.n0 AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_2130,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.hc AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_0124,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.n1 AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_9h\n FROM jours j JOIN e ON e.j = j.j\n WHERE j.n1 <= now() AND j.j >= date '2026-09-04'\n)\nSELECT soiree_kwh AS \"Soiree\", maison_nuit_kwh AS \"Nuit avec voiture\" FROM nuits WHERE voiture_kwh >= 0.5 ORDER BY 1"
|
|
},
|
|
{
|
|
"refId": "C",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "table",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "WITH pts AS (\n SELECT cle, ts, valeur,\n least(coalesce(lead(ts) OVER (PARTITION BY cle ORDER BY ts), now()), ts + interval '1 hour') AS fin\n FROM mesure\n WHERE cle IN ('sensor.victron_consumption_power_l1', 'sensor.victron_evcs_ac_power',\n 'sensor.victron_grid_power_l1', 'sensor.victron_pv_power_system')\n AND ts > now() - interval '40 days'\n),\njours AS (\n SELECT d::date AS j,\n (d::date + time '18:00') AT TIME ZONE 'Europe/Paris' AS s0,\n (d::date + time '21:30') AT TIME ZONE 'Europe/Paris' AS n0,\n (d::date + 1 + time '01:24') AT TIME ZONE 'Europe/Paris' AS hc,\n (d::date + 1 + time '09:00') AT TIME ZONE 'Europe/Paris' AS n1\n FROM generate_series(current_date - 35, current_date, interval '1 day') d\n),\ne AS (\n SELECT j.j,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n0) - greatest(p.ts, j.s0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.s0 AND p.ts < j.n0) AS c_soir,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n0) - greatest(p.ts, j.s0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.s0 AND p.ts < j.n0) AS v_soir,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.hc) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.n0 AND p.ts < j.hc) AS c_hc,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.hc) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.n0 AND p.ts < j.hc) AS v_hc,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.n0 AND p.ts < j.n1) AS c_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.n0 AND p.ts < j.n1) AS v_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_grid_power_l1' AND p.fin > j.n0 AND p.ts < j.n1) AS r_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_pv_power_system' AND p.fin > j.n0 AND p.ts < j.n1) AS pv_nuit\n FROM jours j JOIN pts p ON p.fin > j.s0 AND p.ts < j.n1\n GROUP BY j.j\n),\nnuits AS (\n SELECT j.j, j.n0, j.n1,\n round(((coalesce(c_soir,0) - coalesce(v_soir,0)) / 3.6e6)::numeric, 2) AS soiree_kwh,\n round(((coalesce(c_hc,0) - coalesce(v_hc,0)) / 3.6e6)::numeric, 2) AS maison_hc_kwh,\n round(((coalesce(c_nuit,0) - coalesce(v_nuit,0)) / 3.6e6)::numeric, 2) AS maison_nuit_kwh,\n round((coalesce(v_nuit,0) / 3.6e6)::numeric, 2) AS voiture_kwh,\n round((coalesce(r_nuit,0) / 3.6e6)::numeric, 2) AS reseau_kwh,\n round((coalesce(pv_nuit,0) / 3.6e6)::numeric, 2) AS pv_avant_9h_kwh,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.n0 AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_2130,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.hc AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_0124,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.n1 AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_9h\n FROM jours j JOIN e ON e.j = j.j\n WHERE j.n1 <= now() AND j.j >= date '2026-09-04'\n)\n\nSELECT v.x AS \"Soiree\", round((r.a + r.b * v.x)::numeric, 2) AS \"Regression\"\n FROM (SELECT regr_intercept(maison_nuit_kwh, soiree_kwh) AS a, regr_slope(maison_nuit_kwh, soiree_kwh) AS b,\n min(soiree_kwh) AS lo, max(soiree_kwh) AS hi FROM nuits) r,\n LATERAL (VALUES (r.lo), (r.hi)) v(x)\n ORDER BY 1"
|
|
},
|
|
{
|
|
"refId": "D",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "table",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "WITH pts AS (\n SELECT cle, ts, valeur,\n least(coalesce(lead(ts) OVER (PARTITION BY cle ORDER BY ts), now()), ts + interval '1 hour') AS fin\n FROM mesure\n WHERE cle IN ('sensor.victron_consumption_power_l1', 'sensor.victron_evcs_ac_power',\n 'sensor.victron_grid_power_l1', 'sensor.victron_pv_power_system')\n AND ts > now() - interval '40 days'\n),\njours AS (\n SELECT d::date AS j,\n (d::date + time '18:00') AT TIME ZONE 'Europe/Paris' AS s0,\n (d::date + time '21:30') AT TIME ZONE 'Europe/Paris' AS n0,\n (d::date + 1 + time '01:24') AT TIME ZONE 'Europe/Paris' AS hc,\n (d::date + 1 + time '09:00') AT TIME ZONE 'Europe/Paris' AS n1\n FROM generate_series(current_date - 35, current_date, interval '1 day') d\n),\ne AS (\n SELECT j.j,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n0) - greatest(p.ts, j.s0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.s0 AND p.ts < j.n0) AS c_soir,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n0) - greatest(p.ts, j.s0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.s0 AND p.ts < j.n0) AS v_soir,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.hc) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.n0 AND p.ts < j.hc) AS c_hc,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.hc) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.n0 AND p.ts < j.hc) AS v_hc,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.n0 AND p.ts < j.n1) AS c_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.n0 AND p.ts < j.n1) AS v_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_grid_power_l1' AND p.fin > j.n0 AND p.ts < j.n1) AS r_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_pv_power_system' AND p.fin > j.n0 AND p.ts < j.n1) AS pv_nuit\n FROM jours j JOIN pts p ON p.fin > j.s0 AND p.ts < j.n1\n GROUP BY j.j\n),\nnuits AS (\n SELECT j.j, j.n0, j.n1,\n round(((coalesce(c_soir,0) - coalesce(v_soir,0)) / 3.6e6)::numeric, 2) AS soiree_kwh,\n round(((coalesce(c_hc,0) - coalesce(v_hc,0)) / 3.6e6)::numeric, 2) AS maison_hc_kwh,\n round(((coalesce(c_nuit,0) - coalesce(v_nuit,0)) / 3.6e6)::numeric, 2) AS maison_nuit_kwh,\n round((coalesce(v_nuit,0) / 3.6e6)::numeric, 2) AS voiture_kwh,\n round((coalesce(r_nuit,0) / 3.6e6)::numeric, 2) AS reseau_kwh,\n round((coalesce(pv_nuit,0) / 3.6e6)::numeric, 2) AS pv_avant_9h_kwh,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.n0 AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_2130,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.hc AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_0124,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.n1 AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_9h\n FROM jours j JOIN e ON e.j = j.j\n WHERE j.n1 <= now() AND j.j >= date '2026-09-04'\n),\nf AS (\n SELECT ((CASE WHEN (now() AT TIME ZONE 'Europe/Paris')::time >= time '18:00'\n THEN (now() AT TIME ZONE 'Europe/Paris')::date\n ELSE (now() AT TIME ZONE 'Europe/Paris')::date - 1 END) + time '18:00')\n AT TIME ZONE 'Europe/Paris' AS s0\n),\nsoir AS (\n SELECT sum(p.valeur * extract(epoch FROM least(p.fin, f.s0 + interval '3 hours 30 minutes', now()) - greatest(p.ts, f.s0))\n * CASE WHEN p.cle = 'sensor.victron_evcs_ac_power' THEN -1\n WHEN p.cle = 'sensor.victron_consumption_power_l1' THEN 1 ELSE 0 END) / 3.6e6 AS kwh\n FROM pts p, f\n WHERE p.fin > f.s0 AND p.ts < least(f.s0 + interval '3 hours 30 minutes', now())\n)\nSELECT round(s.kwh::numeric, 2) AS \"Soiree\",\n round((regr_intercept(maison_nuit_kwh, soiree_kwh) + regr_slope(maison_nuit_kwh, soiree_kwh) * s.kwh)::numeric, 2) AS \"Ce soir (prevu)\"\n FROM nuits, soir s GROUP BY s.kwh"
|
|
}
|
|
],
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "kwatth",
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"custom": {
|
|
"show": "points",
|
|
"pointSize": {
|
|
"fixed": 9
|
|
},
|
|
"pointShape": "circle",
|
|
"lineWidth": 2,
|
|
"fillOpacity": 60
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Nuit sans voiture"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "green"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Nuit avec voiture"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "blue"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Regression"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "orange"
|
|
}
|
|
},
|
|
{
|
|
"id": "custom.show",
|
|
"value": "lines"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Ce soir (prevu)"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "red"
|
|
}
|
|
},
|
|
{
|
|
"id": "custom.pointSize",
|
|
"value": {
|
|
"fixed": 18
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"mapping": "manual",
|
|
"series": [
|
|
{
|
|
"frame": {
|
|
"matcher": {
|
|
"id": "byIndex",
|
|
"options": 0
|
|
}
|
|
},
|
|
"x": {
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Soiree"
|
|
}
|
|
},
|
|
"y": {
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Nuit sans voiture"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"frame": {
|
|
"matcher": {
|
|
"id": "byIndex",
|
|
"options": 1
|
|
}
|
|
},
|
|
"x": {
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Soiree"
|
|
}
|
|
},
|
|
"y": {
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Nuit avec voiture"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"frame": {
|
|
"matcher": {
|
|
"id": "byIndex",
|
|
"options": 2
|
|
}
|
|
},
|
|
"x": {
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Soiree"
|
|
}
|
|
},
|
|
"y": {
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Regression"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"frame": {
|
|
"matcher": {
|
|
"id": "byIndex",
|
|
"options": 3
|
|
}
|
|
},
|
|
"x": {
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Soiree"
|
|
}
|
|
},
|
|
"y": {
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Ce soir (prevu)"
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"legend": {
|
|
"showLegend": true,
|
|
"displayMode": "list",
|
|
"placement": "bottom"
|
|
},
|
|
"tooltip": {
|
|
"mode": "single",
|
|
"sort": "none"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "table",
|
|
"title": "Les nuits, une ligne par nuit",
|
|
"description": "kWh ; « Maison » = voiture exclue. La nuit en cours apparait le lendemain a 09:00, une fois close. C'est la matiere du nuage de gauche.",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "table",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "WITH pts AS (\n SELECT cle, ts, valeur,\n least(coalesce(lead(ts) OVER (PARTITION BY cle ORDER BY ts), now()), ts + interval '1 hour') AS fin\n FROM mesure\n WHERE cle IN ('sensor.victron_consumption_power_l1', 'sensor.victron_evcs_ac_power',\n 'sensor.victron_grid_power_l1', 'sensor.victron_pv_power_system')\n AND ts > now() - interval '40 days'\n),\njours AS (\n SELECT d::date AS j,\n (d::date + time '18:00') AT TIME ZONE 'Europe/Paris' AS s0,\n (d::date + time '21:30') AT TIME ZONE 'Europe/Paris' AS n0,\n (d::date + 1 + time '01:24') AT TIME ZONE 'Europe/Paris' AS hc,\n (d::date + 1 + time '09:00') AT TIME ZONE 'Europe/Paris' AS n1\n FROM generate_series(current_date - 35, current_date, interval '1 day') d\n),\ne AS (\n SELECT j.j,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n0) - greatest(p.ts, j.s0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.s0 AND p.ts < j.n0) AS c_soir,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n0) - greatest(p.ts, j.s0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.s0 AND p.ts < j.n0) AS v_soir,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.hc) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.n0 AND p.ts < j.hc) AS c_hc,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.hc) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.n0 AND p.ts < j.hc) AS v_hc,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_consumption_power_l1' AND p.fin > j.n0 AND p.ts < j.n1) AS c_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_evcs_ac_power' AND p.fin > j.n0 AND p.ts < j.n1) AS v_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_grid_power_l1' AND p.fin > j.n0 AND p.ts < j.n1) AS r_nuit,\n sum(p.valeur * extract(epoch FROM least(p.fin, j.n1) - greatest(p.ts, j.n0))) FILTER (WHERE p.cle = 'sensor.victron_pv_power_system' AND p.fin > j.n0 AND p.ts < j.n1) AS pv_nuit\n FROM jours j JOIN pts p ON p.fin > j.s0 AND p.ts < j.n1\n GROUP BY j.j\n),\nnuits AS (\n SELECT j.j, j.n0, j.n1,\n round(((coalesce(c_soir,0) - coalesce(v_soir,0)) / 3.6e6)::numeric, 2) AS soiree_kwh,\n round(((coalesce(c_hc,0) - coalesce(v_hc,0)) / 3.6e6)::numeric, 2) AS maison_hc_kwh,\n round(((coalesce(c_nuit,0) - coalesce(v_nuit,0)) / 3.6e6)::numeric, 2) AS maison_nuit_kwh,\n round((coalesce(v_nuit,0) / 3.6e6)::numeric, 2) AS voiture_kwh,\n round((coalesce(r_nuit,0) / 3.6e6)::numeric, 2) AS reseau_kwh,\n round((coalesce(pv_nuit,0) / 3.6e6)::numeric, 2) AS pv_avant_9h_kwh,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.n0 AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_2130,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.hc AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_0124,\n (SELECT valeur FROM mesure WHERE cle = 'sensor.victron_battery_soc' AND ts <= j.n1 AND valeur > 0 ORDER BY ts DESC LIMIT 1) AS soc_9h\n FROM jours j JOIN e ON e.j = j.j\n WHERE j.n1 <= now() AND j.j >= date '2026-09-04'\n)\nSELECT to_char(j, 'DD/MM') AS \"Nuit du\", soc_2130 AS \"SOC 21:30\", soc_0124 AS \"SOC 01:24\", soc_9h AS \"SOC 09:00\", soiree_kwh AS \"Soiree 18-21:30\", maison_hc_kwh AS \"Maison 21:30-01:24\", maison_nuit_kwh AS \"Maison 21:30-09:00\", voiture_kwh AS \"Voiture\", reseau_kwh AS \"Reseau\", pv_avant_9h_kwh AS \"PV avant 9h\" FROM nuits ORDER BY j DESC"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 14,
|
|
"y": 32,
|
|
"w": 10,
|
|
"h": 11
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"custom": {
|
|
"align": "left",
|
|
"cellOptions": {
|
|
"type": "auto"
|
|
},
|
|
"filterable": true
|
|
}
|
|
},
|
|
"overrides": []
|
|
},
|
|
"options": {
|
|
"showHeader": true,
|
|
"cellHeight": "sm",
|
|
"footer": {
|
|
"show": false
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "barchart",
|
|
"title": "Profil horaire de la maison : 20 nuits contre cette nuit",
|
|
"description": "kWh consommes par la maison (voiture exclue) heure par heure, de 18 h a 17 h. Mediane et valeur haute (8 nuits sur 10 en dessous) sur 20 jours, et la nuit en cours par-dessus — l'heure en cours est partielle. C'est ce profil moyen que le bilan utilise ; une soiree au-dessus de la mediane annonce une nuit au-dessus.",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "table",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "WITH pts AS (\n SELECT cle, ts, valeur,\n least(coalesce(lead(ts) OVER (PARTITION BY cle ORDER BY ts), now()), ts + interval '1 hour') AS fin\n FROM mesure\n WHERE cle IN ('sensor.victron_consumption_power_l1', 'sensor.victron_evcs_ac_power')\n AND ts > now() - interval '22 days'\n),\nheures AS (\n SELECT h AS h0, h + interval '1 hour' AS h1\n FROM generate_series(date_trunc('hour', now() - interval '20 days'), date_trunc('hour', now()), interval '1 hour') h\n),\ne AS (\n SELECT h.h0, least(h.h1, now()) AS h1,\n sum(p.valeur * extract(epoch FROM least(p.fin, h.h1) - greatest(p.ts, h.h0))\n * CASE WHEN p.cle = 'sensor.victron_evcs_ac_power' THEN -1 ELSE 1 END) / 3.6e6 AS kwh\n FROM heures h JOIN pts p ON p.fin > h.h0 AND p.ts < h.h1\n GROUP BY 1, 2\n),\ncadre AS (\n SELECT *, extract(hour FROM h0 AT TIME ZONE 'Europe/Paris')::int AS heure,\n ((extract(hour FROM h0 AT TIME ZONE 'Europe/Paris')::int + 6) % 24) AS rang\n FROM e\n)\nSELECT lpad(heure::text, 2, '0') || ' h' AS \"Heure\",\n round(percentile_cont(0.5) WITHIN GROUP (ORDER BY kwh) FILTER (WHERE h1 - h0 = interval '1 hour' AND h0 < date_trunc('hour', now()) - interval '18 hours')::numeric, 2) AS \"Mediane 20 nuits\",\n round(percentile_cont(0.8) WITHIN GROUP (ORDER BY kwh) FILTER (WHERE h1 - h0 = interval '1 hour' AND h0 < date_trunc('hour', now()) - interval '18 hours')::numeric, 2) AS \"8 nuits sur 10 sous\",\n round((max(kwh) FILTER (WHERE h0 >= (CASE WHEN extract(hour FROM now() AT TIME ZONE 'Europe/Paris') >= 18\n THEN date_trunc('day', now() AT TIME ZONE 'Europe/Paris') + interval '18 hours'\n ELSE date_trunc('day', now() AT TIME ZONE 'Europe/Paris') - interval '6 hours' END) AT TIME ZONE 'Europe/Paris'))::numeric, 2) AS \"Cette nuit\"\n FROM cadre\n GROUP BY heure, rang\n ORDER BY rang\n"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 43,
|
|
"w": 24,
|
|
"h": 9
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "kwatth",
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"custom": {
|
|
"lineWidth": 1,
|
|
"fillOpacity": 80,
|
|
"gradientMode": "none",
|
|
"axisBorderShow": false
|
|
}
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Cette nuit"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "red"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Mediane 20 nuits"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "green"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "8 nuits sur 10 sous"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "orange"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"orientation": "auto",
|
|
"xTickLabelRotation": -45,
|
|
"showValue": "never",
|
|
"stacking": "none",
|
|
"groupWidth": 0.7,
|
|
"barWidth": 0.9,
|
|
"legend": {
|
|
"displayMode": "list",
|
|
"placement": "bottom",
|
|
"showLegend": true
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "none"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|