DLMS-SPODES 0.87.16__py3-none-any.whl → 0.88.1__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.
- DLMS_SPODES/Values/EN/__init__.py +1 -1
- DLMS_SPODES/Values/EN/actors.py +8 -8
- DLMS_SPODES/Values/EN/relation_to_obis_names.py +387 -387
- DLMS_SPODES/Values/RU/__init__.py +1 -1
- DLMS_SPODES/Values/RU/actors.py +8 -8
- DLMS_SPODES/Values/RU/relation_to_obis_names.py +396 -396
- DLMS_SPODES/__init__.py +6 -6
- DLMS_SPODES/configEN.ini +126 -126
- DLMS_SPODES/config_parser.py +53 -53
- DLMS_SPODES/cosem_interface_classes/Overview/__init__.py +0 -0
- DLMS_SPODES/cosem_interface_classes/Overview/class_id.py +107 -0
- DLMS_SPODES/cosem_interface_classes/__class_init__.py +3 -3
- DLMS_SPODES/cosem_interface_classes/__init__.py +3 -2
- DLMS_SPODES/cosem_interface_classes/activity_calendar.py +210 -254
- DLMS_SPODES/cosem_interface_classes/arbitrator.py +78 -105
- DLMS_SPODES/cosem_interface_classes/association_ln/abstract.py +50 -34
- DLMS_SPODES/cosem_interface_classes/association_ln/authentication_mechanism_name.py +25 -25
- DLMS_SPODES/cosem_interface_classes/association_ln/mechanism_id.py +25 -25
- DLMS_SPODES/cosem_interface_classes/association_ln/method.py +5 -5
- DLMS_SPODES/cosem_interface_classes/association_ln/ver0.py +440 -485
- DLMS_SPODES/cosem_interface_classes/association_ln/ver1.py +126 -133
- DLMS_SPODES/cosem_interface_classes/association_ln/ver2.py +30 -36
- DLMS_SPODES/cosem_interface_classes/association_ln/ver3.py +3 -4
- DLMS_SPODES/cosem_interface_classes/association_sn/ver0.py +14 -12
- DLMS_SPODES/cosem_interface_classes/clock.py +81 -131
- DLMS_SPODES/cosem_interface_classes/collection.py +2106 -2122
- DLMS_SPODES/cosem_interface_classes/cosem_interface_class.py +525 -583
- DLMS_SPODES/cosem_interface_classes/data.py +12 -21
- DLMS_SPODES/cosem_interface_classes/demand_register/ver0.py +32 -59
- DLMS_SPODES/cosem_interface_classes/disconnect_control.py +56 -74
- DLMS_SPODES/cosem_interface_classes/extended_register.py +18 -27
- DLMS_SPODES/cosem_interface_classes/gprs_modem_setup.py +33 -43
- DLMS_SPODES/cosem_interface_classes/gsm_diagnostic/ver0.py +78 -103
- DLMS_SPODES/cosem_interface_classes/gsm_diagnostic/ver1.py +42 -40
- DLMS_SPODES/cosem_interface_classes/gsm_diagnostic/ver2.py +6 -9
- DLMS_SPODES/cosem_interface_classes/iec_hdlc_setup/ver0.py +11 -11
- DLMS_SPODES/cosem_interface_classes/iec_hdlc_setup/ver1.py +27 -53
- DLMS_SPODES/cosem_interface_classes/iec_local_port_setup.py +9 -11
- DLMS_SPODES/cosem_interface_classes/image_transfer/image_transfer_status.py +15 -15
- DLMS_SPODES/cosem_interface_classes/image_transfer/ver0.py +54 -126
- DLMS_SPODES/cosem_interface_classes/implementations/__init__.py +3 -3
- DLMS_SPODES/cosem_interface_classes/implementations/arbitrator.py +19 -19
- DLMS_SPODES/cosem_interface_classes/implementations/data.py +491 -487
- DLMS_SPODES/cosem_interface_classes/implementations/profile_generic.py +85 -83
- DLMS_SPODES/cosem_interface_classes/ipv4_setup.py +42 -72
- DLMS_SPODES/cosem_interface_classes/limiter.py +77 -111
- DLMS_SPODES/cosem_interface_classes/ln_pattern.py +334 -333
- DLMS_SPODES/cosem_interface_classes/modem_configuration/ver0.py +51 -65
- DLMS_SPODES/cosem_interface_classes/modem_configuration/ver1.py +27 -39
- DLMS_SPODES/cosem_interface_classes/ntp_setup/ver0.py +48 -67
- DLMS_SPODES/cosem_interface_classes/obis.py +28 -23
- DLMS_SPODES/cosem_interface_classes/overview.py +198 -197
- DLMS_SPODES/cosem_interface_classes/parameter.py +548 -547
- DLMS_SPODES/cosem_interface_classes/parameters.py +172 -172
- DLMS_SPODES/cosem_interface_classes/profile_generic/ver0.py +90 -122
- DLMS_SPODES/cosem_interface_classes/profile_generic/ver1.py +268 -277
- DLMS_SPODES/cosem_interface_classes/push_setup/ver0.py +13 -12
- DLMS_SPODES/cosem_interface_classes/push_setup/ver1.py +9 -10
- DLMS_SPODES/cosem_interface_classes/push_setup/ver2.py +124 -166
- DLMS_SPODES/cosem_interface_classes/register.py +18 -45
- DLMS_SPODES/cosem_interface_classes/register_activation/ver0.py +45 -80
- DLMS_SPODES/cosem_interface_classes/register_monitor.py +33 -46
- DLMS_SPODES/cosem_interface_classes/reports.py +72 -70
- DLMS_SPODES/cosem_interface_classes/schedule.py +88 -176
- DLMS_SPODES/cosem_interface_classes/script_table.py +54 -87
- DLMS_SPODES/cosem_interface_classes/security_setup/ver0.py +45 -68
- DLMS_SPODES/cosem_interface_classes/security_setup/ver1.py +122 -158
- DLMS_SPODES/cosem_interface_classes/single_action_schedule.py +34 -50
- DLMS_SPODES/cosem_interface_classes/special_days_table.py +54 -84
- DLMS_SPODES/cosem_interface_classes/tcp_udp_setup.py +20 -42
- DLMS_SPODES/cosem_pdu.py +93 -93
- DLMS_SPODES/enums.py +625 -625
- DLMS_SPODES/exceptions.py +106 -106
- DLMS_SPODES/firmwares.py +99 -99
- DLMS_SPODES/hdlc/frame.py +875 -875
- DLMS_SPODES/hdlc/sub_layer.py +54 -54
- DLMS_SPODES/literals.py +17 -17
- DLMS_SPODES/obis/__init__.py +1 -1
- DLMS_SPODES/obis/media_id.py +931 -931
- DLMS_SPODES/pardata.py +22 -22
- DLMS_SPODES/pdu_enums.py +98 -98
- DLMS_SPODES/relation_to_OBIS.py +463 -465
- DLMS_SPODES/settings.py +551 -551
- DLMS_SPODES/types/choices.py +140 -142
- DLMS_SPODES/types/common_data_types.py +2379 -2401
- DLMS_SPODES/types/cosem_service_types.py +109 -109
- DLMS_SPODES/types/implementations/arrays.py +25 -25
- DLMS_SPODES/types/implementations/bitstrings.py +97 -97
- DLMS_SPODES/types/implementations/double_long_usingneds.py +35 -35
- DLMS_SPODES/types/implementations/enums.py +57 -57
- DLMS_SPODES/types/implementations/integers.py +12 -11
- DLMS_SPODES/types/implementations/long_unsigneds.py +127 -127
- DLMS_SPODES/types/implementations/octet_string.py +11 -11
- DLMS_SPODES/types/implementations/structs.py +64 -64
- DLMS_SPODES/types/type_alias.py +74 -0
- DLMS_SPODES/types/useful_types.py +627 -677
- {dlms_spodes-0.87.16.dist-info → dlms_spodes-0.88.1.dist-info}/METADATA +30 -30
- dlms_spodes-0.88.1.dist-info/RECORD +118 -0
- {dlms_spodes-0.87.16.dist-info → dlms_spodes-0.88.1.dist-info}/WHEEL +1 -1
- DLMS_SPODES/cosem_interface_classes/a_parameter.py +0 -20
- DLMS_SPODES/cosem_interface_classes/attr_indexes.py +0 -12
- dlms_spodes-0.87.16.dist-info/RECORD +0 -117
- {dlms_spodes-0.87.16.dist-info → dlms_spodes-0.88.1.dist-info}/top_level.txt +0 -0
|
@@ -1,254 +1,210 @@
|
|
|
1
|
-
from
|
|
2
|
-
from
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
start_time
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
for
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
nonlocal index, duplicates
|
|
212
|
-
if len(duplicates) != 0:
|
|
213
|
-
raise ic.ObjectValidationError(
|
|
214
|
-
ln=self.logical_name,
|
|
215
|
-
i=index,
|
|
216
|
-
message=F"find duplicate {name}: {', '.join(map(str, duplicates))} in {self.get_attr_element(index)}")
|
|
217
|
-
index -= 1
|
|
218
|
-
|
|
219
|
-
days: list[DayProfile.day_id] = list()
|
|
220
|
-
duplicates: set[DayProfile.day_id] | set[WeekProfile.week_profile_name] | set[Season.season_profile_name] = set()
|
|
221
|
-
for it in self.get_attr(index):
|
|
222
|
-
if it.day_id not in days:
|
|
223
|
-
days.append(it.day_id)
|
|
224
|
-
else:
|
|
225
|
-
duplicates.add(it.day_id)
|
|
226
|
-
handle_duplicates("day_id")
|
|
227
|
-
weeks: list[WeekProfile.week_profile_name] = list()
|
|
228
|
-
for week_profile in self.get_attr(index):
|
|
229
|
-
if week_profile.week_profile_name not in weeks:
|
|
230
|
-
weeks.append(week_profile.week_profile_name)
|
|
231
|
-
else:
|
|
232
|
-
duplicates.add(week_profile.week_profile_name)
|
|
233
|
-
for i in range(1, 7):
|
|
234
|
-
if week_profile[i] not in days:
|
|
235
|
-
raise ic.ObjectValidationError(
|
|
236
|
-
ln=self.logical_name,
|
|
237
|
-
i=index,
|
|
238
|
-
message=F"in {self.get_attr_element(index)} got {week_profile} with day_id: {week_profile[i]}; expected: {', '.join(map(str, days))}")
|
|
239
|
-
handle_duplicates("week_profile_name")
|
|
240
|
-
seasons: list[Season.season_profile_name] = list()
|
|
241
|
-
for season in self.get_attr(index):
|
|
242
|
-
if season.season_profile_name not in seasons:
|
|
243
|
-
seasons.append(season.season_profile_name)
|
|
244
|
-
else:
|
|
245
|
-
duplicates.add(season.season_profile_name)
|
|
246
|
-
if season.week_name not in weeks:
|
|
247
|
-
raise ic.ObjectValidationError(
|
|
248
|
-
ln=self.logical_name,
|
|
249
|
-
i=index,
|
|
250
|
-
message=F"in {self.get_attr_element(index)} got {season} with: {season.week_name}, expected: {', '.join(map(str, weeks))}")
|
|
251
|
-
handle_duplicates("season_profile_name")
|
|
252
|
-
|
|
253
|
-
validate_seasons(5)
|
|
254
|
-
validate_seasons(9)
|
|
1
|
+
from typing import Self
|
|
2
|
+
from ..types.implementations import integers, octet_string
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from ..types import cdt, cst
|
|
5
|
+
from .cosem_interface_class import ICAElement, ICMElement, ICAuto
|
|
6
|
+
from .Overview import class_id
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Season(cdt.Structure):
|
|
10
|
+
""" Defined by their starting date and a specific week_profile to be executed """
|
|
11
|
+
season_profile_name: cdt.OctetString
|
|
12
|
+
season_start: cst.OctetStringDateTime
|
|
13
|
+
week_name: cdt.OctetString
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SeasonProfile(cdt.Array):
|
|
17
|
+
""" Contains a list of seasons defined by their starting date and a specific week_profile to be executed. The list is sorted according to season_start. """
|
|
18
|
+
TYPE = Season
|
|
19
|
+
values: list[Season]
|
|
20
|
+
|
|
21
|
+
def new_element(self) -> Season:
|
|
22
|
+
names: list[bytes] = [bytes(el.season_profile_name) for el in self.values]
|
|
23
|
+
for new_name in (i.to_bytes(1, 'big') for i in range(256)):
|
|
24
|
+
if new_name not in names:
|
|
25
|
+
return Season((bytearray(new_name), None, bytearray(b'week_name?')))
|
|
26
|
+
raise ValueError(F'in {self} all season names is busy')
|
|
27
|
+
|
|
28
|
+
def sort(self, date_time: cdt.DateTime) -> Self:
|
|
29
|
+
"""sort by date-time
|
|
30
|
+
:return now Season + next Seasons"""
|
|
31
|
+
s: Season
|
|
32
|
+
d_t = date_time.to_datetime()
|
|
33
|
+
l = list()
|
|
34
|
+
"""left datetime"""
|
|
35
|
+
r = list()
|
|
36
|
+
"""right datetime"""
|
|
37
|
+
for i, s in enumerate(self):
|
|
38
|
+
if (el := s.season_start.get_left_nearest_datetime(d_t)) is not None:
|
|
39
|
+
l.append((i, el))
|
|
40
|
+
if (el := s.season_start.get_right_nearest_datetime(d_t)) is not None:
|
|
41
|
+
r.append((i, el))
|
|
42
|
+
l.sort(key=lambda it: it[1])
|
|
43
|
+
r.sort(key=lambda it: it[1])
|
|
44
|
+
now = l[-1][0]
|
|
45
|
+
indexes: list[int] = [now]
|
|
46
|
+
for el in r:
|
|
47
|
+
if el[0] == now:
|
|
48
|
+
continue
|
|
49
|
+
else:
|
|
50
|
+
indexes.append(el[0])
|
|
51
|
+
sorted_data = self.__class__()
|
|
52
|
+
for i in indexes:
|
|
53
|
+
sorted_data.append(self[i])
|
|
54
|
+
return sorted_data
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class WeekProfile(cdt.Structure):
|
|
58
|
+
""" For each week_profile, the day_profile for every day of a week is identified. """
|
|
59
|
+
week_profile_name: cdt.OctetString
|
|
60
|
+
monday: cdt.Unsigned
|
|
61
|
+
tuesday: cdt.Unsigned
|
|
62
|
+
wednesday: cdt.Unsigned
|
|
63
|
+
thursday: cdt.Unsigned
|
|
64
|
+
friday: cdt.Unsigned
|
|
65
|
+
saturday: cdt.Unsigned
|
|
66
|
+
sunday: cdt.Unsigned
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class WeekProfileTable(cdt.Array):
|
|
70
|
+
""" Contains an array of week_profiles to be used in the different seasons. For each week_profile, the day_profile for every day of a week is
|
|
71
|
+
identified. """
|
|
72
|
+
TYPE = WeekProfile
|
|
73
|
+
values: list[WeekProfile]
|
|
74
|
+
|
|
75
|
+
def new_element(self) -> WeekProfile:
|
|
76
|
+
"""return default WeekProfile with vacant week_profile_name, existed day ID and insert callback for validate change DayID"""
|
|
77
|
+
names: list[bytes] = [bytes(el.week_profile_name) for el in self.values]
|
|
78
|
+
for new_name in (i.to_bytes(1, 'big') for i in range(256)):
|
|
79
|
+
if new_name not in names:
|
|
80
|
+
return WeekProfile((bytearray(new_name), *[0]*7))
|
|
81
|
+
raise ValueError(F'in {self} all week names is busy')
|
|
82
|
+
|
|
83
|
+
def get_week_profile_names(self) -> tuple[cdt.OctetString, ...]:
|
|
84
|
+
return tuple((el.week_profile_name for el in self.values))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class DayProfileAction(cdt.Structure):
|
|
88
|
+
""" Scheduled action is defined by a script to be executed and the corresponding activation time (start_time). """
|
|
89
|
+
start_time: cst.OctetStringTime
|
|
90
|
+
script_logical_name: cst.LogicalName
|
|
91
|
+
script_selector: cdt.LongUnsigned
|
|
92
|
+
|
|
93
|
+
def __lt__(self, other: Self):
|
|
94
|
+
return self.start_time.to_time() < other.start_time.to_time()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# TODO: make unique by start_time
|
|
98
|
+
class DaySchedule(cdt.Array):
|
|
99
|
+
""" Contains an array of day_profile_action. """
|
|
100
|
+
TYPE = DayProfileAction
|
|
101
|
+
values: list[DayProfileAction]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class DayProfile(cdt.Structure):
|
|
105
|
+
""" list of Scheduled actions is defined by a script to be executed and the corresponding activation time (start_time) with day ID. """
|
|
106
|
+
day_id: cdt.Unsigned
|
|
107
|
+
day_schedule: DaySchedule
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class DayProfileTable(cdt.Array):
|
|
111
|
+
""" Contains an array of day_profiles, identified by their day_id. For each day_profile, a list of scheduled actions is defined by a script to be
|
|
112
|
+
executed and the corresponding activation time (start_time). The list is sorted according to start_time. """
|
|
113
|
+
TYPE = DayProfile
|
|
114
|
+
values: list[DayProfile]
|
|
115
|
+
|
|
116
|
+
def new_element(self) -> DayProfile:
|
|
117
|
+
"""return default DayProfile with vacant Day ID"""
|
|
118
|
+
day_ids: list[int] = [int(el.day_id) for el in self.values]
|
|
119
|
+
for i in range(0xff):
|
|
120
|
+
if i not in day_ids:
|
|
121
|
+
return DayProfile((i, None))
|
|
122
|
+
raise ValueError(F'in {self} all days ID is busy')
|
|
123
|
+
|
|
124
|
+
def get_day_ids(self) -> tuple[cdt.Unsigned, ...]:
|
|
125
|
+
return tuple((day_profile.day_id for day_profile in self.values))
|
|
126
|
+
|
|
127
|
+
def normalize(self) -> bool:
|
|
128
|
+
d_p: DayProfile
|
|
129
|
+
res = False
|
|
130
|
+
for d_p in self:
|
|
131
|
+
if (new := DaySchedule(sorted(d_p.day_schedule))) != d_p.day_schedule:
|
|
132
|
+
res = True
|
|
133
|
+
d_p.day_schedule.__dict__["values"] = new.values
|
|
134
|
+
return res
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class ActivityCalendar(ICAuto):
|
|
138
|
+
"""DLMS UA 1000-1 Ed. 14 4.5.5 Activity calendar"""
|
|
139
|
+
CLASS_ID = class_id.ACTIVITY_CALENDAR
|
|
140
|
+
VERSION = 0
|
|
141
|
+
A_ELEMENTS = (ICAElement(2, "calendar_name_active", octet_string.ID),
|
|
142
|
+
ICAElement(3, "season_profile_active", SeasonProfile),
|
|
143
|
+
ICAElement(4, "week_profile_table_active", WeekProfileTable),
|
|
144
|
+
ICAElement(5, "day_profile_table_active", DayProfileTable),
|
|
145
|
+
ICAElement(6, "calendar_name_passive", octet_string.ID),
|
|
146
|
+
ICAElement(7, "season_profile_passive", SeasonProfile),
|
|
147
|
+
ICAElement(8, "week_profile_table_passive", WeekProfileTable),
|
|
148
|
+
ICAElement(9, "day_profile_table_passive", DayProfileTable),
|
|
149
|
+
ICAElement(10, "activate_passive_calendar_time", cst.OctetStringDateTime))
|
|
150
|
+
M_ELEMENTS = ICMElement(1, "activate_passive_calendar", integers.INTEGER_0),
|
|
151
|
+
calendar_name_active: Optional[octet_string.ID]
|
|
152
|
+
season_profile_active: Optional[SeasonProfile]
|
|
153
|
+
week_profile_table_active: Optional[WeekProfileTable]
|
|
154
|
+
day_profile_table_active: Optional[DayProfileTable]
|
|
155
|
+
calendar_name_passive: Optional[octet_string.ID]
|
|
156
|
+
season_profile_passive: Optional[SeasonProfile]
|
|
157
|
+
week_profile_table_passive: Optional[WeekProfileTable]
|
|
158
|
+
day_profile_table_passive: Optional[DayProfileTable]
|
|
159
|
+
activate_passive_calendar_time: Optional[cst.OctetStringDateTime]
|
|
160
|
+
|
|
161
|
+
def ActivatePassiveCalendar(cls, value=None) -> integers.Only0:
|
|
162
|
+
return cls.M_ELEMENTS[0].DATA_TYPE
|
|
163
|
+
|
|
164
|
+
def validate(self):
|
|
165
|
+
def validate_seasons(index: int):
|
|
166
|
+
def handle_duplicates(name: str):
|
|
167
|
+
nonlocal index, duplicates
|
|
168
|
+
if len(duplicates) != 0:
|
|
169
|
+
raise ObjectValidationError(
|
|
170
|
+
ln=self.logical_name,
|
|
171
|
+
i=index,
|
|
172
|
+
message=F"find duplicate {name}: {', '.join(map(str, duplicates))} in {self.getAElement(index).unwrap()}")
|
|
173
|
+
index -= 1
|
|
174
|
+
|
|
175
|
+
days: list[DayProfile.day_id] = []
|
|
176
|
+
duplicates: set[DayProfile.day_id] | set[WeekProfile.week_profile_name] | set[Season.season_profile_name] = set()
|
|
177
|
+
for it in self.get_attr(index):
|
|
178
|
+
if it.day_id not in days:
|
|
179
|
+
days.append(it.day_id)
|
|
180
|
+
else:
|
|
181
|
+
duplicates.add(it.day_id)
|
|
182
|
+
handle_duplicates("day_id")
|
|
183
|
+
weeks: list[WeekProfile.week_profile_name] = []
|
|
184
|
+
for week_profile in self.get_attr(index):
|
|
185
|
+
if week_profile.week_profile_name not in weeks:
|
|
186
|
+
weeks.append(week_profile.week_profile_name)
|
|
187
|
+
else:
|
|
188
|
+
duplicates.add(week_profile.week_profile_name)
|
|
189
|
+
for i in range(1, 7):
|
|
190
|
+
if week_profile[i] not in days:
|
|
191
|
+
raise ObjectValidationError(
|
|
192
|
+
ln=self.logical_name,
|
|
193
|
+
i=index,
|
|
194
|
+
message=F"in {self.getAElement(index).unwrap()} got {week_profile} with day_id: {week_profile[i]}; expected: {', '.join(map(str, days))}")
|
|
195
|
+
handle_duplicates("week_profile_name")
|
|
196
|
+
seasons: list[Season.season_profile_name] = []
|
|
197
|
+
for season in self.get_attr(index):
|
|
198
|
+
if season.season_profile_name not in seasons:
|
|
199
|
+
seasons.append(season.season_profile_name)
|
|
200
|
+
else:
|
|
201
|
+
duplicates.add(season.season_profile_name)
|
|
202
|
+
if season.week_name not in weeks:
|
|
203
|
+
raise ObjectValidationError(
|
|
204
|
+
ln=self.logical_name,
|
|
205
|
+
i=index,
|
|
206
|
+
message=F"in {self.get_attr_element(index)} got {season} with: {season.week_name}, expected: {', '.join(map(str, weeks))}")
|
|
207
|
+
handle_duplicates("season_profile_name")
|
|
208
|
+
|
|
209
|
+
validate_seasons(5)
|
|
210
|
+
validate_seasons(9)
|