Skip to content

Commit de397f4

Browse files
authored
2025.10.0 (#389)
Fix error with storing forecast (there was no timezone-correction) Fixed several other errors
1 parent d386a8d commit de397f4

File tree

8 files changed

+70
-33
lines changed

8 files changed

+70
-33
lines changed

dao/CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,35 @@
11
# Changelog 刀 DAO
22
# Day Ahead Optimizer
33

4+
# 2025.10.0
5+
This version is similar with 2025.10.0.rc1 in the testing-channel
6+
- Fix error with storing forecast (there was no timezone-correction)
7+
- Maximised the calculationtime to 20 sec, the accuracy to 0.005 euro (whichever comes first)
8+
- Fixed format-error when loglevel=debug
9+
- Set max of y-as for soc to 102%: when soc=100% the line is visible
10+
- Extra information in the logging (level info) for control of the calculation of the profit
11+
- Fixed error calculation/presentation "time needed" charging an ev
12+
- Fixed error with postgresql da-database
13+
- Added logging of free/used memory in logging on level "debug"
14+
15+
Know issue:
16+
- The forecast-calculation in the reports is nog good working
17+
18+
19+
**Interval**<br>
20+
This release supports two intervals: **1hour** and **15min**
21+
You make your choice in the settings, put in your settings somewhere in the root the setting:<br>
22+
"interval": "1hour" or "interval": "15min", 1hour will be default when you make no intervalsetting
23+
24+
**source prices**<br>
25+
At the moment only Nordpool, Tibber and Entsoe (the last one could not be tested) supports 15min prices.<br>
26+
If you don't want trouble: make nordpool your price-source.
27+
28+
**boiler**<br>
29+
The boiler part is completely redesigned and (in my opinion) become better.
30+
The (thermal and financial) value of the boiler at the beginning and the end of the calculationperiod si taken into account.
31+
For every interval the electricity consumption for reheating is calculated and thee best fitting will be choosen in the algortime.
32+
433
# 2025.9.0
534
Fix error api prognose pv_dc
635

dao/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: 刀 Day Ahead Optimizer
3-
version: 2025.9.0
3+
version: 2025.10.0
44
slug: day_ahead_opt
55
description: Home Assistant Community Add-ons for day ahead optimizations
66
url: https://github.com/corneel27/day-ahead

dao/prog/da_base.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import fnmatch
55
import time
6+
import pytz
67
from requests import get
78
import json
89
import hassapi as hass
@@ -113,11 +114,13 @@ def __init__(self, file_name: str = None):
113114
self.config.set("latitude", resp_dict["latitude"])
114115
self.config.set("longitude", resp_dict["longitude"])
115116
self.config.set("time_zone", resp_dict["time_zone"])
117+
self.time_zone = resp_dict["time_zone"]
116118
self.config.set("country", resp_dict["country"])
117119
self.db_da = self.config.get_db_da()
118120
self.db_ha = self.config.get_db_ha()
119121
self.meteo = Meteo(self.config, self.db_da)
120122
self.solar = self.config.get(["solar"])
123+
self.interval = self.config.get(["interval"], None, "1hour").lower()
121124

122125
self.prices = DaPrices(self.config, self.db_da)
123126
self.prices_options = self.config.get(["prices"])
@@ -231,7 +234,7 @@ def generate_tasks():
231234
"calc_optimum": {
232235
"name": "Optimaliseringsberekening zonder debug",
233236
"cmd": ["python3", "../prog/day_ahead.py", "calc"],
234-
"object": "DaCalc",
237+
"object": "DaBase",
235238
"function": "calc_optimum",
236239
"file_name": "calc",
237240
},
@@ -341,8 +344,11 @@ def save_df(self, tablename: str, tijd: list, df: pd.DataFrame):
341344
df_db = pd.DataFrame(columns=["time", "code", "value"])
342345
df = df.reset_index(drop=True)
343346
columns = df.columns.values.tolist()[1:]
347+
tz = pytz.timezone(self.time_zone)
344348
for index in range(len(tijd)):
345-
utc = int(tijd[index].timestamp())
349+
dt = pd.to_datetime(tijd[index])
350+
dt = tz.localize(dt)
351+
utc = int(dt.timestamp())
346352
for c in columns:
347353
db_row = [str(utc), c, float(df.loc[index, c])]
348354
df_db.loc[df_db.shape[0]] = db_row
@@ -513,7 +519,7 @@ def calc_optimum_met_debug(self):
513519
# dacalc = DaCalc("../data/tst_options/options_mirabis.json")
514520
dacalc.debug = True
515521
dacalc.calc_optimum()
516-
# dacalc.calc_optimum(_start_dt=datetime.datetime(2025, 9, 16, 10, minute=45), _start_soc=98)
522+
# dacalc.calc_optimum(_start_dt=datetime.datetime(2025, 9, 28, 21, minute=0), _start_soc=50)
517523

518524
def calc_optimum(self):
519525
from day_ahead import DaCalc

dao/prog/da_report.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,9 +1967,6 @@ def get_grid_data(
19671967
df_prices = pd.read_sql_query(query, connection)
19681968
logging.debug(f"Prijzen \n{df_prices.to_string()}\n")
19691969
"""
1970-
df_prices = self.get_price_data(
1971-
last_moment, tot
1972-
) # +datetime.timedelta(hours=1))
19731970

19741971
df_ha = pd.DataFrame()
19751972
if source == "all" or source == "ha":
@@ -2008,6 +2005,7 @@ def get_grid_data(
20082005
df_ha["datasoort"] = "recorded"
20092006
else:
20102007
last_moment = vanaf
2008+
df_prices = self.get_price_data(vanaf, last_moment, interval="1hour")
20112009

20122010
if source == "all" or source == "da":
20132011
if last_moment < tot:
@@ -2051,10 +2049,15 @@ def get_grid_data(
20512049
df_prog.index = pd.to_datetime(df_prog["tijd"])
20522050
df_prog["datasoort"] = "expected"
20532051
if len(df_prog) > 0:
2052+
df_prog_prices = self.get_price_data(last_moment, tot, interval=self.interval)
20542053
if len(df_ha) == 0:
20552054
df_ha = df_prog
2055+
df_prices = df_prog_prices
20562056
else:
20572057
df_ha = pd.concat([df_ha, df_prog])
2058+
df_prices.index = pd.to_datetime(df_prices["time"])
2059+
df_prog_prices.index = pd.to_datetime(df_prog_prices["time"])
2060+
df_prices = pd.concat([df_prices, df_prog_prices])
20582061

20592062
df_prices.rename(columns={"time": "tijd"}, inplace=True)
20602063
df_prices.index = pd.to_datetime(df_prices["tijd"])

dao/prog/day_ahead.py

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ def __init__(self, file_name=None):
2828
super().__init__(file_name=file_name)
2929
if self.config is None:
3030
return
31-
self.interval = self.config.get(["interval"], None, "1hour").lower()
3231
self.interval_s = 3600 if self.interval == "1hour" else 900
3332
self.interval_name = "uur" if self.interval == "1hour" else "kwartier"
3433
self.steps_day = 24 if self.interval == "1hour" else 96
@@ -122,8 +121,8 @@ def calc_optimum(
122121
return
123122
if u_data <= 8 or u_prices <= 8:
124123
logging.warning(
125-
f"Er ontbreken voor een aantal uur gegevens "
126-
f"(meteo en/of dynamische prijzen)\n"
124+
f"Er ontbreken voor een aantal uur meteogegevens "
125+
f"(en/of dynamische prijzen)\n"
127126
f"controleer of alle gegevens zijn opgehaald"
128127
)
129128
if self.notification_entity is not None:
@@ -234,8 +233,6 @@ def calc_optimum(
234233
uur.append(hour)
235234
tijd.append(dtime)
236235
gr = row.glob_rad
237-
if self.interval == "15min":
238-
gr *= 4
239236
global_rad.append(gr)
240237
pv_total = 0
241238
if first_interval:
@@ -248,10 +245,8 @@ def calc_optimum(
248245
interval_fraction.append(1)
249246
for s in range(solar_num):
250247
prod = self.calc_prod_solar(
251-
self.solar[s], row.time, gr, interval_fraction[-1]
248+
self.solar[s], row.time, gr, hour_fraction[-1]
252249
)
253-
if self.interval == "15min":
254-
prod /= 4
255250
solar_prod[s].append(prod)
256251
pv_total += prod
257252
pv_org_ac.append(pv_total)
@@ -268,7 +263,7 @@ def calc_optimum(
268263
self.battery_options[b]["solar"][s],
269264
row.time,
270265
gr,
271-
interval_fraction[-1],
266+
hour_fraction[-1],
272267
)
273268
pv_total += prod
274269
pv_org_dc.append(pv_total)
@@ -492,8 +487,6 @@ def calc_optimum(
492487
global_rad[u],
493488
hour_fraction[u],
494489
)
495-
if self.interval =="15min":
496-
prod_dc /= 4
497490
eff = 1
498491
for ds in range(DS[b]):
499492
if discharge_stages[b][ds]["power"] / 1000 > prod_dc:
@@ -1820,8 +1813,8 @@ def calc_optimum(
18201813
max_heat_power = stages[-1]["max_power"] * stages[-1]["cop"] / 1000
18211814

18221815
# een of meer intervallen minder als boiler via wp gaat
1823-
if boiler_heated_by_heatpump and boiler_start_index < U:
1824-
boiler_int = est_needed_intv[U - 1]
1816+
if boiler_heated_by_heatpump and boiler_start < U:
1817+
boiler_int = est_needed_intv[boiler_start] + 1
18251818
else:
18261819
boiler_int = 0
18271820
max_heat_prod = sum(
@@ -2727,17 +2720,16 @@ def calc_optimum(
27272720
+ boiler_storage
27282721
)
27292722

2730-
logging.info("Calculation profit after optimize in €")
2731-
logging.info(f"Cost before optimize {old_cost_da: 7.2f}")
2732-
logging.info(f"Cost consumption {cost_consumption: 7.2f}")
2733-
logging.info(f"Profit production {profit_production: 7.2f}")
2734-
logging.info(f"Cycle cost {total_cycle_cost: 7.2f}")
2735-
logging.info(f"Battery storage {battery_storage: 7.2f}")
2736-
logging.info(f"Boiler storage {boiler_storage: 7.2f}")
2737-
logging.info(f"Total {total_cost: 7.2f}")
2738-
logging.info(f"Cost after optimize {cost.x: 7.2f}")
2739-
logging.info(
2740-
f"Profit: {old_cost_da - cost.x: 7.2f}"
2723+
logging.info("/nCalculation profit after optimize in €\n"
2724+
f"Cost before optimize {old_cost_da: 7.2f}\n"
2725+
f"Cost consumption {cost_consumption: 7.2f}\n"
2726+
f"Profit production {profit_production: 7.2f}\n"
2727+
f"Cycle cost {total_cycle_cost: 7.2f}\n"
2728+
f"Battery storage {battery_storage: 7.2f}\n"
2729+
f"Boiler storage {boiler_storage: 7.2f}\n"
2730+
f"Total {total_cost: 7.2f}\n"
2731+
f"Cost after optimize {cost.x: 7.2f}\n"
2732+
f"Profit: {old_cost_da - cost.x: 7.2f}"
27412733
)
27422734

27432735
# doorzetten van alle settings naar HA

dao/prog/db_manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ def get_prognose_data(self, start, end=None, interval="1hour"):
426426
fld_df = self.get_prognose_field(field, start, end, interval)
427427
# fld_df.index = pd.to_datetime(fld_df["tijd"])
428428
# fld_df = interpolate(fld_df, field, 15, (field == "gr"))
429-
fld_df = interpolate(fld_df, field, (field == "gr"))
429+
fld_df = interpolate(fld_df, field, False)
430430
if result_df is None:
431431
result_df = fld_df
432432
else:

release-testing/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog 刀 DAO
22
# Day Ahead Optimizer
3+
# 2025.10.0.rc1
4+
This version is similar with 2025.10.0 in the stable-channel
5+
- Fix error with storing forecast (there was no timezone-correction)
6+
7+
Know issue:
8+
- The forecast in the reports still nog good working
9+
310
# 2025.9.1.rc7
411
- Fix error (Signal SIGSEGV caught) in rc6 on x86 (arch=amd64) machines
512

release-testing/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: 刀 Day Ahead Optimizer (TESTING)
3-
version: 2025.9.1.rc7
3+
version: 2025.10.0.rc1
44
stage: experimental
55
slug: day_ahead_opt-testing
66
description: Beta version of DAO. Use only for testing!

0 commit comments

Comments
 (0)