Files
EOS/docs/akkudoktoreos/resource.md
T
Bobby NoelteandClaude Opus 5.5 faf37abfe7 feat(devices): add inverter profiles
An inverter profile describes the technical data of an inverter model: its
nominal AC power, the DC→AC and AC→DC efficiency curves over the load
fraction (AC power relative to the nominal power), the AC charge power
limit of the model, whether that limit also limits PV charging, and an
optional power derating over the ambient temperature. Curves are read
linearly and clamped at their ends, so every lookup yields a value. The
packaged profile generic-hybrid has typical hybrid inverter efficiencies,
no nominal power (the inverter device has to provide it) and full power up
to 45 degC.

Inverter settings name their profile (inverter_profile, default
generic-hybrid) and hold the differences of the unit in profile_adjustment:
nominal_power_w (replaces the profile value, required for a generic
profile), max_power_w and max_ac_charge_power_w (installation limits that
can only lower; an AC charge limit of 0 disables AC charging). The
effective parameters are resolved at the ambient temperature of the
inverter, given by the new measurement key <device_id>-temperature-degc
(45 degC without a fresh value); the power derating lowers the maximum
power and the AC charge limit.

Optimization parameters are always valid: the GENETIC and GENETIC0
parameter preparation resolve the inverter with
resolve_current_operating_parameters_or_defaults, which never raises. An
unusable profile gives the generic-hybrid profile, a missing nominal power
the fallback of 10000 W, an inverter derated to zero power the parameters
at 45 degC, and no usable profile at all the profile adjustment with
constant efficiency; each is logged as error. The GENETIC inverter takes
the AC→DC efficiency curve of the profile, solved exactly on each linear
piece of the curve (about 2 % longer runs); GENETIC0 keeps constant
efficiencies and no longer replaces the configured inverters with the demo
inverter; a battery, electric vehicle or inverter that cannot be prepared
is left out of the GENETIC0 run, never replaced by a demo device.

Configurations migrate: max_power_w becomes
profile_adjustment.nominal_power_w, max_ac_charge_power_w moves into the
adjustment, an ac_to_dc_efficiency of 0 keeps AC charging disabled, and
the efficiency fields are dropped with an error log, as for batteries, so
the profile efficiencies apply. Home Assistant config paths follow.

Additional changes
- Move the curve algorithms of the battery profile into profilecurve, so
  battery and inverter profiles share them; the battery profile keeps its
  document format and classes.
- Move ProfileBaseModel, the strict base of profile documents, into
  profilestore.
- Serve inverter profiles through the profile REST API. Refuse to delete a
  profile that a configured device uses and that has no packaged profile
  to revert to (409).
- Share the measurement access of the device settings in
  devicemeasurement.
- Rename check_battery_profiles to check_device_profiles; the device
  profile check at configuration setup covers inverters, too.
- Document inverter profiles, their configuration, defaults and sharing;
  regenerate the configuration and OpenAPI documentation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assisted-by: Claude Code (claude-opus-5-5)
2026-11-11 22:08:18 +01:00

24 KiB
Raw Blame History

% SPDX-License-Identifier: Apache-2.0 (resource-page)=

Resources (Device Simulations)

Concepts

The simulations for resources are leaning on general concepts of the [S2 standard].

Control Types

The control of resources and such what a resource simulation will simulate follows three basic control principles:

  • Operation Mode Based Control (OMBC)
  • Fill Rate Based Control (FRBC)
  • Demand Driven Based Control (DDBC)

Although these control principles differ enough to separate them into three distinct control types, there are some common aspects that make them similar:

  • Operation Modes
  • Transitions and
  • Timers.

The objective for a control type is under which circumstances what things can be adjusted, and what the constraints are for these adjustments. The three control types model a virtual, abstract resource for simulation.

The abstract resource ignores all details of pyhsical device that are not relevant to energy management. In addition, physical devices have an enormous variety in parameters, sensors, control strategies, concerns, safeguards, and so on. It would be practically impossible to develop a simulation that can understand all the parameters of all the physical devices on the market. By making the resource more abstract, its concepts can be translated to all sorts of physical devices, even though internally they function very differently. As a consequence, it not always possible to make a 100% accurate description of all the behaviors and constraints in these abstractions. But the abstractions used in the control types are quite powerful, and should allow you to come pretty close.

The control types basically define how the simulated resource can be described. The user in the end selects the proper desciption of a physical device using the configuration options provided for resource simulations. The configuration sets how the simulated resource functions, what it can do and what kind of constraints it has.

