You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/02/24 08:44:21 UTC

[plc4x] 05/06: - Started implementing a driver for the Luxtronik2 protocol

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

cdutz pushed a commit to branch feature/luxtronik2-driver
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 2c0705abee4af305e891ab19f137afbef5a2e044
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Feb 24 09:26:22 2020 +0100

    - Started implementing a driver for the Luxtronik2 protocol
---
 .../plc4x/java/examples/helloplc4x/HelloPlc4x.java |  12 +++
 sandbox/pom.xml                                    |   2 +-
 sandbox/test-java-luxtronik2-driver/README.adoc    |  22 ++++
 sandbox/test-java-luxtronik2-driver/luxtronik2.js  |  15 +++
 sandbox/test-java-luxtronik2-driver/luxtronik2.xml |  51 ++++++++++
 sandbox/test-java-luxtronik2-driver/pom.xml        |  98 ++++++++++++++++++
 .../NoOriginWebSocketClientHandshaker13.java       | 104 +++++++++++++++++++
 .../java/org/apache/plc4x/java/atic/Test2.java     |  33 ++++++
 .../apache/plc4x/java/atic/WebSocketClient.java    |  88 ++++++++++++++++
 .../plc4x/java/luxtronik2/Luxtronik2Driver.java    |  66 ++++++++++++
 .../configuration/Luxtronik2Configuration.java     |  31 ++++++
 .../java/luxtronik2/field/Luxtronik2Field.java     |  25 +++++
 .../luxtronik2/field/Luxtronik2FieldHandler.java   |  32 ++++++
 .../plc4x/java/luxtronik2/message/GetMessage.java  |  51 ++++++++++
 .../java/luxtronik2/message/LoginMessage.java      |  51 ++++++++++
 .../java/luxtronik2/message/Luxtronik2Message.java |  34 +++++++
 .../luxtronik2/message/Luxtronik2MessageIO.java    |  56 +++++++++++
 .../java/luxtronik2/message/RefreshMessage.java    |  41 ++++++++
 .../plc4x/java/luxtronik2/message/SaveMessage.java |  51 ++++++++++
 .../plc4x/java/luxtronik2/message/SetMessage.java  |  57 +++++++++++
 .../plc4x/java/luxtronik2/model/Operation.java     |  29 ++++++
 .../protocol/Luxtronik2ProtocolLogic.java          |  52 ++++++++++
 .../Luxtronik2WebSocketClientHandler.java          | 111 +++++++++++++++++++++
 .../luxtronik2/Luxtronik2WebSocketTransport.java   |  82 +++++++++++++++
 .../Luxtronik2WebSocketTransportFactory.java       |  84 ++++++++++++++++
 .../services/org.apache.plc4x.java.api.PlcDriver   |  20 ++++
 .../org.apache.plc4x.java.spi.transport.Transport  |  20 ++++
 .../org/apache/plc4x/java/luxtronik2/Test.java     |  31 ++++++
 28 files changed, 1348 insertions(+), 1 deletion(-)

diff --git a/plc4j/examples/hello-world-plc4x/src/main/java/org/apache/plc4x/java/examples/helloplc4x/HelloPlc4x.java b/plc4j/examples/hello-world-plc4x/src/main/java/org/apache/plc4x/java/examples/helloplc4x/HelloPlc4x.java
index f9bed87..793f903 100644
--- a/plc4j/examples/hello-world-plc4x/src/main/java/org/apache/plc4x/java/examples/helloplc4x/HelloPlc4x.java
+++ b/plc4j/examples/hello-world-plc4x/src/main/java/org/apache/plc4x/java/examples/helloplc4x/HelloPlc4x.java
@@ -22,6 +22,8 @@ import org.apache.plc4x.java.PlcDriverManager;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.apache.plc4x.java.api.messages.PlcWriteRequest;
+import org.apache.plc4x.java.api.messages.PlcWriteResponse;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.slf4j.Logger;
@@ -89,6 +91,16 @@ public class HelloPlc4x {
                 }
             });
 
