flexmeasures.data.schemas.scheduling
Modules
These descriptions are used in documentation/features/scheduling.rst and in OpenAPI. If you need to use a new .rst directive, update make_openapi_compatible accordingly, so it shows up nicely in OpenAPI. For instance: - the X directive is converted to a <abbr title="Y">X</abbr> HTML tag. - any footnote references, such as [#quantity_field]_, are stripped (these are meant for .rst docs to explain field types, which in OpenAPI is redundant, given that each field is already documented as being of an explicit type). |
|
Classes
- class flexmeasures.data.schemas.scheduling.AssetTriggerSchema(*, only: Sequence[str] | AbstractSet[str] | None = None, exclude: Sequence[str] | AbstractSet[str] = (), many: bool | None = None, load_only: Sequence[str] | AbstractSet[str] = (), dump_only: Sequence[str] | AbstractSet[str] = (), partial: bool | Sequence[str] | AbstractSet[str] | None = None, unknown: Literal['exclude', 'include', 'raise'] | None = None)
- {
“start”: “2025-01-21T15:00+01”, “flex-model”: [
- {
“sensor”: 1, “soc-at-start”: “10 kWh”
}, {
“sensor”: 2, “soc-at-start”: “20 kWh”
},
]
}
- check_flex_model_sensors(data, **kwargs)
Verify that the flex-model’s sensors live under the asset for which a schedule is triggered.
- normalize_flex_context_format(data, **kwargs)
Normalize flex_context to always be a dict.
Accepts both: - Single commodity dict: {“commodity”: “electricity”, …} - List of commodity dicts: [{“commodity”: “electricity”, …}, {“commodity”: “heat”, …}] - MultiDict with multiple ‘flex-context’ entries (when JSON list is parsed by webargs)
If a list is provided, it is wrapped under the ‘commodities’ field. If a dict is provided, it is kept as-is. This ensures downstream code always sees a dict structure.
- class flexmeasures.data.schemas.scheduling.CommitmentSchema(*, only: Sequence[str] | AbstractSet[str] | None = None, exclude: Sequence[str] | AbstractSet[str] = (), many: bool | None = None, load_only: Sequence[str] | AbstractSet[str] = (), dump_only: Sequence[str] | AbstractSet[str] = (), partial: bool | Sequence[str] | AbstractSet[str] | None = None, unknown: Literal['exclude', 'include', 'raise'] | None = None)
- class flexmeasures.data.schemas.scheduling.CommodityFlexContextSchema(*args, **kwargs)
- __init__(*args, **kwargs)
- _default_zero_capacity_as_soft_constraint(data: dict, field: str, zero_capacity: Quantity)
Default a site capacity field to 0, as a soft constraint.
Also fills in a default breach price for that direction (unless one was already set), so the 0 capacity is enforced as a soft constraint (breaching is possible, but penalized) rather than a hard, potentially infeasible, one. This mirrors FlexContextSchema.check_prices, but scoped to a single commodity context, and only fired for capacities defaulted here (not for capacities the caller explicitly set to 0).
- fill_grid_connection_defaults(data: dict, original_data: dict, **kwargs)
Fill in smarter defaults for a commodity context’s grid-connection fields.
A commodity context (an entry of the top-level commodities list) may omit some or all of the grid-connection fields (consumption-price, production-price, site-consumption-capacity, site-production-capacity, site-power-capacity). Rather than leaving those simply unset (which, for consumption-price, would make the scheduler fail, since it requires one), we derive sensible defaults from which of those five fields were explicitly given (inspecting the original input, not post-default-fill presence).
A price given for a direction (consumption or production) implies a grid connection in that direction, with an unlimited capacity unless a capacity is also given; a capacity given for a direction (without a price) implies a 0 price in that direction; and anything not implied by a given field defaults to “no connection” (0 capacity, as a soft constraint). The exception is site-power-capacity given on its own, which sets a hard (symmetric) capacity limit instead. See Smart defaults for commodity-context grid connections for the full user-facing explanation, including worked examples.
Precedence (single-field triggers):
None of the five given (e.g. just {“commodity”: “gas”}): no grid connection at all. site-consumption-capacity and site-production-capacity default to 0, as soft constraints (a default breach price is filled in, so breaching is possible but penalized – this relies on relax-constraints/relax-site-capacity-constraints, which default to True). site-power-capacity is left unlimited (unset).
Only consumption-price given: assume a grid connection for consumption. site-power-capacity and site-consumption-capacity stay unlimited. site-production-capacity defaults to 0 (soft).
Only production-price given: the mirror image of (2), for production.
Only site-consumption-capacity given: site-power-capacity stays unlimited; consumption-price defaults to 0; site-production-capacity (and, transitively, production-price) default to 0.
Only site-production-capacity given: the mirror image of (4).
Only site-power-capacity given: a hard constraint at that capacity. site-consumption-capacity and site-production-capacity are both set equal to it (no breach price is filled in, so the constraint stays hard); consumption-price and production-price default to 0.
As a safety net (since the scheduler requires a resolvable consumption price), consumption-price defaults to 0 if still unset after applying the rules above (production-price already falls back to consumption-price at the scheduler level, so no separate safety net is needed for it).
A commodity context with no user-given price fields does not trip a spurious cross-currency error against a differently-currencied portfolio; its 0-price/breach-price fields instead inherit the portfolio’s real currency where determinable (from a top-level price or a sibling commodity context).
- class flexmeasures.data.schemas.scheduling.DBCommitmentSchema(*, only: Sequence[str] | AbstractSet[str] | None = None, exclude: Sequence[str] | AbstractSet[str] = (), many: bool | None = None, load_only: Sequence[str] | AbstractSet[str] = (), dump_only: Sequence[str] | AbstractSet[str] = (), partial: bool | Sequence[str] | AbstractSet[str] | None = None, unknown: Literal['exclude', 'include', 'raise'] | None = None)
- class flexmeasures.data.schemas.scheduling.DBFlexContextSchema(*, only: Sequence[str] | AbstractSet[str] | None = None, exclude: Sequence[str] | AbstractSet[str] = (), many: bool | None = None, load_only: Sequence[str] | AbstractSet[str] = (), dump_only: Sequence[str] | AbstractSet[str] = (), partial: bool | Sequence[str] | AbstractSet[str] | None = None, unknown: Literal['exclude', 'include', 'raise'] | None = None)
- _forbid_fixed_prices(data: dict, **kwargs)
Do not allow fixed consumption price or fixed production price in the flex-context fields saved in the db.
This is a temporary restriction as future iterations will allow fixed prices on these fields as well.
- class flexmeasures.data.schemas.scheduling.FlexContextSchema(*, only: Sequence[str] | AbstractSet[str] | None = None, exclude: Sequence[str] | AbstractSet[str] = (), many: bool | None = None, load_only: Sequence[str] | AbstractSet[str] = (), dump_only: Sequence[str] | AbstractSet[str] = (), partial: bool | Sequence[str] | AbstractSet[str] | None = None, unknown: Literal['exclude', 'include', 'raise'] | None = None)
This schema defines fields that provide context to the portfolio to be optimized.
- _check_deprecated_price_sensor_migration(data: dict, original_data: dict)
New price fields can only be used after updating to consumption-price/production-price.
- _reconcile_commodity_context_currencies(data: dict) str
Backfill price-free contexts’ currency with the portfolio’s real currency.
Determines the portfolio’s real (user-given) shared currency, if any: the top-level one, unless it’s itself just a fallback (no user-given price fields at the top level), in which case falls back to the first non-default commodity context’s currency, if any. Then rebases any price-free (“default currency”) commodity context onto that real currency, so their 0-price/breach-price fills inherit it. Returns the (possibly just-updated) top-level shared_currency_unit.
- check_prices(data: dict, original_data: dict, **kwargs)
Check assumptions about prices.
The flex-context must contain at most 1 consumption price and at most 1 production price field.
All prices must share the same currency.
Validate that all prices across commodity contexts share the same currency.
Each commodity context already computed its own normalized
shared_currency_unit(a base-unit currency string, e.g. “EUR”) via the inherited_try_to_convert_price_unitsschema-level validator. We simply compare those.
- class flexmeasures.data.schemas.scheduling.GetScheduleSchema(*, only: Sequence[str] | AbstractSet[str] | None = None, exclude: Sequence[str] | AbstractSet[str] = (), many: bool | None = None, load_only: Sequence[str] | AbstractSet[str] = (), dump_only: Sequence[str] | AbstractSet[str] = (), partial: bool | Sequence[str] | AbstractSet[str] | None = None, unknown: Literal['exclude', 'include', 'raise'] | None = None)
- class flexmeasures.data.schemas.scheduling.MultiSensorFlexModelSchema(*, only: Sequence[str] | AbstractSet[str] | None = None, exclude: Sequence[str] | AbstractSet[str] = (), many: bool | None = None, load_only: Sequence[str] | AbstractSet[str] = (), dump_only: Sequence[str] | AbstractSet[str] = (), partial: bool | Sequence[str] | AbstractSet[str] | None = None, unknown: Literal['exclude', 'include', 'raise'] | None = None)
This schema is agnostic to the underlying type of flex-model, which is governed by the chosen Scheduler instead. Therefore, the underlying type of flex-model is not deserialized.
So:
- {
“sensor”: 1, “soc-at-start”: “10 kWh”
}
becomes:
- {
“sensor”: <Sensor 1>, “sensor_flex_model”: {
“soc-at-start”: “10 kWh”
}
}
- unwrap_envelope(data, **kwargs)
Any field other than ‘sensor’ and ‘asset’ becomes part of the sensor’s flex-model.
- wrap_with_envelope(data, **kwargs)
Any field in the ‘sensor-flex-model’ field becomes a main field.
- class flexmeasures.data.schemas.scheduling.NoTimeSeriesSpecs(*, only: Sequence[str] | AbstractSet[str] | None = None, exclude: Sequence[str] | AbstractSet[str] = (), many: bool | None = None, load_only: Sequence[str] | AbstractSet[str] = (), dump_only: Sequence[str] | AbstractSet[str] = (), partial: bool | Sequence[str] | AbstractSet[str] | None = None, unknown: Literal['exclude', 'include', 'raise'] | None = None)
- class flexmeasures.data.schemas.scheduling.ScheduleSignConvention
Named constants for the three sign-convention modes of the get_schedule endpoint.
- Variables:
CONSUMPTION_POSITIVE – Always return schedules with consumption as positive values and production as negative values. This is the default and matches the view a consumer has of their device.
PRODUCTION_POSITIVE – Always return schedules with production as positive values and consumption as negative values. This matches the view a producer (or generator) has of their device.
WYSIWYG – Return the raw values from the database without any sign inversion, regardless of the sensor’s
consumption_is_positiveattribute. Useful when you want to see exactly what was stored.
Shared schema for fields common across commodities in flex-context and commodity-context.
Re-express a price-free context’s fallback-currency fields in another currency.
Only called for a commodity context that had no user-given price fields (
shared_currency_unit_is_defaultis True), once a real portfolio currency becomes known (e.g. from the top-level flex-context, or from a sibling commodity context). All of that context’s currency-denominated fields were filled with plain quantities in a fallback “EUR”, so their magnitudes carry over unchanged under the new currency label (no FX conversion is implied or attempted).
Convert a price unit to a base currency used to express that price per MWh.
>>> FlexContextSchema()._to_currency_per_mwh("EUR/MWh") 'EUR' >>> FlexContextSchema()._to_currency_per_mwh("EUR/kWh") 'EUR'
Convert price units to the same unit and scale if they can (incl. same currency).
Dictionary mapping field_names ->
Fieldobjects
Fill in default breach prices.
This relies on _try_to_convert_price_units to run first, setting a shared currency unit.