Skip to content

Commit

Permalink
Json configuration (Akkudoktor-EOS#141)
Browse files Browse the repository at this point in the history
* Add json config
* Adjust code to new config

---------

Co-authored-by: Chris <git@nootch.de>
  • Loading branch information
noootch and Chris authored Nov 11, 2024
1 parent f2ecb5a commit 057f86d
Show file tree
Hide file tree
Showing 21 changed files with 729 additions and 174 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
cache/
output/
EOS.config.json

# Default ignore folders and files for VS Code, Python

Expand Down
25 changes: 21 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,29 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
## Installation

Good installation guide:
https://meintechblog.de/2024/09/05/andreas-schmitz-joerg-installiert-mein-energieoptimierungssystem/
<https://meintechblog.de/2024/09/05/andreas-schmitz-joerg-installiert-mein-energieoptimierungssystem/>

The project requires Python 3.10 or newer.

## Configuration

This project uses a `config.json` file to manage configuration settings.

### Default Configuration

A default configuration file `default.config.json` is provided. This file contains all the necessary configuration keys with their default values.

### Custom Configuration

Users can specify a custom configuration directory by setting the environment variable `EOS_DIR`.

- If the directory specified by `EOS_DIR` contains an existing `config.json` file, the application will use this configuration file.
- If the `config.json` file does not exist in the specified directory, the `default.config.json` file will be copied to the directory as `config.json`.

### Configuration Updates

If the configuration keys in the `config.json` file are missing or different from those in `default.config.json`, they will be automatically updated to match the default settings, ensuring that all required keys are present.

### Quick Start Guide

On Linux (Ubuntu/Debian):
Expand All @@ -27,8 +46,7 @@ On MacOS (requires [Homebrew](https://brew.sh)):
brew install make
```

Next, adjust `config.py`.
The server can then be started with `make run`. A full overview of the main shortcuts is given by `make help`.
The server can be started with `make run`. A full overview of the main shortcuts is given by `make help`.

### Detailed Instructions

Expand Down Expand Up @@ -65,7 +83,6 @@ source .venv/bin/activate

## Usage

Adjust `config.py`.
To use the system, run `flask_server.py`, which starts the server:

```bash
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ services:
networks:
- "eos"
volumes:
- ./src/akkudoktoreos/config.py:/opt/eos/akkudoktoreos/config.py:ro
- ./src/akkudoktoreos/default.config.json:/opt/eos/EOS.config.json:ro
ports:
- "${EOS_PORT}:${EOS_PORT}"
26 changes: 24 additions & 2 deletions docs/develop/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ On MacOS (requires [Homebrew](https://brew.sh)):
brew install make
```

Next, adjust `config.py`.
The server can then be started with `make run`. A full overview of the main shortcuts is given by `make help`.

### Detailed Instructions
Expand Down Expand Up @@ -52,6 +51,7 @@ To always use the Python version from the virtual environment, you should activa
```bash
source .venv/bin/activate
```

(for Bash users, the default under Linux) or

```zsh
Expand All @@ -60,7 +60,29 @@ source .venv/bin/activate

## Usage

Adjust `config.py`.
### Configuration

---

This project uses a `config.json` file to manage configuration settings.

#### Default Configuration

A default configuration file `default.config.json` is provided. This file contains all the necessary configuration keys with their default values.

#### Custom Configuration

Users can specify a custom configuration directory by setting the environment variable `EOS_DIR`.

- If the directory specified by `EOS_DIR` contains an existing `config.json` file, the application will use this configuration file.
- If the `config.json` file does not exist in the specified directory, the `default.config.json` file will be copied to the directory as `config.json`.

#### Configuration Updates

If the configuration keys in the `config.json` file are missing or different from those in `default.config.json`, they will be automatically updated to match the default settings, ensuring that all required keys are present.

### Run server

To use the system, run `flask_server.py`, which starts the server:

```bash
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ where = ["src/"]
include = ["akkudoktoreos", "akkudoktoreosserver", ]

[tool.setuptools.package-data]
akkudoktoreos = ["*.json", ]
akkudoktoreosserver = ["data/*.npz", ]

[tool.pyright]
Expand Down
35 changes: 18 additions & 17 deletions single_test_optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
import numpy as np

from akkudoktoreos.class_numpy_encoder import NumpyEncoder

# Import necessary modules from the project
from akkudoktoreos.class_optimize import optimization_problem
from akkudoktoreos.config import get_working_dir, load_config
from akkudoktoreos.visualize import visualisiere_ergebnisse

start_hour = 0
Expand Down Expand Up @@ -276,10 +275,10 @@
# Startzeit nehmen
start_time = time.time()

# Initialize the optimization problem
opt_class = optimization_problem(
prediction_hours=48, strafe=10, optimization_hours=24, verbose=True, fixed_seed=42
)
# Initialize the optimization problem using the default configuration
working_dir = get_working_dir()
config = load_config(working_dir)
opt_class = optimization_problem(config, verbose=True, fixed_seed=42)

# Perform the optimisation based on the provided parameters and start hour
ergebnis = opt_class.optimierung_ems(parameter=parameter, start_hour=start_hour)
Expand All @@ -299,17 +298,19 @@
)

visualisiere_ergebnisse(
gesamtlast,
pv_forecast,
strompreis_euro_pro_wh,
ergebnis["result"],
ac_charge,
dc_charge,
discharge,
temperature_forecast,
start_hour,
48,
np.full(48, parameter["einspeiseverguetung_euro_pro_wh"]),
gesamtlast=gesamtlast,
pv_forecast=pv_forecast,
strompreise=strompreis_euro_pro_wh,
ergebnisse=ergebnis["result"],
ac=ac_charge,
dc=dc_charge,
discharge=discharge,
temperature=temperature_forecast,
start_hour=start_hour,
einspeiseverguetung_euro_pro_wh=np.full(
config.eos.feed_in_tariff_eur_per_wh, parameter["einspeiseverguetung_euro_pro_wh"]
),
config=config,
filename="visualization_results.pdf",
extra_data=None,
)
Expand Down
9 changes: 5 additions & 4 deletions src/akkudoktoreos/class_ems.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

import numpy as np

from akkudoktoreos.config import prediction_hours
from akkudoktoreos.config import EOSConfig


class EnergieManagementSystem:
def __init__(
self,
config: EOSConfig,
pv_prognose_wh: Optional[np.ndarray] = None,
strompreis_euro_pro_wh: Optional[np.ndarray] = None,
einspeiseverguetung_euro_pro_wh: Optional[np.ndarray] = None,
Expand All @@ -25,9 +26,9 @@ def __init__(
self.eauto = eauto
self.haushaltsgeraet = haushaltsgeraet
self.wechselrichter = wechselrichter
self.ac_charge_hours = np.full(prediction_hours, 0)
self.dc_charge_hours = np.full(prediction_hours, 1)
self.ev_charge_hours = np.full(prediction_hours, 0)
self.ac_charge_hours = np.full(config.prediction_hours, 0)
self.dc_charge_hours = np.full(config.prediction_hours, 1)
self.ev_charge_hours = np.full(config.prediction_hours, 0)

def set_akku_discharge_hours(self, ds: List[int]) -> None:
self.akku.set_discharge_per_hour(ds)
Expand Down
51 changes: 28 additions & 23 deletions src/akkudoktoreos/class_optimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,24 @@
from akkudoktoreos.class_ems import EnergieManagementSystem
from akkudoktoreos.class_haushaltsgeraet import Haushaltsgeraet
from akkudoktoreos.class_inverter import Wechselrichter
from akkudoktoreos.config import possible_ev_charge_currents
from akkudoktoreos.config import AppConfig
from akkudoktoreos.visualize import visualisiere_ergebnisse


class optimization_problem:
def __init__(
self,
prediction_hours: int = 48,
strafe: float = 10,
optimization_hours: int = 24,
config: AppConfig,
verbose: bool = False,
fixed_seed: Optional[int] = None,
):
"""Initialize the optimization problem with the required parameters."""
self.prediction_hours = prediction_hours
self.strafe = strafe
self._config = config
self.prediction_hours = config.eos.prediction_hours
self.strafe = config.eos.penalty
self.opti_param = None
self.fixed_eauto_hours = prediction_hours - optimization_hours
self.possible_charge_values = possible_ev_charge_currents
self.fixed_eauto_hours = config.eos.prediction_hours - config.eos.optimization_hours
self.possible_charge_values = config.eos.available_charging_rates_in_percentage
self.verbose = verbose
self.fix_seed = fixed_seed
self.optimize_ev = True
Expand Down Expand Up @@ -210,7 +209,10 @@ def setup_deap_environment(self, opti_param: Dict[str, Any], start_hour: int) ->

if self.optimize_ev:
self.toolbox.register(
"attr_ev_charge_index", random.randint, 0, len(possible_ev_charge_currents) - 1
"attr_ev_charge_index",
random.randint,
0,
len(self._config.eos.available_charging_rates_in_percentage) - 1,
)
self.toolbox.register("attr_int", random.randint, start_hour, 23)

Expand All @@ -236,7 +238,7 @@ def setup_deap_environment(self, opti_param: Dict[str, Any], start_hour: int) ->
"mutate_ev_charge_index",
tools.mutUniformInt,
low=0,
up=len(possible_ev_charge_currents) - 1,
up=len(self._config.eos.available_charging_rates_in_percentage) - 1,
indpb=0.2,
)
# - Start hour mutation for household devices
Expand Down Expand Up @@ -271,7 +273,8 @@ def evaluate_inner(

if self.optimize_ev:
eautocharge_hours_float = [
possible_ev_charge_currents[i] for i in eautocharge_hours_index
self._config.eos.available_charging_rates_in_percentage[i]
for i in eautocharge_hours_index
]
ems.set_ev_charge_hours(eautocharge_hours_float)
else:
Expand Down Expand Up @@ -420,6 +423,7 @@ def optimierung_ems(
# Initialize the inverter and energy management system
wr = Wechselrichter(10000, akku)
ems = EnergieManagementSystem(
config=self._config.eos,
gesamtlast=parameter["gesamtlast"],
pv_prognose_wh=parameter["pv_forecast"],
strompreis_euro_pro_wh=parameter["strompreis_euro_pro_wh"],
Expand All @@ -444,23 +448,24 @@ def optimierung_ems(
)
if self.optimize_ev:
eautocharge_hours_float = [
possible_ev_charge_currents[i] for i in eautocharge_hours_float
self._config.eos.available_charging_rates_in_percentage[i]
for i in eautocharge_hours_float
]

ac_charge, dc_charge, discharge = self.decode_charge_discharge(discharge_hours_bin)
# Visualize the results
visualisiere_ergebnisse(
parameter["gesamtlast"],
parameter["pv_forecast"],
parameter["strompreis_euro_pro_wh"],
o,
ac_charge,
dc_charge,
discharge,
parameter["temperature_forecast"],
start_hour,
self.prediction_hours,
einspeiseverguetung_euro_pro_wh,
gesamtlast=parameter["gesamtlast"],
pv_forecast=parameter["pv_forecast"],
strompreise=parameter["strompreis_euro_pro_wh"],
ergebnisse=o,
ac=ac_charge,
dc=dc_charge,
discharge=discharge,
temperature=parameter["temperature_forecast"],
start_hour=start_hour,
einspeiseverguetung_euro_pro_wh=einspeiseverguetung_euro_pro_wh,
config=self._config,
extra_data=extra_data,
)

Expand Down
Loading

0 comments on commit 057f86d

Please sign in to comment.