Skip to content

Commit 56b4f08

Browse files
committed
Update to support VOLTTRON gui hrefs
1 parent 0c2f9a9 commit 56b4f08

File tree

7 files changed

+59
-35
lines changed

7 files changed

+59
-35
lines changed

ieee_2030_5/adapters/__init__.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,11 @@ def add_child(self, parent: T, name: str, child: Any, href: str = None):
111111
if len(self._child_map[found_index][name]) > 0:
112112
if not isinstance(child, type(self._child_map[found_index][name][0])):
113113
raise ValueError(f"Children can only have single types {type(child)} != {type(self._child_map[found_index][name][0])}")
114-
if href:
115-
child.href = href
116-
else:
117-
child.href = hrefs.SEP.join([parent.href, name, str(len(self._child_map[found_index][name]))])
114+
if not child.href:
115+
if href:
116+
child.href = href
117+
else:
118+
child.href = hrefs.SEP.join([parent.href, name, str(len(self._child_map[found_index][name]))])
118119
self._child_map[found_index][name].append(child)
119120

120121
def fetch_children_by_parent_index(self, parent_index: int, child_type: Type) -> List[Type]:
@@ -230,6 +231,8 @@ def replace_child(self, parent: T, name: str, index: int, child: Any):
230231
if not type(child) == type(children[index]):
231232
return ValueError(f"Children should be of the same type {type(child)} is not {type(children[index])}")
232233
parent_index = self.fetch_index(parent)
234+
if not child.href:
235+
child.href = children[index].href
233236
self._child_map[parent_index][name][index] = child
234237

235238

ieee_2030_5/adapters/der.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import logging
4-
import uuid
54
from dataclasses import fields
65
from enum import Enum
76
from typing import Any, Dict, List, NamedTuple, Optional, Tuple
@@ -100,31 +99,35 @@ def time_updated(timestamp):
10099

101100
for ctrl_index, ctrl in enumerate(controls):
102101
if not ctrl.EventStatus:
103-
_log.debug(f"Setting up event for ctrl {ctrl_index} current_time: {timestamp} start_time: {ctrl.interval.start}")
104-
if timestamp > ctrl.interval.start and timestamp < ctrl.interval.start + ctrl.interval.duration:
105-
ctrl.EventStatus = m.EventStatus(currentStatus=1, dateTime=timestamp, potentiallySuperseded=False, reason="Active")
102+
if ctrl.interval is not None:
103+
_log.debug(f"Setting up event for ctrl {ctrl_index} current_time: {timestamp} start_time: {ctrl.interval.start}")
104+
if timestamp > ctrl.interval.start and timestamp < ctrl.interval.start + ctrl.interval.duration:
105+
ctrl.EventStatus = m.EventStatus(currentStatus=1, dateTime=timestamp, potentiallySuperseded=False, reason="Active")
106+
else:
107+
ctrl.EventStatus = m.EventStatus(currentStatus=0, dateTime=timestamp, potentiallySuperseded=False, reason="Scheduled")
108+
_log.debug(f"ctrl.EventStatus is {ctrl.EventStatus}")
106109
else:
107110
ctrl.EventStatus = m.EventStatus(currentStatus=0, dateTime=timestamp, potentiallySuperseded=False, reason="Scheduled")
108-
_log.debug(f"ctrl.EventStatus is {ctrl.EventStatus}")
109111

