-
Notifications
You must be signed in to change notification settings - Fork 5
Add sensors listing and data streaming #144
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
Conversation
We also use a fixture to always clean the client used for test appropriately. Signed-off-by: Leandro Lucarella <[email protected]>
Signed-off-by: Leandro Lucarella <[email protected]>
Signed-off-by: Leandro Lucarella <[email protected]>
Signed-off-by: Leandro Lucarella <[email protected]>
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.
Pull Request Overview
This PR enhances the microgrid client with support for sensor interactions by introducing new RPCs and a sensor class hierarchy while also addressing bugs related to metadata location defaults and resource cleanup.
- Added sensor listing via list_sensors() and sensor data streaming via stream_sensor_data().
- Introduced dedicated sensor classes and associated data structures (e.g., Pyranometer, SensorId).
- Fixed issues with default metadata location and disconnection cleanup.
Reviewed Changes
Copilot reviewed 38 out of 38 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/frequenz/client/microgrid/sensor/_pyranometer.py | Added a new sensor class for pyranometer functionality. |
| src/frequenz/client/microgrid/sensor/_proto.py | Implements sensor construction from protobuf messages. |
| src/frequenz/client/microgrid/sensor/_problematic.py | Adds classes to handle problematic sensor cases. |
| src/frequenz/client/microgrid/sensor/_data_proto.py | Provides conversion of sensor data samples from protobuf. |
| src/frequenz/client/microgrid/_client.py | Adds list_sensors() and stream_sensor_data() with cleanup fixes. |
| Others | Introduce sensor types, metrics, lifetime, and utility functions to support the new sensor functionality. |
|
I still need to do some proper testing against a real microgrid API, but I'm pretty confident things shouldn't change much after the tests, so it should be fairly safe to review. This PR aligns as much as possible with: |
ea8f3b6 to
ada656a
Compare
The lifetime will be introduced in the next microgrid API version, but we add it now so we can add a rpc call to get sensors information in a way that is compatible with future microgrid API versions. Signed-off-by: Leandro Lucarella <[email protected]>
Signed-off-by: Leandro Lucarella <[email protected]>
This RPC is based on version 0.17 of the microgrid API instead of the current 0.15 version, so users can already use the new interface and make migrating to 0.17 more straight forward. Instead of having only one sensor class as done in the current client, we introduce a Sensor hierarchy, with a specific type for each sensor type. This allows grouping sensors more easily (like problematic sensors), and also provides a more Pythonic interface. The same approach will be done for component in future versions of this client. To be compatible with 0.17, sensors also have a "fake" lifetime that is not really retrieved from the microgrid (it is filled with a "eternal" lifetime, so sensors are present always). Signed-off-by: Leandro Lucarella <[email protected]>
This class will not really be used in this microgrid API version, but it is added in preparation of the upcoming v0.17 update, which includes aggregated metric values as possible sample values, so clients can already start writing code that contemplates the possibility of receiving these type of values. Signed-off-by: Leandro Lucarella <[email protected]>
This RPC is based on version 0.17 of the microgrid API instead of the current 0.15 version, so users can already use the new interface and make migrating to 0.17 more straight forward. Because of this the data structures used to encapsulate the data samples is based on the data structures in 0.17. Signed-off-by: Leandro Lucarella <[email protected]>
Signed-off-by: Leandro Lucarella <[email protected]>
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.
Taking a break in the middle of the big commit.
|
|
||
| location: Location | None = None | ||
| if microgrid_metadata.location: | ||
| if microgrid_metadata.HasField("location"): |
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.
What happened to all our deployments at https://en.wikipedia.org/wiki/Null_Island? 😱
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.
We are fine, now microgrids in Null Island need to provide a explicit (0, 0) location 😆
| return False | ||
| if self.end is not None: | ||
| return self.end >= timestamp | ||
| # Both are None, so it is always active |
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.
Only self.end is known to be None with the above checks. self.start could be None or earlier than the given timestamp.
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.
Fixed.
| start_type=_Time.NOW, | ||
| end_type=_Time.NOW, | ||
| expected_active=True, | ||
| ), |
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.
missed case: start=None, end=PAST? Probably need a _Time.PLUSQUAM
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.
😑 Added.
| class Barometer(Sensor): | ||
| """A barometer sensor. | ||
| Measures pressure. |
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.
| Measures pressure. | |
| Measures atmospheric pressure. |
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.
Most text here is copied from the API, so maybe you can create an issue in the API specs to suggests improvements there too.
|
|
||
|
|
||
| @dataclasses.dataclass(frozen=True, kw_only=True) | ||
| class Sensor: |
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.
Come on @llucax, make more commits!
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 don't see the point on splitting commits that are only adding files, you can just mark files as viewed and that's it. I guess it is very related to your review workflow. But if it makes reviewing easier for you, I can split them, sure, but only if you ask nicely 😄
| It is only provided for using with a newer version of the API where the | ||
| client doesn't know about a new category yet (i.e. for use with | ||
| [`UnrecognizedSensor`][frequenz.client.microgrid.sensor.UnrecognizedSensor]) | ||
| and in case some low level code needs to know the category of a sensor. |
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 why it can't be an ABC? you're blocking __new__ below anyway.
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 did this a long time ago in #94, and to be honest I'm not sure if I tried to make it a ABC or not and if I had issues if I did. I would have to refresh my mind a bit. But in any case, I will remove all the class hierarchy for sensors, as we are removing the sensor type anyways, so we can leave that for #94.
| @cached_property | ||
| def active(self) -> bool: | ||
| """Whether this sensor is currently active.""" | ||
| return self.active_at(datetime.now(timezone.utc)) |
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.
Not sure you can make this a cached_property. datetime.now is not a constant value
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.
Yeah, good point, it doesn't make sense for active. 👍 🤦
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 decided to remove these active properties methods, if we need to add them is a non-breaking change, and they make no sense right now, as sensors will always be active in this sense.
| @cached_property | ||
| def active(self) -> bool: | ||
| """Whether this lifetime is currently active.""" | ||
| return self.active_at(datetime.now(timezone.utc)) |
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 shouldn't be a cached_property, because then you can do this with less assumptions. This property is not expected to be in any hot path, so this is too much optimization anyway.
| UNSPECIFIED = 0 | ||
| """Unspecified sensor category.""" | ||
|
|
||
| THERMOMETER = 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.
These numbers are copied from proto? If you don't want to import the generated code here and assign from that, maybe you should add a link to the proto as a comment.
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.
Yeah, we also talked about this in #94. I'm not a 100% convinced about this, but since these numbers should NEVER EVER change, and we are writing the wrappers manually, I thought I could just skip the generated wrappers, there no value in using them, and if we use them it means all the protobuf definition will be imported when using this simple Python enum (it will probably be imported anyway indirectly at some point, at least if parsing from protobuf is involved, so this is probably more a philosophical issue and a practical one, I know :D).
But the code also looked really ugly or I had to add exceptions for long lines when using stuff like sensor_pb2.SENSOR_CATEGORY_THERMOMETER (with sensors is also not that bad, but for components there are enum names that are really long, and will get worse when they are named ElectricalComponentCategory.ELECTRICAL_COMPONENT_CATEGORY_INVERTER).
Maybe we can have a brief meeting to discuss this, I was hoping to open the discussion when I move this to api-common, whichever we pick it is a backwards compatible change.
|
Sorry @shsms, of course I was wrong and after doing some tests with the real API I found out the specs for sensors are very old (even in So this PR will need some big update. I will split it though, as I accumulated enough unrelated stuff to be worth of a separate PR. |
|
Split out the bugfixes to: I will probably open a new PR for the sensor stuff, so I leave this PR/branch as is, as the sensors specs seem to be changing, I want to have this PR under my sleeve in case case we decide to go back to sensor types somehow. |
|
Superseded by: |
This pull request introduces support for sensors to the microgrid client and includes several bug fixes.
A key focus of this update is forward-compatibility with the upcoming microgrid API v0.17. The new sensor-related RPCs (
list_sensors(),stream_sensor_data()) and their associated data structures (AggregatedMetricValue,Lifetime) have been designed based on the v0.17 specifications. This approach aims to simplify the future migration process for users.The
list_sensors()functionality introduces a new sensor class hierarchy, offering a more Pythonic and organized way to interact with different sensor types.The main changes are:
Sensor Support:
list_sensors()RPC to retrieve available sensors.stream_sensor_data()RPC to stream data from sensors.SensorId,Lifetime, andAggregatedMetricValueto support current and future sensor functionalities.Bug Fixes:
Testing:
Fixes #136.