Skip to content

Commit fe62ffd

Browse files
Add tests for voltage streaming
Signed-off-by: Daniel Zullo <[email protected]>
1 parent 1e69b8e commit fe62ffd

File tree

2 files changed

+162
-4
lines changed

2 files changed

+162
-4
lines changed

tests/timeseries/mock_resampler.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,15 @@ def frequency_senders(
8181
[NON_EXISTING_COMPONENT_ID]
8282
)[0]
8383

84-
def current_senders(ids: list[int]) -> list[list[Sender[Sample[Quantity]]]]:
84+
def multi_phase_senders(
85+
ids: list[int],
86+
metrics: tuple[ComponentMetricId, ComponentMetricId, ComponentMetricId],
87+
) -> list[list[Sender[Sample[Quantity]]]]:
8588
senders: list[list[Sender[Sample[Quantity]]]] = []
8689
for comp_id in ids:
87-
p1_name = f"{comp_id}:{ComponentMetricId.CURRENT_PHASE_1}"
88-
p2_name = f"{comp_id}:{ComponentMetricId.CURRENT_PHASE_2}"
89-
p3_name = f"{comp_id}:{ComponentMetricId.CURRENT_PHASE_3}"
90+
p1_name = f"{comp_id}:{metrics[0]}"
91+
p2_name = f"{comp_id}:{metrics[1]}"
92+
p3_name = f"{comp_id}:{metrics[2]}"
9093

