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.zoneminder.internal.handler;
15 import java.io.IOException;
16 import java.math.BigDecimal;
17 import java.security.GeneralSecurityException;
18 import java.util.List;
19 import java.util.concurrent.locks.Lock;
20 import java.util.concurrent.locks.ReentrantLock;
22 import org.openhab.binding.zoneminder.internal.DataRefreshPriorityEnum;
23 import org.openhab.binding.zoneminder.internal.ZoneMinderConstants;
24 import org.openhab.binding.zoneminder.internal.config.ZoneMinderThingConfig;
25 import org.openhab.core.library.types.OnOffType;
26 import org.openhab.core.library.types.StringType;
27 import org.openhab.core.thing.Bridge;
28 import org.openhab.core.thing.Channel;
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.State;
38 import org.openhab.core.types.UnDefType;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 import name.eskildsen.zoneminder.IZoneMinderConnectionInfo;
43 import name.eskildsen.zoneminder.IZoneMinderSession;
44 import name.eskildsen.zoneminder.ZoneMinderFactory;
45 import name.eskildsen.zoneminder.exception.ZoneMinderUrlNotFoundException;
48 * The {@link ZoneMinderBaseThingHandler} is responsible for handling commands, which are
49 * sent to one of the channels.
51 * @author Martin S. Eskildsen - Initial contribution
53 public abstract class ZoneMinderBaseThingHandler extends BaseThingHandler implements ZoneMinderHandler {
55 /** Logger for the Thing. */
56 private final Logger logger = LoggerFactory.getLogger(ZoneMinderBaseThingHandler.class);
58 /** Bridge Handler for the Thing. */
59 public ZoneMinderServerBridgeHandler zoneMinderBridgeHandler;
61 /** This refresh status. */
62 private boolean thingRefreshed;
64 private Lock lockSession = new ReentrantLock();
65 private IZoneMinderSession zoneMinderSession;
67 /** Configuration from openHAB */
68 protected ZoneMinderThingConfig configuration;
70 private DataRefreshPriorityEnum refreshPriority = DataRefreshPriorityEnum.SCHEDULED;
72 protected boolean isOnline() {
73 if (zoneMinderSession == null) {
77 if (!zoneMinderSession.isConnected()) {
84 public DataRefreshPriorityEnum getRefreshPriority() {
85 return refreshPriority;
88 public ZoneMinderBaseThingHandler(Thing thing) {
93 * Initializes the monitor.
95 * @author Martin S. Eskildsen
99 public void initialize() {
100 updateStatus(ThingStatus.ONLINE);
103 protected boolean isConnected() {
104 if (zoneMinderSession == null) {
107 return zoneMinderSession.isConnected();
110 protected IZoneMinderSession aquireSession() {
112 return zoneMinderSession;
115 protected void releaseSession() {
116 lockSession.unlock();
120 * Method to start a priority data refresh task.
123 protected boolean startPriorityRefresh() {
124 logger.info("[MONITOR-{}]: Starting High Priority Refresh", getZoneMinderId());
125 refreshPriority = DataRefreshPriorityEnum.HIGH_PRIORITY;
130 * Method to stop the data Refresh task.
132 protected void stopPriorityRefresh() {
133 logger.info("{}: Stopping Priority Refresh for Monitor", getLogIdentifier());
134 refreshPriority = DataRefreshPriorityEnum.SCHEDULED;
138 public void dispose() {
142 * Helper method for getting ChannelUID from ChannelId.
145 public ChannelUID getChannelUIDFromChannelId(String id) {
146 Channel ch = thing.getChannel(id);
154 protected abstract void onFetchData();
157 * Method to Refresh Thing Handler.
159 public final synchronized void refreshThing(IZoneMinderSession session, DataRefreshPriorityEnum refreshPriority) {
160 if ((refreshPriority != getRefreshPriority()) && (!isConnected())) {
164 if (refreshPriority == DataRefreshPriorityEnum.HIGH_PRIORITY) {
165 logger.debug("{}: Performing HIGH PRIORITY refresh", getLogIdentifier());
167 logger.debug("{}: Performing refresh", getLogIdentifier());
170 if (getZoneMinderBridgeHandler() != null) {
172 logger.debug("{}: refreshThing(): Bridge '{}' Found for Thing '{}'!", getLogIdentifier(),
173 getThing().getUID(), this.getThing().getUID());
179 Thing thing = getThing();
180 List<Channel> channels = thing.getChannels();
181 logger.debug("{}: refreshThing(): Refreshing Thing - {}", getLogIdentifier(), thing.getUID());
183 for (Channel channel : channels) {
184 updateChannel(channel.getUID());
187 this.setThingRefreshed(true);
188 logger.debug("[{}: refreshThing(): Thing Refreshed - {}", getLogIdentifier(), thing.getUID());
192 * Get the Bridge Handler for ZoneMinder.
194 * @return zoneMinderBridgeHandler
196 public synchronized ZoneMinderServerBridgeHandler getZoneMinderBridgeHandler() {
197 if (this.zoneMinderBridgeHandler == null) {
198 Bridge bridge = getBridge();
200 if (bridge == null) {
201 logger.debug("{}: getZoneMinderBridgeHandler(): Unable to get bridge!", getLogIdentifier());
205 logger.debug("{}: getZoneMinderBridgeHandler(): Bridge for '{}' - '{}'", getLogIdentifier(),
206 getThing().getUID(), bridge.getUID());
207 ThingHandler handler = null;
209 handler = bridge.getHandler();
210 } catch (Exception ex) {
211 logger.debug("{}: Exception in 'getZoneMinderBridgeHandler()': {}", getLogIdentifier(),
215 if (handler instanceof ZoneMinderServerBridgeHandler) {
216 this.zoneMinderBridgeHandler = (ZoneMinderServerBridgeHandler) handler;
218 logger.debug("{}: getZoneMinderBridgeHandler(): Unable to get bridge handler!", getLogIdentifier());
222 return this.zoneMinderBridgeHandler;
226 * Method to Update a Channel
231 public void updateChannel(ChannelUID channel) {
232 switch (channel.getId()) {
233 case ZoneMinderConstants.CHANNEL_ONLINE:
234 updateState(channel, getChannelBoolAsOnOffState(isOnline()));
238 "{}: updateChannel() in base class, called for an unknown channel '{}', this channel must be handled in super class.",
239 getLogIdentifier(), channel.getId());
244 public void handleCommand(ChannelUID channelUID, Command command) {
248 public void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionInfo connection)
249 throws IllegalArgumentException, GeneralSecurityException, IOException, ZoneMinderUrlNotFoundException {
252 zoneMinderSession = ZoneMinderFactory.CreateSession(connection);
255 lockSession.unlock();
260 public void onBridgeDisconnected(ZoneMinderServerBridgeHandler bridge) {
261 if (bridge.getThing().getUID().equals(getThing().getBridgeUID())) {
262 this.setThingRefreshed(false);
267 zoneMinderSession = null;
269 lockSession.unlock();
274 * Get Channel by ChannelUID.
276 * @param {ChannelUID} channelUID Identifier of Channel
278 public Channel getChannel(ChannelUID channelUID) {
279 Channel channel = null;
281 List<Channel> channels = getThing().getChannels();
283 for (Channel ch : channels) {
284 if (channelUID == ch.getUID()) {
294 * Get Thing Handler refresh status.
296 * @return thingRefresh
298 public boolean isThingRefreshed() {
299 return thingRefreshed;
303 * Set Thing Handler refresh status.
305 * @param {boolean} refreshed Sets status refreshed of thing
307 public void setThingRefreshed(boolean refreshed) {
308 this.thingRefreshed = refreshed;
311 protected abstract String getZoneMinderThingType();
313 private Object getConfigValue(String configKey) {
314 return getThing().getConfiguration().getProperties().get(configKey);
318 * Helper to get a value from configuration as a String
320 * @author Martin S. Eskildsen
323 protected String getConfigValueAsString(String configKey) {
324 return (String) getConfigValue(configKey);
328 * Helper to get a value from configuration as a Integer
330 * @author Martin S. Eskildsen
333 protected Integer getConfigValueAsInteger(String configKey) {
334 return (Integer) getConfigValue(configKey);
337 protected BigDecimal getConfigValueAsBigDecimal(String configKey) {
338 return (BigDecimal) getConfigValue(configKey);
341 protected State getChannelStringAsStringState(String channelValue) {
342 State state = UnDefType.UNDEF;
346 state = new StringType(channelValue);
349 } catch (Exception ex) {
350 logger.error("{}", ex.getMessage());
356 protected State getChannelBoolAsOnOffState(boolean value) {
357 State state = UnDefType.UNDEF;
361 state = value ? OnOffType.ON : OnOffType.OFF;
364 } catch (Exception ex) {
365 logger.error("{}: Exception occurred in 'getChannelBoolAsOnOffState()' (Exception='{}')",
366 getLogIdentifier(), ex.getMessage());
373 public abstract String getLogIdentifier();
375 protected void updateThingStatus(ThingStatus thingStatus, ThingStatusDetail statusDetail,
376 String statusDescription) {
377 ThingStatusInfo curStatusInfo = thing.getStatusInfo();
378 String curDescription = ((curStatusInfo.getDescription() == null) ? "" : curStatusInfo.getDescription());
380 if ((curStatusInfo.getStatus() != thingStatus) || (curStatusInfo.getStatusDetail() != statusDetail)
381 || (curDescription != statusDescription)) {
382 // Update Status correspondingly
383 if ((thingStatus == ThingStatus.OFFLINE) && (statusDetail != ThingStatusDetail.NONE)) {
384 logger.info("{}: Thing status changed from '{}' to '{}' (DetailedStatus='{}', Description='{}')",
385 getLogIdentifier(), thing.getStatus(), thingStatus, statusDetail, statusDescription);
386 updateStatus(thingStatus, statusDetail, statusDescription);
388 logger.info("{}: Thing status changed from '{}' to '{}'", getLogIdentifier(), thing.getStatus(),
390 updateStatus(thingStatus);