DLMS-SPODES 0.87.17__py3-none-any.whl → 0.88.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- DLMS_SPODES/Values/EN/__init__.py +1 -1
- DLMS_SPODES/Values/EN/actors.py +8 -8
- DLMS_SPODES/Values/EN/relation_to_obis_names.py +387 -387
- DLMS_SPODES/Values/RU/__init__.py +1 -1
- DLMS_SPODES/Values/RU/actors.py +8 -8
- DLMS_SPODES/Values/RU/relation_to_obis_names.py +396 -396
- DLMS_SPODES/__init__.py +6 -6
- DLMS_SPODES/configEN.ini +126 -126
- DLMS_SPODES/config_parser.py +53 -53
- DLMS_SPODES/cosem_interface_classes/Overview/__init__.py +0 -0
- DLMS_SPODES/cosem_interface_classes/Overview/class_id.py +107 -0
- DLMS_SPODES/cosem_interface_classes/__class_init__.py +3 -3
- DLMS_SPODES/cosem_interface_classes/__init__.py +3 -2
- DLMS_SPODES/cosem_interface_classes/activity_calendar.py +210 -254
- DLMS_SPODES/cosem_interface_classes/arbitrator.py +78 -105
- DLMS_SPODES/cosem_interface_classes/association_ln/abstract.py +50 -34
- DLMS_SPODES/cosem_interface_classes/association_ln/authentication_mechanism_name.py +25 -25
- DLMS_SPODES/cosem_interface_classes/association_ln/mechanism_id.py +25 -25
- DLMS_SPODES/cosem_interface_classes/association_ln/method.py +5 -5
- DLMS_SPODES/cosem_interface_classes/association_ln/ver0.py +440 -485
- DLMS_SPODES/cosem_interface_classes/association_ln/ver1.py +126 -133
- DLMS_SPODES/cosem_interface_classes/association_ln/ver2.py +30 -36
- DLMS_SPODES/cosem_interface_classes/association_ln/ver3.py +3 -4
- DLMS_SPODES/cosem_interface_classes/association_sn/ver0.py +14 -12
- DLMS_SPODES/cosem_interface_classes/clock.py +81 -131
- DLMS_SPODES/cosem_interface_classes/collection.py +2106 -2122
- DLMS_SPODES/cosem_interface_classes/cosem_interface_class.py +525 -583
- DLMS_SPODES/cosem_interface_classes/data.py +12 -21
- DLMS_SPODES/cosem_interface_classes/demand_register/ver0.py +32 -59
- DLMS_SPODES/cosem_interface_classes/disconnect_control.py +56 -74
- DLMS_SPODES/cosem_interface_classes/extended_register.py +18 -27
- DLMS_SPODES/cosem_interface_classes/gprs_modem_setup.py +33 -43
- DLMS_SPODES/cosem_interface_classes/gsm_diagnostic/ver0.py +78 -103
- DLMS_SPODES/cosem_interface_classes/gsm_diagnostic/ver1.py +42 -40
- DLMS_SPODES/cosem_interface_classes/gsm_diagnostic/ver2.py +6 -9
- DLMS_SPODES/cosem_interface_classes/iec_hdlc_setup/ver0.py +11 -11
- DLMS_SPODES/cosem_interface_classes/iec_hdlc_setup/ver1.py +27 -53
- DLMS_SPODES/cosem_interface_classes/iec_local_port_setup.py +9 -11
- DLMS_SPODES/cosem_interface_classes/image_transfer/image_transfer_status.py +15 -15
- DLMS_SPODES/cosem_interface_classes/image_transfer/ver0.py +54 -126
- DLMS_SPODES/cosem_interface_classes/implementations/__init__.py +3 -3
- DLMS_SPODES/cosem_interface_classes/implementations/arbitrator.py +19 -19
- DLMS_SPODES/cosem_interface_classes/implementations/data.py +491 -487
- DLMS_SPODES/cosem_interface_classes/implementations/profile_generic.py +85 -83
- DLMS_SPODES/cosem_interface_classes/ipv4_setup.py +42 -72
- DLMS_SPODES/cosem_interface_classes/limiter.py +77 -111
- DLMS_SPODES/cosem_interface_classes/ln_pattern.py +334 -333
- DLMS_SPODES/cosem_interface_classes/modem_configuration/ver0.py +51 -65
- DLMS_SPODES/cosem_interface_classes/modem_configuration/ver1.py +27 -39
- DLMS_SPODES/cosem_interface_classes/ntp_setup/ver0.py +48 -67
- DLMS_SPODES/cosem_interface_classes/obis.py +28 -23
- DLMS_SPODES/cosem_interface_classes/overview.py +198 -197
- DLMS_SPODES/cosem_interface_classes/parameter.py +548 -547
- DLMS_SPODES/cosem_interface_classes/parameters.py +172 -172
- DLMS_SPODES/cosem_interface_classes/profile_generic/ver0.py +90 -133
- DLMS_SPODES/cosem_interface_classes/profile_generic/ver1.py +268 -277
- DLMS_SPODES/cosem_interface_classes/push_setup/ver0.py +13 -12
- DLMS_SPODES/cosem_interface_classes/push_setup/ver1.py +9 -10
- DLMS_SPODES/cosem_interface_classes/push_setup/ver2.py +124 -166
- DLMS_SPODES/cosem_interface_classes/register.py +18 -45
- DLMS_SPODES/cosem_interface_classes/register_activation/ver0.py +45 -80
- DLMS_SPODES/cosem_interface_classes/register_monitor.py +33 -46
- DLMS_SPODES/cosem_interface_classes/reports.py +72 -70
- DLMS_SPODES/cosem_interface_classes/schedule.py +88 -176
- DLMS_SPODES/cosem_interface_classes/script_table.py +54 -87
- DLMS_SPODES/cosem_interface_classes/security_setup/ver0.py +45 -68
- DLMS_SPODES/cosem_interface_classes/security_setup/ver1.py +122 -158
- DLMS_SPODES/cosem_interface_classes/single_action_schedule.py +34 -50
- DLMS_SPODES/cosem_interface_classes/special_days_table.py +54 -84
- DLMS_SPODES/cosem_interface_classes/tcp_udp_setup.py +20 -42
- DLMS_SPODES/cosem_pdu.py +93 -93
- DLMS_SPODES/enums.py +625 -625
- DLMS_SPODES/exceptions.py +106 -106
- DLMS_SPODES/firmwares.py +99 -99
- DLMS_SPODES/hdlc/frame.py +875 -875
- DLMS_SPODES/hdlc/sub_layer.py +54 -54
- DLMS_SPODES/literals.py +17 -17
- DLMS_SPODES/obis/__init__.py +1 -1
- DLMS_SPODES/obis/media_id.py +931 -931
- DLMS_SPODES/pardata.py +22 -22
- DLMS_SPODES/pdu_enums.py +98 -98
- DLMS_SPODES/relation_to_OBIS.py +463 -465
- DLMS_SPODES/settings.py +551 -551
- DLMS_SPODES/types/choices.py +140 -142
- DLMS_SPODES/types/common_data_types.py +2379 -2401
- DLMS_SPODES/types/cosem_service_types.py +109 -109
- DLMS_SPODES/types/implementations/arrays.py +25 -25
- DLMS_SPODES/types/implementations/bitstrings.py +97 -97
- DLMS_SPODES/types/implementations/double_long_usingneds.py +35 -35
- DLMS_SPODES/types/implementations/enums.py +57 -57
- DLMS_SPODES/types/implementations/integers.py +12 -11
- DLMS_SPODES/types/implementations/long_unsigneds.py +127 -127
- DLMS_SPODES/types/implementations/octet_string.py +11 -11
- DLMS_SPODES/types/implementations/structs.py +64 -64
- DLMS_SPODES/types/type_alias.py +74 -0
- DLMS_SPODES/types/useful_types.py +627 -677
- {dlms_spodes-0.87.17.dist-info → dlms_spodes-0.88.1.dist-info}/METADATA +30 -30
- dlms_spodes-0.88.1.dist-info/RECORD +118 -0
- {dlms_spodes-0.87.17.dist-info → dlms_spodes-0.88.1.dist-info}/WHEEL +1 -1
- DLMS_SPODES/cosem_interface_classes/a_parameter.py +0 -20
- DLMS_SPODES/cosem_interface_classes/attr_indexes.py +0 -12
- dlms_spodes-0.87.17.dist-info/RECORD +0 -117
- {dlms_spodes-0.87.17.dist-info → dlms_spodes-0.88.1.dist-info}/top_level.txt +0 -0
|
@@ -1,70 +1,72 @@
|
|
|
1
|
-
from typing import Any, Iterable
|
|
2
|
-
from StructResult import result
|
|
3
|
-
from . import cosem_interface_class as ic
|
|
4
|
-
from ..types import cdt
|
|
5
|
-
from .parameter import Parameter
|
|
6
|
-
from ..cosem_interface_classes import collection
|
|
7
|
-
from ..config_parser import get_values
|
|
8
|
-
from ..settings import settings
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def from_obj(
|
|
12
|
-
col: collection.Collection,
|
|
13
|
-
obj: ic.
|
|
14
|
-
attr_index_par: tuple[int, ...]
|
|
15
|
-
) -> result.SimpleOrError[str]:
|
|
16
|
-
if not hasattr(from_obj, "struct_pattern"):
|
|
17
|
-
from_obj.struct_pattern = dict(settings.report.struct)
|
|
18
|
-
ret: str = F"[{collection.get_name(obj.logical_name)}]\n"
|
|
19
|
-
for i in attr_index_par:
|
|
20
|
-
par = Parameter(obj.logical_name.contents).set_i(i)
|
|
21
|
-
if isinstance(res_data := col.par2data(par), result.Error):
|
|
22
|
-
return res_data
|
|
23
|
-
a_data = res_data.value
|
|
24
|
-
if isinstance(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
ret += F"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if isinstance(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
case "
|
|
54
|
-
result_ += str(data[index])
|
|
55
|
-
case
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
ret +=
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
1
|
+
from typing import Any, Iterable
|
|
2
|
+
from StructResult import result
|
|
3
|
+
from . import cosem_interface_class as ic
|
|
4
|
+
from ..types import cdt
|
|
5
|
+
from .parameter import Parameter
|
|
6
|
+
from ..cosem_interface_classes import collection
|
|
7
|
+
from ..config_parser import get_values
|
|
8
|
+
from ..settings import settings
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def from_obj(
|
|
12
|
+
col: collection.Collection,
|
|
13
|
+
obj: ic.IC,
|
|
14
|
+
attr_index_par: tuple[int, ...]
|
|
15
|
+
) -> result.SimpleOrError[str]:
|
|
16
|
+
if not hasattr(from_obj, "struct_pattern"):
|
|
17
|
+
from_obj.struct_pattern = dict(settings.report.struct)
|
|
18
|
+
ret: str = F"[{collection.get_name(obj.logical_name)}]\n"
|
|
19
|
+
for i in attr_index_par:
|
|
20
|
+
par = Parameter(obj.logical_name.contents).set_i(i)
|
|
21
|
+
if isinstance(res_data := col.par2data(par), result.Error):
|
|
22
|
+
return res_data
|
|
23
|
+
a_data = res_data.value
|
|
24
|
+
if isinstance(res_a_el := obj.getAElement(i), result.Error):
|
|
25
|
+
return res_a_el
|
|
26
|
+
if isinstance(a_data, cdt.SimpleDataType):
|
|
27
|
+
rep = col.par2rep(par, a_data)
|
|
28
|
+
ret += F" {res_a_el.value}: {rep.msg}{f" {rep.unit}" if rep.unit else ""}\n"
|
|
29
|
+
elif isinstance(a_data, cdt.ComplexDataType):
|
|
30
|
+
ret += F" [{res_a_el.value}]\n"
|
|
31
|
+
stack: list[tuple[Any, Any]] = [("", iter(a_data))]
|
|
32
|
+
while stack:
|
|
33
|
+
name, value_it = stack[-1]
|
|
34
|
+
indent = F"{' ' * (len(stack) + 1)}"
|
|
35
|
+
data = next(value_it, None)
|
|
36
|
+
if data:
|
|
37
|
+
if not isinstance(name, str):
|
|
38
|
+
name = str(next(name))
|
|
39
|
+
if isinstance(data, cdt.Array):
|
|
40
|
+
ret += F"{indent}[{name}]\n"
|
|
41
|
+
stack.append(("*", iter(data)))
|
|
42
|
+
elif isinstance(data, cdt.Structure):
|
|
43
|
+
if (pattern := from_obj.struct_pattern.get(data.__class__.__name__)):
|
|
44
|
+
val = list(pattern)
|
|
45
|
+
val.reverse()
|
|
46
|
+
result_ = str()
|
|
47
|
+
while val:
|
|
48
|
+
match val.pop():
|
|
49
|
+
case "%":
|
|
50
|
+
par_ = val.pop()
|
|
51
|
+
index = int(val.pop() + val.pop())
|
|
52
|
+
match par_:
|
|
53
|
+
case "n":
|
|
54
|
+
result_ += str(data.ELEMENTS[index])
|
|
55
|
+
case "v":
|
|
56
|
+
result_ += str(data[index])
|
|
57
|
+
case err:
|
|
58
|
+
raise ValueError(F"unknown macros &{err}{index}")
|
|
59
|
+
case symbol:
|
|
60
|
+
result_ += symbol
|
|
61
|
+
ret += F"{indent}{result_}\n"
|
|
62
|
+
else:
|
|
63
|
+
if name == "":
|
|
64
|
+
ret += "\n"
|
|
65
|
+
else:
|
|
66
|
+
ret += F"{indent}[{name}]\n"
|
|
67
|
+
stack.append((iter(data.ELEMENTS), iter(data)))
|
|
68
|
+
else:
|
|
69
|
+
ret += F"{indent}{name}: {data}\n"
|
|
70
|
+
else:
|
|
71
|
+
stack.pop()
|
|
72
|
+
return result.Simple(ret)
|
|
@@ -1,176 +1,88 @@
|
|
|
1
|
-
from typing import Callable, Self
|
|
2
|
-
from
|
|
3
|
-
from .
|
|
4
|
-
from
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
ret
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
for schedule_table_entry
|
|
57
|
-
|
|
58
|
-
schedule_table_entry
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Schedule:
|
|
90
|
-
|
|
91
|
-
Index | enable | action | Switch_time | validity_window | exec_weekdays | exec_specdays | date range
|
|
92
|
-
| |(script)| | | Mo Tu We Th Fr Sa Su | S1 S2 ... S8 S9 | begin_date | end_date
|
|
93
|
-
120 Yes xxxx:yy 06:00 0xFFFF x x x x x x xx-04-01 xx-09-30
|
|
94
|
-
121 Yes xxxx:yy 22:00 15 x x x x x xx-04-01 xx-09-30
|
|
95
|
-
122 Yes xxxx:yy 12:00 0 x xx-04-01 xx-09-30
|
|
96
|
-
200 No xxxx:yy 06:30 x x x x x x xx-04-01 xx-09-30
|
|
97
|
-
201 No xxxx:yy 21:30 x x x x x xx-04-01 xx-09-30
|
|
98
|
-
202 No xxxx:yy 11:00 x xx-04-01 xx-09-30
|
|
99
|
-
|
|
100
|
-
Special days table:
|
|
101
|
-
|
|
102
|
-
Index | special_day_date | day_id
|
|
103
|
-
12 xx-12-24 S1
|
|
104
|
-
33 xx-12-25 S3
|
|
105
|
-
77 97-03-31 S3
|
|
106
|
-
|
|
107
|
-
Recovery after power failure
|
|
108
|
-
After a power failure, the whole schedule is processed to execute all the necessary scripts that would get lost during a power failure. For this,
|
|
109
|
-
the entries that were not executed during the power failure must be detected. Depending on the validity window attribute they are executed in
|
|
110
|
-
the correct order (as they would have been executed in normal operation).
|
|
111
|
-
|
|
112
|
-
Handling of time changes
|
|
113
|
-
There are four different "actions" of time changes:
|
|
114
|
-
a) time setting forward; b) time setting backwards; c) time synchronization; d) daylight saving action.
|
|
115
|
-
All these four actions need a different handling executed by the schedule in interaction with the time setting activity.
|
|
116
|
-
|
|
117
|
-
Time setting forward*
|
|
118
|
-
This is handled the same way as a power failure. All entries missed are executed depending on the validity window attribute.
|
|
119
|
-
A (manufacturer specific defined) short time setting can be handled like time synchronization.
|
|
120
|
-
* Writing to the attribute “time” of the “Clock” object.
|
|
121
|
-
|
|
122
|
-
Time setting backward*
|
|
123
|
-
This results in a repetition of those entries that are activated during the repeated time. A (manufacturer specific defined) short time setting
|
|
124
|
-
can be handled like time synchronization.
|
|
125
|
-
* Writing to the attribute “time” of the “Clock” object.
|
|
126
|
-
|
|
127
|
-
Time synchronization*
|
|
128
|
-
Time synchronization is used to correct small deviations between a master clock and the local clock. The algorithm is manufacturer specific.
|
|
129
|
-
It shall guarantee that no entry of the schedule gets lost, or is executed twice. The validity window attribute has no effect, because all
|
|
130
|
-
entries must be executed in normal operation.
|
|
131
|
-
* Using the method “adjust_to_quarter” of the “Clock” object.
|
|
132
|
-
|
|
133
|
-
Daylight saving
|
|
134
|
-
If the clock is put forward, then all scripts, which fall into the forwarding interval (and would therefore get lost) are executed.
|
|
135
|
-
If the clock is put back, re-execution of the scripts, which fall into the backwarding interval is suppressed. """
|
|
136
|
-
CLASS_ID = ClassID.SCHEDULE
|
|
137
|
-
VERSION = VERSION_0
|
|
138
|
-
A_ELEMENTS = ic.ICAElement("entries", Entries),
|
|
139
|
-
M_ELEMENTS = (ic.ICMElement("enable_disable", DataED),
|
|
140
|
-
ic.ICMElement("insert", ScheduleTableEntry),
|
|
141
|
-
ic.ICMElement("delete", DataDelete))
|
|
142
|
-
|
|
143
|
-
def characteristics_init(self):
|
|
144
|
-
self.set_attr(2, None)
|
|
145
|
-
self._cbs_attr_post_init.update({2: self.__set_index_cbs})
|
|
146
|
-
|
|
147
|
-
@property
|
|
148
|
-
def entries(self) -> Entries:
|
|
149
|
-
return self.get_attr(2)
|
|
150
|
-
|
|
151
|
-
@property
|
|
152
|
-
def enable_disable(self) -> DataED:
|
|
153
|
-
return self.get_meth(1)
|
|
154
|
-
|
|
155
|
-
@property
|
|
156
|
-
def insert(self) -> ScheduleTableEntry:
|
|
157
|
-
return self.get_meth(2)
|
|
158
|
-
|
|
159
|
-
@property
|
|
160
|
-
def delete(self) -> DataDelete:
|
|
161
|
-
return self.get_meth(3)
|
|
162
|
-
|
|
163
|
-
def __set_index_cbs(self):
|
|
164
|
-
""" set callbacks to methods """
|
|
165
|
-
try:
|
|
166
|
-
indexes: Callable = self.entries.get_indexes
|
|
167
|
-
self.enable_disable.firstIndexA.set_callback(indexes)
|
|
168
|
-
self.enable_disable.firstIndexB.set_callback(indexes)
|
|
169
|
-
self.enable_disable.lastIndexA.set_callback(indexes)
|
|
170
|
-
self.enable_disable.lastIndexB.set_callback(indexes)
|
|
171
|
-
self.insert.index.set_callback(indexes)
|
|
172
|
-
self.delete.firstIndex.set_callback(indexes)
|
|
173
|
-
self.delete.lastIndex.set_callback(indexes)
|
|
174
|
-
# print('set delete')
|
|
175
|
-
except KeyError: # At init time
|
|
176
|
-
print('set delete NO:')
|
|
1
|
+
from typing import Callable, Self
|
|
2
|
+
from .cosem_interface_class import ICAuto, ICAElement, ICMElement
|
|
3
|
+
from .Overview import class_id
|
|
4
|
+
from ..types import cdt, cst
|
|
5
|
+
from ..types.type_alias import Attr
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Index(cdt.LongUnsigned, min=1, max=9999):
|
|
9
|
+
""" LongUnsigned type with validation """
|
|
10
|
+
__cb_get_indexes: Callable
|
|
11
|
+
DEFAULT = 1
|
|
12
|
+
|
|
13
|
+
def set_callback(self, cb: Callable):
|
|
14
|
+
self.__cb_get_indexes = cb
|
|
15
|
+
|
|
16
|
+
def get_indexes(self) -> list[int]:
|
|
17
|
+
""" return indexes container """
|
|
18
|
+
return self.__cb_get_indexes()
|
|
19
|
+
|
|
20
|
+
def check(self, string: str):
|
|
21
|
+
""" raise ValueError with message if string not is valid """
|
|
22
|
+
instance = type(self)(value=string)
|
|
23
|
+
if int(instance) in self.__cb_get_indexes():
|
|
24
|
+
raise ValueError('New index not unique')
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def with_cb(cls, value, cb: Callable) -> Self:
|
|
28
|
+
""" get instance with callback """
|
|
29
|
+
ret = cls(value)
|
|
30
|
+
ret.set_callback(cb)
|
|
31
|
+
return ret
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ScheduleTableEntry(cdt.Structure):
|
|
35
|
+
"""schedule_table_entry"""
|
|
36
|
+
index: Index
|
|
37
|
+
enable: cdt.Boolean
|
|
38
|
+
script_logical_name: cst.LogicalName
|
|
39
|
+
script_selector: cdt.LongUnsigned
|
|
40
|
+
switch_time: cst.OctetStringTime
|
|
41
|
+
validity_window: cdt.LongUnsigned
|
|
42
|
+
exec_weekdays: cdt.BitString
|
|
43
|
+
exec_specdays: cdt.BitString
|
|
44
|
+
begin_date: cst.OctetStringDate
|
|
45
|
+
end_date: cst.OctetStringDate
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# TODO: rewrite to new API
|
|
49
|
+
class Entries(cdt.Array):
|
|
50
|
+
"""entries attribute"""
|
|
51
|
+
TYPE = ScheduleTableEntry
|
|
52
|
+
unique = True
|
|
53
|
+
|
|
54
|
+
def __init__(self, value: bytes = None):
|
|
55
|
+
super(Entries, self).__init__(value)
|
|
56
|
+
# setting callback for validate schedule_table_entry index
|
|
57
|
+
for schedule_table_entry in self:
|
|
58
|
+
schedule_table_entry: ScheduleTableEntry
|
|
59
|
+
schedule_table_entry.index.set_callback(self.get_indexes)
|
|
60
|
+
|
|
61
|
+
def get_indexes(self) -> list[int]:
|
|
62
|
+
""" getter for callback Index """
|
|
63
|
+
return [entries_element.index.decode() for entries_element in self]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class DataED(cdt.Structure):
|
|
67
|
+
""" enable/disable"""
|
|
68
|
+
firstIndexA: Index
|
|
69
|
+
lastIndexA: Index
|
|
70
|
+
firstIndexB: Index
|
|
71
|
+
lastIndexB: Index
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class DataDelete(cdt.Structure):
|
|
75
|
+
"""delete"""
|
|
76
|
+
firstIndex: Index
|
|
77
|
+
lastIndex: Index
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Schedule(ICAuto):
|
|
81
|
+
"""4.5.3 Schedule"""
|
|
82
|
+
CLASS_ID = class_id.SCHEDULE
|
|
83
|
+
VERSION = 0
|
|
84
|
+
A_ELEMENTS = ICAElement(2, "entries", Entries),
|
|
85
|
+
M_ELEMENTS = (ICMElement(1, "enable_disable", DataED),
|
|
86
|
+
ICMElement(2, "insert", ScheduleTableEntry),
|
|
87
|
+
ICMElement(3, "delete", DataDelete))
|
|
88
|
+
entries: Attr
|
|
@@ -1,87 +1,54 @@
|
|
|
1
|
-
from
|
|
2
|
-
from ..types import
|
|
3
|
-
from .
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
script_identifier
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
for
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
self.set_attr(2, None)
|
|
56
|
-
self._cbs_attr_post_init.update({2: self.__set_script_identifier_cbs})
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
def scripts(self) -> Scripts:
|
|
60
|
-
return self.get_attr(2)
|
|
61
|
-
|
|
62
|
-
@property
|
|
63
|
-
def execute(self) -> cdt.LongUnsigned:
|
|
64
|
-
return self.get_meth(1)
|
|
65
|
-
|
|
66
|
-
def __set_script_identifier_cbs(self):
|
|
67
|
-
pass
|
|
68
|
-
# try:
|
|
69
|
-
# indexes: Callable = self.entries.get_indexes
|
|
70
|
-
# self.enable_disable.firstIndexA.set_callback(indexes)
|
|
71
|
-
# self.enable_disable.firstIndexB.set_callback(indexes)
|
|
72
|
-
# self.enable_disable.lastIndexA.set_callback(indexes)
|
|
73
|
-
# self.enable_disable.lastIndexB.set_callback(indexes)
|
|
74
|
-
# self.insert.index.set_callback(indexes)
|
|
75
|
-
# self.delete.firstIndex.set_callback(indexes)
|
|
76
|
-
# self.delete.lastIndex.set_callback(indexes)
|
|
77
|
-
# print('set delete')
|
|
78
|
-
# except KeyError: # At init time
|
|
79
|
-
# print('set delete NO:')
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if __name__ == '__main__':
|
|
83
|
-
a = b'\x01\x04\x02\x02\x12\x00\x01\x01\x01\x02\x05\x16\x01\x12\x00F\t\x06\x00\x00`\x03\n\xff\x0f\x04\x16\x00\x02\x02\x12\x00\x02\x01\x01\x02\x05\x16\x02\x12\x00F\t\x06\x00\x00`\x03\n\xff\x0f\x01\x03\x00\x02\x02\x12\x00\x03\x01\x01\x02\x05\x16\x01\x12\x00F\t\x06\x00\x00`\x03\n\xff\x0f\x04\x16\x01\x02\x02\x12\x00\x04\x01\x01\x02\x05\x16\x02\x12\x00F\t\x06\x00\x00`\x03\n\xff\x0f\x01\x03\x01'
|
|
84
|
-
b = Scripts(a)
|
|
85
|
-
a = ScriptTable('0.0.10.0.0.255')
|
|
86
|
-
pass
|
|
87
|
-
print(a)
|
|
1
|
+
from ..types import choices, cdt, cst
|
|
2
|
+
from ..types.type_alias import Attr
|
|
3
|
+
from .cosem_interface_class import ICAuto, ICAElement, ICMElement
|
|
4
|
+
from .Overview import class_id
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ServiceId(cdt.Enum, elements=(1, 2)):
|
|
8
|
+
"""defines which action to be applied to the referenced object."""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ActionSpecification(cdt.Structure):
|
|
12
|
+
""" Specifies the different scripts, i.e. the lists of actions. The first attribute (logical_name) has index 1, the first specific method has
|
|
13
|
+
index 1 as well. NOTE The action_specification is limited to activate methods that do not produce any response (from the server to the client). """
|
|
14
|
+
service_id: ServiceId
|
|
15
|
+
class_id: cdt.LongUnsigned
|
|
16
|
+
logical_name: cst.LogicalName
|
|
17
|
+
index: cdt.Integer
|
|
18
|
+
parameter: choices.common_dt
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Actions(cdt.Array):
|
|
22
|
+
""" Specifies the list of action specification """
|
|
23
|
+
TYPE = ActionSpecification
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Script(cdt.Structure):
|
|
27
|
+
""" Specifies the different scripts. The script_identifier 0 is reserved. If specified with an execute method, it results in a null script (no actions to perform)"""
|
|
28
|
+
script_identifier: cdt.LongUnsigned
|
|
29
|
+
actions: Actions
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Scripts(cdt.Array):
|
|
33
|
+
""" Specifies the lists of actions """
|
|
34
|
+
TYPE = Script
|
|
35
|
+
__get_item__: Script
|
|
36
|
+
|
|
37
|
+
def new_element(self) -> Script:
|
|
38
|
+
"""return default Script with vacant script_identifier"""
|
|
39
|
+
# todo: make common function by ID element
|
|
40
|
+
el: Script
|
|
41
|
+
day_ids: list[int] = [int(el.script_identifier) for el in self.values]
|
|
42
|
+
for i in range(0xffff):
|
|
43
|
+
if i not in day_ids:
|
|
44
|
+
return Script((i, None))
|
|
45
|
+
raise ValueError(F"in {self} all <script_identifier> is busy")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ScriptTable(ICAuto):
|
|
49
|
+
"""Script table"""
|
|
50
|
+
CLASS_ID = class_id.SCRIPT_TABLE
|
|
51
|
+
VERSION = 0
|
|
52
|
+
A_ELEMENTS = ICAElement(2, "scripts", Scripts),
|
|
53
|
+
M_ELEMENTS = ICMElement(1, "execute", cdt.LongUnsigned),
|
|
54
|
+
scripts: Attr
|