DLMS-SPODES 0.87.3__py3-none-any.whl → 0.87.6__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.
@@ -7,7 +7,7 @@ import inspect
7
7
  from dataclasses import dataclass
8
8
  from itertools import count, chain
9
9
  from functools import reduce, cached_property, lru_cache
10
- from typing import TypeAlias, Iterator, Type, Self, Callable, Literal, Iterable, Optional, Hashable
10
+ from typing import TypeAlias, Iterator, Type, Self, Callable, Literal, Iterable, Optional, Hashable, Protocol, cast, Annotated
11
11
  from semver import Version as SemVer
12
12
  from StructResult import result
13
13
  from ..types import common_data_types as cdt, cosem_service_types as cst, useful_types as ut
@@ -62,7 +62,7 @@ from .. import pdu_enums as pdu
62
62
  from ..config_parser import config, get_message
63
63
  from ..obis import media_id
64
64
  from .parameter import Parameter
65
- from typing_extensions import deprecated
65
+ from typing_extensions import deprecated, override
66
66
  from ..settings import settings
67
67
 
68
68
 
@@ -97,123 +97,72 @@ SortMode: TypeAlias = Literal["l", "n", "c", "cl", "cn"]
97
97
 
98
98
 
99
99
  # todo: make new class ClassMap(for field Collection.spec_map). fields: name, version, dict(current version ClassMap)
100
- class ClassMap(dict):
101
- def __hash__(self):
102
- return hash(tuple(it.hash_ for it in self.values()))
100
+ class ClassMap:
103
101
 
104
- def renew(self, ver: int, cls_: Type[InterfaceClass]) -> Self:
105
- """return with one change"""
106
- ret = self.__class__(self)
107
- ret[ver] = cls_
108
- return ret
102
+ def __init__(self, *values: type[InterfaceClass]):
103
+ self._values = values
109
104
 
105
+ def __hash__(self) -> int:
106
+ return hash(it.hash_ for it in self._values)
110
107
 
111
- DataMap = ClassMap({
112
- 0: Data})
113
- DataStaticMap = ClassMap({
114
- 0: impl.data.DataStatic})
115
- DataDynamicMap = ClassMap({
116
- 0: impl.data.DataDynamic})
117
- RegisterMap = ClassMap({
118
- 0: Register})
119
- ExtendedRegisterMap = ClassMap({
120
- 0: ExtendedRegister})
121
- DemandRegisterMap = ClassMap({
122
- 0: DemandRegisterVer0})
123
- RegisterActivationMap = ClassMap({
124
- 0: RegisterActivation})
125
- ProfileGenericMap = ClassMap({
126
- 0: ProfileGenericVer0,
127
- 1: ProfileGenericVer1})
128
- ClockMap = ClassMap({
129
- 0: Clock})
130
- ScriptTableMap = ClassMap({
131
- 0: ScriptTable})
132
- ScheduleMap = ClassMap({
133
- 0: Schedule})
134
- SpecialDaysTableMap = ClassMap({
135
- 0: SpecialDaysTable
136
- })
137
- AssociationSNMap = ClassMap({
138
- 0: AssociationSNVer0,
139
- })
140
- AssociationLNMap = ClassMap({
141
- 0: AssociationLNVer0,
142
- 1: AssociationLNVer1,
143
- 2: AssociationLNVer2,
144
- })
145
- ImageTransferMap = ClassMap({
146
- 0: ImageTransfer
147
- })
148
- ActivityCalendarMap = ClassMap({
149
- 0: ActivityCalendar
150
- })
151
- RegisterMonitorMap = ClassMap({
152
- 0: RegisterMonitor
153
- })
154
- SingleActionScheduleMap = ClassMap({
155
- 0: SingleActionSchedule
156
- })
157
- IECHDLCSetupMap = ClassMap({
158
- 0: IECHDLCSetupVer0,
159
- 1: IECHDLCSetupVer1
160
- })
161
- ModemConfigurationMap = ClassMap({
162
- 0: PSTNModemConfiguration,
163
- 1: ModemConfigurationVer1
164
- })
165
- TCPUDPSetupMap = ClassMap({
166
- 0: TCPUDPSetup
167
- })
168
- IPv4SetupMap = ClassMap({
169
- 0: IPv4Setup
170
- })
171
- GPRSModemSetupMap = ClassMap({
172
- 0: GPRSModemSetup
173
- })
174
- GSMDiagnosticMap = ClassMap({
175
- 0: GSMDiagnosticVer0,
176
- 1: GSMDiagnosticVer1,
177
- 2: GSMDiagnosticVer2
178
- })
179
- PushSetupMap = ClassMap({
180
- 0: PushSetupVer0,
181
- 1: PushSetupVer1,
182
- 2: PushSetupVer2,
183
- })
184
- SecuritySetupMap = ClassMap({
185
- 0: SecuritySetupVer0,
186
- 1: SecuritySetupVer1
187
- })
188
- ArbitratorMap = ClassMap({
189
- 0: Arbitrator
190
- })
191
- DisconnectControlMap = ClassMap({
192
- 0: DisconnectControl
193
- })
194
- LimiterMap = ClassMap({
195
- 0: Limiter
196
- })
197
- NTPSetupMap = ClassMap({
198
- 0: NTPSetup
199
- })
108
+ def get(self, ver: int) -> type[InterfaceClass]:
109
+ if (ver := int(ver)) < len(self._values):
110
+ return self._values[ver]
111
+ raise RuntimeError(f"got {ver=}, expected maximal={len(self._values)}")
200
112
 
201
- # implementation ClassMap
202
- UnsignedDataMap = ClassMap({
203
- 0: impl.data.Unsigned
204
- })
205
-
206
- CosemClassMap: TypeAlias = DataMap | RegisterMap | ExtendedRegisterMap | DemandRegisterMap | ProfileGenericMap | ClockMap | ScriptTableMap | ScheduleMap | SpecialDaysTableMap | \
207
- AssociationLNMap | ImageTransferMap | ActivityCalendarMap | RegisterMonitorMap | SingleActionScheduleMap | IECHDLCSetupMap | ModemConfigurationMap | \
208
- TCPUDPSetupMap | IPv4SetupMap | GPRSModemSetupMap | GSMDiagnosticMap | SecuritySetupMap | ArbitratorMap | DisconnectControlMap | LimiterMap | \
209
- NTPSetupMap
113
+ def renew(self, ver: int, cls_: type[InterfaceClass]) -> Self:
114
+ """return with one change"""
115
+ if ver < (l := len(self._values)):
116
+ tmp = list(self._values)
117
+ tmp.insert(ver, cls_)
118
+ return self.__class__(*tmp)
119
+ if ver == l:
120
+ return self.__class__(*(self._values + (cls_,)))
121
+ raise RuntimeError(f"got {ver=}, expected maximal={len(self._values)}")
122
+
123
+ def __str__(self) -> str:
124
+ return f"{self._values[0].CLASS_ID}[{len(self._values)}]"
125
+
126
+
127
+ DataMap = ClassMap(Data)
128
+ DataStaticMap = ClassMap(impl.data.DataStatic)
129
+ DataDynamicMap = ClassMap(impl.data.DataDynamic)
130
+ RegisterMap = ClassMap(Register)
131
+ ExtendedRegisterMap = ClassMap(ExtendedRegister)
132
+ DemandRegisterMap = ClassMap(DemandRegisterVer0)
133
+ RegisterActivationMap = ClassMap(RegisterActivation)
134
+ ProfileGenericMap = ClassMap(ProfileGenericVer0, ProfileGenericVer1)
135
+ ClockMap = ClassMap(Clock)
136
+ ScriptTableMap = ClassMap(ScriptTable)
137
+ ScheduleMap = ClassMap(Schedule)
138
+ SpecialDaysTableMap = ClassMap(SpecialDaysTable)
139
+ AssociationSNMap = ClassMap(AssociationSNVer0)
140
+ AssociationLNMap = ClassMap(AssociationLNVer0, AssociationLNVer1, AssociationLNVer2)
141
+ ImageTransferMap = ClassMap(ImageTransfer)
142
+ ActivityCalendarMap = ClassMap(ActivityCalendar)
143
+ RegisterMonitorMap = ClassMap(RegisterMonitor)
144
+ SingleActionScheduleMap = ClassMap(SingleActionSchedule)
145
+ IECHDLCSetupMap = ClassMap(IECHDLCSetupVer0, IECHDLCSetupVer1)
146
+ ModemConfigurationMap = ClassMap(PSTNModemConfiguration, ModemConfigurationVer1)
147
+ TCPUDPSetupMap = ClassMap(TCPUDPSetup)
148
+ IPv4SetupMap = ClassMap(IPv4Setup)
149
+ GPRSModemSetupMap = ClassMap(GPRSModemSetup)
150
+ GSMDiagnosticMap = ClassMap(GSMDiagnosticVer0, GSMDiagnosticVer1, GSMDiagnosticVer2)
151
+ PushSetupMap = ClassMap(PushSetupVer0, PushSetupVer1, PushSetupVer2)
152
+ SecuritySetupMap = ClassMap(SecuritySetupVer0, SecuritySetupVer1)
153
+ ArbitratorMap = ClassMap(Arbitrator)
154
+ DisconnectControlMap = ClassMap(DisconnectControl)
155
+ LimiterMap = ClassMap(Limiter)
156
+ NTPSetupMap = ClassMap(NTPSetup)
210
157
 
