Skip to content

Commit 90ad331

Browse files
authored
Fix frequency sending Quantity (#804)
- Move frequency() tests into own file - Fix frequency() sending `Quantities` instead of `Frequency`
2 parents f89c53b + 29d73a8 commit 90ad331

File tree

4 files changed

+172
-148
lines changed

4 files changed

+172
-148
lines changed

RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,4 @@
5757
## Bug Fixes
5858

5959
- 0W power requests are now not adjusted to exclusion bounds by the `PowerManager` and `PowerDistributor`, and are sent over to the microgrid API directly.
60+
- Fixed that `microgrid.frequency()` was sending `Quantity` objects instead of `Frequency`.

src/frequenz/sdk/timeseries/_grid_frequency.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ def new_receiver(self) -> Receiver[Sample[Frequency]]:
9393
"Grid frequency request already sent: %s", self._source_component
9494
)
9595

96-
return receiver
96+
return receiver.map(
97+
lambda sample: Sample(
98+
sample.timestamp, Frequency.from_hertz(sample.value.base_value)
99+
)
100+
)
97101

98102
async def _send_request(self) -> None:
99103
"""Send the request for grid frequency."""
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# License: MIT
2+
# Copyright © 2022 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Tests for the logical meter."""
5+
6+
7+
import asyncio
8+
from datetime import datetime, timezone
9+
10+
from pytest_mock import MockerFixture
11+
12+
from frequenz.sdk import microgrid
13+
from frequenz.sdk.timeseries._quantities import Frequency
14+
from tests.utils import component_data_wrapper
15+
16+
from ._formula_engine.utils import equal_float_lists
17+
from .mock_microgrid import MockMicrogrid
18+
19+
# pylint: disable=protected-access
20+
21+
22+
async def test_grid_frequency_1(mocker: MockerFixture) -> None:
23+
"""Test the grid frequency formula."""
24+
mockgrid = MockMicrogrid(grid_meter=True)
25+
mockgrid.add_batteries(2)
26+
mockgrid.add_solar_inverters(1)
27+
await mockgrid.start(mocker)
28+
29+
grid_freq = microgrid.frequency()
30+
grid_freq_recv = grid_freq.new_receiver()
31+
32+
assert grid_freq._task is not None
33+
# We have to wait for the metric request to be sent
34+
await grid_freq._task
35+
# And consumed
36+
await asyncio.sleep(0)
37+
38+
results = []
39+
grid_meter_data = []
40+
for count in range(10):
41+
freq = float(50.0 + (1 if count % 2 == 0 else -1) * 0.01)
42+
await mockgrid.mock_client.send(
43+
component_data_wrapper.MeterDataWrapper(
44+
mockgrid.meter_ids[0], datetime.now(tz=timezone.utc), frequency=freq
45+
)
46+
)
47+
48+
grid_meter_data.append(Frequency.from_hertz(freq))
49+
val = await grid_freq_recv.receive()
50+
assert val is not None and val.value is not None
51+
assert val.value.as_hertz() == freq
52+
results.append(val.value)
53+
await mockgrid.cleanup()
54+
assert equal_float_lists(results, grid_meter_data)
55+
56+
57+
async def test_grid_frequency_no_grid_meter_no_consumer_meter(
58+
mocker: MockerFixture,
59+
) -> None:
60+
"""Test the grid frequency formula without a grid side meter."""
61+
mockgrid = MockMicrogrid(grid_meter=False)
62+
mockgrid.add_consumer_meters()
63+
mockgrid.add_batteries(1, no_meter=False)
64+
mockgrid.add_batteries(1, no_meter=False)
65+
await mockgrid.start(mocker)
66+
grid_freq = microgrid.frequency()
67+
68+
grid_freq_recv = grid_freq.new_receiver()
69+
# We have to wait for the metric request to be sent
70+
assert grid_freq._task is not None
71+
await grid_freq._task
72+
# And consumed
73+
await asyncio.sleep(0)
74+
75+
results = []
76+
meter_data = []
77+
for count in range(10):
78+
freq = float(50.0 + (1 if count % 2 == 0 else -1) * 0.01)
79+
await mockgrid.mock_client.send(
80+
component_data_wrapper.MeterDataWrapper(
81+
mockgrid.meter_ids[0], datetime.now(tz=timezone.utc), frequency=freq
82+
)
83+
)
84+
meter_data.append(Frequency.from_hertz(freq))
85+
86+
val = await grid_freq_recv.receive()
87+
assert val is not None and val.value is not None
88+
assert val.value.as_hertz() == freq
89+
results.append(val.value)
90+
await mockgrid.cleanup()
91+
assert equal_float_lists(results, meter_data)
92+
93+
94+
async def test_grid_frequency_no_grid_meter(
95+
mocker: MockerFixture,
96+
) -> None:
97+
"""Test the grid frequency formula without a grid side meter."""
98+
mockgrid = MockMicrogrid(grid_meter=False)
99+
mockgrid.add_batteries(1, no_meter=False)
100+
mockgrid.add_batteries(1, no_meter=True)
101+
await mockgrid.start(mocker)
102+
grid_freq = microgrid.frequency()
103+
104+
grid_freq_recv = grid_freq.new_receiver()
105+
# We have to wait for the metric request to be sent
106+
assert grid_freq._task is not None
107+
await grid_freq._task
108+
# And consumed
109+
await asyncio.sleep(0)
110+
111+
results = []
112+
meter_data = []
113+
for count in range(10):
114+
freq = float(50.0 + (1 if count % 2 == 0 else -1) * 0.01)
115+
await mockgrid.mock_client.send(
116+
component_data_wrapper.MeterDataWrapper(
117+
mockgrid.meter_ids[0], datetime.now(tz=timezone.utc), frequency=freq
118+
)
119+
)
120+
meter_data.append(Frequency.from_hertz(freq))
121+
122+
val = await grid_freq_recv.receive()
123+
assert val is not None and val.value is not None
124+
assert val.value.as_hertz() == freq
125+
results.append(val.value)
126+
await mockgrid.cleanup()
127+
assert equal_float_lists(results, meter_data)
128+
129+
130+
async def test_grid_frequency_only_inverter(
131+
mocker: MockerFixture,
132+
) -> None:
133+
"""Test the grid frequency formula without any meter but only inverters."""
134+
mockgrid = MockMicrogrid(grid_meter=False)
135+
mockgrid.add_batteries(2, no_meter=True)
136+
await mockgrid.start(mocker)
137+
138+
grid_freq = microgrid.frequency()
139+
grid_freq_recv = grid_freq.new_receiver()
140+
# We have to wait for the metric request to be sent
141+
assert grid_freq._task is not None
142+
await grid_freq._task
143+
# And consumed
144+
await asyncio.sleep(0)
145+
146+
results = []
147+
meter_data = []
148+
for count in range(10):
149+
freq = float(50.0 + (1 if count % 2 == 0 else -1) * 0.01)
150+
151+
await mockgrid.mock_client.send(
152+
component_data_wrapper.InverterDataWrapper(
153+
mockgrid.battery_inverter_ids[0],
154+
datetime.now(tz=timezone.utc),
155+
frequency=freq,
156+
)
157+
)
158+
159+
meter_data.append(Frequency.from_hertz(freq))
160+
val = await grid_freq_recv.receive()
161+
assert val is not None and val.value is not None
162+
assert val.value.as_hertz() == freq
163+
results.append(val.value)
164+
await mockgrid.cleanup()
165+
assert equal_float_lists(results, meter_data)

