DLMS-SPODES 0.87.13__py3-none-any.whl → 0.87.16__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.
Files changed (100) hide show
  1. DLMS_SPODES/Values/EN/__init__.py +1 -1
  2. DLMS_SPODES/Values/EN/actors.py +8 -8
  3. DLMS_SPODES/Values/EN/relation_to_obis_names.py +387 -387
  4. DLMS_SPODES/Values/RU/__init__.py +1 -1
  5. DLMS_SPODES/Values/RU/actors.py +8 -8
  6. DLMS_SPODES/Values/RU/relation_to_obis_names.py +396 -396
  7. DLMS_SPODES/__init__.py +6 -6
  8. DLMS_SPODES/configEN.ini +126 -126
  9. DLMS_SPODES/config_parser.py +53 -53
  10. DLMS_SPODES/cosem_interface_classes/__class_init__.py +3 -3
  11. DLMS_SPODES/cosem_interface_classes/__init__.py +1 -1
  12. DLMS_SPODES/cosem_interface_classes/a_parameter.py +20 -20
  13. DLMS_SPODES/cosem_interface_classes/activity_calendar.py +254 -254
  14. DLMS_SPODES/cosem_interface_classes/arbitrator.py +105 -105
  15. DLMS_SPODES/cosem_interface_classes/association_ln/abstract.py +34 -34
  16. DLMS_SPODES/cosem_interface_classes/association_ln/authentication_mechanism_name.py +25 -25
  17. DLMS_SPODES/cosem_interface_classes/association_ln/mechanism_id.py +25 -25
  18. DLMS_SPODES/cosem_interface_classes/association_ln/method.py +5 -5
  19. DLMS_SPODES/cosem_interface_classes/association_ln/ver0.py +485 -485
  20. DLMS_SPODES/cosem_interface_classes/association_ln/ver1.py +133 -133
  21. DLMS_SPODES/cosem_interface_classes/association_ln/ver2.py +36 -36
  22. DLMS_SPODES/cosem_interface_classes/association_ln/ver3.py +4 -4
  23. DLMS_SPODES/cosem_interface_classes/association_sn/ver0.py +12 -12
  24. DLMS_SPODES/cosem_interface_classes/attr_indexes.py +12 -12
  25. DLMS_SPODES/cosem_interface_classes/clock.py +131 -131
  26. DLMS_SPODES/cosem_interface_classes/collection.py +2122 -2122
  27. DLMS_SPODES/cosem_interface_classes/cosem_interface_class.py +583 -583
  28. DLMS_SPODES/cosem_interface_classes/data.py +21 -21
  29. DLMS_SPODES/cosem_interface_classes/demand_register/ver0.py +59 -59
  30. DLMS_SPODES/cosem_interface_classes/disconnect_control.py +74 -74
  31. DLMS_SPODES/cosem_interface_classes/extended_register.py +27 -27
  32. DLMS_SPODES/cosem_interface_classes/gprs_modem_setup.py +43 -43
  33. DLMS_SPODES/cosem_interface_classes/gsm_diagnostic/ver0.py +103 -103
  34. DLMS_SPODES/cosem_interface_classes/gsm_diagnostic/ver1.py +40 -40
  35. DLMS_SPODES/cosem_interface_classes/gsm_diagnostic/ver2.py +9 -9
  36. DLMS_SPODES/cosem_interface_classes/iec_hdlc_setup/ver0.py +11 -11
  37. DLMS_SPODES/cosem_interface_classes/iec_hdlc_setup/ver1.py +53 -53
  38. DLMS_SPODES/cosem_interface_classes/iec_local_port_setup.py +11 -11
  39. DLMS_SPODES/cosem_interface_classes/image_transfer/image_transfer_status.py +15 -15
  40. DLMS_SPODES/cosem_interface_classes/image_transfer/ver0.py +126 -126
  41. DLMS_SPODES/cosem_interface_classes/implementations/__init__.py +3 -3
  42. DLMS_SPODES/cosem_interface_classes/implementations/arbitrator.py +19 -19
  43. DLMS_SPODES/cosem_interface_classes/implementations/data.py +487 -487
  44. DLMS_SPODES/cosem_interface_classes/implementations/profile_generic.py +83 -83
  45. DLMS_SPODES/cosem_interface_classes/ipv4_setup.py +72 -72
  46. DLMS_SPODES/cosem_interface_classes/limiter.py +111 -111
  47. DLMS_SPODES/cosem_interface_classes/ln_pattern.py +333 -333
  48. DLMS_SPODES/cosem_interface_classes/modem_configuration/ver0.py +65 -65
  49. DLMS_SPODES/cosem_interface_classes/modem_configuration/ver1.py +39 -39
  50. DLMS_SPODES/cosem_interface_classes/ntp_setup/ver0.py +67 -67
  51. DLMS_SPODES/cosem_interface_classes/obis.py +23 -23
  52. DLMS_SPODES/cosem_interface_classes/overview.py +197 -197
  53. DLMS_SPODES/cosem_interface_classes/parameter.py +547 -547
  54. DLMS_SPODES/cosem_interface_classes/parameters.py +172 -172
  55. DLMS_SPODES/cosem_interface_classes/profile_generic/ver0.py +122 -122
  56. DLMS_SPODES/cosem_interface_classes/profile_generic/ver1.py +277 -277
  57. DLMS_SPODES/cosem_interface_classes/push_setup/ver0.py +12 -12
  58. DLMS_SPODES/cosem_interface_classes/push_setup/ver1.py +10 -10
  59. DLMS_SPODES/cosem_interface_classes/push_setup/ver2.py +166 -166
  60. DLMS_SPODES/cosem_interface_classes/register.py +45 -45
  61. DLMS_SPODES/cosem_interface_classes/register_activation/ver0.py +80 -80
  62. DLMS_SPODES/cosem_interface_classes/register_monitor.py +46 -46
  63. DLMS_SPODES/cosem_interface_classes/reports.py +70 -70
  64. DLMS_SPODES/cosem_interface_classes/schedule.py +176 -176
  65. DLMS_SPODES/cosem_interface_classes/script_table.py +87 -87
  66. DLMS_SPODES/cosem_interface_classes/security_setup/ver0.py +68 -68
  67. DLMS_SPODES/cosem_interface_classes/security_setup/ver1.py +158 -158
  68. DLMS_SPODES/cosem_interface_classes/single_action_schedule.py +50 -50
  69. DLMS_SPODES/cosem_interface_classes/special_days_table.py +84 -84
  70. DLMS_SPODES/cosem_interface_classes/tcp_udp_setup.py +42 -42
  71. DLMS_SPODES/cosem_pdu.py +93 -93
  72. DLMS_SPODES/enums.py +625 -625
  73. DLMS_SPODES/exceptions.py +106 -106
  74. DLMS_SPODES/firmwares.py +99 -99
  75. DLMS_SPODES/hdlc/frame.py +875 -875
  76. DLMS_SPODES/hdlc/sub_layer.py +54 -54
  77. DLMS_SPODES/literals.py +17 -17
  78. DLMS_SPODES/obis/__init__.py +1 -1
  79. DLMS_SPODES/obis/media_id.py +931 -931
  80. DLMS_SPODES/pardata.py +22 -22
  81. DLMS_SPODES/pdu_enums.py +98 -98
  82. DLMS_SPODES/relation_to_OBIS.py +465 -463
  83. DLMS_SPODES/settings.py +551 -551
  84. DLMS_SPODES/types/choices.py +142 -142
  85. DLMS_SPODES/types/common_data_types.py +2401 -2401
  86. DLMS_SPODES/types/cosem_service_types.py +109 -109
  87. DLMS_SPODES/types/implementations/arrays.py +25 -25
  88. DLMS_SPODES/types/implementations/bitstrings.py +97 -97
  89. DLMS_SPODES/types/implementations/double_long_usingneds.py +35 -35
  90. DLMS_SPODES/types/implementations/enums.py +57 -57
  91. DLMS_SPODES/types/implementations/integers.py +11 -11
  92. DLMS_SPODES/types/implementations/long_unsigneds.py +127 -127
  93. DLMS_SPODES/types/implementations/octet_string.py +11 -11
  94. DLMS_SPODES/types/implementations/structs.py +64 -64
  95. DLMS_SPODES/types/useful_types.py +677 -677
  96. {dlms_spodes-0.87.13.dist-info → dlms_spodes-0.87.16.dist-info}/METADATA +30 -30
  97. dlms_spodes-0.87.16.dist-info/RECORD +117 -0
  98. {dlms_spodes-0.87.13.dist-info → dlms_spodes-0.87.16.dist-info}/WHEEL +1 -1
  99. dlms_spodes-0.87.13.dist-info/RECORD +0 -117
  100. {dlms_spodes-0.87.13.dist-info → dlms_spodes-0.87.16.dist-info}/top_level.txt +0 -0
