]> git.basschouten.com Git - openhab-addons.git/blob
4af9b3dbcae0078fa4ab9475c4b67ddc975f030f
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.milight.internal.handler;
14
15 import org.eclipse.jdt.annotation.NonNullByDefault;
16 import org.openhab.binding.milight.internal.MilightThingState;
17 import org.openhab.binding.milight.internal.protocol.ProtocolConstants;
18 import org.openhab.binding.milight.internal.protocol.QueueItem;
19 import org.openhab.binding.milight.internal.protocol.QueuedSend;
20 import org.openhab.core.thing.Thing;
21
22 /**
23  * Implements functionality for the Dual White bulbs for protocol version 3.
24  * Color temperature is supported for this type of bulbs.
25  *
26  * @author David Graeff - Initial contribution
27  */
28 @NonNullByDefault
29 public class MilightV3WhiteHandler extends AbstractLedV3Handler {
30     protected static final int BRIGHTNESS_LEVELS = 11;
31
32     public MilightV3WhiteHandler(Thing thing, QueuedSend sendQueue) {
33         super(thing, sendQueue, 0);
34     }
35
36     private static final byte COMMAND_FULL[] = { (byte) 0xB5, (byte) 0xB8, (byte) 0xBD, (byte) 0xB7, (byte) 0xB2 };
37     private static final byte COMMAND_ON[] = { (byte) 0x35, (byte) 0x38, (byte) 0x3D, (byte) 0x37, (byte) 0x32 };
38     private static final byte COMMAND_OFF[] = { (byte) 0x39, (byte) 0x3B, (byte) 0x33, (byte) 0x3A, (byte) 0x36 };
39     private static final byte COMMAND_NIGHTMODE[] = { (byte) 0xB9, (byte) 0xBB, (byte) 0xB3, (byte) 0xBA, (byte) 0xB6 };
40     private static final byte PREV_ANIMATION_MODE[] = { 0x27, 0x00, 0x55 };
41     private static final byte NEXT_ANIMATION_MODE[] = { 0x27, 0x00, 0x55 };
42
43     protected void setFull(int zone, MilightThingState state) {
44         sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_BRIGHTNESS_SET),
45                 new byte[] { COMMAND_FULL[zone], 0x00, 0x55 }));
46         state.brightness = 100;
47     }
48
49     @Override
50     public void setHSB(int hue, int saturation, int brightness, MilightThingState state) {
51         // This bulb type only supports a brightness value
52         if (brightness != -1) {
53             setBrightness(brightness, state);
54         }
55     }
56
57     @Override
58     public void setPower(boolean on, MilightThingState state) {
59         if (on) {
60             sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_POWER_MODE),
61                     new byte[] { COMMAND_ON[config.zone], 0x00, 0x55 }));
62         } else {
63             sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_POWER_MODE),
64                     new byte[] { COMMAND_OFF[config.zone], 0x00, 0x55 }));
65             state.brightness = 0;
66         }
67     }
68
69     @Override
70     public void whiteMode(MilightThingState state) {
71     }
72
73     @Override
74     public void nightMode(MilightThingState state) {
75         final byte cOn[] = { COMMAND_ON[config.zone], 0x00, 0x55 };
76         final byte cNight[] = { COMMAND_NIGHTMODE[config.zone], 0x00, 0x55 };
77         sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_POWER_MODE), cOn).addRepeatable(cNight));
78     }
79
80     @Override
81     public void setColorTemperature(int colorTemp, MilightThingState state) {
82         // White Bulbs: 11 levels of temperature + Off.
83         int newLevel;
84         int oldLevel;
85         // Reset bulb to known state
86         if (colorTemp <= 0) {
87             colorTemp = 0;
88             newLevel = 1;
89             oldLevel = BRIGHTNESS_LEVELS;
90         } else if (colorTemp >= 100) {
91             colorTemp = 100;
92             newLevel = BRIGHTNESS_LEVELS;
93             oldLevel = 1;
94         } else {
95             newLevel = (int) Math.ceil((colorTemp * BRIGHTNESS_LEVELS) / 100.0);
96             oldLevel = (int) Math.ceil((state.colorTemperature * BRIGHTNESS_LEVELS) / 100.0);
97         }
98
99         final int repeatCount = Math.abs(newLevel - oldLevel);
100         if (newLevel > oldLevel) {
101             for (int i = 0; i < repeatCount; i++) {
102                 changeColorTemperature(1, state);
103             }
104         } else if (newLevel < oldLevel) {
105             for (int i = 0; i < repeatCount; i++) {
106                 changeColorTemperature(-1, state);
107             }
108         }
109
110         state.colorTemperature = colorTemp;
111     }
112
113     @Override
114     public void changeColorTemperature(int colorTempRelative, MilightThingState state) {
115         state.colorTemperature = Math.min(100, Math.max(state.colorTemperature + colorTempRelative, 0));
116         final byte cOn[] = { COMMAND_ON[config.zone], 0x00, 0x55 };
117         final byte cTemp[] = { (byte) (colorTempRelative > 0 ? 0x3E : 0x3F), 0x00, 0x55 };
118         sendQueue.queue(createRepeatable(cOn).addNonRepeatable(cTemp));
119     }
120
121     // This just emulates an absolute brightness command with the relative commands.
122     @Override
123     public void setBrightness(int value, MilightThingState state) {
124         if (value <= 0) {
125             setPower(false, state);
126             return;
127         } else if (value >= 100) {
128             setFull(config.zone, state);
129             return;
130         }
131
132         // White Bulbs: 11 levels of brightness + Off.
133         final int newLevel = (int) Math.ceil((value * BRIGHTNESS_LEVELS) / 100.0);
134
135         // When turning on start from full brightness
136         int oldLevel;
137         final byte cFull[] = { COMMAND_FULL[config.zone], 0x00, 0x55 };
138         QueueItem item = createRepeatable(cFull);
139         boolean skipFirst = false;
140
141         if (state.brightness == 0) {
142             oldLevel = BRIGHTNESS_LEVELS;
143         } else {
144             oldLevel = (int) Math.ceil((state.brightness * BRIGHTNESS_LEVELS) / 100.0);
145             skipFirst = true;
146
147             if (newLevel == oldLevel) {
148                 return;
149             }
150         }
151
152         final int repeatCount = Math.abs(newLevel - oldLevel);
153
154         logger.debug("milight: dim from '{}' with command '{}' via '{}' steps.", String.valueOf(state.brightness),
155                 String.valueOf(value), repeatCount);
156
157         int op = newLevel > oldLevel ? +1 : -1;
158         final byte cOn[] = { COMMAND_ON[config.zone], 0x00, 0x55 };
159         for (int i = 0; i < repeatCount; i++) {
160             final byte[] cBr = { (byte) (op < 0 ? 0x34 : 0x3C), 0x00, 0x55 };
161             item = item.addRepeatable(cOn).addNonRepeatable(cBr);
162         }
163
164         final QueueItem nextItem = item.next;
165         if (nextItem != null && skipFirst) {
166             sendQueue.queue(nextItem);
167         } else {
168             sendQueue.queue(item);
169         }
170
171         state.brightness = value;
172     }
173
174     @Override
175     public void changeBrightness(int relativeBrightness, MilightThingState state) {
176         if (relativeBrightness == 0) {
177             return;
178         }
179         state.brightness = Math.min(Math.max(state.brightness + relativeBrightness, 0), 100);
180
181         if (state.brightness == 0) {
182             sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_POWER_MODE),
183                     new byte[] { COMMAND_OFF[config.zone], 0x00, 0x55 }));
184         } else {
185             final byte cOn[] = { COMMAND_ON[config.zone], 0x00, 0x55 };
186             final byte cBr[] = { (byte) (relativeBrightness < 0 ? 0x34 : 0x3C), 0x00, 0x55 };
187             sendQueue.queue(createRepeatable(cOn).addNonRepeatable(cBr));
188         }
189     }
190
191     @Override
192     public void changeSpeed(int relativeSpeed, MilightThingState state) {
193     }
194
195     @Override
196     public void previousAnimationMode(MilightThingState state) {
197         final byte cOn[] = { COMMAND_ON[config.zone], 0x00, 0x55 };
198         sendQueue.queue(createRepeatable(cOn).addNonRepeatable(PREV_ANIMATION_MODE));
199         state.animationMode = Math.max(state.animationMode - 1, 0);
200     }
201
202     @Override
203     public void nextAnimationMode(MilightThingState state) {
204         final byte cOn[] = { COMMAND_ON[config.zone], 0x00, 0x55 };
205         sendQueue.queue(createRepeatable(cOn).addNonRepeatable(NEXT_ANIMATION_MODE));
206         state.animationMode = Math.min(state.animationMode + 1, MAX_ANIM_MODES);
207     }
208 }