s2-python 0.4.1__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. {s2_python-0.4.1.dist-info → s2_python-0.5.0.dist-info}/METADATA +3 -2
  2. s2_python-0.5.0.dist-info/RECORD +82 -0
  3. {s2_python-0.4.1.dist-info → s2_python-0.5.0.dist-info}/WHEEL +1 -1
  4. s2python/common/__init__.py +32 -0
  5. s2python/common/duration.py +3 -1
  6. s2python/common/handshake.py +2 -2
  7. s2python/common/handshake_response.py +2 -2
  8. s2python/common/instruction_status_update.py +3 -3
  9. s2python/common/number_range.py +1 -1
  10. s2python/common/power_forecast.py +3 -3
  11. s2python/common/power_forecast_element.py +5 -5
  12. s2python/common/power_forecast_value.py +1 -1
  13. s2python/common/power_measurement.py +3 -3
  14. s2python/common/power_range.py +1 -1
  15. s2python/common/power_value.py +1 -1
  16. s2python/common/reception_status.py +2 -2
  17. s2python/common/resource_manager_details.py +6 -6
  18. s2python/common/revoke_object.py +3 -3
  19. s2python/common/role.py +1 -1
  20. s2python/common/select_control_type.py +2 -2
  21. s2python/common/session_request.py +2 -2
  22. s2python/common/timer.py +3 -3
  23. s2python/common/transition.py +8 -8
  24. s2python/ddbc/__init__.py +21 -0
  25. s2python/ddbc/ddbc_actuator_description.py +30 -0
  26. s2python/ddbc/ddbc_actuator_status.py +22 -0
  27. s2python/ddbc/ddbc_average_demand_rate_forecast.py +28 -0
  28. s2python/ddbc/ddbc_average_demand_rate_forecast_element.py +21 -0
  29. s2python/ddbc/ddbc_instruction.py +19 -0
  30. s2python/ddbc/ddbc_operation_mode.py +26 -0
  31. s2python/ddbc/ddbc_system_description.py +29 -0
  32. s2python/ddbc/ddbc_timer_status.py +18 -0
  33. s2python/frbc/__init__.py +19 -3
  34. s2python/frbc/frbc_actuator_description.py +9 -7
  35. s2python/frbc/frbc_actuator_status.py +5 -5
  36. s2python/frbc/frbc_fill_level_target_profile.py +3 -3
  37. s2python/frbc/frbc_fill_level_target_profile_element.py +3 -5
  38. s2python/frbc/frbc_instruction.py +5 -5
  39. s2python/frbc/frbc_leakage_behaviour.py +3 -3
  40. s2python/frbc/frbc_leakage_behaviour_element.py +2 -4
  41. s2python/frbc/frbc_operation_mode.py +6 -4
  42. s2python/frbc/frbc_operation_mode_element.py +5 -5
  43. s2python/frbc/frbc_storage_description.py +2 -2
  44. s2python/frbc/frbc_storage_status.py +2 -2
  45. s2python/frbc/frbc_system_description.py +4 -4
  46. s2python/frbc/frbc_timer_status.py +4 -4
  47. s2python/frbc/frbc_usage_forecast.py +3 -3
  48. s2python/frbc/frbc_usage_forecast_element.py +2 -2
  49. s2python/generated/gen_s2.py +507 -543
  50. s2python/message.py +90 -6
  51. s2python/pebc/__init__.py +21 -0
  52. s2python/pebc/pebc_allowed_limit_range.py +26 -0
  53. s2python/pebc/pebc_energy_constraint.py +25 -0
  54. s2python/pebc/pebc_instruction.py +27 -0
  55. s2python/pebc/pebc_power_constraints.py +27 -0
  56. s2python/pebc/pebc_power_envelope.py +23 -0
  57. s2python/pebc/pebc_power_envelope_element.py +16 -0
  58. s2python/ppbc/__init__.py +15 -6
  59. s2python/ppbc/ppbc_end_interruption_instruction.py +6 -8
  60. s2python/ppbc/ppbc_power_profile_definition.py +4 -6
  61. s2python/ppbc/ppbc_power_profile_status.py +2 -4
  62. s2python/ppbc/ppbc_power_sequence.py +6 -6
  63. s2python/ppbc/ppbc_power_sequence_container.py +5 -7
  64. s2python/ppbc/ppbc_power_sequence_container_status.py +7 -9
  65. s2python/ppbc/ppbc_power_sequence_element.py +3 -5
  66. s2python/ppbc/ppbc_schedule_instruction.py +6 -8
  67. s2python/ppbc/ppbc_start_interruption_instruction.py +6 -8
  68. s2python/s2_connection.py +30 -12
  69. s2python/s2_control_type.py +15 -0
  70. s2python/s2_parser.py +1 -3
  71. s2python/validate_values_mixin.py +29 -14
  72. s2_python-0.4.1.dist-info/RECORD +0 -66
  73. {s2_python-0.4.1.dist-info → s2_python-0.5.0.dist-info}/entry_points.txt +0 -0
  74. {s2_python-0.4.1.dist-info → s2_python-0.5.0.dist-info}/top_level.txt +0 -0
