DLMS-SPODES 0.87.3__py3-none-any.whl → 0.87.5__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
 
@@ -330,6 +330,7 @@ class COSEMInterfaceClasses(Protocol):
330
330
  __specific_methods: tuple[cdt.CommonDataType, ...] = None
331
331
  _cbs_attr_post_init: dict[int, Callable]
332
332
  collection: Any | None # Collection. todo: remove in future
333
+ hash_: int
333
334
 
334
335
  def __init__(self, logical_name: cst.LogicalName | bytes | str):
335
336
  self.collection = None
@@ -302,6 +302,15 @@ class KPZAlarm1(DataStatic):
302
302
  A_ELEMENTS = DataStatic.get_attr_element(2).get_change(data_type=KPZAlarm1Values),
303
303
 
304
304
 
305
+ class SPODES3ControlAlarm1Values(cdt.IntegerFlag, cdt.DoubleLongUnsigned):
306
+ ...
307
+
308
+
309
+ class SPODES3ControlAlarm1(DataDynamic):
310
+ """СТО 34.01-5.1-006-2023v4 Таблица 13.5 Распределение событий отключения реле нагрузки по битам"""
311
+ A_ELEMENTS = DataNotSpecific.get_attr_element(2).get_change(data_type=SPODES3ControlAlarm1Values),
312
+
313
+
305
314
  class SPODES3PowerQuality1Event(DataNotSpecific):
306
315
  """СТО_34.01-5.1-006-2019v3 E.1 Статус качества сети (журнал качества сети)"""
307
316
  A_ELEMENTS = DataNotSpecific.get_attr_element(2).get_change(data_type=SPODES3PowerQuality1EventValues),
DLMS_SPODES/pardata.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from .cosem_interface_classes import Parameter
2
+ from .cosem_interface_classes.parameter import Parameter
3
3
  from typing import Optional, Iterator
4
4
  from .types import cdt
5
5
 
@@ -9,14 +9,6 @@ class ParValues[T]:
9
9
  par: Parameter
10
10
  data: T
11
11
 
12
- def __getitem__(self, item):
13
- if item == 0:
14
- return self.par
15
- elif item == 1:
16
- return self.data
17
- else:
18
- raise StopIteration
19
-
20
12
  def __iter__(self) -> Iterator[Parameter | T]:
21
13
  yield self.par
22
14
  yield self.data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DLMS_SPODES
3
- Version: 0.87.3
3
+ Version: 0.87.5
4
4
  Summary: dlms-spodes
5
5
  Author-email: Serj Kotilevski <youserj@outlook.com>
6
6
  Project-URL: Source, https://github.com/youserj/DlmsSPODES-project
@@ -6,7 +6,7 @@ DLMS_SPODES/enums.py,sha256=13BE0owOyJBNlOI4NY1d-kpqVoHF7JPR9brkPKHLERE,17789
6
6
  DLMS_SPODES/exceptions.py,sha256=UBZRQlQIRi1CzRxWTeqX5PVNuFS770f77BAizQ99IDU,3006
7
7
  DLMS_SPODES/firmwares.py,sha256=lFRnxtq4joYhpZPxHD8Pv30-GvgcEfZCDZUYo_pIeQU,3850
8
8
  DLMS_SPODES/literals.py,sha256=5u6hreLSXgmN7Z_5pXchyBKsuPYJ5deqxKHqewQEFoI,1632
9
- DLMS_SPODES/pardata.py,sha256=yktr4g59FITC_L1kRbQuwp0PMQvGdMwXqWxpXcCDpQU,700
9
+ DLMS_SPODES/pardata.py,sha256=_VluNrP4R7PLVXa9xmqD7fiqEXQqyVXp48NieTct5jY,519
10
10
  DLMS_SPODES/pdu_enums.py,sha256=5xiV-tZTPXOcHT8XQcHWrwAMKTOmCH09Sk4iL1N7I3c,2276
