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.
Files changed (79) hide show
  1. {dlms_spodes_client-0.19.6/src/DLMS_SPODES_client.egg-info → dlms_spodes_client-0.19.8}/PKG-INFO +1 -1
  2. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/pyproject.toml +1 -1
  3. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/client.py +102 -29
  4. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSLNParameters.py +5 -5
  5. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSSettings.py +0 -1
  6. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/task.py +83 -23
  7. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8/src/DLMS_SPODES_client.egg-info}/PKG-INFO +1 -1
  8. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/client_log.txt +407 -0
  9. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/test_Client.py +8 -0
  10. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/.gitignore +0 -0
  11. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/README.md +0 -0
  12. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/setup.cfg +0 -0
  13. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/FCS16.py +0 -0
  14. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/__init__.py +0 -0
  15. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_common/enums/TraceLevel.py +0 -0
  16. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_common/enums/__init__.py +0 -0
  17. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/AesGcmParameter.py +0 -0
  18. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/CountType.py +0 -0
  19. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXByteBuffer.py +0 -0
  20. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXCiphering.py +0 -0
  21. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMS.py +0 -0
  22. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSChippering.py +0 -0
  23. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSChipperingStream.py +0 -0
  24. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSConfirmedServiceError.py +0 -0
  25. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSException.py +0 -0
  26. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSSNParameters.py +0 -0
  27. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/GXReplyData.py +0 -0
  28. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/HdlcControlFrame.py +0 -0
  29. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/MBusCommand.py +0 -0
  30. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/MBusEncryptionMode.py +0 -0
  31. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/ResponseType.py +0 -0
  32. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/SetResponseType.py +0 -0
  33. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/_HDLCInfo.py +0 -0
  34. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/__init__.py +0 -0
  35. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Access.py +0 -0
  36. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ApplicationReference.py +0 -0
  37. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Authentication.py +0 -0
  38. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/BerType.py +0 -0
  39. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Command.py +0 -0
  40. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Definition.py +0 -0
  41. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ErrorCode.py +0 -0
  42. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ExceptionServiceError.py +0 -0
  43. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/HardwareResource.py +0 -0
  44. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/HdlcFrameType.py +0 -0
  45. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Initiate.py +0 -0
  46. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/LoadDataSet.py +0 -0
  47. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ObjectType.py +0 -0
  48. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Priority.py +0 -0
  49. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/RequestTypes.py +0 -0
  50. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Security.py +0 -0
  51. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Service.py +0 -0
  52. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ServiceClass.py +0 -0
  53. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/ServiceError.py +0 -0
  54. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Standard.py +0 -0
  55. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/StateError.py +0 -0
  56. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/Task.py +0 -0
  57. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/VdeStateError.py +0 -0
  58. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/enums/__init__.py +0 -0
  59. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/gurux_dlms/internal/_GXCommon.py +0 -0
  60. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/logger.py +0 -0
  61. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/py.typed +0 -0
  62. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/services.py +0 -0
  63. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/session.py +0 -0
  64. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client/settings.py +0 -0
  65. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client.egg-info/SOURCES.txt +0 -0
  66. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client.egg-info/dependency_links.txt +0 -0
  67. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client.egg-info/entry_points.txt +0 -0
  68. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client.egg-info/requires.txt +0 -0
  69. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/src/DLMS_SPODES_client.egg-info/top_level.txt +0 -0
  70. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/Firmwares/firmwares.dat +0 -0
  71. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/Firmwares/firmwares_1_2_11.dat +0 -0
  72. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/Firmwares/firmwares_1_7_2.dat +0 -0
  73. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/Types/303030/0000600101ff020009054d324d5f31/0000600102ff02000906312e332e3330.xml +0 -0
  74. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/Types/313031/0000600101ff020009054d324d5f31/0000600102ff02000906312e322e3131.xml +0 -0
  75. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/config.toml +0 -0
  76. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/name2.csv +0 -0
  77. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/test_logger.py +0 -0
  78. {dlms_spodes_client-0.19.6 → dlms_spodes_client-0.19.8}/test/test_services.py +0 -0
  79. {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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DLMS_SPODES_client
3
- Version: 0.19.6
3
+ Version: 0.19.8
4
4
  Summary: dlms-spodes
5
5
  Author-email: Serj Kotilevski <youserj@outlook.com>
6
6
  Project-URL: Source, https://github.com/youserj/SPODESclient_prj
@@ -15,7 +15,7 @@ exclude = ["Types"]
15
15
 
16
16
  [project]
17
17
  name = "DLMS_SPODES_client"
18
- version = "0.19.6"
18
+ version = "0.19.8"
19
19
  requires-python = ">= 3.12"
20
20
  authors = [
21
21
  {name="Serj Kotilevski", email="youserj@outlook.com"}
@@ -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 _GXCommon.getObjectCount(buff) > len(buff) - buff.position:
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 p.command == XDLMSAPDU.DATA_NOTIFICATION or p.command == XDLMSAPDU.EVENT_NOTIFICATION_REQUEST:
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 = p.command != ACSEAPDU.AARQ and p.command != ACSEAPDU.AARE and self.settings.cipher and self.settings.cipher.security != Security.NONE
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 self.settings.gateway and self.settings.gateway.physicalDeviceAddress:
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 p.command != XDLMSAPDU.GET_REQUEST and p.data and reply:
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 p.multipleBlocks and not self.negotiated_conformance.general_block_transfer:
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 p.multipleBlocks and not self.negotiated_conformance.general_block_transfer:
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 self.settings.is_multiple_block() and self.negotiated_conformance.general_block_transfer:
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 p.status != 0 and p.command == XDLMSAPDU.GET_RESPONSE:
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 p.status != 0xFF and p.command != XDLMSAPDU.GENERAL_BLOCK_TRANSFER:
1665
- if p.status != 0 and p.command == XDLMSAPDU.GET_RESPONSE:
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 ciphering and p.command != XDLMSAPDU.GENERAL_BLOCK_TRANSFER:
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 p.command != XDLMSAPDU.GET_REQUEST and len_ + len(reply) > self.settings.maxPduSize:
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 (self.settings.gateway and self.settings.gateway.physicalDeviceAddress) and \
1699
- not (p.command == XDLMSAPDU.GENERAL_BLOCK_TRANSFER or (p.multipleBlocks and self.negotiated_conformance.general_block_transfer)):
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 ciphering and reply and not self.negotiated_conformance.general_block_transfer and p.command != XDLMSAPDU.RELEASE_REQUEST:
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 p.command == XDLMSAPDU.GENERAL_BLOCK_TRANSFER or (p.multipleBlocks and self.negotiated_conformance.general_block_transfer):
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 |= 0x40
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 p.command != XDLMSAPDU.DATA_NOTIFICATION and p.blockNumberAck != 0:
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 self.settings.gateway and self.settings.gateway.physicalDeviceAddress:
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 p.command == ACSEAPDU.AARQ and p.command == XDLMSAPDU.GET_REQUEST:
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 not p.data or p.data.position == p.data.size:
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.count != self.settings.index
24
- """ Are there more data to send or more data to receive. DEPRECATED, USE: client.setting.is_multiple_block """
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:
@@ -176,7 +176,6 @@ class GXDLMSSettings:
176
176
  # update invoke ID.
177
177
  #
178
178
  def updateInvokeId(self, value):
179
- #pylint: disable=bad-option-value,redefined-variable-type
180
179
  if (value & 0x80) != 0:
181
180
  self.priority = Priority.HIGH
182
181
  else:
@@ -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 WriteParTranscript(SimpleCopy, OK):
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
- value = int(float(self.value) * 10 ** -int(s_u.scaler))
1728
- data.set(self.value)
1729
- return await WriteAttribute(
1730
- ln=self.par.obis,
1731
- index=self.par.i,
1732
- value=data.encoding
1733
- ).exchange(c)
1734
-
1735
-
1736
- Ts = TypeVarTuple("Ts")
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
- @dataclass
1740
- class WriteParTranscripts(SimpleCopy, Sequence[*Ts]):
1792
+ class WriteTranscripts(SimpleCopy, _List[result.Ok]):
1741
1793
  """write by ParValues[Transcript] list"""
1742
- par_values: list[ParValues[cdt.Transcript]]
1743
- msg: str = ""
1794
+ par_values: tuple[tuple[Parameter, cdt.Transcript], ...]
1795
+ err_ignore: bool
1744
1796
 
1745
- async def exchange(self, c: Client) -> result.Sequence[*Ts] | result.Error:
1746
- res = result.Sequence()
1747
- for par_value in self.par_values:
1748
- if isinstance(res_one := await WriteParTranscript(*par_value).exchange(c), result.Error):
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 = res.add(res_one)
1810
+ res.append(res_one)
1751
1811
  return res
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DLMS_SPODES_client
3
- Version: 0.19.6
3
+ Version: 0.19.8
4
4
  Summary: dlms-spodes
5
5
  Author-email: Serj Kotilevski <youserj@outlook.com>
6
6
  Project-URL: Source, https://github.com/youserj/SPODESclient_prj