Skip to content

Commit

Permalink
add first season fix
Browse files Browse the repository at this point in the history
  • Loading branch information
jessicamillar committed Sep 13, 2024
1 parent ccc33c8 commit 92553f7
Show file tree
Hide file tree
Showing 14 changed files with 115 additions and 37 deletions.
1 change: 0 additions & 1 deletion src/gjk/enums/change_aquastat_control.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Literal Enum:
# - no additional values can be added over time.
# - Sent as-is, not in hex symbol
Expand Down
1 change: 0 additions & 1 deletion src/gjk/enums/change_heat_pump_control.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Literal Enum:
# - no additional values can be added over time.
# - Sent as-is, not in hex symbol
Expand Down
1 change: 0 additions & 1 deletion src/gjk/enums/change_heatcall_source.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Literal Enum:
# - no additional values can be added over time.
# - Sent as-is, not in hex symbol
Expand Down
1 change: 0 additions & 1 deletion src/gjk/enums/change_lg_operating_mode.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Literal Enum:
# - no additional values can be added over time.
# - Sent as-is, not in hex symbol
Expand Down
1 change: 0 additions & 1 deletion src/gjk/enums/change_primary_pump_control.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Literal Enum:
# - no additional values can be added over time.
# - Sent as-is, not in hex symbol
Expand Down
1 change: 0 additions & 1 deletion src/gjk/enums/change_primary_pump_state.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Literal Enum:
# - no additional values can be added over time.
# - Sent as-is, not in hex symbol
Expand Down
1 change: 0 additions & 1 deletion src/gjk/enums/change_relay_pin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Literal Enum:
# - no additional values can be added over time.
# - Sent as-is, not in hex symbol
Expand Down
1 change: 0 additions & 1 deletion src/gjk/enums/change_valve_state.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Literal Enum:
# - no additional values can be added over time.
# - Sent as-is, not in hex symbol
Expand Down
2 changes: 1 addition & 1 deletion src/gjk/types/fsm_atomic_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def check_axiom_3(self) -> Self:
elif self.event_type or self.event or self.from_state or self.to_state:
raise ValueError(
"ReportType is NOT event => EventType, Event, FromState, ToState do not exist"
)
)
return self

@model_validator(mode="before")
Expand Down
83 changes: 69 additions & 14 deletions src/gjk/types/gridworks_event_gt_sh_status.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"""Type gridworks.event.gt.sh.status, version 000"""

import copy
import json
import logging
from typing import Any, Dict, Literal

from gw.errors import GwTypeError
from gw.utils import is_pascal_case, snake_to_pascal
from gw.utils import recursively_pascal, snake_to_pascal
from pydantic import (
BaseModel,
ConfigDict,
Expand All @@ -14,19 +14,14 @@
)
from typing_extensions import Self

from gjk.enums import TelemetryName
from gjk.type_helpers.property_format import (
LeftRightDot,
ReallyAnInt,
UUID4Str,
)
from gjk.types.gt_sh_status import GtShStatus

LOG_FORMAT = (
"%(levelname) -10s %(asctime)s %(name) -30s %(funcName) "
"-35s %(lineno) -5d: %(message)s"
)
LOGGER = logging.getLogger(__name__)


class GridworksEventGtShStatus(BaseModel):
"""
Expand Down Expand Up @@ -55,7 +50,12 @@ def check_axiom_1(self) -> Self:
Axiom 1: SCADA time consistency.
SlotStartS + ReportingPeriodS < MessageCreatedS (which is TimeNS / 10**9)
"""
# Implement check for axiom 1"
# a = self.status.slot_start_unix_s + self.status.reporting_period_s
# b = self.time_n_s / 10**9
# if a > b:
# raise ValueError(
# f"slot_start + reporting_period was larger than message created time!: {self.message_id}"
# )
return self