s2python/s2_connection.py CHANGED
@@ -4,8 +4,9 @@ import logging
4
4
  import time
5
5
  import threading
6
6
  import uuid
7
+ import ssl
7
8
  from dataclasses import dataclass
8
- from typing import Optional, List, Type, Dict, Callable, Awaitable, Union
9
+ from typing import Any, Optional, List, Type, Dict, Callable, Awaitable, Union
9
10
 
10
11
  import websockets
11
12
  from websockets.asyncio.client import ClientConnection as WSConnection, connect as ws_connect
@@ -35,7 +36,7 @@ logger = logging.getLogger("s2python")
35
36
 
36
37
  @dataclass
37
38
  class AssetDetails: # pylint: disable=too-many-instance-attributes
38
- resource_id: str
39
+ resource_id: uuid.UUID
39
40
 
40
41
  provides_forecast: bool
41
42
  provides_power_measurements: List[CommodityQuantity]
@@ -92,7 +93,7 @@ class SendOkay:
92
93
  self.status_is_send.set()
93
94
 
94
95
  await self.connection.respond_with_reception_status(
95
- subject_message_id=str(self.subject_message_id),
96
+ subject_message_id=self.subject_message_id,
96
97
  status=ReceptionStatusValues.OK,
97
98
  diagnostic_label="Processed okay.",
98
99
  )
@@ -101,7 +102,7 @@ class SendOkay:
101
102
  self.status_is_send.set()
102
103
 
103
104
  self.connection.respond_with_reception_status_sync(
104
- subject_message_id=str(self.subject_message_id),
105
+ subject_message_id=self.subject_message_id,
105
106
  status=ReceptionStatusValues.OK,
106
107
  diagnostic_label="Processed okay.",
107
108
  )
@@ -158,7 +159,7 @@ class MessageHandlers:
158
159
  except Exception:
159
160
  if not send_okay.status_is_send.is_set():
