- Historical Cost Comparison: the chained joins renamed _value columns to _value_j2/_value (not _value_gi/_value_sp as the map expected), so the solar ratio was always null->0 and the whole cost line was priced at full grid price (EUR 4.67K instead of ~3.4K). Streams now pre-rename columns to h/d/gi/ge/sp so the join is unambiguous. - Blended price now uses counter deltas since heat-pump install (Oct 2024) instead of device-lifetime counters that include 1.4 years of PV-only history from May 2023 (ratio 0.369 vs 0.322 -> EUR 0.236/kWh vs 0.248). Applied consistently to all cost/savings/ROI stats and the cost chart (chart subtracts install-date counter baselines). - Annual savings / payback: replace the calendar-YTD extrapolation (12 / (month + day/30) - which overcounts elapsed time by a month and is seasonally biased) with the actual trailing-365-day consumption spread. - Fix stale legend 'Last' values (10734/1230/EUR 9.47K): the counters' friendly_name tag changed 2026-03-04, splitting each series into two tables; group()+sort() merges them before aggregateWindow. - New oil_baseline dashboard variable (6650) replaces six hardcoded copies. - Running Cost: neutral color (was green/yellow/red on a forever-growing cumulative), retitled '(Since Install)'; added descriptions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
460 lines
53 KiB
JSON
460 lines
53 KiB
JSON
{
|
|
"annotations": {"list": []},
|
|
"description": "Heat Pump ROI Analysis - Viessmann Vitocal 250-A. All panels read from InfluxDB (bucket suedstr28), which is authoritative and live. After the 2026-07 ViCare->open3e/MQTT migration the heat-pump/PV entities were renamed; panels query the current entity_ids and, where an entity was renamed, UNION the pre-migration e3_* series with the post-migration series so history stays unbroken. The blended electricity price weights solar vs grid by the self-consumption ratio accumulated since the heat-pump install (Oct 2024); annual savings and payback use the actual trailing-12-month consumption.",
|
|
"editable": true,
|
|
"fiscalYearStartMonth": 0,
|
|
"graphTooltip": 1,
|
|
"id": null,
|
|
"links": [],
|
|
"panels": [
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "blue", "value": null}]}, "unit": "currencyEUR"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 4, "w": 4, "x": 0, "y": 0},
|
|
"id": 1,
|
|
"options": {"colorMode": "value", "graphMode": "none", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "import \"array\"\narray.from(rows: [{_time: now(), _value: float(v: \"${investment_cost}\")}])", "refId": "A"}],
|
|
"title": "Investment Cost",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "orange", "value": null}]}, "unit": "currencyEUR"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 4, "w": 4, "x": 4, "y": 0},
|
|
"id": 2,
|
|
"options": {"colorMode": "value", "graphMode": "none", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "import \"array\"\narray.from(rows: [{_time: now(), _value: float(v: \"${oil_baseline}\")}])", "refId": "A"}],
|
|
"title": "Oil Baseline (Annual)",
|
|
"description": "Based on 2022-2023 oil orders: ~5,000L at ~1.33 EUR/L average",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "green", "value": null}]}, "unit": "currencyEUR"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 4, "w": 4, "x": 8, "y": 0},
|
|
"id": 3,
|
|
"options": {"colorMode": "value", "graphMode": "none", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "import \"array\"\ngi = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_import_from_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_supplied_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nge = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_export_to_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_feed_in_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nsp = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_solar_energy_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_pv_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nselfc = sp[0] - ge[0]\ntotal = gi[0] + selfc\nblended = (selfc / total) * ${solar_price} + (1.0 - selfc / total) * ${grid_price}\narray.from(rows: [{_time: now(), _value: blended}])", "refId": "A"}],
|
|
"title": "Blended Price",
|
|
"description": "Weighted average: solar self-consumption @ EUR ${solar_price}, grid @ EUR ${grid_price}. Self-consumption ratio from Vitocharge PV/grid counter deltas since heat-pump install (Oct 2024), unioning pre-migration ViCare with post-migration open3e counters.",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "purple", "value": null}]}, "unit": "kwh"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 4, "w": 4, "x": 12, "y": 0},
|
|
"id": 4,
|
|
"options": {"colorMode": "value", "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: -30d) |> filter(fn: (r) => r._field == \"value\" and (r.entity_id == \"e3_vitocal_heating_energy_consumption_total\" or r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\")) |> group(columns: [\"entity_id\"]) |> max() |> group() |> sum()", "refId": "A"}],
|
|
"title": "Total Consumption",
|
|
"description": "Cumulative heat-pump electricity since install: sum of the heating + DHW utility_meter counters.",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "yellow", "value": null}]}, "unit": "currencyEUR"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 4, "w": 4, "x": 16, "y": 0},
|
|
"id": 5,
|
|
"options": {"colorMode": "value", "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "import \"array\"\ngi = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_import_from_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_supplied_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nge = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_export_to_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_feed_in_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nsp = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_solar_energy_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_pv_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nselfc = sp[0] - ge[0]\ntotal = gi[0] + selfc\nblended = (selfc / total) * ${solar_price} + (1.0 - selfc / total) * ${grid_price}\ncons = from(bucket: \"suedstr28\") |> range(start: -30d) |> filter(fn: (r) => r._field == \"value\" and (r.entity_id == \"e3_vitocal_heating_energy_consumption_total\" or r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\")) |> group(columns: [\"entity_id\"]) |> max() |> group() |> sum() |> findColumn(fn: (key) => true, column: \"_value\")\narray.from(rows: [{_time: now(), _value: cons[0] * blended}])", "refId": "A"}],
|
|
"title": "Running Cost (Since Install)",
|
|
"description": "Total consumption times blended price. Cumulative since Oct 2024, not an annual figure.",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "green", "value": null}]}, "unit": "currencyEUR"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 4, "w": 4, "x": 20, "y": 0},
|
|
"id": 6,
|
|
"options": {"colorMode": "value", "graphMode": "none", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "import \"array\"\ngi = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_import_from_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_supplied_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nge = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_export_to_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_feed_in_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nsp = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_solar_energy_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_pv_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nselfc = sp[0] - ge[0]\ntotal = gi[0] + selfc\nblended = (selfc / total) * ${solar_price} + (1.0 - selfc / total) * ${grid_price}\nyr = from(bucket: \"suedstr28\") |> range(start: -30d) |> filter(fn: (r) => r._field == \"value\" and (r.entity_id == \"vitocal_250_a_vitocal_heating_electric_energy_year\" or r.entity_id == \"vitocal_250_a_vitocal_dhw_electric_energy_year\")) |> group(columns: [\"entity_id\"]) |> last() |> group() |> sum() |> findColumn(fn: (key) => true, column: \"_value\")\narray.from(rows: [{_time: now(), _value: yr[0] * blended}])", "refId": "A"}],
|
|
"title": "Cost This Year",
|
|
"description": "Device year counters (heating + DHW electric energy) times blended price.",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "decimals": 1, "mappings": [], "max": 5, "min": 1, "thresholds": {"mode": "absolute", "steps": [{"color": "red", "value": null}, {"color": "yellow", "value": 2.5}, {"color": "green", "value": 3}]}},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 5, "w": 3, "x": 0, "y": 4},
|
|
"id": 7,
|
|
"options": {"minVizHeight": 75, "minVizWidth": 75, "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "showThresholdLabels": false, "showThresholdMarkers": true},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: -30d) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"vitocal_250_a_vitocal_scop_total\") |> last() |> keep(columns: [\"_value\"])", "refId": "A"}],
|
|
"title": "Overall SPF",
|
|
"type": "gauge"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "decimals": 1, "mappings": [], "max": 5, "min": 1, "thresholds": {"mode": "absolute", "steps": [{"color": "red", "value": null}, {"color": "yellow", "value": 2.5}, {"color": "green", "value": 3}]}},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 5, "w": 3, "x": 3, "y": 4},
|
|
"id": 8,
|
|
"options": {"minVizHeight": 75, "minVizWidth": 75, "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "showThresholdLabels": false, "showThresholdMarkers": true},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: -30d) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"vitocal_250_a_vitocal_scop_heating\") |> last() |> keep(columns: [\"_value\"])", "refId": "A"}],
|
|
"title": "Heating SPF",
|
|
"type": "gauge"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "decimals": 1, "mappings": [], "max": 5, "min": 1, "thresholds": {"mode": "absolute", "steps": [{"color": "red", "value": null}, {"color": "yellow", "value": 2.5}, {"color": "green", "value": 3}]}},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 5, "w": 3, "x": 6, "y": 4},
|
|
"id": 9,
|
|
"options": {"minVizHeight": 75, "minVizWidth": 75, "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "showThresholdLabels": false, "showThresholdMarkers": true},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: -30d) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"vitocal_250_a_vitocal_scop_dhw\") |> last() |> keep(columns: [\"_value\"])", "refId": "A"}],
|
|
"title": "DHW SPF",
|
|
"type": "gauge"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "green", "value": null}]}, "unit": "currencyEUR"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 5, "w": 4, "x": 9, "y": 4},
|
|
"id": 10,
|
|
"options": {"colorMode": "value", "graphMode": "none", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "import \"array\"\ngi = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_import_from_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_supplied_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nge = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_export_to_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_feed_in_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nsp = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_solar_energy_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_pv_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nselfc = sp[0] - ge[0]\ntotal = gi[0] + selfc\nblended = (selfc / total) * ${solar_price} + (1.0 - selfc / total) * ${grid_price}\nhp = from(bucket: \"suedstr28\") |> range(start: -365d) |> filter(fn: (r) => r._field == \"value\" and (r.entity_id == \"e3_vitocal_heating_energy_consumption_total\" or r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\")) |> group(columns: [\"entity_id\"]) |> spread() |> group() |> sum() |> findColumn(fn: (key) => true, column: \"_value\")\narray.from(rows: [{_time: now(), _value: float(v: \"${oil_baseline}\") - hp[0] * blended}])", "refId": "A"}],
|
|
"title": "Annual Savings (Trailing 12M)",
|
|
"description": "Oil baseline minus actual heat-pump electricity cost of the last 365 days (counter deltas x blended price). A true rolling year, immune to seasonal extrapolation bias.",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "decimals": 1, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "green", "value": null}, {"color": "yellow", "value": 15}, {"color": "red", "value": 20}]}, "unit": "short"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 5, "w": 4, "x": 13, "y": 4},
|
|
"id": 11,
|
|
"options": {"colorMode": "value", "graphMode": "none", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "import \"array\"\ngi = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_import_from_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_supplied_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nge = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_export_to_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_feed_in_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nsp = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_solar_energy_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_pv_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nselfc = sp[0] - ge[0]\ntotal = gi[0] + selfc\nblended = (selfc / total) * ${solar_price} + (1.0 - selfc / total) * ${grid_price}\nhp = from(bucket: \"suedstr28\") |> range(start: -365d) |> filter(fn: (r) => r._field == \"value\" and (r.entity_id == \"e3_vitocal_heating_energy_consumption_total\" or r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\")) |> group(columns: [\"entity_id\"]) |> spread() |> group() |> sum() |> findColumn(fn: (key) => true, column: \"_value\")\narray.from(rows: [{_time: now(), _value: float(v: \"${investment_cost}\") / (float(v: \"${oil_baseline}\") - hp[0] * blended)}])", "refId": "A"}],
|
|
"title": "Payback Period (Years)",
|
|
"description": "Investment / annual savings (trailing 12 months)",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "green", "value": null}]}, "unit": "currencyEUR"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 5, "w": 4, "x": 17, "y": 4},
|
|
"id": 12,
|
|
"options": {"colorMode": "value", "graphMode": "none", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "import \"array\"\ngi = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_import_from_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_supplied_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nge = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_export_to_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_feed_in_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nsp = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_solar_energy_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_pv_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nselfc = sp[0] - ge[0]\ntotal = gi[0] + selfc\nblended = (selfc / total) * ${solar_price} + (1.0 - selfc / total) * ${grid_price}\ncons = from(bucket: \"suedstr28\") |> range(start: -30d) |> filter(fn: (r) => r._field == \"value\" and (r.entity_id == \"e3_vitocal_heating_energy_consumption_total\" or r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\")) |> group(columns: [\"entity_id\"]) |> max() |> group() |> sum() |> findColumn(fn: (key) => true, column: \"_value\")\narray.from(rows: [{_time: now(), _value: float(v: \"${oil_baseline}\") * (float(v: uint(v: now()) - uint(v: 2024-10-01T00:00:00Z)) / 1000000000.0) / 31536000.0 - cons[0] * blended}])", "refId": "A"}],
|
|
"title": "Savings Since Install",
|
|
"description": "Oil baseline prorated since Oct 2024 minus actual costs",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "decimals": 1, "mappings": [], "max": 100, "min": 0, "thresholds": {"mode": "absolute", "steps": [{"color": "red", "value": null}, {"color": "yellow", "value": 25}, {"color": "green", "value": 50}]}, "unit": "percent"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 5, "w": 3, "x": 21, "y": 4},
|
|
"id": 40,
|
|
"options": {"minVizHeight": 75, "minVizWidth": 75, "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "showThresholdLabels": false, "showThresholdMarkers": true},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "import \"array\"\ngi = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_import_from_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_supplied_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nge = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_export_to_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_feed_in_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nsp = union(tables: [from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_solar_energy_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value})), from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_pv_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0}))]) |> group() |> spread() |> findColumn(fn: (key) => true, column: \"_value\")\nselfc = sp[0] - ge[0]\ntotal = gi[0] + selfc\nblended = (selfc / total) * ${solar_price} + (1.0 - selfc / total) * ${grid_price}\ncons = from(bucket: \"suedstr28\") |> range(start: -30d) |> filter(fn: (r) => r._field == \"value\" and (r.entity_id == \"e3_vitocal_heating_energy_consumption_total\" or r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\")) |> group(columns: [\"entity_id\"]) |> max() |> group() |> sum() |> findColumn(fn: (key) => true, column: \"_value\")\narray.from(rows: [{_time: now(), _value: (float(v: \"${oil_baseline}\") * (float(v: uint(v: now()) - uint(v: 2024-10-01T00:00:00Z)) / 1000000000.0) / 31536000.0 - cons[0] * blended) / float(v: \"${investment_cost}\") * 100.0}])", "refId": "A"}],
|
|
"title": "ROI Progress",
|
|
"description": "Percentage of investment recovered through savings",
|
|
"type": "gauge"
|
|
},
|
|
{
|
|
"collapsed": false,
|
|
"gridPos": {"h": 1, "w": 24, "x": 0, "y": 9},
|
|
"id": 30,
|
|
"panels": [],
|
|
"title": "Historical Data (InfluxDB - full history)",
|
|
"type": "row"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "palette-classic"},
|
|
"custom": {"axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 20, "gradientMode": "none", "hideFrom": {"legend": false, "tooltip": false, "viz": false}, "lineInterpolation": "smooth", "lineWidth": 2, "pointSize": 5, "scaleDistribution": {"type": "linear"}, "showPoints": "never", "spanNulls": true, "stacking": {"group": "A", "mode": "none"}, "thresholdsStyle": {"mode": "off"}},
|
|
"mappings": [],
|
|
"thresholds": {"mode": "absolute", "steps": [{"color": "green", "value": null}]},
|
|
"unit": "kwh"
|
|
},
|
|
"overrides": [
|
|
{"matcher": {"id": "byName", "options": "Heating Total"}, "properties": [{"id": "color", "value": {"fixedColor": "red", "mode": "fixed"}}]},
|
|
{"matcher": {"id": "byName", "options": "DHW Total"}, "properties": [{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}}]}
|
|
]
|
|
},
|
|
"gridPos": {"h": 10, "w": 12, "x": 0, "y": 10},
|
|
"id": 21,
|
|
"options": {"legend": {"calcs": ["min", "max", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "tooltip": {"mode": "multi", "sort": "desc"}},
|
|
"targets": [
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"query": "from(bucket: \"suedstr28\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"kWh\")\n |> filter(fn: (r) => r.entity_id == \"e3_vitocal_heating_energy_consumption_total\")\n |> filter(fn: (r) => r._field == \"value\")\n |> group()\n |> sort(columns: [\"_time\"])\n |> aggregateWindow(every: 1d, fn: last, createEmpty: false)\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"Heating Total\"})",
|
|
"refId": "A"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"query": "from(bucket: \"suedstr28\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"kWh\")\n |> filter(fn: (r) => r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\")\n |> filter(fn: (r) => r._field == \"value\")\n |> group()\n |> sort(columns: [\"_time\"])\n |> aggregateWindow(every: 1d, fn: last, createEmpty: false)\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"DHW Total\"})",
|
|
"refId": "B"
|
|
}
|
|
],
|
|
"title": "Historical Energy Consumption",
|
|
"type": "timeseries"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "palette-classic"},
|
|
"custom": {"axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 20, "gradientMode": "none", "hideFrom": {"legend": false, "tooltip": false, "viz": false}, "lineInterpolation": "smooth", "lineWidth": 2, "pointSize": 5, "scaleDistribution": {"type": "linear"}, "showPoints": "never", "spanNulls": true, "stacking": {"group": "A", "mode": "none"}, "thresholdsStyle": {"mode": "off"}},
|
|
"mappings": [],
|
|
"thresholds": {"mode": "absolute", "steps": [{"color": "green", "value": null}]},
|
|
"unit": "currencyEUR"
|
|
},
|
|
"overrides": [
|
|
{"matcher": {"id": "byName", "options": "Electricity Cost"}, "properties": [{"id": "color", "value": {"fixedColor": "green", "mode": "fixed"}}]},
|
|
{"matcher": {"id": "byName", "options": "Oil Baseline"}, "properties": [{"id": "color", "value": {"fixedColor": "orange", "mode": "fixed"}}]}
|
|
]
|
|
},
|
|
"gridPos": {"h": 10, "w": 12, "x": 12, "y": 10},
|
|
"id": 22,
|
|
"options": {"legend": {"calcs": ["min", "max", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "tooltip": {"mode": "multi", "sort": "desc"}},
|
|
"targets": [
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"query": "// Heat pump consumption (survivor utility_meters, continuous). group()+sort() merges the\n// friendly_name-era table split (tag changed 2026-03) so daily lasts stay time-ordered.\nheatpump_heating = from(bucket: \"suedstr28\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"kWh\" and r.entity_id == \"e3_vitocal_heating_energy_consumption_total\" and r._field == \"value\")\n |> group()\n |> sort(columns: [\"_time\"])\n |> aggregateWindow(every: 1d, fn: last, createEmpty: false)\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"h\"})\n\nheatpump_dhw = from(bucket: \"suedstr28\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"kWh\" and r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\" and r._field == \"value\")\n |> group()\n |> sort(columns: [\"_time\"])\n |> aggregateWindow(every: 1d, fn: last, createEmpty: false)\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"d\"})\n\n// Grid import: old ViCare (Wh) UNION new open3e (kWh) -> normalize to kWh\ngrid_import = union(tables: [\n from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_import_from_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})),\n from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_supplied_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))])\n |> group()\n |> sort(columns: [\"_time\"])\n |> aggregateWindow(every: 1d, fn: last, createEmpty: false)\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"gi\"})\n\n// Grid export: old ViCare (Wh) UNION new open3e (kWh) -> normalize to kWh\ngrid_export = union(tables: [\n from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_export_to_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})),\n from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_feed_in_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))])\n |> group()\n |> sort(columns: [\"_time\"])\n |> aggregateWindow(every: 1d, fn: last, createEmpty: false)\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"ge\"})\n\n// Solar production: old ViCare (kWh) UNION new open3e (Wh) -> normalize to kWh\nsolar_prod = union(tables: [\n from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_solar_energy_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value})),\n from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_pv_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0}))])\n |> group()\n |> sort(columns: [\"_time\"])\n |> aggregateWindow(every: 1d, fn: last, createEmpty: false)\n |> keep(columns: [\"_time\", \"_value\"])\n |> rename(columns: {_value: \"sp\"})\n\n// Counter values at heat-pump install (Oct 2024): subtracted so the self-consumption ratio\n// only counts flows since install, not the PV history from May 2023.\ngiB = union(tables: [\n from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_import_from_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})),\n from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_supplied_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))])\n |> group() |> min() |> findColumn(fn: (key) => true, column: \"_value\")\ngeB = union(tables: [\n from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_energy_export_to_grid\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0})),\n from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_grid_feed_in_energy\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))])\n |> group() |> min() |> findColumn(fn: (key) => true, column: \"_value\")\nspB = union(tables: [\n from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"e3_vitocharge_03_solar_energy_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value})),\n from(bucket: \"suedstr28\") |> range(start: 2024-10-01T00:00:00Z) |> filter(fn: (r) => r.entity_id == \"vitocharge_vx3_vx3_pv_production_total\" and r._field == \"value\") |> map(fn: (r) => ({_time: r._time, _value: r._value / 1000.0}))])\n |> group() |> min() |> findColumn(fn: (key) => true, column: \"_value\")\n\n// Chain joins (Flux only supports 2-way joins). Columns are pre-renamed to h/d/gi/ge/sp because\n// join() suffixes colliding _value columns unpredictably across chained joins.\njoin1 = join(tables: {h: heatpump_heating, d: heatpump_dhw}, on: [\"_time\"])\njoin2 = join(tables: {j1: join1, gi: grid_import}, on: [\"_time\"])\njoin3 = join(tables: {j2: join2, ge: grid_export}, on: [\"_time\"])\njoin(tables: {j3: join3, sp: solar_prod}, on: [\"_time\"])\n |> map(fn: (r) => {\n heatpump = r.h + r.d\n self_consumption = (r.sp - spB[0]) - (r.ge - geB[0])\n total_consumption = (r.gi - giB[0]) + self_consumption\n solar_ratio = if total_consumption > 0.0 then self_consumption / total_consumption else 0.0\n return {_time: r._time, _value: heatpump * ((1.0 - solar_ratio) * ${grid_price} + solar_ratio * ${solar_price})}\n })\n |> rename(columns: {_value: \"Electricity Cost\"})",
|
|
"refId": "A"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"query": "from(bucket: \"suedstr28\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"kWh\")\n |> filter(fn: (r) => r.entity_id == \"e3_vitocal_heating_energy_consumption_total\")\n |> filter(fn: (r) => r._field == \"value\")\n |> group()\n |> sort(columns: [\"_time\"])\n |> aggregateWindow(every: 1d, fn: last, createEmpty: false)\n |> keep(columns: [\"_time\", \"_value\"])\n |> map(fn: (r) => ({_time: r._time, _value: float(v: \"${oil_baseline}\") * float(v: uint(v: r._time) - uint(v: 2024-10-01T00:00:00Z)) / 31536000000000000.0}))\n |> rename(columns: {_value: \"Oil Baseline\"})",
|
|
"refId": "B"
|
|
}
|
|
],
|
|
"title": "Historical Cost Comparison",
|
|
"description": "Actual electricity cost vs what oil would have cost. Solar/grid series union pre-migration ViCare (e3_*) with post-migration open3e (vitocharge_vx3_*), unit-normalized to kWh.",
|
|
"type": "timeseries"
|
|
},
|
|
{
|
|
"collapsed": false,
|
|
"gridPos": {"h": 1, "w": 24, "x": 0, "y": 20},
|
|
"id": 31,
|
|
"panels": [],
|
|
"title": "Recent Data (InfluxDB)",
|
|
"type": "row"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "palette-classic"},
|
|
"custom": {"axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 20, "gradientMode": "none", "hideFrom": {"legend": false, "tooltip": false, "viz": false}, "lineInterpolation": "smooth", "lineWidth": 2, "pointSize": 5, "scaleDistribution": {"type": "linear"}, "showPoints": "never", "spanNulls": false, "stacking": {"group": "A", "mode": "none"}, "thresholdsStyle": {"mode": "off"}},
|
|
"mappings": [],
|
|
"thresholds": {"mode": "absolute", "steps": [{"color": "green", "value": null}]},
|
|
"unit": "kwh"
|
|
},
|
|
"overrides": [
|
|
{"matcher": {"id": "byName", "options": "Heating Total"}, "properties": [{"id": "color", "value": {"fixedColor": "red", "mode": "fixed"}}]},
|
|
{"matcher": {"id": "byName", "options": "DHW Total"}, "properties": [{"id": "color", "value": {"fixedColor": "blue", "mode": "fixed"}}]}
|
|
]
|
|
},
|
|
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 21},
|
|
"id": 13,
|
|
"options": {"legend": {"calcs": ["mean", "max", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true}, "tooltip": {"mode": "multi", "sort": "desc"}},
|
|
"targets": [
|
|
{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"e3_vitocal_heating_energy_consumption_total\") |> aggregateWindow(every: 1h, fn: last, createEmpty: false) |> keep(columns: [\"_time\", \"_value\"]) |> rename(columns: {_value: \"Heating Total\"})", "refId": "A"},
|
|
{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\") |> aggregateWindow(every: 1h, fn: last, createEmpty: false) |> keep(columns: [\"_time\", \"_value\"]) |> rename(columns: {_value: \"DHW Total\"})", "refId": "B"}
|
|
],
|
|
"timeFrom": "7d",
|
|
"title": "Cumulative Energy Consumption (Recent)",
|
|
"type": "timeseries"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "palette-classic"},
|
|
"custom": {"axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "bars", "fillOpacity": 60, "gradientMode": "none", "hideFrom": {"legend": false, "tooltip": false, "viz": false}, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": {"type": "linear"}, "showPoints": "never", "spanNulls": false, "stacking": {"group": "A", "mode": "none"}, "thresholdsStyle": {"mode": "off"}},
|
|
"mappings": [],
|
|
"thresholds": {"mode": "absolute", "steps": [{"color": "green", "value": null}]},
|
|
"unit": "kwh"
|
|
},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 21},
|
|
"id": 15,
|
|
"options": {"legend": {"calcs": ["mean", "sum"], "displayMode": "table", "placement": "right", "showLegend": true}, "tooltip": {"mode": "multi", "sort": "desc"}},
|
|
"targets": [
|
|
{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"e3_vitocal_heating_energy_consumption_total\") |> aggregateWindow(every: 1d, fn: last, createEmpty: false) |> difference(nonNegative: true) |> keep(columns: [\"_time\", \"_value\"]) |> rename(columns: {_value: \"Heating (daily)\"})", "refId": "A"},
|
|
{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\") |> aggregateWindow(every: 1d, fn: last, createEmpty: false) |> difference(nonNegative: true) |> keep(columns: [\"_time\", \"_value\"]) |> rename(columns: {_value: \"DHW (daily)\"})", "refId": "B"}
|
|
],
|
|
"timeFrom": "14d",
|
|
"title": "Daily Consumption",
|
|
"description": "Daily kWh consumed (delta of cumulative counters). Replaces the retired *_last_seven_days sensors.",
|
|
"type": "timeseries"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "palette-classic"},
|
|
"custom": {"axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": {"legend": false, "tooltip": false, "viz": false}, "lineInterpolation": "smooth", "lineWidth": 2, "pointSize": 5, "scaleDistribution": {"type": "linear"}, "showPoints": "never", "spanNulls": true, "stacking": {"group": "A", "mode": "none"}, "thresholdsStyle": {"mode": "off"}},
|
|
"mappings": [],
|
|
"thresholds": {"mode": "absolute", "steps": [{"color": "green", "value": null}]},
|
|
"unit": "short"
|
|
},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 8, "w": 24, "x": 0, "y": 29},
|
|
"id": 16,
|
|
"options": {"legend": {"calcs": ["mean", "min", "max"], "displayMode": "table", "placement": "right", "showLegend": true}, "tooltip": {"mode": "multi", "sort": "desc"}},
|
|
"targets": [
|
|
{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "union(tables: [from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"e3_vitocal_seasonal_performance_factor\") |> map(fn: (r) => ({_time: r._time, _value: r._value})), from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"vitocal_250_a_vitocal_scop_total\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> aggregateWindow(every: 6h, fn: last, createEmpty: false) |> keep(columns: [\"_time\", \"_value\"]) |> rename(columns: {_value: \"Overall SPF\"})", "refId": "A"},
|
|
{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "union(tables: [from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"e3_vitocal_seasonal_performance_factor_heating\") |> map(fn: (r) => ({_time: r._time, _value: r._value})), from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"vitocal_250_a_vitocal_scop_heating\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> aggregateWindow(every: 6h, fn: last, createEmpty: false) |> keep(columns: [\"_time\", \"_value\"]) |> rename(columns: {_value: \"Heating SPF\"})", "refId": "B"},
|
|
{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "union(tables: [from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"e3_vitocal_seasonal_performance_factor_domestic_hot_water\") |> map(fn: (r) => ({_time: r._time, _value: r._value})), from(bucket: \"suedstr28\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"vitocal_250_a_vitocal_scop_dhw\") |> map(fn: (r) => ({_time: r._time, _value: r._value}))]) |> aggregateWindow(every: 6h, fn: last, createEmpty: false) |> keep(columns: [\"_time\", \"_value\"]) |> rename(columns: {_value: \"DHW SPF\"})", "refId": "C"}
|
|
],
|
|
"timeFrom": "90d",
|
|
"title": "Seasonal Performance Factor Over Time",
|
|
"type": "timeseries"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "blue", "value": null}]}, "unit": "kwh"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 4, "w": 6, "x": 0, "y": 37},
|
|
"id": 17,
|
|
"options": {"colorMode": "value", "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: -30d) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"vitocal_250_a_vitocal_heating_electric_energy_year\") |> last() |> keep(columns: [\"_value\"])", "refId": "A"}],
|
|
"title": "Heating This Year",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "blue", "value": null}]}, "unit": "kwh"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 4, "w": 6, "x": 6, "y": 37},
|
|
"id": 18,
|
|
"options": {"colorMode": "value", "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: -30d) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"vitocal_250_a_vitocal_dhw_electric_energy_year\") |> last() |> keep(columns: [\"_value\"])", "refId": "A"}],
|
|
"title": "DHW This Year",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "purple", "value": null}]}, "unit": "kwh"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 4, "w": 6, "x": 12, "y": 37},
|
|
"id": 19,
|
|
"options": {"colorMode": "value", "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: -7d) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"e3_vitocal_heating_energy_consumption_total\") |> spread() |> keep(columns: [\"_value\"])", "refId": "A"}],
|
|
"title": "Heating Last 7 Days",
|
|
"type": "stat"
|
|
},
|
|
{
|
|
"datasource": {"type": "influxdb", "uid": "influxdb"},
|
|
"fieldConfig": {
|
|
"defaults": {"color": {"mode": "thresholds"}, "mappings": [], "thresholds": {"mode": "absolute", "steps": [{"color": "purple", "value": null}]}, "unit": "kwh"},
|
|
"overrides": []
|
|
},
|
|
"gridPos": {"h": 4, "w": 6, "x": 18, "y": 37},
|
|
"id": 20,
|
|
"options": {"colorMode": "value", "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}, "textMode": "auto"},
|
|
"targets": [{"datasource": {"type": "influxdb", "uid": "influxdb"}, "query": "from(bucket: \"suedstr28\") |> range(start: -7d) |> filter(fn: (r) => r._field == \"value\" and r.entity_id == \"e3_vitocal_dhw_energy_consumption_total\") |> spread() |> keep(columns: [\"_value\"])", "refId": "A"}],
|
|
"title": "DHW Last 7 Days",
|
|
"type": "stat"
|
|
}
|
|
],
|
|
"refresh": "5m",
|
|
"schemaVersion": 38,
|
|
"style": "dark",
|
|
"tags": ["homelab", "heatpump", "energy", "roi"],
|
|
"templating": {"list": [
|
|
{
|
|
"current": {"selected": true, "text": "72968", "value": "72968"},
|
|
"description": "Heat pump investment cost (excluding water softener EUR 9,225)",
|
|
"hide": 0,
|
|
"label": "Investment",
|
|
"name": "investment_cost",
|
|
"options": [
|
|
{"selected": true, "text": "72968", "value": "72968"}
|
|
],
|
|
"query": "72968",
|
|
"type": "custom"
|
|
},
|
|
{
|
|
"current": {"selected": true, "text": "6650", "value": "6650"},
|
|
"description": "Annual oil heating cost baseline: ~5,000L at ~1.33 EUR/L (2022-2023 oil orders)",
|
|
"hide": 0,
|
|
"label": "Oil Baseline",
|
|
"name": "oil_baseline",
|
|
"options": [
|
|
{"selected": true, "text": "6650", "value": "6650"}
|
|
],
|
|
"query": "6650",
|
|
"type": "custom"
|
|
},
|
|
{
|
|
"current": {"selected": true, "text": "0.08", "value": "0.08"},
|
|
"description": "Electricity price when battery full/solar excess",
|
|
"hide": 0,
|
|
"label": "Solar Price",
|
|
"name": "solar_price",
|
|
"options": [
|
|
{"selected": true, "text": "0.08", "value": "0.08"}
|
|
],
|
|
"query": "0.08",
|
|
"type": "custom"
|
|
},
|
|
{
|
|
"current": {"selected": true, "text": "0.3271", "value": "0.3271"},
|
|
"description": "Grid electricity price EUR/kWh (replaces the retired live input_number.strompreis read)",
|
|
"hide": 0,
|
|
"label": "Grid Price",
|
|
"name": "grid_price",
|
|
"options": [
|
|
{"selected": true, "text": "0.3271", "value": "0.3271"}
|
|
],
|
|
"query": "0.3271",
|
|
"type": "custom"
|
|
}
|
|
]},
|
|
"time": {"from": "2024-10-01T00:00:00.000Z", "to": "now"},
|
|
"timepicker": {},
|
|
"timezone": "",
|
|
"title": "Heat Pump ROI",
|
|
"uid": "heatpump-roi",
|
|
"version": 1,
|
|
"weekStart": ""
|
|
}
|