Repository navigation
docs(changelog): say each S2 change plainly - #283
Conversation
Rewrite the Unreleased entries of CHANGELOG-S2.rst, and the three this work added to CHANGELOG.rst, for legibility: lead with what changes for the reader, in short sentences with plain word order, and split the longest entries into a lead sentence and a list. No claim is added or dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW Signed-off-by: F.N. Claessen <claessen@seita.nl>
Coverage Report for CI Build 42489871952Warning No base build found for commit Coverage: 95.175%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsRequires a base build to compare against. How to fix this → Coverage Stats
💛 - Coveralls |
A check of every entry against the text it replaced found the rewrite had given the charging-efficiency risk a direction (wrong for a heat pump, whose COP exceeds one), made "a lower bound" of the hard upper bound, and dropped or shifted several smaller facts: planning from an unrecorded state of charge, the storage efficiency named only once confirmed, the DST boundary rule, abnormal modes being left out of both capacities and bands, power being converted into power_unit, polling, and the handler always tracking the batch in force. Restore each. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW Signed-off-by: F.N. Claessen <claessen@seita.nl>
| * ``FRBCSimple`` can record what a resource manager declares about its storage, so it can be seen and planned with. Give it any of the new ``soc_minima_sensor_id``, ``soc_maxima_sensor_id``, ``usage_forecast_sensor_id`` and ``leakage_behaviour_sensor_id``; a declaration without a sensor is not recorded. | ||
|
|
||
| - A fill-level target profile is recorded on the minima and maxima sensors, if both are given. It is recorded on the handler's ``resolution`` steps, starting from the step its start falls in. It is kept inside the declared fill-level range: a target past either end, such as a night setback below the range, is cut back to the range, and a target band wholly outside the range is recorded at its nearest end, with a warning. If one of the two bounds cannot be recorded, this is logged and the other is still recorded. | ||
| - A usage forecast is recorded in ``<energy_unit>/s``. A negative expected usage is recorded as zero, with a warning. |
There was a problem hiding this comment.
Even though RMs are expected to use negative expected usage to model soc-gain? Sounds like this decision is a CEM side workaround to remedy a problem in a specific RM for a specific use case.
There was a problem hiding this comment.
Agreed. S2 allows a negative expected usage, and clipping it was added on the CEM side to keep plans feasible, not because the protocol forbids it.
Recording and planning are separate questions, though. I'd record what the resource manager states, always, and only decide at planning time what to do with a usage the storage cannot absorb. #286 already records it as stated when the usage correction is on. I propose to make that the default: record as stated in every case, and without a correction, clip only the forecast sent with the schedule request, as #286 already does when the correction is unavailable. I'd do that in #286.
There was a problem hiding this comment.
| - A leakage behaviour is recorded as a storage efficiency, each time a schedule is requested (see Changed). | ||
|
|
||
| [`#244 <https://github.com/FlexMeasures/flexmeasures-client/pull/244>`__, `#259 <https://github.com/FlexMeasures/flexmeasures-client/pull/259>`__, `#271 <https://github.com/FlexMeasures/flexmeasures-client/pull/271>`__, `#274 <https://github.com/FlexMeasures/flexmeasures-client/pull/274>`__] | ||
| * ``FRBCSimple`` takes an ``energy_unit`` (default ``kWh``). The state of charge, the fill-level band, the fill rate and the usage forecast are recorded in this unit (the last two per second). Allowed units are ``J``, ``kJ``, ``MJ``, ``Wh``, ``kWh`` and ``MWh``; any other unit is refused when the handler is created. In a flex model, the state of charge is stated in ``kWh`` or ``MWh``, converted from the other units, because FlexMeasures accepts no others [`#244 <https://github.com/FlexMeasures/flexmeasures-client/pull/244>`__, `#260 <https://github.com/FlexMeasures/flexmeasures-client/pull/260>`__] |
There was a problem hiding this comment.
Potential FM issue (maybe already exists) to allow arbitrary fill level units, maybe even arbitrary flow units. Conversion efficiencies would require matching units, e.g. kWh/(kW•h) for fill level delta per integral of power (i.e. our old % unit), or °C/(kW•h) when a fill level is recorded in degrees Celsius.
There was a problem hiding this comment.
There wasn't one yet (#1796 and #1995 only cover percentages), so I opened FlexMeasures/flexmeasures#2847, with your examples of matching efficiency units and a cross-reference to #2832.
| * ``FRBCSimple`` takes an ``energy_unit`` (default ``kWh``). The state of charge, the fill-level band, the fill rate and the usage forecast are recorded in this unit (the last two per second). Allowed units are ``J``, ``kJ``, ``MJ``, ``Wh``, ``kWh`` and ``MWh``; any other unit is refused when the handler is created. In a flex model, the state of charge is stated in ``kWh`` or ``MWh``, converted from the other units, because FlexMeasures accepts no others [`#244 <https://github.com/FlexMeasures/flexmeasures-client/pull/244>`__, `#260 <https://github.com/FlexMeasures/flexmeasures-client/pull/260>`__] | ||
| * ``FRBCSimple`` takes a ``fill_level_scale`` (default 1). Every fill level and fill rate sent to FlexMeasures is multiplied by it: the state of charge, the flex model, the fill-level band, the fill rate, the usage forecast and the storage efficiency. Translating a schedule into instructions keeps the resource manager's own units, because it matches fill levels against the operation modes, which are stated in those units. A scale of zero or below is refused. ``FRBCSimple`` also takes a ``power_unit`` (default ``W``), which an actuator's power is converted into and posted in [`#236 <https://github.com/FlexMeasures/flexmeasures-client/pull/236>`__, `#244 <https://github.com/FlexMeasures/flexmeasures-client/pull/244>`__, `#245 <https://github.com/FlexMeasures/flexmeasures-client/pull/245>`__, `#252 <https://github.com/FlexMeasures/flexmeasures-client/pull/252>`__] | ||
| * ``FRBCSimple`` takes a ``hard_bound_factor`` (default 1.5). It sets how far above the declared fill-level range a schedule's hard upper bound lies. If a schedule starts from a state of charge above that bound, the bound is raised to include it. A factor below 1 is refused: FlexMeasures clips the band to the hard bounds, so a hard upper bound inside the declared range would narrow the band to something the resource manager never asked for [`#245 <https://github.com/FlexMeasures/flexmeasures-client/pull/245>`__] | ||
| * ``FRBCSimple`` can take the actuator's charging efficiency into account. Give it the new ``charging_efficiency_sensor_id``: it records there what the operation modes say about converting drawn power into stored energy, and requests a schedule with it as ``charging-efficiency``. For a heat pump, this ratio is its coefficient of performance. Without it, the scheduler assumes power converts into stored energy one to one, and plans to reach fill-level targets at a power the actuator cannot deliver. |
There was a problem hiding this comment.
Possible follow-up: record efficiencies of different operation modes under separate sensors. For now: clarify how efficiencies of different operation modes are apparently stored under a single sensor.
There was a problem hiding this comment.
Right, this entry hides that. The client records one value per schedule window on the single charging_efficiency_sensor_id, evaluated at the fill level the schedule starts from. Where the operation modes disagree, it records the lowest of them and logs a warning (the sub-bullet below says "the lowest is used", but not that it is one sensor for all modes).
I'll say so in this bullet, and point to FlexMeasures/flexmeasures#2832 (each operation mode stating its own efficiency) as the follow-up, since separate sensors per mode only help once the scheduler can use them per mode.
There was a problem hiding this comment.
Clarified in #288, with a pointer to FlexMeasures/flexmeasures#2832.
| - The hard bounds ``soc-min`` and ``soc-max`` are now zero and ``hard_bound_factor`` times the top of the range, raised to include a state of charge above it. In v0.9.0, the declared range itself was the hard bound. So a storage that really was outside it, for example floating above the top or left below the bottom, made the problem infeasible: there was no schedule at all, or one from a fallback scheduler. A storage reported below zero is planned from zero, with a warning, because FlexMeasures refuses a negative ``soc-min``. | ||
| - FlexMeasures older than v0.26.0 cannot relax the band. Then the band is left out, and this is logged, so the storage is planned anywhere between the wide hard bounds. | ||
| - The usage forecast is sent as ``soc-usage`` if its sensor is given and the resource manager provides a forecast (or has sent one anyway). | ||
| - The leakage behaviour is recorded as a ``storage-efficiency`` with each schedule request, over the window of the schedule. It uses the leakage at the starting fill level, as a share of that fill level (or of the middle of the range, if the storage starts below that). It is only named in the flex model if FlexMeasures confirmed storing it. FlexMeasures takes a storage efficiency as a share of the stock, whereas S2 states a rate, so the loss is exact only at that one fill level. |
There was a problem hiding this comment.
If S2 states a rate, shouldn't this then be better modelled as an extra component in the soc-usage list?
There was a problem hiding this comment.
Yes, I think that is more faithful. S2 states leakage as a rate per fill-level range, in fill-level units per second. Recording it as a storage efficiency turns that rate into a share of the fill level, so the plan has the storage leak proportionally to how full it is. That is only right where leakage really is proportional, and S2 does not say it is.
As an extra soc-usage component, the rate is used as stated, and constant within a range, which is what S2 describes. Two caveats:
- A flat rate keeps draining at an empty storage, where physical leakage stops. That is the same situation as a usage forecast the storage cannot absorb, which the usage correction in feat(FRBC): correct a usage forecast no plan can absorb, instead of clipping it #286 handles.
- The rate depends on the fill-level range, and the plan moves the fill level. With one series, we would still pick the range of the starting fill level, as now.
I'd make this a follow-up PR on top of #286, since it relies on the correction.
| - The first ``FRBC.TimerStatus`` for each timer also causes the warning. Every timer status is now stored. | ||
|
|
||
| [`#273 <https://github.com/FlexMeasures/flexmeasures-client/pull/273>`__] | ||
| * The example resource manager is now a heat pump that keeps a hot-water buffer warm. |
There was a problem hiding this comment.
Potential follow-up: adding this to the FM QA workflow.
There was a problem hiding this comment.
Agreed, this example resource manager would make a good S2 end-to-end check in FlexMeasures' QA workflow. Shall I open an issue for it in the FlexMeasures repo?
| * ``FillRateBasedControlTUNES`` records an ``FRBC.LeakageBehaviour`` instead of answering it with ``PERMANENT_ERROR``. It read its fill-level scale from a misspelt attribute, and the error that raised was taken for a failed post, so no leakage behaviour was ever recorded [`#255 <https://github.com/FlexMeasures/flexmeasures-client/pull/255>`__] | ||
| * A full message history now keeps the newest messages. It used to make room by evicting the newest entry, so it kept a session's first messages and lost all later ones except the last. A message stored again under the same id now counts as the latest [`#274 <https://github.com/FlexMeasures/flexmeasures-client/pull/274>`__] | ||
| * ``Handler.is_revoked()`` now finds objects the resource manager revoked. The CEM and its handlers stored a revoked object's id as a ``UUID``, so a lookup by its string id always missed [`#257 <https://github.com/FlexMeasures/flexmeasures-client/pull/257>`__] | ||
| * An FRBC actuator status that arrives before any system description is logged and skipped, instead of raising an error in a background task. This can happen after a reconnection [`#274 <https://github.com/FlexMeasures/flexmeasures-client/pull/274>`__] |
There was a problem hiding this comment.
Potential follow-up: keep around the statuses until a system description came in, then process them.
There was a problem hiding this comment.
Agreed. Since an actuator status describes the current state, only the latest per actuator matters: the handler could keep that one and process it as soon as a system description arrives, instead of dropping it. That is a small change; I can make it a follow-up PR.
There was a problem hiding this comment.
Done in #287: the latest status per actuator is kept, and recorded once a system description arrives.
Into the integration branch
dev/s2-frbc-complete(#279), notmain.Answers the review comment on #278 that the changelog's sentence constructions reduce legibility, and that the problem is widespread.
The Unreleased section of
CHANGELOG-S2.rstis rewritten entry by entry, and so are the three entries this work added toCHANGELOG.rst:No claim is added or dropped. The RST parses without warnings.
The rewrite is done here rather than in #278, because #279 replaces the whole Unreleased section that #278 adds.
🤖 Generated with Claude Code
https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW