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);
+ }
+
+}