Resource Simulation

Based on the description of this virtual resource, the resource simulation can make predictions of what the physical device will do in certain situations, and when it is allowed to execute instructions generated by the optimization as part of the energy management plan evaluation.

Resource Status

Once the physical device has changed it's behavior, the resource simulation should be informed to make the simulation change it's state accordingly.

The actual state of a pyhsical device may be reported to the resource simulation by the PUT /v1/resource/status API endpoint.

Battery

There is a wealth of possible battery operation modes:

Mode Purpose / Behavior Typical Trigger / Context
IDLE Battery neither charges nor discharges (SOC stable). No active control objective or power imbalance below thresholds.
SELF_CONSUMPTION Charge from PV surplus and discharge to cover local load. PV generation > load (charge) or load > PV (discharge).
NON_EXPORT Charge from on-site or local surplus with the goal of minimizing or preventing energy export to the external grid. Discharging to the grid is not allowed. Export limit reached and SOC < SOC_max.
PEAK_SHAVING Discharge to keep grid import below a target threshold. Predicted or measured site load exceeds peak limit.
GRID_SUPPORT_EXPORT Discharge energy to grid for revenue (V2G, wholesale market, flexibility service). Market or signal permits profitable export.
GRID_SUPPORT_IMPORT Charge from grid to absorb surplus or provide up-regulation service. Low-price or grid-support signal detected.
FREQUENCY_REGULATION Rapid charge/discharge response to grid frequency deviations. Active participation in frequency control.
RAMP_RATE_CONTROL Smooth site-level power ramp rates by buffering fluctuations. Sudden PV/load change exceeding ramp limit.
RESERVE_BACKUP Maintain SOC ≥ reserve threshold to ensure backup capacity. Resilience mode active, grid operational.
OUTAGE_SUPPLY Islanded operation: power local loads using stored energy (and PV if available). Grid failure detected.
FORCED_CHARGE Manual or external control command to charge (e.g., pre-event, maintenance). No discharge. Operator or optimizer command.
FORCED_DISCHARGE Manual or external control command to discharge. No charge. Operator or optimizer command.
FAULT Battery unavailable due to fault, safety, or protection state. Fault detected (thermal, voltage, comms, etc.).

The optimization algorithm, the device simulation and the configuration properties only support the most important of these modes.

Battery Simulation

The battery simulation assumes an idealized battery model. Under this model, the battery can be operated in three discrete operation modes with fill rate based control (FRBC):

Operation Mode ID Description
SELF_CONSUMPTION Charge from local surplus and discharge to cover local load.
NON_EXPORT Charge from local surplus and do not discharge.
FORCED_CHARGE Charge.

The operation mode factor (0.0–1.0) specifies the normalized power rate relative to the battery's nominal maximum charge or discharge power. A value of 1.0 corresponds to full-rate charging or discharging, while 0.0 indicates no power transfer. Intermediate values scale the power proportionally.

The fill level (0.0–1.0) specifies the normalized fill level relative to the battery's nominal maximum charge. A value of 1.0 corresponds to full while 0.0 indicates empty. Intermediate values scale the fill level proportionally.

Battery Configuration

The technical data of a battery or electric vehicle comes from a battery profile. The configuration of the device (devices/batteries/<device_id> or devices/electric_vehicles/<device_id>) selects the profile, adjusts it to the installed unit and sets how the battery is operated:

Field Description
battery_profile Battery profile name (without .json), default generic-lfp.
profile_adjustment/nominal_capacity_wh Capacity of the installed unit [Wh]. Replaces the profile's.
profile_adjustment/max_charge_power_w Charge power limit of the installation [W]. Only lowers.
profile_adjustment/max_discharge_power_w Discharge power limit of the installation [W]. Only lowers.
profile_adjustment/full_charge_interval_days Days between two full charges [d]. Replaces the profile's.
profile_adjustment/full_charge_detect_percentage SoC that counts as full [%]. Replaces the profile's.
min_soc_percentage Minimum SoC [%], at least the technical minimum of the profile.
max_soc_percentage Maximum SoC [%], at most the technical maximum of the profile.
"house": {
  "battery_profile": "generic-lfp",
  "profile_adjustment": {
    "nominal_capacity_wh": 10240,
    "max_charge_power_w": 5000,
    "max_discharge_power_w": 5000
  },
  "min_soc_percentage": 10,
  "max_soc_percentage": 95
}