158
+ # implementation ClassMap
159
+ UnsignedDataMap = ClassMap(impl.data.Unsigned)
211
160
 
212
161
  LN_C: TypeAlias = int
213
162
  LN_D: TypeAlias = int
214
163
 
215
164
 
216
- common_interface_class_map: dict[int, dict[[int, None], Type[InterfaceClass]]] = {
165
+ common_interface_class_map: dict[int, ClassMap] = {
217
166
  1: DataMap,
218
167
  3: RegisterMap,
219
168
  4: ExtendedRegisterMap,
@@ -243,16 +192,11 @@ common_interface_class_map: dict[int, dict[[int, None], Type[InterfaceClass]]] =
243
192
  }
244
193
 
245
194
 
246
- def get_interface_class(class_map: dict[int, CosemClassMap], c_id: ut.CosemClassId, ver: cdt.Unsigned) -> Type[InterfaceClass]:
195
+ def get_interface_class(class_map: dict[int, ClassMap], c_id: ut.CosemClassId, ver: cdt.Unsigned) -> type[InterfaceClass]:
247
196
  """new version <get_type_from_class>"""
248
197
  ret = class_map.get(int(c_id), None)
249
- if ret:
250
- ret2 = ret.get(int(ver), None)
251
- """interface class type"""
252
- if ret2:
253
- return ret2
254
- else:
255
- raise CollectionMapError(F"got DLMS class version: {ver} for {c_id=}, expected: {", ".join(map(str, ret.keys()))}")
198
+ if isinstance(ret, ClassMap):
199
+ return ret.get(int(ver))
256
200
  else:
257
201
  if int(c_id) not in common_interface_class_map.keys():
258
202
  raise CollectionMapError(F"unknown {c_id=}")
@@ -275,19 +219,12 @@ _NOT_PROCESSING_OF_MEASUREMENT_VALUES = tuple(set(range(256)).difference((0, 93,
275
219
  _RU_CHANGE_LIMIT_LEVEL = 134
276
220
 
277
221
 
278
-
279
- @dataclass(frozen=True)
280
- class ObjectRelation:
281
- IC: int | tuple[int, ...] | ic.COSEMInterfaceClasses
282
- Additional: bytes | dict | bool = None
283
-
284
-
285
222
  @lru_cache()
286
- def _create_map(maps: ClassMap | tuple[ClassMap]) -> dict[int, CosemClassMap]:
223
+ def _create_map(maps: ClassMap | tuple[ClassMap]) -> dict[int, ClassMap]:
287
224
  if isinstance(maps, tuple):
288
- return {int(map_[0].CLASS_ID): map_ for map_ in maps}
225
+ return {int(map_.get(0).CLASS_ID): map_ for map_ in maps}
289
226
  else:
290
- return {int((tuple(maps.values())[0]).CLASS_ID): maps}
227
+ return {int(maps.get(0).CLASS_ID): maps}
291
228
 
292
229
 
293
230
  A: TypeAlias = int
@@ -296,185 +233,257 @@ C: TypeAlias = int
296
233
  D: TypeAlias = int
297
234
  E: TypeAlias = int
298
235
 
299
- FOR_C: TypeAlias = tuple[A, C]
300
- FOR_CD: TypeAlias = tuple[A, C | tuple[C, ...], D] | tuple[A, tuple[C, ...], tuple[D, ...]]
301
- FOR_CDE: TypeAlias = tuple[A, C, D | tuple[D, ...], E | tuple[E, ...]]
302
- FOR_BCDE: TypeAlias = tuple[A, B, C, D, E | tuple[E, ...]]
303
- FUNC_MAP: TypeAlias = dict[bytes, dict[int, CosemClassMap]]
236
+
237
+ class Xgroup(Protocol):
238
+ fmt: str
239
+
240
+ def get_key(self) -> Iterator[bytes]:
241
+ ...
242
+
243
+
244
+ class SimpleGroup(Xgroup, Protocol):
245
+ def get_key(self) -> Iterator[bytes]:
246
+ yield pack(self.fmt, *self) # type: ignore[misc]
247
+
248
+
249
+ class ACgroup(SimpleGroup, tuple[A, C]):
250
+ """Grouping of OBIS codes by group A (media) and group C (attribute).
251
+ Creates a composite key for objects sharing the same media type and attribute.
252
+ """
253
+ fmt = ">BB"
254
+
255
+
256
+ class ACDgroup_(Xgroup, Protocol):
257
+ """Grouping of OBIS codes by groups A (media), C (attribute), and D (data) with mask support.
258
+ Supports exact values or masks for attribute (C) and data (D) groups.
259
+ Allows flexible grouping by media type with variable attribute and data patterns.
260
+ """
261
+ fmt: str = ">BBB"
262
+
263
+
264
+ class ACDgroup(SimpleGroup, ACDgroup_, tuple[A, C, D]):
265
+ ...
266
+
267
+
268
+ class ACCDgroup(ACDgroup_, tuple[A, tuple[C, ...], D]):
269
+ def get_key(self) -> Iterator[bytes]:
270
+ a, _, d = self
271
+ return (pack(self.fmt, a, c, d) for c in self[1])
272
+
273
+
274
+ class ACDDgroup(ACDgroup_, tuple[A, C, tuple[D, ...]]):
275
+ def get_key(self) -> Iterator[bytes]:
276
+ a, c, _ = self
277
+ return (pack(self.fmt, a, c, d) for d in self[2])
278
+
279
+
280
+ class ACCDDgroup(ACDgroup_, tuple[A, tuple[C, ...], tuple[D, ...]]):
281
+ """Grouping of OBIS codes by groups A (media), C (attribute), and D (data) with mask support.
282
+ Supports exact values or masks for attribute (C) and data (D) groups.
283
+ Allows flexible grouping by media type with variable attribute and data patterns.
284
+ """
285
+ def get_key(self) -> Iterator[bytes]:
286
+ a = self[0]
287
+ return (pack(self.fmt, a, c, d) for c in self[1] for d in self[2])
288
+
289
+
290
+ class ACDEgroup_(Xgroup, Protocol):
291
+ """Grouping of OBIS codes by groups A (media), C (attribute), D (data), and E (data version) with mask support.
292
+ Groups by fixed media and attribute with support for data and data version masks.
293
+ Enables precise control over data grouping with optional version filtering.
294
+ """
295
+ fmt: str = ">BBBB"
296
+
297
+
298
+ class ACDEgroup(SimpleGroup, ACDEgroup_, tuple[A, C, D, E]):
299
+ ...
300
+
301
+
302
+ class ACDDEgroup(ACDEgroup_, tuple[A, C, tuple[D, ...], E]):
303
+ def get_key(self) -> Iterator[bytes]:
304
+ a, c, _, e = self
305
+ return (pack(self.fmt, a, c, d, e) for d in self[2])
306
+
307
+
308
+
309
+ class ACDEEgroup(ACDEgroup_, tuple[A, C, D, tuple[E, ...]]):
310
+ def get_key(self) -> Iterator[bytes]:
311
+ a, c, d, _ = self
312
+ return (pack(self.fmt, a, c, d, e) for e in self[3])
313
+
314
+
315
+ class ACDDEEgroup(ACDEgroup_, tuple[A, C, tuple[D, ...], tuple[E, ...]]):
316
+ def get_key(self) -> Iterator[bytes]:
317
+ a, c, _, _ = self
318
+ return (pack(self.fmt, a, c, d, e) for d in self[2] for e in self[3])
319
+
320
+
321
+ class ABCDEgroup_(Xgroup, Protocol):
322
+ """Grouping of OBIS codes by all OBIS groups A-E with data version mask support.
323
+
324
+ Comprehensive grouping by:
325
+ - A: media
326
+ - B: channel/interface
327
+ - C: attribute
328
+ - D: data
329
+ - E: data version (with mask support)
330
+
331
+ Provides complete OBIS code grouping with flexible version matching.
332
+ """
333
+ fmt: str = ">BBBBB"
334
+
335
+
336
+ class ABCDEgroup(SimpleGroup, ABCDEgroup_, tuple[A, B, C, D, E]):
337
+ ...
338
+
339
+
340
+ class ABCCDEgroup(ABCDEgroup_, tuple[A, B, tuple[C, ...], D, E]):
341
+ def get_key(self) -> Iterator[bytes]:
342
+ a, b, _, d, e = self
343
+ return (pack(self.fmt, a, b, c, d, e) for c in self[2])
344
+
345
+
346
+ class ABCDEEgroup(ABCDEgroup_, tuple[A, B, C, D, tuple[E, ...]]):
347
+ def get_key(self) -> Iterator[bytes]:
348
+ a, b, c, d, _ = self
349
+ return (pack(self.fmt, a, b, c, d, e) for e in self[4])
350
+
351
+
352
+ type PossibleGroup = ACgroup | ACDgroup_ | ACDEgroup | ABCDEgroup
353
+ FUNC_MAP: TypeAlias = dict[bytes, dict[int, ClassMap]]
304
354
  """ln.BCDE | ln.CDE | ln.CD | ln.C: {class_id: {version: CosemInterfaceClass}}"""
305
355
 
306
356
 
307
- func_maps: dict[str, FUNC_MAP] = dict()
308
-
309
-
310
- def get_func_map(for_create_map: dict) -> FUNC_MAP:
311
- keys: list[bytes]
312
- ret: FUNC_MAP = dict()
313
- for it in for_create_map:
314
- keys = list()
315
- match len(it):
316
- case 4:
317
- match it[2], it[3]:
318
- case int(), tuple() as e_g:
319
- for e in e_g:
320
- keys.append(pack(">BBBB", it[0], it[1], it[2], e))
321
- case tuple() as d_g, int():
322
- for d in d_g:
323
- keys.append(pack(">BBBB", it[0], it[1], d, it[3]))
324
- case tuple() as d_g, tuple() as e_g:
325
- for d in d_g:
326
- for e in e_g:
327
- keys.append(pack(">BBBB", it[0], it[1], d, e))
328
- case int(), int():
329
- keys.append(bytes(it))
330
- case _:
331
- raise ValueError(F"unknown {it[2]=} and {it[3]=} in dict values: {it}")
332
- case 3:
333
- match it[1], it[2]:
334
- case int(), int():
335
- keys.append(bytes(it))
336
- case tuple() as c_g, int():
337
- for c in c_g:
338
- keys.append(pack(">BBB", it[0], c, it[2]))
339
- case int(), tuple() as d_g:
340
- for d in d_g:
341
- keys.append(pack(">BBB", it[0], it[1], d))
342
- case tuple() as c_g, tuple() as d_g:
343
- for c in c_g:
344
- for d in d_g:
345
- keys.append(pack(">BBB", it[0], c, d))
346
- case err:
347
- raise ValueError(F"unknown {it[1]=} in dict values: {err}")
348
- case 5:
349
- match it[2], it[4]:
350
- case int(), int():
351
- keys.append(bytes(it))
352
- case int(), tuple() as e_g:
353
- for e in e_g:
354
- keys.append(pack(">BBBBB", it[0], it[1], it[2], it[3], e))
355
- case tuple() as c_g, int():
356
- for c in c_g:
357
- keys.append(pack(">BBBBB", it[0], it[1], c, it[3], it[4]))
358
- case _:
359
- raise ValueError(F"unknown dict values: {it}")
360
- case 2:
361
- keys.append(bytes(it))
362
- case err_len:
363
- raise ValueError(F"got {err_len=} map_for_create, expect 2..5")
364
- for k in keys:
365
- ret[k] = _create_map(for_create_map[it])
357
+ func_maps: dict[str, FUNC_MAP] = {}
358
+ type PossibleClassMap = tuple[ClassMap, ...] | ClassMap
359
+
360
+
361
+ def get_func_map(for_create_map: dict[PossibleGroup, PossibleClassMap]) -> FUNC_MAP:
362
+ ret: FUNC_MAP = {}
363
+ for g in for_create_map:
364
+ for k in g.get_key():
365
+ ret[k] = _create_map(for_create_map[g])
366
366
  return ret
367
367
 
368
368
 
369
- __func_map_for_create: dict[FOR_C | FOR_CD | FOR_CDE | FOR_BCDE, tuple[ClassMap, ...] | ClassMap] = {
369
+ __func_map_for_create: dict[PossibleGroup, PossibleClassMap] = {
370
370
  # abstract
371
- (0, 0, 1): DataMap,
372
- (0, 0, 2): DataMap,
373
- (0, 0, 2, 1): ClassMap({0: impl.data.ActiveFirmwareId}),
374
- (0, 0, 9): DataMap,
375
- (0, 1, 0): ClockMap,
376
- (0, 1, 1): DataMap,
377
- (0, 1, 2): DataMap,
378
- (0, 1, 3): DataMap,
379
- (0, 1, 4): DataMap,
380
- (0, 1, 5): DataMap,
381
- (0, 1, 6): DataMap,
382
- (0, 2, 0, 0): ModemConfigurationMap,
371
+ ACDgroup((0, 0, 1)): DataMap,
372
+ ACDgroup((0, 0, 2)): DataMap,
373
+ ACDEgroup((0, 0, 2, 1)): ClassMap(impl.data.ActiveFirmwareId),
374
+ ACDgroup((0, 0, 9)): DataMap,
375
+ ACDgroup((0, 1, 0)): ClockMap,
376
+ ACDgroup((0, 1, 1)): DataMap,
377
+ ACDgroup((0, 1, 2)): DataMap,
378
+ ACDgroup((0, 1, 3)): DataMap,
379
+ ACDgroup((0, 1, 4)): DataMap,
380
+ ACDgroup((0, 1, 5)): DataMap,
381
+ ACDgroup((0, 1, 6)): DataMap,
382
+ ACDEgroup((0, 2, 0, 0)): ModemConfigurationMap,
383
383
  #
384
- (0, 10, 0, (0, 1, 125)+tuple(range(100, 112))): ScriptTableMap,
385
- (0, 11, 0): SpecialDaysTableMap,
386
- (0, 12, 0): ScheduleMap,
387
- (0, 13, 0): ActivityCalendarMap,
388
- (0, 14, 0): RegisterActivationMap,
389
- (0, 15, 0, tuple(range(0, 8))): SingleActionScheduleMap,
390
- (0, 16, 0): RegisterMonitorMap,
391
- (0, 16, 1, tuple(range(0, 10))): RegisterMonitorMap,
384
+ ACDEEgroup((0, 10, 0, (0, 1, 125)+tuple(range(100, 112)))): ScriptTableMap,
385
+ ACDgroup((0, 11, 0)): SpecialDaysTableMap,
386
+ ACDgroup((0, 12, 0)): ScheduleMap,
387
+ ACDgroup((0, 13, 0)): ActivityCalendarMap,
388
+ ACDgroup((0, 14, 0)): RegisterActivationMap,
389
+ ACDEEgroup((0, 15, 0, tuple(range(0, 8)))): SingleActionScheduleMap,
390
+ ACDgroup((0, 16, 0)): RegisterMonitorMap,
391
+ ACDEEgroup((0, 16, 1, tuple(range(0, 10)))): RegisterMonitorMap,
392
392
  #
393
- (0, 17, 0): LimiterMap,
393
+ ACDgroup((0, 17, 0)): LimiterMap,
394
394
  #
395
- (0, 19, tuple(range(50, 60)), (1, 2)): DataMap,
395
+ ACDDEEgroup((0, 19, tuple(range(50, 60)), (1, 2))): DataMap,
396
396
  #
397
- (0, 21, 0): (DataMap, ProfileGenericMap),
398
- (0, 22, 0, 0): IECHDLCSetupMap,
397
+ ACDgroup((0, 21, 0)): (DataMap, ProfileGenericMap),
398
+ ACDEgroup((0, 22, 0, 0)): IECHDLCSetupMap,
399
399
  #
400
- (0, 23, 2, 0): DataMap,
401
- (0, 23, 3, tuple(range(0, 10))): (DataMap, ProfileGenericMap),
402
- (0, 23, 3, tuple(range(10, 256))): DataMap,
400
+ ACDEgroup((0, 23, 2, 0)): DataMap,
401
+ ACDEEgroup((0, 23, 3, tuple(range(0, 10)))): (DataMap, ProfileGenericMap),
402
+ ACDEEgroup((0, 23, 3, tuple(range(10, 256)))): DataMap,
403
403
  #
404
- (0, 24, 2): ExtendedRegisterMap,
405
- (0, 24, 3): ProfileGenericMap,
406
- (0, 24, 4, 0): DisconnectControlMap,
407
- (0, 24, 5, 0): ProfileGenericMap,
404
+ ACDgroup((0, 24, 2)): ExtendedRegisterMap,
405
+ ACDgroup((0, 24, 3)): ProfileGenericMap,
406
+ ACDEgroup((0, 24, 4, 0)): DisconnectControlMap,
407
+ ACDEgroup((0, 24, 5, 0)): ProfileGenericMap,
408
408
  #
409
- (0, 25, 0, 0): TCPUDPSetupMap,
410
- (0, 25, 1, 0): IPv4SetupMap,
409
+ ACDEgroup((0, 25, 0, 0)): TCPUDPSetupMap,
410
+ ACDEgroup((0, 25, 1, 0)): IPv4SetupMap,
411
411
  #
412
- (0, 25, 4, 0): GPRSModemSetupMap,
412
+ ACDEgroup((0, 25, 4, 0)): GPRSModemSetupMap,
413
413
  #
414
- (0, 25, 6, 0): GSMDiagnosticMap,
414
+ ACDEgroup((0, 25, 6, 0)): GSMDiagnosticMap,
415
415
  #
416
- (0, 25, 9, 0): PushSetupMap,
417
- (0, 25, 10, 0): NTPSetupMap,
416
+ ACDEgroup((0, 25, 9, 0)): PushSetupMap,
417
+ ACDEgroup((0, 25, 10, 0)): NTPSetupMap,
418
418
  #
419
- (0, 0, 40, 0, tuple(range(8))): (AssociationSNMap, AssociationLNMap), # todo: now limit by 8 association, solve it
419
+ ABCDEEgroup((0, 0, 40, 0, tuple(range(8)))): (AssociationSNMap, AssociationLNMap), # todo: now limit by 8 association, solve it
420
420
  #
421
- (0, 0, 42, 0, 0): ClassMap({0: impl.data.LDN}),
422
- (0, 0, 43, 0, tuple(range(256))): SecuritySetupMap,
423
- (0, 43, 1): DataMap,
421
+ ABCDEgroup((0, 0, 42, 0, 0)): ClassMap(impl.data.LDN),
422
+ ABCDEEgroup((0, 0, 43, 0, tuple(range(256)))): SecuritySetupMap,
423
+ ACDgroup((0, 43, 1)): DataMap,
424
424
  #
425
- (0, 0, 44, 0, tuple(range(256))): ImageTransferMap,
425
+ ABCDEEgroup((0, 0, 44, 0, tuple(range(256)))): ImageTransferMap,
426
426
  #
427
- (0, 96, 1, tuple(range(0, 11))): ClassMap({0: impl.data.DLMSDeviceIDObject}),
428
- (0, 96, 1, 255): ProfileGenericMap, # todo: add RegisterTable
429
- (0, 96, 2): DataDynamicMap,
430
- (0, 96, 3, tuple(range(0, 4))): DataMap, # todo: add StatusMapping
431
- (0, 96, 3, 10): DisconnectControlMap,
432
- (0, 96, 3, tuple(range(20, 29))): ArbitratorMap,
433
- (0, 96, (4, 5), 0): (DataMap, ProfileGenericMap), # todo: add RegisterTable, StatusMapping
434
- (0, 96, (4, 5), (1, 2, 3, 4)): DataMap, # todo: add StatusMapping
435
- (0, 96, 6, tuple(range(0, 7))): (DataMap, RegisterMap, ExtendedRegisterMap),
436
- (0, 96, 7, tuple(range(0, 22))): (DataMap, RegisterMap, ExtendedRegisterMap),
437
- (0, 96, 8, tuple(range(0, 64))): (DataMap, RegisterMap, ExtendedRegisterMap),
438
- (0, 96, 9, (0, 1, 2)): (RegisterMap, ExtendedRegisterMap),
439
- (0, 96, 10, tuple(range(1, 10))): DataMap, # todo: add StatusMapping
440
- (0, 96, 11, tuple(range(100))): (DataDynamicMap, RegisterMap, ExtendedRegisterMap),
441
- (0, 96, 12, (0, 1, 2, 3, 5, 6)): (DataMap, RegisterMap, ExtendedRegisterMap),
442
- (0, 96, 12, 4): ClassMap({0: impl.data.CommunicationPortParameter}),
443
- (0, 96, 13, (0, 1)): (DataMap, RegisterMap, ExtendedRegisterMap),
444
- (0, 96, 14, tuple(range(16))): (DataMap, RegisterMap, ExtendedRegisterMap),
445
- (0, 96, 15, tuple(range(100))): (DataMap, RegisterMap, ExtendedRegisterMap),
446
- (0, 96, 16, tuple(range(10))): (DataMap, RegisterMap, ExtendedRegisterMap),
447
- (0, 96, 17, tuple(range(128))): (DataMap, RegisterMap, ExtendedRegisterMap),
448
- (0, 96, 20): (DataMap, RegisterMap, ExtendedRegisterMap),
449
- (0, 97, 97, tuple(range(10))): DataMap,
450
- (0, 97, (97, 98), 255): ProfileGenericMap, # todo: add RegisterTable
451
- (0, 97, 98, tuple(range(10))+tuple(range(10, 30))): DataMap,
452
- (0, 98,): ProfileGenericMap,
453
- (0, 99, 98): ProfileGenericMap,
427
+ ACDEEgroup((0, 96, 1, tuple(range(0, 11)))): ClassMap(impl.data.DLMSDeviceIDObject),
428
+ ACDEgroup((0, 96, 1, 255)): ProfileGenericMap, # todo: add RegisterTable
429
+ ACDgroup((0, 96, 2)): DataDynamicMap,
430
+ ACDEEgroup((0, 96, 3, tuple(range(0, 4)))): DataMap, # todo: add StatusMapping
431
+ ACDEgroup((0, 96, 3, 10)): DisconnectControlMap,
432
+ ACDEEgroup((0, 96, 3, tuple(range(20, 29)))): ArbitratorMap,
433
+ ACDDEgroup((0, 96, (4, 5), 0)): (DataMap, ProfileGenericMap), # todo: add RegisterTable, StatusMapping
434
+ ACDDEEgroup((0, 96, (4, 5), (1, 2, 3, 4))): DataMap, # todo: add StatusMapping
435
+ ACDEEgroup((0, 96, 6, tuple(range(0, 7)))): (DataMap, RegisterMap, ExtendedRegisterMap),
436
+ ACDEEgroup((0, 96, 7, tuple(range(0, 22)))): (DataMap, RegisterMap, ExtendedRegisterMap),
437
+ ACDEEgroup((0, 96, 8, tuple(range(0, 64)))): (DataMap, RegisterMap, ExtendedRegisterMap),
438
+ ACDEEgroup((0, 96, 9, (0, 1, 2))): (RegisterMap, ExtendedRegisterMap),
439
+ ACDEEgroup((0, 96, 10, tuple(range(1, 10)))): DataMap, # todo: add StatusMapping
440
+ ACDEEgroup((0, 96, 11, tuple(range(100)))): (DataDynamicMap, RegisterMap, ExtendedRegisterMap),
441
+ ACDEEgroup((0, 96, 12, (0, 1, 2, 3, 5, 6))): (DataMap, RegisterMap, ExtendedRegisterMap),
442
+ ACDEgroup((0, 96, 12, 4)): ClassMap(impl.data.CommunicationPortParameter),
443
+ ACDEEgroup((0, 96, 13, (0, 1))): (DataMap, RegisterMap, ExtendedRegisterMap),
444
+ ACDEEgroup((0, 96, 14, tuple(range(16)))): (DataMap, RegisterMap, ExtendedRegisterMap),
445
+ ACDEEgroup((0, 96, 15, tuple(range(100)))): (DataMap, RegisterMap, ExtendedRegisterMap),
446
+ ACDEEgroup((0, 96, 16, tuple(range(10)))): (DataMap, RegisterMap, ExtendedRegisterMap),
447
+ ACDEEgroup((0, 96, 17, tuple(range(128)))): (DataMap, RegisterMap, ExtendedRegisterMap),
448
+ ACDgroup((0, 96, 20)): (DataMap, RegisterMap, ExtendedRegisterMap),
449
+ ACDEEgroup((0, 97, 97, tuple(range(10)))): DataMap,
450
+ ACDDEgroup((0, 97, (97, 98), 255)): ProfileGenericMap, # todo: add RegisterTable
451
+ ACDEEgroup((0, 97, 98, tuple(range(10))+tuple(range(10, 30)))): DataMap,
452
+ ACgroup((0, 98)): ProfileGenericMap,
453
+ ACDgroup((0, 99, 98)): ProfileGenericMap,
454
454
  # electricity
455
- (1, 0, 0, tuple(range(10))): DataMap,
456
- (1, 0, 0, 255): ProfileGenericMap, # todo: add RegisterTable
457
- (1, 0, 1): DataMap,
458
- (1, 0, 2): DataStaticMap,
459
- (1, 0, (3, 4, 7, 8, 9)): (DataStaticMap, RegisterMap, ExtendedRegisterMap),
460
- (1, 0, (6, 10)): (RegisterMap, ExtendedRegisterMap),
461
- (1, 0, 11, tuple(range(1, 8))): DataMap,
462
- (1, 96, 1, tuple(range(10))): DataMap,
463
- (1, 96, 1, 255): ProfileGenericMap, # todo: add RegisterTable
464
- (1, 96, 5, (0, 1, 2, 3, 4, 5)): DataMap, # todo: add StatusMapping
465
- (1, 96, 10, (0, 1, 2, 3)): DataMap, # todo: add StatusMapping
466
- (1, 98,): ProfileGenericMap,
467
- (1, 99, (1, 2, 11, 12, 97, 98, 99)): ProfileGenericMap,
468
- (1, 99, (3, 13, 14), 0): ProfileGenericMap,
469
- (1, 99, 10, (1, 2, 3)): ProfileGenericMap,
470
- (1, _CUMULATIVE, _RU_CHANGE_LIMIT_LEVEL): RegisterMap,
471
- (1, _NOT_PROCESSING_OF_MEASUREMENT_VALUES, tuple(chain(_CUMULATIVE, _TIME_INTEGRAL_VALUES, _CONTRACTED_VALUES,
472
- _UNDER_OVER_LIMIT_THRESHOLDS, _UNDER_OVER_LIMIT_OCCURRENCE_COUNTERS,
473
- _UNDER_OVER_LIMIT_DURATIONS, _UNDER_OVER_LIMIT_MAGNITUDES))): (RegisterMap, ExtendedRegisterMap),
474
- (1, _NOT_PROCESSING_OF_MEASUREMENT_VALUES, _INSTANTANEOUS_VALUES): RegisterMap,
475
- (1, _NOT_PROCESSING_OF_MEASUREMENT_VALUES, _MAX_MIN_VALUES): (RegisterMap, ExtendedRegisterMap, ProfileGenericMap),
476
- (1, _NOT_PROCESSING_OF_MEASUREMENT_VALUES, _CURRENT_AND_LAST_AVERAGE_VALUES): (RegisterMap, DemandRegisterMap),
477
- (1, _NOT_PROCESSING_OF_MEASUREMENT_VALUES, 40): (DataMap, RegisterMap),
455
+ ACDEEgroup((1, 0, 0, tuple(range(10)))): DataMap,
456
+ ACDEgroup((1, 0, 0, 255)): ProfileGenericMap, # todo: add RegisterTable
457
+ ACDgroup((1, 0, 1)): DataMap,
458
+ ACDgroup((1, 0, 2)): DataStaticMap,
459
+ ACDDgroup((1, 0, (3, 4, 7, 8, 9))): (DataStaticMap, RegisterMap, ExtendedRegisterMap),
460
+ ACDDgroup((1, 0, (6, 10))): (RegisterMap, ExtendedRegisterMap),
461
+ ACDEEgroup((1, 0, 11, tuple(range(1, 8)))): DataMap,
462
+ ACDEEgroup((1, 96, 1, tuple(range(10)))): DataMap,
463
+ ACDEgroup((1, 96, 1, 255)): ProfileGenericMap, # todo: add RegisterTable
464
+ ACDEEgroup((1, 96, 5, (0, 1, 2, 3, 4, 5))): DataMap, # todo: add StatusMapping
465
+ ACDEEgroup((1, 96, 10, (0, 1, 2, 3))): DataMap, # todo: add StatusMapping
466
+ ACgroup((1, 98)): ProfileGenericMap,
467
+ ACDDgroup((1, 99, (1, 2, 11, 12, 97, 98, 99))): ProfileGenericMap,
468
+ ACDDEgroup((1, 99, (3, 13, 14), 0)): ProfileGenericMap,
469
+ ACDEEgroup((1, 99, 10, (1, 2, 3))): ProfileGenericMap,
470
+ ACCDgroup((1, _CUMULATIVE, _RU_CHANGE_LIMIT_LEVEL)): RegisterMap,
471
+ ACCDDgroup((
472
+ 1,
473
+ _NOT_PROCESSING_OF_MEASUREMENT_VALUES,
474
+ tuple(chain(
475
+ _CUMULATIVE,
476
+ _TIME_INTEGRAL_VALUES,
477
+ _CONTRACTED_VALUES,
478
+ _UNDER_OVER_LIMIT_THRESHOLDS,
479
+ _UNDER_OVER_LIMIT_OCCURRENCE_COUNTERS,
480
+ _UNDER_OVER_LIMIT_DURATIONS,
481
+ _UNDER_OVER_LIMIT_MAGNITUDES
482
+ )))): (RegisterMap, ExtendedRegisterMap),
483
+ ACCDDgroup((1, _NOT_PROCESSING_OF_MEASUREMENT_VALUES, _INSTANTANEOUS_VALUES)): RegisterMap,
484
+ ACCDDgroup((1, _NOT_PROCESSING_OF_MEASUREMENT_VALUES, _MAX_MIN_VALUES)): (RegisterMap, ExtendedRegisterMap, ProfileGenericMap),
485
+ ACCDDgroup((1, _NOT_PROCESSING_OF_MEASUREMENT_VALUES, _CURRENT_AND_LAST_AVERAGE_VALUES)): (RegisterMap, DemandRegisterMap),
486
+ ACCDgroup((1, _NOT_PROCESSING_OF_MEASUREMENT_VALUES, 40)): (DataMap, RegisterMap),
478
487
  }
479
488
 
480
489
  func_maps["DLMS_6"] = get_func_map(__func_map_for_create)
@@ -482,92 +491,101 @@ func_maps["DLMS_6"] = get_func_map(__func_map_for_create)
482
491
 
483
492
  # SPODES3 Update
484
493
  __func_map_for_create.update({
485
- (0, 21, 0): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3DisplayReadout),
486
- (0, 96, 1, (0, 2, 4, 5, 8, 9, 10)): ClassMap({0: impl.data.SPODES3IDNotSpecific}),
487
- (0, 96, 1, 6): ClassMap({0: impl.data.SPODES3SPODESVersion}),
488
- (0, 96, 2, (1, 2, 3, 5, 6, 7, 11, 12)): ClassMap({0: impl.data.AnyDateTime}),
489
- (0, 96, 3, 20): ClassMap({0: impl.arbitrator.SPODES3Arbitrator}),
490
- (0, 96, 4, 3): ClassMap({0: impl.data.SPODES3LoadLocker}),
491
- (0, 96, 5, 1): ClassMap({0: impl.data.SPODES3PowerQuality2Event}),
492
- (0, 96, 5, 4): ClassMap({0: impl.data.SPODES3PowerQuality1Event}),
493
- (0, 96, 5, 132): ClassMap({0: impl.data.Unsigned}), # TODO: make according with СПОДЭС3 13.9. Контроль чередования фаз
494
- (0, 96, 11, 0): ClassMap({0: impl.data.SPODES3VoltageEvent}),
495
- (0, 96, 11, 1): ClassMap({0: impl.data.SPODES3CurrentEvent}),
496
- (0, 96, 11, 2): ClassMap({0: impl.data.SPODES3CommutationEvent}),
497
- (0, 96, 11, 3): ClassMap({0: impl.data.SPODES3ProgrammingEvent}),
498
- (0, 96, 11, 4): ClassMap({0: impl.data.SPODES3ExternalEvent}),
499
- (0, 96, 11, 5): ClassMap({0: impl.data.SPODES3CommunicationEvent}),
500
- (0, 96, 11, 6): ClassMap({0: impl.data.SPODES3AccessEvent}),
501
- (0, 96, 11, 7): ClassMap({0: impl.data.SPODES3SelfDiagnosticEvent}),
502
- (0, 96, 11, 8): ClassMap({0: impl.data.SPODES3ReactivePowerEvent}),
503
- (0, 0, 96, 51, 0): ClassMap({0: impl.data.OpeningBody}),
504
- (0, 0, 96, 51, 1): ClassMap({0: impl.data.OpeningCover}),
505
- (0, 0, 96, 51, 3): ClassMap({0: impl.data.ExposureToMagnet}),
506
- (0, 0, 96, 51, 4): ClassMap({0: impl.data.ExposureToHSField}),
507
- (0, 0, 96, 51, 5): ClassMap({0: impl.data.SealStatus}),
508
- (0, 0, 96, 51, (6, 7)): UnsignedDataMap,
509
- (0, 0, 96, 51, (8, 9)): ClassMap({0: impl.data.OctetStringDateTime}),
510
- (0, 0, 97, 98, (0, 10, 20)): ClassMap({0: impl.data.SPODES3Alarm1}),
494
+ ACDgroup((0, 21, 0)): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3DisplayReadout),
495
+ ACDEEgroup((0, 96, 1, (0, 2, 4, 5, 8, 9, 10))): ClassMap(impl.data.SPODES3IDNotSpecific),
496
+ ACDEgroup((0, 96, 1, 6)): ClassMap(impl.data.SPODES3SPODESVersion),
497
+ ACDEEgroup((0, 96, 2, (1, 2, 3, 5, 6, 7, 11, 12))): ClassMap(impl.data.AnyDateTime),
498
+ ACDEgroup((0, 96, 3, 20)): ClassMap(impl.arbitrator.SPODES3Arbitrator),
499
+ ACDEgroup((0, 96, 4, 3)): ClassMap(impl.data.SPODES3LoadLocker),
500
+ ACDEgroup((0, 96, 5, 1)): ClassMap(impl.data.SPODES3PowerQuality2Event),
501
+ ACDEgroup((0, 96, 5, 4)): ClassMap(impl.data.SPODES3PowerQuality1Event),
502
+ ACDEgroup((0, 96, 5, 132)): ClassMap(impl.data.Unsigned), # TODO: make according with СПОДЭС3 13.9. Контроль чередования фаз
503
+ ACDEgroup((0, 96, 11, 0)): ClassMap(impl.data.SPODES3VoltageEvent),
504
+ ACDEgroup((0, 96, 11, 1)): ClassMap(impl.data.SPODES3CurrentEvent),
505
+ ACDEgroup((0, 96, 11, 2)): ClassMap(impl.data.SPODES3CommutationEvent),
506
+ ACDEgroup((0, 96, 11, 3)): ClassMap(impl.data.SPODES3ProgrammingEvent),
507
+ ACDEgroup((0, 96, 11, 4)): ClassMap(impl.data.SPODES3ExternalEvent),
508
+ ACDEgroup((0, 96, 11, 5)): ClassMap(impl.data.SPODES3CommunicationEvent),
509
+ ACDEgroup((0, 96, 11, 6)): ClassMap(impl.data.SPODES3AccessEvent),
510
+ ACDEgroup((0, 96, 11, 7)): ClassMap(impl.data.SPODES3SelfDiagnosticEvent),
511
+ ACDEgroup((0, 96, 11, 8)): ClassMap(impl.data.SPODES3ReactivePowerEvent),
512
+ ABCDEgroup((0, 0, 96, 51, 0)): ClassMap(impl.data.OpeningBody),
513
+ ABCDEgroup((0, 0, 96, 51, 1)): ClassMap(impl.data.OpeningCover),
514
+ ABCDEgroup((0, 0, 96, 51, 3)): ClassMap(impl.data.ExposureToMagnet),
515
+ ABCDEgroup((0, 0, 96, 51, 4)): ClassMap(impl.data.ExposureToHSField),
516
+ ABCDEgroup((0, 0, 96, 51, 5)): ClassMap(impl.data.SealStatus),
517
+ ABCDEEgroup((0, 0, 96, 51, (6, 7))): UnsignedDataMap,
518
+ ABCDEEgroup((0, 0, 96, 51, (8, 9))): ClassMap(impl.data.OctetStringDateTime),
519
+ ABCDEEgroup((0, 0, 97, 98, (0, 10, 20))): ClassMap(impl.data.SPODES3Alarm1),
520
+ ABCDEEgroup((0, 0, 97, 98, (1, 11))): ClassMap(impl.data.SPODES3ControlAlarm1),
511
521
  # electricity
512
- (1, 0, 8, (4, 5)): ClassMap({0: impl.data.SPODES3MeasurementPeriod}),
513
- (1, 98, 1): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3MonthProfile),
514
- (1, 98, 2): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3DailyProfile),
515
- (1, 99, (1, 2)): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3LoadProfile),
516
- (1, 0, 131, 35, 0): RegisterMap,
517
- (1, 0, 133, 35, 0): RegisterMap,
518
- (1, 0, 147, 133, 0): RegisterMap,
519
- (1, 0, 148, 136, 0): RegisterMap,
520
- (1, 94, 7, 0): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3CurrentProfile),
521
- (1, 94, 7, (1, 2, 3, 4, 5, 6)): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3ScalesProfile), # Todo: RU. Scaler-profile With 1 entry and more
522
+ ACDEEgroup((1, 0, 8, (4, 5))): ClassMap(impl.data.SPODES3MeasurementPeriod),
523
+ ACDgroup((1, 98, 1)): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3MonthProfile),
524
+ ACDgroup((1, 98, 2)): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3DailyProfile),
525
+ ACDDgroup((1, 99, (1, 2))): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3LoadProfile),
526
+ ABCDEgroup((1, 0, 131, 35, 0)): RegisterMap,
527
+ ABCDEgroup((1, 0, 133, 35, 0)): RegisterMap,
528
+ ABCDEgroup((1, 0, 147, 133, 0)): RegisterMap,
529
+ ABCDEgroup((1, 0, 148, 136, 0)): RegisterMap,
530
+ ACDEgroup((1, 94, 7, 0)): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3CurrentProfile),
531
+ ACDEEgroup((1, 94, 7, (1, 2, 3, 4, 5, 6))): ProfileGenericMap.renew(1, impl.profile_generic.SPODES3ScalesProfile), # Todo: RU. Scaler-profile With 1 entry and more
522
532
  })
