[zoneminder] Rework discovery to not use the thing handler thread (#9600)
Signed-off-by: Mark Hilbush <mark@hilbush.com>
This commit is contained in:
parent
55a956e48c
commit
4ef61c9949
|
@ -37,7 +37,7 @@ import org.osgi.service.component.annotations.Reference;
|
|||
* @author Mark Hilbush - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.zm", service = ThingHandlerFactory.class)
|
||||
@Component(configurationPid = "binding.zoneminder", service = ThingHandlerFactory.class)
|
||||
public class ZmHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private final TimeZoneProvider timeZoneProvider;
|
||||
|
|
|
@ -50,16 +50,6 @@ public class ZmBridgeConfig {
|
|||
*/
|
||||
public @Nullable Integer refreshInterval;
|
||||
|
||||
/**
|
||||
* Enable/disable monitor discovery
|
||||
*/
|
||||
public @Nullable Boolean discoveryEnabled;
|
||||
|
||||
/**
|
||||
* Frequency at which the binding will try to discover monitors
|
||||
*/
|
||||
public @Nullable Integer discoveryInterval;
|
||||
|
||||
/**
|
||||
* Alarm duration set on monitor things when they're discovered
|
||||
*/
|
||||
|
@ -70,6 +60,11 @@ public class ZmBridgeConfig {
|
|||
*/
|
||||
public @Nullable Integer defaultImageRefreshInterval;
|
||||
|
||||
/**
|
||||
* Enable/disable monitor discovery
|
||||
*/
|
||||
public Boolean discoveryEnabled = Boolean.TRUE;
|
||||
|
||||
/**
|
||||
* Zoneminder user name
|
||||
*/
|
||||
|
|
|
@ -17,6 +17,8 @@ import static org.openhab.binding.zoneminder.internal.ZmBindingConstants.*;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
@ -44,17 +46,32 @@ public class MonitorDiscoveryService extends AbstractDiscoveryService implements
|
|||
|
||||
private final Logger logger = LoggerFactory.getLogger(MonitorDiscoveryService.class);
|
||||
|
||||
private @Nullable ZmBridgeHandler bridgeHandler;
|
||||
private static final int DISCOVERY_INTERVAL_SECONDS = 300;
|
||||
private static final int DISCOVERY_INITIAL_DELAY_SECONDS = 10;
|
||||
private static final int DISCOVERY_TIMEOUT_SECONDS = 6;
|
||||
|
||||
private @NonNullByDefault({}) ZmBridgeHandler bridgeHandler;
|
||||
|
||||
private @Nullable Future<?> discoveryJob;
|
||||
|
||||
public MonitorDiscoveryService() {
|
||||
super(30);
|
||||
super(SUPPORTED_MONITOR_THING_TYPES_UIDS, DISCOVERY_TIMEOUT_SECONDS, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
super.activate(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
if (handler instanceof ZmBridgeHandler) {
|
||||
((ZmBridgeHandler) handler).setDiscoveryService(this);
|
||||
this.bridgeHandler = (ZmBridgeHandler) handler;
|
||||
bridgeHandler = (ZmBridgeHandler) handler;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,66 +80,69 @@ public class MonitorDiscoveryService extends AbstractDiscoveryService implements
|
|||
return bridgeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypes() {
|
||||
return SUPPORTED_MONITOR_THING_TYPES_UIDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startBackgroundDiscovery() {
|
||||
logger.trace("Discovery: Performing background discovery scan for {}", getBridgeUID());
|
||||
discoverMonitors();
|
||||
protected void startBackgroundDiscovery() {
|
||||
Future<?> localDiscoveryJob = discoveryJob;
|
||||
if (localDiscoveryJob == null || localDiscoveryJob.isCancelled()) {
|
||||
logger.debug("ZoneminderDiscovery: Starting background discovery job");
|
||||
discoveryJob = scheduler.scheduleWithFixedDelay(this::backgroundDiscoverMonitors,
|
||||
DISCOVERY_INITIAL_DELAY_SECONDS, DISCOVERY_INTERVAL_SECONDS, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopBackgroundDiscovery() {
|
||||
Future<?> localDiscoveryJob = discoveryJob;
|
||||
if (localDiscoveryJob != null) {
|
||||
logger.debug("ZoneminderDiscovery: Stopping background discovery job");
|
||||
localDiscoveryJob.cancel(true);
|
||||
discoveryJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startScan() {
|
||||
logger.debug("Discovery: Starting monitor discovery scan for {}", getBridgeUID());
|
||||
logger.debug("ZoneminderDiscovery: Running discovery scan");
|
||||
discoverMonitors();
|
||||
}
|
||||
|
||||
private @Nullable ThingUID getBridgeUID() {
|
||||
ZmBridgeHandler localBridgeHandler = bridgeHandler;
|
||||
return localBridgeHandler != null ? localBridgeHandler.getThing().getUID() : null;
|
||||
private void backgroundDiscoverMonitors() {
|
||||
if (!bridgeHandler.isBackgroundDiscoveryEnabled()) {
|
||||
return;
|
||||
}
|
||||
logger.debug("ZoneminderDiscovery: Running background discovery scan");
|
||||
discoverMonitors();
|
||||
}
|
||||
|
||||
private synchronized void discoverMonitors() {
|
||||
ZmBridgeHandler localBridgeHandler = bridgeHandler;
|
||||
ThingUID bridgeUID = getBridgeUID();
|
||||
if (localBridgeHandler != null && bridgeUID != null) {
|
||||
Integer alarmDuration = localBridgeHandler.getDefaultAlarmDuration();
|
||||
Integer imageRefreshInterval = localBridgeHandler.getDefaultImageRefreshInterval();
|
||||
for (Monitor monitor : localBridgeHandler.getSavedMonitors()) {
|
||||
String id = monitor.getId();
|
||||
String name = monitor.getName();
|
||||
ThingUID thingUID = new ThingUID(UID_MONITOR, bridgeUID, monitor.getId());
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(CONFIG_MONITOR_ID, id);
|
||||
properties.put(CONFIG_ALARM_DURATION, alarmDuration);
|
||||
if (imageRefreshInterval != null) {
|
||||
properties.put(CONFIG_IMAGE_REFRESH_INTERVAL, imageRefreshInterval);
|
||||
}
|
||||
thingDiscovered(createDiscoveryResult(thingUID, bridgeUID, id, name, properties));
|
||||
logger.trace("Discovery: Monitor with id '{}' and name '{}' added to Inbox with UID '{}'",
|
||||
monitor.getId(), monitor.getName(), thingUID);
|
||||
ThingUID bridgeUID = bridgeHandler.getThing().getUID();
|
||||
Integer alarmDuration = bridgeHandler.getDefaultAlarmDuration();
|
||||
Integer imageRefreshInterval = bridgeHandler.getDefaultImageRefreshInterval();
|
||||
for (Monitor monitor : bridgeHandler.getSavedMonitors()) {
|
||||
String id = monitor.getId();
|
||||
String name = monitor.getName();
|
||||
ThingUID thingUID = new ThingUID(UID_MONITOR, bridgeUID, monitor.getId());
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(CONFIG_MONITOR_ID, id);
|
||||
properties.put(CONFIG_ALARM_DURATION, alarmDuration);
|
||||
if (imageRefreshInterval != null) {
|
||||
properties.put(CONFIG_IMAGE_REFRESH_INTERVAL, imageRefreshInterval);
|
||||
}
|
||||
thingDiscovered(createDiscoveryResult(thingUID, bridgeUID, id, name, properties));
|
||||
logger.debug("ZoneminderDiscovery: Monitor with id '{}' and name '{}' added to Inbox with UID '{}'",
|
||||
monitor.getId(), monitor.getName(), thingUID);
|
||||
}
|
||||
}
|
||||
|
||||
private DiscoveryResult createDiscoveryResult(ThingUID monitorUID, ThingUID bridgeUID, String id, String name,
|
||||
Map<String, Object> properties) {
|
||||
return DiscoveryResultBuilder.create(monitorUID).withProperties(properties).withBridge(bridgeUID)
|
||||
.withLabel(buildLabel(name)).withRepresentationProperty(CONFIG_MONITOR_ID).build();
|
||||
}
|
||||
|
||||
private String buildLabel(String name) {
|
||||
return String.format("Zoneminder Monitor %s", name);
|
||||
.withLabel(String.format("Zoneminder Monitor %s", name)).withRepresentationProperty(CONFIG_MONITOR_ID)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
@ -81,14 +80,8 @@ import com.google.gson.JsonSyntaxException;
|
|||
@NonNullByDefault
|
||||
public class ZmBridgeHandler extends BaseBridgeHandler {
|
||||
|
||||
private static final int REFRESH_INTERVAL_SECONDS = 1;
|
||||
private static final int REFRESH_STARTUP_DELAY_SECONDS = 3;
|
||||
|
||||
private static final int MONITORS_INTERVAL_SECONDS = 5;
|
||||
private static final int MONITORS_INITIAL_DELAY_SECONDS = 3;
|
||||
|
||||
private static final int DISCOVERY_INTERVAL_SECONDS = 300;
|
||||
private static final int DISCOVERY_INITIAL_DELAY_SECONDS = 10;
|
||||
private static final int MONITOR_REFRESH_INTERVAL_SECONDS = 10;
|
||||
private static final int MONITOR_REFRESH_STARTUP_DELAY_SECONDS = 5;
|
||||
|
||||
private static final int API_TIMEOUT_MSEC = 10000;
|
||||
|
||||
|
@ -104,10 +97,6 @@ public class ZmBridgeHandler extends BaseBridgeHandler {
|
|||
private final Logger logger = LoggerFactory.getLogger(ZmBridgeHandler.class);
|
||||
|
||||
private @Nullable Future<?> refreshMonitorsJob;
|
||||
private final AtomicInteger monitorsCounter = new AtomicInteger();
|
||||
|
||||
private @Nullable MonitorDiscoveryService discoveryService;
|
||||
private final AtomicInteger discoveryCounter = new AtomicInteger();
|
||||
|
||||
private List<Monitor> savedMonitors = new ArrayList<>();
|
||||
|
||||
|
@ -115,9 +104,8 @@ public class ZmBridgeHandler extends BaseBridgeHandler {
|
|||
private boolean useSSL;
|
||||
private @Nullable String portNumber;
|
||||
private String urlPath = DEFAULT_URL_PATH;
|
||||
private int monitorsInterval;
|
||||
private int discoveryInterval;
|
||||
private boolean discoveryEnabled;
|
||||
private int monitorRefreshInterval;
|
||||
private boolean backgroundDiscoveryEnabled;
|
||||
private int defaultAlarmDuration;
|
||||
private @Nullable Integer defaultImageRefreshInterval;
|
||||
|
||||
|
@ -144,17 +132,15 @@ public class ZmBridgeHandler extends BaseBridgeHandler {
|
|||
|
||||
Integer value;
|
||||
value = config.refreshInterval;
|
||||
monitorsInterval = value == null ? MONITORS_INTERVAL_SECONDS : value;
|
||||
|
||||
value = config.discoveryInterval;
|
||||
discoveryInterval = value == null ? DISCOVERY_INTERVAL_SECONDS : value;
|
||||
monitorRefreshInterval = value == null ? MONITOR_REFRESH_INTERVAL_SECONDS : value;
|
||||
|
||||
value = config.defaultAlarmDuration;
|
||||
defaultAlarmDuration = value == null ? DEFAULT_ALARM_DURATION_SECONDS : value;
|
||||
|
||||
defaultImageRefreshInterval = config.defaultImageRefreshInterval;
|
||||
|
||||
discoveryEnabled = config.discoveryEnabled == null ? false : config.discoveryEnabled.booleanValue();
|
||||
backgroundDiscoveryEnabled = config.discoveryEnabled;
|
||||
logger.debug("Bridge: Background discovery is {}", backgroundDiscoveryEnabled == true ? "ENABLED" : "DISABLED");
|
||||
|
||||
host = config.host;
|
||||
useSSL = config.useSSL.booleanValue();
|
||||
|
@ -222,12 +208,8 @@ public class ZmBridgeHandler extends BaseBridgeHandler {
|
|||
return Collections.singleton(MonitorDiscoveryService.class);
|
||||
}
|
||||
|
||||
public void setDiscoveryService(MonitorDiscoveryService discoveryService) {
|
||||
this.discoveryService = discoveryService;
|
||||
}
|
||||
|
||||
public boolean isDiscoveryEnabled() {
|
||||
return discoveryEnabled;
|
||||
public boolean isBackgroundDiscoveryEnabled() {
|
||||
return backgroundDiscoveryEnabled;
|
||||
}
|
||||
|
||||
public Integer getDefaultAlarmDuration() {
|
||||
|
@ -571,40 +553,14 @@ public class ZmBridgeHandler extends BaseBridgeHandler {
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The refresh job is executed every second
|
||||
* - updates the monitor handlers every monitorsInterval seconds, and
|
||||
* - runs the monitor discovery every discoveryInterval seconds
|
||||
*/
|
||||
private void refresh() {
|
||||
refreshMonitors();
|
||||
discoverMonitors();
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
private void refreshMonitors() {
|
||||
if (monitorsCounter.getAndDecrement() == 0) {
|
||||
monitorsCounter.set(monitorsInterval);
|
||||
List<Monitor> monitors = getMonitors();
|
||||
savedMonitors = monitors;
|
||||
for (Monitor monitor : monitors) {
|
||||
ZmMonitorHandler handler = monitorHandlers.get(monitor.getId());
|
||||
if (handler != null) {
|
||||
handler.updateStatus(monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void discoverMonitors() {
|
||||
if (isDiscoveryEnabled()) {
|
||||
if (discoveryCounter.getAndDecrement() == 0) {
|
||||
discoveryCounter.set(discoveryInterval);
|
||||
MonitorDiscoveryService localDiscoveryService = discoveryService;
|
||||
if (localDiscoveryService != null) {
|
||||
logger.trace("Bridge: Running monitor discovery");
|
||||
localDiscoveryService.startBackgroundDiscovery();
|
||||
}
|
||||
List<Monitor> monitors = getMonitors();
|
||||
savedMonitors = monitors;
|
||||
for (Monitor monitor : monitors) {
|
||||
ZmMonitorHandler handler = monitorHandlers.get(monitor.getId());
|
||||
if (handler != null) {
|
||||
handler.updateStatus(monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -612,10 +568,8 @@ public class ZmBridgeHandler extends BaseBridgeHandler {
|
|||
private void scheduleRefreshJob() {
|
||||
logger.debug("Bridge: Scheduling monitors refresh job");
|
||||
cancelRefreshJob();
|
||||
monitorsCounter.set(MONITORS_INITIAL_DELAY_SECONDS);
|
||||
discoveryCounter.set(DISCOVERY_INITIAL_DELAY_SECONDS);
|
||||
refreshMonitorsJob = scheduler.scheduleWithFixedDelay(this::refresh, REFRESH_STARTUP_DELAY_SECONDS,
|
||||
REFRESH_INTERVAL_SECONDS, TimeUnit.SECONDS);
|
||||
refreshMonitorsJob = scheduler.scheduleWithFixedDelay(this::refreshMonitors,
|
||||
MONITOR_REFRESH_STARTUP_DELAY_SECONDS, monitorRefreshInterval, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void cancelRefreshJob() {
|
||||
|
@ -623,6 +577,7 @@ public class ZmBridgeHandler extends BaseBridgeHandler {
|
|||
if (localRefreshThermostatsJob != null) {
|
||||
localRefreshThermostatsJob.cancel(true);
|
||||
logger.debug("Bridge: Canceling monitors refresh job");
|
||||
refreshMonitorsJob = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,6 +254,7 @@ public class ZmMonitorHandler extends BaseThingHandler {
|
|||
}
|
||||
|
||||
private void startImageRefreshJob() {
|
||||
stopImageRefreshJob();
|
||||
Integer interval = imageRefreshIntervalSeconds;
|
||||
if (interval != null) {
|
||||
long delay = getRandomDelay(interval);
|
||||
|
|
|
@ -14,31 +14,8 @@
|
|||
<parameter-group name="auth-info">
|
||||
<label>Authentication Information</label>
|
||||
</parameter-group>
|
||||
<parameter name="refreshInterval" type="integer" min="2" unit="s" required="true" groupName="config-info">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Interval in seconds at which monitor status is updated</description>
|
||||
<default>5</default>
|
||||
</parameter>
|
||||
<parameter name="discoveryEnabled" type="boolean" required="true" groupName="config-info">
|
||||
<label>Discovery Enabled</label>
|
||||
<description>Enable/disable automatic discovery</description>
|
||||
<default>true</default>
|
||||
</parameter>
|
||||
<parameter name="discoveryInterval" type="integer" min="60" unit="s" required="true" groupName="config-info">
|
||||
<label>Monitor Discovery Interval</label>
|
||||
<description>Specifies time in seconds in which the binding will attempt to discover monitors</description>
|
||||
<default>300</default>
|
||||
</parameter>
|
||||
<parameter name="defaultAlarmDuration" type="integer" unit="s" required="false" groupName="config-info">
|
||||
<label>Default Alarm Duration</label>
|
||||
<description>Duration in seconds after which the alarm will be turned off</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
<parameter name="defaultImageRefreshInterval" type="integer" unit="s" required="false"
|
||||
groupName="config-info">
|
||||
<label>Default Image Refresh Interval</label>
|
||||
<description>Interval in seconds at which monitor image snapshot will be updated</description>
|
||||
</parameter>
|
||||
|
||||
<!-- Parameter Group url-info -->
|
||||
<parameter name="host" type="text" required="true" groupName="url-info">
|
||||
<label>Server</label>
|
||||
<description>ZoneMinder server name or IP address</description>
|
||||
|
@ -58,6 +35,30 @@
|
|||
<description>URL path (Default is /zm. Use / if Zoneminder installed under the root directory)</description>
|
||||
<default>/zm</default>
|
||||
</parameter>
|
||||
|
||||
<!-- Parameter Group config-info -->
|
||||
<parameter name="refreshInterval" type="integer" min="2" unit="s" required="true" groupName="config-info">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Interval in seconds at which monitor status is updated</description>
|
||||
<default>5</default>
|
||||
</parameter>
|
||||
<parameter name="defaultAlarmDuration" type="integer" unit="s" required="false" groupName="config-info">
|
||||
<label>Default Alarm Duration</label>
|
||||
<description>Duration in seconds after which the alarm will be turned off</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
<parameter name="defaultImageRefreshInterval" type="integer" unit="s" required="false"
|
||||
groupName="config-info">
|
||||
<label>Default Image Refresh Interval</label>
|
||||
<description>Interval in seconds at which monitor image snapshot will be updated</description>
|
||||
</parameter>
|
||||
<parameter name="discoveryEnabled" type="boolean" required="true" groupName="config-info">
|
||||
<label>Background Discovery Enabled</label>
|
||||
<description>Enable/disable background discovery of monitors</description>
|
||||
<default>true</default>
|
||||
</parameter>
|
||||
|
||||
<!-- Parameter Group auth-info -->
|
||||
<parameter name="user" type="text" required="false" groupName="auth-info">
|
||||
<label>User Name</label>
|
||||
<description>User name (if authentication enabled in ZoneMinder)</description>
|
||||
|
|
|
@ -73,6 +73,9 @@
|
|||
<channel id="eventAlarmFrames" typeId="eventAlarmFrames"/>
|
||||
<channel id="eventLength" typeId="eventLength"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>monitorId</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:zoneminder:monitor"/>
|
||||
</thing-type>
|
||||
|
||||
|
|
Loading…
Reference in New Issue