110-
# Active control
111-
if ctrl.interval.start < timestamp and timestamp < ctrl.interval.start + ctrl.interval.duration:
112-
if ctrl.EventStatus.currentStatus == 0:
113-
_log.debug(f"Activating control {ctrl_index}")
114-
ctrl.EventStatus.currentStatus = 1 # Active
115-
ctrl.EventStatus.dateTime = timestamp
116-
ctrl.EventStatus.reason = f"Control event active {ctrl.mRID}"
117-
118-
if ctrl.mRID not in [x.mRID for x in current_active]:
119-
DERProgramAdapter.add_child(derp, hrefs.DER_CONTROL_ACTIVE, ctrl)
120-
121-
elif timestamp > ctrl.interval.start + ctrl.interval.duration:
122-
if ctrl.EventStatus.currentStatus == 1:
123-
_log.debug(f"Deactivating control {ctrl_index}")
124-
125-
ctrl.EventStatus.currentStatus = -1 # for me this means complete
126-
DERProgramAdapter.remove_child(derp, hrefs.DER_CONTROL_ACTIVE, ctrl)
127-
112+
if ctrl.EventStatus:
113+
# Active control
114+
if ctrl.interval.start < timestamp and timestamp < ctrl.interval.start + ctrl.interval.duration:
115+
if ctrl.EventStatus.currentStatus == 0:
116+
_log.debug(f"Activating control {ctrl_index}")
117+
ctrl.EventStatus.currentStatus = 1 # Active
118+
ctrl.EventStatus.dateTime = timestamp
119+
ctrl.EventStatus.reason = f"Control event active {ctrl.mRID}"
120+
121+
if ctrl.mRID not in [x.mRID for x in current_active]:
122+
DERProgramAdapter.add_child(derp, hrefs.DER_CONTROL_ACTIVE, ctrl)
123+
124+
elif timestamp > ctrl.interval.start + ctrl.interval.duration:
125+
if ctrl.EventStatus.currentStatus == 1:
126+
_log.debug(f"Deactivating control {ctrl_index}")
127+
128+
ctrl.EventStatus.currentStatus = -1 # for me this means complete
129+
DERProgramAdapter.remove_child(derp, hrefs.DER_CONTROL_ACTIVE, ctrl)
130+
128131

129132
def initialize_der_program_adapter(sender):
130133

ieee_2030_5/adapters/enddevices.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ def initialize_end_device_adapter(sender):
432432
EndDeviceAdapter.add_child(edev, hrefs.FSA, fsa)
433433

434434
has_der = False
435-
for der_indx, der in enumerate(dev.ders):
435+
for der_indx, der_cfg in enumerate(dev.ders):
436436
der_href = hrefs.EdevHref(edev_index=index, edev_subtype=hrefs.EDevSubType.DER, edev_subtype_index=der_indx)
437437
der = m.DER(href=str(der_href))
438438
der_href.edev_der_subtype = hrefs.DERSubType.Availability
@@ -447,6 +447,15 @@ def initialize_end_device_adapter(sender):
447447
der_href.edev_der_subtype = hrefs.DERSubType.Status
448448
der.DERStatusLink = m.DERStatusLink(str(der_href))
449449

450+
# Configure a link to the current program for the der.
451+
cfg_der_program = der_cfg.get("program")
452+
if cfg_der_program:
453+
for derp_index, derp in enumerate(programs):
454+
if cfg_der_program == derp.description:
455+
der.CurrentDERProgramLink = derp.href
456+
break
457+
458+
450459
EndDeviceAdapter.add_child(edev, hrefs.DER, der)
451460
has_der = True
452461

ieee_2030_5/hrefs.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,14 @@ class DERProgramSubType(Enum):
7474
DERControlListLink = 3
7575
DERCurveListLink= 4
7676
DERControlReplyTo = 5
77+
DERControl = 6
7778

7879
class DERProgramHref(NamedTuple):
7980
root: str
8081
index: int
81-
der_subtype: DERProgramSubType = DERProgramSubType.NoLink
82+
derp_subtype: DERProgramSubType = DERProgramSubType.NoLink
83+
derp_subtype_index: int = NO_INDEX
84+
8285

