]> git.basschouten.com Git - openhab-addons.git/blob
885b33e9335add2b5e3e89cfe618428ee115f380
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.wifiled.internal.handler;
14
15 import static org.openhab.binding.wifiled.internal.handler.ClassicWiFiLEDDriver.bytesToHex;
16
17 import java.io.DataInputStream;
18 import java.io.DataOutputStream;
19 import java.io.IOException;
20 import java.net.Socket;
21
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;
28
29 /**
30  * Abstract WiFi LED driver.
31  *
32  * @author Osman Basha - Initial contribution
33  * @author Stefan Endrullis - Improvements
34  * @author Ries van Twisk - Improvements
35  */
36 public abstract class AbstractWiFiLEDDriver {
37
38     public enum Protocol {
39         LD382,
40         LD382A,
41         LD686
42     }
43
44     public enum Driver {
45         CLASSIC,
46         FADING
47     }
48
49     public static final Integer DEFAULT_PORT = 5577;
50
51     protected static final int DEFAULT_SOCKET_TIMEOUT = 5000;
52
53     protected Logger logger = LoggerFactory.getLogger(AbstractWiFiLEDDriver.class);
54     protected String host;
55     protected int port;
56     protected Protocol protocol;
57
58     public AbstractWiFiLEDDriver(String host, int port, Protocol protocol) {
59         this.host = host;
60         this.port = port;
61         this.protocol = protocol;
62     }
63
64     /**
65      * Allow to cleanup the driver
66      */
67     public abstract void shutdown();
68
69     public abstract void setColor(HSBType color) throws IOException;
70
71     public abstract void setBrightness(PercentType brightness) throws IOException;
72
73     public abstract void incBrightness(int step) throws IOException;
74
75     public void decBrightness(int step) throws IOException {
76         incBrightness(-step);
77     }
78
79     public abstract void setWhite(PercentType white) throws IOException;
80
81     public abstract void incWhite(int step) throws IOException;
82
83     public void decWhite(int step) throws IOException {
84         incWhite(-step);
85     }
86
87     public abstract void setWhite2(PercentType white2) throws IOException;
88
89     public abstract void incWhite2(int step) throws IOException;
90
91     public void decWhite2(int step) throws IOException {
92         incWhite2(-step);
93     }
94
95     public abstract void setProgram(StringType program) throws IOException;
96
97     public abstract void setProgramSpeed(PercentType speed) throws IOException;
98
99     public abstract void incProgramSpeed(int step) throws IOException;
100
101     public void decProgramSpeed(int step) throws IOException {
102         incProgramSpeed(-step);
103     }
104
105     public abstract void setPower(OnOffType command) throws IOException;
106
107     public void init() throws IOException {
108         getLEDState();
109     }
110
111     public abstract LEDStateDTO getLEDStateDTO() throws IOException;
112
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);
118
119             socket.setSoTimeout(DEFAULT_SOCKET_TIMEOUT);
120
121             byte[] data = { (byte) 0x81, (byte) 0x8A, (byte) 0x8B, (byte) 0x96 };
122             outputStream.write(data);
123             logger.debug("Data sent: '{}'", bytesToHex(data));
124
125             byte[] statusBytes = new byte[14];
126             inputStream.readFully(statusBytes);
127             logger.debug("Data read: '{}'", bytesToHex(statusBytes));
128
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...............
133
134             int state = statusBytes[2] & 0xFF; // On/Off
135             int program = statusBytes[3] & 0xFF;
136             int programSpeed = statusBytes[5] & 0xFF;
137
138             // On factory default the controller can be configured
139             // with a value of 255 but max should be 31.
140             if (programSpeed > 31) {
141                 programSpeed = 31;
142             }
143
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;
149
150             logger.debug("RGBW: {},{},{},{}, {}", red, green, blue, white, white2);
151
152             return new LEDState(state, program, programSpeed, red, green, blue, white, white2);
153         }
154     }
155
156     protected void sendRaw(byte[] data) throws IOException {
157         sendRaw(data, 100);
158     }
159
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);
164
165             socket.setSoTimeout(DEFAULT_SOCKET_TIMEOUT);
166
167             sendRaw(data, outputStream);
168
169             if (delay > 0) {
170                 Thread.sleep(delay);
171             }
172         } catch (InterruptedException e) {
173             Thread.currentThread().interrupt();
174         }
175     }
176
177     protected void sendRaw(byte[] data, DataOutputStream outputStream) throws IOException {
178         byte[] dataWithCS;
179
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;
184         } else {
185             dataWithCS = new byte[data.length + 1];
186         }
187
188         // append checksum
189         System.arraycopy(data, 0, dataWithCS, 0, data.length);
190         int cs = 0;
191         for (int i = 0; i < dataWithCS.length - 1; i++) {
192             cs += dataWithCS[i];
193         }
194         cs = cs & 0xFF;
195         dataWithCS[dataWithCS.length - 1] = (byte) cs;
196
197         outputStream.write(dataWithCS);
198         logger.debug("RAW data sent: '{}'", bytesToHex(dataWithCS));
199     }
200
201     protected byte[] getBytesForColor(byte r, byte g, byte b, byte w, byte w2) {
202         byte[] bytes;
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 };
207         } else {
208             throw new UnsupportedOperationException("Protocol " + protocol + " not yet implemented");
209         }
210         return bytes;
211     }
212
213     protected byte[] getBytesForPower(boolean on) {
214         return new byte[] { 0x71, on ? (byte) 0x23 : 0x24 };
215     }
216 }