EOS resolves every effective parameter from exactly two sources, the profile and the profile adjustment, evaluated at the operating point (battery temperature and SoC). There are no built-in fallback values:

  • Capacity: profile_adjustment/nominal_capacity_wh, else the nominal capacity of the profile. A generic profile such as generic-lfp describes its limits as C-rates and has no capacity of its own, so the adjustment has to provide it.
  • Power limits: the profile limit maps give the maximum charge and discharge rate per temperature and SoC. The power limits of the adjustment can only lower them. At temperatures outside the hard cutoffs of the profile charging or discharging is inhibited.
  • Efficiencies: the profile efficiency curves at the charge and discharge power.

The GENETIC optimization evaluates the profile at the measured battery temperature, or at 25 °C if no temperature is measured. Its battery simulation then limits the charge and discharge power by the SoC at the start of each charge or discharge step, and takes the charge and discharge efficiency at the power of the slot.

The resolved values are shown as read-only fields of the device configuration (effective_nominal_capacity_wh, effective_max_charge_power_w, effective_max_discharge_power_w, effective_charging_efficiency, effective_discharging_efficiency, effective_min_soc_percentage, effective_max_soc_percentage, effective_full_charge_interval_days, effective_full_charge_detect_percentage). These fields are evaluated at the reference operating point of 25 °C and 50 % SoC.

If a battery cannot be resolved, e.g. its profile does not exist or a generic profile lacks the capacity in the adjustment, its read-only fields are empty (null) and EOS logs an error naming the battery whenever the configuration is set up or changed. A power limit in the adjustment above the profile limit has no effect and is logged as a warning.

The parameter preparation of the GENETIC and GENETIC0 optimizations always succeeds for such a configuration error. It resolves whatever the configuration allows and fills only the rest with the defaults of earlier versions, and it logs an error that names the battery, the problem and the default values used:

  • Profile not usable (missing, unreadable, invalid): the packaged generic profile generic-lfp with the profile adjustment.
  • Generic profile not usable either: the profile adjustment where set, else 8000 Wh, 5000 W charge and discharge power and efficiencies of 0.88, without SoC dependent power limits.
  • Generic profile without capacity in the adjustment: the profile with a capacity of 8000 Wh.
  • SoC range outside the technical SoC bounds of the profile: the technical SoC range.

A profile that inhibits charging at the measured battery temperature is not a configuration error; the optimization reports it as error.

:::{admonition} Note :class: note Configurations of earlier versions are migrated automatically. capacity_wh becomes profile_adjustment/nominal_capacity_wh and max_charge_power_w becomes the installation limit profile_adjustment/max_charge_power_w. A battery that relied on the former defaults gets them written into its profile adjustment (8000 Wh, 5000 W), so its capacity and charge limit do not change. The former fields charging_efficiency and discharging_efficiency are computed from the profile now and are dropped. The periodic full charge settings full_charge_interval_days and full_charge_detect_percentage move into the profile adjustment, cell_chemistry is dropped (the profile has the chemistry). Home Assistant config_entity_ids that point at moved fields are rewritten to the new paths. An entity on the former max_charge_power_w sets both profile_adjustment/max_charge_power_w and profile_adjustment/max_discharge_power_w, unless the discharge limit has its own entity. :::

Battery Profiles

A battery profile is a JSON document with:

  • charge and discharge limit maps over temperature and SoC (as C-rate, W or A), with their axes and units,
  • charge and discharge efficiency curves over the C-rate,
  • technical SoC bounds and hard temperature cutoffs for charging and discharging,
  • the nominal capacity, except for a generic profile,
  • optionally the nominal voltage and model power limits,
  • optionally the cell chemistry and the periodic full charge the battery management system needs to recalibrate its SoC: full_charge_interval_days (none by default) and full_charge_detect_percentage (default 99), see the periodic full charge of the GENETIC optimization.

All of these are required, except the optional ones. Unknown keys are rejected, so a misspelled key fails validation instead of being ignored.

EOS ships the profile generic-lfp for a generic LFP home battery. Profiles are looked up by name first in the user data directory <general/data_folder_path>/profile/battery/ and then in the packaged profiles. Saving a profile always writes to the user data directory; a user profile with the name of a packaged profile replaces it until the user profile is deleted. Changed profiles are used on their next access, without a restart of EOS. A profile name is the file name without .json: letters, digits, ., _ and -, starting with a letter or digit, at most 100 characters. schema is reserved.

Profiles can be managed with the REST API:

