-
Notifications
You must be signed in to change notification settings - Fork 3
Allow targeting categories with subtypes #168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v0.x.x
Are you sure you want to change the base?
Conversation
Renames a few fields, but stays compatible otherwise. Signed-off-by: Mathias L. Baumann <[email protected]>
..and support the latest CategoryAndType target type. This implements extra classes for each target component case: * List of Ids `TargetIds` * List of categories: `TargetCategories` * List of categories + subtypes: `TargetCategoriesAndTypes` This was easier to do together as the addition of the new type increased the places where it was difficult to find out what the actual target type/ids is/are. Signed-off-by: Mathias L. Baumann <[email protected]>
@@ -86,7 +86,8 @@ def print_dispatch(dispatch: Dispatch) -> None: | |||
# Format the target | |||
if dispatch.target: | |||
if len(dispatch.target) == 1: | |||
target_str: str = str(dispatch.target[0]) | |||
(el,) = dispatch.target | |||
target_str: str = str(el) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is because target
is a frozenset now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, but why can't use use [0]
for something frozen? You should be able, or is it because it is a set
now?
Also what the hell does el
stands for? It look it is pretty cryptic. Also if you need to clarify in the PR, maybe it is best to add a comment in the code itself for the future ourselves looking at this code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You cannot index-access a set, it has no order :)
el
stands for element
.. sure I'll make it more clear 😄
I was surprised as well, but this seems to be the easiest way to access the only element of a set with size 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM in general, although not completely convinced about the current approach with CategoryAndType
, looks a bit too low-level for the "high-level interface".
@@ -86,7 +86,8 @@ def print_dispatch(dispatch: Dispatch) -> None: | |||
# Format the target | |||
if dispatch.target: | |||
if len(dispatch.target) == 1: | |||
target_str: str = str(dispatch.target[0]) | |||
(el,) = dispatch.target | |||
target_str: str = str(el) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, but why can't use use [0]
for something frozen? You should be able, or is it because it is a set
now?
Also what the hell does el
stands for? It look it is pretty cryptic. Also if you need to clarify in the PR, maybe it is best to add a comment in the code itself for the future ourselves looking at this code.
class EvChargerType(IntEnum): | ||
"""Enum representing the type of EV charger.""" | ||
|
||
EV_CHARGER_TYPE_UNSPECIFIED = PBEvChargerType.EV_CHARGER_TYPE_UNSPECIFIED | ||
"""Unspecified type of EV charger.""" | ||
|
||
EV_CHARGER_TYPE_AC = PBEvChargerType.EV_CHARGER_TYPE_AC | ||
"""AC EV charger.""" | ||
|
||
EV_CHARGER_TYPE_DC = PBEvChargerType.EV_CHARGER_TYPE_DC | ||
"""DC EV charger.""" | ||
|
||
EV_CHARGER_TYPE_HYBRID = PBEvChargerType.EV_CHARGER_TYPE_HYBRID | ||
"""Hybrid EV charger.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have these in the microgrid API too, next step is to move them to client-common
so we can share it. I will do a PR with this soon after I finish the microgrid API 0.17 PR, probably this week. But just FYI, I think we should move forward adding it where needed locally as it might take some time to agree on something we are all happy about to put in common + release. In any case, I would remove the EV_CHARGER_TYPE_
prefix here.
@@ -66,6 +76,30 @@ def generate_recurrence_rule(self) -> RecurrenceRule: | |||
], | |||
) | |||
|
|||
def generate_target_cat_and_type(self) -> CategoryAndType: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: This is already pretty long, I wouldn't save the 5 extra chars from egory
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're worse than copilot
|
||
This is a frozen set, so it is immutable. | ||
The target components are used to specify the components that a dispatch | ||
should target. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe include a match
example here?
@@ -99,7 +130,7 @@ def test_dispatch() -> None: | |||
start_time=datetime(2024, 10, 10, tzinfo=timezone.utc), | |||
end_time=datetime(2024, 10, 20, tzinfo=timezone.utc), | |||
duration=timedelta(days=10), | |||
target=[1, 2, 3], | |||
target=TargetIds([1, 2, 3]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can add a __init__()
here to simply allow: TargetIds(1, 2, 3)
?
@@ -120,7 +151,7 @@ def test_dispatch() -> None: | |||
start_time=datetime(2024, 11, 10, tzinfo=timezone.utc), | |||
end_time=datetime(2024, 11, 20, tzinfo=timezone.utc), | |||
duration=timedelta(seconds=20), | |||
target=[ComponentCategory.BATTERY], | |||
target=TargetCategories([ComponentCategory.BATTERY]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here: TargetCategories(ComponentCategory.BATTERY)
and for TargetCategoryAndTypes
, maybe allow something like TargetCategoryAndTypes(ComponentCategory.BATTERY, InverterType.SOLAR)
(as with the type, we can infer the category, seems to be pretty redundant to require both).
@dataclass(frozen=True) | ||
class CategoryAndType: | ||
"""Represents a category and type of dispatch.""" | ||
|
||
category: ComponentCategory | ||
"""The category of the dispatch.""" | ||
|
||
type: BatteryType | EvChargerType | InverterType | None | ||
"""The type of the dispatch.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably for the API repo, but it seems we now have overlapping target
options:
TargetCategories([cat1, cat2]) == TargetCategoryAndTypes([CategoryAndType(cat1), CategoryAndType(cat2)])
(figuratively speaking)
As for the high-level user interface, since as soon as we have a type
, the category
can be inferred, I would simplify for the end user:
# Could still be CategoryAndType, but it sounds a bit weird type is not always present
@dataclass(frozen=True)
class Group:
target: ComponentCategory | BatteryType | EvChargerType | InverterType
@property
def category(self) -> ComponentCategory:
match self.target:
case ComponentCategory():
return self.target
case BattertyType():
return ComponentCategory.BATTERY
...
@property
def type(self) -> ComponentCategory:
match self.target:
case ComponentCategory():
return None
case type:
return type
...
And then add a ctor to class TargetCategoryAndTypes
to allow for:
TargetCategoryAndTypes(ComponentCategory.BATTERY, InverterType.SOLAR)
to result in:
frozenset([Group(ComponentCategory.BATTERY), Group(InverterType.SOLAR)])
I'm not sure if we already touched on the redundancy between CategorySet
and CategoryTypeSet
in the protocol, if not maybe we should.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we already touched on the redundancy between CategorySet and CategoryTypeSet in the protocol, if not maybe we should.
We don't need to talk about those redundancies because they are deprecated and scheduled to be removed, the whole typeless category and it's field in the oneof
construct will be gone once all clients are a capable of reading/writing both.
@@ -5,13 +5,23 @@ | |||
|
|||
import json | |||
from datetime import datetime, timedelta, timezone | |||
from sre_constants import IN |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I bet this was Tab-oriented-programming + auto-import 😆
from sre_constants import IN |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was more desperation, but this is a draft after all :P
Fixes #139