DLMS_SPODES/exceptions.py CHANGED
@@ -1,106 +1,106 @@
1
- from enum import IntEnum
2
- from .enums import Transmit, Application
3
- from semver import Version as SemVer
4
- from . import pdu_enums as pdu
5
-
6
-
7
- class TomlKeyError(Exception):
8
- """for handle exceptions of toml"""
9
-
10
-
11
- class DLMSException(Exception):
12
- """ Common InterTechElectric exceptions class """
13
- error: Transmit | Application = Transmit.UNKNOWN
14
-
15
-
16
- class AssociationResultError(DLMSException):
17
- """ Result of the proposed AA establishment and eventually the reason of the rejection of the association establishment request, as it is specified in ISO/IEC 8650-1.
18
- When no diagnostics are included, a null value is assigned to the result-source-diagnostics field. IEC62056-53 2004 7.3.3 The AARQ and AARE APDUs """
19
- error = Transmit.NO_ACCESS
20
- __match_args_ = ('result_source_diagnostics', )
21
-
22
- # TODO: make arg right type
23
- def __init__(self, result_source_diagnostics: IntEnum):
24
- Exception.__init__(self, F'Connection is {result_source_diagnostics.name}')
25
- self.result_source_diagnostics = result_source_diagnostics
26
-
27
-
28
- class Timeout(DLMSException):
29
- """ timeout during connection or exchange """
30
- error = Transmit.TIMEOUT
31
-
32
-
33
- class NoPort(DLMSException):
34
- """ not found port """
35
- error = Transmit.NO_PORT
36
-
37
-
38
- class Abort(DLMSException):
39
- """ manual interrupt """
40
- error = Transmit.ABORT
41
-
42
-
43
- class ITEConnection(DLMSException):
44
- """"""
45
- error = Transmit.UNKNOWN
46
-
47
-
48
- class NoTransport(ITEConnection):
49
- """"""
50
- error = Transmit.NO_TRANSPORT
51
-
52
-
53
- class ITEApplication(DLMSException):
54
- """"""
55
-
56
-
57
- class NoObject(ITEApplication):
58
- """ object missing in collection """
59
- error = Application.MISSING_OBJ
60
-
61
-
62
- class IDError(ITEApplication):
63
- """"""
64
- error = Application.ID_ERROR
65
-
66
-
67
- class EmptyObj(ITEApplication):
68
- """ emtpy field in DLMS object """
69
- error = Application.EMPTY_OBJ
70
-
71
-
72
- class NoConfig(ITEApplication):
73
- """ configuration for device not founded """
74
- error = Application.NO_CONFIG
75
-
76
-
77
- class TypeErr(ITEApplication):
78
- """ unknown device type """
79
- error = Application.TYPE_ERROR
80
-
81
-
82
- class VersionError(ITEApplication):
83
- """ Version error """
84
- error = Application.VERSION_ERROR
85
-
86
- def __init__(self, error_version: SemVer, additional: str = 'device'):
87
- Exception.__init__(self, F'Unsupported {additional} version: {error_version}')
88
- self.version = error_version
89
-
90
-
91
- class ResultError(ITEApplication):
92
- """ DLMS COSEMpdu_GB83.asn error """
93
- error = Application.RESULT_ERROR
94
-
95
- def __init__(self, error: pdu.DataAccessResult | pdu.ActionResult):
96
- Exception.__init__(self, error)
97
-
98
-
99
- class UnknownError(DLMSException):
100
- """ for unknown errors """
101
- error = Transmit.UNKNOWN
102
-
103
-
104
- class NeedUpdate(ITEApplication):
105
- """error until there is no action"""
106
- error = Application.VERSION_ERROR
1
+ from enum import IntEnum
2
+ from .enums import Transmit, Application
3
+ from semver import Version as SemVer
4
+ from . import pdu_enums as pdu
5
+
6
+
7
+ class TomlKeyError(Exception):
8
+ """for handle exceptions of toml"""
9
+
10
+
11
+ class DLMSException(Exception):
12
+ """ Common InterTechElectric exceptions class """
13
+ error: Transmit | Application = Transmit.UNKNOWN
14
+
15
+
16
+ class AssociationResultError(DLMSException):
17
+ """ Result of the proposed AA establishment and eventually the reason of the rejection of the association establishment request, as it is specified in ISO/IEC 8650-1.
18
+ When no diagnostics are included, a null value is assigned to the result-source-diagnostics field. IEC62056-53 2004 7.3.3 The AARQ and AARE APDUs """
19
+ error = Transmit.NO_ACCESS
20
+ __match_args_ = ('result_source_diagnostics', )
21
+
22
+ # TODO: make arg right type
23
+ def __init__(self, result_source_diagnostics: IntEnum):
24
+ Exception.__init__(self, F'Connection is {result_source_diagnostics.name}')
25
+ self.result_source_diagnostics = result_source_diagnostics
26
+
27
+
28
+ class Timeout(DLMSException):
29
+ """ timeout during connection or exchange """
30
+ error = Transmit.TIMEOUT
31
+
32
+
33
+ class NoPort(DLMSException):
34
+ """ not found port """
35
+ error = Transmit.NO_PORT
36
+
37
+
38
+ class Abort(DLMSException):
39
+ """ manual interrupt """
40
+ error = Transmit.ABORT
41
+
42
+
43
+ class ITEConnection(DLMSException):
44
+ """"""
45
+ error = Transmit.UNKNOWN
46
+
47
+
48
+ class NoTransport(ITEConnection):
49
+ """"""
50
+ error = Transmit.NO_TRANSPORT
51
+
52
+
53
+ class ITEApplication(DLMSException):
54
+ """"""
55
+
56
+
57
+ class NoObject(ITEApplication):
58
+ """ object missing in collection """
59
+ error = Application.MISSING_OBJ
60
+
61
+
62
+ class IDError(ITEApplication):
63
+ """"""
64
+ error = Application.ID_ERROR
65
+
66
+
67
+ class EmptyObj(ITEApplication):
68
+ """ emtpy field in DLMS object """
69
+ error = Application.EMPTY_OBJ
70
+
71
+
72
+ class NoConfig(ITEApplication):
73
+ """ configuration for device not founded """
74
+ error = Application.NO_CONFIG
75
+
76
+
77
+ class TypeErr(ITEApplication):
78
+ """ unknown device type """
79
+ error = Application.TYPE_ERROR
80
+
81
+
82
+ class VersionError(ITEApplication):
83
+ """ Version error """
84
+ error = Application.VERSION_ERROR
85
+
86
+ def __init__(self, error_version: SemVer, additional: str = 'device'):
87
+ Exception.__init__(self, F'Unsupported {additional} version: {error_version}')
88
+ self.version = error_version
89
+
90
+
91
+ class ResultError(ITEApplication):
92
+ """ DLMS COSEMpdu_GB83.asn error """
93
+ error = Application.RESULT_ERROR
94
+
95
+ def __init__(self, error: pdu.DataAccessResult | pdu.ActionResult):
96
+ Exception.__init__(self, error)
97
+
98
+
99
+ class UnknownError(DLMSException):
100
+ """ for unknown errors """
101
+ error = Transmit.UNKNOWN
102
+
103
+
104
+ class NeedUpdate(ITEApplication):
105
+ """error until there is no action"""
106
+ error = Application.VERSION_ERROR
DLMS_SPODES/firmwares.py CHANGED
@@ -1,99 +1,99 @@
1
- from functools import lru_cache
2
- from typing import Optional
3
- import pickle
4
- import hashlib
5
- import os
6
- from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
7
- from cryptography.hazmat.primitives import padding
8
- from cryptography.hazmat.backends import default_backend
9
- from .settings import settings
10
-
11
-
12
- def init_cipher(key: bytes) -> tuple[Cipher, bytes]:
13
- """Initialize AES-CBC cipher with random IV"""
14
- iv = os.urandom(16)
15
- cipher = Cipher(
16
- algorithms.AES(key),
17
- modes.CBC(iv),
18
- backend=default_backend()
19
- )
20
- return cipher, iv
21
-
22
-
23
- def decrypt(key: bytes, iv: bytes, ciphertext: bytes) -> bytes:
24
- """Decrypt data with hash verification: dec(dummy + data + sha256)"""
25
- cipher = Cipher(
26
- algorithms.AES(key),
27
- modes.CBC(iv),
28
- backend=default_backend()
29
- )
30
- decryptor = cipher.decryptor()
31
- # Decrypt and remove padding
32
- padded_plaintext = decryptor.update(ciphertext) + decryptor.finalize()
33
- unpadder = padding.PKCS7(128).unpadder()
34
- plaintext = unpadder.update(padded_plaintext) + unpadder.finalize()
35
- # Verify hash
36
- data, data_hash = plaintext[16:-32], plaintext[-32:]
37
- if hashlib.sha256(data).digest() == data_hash:
38
- return data
39
- else:
40
- raise ValueError('Invalid password or corrupted data')
41
-
42
-
43
- def encrypt(key: bytes, iv: bytes, data: bytes) -> bytes:
44
- """Encrypt data with hash: ciphertext = enc(dummy + plaintext + sha256)"""
45
- # Prepare data (16 dummy bytes + data + hash)
46
- plaintext = bytes(16) + data + hashlib.sha256(data).digest()
47
-
48
- # Add padding
49
- padder = padding.PKCS7(128).padder()
50
- padded_plaintext = padder.update(plaintext) + padder.finalize()
51
-
52
- # Encrypt
53
- cipher = Cipher(
54
- algorithms.AES(key),
55
- modes.CBC(iv),
56
- backend=default_backend()
57
- )
58
- encryptor = cipher.encryptor()
59
- return encryptor.update(padded_plaintext) + encryptor.finalize()
60
-
61
-
62
- @lru_cache(maxsize=10)
63
- def get_firmware(man: bytes) -> Optional[tuple[
64
- dict[tuple[tuple[int, int, int], str], bytes],
65
- dict[tuple[int, str], bytes]
66
- ]]:
67
- for firmware in settings.firmwares:
68
- if firmware.man.encode() == man:
69
- match firmware.key.codec:
70
- case "ascii":
71
- cipher_key = firmware.key.value.encode("ascii")
72
- case "hex":
73
- cipher_key = bytes.fromhex(firmware.key.value)
74
- case _:
75
- raise ValueError(f"in get firmware, unknown firmware.key.codec={firmware.key.codec}")
76
- new_firmwares = {}
77
- new_boots = {}
78
- with open(firmware.path, 'rb') as file:
79
- try:
80
- name, firmwares_, boots_ = pickle.load(file)
81
- load_name, version = name.split('_')
82
-
83
- if load_name == "CryptoFirmware":
84
- iv = os.urandom(16)
85
- for it in firmwares_:
86
- decryption = decrypt(cipher_key, iv, firmwares_[it])
87
- new_firmwares[it] = decryption
88
- for it in boots_:
89
- decryption = decrypt(cipher_key, iv, boots_[it])
90
- new_boots[it] = decryption
91
- else:
92
- raise ValueError(f"Wrong firmware.path={firmware.path}")
93
- except KeyError as e:
94
- raise ValueError(f"Decoding error firmware.path={firmware.path}, {e}")
95
- except ValueError as e:
96
- raise ValueError(f"Decoding error firmware.path={firmware.path}, {e}")
97
- except Exception as e:
98
- raise ValueError(f"unknown error: {e}")
99
- return new_firmwares, new_boots
1
+ from functools import lru_cache
2
+ from typing import Optional
3
+ import pickle
4
+ import hashlib
5
+ import os
6
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
7
+ from cryptography.hazmat.primitives import padding
8
+ from cryptography.hazmat.backends import default_backend
9
+ from .settings import settings
10
+
11
+
12
+ def init_cipher(key: bytes) -> tuple[Cipher, bytes]:
13
+ """Initialize AES-CBC cipher with random IV"""
14
+ iv = os.urandom(16)
15
+ cipher = Cipher(
16
+ algorithms.AES(key),
17
+ modes.CBC(iv),
18
+ backend=default_backend()
19
+ )
20
+ return cipher, iv
21
+
22
+
23
+ def decrypt(key: bytes, iv: bytes, ciphertext: bytes) -> bytes:
24
+ """Decrypt data with hash verification: dec(dummy + data + sha256)"""
25
+ cipher = Cipher(
26
+ algorithms.AES(key),
27
+ modes.CBC(iv),
28
+ backend=default_backend()
29
+ )
30
+ decryptor = cipher.decryptor()
31
+ # Decrypt and remove padding
32
+ padded_plaintext = decryptor.update(ciphertext) + decryptor.finalize()
33
+ unpadder = padding.PKCS7(128).unpadder()
34
+ plaintext = unpadder.update(padded_plaintext) + unpadder.finalize()
35
+ # Verify hash
36
+ data, data_hash = plaintext[16:-32], plaintext[-32:]
37
+ if hashlib.sha256(data).digest() == data_hash:
38
+ return data
39
+ else:
40
+ raise ValueError('Invalid password or corrupted data')
41
+
42
+
43
+ def encrypt(key: bytes, iv: bytes, data: bytes) -> bytes:
44
+ """Encrypt data with hash: ciphertext = enc(dummy + plaintext + sha256)"""
45
+ # Prepare data (16 dummy bytes + data + hash)
46
+ plaintext = bytes(16) + data + hashlib.sha256(data).digest()
47
+
48
+ # Add padding
49
+ padder = padding.PKCS7(128).padder()
50
+ padded_plaintext = padder.update(plaintext) + padder.finalize()
51
+
52
+ # Encrypt
53
+ cipher = Cipher(
54
+ algorithms.AES(key),
55
+ modes.CBC(iv),
56
+ backend=default_backend()
57
+ )
58
+ encryptor = cipher.encryptor()
59
+ return encryptor.update(padded_plaintext) + encryptor.finalize()
60
+
61
+
62
+ @lru_cache(maxsize=10)
63
+ def get_firmware(man: bytes) -> Optional[tuple[
64
+ dict[tuple[tuple[int, int, int], str], bytes],
65
+ dict[tuple[int, str], bytes]
66
+ ]]:
67
+ for firmware in settings.firmwares:
68
+ if firmware.man.encode() == man:
69
+ match firmware.key.codec:
70
+ case "ascii":
71
+ cipher_key = firmware.key.value.encode("ascii")
72
+ case "hex":
73
+ cipher_key = bytes.fromhex(firmware.key.value)
74
+ case _:
75
+ raise ValueError(f"in get firmware, unknown firmware.key.codec={firmware.key.codec}")
76
+ new_firmwares = {}
77
+ new_boots = {}
78
+ with open(firmware.path, 'rb') as file:
79
+ try:
80
+ name, firmwares_, boots_ = pickle.load(file)
81
+ load_name, version = name.split('_')
82
+
83
+ if load_name == "CryptoFirmware":
84
+ iv = os.urandom(16)
85
+ for it in firmwares_:
86
+ decryption = decrypt(cipher_key, iv, firmwares_[it])
87
+ new_firmwares[it] = decryption
88
+ for it in boots_:
89
+ decryption = decrypt(cipher_key, iv, boots_[it])
90
+ new_boots[it] = decryption
91
+ else:
92
+ raise ValueError(f"Wrong firmware.path={firmware.path}")
93
+ except KeyError as e:
94
+ raise ValueError(f"Decoding error firmware.path={firmware.path}, {e}")
95
+ except ValueError as e:
96
+ raise ValueError(f"Decoding error firmware.path={firmware.path}, {e}")
97
+ except Exception as e:
98
+ raise ValueError(f"unknown error: {e}")
99
+ return new_firmwares, new_boots