Endpoint Description
GET /v1/profile List the profile kinds (battery, inverter).
GET /v1/profile/{kind} List the user and packaged profiles of a kind.
GET /v1/profile/{kind}/schema JSON schema of the profile documents of a kind.
GET /v1/profile/{kind}/{name} Get a profile document.
PUT /v1/profile/{kind}/{name} Validate a profile document and save it as user profile.
DELETE /v1/profile/{kind}/{name} Delete a user profile. Returns the profile that applies instead.

The Profiles page of EOSdash edits battery and inverter profiles as JSON and plots them as EOS evaluates them: for a battery the limit maps and efficiency curves, for an inverter the efficiency curves and the power derating. Edits can be previewed before they are saved.

To share a profile with other users, open it on the Profiles page and press Share. It opens a new issue with the battery or inverter profile form in your browser, filled in with the profile; check it and submit it. EOS sends nothing itself. Reviewed profiles are packaged with EOS.

Battery Stati

To keep the battery simulation in synchonization with the actual stati of the battery the following resource stati may be reported to EOS by the PUT /v1/resource/status API endpoint.

Battery FRBCActuatorStatus

The operation mode the battery is currently operated.

{
  "type": "FRBCActuatorStatus",
  "active_operation_mode_id": "GRID_SUPPORT_IMPORT",
  "operation_mode_factor": "0.375",
  "previous_operation_mode_id": "SELF_CONSUMPTION",
  "transistion_timestamp": "20250725T12:00:12"
}

Battery FRBCStorageStatus

The current battery state of charge (SoC).

{
  "type": "FRBCStorageStatus",
  "present_fill_level": "0.88"
}

Battery PowerMeasurement

The current power that the battery is charged or discharged with [W].

{
  "type": "PowerMeasurement",
  "measurement_timestamp": "20250725T12:00:12",
  "values": [
    {
      "commodity_quantity": "ELECTRIC.POWER.L1",
      "value": "887.5"
    },
    {
      "commodity_quantity": "ELECTRIC.POWER.L2",
      "value": "905.5"
    },
    {
      "commodity_quantity": "ELECTRIC.POWER.L2",
      "value": "1100.7"
    },
  ]
}

For symmetric (or unknown) power distribution:

{
  "type": "PowerMeasurement",
  "measurement_timestamp": "20250725T12:00:12",
  "values": [
    {
      "commodity_quantity": "ELECTRIC.POWER.3_PHASE_SYM",
      "value": "1000"
    }
  ]
}

Electric Vehicle

The electric vehicle is basically a battery with a reduced set of operation modes.

Electric Vehicle Instructions

The electric vehicle control instructions assume an idealized EV battery model. Under this model, the EV battery can be operated in two operation modes:

Operation Mode ID Description
IDLE Battery neither charges nor discharges; holds its state of charge.
FORCED_CHARGE Charge at a specified power rate up to the allowable maximum.

The operation mode factor (0.0–1.0) specifies the normalized power rate relative to the battery's nominal maximum charge power. A value of 1.0 corresponds to full-rate charging, while 0.0 indicates no power transfer. Intermediate values scale the power proportionally.

Inverter

The inverter connects the DC side (PV, battery) with the AC side (household, grid). Its configuration (devices/inverters/<device_id>) is described in the automatic optimization, see the inverter simulation configuration there.

(inverter-profiles)=

Inverter Profiles

The technical data of an inverter comes from an inverter profile, a JSON document with:

  • the DC→AC efficiency curve (battery discharge) and the AC→DC efficiency curve (charging the battery from the grid) over the load fraction, the AC power relative to the nominal power,
  • the nominal AC power, except for a generic profile,
  • optionally the AC charge power limit of the model (max_ac_charge_power_w) and whether this limit also limits PV charging of the battery (ac_charge_limits_total_charge, e.g. some hybrid inverters in time-of-use grid charging),
  • optionally the power derating over the ambient temperature (power_derating: the allowed fraction of the nominal power at each temperature).

The curves are read linearly between their breakpoints and held at their end values beyond them. Unknown keys are rejected.

{
  "inverter_model": "My hybrid inverter",
  "nominal_power_w": 10000,
  "dc_to_ac_efficiency": {
    "load_fraction": [0.05, 0.2, 0.5, 1.0],
    "efficiency": [0.88, 0.955, 0.97, 0.965]
  },
  "ac_to_dc_efficiency": {
    "load_fraction": [0.05, 0.2, 0.5, 1.0],
    "efficiency": [0.86, 0.95, 0.965, 0.96]
  },
  "power_derating": {
    "temperature_degC": [45.0, 60.0],
    "power_fraction": [1.0, 0.6]
  }
}