160
161
  await connection.respond_with_reception_status(
161
- subject_message_id=str(msg.message_id), # type: ignore[attr-defined, union-attr]
162
+ subject_message_id=msg.message_id, # type: ignore[attr-defined, union-attr]
162
163
  status=ReceptionStatusValues.PERMANENT_ERROR,
163
164
  diagnostic_label=f"While processing message {msg.message_id} " # type: ignore[attr-defined, union-attr] # pylint: disable=line-too-long
164
165
  f"an unrecoverable error occurred.",
@@ -198,6 +199,8 @@ class S2Connection: # pylint: disable=too-many-instance-attributes
198
199
  _eventloop: asyncio.AbstractEventLoop
199
200
  _stop_event: asyncio.Event
200
201
  _restart_connection_event: asyncio.Event
202
+ _verify_certificate: bool
203
+ _bearer_token: Optional[str]
201
204
 
202
205
  def __init__( # pylint: disable=too-many-arguments
203
206
  self,
@@ -206,6 +209,8 @@ class S2Connection: # pylint: disable=too-many-instance-attributes
206
209
  control_types: List[S2ControlType],
207
210
  asset_details: AssetDetails,
208
211
  reconnect: bool = False,
212
+ verify_certificate: bool = True,
213
+ bearer_token: Optional[str] = None,
209
214
  ) -> None:
210
215
  self.url = url
211
216
  self.reconnect = reconnect
@@ -221,10 +226,12 @@ class S2Connection: # pylint: disable=too-many-instance-attributes
221
226
  self.control_types = control_types
222
227
  self.role = role
223
228
  self.asset_details = asset_details
229
+ self._verify_certificate = verify_certificate
224
230
 
225
231
  self._handlers.register_handler(SelectControlType, self.handle_select_control_type_as_rm)
226
232
  self._handlers.register_handler(Handshake, self.handle_handshake)
227
233
  self._handlers.register_handler(HandshakeResponse, self.handle_handshake_response_as_rm)
234
+ self._bearer_token = bearer_token
228
235
 
229
236
  def start_as_rm(self) -> None:
230
237
  self._run_eventloop(self._run_as_rm())
@@ -247,8 +254,7 @@ class S2Connection: # pylint: disable=too-many-instance-attributes
247
254
  """
248
255
  if threading.current_thread() == self._thread:
249
256
  raise RuntimeError(
250
- "Do not call stop from the thread running the S2 connection. This results in an "
251
- "infinite block!"
257
+ "Do not call stop from the thread running the S2 connection. This results in an infinite block!"
252
258
  )
253
259
  if self._eventloop.is_running():
254
260
  asyncio.run_coroutine_threadsafe(self._do_stop(), self._eventloop).result()
@@ -319,7 +325,19 @@ class S2Connection: # pylint: disable=too-many-instance-attributes
319
325
 
320
326
  async def _connect_ws(self) -> None:
321
327
  try:
322
- self.ws = await ws_connect(uri=self.url)
328
+ # set up connection arguments for SSL and bearer token, if required
329
+ connection_kwargs: Dict[str, Any] = {}
330
+ if self.url.startswith("wss://") and not self._verify_certificate:
331
+ connection_kwargs["ssl"] = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
332
+ connection_kwargs["ssl"].check_hostname = False
333
+ connection_kwargs["ssl"].verify_mode = ssl.CERT_NONE
334
+
335
+ if self._bearer_token:
336
+ connection_kwargs["additional_headers"] = {
337
+ "Authorization": f"Bearer {self._bearer_token}"
338
+ }
339
+
340
+ self.ws = await ws_connect(uri=self.url, **connection_kwargs)
323
341
  except (EOFError, OSError) as e:
324
342
  logger.info("Could not connect due to: %s", str(e))
325
343
 
@@ -418,7 +436,7 @@ class S2Connection: # pylint: disable=too-many-instance-attributes
418
436
  except json.JSONDecodeError:
419
437
  await self._send_and_forget(
420
438
  ReceptionStatus(
421
- subject_message_id="00000000-0000-0000-0000-000000000000",
439
+ subject_message_id=uuid.UUID("00000000-0000-0000-0000-000000000000"),
422
440
  status=ReceptionStatusValues.INVALID_DATA,
423
441
  diagnostic_label="Not valid json.",
424
442
  )
@@ -434,7 +452,7 @@ class S2Connection: # pylint: disable=too-many-instance-attributes
434
452
  )
435
453
  else:
436
454
  await self.respond_with_reception_status(
437
- subject_message_id="00000000-0000-0000-0000-000000000000",
455
+ subject_message_id=uuid.UUID("00000000-0000-0000-0000-000000000000"),
438
456
  status=ReceptionStatusValues.INVALID_DATA,
439
457
  diagnostic_label="Message appears valid json but could not find a message_id field.",
440
458
  )
@@ -465,7 +483,7 @@ class S2Connection: # pylint: disable=too-many-instance-attributes
465
483
  self._restart_connection_event.set()
466
484
 
467
485
  async def respond_with_reception_status(
468
- self, subject_message_id: str, status: ReceptionStatusValues, diagnostic_label: str
486
+ self, subject_message_id: uuid.UUID, status: ReceptionStatusValues, diagnostic_label: str
469
487
  ) -> None:
470
488
  logger.debug("Responding to message %s with status %s", subject_message_id, status)
471
489
  await self._send_and_forget(
@@ -477,7 +495,7 @@ class S2Connection: # pylint: disable=too-many-instance-attributes
477
495
  )
478
496
 
479
497
  def respond_with_reception_status_sync(
480
- self, subject_message_id: str, status: ReceptionStatusValues, diagnostic_label: str
498
+ self, subject_message_id: uuid.UUID, status: ReceptionStatusValues, diagnostic_label: str
481
499
  ) -> None:
482
500
  asyncio.run_coroutine_threadsafe(
483
501
  self.respond_with_reception_status(subject_message_id, status, diagnostic_label),
@@ -66,6 +66,21 @@ class PPBCControlType(S2ControlType):
66
66
  """Overwrite with the actual deactivation logic of your Resource Manager for this particular control type."""
67
67
 
68
68
 
69
+
70
+ class PEBCControlType(S2ControlType):
71
+ def get_protocol_control_type(self) -> ProtocolControlType:
72
+ return ProtocolControlType.POWER_ENVELOPE_BASED_CONTROL
73
+
74
+ def register_handlers(self, handlers: "MessageHandlers") -> None:
75
+ pass
76
+
77
+ @abc.abstractmethod
78
+ def activate(self, conn: "S2Connection") -> None: ...
79
+
80
+ @abc.abstractmethod
81
+ def deactivate(self, conn: "S2Connection") -> None: ...
82
+
83
+
69
84
  class NoControlControlType(S2ControlType):
70
85
  def get_protocol_control_type(self) -> ProtocolControlType:
71
86
  return ProtocolControlType.NOT_CONTROLABLE
s2python/s2_parser.py CHANGED
@@ -90,9 +90,7 @@ class S2Parser:
90
90
  return TYPE_TO_MESSAGE_CLASS[message_type].model_validate(message_json)
91
91
 
92
92
  @staticmethod
93
- def parse_as_message(
94
- unparsed_message: Union[dict, str, bytes], as_message: Type[M]
95
- ) -> M:
93
+ def parse_as_message(unparsed_message: Union[dict, str, bytes], as_message: Type[M]) -> M:
96
94
  """Parse the message to a specific S2 python message.
97
95
 
98
96
  :param unparsed_message: The message as a JSON-formatted string or as a JSON-parsed dictionary.
@@ -1,22 +1,34 @@
1
- from typing import TypeVar, Generic, Type, Callable, Any, Union, AbstractSet, Mapping, List, Dict
1
+ from typing import (
2
+ TypeVar,
3
+ Type,
4
+ Callable,
5
+ Any,
6
+ Union,
7
+ AbstractSet,
8
+ Mapping,
9
+ List,
10
+ Dict,
11
+ )
12
+
13
+ from typing_extensions import Self
2
14
 
3
- from pydantic import BaseModel, ValidationError # pylint: disable=no-name-in-module
4
15
  from pydantic.v1.error_wrappers import display_errors # pylint: disable=no-name-in-module
5
16
 
17
+ from pydantic import ( # pylint: disable=no-name-in-module
18
+ BaseModel,
19
+ ValidationError,
20
+ )
21
+
6
22
  from s2python.s2_validation_error import S2ValidationError
7
23
 
8
- B_co = TypeVar("B_co", bound=BaseModel, covariant=True)
9
24
 
10
25
  IntStr = Union[int, str]
11
26
  AbstractSetIntStr = AbstractSet[IntStr]
12
27
  MappingIntStrAny = Mapping[IntStr, Any]
13
28
 
14
29
 
15
- C = TypeVar("C", bound="BaseModel")
16
-
17
-
18
- class S2MessageComponent(BaseModel, Generic[C]):
19
- def to_json(self: C) -> str:
30
+ class S2MessageComponent(BaseModel):
31
+ def to_json(self) -> str:
20
32
  try:
21
33
  return self.model_dump_json(by_alias=True, exclude_none=True)
22
34
  except (ValidationError, TypeError) as e:
@@ -24,17 +36,17 @@ class S2MessageComponent(BaseModel, Generic[C]):
24
36
  type(self), self, "Pydantic raised a format validation error.", e
25
37
  ) from e
