DLMS-SPODES 0.87.2__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.
- DLMS_SPODES/cosem_interface_classes/collection.py +389 -367
- DLMS_SPODES/cosem_interface_classes/cosem_interface_class.py +1 -0
- DLMS_SPODES/cosem_interface_classes/implementations/data.py +9 -0
- DLMS_SPODES/cosem_interface_classes/parameters.py +73 -2
- DLMS_SPODES/cosem_interface_classes/reports.py +42 -44
- DLMS_SPODES/pardata.py +1 -9
- {dlms_spodes-0.87.2.dist-info → dlms_spodes-0.87.5.dist-info}/METADATA +1 -1
- {dlms_spodes-0.87.2.dist-info → dlms_spodes-0.87.5.dist-info}/RECORD +10 -11
- DLMS_SPODES/obis/abstract_objects.py +0 -17
- {dlms_spodes-0.87.2.dist-info → dlms_spodes-0.87.5.dist-info}/WHEEL +0 -0
- {dlms_spodes-0.87.2.dist-info → dlms_spodes-0.87.5.dist-info}/top_level.txt +0 -0
|
@@ -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
|
|
101
|
-
def __hash__(self):
|
|
102
|
-
return hash(tuple(it.hash_ for it in self.values()))
|
|
100
|
+
class ClassMap:
|
|
103
101
|
|
|
104
|
-
def
|
|
105
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
223
|
+
def _create_map(maps: ClassMap | tuple[ClassMap]) -> dict[int, ClassMap]:
|
|
287
224
|
if isinstance(maps, tuple):
|
|
288
|
-
return {int(map_
|
|
225
|
+
return {int(map_.get(0).CLASS_ID): map_ for map_ in maps}
|
|
289
226
|
else:
|
|
290
|
-
return {int(
|
|
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
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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] =
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
ret: FUNC_MAP =
|
|
313
|
-
for
|
|
314
|
-
|
|
315
|
-
|
|
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[
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
(
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
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(
|
|
487
|
-
(0, 96, 1, 6): ClassMap(
|
|
488
|
-
(0, 96, 2, (1, 2, 3, 5, 6, 7, 11, 12)): ClassMap(
|
|
489
|
-
(0, 96, 3, 20): ClassMap(
|
|
490
|
-
(0, 96, 4, 3): ClassMap(
|
|
491
|
-
(0, 96, 5, 1): ClassMap(
|
|
492
|
-
(0, 96, 5, 4): ClassMap(
|
|
493
|
-
(0, 96, 5, 132): ClassMap(
|
|
494
|
-
(0, 96, 11, 0): ClassMap(
|
|
495
|
-
(0, 96, 11, 1): ClassMap(
|
|
496
|
-
(0, 96, 11, 2): ClassMap(
|
|
497
|
-
(0, 96, 11, 3): ClassMap(
|
|
498
|
-
(0, 96, 11, 4): ClassMap(
|
|
499
|
-
(0, 96, 11, 5): ClassMap(
|
|
500
|
-
(0, 96, 11, 6): ClassMap(
|
|
501
|
-
(0, 96, 11, 7): ClassMap(
|
|
502
|
-
(0, 96, 11, 8): ClassMap(
|
|
503
|
-
(0, 0, 96, 51, 0): ClassMap(
|
|
504
|
-
(0, 0, 96, 51, 1): ClassMap(
|
|
505
|
-
(0, 0, 96, 51, 3): ClassMap(
|
|
506
|
-
(0, 0, 96, 51, 4): ClassMap(
|
|
507
|
-
(0, 0, 96, 51, 5): ClassMap(
|
|
508
|
-
(0, 0, 96, 51, (6, 7)): UnsignedDataMap,
|
|
509
|
-
(0, 0, 96, 51, (8, 9)): ClassMap(
|
|
510
|
-
(0, 0, 97, 98, (0, 10, 20)): ClassMap(
|
|
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(
|
|
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(
|
|
529
|
-
(0, 0, 97, 98, (0, 10, 20)): ClassMap(
|
|
530
|
-
(0, 128, 25, 6, 0): ClassMap(
|
|
531
|
-
(0, 128, 96, 2, (0, 1, 2)): ClassMap(
|
|
532
|
-
(0, 128, 96, 13, 1): ClassMap(
|
|
533
|
-
(0, 128, 154, 0, 0): ClassMap(
|
|
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"]
|
|
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(
|
|
541
|
-
(0, 96, 11, 1): ClassMap(
|
|
542
|
-
(0, 96, 11, 2): ClassMap(
|
|
543
|
-
(0, 96, 11, 3): ClassMap(
|
|
544
|
-
(0, 96, 11, 4): ClassMap(
|
|
545
|
-
(0, 96, 11, 5): ClassMap(
|
|
546
|
-
(0, 96, 11, 6): ClassMap(
|
|
547
|
-
(0, 96, 11, 7): ClassMap(
|
|
548
|
-
(0, 96, 11, 8): ClassMap(
|
|
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"]
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
662
|
-
__country: CountrySpecificIdentifiers
|
|
663
|
-
__country_ver: ParameterValue
|
|
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:
|
|
696
|
-
|
|
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
|
|
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] =
|
|
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
|
|