11
11
  DLMS_SPODES/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  DLMS_SPODES/relation_to_OBIS.py,sha256=KcSMIQ_5amjeT0Lya3HbYoaDdz_BjZC2JLVhl2nffwo,32761
@@ -25,8 +25,8 @@ DLMS_SPODES/cosem_interface_classes/activity_calendar.py,sha256=VWSiKn2LNBA1VLAA
25
25
  DLMS_SPODES/cosem_interface_classes/arbitrator.py,sha256=S9TguoMG6O5DpMBp6mpcJpw6PHanvh4SEAN3M_v6qts,3240
26
26
  DLMS_SPODES/cosem_interface_classes/attr_indexes.py,sha256=aUSnT-dKoBsDbwLhlgtLIHGRl7PZrT-ld2ThCEUjUeA,328
27
27
  DLMS_SPODES/cosem_interface_classes/clock.py,sha256=9OJwRGrbFPws_VZPayHv-hzFJegIcjgoJoenIqofd5w,4525
28
- DLMS_SPODES/cosem_interface_classes/collection.py,sha256=3ivTtIv2dCanGsXqBbvcuoNqRm211S523DeZvN9dwuU,96317
29
- DLMS_SPODES/cosem_interface_classes/cosem_interface_class.py,sha256=SIME0IC1XyX9RSsfxt0cbghN7rCyWzjqCbesQEpTCM8,23347
28
+ DLMS_SPODES/cosem_interface_classes/collection.py,sha256=4zafwek9zuWPLlpOZqZ0-uC7z2X-IhsVC5kCUaxhEmY,98545
29
+ DLMS_SPODES/cosem_interface_classes/cosem_interface_class.py,sha256=pY3UoW7XVV2TJ5cjphKsQZnngA8Q9S6TsjjZnMDLKb4,23363
30
30
  DLMS_SPODES/cosem_interface_classes/data.py,sha256=YSjA3Y0M5NMcfYzWPEuZw6ojIqr2UghgW_ck8dXySMU,809
31
31
  DLMS_SPODES/cosem_interface_classes/disconnect_control.py,sha256=CIx7I4QRpPxAC5iYxpbhCIuv6U2P3s6ELam8eD-kD5w,2926
32
32
  DLMS_SPODES/cosem_interface_classes/extended_register.py,sha256=xULCS11YVWjFMoaRUrm4whvH39Gx0Cu6breUos_oLCs,1153
@@ -72,7 +72,7 @@ DLMS_SPODES/cosem_interface_classes/image_transfer/image_transfer_status.py,sha2
72
72
  DLMS_SPODES/cosem_interface_classes/image_transfer/ver0.py,sha256=rnHj2XnK1Zr4CvPG_MrPSoBBcdh883rwqdIus1RxKMw,5371
73
73
  DLMS_SPODES/cosem_interface_classes/implementations/__init__.py,sha256=z4OfnPPyYr6f94rj-PU3---Wk05ddduf9MkmWxhczXA,77
74
74
  DLMS_SPODES/cosem_interface_classes/implementations/arbitrator.py,sha256=cMhYLi9ZFqfJ0yxjONHq9JZZJ3QuzrF0jtPjk4nf0eo,573
75
- DLMS_SPODES/cosem_interface_classes/implementations/data.py,sha256=zyhnnJ-9erdj2rZ28ZjtP7rHH704yuUkqdvJAafvaQs,18598
75
+ DLMS_SPODES/cosem_interface_classes/implementations/data.py,sha256=PCa_exj-y0WFt5gVTZQvIpI1wNTqTFc6ZoUSmLKz1Ys,19001
76
76
  DLMS_SPODES/cosem_interface_classes/implementations/profile_generic.py,sha256=oibO3EV9fRHxxaBdMQqz436GrMMqo1BlT6lgVtzUKU0,4318
