From ccb2f62b3f5ab268dbcaf416d36c07ea28170e7f Mon Sep 17 00:00:00 2001 From: Jessica Millar Date: Wed, 1 Jan 2025 02:04:32 -0500 Subject: [PATCH] RelayActorConfig has StateType and also some axioms - not enforced yet but axioms to ensure consistency between events and states - also updated tests and made sure code gen was idempotent - and corrected version of TelemetryName (004 with addition of StorageLayer) --- src/gwproto/enums/__init__.py | 2 +- src/gwproto/enums/telemetry_name.py | 3 +- src/gwproto/named_types/relay_actor_config.py | 45 ++++++++++++++++++- tests/enums/telemetry_name_test.py | 4 +- ..._i2c_multichannel_dt_relay_component_gt.py | 17 +++++-- tests/named_types/test_relay_actor_config.py | 5 ++- 6 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/gwproto/enums/__init__.py b/src/gwproto/enums/__init__.py index 1602f931..9d02e9c2 100644 --- a/src/gwproto/enums/__init__.py +++ b/src/gwproto/enums/__init__.py @@ -94,7 +94,7 @@ "RelayWiringConfig", # [relay.wiring.config.000](https://gridworks-type-registry.readthedocs.io/en/latest/enums.html#relaywiringconfig) "StoreFlowRelay", # [store.flow.relay.000](https://gridworks-type-registry.readthedocs.io/en/latest/enums.html#storeflowrelay) "Strategy", # [spaceheat.strategy.000](https://gridworks-type-registry.readthedocs.io/en/latest/enums.html#spaceheatstrategy) - "TelemetryName", # [spaceheat.telemetry.name.003](https://gridworks-type-registry.readthedocs.io/en/latest/enums.html#spaceheattelemetryname) + "TelemetryName", # [spaceheat.telemetry.name.004](https://gridworks-type-registry.readthedocs.io/en/latest/enums.html#spaceheattelemetryname) "TempCalcMethod", # [temp.calc.method.000](https://gridworks-type-registry.readthedocs.io/en/latest/enums.html#tempcalcmethod) "ThermistorDataMethod", # [thermistor.data.method.000](https://gridworks-type-registry.readthedocs.io/en/latest/enums.html#thermistordatamethod) "Unit", # [spaceheat.unit.001](https://gridworks-type-registry.readthedocs.io/en/latest/enums.html#spaceheatunit) diff --git a/src/gwproto/enums/telemetry_name.py b/src/gwproto/enums/telemetry_name.py index 6caae1e4..d381790a 100644 --- a/src/gwproto/enums/telemetry_name.py +++ b/src/gwproto/enums/telemetry_name.py @@ -33,6 +33,7 @@ class TelemetryName(GwStrEnum): - MicroVolts: Microvolts RMS - VoltsTimesTen - WattHours + - StorageLayer For more information: - [ASLs](https://gridworks-type-registry.readthedocs.io/en/latest/) @@ -73,4 +74,4 @@ def enum_name(cls) -> str: @classmethod def enum_version(cls) -> str: - return "003" + return "004" diff --git a/src/gwproto/named_types/relay_actor_config.py b/src/gwproto/named_types/relay_actor_config.py index d17acb47..2a68f978 100644 --- a/src/gwproto/named_types/relay_actor_config.py +++ b/src/gwproto/named_types/relay_actor_config.py @@ -1,8 +1,9 @@ -"""Type relay.actor.config, version 001""" +"""Type relay.actor.config, version 002""" from typing import Literal -from pydantic import PositiveInt +from pydantic import PositiveInt, model_validator +from typing_extensions import Self from gwproto.enums import RelayWiringConfig from gwproto.named_types import ChannelConfig @@ -12,13 +13,53 @@ class RelayActorConfig(ChannelConfig): + """ + Relay Actor Config. + + Used to associate individual relays on a multi-channel relay board to specific SpaceheatNode + actors. Each actor managed by the Spaceheat SCADA has an associated SpaceheatNode. That + Node will be associated to a relay board component with multiple relays. Th relay board + will have a list of relay actor configs so that the actor can identify which relay it has + purview over. Has DeEnergizedState and EnergizedState + + [More info](https://gridworks-protocol.readthedocs.io/en/latest/spaceheat-actor.html) + """ + RelayIdx: PositiveInt ActorName: SpaceheatName WiringConfig: RelayWiringConfig EventType: str DeEnergizingEvent: str EnergizingEvent: str + StateType: str DeEnergizedState: str EnergizedState: str TypeName: Literal["relay.actor.config"] = "relay.actor.config" Version: Literal["002"] = "002" + + @model_validator(mode="after") + def check_axiom_1(self) -> Self: + """ + Axiom 1: EventType, DeEnergizingEvent/EnergizingEvent consistency. + If the event type is the name of a known enum, then the DeEnergizingEvent, EnergizingEvent pair are the values of that enum. + """ + # Implement check for axiom 1" + return self + + @model_validator(mode="after") + def check_axiom_2(self) -> Self: + """ + Axiom 2: StateType, EnergizedState/DeEnergizedState consistency. + If the state type is the name of a known enum, then the DeEnergizedState, EnergizedState pair are the values of that enum. + """ + # Implement check for axiom 2" + return self + + @model_validator(mode="after") + def check_axiom_3(self) -> Self: + """ + Axiom 3: Events and States match. . + E.g. if RelayOpen is the EnergizedState then the EnergizingEvent is OpenRelay. + """ + # Implement check for axiom 3" + return self diff --git a/tests/enums/telemetry_name_test.py b/tests/enums/telemetry_name_test.py index 59b1ee5a..8d9b61f2 100644 --- a/tests/enums/telemetry_name_test.py +++ b/tests/enums/telemetry_name_test.py @@ -1,5 +1,5 @@ """ -Tests for enum spaceheat.telemetry.name.003 from the GridWorks Type Registry. +Tests for enum spaceheat.telemetry.name.004 from the GridWorks Type Registry. """ from gwproto.enums import TelemetryName @@ -29,4 +29,4 @@ def test_telemetry_name() -> None: assert TelemetryName.default() == TelemetryName.Unknown assert TelemetryName.enum_name() == "spaceheat.telemetry.name" - assert TelemetryName.enum_version() == "003" + assert TelemetryName.enum_version() == "004" diff --git a/tests/named_types/test_i2c_multichannel_dt_relay_component_gt.py b/tests/named_types/test_i2c_multichannel_dt_relay_component_gt.py index 4c101113..e1265c44 100644 --- a/tests/named_types/test_i2c_multichannel_dt_relay_component_gt.py +++ b/tests/named_types/test_i2c_multichannel_dt_relay_component_gt.py @@ -17,13 +17,16 @@ def test_i2c_multichannel_dt_relay_component_gt_generated() -> None: "ChannelName": "vdc-relay1", "DeEnergizingEvent": "CloseRelay", "EnergizingEvent": "OpenRelay", + "DeEnergizedState": "RelayClosed", + "EnergizedState": "RelayOpen", "EventType": "change.relay.state", + "StateType": "relay.closed.or.open", "Exponent": 0, "PollPeriodMs": 200, "RelayIdx": 1, "TypeName": "relay.actor.config", "Unit": "Unitless", - "Version": "001", + "Version": "002", "WiringConfig": "NormallyClosed", }, { @@ -33,13 +36,16 @@ def test_i2c_multichannel_dt_relay_component_gt_generated() -> None: "ChannelName": "tstat-common-relay2", "DeEnergizingEvent": "CloseRelay", "EnergizingEvent": "OpenRelay", + "DeEnergizedState": "RelayClosed", + "EnergizedState": "RelayOpen", "EventType": "change.relay.state", + "StateType": "relay.closed.or.open", "Exponent": 0, "PollPeriodMs": 200, "RelayIdx": 2, "TypeName": "relay.actor.config", "Unit": "Unitless", - "Version": "001", + "Version": "002", "WiringConfig": "NormallyClosed", }, { @@ -49,20 +55,23 @@ def test_i2c_multichannel_dt_relay_component_gt_generated() -> None: "ChannelName": "charge-discharge-relay3", "DeEnergizingEvent": "DischargeStore", "EnergizingEvent": "ChargeStore", + "DeEnergizedState": "DischargingStore", + "EnergizedState": "ChargingStore", "EventType": "change.store.flow.relay", + "StateType": "store.flow.relay", "Exponent": 0, "PollPeriodMs": 200, "RelayIdx": 3, "TypeName": "relay.actor.config", "Unit": "Unitless", - "Version": "001", + "Version": "002", "WiringConfig": "NormallyOpen", }, ], "DisplayName": "i2c krida relay boards", "I2cAddressList": [32, 33], "TypeName": "i2c.multichannel.dt.relay.component.gt", - "Version": "001", + "Version": "002", } d2 = I2cMultichannelDtRelayComponentGt.model_validate(d).model_dump( diff --git a/tests/named_types/test_relay_actor_config.py b/tests/named_types/test_relay_actor_config.py index 0bc1c93e..9da6102d 100644 --- a/tests/named_types/test_relay_actor_config.py +++ b/tests/named_types/test_relay_actor_config.py @@ -19,10 +19,13 @@ def test_relay_actor_config_generated() -> None: "ActorName": "zone1-ctrl-relay", "WiringConfig": "NormallyOpen", "EventType": "change.relay.state", + "StateType": "relay.open.or.closed", "DeEnergizingEvent": "OpenRelay", "EnergizingEvent": "CloseRelay", + "DeEnergizedState": "RelayOpen", + "EnergizedState": "RelayClosed", "TypeName": "relay.actor.config", - "Version": "001", + "Version": "002", } t = RelayActorConfig.model_validate(d).model_dump_json(exclude_none=True)