EOS ships the profile generic-hybrid with typical efficiencies of a hybrid inverter, no nominal power (set profile_adjustment.nominal_power_w) and full power up to 45 °C. EOS evaluates the derating at the ambient temperature measured as <device_id>-temperature-degc, or at 45 °C without a measurement. Inverter profiles are stored, looked up and managed like battery profiles (kind inverter, user directory <general/data_folder_path>/profile/inverter/), with the same REST API and the Profiles page of EOSdash.

The optimization always gets valid inverter parameters. If they cannot be resolved, EOS logs an error and uses defaults: the profile generic-hybrid for an unusable profile, a nominal power of 10000 W if none is set, and the parameters at 45 °C if the inverter is derated to zero power at the measured temperature.

Home Appliance

The optimization algorithm supports one start of the home appliance within the optimization horizon.

Home Appliance Simulation

GENETIC0 Home Appliance Configuration

Home appliance to run within the optimization horizon.

{
  "dishwasher1": {
    "device_id": "dishwasher1",
    "consumption_wh": 2000,
    "duration_h": 3
  }
}

Home appliance to run within a time window of 5 hours starting at 8:00 every day and another time window of 3 hours starting at 15:00 every day. See Time Window Sequence Configuration for more information.

{
  "dishwasher1": {
    "device_id": "dishwasher1",
    "consumption_wh": 2000,
    "duration_h": 3,
    "time_windows": {
      "windows": [
        {
          "start_time": "08:00",
          "duration": "5 hours"
        },
        {
          "start_time": "15:00",
          "duration": "3 hours"
        }
      ]
    }
  }
}

:::{admonition} Note :class: note The optimization algorithm always restricts to one start within the optimization horizon per energy management run. :::

GENETIC Home Appliance Configuration

Home appliance to run once, unconstrained, within the optimization horizon:

{
  "dishwasher1": {
    "device_id": "dishwasher1",
    "consumption_wh": 2000,
    "duration_h": 3,
    "num_cycles": 1
  }
}

Home appliance to run within a time window of 5 hours starting at 8:00. Each window's value field carries the 0-based cycle index it applies to -- here there is only one cycle (index 0), so num_cycles does not need to be set explicitly; it is derived from the distinct cycle indices found in cycle_time_windows. See ime Window Sequence Configuration for more information.

{
  "dishwasher1": {
    "device_id": "dishwasher1",
    "consumption_wh": 2000,
    "duration_h": 3,
    "cycle_time_windows": {
      "windows": [
        {
          "start_time": "08:00",
          "duration": "5 hours",
          "value": 0
        }
      ]
    }
  }
}

Home appliance that must run twice per day, each run confined to its own time window -- cycle 0 in the morning (07:00, 5 hours), cycle 1 in the evening (17:00, 5 hours) -- with at least 1 hour idle between the two runs:

{
  "washing_machine1": {
    "device_id": "washing_machine1",
    "consumption_wh": 2000,
    "duration_h": 2,
    "min_cycle_gap_h": 1,
    "cycle_time_windows": {
      "windows": [
        {
          "start_time": "07:00",
          "duration": "5 hours",
          "value": 0
        },
        {
          "start_time": "17:00",
          "duration": "5 hours",
          "value": 1
        }
      ]
    }
  }
}

min_cycle_gap_h enforces a minimum idle time between the end of one cycle and the start of the next; it defaults to 0, which permits back-to-back runs. To let both cycles run anywhere in a shared window instead of separate morning/evening slots, give both windows the same start_time and duration but keep their distinct value (cycle index) -- the optimizer still places each cycle independently within that shared window.

How many cycles remain to be scheduled on a given energy management run is read at runtime from the measurement store, under the key configured in cycles_completed_measurement_key (defaults to {device_id}.cycles_completed). This lets the optimizer skip cycles the appliance has already completed earlier the same day.

:::{admonition} Note :class: note Unlike GENETIC0, the GENETIC algorithm can plan multiple cycles -- and therefore multiple starts -- of the same appliance within a single energy management run, whenever num_cycles (or the number of distinct cycle indices in cycle_time_windows) is greater than 1. :::

Home Appliance Instructions

The home appliance instructions assume an idealized home appliance model. Under this model, the home appliance can be operated in two operation modes:

Operation Mode ID Description
RUN The home appliance is started and runs until the end of it's power
sequence.
OFF The home appliance does not run.

The operation mode factor (0.0–1.0) is ignored.