@model_validator(mode="after")
Expand All @@ -64,16 +64,71 @@ def check_axiom_2(self) -> Self:
Axiom 2: Src is Status.FromGNodeAlias and MessageId matches Status.StatusUid.
Src == Status.FromGNodeAlias
"""
# Implement check for axiom 2"
if self.src != self.status.from_g_node_alias:
raise ValueError(
f"self.src <{self.src}> must be status.from_g_node_alias <{self.status.from_g_node_alias}>"
)

if self.message_id != self.status.status_uid:
raise ValueError(
f"message_id <{self.message_id}> must be status.status_uid <{self.status.status_uid}>"
)

return self

@classmethod
def first_season_fix(cls, d: dict) -> dict:
"""
Makes key "status" -> "Status", following the rule that
all GridWorks types must have PascalCase keys
"""

d2 = copy.deepcopy(d)
if "status" in d2.keys():
d2["Status"] = d2["status"]
del d2["status"]
if "Status" not in d2.keys():
raise GwTypeError(f"dict missing Status: <{d2}>")

status = d2["Status"]

# replace values with symbols for TelemetryName in SimpleTelemetryList
simple_list = status["SimpleTelemetryList"]
for simple in simple_list:
if "TelemetryName" not in simple.keys():
raise Exception(
f"simple does not have TelemetryName in keys! simple.key()): <{simple.keys()}>"
)
simple["TelemetryNameGtEnumSymbol"] = TelemetryName.value_to_symbol(
simple["TelemetryName"]
)
del simple["TelemetryName"]
status["SimpleTelemetryList"] = simple_list

# replace values with symbols for TelemetryName in MultipurposeTelemetryList
multi_list = status["MultipurposeTelemetryList"]
for multi in multi_list:
multi["TelemetryNameGtEnumSymbol"] = TelemetryName.value_to_symbol(
multi["TelemetryName"]
)
del multi["TelemetryName"]
status["MultipurposeTelemetryList"] = multi_list

orig_message_id = d2["MessageId"]
if orig_message_id != status["StatusUid"]:
d2["MessageId"] = status["StatusUid"]

d2["Status"] = status
d2["Version"] = "000"
return d2

@classmethod
def from_dict(cls, d: dict) -> "GridworksEventGtShStatus":
for key in d:
if not is_pascal_case(key):
raise GwTypeError(f"Key '{key}' is not PascalCase")
d2 = cls.first_season_fix(d)
if not recursively_pascal(d2):
raise GwTypeError(f"Not recursively PascalCase: {d}")
try:
t = cls(**d)
t = cls(**d2)
except ValidationError as e:
raise GwTypeError(f"Pydantic validation error: {e}") from e
return t
Expand Down
47 changes: 42 additions & 5 deletions src/gjk/types/gridworks_event_snapshot_spaceheat.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""Type gridworks.event.snapshot.spaceheat, version 000"""

import copy
import json
import logging
from typing import Any, Dict, Literal

from gw.errors import GwTypeError
from gw.utils import is_pascal_case, snake_to_pascal
from gw.utils import recursively_pascal, snake_to_pascal
from pydantic import BaseModel, ConfigDict, ValidationError

from gjk.enums import TelemetryName
from gjk.type_helpers.property_format import (
LeftRightDot,
ReallyAnInt,
Expand Down Expand Up @@ -45,13 +47,48 @@ class GridworksEventSnapshotSpaceheat(BaseModel):
populate_by_name=True,
)

@classmethod
def first_season_fix(cls, d: dict[str, Any]) -> dict[str, Any]:
"""
Makes key "snap" -> "Snap", following the rule that
all GridWorks types must have PascalCase keys
"""

d2 = copy.deepcopy(d)

if "snap" in d2.keys():
d2["Snap"] = d2["snap"]
del d2["snap"]

if "Snap" not in d2.keys():
raise GwTypeError(f"dict missing Snap: <{d2.keys()}>")

if "Snapshot" not in d2["Snap"].keys():
raise GwTypeError(f"dict['Snap'] missing Snapshot: <{d2['Snap'].keys()}>")

snapshot = d2["Snap"]["Snapshot"]
# replace values with symbols for TelemetryName in SimpleTelemetryList
if "TelemetryNameList" not in snapshot.keys():
raise Exception(
f"Snapshot does not have TelemetryNameList in keys! simple.key()): <{snapshot.keys()}>"
)
telemetry_name_list = snapshot["TelemetryNameList"]
new_list = []
for tn in telemetry_name_list:
new_list.append(TelemetryName.value_to_symbol(tn))
snapshot["TelemetryNameList"] = new_list

d2["Snap"]["Snapshot"] = snapshot
d2["Version"] = "000"
return d2

@classmethod
def from_dict(cls, d: dict) -> "GridworksEventSnapshotSpaceheat":
for key in d:
if not is_pascal_case(key):
raise GwTypeError(f"Key '{key}' is not PascalCase")
d2 = cls.first_season_fix(d)
if not recursively_pascal(d2):
raise GwTypeError(f"Not recursively PascalCase: {d2}")
try:
t = cls(**d)
t = cls(**d2)
except ValidationError as e:
raise GwTypeError(f"Pydantic validation error: {e}") from e
return t
Expand Down
4 changes: 3 additions & 1 deletion tests/enums/change_primary_pump_control_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ def test_change_primary_pump_control() -> None:
"SwitchToHeatPump",
}

assert ChangePrimaryPumpControl.default() == ChangePrimaryPumpControl.SwitchToHeatPump
assert (
ChangePrimaryPumpControl.default() == ChangePrimaryPumpControl.SwitchToHeatPump
)
assert ChangePrimaryPumpControl.enum_name() == "change.primary.pump.control"
7 changes: 0 additions & 7 deletions tests/types/test_fsm_atomic_report.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
"""Tests fsm.atomic.report, version 000"""

from gjk.enums import (
FsmActionType,
FsmEventType,
FsmName,
FsmReportType,
)
from gjk.types import FsmAtomicReport


Expand Down Expand Up @@ -33,4 +27,3 @@ def test_fsm_atomic_report_generated() -> None:
del d2["ActionType"]
d2["ActionTypeGtEnumSymbol"] = "00000000"
assert t == FsmAtomicReport.from_dict(d2)

1 change: 0 additions & 1 deletion tests/types/test_fsm_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,3 @@ def test_fsm_event_generated() -> None:
del d2["EventType"]
d2["EventTypeGtEnumSymbol"] = "c234ee7a"
assert t == FsmEvent.from_dict(d2)

0 comments on commit 92553f7

Please sign in to comment.