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.powermax.internal.handler;
15 import static org.openhab.binding.powermax.internal.PowermaxBindingConstants.*;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.openhab.binding.powermax.internal.config.PowermaxX10Configuration;
19 import org.openhab.binding.powermax.internal.config.PowermaxZoneConfiguration;
20 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettings;
21 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettingsListener;
22 import org.openhab.binding.powermax.internal.state.PowermaxState;
23 import org.openhab.binding.powermax.internal.state.PowermaxStateContainer.Value;
24 import org.openhab.binding.powermax.internal.state.PowermaxX10Settings;
25 import org.openhab.binding.powermax.internal.state.PowermaxZoneSettings;
26 import org.openhab.core.library.types.OnOffType;
27 import org.openhab.core.thing.Bridge;
28 import org.openhab.core.thing.ChannelUID;
29 import org.openhab.core.thing.Thing;
30 import org.openhab.core.thing.ThingStatus;
31 import org.openhab.core.thing.ThingStatusDetail;
32 import org.openhab.core.thing.ThingStatusInfo;
33 import org.openhab.core.thing.binding.BaseThingHandler;
34 import org.openhab.core.thing.binding.ThingHandler;
35 import org.openhab.core.types.Command;
36 import org.openhab.core.types.RefreshType;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * The {@link PowermaxThingHandler} is responsible for handling commands, which are
42 * sent to one of the channels.
44 * @author Laurent Garnier - Initial contribution
46 public class PowermaxThingHandler extends BaseThingHandler implements PowermaxPanelSettingsListener {
48 private final Logger logger = LoggerFactory.getLogger(PowermaxThingHandler.class);
50 private static final int ZONE_NR_MIN = 1;
51 private static final int ZONE_NR_MAX = 64;
52 private static final int X10_NR_MIN = 1;
53 private static final int X10_NR_MAX = 16;
55 private PowermaxBridgeHandler bridgeHandler;
57 public PowermaxThingHandler(Thing thing) {
62 public void initialize() {
63 logger.debug("Initializing handler for thing {}", getThing().getUID());
64 Bridge bridge = getBridge();
66 initializeThingState(null, null);
68 initializeThingState(bridge.getHandler(), bridge.getStatus());
73 public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
74 logger.debug("Bridge status changed to {} for thing {}", bridgeStatusInfo, getThing().getUID());
75 Bridge bridge = getBridge();
76 initializeThingState((bridge == null) ? null : bridge.getHandler(), bridgeStatusInfo.getStatus());
79 private void initializeThingState(ThingHandler bridgeHandler, ThingStatus bridgeStatus) {
80 if (bridgeHandler != null && bridgeStatus != null) {
81 if (bridgeStatus == ThingStatus.ONLINE) {
82 boolean validConfig = false;
83 String errorMsg = "Unexpected thing type " + getThing().getThingTypeUID();
85 if (getThing().getThingTypeUID().equals(THING_TYPE_ZONE)) {
86 PowermaxZoneConfiguration config = getConfigAs(PowermaxZoneConfiguration.class);
87 if (config.zoneNumber != null && config.zoneNumber >= ZONE_NR_MIN
88 && config.zoneNumber <= ZONE_NR_MAX) {
91 errorMsg = "zoneNumber setting must be defined in thing configuration and set between "
92 + ZONE_NR_MIN + " and " + ZONE_NR_MAX;
94 } else if (getThing().getThingTypeUID().equals(THING_TYPE_X10)) {
95 PowermaxX10Configuration config = getConfigAs(PowermaxX10Configuration.class);
96 if (config.deviceNumber != null && config.deviceNumber >= X10_NR_MIN
97 && config.deviceNumber <= X10_NR_MAX) {
100 errorMsg = "deviceNumber setting must be defined in thing configuration and set between "
101 + X10_NR_MIN + " and " + X10_NR_MAX;
106 updateStatus(ThingStatus.UNKNOWN);
107 logger.debug("Set handler status to UNKNOWN for thing {} (bridge ONLINE)", getThing().getUID());
108 this.bridgeHandler = (PowermaxBridgeHandler) bridgeHandler;
109 this.bridgeHandler.registerPanelSettingsListener(this);
110 onPanelSettingsUpdated(this.bridgeHandler.getPanelSettings());
112 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg);
115 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
116 logger.debug("Set handler status to OFFLINE for thing {} (bridge OFFLINE)", getThing().getUID());
119 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
120 logger.debug("Set handler status to OFFLINE for thing {}", getThing().getUID());
125 public void dispose() {
126 logger.debug("Handler disposed for thing {}", getThing().getUID());
127 if (bridgeHandler != null) {
128 bridgeHandler.unregisterPanelSettingsListener(this);
134 public void handleCommand(ChannelUID channelUID, Command command) {
135 logger.debug("Received command {} from channel {}", command, channelUID.getId());
137 if (bridgeHandler == null) {
139 } else if (command instanceof RefreshType) {
140 updateChannelFromAlarmState(channelUID.getId(), bridgeHandler.getCurrentState());
142 switch (channelUID.getId()) {
144 if (command instanceof OnOffType) {
145 bridgeHandler.zoneBypassed(getConfigAs(PowermaxZoneConfiguration.class).zoneNumber.byteValue(),
146 command.equals(OnOffType.ON));
148 logger.debug("Command of type {} while OnOffType is expected. Command is ignored.",
149 command.getClass().getSimpleName());
153 bridgeHandler.x10Command(getConfigAs(PowermaxX10Configuration.class).deviceNumber.byteValue(),
157 logger.debug("No available command for channel {}. Command is ignored.", channelUID.getId());
164 * Update channel to match a new alarm system state
166 * @param channel: the channel
167 * @param state: the alarm system state
169 public void updateChannelFromAlarmState(String channel, PowermaxState state) {
170 if (state == null || channel == null || !isLinked(channel)) {
174 if (getThing().getThingTypeUID().equals(THING_TYPE_ZONE)) {
175 int num = getConfigAs(PowermaxZoneConfiguration.class).zoneNumber.intValue();
177 for (Value<?> value : state.getZone(num).getValues()) {
178 String v_channel = value.getChannel();
180 if (channel.equals(v_channel) && (value.getValue() != null)) {
181 updateState(v_channel, value.getState());
184 } else if (getThing().getThingTypeUID().equals(THING_TYPE_X10)) {
185 int num = getConfigAs(PowermaxX10Configuration.class).deviceNumber.intValue();
186 if (channel.equals(X10_STATUS) && (state.getPGMX10DeviceStatus(num) != null)) {
187 updateState(X10_STATUS, state.getPGMX10DeviceStatus(num) ? OnOffType.ON : OnOffType.OFF);
193 public void onPanelSettingsUpdated(@Nullable PowermaxPanelSettings settings) {
194 if (getThing().getThingTypeUID().equals(THING_TYPE_ZONE)) {
195 PowermaxZoneConfiguration config = getConfigAs(PowermaxZoneConfiguration.class);
196 onZoneSettingsUpdated(config.zoneNumber, settings);
197 } else if (getThing().getThingTypeUID().equals(THING_TYPE_X10)) {
198 if (isNotReadyForThingStatusUpdate()) {
202 PowermaxX10Configuration config = getConfigAs(PowermaxX10Configuration.class);
203 PowermaxX10Settings deviceSettings = (settings == null) ? null
204 : settings.getX10Settings(config.deviceNumber);
205 if (settings == null) {
206 if (getThing().getStatus() != ThingStatus.UNKNOWN) {
207 updateStatus(ThingStatus.UNKNOWN);
208 logger.debug("Set handler status to UNKNOWN for thing {}", getThing().getUID());
210 } else if (deviceSettings == null || !deviceSettings.isEnabled()) {
211 if (getThing().getStatus() != ThingStatus.OFFLINE) {
212 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Disabled device");
213 logger.debug("Set handler status to OFFLINE for thing {} (X10 device {} disabled)",
214 getThing().getUID(), config.deviceNumber);
216 } else if (getThing().getStatus() != ThingStatus.ONLINE) {
217 updateStatus(ThingStatus.ONLINE);
218 logger.debug("Set handler status to ONLINE for thing {} (X10 device {} enabled)", getThing().getUID(),
219 config.deviceNumber);
225 public void onZoneSettingsUpdated(int zoneNumber, @Nullable PowermaxPanelSettings settings) {
226 if (getThing().getThingTypeUID().equals(THING_TYPE_ZONE)) {
227 PowermaxZoneConfiguration config = getConfigAs(PowermaxZoneConfiguration.class);
228 if (zoneNumber == config.zoneNumber) {
229 if (isNotReadyForThingStatusUpdate()) {
233 PowermaxZoneSettings zoneSettings = (settings == null) ? null
234 : settings.getZoneSettings(config.zoneNumber);
235 if (settings == null) {
236 if (getThing().getStatus() != ThingStatus.UNKNOWN) {
237 updateStatus(ThingStatus.UNKNOWN);
238 logger.debug("Set handler status to UNKNOWN for thing {}", getThing().getUID());
240 } else if (zoneSettings == null) {
241 if (getThing().getStatus() != ThingStatus.OFFLINE) {
242 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Zone not paired");
243 logger.debug("Set handler status to OFFLINE for thing {} (zone number {} not paired)",
244 getThing().getUID(), config.zoneNumber);
246 } else if (getThing().getStatus() != ThingStatus.ONLINE) {
247 updateStatus(ThingStatus.ONLINE);
248 logger.debug("Set handler status to ONLINE for thing {} (zone number {} paired)",
249 getThing().getUID(), config.zoneNumber);
255 private boolean isNotReadyForThingStatusUpdate() {
256 return (getThing().getStatus() == ThingStatus.OFFLINE)
257 && ((getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.CONFIGURATION_ERROR)
258 || (getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.BRIDGE_OFFLINE)
259 || (getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.BRIDGE_UNINITIALIZED));
262 public PowermaxZoneConfiguration getZoneConfiguration() {
263 return getConfigAs(PowermaxZoneConfiguration.class);
266 public PowermaxX10Configuration getX10Configuration() {
267 return getConfigAs(PowermaxX10Configuration.class);