node-red-contrib-power-saver 5.0.0-beta.2 → 5.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,11 @@ sidebarDepth: 1
7
7
 
8
8
  List the most significant changes.
9
9
 
10
+ ## 5.0.0.beta.3
11
+
12
+ - Implement minute support in Heat Capacitor
13
+ - Fix bug so recoveryPercentage is used properly
14
+
10
15
  ## 5.0.0.beta.2
11
16
 
12
17
  - Fix bug in Min minutes off
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-power-saver",
3
- "version": "5.0.0-beta.2",
3
+ "version": "5.0.0-beta.3",
4
4
  "description": "A module for Node-RED that you can use to turn on and off a switch based on power prices",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -59,6 +59,8 @@ function isOnOffSequencesOk(
59
59
  if (onCount >= minOnAfterOff) {
60
60
  reachedMaxOff = false;
61
61
  reachedMinOn = true;
62
+ } else {
63
+ reachedMinOn = false;
62
64
  }
63
65
  offCount = 0;
64
66
  reachedMinOff = null;
@@ -2,22 +2,51 @@
2
2
  const { DateTime } = require("luxon");
3
3
  const { roundPrice, getDiffToNextOn } = require("./utils");
4
4
 
5
- function calculateOpportunities(prices, pattern, amount) {
6
- //creating a price vector with minute granularity
7
- const tempPrice = Array(prices.length * 60).fill(0);
8
- for (let i = 0; i < prices.length; i++) {
9
- tempPrice.fill(prices[i], i * 60, (i + 1) * 60);
10
- //debugger;
5
+ function buildMinutePriceVector(priceData) {
6
+ if (!priceData || priceData.length === 0) {
7
+ return { minutePrices: [], startDate: null };
11
8
  }
12
9
 
10
+ const sorted = [...priceData].sort(
11
+ (a, b) => DateTime.fromISO(a.start).toMillis() - DateTime.fromISO(b.start).toMillis()
12
+ );
13
+
14
+ const minutePrices = [];
15
+ let previousIntervalMinutes = 60;
16
+
17
+ for (let i = 0; i < sorted.length; i++) {
18
+ const currentStart = DateTime.fromISO(sorted[i].start);
19
+ let intervalMinutes = previousIntervalMinutes;
20
+
21
+ if (sorted[i + 1]) {
22
+ intervalMinutes = DateTime.fromISO(sorted[i + 1].start).diff(currentStart, "minutes").minutes;
23
+ } else if (sorted[i].end) {
24
+ intervalMinutes = DateTime.fromISO(sorted[i].end).diff(currentStart, "minutes").minutes;
25
+ }
26
+
27
+ intervalMinutes = Math.max(1, Math.round(intervalMinutes));
28
+ previousIntervalMinutes = intervalMinutes;
29
+
30
+ for (let m = 0; m < intervalMinutes; m++) {
31
+ minutePrices.push(sorted[i].value);
32
+ }
33
+ }
34
+
35
+ return { minutePrices, startDate: DateTime.fromISO(sorted[0].start) };
36
+ }
37
+
38
+ function calculateOpportunities(pricesPerMinute, pattern, amount) {
39
+ const tempPrice = pricesPerMinute;
40
+
13
41
  //Calculate weighted pattern
14
42
  const weight = amount / pattern.reduce((a, b) => a + b, 0); //last calculates the sum of all numbers in the pattern
15
43
  const weightedPattern = pattern.map((x) => x * weight);
16
44
 
17
45
  //Calculating procurement opportunities. Sliding the pattern over the price vector to find the price for procuring
18
46
  //at time t
19
- const dot = (a, b) => a.map((x, i) => a[i] * b[i]).reduce((m, n) => m + n);
20
- const procurementOpportunities = Array(prices.length * 60 - pattern.length + 1);
47
+ const dot = (a, b) => a.map((x, i) => a[i] * b[i]).reduce((m, n) => m + n, 0);
48
+ const procurementLength = Math.max(tempPrice.length - pattern.length + 1, 0);
49
+ const procurementOpportunities = Array(procurementLength);
21
50
  for (let i = 0; i < procurementOpportunities.length; i++) {
22
51
  procurementOpportunities[i] = dot(weightedPattern, tempPrice.slice(i, i + pattern.length));
23
52
  }
@@ -232,8 +261,7 @@ function runBuySellAlgorithm(
232
261
  maxTempAdjustment,
233
262
  minSavings
234
263
  ) {
235
- const prices = [...priceData.map((pd) => pd.value)];
236
- const startDate = DateTime.fromISO(priceData[0].start);
264
+ const { minutePrices, startDate } = buildMinutePriceVector(priceData);
237
265
 
238
266
  //pattern for how much power is procured/sold when.
239
267
  //This has, for now, just a flat acquisition/divestment profile
@@ -243,8 +271,8 @@ function runBuySellAlgorithm(
243
271
  const sellPattern = Array(sellDuration).fill(1);
244
272
 
245
273
  //Calculate what it will cost to procure/sell 1 kWh as a function of time
246
- const buyPrices = calculateOpportunities(prices, buyPattern, 1);
247
- const sellPrices = calculateOpportunities(prices, sellPattern, 1);
274
+ const buyPrices = calculateOpportunities(minutePrices, buyPattern, 1);
275
+ const sellPrices = calculateOpportunities(minutePrices, sellPattern, 1);
248
276
 
249
277
  //Find dates for when to procure/sell
250
278
  const buySell = findBestBuySellPattern(buyPrices, buyPattern.length, sellPrices, sellPattern.length);
@@ -80,10 +80,14 @@ module.exports = function (RED) {
80
80
  if (msg.payload.hasOwnProperty("priceData")) {
81
81
  if (node.hasOwnProperty("priceData")) {
82
82
  node.priceData = mergePriceData(node.priceData, msg.payload.priceData);
83
- if (node.priceData.length > 72) node.priceData = node.priceData.slice(-72);
84
83
  } else {
85
84
  node.priceData = msg.payload.priceData;
86
85
  }
86
+ if (node.priceData.length) {
87
+ const latestStart = DateTime.fromISO(node.priceData[node.priceData.length - 1].start);
88
+ const cutoff = latestStart.minus({ hours: 72 });
89
+ node.priceData = node.priceData.filter((entry) => DateTime.fromISO(entry.start) >= cutoff);
90
+ }
87
91
  }
88
92
 
89
93
  if (node.hasOwnProperty("priceData")) {
@@ -136,21 +140,16 @@ module.exports = function (RED) {
136
140
  };
137
141
 
138
142
  function mergePriceData(priceDataA, priceDataB) {
139
- const tempDict = {};
140
- priceDataA.forEach((e) => {
141
- tempDict[e.start] = e.value;
142
- });
143
- priceDataB.forEach((e) => {
144
- tempDict[e.start] = e.value;
143
+ const mergedEntries = new Map();
144
+ priceDataA.concat(priceDataB).forEach((entry) => {
145
+ if (!entry?.start) {
146
+ return;
147
+ }
148
+ const existing = mergedEntries.get(entry.start);
149
+ mergedEntries.set(entry.start, Object.assign({}, existing, entry));
145
150
  });
146
151
 
147
- const keys = Object.keys(tempDict);
148
- keys.sort();
149
-
150
- const res = Array(keys.length);
151
- for (let i = 0; i < res.length; i++) {
152
- res[i] = { value: tempDict[keys[i]], start: keys[i] };
153
- }
154
-
155
- return res;
152
+ return Array.from(mergedEntries.values()).sort(
153
+ (a, b) => DateTime.fromISO(a.start).toMillis() - DateTime.fromISO(b.start).toMillis()
154
+ );
156
155
  }
@@ -0,0 +1,198 @@
1
+ {
2
+ "priceData": [
3
+ { "value": 0.4649, "start": "2025-11-07T00:00:00.000+01:00" },
4
+ { "value": 0.458, "start": "2025-11-07T00:15:00.000+01:00" },
5
+ { "value": 0.4438, "start": "2025-11-07T00:30:00.000+01:00" },
6
+ { "value": 0.4435, "start": "2025-11-07T00:45:00.000+01:00" },
7
+ { "value": 0.46, "start": "2025-11-07T01:00:00.000+01:00" },
8
+ { "value": 0.452, "start": "2025-11-07T01:15:00.000+01:00" },
9
+ { "value": 0.448, "start": "2025-11-07T01:30:00.000+01:00" },
10
+ { "value": 0.446, "start": "2025-11-07T01:45:00.000+01:00" },
11
+ { "value": 0.4451, "start": "2025-11-07T02:00:00.000+01:00" },
12
+ { "value": 0.446, "start": "2025-11-07T02:15:00.000+01:00" },
13
+ { "value": 0.4469, "start": "2025-11-07T02:30:00.000+01:00" },
14
+ { "value": 0.4499, "start": "2025-11-07T02:45:00.000+01:00" },
15
+ { "value": 0.4392, "start": "2025-11-07T03:00:00.000+01:00" },
16
+ { "value": 0.444, "start": "2025-11-07T03:15:00.000+01:00" },
17
+ { "value": 0.4469, "start": "2025-11-07T03:30:00.000+01:00" },
18
+ { "value": 0.4558, "start": "2025-11-07T03:45:00.000+01:00" },
19
+ { "value": 0.4451, "start": "2025-11-07T04:00:00.000+01:00" },
20
+ { "value": 0.4604, "start": "2025-11-07T04:15:00.000+01:00" },
21
+ { "value": 0.471, "start": "2025-11-07T04:30:00.000+01:00" },
22
+ { "value": 0.4841, "start": "2025-11-07T04:45:00.000+01:00" },
23
+ { "value": 0.4792, "start": "2025-11-07T05:00:00.000+01:00" },
24
+ { "value": 0.5111, "start": "2025-11-07T05:15:00.000+01:00" },
25
+ { "value": 0.5364, "start": "2025-11-07T05:30:00.000+01:00" },
26
+ { "value": 0.5405, "start": "2025-11-07T05:45:00.000+01:00" },
27
+ { "value": 0.5406, "start": "2025-11-07T06:00:00.000+01:00" },
28
+ { "value": 0.5449, "start": "2025-11-07T06:15:00.000+01:00" },
29
+ { "value": 0.627, "start": "2025-11-07T06:30:00.000+01:00" },
30
+ { "value": 0.9012, "start": "2025-11-07T06:45:00.000+01:00" },
31
+ { "value": 0.9481, "start": "2025-11-07T07:00:00.000+01:00" },
32
+ { "value": 1.0486, "start": "2025-11-07T07:15:00.000+01:00" },
33
+ { "value": 1.2117, "start": "2025-11-07T07:30:00.000+01:00" },
34
+ { "value": 1.5884, "start": "2025-11-07T07:45:00.000+01:00" },
35
+ { "value": 1.5013, "start": "2025-11-07T08:00:00.000+01:00" },
36
+ { "value": 1.7345, "start": "2025-11-07T08:15:00.000+01:00" },
37
+ { "value": 1.5688, "start": "2025-11-07T08:30:00.000+01:00" },
38
+ { "value": 1.2983, "start": "2025-11-07T08:45:00.000+01:00" },
39
+ { "value": 0.9651, "start": "2025-11-07T09:00:00.000+01:00" },
40
+ { "value": 0.9504, "start": "2025-11-07T09:15:00.000+01:00" },
41
+ { "value": 0.9516, "start": "2025-11-07T09:30:00.000+01:00" },
42
+ { "value": 0.9525, "start": "2025-11-07T09:45:00.000+01:00" },
43
+ { "value": 0.9551, "start": "2025-11-07T10:00:00.000+01:00" },
44
+ { "value": 0.9567, "start": "2025-11-07T10:15:00.000+01:00" },
45
+ { "value": 0.9584, "start": "2025-11-07T10:30:00.000+01:00" },
46
+ { "value": 0.96, "start": "2025-11-07T10:45:00.000+01:00" },
47
+ { "value": 0.9554, "start": "2025-11-07T11:00:00.000+01:00" },
48
+ { "value": 0.957, "start": "2025-11-07T11:15:00.000+01:00" },
49
+ { "value": 0.9577, "start": "2025-11-07T11:30:00.000+01:00" },
50
+ { "value": 0.9591, "start": "2025-11-07T11:45:00.000+01:00" },
51
+ { "value": 0.9514, "start": "2025-11-07T12:00:00.000+01:00" },
52
+ { "value": 0.9558, "start": "2025-11-07T12:15:00.000+01:00" },
53
+ { "value": 0.9572, "start": "2025-11-07T12:30:00.000+01:00" },
54
+ { "value": 0.9574, "start": "2025-11-07T12:45:00.000+01:00" },
55
+ { "value": 0.954, "start": "2025-11-07T13:00:00.000+01:00" },
56
+ { "value": 0.9545, "start": "2025-11-07T13:15:00.000+01:00" },
57
+ { "value": 0.9555, "start": "2025-11-07T13:30:00.000+01:00" },
58
+ { "value": 0.957, "start": "2025-11-07T13:45:00.000+01:00" },
59
+ { "value": 0.9567, "start": "2025-11-07T14:00:00.000+01:00" },
60
+ { "value": 0.9578, "start": "2025-11-07T14:15:00.000+01:00" },
61
+ { "value": 1.2984, "start": "2025-11-07T14:30:00.000+01:00" },
62
+ { "value": 1.7027, "start": "2025-11-07T14:45:00.000+01:00" },
63
+ { "value": 1.2913, "start": "2025-11-07T15:00:00.000+01:00" },
64
+ { "value": 1.4679, "start": "2025-11-07T15:15:00.000+01:00" },
65
+ { "value": 1.6917, "start": "2025-11-07T15:30:00.000+01:00" },
66
+ { "value": 2.032, "start": "2025-11-07T15:45:00.000+01:00" },
67
+ { "value": 1.6871, "start": "2025-11-07T16:00:00.000+01:00" },
68
+ { "value": 1.9684, "start": "2025-11-07T16:15:00.000+01:00" },
69
+ { "value": 2.0491, "start": "2025-11-07T16:30:00.000+01:00" },
70
+ { "value": 2.0605, "start": "2025-11-07T16:45:00.000+01:00" },
71
+ { "value": 1.9401, "start": "2025-11-07T17:00:00.000+01:00" },
72
+ { "value": 1.8698, "start": "2025-11-07T17:15:00.000+01:00" },
73
+ { "value": 1.604, "start": "2025-11-07T17:30:00.000+01:00" },
74
+ { "value": 1.3766, "start": "2025-11-07T17:45:00.000+01:00" },
75
+ { "value": 2.0411, "start": "2025-11-07T18:00:00.000+01:00" },
76
+ { "value": 1.8794, "start": "2025-11-07T18:15:00.000+01:00" },
77
+ { "value": 1.4522, "start": "2025-11-07T18:30:00.000+01:00" },
78
+ { "value": 1.2228, "start": "2025-11-07T18:45:00.000+01:00" },
79
+ { "value": 0.996, "start": "2025-11-07T19:00:00.000+01:00" },
80
+ { "value": 0.9816, "start": "2025-11-07T19:15:00.000+01:00" },
81
+ { "value": 0.872, "start": "2025-11-07T19:30:00.000+01:00" },
82
+ { "value": 0.7728, "start": "2025-11-07T19:45:00.000+01:00" },
83
+ { "value": 0.9714, "start": "2025-11-07T20:00:00.000+01:00" },
84
+ { "value": 0.8548, "start": "2025-11-07T20:15:00.000+01:00" },
85
+ { "value": 0.7729, "start": "2025-11-07T20:30:00.000+01:00" },
86
+ { "value": 0.641, "start": "2025-11-07T20:45:00.000+01:00" },
87
+ { "value": 0.8416, "start": "2025-11-07T21:00:00.000+01:00" },
88
+ { "value": 0.7728, "start": "2025-11-07T21:15:00.000+01:00" },
89
+ { "value": 0.6528, "start": "2025-11-07T21:30:00.000+01:00" },
90
+ { "value": 0.6256, "start": "2025-11-07T21:45:00.000+01:00" },
91
+ { "value": 0.6478, "start": "2025-11-07T22:00:00.000+01:00" },
92
+ { "value": 0.6292, "start": "2025-11-07T22:15:00.000+01:00" },
93
+ { "value": 0.6031, "start": "2025-11-07T22:30:00.000+01:00" },
94
+ { "value": 0.5945, "start": "2025-11-07T22:45:00.000+01:00" },
95
+ { "value": 0.6175, "start": "2025-11-07T23:00:00.000+01:00" },
96
+ { "value": 0.5984, "start": "2025-11-07T23:15:00.000+01:00" },
97
+ { "value": 0.576, "start": "2025-11-07T23:30:00.000+01:00" },
98
+ { "value": 0.563, "start": "2025-11-07T23:45:00.000+01:00" },
99
+ { "value": 0.5924, "start": "2025-11-08T00:00:00.000+01:00" },
100
+ { "value": 0.5696, "start": "2025-11-08T00:15:00.000+01:00" },
101
+ { "value": 0.5525, "start": "2025-11-08T00:30:00.000+01:00" },
102
+ { "value": 0.5456, "start": "2025-11-08T00:45:00.000+01:00" },
103
+ { "value": 0.5677, "start": "2025-11-08T01:00:00.000+01:00" },
104
+ { "value": 0.5513, "start": "2025-11-08T01:15:00.000+01:00" },
105
+ { "value": 0.5376, "start": "2025-11-08T01:30:00.000+01:00" },
106
+ { "value": 0.5362, "start": "2025-11-08T01:45:00.000+01:00" },
107
+ { "value": 0.5689, "start": "2025-11-08T02:00:00.000+01:00" },
108
+ { "value": 0.5622, "start": "2025-11-08T02:15:00.000+01:00" },
109
+ { "value": 0.5498, "start": "2025-11-08T02:30:00.000+01:00" },
110
+ { "value": 0.5387, "start": "2025-11-08T02:45:00.000+01:00" },
111
+ { "value": 0.562, "start": "2025-11-08T03:00:00.000+01:00" },
112
+ { "value": 0.5544, "start": "2025-11-08T03:15:00.000+01:00" },
113
+ { "value": 0.5542, "start": "2025-11-08T03:30:00.000+01:00" },
114
+ { "value": 0.5503, "start": "2025-11-08T03:45:00.000+01:00" },
115
+ { "value": 0.5522, "start": "2025-11-08T04:00:00.000+01:00" },
116
+ { "value": 0.5532, "start": "2025-11-08T04:15:00.000+01:00" },
117
+ { "value": 0.5535, "start": "2025-11-08T04:30:00.000+01:00" },
118
+ { "value": 0.5533, "start": "2025-11-08T04:45:00.000+01:00" },
119
+ { "value": 0.5549, "start": "2025-11-08T05:00:00.000+01:00" },
120
+ { "value": 0.558, "start": "2025-11-08T05:15:00.000+01:00" },
121
+ { "value": 0.5642, "start": "2025-11-08T05:30:00.000+01:00" },
122
+ { "value": 0.6096, "start": "2025-11-08T05:45:00.000+01:00" },
123
+ { "value": 0.5685, "start": "2025-11-08T06:00:00.000+01:00" },
124
+ { "value": 0.5644, "start": "2025-11-08T06:15:00.000+01:00" },
125
+ { "value": 0.6212, "start": "2025-11-08T06:30:00.000+01:00" },
126
+ { "value": 0.626, "start": "2025-11-08T06:45:00.000+01:00" },
127
+ { "value": 0.6303, "start": "2025-11-08T07:00:00.000+01:00" },
128
+ { "value": 0.6445, "start": "2025-11-08T07:15:00.000+01:00" },
129
+ { "value": 0.6787, "start": "2025-11-08T07:30:00.000+01:00" },
130
+ { "value": 0.6967, "start": "2025-11-08T07:45:00.000+01:00" },
131
+ { "value": 0.6776, "start": "2025-11-08T08:00:00.000+01:00" },
132
+ { "value": 0.6968, "start": "2025-11-08T08:15:00.000+01:00" },
133
+ { "value": 0.7764, "start": "2025-11-08T08:30:00.000+01:00" },
134
+ { "value": 0.8068, "start": "2025-11-08T08:45:00.000+01:00" },
135
+ { "value": 0.8184, "start": "2025-11-08T09:00:00.000+01:00" },
136
+ { "value": 0.8417, "start": "2025-11-08T09:15:00.000+01:00" },
137
+ { "value": 0.8584, "start": "2025-11-08T09:30:00.000+01:00" },
138
+ { "value": 0.9063, "start": "2025-11-08T09:45:00.000+01:00" },
139
+ { "value": 0.8719, "start": "2025-11-08T10:00:00.000+01:00" },
140
+ { "value": 0.874, "start": "2025-11-08T10:15:00.000+01:00" },
141
+ { "value": 0.8765, "start": "2025-11-08T10:30:00.000+01:00" },
142
+ { "value": 0.877, "start": "2025-11-08T10:45:00.000+01:00" },
143
+ { "value": 0.8902, "start": "2025-11-08T11:00:00.000+01:00" },
144
+ { "value": 0.8982, "start": "2025-11-08T11:15:00.000+01:00" },
145
+ { "value": 0.9025, "start": "2025-11-08T11:30:00.000+01:00" },
146
+ { "value": 0.8984, "start": "2025-11-08T11:45:00.000+01:00" },
147
+ { "value": 0.9157, "start": "2025-11-08T12:00:00.000+01:00" },
148
+ { "value": 0.9229, "start": "2025-11-08T12:15:00.000+01:00" },
149
+ { "value": 0.9233, "start": "2025-11-08T12:30:00.000+01:00" },
150
+ { "value": 0.924, "start": "2025-11-08T12:45:00.000+01:00" },
151
+ { "value": 0.9183, "start": "2025-11-08T13:00:00.000+01:00" },
152
+ { "value": 0.9194, "start": "2025-11-08T13:15:00.000+01:00" },
153
+ { "value": 0.9309, "start": "2025-11-08T13:30:00.000+01:00" },
154
+ { "value": 0.9635, "start": "2025-11-08T13:45:00.000+01:00" },
155
+ { "value": 1.0168, "start": "2025-11-08T14:00:00.000+01:00" },
156
+ { "value": 1.0784, "start": "2025-11-08T14:15:00.000+01:00" },
157
+ { "value": 1.2278, "start": "2025-11-08T14:30:00.000+01:00" },
158
+ { "value": 1.3086, "start": "2025-11-08T14:45:00.000+01:00" },
159
+ { "value": 0.9526, "start": "2025-11-08T15:00:00.000+01:00" },
160
+ { "value": 1.2403, "start": "2025-11-08T15:15:00.000+01:00" },
161
+ { "value": 1.419, "start": "2025-11-08T15:30:00.000+01:00" },
162
+ { "value": 1.8, "start": "2025-11-08T15:45:00.000+01:00" },
163
+ { "value": 1.4804, "start": "2025-11-08T16:00:00.000+01:00" },
164
+ { "value": 1.6303, "start": "2025-11-08T16:15:00.000+01:00" },
165
+ { "value": 1.704, "start": "2025-11-08T16:30:00.000+01:00" },
166
+ { "value": 1.9417, "start": "2025-11-08T16:45:00.000+01:00" },
167
+ { "value": 1.6725, "start": "2025-11-08T17:00:00.000+01:00" },
168
+ { "value": 1.8313, "start": "2025-11-08T17:15:00.000+01:00" },
169
+ { "value": 1.8342, "start": "2025-11-08T17:30:00.000+01:00" },
170
+ { "value": 1.8221, "start": "2025-11-08T17:45:00.000+01:00" },
171
+ { "value": 1.8094, "start": "2025-11-08T18:00:00.000+01:00" },
172
+ { "value": 1.708, "start": "2025-11-08T18:15:00.000+01:00" },
173
+ { "value": 1.367, "start": "2025-11-08T18:30:00.000+01:00" },
174
+ { "value": 1.1441, "start": "2025-11-08T18:45:00.000+01:00" },
175
+ { "value": 1.1921, "start": "2025-11-08T19:00:00.000+01:00" },
176
+ { "value": 1.0164, "start": "2025-11-08T19:15:00.000+01:00" },
177
+ { "value": 0.9805, "start": "2025-11-08T19:30:00.000+01:00" },
178
+ { "value": 0.8764, "start": "2025-11-08T19:45:00.000+01:00" },
179
+ { "value": 0.9077, "start": "2025-11-08T20:00:00.000+01:00" },
180
+ { "value": 0.8316, "start": "2025-11-08T20:15:00.000+01:00" },
181
+ { "value": 0.6575, "start": "2025-11-08T20:30:00.000+01:00" },
182
+ { "value": 0.5803, "start": "2025-11-08T20:45:00.000+01:00" },
183
+ { "value": 0.6191, "start": "2025-11-08T21:00:00.000+01:00" },
184
+ { "value": 0.6142, "start": "2025-11-08T21:15:00.000+01:00" },
185
+ { "value": 0.5656, "start": "2025-11-08T21:30:00.000+01:00" },
186
+ { "value": 0.5521, "start": "2025-11-08T21:45:00.000+01:00" },
187
+ { "value": 0.5593, "start": "2025-11-08T22:00:00.000+01:00" },
188
+ { "value": 0.5466, "start": "2025-11-08T22:15:00.000+01:00" },
189
+ { "value": 0.5369, "start": "2025-11-08T22:30:00.000+01:00" },
190
+ { "value": 0.5341, "start": "2025-11-08T22:45:00.000+01:00" },
191
+ { "value": 0.5377, "start": "2025-11-08T23:00:00.000+01:00" },
192
+ { "value": 0.5303, "start": "2025-11-08T23:15:00.000+01:00" },
193
+ { "value": 0.5271, "start": "2025-11-08T23:30:00.000+01:00" },
194
+ { "value": 0.5256, "start": "2025-11-08T23:45:00.000+01:00", "end": "2025-11-09T00:00:00.000+01:00" }
195
+ ],
196
+ "source": "Tibber",
197
+ "config": { "hoursOn": 10 }
198
+ }