2 * Copyright (c) 2010-2023 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.milight.internal.handler;
15 import org.openhab.binding.milight.internal.MilightThingState;
16 import org.openhab.binding.milight.internal.protocol.ProtocolConstants;
17 import org.openhab.binding.milight.internal.protocol.QueuedSend;
18 import org.openhab.core.thing.Thing;
21 * Implements functionality for the RGB/White bulbs for protocol version 3.
22 * Color temperature and saturation are not supported for this type of bulbs.
24 * @author David Graeff - Initial contribution
26 public class MilightV3RGBWHandler extends AbstractLedV3Handler {
27 protected static final int BRIGHTNESS_LEVELS = 26;
29 private static final byte[] COMMAND_ON = { (byte) 0x42, (byte) 0x45, (byte) 0x47, (byte) 0x49, (byte) 0x4B };
30 private static final byte[] COMMAND_OFF = { (byte) 0x41, (byte) 0x46, (byte) 0x48, (byte) 0x4A, (byte) 0x4C };
31 private static final byte[] COMMAND_WHITEMODE = { (byte) 0xC2, (byte) 0xC5, (byte) 0xC7, (byte) 0xC9, (byte) 0xCB };
32 private static final byte[] NIGHTMODE_FIRST = { 0x41, 0x46, 0x48, 0x4A, 0x4C };
33 private static final byte[] NIGHTMODE_SECOND = { (byte) 0xC1, (byte) 0xC6, (byte) 0xC8, (byte) 0xCA, (byte) 0xCC };
34 private static final byte[] NEXT_ANIMATION_MODE = { 0x4D, 0x00, 0x55 };
36 public MilightV3RGBWHandler(Thing thing, QueuedSend sendQueue) {
37 super(thing, sendQueue, 10);
40 // We have no real saturation control for RGBW bulbs. If the saturation is under a 50% threshold
41 // we just change to white mode instead.
43 public void setHSB(int hue, int saturation, int brightness, MilightThingState state) {
44 if (saturation < 50) {
48 final byte[] messageBytes = new byte[] { 0x40, makeColor(hue), 0x55 };
49 final byte[] cOn = { COMMAND_ON[config.zone], 0x00, 0x55 };
50 sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_COLOR_SET), cOn).addRepeatable(messageBytes));
53 if (brightness != -1) {
54 setBrightness(brightness, state);
59 public void setPower(boolean on, MilightThingState state) {
61 sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_POWER_MODE),
62 new byte[] { COMMAND_ON[config.zone], 0x00, 0x55 }));
64 sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_POWER_MODE),
65 new byte[] { COMMAND_OFF[config.zone], 0x00, 0x55 }));
70 public void whiteMode(MilightThingState state) {
71 final byte[] cOn = { COMMAND_ON[config.zone], 0x00, 0x55 };
72 final byte[] cWhite = { COMMAND_WHITEMODE[config.zone], 0x00, 0x55 };
73 sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_WHITEMODE), cOn).addRepeatable(cWhite));
77 public void nightMode(MilightThingState state) {
78 final byte[] cN1 = { NIGHTMODE_FIRST[config.zone], 0x00, 0x55 };
79 final byte[] cN2 = { NIGHTMODE_SECOND[config.zone], 0x00, 0x55 };
80 sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_POWER_MODE), cN1).addRepeatable(cN2));
84 public void setColorTemperature(int colorTemp, MilightThingState state) {
88 public void changeColorTemperature(int colorTempRelative, MilightThingState state) {
92 public void setBrightness(int newvalue, MilightThingState state) {
93 int value = Math.min(Math.max(newvalue, 0), 100);
96 state.brightness = value;
97 sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_POWER_MODE),
98 new byte[] { COMMAND_OFF[config.zone], 0x00, 0x55 }));
102 int br = (int) Math.ceil((value * BRIGHTNESS_LEVELS) / 100.0) + 1;
104 final byte[] cOn = { COMMAND_ON[config.zone], 0x00, 0x55 };
105 sendQueue.queue(createRepeatable(uidc(ProtocolConstants.CAT_BRIGHTNESS_SET), cOn)
106 .addRepeatable(new byte[] { 0x4E, (byte) br, 0x55 }));
108 state.brightness = value;
112 public void changeBrightness(int relativeBrightness, MilightThingState state) {
113 setBrightness(Math.max(0, Math.min(100, state.brightness + relativeBrightness)), state);
117 public void changeSpeed(int relativeSpeed, MilightThingState state) {
118 if (relativeSpeed == 0) {
122 final byte[] cOn = { COMMAND_ON[config.zone], 0x00, 0x55 };
123 final byte[] cSpeed = { (byte) (relativeSpeed > 0 ? 0x44 : 0x43), 0x00, 0x55 };
124 sendQueue.queue(createRepeatable(cOn).addNonRepeatable(cSpeed));
127 // This bulb actually doesn't implement a previous animation mode command. We just use the next mode command
130 public void previousAnimationMode(MilightThingState state) {
131 final byte[] cOn = { COMMAND_ON[config.zone], 0x00, 0x55 };
132 sendQueue.queue(createRepeatable(cOn).addNonRepeatable(NEXT_ANIMATION_MODE));
133 state.animationMode = (state.animationMode + 1) % (MAX_ANIM_MODES + 1);
137 public void nextAnimationMode(MilightThingState state) {
138 final byte[] cOn = { COMMAND_ON[config.zone], 0x00, 0x55 };
139 sendQueue.queue(createRepeatable(cOn).addNonRepeatable(NEXT_ANIMATION_MODE));
140 state.animationMode = (state.animationMode + 1) % (MAX_ANIM_MODES + 1);