8386
@staticmethod
8487
def parse(href: str) -> DERProgramHref:
@@ -93,6 +96,8 @@ def parse(href: str) -> DERProgramHref:
9396
derca=DERProgramSubType.ActiveDERControlListLink,
9497
dderc=DERProgramSubType.DefaultDERControlLink,
9598
)
99+
if len(parsed) == 4:
100+
return DERProgramHref(parsed[0], int(parsed[1]), mapped[parsed[2]], int(parsed[3]))
96101
return DERProgramHref(parsed[0], int(parsed[1]), mapped[parsed[2]])
97102

98103
def der_program_parse(href: str) -> DERProgramHref:

ieee_2030_5/server/admin_endpoints.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def _admin_derp_derc(self, derp_index: int) -> Response:
135135

136136
if isinstance(data, m.DefaultDERControl):
137137
status_code = 201
138-
data.href = hrefs.der_program_href(derp_index, hrefs.DERProgramSubType.DefaultDERControlLink)
138+
# data.href = hrefs.der_program_href(derp_index, hrefs.DERProgramSubType.DefaultDERControlLink)
139139
if DERProgramAdapter.size_children(derp, hrefs.DDERC) > 0:
140140
status_code = 204
141141
DERProgramAdapter.remove_child(derp, hrefs.DDERC)
@@ -145,6 +145,7 @@ def _admin_derp_derc(self, derp_index: int) -> Response:
145145
return Response(headers={'Location': data.href}, status=status_code)
146146
elif isinstance(data, m.DERControl):
147147
status_code = 201
148+
# data.href = hrefs.der_program_href(derp_index, hrefs.DERProgramSubType.DERControlListLink)
148149
try:
149150
index = DERProgramAdapter.fetch_child_index_by_mrid(derp, hrefs.DERC, data.mRID)
150151
DERProgramAdapter.replace_child(derp, hrefs.DERC, index, data)

ieee_2030_5/server/derfs.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,16 @@ def get(self) -> Response:
5151
else:
5252
derp = adpt.DERProgramAdapter.fetch(derp_href.index)
5353

54-
if derp_href.der_subtype == hrefs.DERProgramSubType.DERControlListLink:
55-
retval = adpt.DERProgramAdapter.fetch_children(derp, hrefs.DERC, m.DERControlList(href=request.path))
56-
elif derp_href.der_subtype == hrefs.DERProgramSubType.ActiveDERControlListLink:
54+
if derp_href.derp_subtype == hrefs.DERProgramSubType.DERControlListLink:
55+
if derp_href.derp_subtype_index == hrefs.NO_INDEX:
56+
retval = adpt.DERProgramAdapter.fetch_children(derp, hrefs.DERC, m.DERControlList(href=request.path))
57+
else:
58+
retval = adpt.DERProgramAdapter.fetch_child(derp, hrefs.DERC, derp_href.derp_subtype_index )
59+
elif derp_href.derp_subtype == hrefs.DERProgramSubType.ActiveDERControlListLink:
5760
retval = adpt.DERProgramAdapter.fetch_children(derp, hrefs.DERCA, m.DERControlList(href=request.path))
5861
# elif derp_href.der_subtype == hrefs.DERProgramSubType.DERCurveListLink:
5962
# retval = adpt.DERProgramAdapter.fetch_der_ _active_control_list(derp_href.index)
60-
elif derp_href.der_subtype == hrefs.DERProgramSubType.DefaultDERControlLink:
63+
elif derp_href.derp_subtype == hrefs.DERProgramSubType.DefaultDERControlLink:
6164
retval = adpt.DERProgramAdapter.fetch_child(derp, hrefs.DDERC)
6265
else:
6366
raise ValueError(f"Found derph {derp_href}")

ieee_2030_5/utils/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,4 @@ def get_sfdi_from_lfdi(lfdi: t.Lfdi) -> int:
7171
return sfdi_from_lfdi(lfdi)
7272

7373
def uuid_2030_5() -> str:
74-
return str(uuid.uuid4()).replace('-', '')
74+
return str(uuid.uuid4()).replace('-', '').upper()

0 commit comments

Comments
 (0)