gridworks-scada-protocol 0.1.0.dev3__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.
- gridworks_scada_protocol-0.1.0.dev3/PKG-INFO +11 -0
- gridworks_scada_protocol-0.1.0.dev3/README.md +0 -0
- gridworks_scada_protocol-0.1.0.dev3/pyproject.toml +20 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/__init__.py +9 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/data_classes/__init__.py +0 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/data_classes/house_0_layout.py +307 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/data_classes/house_0_names.py +387 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/__init__.py +59 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/atomic_ally_state.py +30 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/change_keep_send.py +31 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/contract_status.py +47 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/flow_manifold_variant.py +35 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/home_alone_strategy.py +36 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/home_alone_top_state.py +42 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/hp_loop_keep_send.py +30 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/hp_model.py +11 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/log_level.py +53 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/main_auto_event.py +44 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/main_auto_state.py +38 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/market_price_unit.py +34 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/market_quantity_unit.py +36 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/pico_cycler_event.py +50 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/pico_cycler_state.py +46 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/top_event.py +36 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/top_state.py +36 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/enums/turn_hp_on_off.py +36 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/__init__.py +93 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/actuators_ready.py +12 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/admin_dispatch.py +13 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/admin_keep_alive.py +11 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/admin_release_control.py +12 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/ally_gives_up.py +11 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/atn_bid.py +38 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/atn_bid_001.py +152 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/channel_flatlined.py +27 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/dispatch_contract_go_dormant.py +21 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/dispatch_contract_go_live.py +26 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/energy_instruction.py +42 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/events.py +13 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/flo_params.py +37 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/flo_params_house0.py +64 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/fsm_event.py +58 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/glitch.py +18 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/go_dormant.py +11 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/ha1_params.py +22 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/hack_oil_off.py +10 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/hack_oil_on.py +10 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/heating_forecast.py +50 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/latest_price.py +17 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/layout_lite.py +86 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/market_maker_ack.py +123 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/new_command_tree.py +27 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/no_new_contract_warning.py +12 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/pico_missing.py +13 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/price_quantity_unitless.py +12 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/remaining_elec.py +13 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/reset_hp_keep_value.py +20 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/scada_params.py +26 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/send_layout.py +14 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/set_lwt_control_params.py +22 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/set_target_lwt.py +27 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/sieg_loop_endpoint_valve_adjustment.py +32 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/sieg_target_too_low.py +17 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/single_machine_state.py +30 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/slow_contract_heartbeat.py +158 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/slow_dispatch_contract.py +42 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/snapshot_spaceheat.py +30 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/start_listening_to_atn.py +11 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/stop_listening_to_atn.py +11 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/suit_up.py +15 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/wake_up.py +12 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/named_types/weather_forecast.py +53 -0
- gridworks_scada_protocol-0.1.0.dev3/src/gwsproto/py.typed +0 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: gridworks-scada-protocol
|
|
3
|
+
Version: 0.1.0.dev3
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Author: Jessica Millar
|
|
6
|
+
Author-email: Jessica Millar <jmillar@gridworks-consulting.com>
|
|
7
|
+
Requires-Dist: gridworks-protocol>=1.2.9
|
|
8
|
+
Requires-Dist: transitions>=0.9.3
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "gridworks-scada-protocol"
|
|
3
|
+
version = "0.1.0.dev3"
|
|
4
|
+
description = "Add your description here"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Jessica Millar", email = "jmillar@gridworks-consulting.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"gridworks-protocol>=1.2.9",
|
|
12
|
+
"transitions>=0.9.3",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[tool.uv.build-backend]
|
|
16
|
+
module-name = "gwsproto"
|
|
17
|
+
|
|
18
|
+
[build-system]
|
|
19
|
+
requires = ["uv_build>=0.8.8,<0.9.0"]
|
|
20
|
+
build-backend = "uv_build"
|
|
File without changes
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, List, Literal, Optional
|
|
4
|
+
|
|
5
|
+
from gw.errors import DcError
|
|
6
|
+
from gwproto.enums import ActorClass
|
|
7
|
+
from gwproto.data_classes.components import Component
|
|
8
|
+
from gwproto.data_classes.data_channel import DataChannel
|
|
9
|
+
from gwproto.data_classes.hardware_layout import (
|
|
10
|
+
HardwareLayout,
|
|
11
|
+
LoadArgs,
|
|
12
|
+
LoadError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from gwsproto.data_classes.house_0_names import H0CN, H0N
|
|
16
|
+
from gwsproto.enums import FlowManifoldVariant, HomeAloneStrategy
|
|
17
|
+
|
|
18
|
+
from gwproto.data_classes.sh_node import ShNode
|
|
19
|
+
from gwproto.data_classes.synth_channel import SynthChannel
|
|
20
|
+
from gwproto.default_decoders import (
|
|
21
|
+
CacDecoder,
|
|
22
|
+
ComponentDecoder,
|
|
23
|
+
)
|
|
24
|
+
from gwproto.named_types import ComponentAttributeClassGt
|
|
25
|
+
|
|
26
|
+
class House0LoadArgs(LoadArgs):
|
|
27
|
+
flow_manifold_variant: FlowManifoldVariant
|
|
28
|
+
use_sieg_loop: bool
|
|
29
|
+
class House0Layout(HardwareLayout):
|
|
30
|
+
zone_list: List[str]
|
|
31
|
+
total_store_tanks: int
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def __init__( # noqa: PLR0913
|
|
35
|
+
self,
|
|
36
|
+
layout: dict[Any, Any],
|
|
37
|
+
*,
|
|
38
|
+
cacs: dict[str, ComponentAttributeClassGt], # by id
|
|
39
|
+
components: dict[str, Component], # by id
|
|
40
|
+
nodes: dict[str, ShNode], # by name
|
|
41
|
+
data_channels: dict[str, DataChannel], # by name
|
|
42
|
+
synth_channels: dict[str, SynthChannel],
|
|
43
|
+
flow_manifold_variant: FlowManifoldVariant = FlowManifoldVariant.House0,
|
|
44
|
+
use_sieg_loop: bool = False,
|
|
45
|
+
) -> None:
|
|
46
|
+
super().__init__(
|
|
47
|
+
layout=layout,
|
|
48
|
+
cacs=cacs,
|
|
49
|
+
components=components,
|
|
50
|
+
nodes=nodes,
|
|
51
|
+
data_channels=data_channels,
|
|
52
|
+
synth_channels=synth_channels,
|
|
53
|
+
)
|
|
54
|
+
self.flow_manifold_variant = flow_manifold_variant
|
|
55
|
+
self.use_sieg_loop = use_sieg_loop
|
|
56
|
+
|
|
57
|
+
# Bolted on right now
|
|
58
|
+
required_keys = ["ZoneList", "TotalStoreTanks"]
|
|
59
|
+
for key in required_keys:
|
|
60
|
+
if key not in layout:
|
|
61
|
+
raise DcError(f"House0 requires {key}!")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
self.zone_list = layout["ZoneList"]
|
|
65
|
+
self.total_store_tanks = layout["TotalStoreTanks"]
|
|
66
|
+
|
|
67
|
+
self.channel_names = H0CN(self.total_store_tanks, self.zone_list)
|
|
68
|
+
if not isinstance(self.total_store_tanks, int):
|
|
69
|
+
raise TypeError("TotalStoreTanks must be an integer")
|
|
70
|
+
if not 1 <= self.total_store_tanks <= 6:
|
|
71
|
+
raise ValueError("Must have between 1 and 6 store tanks")
|
|
72
|
+
if not isinstance(self.zone_list, List):
|
|
73
|
+
raise TypeError("ZoneList must be a list")
|
|
74
|
+
if not 1 <= len(self.zone_list) <= 6:
|
|
75
|
+
raise ValueError("Must have between 1 and 6 store zones")
|
|
76
|
+
self.h0n = H0N(self.total_store_tanks, self.zone_list)
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def validate_house0( # noqa: C901
|
|
80
|
+
cls,
|
|
81
|
+
load_args: House0LoadArgs,
|
|
82
|
+
*,
|
|
83
|
+
raise_errors: bool,
|
|
84
|
+
errors: Optional[list[LoadError]] = None,
|
|
85
|
+
) -> None:
|
|
86
|
+
nodes = load_args["nodes"]
|
|
87
|
+
data_channels = load_args["data_channels"]
|
|
88
|
+
errors_caught = []
|
|
89
|
+
flow_manifold_variant = load_args["flow_manifold_variant"]
|
|
90
|
+
use_sieg_loop = load_args["use_sieg_loop"]
|
|
91
|
+
|
|
92
|
+
# Can't use the siegenthaler loop in the code if it isn't in the plumbing
|
|
93
|
+
if use_sieg_loop and flow_manifold_variant != FlowManifoldVariant.House0Sieg:
|
|
94
|
+
raise DcError("Cannot use Sieg Loop when FlowManifoldVariant is not House0Sieg!")
|
|
95
|
+
|
|
96
|
+
# Make sure sieg relays, sieg flow and sieg temp nodes and channels exist
|
|
97
|
+
if flow_manifold_variant == FlowManifoldVariant.House0Sieg:
|
|
98
|
+
try:
|
|
99
|
+
cls.check_house0_sieg_manifold(data_channels)
|
|
100
|
+
except Exception as e:
|
|
101
|
+
if raise_errors:
|
|
102
|
+
raise
|
|
103
|
+
errors_caught.append(LoadError("hardware.layout", nodes, e))
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
if use_sieg_loop: # HpBoss and SiegLoop need to be actors
|
|
107
|
+
try:
|
|
108
|
+
cls.check_actors_when_using_sieg_loop(nodes)
|
|
109
|
+
except Exception as e:
|
|
110
|
+
if raise_errors:
|
|
111
|
+
raise
|
|
112
|
+
errors_caught.append(LoadError("hardware.layout", nodes, e))
|
|
113
|
+
else: # HpBoss and SiegLoop should NOT be actors
|
|
114
|
+
try:
|
|
115
|
+
cls.check_actors_when_not_using_sieg_loop(nodes)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
if raise_errors:
|
|
118
|
+
raise
|
|
119
|
+
errors_caught.append(LoadError("hardware.layout", nodes, e))
|
|
120
|
+
@classmethod
|
|
121
|
+
def check_house0_sieg_manifold(cls, channels: dict[str, DataChannel]) -> None:
|
|
122
|
+
# if H0CN.sieg_cold not in channels.keys():
|
|
123
|
+
# raise DcError(f"Need {H0CN.sieg_cold} channel with House0Sieg flow manifold variant")
|
|
124
|
+
# if H0CN.sieg_flow not in channels.keys():
|
|
125
|
+
# raise DcError(f"Need {H0CN.sieg_flow} channel with House0Sieg flow manifold variant")
|
|
126
|
+
if H0CN.hp_loop_on_off_relay_state not in channels.keys():
|
|
127
|
+
raise DcError(f"Need {H0CN.hp_loop_on_off_relay_state} channel with House0Sieg flow manifold variant")
|
|
128
|
+
if H0CN.hp_loop_keep_send_relay_state not in channels.keys():
|
|
129
|
+
raise DcError(f"Need {H0CN.hp_loop_keep_send_relay_state} channel with House0Sieg flow manifold variant")
|
|
130
|
+
|
|
131
|
+
@classmethod
|
|
132
|
+
def check_actors_when_using_sieg_loop(cls, nodes: dict[str, ShNode]) -> None:
|
|
133
|
+
if H0N.sieg_loop not in nodes.keys():
|
|
134
|
+
raise DcError(f"Need a SiegLoop actor when using sieg loop!")
|
|
135
|
+
sieg_loop = nodes[H0N.sieg_loop]
|
|
136
|
+
if sieg_loop.actor_class != ActorClass.SiegLoop:
|
|
137
|
+
raise DcError(f"SiegLoop actor {sieg_loop.name} shoud have actor class SiegLoop, not {sieg_loop.actor_class}")
|
|
138
|
+
if H0N.hp_boss not in nodes.keys():
|
|
139
|
+
raise DcError(f"Need HpBoss actor when using sieg loop!")
|
|
140
|
+
hp_boss = nodes[H0N.hp_boss]
|
|
141
|
+
if hp_boss.actor_class != ActorClass.HpBoss:
|
|
142
|
+
raise DcError(f"HpBoss actor {hp_boss.name} shoud have actor class HpBoss, not {hp_boss.actor_class}")
|
|
143
|
+
|
|
144
|
+
@classmethod
|
|
145
|
+
def check_actors_when_not_using_sieg_loop(cls, nodes: dict[str, ShNode]) -> None:
|
|
146
|
+
if H0N.sieg_loop in nodes.keys():
|
|
147
|
+
raise DcError(f"If not using sieg loop, should not have node {H0N.sieg_loop}!")
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def ha_strategy(self) -> str:
|
|
151
|
+
"""Returns the current home alone strategy"""
|
|
152
|
+
# Could be stored as a property or derived from a node
|
|
153
|
+
ha_node = self.nodes.get(H0N.home_alone)
|
|
154
|
+
return HomeAloneStrategy(HomeAloneStrategy(getattr(ha_node, "Strategy", None)))
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def actuators(self) -> List[ShNode]:
|
|
158
|
+
return self.relays + self.zero_tens
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def relays(self) -> List[ShNode]:
|
|
162
|
+
return [
|
|
163
|
+
node for node in self.nodes.values()
|
|
164
|
+
if node.ActorClass == ActorClass.Relay
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def zero_tens(self) -> List[ShNode]:
|
|
169
|
+
return [
|
|
170
|
+
node for node in self.nodes.values()
|
|
171
|
+
if node.ActorClass == ActorClass.ZeroTenOutputer
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# overwrites base class to return correct object
|
|
176
|
+
@classmethod
|
|
177
|
+
def load( # noqa: PLR0913
|
|
178
|
+
cls,
|
|
179
|
+
layout_path: Path | str,
|
|
180
|
+
*,
|
|
181
|
+
included_node_names: Optional[set[str]] = None,
|
|
182
|
+
raise_errors: bool = True,
|
|
183
|
+
errors: Optional[list[LoadError]] = None,
|
|
184
|
+
cac_decoder: Optional[CacDecoder] = None,
|
|
185
|
+
component_decoder: Optional[ComponentDecoder] = None,
|
|
186
|
+
) -> "House0Layout":
|
|
187
|
+
with Path(layout_path).open() as f:
|
|
188
|
+
layout = json.loads(f.read())
|
|
189
|
+
return cls.load_dict(
|
|
190
|
+
layout,
|
|
191
|
+
included_node_names=included_node_names,
|
|
192
|
+
raise_errors=raise_errors,
|
|
193
|
+
errors=errors,
|
|
194
|
+
cac_decoder=cac_decoder,
|
|
195
|
+
component_decoder=component_decoder,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# overwrites base class to return correct object
|
|
199
|
+
@classmethod
|
|
200
|
+
def load_dict( # noqa: PLR0913
|
|
201
|
+
cls,
|
|
202
|
+
layout: dict[Any, Any],
|
|
203
|
+
*,
|
|
204
|
+
included_node_names: Optional[set[str]] = None,
|
|
205
|
+
raise_errors: bool = True,
|
|
206
|
+
errors: Optional[list[LoadError]] = None,
|
|
207
|
+
cac_decoder: Optional[CacDecoder] = None,
|
|
208
|
+
component_decoder: Optional[ComponentDecoder] = None,
|
|
209
|
+
) -> "House0Layout":
|
|
210
|
+
if errors is None:
|
|
211
|
+
errors = []
|
|
212
|
+
cacs = cls.load_cacs(
|
|
213
|
+
layout=layout,
|
|
214
|
+
raise_errors=raise_errors,
|
|
215
|
+
errors=errors,
|
|
216
|
+
cac_decoder=cac_decoder,
|
|
217
|
+
)
|
|
218
|
+
components = cls.load_components(
|
|
219
|
+
layout=layout,
|
|
220
|
+
cacs=cacs,
|
|
221
|
+
raise_errors=raise_errors,
|
|
222
|
+
errors=errors,
|
|
223
|
+
component_decoder=component_decoder,
|
|
224
|
+
)
|
|
225
|
+
nodes = cls.load_nodes(
|
|
226
|
+
layout=layout,
|
|
227
|
+
components=components,
|
|
228
|
+
raise_errors=raise_errors,
|
|
229
|
+
errors=errors,
|
|
230
|
+
included_node_names=included_node_names,
|
|
231
|
+
)
|
|
232
|
+
data_channels = cls.load_data_channels(
|
|
233
|
+
layout=layout,
|
|
234
|
+
nodes=nodes,
|
|
235
|
+
raise_errors=raise_errors,
|
|
236
|
+
errors=errors,
|
|
237
|
+
)
|
|
238
|
+
synth_channels = cls.load_synth_channels(
|
|
239
|
+
layout=layout,
|
|
240
|
+
nodes=nodes,
|
|
241
|
+
raise_errors=raise_errors,
|
|
242
|
+
errors=errors,
|
|
243
|
+
)
|
|
244
|
+
load_args: House0LoadArgs = {
|
|
245
|
+
"cacs": cacs,
|
|
246
|
+
"components": components,
|
|
247
|
+
"nodes": nodes,
|
|
248
|
+
"data_channels": data_channels,
|
|
249
|
+
"synth_channels": synth_channels,
|
|
250
|
+
"flow_manifold_variant": FlowManifoldVariant(layout.get("FlowManifoldVariant", "House0")),
|
|
251
|
+
"use_sieg_loop": bool(layout.get("UseSiegLoop", False))
|
|
252
|
+
}
|
|
253
|
+
cls.resolve_links(
|
|
254
|
+
load_args["nodes"],
|
|
255
|
+
load_args["components"],
|
|
256
|
+
raise_errors=raise_errors,
|
|
257
|
+
errors=errors,
|
|
258
|
+
)
|
|
259
|
+
cls.validate_layout(load_args, raise_errors=raise_errors, errors=errors)
|
|
260
|
+
cls.validate_house0(load_args, raise_errors=raise_errors, errors=errors)
|
|
261
|
+
return House0Layout(layout, **load_args)
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def home_alone(self) -> ShNode:
|
|
265
|
+
return self.node(H0N.home_alone)
|
|
266
|
+
|
|
267
|
+
@property
|
|
268
|
+
def auto_node(self) -> ShNode:
|
|
269
|
+
return self.node(H0N.auto)
|
|
270
|
+
|
|
271
|
+
@property
|
|
272
|
+
def atomic_ally(self) -> ShNode:
|
|
273
|
+
return self.node(H0N.atomic_ally)
|
|
274
|
+
|
|
275
|
+
@property
|
|
276
|
+
def atn(self) -> ShNode:
|
|
277
|
+
return self.node(H0N.atn)
|
|
278
|
+
|
|
279
|
+
@property
|
|
280
|
+
def pico_cycler(self) -> ShNode:
|
|
281
|
+
return self.node(H0N.pico_cycler)
|
|
282
|
+
|
|
283
|
+
@property
|
|
284
|
+
def vdc_relay(self) -> ShNode:
|
|
285
|
+
return self.node(H0N.vdc_relay)
|
|
286
|
+
|
|
287
|
+
@property
|
|
288
|
+
def tstat_common_relay(self) -> ShNode:
|
|
289
|
+
return self.node(H0N.tstat_common_relay)
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
def charge_discharge_relay(self) -> ShNode:
|
|
293
|
+
return self.node(H0N.store_charge_discharge_relay)#
|
|
294
|
+
|
|
295
|
+
def scada2_gnode_name(self) -> str:
|
|
296
|
+
return f"{self.scada_g_node_alias}.{H0N.secondary_scada}"
|
|
297
|
+
|
|
298
|
+
def deserialize_house0_load_args(data: dict) -> House0LoadArgs:
|
|
299
|
+
valid_keys = set(House0LoadArgs.__annotations__.keys())
|
|
300
|
+
|
|
301
|
+
# Validate the FlowManifoldVariant
|
|
302
|
+
data["FlowManifoldVariant"] = FlowManifoldVariant(data.get("FlowManifoldVariant", "House0"))
|
|
303
|
+
# Validate use_sieg_loop
|
|
304
|
+
data["UseSiegLoop"] = bool(data.get("UseSiegLoop", False))
|
|
305
|
+
# TypedDict expects a regular dictionary, so we just pass it in
|
|
306
|
+
return House0LoadArgs(**data)
|
|
307
|
+
|