span-panel-api-schema-1 1.2.0__tar.gz → 1.2.1b1__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.2.0 → span_panel_api_schema_1-1.2.1b1}/CHANGELOG.md +13 -1
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/PKG-INFO +2 -2
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/pyproject.toml +3 -2
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/snapshot.py +37 -32
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/.gitignore +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/README.md +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/breaker.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/charge-limit.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/connection.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/door.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/grid-forming.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/grid.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/info.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/load-shed.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/meter.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/pcs.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/power-flows.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/shed-forecast.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/shed.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/soc.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/status.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/switch.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/registries/device-types.md +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/__init__.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/adapter.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/adoption.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/catalog.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/charge_limit.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/circuits.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/const.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/description.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/devices.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/extension.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/field_metadata.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/firmware.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/panel.py +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/py.typed +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/reference/parent_child_tree.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/spec_lock.json +0 -0
- {span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/src/span_panel_api_schema_1/transport.py +0 -0
|
@@ -9,7 +9,19 @@ 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.2.
|
|
12
|
+
## [1.2.1b1]
|
|
13
|
+
|
|
14
|
+
No inverter is primary any more. Requires `span-panel-api` **3.6.1 or newer**. 1.2.0 was withdrawn from PyPI; this release carries its changes, listed under 1.2.0 below, except how `pv` is chosen, which this release replaces.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **`pv` describes the inverters together when a panel commissions more than one**, with their shared vendor and model, the sum of their installed DC sizes and a link that is down if any is down, rather than the one on the lowest breaker space.
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
|
|
22
|
+
- **`snapshot.primary_pv` and `TreeRoles.pv`**, which singled out one inverter as `pv`.
|
|
23
|
+
|
|
24
|
+
## [1.2.0] [YANKED]
|
|
13
25
|
|
|
14
26
|
Every PV inverter a panel commissions is read, and the battery's power keeps its sign on firmware r202639. Requires `span-panel-api` **3.6.0 or newer**.
|
|
15
27
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: span-panel-api-schema-1
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.1b1
|
|
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
|
|
@@ -8,7 +8,7 @@ Author: SpanPanel
|
|
|
8
8
|
License-Expression: MIT
|
|
9
9
|
Requires-Python: <4.0,>=3.14
|
|
10
10
|
Requires-Dist: ebus-sdk<0.24,>=0.19.0
|
|
11
|
-
Requires-Dist: span-panel-api<4.0,>=3.6.
|
|
11
|
+
Requires-Dist: span-panel-api<4.0,>=3.6.1b1
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
|
|
14
14
|
# span-panel-api-schema-1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "span-panel-api-schema-1"
|
|
3
|
-
version = "1.2.
|
|
3
|
+
version = "1.2.1b1"
|
|
4
4
|
description = "Parent/child schema (data-model-version 1.x) parser for span-panel-api"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "SpanPanel"}
|
|
@@ -25,7 +25,8 @@ dependencies = [
|
|
|
25
25
|
# and the inverter's `serial_number`, `device_id` and `node_id`, which this
|
|
26
26
|
# parser fills. Against an earlier one, building a snapshot fails on those
|
|
27
27
|
# arguments.
|
|
28
|
-
|
|
28
|
+
# Raised to 3.6.1b1, whose SpanPanelSnapshot.pv documents what this parser builds.
|
|
29
|
+
"span-panel-api>=3.6.1b1,<4.0",
|
|
29
30
|
# Only this distribution depends on the eBus SDK. The bootstrap and
|
|
30
31
|
# schema-0 stay clean, so a flat-panel install never pulls it in — which is
|
|
31
32
|
# what bounds the release coupling this dependency introduces to panels on
|
|
@@ -13,7 +13,7 @@ from typing import TYPE_CHECKING
|
|
|
13
13
|
|
|
14
14
|
from span_panel_api.models import ExtensionSubject, SpanPanelSnapshot, SpanPVSnapshot
|
|
15
15
|
from span_panel_api_schema_1.adoption import build_adopted_devices
|
|
16
|
-
from span_panel_api_schema_1.circuits import build_circuit
|
|
16
|
+
from span_panel_api_schema_1.circuits import build_circuit
|
|
17
17
|
from span_panel_api_schema_1.const import (
|
|
18
18
|
NODE_CONNECTION,
|
|
19
19
|
NODE_INFO,
|
|
@@ -75,7 +75,8 @@ class TreeRoles:
|
|
|
75
75
|
self.evse: list[DiscoveredDevice] = []
|
|
76
76
|
self.bess: DiscoveredDevice | None = None
|
|
77
77
|
# Every inverter, in tree order. From r202639 each commissioned inverter
|
|
78
|
-
# is its own device; earlier firmware published one.
|
|
78
|
+
# is its own device; earlier firmware published one. None of them is
|
|
79
|
+
# primary.
|
|
79
80
|
self.pvs: list[DiscoveredDevice] = []
|
|
80
81
|
self.mid: DiscoveredDevice | None = None
|
|
81
82
|
|
|
@@ -94,33 +95,37 @@ class TreeRoles:
|
|
|
94
95
|
elif declared == TYPE_MID and self.mid is None:
|
|
95
96
|
self.mid = device
|
|
96
97
|
|
|
97
|
-
self.pv: DiscoveredDevice | None = primary_pv(self.pvs, self.circuits)
|
|
98
98
|
|
|
99
|
+
def _pv_for(inverters: Sequence[SpanPVSnapshot]) -> SpanPVSnapshot:
|
|
100
|
+
"""`SpanPanelSnapshot.pv`: the lone inverter, or the inverters together.
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
one with no feeding circuit (or a circuit that publishes none);
|
|
108
|
-
2. among those, the lowest breaker space the feeding circuit occupies;
|
|
109
|
-
3. then the lowest device id.
|
|
110
|
-
|
|
111
|
-
A single inverter is chosen whatever it publishes, so a panel with one
|
|
112
|
-
inverter reads exactly as it did before more than one could be published.
|
|
102
|
+
No inverter stands for the others. With several, `pv` identifies none of
|
|
103
|
+
them -- no device id, key, serial, firmware, feeding circuit or position --
|
|
104
|
+
and carries only what describes them together: the vendor and model where
|
|
105
|
+
every inverter shares one, the sum of their installed DC sizes where every
|
|
106
|
+
inverter publishes one, and their link as a three-valued AND (down if any
|
|
107
|
+
is reported down, up if every one is reported up, unknown otherwise).
|
|
108
|
+
Independent of order.
|
|
113
109
|
"""
|
|
114
|
-
if not
|
|
115
|
-
return
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
110
|
+
if not inverters:
|
|
111
|
+
return SpanPVSnapshot()
|
|
112
|
+
if len(inverters) == 1:
|
|
113
|
+
return inverters[0]
|
|
114
|
+
vendors = {inverter.vendor_name for inverter in inverters}
|
|
115
|
+
models = {inverter.model for inverter in inverters}
|
|
116
|
+
nameplates = [inverter.nameplate_capacity_w for inverter in inverters if inverter.nameplate_capacity_w is not None]
|
|
117
|
+
links = [inverter.connected for inverter in inverters]
|
|
118
|
+
connected: bool | None = None
|
|
119
|
+
if any(link is False for link in links):
|
|
120
|
+
connected = False
|
|
121
|
+
elif all(link is True for link in links):
|
|
122
|
+
connected = True
|
|
123
|
+
return SpanPVSnapshot(
|
|
124
|
+
vendor_name=vendors.pop() if len(vendors) == 1 else None,
|
|
125
|
+
model=models.pop() if len(models) == 1 else None,
|
|
126
|
+
nameplate_capacity_w=sum(nameplates) if len(nameplates) == len(inverters) else None,
|
|
127
|
+
connected=connected,
|
|
128
|
+
)
|
|
124
129
|
|
|
125
130
|
|
|
126
131
|
def build_snapshot(panel: DiscoveredDevice, children: list[DiscoveredDevice], ready_since: float = 0.0) -> SpanPanelSnapshot:
|
|
@@ -138,10 +143,10 @@ def build_snapshot(panel: DiscoveredDevice, children: list[DiscoveredDevice], re
|
|
|
138
143
|
# A DER's device type decides how its feeding circuit is labelled, so the
|
|
139
144
|
# circuit inherits it — matching the flat adapter, where the same circuit
|
|
140
145
|
# reports device_type "pv" rather than "circuit". Every inverter's circuit,
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
146
|
+
# however many are commissioned: a PV circuit left labeled "circuit" is
|
|
147
|
+
# read as a load, with its power in the opposite sign. Read from the
|
|
148
|
+
# circuit side rather than through `feeds`, which keeps one circuit per
|
|
149
|
+
# DER: every circuit of a DER fed by several carries its power.
|
|
145
150
|
kind_by_der = {device.device_id: "pv" for device in roles.pvs} | {device.device_id: "evse" for device in roles.evse}
|
|
146
151
|
der_type_by_circuit = {
|
|
147
152
|
circuit.device_id: kind
|
|
@@ -214,7 +219,7 @@ def build_snapshot(panel: DiscoveredDevice, children: list[DiscoveredDevice], re
|
|
|
214
219
|
("panel", panel),
|
|
215
220
|
("battery", roles.bess),
|
|
216
221
|
("mid", roles.mid),
|
|
217
|
-
*((("pv", roles.
|
|
222
|
+
*((("pv", roles.pvs[0]),) if len(roles.pvs) == 1 else ()),
|
|
218
223
|
)
|
|
219
224
|
if device is not None
|
|
220
225
|
]
|
|
@@ -297,7 +302,7 @@ def build_snapshot(panel: DiscoveredDevice, children: list[DiscoveredDevice], re
|
|
|
297
302
|
firmware_version=fields.firmware_version,
|
|
298
303
|
power_flow_battery=fields.power_flow_battery,
|
|
299
304
|
),
|
|
300
|
-
pv=pv_inverters
|
|
305
|
+
pv=_pv_for(list(pv_inverters.values())),
|
|
301
306
|
pv_inverters=pv_inverters,
|
|
302
307
|
mid=build_mid(roles.mid, device_names),
|
|
303
308
|
# Gated on the node being declared, not on any value: every limit this
|
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/breaker.json
RENAMED
|
File without changes
|
{span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/charge-limit.json
RENAMED
|
File without changes
|
{span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/connection.json
RENAMED
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/grid-forming.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/load-shed.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/catalogs/power-flows.json
RENAMED
|
File without changes
|
{span_panel_api_schema_1-1.2.0 → span_panel_api_schema_1-1.2.1b1}/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.2.0 → span_panel_api_schema_1-1.2.1b1}/spec/registries/device-types.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|