9194
senders.append(
9295
[
@@ -109,12 +112,34 @@ def current_senders(ids: list[int]) -> list[list[Sender[Sample[Quantity]]]]:
109112
]
110113
return senders
111114

115+
def current_senders(ids: list[int]) -> list[list[Sender[Sample[Quantity]]]]:
116+
return multi_phase_senders(
117+
ids,
118+
(
119+
ComponentMetricId.CURRENT_PHASE_1,
120+
ComponentMetricId.CURRENT_PHASE_2,
121+
ComponentMetricId.CURRENT_PHASE_3,
122+
),
123+
)
124+
125+
def voltage_senders(ids: list[int]) -> list[list[Sender[Sample[Quantity]]]]:
126+
return multi_phase_senders(
127+
ids,
128+
(
129+
ComponentMetricId.VOLTAGE_PHASE_1,
130+
ComponentMetricId.VOLTAGE_PHASE_2,
131+
ComponentMetricId.VOLTAGE_PHASE_3,
132+
),
133+
)
134+
112135
self._bat_inverter_current_senders = current_senders(bat_inverter_ids)
113136
self._pv_inverter_current_senders = current_senders(pv_inverter_ids)
114137
self._ev_current_senders = current_senders(evc_ids)
115138
self._chp_current_senders = current_senders(chp_ids)
116139
self._meter_current_senders = current_senders(meter_ids)
117140

141+
self._meter_voltage_senders = voltage_senders(meter_ids)
142+
118143
self._next_ts = datetime.now()
119144

120145
mocker.patch(
@@ -242,3 +267,12 @@ async def send_meter_current(self, values: list[list[float | None]]) -> None:
242267
for phase, value in enumerate(meter_values):
243268
sample = Sample(self._next_ts, None if not value else Quantity(value))
244269
await chan[phase].send(sample)
270+
271+
async def send_meter_voltage(self, values: list[list[float | None]]) -> None:
272+
"""Send the given values as resampler output for meter voltage."""
273+
assert len(values) == len(self._meter_voltage_senders)
274+
for chan, meter_values in zip(self._meter_voltage_senders, values):
275+
assert len(meter_values) == 3 # 3 values for phases
276+
for phase, value in enumerate(meter_values):
277+
sample = Sample(self._next_ts, None if not value else Quantity(value))
278+
await chan[phase].send(sample)
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# License: MIT
2+
# Copyright © 2023 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Tests for fetching and streaming the phase-to-neutral voltage."""
5+
6+
7+
import asyncio
8+
9+
from pytest_mock import MockerFixture
10+
11+
from frequenz.sdk import microgrid
12+
13+
from .mock_microgrid import MockMicrogrid
14+
15+
# pylint: disable=protected-access
16+
17+
18+
async def test_voltage_1(mocker: MockerFixture) -> None:
19+
"""Test the phase-to-neutral voltage with a grid side meter."""
20+
mockgrid = MockMicrogrid(grid_meter=True)
21+
mockgrid.add_batteries(1, no_meter=True)
22+
mockgrid.add_batteries(1, no_meter=False)
23+
await mockgrid.start(mocker)
24+
25+
voltage = microgrid.voltage()
26+
voltage_recv = voltage.new_receiver()
27+
28+
assert voltage._task is not None
29+
# Wait for voltage requests to be sent, one request per phase.
30+
await asyncio.sleep(0)
31+
await asyncio.sleep(0)
32+
await asyncio.sleep(0)
33+
34+
for count in range(10):
35+
volt_delta = 1 if count % 2 == 0 else -1
36+
volt_phases: list[float | None] = [
37+
220.0 * volt_delta,
38+
219.8 * volt_delta,
39+
220.2 * volt_delta,
40+
]
41+
42+
await mockgrid.mock_resampler.send_meter_voltage([volt_phases, volt_phases])
43+
44+
val = await voltage_recv.receive()
45+
assert val is not None
46+
assert val.value_p1 and val.value_p2 and val.value_p3
47+
assert val.value_p1.as_volts() == volt_phases[0]
48+
assert val.value_p2.as_volts() == volt_phases[1]
49+
assert val.value_p3.as_volts() == volt_phases[2]
50+
51+
await mockgrid.cleanup()
52+
53+
54+
async def test_voltage_2(mocker: MockerFixture) -> None:
55+
"""Test the phase-to-neutral voltage without a grid side meter."""
56+
mockgrid = MockMicrogrid(grid_meter=False)
57+
mockgrid.add_batteries(1, no_meter=False)
58+
mockgrid.add_batteries(1, no_meter=True)
59+
await mockgrid.start(mocker)
60+
61+
voltage = microgrid.voltage()
62+
voltage_recv = voltage.new_receiver()
63+
64+
assert voltage._task is not None
65+
# Wait for voltage requests to be sent, one request per phase.
66+
await asyncio.sleep(0)
67+
await asyncio.sleep(0)
68+
await asyncio.sleep(0)
69+
70+
for count in range(10):
71+
volt_delta = 1 if count % 2 == 0 else -1
72+
volt_phases: list[float | None] = [
73+
220.0 * volt_delta,
74+
219.8 * volt_delta,
75+
220.2 * volt_delta,
76+
]
77+
78+
await mockgrid.mock_resampler.send_meter_voltage([volt_phases])
79+
80+
val = await voltage_recv.receive()
81+
assert val is not None
82+
assert val.value_p1 and val.value_p2 and val.value_p3
83+
assert val.value_p1.as_volts() == volt_phases[0]
84+
assert val.value_p2.as_volts() == volt_phases[1]
85+
assert val.value_p3.as_volts() == volt_phases[2]
86+
87+
await mockgrid.cleanup()
88+
89+
90+
async def test_voltage_3(mocker: MockerFixture) -> None:
91+
"""Test the phase-to-neutral voltage with None values."""
92+
mockgrid = MockMicrogrid(grid_meter=True)
93+
mockgrid.add_batteries(2, no_meter=False)
94+
await mockgrid.start(mocker)
95+
96+
voltage = microgrid.voltage()
97+
voltage_recv = voltage.new_receiver()
98+
99+
assert voltage._task is not None
100+
# Wait for voltage requests to be sent, one request per phase.
101+
await asyncio.sleep(0)
102+
await asyncio.sleep(0)
103+
await asyncio.sleep(0)
104+
105+
for count in range(10):
106+
volt_delta = 1 if count % 2 == 0 else -1
107+
volt_phases: list[float | None] = [
108+
220.0 * volt_delta,
109+
219.8 * volt_delta,
110+
220.2 * volt_delta,
111+
]
112+
113+
await mockgrid.mock_resampler.send_meter_voltage(
114+
[volt_phases, [None, None, None], [None, 219.8, 220.2]]
115+
)
116+
117+
val = await voltage_recv.receive()
118+
assert val is not None
119+
assert val.value_p1 and val.value_p2 and val.value_p3
120+
assert val.value_p1.as_volts() == volt_phases[0]
121+
assert val.value_p2.as_volts() == volt_phases[1]
122+
assert val.value_p3.as_volts() == volt_phases[2]
123+
124+
await mockgrid.cleanup()

0 commit comments

Comments
 (0)