523
533
 
524
534
  func_maps["SPODES_3"] = get_func_map(__func_map_for_create)
525
535
 
526
536
  # KPZ Update
527
537
  __func_map_for_create.update({
528
- (0, 96, 11, 4): ClassMap({0: impl.data.KPZSPODES3ExternalEvent}),
529
- (0, 0, 97, 98, (0, 10, 20)): ClassMap({0: impl.data.KPZAlarm1}),
530
- (0, 128, 25, 6, 0): ClassMap({0: impl.data.DataStatic}),
531
- (0, 128, 96, 2, (0, 1, 2)): ClassMap({0: impl.data.KPZAFEOffsets}),
532
- (0, 128, 96, 13, 1): ClassMap({0: impl.data.ITEBitMap}),
533
- (0, 128, 154, 0, 0): ClassMap({0: impl.data.KPZGSMPingIP}),
534
- (0, 0, 128, (100, 101, 102, 103, 150, 151, 152, 170)): DataMap,
535
- (128, 0, tuple(range(20)), 0, 0): RegisterMap
538
+ ACDEgroup((0, 96, 11, 4)): ClassMap(impl.data.KPZSPODES3ExternalEvent),
539
+ ABCDEEgroup((0, 0, 97, 98, (0, 10, 20))): ClassMap(impl.data.KPZAlarm1),
540
+ ABCDEgroup((0, 128, 25, 6, 0)): ClassMap(impl.data.DataStatic),
541
+ ABCDEEgroup((0, 128, 96, 2, (0, 1, 2))): ClassMap(impl.data.KPZAFEOffsets),
542
+ ABCDEgroup((0, 128, 96, 13, 1)): ClassMap(impl.data.ITEBitMap),
543
+ ABCDEgroup((0, 128, 154, 0, 0)): ClassMap(impl.data.KPZGSMPingIP),
544
+ ACDEEgroup((0, 0, 128, (100, 101, 102, 103, 150, 151, 152, 170))): DataMap,
545
+ ABCCDEgroup((128, 0, tuple(range(20)), 0, 0)): RegisterMap
536
546
  })
