2 * Copyright (c) 2010-2020 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.lutron.internal.handler;
15 import static org.openhab.binding.lutron.internal.LutronBindingConstants.*;
17 import java.math.BigDecimal;
19 import org.openhab.binding.lutron.internal.config.BlindConfig;
20 import org.openhab.binding.lutron.internal.protocol.LutronCommandType;
21 import org.openhab.core.library.types.PercentType;
22 import org.openhab.core.library.types.StopMoveType;
23 import org.openhab.core.library.types.UpDownType;
24 import org.openhab.core.thing.Bridge;
25 import org.openhab.core.thing.ChannelUID;
26 import org.openhab.core.thing.Thing;
27 import org.openhab.core.thing.ThingStatus;
28 import org.openhab.core.thing.ThingStatusDetail;
29 import org.openhab.core.types.Command;
30 import org.openhab.core.types.RefreshType;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
35 * Handler responsible for communicating with Lutron blinds
37 * @author Bob Adair - Initial contribution based on Alan Tong's DimmerHandler
39 public class BlindHandler extends LutronHandler {
40 private static final Integer ACTION_LIFTLEVEL = 1;
41 private static final Integer ACTION_TILTLEVEL = 9;
42 private static final Integer ACTION_LIFTTILTLEVEL = 10;
43 private static final Integer ACTION_STARTRAISINGTILT = 11;
44 private static final Integer ACTION_STARTLOWERINGTILT = 12;
45 private static final Integer ACTION_STOPTILT = 13;
46 private static final Integer ACTION_STARTRAISINGLIFT = 14;
47 private static final Integer ACTION_STARTLOWERINGLIFT = 15;
48 private static final Integer ACTION_STOPLIFT = 16;
49 private static final Integer ACTION_POSITION_UPDATE = 32; // undocumented in integration protocol guide
50 private static final Integer PARAMETER_POSITION_UPDATE = 2; // undocumented in integration protocol guide
52 private int tiltMax = 100; // max 50 for horizontal sheer, 100 for venetian
54 private final Logger logger = LoggerFactory.getLogger(BlindHandler.class);
56 private BlindConfig config;
58 public BlindHandler(Thing thing) {
63 public int getIntegrationId() {
65 throw new IllegalStateException("handler configuration not initialized");
67 return config.integrationId;
71 public void initialize() {
72 config = getThing().getConfiguration().as(BlindConfig.class);
73 if (config.integrationId <= 0) {
74 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No integrationId configured");
77 if (config.type == null || (!(BLIND_TYPE_SHEER.equalsIgnoreCase(config.type))
78 && !(BLIND_TYPE_VENETIAN.equalsIgnoreCase(config.type)))) {
79 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
80 "Parameter type not set to valid value");
83 String blindType = config.type;
84 if (BLIND_TYPE_SHEER.equalsIgnoreCase(blindType)) {
87 logger.debug("Initializing Blind handler with type {} for integration ID {}", blindType, config.integrationId);
92 protected void initDeviceState() {
93 logger.debug("Initializing device state for Shade {}", getIntegrationId());
94 Bridge bridge = getBridge();
96 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No bridge configured");
97 } else if (bridge.getStatus() == ThingStatus.ONLINE) {
98 updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "Awaiting initial response");
99 queryOutput(ACTION_LIFTLEVEL); // handleUpdate() will set thing status to online when response arrives
100 queryOutput(ACTION_TILTLEVEL);
102 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
107 public void channelLinked(ChannelUID channelUID) {
108 // Refresh state when new item is linked.
109 if (channelUID.getId().equals(CHANNEL_BLINDLIFTLEVEL)) {
110 queryOutput(ACTION_LIFTLEVEL);
111 } else if (channelUID.getId().equals(CHANNEL_BLINDTILTLEVEL)) {
112 queryOutput(ACTION_TILTLEVEL);
117 public void handleCommand(ChannelUID channelUID, Command command) {
118 if (channelUID.getId().equals(CHANNEL_BLINDLIFTLEVEL)) {
119 handleLiftCommand(command);
120 } else if (channelUID.getId().equals(CHANNEL_BLINDTILTLEVEL)) {
121 handleTiltCommand(command);
125 private void handleLiftCommand(Command command) {
126 if (command instanceof PercentType) {
127 int level = ((PercentType) command).intValue();
128 output(ACTION_LIFTLEVEL, level, 0);
129 } else if (command.equals(UpDownType.UP)) {
130 output(ACTION_STARTRAISINGLIFT);
131 } else if (command.equals(UpDownType.DOWN)) {
132 output(ACTION_STARTLOWERINGLIFT);
133 } else if (command.equals(StopMoveType.STOP)) {
134 output(ACTION_STOPLIFT);
135 } else if (command instanceof RefreshType) {
136 queryOutput(ACTION_LIFTLEVEL);
140 private void handleTiltCommand(Command command) {
141 if (command instanceof PercentType) {
142 int level = ((PercentType) command).intValue();
143 output(ACTION_TILTLEVEL, Math.min(level, tiltMax), 0);
144 } else if (command.equals(UpDownType.UP)) {
145 output(ACTION_STARTRAISINGTILT);
146 } else if (command.equals(UpDownType.DOWN)) {
147 output(ACTION_STARTLOWERINGTILT);
148 } else if (command.equals(StopMoveType.STOP)) {
149 output(ACTION_STOPTILT);
150 } else if (command instanceof RefreshType) {
151 queryOutput(ACTION_TILTLEVEL);
156 public void handleUpdate(LutronCommandType type, String... parameters) {
157 if (type == LutronCommandType.OUTPUT && parameters.length >= 2) {
158 if (getThing().getStatus() == ThingStatus.UNKNOWN) {
159 updateStatus(ThingStatus.ONLINE);
162 if (ACTION_LIFTLEVEL.toString().equals(parameters[0])) {
163 BigDecimal liftLevel = new BigDecimal(parameters[1]);
164 logger.trace("Blind {} received lift level: {}", getIntegrationId(), liftLevel);
165 updateState(CHANNEL_BLINDLIFTLEVEL, new PercentType(liftLevel));
166 } else if (ACTION_TILTLEVEL.toString().equals(parameters[0])) {
167 BigDecimal tiltLevel = new BigDecimal(parameters[1]);
168 logger.trace("Blind {} received tilt level: {}", getIntegrationId(), tiltLevel);
169 updateState(CHANNEL_BLINDTILTLEVEL, new PercentType(tiltLevel));
170 } else if (ACTION_LIFTTILTLEVEL.toString().equals(parameters[0]) && parameters.length > 2) {
171 BigDecimal liftLevel = new BigDecimal(parameters[1]);
172 BigDecimal tiltLevel = new BigDecimal(parameters[2]);
173 logger.trace("Blind {} received lift/tilt level: {} {}", getIntegrationId(), liftLevel, tiltLevel);
174 updateState(CHANNEL_BLINDLIFTLEVEL, new PercentType(liftLevel));
175 updateState(CHANNEL_BLINDTILTLEVEL, new PercentType(tiltLevel));
176 } else if (ACTION_POSITION_UPDATE.toString().equals(parameters[0])
177 && PARAMETER_POSITION_UPDATE.toString().equals(parameters[1]) && parameters.length >= 3) {
178 BigDecimal level = new BigDecimal(parameters[2]);
179 logger.trace("Blind {} received lift level position update: {}", getIntegrationId(), level);
180 updateState(CHANNEL_BLINDLIFTLEVEL, new PercentType(level));