DLMS-SPODES-client 0.19.27__tar.gz → 0.19.29__tar.gz
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_client-0.19.29/.vscode/launch.json +24 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/PKG-INFO +1 -1
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/pyproject.toml +1 -1
- dlms_spodes_client-0.19.29/src/DLMS_SPODES_client/services.py +90 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/task.py +37 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client.egg-info/PKG-INFO +1 -1
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client.egg-info/SOURCES.txt +2 -0
- dlms_spodes_client-0.19.29/test/__init__.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/test_Client.py +12 -2
- dlms_spodes_client-0.19.27/src/DLMS_SPODES_client/services.py +0 -97
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/.github/workflows/publish.yaml +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/.gitignore +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/README.md +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/setup.cfg +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/FCS16.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/__init__.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/client.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_common/enums/TraceLevel.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_common/enums/__init__.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/AesGcmParameter.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/CountType.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXByteBuffer.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXCiphering.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXDLMS.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSChippering.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSChipperingStream.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSConfirmedServiceError.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSException.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSLNParameters.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSSNParameters.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSSettings.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/GXReplyData.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/HdlcControlFrame.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/MBusCommand.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/MBusEncryptionMode.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/ResponseType.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/SetResponseType.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/_HDLCInfo.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/__init__.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/Access.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/ApplicationReference.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/Authentication.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/BerType.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/Command.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/Definition.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/ErrorCode.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/ExceptionServiceError.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/HardwareResource.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/HdlcFrameType.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/Initiate.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/LoadDataSet.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/ObjectType.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/Priority.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/RequestTypes.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/Security.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/Service.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/ServiceClass.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/ServiceError.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/Standard.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/StateError.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/Task.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/VdeStateError.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/enums/__init__.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/gurux_dlms/internal/_GXCommon.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/logger.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/py.typed +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/session.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/settings.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client.egg-info/dependency_links.txt +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client.egg-info/entry_points.txt +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client.egg-info/requires.txt +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client.egg-info/top_level.txt +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/Firmwares/firmwares.dat +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/Firmwares/firmwares_1_2_11.dat +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/Firmwares/firmwares_1_7_2.dat +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/client_log.txt +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/config.toml +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/name2.csv +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/test_logger.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/test_services.py +0 -0
- {dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test//320/272/320/276/320/275/321/204/320/270/320/263/321/203/321/200/320/260/321/206/320/270/321/217 GSM.csv" +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Debug test_SetBits",
|
|
9
|
+
"type": "debugpy",
|
|
10
|
+
"request": "launch",
|
|
11
|
+
"program": "-m",
|
|
12
|
+
"args": [
|
|
13
|
+
"unittest",
|
|
14
|
+
"test.test_Client.TestType.test_Session",
|
|
15
|
+
"-v"
|
|
16
|
+
],
|
|
17
|
+
"console": "integratedTerminal",
|
|
18
|
+
"justMyCode": false,
|
|
19
|
+
"env": {
|
|
20
|
+
"PYTHONPATH": "${workspaceFolder}"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from .client import Client, Network, IDFactory, c_pf
|
|
2
|
+
import csv
|
|
3
|
+
from itertools import count
|
|
4
|
+
from .settings import settings
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
_h: dict[str, [str]] = dict(settings.from_csv.header_names)
|
|
8
|
+
"""header names"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class IpAddress:
|
|
12
|
+
__value: list[int]
|
|
13
|
+
|
|
14
|
+
def __init__(self, value: str = "127.0.0.1"):
|
|
15
|
+
self.__value = list()
|
|
16
|
+
for el1 in value.split("."):
|
|
17
|
+
if el1.isdigit():
|
|
18
|
+
el = int(el1)
|
|
19
|
+
if 0 <= el <= 255:
|
|
20
|
+
self.__value.append(el)
|
|
21
|
+
else:
|
|
22
|
+
raise ValueError(F"Wrong digit in value: {el}, must be 0..255")
|
|
23
|
+
else:
|
|
24
|
+
raise ValueError(F"Value is not digit: {el1}")
|
|
25
|
+
if len(self.__value) != 4:
|
|
26
|
+
raise ValueError(F"Length of Ip address {value} must be 4, got {len(self.__value)}")
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def is_valid(cls, value: str) -> bool:
|
|
30
|
+
try:
|
|
31
|
+
cls(value)
|
|
32
|
+
return True
|
|
33
|
+
except ValueError:
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
def __str__(self):
|
|
37
|
+
return ".".join(map(str, self.__value))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_client_from_csv(
|
|
41
|
+
file_name: str,
|
|
42
|
+
id_factory: IDFactory,
|
|
43
|
+
universal: bool = False
|
|
44
|
+
) -> list[Client]:
|
|
45
|
+
"""file in utf-8 format"""
|
|
46
|
+
da: str
|
|
47
|
+
with open(file_name, "r", encoding="utf-8-sig") as csv_file:
|
|
48
|
+
dialect = csv.Sniffer().sniff(csv_file.readline(1024))
|
|
49
|
+
csv_file.seek(0)
|
|
50
|
+
reader = csv.reader(csv_file, dialect=dialect)
|
|
51
|
+
first_row: list[str] = next(reader)
|
|
52
|
+
if any(map(IpAddress.is_valid, first_row)): # search ip_address in first row
|
|
53
|
+
raise ValueError("Table header not found")
|
|
54
|
+
# header is exist search column by name
|
|
55
|
+
field_names: list[str] = []
|
|
56
|
+
for index, cell in enumerate(first_row):
|
|
57
|
+
for column in _h:
|
|
58
|
+
if any(map(cell.lower().startswith, _h[column])):
|
|
59
|
+
field_names.append(_h[column][0])
|
|
60
|
+
break
|
|
61
|
+
else:
|
|
62
|
+
field_names.append(F"unknown{index}")
|
|
63
|
+
if all(map(lambda name: name in field_names, ("ip",))):
|
|
64
|
+
csv_file.seek(0)
|
|
65
|
+
reader = csv.DictReader(csv_file, fieldnames=field_names, dialect=dialect)
|
|
66
|
+
next(reader) # skeep header
|
|
67
|
+
res: list[Client] = []
|
|
68
|
+
for i in reader:
|
|
69
|
+
if IpAddress.is_valid(i["ip"]):
|
|
70
|
+
res.append(c := Client(
|
|
71
|
+
media=Network(
|
|
72
|
+
host=i.get("ip") or "127.0.0.1",
|
|
73
|
+
port=i.get("port") or "8888",
|
|
74
|
+
to_recv=float(i.get("timeout") or 120.0)
|
|
75
|
+
),
|
|
76
|
+
SAP=int(i.get("sap") or 0x30),
|
|
77
|
+
secret=bytes(i.get("secret", "0000000000000000"), "utf-8"),
|
|
78
|
+
m_id=int(i.get("m_id") or 2),
|
|
79
|
+
id_=id_factory.create(),
|
|
80
|
+
universal=universal
|
|
81
|
+
))
|
|
82
|
+
if (
|
|
83
|
+
(da := i.get("da"))
|
|
84
|
+
and da.isdigit()
|
|
85
|
+
):
|
|
86
|
+
c.com_profile.parameters.device_address = int(da)
|
|
87
|
+
if name := i.get("name"):
|
|
88
|
+
c.name = name
|
|
89
|
+
return res
|
|
90
|
+
raise ValueError("not find at least one client")
|
|
@@ -1240,6 +1240,43 @@ class Write2(SimpleCopy, OK):
|
|
|
1240
1240
|
return result.OK
|
|
1241
1241
|
|
|
1242
1242
|
|
|
1243
|
+
@dataclass(frozen=True)
|
|
1244
|
+
class SetBits(SimpleCopy, OK):
|
|
1245
|
+
"""set bits by pattern"""
|
|
1246
|
+
par: Parameter
|
|
1247
|
+
pattern: dict[int, int]
|
|
1248
|
+
msg: str = "set bits"
|
|
1249
|
+
|
|
1250
|
+
async def exchange(self, c: Client) -> result.Ok | result.Error:
|
|
1251
|
+
if isinstance(res_obj := c.objects.par2obj(self.par), result.Error):
|
|
1252
|
+
return res_obj
|
|
1253
|
+
if isinstance(res_read := await Par2Data[cdt.Digital | cdt.BitString](self.par.attr).exchange(c), result.Error):
|
|
1254
|
+
return res_read
|
|
1255
|
+
data = res_read.value
|
|
1256
|
+
for el in self.par.elements():
|
|
1257
|
+
data = data[el]
|
|
1258
|
+
if isinstance(data, cdt.Digital):
|
|
1259
|
+
data_int = int(data)
|
|
1260
|
+
for pos, val in self.pattern.items():
|
|
1261
|
+
data_int = (data_int | (1 << pos)) if val else (data_int & ~(1 << pos))
|
|
1262
|
+
data.set(data_int)
|
|
1263
|
+
elif isinstance(data, cdt.BitString):
|
|
1264
|
+
for pos, val in self.pattern.items():
|
|
1265
|
+
try:
|
|
1266
|
+
data[pos] = val
|
|
1267
|
+
except IndexError as e:
|
|
1268
|
+
return result.Error.from_e(ValueError(f"can't set bit {pos} in {self.par}"))
|
|
1269
|
+
else:
|
|
1270
|
+
return result.Error.from_e(TypeError(f"{self.par} not available SetBits"))
|
|
1271
|
+
c.get_set_request_normal(
|
|
1272
|
+
obj=res_obj.value,
|
|
1273
|
+
attr_index=self.par.i,
|
|
1274
|
+
value=res_read.value.encoding)
|
|
1275
|
+
if isinstance(res_pdu := await c.read_data_block(), result.Error):
|
|
1276
|
+
return res_pdu
|
|
1277
|
+
return result.OK
|
|
1278
|
+
|
|
1279
|
+
|
|
1243
1280
|
@dataclass
|
|
1244
1281
|
@deprecated("use <WriteTranscript>")
|
|
1245
1282
|
class WriteParValue(SimpleCopy, OK):
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
4
|
.github/workflows/publish.yaml
|
|
5
|
+
.vscode/launch.json
|
|
5
6
|
src/DLMS_SPODES_client/FCS16.py
|
|
6
7
|
src/DLMS_SPODES_client/__init__.py
|
|
7
8
|
src/DLMS_SPODES_client/client.py
|
|
@@ -64,6 +65,7 @@ src/DLMS_SPODES_client/gurux_dlms/enums/Task.py
|
|
|
64
65
|
src/DLMS_SPODES_client/gurux_dlms/enums/VdeStateError.py
|
|
65
66
|
src/DLMS_SPODES_client/gurux_dlms/enums/__init__.py
|
|
66
67
|
src/DLMS_SPODES_client/gurux_dlms/internal/_GXCommon.py
|
|
68
|
+
test/__init__.py
|
|
67
69
|
test/client_log.txt
|
|
68
70
|
test/config.toml
|
|
69
71
|
test/name2.csv
|
|
File without changes
|
|
@@ -20,8 +20,8 @@ from src.DLMS_SPODES_client import task
|
|
|
20
20
|
task.get_adapter(adapter := xml50)
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
port1 = "
|
|
24
|
-
port2 = "
|
|
23
|
+
port1 = "COM5"
|
|
24
|
+
port2 = "COM6"
|
|
25
25
|
# mac = "A0:6C:65:53:7D:86"
|
|
26
26
|
mac = "5C:53:10:5A:E2:4B"
|
|
27
27
|
|
|
@@ -132,6 +132,16 @@ class TestType(unittest.TestCase):
|
|
|
132
132
|
))
|
|
133
133
|
print(sess)
|
|
134
134
|
|
|
135
|
+
def test_SetBits(self):
|
|
136
|
+
self.start_coro(sess := Session(
|
|
137
|
+
c=c_Serial_HIGH,
|
|
138
|
+
tsk=task.SetBits(
|
|
139
|
+
par=Parameter.parse("0.0.96.3.20.255:3").append(0),
|
|
140
|
+
pattern={1: 1, 0: 0}
|
|
141
|
+
)
|
|
142
|
+
))
|
|
143
|
+
print(sess)
|
|
144
|
+
|
|
135
145
|
def test_WriteTime(self):
|
|
136
146
|
self.start_coro(sess := Session(
|
|
137
147
|
c=c_Serial_HIGH,
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
from .client import Client, Network, IDFactory, c_pf
|
|
2
|
-
import csv
|
|
3
|
-
from itertools import count
|
|
4
|
-
from .settings import settings
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
_h: dict[str, [str]] = dict(settings.from_csv.header_names)
|
|
8
|
-
"""header names"""
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class IpAddress:
|
|
12
|
-
__value: list[int]
|
|
13
|
-
|
|
14
|
-
def __init__(self, value: str = '127.0.0.1'):
|
|
15
|
-
self.__value = list()
|
|
16
|
-
for el1 in value.split('.'):
|
|
17
|
-
if el1.isdigit():
|
|
18
|
-
el = int(el1)
|
|
19
|
-
if 0 <= el <= 255:
|
|
20
|
-
self.__value.append(el)
|
|
21
|
-
else:
|
|
22
|
-
raise ValueError(F'Wrong digit in value: {el}, must be 0..255')
|
|
23
|
-
else:
|
|
24
|
-
raise ValueError(F'Value is not digit: {el1}')
|
|
25
|
-
if len(self.__value) != 4:
|
|
26
|
-
raise ValueError(F'Length of Ip address {value} must be 4, got {len(self.__value)}')
|
|
27
|
-
|
|
28
|
-
@classmethod
|
|
29
|
-
def is_valid(cls, value: str) -> bool:
|
|
30
|
-
try:
|
|
31
|
-
cls(value)
|
|
32
|
-
return True
|
|
33
|
-
except ValueError:
|
|
34
|
-
return False
|
|
35
|
-
|
|
36
|
-
def __str__(self):
|
|
37
|
-
return '.'.join(map(str, self.__value))
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def get_client_from_csv(
|
|
41
|
-
file_name: str,
|
|
42
|
-
id_factory: IDFactory = None,
|
|
43
|
-
universal: bool = False
|
|
44
|
-
) -> list[Client]:
|
|
45
|
-
"""file in utf-8 format"""
|
|
46
|
-
da: str
|
|
47
|
-
with open(file_name, 'r', encoding="utf-8-sig") as csv_file:
|
|
48
|
-
sniffer = csv.Sniffer()
|
|
49
|
-
dialect = sniffer.sniff(csv_file.readline(1024))
|
|
50
|
-
csv_file.seek(0)
|
|
51
|
-
reader = csv.reader(csv_file, dialect=dialect)
|
|
52
|
-
first_row: list[str] = next(reader)
|
|
53
|
-
if any(map(IpAddress.is_valid, first_row)): # search ip_address in first row
|
|
54
|
-
# header is absence
|
|
55
|
-
raise ValueError('Не найден заголовок таблицы')
|
|
56
|
-
else: # header is exist
|
|
57
|
-
# search column by name
|
|
58
|
-
column_name_count = count()
|
|
59
|
-
field_names: list[str] = list()
|
|
60
|
-
for index, cell in enumerate(first_row):
|
|
61
|
-
for column in _h:
|
|
62
|
-
if any(map(cell.lower().startswith, _h[column])):
|
|
63
|
-
field_names.append(_h[column][0])
|
|
64
|
-
break
|
|
65
|
-
else:
|
|
66
|
-
field_names.append(F'unknown{next(column_name_count)}')
|
|
67
|
-
if all(map(lambda name: name in field_names, ('ip',))):
|
|
68
|
-
csv_file.seek(0)
|
|
69
|
-
reader = csv.DictReader(csv_file, fieldnames=field_names, dialect=dialect)
|
|
70
|
-
next(reader)
|
|
71
|
-
res: list[Client] = list()
|
|
72
|
-
for i in reader:
|
|
73
|
-
if IpAddress.is_valid(i['ip']):
|
|
74
|
-
res.append(c := Client(
|
|
75
|
-
media=Network(
|
|
76
|
-
host=i.get("ip", "127.0.0.1"),
|
|
77
|
-
port="8888"
|
|
78
|
-
),
|
|
79
|
-
id_=id_factory.create() if id_factory else None,
|
|
80
|
-
universal=universal
|
|
81
|
-
))
|
|
82
|
-
c.com_profile.parameters.inactivity_time_out = int(i.get("timeout", 120)) # todo: work only for HDLC, make better
|
|
83
|
-
c.secret = bytes(i.get('secret', '0000000000000000'), 'utf-8')
|
|
84
|
-
if m_id := i.get('m_id'):
|
|
85
|
-
c.m_id.set(m_id)
|
|
86
|
-
if port := i.get('port'):
|
|
87
|
-
c.media.port = port
|
|
88
|
-
if sap := i.get('sap'):
|
|
89
|
-
c.SAP.set(sap)
|
|
90
|
-
if (
|
|
91
|
-
(da := i.get('da'))
|
|
92
|
-
and da.isdigit()
|
|
93
|
-
):
|
|
94
|
-
c.com_profile.parameters.device_address = int(da)
|
|
95
|
-
if name := i.get("name"):
|
|
96
|
-
c.name = name
|
|
97
|
-
return res
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/src/DLMS_SPODES_client/settings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/Firmwares/firmwares_1_2_11.dat
RENAMED
|
File without changes
|
{dlms_spodes_client-0.19.27 → dlms_spodes_client-0.19.29}/test/Firmwares/firmwares_1_7_2.dat
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|