You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by hu...@apache.org on 2024/10/29 09:45:42 UTC

(plc4x) branch feat/umas_write updated (6f959f4a73 -> 422055d1e7)

This is an automated email from the ASF dual-hosted git repository.

hutcheb pushed a change to branch feat/umas_write
in repository https://gitbox.apache.org/repos/asf/plc4x.git


    from 6f959f4a73 fix(plc4py/umas): Start testing all the data types.
     new 8d514900f4 feat(plc4py/umas): Update documentation, test and look at random datatypes
     add 750092535b build(deps): bump org.apache.maven.shared:maven-dependency-analyzer (#1828)
     add 6c6d933003 build(deps): bump nl.jqno.equalsverifier:equalsverifier (#1824)
     add 1f05ed4378 build(deps): bump mypy from 1.12.0 to 1.12.1 in /plc4py (#1836)
     add 141b342fbd build(deps): bump coverage from 7.6.3 to 7.6.4 in /plc4py (#1835)
     add 947c6657a4 build(deps): bump virtualenv from 20.26.6 to 20.27.0 in /plc4py (#1831)
     add 4d912a757d build(deps): bump junit.jupiter.version from 5.11.2 to 5.11.3 (#1837)
     add 2e92314dd5 build(deps): bump com.google.googlejavaformat:google-java-format (#1838)
     add 886c1e72ce fix(plc4j): Use pre-provisioned security keys for OPC-UA tests.
     add 431cf2460d fix(plc4j): Use pre-provisioned security keys for OPC-UA tests.
     add 5e8fa8b6ef chore(plc4j): Reduce log level of opc-ua driver tests.
     add 8b6c7a9b30 build(deps): bump mypy from 1.12.1 to 1.13.0 in /plc4py (#1840)
     add 61f95d7366 fix(code-gen/go): sub types should now be assignable
     add ccce45013b build(deps): bump io.vavr:vavr from 0.10.4 to 0.10.5 (#1843)
     add babee86a4d build(deps-dev): bump com.google.cloud.tools:jib-core (#1842)
     add 5be656d7df build(deps): bump github.com/fatih/color in /plc4go (#1841)
     add 654802f840 build(deps): bump org.apache.maven.plugins:maven-failsafe-plugin (#1847)
     add b0afc8ce8a build(deps): bump mockito.version from 5.14.1 to 5.14.2 (#1846)
     add 862efa519b Draft of metadata API with timestamp tracking capabilities.
     add 35b69bd6dd build(deps): bump org.cyclonedx:cyclonedx-maven-plugin (#1849)
     add c936cf26f8 build(deps): bump org.apache.maven.plugins:maven-dependency-plugin (#1848)
     new e4dc8ecfa0 Merge branch 'develop' into feat/umas_write
     new 422055d1e7 fix(plc4py/modbus): Update trailing white space in modebus tests

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../templates/go/complex-type-template.go.ftlh     |   5 +-
 .../python/PythonLanguageTemplateHelper.java       |   9 +-
 .../python/complex-type-template.python.ftlh       |   2 +-
 .../templates/python/data-io-template.python.ftlh  |   8 +-
 .../protocols/opcua/ParserSerializerTestsuite.xml  |  46 +--
 plc4go/go.mod                                      |   2 +-
 plc4go/go.sum                                      |   4 +-
 .../readwrite/model/CIPEncapsulationPacket.go      |   5 +-
 .../abeth/readwrite/model/DF1RequestCommand.go     |   5 +-
 .../abeth/readwrite/model/DF1RequestMessage.go     |   5 +-
 .../abeth/readwrite/model/DF1ResponseMessage.go    |   5 +-
 .../discovery/readwrite/model/AdsDiscoveryBlock.go |   5 +-
 .../ads/readwrite/model/AdsMultiRequestItem.go     |   5 +-
 plc4go/protocols/ads/readwrite/model/AmsPacket.go  |   5 +-
 plc4go/protocols/bacnetip/readwrite/model/APDU.go  |   5 +-
 .../readwrite/model/BACnetApplicationTag.go        |   7 +-
 .../readwrite/model/BACnetCalendarEntry.go         |   5 +-
 .../bacnetip/readwrite/model/BACnetChannelValue.go |   5 +-
 .../bacnetip/readwrite/model/BACnetClientCOV.go    |   5 +-
 .../model/BACnetConfirmedServiceRequest.go         |   5 +-
 ...edServiceRequestAtomicReadFileStreamOrRecord.go |   5 +-
 ...rviceRequestConfirmedTextMessageMessageClass.go |   5 +-
 .../BACnetConfirmedServiceRequestReadRangeRange.go |   5 +-
 .../readwrite/model/BACnetConstructedData.go       |   5 +-
 .../bacnetip/readwrite/model/BACnetContextTag.go   |   7 +-
 .../bacnetip/readwrite/model/BACnetError.go        |   5 +-
 .../model/BACnetEventLogRecordLogDatum.go          |   5 +-
 .../readwrite/model/BACnetEventParameter.go        |   5 +-
 ...BACnetEventParameterChangeOfValueCivCriteria.go |   5 +-
 .../readwrite/model/BACnetFaultParameter.go        |   5 +-
 ...etFaultParameterFaultExtendedParametersEntry.go |   5 +-
 ...tFaultParameterFaultOutOfRangeMaxNormalValue.go |   5 +-
 ...tFaultParameterFaultOutOfRangeMinNormalValue.go |   5 +-
 .../bacnetip/readwrite/model/BACnetHostAddress.go  |   5 +-
 .../model/BACnetLandingCallStatusCommand.go        |   5 +-
 .../bacnetip/readwrite/model/BACnetLogData.go      |   5 +-
 .../readwrite/model/BACnetLogDataLogDataEntry.go   |   5 +-
 .../readwrite/model/BACnetLogRecordLogDatum.go     |   5 +-
 .../model/BACnetNotificationParameters.go          |   5 +-
 ...ationParametersChangeOfDiscreteValueNewValue.go |   5 +-
 ...tNotificationParametersChangeOfValueNewValue.go |   5 +-
 .../readwrite/model/BACnetOptionalBinaryPV.go      |   5 +-
 .../model/BACnetOptionalCharacterString.go         |   5 +-
 .../bacnetip/readwrite/model/BACnetOptionalREAL.go |   5 +-
 .../readwrite/model/BACnetOptionalUnsigned.go      |   5 +-
 .../readwrite/model/BACnetPriorityValue.go         |   5 +-
 .../readwrite/model/BACnetProcessIdSelection.go    |   5 +-
 .../BACnetPropertyAccessResultAccessResult.go      |   5 +-
 .../readwrite/model/BACnetPropertyStates.go        |   5 +-
 .../bacnetip/readwrite/model/BACnetRecipient.go    |   5 +-
 .../bacnetip/readwrite/model/BACnetScale.go        |   5 +-
 .../bacnetip/readwrite/model/BACnetServiceAck.go   |   5 +-
 ...BACnetServiceAckAtomicReadFileStreamOrRecord.go |   5 +-
 .../bacnetip/readwrite/model/BACnetShedLevel.go    |   5 +-
 .../readwrite/model/BACnetSpecialEventPeriod.go    |   5 +-
 .../bacnetip/readwrite/model/BACnetTimeStamp.go    |   5 +-
 .../readwrite/model/BACnetTimerStateChangeValue.go |   5 +-
 .../model/BACnetUnconfirmedServiceRequest.go       |   5 +-
 .../BACnetUnconfirmedServiceRequestWhoHasObject.go |   5 +-
 .../bacnetip/readwrite/model/BACnetValueSource.go  |   5 +-
 plc4go/protocols/bacnetip/readwrite/model/BVLC.go  |   5 +-
 plc4go/protocols/bacnetip/readwrite/model/NLM.go   |   5 +-
 .../cbus/readwrite/model/AccessControlData.go      |   5 +-
 .../cbus/readwrite/model/AirConditioningData.go    |   5 +-
 plc4go/protocols/cbus/readwrite/model/CALData.go   |   5 +-
 plc4go/protocols/cbus/readwrite/model/CALReply.go  |   9 +-
 .../protocols/cbus/readwrite/model/CBusCommand.go  |   7 +-
 .../protocols/cbus/readwrite/model/CBusMessage.go  |   5 +-
 .../model/CBusPointToMultiPointCommand.go          |   5 +-
 .../readwrite/model/CBusPointToPointCommand.go     |   5 +-
 .../model/CBusPointToPointToMultiPointCommand.go   |   5 +-
 .../readwrite/model/ClockAndTimekeepingData.go     |   5 +-
 .../protocols/cbus/readwrite/model/EncodedReply.go |   5 +-
 .../cbus/readwrite/model/ErrorReportingData.go     |   5 +-
 .../model/ErrorReportingSystemCategoryType.go      |   5 +-
 .../cbus/readwrite/model/IdentifyReplyCommand.go   |   5 +-
 .../cbus/readwrite/model/LevelInformation.go       |   7 +-
 .../protocols/cbus/readwrite/model/LightingData.go |   5 +-
 .../cbus/readwrite/model/MeasurementData.go        |   5 +-
 .../readwrite/model/MediaTransportControlData.go   |   5 +-
 .../protocols/cbus/readwrite/model/MeteringData.go |   5 +-
 .../protocols/cbus/readwrite/model/MonitoredSAL.go |   7 +-
 .../cbus/readwrite/model/ParameterValue.go         |   5 +-
 plc4go/protocols/cbus/readwrite/model/Reply.go     |   5 +-
 .../cbus/readwrite/model/ReplyOrConfirmation.go    |   5 +-
 plc4go/protocols/cbus/readwrite/model/Request.go   |   5 +-
 plc4go/protocols/cbus/readwrite/model/SALData.go   |   7 +-
 .../protocols/cbus/readwrite/model/SecurityData.go |   5 +-
 .../cbus/readwrite/model/StatusRequest.go          |   5 +-
 .../cbus/readwrite/model/TelephonyData.go          |   5 +-
 .../cbus/readwrite/model/TriggerControlData.go     |   5 +-
 plc4go/protocols/df1/readwrite/model/DF1Command.go |   5 +-
 plc4go/protocols/df1/readwrite/model/DF1Symbol.go  |   5 +-
 plc4go/protocols/eip/readwrite/model/CipService.go |   5 +-
 .../eip/readwrite/model/CommandSpecificDataItem.go |   5 +-
 .../eip/readwrite/model/DataSegmentType.go         |   5 +-
 plc4go/protocols/eip/readwrite/model/EipPacket.go  |   5 +-
 .../eip/readwrite/model/LogicalSegmentType.go      |   5 +-
 .../protocols/eip/readwrite/model/PathSegment.go   |   5 +-
 .../eip/readwrite/model/PortSegmentType.go         |   5 +-
 plc4go/protocols/eip/readwrite/model/TypeId.go     |   5 +-
 .../firmata/readwrite/model/FirmataCommand.go      |   5 +-
 .../firmata/readwrite/model/FirmataMessage.go      |   5 +-
 .../firmata/readwrite/model/SysexCommand.go        |   5 +-
 plc4go/protocols/knxnetip/readwrite/model/Apdu.go  |   5 +-
 .../knxnetip/readwrite/model/ApduControl.go        |   5 +-
 .../protocols/knxnetip/readwrite/model/ApduData.go |   5 +-
 .../knxnetip/readwrite/model/ApduDataExt.go        |   5 +-
 plc4go/protocols/knxnetip/readwrite/model/CEMI.go  |   5 +-
 .../readwrite/model/CEMIAdditionalInformation.go   |   5 +-
 .../knxnetip/readwrite/model/ComObjectTable.go     |   5 +-
 .../model/ConnectionRequestInformation.go          |   5 +-
 .../readwrite/model/ConnectionResponseDataBlock.go |   5 +-
 .../knxnetip/readwrite/model/KnxGroupAddress.go    |   5 +-
 .../knxnetip/readwrite/model/KnxManufacturer.go    |  26 +-
 .../knxnetip/readwrite/model/KnxNetIpMessage.go    |   5 +-
 .../knxnetip/readwrite/model/LDataFrame.go         |   5 +-
 .../knxnetip/readwrite/model/ServiceId.go          |   5 +-
 .../protocols/modbus/readwrite/model/ModbusADU.go  |   5 +-
 .../protocols/modbus/readwrite/model/ModbusPDU.go  |   5 +-
 .../readwrite/model/ExtensionObjectDefinition.go   |   5 +-
 .../protocols/opcua/readwrite/model/MessagePDU.go  |   7 +-
 .../opcua/readwrite/model/NodeIdTypeDefinition.go  |   5 +-
 .../opcua/readwrite/model/OpenChannelMessage.go    |   5 +-
 plc4go/protocols/opcua/readwrite/model/Payload.go  |   5 +-
 .../readwrite/model/UserIdentityTokenDefinition.go |   5 +-
 plc4go/protocols/opcua/readwrite/model/Variant.go  |   5 +-
 plc4go/protocols/s7/readwrite/model/COTPPacket.go  |   5 +-
 .../protocols/s7/readwrite/model/COTPParameter.go  |   5 +-
 .../s7/readwrite/model/CycServiceItemType.go       |   5 +-
 plc4go/protocols/s7/readwrite/model/S7Address.go   |   5 +-
 .../s7/readwrite/model/S7DataAlarmMessage.go       |   5 +-
 plc4go/protocols/s7/readwrite/model/S7Message.go   |   5 +-
 plc4go/protocols/s7/readwrite/model/S7Parameter.go |   5 +-
 .../s7/readwrite/model/S7ParameterUserDataItem.go  |   5 +-
 plc4go/protocols/s7/readwrite/model/S7Payload.go   |   5 +-
 .../s7/readwrite/model/S7PayloadUserDataItem.go    |   5 +-
 .../readwrite/model/S7VarRequestParameterItem.go   |   5 +-
 .../plc4x/java/api/messages/PlcMetadataKeys.java}  |  18 +-
 .../plc4x/java/api/messages/PlcTagResponse.java    |   6 +
 .../apache/plc4x/java/api/metadata/Metadata.java   |  89 +++++
 .../plc4x/java/api/metadata/time/TimeSource.java}  |  16 +-
 .../plc4x/java/ads/protocol/AdsProtocolLogic.java  |  65 +++-
 plc4j/drivers/opcua/pom.xml                        |   2 +-
 ...rtificateVerifier.java => OpcMetadataKeys.java} |  19 +-
 .../java/opcua/protocol/OpcuaProtocolLogic.java    |  41 ++-
 .../opcua/protocol/OpcuaSubscriptionHandle.java    |  17 +-
 .../plc4x/java/opcua/tag/OpcuaQualityStatus.java   |  58 +++
 .../apache/plc4x/java/opcua/KeystoreGenerator.java | 115 ++++++
 .../apache/plc4x/java/opcua/MiloTestContainer.java |   9 +-
 .../plc4x/java/opcua/OpcuaPlcDriverTest.java       | 144 +++++---
 .../protocol/OpcuaSubscriptionHandleTest.java      |  27 +-
 .../milo/examples/server/TestMiloServer.java       |   2 -
 .../opcua/src/test/resources/logback-test.xml      |   2 +
 .../apache/plc4x/java/s7/events/S7AlarmEvent.java  | 317 ++++++++--------
 .../apache/plc4x/java/s7/events/S7CyclicEvent.java | 217 ++++-------
 .../apache/plc4x/java/s7/events/S7EventBase.java   |  59 +++
 .../apache/plc4x/java/s7/events/S7ModeEvent.java   |  18 +-
 .../apache/plc4x/java/s7/events/S7SysEvent.java    |  55 ++-
 .../apache/plc4x/java/s7/events/S7UserEvent.java   |  13 +-
 .../s7/readwrite/protocol/S7ProtocolLogic.java     |   6 +-
 .../java/spi/messages/DefaultPlcReadResponse.java  |  30 ++
 .../spi/messages/DefaultPlcSubscriptionEvent.java  |  13 +-
 .../java/spi/messages/DefaultPlcWriteResponse.java |  30 ++
 .../plc4x/java/spi/metadata/DefaultMetadata.java   | 132 +++++++
 .../driver/internal/validator/ApiValidator.java    |   5 +
 .../test/driver/xmlunit/SkipAttributeFilter.java}  |  18 +-
 .../driver/xmlunit/SkipDifferenceEvaluator.java    |  56 +++
 plc4py/plc4py/api/messages/PlcResponse.py          |   7 +-
 plc4py/plc4py/drivers/modbus/ModbusConnection.py   |   2 +-
 plc4py/plc4py/drivers/modbus/ModbusDevice.py       |   1 +
 plc4py/plc4py/drivers/umas/UmasDevice.py           |  90 ++++-
 plc4py/plc4py/drivers/umas/UmasTag.py              |   6 +-
 plc4py/plc4py/drivers/umas/UmasVariables.py        |  35 +-
 .../plc4py/protocols/modbus/readwrite/DataItem.py  |   8 +-
 .../plc4py/protocols/modbus/readwrite/ModbusADU.py |   2 +-
 .../protocols/modbus/readwrite/ModbusAsciiADU.py   |   2 +-
 .../plc4py/protocols/modbus/readwrite/ModbusPDU.py |   2 +-
 .../modbus/readwrite/ModbusPDUDiagnosticRequest.py |   2 +-
 .../readwrite/ModbusPDUDiagnosticResponse.py       |   2 +-
 .../protocols/modbus/readwrite/ModbusPDUError.py   |   2 +-
 .../ModbusPDUGetComEventCounterRequest.py          |   2 +-
 .../ModbusPDUGetComEventCounterResponse.py         |   2 +-
 .../readwrite/ModbusPDUGetComEventLogRequest.py    |   2 +-
 .../readwrite/ModbusPDUGetComEventLogResponse.py   |   2 +-
 .../ModbusPDUMaskWriteHoldingRegisterRequest.py    |   2 +-
 .../ModbusPDUMaskWriteHoldingRegisterResponse.py   |   2 +-
 .../modbus/readwrite/ModbusPDUReadCoilsRequest.py  |   2 +-
 .../modbus/readwrite/ModbusPDUReadCoilsResponse.py |   2 +-
 .../ModbusPDUReadDeviceIdentificationRequest.py    |   2 +-
 .../ModbusPDUReadDeviceIdentificationResponse.py   |   2 +-
 .../ModbusPDUReadDiscreteInputsRequest.py          |   2 +-
 .../ModbusPDUReadDiscreteInputsResponse.py         |   2 +-
 .../ModbusPDUReadExceptionStatusRequest.py         |   2 +-
 .../ModbusPDUReadExceptionStatusResponse.py        |   2 +-
 .../readwrite/ModbusPDUReadFifoQueueRequest.py     |   2 +-
 .../readwrite/ModbusPDUReadFifoQueueResponse.py    |   2 +-
 .../readwrite/ModbusPDUReadFileRecordRequest.py    |   2 +-
 .../readwrite/ModbusPDUReadFileRecordResponse.py   |   2 +-
 .../ModbusPDUReadHoldingRegistersRequest.py        |   2 +-
 .../ModbusPDUReadHoldingRegistersResponse.py       |   2 +-
 .../ModbusPDUReadInputRegistersRequest.py          |   2 +-
 .../ModbusPDUReadInputRegistersResponse.py         |   2 +-
 ...sPDUReadWriteMultipleHoldingRegistersRequest.py |   2 +-
 ...PDUReadWriteMultipleHoldingRegistersResponse.py |   2 +-
 .../readwrite/ModbusPDUReportServerIdRequest.py    |   2 +-
 .../readwrite/ModbusPDUReportServerIdResponse.py   |   2 +-
 .../readwrite/ModbusPDUWriteFileRecordRequest.py   |   2 +-
 .../readwrite/ModbusPDUWriteFileRecordResponse.py  |   2 +-
 .../ModbusPDUWriteMultipleCoilsRequest.py          |   2 +-
 .../ModbusPDUWriteMultipleCoilsResponse.py         |   2 +-
 ...odbusPDUWriteMultipleHoldingRegistersRequest.py |   2 +-
 ...dbusPDUWriteMultipleHoldingRegistersResponse.py |   2 +-
 .../readwrite/ModbusPDUWriteSingleCoilRequest.py   |   2 +-
 .../readwrite/ModbusPDUWriteSingleCoilResponse.py  |   2 +-
 .../ModbusPDUWriteSingleRegisterRequest.py         |   2 +-
 .../ModbusPDUWriteSingleRegisterResponse.py        |   2 +-
 .../protocols/modbus/readwrite/ModbusRtuADU.py     |   2 +-
 .../protocols/modbus/readwrite/ModbusTcpADU.py     |   2 +-
 .../protocols/simulated/readwrite/DataItem.py      |  12 +-
 plc4py/plc4py/protocols/umas/StaticHelper.py       |   7 +-
 plc4py/plc4py/protocols/umas/readwrite/DataItem.py |  57 +--
 .../protocols/umas/readwrite/UmasDataType.py       |  52 +--
 plc4py/plc4py/spi/generation/WriteBuffer.py        |  14 +
 plc4py/plc4py/spi/messages/PlcWriter.py            |   2 +-
 plc4py/plc4py/spi/messages/utils/ResponseItem.py   |  30 +-
 plc4py/plc4py/utils/ConnectionStringHandling.py    |   8 +
 plc4py/pom.xml                                     |  18 +
 plc4py/pyproject.toml                              |  81 +++++
 plc4py/requirements.txt                            |  54 ---
 plc4py/{setup.py => setup_old.py}                  |   1 +
 .../drivers/modbus/test_modbus_connection.py       | 399 +++++----------------
 .../plc4py/drivers/umas/test_umas_connection.py    | 256 ++++---------
 pom.xml                                            |  18 +-
 .../resources/protocols/ads/DriverTestsuite.xml    |  12 +
 .../protocols/knxnetip/knx-master-data.mspec       |   5 +-
 .../src/main/resources/protocols/umas/umas.mspec   |  70 ++--
 src/site/asciidoc/users/protocols/umas.adoc        | 119 +-----
 238 files changed, 2309 insertions(+), 1512 deletions(-)
 copy plc4j/{drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/security/PermissiveCertificateVerifier.java => api/src/main/java/org/apache/plc4x/java/api/messages/PlcMetadataKeys.java} (61%)
 create mode 100644 plc4j/api/src/main/java/org/apache/plc4x/java/api/metadata/Metadata.java
 copy plc4j/{drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/security/CertificateVerifier.java => api/src/main/java/org/apache/plc4x/java/api/metadata/time/TimeSource.java} (67%)
 copy plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/{security/PermissiveCertificateVerifier.java => OpcMetadataKeys.java} (60%)
 create mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/tag/OpcuaQualityStatus.java
 create mode 100644 plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/KeystoreGenerator.java
 create mode 100644 plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7EventBase.java
 create mode 100644 plc4j/spi/src/main/java/org/apache/plc4x/java/spi/metadata/DefaultMetadata.java
 copy plc4j/{drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/security/PermissiveCertificateVerifier.java => utils/test-utils/src/main/java/org/apache/plc4x/test/driver/xmlunit/SkipAttributeFilter.java} (65%)
 create mode 100644 plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/xmlunit/SkipDifferenceEvaluator.java
 create mode 100644 plc4py/pyproject.toml
 delete mode 100644 plc4py/requirements.txt
 rename plc4py/{setup.py => setup_old.py} (99%)


(plc4x) 01/03: feat(plc4py/umas): Update documentation, test and look at random datatypes

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hutcheb pushed a commit to branch feat/umas_write
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 8d514900f4bf667f071993050b1e5d30338eb9d1
Author: hutcheb <be...@gmail.com>
AuthorDate: Tue Oct 29 17:38:32 2024 +0800

    feat(plc4py/umas): Update documentation, test and look at random datatypes
---
 .../python/PythonLanguageTemplateHelper.java       |   9 +-
 .../python/complex-type-template.python.ftlh       |   2 +-
 .../templates/python/data-io-template.python.ftlh  |   8 +-
 plc4py/plc4py/api/messages/PlcResponse.py          |   7 +-
 plc4py/plc4py/drivers/modbus/ModbusConnection.py   |   2 +-
 plc4py/plc4py/drivers/modbus/ModbusDevice.py       |   1 +
 plc4py/plc4py/drivers/umas/UmasDevice.py           |  90 ++++-
 plc4py/plc4py/drivers/umas/UmasTag.py              |   6 +-
 plc4py/plc4py/drivers/umas/UmasVariables.py        |  35 +-
 .../plc4py/protocols/modbus/readwrite/DataItem.py  |   8 +-
 .../plc4py/protocols/modbus/readwrite/ModbusADU.py |   2 +-
 .../protocols/modbus/readwrite/ModbusAsciiADU.py   |   2 +-
 .../plc4py/protocols/modbus/readwrite/ModbusPDU.py |   2 +-
 .../modbus/readwrite/ModbusPDUDiagnosticRequest.py |   2 +-
 .../readwrite/ModbusPDUDiagnosticResponse.py       |   2 +-
 .../protocols/modbus/readwrite/ModbusPDUError.py   |   2 +-
 .../ModbusPDUGetComEventCounterRequest.py          |   2 +-
 .../ModbusPDUGetComEventCounterResponse.py         |   2 +-
 .../readwrite/ModbusPDUGetComEventLogRequest.py    |   2 +-
 .../readwrite/ModbusPDUGetComEventLogResponse.py   |   2 +-
 .../ModbusPDUMaskWriteHoldingRegisterRequest.py    |   2 +-
 .../ModbusPDUMaskWriteHoldingRegisterResponse.py   |   2 +-
 .../modbus/readwrite/ModbusPDUReadCoilsRequest.py  |   2 +-
 .../modbus/readwrite/ModbusPDUReadCoilsResponse.py |   2 +-
 .../ModbusPDUReadDeviceIdentificationRequest.py    |   2 +-
 .../ModbusPDUReadDeviceIdentificationResponse.py   |   2 +-
 .../ModbusPDUReadDiscreteInputsRequest.py          |   2 +-
 .../ModbusPDUReadDiscreteInputsResponse.py         |   2 +-
 .../ModbusPDUReadExceptionStatusRequest.py         |   2 +-
 .../ModbusPDUReadExceptionStatusResponse.py        |   2 +-
 .../readwrite/ModbusPDUReadFifoQueueRequest.py     |   2 +-
 .../readwrite/ModbusPDUReadFifoQueueResponse.py    |   2 +-
 .../readwrite/ModbusPDUReadFileRecordRequest.py    |   2 +-
 .../readwrite/ModbusPDUReadFileRecordResponse.py   |   2 +-
 .../ModbusPDUReadHoldingRegistersRequest.py        |   2 +-
 .../ModbusPDUReadHoldingRegistersResponse.py       |   2 +-
 .../ModbusPDUReadInputRegistersRequest.py          |   2 +-
 .../ModbusPDUReadInputRegistersResponse.py         |   2 +-
 ...sPDUReadWriteMultipleHoldingRegistersRequest.py |   2 +-
 ...PDUReadWriteMultipleHoldingRegistersResponse.py |   2 +-
 .../readwrite/ModbusPDUReportServerIdRequest.py    |   2 +-
 .../readwrite/ModbusPDUReportServerIdResponse.py   |   2 +-
 .../readwrite/ModbusPDUWriteFileRecordRequest.py   |   2 +-
 .../readwrite/ModbusPDUWriteFileRecordResponse.py  |   2 +-
 .../ModbusPDUWriteMultipleCoilsRequest.py          |   2 +-
 .../ModbusPDUWriteMultipleCoilsResponse.py         |   2 +-
 ...odbusPDUWriteMultipleHoldingRegistersRequest.py |   2 +-
 ...dbusPDUWriteMultipleHoldingRegistersResponse.py |   2 +-
 .../readwrite/ModbusPDUWriteSingleCoilRequest.py   |   2 +-
 .../readwrite/ModbusPDUWriteSingleCoilResponse.py  |   2 +-
 .../ModbusPDUWriteSingleRegisterRequest.py         |   2 +-
 .../ModbusPDUWriteSingleRegisterResponse.py        |   2 +-
 .../protocols/modbus/readwrite/ModbusRtuADU.py     |   2 +-
 .../protocols/modbus/readwrite/ModbusTcpADU.py     |   2 +-
 .../protocols/simulated/readwrite/DataItem.py      |  12 +-
 plc4py/plc4py/protocols/umas/StaticHelper.py       |   7 +-
 plc4py/plc4py/protocols/umas/readwrite/DataItem.py |  57 +--
 .../protocols/umas/readwrite/UmasDataType.py       |  52 +--
 plc4py/plc4py/spi/generation/WriteBuffer.py        |  14 +
 plc4py/plc4py/spi/messages/PlcWriter.py            |   2 +-
 plc4py/plc4py/spi/messages/utils/ResponseItem.py   |  30 +-
 plc4py/plc4py/utils/ConnectionStringHandling.py    |   8 +
 plc4py/pom.xml                                     |  18 +
 plc4py/pyproject.toml                              |  81 +++++
 plc4py/requirements.txt                            |  54 ---
 plc4py/{setup.py => setup_old.py}                  |   1 +
 .../drivers/modbus/test_modbus_connection.py       | 398 +++++----------------
 .../plc4py/drivers/umas/test_umas_connection.py    | 256 ++++---------
 .../src/main/resources/protocols/umas/umas.mspec   |  70 ++--
 src/site/asciidoc/users/protocols/umas.adoc        | 119 +-----
 70 files changed, 594 insertions(+), 841 deletions(-)

diff --git a/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java b/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java
index c4054c61ce..c842e5ebe9 100644
--- a/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java
+++ b/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java
@@ -895,7 +895,8 @@ public class PythonLanguageTemplateHelper extends BaseFreemarkerLanguageTemplate
             case BIT:
                 return "write_buffer.write_bit(" + fieldName + ", \"" + logicalName + "\"" + writerArgsString + ")";
             case BYTE:
-                return "write_buffer.write_byte(" + fieldName + ", \"" + logicalName + "\"" + writerArgsString + ")";
+                ByteTypeReference byteTypeReference = (ByteTypeReference) simpleTypeReference;
+                return "write_buffer.write_byte(" + fieldName + ", " + byteTypeReference.getSizeInBits() + ", \"" + logicalName + "\"" + writerArgsString + ")";
             case UINT:
                 IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
                 if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
@@ -945,7 +946,7 @@ public class PythonLanguageTemplateHelper extends BaseFreemarkerLanguageTemplate
                     .orElseThrow(() -> new FreemarkerException("Encoding must be a quoted string value")).getValue();
                 String length = Integer.toString(simpleTypeReference.getSizeInBits());
                 return "write_buffer.write_str(" + fieldName + ", " + length + ", \"" +
-                    encoding + "\", \"" + logicalName + "\"" + writerArgsString + ")";
+                    logicalName + "\", \"" + encoding + "\"" + writerArgsString + ")";
             }
             case VSTRING: {
                 VstringTypeReference vstringTypeReference = (VstringTypeReference) simpleTypeReference;
@@ -957,7 +958,7 @@ public class PythonLanguageTemplateHelper extends BaseFreemarkerLanguageTemplate
                 String lengthExpression = toExpression(field, null, vstringTypeReference.getLengthExpression(), null, Collections.singletonList(new DefaultArgument("stringLength", new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.INT, 32))), true, false);
                 String length = Integer.toString(simpleTypeReference.getSizeInBits());
                 return "write_buffer.write_str(" + fieldName + ", " + lengthExpression + ", \"" +
-                    encoding + "\", \"" + logicalName + "\"" + writerArgsString + ")";
+                    logicalName + "\", \"" + encoding + "\"" + writerArgsString + ")";
             }
             case DATE:
             case TIME:
@@ -1511,7 +1512,7 @@ public class PythonLanguageTemplateHelper extends BaseFreemarkerLanguageTemplate
         } else if ((serializerArguments != null) && serializerArguments.stream()
             .anyMatch(argument -> argument.getName().equals(variableLiteralName))) {
             tracer = tracer.dive("serialization argument");
-            return tracer + "self." + camelCaseToSnakeCase(variableLiteralName) +
+            return tracer + camelCaseToSnakeCase(variableLiteralName) +
                 variableLiteral.getChild()
                     .map(child -> "." + camelCaseToSnakeCase(toVariableExpression(field, typeReference, child, parserArguments, serializerArguments, serialize, suppressPointerAccess, true)))
                     .orElse("");
diff --git a/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh b/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh
index 626d950a53..10a98c6a29 100644
--- a/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh
+++ b/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh
@@ -565,7 +565,7 @@ class ${type.name}<#if type.isDiscriminatedParentTypeDefinition()></#if>(<#if ty
             <#if parserArgument.type.isEnumTypeReference()>
             ${helper.camelCaseToSnakeCase(parserArgument.name)} = ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}[${helper.camelCaseToSnakeCase(parserArgument.name)}]
             <#elseif helper.getLanguageTypeNameForTypeReference(parserArgument.type, false) = "bool">
-            <@emitImport import="from distutils.util import strtobool" />
+            <@emitImport import="from plc4py.utils.ConnectionStringHandling import strtobool" />
             ${helper.camelCaseToSnakeCase(parserArgument.name)} = bool(strtobool(${helper.camelCaseToSnakeCase(parserArgument.name)}))
             <#else>
             ${helper.camelCaseToSnakeCase(parserArgument.name)} = ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}(${helper.camelCaseToSnakeCase(parserArgument.name)})
diff --git a/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh b/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh
index 19ad41c98a..1daeb76bcc 100644
--- a/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh
+++ b/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh
@@ -372,7 +372,7 @@ class ${type.name}:
             for val in values.getStruct().get("${arrayField.name}").get_list():
                 <#if elementTypeReference.isByteBased()>
                 value: ${helper.getLanguageTypeNameForField(arrayField)} = val.get_raw()
-                write_buffer.write_byte_array("", value)
+                write_buffer.write_byte(value, 8, "")
                 <#else>
                 value: ${helper.getLanguageTypeNameForField(arrayField)} = val.get_${helper.camelCaseToSnakeCase(helper.getLanguageTypeNameForField(arrayField)?cap_first)}()
                 ${helper.getWriteBufferWriteMethodCall(elementTypeReference.asSimpleTypeReference().orElseThrow(), "value", arrayField)}
@@ -382,7 +382,7 @@ class ${type.name}:
                 <#if elementTypeReference.isByteBased()>
                 <@emitImport import="from typing import List" />
                 value: ${helper.getLanguageTypeNameForField(arrayField)} = val.get_raw()
-                write_buffer.write_byte_array("", value)
+                write_buffer.write_byte(value, 8, "")
                 <#else>
                 value: ${helper.getLanguageTypeNameForTypeReference(elementTypeReference)} = val.get_${helper.camelCaseToSnakeCase(helper.getLanguageTypeNameForTypeReference(elementTypeReference)?cap_first)}()
                 ${helper.getWriteBufferWriteMethodCall(elementTypeReference.asSimpleTypeReference().orElseThrow(), "(" + arrayField.name + ")", arrayField)}
@@ -410,7 +410,9 @@ class ${type.name}:
                     <#case "manual">
                         <#assign manualField=field.asManualField().orElseThrow()>
             # Manual Field (${manualField.name})
-            ${helper.toSerializationExpression(manualField, manualField.type, manualField.serializeExpression, type.parserArguments.orElse(null))}
+            <@emitImport import="from plc4py.protocols.${protocolName} import StaticHelper" />
+            value: PlcValue = _value
+            StaticHelper.${helper.toSerializationExpression(manualField, manualField.type, manualField.serializeExpression, type.parserArguments.orElse(null))}
                     <#break>
 
                     <#case "reserved">
diff --git a/plc4py/plc4py/api/messages/PlcResponse.py b/plc4py/plc4py/api/messages/PlcResponse.py
index 807dba5d43..f61457bd96 100644
--- a/plc4py/plc4py/api/messages/PlcResponse.py
+++ b/plc4py/plc4py/api/messages/PlcResponse.py
@@ -22,7 +22,7 @@ from typing import Dict, List, cast
 from plc4py.api.messages.PlcField import PlcTag
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.api.value.PlcValue import PlcResponseCode, PlcValue
-from plc4py.spi.messages.utils.ResponseItem import ResponseItem
+from plc4py.spi.messages.utils.ResponseItem import ResponseItem, PlcBrowseItem
 
 
 @dataclass
@@ -75,7 +75,7 @@ class PlcWriteResponse(PlcTagResponse):
 
 @dataclass
 class PlcQueryResponse(PlcResponse):
-    tags: Dict[str, List[ResponseItem[PlcTag]]]
+    tags: Dict[str, List[PlcBrowseItem[PlcTag]]]
 
     @property
     def tag_names(self):
@@ -84,5 +84,6 @@ class PlcQueryResponse(PlcResponse):
 
 @dataclass
 class PlcBrowseResponse(PlcQueryResponse):
-    def get_tags(self) -> Dict[str, List[ResponseItem[PlcTag]]]:
+
+    def get_tags(self) -> Dict[str, List[PlcBrowseItem[PlcTag]]]:
         return self.tags
diff --git a/plc4py/plc4py/drivers/modbus/ModbusConnection.py b/plc4py/plc4py/drivers/modbus/ModbusConnection.py
index d12b437f6a..dc91546401 100644
--- a/plc4py/plc4py/drivers/modbus/ModbusConnection.py
+++ b/plc4py/plc4py/drivers/modbus/ModbusConnection.py
@@ -104,7 +104,7 @@ class ModbusConnection(PlcConnection, DefaultPlcReader, DefaultPlcWriter):
                     host=config.host,
                     port=config.port,
                 ),
-                10,
+                15,
             )
         except asyncio.TimeoutError:
             # If the creation times out, cancel the Future
diff --git a/plc4py/plc4py/drivers/modbus/ModbusDevice.py b/plc4py/plc4py/drivers/modbus/ModbusDevice.py
index b52993027a..056d3798bd 100644
--- a/plc4py/plc4py/drivers/modbus/ModbusDevice.py
+++ b/plc4py/plc4py/drivers/modbus/ModbusDevice.py
@@ -209,6 +209,7 @@ class ModbusDevice:
         message_future = loop.create_future()
         values = request.values[request.tag_names[0]]
         if isinstance(tag, ModbusTagCoil):
+            values = self._serialize_data_items(tag, values)
             pdu = ModbusPDUWriteMultipleCoilsRequest(tag.address, tag.quantity, values)
         elif isinstance(tag, ModbusTagDiscreteInput):
             raise PlcRuntimeException(
diff --git a/plc4py/plc4py/drivers/umas/UmasDevice.py b/plc4py/plc4py/drivers/umas/UmasDevice.py
index 593a4e8cd7..cb3ad77075 100644
--- a/plc4py/plc4py/drivers/umas/UmasDevice.py
+++ b/plc4py/plc4py/drivers/umas/UmasDevice.py
@@ -19,9 +19,11 @@
 import asyncio
 from asyncio import AbstractEventLoop, Transport
 from dataclasses import dataclass, field
+from logging import raiseExceptions
 from typing import Dict, List, Tuple, cast
 
-from plc4py.api.exceptions.exceptions import PlcFieldParseException
+from plc4py.drivers.umas.UmasVariables import UmasCustomVariable, UmasArrayVariable
+from plc4py.api.exceptions.exceptions import PlcFieldParseException, PlcRuntimeException
 from plc4py.api.messages.PlcRequest import (
     PlcBrowseRequest,
     PlcReadRequest,
@@ -34,7 +36,7 @@ from plc4py.api.messages.PlcResponse import (
 )
 from plc4py.api.value.PlcValue import PlcResponseCode, PlcValue
 from plc4py.drivers.umas.UmasConfiguration import UmasConfiguration
-from plc4py.drivers.umas.UmasTag import UmasTag
+from plc4py.drivers.umas.UmasTag import UmasTag, UmasTagBuilder
 from plc4py.drivers.umas.UmasVariables import (
     UmasVariable,
     UmasVariableBuilder,
@@ -103,7 +105,11 @@ from plc4py.protocols.umas.readwrite.VariableReadRequestReference import (
     VariableReadRequestReference,
 )
 from plc4py.spi.generation.ReadBuffer import ReadBufferByteBased
-from plc4py.spi.messages.utils.ResponseItem import ResponseItem
+from plc4py.spi.messages.utils.ResponseItem import (
+    ResponseItem,
+    PlcBrowseItem,
+    ArrayInfo,
+)
 from plc4py.utils.GenericTypes import ByteOrder
 from plc4py.protocols.umas.readwrite.UmasPDUWriteVariableRequest import (
     UmasPDUWriteVariableRequestBuilder,
@@ -420,13 +426,11 @@ class UmasDevice:
                 quantity = 1
 
             if request_tag.data_type == None:
-                request_tag.data_type = UmasDataType(
-                    self.variables[request_tag.tag_name].data_type
-                )
+                data_type = UmasDataType(self.variables[request_tag.tag_name].data_type)
+            else:
+                data_type = UmasDataType[request_tag.data_type]
 
-            value = DataItem.static_parse(
-                read_buffer, request_tag.data_type, request_tag.quantity
-            )
+            value = DataItem.static_parse(read_buffer, data_type, request_tag.quantity)
             response_item = ResponseItem(
                 PlcResponseCode.OK,
                 value,
@@ -619,6 +623,66 @@ class UmasDevice:
             response.tags = {**response.tags, **response_chunk.tags}
         return response
 
+    def generate_browse_tree(self, tag) -> PlcBrowseItem[UmasTag]:
+        builder = UmasTagBuilder()
+        if isinstance(tag, UmasElementryVariable):
+            plc_tag = builder.create(
+                tag.variable_name
+                + ":"
+                + str(UmasDataType(tag.data_type).data_type_conversion)
+            )
+
+            return PlcBrowseItem[UmasTag](
+                plc_tag, tag.variable_name, True, True, False, False, False
+            )
+
+        elif isinstance(tag, UmasCustomVariable):
+            plc_tag = builder.create(tag.variable_name)
+            children: Dict[str, "PlcBrowseItem"] = {}
+            for tag_name, child in tag.children.items():
+                children[tag_name] = self.generate_browse_tree(child)
+            return PlcBrowseItem[UmasTag](
+                plc_tag,
+                tag.variable_name,
+                True,
+                True,
+                False,
+                False,
+                False,
+                [],
+                children,
+            )
+        elif isinstance(tag, UmasArrayVariable):
+            plc_tag = builder.create(
+                tag.variable_name
+                + ":"
+                + str(UmasDataType(tag.data_type).data_type_conversion)
+                + "["
+                + str(tag.end_index)
+                + "]"
+            )
+
+            return PlcBrowseItem[UmasTag](
+                plc_tag,
+                tag.variable_name,
+                True,
+                True,
+                False,
+                False,
+                True,
+                [
+                    ArrayInfo(
+                        tag.end_index - tag.start_index + 1,
+                        tag.start_index,
+                        tag.end_index,
+                    )
+                ],
+            )
+        else:
+            raise PlcRuntimeException(
+                f"Variable of type {type(tag).__name__} is not supported"
+            )
+
     async def browse(
         self, request: PlcBrowseRequest, transport: Transport
     ) -> PlcBrowseResponse:
@@ -628,9 +692,9 @@ class UmasDevice:
         loop = asyncio.get_running_loop()
         await self._update_plc_project_info(transport, loop)
         response_items = {}
+
         for key, query in request.queries.items():
-            response_items[key] = [
-                ResponseItem[UmasTag](PlcResponseCode.OK, tag)
-                for tag in self.variables.values()
-            ]
+            response_items[key] = []
+            for tag in self.variables.values():
+                response_items[key].append(self.generate_browse_tree(tag))
         return PlcBrowseResponse(PlcResponseCode.OK, response_items)
diff --git a/plc4py/plc4py/drivers/umas/UmasTag.py b/plc4py/plc4py/drivers/umas/UmasTag.py
index c6f48fdf92..69ab09202b 100644
--- a/plc4py/plc4py/drivers/umas/UmasTag.py
+++ b/plc4py/plc4py/drivers/umas/UmasTag.py
@@ -27,7 +27,7 @@ from plc4py.spi.messages.PlcRequest import TagBuilder
 
 class UmasTag(PlcTag):
     _ADDRESS_PATTERN: str = (
-        "^(?P<tag>[%a-zA-Z_.0-9]+\\[?[0-9]*]?):?(?P<dataType>[A-Z]*):?(?P<elementNb>[0-9]*)"
+        "^(?P<tag>[%a-zA-Z_.0-9]+):?(?P<dataType>[A-Z_]*)(\[(?P<elementNb>[0-9]*)\])?"
     )
 
     _ADDRESS_COMPILED: Pattern[AnyStr] = re.compile(_ADDRESS_PATTERN)
@@ -36,7 +36,7 @@ class UmasTag(PlcTag):
     def __init__(self, tag_name: str, quantity: int, data_type: UmasDataType):
         self.tag_name: str = tag_name
         self.quantity: int = quantity
-        self.data_type: UmasDataType = data_type
+        self.data_type: str = data_type
 
     @classmethod
     def matches(cls, address_string: str):
@@ -60,7 +60,7 @@ class UmasTag(PlcTag):
             else 1
         )
         data_type = (
-            UmasDataType[matcher.group("dataType")]
+            matcher.group("dataType")
             if "dataType" in matcher.groupdict()
             and matcher.group("dataType") is not None
             and len(matcher.group("dataType")) is not 0
diff --git a/plc4py/plc4py/drivers/umas/UmasVariables.py b/plc4py/plc4py/drivers/umas/UmasVariables.py
index 92eb364b02..8a22194eaf 100644
--- a/plc4py/plc4py/drivers/umas/UmasVariables.py
+++ b/plc4py/plc4py/drivers/umas/UmasVariables.py
@@ -94,7 +94,6 @@ class UmasElementryVariable(UmasVariable):
     def get_write_variable_reference(
         self, address: str, value: PlcValue
     ) -> VariableWriteRequestReference:
-        ss = UmasDataType(self.data_type).data_type_size
         write_buffer = WriteBufferByteBased(
             UmasDataType(self.data_type).data_type_size, ByteOrder.LITTLE_ENDIAN
         )
@@ -108,11 +107,11 @@ class UmasElementryVariable(UmasVariable):
         if self.data_type == UmasDataType.STRING.value:
             return VariableWriteRequestReference(
                 is_array=1,
-                data_size_index=UmasDataType(self.data_type).request_size,
+                data_size_index=1,
                 block=self.block_no,
                 base_offset=self.offset,
                 offset=self.base_offset,
-                array_length=16,
+                array_length=len(value.value),
                 record_data=bytearray(write_buffer.bb),
             )
         else:
@@ -204,7 +203,19 @@ class UmasArrayVariable(UmasVariable):
         if len(split_tag_address) > 1:
             address_index = int(split_tag_address[1])
         data_type_enum = UmasDataType(self.data_type)
+
         if address_index:
+            write_buffer = WriteBufferByteBased(
+                UmasDataType(self.data_type).data_type_size * address_index,
+                ByteOrder.LITTLE_ENDIAN,
+            )
+            DataItem.static_serialize(
+                write_buffer,
+                value,
+                UmasDataType(self.data_type),
+                address_index,
+                ByteOrder.LITTLE_ENDIAN,
+            )
             return VariableWriteRequestReference(
                 is_array=0,
                 data_size_index=data_type_enum.request_size,
@@ -212,10 +223,22 @@ class UmasArrayVariable(UmasVariable):
                 base_offset=self.base_offset,
                 offset=self.offset
                 + (address_index - self.start_index) * data_type_enum.data_type_size,
-                array_length=None,
-                record_data=None,
+                array_length=address_index,
+                record_data=bytearray(write_buffer.bb),
             )
         else:
+            write_buffer = WriteBufferByteBased(
+                UmasDataType(self.data_type).data_type_size
+                * (self.end_index - self.start_index + 1),
+                ByteOrder.LITTLE_ENDIAN,
+            )
+            DataItem.static_serialize(
+                write_buffer,
+                value,
+                UmasDataType(self.data_type),
+                self.end_index - self.start_index + 1,
+                ByteOrder.LITTLE_ENDIAN,
+            )
             return VariableWriteRequestReference(
                 is_array=1,
                 data_size_index=data_type_enum.request_size,
@@ -223,7 +246,7 @@ class UmasArrayVariable(UmasVariable):
                 base_offset=self.base_offset,
                 offset=self.offset,
                 array_length=self.end_index - self.start_index + 1,
-                record_data=None,
+                record_data=bytearray(write_buffer.bb),
             )
 
     def get_byte_length(self) -> int:
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/DataItem.py b/plc4py/plc4py/protocols/modbus/readwrite/DataItem.py
index 9d76786554..50fbafeefa 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/DataItem.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/DataItem.py
@@ -697,24 +697,24 @@ class DataItem:
         elif data_type == ModbusDataType.CHAR and number_of_values == int(1):  # CHAR
             # Simple Field (value)
             value: str = _value.get_str()
-            write_buffer.write_str((value), 8, "UTF-8", "value")
+            write_buffer.write_str((value), 8, "value", "UTF-8")
 
         elif data_type == ModbusDataType.CHAR:  # List
             values: PlcList = cast(PlcList, _value)
             for val in values.get_list():
                 value: str = val.get_str()
-                write_buffer.write_str((value), 8, "UTF-8", "value")
+                write_buffer.write_str((value), 8, "value", "UTF-8")
 
         elif data_type == ModbusDataType.WCHAR and number_of_values == int(1):  # WCHAR
             # Simple Field (value)
             value: str = _value.get_str()
-            write_buffer.write_str((value), 16, "UTF-16", "value")
+            write_buffer.write_str((value), 16, "value", "UTF-16")
 
         elif data_type == ModbusDataType.WCHAR:  # List
             values: PlcList = cast(PlcList, _value)
             for val in values.get_list():
                 value: str = val.get_str()
-                write_buffer.write_str((value), 16, "UTF-16", "value")
+                write_buffer.write_str((value), 16, "value", "UTF-16")
 
     @staticmethod
     def get_length_in_bytes(
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusADU.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusADU.py
index 7cac135246..ec7864cbc7 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusADU.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusADU.py
@@ -21,7 +21,6 @@ from dataclasses import dataclass
 
 from abc import ABC
 from abc import abstractmethod
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import ParseException
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
@@ -29,6 +28,7 @@ from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.DriverType import DriverType
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 import math
 
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusAsciiADU.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusAsciiADU.py
index e18f5e9fac..8f78079ba2 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusAsciiADU.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusAsciiADU.py
@@ -19,7 +19,6 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
@@ -29,6 +28,7 @@ from plc4py.protocols.modbus.readwrite.ModbusADU import ModbusADU
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from plc4py.utils.GenericTypes import ByteOrder
 from typing import ClassVar
 import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDU.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDU.py
index d2fbad670b..e03ec11f67 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDU.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDU.py
@@ -21,13 +21,13 @@ from dataclasses import dataclass
 
 from abc import ABC
 from abc import abstractmethod
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import ParseException
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 import math
 
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticRequest.py
index 9d8dc6ecbd..92bab7e1f9 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticResponse.py
index 5644e5cbd7..dc61819220 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUError.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUError.py
index 0d0625be68..f7a542b19b 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUError.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUError.py
@@ -19,7 +19,6 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
@@ -27,6 +26,7 @@ from plc4py.protocols.modbus.readwrite.ModbusErrorCode import ModbusErrorCode
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterRequest.py
index eed5c85f3a..1a8967bbba 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterResponse.py
index ddb93a5e45..0a857bb247 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogRequest.py
index 61327aae3c..68ca6e23df 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogResponse.py
index 2717794df7..f0fbcceb40 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterRequest.py
index 7f594f9608..bf9ec7bfba 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterResponse.py
index 8bddc99dca..9b14ca9e60 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsRequest.py
index 9f95e4d164..72b5180d94 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsResponse.py
index c3ddcba5a1..2c0133cc06 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationRequest.py
index 21418393f2..00a81f2641 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationRequest.py
@@ -19,7 +19,6 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
@@ -29,6 +28,7 @@ from plc4py.protocols.modbus.readwrite.ModbusDeviceInformationLevel import (
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationResponse.py
index 77fa52e63f..558ffd12f0 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationResponse.py
@@ -19,7 +19,6 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
@@ -38,6 +37,7 @@ from plc4py.protocols.modbus.readwrite.ModbusDeviceInformationObject import (
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsRequest.py
index a93d3ca31a..11f544328a 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsResponse.py
index 8f86ea5ad4..54c20fd0ed 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusRequest.py
index 38b316eb94..da9b7c0736 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusResponse.py
index b5641feeab..6c845db182 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueRequest.py
index 41a8615efa..62617f9f60 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueResponse.py
index 085c774461..2b74fd2d17 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordRequest.py
index a0b948f08f..04b340d5e7 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordRequest.py
@@ -19,7 +19,6 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
@@ -30,6 +29,7 @@ from plc4py.protocols.modbus.readwrite.ModbusPDUReadFileRecordRequestItem import
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
 from plc4py.spi.values.Common import get_size_of_array
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordResponse.py
index 90173fa6be..89e58c226e 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordResponse.py
@@ -19,7 +19,6 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
@@ -30,6 +29,7 @@ from plc4py.protocols.modbus.readwrite.ModbusPDUReadFileRecordResponseItem impor
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
 from plc4py.spi.values.Common import get_size_of_array
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersRequest.py
index fae809b11f..6a784d0651 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersResponse.py
index 2bc94d6ea8..35b9dc7760 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersRequest.py
index e37e5aef01..14f8d978c7 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersResponse.py
index 68782da420..1fbefc6fd3 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersRequest.py
index c788957852..8a669dbb3b 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersResponse.py
index 7c493df65b..a23dcdafec 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdRequest.py
index eec8b49261..213f265abd 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdResponse.py
index 60a26aa2ec..43725092e7 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordRequest.py
index ee142fb92b..53e8fa097c 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordRequest.py
@@ -19,7 +19,6 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
@@ -30,6 +29,7 @@ from plc4py.protocols.modbus.readwrite.ModbusPDUWriteFileRecordRequestItem impor
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
 from plc4py.spi.values.Common import get_size_of_array
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordResponse.py
index f1905c6395..7a1cc06565 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordResponse.py
@@ -19,7 +19,6 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
@@ -30,6 +29,7 @@ from plc4py.protocols.modbus.readwrite.ModbusPDUWriteFileRecordResponseItem impo
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
 from plc4py.spi.values.Common import get_size_of_array
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsRequest.py
index bd95b6f942..3f82c855f3 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsResponse.py
index d8b8b42150..fb4ec735d0 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersRequest.py
index fdaec56e0d..380debfe54 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import Any
 from typing import ClassVar
 from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersResponse.py
index 4c014d685a..6898b495f6 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilRequest.py
index 044baa61df..ddcba2e434 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilResponse.py
index 670e698d03..2f1d45a1a9 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterRequest.py
index 1303b8c557..99482c8896 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterRequest.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterResponse.py
index f363b238b4..9e43b12b80 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterResponse.py
@@ -19,13 +19,13 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from typing import ClassVar
 import math
 
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusRtuADU.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusRtuADU.py
index 30cd9f37fc..48b881c666 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusRtuADU.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusRtuADU.py
@@ -19,7 +19,6 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
@@ -29,6 +28,7 @@ from plc4py.protocols.modbus.readwrite.ModbusADU import ModbusADU
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from plc4py.utils.GenericTypes import ByteOrder
 from typing import ClassVar
 import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusTcpADU.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusTcpADU.py
index b0dac480c5..e89c73d487 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusTcpADU.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusTcpADU.py
@@ -19,7 +19,6 @@
 
 from dataclasses import dataclass
 
-from distutils.util import strtobool
 from plc4py.api.exceptions.exceptions import PlcRuntimeException
 from plc4py.api.exceptions.exceptions import SerializationException
 from plc4py.api.messages.PlcMessage import PlcMessage
@@ -28,6 +27,7 @@ from plc4py.protocols.modbus.readwrite.ModbusADU import ModbusADU
 from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
 from plc4py.spi.generation.ReadBuffer import ReadBuffer
 from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
 from plc4py.utils.GenericTypes import ByteOrder
 from typing import ClassVar
 import math
diff --git a/plc4py/plc4py/protocols/simulated/readwrite/DataItem.py b/plc4py/plc4py/protocols/simulated/readwrite/DataItem.py
index 02af3dea89..7ff9685f54 100644
--- a/plc4py/plc4py/protocols/simulated/readwrite/DataItem.py
+++ b/plc4py/plc4py/protocols/simulated/readwrite/DataItem.py
@@ -529,34 +529,34 @@ class DataItem:
         elif data_type == "CHAR" and number_of_values == int(1):  # CHAR
             # Simple Field (value)
             value: str = _value.get_str()
-            write_buffer.write_str((value), 8, "UTF-8", "value")
+            write_buffer.write_str((value), 8, "value", "UTF-8")
 
         elif data_type == "CHAR":  # List
             values: PlcList = cast(PlcList, _value)
             for val in values.get_list():
                 value: str = val.get_str()
-                write_buffer.write_str((value), 8, "UTF-8", "value")
+                write_buffer.write_str((value), 8, "value", "UTF-8")
 
         elif data_type == "WCHAR" and number_of_values == int(1):  # WCHAR
             # Simple Field (value)
             value: str = _value.get_str()
-            write_buffer.write_str((value), 16, "UTF-16", "value")
+            write_buffer.write_str((value), 16, "value", "UTF-16")
 
         elif data_type == "WCHAR":  # List
             values: PlcList = cast(PlcList, _value)
             for val in values.get_list():
                 value: str = val.get_str()
-                write_buffer.write_str((value), 16, "UTF-16", "value")
+                write_buffer.write_str((value), 16, "value", "UTF-16")
 
         elif data_type == "STRING":  # STRING
             # Simple Field (value)
             value: str = _value.get_str()
-            write_buffer.write_str((value), 255, "UTF-8", "value")
+            write_buffer.write_str((value), 255, "value", "UTF-8")
 
         elif data_type == "WSTRING":  # STRING
             # Simple Field (value)
             value: str = _value.get_str()
-            write_buffer.write_str((value), 255, "UTF-16", "value")
+            write_buffer.write_str((value), 255, "value", "UTF-16")
 
     @staticmethod
     def get_length_in_bytes(
diff --git a/plc4py/plc4py/protocols/umas/StaticHelper.py b/plc4py/plc4py/protocols/umas/StaticHelper.py
index b6f7e15392..686acf1adf 100644
--- a/plc4py/plc4py/protocols/umas/StaticHelper.py
+++ b/plc4py/plc4py/protocols/umas/StaticHelper.py
@@ -137,4 +137,9 @@ def parse_terminated_string_bytes(read_buffer: ReadBuffer, string_length) -> str
 
 
 def serialize_terminated_string(write_buffer, value, string_length):
-    pass
+    terminated_char_position = len(value.value)
+    for i in range(len(value.value)):
+        if value.value[i] == "":
+            terminated_char_position = i
+            break
+    write_buffer.write_str(value.value, (terminated_char_position + 1) * 8)
diff --git a/plc4py/plc4py/protocols/umas/readwrite/DataItem.py b/plc4py/plc4py/protocols/umas/readwrite/DataItem.py
index 8e75e9bf42..0fa4e4827b 100644
--- a/plc4py/plc4py/protocols/umas/readwrite/DataItem.py
+++ b/plc4py/plc4py/protocols/umas/readwrite/DataItem.py
@@ -69,15 +69,6 @@ class DataItem:
             value: bool = read_buffer.read_bit("")
 
             return PlcBOOL(value)
-        if data_type == UmasDataType.BOOL:  # List
-            # Array field (value)
-            # Count array
-            item_count: int = int(number_of_values)
-            value: List[PlcValue] = []
-            for _ in range(item_count):
-                value.append(PlcBOOL(bool(read_buffer.read_bit(""))))
-
-            return PlcList(value)
         if data_type == UmasDataType.EBOOL and number_of_values == int(1):  # BOOL
 
             # Reserved Field (Compartmentalized so the "reserved" variable can't leak)
@@ -95,15 +86,6 @@ class DataItem:
             value: bool = read_buffer.read_bit("")
 
             return PlcBOOL(value)
-        if data_type == UmasDataType.EBOOL:  # List
-            # Array field (value)
-            # Count array
-            item_count: int = int(number_of_values)
-            value: List[PlcValue] = []
-            for _ in range(item_count):
-                value.append(PlcBOOL(bool(read_buffer.read_bit(""))))
-
-            return PlcList(value)
         if data_type == UmasDataType.BYTE and number_of_values == int(1):  # BYTE
 
             # Simple Field (value)
@@ -113,7 +95,7 @@ class DataItem:
         if data_type == UmasDataType.BYTE:  # List
             # Array field (value)
             # Count array
-            item_count: int = int(number_of_values * int(8))
+            item_count: int = int(number_of_values)
             value: List[PlcValue] = []
             for _ in range(item_count):
                 value.append(PlcBYTE(int(read_buffer.read_byte(""))))
@@ -285,7 +267,9 @@ class DataItem:
                 )
 
             return PlcList(value)
-        if data_type == UmasDataType.DT and number_of_values == int(1):  # DATE_AND_TIME
+        if data_type == UmasDataType.DATE_AND_TIME and number_of_values == int(
+            1
+        ):  # DATE_AND_TIME
 
             # Simple Field (unused)
             unused: int = read_buffer.read_unsigned_short(8, logical_name="")
@@ -341,12 +325,6 @@ class DataItem:
             value: bool = _value.get_bool()
             write_buffer.write_bit((value), "value")
 
-        elif data_type == UmasDataType.BOOL:  # List
-            values: PlcList = cast(PlcList, _value)
-            for val in values.get_list():
-                value: bool = val.get_bool()
-                write_buffer.write_bit((value), "value")
-
         elif data_type == UmasDataType.EBOOL and number_of_values == int(1):  # BOOL
             # Reserved Field
             write_buffer.write_byte(int(0x0000), 7, "int0x0000")
@@ -354,22 +332,16 @@ class DataItem:
             value: bool = _value.get_bool()
             write_buffer.write_bit((value), "value")
 
-        elif data_type == UmasDataType.EBOOL:  # List
-            values: PlcList = cast(PlcList, _value)
-            for val in values.get_list():
-                value: bool = val.get_bool()
-                write_buffer.write_bit((value), "value")
-
         elif data_type == UmasDataType.BYTE and number_of_values == int(1):  # BYTE
             # Simple Field (value)
             value: int = _value.get_int()
-            write_buffer.write_byte((value), "value")
+            write_buffer.write_byte((value), 8, "value")
 
         elif data_type == UmasDataType.BYTE:  # List
             values: PlcList = cast(PlcList, _value)
             for val in values.get_list():
                 value: List[int] = val.get_raw()
-                write_buffer.write_byte_array("", value)
+                write_buffer.write_byte(value, 8, "")
 
         elif data_type == UmasDataType.WORD:  # WORD
             # Simple Field (value)
@@ -438,7 +410,10 @@ class DataItem:
 
         elif data_type == UmasDataType.STRING and number_of_values == int(1):  # STRING
             # Manual Field (value)
-            serialize_terminated_string(write_buffer, self.value, self.number_of_values)
+            value: PlcValue = _value
+            StaticHelper.serialize_terminated_string(
+                write_buffer, value, number_of_values
+            )
         elif data_type == UmasDataType.STRING:  # List
             values: PlcList = cast(PlcList, _value)
             for val in values.get_list():
@@ -482,7 +457,7 @@ class DataItem:
                 value: int = val.get_int()
                 write_buffer.write_unsigned_int((value), 32, "value")
 
-        elif data_type == UmasDataType.DT and number_of_values == int(
+        elif data_type == UmasDataType.DATE_AND_TIME and number_of_values == int(
             1
         ):  # DATE_AND_TIME
             # Simple Field (unused)
@@ -534,17 +509,11 @@ class DataItem:
             size_in_bits += 7
             # Simple Field (value)
             size_in_bits += 1
-        elif data_type == UmasDataType.BOOL:  # List
-            values: PlcList = cast(PlcList, _value)
-            size_in_bits += len(values.get_list()) * 1
         elif data_type == UmasDataType.EBOOL and number_of_values == int(1):  # BOOL
             # Reserved Field
             size_in_bits += 7
             # Simple Field (value)
             size_in_bits += 1
-        elif data_type == UmasDataType.EBOOL:  # List
-            values: PlcList = cast(PlcList, _value)
-            size_in_bits += len(values.get_list()) * 1
         elif data_type == UmasDataType.BYTE and number_of_values == int(1):  # BYTE
             # Simple Field (value)
             size_in_bits += 8
@@ -589,7 +558,7 @@ class DataItem:
             size_in_bits += len(values.get_list()) * 32
         elif data_type == UmasDataType.STRING and number_of_values == int(1):  # STRING
             # Manual Field (value)
-            size_in_bits += self.number_of_values * int(8)
+            size_in_bits += number_of_values * int(8)
         elif data_type == UmasDataType.STRING:  # List
             values: PlcList = cast(PlcList, _value)
             size_in_bits += len(values.get_list()) * 32
@@ -614,7 +583,7 @@ class DataItem:
         elif data_type == UmasDataType.TOD:  # List
             values: PlcList = cast(PlcList, _value)
             size_in_bits += len(values.get_list()) * 32
-        elif data_type == UmasDataType.DT and number_of_values == int(
+        elif data_type == UmasDataType.DATE_AND_TIME and number_of_values == int(
             1
         ):  # DATE_AND_TIME
             # Simple Field (unused)
diff --git a/plc4py/plc4py/protocols/umas/readwrite/UmasDataType.py b/plc4py/plc4py/protocols/umas/readwrite/UmasDataType.py
index 061afb668b..81366a2252 100644
--- a/plc4py/plc4py/protocols/umas/readwrite/UmasDataType.py
+++ b/plc4py/plc4py/protocols/umas/readwrite/UmasDataType.py
@@ -22,29 +22,29 @@ from aenum import AutoNumberEnum
 
 
 class UmasDataType(AutoNumberEnum):
-    _init_ = "value, request_size, data_type_size"
-    BOOL = (1, int(1), int(1))
-    UNKNOWN2 = (2, int(1), int(1))
-    UNKNOWN3 = (3, int(1), int(1))
-    INT = (4, int(2), int(2))
-    UINT = (5, int(2), int(2))
-    DINT = (6, int(3), int(4))
-    UDINT = (7, int(3), int(4))
-    REAL = (8, int(3), int(4))
-    STRING = (9, int(17), int(1))
-    TIME = (10, int(3), int(4))
-    UNKNOWN11 = (11, int(1), int(1))
-    UNKNOWN12 = (12, int(1), int(1))
-    UNKNOWN13 = (13, int(1), int(1))
-    DATE = (14, int(3), int(4))
-    TOD = (15, int(3), int(4))
-    DT = (16, int(4), int(8))
-    UNKNOWN17 = (17, int(1), int(1))
-    UNKNOWN18 = (18, int(1), int(1))
-    UNKNOWN19 = (19, int(1), int(1))
-    UNKNOWN20 = (20, int(1), int(1))
-    BYTE = (21, int(1), int(1))
-    WORD = (22, int(2), int(2))
-    DWORD = (23, int(3), int(4))
-    UNKNOWN24 = (24, int(1), int(1))
-    EBOOL = (25, int(1), int(1))
+    _init_ = "value, data_type_conversion, request_size, data_type_size"
+    BOOL = (1, str("BOOL"), int(1), int(1))
+    UNKNOWN2 = (2, str("BOOL"), int(1), int(1))
+    UNKNOWN3 = (3, str("BOOL"), int(1), int(1))
+    INT = (4, str("INT"), int(2), int(2))
+    UINT = (5, str("UINT"), int(2), int(2))
+    DINT = (6, str("DINT"), int(3), int(4))
+    UDINT = (7, str("UDINT"), int(3), int(4))
+    REAL = (8, str("REAL"), int(3), int(4))
+    STRING = (9, str("STRING"), int(17), int(1))
+    TIME = (10, str("TIME"), int(3), int(4))
+    UNKNOWN11 = (11, str("BYTE"), int(1), int(1))
+    UNKNOWN12 = (12, str("BYTE"), int(1), int(1))
+    UNKNOWN13 = (13, str("BYTE"), int(1), int(1))
+    DATE = (14, str("DATE"), int(3), int(4))
+    TOD = (15, str("TIME_OF_DAY"), int(3), int(4))
+    DATE_AND_TIME = (16, str("DATE_AND_TIME"), int(4), int(8))
+    UNKNOWN17 = (17, str("BYTE"), int(1), int(1))
+    UNKNOWN18 = (18, str("BYTE"), int(1), int(1))
+    UNKNOWN19 = (19, str("BYTE"), int(1), int(1))
+    UNKNOWN20 = (20, str("BYTE"), int(1), int(1))
+    BYTE = (21, str("BYTE"), int(1), int(1))
+    WORD = (22, str("WORD"), int(2), int(2))
+    DWORD = (23, str("DWORD"), int(3), int(4))
+    UNKNOWN24 = (24, str("BYTE"), int(1), int(1))
+    EBOOL = (25, str("BOOL"), int(1), int(1))
diff --git a/plc4py/plc4py/spi/generation/WriteBuffer.py b/plc4py/plc4py/spi/generation/WriteBuffer.py
index 2517f8e79c..2a5e0ec145 100644
--- a/plc4py/plc4py/spi/generation/WriteBuffer.py
+++ b/plc4py/plc4py/spi/generation/WriteBuffer.py
@@ -348,6 +348,20 @@ class WriteBufferByteBased(WriteBuffer, metaclass=ABCMeta):
             raise SerializationException("Double can only contain max 64 bits")
         self._handle_numeric_encoding(value, bit_length, numeric_format="d", **kwargs)
 
+    def write_str(
+        self,
+        value: str,
+        bit_length: int = -1,
+        logical_name: str = "",
+        encoding: str = "UTF-8",
+        **kwargs,
+    ) -> None:
+        bit_order = kwargs.get("bit_order", ByteOrder.BIG_ENDIAN)
+        src = bitarray(endian=ByteOrder.get_short_name(bit_order))
+        src.frombytes(value.encode(encoding))
+        self.bb[self.position : self.position + bit_length] = src[:bit_length]
+        self.position += bit_length
+
     def write_complex_array(
         self, value: List[PlcMessage], logical_name: str = "", **kwargs
     ) -> None:
diff --git a/plc4py/plc4py/spi/messages/PlcWriter.py b/plc4py/plc4py/spi/messages/PlcWriter.py
index f3d943c5fd..fc9c36b56d 100644
--- a/plc4py/plc4py/spi/messages/PlcWriter.py
+++ b/plc4py/plc4py/spi/messages/PlcWriter.py
@@ -86,7 +86,7 @@ class DefaultPlcWriter(PlcWriter):
             # Send the write request to the device and wait for a response
             logging.debug("Sending write request to Device")
             response = await asyncio.wait_for(
-                self._device.write(request, self._transport), 5
+                self._device.write(request, self._transport), 15
             )
             # Return the response
             return response
diff --git a/plc4py/plc4py/spi/messages/utils/ResponseItem.py b/plc4py/plc4py/spi/messages/utils/ResponseItem.py
index f62912773c..ddf225d206 100644
--- a/plc4py/plc4py/spi/messages/utils/ResponseItem.py
+++ b/plc4py/plc4py/spi/messages/utils/ResponseItem.py
@@ -17,9 +17,11 @@
 # under the License.
 #
 from abc import ABC
-from dataclasses import dataclass
-from typing import Generic, TypeVar, Union
+from dataclasses import dataclass, field
 
+from typing import Generic, TypeVar, Union, Dict, List
+
+from plc4py.api.messages.PlcField import PlcTag
 from plc4py.api.messages.PlcResponse import PlcResponseCode
 from plc4py.api.value.PlcValue import PlcValue
 
@@ -30,3 +32,27 @@ T = TypeVar("T", bound=Union[PlcValue, None])
 class ResponseItem(Generic[T], ABC):
     response_code: PlcResponseCode
     value: T
+
+
+@dataclass
+class ArrayInfo:
+    size: int
+    lower_bound: int
+    upper_bound: int
+
+
+R = TypeVar("R", bound=Union[PlcTag, None])
+
+
+@dataclass
+class PlcBrowseItem(Generic[R], ABC):
+    tag: R
+    name: str
+    readable: bool
+    writeable: bool
+    subscribable: bool
+    publishable: bool
+    array: bool
+    array_info: List[ArrayInfo] = field(default_factory=lambda: [])
+    children: Dict[str, "PlcBrowseItem"] = field(default_factory=lambda: {})
+    options: Dict[str, PlcValue] = field(default_factory=lambda: {})
diff --git a/plc4py/plc4py/utils/ConnectionStringHandling.py b/plc4py/plc4py/utils/ConnectionStringHandling.py
index c4954de32d..4968c5b7ea 100644
--- a/plc4py/plc4py/utils/ConnectionStringHandling.py
+++ b/plc4py/plc4py/utils/ConnectionStringHandling.py
@@ -30,3 +30,11 @@ def get_protocol_code(url: str) -> str:
     """
     parsed = urlparse(url)
     return parsed.scheme
+
+
+def strtobool(value: str) -> bool:
+    """Credit goes to https://danielms.site/zet/2023/pythons-distutil-strtobool-replacement/"""
+    value = value.lower()
+    if value in ("y", "yes", "on", "1", "true", "t"):
+        return True
+    return False
diff --git a/plc4py/pom.xml b/plc4py/pom.xml
index a213368057..eefa47fa70 100644
--- a/plc4py/pom.xml
+++ b/plc4py/pom.xml
@@ -247,6 +247,24 @@
             </configuration>
           </execution>
 
+          <execution>
+            <id>python-dependency-check</id>
+            <phase>test-compile</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <executable>${python.venv.bin}${python.exe.bin}</executable>
+              <arguments>
+                <argument>-m</argument>
+                <argument>deptry</argument>
+                <argument>-ddg</argument>
+                <argument>dev</argument>
+                <argument>.</argument>
+              </arguments>
+            </configuration>
+          </execution>
+
           <execution>
             <id>python-test</id>
             <phase>test</phase>
diff --git a/plc4py/pyproject.toml b/plc4py/pyproject.toml
new file mode 100644
index 0000000000..811b21ef18
--- /dev/null
+++ b/plc4py/pyproject.toml
@@ -0,0 +1,81 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+[build-system]
+requires = ["setuptools>=61.0", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[tool.setuptools.packages.find]
+where = ["."]  # list of folders that contain the packages (["."] by default)
+include = ["plc4py*"]  # package names should match these glob patterns (["*"] by default)
+#exclude = ["my_package.tests*"]  # exclude packages matching these glob patterns (empty by default)
+namespaces = false  # to disable scanning PEP 420 namespaces (true by default)
+
+[project]
+name = "plc4py"
+description = "Plc4Py The Python Industrial IOT Adapter"
+version = "0.13"
+readme = "README.md"
+dependencies = [
+        "setuptools",
+        "aenum",
+        "bitarray",
+        "typing_extensions",
+        "pluggy",
+        "xsdata",
+]
+classifiers = [
+        "Development Status :: 3 - Alpha",
+        "License :: OSI Approved :: Apache Software License",
+        "Programming Language :: Python :: 3.8",
+        "Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator",
+]
+keywords=["modbus", "plc4x"]
+authors=[
+    {name='"Apache PLC4X <>"', email="dev@plc4x.apache.org"}
+]
+
+[project.urls]
+HomePage="https://plc4x.apache.org"
+Repository="https://github.com/apache/plc4x"
+
+[project.optional-dependencies]
+dev = [
+        "pytest-asyncio>=0.18.3",
+        "pip-tools",
+        "black",
+        "pip",
+        "deptry",
+        "requires",
+        "pre-commit>=2.6.0",
+        "pytest-mock>=3.8.1",
+        "mock>=4.0.2",
+        "mypy>=0.942",
+        "flake8>=4.0.1",
+        "pytest-asyncio",
+        "xsdata",
+]
+
+[project.entry-points."plc4py.drivers"]
+mock = "plc4py.drivers.mock.MockConnection:MockDriverLoader"
+modbus = "plc4py.drivers.modbus.ModbusConnection:ModbusDriverLoader"
+umas = "plc4py.drivers.umas.UmasConnection:UmasDriverLoader"
+
+[project.entry-points."plc4py.transports"]
+tcp = "plc4py.spi.transport.TCPTransport:TCPTransportLoader"
+mock = "plc4py.spi.transport.MockTransport:MockTransportLoader"
diff --git a/plc4py/requirements.txt b/plc4py/requirements.txt
deleted file mode 100644
index f35cd238a2..0000000000
--- a/plc4py/requirements.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-aenum==3.1.15
-annotated-types==0.7.0
-bitarray==3.0.0
-black==24.10.0
-build==1.2.2.post1
-cfgv==3.4.0
-click==8.1.7
-coverage==7.6.3
-distlib==0.3.9
-filelock==3.16.1
-flake8==7.1.1
-funkify==0.4.5
-identify==2.6.1
-iniconfig==2.0.0
-mccabe==0.7.0
-mock==5.1.0
-mypy==1.12.0
-mypy-extensions==1.0.0
-nodeenv==1.9.1
-packaging==24.1
-pathspec==0.12.1
-pip-tools==7.4.1
-platformdirs==4.3.6
-pluggy==1.5.0
-pre-commit==4.0.1
-pycodestyle==2.12.1
-pyflakes==3.2.0
-pyproject_hooks==1.2.0
-pytest==8.3.3
-pytest-asyncio==0.24.0
-pytest-mock==3.14.0
-PyYAML==6.0.2
-requires==0.10.5
-typing_extensions==4.12.2
-virtualenv==20.26.6
-xtyping==0.8.2
diff --git a/plc4py/setup.py b/plc4py/setup_old.py
similarity index 99%
rename from plc4py/setup.py
rename to plc4py/setup_old.py
index 15faec5ac6..39f2facb61 100644
--- a/plc4py/setup.py
+++ b/plc4py/setup_old.py
@@ -39,6 +39,7 @@ setup(
         "wheel",
     ],
     install_requires=[
+        "setuptools",
         "pytest-asyncio>=0.18.3",
         "pip-tools",
         "black",
diff --git a/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py b/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py
index edf295d8e9..7b385ca291 100644
--- a/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py
+++ b/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py
@@ -17,382 +17,172 @@
 # under the License.
 #
 import time
+from typing import AsyncGenerator
 from unittest import TestCase
 
 import pytest
+import pytest_asyncio
+from plc4py.api.PlcConnection import PlcConnection
 
 from plc4py.PlcDriverManager import PlcDriverManager
 from plc4py.api.value.PlcValue import PlcResponseCode
 import logging
 
-from plc4py.spi.values.PlcValues import PlcINT, PlcREAL, PlcList
+from plc4py.spi.values.PlcValues import PlcINT, PlcREAL, PlcList, PlcBOOL, PlcCHAR
 
 logger = logging.getLogger("testing")
 TEST_SERVER_IP = "192.168.190.152"
 
 
-@pytest.mark.asyncio
-@pytest.mark.xfail
-async def manual_test_plc_driver_modbus_connect():
-    """
-    Test the connection to a Modbus PLC using PlcDriverManager.
-    """
-    # Initialize the PlcDriverManager
+@pytest_asyncio.fixture
+async def connection() -> AsyncGenerator[PlcConnection, None]:
     driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(f"modbus://{TEST_SERVER_IP}") as connection:
-        # Check if the connection is successful
-        assert connection.is_connected()
-
-    # Ensure the connection is closed after exiting the context manager
-    assert not connection.is_connected()
+    async with driver_manager.connection("modbus://192.168.190.152:502") as connection:
+        yield connection
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_coil():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
+async def test_plc_driver_modbus_connect(connection):
+    assert connection.is_connected
 
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "0x00001")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == True
 
+async def write_read(connection, tag_name, tag_value):
+    tag_alias = "Some Random Alias"
+    with connection.write_request_builder() as builder:
+        builder.add_item(tag_alias, tag_name, tag_value)
+        write_request = builder.build()
+    with connection.read_request_builder() as builder:
+        builder.add_item(tag_alias, tag_name)
+        read_request = builder.build()
+    future = connection.execute(write_request)
+    response = await future
+    assert response.response_code == PlcResponseCode.OK
 
-@pytest.mark.asyncio
-@pytest.mark.xfail
-async def test_plc_driver_modbus_read_coil_non_bool():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
+    future = connection.execute(read_request)
+    response = await future
+    assert response.response_code == PlcResponseCode.OK
 
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "0x00001:REAL")
-            request = builder.build()
-            TestCase.assertRaises(
-                await connection.execute(request), NotImplementedError
-            )
+    value = response.tags[tag_alias].value
+    response_code = response.tags[tag_alias].response_code
+    assert value == tag_value
+    assert response_code == PlcResponseCode.OK
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_coil_array():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "0x00001[2]")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == [True, False]
+async def test_plc_driver_modbus_read_boolean(connection):
+    tag_name = "0x00001"
+    await write_read(connection, tag_name, PlcBOOL(True))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_contacts():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "1x00001")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == True
+async def test_plc_driver_modbus_read_int(connection):
+    tag_name = "4x00001"
+    await write_read(connection, tag_name, PlcINT(83))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_contact_array():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "1x00001[2]")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == [True, False]
+async def test_plc_driver_modbus_read_real(connection):
+    tag_name = "4x00001"
+    await write_read(connection, tag_name, PlcINT(83))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_input_register():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "3x00001")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == 333
+async def test_plc_driver_modbus_read_bool_array(connection):
+    tag_name = "0x00001[2]"
+    await write_read(connection, tag_name, PlcList([PlcBOOL(True), PlcBOOL(False)]))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_input_register_array():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "3x00001[2]")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == [333, 0]
+async def test_plc_driver_modbus_read_contacts(connection):
+    tag_name = "1x00001"
+    await write_read(connection, tag_name, PlcBOOL(True))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_holding():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "4x00001")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == 874
+async def test_plc_driver_modbus_read_bool_array_discrete_input(connection):
+    tag_name = "1x00001[2]"
+    await write_read(connection, tag_name, PlcList([PlcBOOL(True), PlcBOOL(False)]))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_holding():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "4x00001[2]")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == [874, 0]
+async def test_plc_driver_modbus_read_input_register(connection):
+    tag_name = "3x00001"
+    await write_read(connection, tag_name, PlcINT(333))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_holding_real():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502?byte_order=BIG_ENDIAN_BYTE_SWAP"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "4x00011:REAL[2]")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == [PlcREAL(value=874), PlcREAL(value=0.0)]
+async def test_plc_driver_modbus_read_input_register_array(connection):
+    tag_name = "3x00001[2]"
+    await write_read(connection, tag_name, PlcList([PlcINT(333), PlcINT(0)]))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_holding_string_even():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "4x00041:CHAR[6]")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == [b"F", b"A", b"F", b"B", b"C", b"B"]
+async def test_plc_driver_modbus_read_holding_register(connection):
+    tag_name = "4x00001"
+    await write_read(connection, tag_name, PlcINT(334))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_read_holding_string_odd():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.read_request_builder() as builder:
-            builder.add_item("Random Tag", "4x00041:CHAR[5]")
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"].value
-            assert value == [b"F", b"A", b"F", b"B", b"C"]
+async def test_plc_driver_modbus_read_holdiong_register_array(connection):
+    tag_name = "4x00001[2]"
+    await write_read(connection, tag_name, PlcList([PlcINT(334), PlcINT(0)]))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_write_holding_int():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.write_request_builder() as builder:
-            builder.add_item("Random Tag", "4x00001", PlcINT(874))
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"]
-            assert value.response_code == PlcResponseCode.OK
+async def test_plc_driver_modbus_read_holding_register_real(connection):
+    tag_name = "4x00011:REAL[2]"
+    await write_read(
+        connection, tag_name, PlcList([PlcREAL(value=874), PlcREAL(value=0.0)])
+    )
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_write_holding_int_array():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
-
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502"
-    ) as connection:
-        with connection.write_request_builder() as builder:
-            builder.add_item(
-                "Random Tag",
-                "4x00001[5]",
-                PlcList([PlcINT(874), PlcINT(0), PlcINT(3), PlcINT(4), PlcINT(5)]),
-            )
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"]
-            assert value.response_code == PlcResponseCode.OK
+async def test_plc_driver_modbus_read_holding_string_even(connection):
+    tag_name = "4x00041:CHAR[6]"
+    await write_read(
+        connection,
+        tag_name,
+        PlcList(
+            [
+                PlcCHAR(value=b"F"),
+                PlcCHAR(value=b"A"),
+                PlcCHAR(value=b"F"),
+                PlcCHAR(value=b"B"),
+                PlcCHAR(value=b"C"),
+                PlcCHAR(value=b"B"),
+            ]
+        ),
+    )
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
-async def test_plc_driver_modbus_write_holding_real():
-    """
-    Test reading data from a Modbus PLC.
-    """
-    log = logging.getLogger(__name__)
-
-    # Initialize the PlcDriverManager
-    driver_manager = PlcDriverManager()
+async def test_plc_driver_modbus_read_holding_string_odd(connection):
+    tag_name = "4x00041:CHAR[5]"
+    await write_read(
+        connection,
+        tag_name,
+        PlcList(
+            [
+                PlcCHAR(value=b"F"),
+                PlcCHAR(value=b"A"),
+                PlcCHAR(value=b"F"),
+                PlcCHAR(value=b"B"),
+                PlcCHAR(value=b"C"),
+            ]
+        ),
+    )
 
-    # Establish a connection to the Modbus PLC
-    async with driver_manager.connection(
-        f"modbus://{TEST_SERVER_IP}:502?byte_order=BIG_ENDIAN_BYTE_SWAP"
-    ) as connection:
-        with connection.write_request_builder() as builder:
-            builder.add_item("Random Tag", "4x00011:REAL", PlcREAL(874))
-            request = builder.build()
-            response = await connection.execute(request)
-            value = response.tags["Random Tag"]
-            assert value.response_code == PlcResponseCode.OK
diff --git a/plc4py/tests/unit/plc4py/drivers/umas/test_umas_connection.py b/plc4py/tests/unit/plc4py/drivers/umas/test_umas_connection.py
index a7a37fb4d0..251bd8eb87 100644
--- a/plc4py/tests/unit/plc4py/drivers/umas/test_umas_connection.py
+++ b/plc4py/tests/unit/plc4py/drivers/umas/test_umas_connection.py
@@ -28,7 +28,18 @@ from plc4py.api.PlcConnection import PlcConnection
 
 from plc4py.api.value.PlcValue import PlcResponseCode
 from plc4py.PlcDriverManager import PlcDriverManager
-from plc4py.spi.values.PlcValues import PlcBOOL, PlcINT, PlcREAL
+from plc4py.spi.values.PlcValues import (
+    PlcBOOL,
+    PlcINT,
+    PlcREAL,
+    PlcDINT,
+    PlcSTRING,
+    PlcTIME,
+    PlcBYTE,
+    PlcDATE,
+    PlcDATE_AND_TIME,
+    PlcList,
+)
 
 
 @pytest_asyncio.fixture
@@ -44,276 +55,147 @@ async def test_plc_driver_umas_connect(connection):
     assert connection.is_connected
 
 
-@pytest.mark.asyncio
-@pytest.mark.xfail
-async def test_plc_driver_umas_read_boolean(connection):
-    tag_alias = "Random Tag"
-    tag_name = "TESTING"
+async def write_read(connection, tag_name, tag_value):
+    tag_alias = "Some Random Alias"
+    with connection.write_request_builder() as builder:
+        builder.add_item(tag_alias, tag_name, tag_value)
+        write_request = builder.build()
     with connection.read_request_builder() as builder:
         builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
+        read_request = builder.build()
+    future = connection.execute(write_request)
+    response = await future
+    assert response.response_code == PlcResponseCode.OK
+
+    future = connection.execute(read_request)
     response = await future
+    assert response.response_code == PlcResponseCode.OK
+
     value = response.tags[tag_alias].value
     response_code = response.tags[tag_alias].response_code
-    assert value == True
+    assert value == tag_value
     assert response_code == PlcResponseCode.OK
 
 
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_boolean(connection):
+    tag_name = "TESTING"
+    await write_read(connection, tag_name, PlcBOOL(True))
+
+
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_boolean_with_data_type(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING:BOOL"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == True
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcBOOL(True))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_int(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_INT"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == 99
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcINT(99))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_int_with_data_type(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_INT:INT"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == 99
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcINT(99))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_dint(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_DINT"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == 763539
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcDINT(763539))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_dint_with_data_type(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_DINT:DINT"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == 763539
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcDINT(763539))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_ebool(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_EBOOL"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == True
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcBOOL(True))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_ebool_with_data_type(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_EBOOL:BOOL"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == True
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcBOOL(True))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_string(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_STRING"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == "Hello World"
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcSTRING("Hello pyToddy!"))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_string_with_data_type(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_STRING:STRING"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == "Hello World"
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcSTRING("Hello pyToddy!"))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_time(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_TIME"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == 200000
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcTIME(200000))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_time_with_data_type(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_TIME:TIME"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == 200000
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcTIME(200000))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_byte(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_BYTE"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == 253
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcBYTE(253))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_byte_with_data_type(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_BYTE:BYTE"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == 253
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcBYTE(253))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_date(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_DATE"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == datetime.datetime(2024, 10, 25)
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcDATE(datetime.datetime(2024, 10, 25)))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_time_with_data_type(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_DATE:DATE"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == datetime.datetime(2024, 10, 25)
-    assert response_code == PlcResponseCode.OK
+    await write_read(connection, tag_name, PlcDATE(datetime.datetime(2025, 11, 22)))
 
 
 @pytest.mark.asyncio
 @pytest.mark.xfail
 async def test_plc_driver_umas_read_dt(connection):
-    tag_alias = "Random Tag"
     tag_name = "TESTING_DT"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == datetime.datetime(2000, 1, 10, 0, 40)
-    assert response_code == PlcResponseCode.OK
+    await write_read(
+        connection, tag_name, PlcDATE_AND_TIME(datetime.datetime(2000, 1, 10, 0, 40))
+    )
 
 
 @pytest.mark.asyncio
@@ -321,15 +203,33 @@ async def test_plc_driver_umas_read_dt(connection):
 async def test_plc_driver_umas_read_dt_with_data_type(connection):
     tag_alias = "Random Tag"
     tag_name = "TESTING_DT:DATE_AND_TIME"
-    with connection.read_request_builder() as builder:
-        builder.add_item(tag_alias, tag_name)
-        request = builder.build()
-    future = connection.execute(request)
-    response = await future
-    value = response.tags[tag_alias].value
-    response_code = response.tags[tag_alias].response_code
-    assert value == datetime.datetime(2000, 1, 10, 0, 40)
-    assert response_code == PlcResponseCode.OK
+    await write_read(
+        connection, tag_name, PlcDATE_AND_TIME(datetime.datetime(2002, 10, 31, 3, 38))
+    )
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_array(connection):
+    tag_name = "TESTING_BYTE_ARRAY:BYTE[10]"
+    await write_read(
+        connection,
+        tag_name,
+        PlcList(
+            [
+                PlcBYTE(1),
+                PlcBYTE(2),
+                PlcBYTE(3),
+                PlcBYTE(4),
+                PlcBYTE(5),
+                PlcBYTE(6),
+                PlcBYTE(7),
+                PlcBYTE(8),
+                PlcBYTE(9),
+                PlcBYTE(10),
+            ]
+        ),
+    )
 
 
 @pytest.mark.asyncio
diff --git a/protocols/umas/src/main/resources/protocols/umas/umas.mspec b/protocols/umas/src/main/resources/protocols/umas/umas.mspec
index de9079130a..cf65be4c06 100644
--- a/protocols/umas/src/main/resources/protocols/umas/umas.mspec
+++ b/protocols/umas/src/main/resources/protocols/umas/umas.mspec
@@ -235,32 +235,22 @@
     [simple uint 32 memoryLength]
 ]
 
-
 [dataIo DataItem(UmasDataType dataType, uint 16 numberOfValues)
     [typeSwitch dataType,numberOfValues
         ['BOOL','1'  BOOL
-            // TODO: Possibly change the order of the bit and the reserved part.
             [reserved uint 7 '0x0000'                         ]
-            [simple   bit     value                            ]
-        ]
-        ['BOOL'      List
-            // TODO: Handle adding some reserved bits at the end to fill up the last word.
-            [array    bit     value count 'numberOfValues'     ]
+            [simple   bit     value                           ]
         ]
         ['EBOOL','1'  BOOL
             // TODO: Possibly change the order of the bit and the reserved part.
             [reserved uint 7 '0x0000'                         ]
             [simple   bit     value                            ]
         ]
-        ['EBOOL'      List
-            // TODO: Handle adding some reserved bits at the end to fill up the last word.
-            [array    bit     value count 'numberOfValues'     ]
-        ]
         ['BYTE','1'  BYTE
             [simple byte value]
         ]
         ['BYTE' List
-            [array    byte     value count 'numberOfValues * 8' ]
+            [array    byte     value count 'numberOfValues' ]
         ]
         ['WORD'      WORD
             [simple   uint 16 value]
@@ -299,7 +289,7 @@
             [array float 32 value count 'numberOfValues']
         ]
         ['STRING','1' STRING
-            [manual vstring value  'STATIC_CALL("parseTerminatedStringBytes", readBuffer, numberOfValues)' 'STATIC_CALL("serializeTerminatedString", writeBuffer, value, numberOfValues)' '(numberOfValues * 8)']
+            [manual vstring value  'STATIC_CALL("parseTerminatedStringBytes", readBuffer, numberOfValues)' 'STATIC_CALL("serializeTerminatedString", writeBuffer, _value, numberOfValues)' '(numberOfValues * 8)']
         ]
         ['STRING' List
             [array float 32 value count 'numberOfValues']
@@ -321,7 +311,7 @@
         ['TOD' List
             [array uint 32 value count 'numberOfValues']
         ]
-        ['DT','1' DATE_AND_TIME
+        ['DATE_AND_TIME','1' DATE_AND_TIME
             [simple uint 8 unused]
             [simple uint 8 seconds encoding='BCD']
             [simple uint 8 minutes encoding='BCD']
@@ -333,32 +323,32 @@
     ]
 ]
 
-[enum uint 8 UmasDataType(uint 8 dataTypeSize, uint 8 requestSize)
-    ['1' BOOL ['1','1']]
-    ['2' UNKNOWN2 ['1','1']]
-    ['3' UNKNOWN3 ['1','1']]
-    ['4' INT ['2', '2']]
-    ['5' UINT ['2','2']]
-    ['6' DINT ['4','3']]
-    ['7' UDINT ['4','3']]
-    ['8' REAL ['4','3']]
-    ['9' STRING ['1','17']]
-    ['10' TIME ['4','3']]
-    ['11' UNKNOWN11 ['1','1']]
-    ['12' UNKNOWN12 ['1','1']]
-    ['13' UNKNOWN13 ['1','1']]
-    ['14' DATE ['4','3']]
-    ['15' TOD ['4','3']]
-    ['16' DT ['8','4']]
-    ['17' UNKNOWN17 ['1','1']]
-    ['18' UNKNOWN18 ['1','1']]
-    ['19' UNKNOWN19 ['1','1']]
-    ['20' UNKNOWN20 ['1','1']]
-    ['21' BYTE ['1','1']]
-    ['22' WORD ['2','2']]
-    ['23' DWORD ['4','3']]
-    ['24' UNKNOWN24 ['1','1']]
-    ['25' EBOOL ['1','1']]
+[enum uint 8 UmasDataType(uint 8 dataTypeSize, uint 8 requestSize, vstring data_type_conversion )
+    ['1' BOOL ['1','1','"BOOL"']]
+    ['2' UNKNOWN2 ['1','1','"BOOL"']]
+    ['3' UNKNOWN3 ['1','1','"BOOL"']]
+    ['4' INT ['2', '2','"INT"']]
+    ['5' UINT ['2','2','"UINT"']]
+    ['6' DINT ['4','3','"DINT"']]
+    ['7' UDINT ['4','3','"UDINT"']]
+    ['8' REAL ['4','3','"REAL"']]
+    ['9' STRING ['1','17','"STRING"']]
+    ['10' TIME ['4','3','"TIME"']]
+    ['11' UNKNOWN11 ['1','1','"BYTE"']]
+    ['12' UNKNOWN12 ['1','1','"BYTE"']]
+    ['13' UNKNOWN13 ['1','1','"BYTE"']]
+    ['14' DATE ['4','3','"DATE"']]
+    ['15' TOD ['4','3','"TIME_OF_DAY"']]
+    ['16' DATE_AND_TIME ['8','4','"DATE_AND_TIME"']]
+    ['17' UNKNOWN17 ['1','1','"BYTE"']]
+    ['18' UNKNOWN18 ['1','1','"BYTE"']]
+    ['19' UNKNOWN19 ['1','1','"BYTE"']]
+    ['20' UNKNOWN20 ['1','1','"BYTE"']]
+    ['21' BYTE ['1','1','"BYTE"']]
+    ['22' WORD ['2','2','"WORD"']]
+    ['23' DWORD ['4','3','"DWORD"']]
+    ['24' UNKNOWN24 ['1','1','"BYTE"']]
+    ['25' EBOOL ['1','1','"BOOL"']]
 ]
 
 [enum uint 8 ModbusErrorCode
diff --git a/src/site/asciidoc/users/protocols/umas.adoc b/src/site/asciidoc/users/protocols/umas.adoc
index 534ba8f08e..3b188c97ee 100644
--- a/src/site/asciidoc/users/protocols/umas.adoc
+++ b/src/site/asciidoc/users/protocols/umas.adoc
@@ -19,6 +19,8 @@
 
 == UMAS (Schneider Electric PLCs)
 
+(Supported by Plc4Py Only)
+
 === Connection String Options
 
 [cols="2,2a,2a,2a,4a"]
@@ -31,7 +33,7 @@
  - `tcp`
 5+|Config options:
 |`request-timeout` |INT |5000| |Default timeout for all types of requests.
-|`default-unit-identifier` |INT |1| |Unit-identifier or slave-id that identifies the target PLC (On RS485 multiple Modbus Devices can be listening). Defaults to 1.
+|`unit-identifier` |INT |1| |Unit-identifier or slave-id that identifies the target PLC. Defaults to 1.
 +++
 
 |===
@@ -70,7 +72,7 @@ Note the transport, port and option fields are optional.
 
 ==== General Format
 
-In general all Modbus addresses have this format:
+In general all UMAS addresses have this format:
 
 ----
 {tag-name}.{child-name}.{child-name}:{data-type}[{array-size}]
@@ -79,42 +81,20 @@ In general all Modbus addresses have this format:
 Depending on the type of tag the child-name parameters are optional.
 e.g. A tag with a BOOL data type could be 'TESTING_BOOL_1' whereas
 if it is a UDT the tag name is followed by the child 'TESTING_UDT_1.START' which in itself could be a BOOL.
+
 If the array-size part is omitted, the size-default of `1` is assumed.
+
 If the data-type part is omitted, it defaults to the data type of the tag read from the PLC.
 
 ==== Memory Areas
 
-There are a number of memory areas defined in the Modbus specification.
-
-- Discrete Input Area
-- Coil Area
-- Input Register Area
-- Holding Register
-- Extended Register Area
-
-[cols="2,2a,5,1,2,1"]
-|===
-|Name |Memory Area Aliases |Description |Bit-Size | Permissions | Starting Address
-
-|Discrete Input   |`discrete-input:` or `1` or `1x`   |Boolean input value, usually representing a binary input to the PLC |1 |Read Only|1
-|Coil             |`coil:` or `0` or `0x`             |Boolean value, usually representing a binary output from the PLC   |1 |Read/Write|1
-|Input Register   |`input-register:` or `3` or `3x`   |Short input value, usually representing an analog input to the PLC  |16 |Read Only|1
-|Holding Register |`holding-register:` or `4` or `4x` |Short value, usually representing an analog output from the PLC    |16 |Read/Write|1
-|Extended Register |`extended-register:` or `6` or `6x` |Short value,    |16 |Read/Write|0
+Apart from tags defined in the PLC the driver is also able to access the %S and %SW
+system memory areas.
 
-|===
-
-Initially the Modbus format allowed up to 10000 address to be specified or the discrete inputs, coils, input registers and holding registers.
-Later on, this was expanded to allow up 65536 address within each memory area (except the extended register area).
-When using the long address format i.e. input-registers:1 the addresses between 1 and 65535 are able to be specified.
-When using the shorter versions there are two formats available  i.e. 30001 and 300001.
-With the shorter format 3XXXX being limited to between 30001 and 39999, while the longer format 3XXXXX being limited to between 300001 and 365535.
-These memory areas all start at address 1.
+The specific address details of the data in these areas are outlined in the devices
+manual.
 
-For the extended register area the addresses 0-99999 are able to be specified. These registers are mapped to file records with a length of 10000. Address 600000 corresponds to the first address in file record 0.
-Address 610000 is then the first address in the second file record and so on. It is noted that there is generally only 10 file records (600000 thru to 699999) however the spec allows for 65536 file records.
-Using the extended-register: format you are able to reference all of these, if the shorter format is used then it is limited to 699999.
-This memory area starts at address 0.
+An example of the address format of these areas is %SW1 or %S20.
 
 ==== Data Types
 
@@ -130,76 +110,9 @@ The following data types are supported
 - DINT (int 32)
 - UDINT (uint 32)
 - DWORD (uint 32)
-- LINT (int 64)
-- ULINT (uint 64)
-- LWORD (uint 64)
 - REAL (float)
-- LREAL (double)
-- CHAR (char)
-- WCHAR (2 byte char)
-
-==== Some useful tips
-
-Most memory areas start at address 1, except for the extended register area which starts at 0. These are both mapped to 0x0000 when it is sent in the Modbus protocol.
-
-The input, holding and extended registers consist of 16-bit registers while the discrete input and coil areas consist of bits.
-
-The following Modbus function codes are supported:-
-
-- 0x01 (Read Coils)
-- 0x02 (Read Discrete Inputs)
-- 0x03 (Read Holding Registers)
-- 0x04 (Read Input Registers)
-- 0x05 (Write Single Coil)
-- 0x06 (Write Single Register)
-- 0x0F (Write Multiple Coils)
-- 0x10 (Write Multiple Registers)
-- 0x14 (Read File Record)(Extended Register Read)
-- 0x15 (Write File Record)(Extended Register Write)
-
-==== Examples
-
-To read 10 holding registers starting at address 20 and parse as Unsigned Integers the following examples are all valid.
-
-- holding-register:20:UINT[10]
-- 400020:UINT[10]
-- 4x00020:UINT[10]
-- 40020:UINT[10]
-- 4x0020:UINT[10]
-
-To read 1 holding register at address 5678 the following examples are valid.
-
-- holding-register:5678
-- 405678
-- 4x05678
-- 45678
-- 4x5678
-
-To read 1 holding register of unit 10 at address 5678 the following examples are valid.
-
-- holding-register:5678{unit-id: 10}
-- 405678{unit-id: 10}
-- 4x05678{unit-id: 10}
-- 45678{unit-id: 10}
-- 4x5678{unit-id: 10}
-
-To read 10 extended registers starting at address 50 the following examples are valid.
-
-- extended-register:50[10]
-- 600050[10]
-- 6x00050[10]
-- 60050[10]
-- 6x0050[10]
-
-This corresponds to addresses 50-59 in file record 1.
-
-To read 10 extended registers starting at address 9995 the following examples are valid.
-
-- extended-register:9995[10]
-- 609995[10]
-- 6x09995[10]
-- 69995[10]
-- 6x9995[10]
-
-This corresponds to addresses 9995-9999 in file record 1 and addresses 0-5 in file record 2.
-Note that this request is split into 2 sub requests in the Modbus protocol.
+- STRING (char)
+- TIME
+- DATE
+- TOD (Time of Day)
+- DATE_AND_TIME


(plc4x) 02/03: Merge branch 'develop' into feat/umas_write

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hutcheb pushed a commit to branch feat/umas_write
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit e4dc8ecfa0eaa8cb1e6d18ec41a78e8a3b459115
Merge: 8d514900f4 c936cf26f8
Author: hutcheb <be...@gmail.com>
AuthorDate: Tue Oct 29 17:41:14 2024 +0800

    Merge branch 'develop' into feat/umas_write
    
    # Conflicts:
    #       plc4py/requirements.txt

 .../templates/go/complex-type-template.go.ftlh     |   5 +-
 .../protocols/opcua/ParserSerializerTestsuite.xml  |  46 +--
 plc4go/go.mod                                      |   2 +-
 plc4go/go.sum                                      |   4 +-
 .../readwrite/model/CIPEncapsulationPacket.go      |   5 +-
 .../abeth/readwrite/model/DF1RequestCommand.go     |   5 +-
 .../abeth/readwrite/model/DF1RequestMessage.go     |   5 +-
 .../abeth/readwrite/model/DF1ResponseMessage.go    |   5 +-
 .../discovery/readwrite/model/AdsDiscoveryBlock.go |   5 +-
 .../ads/readwrite/model/AdsMultiRequestItem.go     |   5 +-
 plc4go/protocols/ads/readwrite/model/AmsPacket.go  |   5 +-
 plc4go/protocols/bacnetip/readwrite/model/APDU.go  |   5 +-
 .../readwrite/model/BACnetApplicationTag.go        |   7 +-
 .../readwrite/model/BACnetCalendarEntry.go         |   5 +-
 .../bacnetip/readwrite/model/BACnetChannelValue.go |   5 +-
 .../bacnetip/readwrite/model/BACnetClientCOV.go    |   5 +-
 .../model/BACnetConfirmedServiceRequest.go         |   5 +-
 ...edServiceRequestAtomicReadFileStreamOrRecord.go |   5 +-
 ...rviceRequestConfirmedTextMessageMessageClass.go |   5 +-
 .../BACnetConfirmedServiceRequestReadRangeRange.go |   5 +-
 .../readwrite/model/BACnetConstructedData.go       |   5 +-
 .../bacnetip/readwrite/model/BACnetContextTag.go   |   7 +-
 .../bacnetip/readwrite/model/BACnetError.go        |   5 +-
 .../model/BACnetEventLogRecordLogDatum.go          |   5 +-
 .../readwrite/model/BACnetEventParameter.go        |   5 +-
 ...BACnetEventParameterChangeOfValueCivCriteria.go |   5 +-
 .../readwrite/model/BACnetFaultParameter.go        |   5 +-
 ...etFaultParameterFaultExtendedParametersEntry.go |   5 +-
 ...tFaultParameterFaultOutOfRangeMaxNormalValue.go |   5 +-
 ...tFaultParameterFaultOutOfRangeMinNormalValue.go |   5 +-
 .../bacnetip/readwrite/model/BACnetHostAddress.go  |   5 +-
 .../model/BACnetLandingCallStatusCommand.go        |   5 +-
 .../bacnetip/readwrite/model/BACnetLogData.go      |   5 +-
 .../readwrite/model/BACnetLogDataLogDataEntry.go   |   5 +-
 .../readwrite/model/BACnetLogRecordLogDatum.go     |   5 +-
 .../model/BACnetNotificationParameters.go          |   5 +-
 ...ationParametersChangeOfDiscreteValueNewValue.go |   5 +-
 ...tNotificationParametersChangeOfValueNewValue.go |   5 +-
 .../readwrite/model/BACnetOptionalBinaryPV.go      |   5 +-
 .../model/BACnetOptionalCharacterString.go         |   5 +-
 .../bacnetip/readwrite/model/BACnetOptionalREAL.go |   5 +-
 .../readwrite/model/BACnetOptionalUnsigned.go      |   5 +-
 .../readwrite/model/BACnetPriorityValue.go         |   5 +-
 .../readwrite/model/BACnetProcessIdSelection.go    |   5 +-
 .../BACnetPropertyAccessResultAccessResult.go      |   5 +-
 .../readwrite/model/BACnetPropertyStates.go        |   5 +-
 .../bacnetip/readwrite/model/BACnetRecipient.go    |   5 +-
 .../bacnetip/readwrite/model/BACnetScale.go        |   5 +-
 .../bacnetip/readwrite/model/BACnetServiceAck.go   |   5 +-
 ...BACnetServiceAckAtomicReadFileStreamOrRecord.go |   5 +-
 .../bacnetip/readwrite/model/BACnetShedLevel.go    |   5 +-
 .../readwrite/model/BACnetSpecialEventPeriod.go    |   5 +-
 .../bacnetip/readwrite/model/BACnetTimeStamp.go    |   5 +-
 .../readwrite/model/BACnetTimerStateChangeValue.go |   5 +-
 .../model/BACnetUnconfirmedServiceRequest.go       |   5 +-
 .../BACnetUnconfirmedServiceRequestWhoHasObject.go |   5 +-
 .../bacnetip/readwrite/model/BACnetValueSource.go  |   5 +-
 plc4go/protocols/bacnetip/readwrite/model/BVLC.go  |   5 +-
 plc4go/protocols/bacnetip/readwrite/model/NLM.go   |   5 +-
 .../cbus/readwrite/model/AccessControlData.go      |   5 +-
 .../cbus/readwrite/model/AirConditioningData.go    |   5 +-
 plc4go/protocols/cbus/readwrite/model/CALData.go   |   5 +-
 plc4go/protocols/cbus/readwrite/model/CALReply.go  |   9 +-
 .../protocols/cbus/readwrite/model/CBusCommand.go  |   7 +-
 .../protocols/cbus/readwrite/model/CBusMessage.go  |   5 +-
 .../model/CBusPointToMultiPointCommand.go          |   5 +-
 .../readwrite/model/CBusPointToPointCommand.go     |   5 +-
 .../model/CBusPointToPointToMultiPointCommand.go   |   5 +-
 .../readwrite/model/ClockAndTimekeepingData.go     |   5 +-
 .../protocols/cbus/readwrite/model/EncodedReply.go |   5 +-
 .../cbus/readwrite/model/ErrorReportingData.go     |   5 +-
 .../model/ErrorReportingSystemCategoryType.go      |   5 +-
 .../cbus/readwrite/model/IdentifyReplyCommand.go   |   5 +-
 .../cbus/readwrite/model/LevelInformation.go       |   7 +-
 .../protocols/cbus/readwrite/model/LightingData.go |   5 +-
 .../cbus/readwrite/model/MeasurementData.go        |   5 +-
 .../readwrite/model/MediaTransportControlData.go   |   5 +-
 .../protocols/cbus/readwrite/model/MeteringData.go |   5 +-
 .../protocols/cbus/readwrite/model/MonitoredSAL.go |   7 +-
 .../cbus/readwrite/model/ParameterValue.go         |   5 +-
 plc4go/protocols/cbus/readwrite/model/Reply.go     |   5 +-
 .../cbus/readwrite/model/ReplyOrConfirmation.go    |   5 +-
 plc4go/protocols/cbus/readwrite/model/Request.go   |   5 +-
 plc4go/protocols/cbus/readwrite/model/SALData.go   |   7 +-
 .../protocols/cbus/readwrite/model/SecurityData.go |   5 +-
 .../cbus/readwrite/model/StatusRequest.go          |   5 +-
 .../cbus/readwrite/model/TelephonyData.go          |   5 +-
 .../cbus/readwrite/model/TriggerControlData.go     |   5 +-
 plc4go/protocols/df1/readwrite/model/DF1Command.go |   5 +-
 plc4go/protocols/df1/readwrite/model/DF1Symbol.go  |   5 +-
 plc4go/protocols/eip/readwrite/model/CipService.go |   5 +-
 .../eip/readwrite/model/CommandSpecificDataItem.go |   5 +-
 .../eip/readwrite/model/DataSegmentType.go         |   5 +-
 plc4go/protocols/eip/readwrite/model/EipPacket.go  |   5 +-
 .../eip/readwrite/model/LogicalSegmentType.go      |   5 +-
 .../protocols/eip/readwrite/model/PathSegment.go   |   5 +-
 .../eip/readwrite/model/PortSegmentType.go         |   5 +-
 plc4go/protocols/eip/readwrite/model/TypeId.go     |   5 +-
 .../firmata/readwrite/model/FirmataCommand.go      |   5 +-
 .../firmata/readwrite/model/FirmataMessage.go      |   5 +-
 .../firmata/readwrite/model/SysexCommand.go        |   5 +-
 plc4go/protocols/knxnetip/readwrite/model/Apdu.go  |   5 +-
 .../knxnetip/readwrite/model/ApduControl.go        |   5 +-
 .../protocols/knxnetip/readwrite/model/ApduData.go |   5 +-
 .../knxnetip/readwrite/model/ApduDataExt.go        |   5 +-
 plc4go/protocols/knxnetip/readwrite/model/CEMI.go  |   5 +-
 .../readwrite/model/CEMIAdditionalInformation.go   |   5 +-
 .../knxnetip/readwrite/model/ComObjectTable.go     |   5 +-
 .../model/ConnectionRequestInformation.go          |   5 +-
 .../readwrite/model/ConnectionResponseDataBlock.go |   5 +-
 .../knxnetip/readwrite/model/KnxGroupAddress.go    |   5 +-
 .../knxnetip/readwrite/model/KnxManufacturer.go    |  26 +-
 .../knxnetip/readwrite/model/KnxNetIpMessage.go    |   5 +-
 .../knxnetip/readwrite/model/LDataFrame.go         |   5 +-
 .../knxnetip/readwrite/model/ServiceId.go          |   5 +-
 .../protocols/modbus/readwrite/model/ModbusADU.go  |   5 +-
 .../protocols/modbus/readwrite/model/ModbusPDU.go  |   5 +-
 .../readwrite/model/ExtensionObjectDefinition.go   |   5 +-
 .../protocols/opcua/readwrite/model/MessagePDU.go  |   7 +-
 .../opcua/readwrite/model/NodeIdTypeDefinition.go  |   5 +-
 .../opcua/readwrite/model/OpenChannelMessage.go    |   5 +-
 plc4go/protocols/opcua/readwrite/model/Payload.go  |   5 +-
 .../readwrite/model/UserIdentityTokenDefinition.go |   5 +-
 plc4go/protocols/opcua/readwrite/model/Variant.go  |   5 +-
 plc4go/protocols/s7/readwrite/model/COTPPacket.go  |   5 +-
 .../protocols/s7/readwrite/model/COTPParameter.go  |   5 +-
 .../s7/readwrite/model/CycServiceItemType.go       |   5 +-
 plc4go/protocols/s7/readwrite/model/S7Address.go   |   5 +-
 .../s7/readwrite/model/S7DataAlarmMessage.go       |   5 +-
 plc4go/protocols/s7/readwrite/model/S7Message.go   |   5 +-
 plc4go/protocols/s7/readwrite/model/S7Parameter.go |   5 +-
 .../s7/readwrite/model/S7ParameterUserDataItem.go  |   5 +-
 plc4go/protocols/s7/readwrite/model/S7Payload.go   |   5 +-
 .../s7/readwrite/model/S7PayloadUserDataItem.go    |   5 +-
 .../readwrite/model/S7VarRequestParameterItem.go   |   5 +-
 .../{PlcTagResponse.java => PlcMetadataKeys.java}  |  24 +-
 .../plc4x/java/api/messages/PlcTagResponse.java    |   6 +
 .../apache/plc4x/java/api/metadata/Metadata.java   |  89 ++++++
 .../plc4x/java/api/metadata/time/TimeSource.java}  |  20 +-
 .../plc4x/java/ads/protocol/AdsProtocolLogic.java  |  65 ++++-
 plc4j/drivers/opcua/pom.xml                        |   2 +-
 .../apache/plc4x/java/opcua/OpcMetadataKeys.java}  |  25 +-
 .../java/opcua/protocol/OpcuaProtocolLogic.java    |  41 ++-
 .../opcua/protocol/OpcuaSubscriptionHandle.java    |  17 +-
 .../plc4x/java/opcua/tag/OpcuaQualityStatus.java   |  58 ++++
 .../apache/plc4x/java/opcua/KeystoreGenerator.java | 115 ++++++++
 .../apache/plc4x/java/opcua/MiloTestContainer.java |   9 +-
 .../plc4x/java/opcua/OpcuaPlcDriverTest.java       | 144 ++++++----
 .../protocol/OpcuaSubscriptionHandleTest.java      |  27 +-
 .../milo/examples/server/TestMiloServer.java       |   2 -
 .../opcua/src/test/resources/logback-test.xml      |   2 +
 .../apache/plc4x/java/s7/events/S7AlarmEvent.java  | 317 +++++++++++----------
 .../apache/plc4x/java/s7/events/S7CyclicEvent.java | 217 +++++---------
 .../apache/plc4x/java/s7/events/S7EventBase.java   |  59 ++++
 .../apache/plc4x/java/s7/events/S7ModeEvent.java   |  18 +-
 .../apache/plc4x/java/s7/events/S7SysEvent.java    |  55 ++--
 .../apache/plc4x/java/s7/events/S7UserEvent.java   |  13 +-
 .../s7/readwrite/protocol/S7ProtocolLogic.java     |   6 +-
 .../java/spi/messages/DefaultPlcReadResponse.java  |  30 ++
 .../spi/messages/DefaultPlcSubscriptionEvent.java  |  13 +-
 .../java/spi/messages/DefaultPlcWriteResponse.java |  30 ++
 .../plc4x/java/spi/metadata/DefaultMetadata.java   | 132 +++++++++
 .../driver/internal/validator/ApiValidator.java    |   5 +
 .../test/driver/xmlunit/SkipAttributeFilter.java}  |  22 +-
 .../driver/xmlunit/SkipDifferenceEvaluator.java    |  56 ++++
 pom.xml                                            |  18 +-
 .../resources/protocols/ads/DriverTestsuite.xml    |  12 +
 .../protocols/knxnetip/knx-master-data.mspec       |   5 +-
 168 files changed, 1722 insertions(+), 683 deletions(-)


(plc4x) 03/03: fix(plc4py/modbus): Update trailing white space in modebus tests

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hutcheb pushed a commit to branch feat/umas_write
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 422055d1e7a3c3e9cf5f5fe3faeb82d741a2b164
Author: hutcheb <be...@gmail.com>
AuthorDate: Tue Oct 29 17:45:26 2024 +0800

    fix(plc4py/modbus): Update trailing white space in modebus tests
---
 plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py b/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py
index 7b385ca291..201358816a 100644
--- a/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py
+++ b/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py
@@ -185,4 +185,3 @@ async def test_plc_driver_modbus_read_holding_string_odd(connection):
             ]
         ),
     )
-