11from __future__ import annotations
22
3- from datetime import datetime
3+ import uuid
4+ from datetime import datetime , timedelta , timezone
45
56import pytest
67from s2python .common import (
1112 EnergyManagementRole ,
1213 Handshake ,
1314 NumberRange ,
15+ PowerForecastValue ,
1416 PowerRange ,
1517 ResourceManagerDetails ,
1618 Role ,
2325 FRBCStorageDescription ,
2426 FRBCSystemDescription ,
2527)
28+ from s2python .ppbc import (
29+ PPBCPowerProfileDefinition ,
30+ PPBCPowerSequence ,
31+ PPBCPowerSequenceContainer ,
32+ PPBCPowerSequenceElement ,
33+ )
2634
2735from flexmeasures_client .s2 .utils import get_unique_id
2836
@@ -46,7 +54,7 @@ def frbc_system_description():
4654 )
4755
4856 thp_operation_mode = FRBCOperationMode (
49- id = "tarnoc-operation-mode" ,
57+ id = str ( uuid . uuid4 ()) ,
5058 elements = [thp_operation_mode_element ],
5159 abnormal_condition_only = False ,
5260 )
@@ -64,13 +72,13 @@ def frbc_system_description():
6472 )
6573
6674 nes_operation_mode = FRBCOperationMode (
67- id = "nestore-operation-mode" ,
75+ id = str ( uuid . uuid4 ()) ,
6876 elements = [nes_operation_mode_element ],
6977 abnormal_condition_only = False ,
7078 )
7179
7280 actuator = FRBCActuatorDescription (
73- id = "id-of-the-actuator" ,
81+ id = str ( uuid . uuid4 ()) ,
7482 supported_commodities = [Commodity .ELECTRICITY ],
7583 operation_modes = [thp_operation_mode , nes_operation_mode ],
7684 transitions = [],
@@ -86,7 +94,7 @@ def frbc_system_description():
8694
8795 system_description_message = FRBCSystemDescription (
8896 message_id = get_unique_id (),
89- valid_from = datetime (2024 , 1 , 1 ),
97+ valid_from = datetime (2024 , 1 , 1 , tzinfo = timezone . utc ), # Attach UTC timezone
9098 actuators = [actuator ],
9199 storage = storage ,
92100 )
@@ -95,12 +103,100 @@ def frbc_system_description():
95103
96104
97105@pytest .fixture (scope = "session" )
98- def resource_manager_details ():
106+ def ppbc_power_profile_definition ():
107+ forecast1 = PowerForecastValue (
108+ value_expected = 100.0 , commodity_quantity = CommodityQuantity .ELECTRIC_POWER_L1
109+ )
110+ forecast2 = PowerForecastValue (
111+ value_expected = 200.0 , commodity_quantity = CommodityQuantity .ELECTRIC_POWER_L1
112+ )
113+ forecast3 = PowerForecastValue (
114+ value_expected = 300.0 , commodity_quantity = CommodityQuantity .ELECTRIC_POWER_L1
115+ )
116+
117+ element1 = PPBCPowerSequenceElement (
118+ duration = Duration (1 ), power_values = [forecast1 , forecast2 ]
119+ )
120+ element2 = PPBCPowerSequenceElement (
121+ duration = Duration (1 ), power_values = [forecast2 , forecast3 , forecast1 ]
122+ )
123+
124+ power_sequence1 = PPBCPowerSequence (
125+ id = uuid .uuid4 (),
126+ elements = [element1 , element2 ],
127+ is_interruptible = False ,
128+ max_pause_before = Duration (0 ),
129+ abnormal_condition_only = False ,
130+ )
131+
132+ power_sequence2 = PPBCPowerSequence (
133+ id = uuid .uuid4 (),
134+ elements = [element2 , element1 ],
135+ is_interruptible = True ,
136+ max_pause_before = Duration (0 ),
137+ abnormal_condition_only = True ,
138+ )
139+
140+ power_sequence3 = PPBCPowerSequence (
141+ id = uuid .uuid4 (),
142+ elements = [element2 ],
143+ is_interruptible = False ,
144+ max_pause_before = Duration (10000 ),
145+ abnormal_condition_only = False ,
146+ )
147+
148+ power_sequence4 = PPBCPowerSequence (
149+ id = uuid .uuid4 (),
150+ elements = [element1 ],
151+ is_interruptible = True ,
152+ max_pause_before = Duration (10000 ),
153+ abnormal_condition_only = True ,
154+ )
155+
156+ power_sequence_container1 = PPBCPowerSequenceContainer (
157+ id = uuid .uuid4 (),
158+ power_sequences = [
159+ power_sequence1 ,
160+ power_sequence2 ,
161+ ],
162+ )
163+
164+ power_sequence_container2 = PPBCPowerSequenceContainer (
165+ id = uuid .uuid4 (),
166+ power_sequences = [
167+ power_sequence3 ,
168+ ],
169+ )
170+
171+ power_sequence_container3 = PPBCPowerSequenceContainer (
172+ id = uuid .uuid4 (),
173+ power_sequences = [
174+ power_sequence4 ,
175+ ],
176+ )
177+
178+ power_profile_definition = PPBCPowerProfileDefinition (
179+ message_id = uuid .uuid4 (),
180+ id = uuid .uuid4 (),
181+ start_time = datetime .now (timezone .utc ),
182+ end_time = datetime .now (timezone .utc ) + timedelta (hours = 4 ),
183+ power_sequences_containers = [
184+ power_sequence_container1 ,
185+ power_sequence_container2 ,
186+ power_sequence_container3 ,
187+ ],
188+ )
189+
190+ return power_profile_definition
191+
192+
193+ @pytest .fixture (scope = "session" )
194+ def resource_manager_details_frbc ():
99195 return ResourceManagerDetails (
100196 message_id = get_unique_id (),
101197 resource_id = get_unique_id (),
102198 roles = [Role (role = RoleType .ENERGY_STORAGE , commodity = Commodity .ELECTRICITY )],
103- instruction_processing_delay = Duration (__root__ = 1.0 ),
199+ instruction_processing_delay = Duration (1 ),
104200 available_control_types = [
105201 ControlType .FILL_RATE_BASED_CONTROL ,
106202 ControlType .NO_SELECTION ,
@@ -112,6 +208,26 @@ def resource_manager_details():
112208 )
113209
114210
211+ @pytest .fixture (scope = "session" )
212+ def resource_manager_details_ppbc ():
213+ return ResourceManagerDetails (
214+ message_id = get_unique_id (),
215+ resource_id = get_unique_id (),
216+ roles = [Role (role = RoleType .ENERGY_CONSUMER , commodity = Commodity .ELECTRICITY )],
217+ instruction_processing_delay = Duration (1 ),
218+ available_control_types = [
219+ ControlType .POWER_PROFILE_BASED_CONTROL ,
220+ ControlType .NO_SELECTION ,
221+ ],
222+ provides_forecast = True ,
223+ provides_power_measurement_types = [
224+ CommodityQuantity .ELECTRIC_POWER_L1 ,
225+ CommodityQuantity .ELECTRIC_POWER_L2 ,
226+ CommodityQuantity .ELECTRIC_POWER_L3 ,
227+ ],
228+ )
229+
230+
115231@pytest .fixture (scope = "session" )
116232def rm_handshake ():
117233 return Handshake (
0 commit comments