537
- func_maps["KPZ"]: FUNC_MAP = get_func_map(__func_map_for_create)
547
+ func_maps["KPZ"] = get_func_map(__func_map_for_create)
538
548
  # KPZ1 with bag in log event profiles
539
549
  __func_map_for_create.update({
540
- (0, 96, 11, 0): ClassMap({0: impl.data.KPZ1SPODES3VoltageEvent}),
541
- (0, 96, 11, 1): ClassMap({0: impl.data.KPZ1SPODES3CurrentEvent}),
542
- (0, 96, 11, 2): ClassMap({0: impl.data.KPZ1SPODES3CommutationEvent}),
543
- (0, 96, 11, 3): ClassMap({0: impl.data.KPZ1SPODES3ProgrammingEvent}),
544
- (0, 96, 11, 4): ClassMap({0: impl.data.KPZ1SPODES3ExternalEvent}),
545
- (0, 96, 11, 5): ClassMap({0: impl.data.KPZ1SPODES3CommunicationEvent}),
546
- (0, 96, 11, 6): ClassMap({0: impl.data.KPZ1SPODES3AccessEvent}),
547
- (0, 96, 11, 7): ClassMap({0: impl.data.KPZ1SPODES3SelfDiagnosticEvent}),
548
- (0, 96, 11, 8): ClassMap({0: impl.data.KPZ1SPODES3ReactivePowerEvent}),
550
+ ACDEgroup((0, 96, 11, 0)): ClassMap(impl.data.KPZ1SPODES3VoltageEvent),
551
+ ACDEgroup((0, 96, 11, 1)): ClassMap(impl.data.KPZ1SPODES3CurrentEvent),
552
+ ACDEgroup((0, 96, 11, 2)): ClassMap(impl.data.KPZ1SPODES3CommutationEvent),
553
+ ACDEgroup((0, 96, 11, 3)): ClassMap(impl.data.KPZ1SPODES3ProgrammingEvent),
554
+ ACDEgroup((0, 96, 11, 4)): ClassMap(impl.data.KPZ1SPODES3ExternalEvent),
555
+ ACDEgroup((0, 96, 11, 5)): ClassMap(impl.data.KPZ1SPODES3CommunicationEvent),
556
+ ACDEgroup((0, 96, 11, 6)): ClassMap(impl.data.KPZ1SPODES3AccessEvent),
557
+ ACDEgroup((0, 96, 11, 7)): ClassMap(impl.data.KPZ1SPODES3SelfDiagnosticEvent),
558
+ ACDEgroup((0, 96, 11, 8)): ClassMap(impl.data.KPZ1SPODES3ReactivePowerEvent),
549
559
  })
