DLMS-SPODES-client 0.19.6__tar.gz → 0.19.8__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.6/src/DLMS_SPODES_client.egg-info → dlms_spodes_client-0.19.8}/PKG-INFO +1 -1
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/pyproject.toml +1 -1
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/client.py +102 -29
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSLNParameters.py +5 -5
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSSettings.py +0 -1
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/task.py +83 -23
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8/src/DLMS_SPODES_client.egg-info}/PKG-INFO +1 -1
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/client_log.txt +407 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/test_Client.py +8 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/.gitignore +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/README.md +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/setup.cfg +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/FCS16.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/__init__.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_common/enums/TraceLevel.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_common/enums/__init__.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/AesGcmParameter.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/CountType.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXByteBuffer.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXCiphering.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMS.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSChippering.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSChipperingStream.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSConfirmedServiceError.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSException.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSSNParameters.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXReplyData.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/HdlcControlFrame.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/MBusCommand.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/MBusEncryptionMode.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/ResponseType.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/SetResponseType.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/_HDLCInfo.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/__init__.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Access.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ApplicationReference.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Authentication.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/BerType.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Command.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Definition.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ErrorCode.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ExceptionServiceError.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/HardwareResource.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/HdlcFrameType.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Initiate.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/LoadDataSet.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ObjectType.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Priority.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/RequestTypes.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Security.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Service.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ServiceClass.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ServiceError.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Standard.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/StateError.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Task.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/VdeStateError.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/__init__.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/internal/_GXCommon.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/logger.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/py.typed +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/services.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/session.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/settings.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client.egg-info/SOURCES.txt +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client.egg-info/dependency_links.txt +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client.egg-info/entry_points.txt +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client.egg-info/requires.txt +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client.egg-info/top_level.txt +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/Firmwares/firmwares.dat +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/Firmwares/firmwares_1_2_11.dat +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/Firmwares/firmwares_1_7_2.dat +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/Types/303030/0000600101ff020009054d324d5f31/0000600102ff02000906312e332e3330.xml +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/Types/313031/0000600101ff020009054d324d5f31/0000600102ff02000906312e322e3131.xml +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/config.toml +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/name2.csv +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/test_logger.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/test_services.py +0 -0
- {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/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
|
@@ -318,7 +318,7 @@ class Client:
|
|
|
318
318
|
self.reply.blockNumberAck = bna
|
|
319
319
|
self.settings.blockNumberAck = self.reply.blockNumber
|
|
320
320
|
self.reply.command = None
|
|
321
|
-
len_ = _GXCommon.getObjectCount(self.reply.data)
|
|
321
|
+
len_, _ = cdt.get_length_and_pdu(self.reply.data.get_data()) # _GXCommon.getObjectCount(self.reply.data)
|
|
322
322
|
if len_ > self.reply.data.size - self.reply.data.position:
|
|
323
323
|
self.reply.complete = False
|
|
324
324
|
return
|
|
@@ -369,7 +369,7 @@ class Client:
|
|
|
369
369
|
match self.reply.data.getUInt8(): # DataBlock-G.result
|
|
370
370
|
case 0:
|
|
371
371
|
if self.reply.data.position != len(self.reply.data):
|
|
372
|
-
block_length = _GXCommon.getObjectCount(self.reply.data)
|
|
372
|
+
block_length, _ = cdt.get_length_and_pdu(self.reply.data.get_data()) # _GXCommon.getObjectCount(self.reply.data)
|
|
373
373
|
if (self.reply.moreData & RequestTypes.FRAME) == 0:
|
|
374
374
|
if block_length > len(self.reply.data) - self.reply.data.position:
|
|
375
375
|
raise ValueError("Invalid block length.")
|
|
@@ -416,7 +416,7 @@ class Client:
|
|
|
416
416
|
case pdu.SetResponse.LAST_DATABLOCK_WITH_LIST:
|
|
417
417
|
raise ValueError("Not released in Client")
|
|
418
418
|
case pdu.SetResponse.WITH_LIST:
|
|
419
|
-
cnt = _GXCommon.getObjectCount(self.reply.data)
|
|
419
|
+
cnt, _ = cdt.get_length_and_pdu(self.reply.data.get_data()) # _GXCommon.getObjectCount(self.reply.data)
|
|
420
420
|
pos = 0
|
|
421
421
|
while pos != cnt:
|
|
422
422
|
self.reply.error = pdu.DataAccessResult(self.reply.data.getUInt8())
|
|
@@ -425,7 +425,7 @@ class Client:
|
|
|
425
425
|
pos += 1
|
|
426
426
|
case err: raise ValueError(F"Got Invalid Set response {err}, expect {', '.join(map(lambda it: F'{it.name} = {it.value}', pdu.SetResponse))}")
|
|
427
427
|
case XDLMSAPDU.WRITE_RESPONSE:
|
|
428
|
-
cnt = _GXCommon.getObjectCount(self.reply.data)
|
|
428
|
+
cnt, _ = cdt.get_length_and_pdu(self.reply.data.get_data()) # _GXCommon.getObjectCount(self.reply.data)
|
|
429
429
|
pos = 0
|
|
430
430
|
while pos != cnt:
|
|
431
431
|
ret = self.reply.data.getUInt8()
|
|
@@ -569,7 +569,7 @@ class Client:
|
|
|
569
569
|
pass
|
|
570
570
|
case XDLMSAPDU.GATEWAY_RESPONSE:
|
|
571
571
|
self.reply.data.getUInt8()
|
|
572
|
-
len_ = _GXCommon.getObjectCount(self.reply.data)
|
|
572
|
+
len_, _ = cdt.get_length_and_pdu(self.reply.data.get_data()) # _GXCommon.getObjectCount(self.reply.data)
|
|
573
573
|
pda = bytearray(len_)
|
|
574
574
|
self.reply.data.get(pda)
|
|
575
575
|
GXDLMS.getDataFromBlock(self.reply, index)
|
|
@@ -1144,7 +1144,7 @@ class Client:
|
|
|
1144
1144
|
else:
|
|
1145
1145
|
if tag != (BerType.APPLICATION | BerType.CONSTRUCTED | AARQapdu.APPLICATION_CONTEXT_NAME):
|
|
1146
1146
|
raise ValueError("Invalid tag.")
|
|
1147
|
-
if
|
|
1147
|
+
if cdt.get_length_and_pdu(buff)[0] > len(buff) - buff.position: # _GXCommon.getObjectCount(buff)
|
|
1148
1148
|
raise ValueError("PDU: Not enough data.")
|
|
1149
1149
|
resultComponent = AssociationResult.ACCEPTED
|
|
1150
1150
|
resultDiagnosticValue = AcseServiceUser.NULL
|
|
@@ -1583,14 +1583,25 @@ class Client:
|
|
|
1583
1583
|
reply = GXByteBuffer()
|
|
1584
1584
|
messages = list()
|
|
1585
1585
|
frame_ = 0
|
|
1586
|
-
if
|
|
1586
|
+
if (
|
|
1587
|
+
p.command == XDLMSAPDU.DATA_NOTIFICATION
|
|
1588
|
+
or p.command == XDLMSAPDU.EVENT_NOTIFICATION_REQUEST
|
|
1589
|
+
):
|
|
1587
1590
|
frame_ = 0x13
|
|
1588
1591
|
while True:
|
|
1589
1592
|
# """ Get next logical name PDU. @param p LN parameters. @param reply Generated message. """
|
|
1590
|
-
ciphering =
|
|
1593
|
+
ciphering = (
|
|
1594
|
+
p.command != ACSEAPDU.AARQ
|
|
1595
|
+
and p.command != ACSEAPDU.AARE
|
|
1596
|
+
and self.settings.cipher
|
|
1597
|
+
and self.settings.cipher.security != Security.NONE
|
|
1598
|
+
)
|
|
1591
1599
|
len_ = 0
|
|
1592
1600
|
if p.command == ACSEAPDU.AARQ:
|
|
1593
|
-
if
|
|
1601
|
+
if (
|
|
1602
|
+
self.settings.gateway
|
|
1603
|
+
and self.settings.gateway.physicalDeviceAddress
|
|
1604
|
+
):
|
|
1594
1605
|
reply.setUInt8(XDLMSAPDU.GATEWAY_REQUEST)
|
|
1595
1606
|
reply.setUInt8(self.settings.gateway.networkId)
|
|
1596
1607
|
reply.setUInt8(len(self.settings.gateway.physicalDeviceAddress))
|
|
@@ -1614,16 +1625,26 @@ class Client:
|
|
|
1614
1625
|
reply.move(pos + 1, pos, len(reply) - pos - 1)
|
|
1615
1626
|
GXDLMS.multipleBlocks(p, reply, ciphering)
|
|
1616
1627
|
elif p.command != ACSEAPDU.RLRQ:
|
|
1617
|
-
if
|
|
1628
|
+
if (
|
|
1629
|
+
p.command != XDLMSAPDU.GET_REQUEST
|
|
1630
|
+
and p.data
|
|
1631
|
+
and reply
|
|
1632
|
+
):
|
|
1618
1633
|
GXDLMS.multipleBlocks(p, reply, ciphering)
|
|
1619
1634
|
if p.command == XDLMSAPDU.SET_REQUEST:
|
|
1620
|
-
if
|
|
1635
|
+
if (
|
|
1636
|
+
p.multipleBlocks
|
|
1637
|
+
and not self.negotiated_conformance.general_block_transfer
|
|
1638
|
+
):
|
|
1621
1639
|
if p.requestType == 1:
|
|
1622
1640
|
p.requestType = SetRequest.SET_REQUEST_FIRST_DATABLOCK
|
|
1623
1641
|
elif p.requestType == 2:
|
|
1624
1642
|
p.requestType = SetRequest.SET_REQUEST_WITH_DATABLOCK
|
|
1625
1643
|
if p.command == XDLMSAPDU.GET_RESPONSE:
|
|
1626
|
-
if
|
|
1644
|
+
if (
|
|
1645
|
+
p.multipleBlocks
|
|
1646
|
+
and not self.negotiated_conformance.general_block_transfer
|
|
1647
|
+
):
|
|
1627
1648
|
if p.requestType == 1:
|
|
1628
1649
|
p.requestType = 2
|
|
1629
1650
|
if p.command != XDLMSAPDU.GENERAL_BLOCK_TRANSFER:
|
|
@@ -1633,7 +1654,10 @@ class Client:
|
|
|
1633
1654
|
else:
|
|
1634
1655
|
reply.setUInt8(GXDLMS.getInvokeIDPriority(self.settings))
|
|
1635
1656
|
reply.set(p.attributeDescriptor)
|
|
1636
|
-
if
|
|
1657
|
+
if (
|
|
1658
|
+
self.settings.is_multiple_block()
|
|
1659
|
+
and self.negotiated_conformance.general_block_transfer
|
|
1660
|
+
):
|
|
1637
1661
|
if p.lastBlock:
|
|
1638
1662
|
reply.setUInt8(1)
|
|
1639
1663
|
self.settings.setCount(0)
|
|
@@ -1643,7 +1667,10 @@ class Client:
|
|
|
1643
1667
|
reply.setUInt32(p.blockIndex)
|
|
1644
1668
|
p.blockIndex += 1
|
|
1645
1669
|
if p.status != 0xFF:
|
|
1646
|
-
if
|
|
1670
|
+
if (
|
|
1671
|
+
p.status != 0
|
|
1672
|
+
and p.command == XDLMSAPDU.GET_RESPONSE
|
|
1673
|
+
):
|
|
1647
1674
|
reply.setUInt8(1)
|
|
1648
1675
|
reply.setUInt8(p.status)
|
|
1649
1676
|
if p.data:
|
|
@@ -1661,8 +1688,14 @@ class Client:
|
|
|
1661
1688
|
_GXCommon.setObjectCount(len_, reply)
|
|
1662
1689
|
reply.set(p.data, len_)
|
|
1663
1690
|
if len_ == 0:
|
|
1664
|
-
if
|
|
1665
|
-
|
|
1691
|
+
if (
|
|
1692
|
+
p.status != 0xFF
|
|
1693
|
+
and p.command != XDLMSAPDU.GENERAL_BLOCK_TRANSFER
|
|
1694
|
+
):
|
|
1695
|
+
if (
|
|
1696
|
+
p.status != 0
|
|
1697
|
+
and p.command == XDLMSAPDU.GET_RESPONSE
|
|
1698
|
+
):
|
|
1666
1699
|
reply.setUInt8(1)
|
|
1667
1700
|
reply.setUInt8(p.status)
|
|
1668
1701
|
if p.data:
|
|
@@ -1680,7 +1713,10 @@ class Client:
|
|
|
1680
1713
|
if self.negotiated_conformance.general_block_transfer:
|
|
1681
1714
|
if 7 + len_ + len(reply) > self.settings.maxPduSize:
|
|
1682
1715
|
len_ = self.settings.maxPduSize - len(reply) - 7
|
|
1683
|
-
if
|
|
1716
|
+
if (
|
|
1717
|
+
ciphering
|
|
1718
|
+
and p.command != XDLMSAPDU.GENERAL_BLOCK_TRANSFER
|
|
1719
|
+
):
|
|
1684
1720
|
reply.set(p.data)
|
|
1685
1721
|
tmp = []
|
|
1686
1722
|
if self.settings.cipher.securitySuite == SecuritySuite.AES_GCM_128_AUT_ENCR_AND_AES_128_KEY_WRAP:
|
|
@@ -1692,11 +1728,25 @@ class Client:
|
|
|
1692
1728
|
if 7 + len_ > self.settings.maxPduSize:
|
|
1693
1729
|
len_ = self.settings.maxPduSize - 7
|
|
1694
1730
|
ciphering = False
|
|
1695
|
-
elif
|
|
1731
|
+
elif (
|
|
1732
|
+
p.command != XDLMSAPDU.GET_REQUEST
|
|
1733
|
+
and len_ + len(reply) > self.settings.maxPduSize
|
|
1734
|
+
):
|
|
1696
1735
|
len_ = self.settings.maxPduSize - len(reply)
|
|
1697
1736
|
reply.set(p.data, p.data.position, len_)
|
|
1698
|
-
elif (
|
|
1699
|
-
|
|
1737
|
+
elif (
|
|
1738
|
+
(
|
|
1739
|
+
self.settings.gateway
|
|
1740
|
+
and self.settings.gateway.physicalDeviceAddress
|
|
1741
|
+
)
|
|
1742
|
+
and not (
|
|
1743
|
+
p.command == XDLMSAPDU.GENERAL_BLOCK_TRANSFER
|
|
1744
|
+
or (
|
|
1745
|
+
p.multipleBlocks
|
|
1746
|
+
and self.negotiated_conformance.general_block_transfer
|
|
1747
|
+
)
|
|
1748
|
+
)
|
|
1749
|
+
):
|
|
1700
1750
|
if 3 + len_ + len(self.settings.gateway.physicalDeviceAddress) > self.settings.maxPduSize:
|
|
1701
1751
|
len_ -= (3 + len(self.settings.gateway.physicalDeviceAddress))
|
|
1702
1752
|
tmp = GXByteBuffer(reply)
|
|
@@ -1706,27 +1756,42 @@ class Client:
|
|
|
1706
1756
|
reply.setUInt8(len(self.settings.gateway.physicalDeviceAddress))
|
|
1707
1757
|
reply.set(self.settings.gateway.physicalDeviceAddress)
|
|
1708
1758
|
reply.set(tmp)
|
|
1709
|
-
if
|
|
1759
|
+
if (
|
|
1760
|
+
ciphering
|
|
1761
|
+
and reply
|
|
1762
|
+
and not self.negotiated_conformance.general_block_transfer
|
|
1763
|
+
and p.command != XDLMSAPDU.RELEASE_REQUEST
|
|
1764
|
+
):
|
|
1710
1765
|
tmp = []
|
|
1711
1766
|
if self.settings.cipher.securitySuite == SecuritySuite.AES_GCM_128_AUT_ENCR_AND_AES_128_KEY_WRAP:
|
|
1712
1767
|
tmp = self.cipher0(p, reply.array())
|
|
1713
1768
|
reply.size = 0
|
|
1714
1769
|
reply.set(tmp)
|
|
1715
|
-
if
|
|
1770
|
+
if (
|
|
1771
|
+
p.command == XDLMSAPDU.GENERAL_BLOCK_TRANSFER
|
|
1772
|
+
or (
|
|
1773
|
+
p.multipleBlocks
|
|
1774
|
+
and self.negotiated_conformance.general_block_transfer
|
|
1775
|
+
)
|
|
1776
|
+
):
|
|
1716
1777
|
bb = GXByteBuffer()
|
|
1717
1778
|
bb.set(reply)
|
|
1718
1779
|
reply.clear()
|
|
1719
1780
|
reply.setUInt8(XDLMSAPDU.GENERAL_BLOCK_TRANSFER)
|
|
1720
|
-
value = 0
|
|
1721
1781
|
if p.lastBlock:
|
|
1722
1782
|
value = 0x80
|
|
1723
1783
|
elif p.streaming:
|
|
1724
|
-
value
|
|
1784
|
+
value = 0x40
|
|
1785
|
+
else:
|
|
1786
|
+
value = 0
|
|
1725
1787
|
value |= p.windowSize
|
|
1726
1788
|
reply.setUInt8(value)
|
|
1727
1789
|
reply.setUInt16(p.blockIndex)
|
|
1728
1790
|
p.blockIndex += 1
|
|
1729
|
-
if
|
|
1791
|
+
if (
|
|
1792
|
+
p.command != XDLMSAPDU.DATA_NOTIFICATION
|
|
1793
|
+
and p.blockNumberAck != 0
|
|
1794
|
+
):
|
|
1730
1795
|
reply.setUInt16(p.blockNumberAck)
|
|
1731
1796
|
p.blockNumberAck += 1
|
|
1732
1797
|
else:
|
|
@@ -1737,7 +1802,10 @@ class Client:
|
|
|
1737
1802
|
if p.command != XDLMSAPDU.GENERAL_BLOCK_TRANSFER:
|
|
1738
1803
|
p.command = XDLMSAPDU.GENERAL_BLOCK_TRANSFER
|
|
1739
1804
|
p.blockNumberAck += 1
|
|
1740
|
-
if
|
|
1805
|
+
if (
|
|
1806
|
+
self.settings.gateway
|
|
1807
|
+
and self.settings.gateway.physicalDeviceAddress
|
|
1808
|
+
):
|
|
1741
1809
|
if 3 + len_ + len(self.settings.gateway.physicalDeviceAddress) > self.settings.maxPduSize:
|
|
1742
1810
|
len_ -= (3 + len(self.settings.gateway.physicalDeviceAddress))
|
|
1743
1811
|
tmp = GXByteBuffer(reply)
|
|
@@ -1747,11 +1815,13 @@ class Client:
|
|
|
1747
1815
|
reply.setUInt8(len(self.settings.gateway.physicalDeviceAddress))
|
|
1748
1816
|
reply.set(self.settings.gateway.physicalDeviceAddress)
|
|
1749
1817
|
reply.set(tmp)
|
|
1750
|
-
|
|
1751
1818
|
p.lastBlock = True
|
|
1752
1819
|
if p.attributeDescriptor is None:
|
|
1753
1820
|
self.settings.increaseBlockIndex()
|
|
1754
|
-
if
|
|
1821
|
+
if (
|
|
1822
|
+
p.command == ACSEAPDU.AARQ
|
|
1823
|
+
and p.command == XDLMSAPDU.GET_REQUEST
|
|
1824
|
+
):
|
|
1755
1825
|
assert not self.settings.maxPduSize < len(reply)
|
|
1756
1826
|
match self.com_profile:
|
|
1757
1827
|
case c_pf.TCPUDPIP():
|
|
@@ -1762,7 +1832,10 @@ class Client:
|
|
|
1762
1832
|
raise ValueError("InterfaceType")
|
|
1763
1833
|
reply.clear()
|
|
1764
1834
|
frame_ = 0
|
|
1765
|
-
if
|
|
1835
|
+
if (
|
|
1836
|
+
not p.data
|
|
1837
|
+
or p.data.position == p.data.size
|
|
1838
|
+
):
|
|
1766
1839
|
break
|
|
1767
1840
|
return messages
|
|
1768
1841
|
|
|
@@ -14,19 +14,19 @@ class GXDLMSLNParameters:
|
|
|
14
14
|
data: GXByteBuffer | None
|
|
15
15
|
# Reply status.
|
|
16
16
|
status: ErrorCode | int
|
|
17
|
+
windowSize: int = 1
|
|
18
|
+
streaming: bool = False
|
|
19
|
+
""" Is this last block in send. """
|
|
17
20
|
|
|
18
21
|
def __post_init__(self):
|
|
19
22
|
self.blockIndex = self.settings.blockIndex
|
|
20
23
|
self.blockNumberAck = self.settings.blockNumberAck
|
|
21
24
|
self.time = None
|
|
22
25
|
""" Send date and time. This is used in Data notification messages. """
|
|
23
|
-
self.multipleBlocks = self.settings.
|
|
24
|
-
""" Are there more data to send or more data to receive
|
|
26
|
+
self.multipleBlocks = self.settings.is_multiple_block()
|
|
27
|
+
""" Are there more data to send or more data to receive"""
|
|
25
28
|
self.lastBlock = self.settings.count == self.settings.index
|
|
26
29
|
""" Is this last block in send. """
|
|
27
|
-
self.windowSize = 1
|
|
28
|
-
self.streaming = False
|
|
29
|
-
""" Is this last block in send. """
|
|
30
30
|
if self.settings:
|
|
31
31
|
self.settings.command = self.command
|
|
32
32
|
if self.command == XDLMSAPDU.GET_REQUEST and self.requestType != ResponseType.WITH_DATABLOCK:
|
|
@@ -1030,7 +1030,7 @@ class ReadObjAttr(SimpleCopy, CDT):
|
|
|
1030
1030
|
|
|
1031
1031
|
|
|
1032
1032
|
@dataclass
|
|
1033
|
-
class Par2Data[T: cdt.CommonDataType](SimpleCopy, CDT):
|
|
1033
|
+
class Par2Data[T: cdt.CommonDataType](SimpleCopy, CDT[T]):
|
|
1034
1034
|
"""get CommonDataType by Parameter"""
|
|
1035
1035
|
par: Parameter
|
|
1036
1036
|
msg: str = "read data by Parameter"
|
|
@@ -1162,6 +1162,7 @@ class ReadAttributes(SimpleCopy, _List[cdt.CommonDataType]):
|
|
|
1162
1162
|
|
|
1163
1163
|
|
|
1164
1164
|
@dataclass
|
|
1165
|
+
@deprecated("use <Write2>")
|
|
1165
1166
|
class Write(SimpleCopy, OK):
|
|
1166
1167
|
"""write with ParameterData struct"""
|
|
1167
1168
|
par_data: ParData
|
|
@@ -1189,6 +1190,35 @@ class Write(SimpleCopy, OK):
|
|
|
1189
1190
|
|
|
1190
1191
|
|
|
1191
1192
|
@dataclass
|
|
1193
|
+
class Write2(SimpleCopy, OK):
|
|
1194
|
+
"""write with ParameterData struct"""
|
|
1195
|
+
par: Parameter
|
|
1196
|
+
data: cdt.CommonDataType
|
|
1197
|
+
msg: str = "write Data"
|
|
1198
|
+
|
|
1199
|
+
async def exchange(self, c: Client) -> result.Ok | result.Error:
|
|
1200
|
+
if isinstance(res_obj := c.objects.par2obj(self.par), result.Error):
|
|
1201
|
+
return res_obj
|
|
1202
|
+
if self.par.n_elements == 0:
|
|
1203
|
+
enc = self.data.encoding
|
|
1204
|
+
elif isinstance(res_read := await Par2Data[cdt.CommonDataType](self.par.attr).exchange(c), result.Error):
|
|
1205
|
+
return res_read
|
|
1206
|
+
else:
|
|
1207
|
+
data = res_read.value
|
|
1208
|
+
for el in self.par.elements():
|
|
1209
|
+
data = data[el]
|
|
1210
|
+
data.set(self.data)
|
|
1211
|
+
enc = data.encoding
|
|
1212
|
+
data = c.get_set_request_normal(
|
|
1213
|
+
obj=res_obj.value,
|
|
1214
|
+
attr_index=self.par.i,
|
|
1215
|
+
value=enc)
|
|
1216
|
+
ret = await c.read_data_block()
|
|
1217
|
+
return result.OK
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
@dataclass
|
|
1221
|
+
@deprecated("use <WriteTranscript>")
|
|
1192
1222
|
class WriteParValue(SimpleCopy, OK):
|
|
1193
1223
|
"""write with ParameterValues struct"""
|
|
1194
1224
|
par_value: ParValues[cdt.Transcript]
|
|
@@ -1694,6 +1724,7 @@ class AccessValidate(Base[result.Ok | result.Simple[list[Parameter]]]):
|
|
|
1694
1724
|
|
|
1695
1725
|
|
|
1696
1726
|
@dataclass
|
|
1727
|
+
@deprecated("use <WriteList>")
|
|
1697
1728
|
class WriteParDatas(SimpleCopy, _List[result.Ok]):
|
|
1698
1729
|
"""write by ParData list"""
|
|
1699
1730
|
par_datas: list[ParData]
|
|
@@ -1710,42 +1741,71 @@ class WriteParDatas(SimpleCopy, _List[result.Ok]):
|
|
|
1710
1741
|
return res
|
|
1711
1742
|
|
|
1712
1743
|
|
|
1744
|
+
class WriteList(SimpleCopy, _List[result.Ok]):
|
|
1745
|
+
"""write by list"""
|
|
1746
|
+
par_datas: tuple[tuple[Parameter, cdt.CommonDataType], ...]
|
|
1747
|
+
err_ignore: bool
|
|
1748
|
+
|
|
1749
|
+
def __init__(self, *par_datas: tuple[Parameter, cdt.CommonDataType], err_ignore: bool = False, msg: str = "") -> None:
|
|
1750
|
+
self.par_datas = par_datas
|
|
1751
|
+
self.err_ignore = err_ignore
|
|
1752
|
+
self.msg = msg
|
|
1753
|
+
|
|
1754
|
+
async def exchange(self, c: Client) -> result.List[result.Ok] | result.Error:
|
|
1755
|
+
res = result.List[result.Ok]()
|
|
1756
|
+
for par, data in self.par_datas:
|
|
1757
|
+
if (
|
|
1758
|
+
isinstance(res_one := await Write2(par, data).exchange(c), result.Error)
|
|
1759
|
+
and not self.err_ignore
|
|
1760
|
+
):
|
|
1761
|
+
return res_one
|
|
1762
|
+
res.append(res_one)
|
|
1763
|
+
return res
|
|
1764
|
+
|
|
1765
|
+
|
|
1713
1766
|
@dataclass
|
|
1714
|
-
class
|
|
1767
|
+
class WriteTranscript(SimpleCopy, OK):
|
|
1715
1768
|
"""write by ParValues[Transcript]"""
|
|
1716
1769
|
par: Parameter
|
|
1717
1770
|
value: cdt.Transcript
|
|
1718
1771
|
msg: str = ""
|
|
1719
1772
|
|
|
1720
1773
|
async def exchange(self, c: Client) -> result.Ok | result.Error:
|
|
1721
|
-
if isinstance((res := await Par2Data(self.par).exchange(c)), result.Error):
|
|
1774
|
+
if isinstance((res := await Par2Data[cdt.CommonDataType](self.par).exchange(c)), result.Error):
|
|
1722
1775
|
return res
|
|
1723
|
-
data = copy(res.value)
|
|
1724
1776
|
if isinstance(data, cdt.Digital):
|
|
1725
1777
|
s_u = c.objects.par2su(self.par)
|
|
1726
1778
|
if isinstance(s_u, cdt.ScalUnitType):
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1779
|
+
if not isinstance(self.value, str):
|
|
1780
|
+
return result.Error.from_e(TypeError(), f"for {self.par} got type: {self.value}, expected String")
|
|
1781
|
+
try:
|
|
1782
|
+
data = res.value.parse(value := str(float(self.value) * 10 ** -int(s_u.scaler)))
|
|
1783
|
+
except ValueError as e:
|
|
1784
|
+
return result.Error.from_e(e, f"for {self.par} got value: {self.value}, expected Float or Digital")
|
|
1785
|
+
else:
|
|
1786
|
+
data = res.value.parse(self.value)
|
|
1787
|
+
else:
|
|
1788
|
+
data = res.value.parse(self.value)
|
|
1789
|
+
return await Write2(self.par, data).exchange(c)
|
|
1737
1790
|
|
|
1738
1791
|
|
|
1739
|
-
|
|
1740
|
-
class WriteParTranscripts(SimpleCopy, Sequence[*Ts]):
|
|
1792
|
+
class WriteTranscripts(SimpleCopy, _List[result.Ok]):
|
|
1741
1793
|
"""write by ParValues[Transcript] list"""
|
|
1742
|
-
par_values:
|
|
1743
|
-
|
|
1794
|
+
par_values: tuple[tuple[Parameter, cdt.Transcript], ...]
|
|
1795
|
+
err_ignore: bool
|
|
1744
1796
|
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1797
|
+
def __init__(self, *par_values: tuple[Parameter, cdt.Transcript], err_ignore: bool = False, msg: str =""):
|
|
1798
|
+
self.par_values = par_values
|
|
1799
|
+
self.err_ignore = err_ignore
|
|
1800
|
+
self.msg = msg
|
|
1801
|
+
|
|
1802
|
+
async def exchange(self, c: Client) -> result.List[result.Ok] | result.Error:
|
|
1803
|
+
res = result.List[result.Ok]()
|
|
1804
|
+
for par, value in self.par_values:
|
|
1805
|
+
if (
|
|
1806
|
+
isinstance(res_one := await WriteTranscript(par, value).exchange(c), result.Error)
|
|
1807
|
+
and not self.err_ignore
|
|
1808
|
+
):
|
|
1749
1809
|
return res_one
|
|
1750
|
-
res
|
|
1810
|
+
res.append(res_one)
|
|
1751
1811
|
return res
|