26
38
 
27
- def to_dict(self: C) -> Dict:
39
+ def to_dict(self) -> Dict[str, Any]:
28
40
  return self.model_dump()
29
41
 
30
42
  @classmethod
31
- def from_json(cls: Type[C], json_str: str) -> C:
32
- gen_model: C = cls.model_validate_json(json_str)
43
+ def from_json(cls, json_str: str) -> Self:
44
+ gen_model = cls.model_validate_json(json_str)
33
45
  return gen_model
34
46
 
35
47
  @classmethod
36
- def from_dict(cls: Type[C], json_dict: dict) -> C:
37
- gen_model: C = cls.model_validate(json_dict)
48
+ def from_dict(cls, json_dict: Dict[str, Any]) -> Self:
49
+ gen_model = cls.model_validate(json_dict)
38
50
  return gen_model
39
51
 
40
52
 
@@ -59,7 +71,10 @@ def convert_to_s2exception(f: Callable) -> Callable:
59
71
  return inner
60
72
 
61
73
 
62
- def catch_and_convert_exceptions(input_class: Type[S2MessageComponent[B_co]]) -> Type[S2MessageComponent[B_co]]:
74
+ S = TypeVar("S", bound=S2MessageComponent)
75
+
76
+
77
+ def catch_and_convert_exceptions(input_class: Type[S]) -> Type[S]:
63
78
  input_class.__init__ = convert_to_s2exception(input_class.__init__) # type: ignore[method-assign]
