Add hourly electricity price chart
This commit is contained in:
@@ -140,6 +140,8 @@ lovelace:
|
||||
type: module
|
||||
- url: /hacsfiles/custom-gauge-card/custom-gauge-card.js
|
||||
type: module
|
||||
- url: /local/community/apexcharts-card/apexcharts-card.js
|
||||
type: module
|
||||
dashboards:
|
||||
lovelace:
|
||||
mode: yaml
|
||||
|
||||
@@ -295,17 +295,138 @@ cards:
|
||||
red: 80
|
||||
|
||||
|
||||
# ⚡ Energi + 🍽️ Opvaskemaskine (kompakt)
|
||||
- type: horizontal-stack
|
||||
# ⚡ El-priser + 🍽️ Opvaskemaskine
|
||||
- type: vertical-stack
|
||||
cards:
|
||||
- type: custom:apexcharts-card
|
||||
graph_span: 24h
|
||||
span:
|
||||
start: hour
|
||||
stacked: false
|
||||
header:
|
||||
show: true
|
||||
title: El-priser næste 24 timer
|
||||
show_states: true
|
||||
colorize_states: true
|
||||
now:
|
||||
show: true
|
||||
label: Nu
|
||||
all_series_config:
|
||||
stroke_width: 0
|
||||
apex_config:
|
||||
chart:
|
||||
height: 260
|
||||
grid:
|
||||
strokeDashArray: 2
|
||||
xaxis:
|
||||
type: datetime
|
||||
labels:
|
||||
datetimeFormatter:
|
||||
hour: HH:mm
|
||||
yaxis:
|
||||
decimalsInFloat: 2
|
||||
tickAmount: 5
|
||||
plotOptions:
|
||||
bar:
|
||||
columnWidth: 82%
|
||||
borderRadius: 3
|
||||
series:
|
||||
- entity: sensor.energi_data_service
|
||||
name: Pris
|
||||
type: column
|
||||
float_precision: 2
|
||||
unit: ' kr/kWh'
|
||||
show:
|
||||
in_header: raw
|
||||
in_chart: true
|
||||
data_generator: |
|
||||
const startOfHour = new Date();
|
||||
startOfHour.setMinutes(0, 0, 0);
|
||||
const endTime = startOfHour.getTime() + (24 * 60 * 60 * 1000);
|
||||
|
||||
- type: tile
|
||||
entity: sensor.dishwasher_next_start_compact
|
||||
name: Næste opvask
|
||||
const rawToday = entity.attributes.raw_today || [];
|
||||
const rawTomorrow = entity.attributes.tomorrow_valid ? (entity.attributes.raw_tomorrow || []) : [];
|
||||
const forecast = entity.attributes.forecast || [];
|
||||
|
||||
- type: tile
|
||||
entity: sensor.opvask_tid_tilbage
|
||||
name: Tid tilbage
|
||||
const allKnown = [...rawToday, ...rawTomorrow];
|
||||
const data = [];
|
||||
const seen = new Set();
|
||||
|
||||
const pushPoint = (item) => {
|
||||
const timestamp = new Date(item.hour).getTime();
|
||||
if (Number.isNaN(timestamp) || timestamp < startOfHour.getTime() || timestamp >= endTime || seen.has(timestamp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const price = Number(item.price);
|
||||
if (Number.isNaN(price)) {
|
||||
return;
|
||||
}
|
||||
|
||||
seen.add(timestamp);
|
||||
data.push({ x: timestamp, y: price });
|
||||
};
|
||||
|
||||
allKnown.forEach(pushPoint);
|
||||
|
||||
if (data.length < 24) {
|
||||
forecast.forEach(pushPoint);
|
||||
}
|
||||
|
||||
data.sort((left, right) => left.x - right.x);
|
||||
|
||||
const trimmed = data.slice(0, 24);
|
||||
if (!trimmed.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const prices = trimmed.map((item) => item.y);
|
||||
const minPrice = Math.min(...prices);
|
||||
const maxPrice = Math.max(...prices);
|
||||
|
||||
const mix = (start, end, ratio) => Math.round(start + ((end - start) * ratio));
|
||||
const toHex = (value) => value.toString(16).padStart(2, '0');
|
||||
const rgbToHex = (red, green, blue) => `#${toHex(red)}${toHex(green)}${toHex(blue)}`;
|
||||
|
||||
const colorByValue = (value) => {
|
||||
if (maxPrice === minPrice) {
|
||||
return '#16a34a';
|
||||
}
|
||||
|
||||
const normalized = (value - minPrice) / (maxPrice - minPrice);
|
||||
|
||||
if (normalized <= 0.5) {
|
||||
const ratio = normalized / 0.5;
|
||||
return rgbToHex(
|
||||
mix(22, 250, ratio),
|
||||
mix(163, 204, ratio),
|
||||
mix(74, 21, ratio)
|
||||
);
|
||||
}
|
||||
|
||||
const ratio = (normalized - 0.5) / 0.5;
|
||||
return rgbToHex(
|
||||
mix(250, 220, ratio),
|
||||
mix(204, 38, ratio),
|
||||
mix(21, 38, ratio)
|
||||
);
|
||||
};
|
||||
|
||||
return trimmed.map((item) => ({
|
||||
x: item.x,
|
||||
y: item.y,
|
||||
fillColor: colorByValue(item.y)
|
||||
}));
|
||||
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- type: tile
|
||||
entity: sensor.dishwasher_next_start_compact
|
||||
name: Næste opvask
|
||||
|
||||
- type: tile
|
||||
entity: sensor.opvask_tid_tilbage
|
||||
name: Tid tilbage
|
||||
|
||||
# 🧹 Støvsuger (forenklet – mindre støj)
|
||||
- type: entities
|
||||
|
||||
Reference in New Issue
Block a user