tests/timeseries/test_logical_meter.py

Lines changed: 1 addition & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,11 @@
44
"""Tests for the logical meter."""
55

66

7-
import asyncio
8-
from datetime import datetime, timezone
9-
107
from pytest_mock import MockerFixture
118

129
from frequenz.sdk import microgrid
13-
from frequenz.sdk.timeseries._quantities import Frequency, Power
14-
from tests.utils import component_data_wrapper
10+
from frequenz.sdk.timeseries._quantities import Power
1511

16-
from ._formula_engine.utils import equal_float_lists
1712
from .mock_microgrid import MockMicrogrid
1813

1914
# pylint: disable=too-many-locals
@@ -23,147 +18,6 @@
2318
class TestLogicalMeter: # pylint: disable=too-many-public-methods
2419
"""Tests for the logical meter."""
2520

26-
async def test_grid_frequency_1(self, mocker: MockerFixture) -> None:
27-
"""Test the grid frequency formula."""
28-
mockgrid = MockMicrogrid(grid_meter=True)
29-
mockgrid.add_batteries(2)
30-
mockgrid.add_solar_inverters(1)
31-
await mockgrid.start(mocker)
32-
33-
grid_freq = microgrid.frequency()
34-
grid_freq_recv = grid_freq.new_receiver()
35-
36-
assert grid_freq._task is not None
37-
# We have to wait for the metric request to be sent
38-
await grid_freq._task
39-
# And consumed
40-
await asyncio.sleep(0)
41-
42-
results = []
43-
grid_meter_data = []
44-
for count in range(10):
45-
freq = float(50.0 + (1 if count % 2 == 0 else -1) * 0.01)
46-
await mockgrid.mock_client.send(
47-
component_data_wrapper.MeterDataWrapper(
48-
mockgrid.meter_ids[0], datetime.now(tz=timezone.utc), frequency=freq
49-
)
50-
)
51-
52-
grid_meter_data.append(Frequency.from_hertz(freq))
53-
val = await grid_freq_recv.receive()
54-
assert val is not None and val.value is not None
55-
results.append(val.value)
56-
await mockgrid.cleanup()
57-
assert equal_float_lists(results, grid_meter_data)
58-
59-
async def test_grid_frequency_no_grid_meter_no_consumer_meter(
60-
self,
61-
mocker: MockerFixture,
62-
) -> None:
63-
"""Test the grid frequency formula without a grid side meter."""
64-
mockgrid = MockMicrogrid(grid_meter=False)
65-
mockgrid.add_consumer_meters()
66-
mockgrid.add_batteries(1, no_meter=False)
67-
mockgrid.add_batteries(1, no_meter=False)
68-
await mockgrid.start(mocker)
69-
grid_freq = microgrid.frequency()
70-
71-
grid_freq_recv = grid_freq.new_receiver()
72-
# We have to wait for the metric request to be sent
73-
assert grid_freq._task is not None
74-
await grid_freq._task
75-
# And consumed
76-
await asyncio.sleep(0)
77-
78-
results = []
79-
meter_data = []
80-
for count in range(10):
81-
freq = float(50.0 + (1 if count % 2 == 0 else -1) * 0.01)
82-
await mockgrid.mock_client.send(
83-
component_data_wrapper.MeterDataWrapper(
84-
mockgrid.meter_ids[0], datetime.now(tz=timezone.utc), frequency=freq
85-
)
86-
)
87-
meter_data.append(Frequency.from_hertz(freq))
88-
89-
val = await grid_freq_recv.receive()
90-
assert val is not None and val.value is not None
91-
results.append(val.value)
92-
await mockgrid.cleanup()
93-
assert equal_float_lists(results, meter_data)
94-
95-
async def test_grid_frequency_no_grid_meter(
96-
self,
97-
mocker: MockerFixture,
98-
) -> None:
99-
"""Test the grid frequency formula without a grid side meter."""
100-
mockgrid = MockMicrogrid(grid_meter=False)
101-
mockgrid.add_batteries(1, no_meter=False)
102-
mockgrid.add_batteries(1, no_meter=True)
103-
await mockgrid.start(mocker)
104-
grid_freq = microgrid.frequency()
105-
106-
grid_freq_recv = grid_freq.new_receiver()
107-
# We have to wait for the metric request to be sent
108-
assert grid_freq._task is not None
109-
await grid_freq._task
110-
# And consumed
111-
await asyncio.sleep(0)
112-
113-
results = []
114-
meter_data = []
115-
for count in range(10):
116-
freq = float(50.0 + (1 if count % 2 == 0 else -1) * 0.01)
117-
await mockgrid.mock_client.send(
118-
component_data_wrapper.MeterDataWrapper(
119-
mockgrid.meter_ids[0], datetime.now(tz=timezone.utc), frequency=freq
120-
)
121-
)
122-
meter_data.append(Frequency.from_hertz(freq))
123-
124-
val = await grid_freq_recv.receive()
125-
assert val is not None and val.value is not None
126-
results.append(val.value)
127-
await mockgrid.cleanup()
128-
assert equal_float_lists(results, meter_data)
129-
130-
async def test_grid_frequency_only_inverter(
131-
self,
132-
mocker: MockerFixture,
133-
) -> None:
134-
"""Test the grid frequency formula without any meter but only inverters."""
135-
mockgrid = MockMicrogrid(grid_meter=False)
136-
mockgrid.add_batteries(2, no_meter=True)
137-
await mockgrid.start(mocker)
138-
139-
grid_freq = microgrid.frequency()
140-
grid_freq_recv = grid_freq.new_receiver()
141-
# We have to wait for the metric request to be sent
142-
assert grid_freq._task is not None
143-
await grid_freq._task
144-
# And consumed
145-
await asyncio.sleep(0)
146-
147-
results = []
148-
meter_data = []
149-
for count in range(10):
150-
freq = float(50.0 + (1 if count % 2 == 0 else -1) * 0.01)
151-
152-
await mockgrid.mock_client.send(
153-
component_data_wrapper.InverterDataWrapper(
154-
mockgrid.battery_inverter_ids[0],
155-
datetime.now(tz=timezone.utc),
156-
frequency=freq,
157-
)
158-
)
159-
160-
meter_data.append(Frequency.from_hertz(freq))
161-
val = await grid_freq_recv.receive()
162-
assert val is not None and val.value is not None
163-
results.append(val.value)
164-
await mockgrid.cleanup()
165-
assert equal_float_lists(results, meter_data)
166-
16721
async def test_chp_power(self, mocker: MockerFixture) -> None:
16822
"""Test the chp power formula."""
16923
mockgrid = MockMicrogrid(grid_meter=False)

0 commit comments

Comments
 (0)