DLMS-SPODES-client 0.19.24__py3-none-any.whl → 0.19.27__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_client/FCS16.py +39 -39
- DLMS_SPODES_client/__init__.py +12 -12
- DLMS_SPODES_client/client.py +2093 -2091
- DLMS_SPODES_client/gurux_common/enums/TraceLevel.py +21 -21
- DLMS_SPODES_client/gurux_dlms/AesGcmParameter.py +37 -37
- DLMS_SPODES_client/gurux_dlms/CountType.py +16 -16
- DLMS_SPODES_client/gurux_dlms/GXByteBuffer.py +545 -545
- DLMS_SPODES_client/gurux_dlms/GXCiphering.py +196 -196
- DLMS_SPODES_client/gurux_dlms/GXDLMS.py +426 -426
- DLMS_SPODES_client/gurux_dlms/GXDLMSChippering.py +237 -237
- DLMS_SPODES_client/gurux_dlms/GXDLMSChipperingStream.py +977 -977
- DLMS_SPODES_client/gurux_dlms/GXDLMSConfirmedServiceError.py +90 -90
- DLMS_SPODES_client/gurux_dlms/GXDLMSException.py +139 -139
- DLMS_SPODES_client/gurux_dlms/GXDLMSLNParameters.py +33 -33
- DLMS_SPODES_client/gurux_dlms/GXDLMSSNParameters.py +21 -21
- DLMS_SPODES_client/gurux_dlms/GXDLMSSettings.py +254 -254
- DLMS_SPODES_client/gurux_dlms/GXReplyData.py +87 -87
- DLMS_SPODES_client/gurux_dlms/HdlcControlFrame.py +9 -9
- DLMS_SPODES_client/gurux_dlms/MBusCommand.py +8 -8
- DLMS_SPODES_client/gurux_dlms/MBusEncryptionMode.py +27 -27
- DLMS_SPODES_client/gurux_dlms/ResponseType.py +8 -8
- DLMS_SPODES_client/gurux_dlms/SetResponseType.py +29 -29
- DLMS_SPODES_client/gurux_dlms/_HDLCInfo.py +9 -9
- DLMS_SPODES_client/gurux_dlms/__init__.py +75 -75
- DLMS_SPODES_client/gurux_dlms/enums/Access.py +12 -12
- DLMS_SPODES_client/gurux_dlms/enums/ApplicationReference.py +14 -14
- DLMS_SPODES_client/gurux_dlms/enums/Authentication.py +41 -41
- DLMS_SPODES_client/gurux_dlms/enums/BerType.py +35 -35
- DLMS_SPODES_client/gurux_dlms/enums/Command.py +285 -285
- DLMS_SPODES_client/gurux_dlms/enums/Definition.py +9 -9
- DLMS_SPODES_client/gurux_dlms/enums/ErrorCode.py +46 -46
- DLMS_SPODES_client/gurux_dlms/enums/ExceptionServiceError.py +12 -12
- DLMS_SPODES_client/gurux_dlms/enums/HardwareResource.py +10 -10
- DLMS_SPODES_client/gurux_dlms/enums/HdlcFrameType.py +9 -9
- DLMS_SPODES_client/gurux_dlms/enums/Initiate.py +10 -10
- DLMS_SPODES_client/gurux_dlms/enums/LoadDataSet.py +13 -13
- DLMS_SPODES_client/gurux_dlms/enums/ObjectType.py +306 -306
- DLMS_SPODES_client/gurux_dlms/enums/Priority.py +7 -7
- DLMS_SPODES_client/gurux_dlms/enums/RequestTypes.py +9 -9
- DLMS_SPODES_client/gurux_dlms/enums/Security.py +14 -14
- DLMS_SPODES_client/gurux_dlms/enums/Service.py +16 -16
- DLMS_SPODES_client/gurux_dlms/enums/ServiceClass.py +9 -9
- DLMS_SPODES_client/gurux_dlms/enums/ServiceError.py +8 -8
- DLMS_SPODES_client/gurux_dlms/enums/Standard.py +18 -18
- DLMS_SPODES_client/gurux_dlms/enums/StateError.py +7 -7
- DLMS_SPODES_client/gurux_dlms/enums/Task.py +10 -10
- DLMS_SPODES_client/gurux_dlms/enums/VdeStateError.py +10 -10
- DLMS_SPODES_client/gurux_dlms/enums/__init__.py +33 -33
- DLMS_SPODES_client/gurux_dlms/internal/_GXCommon.py +1673 -1673
- DLMS_SPODES_client/logger.py +56 -56
- DLMS_SPODES_client/services.py +97 -97
- DLMS_SPODES_client/session.py +365 -365
- DLMS_SPODES_client/settings.py +48 -48
- DLMS_SPODES_client/task.py +1847 -1841
- {dlms_spodes_client-0.19.24.dist-info → dlms_spodes_client-0.19.27.dist-info}/METADATA +29 -29
- dlms_spodes_client-0.19.27.dist-info/RECORD +61 -0
- dlms_spodes_client-0.19.24.dist-info/RECORD +0 -61
- {dlms_spodes_client-0.19.24.dist-info → dlms_spodes_client-0.19.27.dist-info}/WHEEL +0 -0
- {dlms_spodes_client-0.19.24.dist-info → dlms_spodes_client-0.19.27.dist-info}/entry_points.txt +0 -0
- {dlms_spodes_client-0.19.24.dist-info → dlms_spodes_client-0.19.27.dist-info}/top_level.txt +0 -0
DLMS_SPODES_client/logger.py
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import sys
|
|
3
|
-
from enum import IntEnum
|
|
4
|
-
from DLMS_SPODES.config_parser import get_values
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
_log_config = {
|
|
8
|
-
"""logging configuration according with config.toml:[DLMSClient.logging] by default"""
|
|
9
|
-
"disabled": False,
|
|
10
|
-
"name": "DLMSClient",
|
|
11
|
-
"level": logging.INFO,
|
|
12
|
-
"fmt": "%(id)s: %(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
13
|
-
"datefmt": "%d.%m %H:%M",
|
|
14
|
-
"handlers": [
|
|
15
|
-
{"type": "Stream"}
|
|
16
|
-
]
|
|
17
|
-
}
|
|
18
|
-
logger = logging.getLogger(name=F"{_log_config['name']}")
|
|
19
|
-
is_file_handler_exist: bool = False
|
|
20
|
-
if __log_config_toml := get_values("DLMSClient", "logging"):
|
|
21
|
-
_log_config.update(__log_config_toml)
|
|
22
|
-
logger.disabled = _log_config.get("disabled", False)
|
|
23
|
-
_state_level = _log_config.get("state_level", 19)
|
|
24
|
-
logger.setLevel(level=_log_config["level"])
|
|
25
|
-
formatter = logging.Formatter(
|
|
26
|
-
fmt=_log_config["fmt"],
|
|
27
|
-
datefmt=_log_config["datefmt"])
|
|
28
|
-
for h in _log_config["handlers"]:
|
|
29
|
-
match h.get("type"):
|
|
30
|
-
case "Stream":
|
|
31
|
-
handler = logging.StreamHandler(stream=sys.stdout)
|
|
32
|
-
case "File":
|
|
33
|
-
is_file_handler_exist = True
|
|
34
|
-
handler = logging.FileHandler(
|
|
35
|
-
filename=h.get("filename", "client_log.txt"),
|
|
36
|
-
mode=h.get("mode", "a"),
|
|
37
|
-
encoding="utf-8")
|
|
38
|
-
case err:
|
|
39
|
-
raise ValueError(F"got error logger type Handler: {err}")
|
|
40
|
-
handler.setFormatter(formatter)
|
|
41
|
-
logger.addHandler(handler)
|
|
42
|
-
logger.debug(F"Start {logger}", extra={"id": "#common"})
|
|
43
|
-
logger.propagate = False
|
|
44
|
-
else:
|
|
45
|
-
_state_level = 19
|
|
46
|
-
logger.disabled = True
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class LogLevel(IntEnum):
|
|
50
|
-
DEB = logging.DEBUG
|
|
51
|
-
STATE = _state_level
|
|
52
|
-
"""for keep in client"""
|
|
53
|
-
INFO = logging.INFO
|
|
54
|
-
WARN = logging.WARNING
|
|
55
|
-
ERR = logging.ERROR
|
|
56
|
-
CRIT = logging.CRITICAL
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
from enum import IntEnum
|
|
4
|
+
from DLMS_SPODES.config_parser import get_values
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
_log_config = {
|
|
8
|
+
"""logging configuration according with config.toml:[DLMSClient.logging] by default"""
|
|
9
|
+
"disabled": False,
|
|
10
|
+
"name": "DLMSClient",
|
|
11
|
+
"level": logging.INFO,
|
|
12
|
+
"fmt": "%(id)s: %(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
13
|
+
"datefmt": "%d.%m %H:%M",
|
|
14
|
+
"handlers": [
|
|
15
|
+
{"type": "Stream"}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
logger = logging.getLogger(name=F"{_log_config['name']}")
|
|
19
|
+
is_file_handler_exist: bool = False
|
|
20
|
+
if __log_config_toml := get_values("DLMSClient", "logging"):
|
|
21
|
+
_log_config.update(__log_config_toml)
|
|
22
|
+
logger.disabled = _log_config.get("disabled", False)
|
|
23
|
+
_state_level = _log_config.get("state_level", 19)
|
|
24
|
+
logger.setLevel(level=_log_config["level"])
|
|
25
|
+
formatter = logging.Formatter(
|
|
26
|
+
fmt=_log_config["fmt"],
|
|
27
|
+
datefmt=_log_config["datefmt"])
|
|
28
|
+
for h in _log_config["handlers"]:
|
|
29
|
+
match h.get("type"):
|
|
30
|
+
case "Stream":
|
|
31
|
+
handler = logging.StreamHandler(stream=sys.stdout)
|
|
32
|
+
case "File":
|
|
33
|
+
is_file_handler_exist = True
|
|
34
|
+
handler = logging.FileHandler(
|
|
35
|
+
filename=h.get("filename", "client_log.txt"),
|
|
36
|
+
mode=h.get("mode", "a"),
|
|
37
|
+
encoding="utf-8")
|
|
38
|
+
case err:
|
|
39
|
+
raise ValueError(F"got error logger type Handler: {err}")
|
|
40
|
+
handler.setFormatter(formatter)
|
|
41
|
+
logger.addHandler(handler)
|
|
42
|
+
logger.debug(F"Start {logger}", extra={"id": "#common"})
|
|
43
|
+
logger.propagate = False
|
|
44
|
+
else:
|
|
45
|
+
_state_level = 19
|
|
46
|
+
logger.disabled = True
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class LogLevel(IntEnum):
|
|
50
|
+
DEB = logging.DEBUG
|
|
51
|
+
STATE = _state_level
|
|
52
|
+
"""for keep in client"""
|
|
53
|
+
INFO = logging.INFO
|
|
54
|
+
WARN = logging.WARNING
|
|
55
|
+
ERR = logging.ERROR
|
|
56
|
+
CRIT = logging.CRITICAL
|
DLMS_SPODES_client/services.py
CHANGED
|
@@ -1,97 +1,97 @@
|
|
|
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
|
|
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
|