64
79
  input_class.__setattr__ = convert_to_s2exception(input_class.__setattr__) # type: ignore[method-assign]
65
80
  input_class.model_validate_json = convert_to_s2exception( # type: ignore[method-assign]
@@ -1,66 +0,0 @@
1
- s2python/__init__.py,sha256=e5lwvqsPl-z7IfEd0hRQhLBRKBYcuw2eqrecXnMfLdg,384
2
- s2python/message.py,sha256=Id-CleYk6ClVh3o5meVtRECLNwQHlyddNSOq0-d2bZk,1027
3
- s2python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- s2python/reception_status_awaiter.py,sha256=jKMliFk1XxwsEGtx3vFESbJhUtClB7cTu-td90-qBN8,2137
5
- s2python/s2_connection.py,sha256=CTTTGzJ6IG9PcQpC5XtnThaYQRpp66gQrauPK8KygOE,20166
6
- s2python/s2_control_type.py,sha256=4L6o_QG9ilYA8c3QWpSjc77xwxEHHsAGZO8WQDgxDr0,2860
7
- s2python/s2_parser.py,sha256=x2JSCSEvXMCt-0kPDH4zER--CsyFYyRAaezr76V_8Qc,4354
8
- s2python/s2_validation_error.py,sha256=BkOLoNsrcQ3MzdCYaPDgs1Wu6lPdlQDpZsTpykKGQmE,384
9
- s2python/utils.py,sha256=QX9b-mi-H_YUGTmGmJsrAbaWWM3dgaoaRLRXHHlaZDE,212
10
- s2python/validate_values_mixin.py,sha256=3WbauPprzWpGdyDUYPoELICi2NbHrCFzlQ7AtrpDSis,2568
11
- s2python/version.py,sha256=IBzoytgbYYYekQnSTfSmWeYAZ4c_yUFU2oLIAG4UYjs,45
12
- s2python/common/__init__.py,sha256=yEAXCS59XpNOEXbEXoN04SwultP-3evgVzFuEUSgB5I,1345
13
- s2python/common/duration.py,sha256=5_zi0wv98dr8lHXh2RdHATzW4Un8ZNUx4-zaI1t77Ak,667
14
- s2python/common/handshake.py,sha256=bsx64flKxVUUMT18O47pV1pnnpXcAGXMJbRi9q4GjwU,467
15
- s2python/common/handshake_response.py,sha256=5cAbtLTZ8fkhUw-XdMlGBro3XKWqXXLw3YUavvwLYNg,523
16
- s2python/common/instruction_status_update.py,sha256=lo5HxoEGFp8bU0-AQ7bNxuDj1StZ73GE_2sGDA7o5vI,692
17
- s2python/common/number_range.py,sha256=N0OUoGtkdYg4GDUwvVHKLjdXxcy9mijgwqmmA079P6k,741
18
- s2python/common/power_forecast.py,sha256=C0D6XOphdcEVjfb0py-l2zLnNC-udWmlDD7g2Hre2uo,704
19
- s2python/common/power_forecast_element.py,sha256=M3weDKlBASjS_VHt4XKdms2fpxEZy17kWuLTUXsFibU,805
20
- s2python/common/power_forecast_value.py,sha256=im5kLyTfDjLuODFWoIuVgVxKjX2FpyPXYoxonjuOpu0,411
21
- s2python/common/power_measurement.py,sha256=mMVpe3T86Xu6ctA2Rpc50aB4WS7xuLXgGVSbB4lykHQ,693
22
- s2python/common/power_range.py,sha256=FKhJRkT3dzUCeK8P3mrcRVtJHPf2WH-eQDottvEMpBs,686
23
- s2python/common/power_value.py,sha256=ujo0yxHnAd-LCIQQuIpNU01jv611UCbcXKl8ilQIILY,363
24
- s2python/common/reception_status.py,sha256=HXdaTu5B2iuHb1pg8d5TMprfi80rUmCgCxrrDFLJB0w,525
25
- s2python/common/resource_manager_details.py,sha256=QTW6VTn-Y_fvVKX6qGgDMuvry5twmDqHjRvOZXgkuLI,1044
26
- s2python/common/revoke_object.py,sha256=7OVNuwu5aMfZ3GJ_b_SRNoTxiX80FY9obp7JHIySzaY,585
27
- s2python/common/role.py,sha256=eHKwnie_7eK8k1CNA7S0TbwmkQR84Pzkwdk8aUaUldw,327
28
- s2python/common/select_control_type.py,sha256=Rbvem30LrrPYTSjwspc-PJyxoNScv9XRVXJ58-WRotk,523
29
- s2python/common/session_request.py,sha256=ztbvGjMwiEmdJ_ToFuPV9Lj_IHJ78fP7IsCt8rMvMu8,502
30
- s2python/common/support.py,sha256=Kbrf_KGB45Wfr8j2pqDe1lLde6CIr3nl_LYkWnilmV0,1015
31
- s2python/common/timer.py,sha256=PWJjHXfL6yr2VQ8O2HwtYB0o3Jw4TdP2iMX2Wdp7Ic4,556
32
- s2python/common/transition.py,sha256=2v0fkxudPhVqmnd-WajJhBsYRnJLAqJU9z1eqQJy8zw,1064
33
- s2python/frbc/__init__.py,sha256=ROV3qZoldPkdgVFfMQr5Mf3GDfBzXaMfhNNCuXY6T0s,1104
34
- s2python/frbc/frbc_actuator_description.py,sha256=fsgYdKvxZnUCuUuyoN0Ibu5FoA0vUBSrKy6WQJGBfGk,6166
35
- s2python/frbc/frbc_actuator_status.py,sha256=cPyAz0B0rThfueKr3CWx61E3eJ8Lp29a-nJPyTPpbls,973
36
- s2python/frbc/frbc_fill_level_target_profile.py,sha256=suRBgT8b9HQjfafW-sjqzjFpgJ2vOf73nmL5-Q6WhOo,880
37
- s2python/frbc/frbc_fill_level_target_profile_element.py,sha256=V7O7oDDfifLcJsSXYWEd00X3C2TPoU8TcrRu2yLWVVU,1280
38
- s2python/frbc/frbc_instruction.py,sha256=Q8w9KB4x6mGsLR-3ADzsyWWf0-uTWGZ31rnKGC9TkIc,809
39
- s2python/frbc/frbc_leakage_behaviour.py,sha256=E23McMu4zbjDIUR_MNBlyUuh1chGM-EKTMuiHqjV_wg,794
40
- s2python/frbc/frbc_leakage_behaviour_element.py,sha256=B3Tzlu3iMVV3NA1WJds_LDl3T_lBGL3HjGiEin02_pQ,1103
41
- s2python/frbc/frbc_operation_mode.py,sha256=w0--55ZByWQukbotR6VpoL9GvNbeNyHcs3NqHAzjq6w,1899
42
- s2python/frbc/frbc_operation_mode_element.py,sha256=64_FJzfCRoUgRCdfA1HpLO9lTE1WBxL3Pbn0vaNeX8c,1073
43
- s2python/frbc/frbc_storage_description.py,sha256=Jc0zpAwf3E7Grl6v0fkSa4yA8-2-klO1aY-50l-u56E,622
44
- s2python/frbc/frbc_storage_status.py,sha256=h6cHTb7Msw5TckPzKsiI3KTSa7Hr5BcXIelF8gmFIdw,523
45
- s2python/frbc/frbc_system_description.py,sha256=_scCAVe4sHEhQMHkDvD2pKGnGLzdnm4uARbdcw0inKk,980
46
- s2python/frbc/frbc_timer_status.py,sha256=sRsvXxsT_TDlPiacLkZlCZM3y36NZRGqj6RKJeil-yc,711
47
- s2python/frbc/frbc_usage_forecast.py,sha256=MWY4Nr2T9NGjQhf7rxTtkqnuSdApTjro81-o_buLABk,747
48
- s2python/frbc/frbc_usage_forecast_element.py,sha256=wQJCBoYFt2HXNaKNL3vK_FpTx5wXvRH03NOw_JWOal8,601
49
- s2python/frbc/rm.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- s2python/generated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
- s2python/generated/gen_s2.py,sha256=eg9J0pcWxCy0oXO8eq9AtoB-GONHZLNd8JANpMhKQCQ,63573
52
- s2python/ppbc/__init__.py,sha256=Rnfl_1n0gkc9mASSzBBMFEKYzJqugV5POtttjLWx_pI,665
53
- s2python/ppbc/ppbc_end_interruption_instruction.py,sha256=0ZXQATN8L35xm9-QWCU8ftnU1_Na9Oq3HzSYna_SMcU,1197
54
- s2python/ppbc/ppbc_power_profile_definition.py,sha256=3y5lw7eeDVVa6JecoGlZrqr6bcQRaDoLO9EISPle3ks,991
55
- s2python/ppbc/ppbc_power_profile_status.py,sha256=E-mNhdaPiuB6qFsG_F1ftIlwaxF75972nvIHKSpau5w,767
56
- s2python/ppbc/ppbc_power_sequence.py,sha256=DCeNstEAUvwCiN1bKDd85gE6pgiataJbwGui6pEk5_M,1158
57
- s2python/ppbc/ppbc_power_sequence_container.py,sha256=L0kD7zkJj9OBafzzA6zcUgFnn5wCx6VzlGoLX3GDf9U,829
58
- s2python/ppbc/ppbc_power_sequence_container_status.py,sha256=3Wq3NasIh_mLDEZvnNsgB8AY8CSd4qQKpPJxXwS7ZiA,1160
59
- s2python/ppbc/ppbc_power_sequence_element.py,sha256=sQMJlIRhMhj_crpaRFDWhbP4eCCw4haFq5sD-ptQsS0,797
60
- s2python/ppbc/ppbc_schedule_instruction.py,sha256=yHDO5omwKYV_P_v70D4gZ26K5MEIFFboX1sp3J6_atA,1098
61
- s2python/ppbc/ppbc_start_interruption_instruction.py,sha256=6Atu6E-Hfs8S2KIdHdGJd9F5gRFqZLNb-dpnphj8hNU,1219
62
- s2_python-0.4.1.dist-info/METADATA,sha256=CJILWeqNUp0VSPUdlLafySNPJag6SvoeYAPO9b5_cQs,3595
63
- s2_python-0.4.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
64
- s2_python-0.4.1.dist-info/entry_points.txt,sha256=feX-xmgJZgSe5-jxMgFKPKCJz4Ys3eQcGrsXsirNZyM,61
65
- s2_python-0.4.1.dist-info/top_level.txt,sha256=OLFq0oDhr77Mp-EYLEcWk5P3jvooOt4IHkTI5KYJMc8,9
66
- s2_python-0.4.1.dist-info/RECORD,,