+            PlcWriteRequest.Builder writeBuilder = plcConnection.writeRequestBuilder();
+            writeBuilder.addItem("value-1", "%Q0.0:BOOL", true);
+            writeBuilder.addItem("value-2", "%Q0.1:BOOL", true);
+            writeBuilder.addItem("value-3", "%Q0.2:BOOL", true);
+            writeBuilder.addItem("value-4", "%Q0.3:BOOL", true);
+            final PlcWriteRequest writeRequest = writeBuilder.build();
+
+            final PlcWriteResponse plcWriteResponse = writeRequest.execute().get();
+            System.out.println(plcWriteResponse);
+
             // Give the async request a little time...
             TimeUnit.MILLISECONDS.sleep(1000);
         } catch (Exception e) {
diff --git a/sandbox/pom.xml b/sandbox/pom.xml
index 5e0bc18..129a2c5 100644
--- a/sandbox/pom.xml
+++ b/sandbox/pom.xml
@@ -41,7 +41,7 @@
     <module>test-java-amsads-driver</module>
     <module>test-java-bacnetip-driver</module>
     <module>test-java-df1-driver</module>
-    <!--module>test-java-s7-driver</module-->
+    <module>test-java-luxtronik2-driver</module>
 
     <module>test-streampipes-plc4x-adapters</module>
     <module>test-streampipes-plc4x-processors</module>
diff --git a/sandbox/test-java-luxtronik2-driver/README.adoc b/sandbox/test-java-luxtronik2-driver/README.adoc
new file mode 100644
index 0000000..ce83990
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/README.adoc
@@ -0,0 +1,22 @@
+//
+//  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
+//
+//      http://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.
+//
+
+== Luxtronik 2.0 Driver
+
+Description of the protocol:
+
+https://www.loxwiki.eu/pages/viewpage.action?pageId=18219339
\ No newline at end of file
diff --git a/sandbox/test-java-luxtronik2-driver/luxtronik2.js b/sandbox/test-java-luxtronik2-driver/luxtronik2.js
new file mode 100644
index 0000000..2abcf16
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/luxtronik2.js
@@ -0,0 +1,15 @@
+const WebSocket = require('ws');
+const webSocket = new WebSocket('ws://192.168.42.15:8214', 'Lux_WS');
+// Login
+webSocket.send('LOGIN;999999');
+// Get a list of all available options and their addresses
+webSocket.send('REFRESH');
+// Get an individual address
+webSocket.send('GET;0x28f928');
+// Set a particular address to a given value
+// TIP: in order to know what value to set a value to, execute GET for the address it will contain a list of options.
+webSocket.send('SET;0x28f928;' + value);
+// Save the change
+webSocket.send('SAVE;1');
+
+
diff --git a/sandbox/test-java-luxtronik2-driver/luxtronik2.xml b/sandbox/test-java-luxtronik2-driver/luxtronik2.xml
new file mode 100644
index 0000000..223f327
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/luxtronik2.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<Navigation id='0x281010'>
+  <item id='0x280848'>
+    <name>Informationen</name>
+    <item id='0x281578'>
+      <name>Temperaturen</name>
+    </item>
+    <item id='0x2815c0'>
+      <name>Eingänge</name>
+    </item>
+    <item id='0x281608'>
+      <name>Ausgänge</name>
+    </item>
+    <item id='0x281650'>
+      <name>Ablaufzeiten</name>
+    </item>
+    <item id='0x281530'>
+      <name>Betriebsstunden</name>
+    </item>
+    <item id='0x281468'>
+      <name>Fehlerspeicher</name>
+    </item>
+    <item id='0x281420'>
+      <name>Abschaltungen</name>
+    </item>
+    <item id='0x2813d8'>
+      <name>Anlagenstatus</name>
+    </item>
+    <item id='0x281390'>
+      <name>Wärmemenge</name>
+    </item>
+    <item id='0x281328'>
+      <name>GLT</name>
+    </item>
+  </item>
+  <item id='0x27c570'>
+    <name>Einstellungen</name>
+    <item id='0x278e20'>
+      <name>Betriebsart</name>
+    </item>
+    <item id='0x278ed0'>
+      <name>Temperaturen</name>
+    </item>
+    <item id='0x280f80'>
+      <name>System Einstellung</name>
+    </item>
+  </item>
+  <item id='0x280fc8'>
+    <name>Zugang: Benutzer</name>
+  </item>
+</Navigation>
\ No newline at end of file
diff --git a/sandbox/test-java-luxtronik2-driver/pom.xml b/sandbox/test-java-luxtronik2-driver/pom.xml
new file mode 100644
index 0000000..ca0eac4
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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
+  ~
+  ~   http://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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x.sandbox</groupId>
+    <artifactId>plc4x-sandbox</artifactId>
+    <version>0.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>test-java-luxtronik2-driver</artifactId>
+
+  <name>Sandbox: Test Luxtronik2 Driver</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-api</artifactId>
+      <version>0.7.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-spi</artifactId>
+      <version>0.7.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-transport-tcp</artifactId>
+      <version>0.7.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-buffer</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-transport</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec-http</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>websocket-client</artifactId>
+      <version>9.4.26.v20200117</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>log4j-over-slf4j</artifactId>
+      <version>1.7.25</version>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-core</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>compile</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>osgi.cmpn</artifactId>
+      <version>6.0.0</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/io/netty/handler/codec/http/websocketx/NoOriginWebSocketClientHandshaker13.java b/sandbox/test-java-luxtronik2-driver/src/main/java/io/netty/handler/codec/http/websocketx/NoOriginWebSocketClientHandshaker13.java
new file mode 100644
index 0000000..55d7be2
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/io/netty/handler/codec/http/websocketx/NoOriginWebSocketClientHandshaker13.java
@@ -0,0 +1,104 @@
+/*
+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
+
+  http://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.
+*/
+package io.netty.handler.codec.http.websocketx;
+
+import io.netty.buffer.Unpooled;
+import io.netty.handler.codec.http.*;
+import io.netty.util.AsciiString;
+import io.netty.util.CharsetUtil;
+import io.netty.util.internal.logging.InternalLogger;
+import io.netty.util.internal.logging.InternalLoggerFactory;
+
+import java.net.URI;
+
+/**
+ * Customized version of the original handshaker however with removed 'origin' header and with header names which are
+ * not just lower-case, as the web-server of the Luxtronik device seems to be quite restrictive.
+ */
+public class NoOriginWebSocketClientHandshaker13 extends WebSocketClientHandshaker13 {
+
+    private static final InternalLogger logger = InternalLoggerFactory.getInstance(NoOriginWebSocketClientHandshaker13.class);
+
+    private String expectedChallengeResponseString;
+
+    public NoOriginWebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subprotocol, boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength) {
+        super(webSocketURL, version, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength);
+    }
+
+    @Override
+    protected FullHttpRequest newHandshakeRequest() {
+        URI wsURL = uri();
+
+        // Get 16 bit nonce and base 64 encode it
+        byte[] nonce = WebSocketUtil.randomBytes(16);
+        String key = WebSocketUtil.base64(nonce);
+
+        String acceptSeed = key + MAGIC_GUID;
+        byte[] sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII));
+        expectedChallengeResponseString = WebSocketUtil.base64(sha1);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug(
+                "Luxtronik 2.0 WebSocket version 13 client handshake key: {}, expected response: {}",
+                key, expectedChallengeResponseString);
+        }
+
+        // Format request
+        FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, upgradeUrl(wsURL),
+            Unpooled.EMPTY_BUFFER);
+        HttpHeaders headers = request.headers();
+
+        headers.set(AsciiString.cached("Upgrade"), HttpHeaderValues.WEBSOCKET)
+            .set(AsciiString.cached("Connection"), HttpHeaderValues.UPGRADE)
+            .set(AsciiString.cached("Host"), websocketHostValue(wsURL))
+            .set(AsciiString.cached("Sec-WebSocket-Protocol"), "Lux_WS")
+            .set(AsciiString.cached("Sec-WebSocket-Version"), "13")
+            .set(AsciiString.cached("Sec-WebSocket-Key"), key)
+            .set(AsciiString.cached("Sec-WebSocket-Extensions"), "permessage-deflate; client_max_window_bits");
+
+        return request;
+    }
+
+    @Override
+    protected void verify(FullHttpResponse response) {
+        final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
+        final HttpHeaders headers = response.headers();
+
+        if (!response.status().equals(status)) {
+            throw new WebSocketHandshakeException("Invalid handshake response getStatus: " + response.status());
+        }
+
+        CharSequence upgrade = headers.get(HttpHeaderNames.UPGRADE);
+        if (!HttpHeaderValues.WEBSOCKET.contentEqualsIgnoreCase(upgrade)) {
+            throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
+        }
+
+        if (!headers.containsValue(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE, true)) {
+            throw new WebSocketHandshakeException("Invalid handshake response connection: "
+                + headers.get(HttpHeaderNames.CONNECTION));
+        }
+
+        CharSequence accept = headers.get(HttpHeaderNames.SEC_WEBSOCKET_ACCEPT);
+        if (accept == null || !accept.equals(expectedChallengeResponseString)) {
+            throw new WebSocketHandshakeException(String.format(
+                "Invalid challenge. Actual: %s. Expected: %s", accept, expectedChallengeResponseString));
+        }
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/atic/Test2.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/atic/Test2.java
new file mode 100644
index 0000000..3663931
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/atic/Test2.java
@@ -0,0 +1,33 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.atic;
+
+public class Test2 {
+
+    public static void main(String[] args) throws Exception {
+        WebSocketClient client = new WebSocketClient("ws://192.168.42.15:8214");
+        try {
+            client.open();
+            client.eval("LOGIN;999999");
+        } finally {
+            client.close();
+        }
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/atic/WebSocketClient.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/atic/WebSocketClient.java
new file mode 100644
index 0000000..a4b89c2
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/atic/WebSocketClient.java
@@ -0,0 +1,88 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.atic;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.websocketx.*;
+import org.apache.plc4x.java.transport.luxtronik2.Luxtronik2WebSocketClientHandler;
+
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class WebSocketClient {
+
+    private final URI uri;
+    private Channel ch;
+    private static final EventLoopGroup group = new NioEventLoopGroup();
+
+    public WebSocketClient(final String uri) {
+        this.uri = URI.create(uri);
+    }
+
+    public void open() throws Exception {
+        Bootstrap bootstrap = new Bootstrap();
+        String protocol = uri.getScheme();
+        if (!"ws".equals(protocol)) {
+            throw new IllegalArgumentException("Unsupported protocol: " + protocol);
+        }
+
+        final Luxtronik2WebSocketClientHandler handler =
+            new Luxtronik2WebSocketClientHandler(
+                new NoOriginWebSocketClientHandshaker13(
+                    uri, WebSocketVersion.V13, "Lux_WS", true, HttpHeaders.EMPTY_HEADERS, 1280000));
+
+        bootstrap.group(group)
+            .channel(NioSocketChannel.class)
+            .handler(new ChannelInitializer<SocketChannel>() {
+                @Override
+                public void initChannel(SocketChannel ch) throws Exception {
+                    ChannelPipeline pipeline = ch.pipeline();
+                    pipeline.addLast("http-codec", new HttpClientCodec());
+                    pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
+                    pipeline.addLast("ws-handler", handler);
+                }
+            });
+
+        ch = bootstrap.connect(uri.getHost(), uri.getPort()).sync().channel();
+        handler.handshakeFuture().sync();
+    }
+
+    public void close() throws InterruptedException {
+        ch.writeAndFlush(new CloseWebSocketFrame());
+        ch.closeFuture().sync();
+    }
+
+    public void eval(final String text) throws IOException {
+        ch.writeAndFlush(new TextWebSocketFrame(text));
+    }
+
+}
\ No newline at end of file
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/Luxtronik2Driver.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/Luxtronik2Driver.java
new file mode 100644
index 0000000..3c457bc
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/Luxtronik2Driver.java
@@ -0,0 +1,66 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2;
+
+import org.apache.plc4x.java.luxtronik2.configuration.Luxtronik2Configuration;
+import org.apache.plc4x.java.luxtronik2.field.Luxtronik2FieldHandler;
+import org.apache.plc4x.java.luxtronik2.message.Luxtronik2Message;
+import org.apache.plc4x.java.luxtronik2.message.Luxtronik2MessageIO;
+import org.apache.plc4x.java.luxtronik2.protocol.Luxtronik2ProtocolLogic;
+import org.apache.plc4x.java.spi.configuration.Configuration;
+import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
+import org.apache.plc4x.java.spi.connection.PlcFieldHandler;
+import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer;
+import org.apache.plc4x.java.spi.connection.SingleProtocolStackConfigurer;
+
+public class Luxtronik2Driver extends GeneratedDriverBase<Luxtronik2Message> {
+
+    @Override
+    public String getProtocolCode() {
+        return "lt2";
+    }
+
+    @Override
+    public String getProtocolName() {
+        return "Luxtronik 2.0 Driver";
+    }
+
+    @Override
+    protected Class<? extends Configuration> getConfigurationType() {
+        return Luxtronik2Configuration.class;
+    }
+
+    @Override
+    protected String getDefaultTransport() {
+        return "lt2ws";
+    }
+
+    @Override
+    protected PlcFieldHandler getFieldHandler() {
+        return new Luxtronik2FieldHandler();
+    }
+
+    @Override
+    protected ProtocolStackConfigurer<Luxtronik2Message> getStackConfigurer() {
+        return SingleProtocolStackConfigurer.builder(Luxtronik2Message.class, Luxtronik2MessageIO.class)
+            .withProtocol(Luxtronik2ProtocolLogic.class)
+            .build();
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/configuration/Luxtronik2Configuration.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/configuration/Luxtronik2Configuration.java
new file mode 100644
index 0000000..b341754
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/configuration/Luxtronik2Configuration.java
@@ -0,0 +1,31 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.configuration;
+
+import org.apache.plc4x.java.spi.configuration.Configuration;
+import org.apache.plc4x.java.transport.tcp.TcpTransportConfiguration;
+
+public class Luxtronik2Configuration implements Configuration, TcpTransportConfiguration {
+
+    @Override
+    public int getDefaultPort() {
+        return 8214;
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/field/Luxtronik2Field.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/field/Luxtronik2Field.java
new file mode 100644
index 0000000..54c848f
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/field/Luxtronik2Field.java
@@ -0,0 +1,25 @@
+/*
+ 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
+
+   http://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.
+ */
+package org.apache.plc4x.java.luxtronik2.field;
+
+import org.apache.plc4x.java.api.model.PlcField;
+
+public interface Luxtronik2Field extends PlcField {
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/field/Luxtronik2FieldHandler.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/field/Luxtronik2FieldHandler.java
new file mode 100644
index 0000000..02e94f3
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/field/Luxtronik2FieldHandler.java
@@ -0,0 +1,32 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.field;
+
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.spi.connection.DefaultPlcFieldHandler;
+
+public class Luxtronik2FieldHandler extends DefaultPlcFieldHandler {
+
+    @Override
+    public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
+        return null;
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/GetMessage.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/GetMessage.java
new file mode 100644
index 0000000..1f3d62f
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/GetMessage.java
@@ -0,0 +1,51 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.message;
+
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.luxtronik2.model.Operation;
+
+public class GetMessage extends Luxtronik2Message {
+
+    private final String address;
+
+    public GetMessage(String address) {
+        this.address = address;
+    }
+
+    @Override
+    public Operation getOperation() {
+        return Operation.SET;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    @Override
+    public int getLengthInBytes() {
+        return 4 + address.length();
+    }
+
+    @Override
+    public PlcValue toPlcValue() {
+        return null;
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/LoginMessage.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/LoginMessage.java
new file mode 100644
index 0000000..e8ac24e
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/LoginMessage.java
@@ -0,0 +1,51 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.message;
+
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.luxtronik2.model.Operation;
+
+public class LoginMessage extends Luxtronik2Message {
+
+    private final String password;
+
+    public LoginMessage(String password) {
+        this.password = password;
+    }
+
+    @Override
+    public Operation getOperation() {
+        return Operation.LOGIN;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    @Override
+    public int getLengthInBytes() {
+        return 6 + password.length();
+    }
+
+    @Override
+    public PlcValue toPlcValue() {
+        return null;
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/Luxtronik2Message.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/Luxtronik2Message.java
new file mode 100644
index 0000000..44052f9
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/Luxtronik2Message.java
@@ -0,0 +1,34 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.message;
+
+import org.apache.plc4x.java.luxtronik2.model.Operation;
+import org.apache.plc4x.java.spi.generation.Message;
+import org.apache.plc4x.java.spi.generation.MessageIO;
+
+public abstract class Luxtronik2Message implements Message {
+
+    public abstract Operation getOperation();
+
+    @Override
+    public MessageIO<? extends Message, ? extends Message> getMessageIO() {
+        return new Luxtronik2MessageIO();
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/Luxtronik2MessageIO.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/Luxtronik2MessageIO.java
new file mode 100644
index 0000000..b36b11b
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/Luxtronik2MessageIO.java
@@ -0,0 +1,56 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.message;
+
+import org.apache.plc4x.java.spi.generation.MessageIO;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.WriteBuffer;
+
+public class Luxtronik2MessageIO implements MessageIO<Luxtronik2Message, Luxtronik2Message> {
+
+    @Override
+    public Luxtronik2Message parse(ReadBuffer io, Object... args) throws ParseException {
+        return null;
+    }
+
+    @Override
+    public void serialize(WriteBuffer io, Luxtronik2Message value, Object... args) throws ParseException {
+        if(value instanceof LoginMessage) {
+            LoginMessage loginMessage = (LoginMessage) value;
+            writeString(io, "LOGIN;" + loginMessage.getPassword());
+        } else if(value instanceof RefreshMessage) {
+            writeString(io, "REFRESH");
+        } else if(value instanceof GetMessage) {
+            GetMessage getMessage = (GetMessage) value;
+            writeString(io, "GET;" + getMessage.getAddress());
+        } else if(value instanceof SetMessage) {
+            SetMessage setMessage = (SetMessage) value;
+            writeString(io, "SET;" + setMessage.getAddress() + ";" + setMessage.getValue());
+        } else if(value instanceof SaveMessage) {
+            SaveMessage saveMessage = (SaveMessage) value;
+            writeString(io, "SAVE;" + (saveMessage.getSave() ? "1" : "0"));
+        }
+    }
+
+    protected void writeString(WriteBuffer io, String str) throws ParseException {
+        io.writeString(str.length() * 8, "UTF-8", str);
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/RefreshMessage.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/RefreshMessage.java
new file mode 100644
index 0000000..b892ea0
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/RefreshMessage.java
@@ -0,0 +1,41 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.message;
+
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.luxtronik2.model.Operation;
+
+public class RefreshMessage extends Luxtronik2Message {
+
+    @Override
+    public Operation getOperation() {
+        return Operation.REFRESH;
+    }
+
+    @Override
+    public int getLengthInBytes() {
+        return 7;
+    }
+
+    @Override
+    public PlcValue toPlcValue() {
+        return null;
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/SaveMessage.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/SaveMessage.java
new file mode 100644
index 0000000..d2d00c9
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/SaveMessage.java
@@ -0,0 +1,51 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.message;
+
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.luxtronik2.model.Operation;
+
+public class SaveMessage extends Luxtronik2Message {
+
+    private final boolean save;
+
+    public SaveMessage(boolean save) {
+        this.save = save;
+    }
+
+    @Override
+    public Operation getOperation() {
+        return Operation.SET;
+    }
+
+    public boolean getSave() {
+        return save;
+    }
+
+    @Override
+    public int getLengthInBytes() {
+        return 5;
+    }
+
+    @Override
+    public PlcValue toPlcValue() {
+        return null;
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/SetMessage.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/SetMessage.java
new file mode 100644
index 0000000..3631aa8
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/message/SetMessage.java
@@ -0,0 +1,57 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.message;
+
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.apache.plc4x.java.luxtronik2.model.Operation;
+
+public class SetMessage extends Luxtronik2Message {
+
+    private final String address;
+    private final String value;
+
+    public SetMessage(String address, String value) {
+        this.address = address;
+        this.value = value;
+    }
+
+    @Override
+    public Operation getOperation() {
+        return Operation.SET;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public int getLengthInBytes() {
+        return 5 + address.length() + value.length();
+    }
+
+    @Override
+    public PlcValue toPlcValue() {
+        return null;
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/model/Operation.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/model/Operation.java
new file mode 100644
index 0000000..44076e9
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/model/Operation.java
@@ -0,0 +1,29 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.model;
+
+public enum Operation {
+
+    LOGIN,
+    REFRESH,
+    GET,
+    SET,
+    SAVE
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/protocol/Luxtronik2ProtocolLogic.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/protocol/Luxtronik2ProtocolLogic.java
new file mode 100644
index 0000000..8666090
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/luxtronik2/protocol/Luxtronik2ProtocolLogic.java
@@ -0,0 +1,52 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2.protocol;
+
+import org.apache.plc4x.java.luxtronik2.configuration.Luxtronik2Configuration;
+import org.apache.plc4x.java.luxtronik2.message.LoginMessage;
+import org.apache.plc4x.java.luxtronik2.message.Luxtronik2Message;
+import org.apache.plc4x.java.spi.ConversationContext;
+import org.apache.plc4x.java.spi.Plc4xProtocolBase;
+import org.apache.plc4x.java.spi.configuration.HasConfiguration;
+
+public class Luxtronik2ProtocolLogic extends Plc4xProtocolBase<Luxtronik2Message> implements HasConfiguration<Luxtronik2Configuration> {
+
+    private Luxtronik2Configuration configuration;
+
+    @Override
+    public void setConfiguration(Luxtronik2Configuration configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public void onConnect(ConversationContext<Luxtronik2Message> context) {
+        context.sendToWire(new LoginMessage("999999"));
+    }
+
+    @Override
+    public void close(ConversationContext<Luxtronik2Message> context) {
+
+    }
+
+    @Override
+    protected void decode(ConversationContext<Luxtronik2Message> context, Luxtronik2Message msg) throws Exception {
+        super.decode(context, msg);
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/transport/luxtronik2/Luxtronik2WebSocketClientHandler.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/transport/luxtronik2/Luxtronik2WebSocketClientHandler.java
new file mode 100644
index 0000000..846160c
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/transport/luxtronik2/Luxtronik2WebSocketClientHandler.java
@@ -0,0 +1,111 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.transport.luxtronik2;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
+import io.netty.handler.codec.http.websocketx.WebSocketFrame;
+import io.netty.util.CharsetUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class Luxtronik2WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {
+
+    private static final Logger logger = LoggerFactory.getLogger(Luxtronik2WebSocketClientHandler.class);
+
+    private final WebSocketClientHandshaker handshaker;
+    private ChannelPromise handshakeFuture;
+
+    public Luxtronik2WebSocketClientHandler(final WebSocketClientHandshaker handshaker) {
+        this.handshaker = handshaker;
+    }
+
+    public ChannelFuture handshakeFuture() {
+        return handshakeFuture;
+    }
+
+    @Override
+    public void handlerAdded(final ChannelHandlerContext ctx) {
+        handshakeFuture = ctx.newPromise();
+    }
+
+    @Override
+    public void channelActive(final ChannelHandlerContext ctx) {
+        handshaker.handshake(ctx.channel());
+    }
+
+    @Override
+    public void channelInactive(final ChannelHandlerContext ctx) {
+        //System.out.println("WebSocket Client disconnected!");
+    }
+
+    @Override
+    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
+        final Channel ch = ctx.channel();
+        if (!handshaker.isHandshakeComplete()) {
+            // web socket client connected
+            handshaker.finishHandshake(ch, (FullHttpResponse) msg);
+            handshakeFuture.setSuccess();
+            return;
+        }
+
+        if (msg instanceof FullHttpResponse) {
+            final FullHttpResponse response = (FullHttpResponse) msg;
+            throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content="
+                + response.content().toString(CharsetUtil.UTF_8) + ')');
+        }
+
+        final WebSocketFrame frame = (WebSocketFrame) msg;
+        if (frame instanceof TextWebSocketFrame) {
+            final TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
+            // uncomment to print request
+            logger.info(textFrame.text());
+        } else if (frame instanceof PongWebSocketFrame) {
+        } else if (frame instanceof CloseWebSocketFrame)
+            ch.close();
+        else if (frame instanceof BinaryWebSocketFrame) {
+            // uncomment to print request
+            logger.info(frame.content().toString());
+        }
+    }
+
+    @Override
+    public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
+        cause.printStackTrace();
+
+        if (!handshakeFuture.isDone()) {
+            handshakeFuture.setFailure(cause);
+        }
+
+        ctx.close();
+    }
+
+}
\ No newline at end of file
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/transport/luxtronik2/Luxtronik2WebSocketTransport.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/transport/luxtronik2/Luxtronik2WebSocketTransport.java
new file mode 100644
index 0000000..68e0c33
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/transport/luxtronik2/Luxtronik2WebSocketTransport.java
@@ -0,0 +1,82 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.transport.luxtronik2;
+
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.spi.configuration.HasConfiguration;
+import org.apache.plc4x.java.spi.connection.ChannelFactory;
+import org.apache.plc4x.java.spi.transport.Transport;
+import org.apache.plc4x.java.transport.tcp.TcpTransportConfiguration;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Luxtronik2WebSocketTransport implements Transport, HasConfiguration<TcpTransportConfiguration> {
+
+    private static final Pattern TRANSPORT_TCP_PATTERN = Pattern.compile(
+        "^((?<ip>[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3})|(?<hostname>[a-zA-Z0-9\\.\\-]+))(:(?<port>[0-9]{1,5}))?");
+
+    private TcpTransportConfiguration configuration;
+
+    @Override
+    public void setConfiguration(TcpTransportConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public String getTransportCode() {
+        return "lt2ws";
+    }
+
+    @Override
+    public String getTransportName() {
+        return "Luxtronik 2 WebSocket Transport";
+    }
+
+    @Override
+    public ChannelFactory createChannelFactory(String transportConfig) {
+        final Matcher matcher = TRANSPORT_TCP_PATTERN.matcher(transportConfig);
+        if(!matcher.matches()) {
+            throw new PlcRuntimeException("Invalid url for TCP transport");
+        }
+        String ip = matcher.group("ip");
+        String hostname = matcher.group("hostname");
+        String portString = matcher.group("port");
+
+        // If the port wasn't specified, try to get a default port from the configuration.
+        int port;
+        if(portString != null) {
+            port = Integer.parseInt(portString);
+        } else if ((configuration != null) &&
+            (configuration.getDefaultPort() != TcpTransportConfiguration.NO_DEFAULT_PORT)) {
+            port = configuration.getDefaultPort();
+        } else {
+            throw new PlcRuntimeException("No port defined");
+        }
+
+        // Create the fully qualified remote socket address which we should connect to.
+        SocketAddress address = new InetSocketAddress((ip == null) ? hostname : ip, port);
+
+        // Initialize the channel factory with the default socket address we want to connect to.
+        return new Luxtronik2WebSocketTransportFactory(address);
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/transport/luxtronik2/Luxtronik2WebSocketTransportFactory.java b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/transport/luxtronik2/Luxtronik2WebSocketTransportFactory.java
new file mode 100644
index 0000000..41cb1c7
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/java/org/apache/plc4x/java/transport/luxtronik2/Luxtronik2WebSocketTransportFactory.java
@@ -0,0 +1,84 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.transport.luxtronik2;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.ChannelPromise;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.websocketx.NoOriginWebSocketClientHandshaker13;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketVersion;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.transport.tcp.TcpChannelFactory;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+public class Luxtronik2WebSocketTransportFactory extends TcpChannelFactory {
+
+    private URI connectionUri;
+
+    public Luxtronik2WebSocketTransportFactory(SocketAddress address) {
+        super(address);
+        InetSocketAddress socketAddress = (InetSocketAddress) address;
+        try {
+            connectionUri = new URI("ws", null, socketAddress.getHostName(), socketAddress.getPort(), "/", null, null);
+        } catch (URISyntaxException e) {
+            throw new PlcRuntimeException(e);
+        }
+    }
+
+    @Override
+    public void initializePipeline(ChannelPipeline pipeline) {
+        final Luxtronik2WebSocketClientHandler handler =
+            new Luxtronik2WebSocketClientHandler(
+                new NoOriginWebSocketClientHandshaker13(
+                    connectionUri, WebSocketVersion.V13, "Lux_WS", true, HttpHeaders.EMPTY_HEADERS, 1280000));
+
+        pipeline.addLast("http-codec", new HttpClientCodec());
+        pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
+        pipeline.addLast("web-socket-handler", handler);
+        pipeline.addLast("wrapper", new ChannelDuplexHandler() {
+            @Override
+            public void read(ChannelHandlerContext ctx) throws Exception {
+                super.read(ctx);
+            }
+
+            @Override
+            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
+                if (msg instanceof ByteBuf) {
+                    ByteBuf byteBuf = (ByteBuf) msg;
+                    byte[] bytes = new byte[byteBuf.readableBytes()];
+                    byteBuf.readBytes(bytes);
+                    ctx.write(new TextWebSocketFrame(new String(bytes)), promise);
+                } else {
+                    ctx.write(msg, promise);
+                }
+            }
+        });
+    }
+
+}
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver b/sandbox/test-java-luxtronik2-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver
new file mode 100644
index 0000000..9277975
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.api.PlcDriver
@@ -0,0 +1,20 @@
+#
+# 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
+#
+#   http://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.
+#
+
+org.apache.plc4x.java.luxtronik2.Luxtronik2Driver
diff --git a/sandbox/test-java-luxtronik2-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.transport.Transport b/sandbox/test-java-luxtronik2-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.transport.Transport
new file mode 100644
index 0000000..37cbe38
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.transport.Transport
@@ -0,0 +1,20 @@
+#
+# 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
+#
+#   http://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.
+#
+
+org.apache.plc4x.java.transport.luxtronik2.Luxtronik2WebSocketTransport
\ No newline at end of file
diff --git a/sandbox/test-java-luxtronik2-driver/src/test/java/org/apache/plc4x/java/luxtronik2/Test.java b/sandbox/test-java-luxtronik2-driver/src/test/java/org/apache/plc4x/java/luxtronik2/Test.java
new file mode 100644
index 0000000..91024a4
--- /dev/null
+++ b/sandbox/test-java-luxtronik2-driver/src/test/java/org/apache/plc4x/java/luxtronik2/Test.java
@@ -0,0 +1,31 @@
+/*
+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
+
+  http://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.
+*/
+package org.apache.plc4x.java.luxtronik2;
+
+import org.apache.plc4x.java.PlcDriverManager;
+import org.apache.plc4x.java.api.PlcConnection;
+
+public class Test {
+
+    public static void main(String[] args) throws Exception {
+        final PlcConnection connection = new PlcDriverManager().getConnection("lt2://192.168.42.15");
+        System.out.println(connection);
+    }
+
+}