span-panel-api-schema-1 1.1.3__tar.gz → 1.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/CHANGELOG.md +12 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/PKG-INFO +1 -1
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/pyproject.toml +1 -1
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/adapter.py +22 -6
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/field_metadata.py +2 -2
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/panel.py +14 -12
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/.gitignore +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/README.md +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/breaker.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/charge-limit.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/connection.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/door.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/grid-forming.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/grid.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/info.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/load-shed.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/meter.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/pcs.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/power-flows.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/shed-forecast.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/shed.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/soc.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/status.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/switch.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/registries/device-types.md +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/__init__.py +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/adoption.py +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/catalog.py +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/charge_limit.py +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/circuits.py +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/const.py +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/description.py +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/devices.py +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/extension.py +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/py.typed +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/reference/parent_child_tree.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/snapshot.py +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/spec_lock.json +0 -0
- {span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/transport.py +0 -0
|
@@ -9,6 +9,18 @@ number. A release here means this parser changed, never that the panel did.
|
|
|
9
9
|
|
|
10
10
|
Pre-releases are not listed separately. A beta is a step towards the next public version, so its changes are folded into that version's entry as they land and are described against the last public release, never against the beta before it.
|
|
11
11
|
|
|
12
|
+
## [1.1.4]
|
|
13
|
+
|
|
14
|
+
The parser reports the islanding state the panel is acting on, and refuses islanding writes the panel would ignore. Reported and fixed by [@dcj](https://github.com/dcj) in [#179](https://github.com/SpanPanel/span-panel-api/pull/179), from issue
|
|
15
|
+
[#178](https://github.com/SpanPanel/span-panel-api/issues/178).
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **An islanding assertion in force is now the reported islanding state even while the MID is ready.** `resolve_islanding_state` returned the MID's sensed value whenever the MID was ready and read `shed/asserted-islanding-state` only when it was not, so
|
|
20
|
+
`dsm_state` could disagree with the state the panel was acting on. `ON_GRID` or `OFF_GRID` asserted now wins; otherwise the ready MID's value, then the existing fallback.
|
|
21
|
+
- **`set_dominant_power_source_target` returns None unless the panel declares `shed/asserted-islanding-state` settable**, the same refusal `set_circuit_relay_target` makes.
|
|
22
|
+
- **`dominant_power_source_payload` refuses `NONE` and `UNKNOWN`** instead of publishing `NONE`, which the panel ignores. An assertion clears itself once the panel's link to the battery recovers.
|
|
23
|
+
|
|
12
24
|
## [1.1.3]
|
|
13
25
|
|
|
14
26
|
`spec_lock.json` ships inside this wheel, so its shape changing is a release here even though the parser did not change.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: span-panel-api-schema-1
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.4
|
|
4
4
|
Summary: Parent/child schema (data-model-version 1.x) parser for span-panel-api
|
|
5
5
|
Project-URL: Homepage, https://github.com/SpanPanel/span-panel-api
|
|
6
6
|
Project-URL: Issues, https://github.com/SpanPanel/span-panel-api/issues
|
|
@@ -40,7 +40,7 @@ from span_panel_api_schema_1.const import (
|
|
|
40
40
|
STATE_READY,
|
|
41
41
|
TYPE_CIRCUIT,
|
|
42
42
|
)
|
|
43
|
-
from span_panel_api_schema_1.description import device_type
|
|
43
|
+
from span_panel_api_schema_1.description import declared_settable, device_type, node_properties
|
|
44
44
|
from span_panel_api_schema_1.field_metadata import build_field_metadata
|
|
45
45
|
from span_panel_api_schema_1.panel import integer
|
|
46
46
|
from span_panel_api_schema_1.snapshot import TreeRoles, build_snapshot, harmonised_evse_keys
|
|
@@ -275,9 +275,23 @@ class SchemaOneAdapter:
|
|
|
275
275
|
the BESS stops discharging. Returning None here, as this did until the
|
|
276
276
|
successor was decided, left that recovery unavailable during an outage.
|
|
277
277
|
|
|
278
|
+
**The panel decides whether a write takes effect, by its own link to the
|
|
279
|
+
battery.** It accepts `ON_GRID` or `OFF_GRID` only while the battery's
|
|
280
|
+
`status/communication-state` is not `OK`; otherwise it ignores the write
|
|
281
|
+
and the published value does not change. A lost MID alone does not make
|
|
282
|
+
the write eligible. `NONE` is always ignored.
|
|
283
|
+
|
|
284
|
+
**None unless the panel declares the assertion `$settable`**, the same
|
|
285
|
+
refusal `set_circuit_relay_target` makes. Absence of the declaration,
|
|
286
|
+
or of the property, authorizes nothing (see
|
|
287
|
+
`description.declared_settable`).
|
|
288
|
+
|
|
278
289
|
Payload translation is not optional: the flat enum this protocol speaks
|
|
279
290
|
is not the one the panel accepts. See `dominant_power_source_payload`.
|
|
280
291
|
"""
|
|
292
|
+
root = self._controller.get_root(self._serial_number)
|
|
293
|
+
if not declared_settable(node_properties(root, NODE_SHED).get(PROP_ASSERTED_ISLANDING_STATE)):
|
|
294
|
+
return None
|
|
281
295
|
return self._target(self._serial_number, NODE_SHED, PROP_ASSERTED_ISLANDING_STATE)
|
|
282
296
|
|
|
283
297
|
def dominant_power_source_payload(self, value: str) -> str | None:
|
|
@@ -291,17 +305,19 @@ class SchemaOneAdapter:
|
|
|
291
305
|
|
|
292
306
|
The narrowing loses nothing, because the six values were a *source
|
|
293
307
|
class* pressed into service as a manual override and the job only ever
|
|
294
|
-
needed on-grid
|
|
295
|
-
|
|
296
|
-
|
|
308
|
+
needed on-grid or off-grid. Anything not recognized returns None rather
|
|
309
|
+
than guessing, so the transport refuses the command instead of
|
|
310
|
+
asserting something the user did not ask for.
|
|
311
|
+
|
|
312
|
+
**`NONE` and `UNKNOWN` are refused too.** The panel ignores a written
|
|
313
|
+
`NONE`, so publishing one would report a clear that never happened. An
|
|
314
|
+
assertion clears itself once the panel's link to the battery recovers.
|
|
297
315
|
"""
|
|
298
316
|
return {
|
|
299
317
|
"GRID": "ON_GRID",
|
|
300
318
|
"BATTERY": "OFF_GRID",
|
|
301
319
|
"PV": "OFF_GRID",
|
|
302
320
|
"GENERATOR": "OFF_GRID",
|
|
303
|
-
"NONE": "NONE",
|
|
304
|
-
"UNKNOWN": "NONE",
|
|
305
321
|
}.get(value.strip().upper())
|
|
306
322
|
|
|
307
323
|
def set_evse_charge_limit_target(self, node_id: str) -> ControlTarget | None:
|
|
@@ -472,8 +472,8 @@ _CONSUMED_OFF_SNAPSHOT: dict[tuple[str, str, str], str] = {
|
|
|
472
472
|
"parses the tree, so it is consumed before any snapshot exists"
|
|
473
473
|
),
|
|
474
474
|
(TYPE_PANEL, NODE_SHED, "asserted-islanding-state"): (
|
|
475
|
-
"tier
|
|
476
|
-
"
|
|
475
|
+
"tier 1 of resolve_islanding_state (panel.py), which returns a non-NONE "
|
|
476
|
+
"assertion first, and the write target of set_dominant_power_source_target"
|
|
477
477
|
),
|
|
478
478
|
(TYPE_LUGS, NODE_CONNECTION, "feeds-device-id"): (
|
|
479
479
|
"the downstream-lugs feedthrough branch of resolve_relative_position "
|
{span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/panel.py
RENAMED
|
@@ -600,7 +600,6 @@ _GRID_POWER_EPSILON_W = 1.0
|
|
|
600
600
|
|
|
601
601
|
ISLANDING_ON_GRID = "ON_GRID"
|
|
602
602
|
ISLANDING_OFF_GRID = "OFF_GRID"
|
|
603
|
-
ASSERTION_NONE = "NONE"
|
|
604
603
|
|
|
605
604
|
|
|
606
605
|
def resolve_islanding_state(mid: DiscoveredDevice | None, panel: DiscoveredDevice) -> str | None:
|
|
@@ -608,17 +607,19 @@ def resolve_islanding_state(mid: DiscoveredDevice | None, panel: DiscoveredDevic
|
|
|
608
607
|
|
|
609
608
|
| tier | condition | source |
|
|
610
609
|
| --- | --- | --- |
|
|
611
|
-
| 1 |
|
|
612
|
-
| 2 | MID
|
|
610
|
+
| 1 | `shed/asserted-islanding-state` is `ON_GRID` or `OFF_GRID` | asserted |
|
|
611
|
+
| 2 | MID `$state` is `ready` and `islanding-state` present | sensed |
|
|
613
612
|
| 3 | no MID at all | `power-flows/grid` heuristic |
|
|
614
613
|
| 4 | none of the above | unknown |
|
|
615
614
|
|
|
616
|
-
**
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
615
|
+
**An assertion in force is the effective state, so it outranks the MID.** When the
|
|
616
|
+
panel's link to the battery is not healthy (the battery's `status/communication-state`
|
|
617
|
+
is not `OK`) and the grid returns, the user asserts the grid is up so the BESS stops
|
|
618
|
+
discharging, and the panel acts on that assertion until it clears. The panel ignores
|
|
619
|
+
the write while that link is healthy.
|
|
620
|
+
Reading the MID first would report the sensed value while the panel is acting on a
|
|
621
|
+
different one. The assertion clears itself back to `NONE` once the battery link
|
|
622
|
+
recovers, so the MID's answer returns without anything here having to expire it.
|
|
622
623
|
|
|
623
624
|
**Tier 3 never answers `OFF_GRID`, and never asserts on-grid from a missing MID.** An
|
|
624
625
|
earlier draft reasoned that no MID means no islanding authority means on-grid. That is
|
|
@@ -627,14 +628,15 @@ def resolve_islanding_state(mid: DiscoveredDevice | None, panel: DiscoveredDevic
|
|
|
627
628
|
counterexample. Grid power flowing is positive evidence of being on-grid; its absence
|
|
628
629
|
is not evidence of the opposite.
|
|
629
630
|
"""
|
|
631
|
+
asserted = text(panel, NODE_SHED, PROP_ASSERTED_ISLANDING_STATE)
|
|
632
|
+
if asserted in (ISLANDING_ON_GRID, ISLANDING_OFF_GRID):
|
|
633
|
+
return asserted
|
|
634
|
+
|
|
630
635
|
if mid is not None:
|
|
631
636
|
if mid.state == "ready":
|
|
632
637
|
sensed = text(mid, NODE_GRID, PROP_ISLANDING_STATE)
|
|
633
638
|
if sensed:
|
|
634
639
|
return sensed
|
|
635
|
-
asserted = text(panel, NODE_SHED, PROP_ASSERTED_ISLANDING_STATE)
|
|
636
|
-
if asserted and asserted != ASSERTION_NONE:
|
|
637
|
-
return asserted
|
|
638
640
|
return None
|
|
639
641
|
|
|
640
642
|
grid_power = number(panel, NODE_POWER_FLOWS, "grid")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/charge-limit.json
RENAMED
|
File without changes
|
{span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/connection.json
RENAMED
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/grid-forming.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/load-shed.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/power-flows.json
RENAMED
|
File without changes
|
{span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/catalogs/shed-forecast.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/spec/registries/device-types.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/const.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.1.3 → span_panel_api_schema_1-1.1.4}/src/span_panel_api_schema_1/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|