550
- func_maps["KPZ1"]: FUNC_MAP = get_func_map(__func_map_for_create)
560
+ func_maps["KPZ1"] = get_func_map(__func_map_for_create)
551
561
 
552
562
 
553
563
  def get_type(class_id: ut.CosemClassId,
554
- version: cdt.Unsigned | None,
564
+ version: cdt.Unsigned,
555
565
  ln: cst.LogicalName,
556
566
  func_map: FUNC_MAP) -> Type[InterfaceClass]:
557
567
  """use DLMS UA 1000-1 Ed. 14 Table 54"""
558
- if (128 <= ln.b <= 199) or (128 <= ln.c <= 199) or ln.c == 240 or (128 <= ln.d <= 254) or (128 <= ln.e <= 254) or (128 <= ln.f <= 254):
568
+ c_m: Optional[dict[int, ClassMap]]
569
+ if (
570
+ (128 <= ln.b <= 199)
571
+ or (128 <= ln.c <= 199)
572
+ or ln.c == 240
573
+ or (128 <= ln.d <= 254)
574
+ or (128 <= ln.e <= 254)
575
+ or (128 <= ln.f <= 254)
576
+ ):
559
577
  # try search in ABCDE group for manufacture object before in CDE
560
578
  c_m = func_map.get(ln.contents[:5], common_interface_class_map)
