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)
This commit is contained in:
Bobby Noelte
2026-11-11 22:08:18 +01:00
co-authored by Claude Opus 5.5
parent e255f987bf
commit faf37abfe7
45 changed files with 3235 additions and 784 deletions
+221 -263
View File
@@ -8,7 +8,7 @@
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "v0.3.0.dev2611111415621708"
"version": "v0.3.0.dev2611111434732824"
},
"paths": {
"/v1/measurement/battery-capacity/{battery_id}": {
@@ -583,7 +583,7 @@
"profile"
],
"summary": "Delete Profile",
"description": "Delete a user profile.\n\nReturns the profile that applies now (the packaged one of the same name),\nor null if there is none.",
"description": "Delete a user profile.\n\nReturns the profile that applies now (the packaged one of the same name),\nor null if there is none. A profile that a configured device uses can only\nbe deleted if a packaged profile of the same name applies afterwards.",
"operationId": "delete_profile_v1_profile__kind___name__delete",
"parameters": [
{
@@ -12414,114 +12414,39 @@
"dishwasher"
]
},
"max_power_w": {
"anyOf": [
"inverter_profile": {
"type": "string",
"minLength": 1,
"title": "Inverter Profile",
"description": "Name of the inverter profile (without '.json') providing the nominal power, efficiency curves, AC charge power limit and power derating. Differences of this unit go into 'profile_adjustment'.",
"default": "generic-hybrid",
"examples": [
"generic-hybrid"
],
"x-scope": [
"GENETIC",
"GENETIC0"
]
},
"profile_adjustment": {
"$ref": "#/components/schemas/InverterProfileAdjustment",
"description": "How this inverter unit differs from its inverter profile: nominal power and installation limits.",
"examples": [
{
"type": "number",
"exclusiveMinimum": 0.0
},
{
"type": "null"
"nominal_power_w": 10000
}
],
"title": "Max Power W",
"description": "Maximum AC output power [W].",
"examples": [
10000
],
"x-scope": [
"GENETIC",
"GENETIC0"
]
},
"ac_to_dc_efficiency": {
"type": "number",
"maximum": 1.0,
"minimum": 0.0,
"title": "Ac To Dc Efficiency",
"description": "Efficiency of AC\u2192DC conversion for grid-to-battery charging (0\u20131). Set to 0 to disable AC charging. Default 1.0.",
"default": 1.0,
"examples": [
0.95,
1.0,
0.0
],
"x-scope": [
"GENETIC",
"GENETIC0"
]
},
"dc_to_ac_efficiency": {
"type": "number",
"maximum": 1.0,
"exclusiveMinimum": 0.0,
"title": "Dc To Ac Efficiency",
"description": "Efficiency of DC\u2192AC conversion for battery discharging (0\u20131). Default 1.0.",
"default": 1.0,
"examples": [
0.95,
1.0
],
"x-scope": [
"GENETIC",
"GENETIC0"
]
},
"dc_to_ac_efficiency_curve": {
"anyOf": [
{
"items": {
"prefixItems": [
{
"type": "number"
},
{
"type": "number"
}
],
"type": "array",
"maxItems": 2,
"minItems": 2
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Dc To Ac Efficiency Curve",
"description": "Load-dependent efficiency of DC\u2192AC conversion for battery discharging as a list of [load_fraction, efficiency] points. The load fraction is the AC power relative to max_power_w (0\u20131); points must be strictly increasing in load fraction, efficiencies in (0, 1]. Values are interpolated linearly and clamped to the first/last point. When set, the curve replaces dc_to_ac_efficiency. null keeps the constant dc_to_ac_efficiency. Default null.",
"examples": [
null,
[
[
0.02,
0.8
],
[
0.07,
0.93
],
[
0.3,
0.96
],
[
1.0,
0.95
]
]
],
"x-scope": [
"GENETIC"
]
},
"dc_to_ac_efficiency_reference_load_fraction": {
"type": "number",
"maximum": 1.0,
"minimum": 0.0,
"title": "Dc To Ac Efficiency Reference Load Fraction",
"description": "Load fraction of max_power_w (0\u20131) at which dc_to_ac_efficiency_curve is evaluated to value stored battery energy without a specific conversion (remaining energy at the end of the horizon, AC charge break-even). Should represent the typical load served by the battery, e.g. the night-time base load. Only used with dc_to_ac_efficiency_curve. Default 0.06.",
"description": "Load fraction of the effective maximum power (0\u20131) at which the DC\u2192AC efficiency curve is evaluated to value stored battery energy without a specific conversion (remaining energy at the end of the horizon, AC charge break-even). Should represent the typical load served by the battery, e.g. the night-time base load. Default 0.06.",
"default": 0.06,
"examples": [
0.06,
@@ -12531,41 +12456,6 @@
"GENETIC"
]
},
"max_ac_charge_power_w": {
"anyOf": [
{
"type": "number",
"minimum": 0.0
},
{
"type": "null"
}
],
"title": "Max Ac Charge Power W",
"description": "Maximum AC charging power [W]. null means no additional limit. 0 disables AC charging.",
"examples": [
null,
0,
5000
],
"x-scope": [
"GENETIC",
"GENETIC0"
]
},
"ac_charge_limits_total_charge": {
"type": "boolean",
"title": "Ac Charge Limits Total Charge",
"description": "True if the AC charge setpoint caps the battery's total charge power, PV included. Some hybrid inverters (e.g. Deye in time-of-use grid charging) limit the whole charge current to the grid charge current; PV surplus above it is exported, not stored. False keeps the default model: PV surplus charges first and the grid adds ac_charge x max_charge_power_w on top.",
"default": false,
"examples": [
false,
true
],
"x-scope": [
"GENETIC"
]
},
"battery_id": {
"anyOf": [
{
@@ -12889,114 +12779,39 @@
"dishwasher"
]
},
"max_power_w": {
"anyOf": [
"inverter_profile": {
"type": "string",
"minLength": 1,
"title": "Inverter Profile",
"description": "Name of the inverter profile (without '.json') providing the nominal power, efficiency curves, AC charge power limit and power derating. Differences of this unit go into 'profile_adjustment'.",
"default": "generic-hybrid",
"examples": [
"generic-hybrid"
],
"x-scope": [
"GENETIC",
"GENETIC0"
]
},
"profile_adjustment": {
"$ref": "#/components/schemas/InverterProfileAdjustment",
"description": "How this inverter unit differs from its inverter profile: nominal power and installation limits.",
"examples": [
{
"type": "number",
"exclusiveMinimum": 0.0
},
{
"type": "null"
"nominal_power_w": 10000
}
],
"title": "Max Power W",
"description": "Maximum AC output power [W].",
"examples": [
10000
],
"x-scope": [
"GENETIC",
"GENETIC0"
]
},
"ac_to_dc_efficiency": {
"type": "number",
"maximum": 1.0,
"minimum": 0.0,
"title": "Ac To Dc Efficiency",
"description": "Efficiency of AC\u2192DC conversion for grid-to-battery charging (0\u20131). Set to 0 to disable AC charging. Default 1.0.",
"default": 1.0,
"examples": [
0.95,
1.0,
0.0
],
"x-scope": [
"GENETIC",
"GENETIC0"
]
},
"dc_to_ac_efficiency": {
"type": "number",
"maximum": 1.0,
"exclusiveMinimum": 0.0,
"title": "Dc To Ac Efficiency",
"description": "Efficiency of DC\u2192AC conversion for battery discharging (0\u20131). Default 1.0.",
"default": 1.0,
"examples": [
0.95,
1.0
],
"x-scope": [
"GENETIC",
"GENETIC0"
]
},
"dc_to_ac_efficiency_curve": {
"anyOf": [
{
"items": {
"prefixItems": [
{
"type": "number"
},
{
"type": "number"
}
],
"type": "array",
"maxItems": 2,
"minItems": 2
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Dc To Ac Efficiency Curve",
"description": "Load-dependent efficiency of DC\u2192AC conversion for battery discharging as a list of [load_fraction, efficiency] points. The load fraction is the AC power relative to max_power_w (0\u20131); points must be strictly increasing in load fraction, efficiencies in (0, 1]. Values are interpolated linearly and clamped to the first/last point. When set, the curve replaces dc_to_ac_efficiency. null keeps the constant dc_to_ac_efficiency. Default null.",
"examples": [
null,
[
[
0.02,
0.8
],
[
0.07,
0.93
],
[
0.3,
0.96
],
[
1.0,
0.95
]
]
],
"x-scope": [
"GENETIC"
]
},
"dc_to_ac_efficiency_reference_load_fraction": {
"type": "number",
"maximum": 1.0,
"minimum": 0.0,
"title": "Dc To Ac Efficiency Reference Load Fraction",
"description": "Load fraction of max_power_w (0\u20131) at which dc_to_ac_efficiency_curve is evaluated to value stored battery energy without a specific conversion (remaining energy at the end of the horizon, AC charge break-even). Should represent the typical load served by the battery, e.g. the night-time base load. Only used with dc_to_ac_efficiency_curve. Default 0.06.",
"description": "Load fraction of the effective maximum power (0\u20131) at which the DC\u2192AC efficiency curve is evaluated to value stored battery energy without a specific conversion (remaining energy at the end of the horizon, AC charge break-even). Should represent the typical load served by the battery, e.g. the night-time base load. Default 0.06.",
"default": 0.06,
"examples": [
0.06,
@@ -13006,41 +12821,6 @@
"GENETIC"
]
},
"max_ac_charge_power_w": {
"anyOf": [
{
"type": "number",
"minimum": 0.0
},
{
"type": "null"
}
],
"title": "Max Ac Charge Power W",
"description": "Maximum AC charging power [W]. null means no additional limit. 0 disables AC charging.",
"examples": [
null,
0,
5000
],
"x-scope": [
"GENETIC",
"GENETIC0"
]
},
"ac_charge_limits_total_charge": {
"type": "boolean",
"title": "Ac Charge Limits Total Charge",
"description": "True if the AC charge setpoint caps the battery's total charge power, PV included. Some hybrid inverters (e.g. Deye in time-of-use grid charging) limit the whole charge current to the grid charge current; PV surplus above it is exported, not stored. False keeps the default model: PV surplus charges first and the grid adds ac_charge x max_charge_power_w on top.",
"default": false,
"examples": [
false,
true
],
"x-scope": [
"GENETIC"
]
},
"battery_id": {
"anyOf": [
{
@@ -13346,18 +13126,95 @@
"UNUSED"
]
},
"effective_nominal_power_w": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Effective Nominal Power W",
"description": "Effective nominal AC power [W]: profile adjustment, else profile.",
"readOnly": true
},
"effective_max_power_w": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Effective Max Power W",
"description": "Maximum AC power [W] at the reference temperature, derated and capped.",
"readOnly": true
},
"effective_max_ac_charge_power_w": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Effective Max Ac Charge Power W",
"description": "AC charge power limit [W] at the reference temperature; 0 disables AC charging.",
"readOnly": true
},
"effective_dc_to_ac_efficiency": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Effective Dc To Ac Efficiency",
"description": "DC\u2192AC efficiency at the reference load fraction.",
"readOnly": true
},
"effective_ac_to_dc_efficiency": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Effective Ac To Dc Efficiency",
"description": "AC\u2192DC efficiency at the AC charge power limit.",
"readOnly": true
},
"measurement_key_temperature_degc": {
"type": "string",
"title": "Measurement Key Temperature Degc",
"description": "Measurement key for the ambient temperature of the inverter [degC].",
"readOnly": true
},
"measurement_keys": {
"items": {
"type": "string"
},
"type": "array",
"title": "Measurement Keys",
"description": "Measurement keys for this inverter.\n\nReturns the ``battery_initial_soc_factor_key`` if non-empty, so\nthe EMS measurement store knows to watch for this key.",
"description": "Measurement keys for this inverter.\n\nThe ambient temperature, and the ``battery_initial_soc_factor_key`` if\nnon-empty, so the EMS measurement store knows to watch for them.",
"readOnly": true
}
},
"type": "object",
"required": [
"effective_nominal_power_w",
"effective_max_power_w",
"effective_max_ac_charge_power_w",
"effective_dc_to_ac_efficiency",
"effective_ac_to_dc_efficiency",
"measurement_key_temperature_degc",
"measurement_keys"
],
"title": "InverterCommonSettings",
@@ -13496,6 +13353,48 @@
0.1
]
},
"ac_to_dc_efficiency_curve": {
"anyOf": [
{
"items": {
"prefixItems": [
{
"type": "number"
},
{
"type": "number"
}
],
"type": "array",
"maxItems": 2,
"minItems": 2
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Ac To Dc Efficiency Curve",
"description": "Load-dependent efficiency of AC to DC conversion (AC/grid charging of the battery) as a list of (load_fraction, efficiency) points. The load fraction is the AC power drawn relative to max_power_wh [0.0 ... 1.0]; same rules as dc_to_ac_efficiency_curve. When set, the curve replaces ac_to_dc_efficiency for the energy drawn from the grid; ac_to_dc_efficiency still converts the AC charge power limit and should be the efficiency at that limit. Default None (constant ac_to_dc_efficiency).",
"examples": [
null,
[
[
0.05,
0.86
],
[
0.3,
0.96
],
[
1.0,
0.96
]
]
]
},
"max_ac_charge_power_w": {
"anyOf": [
{
@@ -13534,6 +13433,65 @@
"title": "InverterParameters",
"description": "Inverter Device Simulation Configuration."
},
"InverterProfileAdjustment": {
"properties": {
"nominal_power_w": {
"anyOf": [
{
"type": "number",
"exclusiveMinimum": 0.0
},
{
"type": "null"
}
],
"title": "Nominal Power W",
"description": "Nominal AC power of the installed inverter [W]. Replaces the nominal power of the inverter profile. Required if the profile is generic and provides no nominal power. The effective value is available as 'effective_nominal_power_w'.",
"examples": [
null,
10000
]
},
"max_power_w": {
"anyOf": [
{
"type": "number",
"exclusiveMinimum": 0.0
},
{
"type": "null"
}
],
"title": "Max Power W",
"description": "Maximum AC power of the installation [W], e.g. a configured output limit. Can only lower the (derated) nominal power. The effective value is available as 'effective_max_power_w'.",
"examples": [
null,
8000
]
},
"max_ac_charge_power_w": {
"anyOf": [
{
"type": "number",
"minimum": 0.0
},
{
"type": "null"
}
],
"title": "Max Ac Charge Power W",
"description": "AC charge power limit of the installation [W]. Can only lower the limit of the inverter profile. 0 disables AC charging. The effective value is available as 'effective_max_ac_charge_power_w'.",
"examples": [
null,
0,
5000
]
}
},
"type": "object",
"title": "InverterProfileAdjustment",
"description": "How an inverter unit differs from its inverter profile.\n\nNone keeps the profile value."
},
"LoadAkkudoktorCommonSettings": {
"properties": {
"loadakkudoktor_year_energy_kwh": {