Il manquait le bilan qu'on cherche en premier : ce qui a ete produit, consomme, achete, et ou c'est alle. « La journee » (evcs-journee) le donne sur la fenetre now/d — le jour civil, pas les 24 dernieres heures, sinon deux journees se melangent et le total de production n'est plus comparable d'un jour a l'autre. En controlant ses chiffres, un defaut bien plus large est apparu : la voiture annoncait 6,9 kWh la ou le compteur cumulatif de la borne et la table des sessions donnent tous deux 3,6. Le report de la derniere valeur connue propageait la MOYENNE de la minute au lieu de sa DERNIERE valeur. Le 07/09 a 14:28 la borne passe de 1577 a 0 W dans la meme minute : cette minute vaut 788 W en moyenne, et le report la maintenait pendant les heures sans ecriture qui suivaient — 0,79 kWh fabriques sur la seule heure de 15 h, exactement 788 x 60 / 1000. Le defaut ne se voyait ni sur le solaire ni sur la maison, ecrits en continu. Il frappe les grandeurs intermittentes, au premier rang la borne qui passe l'essentiel de la journee a zero. Les colonnes « Voiture » de « Le systeme » et « Les vehicules » etaient donc fausses depuis leur creation, en surestimation. Corrige dans les trois constructeurs de requetes : la minute observee garde sa moyenne, juste pour l'energie consommee dans cette minute, mais le report propage la derniere valeur reellement lue. Aucun seuil, aucune peremption arbitraire. Apres correction la voiture tombe a 3,6 kWh, egal au centieme a la somme des sessions. verifier-dashboards annoncait 73/73 avec le chiffre faux : il prouve qu'une requete s'execute, pas qu'elle rend la bonne grandeur. Deuxieme fois en trois jours qu'une source independante est le seul controle qui attrape le defaut. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
520 lines
16 KiB
JSON
520 lines
16 KiB
JSON
{
|
|
"templating": {
|
|
"list": []
|
|
},
|
|
"uid": "evcs-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.",
|
|
"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": "Production, maison, et ce qui reste",
|
|
"description": "L'excedent (production moins maison hors voiture) est la grandeur qui decide d'un demarrage depuis le 03/09. Le 03/09 a 19:44, la production valait 758 W — au-dessus du seuil — pour un excedent de MOINS 444 W : la voiture a vide la batterie.",
|
|
"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_pv_power_system') AS Production,\n (array_agg(valeur ORDER BY ts DESC) FILTER (WHERE cle = 'sensor.victron_pv_power_system'))[1] AS d_Production,\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 Production, count(d_Production) OVER (ORDER BY t) AS g_Production,\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_Production,\n d_Maison,\n d_Voiture\n FROM par_minute\n),\nreport AS (\n SELECT t,\n coalesce(Production, first_value(d_Production) OVER (PARTITION BY g_Production ORDER BY t)) AS Production,\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 Production AS \"Production\",\n Maison AS \"Maison\",\n Voiture AS \"Voiture\",\n Production - Maison AS \"Excedent\"\nFROM report ORDER BY t"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 0,
|
|
"w": 24,
|
|
"h": 9
|
|
},
|
|
"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": "Production"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "yellow"
|
|
}
|
|
},
|
|
{
|
|
"id": "custom.fillOpacity",
|
|
"value": 22
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"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"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "Excedent"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "green"
|
|
}
|
|
},
|
|
{
|
|
"id": "custom.lineWidth",
|
|
"value": 3
|
|
},
|
|
{
|
|
"id": "custom.fillOpacity",
|
|
"value": 0
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"displayMode": "list",
|
|
"placement": "bottom",
|
|
"showLegend": true,
|
|
"calcs": []
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "state-timeline",
|
|
"title": "Production bridee ?",
|
|
"description": "Bridee = de la ressource solaire est REFUSEE faute de preneur. Charger la voiture pendant ces heures-la ne coute rien.",
|
|
"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 CASE WHEN pv_censure THEN coalesce(motif_censure, 'bridee')\n ELSE 'libre' END AS \"Production\"\nFROM bilan\nWHERE $__timeFilter(ts)\nORDER BY 1"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 9,
|
|
"w": 12,
|
|
"h": 6
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "continuous-GrYlRd"
|
|
},
|
|
"custom": {
|
|
"lineWidth": 0,
|
|
"fillOpacity": 80,
|
|
"insertNulls": false,
|
|
"spanNulls": true
|
|
},
|
|
"mappings": [
|
|
{
|
|
"type": "value",
|
|
"options": {
|
|
"libre": {
|
|
"color": "green",
|
|
"index": 0
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "regex",
|
|
"options": {
|
|
"pattern": ".*",
|
|
"result": {
|
|
"color": "orange",
|
|
"index": 1
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"overrides": []
|
|
},
|
|
"options": {
|
|
"showValue": "auto",
|
|
"mergeValues": true,
|
|
"alignValue": "left",
|
|
"rowHeight": 0.85,
|
|
"legend": {
|
|
"displayMode": "list",
|
|
"placement": "bottom",
|
|
"showLegend": false
|
|
},
|
|
"tooltip": {
|
|
"mode": "single"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "state-timeline",
|
|
"title": "Ce que les chargeurs declarent eux-memes",
|
|
"description": "mppt_active = ce chargeur donne tout ce qu'il peut. voltage_current_limited ou off = il se retient, faute de preneur. Le 03/09 ces capteurs ont bascule 24 minutes avant le drapeau du bilan — c'est le signal le plus direct dont on dispose.",
|
|
"datasource": {
|
|
"type": "influxdb",
|
|
"uid": "evcs-influx"
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "influxdb",
|
|
"uid": "evcs-influx"
|
|
},
|
|
"query": "from(bucket: \"evcs\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._field == \"state\")\n |> filter(fn: (r) => r._measurement =~ /operation_mode$/)\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> map(fn: (r) => ({ r with tracker:\n if r._measurement =~ /solar_1/ then \"Sud 1\"\n else if r._measurement =~ /solar_2/ then \"Sud 2\"\n else if r._measurement =~ /solar_3/ then \"Sud 3\"\n else if r._measurement =~ /solar_4/ then \"Ouest\"\n else if r._measurement =~ /mppt1/ then \"Sud-est\"\n else \"Ensemble\" }))\n |> keep(columns: [\"_time\", \"_value\", \"tracker\"])\n |> pivot(rowKey: [\"_time\"], columnKey: [\"tracker\"], valueColumn: \"_value\")"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 12,
|
|
"y": 9,
|
|
"w": 12,
|
|
"h": 6
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {
|
|
"mode": "continuous-GrYlRd"
|
|
},
|
|
"custom": {
|
|
"lineWidth": 0,
|
|
"fillOpacity": 80,
|
|
"insertNulls": false,
|
|
"spanNulls": true
|
|
},
|
|
"mappings": [
|
|
{
|
|
"type": "value",
|
|
"options": {
|
|
"mppt_active": {
|
|
"color": "green",
|
|
"index": 0
|
|
},
|
|
"voltage_current_limited": {
|
|
"color": "orange",
|
|
"index": 1
|
|
},
|
|
"off": {
|
|
"color": "dark-blue",
|
|
"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": "Batterie",
|
|
"description": "Le SOC n'est pas lineaire : 0,169 kWh par point au-dessus de 33 %, 0,097 en dessous (576 paliers mesures). Un point en bas d'echelle vaut la moitie d'un point en haut.",
|
|
"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 date_trunc('minute', ts) AS time, avg(valeur) AS \"SOC\"\nFROM mesure WHERE cle = 'sensor.victron_battery_soc'\n AND $__timeFilter(ts) GROUP BY 1 ORDER BY 1"
|
|
},
|
|
{
|
|
"refId": "B",
|
|
"datasource": {
|
|
"type": "grafana-postgresql-datasource",
|
|
"uid": "evcs-pg"
|
|
},
|
|
"format": "time_series",
|
|
"rawQuery": true,
|
|
"editorMode": "code",
|
|
"rawSql": "SELECT date_trunc('minute', ts) AS time, avg(valeur) AS \"Courant\"\nFROM mesure WHERE cle = 'sensor.victron_battery_current'\n AND $__timeFilter(ts) GROUP BY 1 ORDER BY 1"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 0,
|
|
"y": 15,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"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": "Courant"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "unit",
|
|
"value": "amp"
|
|
},
|
|
{
|
|
"id": "custom.axisPlacement",
|
|
"value": "right"
|
|
},
|
|
{
|
|
"id": "max",
|
|
"value": null
|
|
},
|
|
{
|
|
"id": "min",
|
|
"value": null
|
|
},
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "purple"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": {
|
|
"id": "byName",
|
|
"options": "SOC"
|
|
},
|
|
"properties": [
|
|
{
|
|
"id": "color",
|
|
"value": {
|
|
"mode": "fixed",
|
|
"fixedColor": "green"
|
|
}
|
|
},
|
|
{
|
|
"id": "custom.lineWidth",
|
|
"value": 3
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"displayMode": "list",
|
|
"placement": "bottom",
|
|
"showLegend": true,
|
|
"calcs": []
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "timeseries",
|
|
"title": "Le detail que PostgreSQL ne voit pas (~1 point/s)",
|
|
"description": "InfluxDB enregistre chaque changement d'etat, pas un echantillon par minute. C'est la resolution qu'il faut pour voir un transitoire de reprise du reseau (~150 s) ou une pointe de cuisson.",
|
|
"datasource": {
|
|
"type": "influxdb",
|
|
"uid": "evcs-influx"
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": "influxdb",
|
|
"uid": "evcs-influx"
|
|
},
|
|
"query": "from(bucket: \"evcs\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"W\" and r._field == \"value\")\n |> filter(fn: (r) => r.entity_id == \"victron_pv_power_system\"\n or r.entity_id == \"victron_consumption_power_l1\"\n or r.entity_id == \"victron_evcs_ac_power\"\n or r.entity_id == \"victron_grid_power_l1\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> keep(columns: [\"_time\", \"_value\", \"entity_id\"])\n |> pivot(rowKey: [\"_time\"], columnKey: [\"entity_id\"], valueColumn: \"_value\")"
|
|
}
|
|
],
|
|
"gridPos": {
|
|
"x": 12,
|
|
"y": 15,
|
|
"w": 12,
|
|
"h": 8
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"unit": "watt",
|
|
"color": {
|
|
"mode": "palette-classic"
|
|
},
|
|
"custom": {
|
|
"lineWidth": 1,
|
|
"fillOpacity": 5,
|
|
"showPoints": "never",
|
|
"spanNulls": true
|
|
}
|
|
},
|
|
"overrides": []
|
|
},
|
|
"options": {
|
|
"legend": {
|
|
"displayMode": "list",
|
|
"placement": "bottom",
|
|
"showLegend": true,
|
|
"calcs": []
|
|
},
|
|
"tooltip": {
|
|
"mode": "multi",
|
|
"sort": "desc"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|