mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-11-13 01:03:45 +01:00
A battery profile describes a battery model: the charge and discharge limit
maps over temperature and SoC, the charge and discharge efficiency curves
over C-rate, the technical SoC bounds, the hard temperature cutoffs and,
for a model, its nominal capacity and power limits. EOS packages the
generic profile generic-lfp; users add their own profiles.
A battery or electric vehicle selects its profile by battery_profile and
describes how the installation differs from it in profile_adjustment
(capacity, power limits of the installation, periodic full charge). The
effective values are resolved from both at the measured operating point
(temperature, SoC, power) and shown as effective_* fields.
The GENETIC simulation uses the limits and efficiencies of the profile over
SoC, with precomputed tables as a fast path; GENETIC0 gets the values at the
operating point. Optimization parameters are always valid: a battery whose
profile is missing, unreadable or invalid uses the packaged generic-lfp
profile, and the former defaults only if that is not usable either; each is
logged as error, and an optimization run is never cancelled because of a
battery.
Additional changes
- Add a generic device profile store: user and packaged profiles, atomic
saves, compiled profiles cached per file and checked again at most once a
second, plain file names as profile names ('schema' is reserved). On
Windows, a save or read that collides with the other is retried briefly.
- Add the REST API /v1/profile to list the profile kinds and to list, read
(document and JSON schema), save and delete profiles.
- Check the hard temperature cutoffs on the exact temperature.
- Resolve inhibited charging or discharging to a power of 0, e.g. for a cold
battery; give GENETIC0 its own discharge limit for that.
- Limit generic profiles without own power limits to the former 5000 W.
- Accept only the implemented units; current limits need the nominal
voltage.
- Migrate legacy battery settings into the profile adjustment, keep the
former charge power limit as discharge limit (also for a Home Assistant
entity on it) and report dropped efficiencies as errors.
- Limit GENETIC battery discharge by the discharge power.
- Allow battery profile lookups while the configuration is created.
- Resolve a battery once per configuration dump.
- Package the bundled profiles, document battery profiles and regenerate
the configuration and OpenAPI documentation.
- Ignore the report PDFs written by the visualization tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assisted-by: Claude Code (claude-opus-5-5)
240 lines
8.9 KiB
Markdown
240 lines
8.9 KiB
Markdown
## Adapter Configuration
|
||
|
||
<!-- pyml disable line-length -->
|
||
:::{table} adapter
|
||
:widths: 10 20 10 5 5 30
|
||
:align: left
|
||
|
||
| Name | Environment Variable | Type | Read-Only | Default | Description |
|
||
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
|
||
| homeassistant | `EOS_ADAPTER__HOMEASSISTANT` | `HomeAssistantAdapterCommonSettings` | `rw` | `required` | Home Assistant adapter settings. |
|
||
| nodered | `EOS_ADAPTER__NODERED` | `NodeREDAdapterCommonSettings` | `rw` | `required` | NodeRED adapter settings. |
|
||
| provider | `EOS_ADAPTER__PROVIDER` | `Optional[list[str]]` | `rw` | `None` | List of adapter provider id(s) of provider(s) to be used. |
|
||
| providers | | `list[str]` | `ro` | `N/A` | Available adapter provider ids. |
|
||
:::
|
||
<!-- pyml enable line-length -->
|
||
|
||
<!-- pyml disable no-emphasis-as-heading -->
|
||
**Example Input**
|
||
<!-- pyml enable no-emphasis-as-heading -->
|
||
|
||
<!-- pyml disable line-length -->
|
||
```json
|
||
{
|
||
"adapter": {
|
||
"provider": [
|
||
"HomeAssistant"
|
||
],
|
||
"homeassistant": {
|
||
"config_entity_ids": null,
|
||
"load_emr_entity_ids": null,
|
||
"grid_export_emr_entity_ids": null,
|
||
"grid_import_emr_entity_ids": null,
|
||
"pv_production_emr_entity_ids": null,
|
||
"device_measurement_entity_ids": null,
|
||
"device_instruction_entity_ids": null,
|
||
"solution_entity_ids": null
|
||
},
|
||
"nodered": {
|
||
"host": "127.0.0.1",
|
||
"port": 1880
|
||
}
|
||
}
|
||
}
|
||
```
|
||
<!-- pyml enable line-length -->
|
||
|
||
<!-- pyml disable no-emphasis-as-heading -->
|
||
**Example Output**
|
||
<!-- pyml enable no-emphasis-as-heading -->
|
||
|
||
<!-- pyml disable line-length -->
|
||
```json
|
||
{
|
||
"adapter": {
|
||
"provider": [
|
||
"HomeAssistant"
|
||
],
|
||
"homeassistant": {
|
||
"config_entity_ids": null,
|
||
"load_emr_entity_ids": null,
|
||
"grid_export_emr_entity_ids": null,
|
||
"grid_import_emr_entity_ids": null,
|
||
"pv_production_emr_entity_ids": null,
|
||
"device_measurement_entity_ids": null,
|
||
"device_instruction_entity_ids": null,
|
||
"solution_entity_ids": null,
|
||
"homeassistant_entity_ids": [],
|
||
"eos_solution_entity_ids": [],
|
||
"eos_device_instruction_entity_ids": []
|
||
},
|
||
"nodered": {
|
||
"host": "127.0.0.1",
|
||
"port": 1880
|
||
},
|
||
"providers": [
|
||
"HomeAssistant",
|
||
"NodeRED"
|
||
]
|
||
}
|
||
}
|
||
```
|
||
<!-- pyml enable line-length -->
|
||
|
||
### Common settings for the NodeRED adapter
|
||
|
||
The Node-RED adapter sends to HTTP IN nodes.
|
||
|
||
This is the example flow:
|
||
|
||
`[HTTP In <URL>] -> [Function (parse payload)] -> [Debug] -> [HTTP Response]`
|
||
|
||
There are two URLs that are used:
|
||
|
||
- GET /eos/data_aquisition
|
||
The GET is issued before the optimization.
|
||
- POST /eos/control_dispatch
|
||
The POST is issued after the optimization.
|
||
|
||
<!-- pyml disable line-length -->
|
||
:::{table} adapter::nodered
|
||
:widths: 10 10 5 5 30
|
||
:align: left
|
||
|
||
| Name | Type | Read-Only | Default | Description |
|
||
| ---- | ---- | --------- | ------- | ----------- |
|
||
| host | `Optional[str]` | `rw` | `127.0.0.1` | Node-RED server IP address. Defaults to 127.0.0.1. |
|
||
| port | `Optional[int]` | `rw` | `1880` | Node-RED server IP port number. Defaults to 1880. |
|
||
:::
|
||
<!-- pyml enable line-length -->
|
||
|
||
<!-- pyml disable no-emphasis-as-heading -->
|
||
**Example Input/Output**
|
||
<!-- pyml enable no-emphasis-as-heading -->
|
||
|
||
<!-- pyml disable line-length -->
|
||
```json
|
||
{
|
||
"adapter": {
|
||
"nodered": {
|
||
"host": "127.0.0.1",
|
||
"port": 1880
|
||
}
|
||
}
|
||
}
|
||
```
|
||
<!-- pyml enable line-length -->
|
||
|
||
### Common settings for the home assistant adapter
|
||
|
||
<!-- pyml disable line-length -->
|
||
:::{table} adapter::homeassistant
|
||
:widths: 10 10 5 5 30
|
||
:align: left
|
||
|
||
| Name | Type | Read-Only | Default | Description |
|
||
| ---- | ---- | --------- | ------- | ----------- |
|
||
| config_entity_ids | `Optional[dict[str, str]]` | `rw` | `None` | Mapping of EOS config keys to Home Assistant entity IDs.
|
||
The config key has to be given by a ‘/’-separated path
|
||
e.g. devices/batteries/battery1/profile_adjustment/nominal_capacity_wh
|
||
Devices are addressed by their device_id. The setting must exist. |
|
||
| device_instruction_entity_ids | `Optional[list[str]]` | `rw` | `None` | Entity IDs for device (resource) instructions to be updated by EOS.
|
||
The device ids (resource ids) have to be prepended by 'sensor.eos_' to build the entity_id.
|
||
E.g. The instruction for device id 'battery1' becomes the entity_id 'sensor.eos_battery1'. |
|
||
| device_measurement_entity_ids | `Optional[dict[str, str]]` | `rw` | `None` | Mapping of EOS device measurement keys to Home Assistant entity IDs. Registered keys such as 'battery1-soc-factor' are accepted; legacy underscore spellings are resolved when they uniquely match a registered key. |
|
||
| eos_device_instruction_entity_ids | `list[str]` | `ro` | `N/A` | Entity IDs for energy management instructions available at EOS. |
|
||
| eos_solution_entity_ids | `list[str]` | `ro` | `N/A` | Entity IDs for optimization solution available at EOS. |
|
||
| grid_export_emr_entity_ids | `Optional[list[str]]` | `rw` | `None` | Entity ID(s) of export to grid energy meter readings [kWh] |
|
||
| grid_import_emr_entity_ids | `Optional[list[str]]` | `rw` | `None` | Entity ID(s) of import from grid energy meter readings [kWh] |
|
||
| homeassistant_entity_ids | `list[str]` | `ro` | `N/A` | Entity IDs available at Home Assistant. |
|
||
| load_emr_entity_ids | `Optional[list[str]]` | `rw` | `None` | Entity ID(s) of load energy meter readings [kWh] |
|
||
| pv_production_emr_entity_ids | `Optional[list[str]]` | `rw` | `None` | Entity ID(s) of PV production energy meter readings [kWh] |
|
||
| solution_entity_ids | `Optional[list[str]]` | `rw` | `None` | Entity IDs for optimization solution keys to be updated by EOS.
|
||
The solution keys have to be prepended by 'sensor.eos_' to build the entity_id.
|
||
E.g. solution key 'battery1_idle_op_mode' becomes the entity_id 'sensor.eos_battery1_idle_op_mode'. |
|
||
:::
|
||
<!-- pyml enable line-length -->
|
||
|
||
<!-- pyml disable no-emphasis-as-heading -->
|
||
**Example Input**
|
||
<!-- pyml enable no-emphasis-as-heading -->
|
||
|
||
<!-- pyml disable line-length -->
|
||
```json
|
||
{
|
||
"adapter": {
|
||
"homeassistant": {
|
||
"config_entity_ids": {
|
||
"devices/batteries/battery1/profile_adjustment/nominal_capacity_wh": "sensor.battery1_capacity"
|
||
},
|
||
"load_emr_entity_ids": [
|
||
"sensor.load_energy_total_kwh"
|
||
],
|
||
"grid_export_emr_entity_ids": [
|
||
"sensor.grid_export_energy_total_kwh"
|
||
],
|
||
"grid_import_emr_entity_ids": [
|
||
"sensor.grid_import_energy_total_kwh"
|
||
],
|
||
"pv_production_emr_entity_ids": [
|
||
"sensor.pv_energy_total_kwh"
|
||
],
|
||
"device_measurement_entity_ids": {
|
||
"ev11-soc-factor": "sensor.ev11_soc_factor",
|
||
"battery1-soc-factor": "sensor.battery1_soc_factor"
|
||
},
|
||
"device_instruction_entity_ids": [
|
||
"sensor.eos_battery1"
|
||
],
|
||
"solution_entity_ids": [
|
||
"sensor.eos_battery1_idle_mode_mode"
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
<!-- pyml enable line-length -->
|
||
|
||
<!-- pyml disable no-emphasis-as-heading -->
|
||
**Example Output**
|
||
<!-- pyml enable no-emphasis-as-heading -->
|
||
|
||
<!-- pyml disable line-length -->
|
||
```json
|
||
{
|
||
"adapter": {
|
||
"homeassistant": {
|
||
"config_entity_ids": {
|
||
"devices/batteries/battery1/profile_adjustment/nominal_capacity_wh": "sensor.battery1_capacity"
|
||
},
|
||
"load_emr_entity_ids": [
|
||
"sensor.load_energy_total_kwh"
|
||
],
|
||
"grid_export_emr_entity_ids": [
|
||
"sensor.grid_export_energy_total_kwh"
|
||
],
|
||
"grid_import_emr_entity_ids": [
|
||
"sensor.grid_import_energy_total_kwh"
|
||
],
|
||
"pv_production_emr_entity_ids": [
|
||
"sensor.pv_energy_total_kwh"
|
||
],
|
||
"device_measurement_entity_ids": {
|
||
"ev11-soc-factor": "sensor.ev11_soc_factor",
|
||
"battery1-soc-factor": "sensor.battery1_soc_factor"
|
||
},
|
||
"device_instruction_entity_ids": [
|
||
"sensor.eos_battery1"
|
||
],
|
||
"solution_entity_ids": [
|
||
"sensor.eos_battery1_idle_mode_mode"
|
||
],
|
||
"homeassistant_entity_ids": [],
|
||
"eos_solution_entity_ids": [],
|
||
"eos_device_instruction_entity_ids": []
|
||
}
|
||
}
|
||
}
|
||
```
|
||
<!-- pyml enable line-length -->
|