@energiok/node-red-contrib-pricecontrol-thermal 1.2.1 → 1.2.2
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.
- package/DASHBOARD-TEMPLATE-3-MODES.md +4 -4
- package/package.json +1 -1
- package/src/strategy-smart-thermal-functions.js +210 -160
- package/src/strategy-smart-thermal.js +2 -0
- package/test/strategy-smart-thermal-functions.test.js +258 -94
- package/test/strategy-smart-thermal-node.test.js +36 -58
- package/test-3day-prices.js +0 -96
- package/test-cold-weather.js +0 -43
- package/test-day-transition.js +0 -161
- package/test-find-params.js +0 -78
- package/test-hourly-alignment.js +0 -114
- package/test-price-analysis.js +0 -77
- package/test-runway.js +0 -118
- package/test-saturday-peak.js +0 -132
- package/test-step-by-step.js +0 -213
- package/test-temp-scaling.js +0 -62
- package/test-thermal-budget.js +0 -174
- package/test-timezone.js +0 -83
- package/test-utc-machine.js +0 -90
package/test-step-by-step.js
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Step-by-step trace of what happens with the price data
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const { DateTime } = require("luxon");
|
|
6
|
-
const { createSchedule, ckmeans, classifyPricesWithCkmeans } = require('./src/strategy-smart-thermal-functions.js');
|
|
7
|
-
|
|
8
|
-
const prices = [{"price":97.41,"currency":"EUR","area":"NO1","timestamp":"2026-01-14T23:00:00Z"},{"price":95.18,"currency":"EUR","area":"NO1","timestamp":"2026-01-14T23:15:00Z"},{"price":92.83,"currency":"EUR","area":"NO1","timestamp":"2026-01-14T23:30:00Z"},{"price":90.1,"currency":"EUR","area":"NO1","timestamp":"2026-01-14T23:45:00Z"},{"price":94.19,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T00:00:00Z"},{"price":92.32,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T00:15:00Z"},{"price":90,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T00:30:00Z"},{"price":88.44,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T00:45:00Z"},{"price":90.22,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T01:00:00Z"},{"price":86.96,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T01:15:00Z"},{"price":84.8,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T01:30:00Z"},{"price":84.1,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T01:45:00Z"},{"price":83.83,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T02:00:00Z"},{"price":83.11,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T02:15:00Z"},{"price":81.99,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T02:30:00Z"},{"price":80.98,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T02:45:00Z"},{"price":80.33,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T03:00:00Z"},{"price":80.33,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T03:15:00Z"},{"price":80.96,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T03:30:00Z"},{"price":81.73,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T03:45:00Z"},{"price":81.46,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T04:00:00Z"},{"price":82.47,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T04:15:00Z"},{"price":84.17,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T04:30:00Z"},{"price":86.6,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T04:45:00Z"},{"price":88.49,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T05:00:00Z"},{"price":92.15,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T05:15:00Z"},{"price":93.8,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T05:30:00Z"},{"price":95.54,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T05:45:00Z"},{"price":95.2,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T06:00:00Z"},{"price":98.28,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T06:15:00Z"},{"price":101.23,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T06:30:00Z"},{"price":103.04,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T06:45:00Z"},{"price":98.12,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T07:00:00Z"},{"price":99.72,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T07:15:00Z"},{"price":99.67,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T07:30:00Z"},{"price":99.31,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T07:45:00Z"},{"price":107.96,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T08:00:00Z"},{"price":104.01,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T08:15:00Z"},{"price":100.59,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T08:30:00Z"},{"price":98.28,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T08:45:00Z"},{"price":108.27,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T09:00:00Z"},{"price":104.8,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T09:15:00Z"},{"price":100.19,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T09:30:00Z"},{"price":98.62,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T09:45:00Z"},{"price":98.98,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T10:00:00Z"},{"price":96.95,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T10:15:00Z"},{"price":95.96,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T10:30:00Z"},{"price":95.11,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T10:45:00Z"},{"price":99.43,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T11:00:00Z"},{"price":96.57,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T11:15:00Z"},{"price":96.77,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T11:30:00Z"},{"price":99.4,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T11:45:00Z"},{"price":101.19,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T12:00:00Z"},{"price":102.56,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T12:15:00Z"},{"price":104.22,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T12:30:00Z"},{"price":101.99,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T12:45:00Z"},{"price":98.83,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T13:00:00Z"},{"price":102.35,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T13:15:00Z"},{"price":101.57,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T13:30:00Z"},{"price":110.66,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T13:45:00Z"},{"price":99.23,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T14:00:00Z"},{"price":117.22,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T14:15:00Z"},{"price":124.09,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T14:30:00Z"},{"price":138.69,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T14:45:00Z"},{"price":121.14,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T15:00:00Z"},{"price":131.5,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T15:15:00Z"},{"price":135.11,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T15:30:00Z"},{"price":141.15,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T15:45:00Z"},{"price":147.79,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T16:00:00Z"},{"price":151.48,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T16:15:00Z"},{"price":140.68,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T16:30:00Z"},{"price":128.72,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T16:45:00Z"},{"price":130.32,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T17:00:00Z"},{"price":113.7,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T17:15:00Z"},{"price":112.49,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T17:30:00Z"},{"price":102.26,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T17:45:00Z"},{"price":107.13,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T18:00:00Z"},{"price":101.56,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T18:15:00Z"},{"price":100.83,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T18:30:00Z"},{"price":100,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T18:45:00Z"},{"price":98.71,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T19:00:00Z"},{"price":97.8,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T19:15:00Z"},{"price":95.31,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T19:30:00Z"},{"price":91.64,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T19:45:00Z"},{"price":91.14,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T20:00:00Z"},{"price":88.64,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T20:15:00Z"},{"price":88.24,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T20:30:00Z"},{"price":88.59,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T20:45:00Z"},{"price":91.23,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T21:00:00Z"},{"price":86.91,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T21:15:00Z"},{"price":86.86,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T21:30:00Z"},{"price":84.67,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T21:45:00Z"},{"price":85.21,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T22:00:00Z"},{"price":83.14,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T22:15:00Z"},{"price":81.22,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T22:30:00Z"},{"price":79.86,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T22:45:00Z"},{"price":83.45,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T23:00:00Z"},{"price":82.96,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T23:15:00Z"},{"price":81.91,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T23:30:00Z"},{"price":80.89,"currency":"EUR","area":"NO1","timestamp":"2026-01-15T23:45:00Z"},{"price":81.62,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T00:00:00Z"},{"price":80.6,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T00:15:00Z"},{"price":79.84,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T00:30:00Z"},{"price":77.88,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T00:45:00Z"},{"price":78.22,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T01:00:00Z"},{"price":77.83,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T01:15:00Z"},{"price":75.03,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T01:30:00Z"},{"price":74.14,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T01:45:00Z"},{"price":72.9,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T02:00:00Z"},{"price":72.47,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T02:15:00Z"},{"price":72.89,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T02:30:00Z"},{"price":73.72,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T02:45:00Z"},{"price":74.65,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T03:00:00Z"},{"price":75.09,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T03:15:00Z"},{"price":77.46,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T03:30:00Z"},{"price":78.48,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T03:45:00Z"},{"price":80.92,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T04:00:00Z"},{"price":82.07,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T04:15:00Z"},{"price":83.29,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T04:30:00Z"},{"price":84.17,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T04:45:00Z"},{"price":83.98,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T05:00:00Z"},{"price":85.58,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T05:15:00Z"},{"price":86.45,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T05:30:00Z"},{"price":87.82,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T05:45:00Z"},{"price":87.25,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T06:00:00Z"},{"price":87.91,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T06:15:00Z"},{"price":88.19,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T06:30:00Z"},{"price":88.69,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T06:45:00Z"},{"price":88.3,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T07:00:00Z"},{"price":88.55,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T07:15:00Z"},{"price":88.88,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T07:30:00Z"},{"price":88.97,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T07:45:00Z"},{"price":88.45,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T08:00:00Z"},{"price":88.83,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T08:15:00Z"},{"price":88.86,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T08:30:00Z"},{"price":89.01,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T08:45:00Z"},{"price":88.37,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T09:00:00Z"},{"price":88.24,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T09:15:00Z"},{"price":88.21,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T09:30:00Z"},{"price":87.97,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T09:45:00Z"},{"price":89.66,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T10:00:00Z"},{"price":89.45,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T10:15:00Z"},{"price":89.48,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T10:30:00Z"},{"price":89.49,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T10:45:00Z"},{"price":88.75,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T11:00:00Z"},{"price":89.62,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T11:15:00Z"},{"price":90.03,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T11:30:00Z"},{"price":90.46,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T11:45:00Z"},{"price":90.12,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T12:00:00Z"},{"price":90.84,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T12:15:00Z"},{"price":92.33,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T12:30:00Z"},{"price":94.23,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T12:45:00Z"},{"price":91.23,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T13:00:00Z"},{"price":93.01,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T13:15:00Z"},{"price":93.14,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T13:30:00Z"},{"price":93.26,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T13:45:00Z"},{"price":92.2,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T14:00:00Z"},{"price":93.38,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T14:15:00Z"},{"price":93.72,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T14:30:00Z"},{"price":93.84,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T14:45:00Z"},{"price":94,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T15:00:00Z"},{"price":95.16,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T15:15:00Z"},{"price":96.72,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T15:30:00Z"},{"price":101.04,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T15:45:00Z"},{"price":96.26,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T16:00:00Z"},{"price":95.19,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T16:15:00Z"},{"price":95.26,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T16:30:00Z"},{"price":95.29,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T16:45:00Z"},{"price":95.16,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T17:00:00Z"},{"price":95,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T17:15:00Z"},{"price":95.31,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T17:30:00Z"},{"price":95.13,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T17:45:00Z"},{"price":95.2,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T18:00:00Z"},{"price":94.93,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T18:15:00Z"},{"price":94.79,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T18:30:00Z"},{"price":94.77,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T18:45:00Z"},{"price":94.72,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T19:00:00Z"},{"price":94.46,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T19:15:00Z"},{"price":94.3,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T19:30:00Z"},{"price":94.21,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T19:45:00Z"},{"price":94,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T20:00:00Z"},{"price":93.94,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T20:15:00Z"},{"price":93.7,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T20:30:00Z"},{"price":93.49,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T20:45:00Z"},{"price":93.77,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T21:00:00Z"},{"price":93.37,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T21:15:00Z"},{"price":93.02,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T21:30:00Z"},{"price":92.7,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T21:45:00Z"},{"price":93.23,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T22:00:00Z"},{"price":92.77,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T22:15:00Z"},{"price":92.08,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T22:30:00Z"},{"price":91.1,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T22:45:00Z"},{"price":94.26,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T23:00:00Z"},{"price":93.55,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T23:15:00Z"},{"price":93.45,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T23:30:00Z"},{"price":91.08,"currency":"EUR","area":"NO1","timestamp":"2026-01-16T23:45:00Z"},{"price":91.02,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T00:00:00Z"},{"price":90.87,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T00:15:00Z"},{"price":90.71,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T00:30:00Z"},{"price":90.6,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T00:45:00Z"},{"price":90.37,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T01:00:00Z"},{"price":90.28,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T01:15:00Z"},{"price":90.22,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T01:30:00Z"},{"price":90.3,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T01:45:00Z"},{"price":91.28,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T02:00:00Z"},{"price":91.79,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T02:15:00Z"},{"price":91.4,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T02:30:00Z"},{"price":91.58,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T02:45:00Z"},{"price":91.51,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T03:00:00Z"},{"price":91.19,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T03:15:00Z"},{"price":91.3,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T03:30:00Z"},{"price":91.46,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T03:45:00Z"},{"price":91.79,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T04:00:00Z"},{"price":90.98,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T04:15:00Z"},{"price":92.16,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T04:30:00Z"},{"price":91.75,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T04:45:00Z"},{"price":91.78,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T05:00:00Z"},{"price":90.08,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T05:15:00Z"},{"price":91.78,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T05:30:00Z"},{"price":91.56,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T05:45:00Z"},{"price":91.3,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T06:00:00Z"},{"price":92.38,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T06:15:00Z"},{"price":94.26,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T06:30:00Z"},{"price":96.68,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T06:45:00Z"},{"price":93.5,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T07:00:00Z"},{"price":97.4,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T07:15:00Z"},{"price":97.65,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T07:30:00Z"},{"price":98.39,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T07:45:00Z"},{"price":99.67,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T08:00:00Z"},{"price":101.82,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T08:15:00Z"},{"price":99.42,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T08:30:00Z"},{"price":97.94,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T08:45:00Z"},{"price":105.19,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T09:00:00Z"},{"price":101.37,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T09:15:00Z"},{"price":98.71,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T09:30:00Z"},{"price":97.29,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T09:45:00Z"},{"price":98.66,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T10:00:00Z"},{"price":98.42,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T10:15:00Z"},{"price":98.17,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T10:30:00Z"},{"price":97.37,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T10:45:00Z"},{"price":98.92,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T11:00:00Z"},{"price":98.03,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T11:15:00Z"},{"price":98.5,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T11:30:00Z"},{"price":98.3,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T11:45:00Z"},{"price":98.26,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T12:00:00Z"},{"price":98.82,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T12:15:00Z"},{"price":98.55,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T12:30:00Z"},{"price":97.99,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T12:45:00Z"},{"price":97.43,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T13:00:00Z"},{"price":97.77,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T13:15:00Z"},{"price":100.74,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T13:30:00Z"},{"price":105.94,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T13:45:00Z"},{"price":100.32,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T14:00:00Z"},{"price":105.32,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T14:15:00Z"},{"price":110.81,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T14:30:00Z"},{"price":113.24,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T14:45:00Z"},{"price":111.59,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T15:00:00Z"},{"price":120.96,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T15:15:00Z"},{"price":122.54,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T15:30:00Z"},{"price":123.82,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T15:45:00Z"},{"price":128.8,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T16:00:00Z"},{"price":126.62,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T16:15:00Z"},{"price":127.73,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T16:30:00Z"},{"price":131.06,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T16:45:00Z"},{"price":123.38,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T17:00:00Z"},{"price":121.69,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T17:15:00Z"},{"price":125.39,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T17:30:00Z"},{"price":124.59,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T17:45:00Z"},{"price":122.52,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T18:00:00Z"},{"price":121.64,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T18:15:00Z"},{"price":120.84,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T18:30:00Z"},{"price":113.53,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T18:45:00Z"},{"price":119.74,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T19:00:00Z"},{"price":106.23,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T19:15:00Z"},{"price":104.52,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T19:30:00Z"},{"price":99.31,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T19:45:00Z"},{"price":104.05,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T20:00:00Z"},{"price":100.21,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T20:15:00Z"},{"price":98.94,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T20:30:00Z"},{"price":96.23,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T20:45:00Z"},{"price":98.37,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T21:00:00Z"},{"price":97.66,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T21:15:00Z"},{"price":98.35,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T21:30:00Z"},{"price":99.81,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T21:45:00Z"},{"price":99.04,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T22:00:00Z"},{"price":98.13,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T22:15:00Z"},{"price":97.85,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T22:30:00Z"},{"price":96,"currency":"EUR","area":"NO1","timestamp":"2026-01-17T22:45:00Z"}];
|
|
9
|
-
|
|
10
|
-
const outdoorTemp = 5; // Example outdoor temperature
|
|
11
|
-
const config = {
|
|
12
|
-
heatLossCoefficient: 0.05,
|
|
13
|
-
minModeDuration: 60,
|
|
14
|
-
minSavingsPercent: 5,
|
|
15
|
-
numPriceGroups: 3,
|
|
16
|
-
outputTimezone: "Europe/Oslo",
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
console.log("═══════════════════════════════════════════════════════════════════");
|
|
20
|
-
console.log("STEP 1: INPUT DATA ANALYSIS");
|
|
21
|
-
console.log("═══════════════════════════════════════════════════════════════════\n");
|
|
22
|
-
|
|
23
|
-
const priceValues = prices.map(p => p.price);
|
|
24
|
-
const n = priceValues.length;
|
|
25
|
-
const avgPrice = priceValues.reduce((a, b) => a + b, 0) / n;
|
|
26
|
-
const minPrice = Math.min(...priceValues);
|
|
27
|
-
const maxPrice = Math.max(...priceValues);
|
|
28
|
-
const priceRange = maxPrice - minPrice;
|
|
29
|
-
const variationPercent = (priceRange / avgPrice) * 100;
|
|
30
|
-
|
|
31
|
-
console.log(`Total intervals: ${n} (${n * 15} minutes = ${(n * 15 / 60).toFixed(1)} hours)`);
|
|
32
|
-
console.log(`Price range: ${minPrice.toFixed(2)} - ${maxPrice.toFixed(2)} EUR/MWh`);
|
|
33
|
-
console.log(`Average price: ${avgPrice.toFixed(2)} EUR/MWh`);
|
|
34
|
-
console.log(`Price variation: ${variationPercent.toFixed(1)}% (range/avg)`);
|
|
35
|
-
console.log(`First timestamp: ${prices[0].timestamp} (UTC)`);
|
|
36
|
-
console.log(`Last timestamp: ${prices[n-1].timestamp} (UTC)`);
|
|
37
|
-
|
|
38
|
-
// Convert to Oslo time to show the actual local times
|
|
39
|
-
const firstOslo = DateTime.fromISO(prices[0].timestamp).setZone("Europe/Oslo");
|
|
40
|
-
const lastOslo = DateTime.fromISO(prices[n-1].timestamp).setZone("Europe/Oslo");
|
|
41
|
-
console.log(`\nIn Oslo time:`);
|
|
42
|
-
console.log(` First: ${firstOslo.toFormat("yyyy-MM-dd HH:mm")} (${firstOslo.toFormat("cccc")})`);
|
|
43
|
-
console.log(` Last: ${lastOslo.toFormat("yyyy-MM-dd HH:mm")} (${lastOslo.toFormat("cccc")})`);
|
|
44
|
-
|
|
45
|
-
console.log("\n═══════════════════════════════════════════════════════════════════");
|
|
46
|
-
console.log("STEP 2: CONFIG VALIDATION");
|
|
47
|
-
console.log("═══════════════════════════════════════════════════════════════════\n");
|
|
48
|
-
|
|
49
|
-
console.log(`Heat loss coefficient: ${config.heatLossCoefficient}`);
|
|
50
|
-
console.log(`Min mode duration: ${config.minModeDuration} minutes`);
|
|
51
|
-
console.log(`Min savings percent: ${config.minSavingsPercent}%`);
|
|
52
|
-
console.log(`Num price groups: ${config.numPriceGroups}`);
|
|
53
|
-
console.log(`Output timezone: ${config.outputTimezone}`);
|
|
54
|
-
console.log(`Outdoor temperature: ${outdoorTemp}°C`);
|
|
55
|
-
|
|
56
|
-
console.log("\n═══════════════════════════════════════════════════════════════════");
|
|
57
|
-
console.log("STEP 3: THERMAL CONSTRAINTS CALCULATION");
|
|
58
|
-
console.log("═══════════════════════════════════════════════════════════════════\n");
|
|
59
|
-
|
|
60
|
-
const comfortNormal = 22;
|
|
61
|
-
const comfortMin = 20;
|
|
62
|
-
const comfortMax = 24;
|
|
63
|
-
const tempDelta = comfortNormal - outdoorTemp;
|
|
64
|
-
const tempBuffer = comfortNormal - comfortMin;
|
|
65
|
-
const heatLossRate = tempDelta * config.heatLossCoefficient;
|
|
66
|
-
const maxCoastHours = tempBuffer / heatLossRate;
|
|
67
|
-
const maxCoastMinutes = maxCoastHours * 60;
|
|
68
|
-
const intervalMinutes = 15;
|
|
69
|
-
const maxCoastIntervals = Math.floor(maxCoastMinutes / intervalMinutes);
|
|
70
|
-
|
|
71
|
-
console.log(`Indoor temp (normal): ${comfortNormal}°C`);
|
|
72
|
-
console.log(`Outdoor temp: ${outdoorTemp}°C`);
|
|
73
|
-
console.log(`Temperature delta: ${tempDelta}°C`);
|
|
74
|
-
console.log(`Temperature buffer (22 - 20): ${tempBuffer}°C`);
|
|
75
|
-
console.log(`Heat loss rate: ${tempDelta} × ${config.heatLossCoefficient} = ${heatLossRate.toFixed(2)}°C/hour`);
|
|
76
|
-
console.log(`Max coast time: ${tempBuffer} / ${heatLossRate.toFixed(2)} = ${maxCoastHours.toFixed(1)} hours (${maxCoastMinutes.toFixed(0)} minutes)`);
|
|
77
|
-
console.log(`Max coast intervals (at 15min each): ${maxCoastIntervals} intervals`);
|
|
78
|
-
|
|
79
|
-
console.log("\n═══════════════════════════════════════════════════════════════════");
|
|
80
|
-
console.log("STEP 4: CKMEANS CLUSTERING");
|
|
81
|
-
console.log("═══════════════════════════════════════════════════════════════════\n");
|
|
82
|
-
|
|
83
|
-
// Calculate effective variation threshold
|
|
84
|
-
const effectiveVariationThreshold = config.minSavingsPercent * 2;
|
|
85
|
-
console.log(`Minimum variation threshold: ${effectiveVariationThreshold}%`);
|
|
86
|
-
console.log(`Actual variation: ${variationPercent.toFixed(1)}%`);
|
|
87
|
-
console.log(`Clustering will activate: ${variationPercent >= effectiveVariationThreshold ? "YES" : "NO"}\n`);
|
|
88
|
-
|
|
89
|
-
const clustering = classifyPricesWithCkmeans(priceValues, effectiveVariationThreshold, config.numPriceGroups);
|
|
90
|
-
|
|
91
|
-
console.log(`Number of clusters: ${clustering.numGroups}`);
|
|
92
|
-
console.log(`Cluster breaks (thresholds):`);
|
|
93
|
-
clustering.breaks.forEach((b, i) => {
|
|
94
|
-
console.log(` Break ${i + 1}: ${b.toFixed(2)} EUR/MWh`);
|
|
95
|
-
});
|
|
96
|
-
console.log(`\nCluster means:`);
|
|
97
|
-
clustering.clusterMeans.forEach((m, i) => {
|
|
98
|
-
const label = i === 0 ? "BOOST (cheapest)" : i === clustering.numGroups - 1 ? "COAST (expensive)" : "NORMAL";
|
|
99
|
-
console.log(` Cluster ${i}: ${m.toFixed(2)} EUR/MWh → ${label}`);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// Count assignments
|
|
103
|
-
const boostCount = clustering.assignments.filter(a => a === 0).length;
|
|
104
|
-
const coastCount = clustering.assignments.filter(a => a === clustering.numGroups - 1).length;
|
|
105
|
-
const normalCount = n - boostCount - coastCount;
|
|
106
|
-
|
|
107
|
-
console.log(`\nRaw clustering results (before thermal constraints):`);
|
|
108
|
-
console.log(` Boost intervals: ${boostCount} (${(boostCount/n*100).toFixed(1)}%)`);
|
|
109
|
-
console.log(` Normal intervals: ${normalCount} (${(normalCount/n*100).toFixed(1)}%)`);
|
|
110
|
-
console.log(` Coast intervals: ${coastCount} (${(coastCount/n*100).toFixed(1)}%)`);
|
|
111
|
-
|
|
112
|
-
console.log("\n═══════════════════════════════════════════════════════════════════");
|
|
113
|
-
console.log("STEP 5: APPLY THERMAL CONSTRAINTS");
|
|
114
|
-
console.log("═══════════════════════════════════════════════════════════════════\n");
|
|
115
|
-
|
|
116
|
-
console.log(`Max coast intervals allowed: ${maxCoastIntervals}`);
|
|
117
|
-
console.log(`Raw coast intervals requested: ${coastCount}`);
|
|
118
|
-
|
|
119
|
-
if (coastCount > maxCoastIntervals) {
|
|
120
|
-
console.log(`\n⚠️ Thermal budget exceeded! Need to reduce coast from ${coastCount} to ${maxCoastIntervals}`);
|
|
121
|
-
console.log(` Will prioritize the ${maxCoastIntervals} most expensive intervals for coasting.`);
|
|
122
|
-
} else {
|
|
123
|
-
console.log(`✓ Thermal budget OK. All ${coastCount} coast intervals can be used.`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
console.log("\n═══════════════════════════════════════════════════════════════════");
|
|
127
|
-
console.log("STEP 6: ENFORCE MINIMUM DURATIONS");
|
|
128
|
-
console.log("═══════════════════════════════════════════════════════════════════\n");
|
|
129
|
-
|
|
130
|
-
const minIntervals = Math.ceil(config.minModeDuration / intervalMinutes);
|
|
131
|
-
console.log(`Min mode duration: ${config.minModeDuration} minutes`);
|
|
132
|
-
console.log(`Interval length: ${intervalMinutes} minutes`);
|
|
133
|
-
console.log(`Min intervals required: ${minIntervals} intervals`);
|
|
134
|
-
console.log(`\nShort runs (< ${minIntervals} intervals) will be converted to "normal" mode.`);
|
|
135
|
-
|
|
136
|
-
console.log("\n═══════════════════════════════════════════════════════════════════");
|
|
137
|
-
console.log("STEP 7: CREATE SCHEDULE WITH TIMEZONE CONVERSION");
|
|
138
|
-
console.log("═══════════════════════════════════════════════════════════════════\n");
|
|
139
|
-
|
|
140
|
-
const schedule = createSchedule(prices, outdoorTemp, config);
|
|
141
|
-
|
|
142
|
-
// Show first few and last few entries
|
|
143
|
-
console.log("Sample schedule entries (first 8 and last 8):\n");
|
|
144
|
-
console.log("Oslo Time | UTC Time | Mode | Price");
|
|
145
|
-
console.log("--------------------|---------------------|--------|--------");
|
|
146
|
-
|
|
147
|
-
const showEntries = [...schedule.slice(0, 8), "...", ...schedule.slice(-8)];
|
|
148
|
-
showEntries.forEach(entry => {
|
|
149
|
-
if (entry === "...") {
|
|
150
|
-
console.log("... (middle entries omitted) ...");
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
const osloTime = entry.time.substring(0, 19);
|
|
154
|
-
const utcTime = entry.timeUtc.substring(0, 19);
|
|
155
|
-
console.log(`${osloTime} | ${utcTime}Z | ${entry.mode.padEnd(6)} | ${entry.price.toFixed(2)}`);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
console.log("\n═══════════════════════════════════════════════════════════════════");
|
|
159
|
-
console.log("STEP 8: FINAL RESULTS");
|
|
160
|
-
console.log("═══════════════════════════════════════════════════════════════════\n");
|
|
161
|
-
|
|
162
|
-
const finalBoost = schedule.filter(s => s.mode === "boost").length;
|
|
163
|
-
const finalNormal = schedule.filter(s => s.mode === "normal").length;
|
|
164
|
-
const finalCoast = schedule.filter(s => s.mode === "coast").length;
|
|
165
|
-
|
|
166
|
-
console.log("Final mode distribution:");
|
|
167
|
-
console.log(` Boost: ${finalBoost} intervals (${(finalBoost/n*100).toFixed(1)}%) - ${(finalBoost * 15 / 60).toFixed(1)} hours`);
|
|
168
|
-
console.log(` Normal: ${finalNormal} intervals (${(finalNormal/n*100).toFixed(1)}%) - ${(finalNormal * 15 / 60).toFixed(1)} hours`);
|
|
169
|
-
console.log(` Coast: ${finalCoast} intervals (${(finalCoast/n*100).toFixed(1)}%) - ${(finalCoast * 15 / 60).toFixed(1)} hours`);
|
|
170
|
-
|
|
171
|
-
// Show tuning info
|
|
172
|
-
if (schedule[0].tuning) {
|
|
173
|
-
const t = schedule[0].tuning;
|
|
174
|
-
console.log("\nTuning info from schedule:");
|
|
175
|
-
console.log(` Cheap threshold: < ${t.clustering.cheapThreshold.toFixed(2)} EUR/MWh → BOOST`);
|
|
176
|
-
console.log(` Expensive threshold: > ${t.clustering.expensiveThreshold.toFixed(2)} EUR/MWh → COAST`);
|
|
177
|
-
console.log(` Raw boost count: ${t.clustering.rawBoostCount}`);
|
|
178
|
-
console.log(` Raw coast count: ${t.clustering.rawCoastCount}`);
|
|
179
|
-
console.log(` Final boost count: ${t.finalModeCount.boost}`);
|
|
180
|
-
console.log(` Final coast count: ${t.finalModeCount.coast}`);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
console.log("\n═══════════════════════════════════════════════════════════════════");
|
|
184
|
-
console.log("VISUAL TIMELINE (Oslo time)");
|
|
185
|
-
console.log("═══════════════════════════════════════════════════════════════════\n");
|
|
186
|
-
|
|
187
|
-
// Group by hour
|
|
188
|
-
const hourlyModes = {};
|
|
189
|
-
schedule.forEach(entry => {
|
|
190
|
-
const hour = DateTime.fromISO(entry.time).toFormat("MM-dd HH");
|
|
191
|
-
if (!hourlyModes[hour]) {
|
|
192
|
-
hourlyModes[hour] = { boost: 0, normal: 0, coast: 0 };
|
|
193
|
-
}
|
|
194
|
-
hourlyModes[hour][entry.mode]++;
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
console.log("Date Hour | B N C | Visual");
|
|
198
|
-
console.log("-----------|-------|----------------------------------------");
|
|
199
|
-
|
|
200
|
-
Object.keys(hourlyModes).sort().forEach(hour => {
|
|
201
|
-
const m = hourlyModes[hour];
|
|
202
|
-
const total = m.boost + m.normal + m.coast;
|
|
203
|
-
|
|
204
|
-
// Create visual bar
|
|
205
|
-
let bar = "";
|
|
206
|
-
bar += "🟢".repeat(m.boost);
|
|
207
|
-
bar += "⚪".repeat(m.normal);
|
|
208
|
-
bar += "🔴".repeat(m.coast);
|
|
209
|
-
|
|
210
|
-
console.log(`${hour}:00 | ${m.boost} ${m.normal} ${m.coast} | ${bar}`);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
console.log("\nLegend: 🟢 = Boost (ON) ⚪ = Normal 🔴 = Coast (OFF)");
|
package/test-temp-scaling.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test: Temperature scaling of minSavingsPercent
|
|
3
|
-
*
|
|
4
|
-
* Below 10°C, the minSavingsPercent increases to make the algorithm
|
|
5
|
-
* more conservative (require bigger price gaps before coasting).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { createSchedule } = require('./src/strategy-smart-thermal-functions.js');
|
|
9
|
-
|
|
10
|
-
const prices = [
|
|
11
|
-
{ timestamp: '2026-01-17T00:00:00Z', price: 90 },
|
|
12
|
-
{ timestamp: '2026-01-17T01:00:00Z', price: 90 },
|
|
13
|
-
{ timestamp: '2026-01-17T02:00:00Z', price: 90 },
|
|
14
|
-
{ timestamp: '2026-01-17T03:00:00Z', price: 90 },
|
|
15
|
-
{ timestamp: '2026-01-17T04:00:00Z', price: 90 },
|
|
16
|
-
{ timestamp: '2026-01-17T05:00:00Z', price: 90 },
|
|
17
|
-
{ timestamp: '2026-01-17T06:00:00Z', price: 95 },
|
|
18
|
-
{ timestamp: '2026-01-17T07:00:00Z', price: 100 },
|
|
19
|
-
{ timestamp: '2026-01-17T08:00:00Z', price: 110 },
|
|
20
|
-
{ timestamp: '2026-01-17T09:00:00Z', price: 120 },
|
|
21
|
-
{ timestamp: '2026-01-17T10:00:00Z', price: 130 },
|
|
22
|
-
{ timestamp: '2026-01-17T11:00:00Z', price: 125 },
|
|
23
|
-
{ timestamp: '2026-01-17T12:00:00Z', price: 115 },
|
|
24
|
-
{ timestamp: '2026-01-17T13:00:00Z', price: 105 },
|
|
25
|
-
{ timestamp: '2026-01-17T14:00:00Z', price: 100 },
|
|
26
|
-
{ timestamp: '2026-01-17T15:00:00Z', price: 95 },
|
|
27
|
-
{ timestamp: '2026-01-17T16:00:00Z', price: 100 },
|
|
28
|
-
{ timestamp: '2026-01-17T17:00:00Z', price: 120 },
|
|
29
|
-
{ timestamp: '2026-01-17T18:00:00Z', price: 130 },
|
|
30
|
-
{ timestamp: '2026-01-17T19:00:00Z', price: 125 },
|
|
31
|
-
{ timestamp: '2026-01-17T20:00:00Z', price: 110 },
|
|
32
|
-
{ timestamp: '2026-01-17T21:00:00Z', price: 100 },
|
|
33
|
-
{ timestamp: '2026-01-17T22:00:00Z', price: 95 },
|
|
34
|
-
{ timestamp: '2026-01-17T23:00:00Z', price: 90 },
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
const config = { minSavingsPercent: 8, numPriceGroups: 3 };
|
|
38
|
-
|
|
39
|
-
console.log('=== TEMPERATURE SCALING OF minSavingsPercent ===\n');
|
|
40
|
-
console.log('Base minSavingsPercent: 8%\n');
|
|
41
|
-
console.log('Temp | Base % | Effective % | Coast Hours');
|
|
42
|
-
console.log('-'.repeat(50));
|
|
43
|
-
|
|
44
|
-
for (const temp of [15, 10, 5, 0, -5, -10, -15, -20]) {
|
|
45
|
-
const schedule = createSchedule(prices, temp, config);
|
|
46
|
-
const tuning = schedule[0]?.tuning;
|
|
47
|
-
const basePct = tuning?.minSavingsPercent;
|
|
48
|
-
const effectivePct = tuning?.effectiveMinSavingsPercent?.toFixed(1);
|
|
49
|
-
const coastCount = schedule.filter(s => s.mode === 'coast').length;
|
|
50
|
-
const marker = temp < 10 ? ' (scaled)' : '';
|
|
51
|
-
console.log(
|
|
52
|
-
`${temp.toString().padStart(3)}°C | ${basePct.toString().padStart(4)}% | ` +
|
|
53
|
-
`${effectivePct.padStart(8)}% | ${coastCount} hrs${marker}`
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
console.log('\n=== EXPLANATION ===');
|
|
58
|
-
console.log('At 10°C and above: uses configured value (8%)');
|
|
59
|
-
console.log('Below 10°C: scales linearly up to 1.5× at extreme cold (-15°C)');
|
|
60
|
-
console.log('At -15°C: 8% × 1.5 = 12%');
|
|
61
|
-
console.log('\nThis makes the algorithm more conservative when cold,');
|
|
62
|
-
console.log('requiring larger price differences to justify coasting.');
|
package/test-thermal-budget.js
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test: Thermal budget varies with outdoor temperature
|
|
3
|
-
*
|
|
4
|
-
* Colder weather = less coast time allowed, more boost needed
|
|
5
|
-
* Warmer weather = more coast time allowed
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { createSchedule } = require('./src/strategy-smart-thermal-functions.js');
|
|
9
|
-
|
|
10
|
-
// Use 15-minute interval prices (matching your actual Tibber data)
|
|
11
|
-
const prices = [
|
|
12
|
-
{ timestamp: "2026-01-17T00:00:00Z", price: 91.02 },
|
|
13
|
-
{ timestamp: "2026-01-17T00:15:00Z", price: 90.87 },
|
|
14
|
-
{ timestamp: "2026-01-17T00:30:00Z", price: 90.71 },
|
|
15
|
-
{ timestamp: "2026-01-17T00:45:00Z", price: 90.60 },
|
|
16
|
-
{ timestamp: "2026-01-17T01:00:00Z", price: 90.37 },
|
|
17
|
-
{ timestamp: "2026-01-17T01:15:00Z", price: 90.28 },
|
|
18
|
-
{ timestamp: "2026-01-17T01:30:00Z", price: 90.22 },
|
|
19
|
-
{ timestamp: "2026-01-17T01:45:00Z", price: 90.30 },
|
|
20
|
-
{ timestamp: "2026-01-17T02:00:00Z", price: 91.28 },
|
|
21
|
-
{ timestamp: "2026-01-17T02:15:00Z", price: 91.79 },
|
|
22
|
-
{ timestamp: "2026-01-17T02:30:00Z", price: 91.40 },
|
|
23
|
-
{ timestamp: "2026-01-17T02:45:00Z", price: 91.58 },
|
|
24
|
-
{ timestamp: "2026-01-17T03:00:00Z", price: 91.51 },
|
|
25
|
-
{ timestamp: "2026-01-17T03:15:00Z", price: 91.19 },
|
|
26
|
-
{ timestamp: "2026-01-17T03:30:00Z", price: 91.30 },
|
|
27
|
-
{ timestamp: "2026-01-17T03:45:00Z", price: 91.46 },
|
|
28
|
-
{ timestamp: "2026-01-17T04:00:00Z", price: 91.79 },
|
|
29
|
-
{ timestamp: "2026-01-17T04:15:00Z", price: 90.98 },
|
|
30
|
-
{ timestamp: "2026-01-17T04:30:00Z", price: 92.16 },
|
|
31
|
-
{ timestamp: "2026-01-17T04:45:00Z", price: 91.75 },
|
|
32
|
-
{ timestamp: "2026-01-17T05:00:00Z", price: 91.78 },
|
|
33
|
-
{ timestamp: "2026-01-17T05:15:00Z", price: 90.08 },
|
|
34
|
-
{ timestamp: "2026-01-17T05:30:00Z", price: 91.78 },
|
|
35
|
-
{ timestamp: "2026-01-17T05:45:00Z", price: 91.56 },
|
|
36
|
-
{ timestamp: "2026-01-17T06:00:00Z", price: 91.30 },
|
|
37
|
-
{ timestamp: "2026-01-17T06:15:00Z", price: 92.38 },
|
|
38
|
-
{ timestamp: "2026-01-17T06:30:00Z", price: 94.26 },
|
|
39
|
-
{ timestamp: "2026-01-17T06:45:00Z", price: 96.68 },
|
|
40
|
-
{ timestamp: "2026-01-17T07:00:00Z", price: 93.50 },
|
|
41
|
-
{ timestamp: "2026-01-17T07:15:00Z", price: 97.40 },
|
|
42
|
-
{ timestamp: "2026-01-17T07:30:00Z", price: 97.65 },
|
|
43
|
-
{ timestamp: "2026-01-17T07:45:00Z", price: 98.39 },
|
|
44
|
-
{ timestamp: "2026-01-17T08:00:00Z", price: 99.67 },
|
|
45
|
-
{ timestamp: "2026-01-17T08:15:00Z", price: 101.82 },
|
|
46
|
-
{ timestamp: "2026-01-17T08:30:00Z", price: 99.42 },
|
|
47
|
-
{ timestamp: "2026-01-17T08:45:00Z", price: 97.94 },
|
|
48
|
-
{ timestamp: "2026-01-17T09:00:00Z", price: 105.19 },
|
|
49
|
-
{ timestamp: "2026-01-17T09:15:00Z", price: 101.37 },
|
|
50
|
-
{ timestamp: "2026-01-17T09:30:00Z", price: 98.71 },
|
|
51
|
-
{ timestamp: "2026-01-17T09:45:00Z", price: 97.29 },
|
|
52
|
-
{ timestamp: "2026-01-17T10:00:00Z", price: 98.66 },
|
|
53
|
-
{ timestamp: "2026-01-17T10:15:00Z", price: 98.42 },
|
|
54
|
-
{ timestamp: "2026-01-17T10:30:00Z", price: 98.17 },
|
|
55
|
-
{ timestamp: "2026-01-17T10:45:00Z", price: 97.37 },
|
|
56
|
-
{ timestamp: "2026-01-17T11:00:00Z", price: 98.92 },
|
|
57
|
-
{ timestamp: "2026-01-17T11:15:00Z", price: 98.03 },
|
|
58
|
-
{ timestamp: "2026-01-17T11:30:00Z", price: 98.50 },
|
|
59
|
-
{ timestamp: "2026-01-17T11:45:00Z", price: 98.30 },
|
|
60
|
-
{ timestamp: "2026-01-17T12:00:00Z", price: 98.26 },
|
|
61
|
-
{ timestamp: "2026-01-17T12:15:00Z", price: 98.82 },
|
|
62
|
-
{ timestamp: "2026-01-17T12:30:00Z", price: 98.55 },
|
|
63
|
-
{ timestamp: "2026-01-17T12:45:00Z", price: 97.99 },
|
|
64
|
-
{ timestamp: "2026-01-17T13:00:00Z", price: 97.43 },
|
|
65
|
-
{ timestamp: "2026-01-17T13:15:00Z", price: 97.77 },
|
|
66
|
-
{ timestamp: "2026-01-17T13:30:00Z", price: 100.74 },
|
|
67
|
-
{ timestamp: "2026-01-17T13:45:00Z", price: 105.94 },
|
|
68
|
-
{ timestamp: "2026-01-17T14:00:00Z", price: 100.32 },
|
|
69
|
-
{ timestamp: "2026-01-17T14:15:00Z", price: 105.32 },
|
|
70
|
-
{ timestamp: "2026-01-17T14:30:00Z", price: 110.81 },
|
|
71
|
-
{ timestamp: "2026-01-17T14:45:00Z", price: 113.24 },
|
|
72
|
-
{ timestamp: "2026-01-17T15:00:00Z", price: 111.59 },
|
|
73
|
-
{ timestamp: "2026-01-17T15:15:00Z", price: 120.96 },
|
|
74
|
-
{ timestamp: "2026-01-17T15:30:00Z", price: 122.54 },
|
|
75
|
-
{ timestamp: "2026-01-17T15:45:00Z", price: 123.82 },
|
|
76
|
-
{ timestamp: "2026-01-17T16:00:00Z", price: 128.80 }, // Peak
|
|
77
|
-
{ timestamp: "2026-01-17T16:15:00Z", price: 126.62 },
|
|
78
|
-
{ timestamp: "2026-01-17T16:30:00Z", price: 127.73 },
|
|
79
|
-
{ timestamp: "2026-01-17T16:45:00Z", price: 131.06 },
|
|
80
|
-
{ timestamp: "2026-01-17T17:00:00Z", price: 123.38 },
|
|
81
|
-
{ timestamp: "2026-01-17T17:15:00Z", price: 121.69 },
|
|
82
|
-
{ timestamp: "2026-01-17T17:30:00Z", price: 125.39 },
|
|
83
|
-
{ timestamp: "2026-01-17T17:45:00Z", price: 124.59 },
|
|
84
|
-
{ timestamp: "2026-01-17T18:00:00Z", price: 122.52 },
|
|
85
|
-
{ timestamp: "2026-01-17T18:15:00Z", price: 121.64 },
|
|
86
|
-
{ timestamp: "2026-01-17T18:30:00Z", price: 120.84 },
|
|
87
|
-
{ timestamp: "2026-01-17T18:45:00Z", price: 113.53 },
|
|
88
|
-
{ timestamp: "2026-01-17T19:00:00Z", price: 119.74 },
|
|
89
|
-
{ timestamp: "2026-01-17T19:15:00Z", price: 106.23 },
|
|
90
|
-
{ timestamp: "2026-01-17T19:30:00Z", price: 104.52 },
|
|
91
|
-
{ timestamp: "2026-01-17T19:45:00Z", price: 99.31 },
|
|
92
|
-
{ timestamp: "2026-01-17T20:00:00Z", price: 104.05 },
|
|
93
|
-
{ timestamp: "2026-01-17T20:15:00Z", price: 100.21 },
|
|
94
|
-
{ timestamp: "2026-01-17T20:30:00Z", price: 98.94 },
|
|
95
|
-
{ timestamp: "2026-01-17T20:45:00Z", price: 96.23 },
|
|
96
|
-
{ timestamp: "2026-01-17T21:00:00Z", price: 98.37 },
|
|
97
|
-
{ timestamp: "2026-01-17T21:15:00Z", price: 97.66 },
|
|
98
|
-
{ timestamp: "2026-01-17T21:30:00Z", price: 98.35 },
|
|
99
|
-
{ timestamp: "2026-01-17T21:45:00Z", price: 99.81 },
|
|
100
|
-
{ timestamp: "2026-01-17T22:00:00Z", price: 99.04 },
|
|
101
|
-
{ timestamp: "2026-01-17T22:15:00Z", price: 98.13 },
|
|
102
|
-
{ timestamp: "2026-01-17T22:30:00Z", price: 97.85 },
|
|
103
|
-
{ timestamp: "2026-01-17T22:45:00Z", price: 96.00 },
|
|
104
|
-
];
|
|
105
|
-
|
|
106
|
-
const config = {
|
|
107
|
-
heatLossCoefficient: 0.05,
|
|
108
|
-
minModeDuration: 60,
|
|
109
|
-
minSavingsPercent: 5,
|
|
110
|
-
numPriceGroups: 3,
|
|
111
|
-
outputTimezone: "Europe/Oslo",
|
|
112
|
-
extremeWeatherThreshold: -15,
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
console.log("=== THERMAL BUDGET VS OUTDOOR TEMPERATURE ===\n");
|
|
116
|
-
console.log("Testing how coast/boost budgets change with temperature\n");
|
|
117
|
-
|
|
118
|
-
const temperatures = [10, 5, 0, -5, -10, -15, -20];
|
|
119
|
-
|
|
120
|
-
console.log("Temp(°C) | Max Coast | Max Boost | Coast Intervals | Boost Intervals");
|
|
121
|
-
console.log("-".repeat(70));
|
|
122
|
-
|
|
123
|
-
for (const temp of temperatures) {
|
|
124
|
-
const schedule = createSchedule(prices, temp, config);
|
|
125
|
-
const tuning = schedule[0]?.tuning;
|
|
126
|
-
|
|
127
|
-
const coastCount = schedule.filter(s => s.mode === "coast").length;
|
|
128
|
-
const boostCount = schedule.filter(s => s.mode === "boost").length;
|
|
129
|
-
|
|
130
|
-
const maxCoast = tuning?.maxCoastIntervals ?? "N/A";
|
|
131
|
-
const maxBoostLookahead = tuning?.maxBoostLookahead ?? "N/A";
|
|
132
|
-
const isExtreme = tuning?.isExtremeWeather ? " (EXTREME)" : "";
|
|
133
|
-
|
|
134
|
-
console.log(
|
|
135
|
-
`${temp.toString().padStart(4)}°C | ` +
|
|
136
|
-
`${maxCoast.toString().padStart(5)} int | ` +
|
|
137
|
-
`${maxBoostLookahead.toString().padStart(5)} int | ` +
|
|
138
|
-
`${coastCount.toString().padStart(7)} actual | ` +
|
|
139
|
-
`${boostCount.toString().padStart(7)} actual${isExtreme}`
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
console.log("\n=== DETAILED COMPARISON: 5°C vs -10°C ===\n");
|
|
144
|
-
|
|
145
|
-
// 5°C - mild weather
|
|
146
|
-
const schedule5 = createSchedule(prices, 5, config);
|
|
147
|
-
const tuning5 = schedule5[0]?.tuning;
|
|
148
|
-
console.log("At 5°C (mild):");
|
|
149
|
-
console.log(` Max coast time: ${tuning5.maxCoastMinutes?.toFixed(0)} min (${tuning5.maxCoastIntervals} intervals)`);
|
|
150
|
-
console.log(` Max boost retention: ${tuning5.maxBoostRetention?.toFixed(0)} min`);
|
|
151
|
-
console.log(` Actual coast: ${schedule5.filter(s => s.mode === "coast").length} intervals`);
|
|
152
|
-
console.log(` Actual boost: ${schedule5.filter(s => s.mode === "boost").length} intervals`);
|
|
153
|
-
|
|
154
|
-
// -10°C - cold weather
|
|
155
|
-
const scheduleM10 = createSchedule(prices, -10, config);
|
|
156
|
-
const tuningM10 = scheduleM10[0]?.tuning;
|
|
157
|
-
console.log("\nAt -10°C (cold):");
|
|
158
|
-
console.log(` Max coast time: ${tuningM10.maxCoastMinutes?.toFixed(0)} min (${tuningM10.maxCoastIntervals} intervals)`);
|
|
159
|
-
console.log(` Max boost retention: ${tuningM10.maxBoostRetention?.toFixed(0)} min`);
|
|
160
|
-
console.log(` Actual coast: ${scheduleM10.filter(s => s.mode === "coast").length} intervals`);
|
|
161
|
-
console.log(` Actual boost: ${scheduleM10.filter(s => s.mode === "boost").length} intervals`);
|
|
162
|
-
|
|
163
|
-
// -20°C - extreme cold (below threshold)
|
|
164
|
-
const scheduleM20 = createSchedule(prices, -20, config);
|
|
165
|
-
const tuningM20 = scheduleM20[0]?.tuning;
|
|
166
|
-
console.log("\nAt -20°C (extreme - below -15°C threshold):");
|
|
167
|
-
console.log(` isExtremeWeather: ${tuningM20.isExtremeWeather}`);
|
|
168
|
-
console.log(` Actual coast: ${scheduleM20.filter(s => s.mode === "coast").length} intervals (disabled!)`);
|
|
169
|
-
console.log(` Actual boost: ${scheduleM20.filter(s => s.mode === "boost").length} intervals`);
|
|
170
|
-
|
|
171
|
-
console.log("\n=== CONCLUSION ===");
|
|
172
|
-
console.log("✓ Colder weather = shorter max coast time (house cools faster)");
|
|
173
|
-
console.log("✓ Colder weather = longer boost retention (heat loss faster)");
|
|
174
|
-
console.log("✓ Below extreme threshold (-15°C) = coasting disabled entirely");
|
package/test-timezone.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test timezone handling for Smart Thermal Strategy
|
|
3
|
-
*
|
|
4
|
-
* This script verifies that the algorithm works correctly regardless of
|
|
5
|
-
* whether the host machine runs in UTC or local time.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { DateTime } = require("luxon");
|
|
9
|
-
const { createSchedule, getCurrentMode } = require('./src/strategy-smart-thermal-functions.js');
|
|
10
|
-
|
|
11
|
-
console.log("=== TIMEZONE HANDLING TEST ===\n");
|
|
12
|
-
|
|
13
|
-
// Simulate price data in UTC (as it comes from most APIs)
|
|
14
|
-
const prices = [
|
|
15
|
-
{ timestamp: "2026-01-16T00:00:00Z", price: 72 }, // 01:00 Oslo time (UTC+1)
|
|
16
|
-
{ timestamp: "2026-01-16T01:00:00Z", price: 70 }, // 02:00 Oslo time - CHEAP
|
|
17
|
-
{ timestamp: "2026-01-16T02:00:00Z", price: 68 }, // 03:00 Oslo time - CHEAP
|
|
18
|
-
{ timestamp: "2026-01-16T03:00:00Z", price: 75 }, // 04:00 Oslo time
|
|
19
|
-
{ timestamp: "2026-01-16T04:00:00Z", price: 82 }, // 05:00 Oslo time
|
|
20
|
-
{ timestamp: "2026-01-16T05:00:00Z", price: 88 }, // 06:00 Oslo time
|
|
21
|
-
{ timestamp: "2026-01-16T06:00:00Z", price: 95 }, // 07:00 Oslo time - EXPENSIVE
|
|
22
|
-
{ timestamp: "2026-01-16T07:00:00Z", price: 98 }, // 08:00 Oslo time - EXPENSIVE
|
|
23
|
-
{ timestamp: "2026-01-16T08:00:00Z", price: 92 }, // 09:00 Oslo time
|
|
24
|
-
{ timestamp: "2026-01-16T09:00:00Z", price: 85 }, // 10:00 Oslo time
|
|
25
|
-
{ timestamp: "2026-01-16T10:00:00Z", price: 80 }, // 11:00 Oslo time
|
|
26
|
-
{ timestamp: "2026-01-16T11:00:00Z", price: 78 }, // 12:00 Oslo time
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
const config = {
|
|
30
|
-
heatLossCoefficient: 0.05,
|
|
31
|
-
minModeDuration: 60,
|
|
32
|
-
outputTimezone: "Europe/Oslo",
|
|
33
|
-
minSavingsPercent: 5,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const schedule = createSchedule(prices, 5, config);
|
|
37
|
-
|
|
38
|
-
console.log("Schedule entries (time = Oslo, timeUtc = UTC):\n");
|
|
39
|
-
console.log("Oslo Time | UTC Time | Mode | Price");
|
|
40
|
-
console.log("--------------------|---------------------|--------|------");
|
|
41
|
-
schedule.forEach(entry => {
|
|
42
|
-
const osloTime = entry.time.substring(0, 19);
|
|
43
|
-
const utcTime = entry.timeUtc.substring(0, 19);
|
|
44
|
-
console.log(`${osloTime} | ${utcTime}Z | ${entry.mode.padEnd(6)} | ${entry.price}`);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
console.log("\n=== getCurrentMode() TIMEZONE TEST ===\n");
|
|
48
|
-
|
|
49
|
-
// Test 1: Pass UTC time (simulating machine running in UTC)
|
|
50
|
-
const utcNow = DateTime.fromISO("2026-01-16T07:30:00Z"); // 08:30 Oslo
|
|
51
|
-
const modeFromUtc = getCurrentMode(schedule, utcNow);
|
|
52
|
-
console.log(`Test 1: UTC time "2026-01-16T07:30:00Z" (= 08:30 Oslo)`);
|
|
53
|
-
console.log(` Mode: ${modeFromUtc}`);
|
|
54
|
-
console.log(` Expected: Should match 08:00 Oslo entry\n`);
|
|
55
|
-
|
|
56
|
-
// Test 2: Pass Oslo time with offset (full ISO)
|
|
57
|
-
const osloNow = DateTime.fromISO("2026-01-16T08:30:00+01:00");
|
|
58
|
-
const modeFromOslo = getCurrentMode(schedule, osloNow);
|
|
59
|
-
console.log(`Test 2: Oslo time "2026-01-16T08:30:00+01:00"`);
|
|
60
|
-
console.log(` Mode: ${modeFromOslo}`);
|
|
61
|
-
console.log(` Expected: Same as Test 1\n`);
|
|
62
|
-
|
|
63
|
-
// Test 3: Pass Oslo time without offset (string)
|
|
64
|
-
// This is the tricky case - should be interpreted as Oslo time
|
|
65
|
-
const osloNoOffset = "2026-01-16T08:30:00";
|
|
66
|
-
const modeFromOsloString = getCurrentMode(schedule, osloNoOffset);
|
|
67
|
-
console.log(`Test 3: Oslo time string "2026-01-16T08:30:00" (no offset)`);
|
|
68
|
-
console.log(` Mode: ${modeFromOsloString}`);
|
|
69
|
-
console.log(` Note: String without offset - getCurrentMode converts via fromISO`);
|
|
70
|
-
|
|
71
|
-
// Test 4: Verify UTC vs Oslo time consistency
|
|
72
|
-
console.log("\n=== VERIFICATION ===\n");
|
|
73
|
-
const testTime = "2026-01-16T02:30:00Z"; // 03:30 Oslo - should be in cheap period
|
|
74
|
-
const mode = getCurrentMode(schedule, DateTime.fromISO(testTime));
|
|
75
|
-
console.log(`At ${testTime} (03:30 Oslo), mode = ${mode}`);
|
|
76
|
-
console.log(`Expected: boost (cheap period at 02:00-03:00 UTC = 03:00-04:00 Oslo)`);
|
|
77
|
-
|
|
78
|
-
// Summary
|
|
79
|
-
console.log("\n=== SUMMARY ===\n");
|
|
80
|
-
console.log("✓ Schedule stores both 'time' (Oslo) and 'timeUtc' (UTC)");
|
|
81
|
-
console.log("✓ getCurrentMode() compares using UTC internally");
|
|
82
|
-
console.log("✓ Works correctly whether machine runs in UTC or local time");
|
|
83
|
-
console.log("✓ Display times (status, logs) use configured timezone (Oslo)");
|