added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.zoneminder-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-zoneminder" description="ZoneMinder Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.zoneminder/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public enum DataRefreshPriorityEnum {
|
||||
SCHEDULED,
|
||||
HIGH_PRIORITY
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link ZoneMinderConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ZoneMinderConstants {
|
||||
|
||||
public static final String BINDING_ID = "zoneminder";
|
||||
|
||||
// ZoneMinder Server Bridge
|
||||
public static final String BRIDGE_ZONEMINDER_SERVER = "server";
|
||||
|
||||
// ZoneMinder Monitor thing
|
||||
public static final String THING_ZONEMINDER_MONITOR = "monitor";
|
||||
|
||||
// ZoneMinder Server displayable name
|
||||
public static final String ZONEMINDER_SERVER_NAME = "ZoneMinder Server";
|
||||
|
||||
// ZoneMinder Monitor displayable name
|
||||
public static final String ZONEMINDER_MONITOR_NAME = "ZoneMinder Monitor";
|
||||
|
||||
/*
|
||||
* ZoneMinder Server Constants
|
||||
*/
|
||||
|
||||
// Thing Type UID for Server
|
||||
public static final ThingTypeUID THING_TYPE_BRIDGE_ZONEMINDER_SERVER = new ThingTypeUID(BINDING_ID,
|
||||
BRIDGE_ZONEMINDER_SERVER);
|
||||
|
||||
// Shared channel for all bridges / things
|
||||
public static final String CHANNEL_ONLINE = "online";
|
||||
|
||||
// Channel Id's for the ZoneMinder Server
|
||||
public static final String CHANNEL_SERVER_DISKUSAGE = "disk-usage";
|
||||
public static final String CHANNEL_SERVER_CPULOAD = "cpu-load";
|
||||
|
||||
// Parameters for the ZoneMinder Server
|
||||
public static final String PARAM_HOSTNAME = "hostname";
|
||||
public static final String PARAM_PORT = "port";
|
||||
public static final String PARAM_REFRESH_INTERVAL = "refresh_interval";
|
||||
public static final String PARAM_REFRESH_INTERVAL_DISKUSAGE = "refresh_interval_disk_usage";
|
||||
|
||||
// Default values for Monitor parameters
|
||||
public static final Integer DEFAULT_HTTP_PORT = 80;
|
||||
public static final Integer DEFAULT_TELNET_PORT = 6802;
|
||||
|
||||
/*
|
||||
* ZoneMinder Monitor Constants
|
||||
*/
|
||||
|
||||
// Thing Type UID for Monitor
|
||||
public static final ThingTypeUID THING_TYPE_THING_ZONEMINDER_MONITOR = new ThingTypeUID(BINDING_ID,
|
||||
THING_ZONEMINDER_MONITOR);
|
||||
/*
|
||||
* Channel Id's for the ZoneMinder Monitor
|
||||
*/
|
||||
public static final String CHANNEL_MONITOR_ENABLED = "enabled";
|
||||
public static final String CHANNEL_MONITOR_FORCE_ALARM = "force-alarm";
|
||||
public static final String CHANNEL_MONITOR_EVENT_STATE = "alarm";
|
||||
public static final String CHANNEL_MONITOR_EVENT_CAUSE = "event-cause";
|
||||
public static final String CHANNEL_MONITOR_RECORD_STATE = "recording";
|
||||
public static final String CHANNEL_MONITOR_DETAILED_STATUS = "detailed-status";
|
||||
public static final String CHANNEL_MONITOR_FUNCTION = "function";
|
||||
|
||||
public static final String CHANNEL_MONITOR_CAPTURE_DAEMON_STATE = "capture-daemon";
|
||||
public static final String CHANNEL_MONITOR_ANALYSIS_DAEMON_STATE = "analysis-daemon";
|
||||
public static final String CHANNEL_MONITOR_FRAME_DAEMON_STATE = "frame-daemon";
|
||||
|
||||
// Parameters for the ZoneMinder Monitor
|
||||
public static final String PARAMETER_MONITOR_ID = "monitorId";
|
||||
public static final String PARAMETER_MONITOR_TRIGGER_TIMEOUT = "monitorTriggerTimeout";
|
||||
public static final String PARAMETER_MONITOR_EVENTTEXT = "monitorEventText";
|
||||
|
||||
// Default values for Monitor parameters
|
||||
public static final Integer PARAMETER_MONITOR_TRIGGER_TIMEOUT_DEFAULTVALUE = 60;
|
||||
|
||||
public static final String PARAMETER_MONITOR_EVENTNOTE_DEFAULTVALUE = "openHAB triggered event";
|
||||
|
||||
// ZoneMinder Event types
|
||||
public static final String MONITOR_EVENT_NONE = "";
|
||||
public static final String MONITOR_EVENT_SIGNAL = "Signal";
|
||||
public static final String MONITOR_EVENT_MOTION = "Motion";
|
||||
public static final String MONITOR_EVENT_FORCED_WEB = "Forced Web";
|
||||
public static final String MONITOR_EVENT_OPENHAB = "openHAB";
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.openhab.binding.zoneminder.internal.handler.ZoneMinderServerBridgeHandler;
|
||||
import org.openhab.binding.zoneminder.internal.handler.ZoneMinderThingMonitorHandler;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link ZoneMinderHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.zoneminder")
|
||||
public class ZoneMinderHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ZoneMinderHandlerFactory.class);
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections
|
||||
.unmodifiableSet(Stream.concat(ZoneMinderServerBridgeHandler.SUPPORTED_THING_TYPES.stream(),
|
||||
ZoneMinderThingMonitorHandler.SUPPORTED_THING_TYPES.stream()).collect(Collectors.toSet()));
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (thingTypeUID.equals(ZoneMinderConstants.THING_TYPE_BRIDGE_ZONEMINDER_SERVER)) {
|
||||
logger.debug("[FACTORY]: creating handler for bridge thing '{}'", thing);
|
||||
return new ZoneMinderServerBridgeHandler((Bridge) thing);
|
||||
} else if (thingTypeUID.equals(ZoneMinderConstants.THING_TYPE_THING_ZONEMINDER_MONITOR)) {
|
||||
return new ZoneMinderThingMonitorHandler(thing);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public class ZoneMinderProperties {
|
||||
public static final String PROPERTY_ID = "Id";
|
||||
|
||||
public static final String PROPERTY_SERVER_VERSION = "Version";
|
||||
public static final String PROPERTY_SERVER_API_VERSION = "API Version";
|
||||
public static final String PROPERTY_SERVER_USE_API = "API Enabled";
|
||||
public static final String PROPERTY_SERVER_USE_AUTHENTIFICATION = "Use Authentification";
|
||||
public static final String PROPERTY_SERVER_TRIGGERS_ENABLED = "Triggers enabled";
|
||||
|
||||
public static final String PROPERTY_MONITOR_NAME = "Name";
|
||||
public static final String PROPERTY_MONITOR_SOURCETYPE = "Sourcetype";
|
||||
|
||||
public static final String PROPERTY_MONITOR_ANALYSIS_FPS = "Analysis FPS";
|
||||
public static final String PROPERTY_MONITOR_MAXIMUM_FPS = "Maximum FPS";
|
||||
public static final String PROPERTY_MONITOR_ALARM_MAXIMUM = "Alarm Maximum FPS";
|
||||
|
||||
public static final String PROPERTY_MONITOR_IMAGE_WIDTH = "Width";
|
||||
public static final String PROPERTY_MONITOR_IMAGE_HEIGHT = "Height";
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal.config;
|
||||
|
||||
import org.openhab.binding.zoneminder.internal.ZoneMinderConstants;
|
||||
|
||||
/**
|
||||
* Configuration data according to zoneminderserver.xml
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public class ZoneMinderBridgeServerConfig extends ZoneMinderConfig {
|
||||
|
||||
private String hostname;
|
||||
private Integer http_port;
|
||||
private Integer telnet_port;
|
||||
|
||||
private String protocol;
|
||||
|
||||
private String urlpath;
|
||||
|
||||
private String user;
|
||||
private String password;
|
||||
private Integer refresh_interval;
|
||||
private Integer refresh_interval_disk_usage;
|
||||
private Boolean autodiscover_things;
|
||||
|
||||
@Override
|
||||
public String getConfigId() {
|
||||
return ZoneMinderConstants.BRIDGE_ZONEMINDER_SERVER;
|
||||
}
|
||||
|
||||
public String getHostName() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public void setHostName(String hostName) {
|
||||
this.hostname = hostName;
|
||||
}
|
||||
|
||||
public Integer getHttpPort() {
|
||||
if ((http_port == null) || (http_port == 0)) {
|
||||
if (getProtocol().equalsIgnoreCase("http")) {
|
||||
http_port = 80;
|
||||
} else {
|
||||
http_port = 443;
|
||||
}
|
||||
}
|
||||
return http_port;
|
||||
}
|
||||
|
||||
public void setHttpPort(Integer port) {
|
||||
this.http_port = port;
|
||||
}
|
||||
|
||||
public Integer getTelnetPort() {
|
||||
return telnet_port;
|
||||
}
|
||||
|
||||
public void setTelnetPort(Integer telnetPort) {
|
||||
this.telnet_port = telnetPort;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public String getServerBasePath() {
|
||||
return urlpath;
|
||||
}
|
||||
|
||||
public void setServerBasePath(String urlpath) {
|
||||
this.urlpath = urlpath;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.user = userName;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Integer getRefreshInterval() {
|
||||
return refresh_interval;
|
||||
}
|
||||
|
||||
public void setRefreshInterval(Integer refreshInterval) {
|
||||
this.refresh_interval = refreshInterval;
|
||||
}
|
||||
|
||||
public Integer getRefreshIntervalLowPriorityTask() {
|
||||
return refresh_interval_disk_usage;
|
||||
}
|
||||
|
||||
public void setRefreshIntervalDiskUsage(Integer refreshIntervalDiskUsage) {
|
||||
this.refresh_interval_disk_usage = refreshIntervalDiskUsage;
|
||||
}
|
||||
|
||||
public Boolean getAutodiscoverThings() {
|
||||
return autodiscover_things;
|
||||
}
|
||||
|
||||
public void setAutodiscoverThings(Boolean autodiscoverThings) {
|
||||
this.autodiscover_things = autodiscoverThings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal.config;
|
||||
|
||||
/**
|
||||
* base class containing Configuration in openHAB
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public abstract class ZoneMinderConfig {
|
||||
public abstract String getConfigId();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal.config;
|
||||
|
||||
import org.openhab.binding.zoneminder.internal.ZoneMinderConstants;
|
||||
|
||||
/**
|
||||
* Monitor configuration from openHAB.
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public abstract class ZoneMinderThingConfig extends ZoneMinderConfig {
|
||||
|
||||
public abstract String getZoneMinderId();
|
||||
|
||||
@Override
|
||||
public String getConfigId() {
|
||||
return ZoneMinderConstants.THING_ZONEMINDER_MONITOR;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal.config;
|
||||
|
||||
import org.openhab.binding.zoneminder.internal.ZoneMinderConstants;
|
||||
|
||||
/**
|
||||
* Specific configuration class for Monitor COnfig.
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public class ZoneMinderThingMonitorConfig extends ZoneMinderThingConfig {
|
||||
|
||||
// Parameters
|
||||
private Integer monitorId;
|
||||
|
||||
@Override
|
||||
public String getConfigId() {
|
||||
return ZoneMinderConstants.THING_ZONEMINDER_MONITOR;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return monitorId.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getZoneMinderId() {
|
||||
return monitorId.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal.discovery;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.zoneminder.internal.ZoneMinderConstants;
|
||||
import org.openhab.binding.zoneminder.internal.handler.ZoneMinderServerBridgeHandler;
|
||||
import org.openhab.binding.zoneminder.internal.handler.ZoneMinderThingMonitorHandler;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import name.eskildsen.zoneminder.IZoneMinderMonitorData;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public class ZoneMinderDiscoveryService extends AbstractDiscoveryService
|
||||
implements DiscoveryService, ThingHandlerService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ZoneMinderDiscoveryService.class);
|
||||
|
||||
private @NonNullByDefault({}) ZoneMinderServerBridgeHandler serverHandler;
|
||||
|
||||
public ZoneMinderDiscoveryService() {
|
||||
super(30);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
if (handler instanceof ZoneMinderServerBridgeHandler) {
|
||||
this.serverHandler = (ZoneMinderServerBridgeHandler) handler;
|
||||
this.serverHandler.setDiscoveryService(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return serverHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
logger.debug("[DISCOVERY]: Activating ZoneMinder discovery service for {}", serverHandler.getThing().getUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
logger.debug("[DISCOVERY]: Deactivating ZoneMinder discovery service for {}",
|
||||
serverHandler.getThing().getUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypes() {
|
||||
return ZoneMinderThingMonitorHandler.SUPPORTED_THING_TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startBackgroundDiscovery() {
|
||||
logger.debug("[DISCOVERY]: Performing background discovery scan for {}", serverHandler.getThing().getUID());
|
||||
discoverMonitors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startScan() {
|
||||
logger.debug("[DISCOVERY]: Starting discovery scan for {}", serverHandler.getThing().getUID());
|
||||
discoverMonitors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void abortScan() {
|
||||
super.abortScan();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stopScan() {
|
||||
super.stopScan();
|
||||
}
|
||||
|
||||
protected String buildMonitorLabel(String id, String name) {
|
||||
return String.format("%s [%s]", ZoneMinderConstants.ZONEMINDER_MONITOR_NAME, name);
|
||||
}
|
||||
|
||||
protected synchronized void discoverMonitors() {
|
||||
// Add all existing devices
|
||||
for (IZoneMinderMonitorData monitor : serverHandler.getMonitors()) {
|
||||
deviceAdded(monitor);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean monitorThingExists(ThingUID newThingUID) {
|
||||
return serverHandler.getThing().getThing(newThingUID) != null ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called once the node is fully discovered. At this point we know most of the information about
|
||||
* the device including manufacturer information.
|
||||
*
|
||||
* @param node the node to be added
|
||||
*/
|
||||
public void deviceAdded(IZoneMinderMonitorData monitor) {
|
||||
try {
|
||||
ThingUID bridgeUID = serverHandler.getThing().getUID();
|
||||
String monitorUID = String.format("%s-%s", ZoneMinderConstants.THING_ZONEMINDER_MONITOR, monitor.getId());
|
||||
ThingUID thingUID = new ThingUID(ZoneMinderConstants.THING_TYPE_THING_ZONEMINDER_MONITOR, bridgeUID,
|
||||
monitorUID);
|
||||
|
||||
// Does Monitor exist?
|
||||
if (!monitorThingExists(thingUID)) {
|
||||
logger.info("[DISCOVERY]: Monitor with Id='{}' and Name='{}' added", monitor.getId(),
|
||||
monitor.getName());
|
||||
Map<String, Object> properties = new HashMap<>(0);
|
||||
properties.put(ZoneMinderConstants.PARAMETER_MONITOR_ID, Integer.valueOf(monitor.getId()));
|
||||
properties.put(ZoneMinderConstants.PARAMETER_MONITOR_TRIGGER_TIMEOUT,
|
||||
ZoneMinderConstants.PARAMETER_MONITOR_TRIGGER_TIMEOUT_DEFAULTVALUE);
|
||||
properties.put(ZoneMinderConstants.PARAMETER_MONITOR_EVENTTEXT,
|
||||
ZoneMinderConstants.MONITOR_EVENT_OPENHAB);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
|
||||
.withBridge(bridgeUID).withLabel(buildMonitorLabel(monitor.getId(), monitor.getName())).build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("[DISCOVERY]: Error occurred when calling 'monitorAdded' from Discovery. Exception={}",
|
||||
ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.openhab.binding.zoneminder.internal.DataRefreshPriorityEnum;
|
||||
import org.openhab.binding.zoneminder.internal.ZoneMinderConstants;
|
||||
import org.openhab.binding.zoneminder.internal.config.ZoneMinderThingConfig;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import name.eskildsen.zoneminder.IZoneMinderConnectionInfo;
|
||||
import name.eskildsen.zoneminder.IZoneMinderSession;
|
||||
import name.eskildsen.zoneminder.ZoneMinderFactory;
|
||||
import name.eskildsen.zoneminder.exception.ZoneMinderUrlNotFoundException;
|
||||
|
||||
/**
|
||||
* The {@link ZoneMinderBaseThingHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public abstract class ZoneMinderBaseThingHandler extends BaseThingHandler implements ZoneMinderHandler {
|
||||
|
||||
/** Logger for the Thing. */
|
||||
private final Logger logger = LoggerFactory.getLogger(ZoneMinderBaseThingHandler.class);
|
||||
|
||||
/** Bridge Handler for the Thing. */
|
||||
public ZoneMinderServerBridgeHandler zoneMinderBridgeHandler;
|
||||
|
||||
/** This refresh status. */
|
||||
private boolean thingRefreshed;
|
||||
|
||||
private Lock lockSession = new ReentrantLock();
|
||||
private IZoneMinderSession zoneMinderSession;
|
||||
|
||||
/** Configuration from openHAB */
|
||||
protected ZoneMinderThingConfig configuration;
|
||||
|
||||
private DataRefreshPriorityEnum refreshPriority = DataRefreshPriorityEnum.SCHEDULED;
|
||||
|
||||
protected boolean isOnline() {
|
||||
if (zoneMinderSession == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!zoneMinderSession.isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public DataRefreshPriorityEnum getRefreshPriority() {
|
||||
return refreshPriority;
|
||||
}
|
||||
|
||||
public ZoneMinderBaseThingHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the monitor.
|
||||
*
|
||||
* @author Martin S. Eskildsen
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
protected boolean isConnected() {
|
||||
if (zoneMinderSession == null) {
|
||||
return false;
|
||||
}
|
||||
return zoneMinderSession.isConnected();
|
||||
}
|
||||
|
||||
protected IZoneMinderSession aquireSession() {
|
||||
lockSession.lock();
|
||||
return zoneMinderSession;
|
||||
}
|
||||
|
||||
protected void releaseSession() {
|
||||
lockSession.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to start a priority data refresh task.
|
||||
*/
|
||||
|
||||
protected boolean startPriorityRefresh() {
|
||||
logger.info("[MONITOR-{}]: Starting High Priority Refresh", getZoneMinderId());
|
||||
refreshPriority = DataRefreshPriorityEnum.HIGH_PRIORITY;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to stop the data Refresh task.
|
||||
*/
|
||||
protected void stopPriorityRefresh() {
|
||||
logger.info("{}: Stopping Priority Refresh for Monitor", getLogIdentifier());
|
||||
refreshPriority = DataRefreshPriorityEnum.SCHEDULED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for getting ChannelUID from ChannelId.
|
||||
*
|
||||
*/
|
||||
public ChannelUID getChannelUIDFromChannelId(String id) {
|
||||
Channel ch = thing.getChannel(id);
|
||||
if (ch == null) {
|
||||
return null;
|
||||
} else {
|
||||
return ch.getUID();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void onFetchData();
|
||||
|
||||
/**
|
||||
* Method to Refresh Thing Handler.
|
||||
*/
|
||||
public final synchronized void refreshThing(IZoneMinderSession session, DataRefreshPriorityEnum refreshPriority) {
|
||||
if ((refreshPriority != getRefreshPriority()) && (!isConnected())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (refreshPriority == DataRefreshPriorityEnum.HIGH_PRIORITY) {
|
||||
logger.debug("{}: Performing HIGH PRIORITY refresh", getLogIdentifier());
|
||||
} else {
|
||||
logger.debug("{}: Performing refresh", getLogIdentifier());
|
||||
}
|
||||
|
||||
if (getZoneMinderBridgeHandler() != null) {
|
||||
if (isConnected()) {
|
||||
logger.debug("{}: refreshThing(): Bridge '{}' Found for Thing '{}'!", getLogIdentifier(),
|
||||
getThing().getUID(), this.getThing().getUID());
|
||||
|
||||
onFetchData();
|
||||
}
|
||||
}
|
||||
|
||||
Thing thing = getThing();
|
||||
List<Channel> channels = thing.getChannels();
|
||||
logger.debug("{}: refreshThing(): Refreshing Thing - {}", getLogIdentifier(), thing.getUID());
|
||||
|
||||
for (Channel channel : channels) {
|
||||
updateChannel(channel.getUID());
|
||||
}
|
||||
|
||||
this.setThingRefreshed(true);
|
||||
logger.debug("[{}: refreshThing(): Thing Refreshed - {}", getLogIdentifier(), thing.getUID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Bridge Handler for ZoneMinder.
|
||||
*
|
||||
* @return zoneMinderBridgeHandler
|
||||
*/
|
||||
public synchronized ZoneMinderServerBridgeHandler getZoneMinderBridgeHandler() {
|
||||
if (this.zoneMinderBridgeHandler == null) {
|
||||
Bridge bridge = getBridge();
|
||||
|
||||
if (bridge == null) {
|
||||
logger.debug("{}: getZoneMinderBridgeHandler(): Unable to get bridge!", getLogIdentifier());
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.debug("{}: getZoneMinderBridgeHandler(): Bridge for '{}' - '{}'", getLogIdentifier(),
|
||||
getThing().getUID(), bridge.getUID());
|
||||
ThingHandler handler = null;
|
||||
try {
|
||||
handler = bridge.getHandler();
|
||||
} catch (Exception ex) {
|
||||
logger.debug("{}: Exception in 'getZoneMinderBridgeHandler()': {}", getLogIdentifier(),
|
||||
ex.getMessage());
|
||||
}
|
||||
|
||||
if (handler instanceof ZoneMinderServerBridgeHandler) {
|
||||
this.zoneMinderBridgeHandler = (ZoneMinderServerBridgeHandler) handler;
|
||||
} else {
|
||||
logger.debug("{}: getZoneMinderBridgeHandler(): Unable to get bridge handler!", getLogIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
return this.zoneMinderBridgeHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to Update a Channel
|
||||
*
|
||||
* @param channel
|
||||
*/
|
||||
@Override
|
||||
public void updateChannel(ChannelUID channel) {
|
||||
switch (channel.getId()) {
|
||||
case ZoneMinderConstants.CHANNEL_ONLINE:
|
||||
updateState(channel, getChannelBoolAsOnOffState(isOnline()));
|
||||
break;
|
||||
default:
|
||||
logger.error(
|
||||
"{}: updateChannel() in base class, called for an unknown channel '{}', this channel must be handled in super class.",
|
||||
getLogIdentifier(), channel.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionInfo connection)
|
||||
throws IllegalArgumentException, GeneralSecurityException, IOException, ZoneMinderUrlNotFoundException {
|
||||
lockSession.lock();
|
||||
try {
|
||||
zoneMinderSession = ZoneMinderFactory.CreateSession(connection);
|
||||
|
||||
} finally {
|
||||
lockSession.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBridgeDisconnected(ZoneMinderServerBridgeHandler bridge) {
|
||||
if (bridge.getThing().getUID().equals(getThing().getBridgeUID())) {
|
||||
this.setThingRefreshed(false);
|
||||
}
|
||||
|
||||
lockSession.lock();
|
||||
try {
|
||||
zoneMinderSession = null;
|
||||
} finally {
|
||||
lockSession.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Channel by ChannelUID.
|
||||
*
|
||||
* @param {ChannelUID} channelUID Identifier of Channel
|
||||
*/
|
||||
public Channel getChannel(ChannelUID channelUID) {
|
||||
Channel channel = null;
|
||||
|
||||
List<Channel> channels = getThing().getChannels();
|
||||
|
||||
for (Channel ch : channels) {
|
||||
if (channelUID == ch.getUID()) {
|
||||
channel = ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Thing Handler refresh status.
|
||||
*
|
||||
* @return thingRefresh
|
||||
*/
|
||||
public boolean isThingRefreshed() {
|
||||
return thingRefreshed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Thing Handler refresh status.
|
||||
*
|
||||
* @param {boolean} refreshed Sets status refreshed of thing
|
||||
*/
|
||||
public void setThingRefreshed(boolean refreshed) {
|
||||
this.thingRefreshed = refreshed;
|
||||
}
|
||||
|
||||
protected abstract String getZoneMinderThingType();
|
||||
|
||||
private Object getConfigValue(String configKey) {
|
||||
return getThing().getConfiguration().getProperties().get(configKey);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper to get a value from configuration as a String
|
||||
*
|
||||
* @author Martin S. Eskildsen
|
||||
*
|
||||
*/
|
||||
protected String getConfigValueAsString(String configKey) {
|
||||
return (String) getConfigValue(configKey);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper to get a value from configuration as a Integer
|
||||
*
|
||||
* @author Martin S. Eskildsen
|
||||
*
|
||||
*/
|
||||
protected Integer getConfigValueAsInteger(String configKey) {
|
||||
return (Integer) getConfigValue(configKey);
|
||||
}
|
||||
|
||||
protected BigDecimal getConfigValueAsBigDecimal(String configKey) {
|
||||
return (BigDecimal) getConfigValue(configKey);
|
||||
}
|
||||
|
||||
protected State getChannelStringAsStringState(String channelValue) {
|
||||
State state = UnDefType.UNDEF;
|
||||
|
||||
try {
|
||||
if (isConnected()) {
|
||||
state = new StringType(channelValue);
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
logger.error("{}", ex.getMessage());
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
protected State getChannelBoolAsOnOffState(boolean value) {
|
||||
State state = UnDefType.UNDEF;
|
||||
|
||||
try {
|
||||
if (isConnected()) {
|
||||
state = value ? OnOffType.ON : OnOffType.OFF;
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
logger.error("{}: Exception occurred in 'getChannelBoolAsOnOffState()' (Exception='{}')",
|
||||
getLogIdentifier(), ex.getMessage());
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract String getLogIdentifier();
|
||||
|
||||
protected void updateThingStatus(ThingStatus thingStatus, ThingStatusDetail statusDetail,
|
||||
String statusDescription) {
|
||||
ThingStatusInfo curStatusInfo = thing.getStatusInfo();
|
||||
String curDescription = ((curStatusInfo.getDescription() == null) ? "" : curStatusInfo.getDescription());
|
||||
// Status changed
|
||||
if ((curStatusInfo.getStatus() != thingStatus) || (curStatusInfo.getStatusDetail() != statusDetail)
|
||||
|| (curDescription != statusDescription)) {
|
||||
// Update Status correspondingly
|
||||
if ((thingStatus == ThingStatus.OFFLINE) && (statusDetail != ThingStatusDetail.NONE)) {
|
||||
logger.info("{}: Thing status changed from '{}' to '{}' (DetailedStatus='{}', Description='{}')",
|
||||
getLogIdentifier(), thing.getStatus(), thingStatus, statusDetail, statusDescription);
|
||||
updateStatus(thingStatus, statusDetail, statusDescription);
|
||||
} else {
|
||||
logger.info("{}: Thing status changed from '{}' to '{}'", getLogIdentifier(), thing.getStatus(),
|
||||
thingStatus);
|
||||
updateStatus(thingStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
|
||||
import name.eskildsen.zoneminder.IZoneMinderConnectionInfo;
|
||||
import name.eskildsen.zoneminder.exception.ZoneMinderUrlNotFoundException;
|
||||
|
||||
/**
|
||||
* Interface for ZoneMinder handlers.
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public interface ZoneMinderHandler {
|
||||
|
||||
String getZoneMinderId();
|
||||
|
||||
/**
|
||||
* Method used to relate a log entry to a thing
|
||||
*/
|
||||
String getLogIdentifier();
|
||||
|
||||
void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection);
|
||||
|
||||
void updateChannel(ChannelUID channel);
|
||||
|
||||
void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionInfo connection)
|
||||
throws IllegalArgumentException, GeneralSecurityException, IOException, ZoneMinderUrlNotFoundException;
|
||||
|
||||
void onBridgeDisconnected(ZoneMinderServerBridgeHandler bridge);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,836 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.security.auth.login.FailedLoginException;
|
||||
|
||||
import org.openhab.binding.zoneminder.internal.DataRefreshPriorityEnum;
|
||||
import org.openhab.binding.zoneminder.internal.ZoneMinderConstants;
|
||||
import org.openhab.binding.zoneminder.internal.ZoneMinderProperties;
|
||||
import org.openhab.binding.zoneminder.internal.config.ZoneMinderThingMonitorConfig;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import name.eskildsen.zoneminder.IZoneMinderConnectionInfo;
|
||||
import name.eskildsen.zoneminder.IZoneMinderDaemonStatus;
|
||||
import name.eskildsen.zoneminder.IZoneMinderEventData;
|
||||
import name.eskildsen.zoneminder.IZoneMinderEventSubscriber;
|
||||
import name.eskildsen.zoneminder.IZoneMinderMonitor;
|
||||
import name.eskildsen.zoneminder.IZoneMinderMonitorData;
|
||||
import name.eskildsen.zoneminder.IZoneMinderSession;
|
||||
import name.eskildsen.zoneminder.ZoneMinderFactory;
|
||||
import name.eskildsen.zoneminder.api.event.ZoneMinderEvent;
|
||||
import name.eskildsen.zoneminder.api.telnet.ZoneMinderTriggerEvent;
|
||||
import name.eskildsen.zoneminder.common.ZoneMinderMonitorFunctionEnum;
|
||||
import name.eskildsen.zoneminder.common.ZoneMinderMonitorStatusEnum;
|
||||
import name.eskildsen.zoneminder.exception.ZoneMinderUrlNotFoundException;
|
||||
|
||||
/**
|
||||
* The {@link ZoneMinderThingMonitorHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public class ZoneMinderThingMonitorHandler extends ZoneMinderBaseThingHandler implements IZoneMinderEventSubscriber {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections
|
||||
.singleton(ZoneMinderConstants.THING_TYPE_THING_ZONEMINDER_MONITOR);
|
||||
|
||||
/** Make sure we can log errors, warnings or what ever somewhere */
|
||||
private final Logger logger = LoggerFactory.getLogger(ZoneMinderThingMonitorHandler.class);
|
||||
|
||||
private ZoneMinderThingMonitorConfig config;
|
||||
|
||||
private ZoneMinderEvent curEvent;
|
||||
|
||||
/**
|
||||
* Channels
|
||||
*/
|
||||
private ZoneMinderMonitorFunctionEnum channelFunction = ZoneMinderMonitorFunctionEnum.NONE;
|
||||
private Boolean channelEnabled = false;
|
||||
private boolean channelRecordingState;
|
||||
private boolean channelAlarmedState;
|
||||
private String channelEventCause = "";
|
||||
private ZoneMinderMonitorStatusEnum channelMonitorStatus = ZoneMinderMonitorStatusEnum.UNKNOWN;
|
||||
private boolean channelDaemonCapture;
|
||||
private boolean channelDaemonAnalysis;
|
||||
private boolean channelDaemonFrame;
|
||||
private boolean channelForceAlarm;
|
||||
|
||||
private int forceAlarmManualState = -1;
|
||||
|
||||
public ZoneMinderThingMonitorHandler(Thing thing) {
|
||||
super(thing);
|
||||
|
||||
logger.info("{}: Starting ZoneMinder Server Thing Handler (Thing='{}')", getLogIdentifier(), thing.getUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getZoneMinderId() {
|
||||
if (config == null) {
|
||||
logger.error("{}: Configuration for Thing '{}' is not loaded correctly.", getLogIdentifier(),
|
||||
getThing().getUID());
|
||||
return "";
|
||||
}
|
||||
return config.getZoneMinderId().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionInfo connection)
|
||||
throws IllegalArgumentException, GeneralSecurityException, IOException, ZoneMinderUrlNotFoundException {
|
||||
try {
|
||||
logger.info("{}: Bridge '{}' connected", getLogIdentifier(), bridge.getThing().getUID().getAsString());
|
||||
super.onBridgeConnected(bridge, connection);
|
||||
|
||||
ZoneMinderFactory.SubscribeMonitorEvents(connection, config.getZoneMinderId(), this);
|
||||
IZoneMinderSession session = aquireSession();
|
||||
IZoneMinderMonitor monitor = ZoneMinderFactory.getMonitorProxy(session, config.getZoneMinderId());
|
||||
IZoneMinderMonitorData monitorData = monitor.getMonitorData();
|
||||
|
||||
logger.debug("{}: SourceType: {}", getLogIdentifier(), monitorData.getSourceType().name());
|
||||
logger.debug("{}: Format: {}", getLogIdentifier(), monitorData.getFormat());
|
||||
logger.debug("{}: AlarmFrameCount: {}", getLogIdentifier(), monitorData.getAlarmFrameCount());
|
||||
logger.debug("{}: AlarmMaxFPS: {}", getLogIdentifier(), monitorData.getAlarmMaxFPS());
|
||||
logger.debug("{}: AnalysisFPS: {}", getLogIdentifier(), monitorData.getAnalysisFPS());
|
||||
logger.debug("{}: Height x Width: {} x {}", getLogIdentifier(), monitorData.getHeight(),
|
||||
monitorData.getWidth());
|
||||
|
||||
updateMonitorProperties(session);
|
||||
} catch (Exception ex) {
|
||||
logger.error("{}: Exception occurred when calling 'onBridgeConencted()'. Exception='{}'",
|
||||
getLogIdentifier(), ex.getMessage());
|
||||
} finally {
|
||||
releaseSession();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBridgeDisconnected(ZoneMinderServerBridgeHandler bridge) {
|
||||
try {
|
||||
logger.info("{}: Bridge '{}' disconnected", getLogIdentifier(), bridge.getThing().getUID().getAsString());
|
||||
|
||||
logger.info("{}: Unsubscribing from Monitor Events: {}", getLogIdentifier(),
|
||||
bridge.getThing().getUID().getAsString());
|
||||
ZoneMinderFactory.UnsubscribeMonitorEvents(config.getZoneMinderId(), this);
|
||||
|
||||
logger.debug("{}: Calling parent onBridgeConnected()", getLogIdentifier());
|
||||
super.onBridgeDisconnected(bridge);
|
||||
} catch (Exception ex) {
|
||||
logger.error("{}: Exception occurred when calling 'onBridgeDisonencted()'. Exception='{}'",
|
||||
getLogIdentifier(), ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
try {
|
||||
logger.debug("{}: Channel '{}' in monitor '{}' received command='{}'", getLogIdentifier(), channelUID,
|
||||
getZoneMinderId(), command);
|
||||
|
||||
// Allow refresh of channels
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateChannel(channelUID);
|
||||
return;
|
||||
}
|
||||
|
||||
// Communication TO Monitor
|
||||
switch (channelUID.getId()) {
|
||||
// Done via Telnet connection
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_FORCE_ALARM:
|
||||
logger.debug(
|
||||
"{}: 'handleCommand' => CHANNEL_MONITOR_FORCE_ALARM: Command '{}' received for monitor '{}'",
|
||||
getLogIdentifier(), command, channelUID.getId());
|
||||
|
||||
if ((command == OnOffType.OFF) || (command == OnOffType.ON)) {
|
||||
String eventText = getConfigValueAsString(ZoneMinderConstants.PARAMETER_MONITOR_EVENTTEXT);
|
||||
|
||||
BigDecimal eventTimeout = getConfigValueAsBigDecimal(
|
||||
ZoneMinderConstants.PARAMETER_MONITOR_TRIGGER_TIMEOUT);
|
||||
|
||||
ZoneMinderServerBridgeHandler bridge = getZoneMinderBridgeHandler();
|
||||
if (bridge == null) {
|
||||
logger.warn("'handleCommand()': Bridge is 'null'!");
|
||||
}
|
||||
|
||||
IZoneMinderMonitor monitorProxy = ZoneMinderFactory.getMonitorProxy(aquireSession(),
|
||||
getZoneMinderId());
|
||||
try {
|
||||
if (command == OnOffType.ON) {
|
||||
forceAlarmManualState = 1;
|
||||
logger.info("{}: Activate 'ForceAlarm' to '{}' (Reason='{}', Timeout='{}')",
|
||||
getLogIdentifier(), command, eventText, eventTimeout.intValue());
|
||||
|
||||
monitorProxy.activateForceAlarm(255, ZoneMinderConstants.MONITOR_EVENT_OPENHAB,
|
||||
eventText, "", eventTimeout.intValue());
|
||||
|
||||
}
|
||||
|
||||
else if (command == OnOffType.OFF) {
|
||||
forceAlarmManualState = 0;
|
||||
logger.info("{}: Cancel 'ForceAlarm'", getLogIdentifier());
|
||||
monitorProxy.deactivateForceAlarm();
|
||||
|
||||
}
|
||||
|
||||
} finally {
|
||||
releaseSession();
|
||||
}
|
||||
|
||||
recalculateChannelStates();
|
||||
|
||||
handleCommand(channelUID, RefreshType.REFRESH);
|
||||
handleCommand(getChannelUIDFromChannelId(ZoneMinderConstants.CHANNEL_MONITOR_EVENT_STATE),
|
||||
RefreshType.REFRESH);
|
||||
handleCommand(getChannelUIDFromChannelId(ZoneMinderConstants.CHANNEL_MONITOR_RECORD_STATE),
|
||||
RefreshType.REFRESH);
|
||||
|
||||
// Force a refresh
|
||||
startPriorityRefresh();
|
||||
}
|
||||
break;
|
||||
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_ENABLED:
|
||||
logger.debug(
|
||||
"{}: 'handleCommand' => CHANNEL_MONITOR_ENABLED: Command '{}' received for monitor '{}'",
|
||||
getLogIdentifier(), command, channelUID.getId());
|
||||
|
||||
if ((command == OnOffType.OFF) || (command == OnOffType.ON)) {
|
||||
boolean newState = ((command == OnOffType.ON) ? true : false);
|
||||
|
||||
IZoneMinderMonitor monitorProxy = ZoneMinderFactory.getMonitorProxy(aquireSession(),
|
||||
getZoneMinderId());
|
||||
try {
|
||||
monitorProxy.SetEnabled(newState);
|
||||
} finally {
|
||||
releaseSession();
|
||||
}
|
||||
|
||||
channelEnabled = newState;
|
||||
|
||||
logger.info("{}: Setting enabled to '{}'", getLogIdentifier(), command);
|
||||
}
|
||||
|
||||
handleCommand(channelUID, RefreshType.REFRESH);
|
||||
break;
|
||||
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_FUNCTION:
|
||||
String commandString = "";
|
||||
if (ZoneMinderMonitorFunctionEnum.isValid(command.toString())) {
|
||||
commandString = ZoneMinderMonitorFunctionEnum.getEnum(command.toString()).toString();
|
||||
|
||||
IZoneMinderMonitor monitorProxy = ZoneMinderFactory.getMonitorProxy(aquireSession(),
|
||||
getZoneMinderId());
|
||||
try {
|
||||
monitorProxy.SetFunction(commandString);
|
||||
} finally {
|
||||
releaseSession();
|
||||
}
|
||||
|
||||
// Make sure local copy is set to new value
|
||||
channelFunction = ZoneMinderMonitorFunctionEnum.getEnum(command.toString());
|
||||
|
||||
logger.info("{}: Setting function to '{}'", getLogIdentifier(), commandString);
|
||||
|
||||
} else {
|
||||
logger.error(
|
||||
"{}: Value '{}' for monitor channel is not valid. Accepted values is: 'None', 'Monitor', 'Modect', Record', 'Mocord', 'Nodect'",
|
||||
getLogIdentifier(), commandString);
|
||||
}
|
||||
handleCommand(channelUID, RefreshType.REFRESH);
|
||||
break;
|
||||
|
||||
// They are all readonly in the channel config.
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_EVENT_STATE:
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_DETAILED_STATUS:
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_RECORD_STATE:
|
||||
case ZoneMinderConstants.CHANNEL_ONLINE:
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_EVENT_CAUSE:
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_CAPTURE_DAEMON_STATE:
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_ANALYSIS_DAEMON_STATE:
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_FRAME_DAEMON_STATE:
|
||||
// Do nothing, they are all read only
|
||||
break;
|
||||
default:
|
||||
logger.warn("{}: Command received for an unknown channel: {}", getLogIdentifier(),
|
||||
channelUID.getId());
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("{}: handleCommand: Command='{}' failed for channel='{}' Exception='{}'", getLogIdentifier(),
|
||||
command, channelUID.getId(), ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
try {
|
||||
super.initialize();
|
||||
this.config = getMonitorConfig();
|
||||
logger.info("{}: ZoneMinder Monitor Handler Initialized", getLogIdentifier());
|
||||
logger.debug("{}: Monitor Id: {}", getLogIdentifier(), config.getZoneMinderId());
|
||||
} catch (Exception ex) {
|
||||
logger.error("{}: Exception occurred when calling 'initialize()'. Exception='{}'", getLogIdentifier(),
|
||||
ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrippedForceAlarm(ZoneMinderTriggerEvent event) {
|
||||
try {
|
||||
logger.info("{}: Received forceAlarm for monitor {}", getLogIdentifier(), event.getMonitorId());
|
||||
|
||||
// Set Current Event to actual event
|
||||
if (event.getState()) {
|
||||
startPriorityRefresh();
|
||||
|
||||
} else {
|
||||
curEvent = null;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("{}: Exception occurred inTrippedForceAlarm() Exception='{}'", getLogIdentifier(),
|
||||
ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected ZoneMinderThingMonitorConfig getMonitorConfig() {
|
||||
return this.getConfigAs(ZoneMinderThingMonitorConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getZoneMinderThingType() {
|
||||
return ZoneMinderConstants.THING_ZONEMINDER_MONITOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
|
||||
// Assume success
|
||||
ThingStatus newThingStatus = ThingStatus.ONLINE;
|
||||
ThingStatusDetail thingStatusDetailed = ThingStatusDetail.NONE;
|
||||
String thingStatusDescription = "";
|
||||
|
||||
ThingStatus curThingStatus = this.getThing().getStatus();
|
||||
|
||||
// Is connected to ZoneMinder and thing is ONLINE
|
||||
if (isConnected() && curThingStatus == ThingStatus.ONLINE) {
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ZoneMinderFactory.validateConnection(connection);
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.error("{}: validateConnection failed with exception='{}'", getLogIdentifier(), e.getMessage());
|
||||
newThingStatus = ThingStatus.OFFLINE;
|
||||
thingStatusDetailed = ThingStatusDetail.COMMUNICATION_ERROR;
|
||||
thingStatusDescription = "Could not connect to thing";
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String msg;
|
||||
|
||||
final Bridge bridge = getBridge();
|
||||
|
||||
// 1. Is there a Bridge assigned?
|
||||
if (bridge == null) {
|
||||
msg = String.format("No Bridge assigned to monitor '%s'", thing.getUID());
|
||||
logger.error("{}: {}", getLogIdentifier(), msg);
|
||||
newThingStatus = ThingStatus.OFFLINE;
|
||||
thingStatusDetailed = ThingStatusDetail.BRIDGE_OFFLINE;
|
||||
thingStatusDescription = "No Bridge assigned to monitor";
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
return;
|
||||
} else {
|
||||
logger.debug("{}: ThingAvailability: Thing '{}' has Bridge '{}' defined (Check PASSED)",
|
||||
getLogIdentifier(), thing.getUID(), bridge.getBridgeUID());
|
||||
}
|
||||
|
||||
// 2. Is Bridge Online?
|
||||
if (bridge.getStatus() != ThingStatus.ONLINE) {
|
||||
msg = String.format("Bridge '%s' is OFFLINE", bridge.getBridgeUID());
|
||||
newThingStatus = ThingStatus.OFFLINE;
|
||||
thingStatusDetailed = ThingStatusDetail.BRIDGE_OFFLINE;
|
||||
thingStatusDescription = msg;
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
logger.error("{}: {}", getLogIdentifier(), msg);
|
||||
return;
|
||||
} else {
|
||||
logger.debug("{}: ThingAvailability: Bridge '{}' is ONLINE (Check PASSED)", getLogIdentifier(),
|
||||
bridge.getBridgeUID());
|
||||
}
|
||||
|
||||
// 3. Is Configuration OK?
|
||||
if (getMonitorConfig() == null) {
|
||||
msg = String.format("No valid configuration found for '%s'", thing.getUID());
|
||||
newThingStatus = ThingStatus.OFFLINE;
|
||||
thingStatusDetailed = ThingStatusDetail.CONFIGURATION_ERROR;
|
||||
thingStatusDescription = msg;
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
|
||||
logger.error("{}: {}", getLogIdentifier(), msg);
|
||||
return;
|
||||
} else {
|
||||
logger.debug("{}: ThingAvailability: Thing '{}' has valid configuration (Check PASSED)",
|
||||
getLogIdentifier(), thing.getUID());
|
||||
}
|
||||
|
||||
// ZoneMinder Id for Monitor not set, we are pretty much lost then
|
||||
if (getMonitorConfig().getZoneMinderId().isEmpty()) {
|
||||
msg = String.format("No Id is specified for monitor '%s'", thing.getUID());
|
||||
newThingStatus = ThingStatus.OFFLINE;
|
||||
thingStatusDetailed = ThingStatusDetail.CONFIGURATION_ERROR;
|
||||
thingStatusDescription = msg;
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
|
||||
logger.error("{}: {}", getLogIdentifier(), msg);
|
||||
return;
|
||||
} else {
|
||||
logger.debug("{}: ThingAvailability: ZoneMinder Id for Thing '{}' defined (Check PASSED)",
|
||||
getLogIdentifier(), thing.getUID());
|
||||
}
|
||||
|
||||
IZoneMinderMonitor monitorProxy = null;
|
||||
IZoneMinderDaemonStatus captureDaemon = null;
|
||||
// TODO:: Also look at Analysis and Frame Daemons (only if they are supposed to be running)
|
||||
// IZoneMinderSession session = aquireSession();
|
||||
|
||||
IZoneMinderSession curSession = null;
|
||||
try {
|
||||
curSession = ZoneMinderFactory.CreateSession(connection);
|
||||
} catch (FailedLoginException | IllegalArgumentException | IOException
|
||||
| ZoneMinderUrlNotFoundException ex) {
|
||||
logger.error("{}: Create Session failed with exception {}", getLogIdentifier(), ex.getMessage());
|
||||
|
||||
newThingStatus = ThingStatus.OFFLINE;
|
||||
thingStatusDetailed = ThingStatusDetail.COMMUNICATION_ERROR;
|
||||
thingStatusDescription = "Failed to connect. (Check Log)";
|
||||
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
return;
|
||||
}
|
||||
|
||||
if (curSession != null) {
|
||||
monitorProxy = ZoneMinderFactory.getMonitorProxy(curSession, getZoneMinderId());
|
||||
|
||||
captureDaemon = monitorProxy.getCaptureDaemonStatus();
|
||||
}
|
||||
|
||||
if (captureDaemon == null) {
|
||||
msg = String.format("Capture Daemon not accssible");
|
||||
newThingStatus = ThingStatus.OFFLINE;
|
||||
thingStatusDetailed = ThingStatusDetail.COMMUNICATION_ERROR;
|
||||
thingStatusDescription = msg;
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
logger.error("{}: {}", getLogIdentifier(), msg);
|
||||
return;
|
||||
} else if (!captureDaemon.getStatus()) {
|
||||
msg = String.format("Capture Daemon is not running");
|
||||
newThingStatus = ThingStatus.OFFLINE;
|
||||
thingStatusDetailed = ThingStatusDetail.COMMUNICATION_ERROR;
|
||||
thingStatusDescription = msg;
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
logger.error("{}: {}", getLogIdentifier(), msg);
|
||||
return;
|
||||
}
|
||||
newThingStatus = ThingStatus.ONLINE;
|
||||
|
||||
} catch (Exception exception) {
|
||||
newThingStatus = ThingStatus.OFFLINE;
|
||||
thingStatusDetailed = ThingStatusDetail.COMMUNICATION_ERROR;
|
||||
thingStatusDescription = "Error occurred (Check log)";
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
|
||||
logger.error("{}: 'ThingMonitorHandler.updateAvailabilityStatus()': Exception occurred '{}'",
|
||||
getLogIdentifier(), exception.getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
|
||||
}
|
||||
|
||||
/*
|
||||
* From here we update states in openHAB
|
||||
*
|
||||
* @see
|
||||
* org.openhab.binding.zoneminder.handler.ZoneMinderBaseThingHandler#updateChannel(org.openhab.core.thing.
|
||||
* ChannelUID)
|
||||
*/
|
||||
@Override
|
||||
public void updateChannel(ChannelUID channel) {
|
||||
State state = null;
|
||||
|
||||
try {
|
||||
switch (channel.getId()) {
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_ENABLED:
|
||||
state = getChannelBoolAsOnOffState(channelEnabled);
|
||||
break;
|
||||
|
||||
case ZoneMinderConstants.CHANNEL_ONLINE:
|
||||
// Ask super class to handle, because this channel is shared for all things
|
||||
super.updateChannel(channel);
|
||||
break;
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_FORCE_ALARM:
|
||||
state = getChannelBoolAsOnOffState(channelForceAlarm);
|
||||
break;
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_EVENT_STATE:
|
||||
state = getChannelBoolAsOnOffState(channelAlarmedState);
|
||||
break;
|
||||
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_RECORD_STATE:
|
||||
state = getChannelBoolAsOnOffState(channelRecordingState);
|
||||
break;
|
||||
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_DETAILED_STATUS:
|
||||
state = getDetailedStatus();
|
||||
break;
|
||||
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_EVENT_CAUSE:
|
||||
state = getChannelStringAsStringState(channelEventCause);
|
||||
break;
|
||||
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_FUNCTION:
|
||||
state = getChannelStringAsStringState(channelFunction.toString());
|
||||
break;
|
||||
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_CAPTURE_DAEMON_STATE:
|
||||
state = getChannelBoolAsOnOffState(channelDaemonCapture);
|
||||
break;
|
||||
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_ANALYSIS_DAEMON_STATE:
|
||||
state = getChannelBoolAsOnOffState(channelDaemonAnalysis);
|
||||
break;
|
||||
|
||||
case ZoneMinderConstants.CHANNEL_MONITOR_FRAME_DAEMON_STATE:
|
||||
state = getChannelBoolAsOnOffState(channelDaemonFrame);
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.warn("{}: updateChannel(): Monitor '{}': No handler defined for channel='{}'",
|
||||
getLogIdentifier(), thing.getLabel(), channel.getAsString());
|
||||
|
||||
// Ask super class to handle
|
||||
super.updateChannel(channel);
|
||||
}
|
||||
|
||||
if (state != null) {
|
||||
logger.debug("{}: Setting channel '{}' to '{}'", getLogIdentifier(), channel.toString(),
|
||||
state.toString());
|
||||
updateState(channel.getId(), state);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("{}: Error when 'updateChannel' was called (channelId='{}'state='{}', exception'{}')",
|
||||
getLogIdentifier(), channel, state, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(ThingStatus status) {
|
||||
super.updateStatus(status);
|
||||
updateState(ZoneMinderConstants.CHANNEL_ONLINE,
|
||||
((status == ThingStatus.ONLINE) ? OnOffType.ON : OnOffType.OFF));
|
||||
}
|
||||
|
||||
protected void recalculateChannelStates() {
|
||||
boolean recordingFunction = false;
|
||||
boolean recordingDetailedState = false;
|
||||
boolean alarmedFunction = false;
|
||||
boolean alarmedDetailedState = false;
|
||||
|
||||
// Calculate based on state of Function
|
||||
switch (channelFunction) {
|
||||
case NONE:
|
||||
case MONITOR:
|
||||
alarmedFunction = false;
|
||||
recordingFunction = false;
|
||||
break;
|
||||
|
||||
case MODECT:
|
||||
alarmedFunction = true;
|
||||
recordingFunction = true;
|
||||
break;
|
||||
case RECORD:
|
||||
alarmedFunction = false;
|
||||
recordingFunction = true;
|
||||
break;
|
||||
case MOCORD:
|
||||
alarmedFunction = true;
|
||||
recordingFunction = true;
|
||||
break;
|
||||
case NODECT:
|
||||
alarmedFunction = false;
|
||||
recordingFunction = true;
|
||||
break;
|
||||
default:
|
||||
recordingFunction = (curEvent != null) ? true : false;
|
||||
}
|
||||
logger.debug(
|
||||
"{}: Recalculate channel states based on Function: Function='{}' -> alarmState='{}', recordingState='{}'",
|
||||
getLogIdentifier(), channelFunction.name(), alarmedFunction, recordingFunction);
|
||||
|
||||
// Calculated based on detailed Monitor Status
|
||||
switch (channelMonitorStatus) {
|
||||
case IDLE:
|
||||
alarmedDetailedState = false;
|
||||
recordingDetailedState = false;
|
||||
channelForceAlarm = false;
|
||||
channelEventCause = "";
|
||||
break;
|
||||
case PRE_ALARM:
|
||||
alarmedDetailedState = true;
|
||||
recordingDetailedState = true;
|
||||
channelForceAlarm = false;
|
||||
break;
|
||||
case ALARM:
|
||||
alarmedDetailedState = true;
|
||||
recordingDetailedState = true;
|
||||
channelForceAlarm = true;
|
||||
break;
|
||||
case ALERT:
|
||||
alarmedDetailedState = true;
|
||||
recordingDetailedState = true;
|
||||
channelForceAlarm = false;
|
||||
break;
|
||||
case RECORDING:
|
||||
alarmedDetailedState = false;
|
||||
recordingDetailedState = true;
|
||||
channelForceAlarm = false;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
|
||||
}
|
||||
logger.debug(
|
||||
"{}: Recalculate channel states based on Detailed State: DetailedState='{}' -> alarmState='{}', recordingState='{}'",
|
||||
getLogIdentifier(), channelMonitorStatus.name(), alarmedDetailedState, recordingDetailedState);
|
||||
|
||||
// Check if Force alarm was initialed from openHAB
|
||||
if (forceAlarmManualState == 0) {
|
||||
if (channelForceAlarm) {
|
||||
channelForceAlarm = false;
|
||||
} else {
|
||||
forceAlarmManualState = -1;
|
||||
}
|
||||
} else if (forceAlarmManualState == 1) {
|
||||
if (!channelForceAlarm) {
|
||||
channelForceAlarm = true;
|
||||
} else {
|
||||
forceAlarmManualState = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Now we can conclude on the Alarmed and Recording channel state
|
||||
channelRecordingState = (recordingFunction && recordingDetailedState && channelEnabled);
|
||||
channelAlarmedState = (alarmedFunction && alarmedDetailedState && channelEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFetchData() {
|
||||
IZoneMinderSession session = null;
|
||||
|
||||
session = aquireSession();
|
||||
try {
|
||||
IZoneMinderMonitor monitorProxy = ZoneMinderFactory.getMonitorProxy(session, getZoneMinderId());
|
||||
|
||||
IZoneMinderMonitorData data = null;
|
||||
IZoneMinderDaemonStatus captureDaemon = null;
|
||||
IZoneMinderDaemonStatus analysisDaemon = null;
|
||||
IZoneMinderDaemonStatus frameDaemon = null;
|
||||
|
||||
data = monitorProxy.getMonitorData();
|
||||
logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
|
||||
monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(),
|
||||
monitorProxy.getHttpResponseMessage());
|
||||
|
||||
captureDaemon = monitorProxy.getCaptureDaemonStatus();
|
||||
logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
|
||||
monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(),
|
||||
monitorProxy.getHttpResponseMessage());
|
||||
|
||||
analysisDaemon = monitorProxy.getAnalysisDaemonStatus();
|
||||
logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
|
||||
monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(),
|
||||
monitorProxy.getHttpResponseMessage());
|
||||
|
||||
frameDaemon = monitorProxy.getFrameDaemonStatus();
|
||||
logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
|
||||
monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(),
|
||||
monitorProxy.getHttpResponseMessage());
|
||||
|
||||
if ((data.getHttpResponseCode() != 200) || (captureDaemon.getHttpResponseCode() != 200)
|
||||
|| (analysisDaemon.getHttpResponseCode() != 200) || (frameDaemon.getHttpResponseCode() != 200)) {
|
||||
if (data.getHttpResponseCode() != 200) {
|
||||
logger.warn("{}: HTTP Response MonitorData: Code='{}', Message'{}'", getLogIdentifier(),
|
||||
data.getHttpResponseCode(), data.getHttpResponseMessage());
|
||||
|
||||
channelMonitorStatus = ZoneMinderMonitorStatusEnum.UNKNOWN;
|
||||
channelFunction = ZoneMinderMonitorFunctionEnum.NONE;
|
||||
channelEnabled = false;
|
||||
channelEventCause = "";
|
||||
}
|
||||
if (captureDaemon.getHttpResponseCode() != 200) {
|
||||
channelDaemonCapture = false;
|
||||
logger.warn("{}: HTTP Response CaptureDaemon: Code='{}', Message'{}'", getLogIdentifier(),
|
||||
captureDaemon.getHttpResponseCode(), captureDaemon.getHttpResponseMessage());
|
||||
|
||||
}
|
||||
if (analysisDaemon.getHttpResponseCode() != 200) {
|
||||
channelDaemonAnalysis = false;
|
||||
|
||||
logger.warn("{}: HTTP Response AnalysisDaemon: Code='{}', Message='{}'", getLogIdentifier(),
|
||||
analysisDaemon.getHttpResponseCode(), analysisDaemon.getHttpResponseMessage());
|
||||
}
|
||||
if (frameDaemon.getHttpResponseCode() != 200) {
|
||||
channelDaemonFrame = false;
|
||||
logger.warn("{}: HTTP Response MonitorData: Code='{}', Message'{}'", getLogIdentifier(),
|
||||
frameDaemon.getHttpResponseCode(), frameDaemon.getHttpResponseMessage());
|
||||
}
|
||||
|
||||
} else {
|
||||
if (isConnected()) {
|
||||
channelMonitorStatus = monitorProxy.getMonitorDetailedStatus();
|
||||
logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
|
||||
monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(),
|
||||
monitorProxy.getHttpResponseMessage());
|
||||
|
||||
channelFunction = data.getFunction();
|
||||
channelEnabled = data.getEnabled();
|
||||
IZoneMinderEventData event = monitorProxy.getLastEvent();
|
||||
if (event != null) {
|
||||
channelEventCause = event.getCause();
|
||||
} else {
|
||||
channelEventCause = "";
|
||||
}
|
||||
|
||||
channelDaemonCapture = captureDaemon.getStatus();
|
||||
channelDaemonAnalysis = analysisDaemon.getStatus();
|
||||
channelDaemonFrame = frameDaemon.getStatus();
|
||||
} else {
|
||||
channelMonitorStatus = ZoneMinderMonitorStatusEnum.UNKNOWN;
|
||||
channelFunction = ZoneMinderMonitorFunctionEnum.NONE;
|
||||
channelEnabled = false;
|
||||
channelEventCause = "";
|
||||
channelDaemonCapture = false;
|
||||
channelDaemonAnalysis = false;
|
||||
channelDaemonFrame = false;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
releaseSession();
|
||||
}
|
||||
|
||||
recalculateChannelStates();
|
||||
|
||||
if (!channelForceAlarm && !channelAlarmedState
|
||||
&& (DataRefreshPriorityEnum.HIGH_PRIORITY == getRefreshPriority())) {
|
||||
stopPriorityRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
protected State getDetailedStatus() {
|
||||
State state = UnDefType.UNDEF;
|
||||
|
||||
try {
|
||||
if (channelMonitorStatus == ZoneMinderMonitorStatusEnum.UNKNOWN) {
|
||||
state = getChannelStringAsStringState("");
|
||||
} else {
|
||||
state = getChannelStringAsStringState(channelMonitorStatus.toString());
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
logger.debug("{}", ex.getMessage());
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is experimental
|
||||
* Try to add different properties
|
||||
*/
|
||||
private void updateMonitorProperties(IZoneMinderSession session) {
|
||||
logger.debug("{}: Update Monitor Properties", getLogIdentifier());
|
||||
// Update property information about this device
|
||||
Map<String, String> properties = editProperties();
|
||||
IZoneMinderMonitor monitorProxy = ZoneMinderFactory.getMonitorProxy(session, getZoneMinderId());
|
||||
IZoneMinderMonitorData monitorData = monitorProxy.getMonitorData();
|
||||
logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
|
||||
monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(), monitorProxy.getHttpResponseMessage());
|
||||
|
||||
properties.put(ZoneMinderProperties.PROPERTY_ID, getLogIdentifier());
|
||||
properties.put(ZoneMinderProperties.PROPERTY_MONITOR_NAME, monitorData.getName());
|
||||
|
||||
properties.put(ZoneMinderProperties.PROPERTY_MONITOR_SOURCETYPE, monitorData.getSourceType().name());
|
||||
|
||||
properties.put(ZoneMinderProperties.PROPERTY_MONITOR_ANALYSIS_FPS, monitorData.getAnalysisFPS());
|
||||
properties.put(ZoneMinderProperties.PROPERTY_MONITOR_MAXIMUM_FPS, monitorData.getMaxFPS());
|
||||
properties.put(ZoneMinderProperties.PROPERTY_MONITOR_ALARM_MAXIMUM, monitorData.getAlarmMaxFPS());
|
||||
|
||||
properties.put(ZoneMinderProperties.PROPERTY_MONITOR_IMAGE_WIDTH, monitorData.getWidth());
|
||||
properties.put(ZoneMinderProperties.PROPERTY_MONITOR_IMAGE_HEIGHT, monitorData.getHeight());
|
||||
|
||||
// Must loop over the new properties since we might have added data
|
||||
boolean update = false;
|
||||
Map<String, String> originalProperties = editProperties();
|
||||
for (String property : properties.keySet()) {
|
||||
if ((originalProperties.get(property) == null
|
||||
|| !originalProperties.get(property).equals(properties.get(property)))) {
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (update) {
|
||||
logger.debug("{}: Properties synchronised", getLogIdentifier());
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLogIdentifier() {
|
||||
String result = "[MONITOR]";
|
||||
|
||||
try {
|
||||
if (config != null) {
|
||||
result = String.format("[MONITOR-%s]", config.getZoneMinderId().toString());
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
result = "[MONITOR]";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.zoneminder.internal.handler;
|
||||
|
||||
/**
|
||||
* Enumerator for each Bridge and Thing
|
||||
*
|
||||
* @author Martin S. Eskildsen - Initial contribution
|
||||
*/
|
||||
public enum ZoneMinderThingType {
|
||||
ZoneMinderServerBridge,
|
||||
ZoneMinderMonitorThing
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="zoneminder" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>ZoneMinder Binding</name>
|
||||
<description>This binding interfaces a ZoneMinder Server</description>
|
||||
<author>Martin S. Eskildsen</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
|
||||
https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
<config-description uri="thing-type:monitor-channels:config">
|
||||
<parameter name="monitorId" type="integer" required="true">
|
||||
<label>Monitor ID</label>
|
||||
<description>The ID of the monitor in ZoneMinder</description>
|
||||
</parameter>
|
||||
<parameter name="monitorTriggerTimeout" type="integer" required="false" min="0" max="65535">
|
||||
<label>ForceAlarm Timeout</label>
|
||||
<description>Timeout in seconds when activating alarm. Default is 60 seconds</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
<parameter name="monitorEventText" type="text" required="false">
|
||||
<label>Event Text</label>
|
||||
<description>Event text in ZoneMinder</description>
|
||||
<default>Triggered from openHAB</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
|
||||
https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
<config-description uri="thing-type:zoneminderserver:config">
|
||||
<parameter-group name="basic">
|
||||
<context>basic</context>
|
||||
<label>Basic</label>
|
||||
</parameter-group>
|
||||
<parameter-group name="credentials">
|
||||
<context>credentials</context>
|
||||
<label>Credentials</label>
|
||||
</parameter-group>
|
||||
<parameter-group name="network">
|
||||
<context>network</context>
|
||||
<label>Port Configuration</label>
|
||||
</parameter-group>
|
||||
<parameter-group name="refreshConfig">
|
||||
<context>refreshConfig</context>
|
||||
<label>Refresh Settings</label>
|
||||
</parameter-group>
|
||||
<parameter-group name="advancedSettings">
|
||||
<context>advancedSettings</context>
|
||||
<label>Advanced</label>
|
||||
</parameter-group>
|
||||
<parameter name="hostname" type="text" required="true" groupName="basic">
|
||||
<context>network-address</context>
|
||||
<label>Host</label>
|
||||
<description>The IP address or hostname of the ZoneMinder Server</description>
|
||||
</parameter>
|
||||
<parameter name="protocol" type="text" required="false" groupName="basic">
|
||||
<label>Protocol</label>
|
||||
<description>Protocol to connect to the ZoneMinder Server API (http or https)</description>
|
||||
<default>http</default>
|
||||
<options>
|
||||
<option value="http">HTTP</option>
|
||||
<option value="https">HTTPS</option>
|
||||
</options>
|
||||
</parameter>
|
||||
<parameter name="urlpath" type="text" required="false" groupName="basic">
|
||||
<label>Additional Path On ZoneMinder Server to Access API</label>
|
||||
<description>Additional path on ZoneMinder Server to access API. In a standard installation this is' /zm'</description>
|
||||
<default>/zm</default>
|
||||
</parameter>
|
||||
<parameter name="user" type="text" required="false" groupName="credentials">
|
||||
<label>Username</label>
|
||||
<description>User to access the ZoneMinder Server API</description>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" required="false" groupName="credentials">
|
||||
<context>password</context>
|
||||
<label>Password</label>
|
||||
<description>Password to access the ZoneMinder Server API</description>
|
||||
</parameter>
|
||||
<parameter name="http_port" type="integer" required="false" min="0" max="65535" groupName="network">
|
||||
<label>Port</label>
|
||||
<description>Port of the ZoneMinder Server API. If '0', then the port will be determined from the protocol</description>
|
||||
<default>0</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="telnet_port" type="integer" required="false" min="1" max="65535" groupName="network">
|
||||
<label>Telnet Port</label>
|
||||
<description>Port to listen for events in (Telnet)</description>
|
||||
<default>6802</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="refresh_interval" type="integer" required="false" min="1" max="65535"
|
||||
groupName="refreshConfig">
|
||||
<label>API Polling Interval</label>
|
||||
<description>Seconds between each call to ZoneMinder Server API to refresh values in openHAB</description>
|
||||
<default>10</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="refresh_interval_disk_usage" type="integer" required="false" min="0" max="65335"
|
||||
groupName="refreshConfig">
|
||||
<label>Refresh Interval for Disk Usage</label>
|
||||
<description>Minutes between each call to ZoneMinder Server to refresh Server DiskUsage in ZoneMinder. Default value
|
||||
is '0' (Disabled)</description>
|
||||
<default>0</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="autodiscover_things" type="boolean" required="false" groupName="advanced">
|
||||
<label>Background Discovery</label>
|
||||
<description>If enabled new monitors on the ZoneMinder Server will automatically be added to the Inbox in openHAB</description>
|
||||
<default>true</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="zoneminder"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Supported ZoneMinder devices and features -->
|
||||
<thing-type id="monitor">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="server"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>ZoneMinder Monitor</label>
|
||||
<description>Camera in ZoneMinder</description>
|
||||
|
||||
<channels>
|
||||
<channel id="online" typeId="monitor_online"/>
|
||||
<channel id="enabled" typeId="monitor_enabled"/>
|
||||
<channel id="force-alarm" typeId="monitor_force_alarm"/>
|
||||
<channel id="alarm" typeId="monitor_alarm"/>
|
||||
<channel id="recording" typeId="monitor_recording"/>
|
||||
<channel id="detailed-status" typeId="monitor_detailed_status"/>
|
||||
<channel id="function" typeId="monitor_function"/>
|
||||
<channel id="event-cause" typeId="monitor_event_cause"/>
|
||||
<channel id="capture-daemon" typeId="monitor_zmc_daemon"/>
|
||||
<channel id="analysis-daemon" typeId="monitor_zma_daemon"/>
|
||||
<channel id="frame-daemon" typeId="monitor_zmf_daemon"/>
|
||||
</channels>
|
||||
|
||||
<config-description-ref uri="thing-type:monitor-channels:config"/>
|
||||
</thing-type>
|
||||
|
||||
<!-- Channel definitions of ZoneMinder Server -->
|
||||
<channel-type id="monitor_online">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Online</label>
|
||||
<description>Switch telling if the monitor is online</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="monitor_enabled">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Enabled</label>
|
||||
<description>Showing the value of the checkbox 'enabled' in ZoneMinder for the monitor</description>
|
||||
<state readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="monitor_force_alarm">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Force Alarm</label>
|
||||
<description>Will force an alarm from openHAB in ZoneMinder</description>
|
||||
<state readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
|
||||
<channel-type id="monitor_alarm">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Alarm Status</label>
|
||||
<description>set to 'ON' when one of the following is true: Motion detected, Signal lost, Force Alarm pressed,
|
||||
External Alarm. Else set to 'OFF'</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="monitor_recording">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Recording Status</label>
|
||||
<description>set to 'ON' when either channel monitor-alarm set to 'ON', or montior function is 'Mocord' or 'Record'.
|
||||
Else set to 'OFF'</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="monitor_detailed_status" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Detailed Status</label>
|
||||
<description>Current Monitor Status: 0=Idle, 1=Pre-alarm, 2=Alarm, 3=Alert, 4=Recording</description>
|
||||
<state pattern="%s" readOnly="true">
|
||||
<options>
|
||||
<option value="Idle">Idle</option>
|
||||
<option value="Pre-alarm">Pre-alarm</option>
|
||||
<option value="Alarm">Alarm</option>
|
||||
<option value="Alert">Alert</option>
|
||||
<option value="Recording">Recording</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="monitor_function" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Operating Mode</label>
|
||||
<description>Current Monitor Function: None, Monitor, Modect, Record, Mocord, Nodect</description>
|
||||
<state pattern="%s" readOnly="false">
|
||||
<options>
|
||||
<option value="None">None</option>
|
||||
<option value="Monitor">Monitor</option>
|
||||
<option value="Modect">Modect</option>
|
||||
<option value="Record">Record</option>
|
||||
<option value="Mocord">Mocord</option>
|
||||
<option value="Nodect">Nodect</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="monitor_event_cause" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Event Cause</label>
|
||||
<description>Cause of event: None, Signal, Motion, Forced Web, openHAB, Other</description>
|
||||
<state pattern="%s" readOnly="true">
|
||||
<options>
|
||||
<option value="none">None</option>
|
||||
<option value="signal">Signal</option>
|
||||
<option value="motion">Motion</option>
|
||||
<option value="forced_web">Forced Web</option>
|
||||
<option value="openhab">openHAB</option>
|
||||
<option value="other">Other</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="monitor_zmc_daemon" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Capture Daemon Status</label>
|
||||
<description>State of ZoneMinder Capture daemon for this monitor</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="monitor_zma_daemon" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Analysis Daemon Status</label>
|
||||
<description>State of ZoneMinder Analysis daemon for this monitor</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="monitor_zmf_daemon" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Frame Daemon Status</label>
|
||||
<description>State of ZoneMinder Frame daemon for this monitor</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="zoneminder"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<bridge-type id="server">
|
||||
<label>ZoneMinder Server</label>
|
||||
<description>ZoneMinder Server</description>
|
||||
<channels>
|
||||
<channel id="online" typeId="server_online"/>
|
||||
<channel id="cpu-load" typeId="server_cpu_load"/>
|
||||
<channel id="disk-usage" typeId="server_disk_usage"/>
|
||||
</channels>
|
||||
|
||||
<config-description-ref uri="thing-type:zoneminderserver:config"/>
|
||||
</bridge-type>
|
||||
|
||||
<channel-type id="server_online">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Online</label>
|
||||
<description>ZoneMinder Server Online Status</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="server_cpu_load">
|
||||
<item-type>Number</item-type>
|
||||
<label>CPU Load</label>
|
||||
<description>ZoneMinder Server CPU Load</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="server_disk_usage">
|
||||
<item-type>Number</item-type>
|
||||
<label>Diskusage</label>
|
||||
<description>ZoneMinder Server Disk Usage</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user