mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-03-18 20:46:17 +00:00
fix: device id in solution follows configuration (#964)
Some checks are pending
Bump Version / Bump Version Workflow (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
docker-build / platform-excludes (push) Waiting to run
docker-build / build (push) Blocked by required conditions
docker-build / merge (push) Blocked by required conditions
pre-commit / pre-commit (push) Waiting to run
Run Pytest on Pull Request / test (push) Waiting to run
Some checks are pending
Bump Version / Bump Version Workflow (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
docker-build / platform-excludes (push) Waiting to run
docker-build / build (push) Blocked by required conditions
docker-build / merge (push) Blocked by required conditions
pre-commit / pre-commit (push) Waiting to run
Run Pytest on Pull Request / test (push) Waiting to run
Make device id in solution follow actual configuration. Adapt version update to new CI bump workflow design. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
2
.env
2
.env
@@ -11,7 +11,7 @@ DOCKER_COMPOSE_DATA_DIR=${HOME}/.local/share/net.akkudoktor.eos
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Image / build
|
# Image / build
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
VERSION=config.yaml
|
VERSION=0.3.0.dev2603180681250771
|
||||||
PYTHON_VERSION=3.13.9
|
PYTHON_VERSION=3.13.9
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -178,18 +178,15 @@ docker-build:
|
|||||||
@docker compose build
|
@docker compose build
|
||||||
|
|
||||||
# Propagete version info to all version files
|
# Propagete version info to all version files
|
||||||
# Take UPDATE_FILES from GitHub action bump-version.yml
|
|
||||||
UPDATE_FILES := $(shell sed -n 's/^[[:space:]]*UPDATE_FILES[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' \
|
|
||||||
.github/workflows/bump-version.yml)
|
|
||||||
prepare-version: install
|
prepare-version: install
|
||||||
@echo "Update version to $(VERSION) from version.py in files $(UPDATE_FILES) and doc"
|
$(PYTHON) ./scripts/update_version.py $(VERSION)
|
||||||
$(PYTHON) ./scripts/update_version.py $(VERSION) $(UPDATE_FILES)
|
|
||||||
$(PYTHON) ./scripts/convert_lightweight_tags.py
|
$(PYTHON) ./scripts/convert_lightweight_tags.py
|
||||||
$(PYTHON) ./scripts/generate_config_md.py --output-file docs/_generated/config.md
|
$(PYTHON) ./scripts/generate_config_md.py --output-file docs/_generated/config.md
|
||||||
$(PYTHON) ./scripts/generate_openapi_md.py --output-file docs/_generated/openapi.md
|
$(PYTHON) ./scripts/generate_openapi_md.py --output-file docs/_generated/openapi.md
|
||||||
$(PYTHON) ./scripts/generate_openapi.py --output-file openapi.json
|
$(PYTHON) ./scripts/generate_openapi.py --output-file openapi.json
|
||||||
$(PYTEST) -vv --finalize tests/test_doc.py
|
$(PYTEST) -vv --finalize tests/test_doc.py
|
||||||
$(PRECOMMIT) run --all-files
|
$(PRECOMMIT) run --all-files
|
||||||
|
@echo "Updated version to $(VERSION) from version.py in config files and doc"
|
||||||
|
|
||||||
test-version:
|
test-version:
|
||||||
echo "Test version information to be correctly set in all version files"
|
echo "Test version information to be correctly set in all version files"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# the root directory (no add-on folder as usual).
|
# the root directory (no add-on folder as usual).
|
||||||
|
|
||||||
name: "Akkudoktor-EOS"
|
name: "Akkudoktor-EOS"
|
||||||
version: "0.3.0"
|
version: "0.3.0.dev2603180681250771"
|
||||||
slug: "eos"
|
slug: "eos"
|
||||||
description: "Akkudoktor-EOS add-on"
|
description: "Akkudoktor-EOS add-on"
|
||||||
url: "https://github.com/Akkudoktor-EOS/EOS"
|
url: "https://github.com/Akkudoktor-EOS/EOS"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Akkudoktor-EOS
|
# Akkudoktor-EOS
|
||||||
|
|
||||||
**Version**: `v0.3.0`
|
**Version**: `v0.3.0.dev2603180681250771`
|
||||||
|
|
||||||
<!-- pyml disable line-length -->
|
<!-- pyml disable line-length -->
|
||||||
**Description**: This project provides a comprehensive solution for simulating and optimizing an energy system based on renewable energy sources. With a focus on photovoltaic (PV) systems, battery storage (batteries), load management (consumer requirements), heat pumps, electric vehicles, and consideration of electricity price data, this system enables forecasting and optimization of energy flow and costs over a specified period.
|
**Description**: This project provides a comprehensive solution for simulating and optimizing an energy system based on renewable energy sources. With a focus on photovoltaic (PV) systems, battery storage (batteries), load management (consumer requirements), heat pumps, electric vehicles, and consideration of electricity price data, this system enables forecasting and optimization of energy flow and costs over a specified period.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"name": "Apache 2.0",
|
"name": "Apache 2.0",
|
||||||
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
|
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
|
||||||
},
|
},
|
||||||
"version": "v0.3.0"
|
"version": "v0.3.0.dev2603180681250771"
|
||||||
},
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
"/v1/admin/cache/clear": {
|
"/v1/admin/cache/clear": {
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ PACKAGE_DIR = PROJECT_ROOT / "src" / "akkudoktoreos"
|
|||||||
SRC_DIR = PROJECT_ROOT / "src"
|
SRC_DIR = PROJECT_ROOT / "src"
|
||||||
sys.path.insert(0, str(SRC_DIR))
|
sys.path.insert(0, str(SRC_DIR))
|
||||||
|
|
||||||
|
DEFAULT_VERSION_FILES = [
|
||||||
|
PROJECT_ROOT / ".env", # Docker compose default environment
|
||||||
|
PROJECT_ROOT / "config.yaml", # Home Assistant config
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# --- Patterns to match version strings ---
|
# --- Patterns to match version strings ---
|
||||||
VERSION_PATTERNS = [
|
VERSION_PATTERNS = [
|
||||||
@@ -146,10 +151,13 @@ def main(version: str, files: List[str]):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if len(sys.argv) < 3:
|
if len(sys.argv) < 2:
|
||||||
print("Usage: python update_version.py <version> <file1> [file2 ...]")
|
print("Usage: python update_version.py <version> [<file1> [file2 ...]]")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
version_arg = sys.argv[1]
|
version_arg = sys.argv[1]
|
||||||
files_arg = sys.argv[2:]
|
if len(sys.argv) == 2:
|
||||||
|
files_arg = [str(f) for f in DEFAULT_VERSION_FILES]
|
||||||
|
else:
|
||||||
|
files_arg = sys.argv[2:]
|
||||||
main(version_arg, files_arg)
|
main(version_arg, files_arg)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from typing import Optional
|
|||||||
|
|
||||||
# For development add `.dev` to previous release
|
# For development add `.dev` to previous release
|
||||||
# For release omit `.dev`.
|
# For release omit `.dev`.
|
||||||
VERSION_BASE = "0.3.0"
|
VERSION_BASE = "0.3.0.dev"
|
||||||
|
|
||||||
# Project hash of relevant files
|
# Project hash of relevant files
|
||||||
HASH_EOS = ""
|
HASH_EOS = ""
|
||||||
|
|||||||
@@ -200,6 +200,27 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
return ElectricVehicleResult(**field.to_dict())
|
return ElectricVehicleResult(**field.to_dict())
|
||||||
return field
|
return field
|
||||||
|
|
||||||
|
def _battery_device_id(self) -> str:
|
||||||
|
"""Get battery device id."""
|
||||||
|
try:
|
||||||
|
return self.config.devices.batteries[0].device_id
|
||||||
|
except Exception:
|
||||||
|
return "battery1"
|
||||||
|
|
||||||
|
def _ev_device_id(self) -> str:
|
||||||
|
"""Get electric vehicle device id."""
|
||||||
|
try:
|
||||||
|
return self.config.devices.electric_vehicles[0].device_id
|
||||||
|
except Exception:
|
||||||
|
return "ev1"
|
||||||
|
|
||||||
|
def _homeappliance_device_id(self) -> str:
|
||||||
|
"""Get home appliance device id."""
|
||||||
|
try:
|
||||||
|
return self.config.devices.home_appliances[0].device_id
|
||||||
|
except Exception:
|
||||||
|
return "homeappliance1"
|
||||||
|
|
||||||
def _battery_operation_from_solution(
|
def _battery_operation_from_solution(
|
||||||
self,
|
self,
|
||||||
ac_charge: float,
|
ac_charge: float,
|
||||||
@@ -377,7 +398,8 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Add battery data
|
# Add battery data
|
||||||
solution["battery1_soc_factor"] = [
|
battery_device_id = self._battery_device_id()
|
||||||
|
solution[f"{battery_device_id}_soc_factor"] = [
|
||||||
v / 100
|
v / 100
|
||||||
for v in self.result.akku_soc_pro_stunde[:n_points] # result starts at start_day_hour
|
for v in self.result.akku_soc_pro_stunde[:n_points] # result starts at start_day_hour
|
||||||
]
|
]
|
||||||
@@ -416,8 +438,8 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
eff_ac, eff_dc, eff_dis
|
eff_ac, eff_dc, eff_dis
|
||||||
)
|
)
|
||||||
for mode in BatteryOperationMode:
|
for mode in BatteryOperationMode:
|
||||||
mode_key = f"battery1_{mode.lower()}_op_mode"
|
mode_key = f"{battery_device_id}_{mode.lower()}_op_mode"
|
||||||
factor_key = f"battery1_{mode.lower()}_op_factor"
|
factor_key = f"{battery_device_id}_{mode.lower()}_op_factor"
|
||||||
if mode_key not in operation.keys():
|
if mode_key not in operation.keys():
|
||||||
operation[mode_key] = []
|
operation[mode_key] = []
|
||||||
operation[factor_key] = []
|
operation[factor_key] = []
|
||||||
@@ -438,17 +460,18 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
# eautocharge_hours_float start at hour 0 of start day
|
# eautocharge_hours_float start at hour 0 of start day
|
||||||
# result.EAuto_SoC_pro_Stunde start at start_datetime.hour
|
# result.EAuto_SoC_pro_Stunde start at start_datetime.hour
|
||||||
if self.eauto_obj:
|
if self.eauto_obj:
|
||||||
|
ev_device_id = self._ev_device_id()
|
||||||
if self.eautocharge_hours_float is None:
|
if self.eautocharge_hours_float is None:
|
||||||
# Electric vehicle is full enough. No load times.
|
# Electric vehicle is full enough. No load times.
|
||||||
solution[f"{self.eauto_obj.device_id}_soc_factor"] = [
|
solution[f"{ev_device_id}_soc_factor"] = [
|
||||||
self.eauto_obj.initial_soc_percentage / 100.0
|
self.eauto_obj.initial_soc_percentage / 100.0
|
||||||
] * n_points
|
] * n_points
|
||||||
solution["genetic_ev_charge_factor"] = [0.0] * n_points
|
solution["genetic_ev_charge_factor"] = [0.0] * n_points
|
||||||
# operation modes
|
# operation modes
|
||||||
operation_mode = BatteryOperationMode.IDLE
|
operation_mode = BatteryOperationMode.IDLE
|
||||||
for mode in BatteryOperationMode:
|
for mode in BatteryOperationMode:
|
||||||
mode_key = f"{self.eauto_obj.device_id}_{mode.lower()}_op_mode"
|
mode_key = f"{ev_device_id}_{mode.lower()}_op_mode"
|
||||||
factor_key = f"{self.eauto_obj.device_id}_{mode.lower()}_op_factor"
|
factor_key = f"{ev_device_id}_{mode.lower()}_op_factor"
|
||||||
if mode == operation_mode:
|
if mode == operation_mode:
|
||||||
solution[mode_key] = [1.0] * n_points
|
solution[mode_key] = [1.0] * n_points
|
||||||
solution[factor_key] = [1.0] * n_points
|
solution[factor_key] = [1.0] * n_points
|
||||||
@@ -456,7 +479,7 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
solution[mode_key] = [0.0] * n_points
|
solution[mode_key] = [0.0] * n_points
|
||||||
solution[factor_key] = [0.0] * n_points
|
solution[factor_key] = [0.0] * n_points
|
||||||
else:
|
else:
|
||||||
solution[f"{self.eauto_obj.device_id}_soc_factor"] = [
|
solution[f"{ev_device_id}_soc_factor"] = [
|
||||||
v / 100 for v in self.result.EAuto_SoC_pro_Stunde[:n_points]
|
v / 100 for v in self.result.EAuto_SoC_pro_Stunde[:n_points]
|
||||||
]
|
]
|
||||||
operation = {
|
operation = {
|
||||||
@@ -472,8 +495,8 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
rate, 0.0, False
|
rate, 0.0, False
|
||||||
)
|
)
|
||||||
for mode in BatteryOperationMode:
|
for mode in BatteryOperationMode:
|
||||||
mode_key = f"{self.eauto_obj.device_id}_{mode.lower()}_op_mode"
|
mode_key = f"{ev_device_id}_{mode.lower()}_op_mode"
|
||||||
factor_key = f"{self.eauto_obj.device_id}_{mode.lower()}_op_factor"
|
factor_key = f"{ev_device_id}_{mode.lower()}_op_factor"
|
||||||
if mode_key not in operation.keys():
|
if mode_key not in operation.keys():
|
||||||
operation[mode_key] = []
|
operation[mode_key] = []
|
||||||
operation[factor_key] = []
|
operation[factor_key] = []
|
||||||
@@ -494,26 +517,28 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
if self.config.devices.max_home_appliances and self.config.devices.max_home_appliances > 0:
|
if self.config.devices.max_home_appliances and self.config.devices.max_home_appliances > 0:
|
||||||
# Use config and not self.washingstart as washingstart may be None (no start)
|
# Use config and not self.washingstart as washingstart may be None (no start)
|
||||||
# even if configured to be started.
|
# even if configured to be started.
|
||||||
|
homeappliance_device_id = self._homeappliance_device_id()
|
||||||
# result starts at start_day_hour
|
# result starts at start_day_hour
|
||||||
solution["homeappliance1_energy_wh"] = self.result.Home_appliance_wh_per_hour[:n_points]
|
solution[f"{homeappliance_device_id}_energy_wh"] = (
|
||||||
|
self.result.Home_appliance_wh_per_hour[:n_points]
|
||||||
|
)
|
||||||
operation = {
|
operation = {
|
||||||
"homeappliance1_run_op_mode": [],
|
f"{homeappliance_device_id}_run_op_mode": [],
|
||||||
"homeappliance1_run_op_factor": [],
|
f"{homeappliance_device_id}_run_op_factor": [],
|
||||||
"homeappliance1_off_op_mode": [],
|
f"{homeappliance_device_id}_off_op_mode": [],
|
||||||
"homeappliance1_off_op_factor": [],
|
f"{homeappliance_device_id}_off_op_factor": [],
|
||||||
}
|
}
|
||||||
for hour_idx, energy in enumerate(solution["homeappliance1_energy_wh"]):
|
for hour_idx, energy in enumerate(solution[f"{homeappliance_device_id}_energy_wh"]):
|
||||||
if energy > 0.0:
|
if energy > 0.0:
|
||||||
operation["homeappliance1_run_op_mode"].append(1.0)
|
operation[f"{homeappliance_device_id}_run_op_mode"].append(1.0)
|
||||||
operation["homeappliance1_run_op_factor"].append(1.0)
|
operation[f"{homeappliance_device_id}_run_op_factor"].append(1.0)
|
||||||
operation["homeappliance1_off_op_mode"].append(0.0)
|
operation[f"{homeappliance_device_id}_off_op_mode"].append(0.0)
|
||||||
operation["homeappliance1_off_op_factor"].append(0.0)
|
operation[f"{homeappliance_device_id}_off_op_factor"].append(0.0)
|
||||||
else:
|
else:
|
||||||
operation["homeappliance1_run_op_mode"].append(0.0)
|
operation[f"{homeappliance_device_id}_run_op_mode"].append(0.0)
|
||||||
operation["homeappliance1_run_op_factor"].append(0.0)
|
operation[f"{homeappliance_device_id}_run_op_factor"].append(0.0)
|
||||||
operation["homeappliance1_off_op_mode"].append(1.0)
|
operation[f"{homeappliance_device_id}_off_op_mode"].append(1.0)
|
||||||
operation["homeappliance1_off_op_factor"].append(1.0)
|
operation[f"{homeappliance_device_id}_off_op_factor"].append(1.0)
|
||||||
for key in operation.keys():
|
for key in operation.keys():
|
||||||
if len(operation[key]) != n_points:
|
if len(operation[key]) != n_points:
|
||||||
error_msg = f"instruction {key} has invalid length {len(operation[key])} - expected {n_points}"
|
error_msg = f"instruction {key} has invalid length {len(operation[key])} - expected {n_points}"
|
||||||
@@ -630,7 +655,7 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
# Add battery instructions (fill rate based control)
|
# Add battery instructions (fill rate based control)
|
||||||
last_operation_mode: Optional[str] = None
|
last_operation_mode: Optional[str] = None
|
||||||
last_operation_mode_factor: Optional[float] = None
|
last_operation_mode_factor: Optional[float] = None
|
||||||
resource_id = "battery1"
|
resource_id = self._battery_device_id()
|
||||||
# ac_charge, dc_charge, discharge_allowed start at hour 0 of start day
|
# ac_charge, dc_charge, discharge_allowed start at hour 0 of start day
|
||||||
logger.debug("BAT: {} - {}", resource_id, self.ac_charge[start_day_hour:])
|
logger.debug("BAT: {} - {}", resource_id, self.ac_charge[start_day_hour:])
|
||||||
for hour_idx, rate in enumerate(self.ac_charge):
|
for hour_idx, rate in enumerate(self.ac_charge):
|
||||||
@@ -677,7 +702,7 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
# Add EV battery instructions (fill rate based control)
|
# Add EV battery instructions (fill rate based control)
|
||||||
# eautocharge_hours_float start at hour 0 of start day
|
# eautocharge_hours_float start at hour 0 of start day
|
||||||
if self.eauto_obj:
|
if self.eauto_obj:
|
||||||
resource_id = self.eauto_obj.device_id
|
resource_id = self._ev_device_id()
|
||||||
if self.eautocharge_hours_float is None:
|
if self.eautocharge_hours_float is None:
|
||||||
# Electric vehicle is full enough. No load times.
|
# Electric vehicle is full enough. No load times.
|
||||||
logger.debug("EV: {} - SoC >= min, no optimization", resource_id)
|
logger.debug("EV: {} - SoC >= min, no optimization", resource_id)
|
||||||
@@ -725,7 +750,7 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
|
|||||||
if self.config.devices.max_home_appliances and self.config.devices.max_home_appliances > 0:
|
if self.config.devices.max_home_appliances and self.config.devices.max_home_appliances > 0:
|
||||||
# Use config and not self.washingstart as washingstart may be None (no start)
|
# Use config and not self.washingstart as washingstart may be None (no start)
|
||||||
# even if configured to be started.
|
# even if configured to be started.
|
||||||
resource_id = "homeappliance1"
|
resource_id = self._homeappliance_device_id()
|
||||||
last_energy: Optional[float] = None
|
last_energy: Optional[float] = None
|
||||||
for hours, energy in enumerate(self.result.Home_appliance_wh_per_hour):
|
for hours, energy in enumerate(self.result.Home_appliance_wh_per_hour):
|
||||||
# hours starts at start_datetime with 0
|
# hours starts at start_datetime with 0
|
||||||
|
|||||||
Reference in New Issue
Block a user