561
579
  else:
562
580
  # try search in ABCDE group
563
581
  c_m = func_map.get(ln.contents[:5], None)
564
- if not c_m:
582
+ if c_m is None:
565
583
  # try search in A-CDE group
566
584
  c_m = func_map.get(ln.contents[:1]+ln.contents[2:5], None)
567
- if not c_m:
585
+ if c_m is None:
568
586
  # try search in A-CD group
569
587
  c_m = func_map.get(ln.contents[:1]+ln.contents[2:4], None)
570
- if not c_m:
588
+ if c_m is None:
571
589
  # try search in A-C group
572
590
  c_m = func_map.get(ln.contents[:1]+ln.contents[3:4], common_interface_class_map)
573
591
  return get_interface_class(class_map=c_m,
@@ -632,17 +650,17 @@ class ParameterValue:
632
650
  par: bytes
633
651
  value: bytes
634
652
 
635
- def __str__(self):
653
+ def __str__(self) -> str:
636
654
  return F"{'.'.join(map(str, self.par[:6]))}:{self.par[6]} - {cdt.get_instance_and_pdu_from_value(self.value)[0].__repr__()}"
637
655
 
638
- def __bytes__(self):
656
+ def __bytes__(self) -> bytes:
639
657
  """par + 0x00 + value""" # todo: 00 in future other parameters
640
658
  return self.par + b'\x00' + self.value
641
659
 
642
660
  @classmethod
643
661
  def parse(cls, value: bytes) -> Self:
644
662
  if value[7] != 0:
645
- raise exc.ITEApplication(F"wrong {value} for {cls.__name__}")
663
+ raise exc.ITEApplication(F"wrong {value!r} for {cls.__name__}")
646
664
  return cls(
647
665
  par=value[:7],
648
666
  value=value[8:]
@@ -658,9 +676,9 @@ class ID:
658
676
 
659
677
  class Collection:
660
678
  __id: ID
661
- __dlms_ver: int | None
662
- __country: CountrySpecificIdentifiers | None
663
- __country_ver: ParameterValue | None
679
+ __dlms_ver: int
680
+ __country: Optional[CountrySpecificIdentifiers]
681
+ __country_ver: Optional[ParameterValue]
664
682
  __objs: dict[o.OBIS, InterfaceClass]
665
683
  __const_objs: int
666
684
  spec_map: str
@@ -668,8 +686,8 @@ class Collection:
668
686
  def __init__(self,
669
687
  id_: ID,
670
688
  dlms_ver: int = 6,
671
- country: CountrySpecificIdentifiers = None,
672
- cntr_ver: ParameterValue = None):
689
+ country: Optional[CountrySpecificIdentifiers] = None,
690
+ cntr_ver: Optional[ParameterValue] = None):
673
691
  self.__id = id_
674
692
  self.__dlms_ver = dlms_ver
675
693
  self.__country = country
@@ -683,7 +701,7 @@ class Collection:
683
701
  def id(self) -> ID:
684
702
  return self.__id
685
703
 
686
- def set_id(self, value: ID):
704
+ def set_id(self, value: ID) -> None:
687
705
  if not self.__id:
688
706
  self.__id = value
689
707
  else:
@@ -692,15 +710,19 @@ class Collection:
692
710
  else:
693
711
  """success validation"""
694
712
 
695
- def __eq__(self, other: Self):
696
- return hash(self) == hash(other)
713
+ def __eq__(self, other: object) -> bool:
714
+ if isinstance(other, Collection):
715
+ return hash(self) == hash(other)
716
+ raise NotImplementedError
697
717
 
698
- def __hash__(self):
718
+ def __hash__(self) -> int:
699
719
  return hash(self.id)
700
720
 
701
- def copy_object_values(self, target: ic.COSEMInterfaceClasses, association_id: int = 3):
721
+ def copy_object_values(self, target: ic.COSEMInterfaceClasses, association_id: int = 3) -> None:
702
722
  """copy object values according by association. only needed"""
703
- source = self.get(target.logical_name.contents)
723
+ source = self.__objs.get(target.logical_name.contents, None)
724
+ if source is None:
725
+ raise RuntimeError(f"can't find {target}")
704
726
  for i, value in source.get_index_with_attributes():
705
727
  el = target.get_attr_element(i)
706
728
  if (
@@ -778,10 +800,10 @@ class Collection:
778
800
  return res
779
801
 
780
802
  @property
781
- def dlms_ver(self):
803
+ def dlms_ver(self) -> int:
782
804
  return self.__dlms_ver
783
805
 
784
- def set_dlms_ver(self, value: int):
806
+ def set_dlms_ver(self, value: int) -> None:
785
807
  if not self.__dlms_ver:
786
808
  self.__dlms_ver = value
787
809
  else:
@@ -791,7 +813,7 @@ class Collection:
791
813
  """success validation"""
792
814
 
793
815
  @property
794
- def country(self):
816
+ def country(self) -> Optional[CountrySpecificIdentifiers]:
795
817
  return self.__country
796
818
 
797
819
  def set_country(self, value: CountrySpecificIdentifiers):
@@ -817,7 +839,7 @@ class Collection:
817
839
  else:
818
840
  """success validation"""
819
841
 
820
- def __str__(self):
842
+ def __str__(self) -> str:
821
843
  return F"[{len(self.__objs)}] DLMS version: {self.__dlms_ver}, country: {self.__country}, country specific version: {self.__country_ver}, " \
822
844
  F"id: {self.id}, uses specification: {self.spec_map}"
823
845
 
@@ -1120,7 +1142,7 @@ class Collection:
1120
1142
  if isinstance(res1 := self.par2obj(par), result.Error):
1121
1143
  res1.append_err(res.err)
1122
1144
  else:
1123
- res.append(res1.value)
1145
+ res.append(res1)
1124
1146
  return res
1125
1147
 
1126
1148
  def iter_classID_objects(self,
@@ -1301,12 +1323,12 @@ class Collection:
1301
1323
 
1302
1324
  def get_script_names(self, ln: cst.LogicalName, selector: cdt.LongUnsigned) -> str:
1303
1325
  """return name from script by selector"""
1304
- obj = self.par2obj(Parameter(ln.contents))
1326
+ obj = self.par2obj(Parameter(ln.contents)).unwrap()
1305
1327
  if isinstance(obj, ScriptTable):
1306
1328
  for script in obj.scripts:
1307
1329
  script: ScriptTable.scripts
1308
1330
  if script.script_identifier == selector:
1309
- names: list[str] = list()
1331
+ names: list[str] = []
1310
1332
  for action in script.actions:
1311
1333
  action_obj = self.par2obj(Parameter(action.logical_name.contents)).unwrap()
1312
1334
  if int(action_obj.CLASS_ID) != int(action.class_id):
@@ -1631,7 +1653,7 @@ def get_sorted(objects: list[InterfaceClass],
1631
1653
  mode: SortMode) -> list[InterfaceClass]:
1632
1654
  """mode: l-logical_name, n-name, c-class_id
1633
1655
  """
1634
- mode = list(mode)
1656
+ mode: list[str] = list(mode)
1635
1657
  while mode:
1636
1658
  match mode.pop():
1637
1659
  case "l":
@@ -1650,7 +1672,7 @@ class Channel:
1650
1672
  """for object filter approve"""
1651
1673
  n: int
1652
1674
 
1653
- def __post_init__(self):
1675
+ def __post_init__(self) -> None:
1654
1676
  if not self.is_channel(self.n):
1655
1677
  raise ValueError(F"got value={self.n}, expected (0..64)")
1656
1678