]> git.basschouten.com Git - openhab-addons.git/blob
77f07e1b23e71d1dc1847bac63e3d212df700516
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.powermax.internal.handler;
14
15 import static org.openhab.binding.powermax.internal.PowermaxBindingConstants.*;
16
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.openhab.binding.powermax.internal.config.PowermaxX10Configuration;
20 import org.openhab.binding.powermax.internal.config.PowermaxZoneConfiguration;
21 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettings;
22 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettingsListener;
23 import org.openhab.binding.powermax.internal.state.PowermaxState;
24 import org.openhab.binding.powermax.internal.state.PowermaxStateContainer.Value;
25 import org.openhab.binding.powermax.internal.state.PowermaxX10Settings;
26 import org.openhab.binding.powermax.internal.state.PowermaxZoneSettings;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.thing.Bridge;
29 import org.openhab.core.thing.ChannelUID;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingStatus;
32 import org.openhab.core.thing.ThingStatusDetail;
33 import org.openhab.core.thing.ThingStatusInfo;
34 import org.openhab.core.thing.binding.BaseThingHandler;
35 import org.openhab.core.thing.binding.ThingHandler;
36 import org.openhab.core.types.Command;
37 import org.openhab.core.types.RefreshType;
38 import org.openhab.core.types.UnDefType;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * The {@link PowermaxThingHandler} is responsible for handling commands, which are
44  * sent to one of the channels.
45  *
46  * @author Laurent Garnier - Initial contribution
47  */
48 @NonNullByDefault
49 public class PowermaxThingHandler extends BaseThingHandler implements PowermaxPanelSettingsListener {
50
51     private static final int ZONE_NR_MIN = 1;
52     private static final int ZONE_NR_MAX = 64;
53     private static final int X10_NR_MIN = 1;
54     private static final int X10_NR_MAX = 16;
55
56     private final Logger logger = LoggerFactory.getLogger(PowermaxThingHandler.class);
57
58     private @Nullable PowermaxBridgeHandler bridgeHandler;
59
60     public PowermaxThingHandler(Thing thing) {
61         super(thing);
62     }
63
64     @Override
65     public void initialize() {
66         logger.debug("Initializing handler for thing {}", getThing().getUID());
67         Bridge bridge = getBridge();
68         if (bridge == null) {
69             initializeThingState(null, null);
70         } else {
71             initializeThingState(bridge.getHandler(), bridge.getStatus());
72         }
73     }
74
75     @Override
76     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
77         logger.debug("Bridge status changed to {} for thing {}", bridgeStatusInfo, getThing().getUID());
78         Bridge bridge = getBridge();
79         initializeThingState((bridge == null) ? null : bridge.getHandler(), bridgeStatusInfo.getStatus());
80     }
81
82     private void initializeThingState(@Nullable ThingHandler bridgeHandler, @Nullable ThingStatus bridgeStatus) {
83         if (bridgeHandler != null && bridgeStatus != null) {
84             if (bridgeStatus == ThingStatus.ONLINE) {
85                 boolean validConfig = false;
86                 String errorMsg = "Unexpected thing type " + getThing().getThingTypeUID();
87
88                 if (getThing().getThingTypeUID().equals(THING_TYPE_ZONE)) {
89                     PowermaxZoneConfiguration config = getConfigAs(PowermaxZoneConfiguration.class);
90                     if (config.zoneNumber >= ZONE_NR_MIN && config.zoneNumber <= ZONE_NR_MAX) {
91                         validConfig = true;
92                     } else {
93                         errorMsg = "zoneNumber setting must be defined in thing configuration and set between "
94                                 + ZONE_NR_MIN + " and " + ZONE_NR_MAX;
95                     }
96                 } else if (getThing().getThingTypeUID().equals(THING_TYPE_X10)) {
97                     PowermaxX10Configuration config = getConfigAs(PowermaxX10Configuration.class);
98                     if (config.deviceNumber >= X10_NR_MIN && config.deviceNumber <= X10_NR_MAX) {
99                         validConfig = true;
100                     } else {
101                         errorMsg = "deviceNumber setting must be defined in thing configuration and set between "
102                                 + X10_NR_MIN + " and " + X10_NR_MAX;
103                     }
104                 }
105
106                 if (validConfig) {
107                     updateStatus(ThingStatus.UNKNOWN);
108                     logger.debug("Set handler status to UNKNOWN for thing {} (bridge ONLINE)", getThing().getUID());
109                     PowermaxBridgeHandler powermaxBridgeHandler = (PowermaxBridgeHandler) bridgeHandler;
110                     this.bridgeHandler = powermaxBridgeHandler;
111                     powermaxBridgeHandler.registerPanelSettingsListener(this);
112                     onPanelSettingsUpdated(powermaxBridgeHandler.getPanelSettings());
113                 } else {
114                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg);
115                 }
116             } else {
117                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
118                 setAllChannelsOffline();
119                 logger.debug("Set handler status to OFFLINE for thing {} (bridge OFFLINE)", getThing().getUID());
120             }
121         } else {
122             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
123             logger.debug("Set handler status to OFFLINE for thing {}", getThing().getUID());
124         }
125     }
126
127     /**
128      * Update all channels to an UNDEF state to indicate that the bridge is offline
129      */
130     private synchronized void setAllChannelsOffline() {
131         getThing().getChannels().forEach(c -> updateState(c.getUID(), UnDefType.UNDEF));
132     }
133
134     @Override
135     public void dispose() {
136         logger.debug("Handler disposed for thing {}", getThing().getUID());
137         PowermaxBridgeHandler powermaxBridgeHandler = bridgeHandler;
138         if (powermaxBridgeHandler != null) {
139             powermaxBridgeHandler.unregisterPanelSettingsListener(this);
140         }
141         super.dispose();
142     }
143
144     @Override
145     public void handleCommand(ChannelUID channelUID, Command command) {
146         logger.debug("Received command {} from channel {}", command, channelUID.getId());
147
148         PowermaxBridgeHandler powermaxBridgeHandler = bridgeHandler;
149         if (powermaxBridgeHandler == null) {
150             return;
151         } else if (command instanceof RefreshType) {
152             updateChannelFromAlarmState(channelUID.getId(), powermaxBridgeHandler.getCurrentState());
153         } else {
154             switch (channelUID.getId()) {
155                 case BYPASSED:
156                     if (command instanceof OnOffType) {
157                         powermaxBridgeHandler.zoneBypassed(
158                                 Byte.valueOf(
159                                         (byte) (getConfigAs(PowermaxZoneConfiguration.class).zoneNumber & 0x000000FF)),
160                                 command.equals(OnOffType.ON));
161                     } else {
162                         logger.debug("Command of type {} while OnOffType is expected. Command is ignored.",
163                                 command.getClass().getSimpleName());
164                     }
165                     break;
166                 case X10_STATUS:
167                     powermaxBridgeHandler.x10Command(
168                             Byte.valueOf(
169                                     (byte) (getConfigAs(PowermaxX10Configuration.class).deviceNumber & 0x000000FF)),
170                             command);
171                     break;
172                 default:
173                     logger.debug("No available command for channel {}. Command is ignored.", channelUID.getId());
174                     break;
175             }
176         }
177     }
178
179     /**
180      * Update channel to match a new alarm system state
181      *
182      * @param channel: the channel
183      * @param state: the alarm system state
184      */
185     public void updateChannelFromAlarmState(String channel, @Nullable PowermaxState state) {
186         if (state == null || !isLinked(channel)) {
187             return;
188         }
189
190         if (getThing().getThingTypeUID().equals(THING_TYPE_ZONE)) {
191             int num = getConfigAs(PowermaxZoneConfiguration.class).zoneNumber;
192
193             for (Value<?> value : state.getZone(num).getValues()) {
194                 String vChannel = value.getChannel();
195
196                 if (channel.equals(vChannel) && (value.getValue() != null)) {
197                     updateState(vChannel, value.getState());
198                 }
199             }
200         } else if (getThing().getThingTypeUID().equals(THING_TYPE_X10)) {
201             int num = getConfigAs(PowermaxX10Configuration.class).deviceNumber;
202             Boolean status = state.getPGMX10DeviceStatus(num);
203             if (channel.equals(X10_STATUS) && (status != null)) {
204                 updateState(X10_STATUS, status ? OnOffType.ON : OnOffType.OFF);
205             }
206         }
207     }
208
209     @Override
210     public void onPanelSettingsUpdated(@Nullable PowermaxPanelSettings settings) {
211         if (getThing().getThingTypeUID().equals(THING_TYPE_ZONE)) {
212             PowermaxZoneConfiguration config = getConfigAs(PowermaxZoneConfiguration.class);
213             onZoneSettingsUpdated(config.zoneNumber, settings);
214         } else if (getThing().getThingTypeUID().equals(THING_TYPE_X10)) {
215             if (isNotReadyForThingStatusUpdate()) {
216                 return;
217             }
218
219             PowermaxX10Configuration config = getConfigAs(PowermaxX10Configuration.class);
220             PowermaxX10Settings deviceSettings = (settings == null) ? null
221                     : settings.getX10Settings(config.deviceNumber);
222             if (settings == null) {
223                 if (getThing().getStatus() != ThingStatus.UNKNOWN) {
224                     updateStatus(ThingStatus.UNKNOWN);
225                     logger.debug("Set handler status to UNKNOWN for thing {}", getThing().getUID());
226                 }
227             } else if (deviceSettings == null || !deviceSettings.isEnabled()) {
228                 if (getThing().getStatus() != ThingStatus.OFFLINE) {
229                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Disabled device");
230                     logger.debug("Set handler status to OFFLINE for thing {} (X10 device {} disabled)",
231                             getThing().getUID(), config.deviceNumber);
232                 }
233             } else if (getThing().getStatus() != ThingStatus.ONLINE) {
234                 updateStatus(ThingStatus.ONLINE);
235                 logger.debug("Set handler status to ONLINE for thing {} (X10 device {} enabled)", getThing().getUID(),
236                         config.deviceNumber);
237             }
238         }
239     }
240
241     @Override
242     public void onZoneSettingsUpdated(int zoneNumber, @Nullable PowermaxPanelSettings settings) {
243         if (getThing().getThingTypeUID().equals(THING_TYPE_ZONE)) {
244             PowermaxZoneConfiguration config = getConfigAs(PowermaxZoneConfiguration.class);
245             if (zoneNumber == config.zoneNumber) {
246                 if (isNotReadyForThingStatusUpdate()) {
247                     return;
248                 }
249
250                 PowermaxZoneSettings zoneSettings = (settings == null) ? null
251                         : settings.getZoneSettings(config.zoneNumber);
252                 if (settings == null) {
253                     if (getThing().getStatus() != ThingStatus.UNKNOWN) {
254                         updateStatus(ThingStatus.UNKNOWN);
255                         logger.debug("Set handler status to UNKNOWN for thing {}", getThing().getUID());
256                     }
257                 } else if (zoneSettings == null) {
258                     if (getThing().getStatus() != ThingStatus.OFFLINE) {
259                         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Zone not paired");
260                         logger.debug("Set handler status to OFFLINE for thing {} (zone number {} not paired)",
261                                 getThing().getUID(), config.zoneNumber);
262                     }
263                 } else if (getThing().getStatus() != ThingStatus.ONLINE) {
264                     updateStatus(ThingStatus.ONLINE);
265                     logger.debug("Set handler status to ONLINE for thing {} (zone number {} paired)",
266                             getThing().getUID(), config.zoneNumber);
267
268                     logger.debug("Using name '{}' for {}", getThing().getLabel(), getThing().getUID());
269                     zoneSettings.setName(getThing().getLabel());
270                 }
271             }
272         }
273     }
274
275     private boolean isNotReadyForThingStatusUpdate() {
276         return (getThing().getStatus() == ThingStatus.OFFLINE)
277                 && ((getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.CONFIGURATION_ERROR)
278                         || (getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.BRIDGE_OFFLINE)
279                         || (getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.BRIDGE_UNINITIALIZED));
280     }
281
282     public PowermaxZoneConfiguration getZoneConfiguration() {
283         return getConfigAs(PowermaxZoneConfiguration.class);
284     }
285
286     public PowermaxX10Configuration getX10Configuration() {
287         return getConfigAs(PowermaxX10Configuration.class);
288     }
289 }