77
77
  DLMS_SPODES/cosem_interface_classes/modem_configuration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  DLMS_SPODES/cosem_interface_classes/modem_configuration/ver0.py,sha256=nFU3Y0fFhsOKfSl21TmA1CaWJo-N9Iqm7XlcGuSSjoQ,3071
@@ -96,7 +96,6 @@ DLMS_SPODES/hdlc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
96
96
  DLMS_SPODES/hdlc/frame.py,sha256=ar5DvkPK5tUGSZcQYCpeku1Ansx7QecugvmcV-xekqI,34784
97
97
  DLMS_SPODES/hdlc/sub_layer.py,sha256=zTxe5ddTt8tliFSY145HhluLwIh57gvOG19Mc8-vnEM,2147
98
98
  DLMS_SPODES/obis/__init__.py,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
99
- DLMS_SPODES/obis/abstract_objects.py,sha256=0ZoJKRQ_7FoChC2rNSgNV573hso8JYZQKdLF3Wgaoqw,443
100
99
  DLMS_SPODES/obis/media_id.py,sha256=GRiwHPe9-3iCg4u_J6qf2rMc3Wjw0aJHKiSnBtNYD3o,22339
101
100
  DLMS_SPODES/types/__init__.py,sha256=UFiP4suA72o_kvaqUnHLGK-cedDXLl8kVHYsjXHYUDw,116
102
101
  DLMS_SPODES/types/choices.py,sha256=z7IasrlRaagOYNfRvgbpojDxf1jgYUc9cz59PH2PMi0,6350
@@ -112,7 +111,7 @@ DLMS_SPODES/types/implementations/integers.py,sha256=Asy4X260t1Fzw_V5iw0uiDOxtfB
112
111
  DLMS_SPODES/types/implementations/long_unsigneds.py,sha256=SxmFvD2moQ03p-KZSBYK1Rv7bQSaywlHVXBfkTZG1OQ,8761
113
112
  DLMS_SPODES/types/implementations/octet_string.py,sha256=Jo_sfWcsfstiP4O6mXfBOOQlksx1c2qJMI-vbAOV-yM,294
114
113
  DLMS_SPODES/types/implementations/structs.py,sha256=GMOo6Jy8jA9d6KTLs0D-j5t0oSRvxUIwtBr_4UePwbA,2059
115
- dlms_spodes-0.87.3.dist-info/METADATA,sha256=ANlxJv9tqVDNQ2qtmssUfyu_kFHEl4V8FglWBADITRQ,1027
116
- dlms_spodes-0.87.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
117
- dlms_spodes-0.87.3.dist-info/top_level.txt,sha256=k26SRuRdwBZrSM3NgNZECAUNIDZREbJuLCnPbWtTNak,12
118
- dlms_spodes-0.87.3.dist-info/RECORD,,
114
+ dlms_spodes-0.87.5.dist-info/METADATA,sha256=dqBhrE-dP748FIQpNtLEBN5seqiaVed7N6t-x44BfVU,1027
115
+ dlms_spodes-0.87.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
116
+ dlms_spodes-0.87.5.dist-info/top_level.txt,sha256=k26SRuRdwBZrSM3NgNZECAUNIDZREbJuLCnPbWtTNak,12
117
+ dlms_spodes-0.87.5.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- """DLMS UA 1000-1 Ed. 14. 7.4 Abstract objects (Value group A = 0)"""
2
- from struct import pack_into
3
- from ..types import cst
4
-
5
-
6
- _buf = bytearray(6)
7
-
8
-
9
- def BILLING_PERIOD_COUNTER(b: int = 0, f: int = 255):
10
- return cst.LogicalName(bytes((0, b, 0, 1, 0, f)))
11
-
12
-
13
- def SPODES3_DISPLAY_MODE():
14
- return cst.LogicalName(pack_into(">6B", _buf, 0, 0, 96, 4, 1, 255))
15
-
16
-
17
- LDN = cst.LogicalName(pack_into(">6B", _buf, 0, 0, 42, 0, 0, 255))