2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.wifiled.internal.handler;
15 import static org.openhab.binding.wifiled.internal.handler.ClassicWiFiLEDDriver.bytesToHex;
17 import java.io.DataInputStream;
18 import java.io.DataOutputStream;
19 import java.io.IOException;
20 import java.net.Socket;
22 import org.openhab.core.library.types.HSBType;
23 import org.openhab.core.library.types.OnOffType;
24 import org.openhab.core.library.types.PercentType;
25 import org.openhab.core.library.types.StringType;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
30 * Abstract WiFi LED driver.
32 * @author Osman Basha - Initial contribution
33 * @author Stefan Endrullis
34 * @author Ries van Twisk
36 public abstract class AbstractWiFiLEDDriver {
38 public enum Protocol {
49 public static final Integer DEFAULT_PORT = 5577;
51 protected static final int DEFAULT_SOCKET_TIMEOUT = 5000;
53 protected Logger logger = LoggerFactory.getLogger(AbstractWiFiLEDDriver.class);
54 protected String host;
56 protected Protocol protocol;
58 public AbstractWiFiLEDDriver(String host, int port, Protocol protocol) {
61 this.protocol = protocol;
65 * Allow to cleanup the driver
67 public abstract void shutdown();
69 public abstract void setColor(HSBType color) throws IOException;
71 public abstract void setBrightness(PercentType brightness) throws IOException;
73 public abstract void incBrightness(int step) throws IOException;
75 public void decBrightness(int step) throws IOException {
79 public abstract void setWhite(PercentType white) throws IOException;
81 public abstract void incWhite(int step) throws IOException;
83 public void decWhite(int step) throws IOException {
87 public abstract void setWhite2(PercentType white2) throws IOException;
89 public abstract void incWhite2(int step) throws IOException;
91 public void decWhite2(int step) throws IOException {
95 public abstract void setProgram(StringType program) throws IOException;
97 public abstract void setProgramSpeed(PercentType speed) throws IOException;
99 public abstract void incProgramSpeed(int step) throws IOException;
101 public void decProgramSpeed(int step) throws IOException {
102 incProgramSpeed(-step);
105 public abstract void setPower(OnOffType command) throws IOException;
107 public void init() throws IOException {
111 public abstract LEDStateDTO getLEDStateDTO() throws IOException;
113 protected synchronized LEDState getLEDState() throws IOException {
114 try (Socket socket = new Socket(host, port);
115 DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
116 DataInputStream inputStream = new DataInputStream(socket.getInputStream())) {
117 logger.debug("Connected to '{}'", socket);
119 socket.setSoTimeout(DEFAULT_SOCKET_TIMEOUT);
121 byte[] data = { (byte) 0x81, (byte) 0x8A, (byte) 0x8B, (byte) 0x96 };
122 outputStream.write(data);
123 logger.debug("Data sent: '{}'", bytesToHex(data));
125 byte[] statusBytes = new byte[14];
126 inputStream.readFully(statusBytes);
127 logger.debug("Data read: '{}'", bytesToHex(statusBytes));
129 // Example response (14 Bytes):
130 // 0x81 0x04 0x23 0x26 0x21 0x10 0x45 0x00 0x00 0x00 0x03 0x00 0x00 0x47
131 // ..........^--- On/Off.........R....G....B....WW........CW
132 // ...............^-- PGM...^---SPEED...............
134 int state = statusBytes[2] & 0xFF; // On/Off
135 int program = statusBytes[3] & 0xFF;
136 int programSpeed = statusBytes[5] & 0xFF;
138 // On factory default the controller can be configured
139 // with a value of 255 but max should be 31.
140 if (programSpeed > 31) {
144 int red = statusBytes[6] & 0xFF;
145 int green = statusBytes[7] & 0xFF;
146 int blue = statusBytes[8] & 0xFF;
147 int white = statusBytes[9] & 0xFF;
148 int white2 = protocol == Protocol.LD686 ? statusBytes[11] & 0xFF : 0;
150 logger.debug("RGBW: {},{},{},{}, {}", red, green, blue, white, white2);
152 return new LEDState(state, program, programSpeed, red, green, blue, white, white2);
156 protected void sendRaw(byte[] data) throws IOException {
160 protected synchronized void sendRaw(byte[] data, int delay) throws IOException {
161 try (Socket socket = new Socket(host, port);
162 DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) {
163 logger.debug("Connected to '{}'", socket);
165 socket.setSoTimeout(DEFAULT_SOCKET_TIMEOUT);
167 sendRaw(data, outputStream);
172 } catch (InterruptedException e) {
173 Thread.currentThread().interrupt();
177 protected void sendRaw(byte[] data, DataOutputStream outputStream) throws IOException {
180 // append 0x0F (if dev.type LD382A)
181 if (protocol == Protocol.LD382A || protocol == Protocol.LD686) {
182 dataWithCS = new byte[data.length + 2];
183 dataWithCS[dataWithCS.length - 2] = 0x0F;
185 dataWithCS = new byte[data.length + 1];
189 System.arraycopy(data, 0, dataWithCS, 0, data.length);
191 for (int i = 0; i < dataWithCS.length - 1; i++) {
195 dataWithCS[dataWithCS.length - 1] = (byte) cs;
197 outputStream.write(dataWithCS);
198 logger.debug("RAW data sent: '{}'", bytesToHex(dataWithCS));
201 protected byte[] getBytesForColor(byte r, byte g, byte b, byte w, byte w2) {
203 if (protocol == Protocol.LD382 || protocol == Protocol.LD382A) {
204 bytes = new byte[] { 0x31, r, g, b, w, 0x00 };
205 } else if (protocol == Protocol.LD686) {
206 bytes = new byte[] { 0x31, r, g, b, w, w2, 0x00 };
208 throw new UnsupportedOperationException("Protocol " + protocol + " not yet implemented");
213 protected byte[] getBytesForPower(boolean on) {
214 return new byte[] { 0x71, on ? (byte) 0x23 : 0x24 };