Skip to content

Commit f70f903

Browse files
authored
Restore sensor support (#228)
This pull request restores sensor support that was temporarily removed in v0.18.0. The sensor API has been redesigned to align with the updated component and metrics model introduced in v0.18.0, providing a more consistent interface for working with environmental sensors in microgrids. Fixes #211.
2 parents 5173e73 + b8a0d64 commit f70f903

25 files changed

Lines changed: 2358 additions & 17 deletions

RELEASE_NOTES.md

Lines changed: 169 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,176 @@
22

33
## Summary
44

5-
This release adds a new `WindTurbine` component type.
5+
This release reintroduces sensor support that was temporarily removed in the v0.18.0 release. The new sensor API has been redesigned to fit the updated component and metrics model introduced in v0.18.0.
66

7-
## Upgrading
7+
## New Features
88

9-
- If you are using `match` and doing exhaustive matching on the `Component` types, you will get `mypy` errors and will need to handle the new `WindTurbine` type.
9+
- New `sensor` module (`frequenz.client.microgrid.sensor`) with sensor related types.
10+
- New `MicrogridApiClient` methods
1011

11-
## New Features
12+
* `list_sensors()`: fetch sensor metadata.
13+
* `receive_sensor_telemetry_stream()`: stream sensor telemetry data.
14+
15+
Example:
16+
17+
```python
18+
import asyncio
19+
from frequenz.client.microgrid import MicrogridApiClient
20+
from frequenz.client.microgrid.metrics import Metric
21+
22+
URL = "grpc://[::1]:62060"
23+
24+
async def main() -> None:
25+
print(f"Connecting to {URL}...")
26+
async with MicrogridApiClient(URL) as client:
27+
print("Listing available sensors...")
28+
sensors = list(await client.list_sensors())
29+
30+
if not sensors:
31+
print("No sensors found.")
32+
return
33+
34+
print(f"Found {len(sensors)}: {sensors}.")
35+
print()
36+
37+
sensor = sensors[0]
38+
print(f"Streaming telemetry from sensor {sensor.id} ({sensor.name})...")
39+
telemetry_stream = client.receive_sensor_telemetry_stream(
40+
sensors[0].id, list(Metric)
41+
)
42+
async for telemetry in telemetry_stream:
43+
print(f"\tReceived: {telemetry}")
44+
45+
asyncio.run(main())
46+
```
47+
48+
## Upgrading (from v0.9)
49+
50+
### Sensor support restored with new API
51+
52+
Sensor support that was removed in v0.18.0 is now back, but with a redesigned API that aligns with the v0.18.0 component and metrics model.
53+
54+
#### `list_sensors()`
55+
56+
The method name remains the same, but the signature and return type have changed:
57+
58+
```python
59+
# Old v0.9.1 API
60+
sensors: Iterable[Sensor] = await client.list_sensors()
61+
62+
# New v0.18.2 API (same method name, different types)
63+
from frequenz.client.common.microgrid.sensors import SensorId
64+
from frequenz.client.microgrid.sensor import Sensor
65+
66+
sensors: Iterable[Sensor] = await client.list_sensors()
67+
68+
# You can also filter by sensor IDs
69+
sensors = await client.list_sensors(sensors=[SensorId(1), SensorId(2)])
70+
```
71+
The `Sensor` class now provides a new attribute `microgrid_id: MicrogridId` and the `identity` property now returns a tuple `(SensorId, MicrogridId)` instead of just `SensorId`.
72+
73+
#### `stream_sensor_data()``receive_sensor_telemetry_stream()`
74+
75+
The streaming method has been renamed and its return type changed:
76+
77+
```python
78+
# Old v0.9.1 API
79+
from frequenz.client.microgrid.sensor import SensorDataSamples, SensorMetric
80+
81+
receiver: Receiver[SensorDataSamples] = client.stream_sensor_data(
82+
sensor=SensorId(1),
83+
metrics=[SensorMetric.TEMPERATURE, SensorMetric.HUMIDITY], # optional
84+
)
85+
86+
async for samples in receiver:
87+
# samples.metric_samples, samples.state_sample, etc.
88+
...
89+
90+
# New v0.18.2 API
91+
from frequenz.client.microgrid.sensor import SensorTelemetry
92+
from frequenz.client.microgrid.metrics import Metric
93+
94+
receiver: Receiver[SensorTelemetry] = client.receive_sensor_telemetry_stream(
95+
sensor=SensorId(1),
96+
metrics=[Metric.TEMPERATURE, Metric.AC_VOLTAGE], # required
97+
)
98+
99+
async for telemetry in receiver:
100+
# telemetry.sensor_id: SensorId
101+
# telemetry.metric_samples: Sequence[MetricSample]
102+
# telemetry.state_snapshots: Sequence[SensorStateSnapshot]
103+
for sample in telemetry.metric_samples:
104+
print(f"{sample.metric}: {sample.value} at {sample.sampled_at}")
105+
...
106+
```
107+
108+
Key differences:
109+
110+
- **Method renamed**: `stream_sensor_data()``receive_sensor_telemetry_stream()`
111+
- **Metrics parameter is now required**: You must specify which metrics to stream. The old API allowed `None` to stream all metrics.
112+
- **Uses unified `Metric` enum**: The old `SensorMetric` enum is removed. Use `frequenz.client.microgrid.metrics.Metric` instead.
113+
- **Return type changed**: `SensorDataSamples``SensorTelemetry`
114+
- **State samples changed**: `SensorStateSample``SensorStateSnapshot` with different structure (see below)
115+
116+
#### Sensor state types
117+
118+
The sensor state types have been redesigned:
119+
120+
| Old v0.9.1 type | New v0.18.2 type |
121+
|---------------------------|-------------------------------------------|
122+
| `SensorMetric` | *Removed* — use `Metric` |
123+
| `SensorStateCode` | `SensorStateCode` (different values) |
124+
| `SensorErrorCode` | `SensorDiagnosticCode` |
125+
| `SensorStateSample` | `SensorStateSnapshot` |
126+
| `SensorMetricSample` | `MetricSample` |
127+
| `SensorDataSamples` | `SensorTelemetry` |
128+
129+
The new `SensorStateSnapshot` structure:
130+
131+
```python
132+
@dataclass(frozen=True, kw_only=True)
133+
class SensorStateSnapshot:
134+
origin_time: datetime # was `sampled_at`
135+
states: Set[SensorStateCode | int] # was `frozenset`
136+
warnings: Sequence[SensorDiagnostic] # new
137+
errors: Sequence[SensorDiagnostic] # replaces error codes
138+
```
139+
140+
The new `SensorDiagnostic` provides richer error/warning information:
141+
142+
```python
143+
@dataclass(frozen=True, kw_only=True)
144+
class SensorDiagnostic:
145+
diagnostic_code: SensorDiagnosticCode | int
146+
message: str | None
147+
vendor_diagnostic_code: str | None
148+
```
149+
150+
#### Import changes
151+
152+
Update your imports for sensor types:
153+
154+
```python
155+
# Old v0.9.1
156+
from frequenz.client.microgrid.sensor import (
157+
Sensor,
158+
SensorDataSamples,
159+
SensorErrorCode,
160+
SensorMetric,
161+
SensorMetricSample,
162+
SensorStateCode,
163+
SensorStateSample,
164+
)
12165

13-
- Add `WindTurbine` component type.
166+
# New v0.18.2
167+
from frequenz.client.microgrid.sensor import (
168+
Sensor,
169+
SensorDiagnostic,
170+
SensorDiagnosticCode,
171+
SensorStateCode,
172+
SensorStateSnapshot,
173+
SensorTelemetry,
174+
)
175+
from frequenz.client.microgrid.metrics import Metric, MetricSample
176+
from frequenz.client.common.microgrid.sensors import SensorId
177+
```

src/frequenz/client/microgrid/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
This package provides a low-level interface for interacting with the microgrid API.
77
"""
88

9-
109
from ._client import (
1110
DEFAULT_CHANNEL_OPTIONS,
1211
DEFAULT_GRPC_CALL_TIMEOUT,

0 commit comments

Comments
 (0)