2 * Copyright (c) 2010-2021 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.tradfri.internal.handler;
15 import static org.openhab.binding.tradfri.internal.TradfriBindingConstants.*;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.openhab.binding.tradfri.internal.model.TradfriLightData;
20 import org.openhab.core.library.types.HSBType;
21 import org.openhab.core.library.types.IncreaseDecreaseType;
22 import org.openhab.core.library.types.OnOffType;
23 import org.openhab.core.library.types.PercentType;
24 import org.openhab.core.thing.ChannelUID;
25 import org.openhab.core.thing.Thing;
26 import org.openhab.core.thing.ThingStatus;
27 import org.openhab.core.types.Command;
28 import org.openhab.core.types.RefreshType;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 import com.google.gson.JsonElement;
35 * The {@link TradfriLightHandler} is responsible for handling commands for individual lights.
37 * @author Kai Kreuzer - Initial contribution
38 * @author Holger Reichert - Support for color bulbs
39 * @author Christoph Weitkamp - Restructuring and refactoring of the binding
42 public class TradfriLightHandler extends TradfriThingHandler {
44 private final Logger logger = LoggerFactory.getLogger(TradfriLightHandler.class);
46 // step size for increase/decrease commands
47 private static final int STEP = 10;
49 // keeps track of the current state for handling of increase/decrease
50 private @Nullable TradfriLightData state;
52 public TradfriLightHandler(Thing thing) {
57 public void onUpdate(JsonElement data) {
58 if (active && !(data.isJsonNull())) {
59 TradfriLightData state = new TradfriLightData(data);
60 updateStatus(state.getReachabilityStatus() ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
62 if (!state.getOnOffState()) {
63 logger.debug("Setting state to OFF");
64 updateState(CHANNEL_BRIGHTNESS, PercentType.ZERO);
65 if (lightHasColorSupport()) {
66 updateState(CHANNEL_COLOR, HSBType.BLACK);
68 // if we are turned off, we do not set any brightness value
72 PercentType dimmer = state.getBrightness();
73 if (dimmer != null && !lightHasColorSupport()) { // color lights do not have brightness channel
74 updateState(CHANNEL_BRIGHTNESS, dimmer);
77 PercentType colorTemp = state.getColorTemperature();
78 if (colorTemp != null) {
79 updateState(CHANNEL_COLOR_TEMPERATURE, colorTemp);
83 if (lightHasColorSupport()) {
84 color = state.getColor();
86 updateState(CHANNEL_COLOR, color);
90 updateDeviceProperties(state);
95 "Updating thing for lightId {} to state {dimmer: {}, colorTemp: {}, color: {}, firmwareVersion: {}, modelId: {}, vendor: {}}",
96 state.getDeviceId(), dimmer, colorTemp, color, state.getFirmwareVersion(), state.getModelId(),
101 private void setBrightness(PercentType percent) {
102 TradfriLightData data = new TradfriLightData();
103 data.setBrightness(percent).setTransitionTime(DEFAULT_DIMMER_TRANSITION_TIME);
104 set(data.getJsonString());
107 private void setState(OnOffType onOff) {
108 TradfriLightData data = new TradfriLightData();
109 data.setOnOffState(onOff == OnOffType.ON);
110 set(data.getJsonString());
113 private void setColorTemperature(PercentType percent) {
114 TradfriLightData data = new TradfriLightData();
115 data.setColorTemperature(percent).setTransitionTime(DEFAULT_DIMMER_TRANSITION_TIME);
116 set(data.getJsonString());
119 private void setColor(HSBType hsb) {
120 TradfriLightData data = new TradfriLightData();
121 data.setColor(hsb).setTransitionTime(DEFAULT_DIMMER_TRANSITION_TIME);
122 set(data.getJsonString());
126 public void handleCommand(ChannelUID channelUID, Command command) {
128 if (command instanceof RefreshType) {
129 logger.debug("Refreshing channel {}", channelUID);
130 coapClient.asyncGet(this);
134 switch (channelUID.getId()) {
135 case CHANNEL_BRIGHTNESS:
136 handleBrightnessCommand(command);
138 case CHANNEL_COLOR_TEMPERATURE:
139 handleColorTemperatureCommand(command);
142 handleColorCommand(command);
145 logger.error("Unknown channel UID {}", channelUID);
150 private void handleBrightnessCommand(Command command) {
151 if (command instanceof PercentType) {
152 setBrightness((PercentType) command);
153 } else if (command instanceof OnOffType) {
154 setState(((OnOffType) command));
155 } else if (command instanceof IncreaseDecreaseType) {
156 final TradfriLightData state = this.state;
157 if (state != null && state.getBrightness() != null) {
158 @SuppressWarnings("null")
159 int current = state.getBrightness().intValue();
160 if (IncreaseDecreaseType.INCREASE.equals(command)) {
161 setBrightness(new PercentType(Math.min(current + STEP, PercentType.HUNDRED.intValue())));
163 setBrightness(new PercentType(Math.max(current - STEP, PercentType.ZERO.intValue())));
166 logger.debug("Cannot handle inc/dec as current state is not known.");
169 logger.debug("Cannot handle command {} for channel {}", command, CHANNEL_BRIGHTNESS);
173 private void handleColorTemperatureCommand(Command command) {
174 if (command instanceof PercentType) {
175 setColorTemperature((PercentType) command);
176 } else if (command instanceof IncreaseDecreaseType) {
177 final TradfriLightData state = this.state;
178 if (state != null && state.getColorTemperature() != null) {
179 @SuppressWarnings("null")
180 int current = state.getColorTemperature().intValue();
181 if (IncreaseDecreaseType.INCREASE.equals(command)) {
182 setColorTemperature(new PercentType(Math.min(current + STEP, PercentType.HUNDRED.intValue())));
184 setColorTemperature(new PercentType(Math.max(current - STEP, PercentType.ZERO.intValue())));
187 logger.debug("Cannot handle inc/dec as current state is not known.");
190 logger.debug("Can't handle command {} on channel {}", command, CHANNEL_COLOR_TEMPERATURE);
194 private void handleColorCommand(Command command) {
195 if (command instanceof HSBType) {
196 setColor((HSBType) command);
197 setBrightness(((HSBType) command).getBrightness());
198 } else if (command instanceof OnOffType) {
199 setState(((OnOffType) command));
200 } else if (command instanceof PercentType) {
201 setBrightness((PercentType) command);
202 } else if (command instanceof IncreaseDecreaseType) {
203 final TradfriLightData state = this.state;
204 // increase or decrease only the brightness, but keep color
205 if (state != null && state.getBrightness() != null) {
206 @SuppressWarnings("null")
207 int current = state.getBrightness().intValue();
208 if (IncreaseDecreaseType.INCREASE.equals(command)) {
209 setBrightness(new PercentType(Math.min(current + STEP, PercentType.HUNDRED.intValue())));
211 setBrightness(new PercentType(Math.max(current - STEP, PercentType.ZERO.intValue())));
214 logger.debug("Cannot handle inc/dec for color as current brightness is not known.");
217 logger.debug("Can't handle command {} on channel {}", command, CHANNEL_COLOR);
222 * Checks if this light supports full color.
224 * @return true if the light supports full color
226 private boolean lightHasColorSupport() {
227 return thing.getThingTypeUID().getId().equals(THING_TYPE_COLOR_LIGHT.getId());