diff --git a/addons/binding/org.openhab.binding.zoneminder/.classpath b/addons/binding/org.openhab.binding.zoneminder/.classpath
index 3801e00168a71..e75fa0c6a7f70 100644
--- a/addons/binding/org.openhab.binding.zoneminder/.classpath
+++ b/addons/binding/org.openhab.binding.zoneminder/.classpath
@@ -3,6 +3,6 @@
-
+
diff --git a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/binding/binding.xml b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/binding/binding.xml
index d6f42b96fc3ce..f85134801d585 100644
--- a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/binding/binding.xml
+++ b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/binding/binding.xml
@@ -1,11 +1,9 @@
-
- ZoneMinder Binding
- This binding interfaces a ZoneMinder Server
- Martin S. Eskildsen
-
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:binding="http://eclipse.org/smarthome/schemas/binding/v1.0.0"
+ xsi:schemaLocation="http://eclipse.org/smarthome/schemas/binding/v1.0.0 http://eclipse.org/smarthome/schemas/binding-1.0.0.xsd">
+ ZoneMinder Binding
+ This binding interfaces a ZoneMinder Server
+ Martin S. Eskildsen
diff --git a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/monitor-channels.xml b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/monitor-channels.xml
deleted file mode 100644
index 0a5f91128a78f..0000000000000
--- a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/monitor-channels.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
- The ID of the monitor in ZoneMinder
-
-
-
- Timeout in seconds when activating alarm. Default is 60 seconds
- 60
-
-
-
- Event text in ZoneMinder
- Triggered from openHAB
-
-
-
diff --git a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/monitor-config.xml b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/monitor-config.xml
new file mode 100644
index 0000000000000..89a6b018fb62f
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/monitor-config.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+ advancedConfig
+
+ true
+
+
+
+ imageConfig
+
+ true
+
+
+
+
+ The ID of the monitor in ZoneMinder
+
+
+
+
+ Timeout in seconds when activating alarm, 0 disables timeout. Default is 60 seconds
+ 60
+ true
+
+
+
+
+ Event text in ZoneMinder
+ Triggered from openHAB
+ true
+
+
+
+
+
+ Refresh priority for still images when event state is idle
+ low
+
+
+
+
+
+
+
+
+
+ Refresh priority for still images when event state is alarmed
+ normal
+
+
+
+
+
+
+
+
+
+
+
+ Rescale image from ZoneMinder Monitor
+ 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/server-config.xml b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/server-config.xml
new file mode 100644
index 0000000000000..53736e93a0655
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/server-config.xml
@@ -0,0 +1,137 @@
+
+
+
+
+ basicConfig
+
+
+
+ credentials
+
+
+
+ networkAdvConfig
+
+
+
+ refreshConfig
+
+
+
+ performanceConfig
+
+
+
+ streamingConfig
+
+ true
+
+
+
+ advancedConfig
+
+
+
+
+
+ network-address
+
+ The IP address or hostname of the ZoneMinder Server
+
+
+
+ Protocol to connect to the ZoneMinder Server API (http or https)
+ http
+
+
+
+
+
+
+
+ User to access the ZoneMinder Server API
+
+
+ password
+
+ Password to access the ZoneMinder Server API
+
+
+
+
+ Additional path on ZoneMinder Server to access ZoneMinder Portal page. In a standard installation this is' /zm'
+ /zm
+ true
+
+
+
+ Additional path on ZoneMinder Server to access API. In a standard installation this is' /zm/api'
+ /zm/api
+ true
+
+
+
+
+ Port of the ZoneMinder Server API. If '0', then the port will be determined from the protocol
+ 0
+ true
+
+
+
+ Port to listen for events in (Telnet)
+ 6802
+ true
+
+
+
+
+ Seconds between each call to ZoneMinder Server API to refresh values in openHAB
+ 10
+ true
+
+
+
+ Seconds between each call to ZoneMinder Server to refresh Server DiskUsage in ZoneMinder. Default value is '60'
+ 60
+ true
+
+
+
+
+ Refresh disk usage counter
+ disabled
+
+
+
+
+ true
+
+
+
+
+ If enabled new monitors on the ZoneMinder Server will automatically be added to the Inbox in openHAB
+ true
+ true
+
+
+
+
+ Specific streaming user
+ false
+ true
+
+
+
+
+ Optional User to access image streams
+
+
+
+
+ Optional Password for streaming user
+
+
+
+
+
\ No newline at end of file
diff --git a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/zoneminderserver.xml b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/zoneminderserver.xml
deleted file mode 100644
index 2ecfa8cc1c433..0000000000000
--- a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/config/zoneminderserver.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
-
-
- basic
-
-
-
- credentials
-
-
-
- network
-
-
-
- refreshConfig
-
-
-
- advancedSettings
-
-
-
- network-address
-
- The IP address or hostname of the ZoneMinder Server
-
-
-
- Protocol to connect to the ZoneMinder Server API (http or https)
- http
-
-
-
-
-
-
-
- Additional path on ZoneMinder Server to access API. In a standard installation this is' /zm'
- /zm
-
-
-
- User to access the ZoneMinder Server API
-
-
- password
-
- Password to access the ZoneMinder Server API
-
-
-
- Port of the ZoneMinder Server API. If '0', then the port will be determined from the protocol
- 0
- true
-
-
-
- Port to listen for events in (Telnet)
- 6802
- true
-
-
-
- Seconds between each call to ZoneMinder Server API to refresh values in openHAB
- 10
- true
-
-
-
- Minutes between each call to ZoneMinder Server to refresh Server DiskUsage in ZoneMinder. Default value is '0' (Disabled)
- 0
- true
-
-
-
- If enabled new monitors on the ZoneMinder Server will automatically be added to the Inbox in openHAB
- true
- true
-
-
-
diff --git a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/bridge-server.xml b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/bridge-server.xml
new file mode 100644
index 0000000000000..56c44a5b9c683
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/bridge-server.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+ ZoneMinder Server
+
+
+
+
+
+
+
+
+
+
+ Switch
+
+ ZoneMinder Server Online Status
+
+
+
+
+ Number
+
+ ZoneMinder Server CPU Load
+
+
+
+ Number
+
+ ZoneMinder Server Disk Usage
+
+
+
+
\ No newline at end of file
diff --git a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/monitor-thing.xml b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/monitor-thing.xml
deleted file mode 100644
index 1f44e59a69745..0000000000000
--- a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/monitor-thing.xml
+++ /dev/null
@@ -1,137 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- Camera in ZoneMinder
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Switch
-
- Switch telling if the monitor is online
-
-
-
-
- Switch
-
- Showing the value of the checkbox 'enabled' in ZoneMinder for the monitor
-
-
-
-
- Switch
-
- Will force an alarm from openHAB in ZoneMinder
-
-
-
-
-
- Switch
-
- set to 'ON' when one of the following is true: Motion detected, Signal lost, Force Alarm pressed, External Alarm. Else set to 'OFF'
-
-
-
-
- Switch
-
- set to 'ON' when either channel monitor-alarm set to 'ON', or montior function is 'Mocord' or 'Record'. Else set to 'OFF'
-
-
-
-
- String
-
- Current Monitor Status: 0=Idle, 1=Pre-alarm, 2=Alarm, 3=Alert, 4=Recording
-
-
-
-
-
-
-
-
-
-
-
-
- String
-
- Current Monitor Function: None, Monitor, Modect, Record, Mocord, Nodect
-
-
-
-
-
-
-
-
-
-
-
-
-
- String
-
- Cause of event: None, Signal, Motion, Forced Web, openHAB, Other
-
-
-
-
-
-
-
-
-
-
-
-
-
- Switch
-
- State of ZoneMinder Capture daemon for this monitor
-
-
-
-
- Switch
-
- State of ZoneMinder Analysis daemon for this monitor
-
-
-
-
- Switch
-
- State of ZoneMinder Frame daemon for this monitor
-
-
-
-
diff --git a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/server-bridge.xml b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/server-bridge.xml
deleted file mode 100644
index 4ce2511ea787e..0000000000000
--- a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/server-bridge.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
- ZoneMinder Server
-
-
-
-
-
-
-
-
-
-
- Switch
-
- ZoneMinder Server Online Status
-
-
-
-
- Number
-
- ZoneMinder Server CPU Load
-
-
-
- Number
-
- ZoneMinder Server Disk Usage
-
-
-
-
diff --git a/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/thing-monitor.xml b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/thing-monitor.xml
new file mode 100644
index 0000000000000..2525d81424059
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/ESH-INF/thing/thing-monitor.xml
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+ Camera in ZoneMinder
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Switch
+
+ Switch telling if the monitor is online
+
+
+
+
+ Switch
+
+ Showing the value of the checkbox 'enabled' in ZoneMinder for the monitor
+
+
+
+
+ Switch
+
+ Will force an alarm from openHAB in ZoneMinder
+
+
+
+
+
+ Switch
+
+ set to 'ON' when one of the following is true: Motion detected, Signal lost, Force Alarm pressed, External Alarm. Else set to 'OFF'
+
+
+
+
+ Switch
+
+ set to 'ON' when either channel monitor-alarm set to 'ON', or montior function is 'Mocord' or 'Record'. Else set to 'OFF'
+
+
+
+
+ Switch
+
+ set to 'ON' when active alarm caused by motion. Else set to 'OFF'
+
+
+
+
+ String
+
+ Current Monitor Status: 0=Idle, 1=Pre-alarm, 2=Alarm, 3=Alert, 4=Recording
+
+
+
+
+
+
+
+
+
+
+
+
+ String
+
+ Current Monitor Function: None, Monitor, Modect, Record, Mocord, Nodect
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ String
+
+ Cause of event: None, Signal, Motion, Forced Web, openHAB, Other
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Switch
+
+ State of ZoneMinder Capture daemon for this monitor
+
+
+
+
+ Switch
+
+ State of ZoneMinder Analysis daemon for this monitor
+
+
+
+
+ Switch
+
+ State of ZoneMinder Frame daemon for this monitor
+
+
+
+
+ Image
+
+ Image channel for Monitor
+
+
+
+
+ String
+
+ Video URL for Monitor
+
+
+
+
diff --git a/addons/binding/org.openhab.binding.zoneminder/META-INF/MANIFEST.MF b/addons/binding/org.openhab.binding.zoneminder/META-INF/MANIFEST.MF
index 6fa47be8643c9..53291ac5d9a75 100644
--- a/addons/binding/org.openhab.binding.zoneminder/META-INF/MANIFEST.MF
+++ b/addons/binding/org.openhab.binding.zoneminder/META-INF/MANIFEST.MF
@@ -3,10 +3,10 @@ Bundle-ClassPath:
.,
lib/gson-2.7.jar,
lib/guava-17.0.jar,
- lib/jersey-common-2.4.1.jar,
lib/javax.ws.rs-api-2.0.1.jar,
+ lib/jersey-common-2.4.1.jar,
lib/jsoup-1.10.1.jar,
- lib/zoneminder4j-0.9.7.jar
+ lib/zoneminder4j-0.9.8.jar
Bundle-ManifestVersion: 2
Bundle-Name: ZoneMinder Binding
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
@@ -18,13 +18,22 @@ Export-Package:
org.openhab.binding.zoneminder.handler
Import-Package:
com.google.common.collect,
+ com.google.gson,
javax.ws.rs.client,
javax.ws.rs.core,
org.apache.commons.lang,
- org.apache.commons.net.util,
org.eclipse.jdt.annotation;resolution:=optional,
+ org.eclipse.jetty.client,
+ org.eclipse.jetty.client.api,
+ org.eclipse.jetty.client.util,
+ org.eclipse.jetty.http,
+ org.eclipse.jetty.io,
+ org.eclipse.jetty.util,
+ org.eclipse.jetty.util.component,
+ org.eclipse.jetty.util.ssl,
org.eclipse.smarthome.config.core,
org.eclipse.smarthome.config.discovery,
+ org.eclipse.smarthome.config.discovery.inbox,
org.eclipse.smarthome.core.library.types,
org.eclipse.smarthome.core.thing,
org.eclipse.smarthome.core.thing.binding,
diff --git a/addons/binding/org.openhab.binding.zoneminder/OSGI-INF/ZoneMinderHandlerFactory.xml b/addons/binding/org.openhab.binding.zoneminder/OSGI-INF/ZoneMinderHandlerFactory.xml
index 73421dcbc315a..a1faa02e54056 100644
--- a/addons/binding/org.openhab.binding.zoneminder/OSGI-INF/ZoneMinderHandlerFactory.xml
+++ b/addons/binding/org.openhab.binding.zoneminder/OSGI-INF/ZoneMinderHandlerFactory.xml
@@ -1,20 +1,15 @@
-
-
-
-
-
-
-
+
+
+
+
diff --git a/addons/binding/org.openhab.binding.zoneminder/README.md b/addons/binding/org.openhab.binding.zoneminder/README.md
index 8886cb6dbb114..fc9f37d957f92 100644
--- a/addons/binding/org.openhab.binding.zoneminder/README.md
+++ b/addons/binding/org.openhab.binding.zoneminder/README.md
@@ -3,7 +3,7 @@
This binding offers integration to a ZoneMinder Server. It currently only offers to integrate to monitors (eg. cameras in ZoneMinder).
It also only offers access to a limited set of values, as well as a even more limited option to update values in ZoneMinder.
It requires at least ZoneMinder 1.29 with API enabled (option 'OPT_USE_API' in ZoneMinder must be enabled).
-The option 'OPT_TRIGGERS' must be anabled to allow openHAB to trip the ForceAlarm in ZoneMinder.
+The option 'OPT_TRIGGERS' must be enabled to allow openHAB to trip the ForceAlarm in ZoneMinder.
## Supported Things
@@ -31,8 +31,8 @@ When a new monitor is discovered it will appear in the Inbox.
| Channel | Type | Description |
|------------|--------|----------------------------------------------|
| online | Switch | Parameter indicating if the server is online |
-| CPU load | Text | Current CPU Load of server |
-| Disk Usage | text | Current Disk Usage on server |
+| cpu-load | Text | Current CPU Load of server |
+| disk-usage | Text | Current Disk Usage on server |
### Thing
@@ -49,15 +49,48 @@ When a new monitor is discovered it will appear in the Inbox.
| capture-daemon | Switch | Run state of ZMC Daemon |
| analysis-daemon | Switch | Run state of ZMA Daemon |
| frame-daemon | Switch | Run state of ZMF Daemon |
+| image | Image | Still image from Monitor |
+| videourl | Text | Url to video stream |
-## Manual configuration
+## Configuration
### Things configuration
+#### Bridge Configuration
+| Parameter | Optional | Description |
+|--------------------------|----------|--------------------------------------------------------------------------------------------|
+| host | | Hostname or Ip address of ZoneMinder server |
+| protocol | | Protocol used ('http' or 'https'). https can cause issues with certificates |
+| user | X | Username to login to ZoneMidner server, if authentication is enabled |
+| password | X | Password to login to ZoneMidner server, if authentication is enabled |
+| urlSite | X | Path to ZoneMinder site (Default: '/zm') |
+| urlApi | X | Path to ZoneMinder API (Default: '/zm/api') |
+| portHttp | X | Port to access ZoneMinder site. (Default: 0 (is either 80 or 443 depending on protocol)) |
+| portTelnet | X | Port to access ZoneMinder with Telnet (Default: 6802) |
+| refreshNormal | X | Refresh rate in seconds for Normal priority (Default: 10) |
+| refreshLow | X | Refresh rate in seconds for Low priority (Default: 60) |
+| diskUsageRefresh | X | Either 'batch' or 'disabled' (Default: 'disabled') |
+| autodiscover | X | Enable / Disable autodiscovery (Default: true) |
+| useSpecificUserStreaming | X | Use specific user for streaming (Default: false) |
+| streamingUser | X | If 'useSpecificUserStreaming' is true, username must be specified here |
+| streamingPassword | X | If 'useSpecificUserStreaming' is true, password must be specified here |
+
+#### Monitor Configuration
+| Parameter | Optional | Description |
+|--------------------------|----------|-----------------------------------------------------------------------------------------------|
+| id | | Id of the monitor. Must match id in ZoneMinder |
+| triggerTimeout | x | Timeout in seconds of events generated from openHAB (Default: 60) |
+| eventText | X | Event text of openHAB trigegred events (Default: 'Triggered from openHAB') |
+| imageRefreshIdle | X | Refresh rate of image when monitor has no active event (normal, low, disabled) (Default: low) |
+| imageRefreshEvent | X | Refresh rate when active event (alarm, normal, low, disabled), (Default: alarm) |
+| imageScale | X | Size (scale) of image. Default: 100 |
+
+
+### Things file
```
-Bridge zoneminder:server:ZoneMinderSample [ hostname="192.168.1.55", user="", password="", telnet_port=6802, refresh_interval_disk_usage=1 ]
+Bridge zoneminder:server:ZoneMinderSample [ host="192.168.1.55", protocol="http", user="", password="", autodiscover=false, useSpecificUserStreaming=true, streamingUser="", streamingPassword="" ]
{
- Thing monitor monitor_1 [ monitorId=1, monitorTriggerTimeout=120, monitorEventText="Trigger activated from openHAB" ]
+ Thing monitor monitor_1 [ monitorId=1, monitorTriggerTimeout=120, monitorEventText="Trigger activated from openHAB", imageRefreshIdle="disabled", imageRefreshEvent="alarm" ]
}
```
diff --git a/addons/binding/org.openhab.binding.zoneminder/build.properties b/addons/binding/org.openhab.binding.zoneminder/build.properties
index 147def4630562..6b9bd7b2cc28a 100644
--- a/addons/binding/org.openhab.binding.zoneminder/build.properties
+++ b/addons/binding/org.openhab.binding.zoneminder/build.properties
@@ -7,3 +7,4 @@ bin.includes = META-INF/,\
lib/,\
about.html
+
diff --git a/addons/binding/org.openhab.binding.zoneminder/lib/zoneminder4j-0.9.7.jar b/addons/binding/org.openhab.binding.zoneminder/lib/zoneminder4j-0.9.7.jar
deleted file mode 100644
index 5f202659325c0..0000000000000
Binary files a/addons/binding/org.openhab.binding.zoneminder/lib/zoneminder4j-0.9.7.jar and /dev/null differ
diff --git a/addons/binding/org.openhab.binding.zoneminder/lib/zoneminder4j-0.9.8.jar b/addons/binding/org.openhab.binding.zoneminder/lib/zoneminder4j-0.9.8.jar
new file mode 100644
index 0000000000000..5343a3a5fd5b7
Binary files /dev/null and b/addons/binding/org.openhab.binding.zoneminder/lib/zoneminder4j-0.9.8.jar differ
diff --git a/addons/binding/org.openhab.binding.zoneminder/out.txt b/addons/binding/org.openhab.binding.zoneminder/out.txt
new file mode 100644
index 0000000000000..ad412d4c5f5c4
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/out.txt
@@ -0,0 +1,300 @@
+[INFO] Scanning for projects...
+Downloading: https://openhab.jfrog.io/openhab/libs-snapshot/org/openhab/pom-tycho/2.3.0-SNAPSHOT/maven-metadata.xml
+599/599 B
Downloaded: https://openhab.jfrog.io/openhab/libs-snapshot/org/openhab/pom-tycho/2.3.0-SNAPSHOT/maven-metadata.xml (599 B at 0.7 KB/sec)
+[WARNING] Could not transfer metadata org.openhab:pom-tycho:2.3.0-SNAPSHOT/maven-metadata.xml from/to p2-smarthome-snapshot (https://openhab.jfrog.io/openhab/eclipse-smarthome-stable): Cannot access https://openhab.jfrog.io/openhab/eclipse-smarthome-stable with type p2 using the available connector factories: BasicRepositoryConnectorFactory
+[WARNING] Could not transfer metadata org.openhab:pom-tycho:2.3.0-SNAPSHOT/maven-metadata.xml from/to p2-openhab-deps-repo (https://dl.bintray.com/openhab/p2/openhab-deps-repo/${ohdr.version}): Cannot access https://dl.bintray.com/openhab/p2/openhab-deps-repo/${ohdr.version} with type p2 using the available connector factories: BasicRepositoryConnectorFactory
+Downloading: https://openhab.jfrog.io/openhab/libs-snapshot/org/openhab/pom/2.3.0-SNAPSHOT/maven-metadata.xml
+593/593 B
Downloaded: https://openhab.jfrog.io/openhab/libs-snapshot/org/openhab/pom/2.3.0-SNAPSHOT/maven-metadata.xml (593 B at 2.2 KB/sec)
+[WARNING] Could not transfer metadata org.openhab:pom:2.3.0-SNAPSHOT/maven-metadata.xml from/to p2-smarthome-snapshot (https://openhab.jfrog.io/openhab/eclipse-smarthome-stable): Cannot access https://openhab.jfrog.io/openhab/eclipse-smarthome-stable with type p2 using the available connector factories: BasicRepositoryConnectorFactory
+[WARNING] Could not transfer metadata org.openhab:pom:2.3.0-SNAPSHOT/maven-metadata.xml from/to p2-openhab-deps-repo (https://dl.bintray.com/openhab/p2/openhab-deps-repo/${ohdr.version}): Cannot access https://dl.bintray.com/openhab/p2/openhab-deps-repo/${ohdr.version} with type p2 using the available connector factories: BasicRepositoryConnectorFactory
+[INFO] Computing target platform for MavenProject: org.openhab.binding:org.openhab.binding.zoneminder:2.3.0-SNAPSHOT @ D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\pom.xml
+[INFO] Fetching p2.index from https://openhab.jfrog.io/openhab/eclipse-smarthome-stable/ (172B)
+[INFO] Fetching p2.index from https://openhab.jfrog.io/openhab/eclipse-smarthome-stable/ (172B)
+[INFO] Adding repository https://openhab.jfrog.io/openhab/eclipse-smarthome-stable
+[INFO] Fetching p2.index from http://download.eclipse.org/smarthome/updates-release/0.9.0/
+[INFO] Fetching p2.index from http://download.eclipse.org/smarthome/updates-release/0.9.0/
+[INFO] Adding repository http://download.eclipse.org/smarthome/updates-release/0.9.0
+[INFO] Fetching p2.index from https://dl.bintray.com/openhab/p2/openhab-deps-repo/1.0.19/ (172B)
+[INFO] Fetching p2.index from https://dl.bintray.com/openhab/p2/openhab-deps-repo/1.0.19/ (172B)
+[INFO] Adding repository https://dl.bintray.com/openhab/p2/openhab-deps-repo/1.0.19
+[INFO] Resolving dependencies of MavenProject: org.openhab.binding:org.openhab.binding.zoneminder:2.3.0-SNAPSHOT @ D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\pom.xml
+[INFO] Resolving class path of MavenProject: org.openhab.binding:org.openhab.binding.zoneminder:2.3.0-SNAPSHOT @ D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\pom.xml
+[INFO]
+[INFO] ------------------------------------------------------------------------
+[INFO] Building ZoneMinder Binding 2.3.0-SNAPSHOT
+[INFO] ------------------------------------------------------------------------
+[INFO]
+[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ org.openhab.binding.zoneminder ---
+[INFO] Deleting D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\target
+[INFO]
+[INFO] --- tycho-packaging-plugin:1.0.0:build-qualifier (default-build-qualifier) @ org.openhab.binding.zoneminder ---
+[INFO] The project's OSGi version is 2.3.0.201802031407
+[INFO]
+[INFO] --- tycho-packaging-plugin:1.0.0:validate-id (default-validate-id) @ org.openhab.binding.zoneminder ---
+[INFO]
+[INFO] --- tycho-packaging-plugin:1.0.0:validate-version (default-validate-version) @ org.openhab.binding.zoneminder ---
+[INFO]
+[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ org.openhab.binding.zoneminder ---
+[INFO] Using 'UTF-8' encoding to copy filtered resources.
+[INFO] skip non existing resourceDirectory D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\resources
+[INFO]
+[INFO] --- tycho-compiler-plugin:1.0.0:compile (default-compile) @ org.openhab.binding.zoneminder ---
+[WARNING] Parameter 'useProjectSettings' is set to true, but preferences file 'D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\.settings\org.eclipse.jdt.core.prefs' could not be found!
+[INFO] Compiling 25 source files to D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\target\classes
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderBaseThingHandler.java:[215]
+ Channel ch = thing.getChannel(id);
+ ^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderBaseThingHandler.java:[216]
+ return ch.getUID();
+ ^^
+Potential null pointer access: The variable ch may be null at this location
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderBaseThingHandler.java:[332]
+ updateState(channel, getChannelBoolAsOnOffState(isOnline()));
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'State' needs unchecked conversion to conform to '@NonNull State'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderBaseThingHandler.java:[493]
+ updateStatus(thingStatus, statusDetail, statusDescription);
+ ^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'ThingStatusDetail' needs unchecked conversion to conform to '@NonNull ThingStatusDetail'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderBaseThingHandler.java:[497]
+ updateStatus(thingStatus);
+ ^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'ThingStatus' needs unchecked conversion to conform to '@NonNull ThingStatus'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\internal\discovery\ZoneMinderDiscoveryService.java:[62]
+ return ZoneMinderThingMonitorHandler.SUPPORTED_THING_TYPES;
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'Set' needs unchecked conversion to conform to '@NonNull Set'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\internal\discovery\ZoneMinderDiscoveryService.java:[101]
+ return serverHandler.getThingByUID(newThingUID) != null ? true : false;
+ ^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'ThingUID' needs unchecked conversion to conform to '@NonNull ThingUID'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\internal\discovery\ZoneMinderDiscoveryService.java:[129]
+ DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
+ ^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'Map' needs unchecked conversion to conform to '@Nullable Map<@NonNull String,@NonNull Object>'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[507]
+ Channel channel = this.getThing().getChannel(ZoneMinderConstants.CHANNEL_MONITOR_DETAILED_STATUS);
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[508]
+ Channel chEventCause = this.getThing().getChannel(ZoneMinderConstants.CHANNEL_MONITOR_EVENT_CAUSE);
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[640]
+ getLogIdentifier(), thing.getUID(), getBridge().getBridgeUID());
+ ^^^^^^^^^^^
+Potential null pointer access: The method getBridge() may return null
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[644]
+ if (getBridge().getStatus() != ThingStatus.ONLINE) {
+ ^^^^^^^^^^^
+Potential null pointer access: The method getBridge() may return null
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[645]
+ msg = String.format("Bridge '%s' is OFFLINE", getBridge().getBridgeUID());
+ ^^^^^^^^^^^
+Potential null pointer access: The method getBridge() may return null
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[654]
+ getLogIdentifier(), getBridge().getBridgeUID());
+ ^^^^^^^^^^^
+Potential null pointer access: The method getBridge() may return null
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[802]
+ updateState(channel.getId(), state);
+ ^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[806]
+ getLogIdentifier(), channel.toString(), state.toString(), ex.getMessage());
+ ^^^^^
+Potential null pointer access: The variable state may be null at this location
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[813]
+ updateState(ZoneMinderConstants.CHANNEL_ONLINE,
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[845]
+ session = null;
+ ^^^^^^^
+Redundant assignment: The variable session can only be null at this location
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[920]
+ if (isLinked(ZoneMinderConstants.CHANNEL_MONITOR_CAPTURE_DAEMON_STATE)) {
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[939]
+ if (isLinked(ZoneMinderConstants.CHANNEL_MONITOR_ANALYSIS_DAEMON_STATE)) {
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[961]
+ if (isLinked(ZoneMinderConstants.CHANNEL_MONITOR_FRAME_DAEMON_STATE)) {
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[981]
+ if (isLinked(ZoneMinderConstants.CHANNEL_MONITOR_STILL_IMAGE)) {
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[1044]
+ if (session != null) {
+ ^^^^^^^
+Redundant null check: The variable session cannot be null at this location
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[1124]
+ updateProperties(properties);
+ ^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'Map' needs unchecked conversion to conform to '@NonNull Map<@NonNull String,@NonNull String>'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingMonitorHandler.java:[1148]
+ updateState(channelUID.getId(), state);
+ ^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\ZoneMinderConstants.java:[42]
+ public static final ThingTypeUID THING_TYPE_BRIDGE_ZONEMINDER_SERVER = new ThingTypeUID(BINDING_ID,
+ ^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\ZoneMinderConstants.java:[43]
+ BRIDGE_ZONEMINDER_SERVER);
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\ZoneMinderConstants.java:[89]
+ public static final ThingTypeUID THING_TYPE_THING_ZONEMINDER_MONITOR = new ThingTypeUID(BINDING_ID,
+ ^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\ZoneMinderConstants.java:[90]
+ THING_ZONEMINDER_MONITOR);
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\ZoneMinderConstants.java:[128]
+ public static final ThingTypeUID THING_TYPE_THING_ZONEMINDER_PTZCONTROL = new ThingTypeUID(BINDING_ID,
+ ^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\ZoneMinderConstants.java:[129]
+ THING_ZONEMINDER_PTZCONTROL);
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderThingPTZControlHandler.java:[78]
+ Channel channel = ChannelBuilder.create(new ChannelUID(channelIdString), "String").withDescription(description)
+ ^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderServerBridgeHandler.java:[314]
+ super.handleConfigurationUpdate(configurationParameters);
+ ^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type '@NonNull Map' needs unchecked conversion to conform to '@NonNull Map<@NonNull String,@NonNull Object>'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderServerBridgeHandler.java:[407]
+ if ((thingHandler.getZoneMinderId().equals(zoneMinderId))
+ ^^^^^^^^^^^^
+Potential null pointer access: The variable thingHandler may be null at this location
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderServerBridgeHandler.java:[495]
+ } else if (hostLoad.getHttpStatus() != HttpStatus.OK_200) {
+ ^^^^^^^^
+Potential null pointer access: The variable hostLoad may be null at this location
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderServerBridgeHandler.java:[529]
+ if (isLinked(channel.getUID().getId())) {
+ ^^^^^^^^^^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderServerBridgeHandler.java:[544]
+ thingHandler.refreshThing(curPriority);
+ ^^^^^^^^^^^^
+Potential null pointer access: The variable thingHandler may be null at this location
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderServerBridgeHandler.java:[1057]
+ curSession = null;
+ ^^^^^^^^^^
+Redundant assignment: The variable curSession can only be null at this location
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderServerBridgeHandler.java:[1476]
+ updateStatus(newStatus, statusDetail, statusDescription);
+ ^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'ThingStatusDetail' needs unchecked conversion to conform to '@NonNull ThingStatusDetail'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderServerBridgeHandler.java:[1484]
+ updateStatus(newStatus);
+ ^^^^^^^^^
+Null type safety (type annotations): The expression of type 'ThingStatus' needs unchecked conversion to conform to '@NonNull ThingStatus'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderServerBridgeHandler.java:[1542]
+ updateState(channel.getId(), state);
+ ^^^^^^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'String' needs unchecked conversion to conform to '@NonNull String'
+[WARNING] D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\main\java\org\openhab\binding\zoneminder\handler\ZoneMinderServerBridgeHandler.java:[1874]
+ updateProperties(properties);
+ ^^^^^^^^^^
+Null type safety (type annotations): The expression of type 'Map' needs unchecked conversion to conform to '@NonNull Map<@NonNull String,@NonNull String>'
+42 problems (42 warnings)
+[INFO]
+[INFO] --- maven-compiler-plugin:3.6.1:compile (default) @ org.openhab.binding.zoneminder ---
+[INFO] Changes detected - recompiling the module!
+[INFO] Nothing to compile - all classes are up to date
+[INFO]
+[INFO] --- maven-scr-plugin:1.24.0:scr (generate-scr-scrdescriptor) @ org.openhab.binding.zoneminder ---
+[INFO]
+[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ org.openhab.binding.zoneminder ---
+[INFO] Using 'UTF-8' encoding to copy filtered resources.
+[INFO] skip non existing resourceDirectory D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\src\test\resources
+[INFO]
+[INFO] --- target-platform-configuration:1.0.0:target-platform (default-target-platform) @ org.openhab.binding.zoneminder ---
+[INFO]
+[INFO] --- tycho-packaging-plugin:1.0.0:package-plugin (default-package-plugin) @ org.openhab.binding.zoneminder ---
+[INFO] Building jar: D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\target\org.openhab.binding.zoneminder-2.3.0-SNAPSHOT.jar
+[INFO]
+[INFO] --- tycho-p2-plugin:1.0.0:p2-metadata-default (default-p2-metadata-default) @ org.openhab.binding.zoneminder ---
+[INFO]
+[INFO] --- sat-plugin:0.4.1:checkstyle (default) @ org.openhab.binding.zoneminder ---
+[INFO] Adding dependency to checkstyle:0.4.1
+[INFO] Adding dependency to checkstyle:8.1
+[INFO] There is 1 error reported by Checkstyle 8.1 with jar:file:/C:/Users/Martin.KAERVEJ/.m2/repository/org/openhab/tools/sat/sat-plugin/0.4.1/sat-plugin-0.4.1.jar!/rulesets/checkstyle/rules.xml ruleset.
+[INFO]
+[INFO] --- sat-plugin:0.4.1:pmd (default) @ org.openhab.binding.zoneminder ---
+[INFO] Adding dependency to pmd:0.4.1
+[INFO] Adding dependency to pmd-core:5.8.1
+[INFO] Adding dependency to pmd-java:5.8.1
+[INFO] Adding dependency to pmd-javascript:5.8.1
+[INFO] Adding dependency to pmd-jsp:5.8.1
+[INFO]
+[INFO] --- sat-plugin:0.4.1:findbugs (default) @ org.openhab.binding.zoneminder ---
+[INFO] Adding dependency to findbugs:0.4.1
+[INFO] Adding dependency to bug-pattern:1.2.4
+[INFO] Adding dependency to spotbugs:3.1.0
+[INFO] Fork Value is false
+ [java] JVM args ignored when same JVM is used.
+[INFO] Done FindBugs Analysis....
+[INFO]
+[INFO] --- sat-plugin:0.4.1:report (default) @ org.openhab.binding.zoneminder ---
+[INFO] Individual report appended to summary report.
+[ERROR] Code Analysis Tool has found:
+ 1 error(s)!
+ 12 warning(s)
+ 214 info(s)
+[WARNING] .binding.zoneminder\ESH-INF\binding\binding.xml:[3]
+There were whitespace characters used for indentation. Please use tab characters instead
+[WARNING] .binding.zoneminder\ESH-INF\config\monitor-config.xml:[3]
+There were whitespace characters used for indentation. Please use tab characters instead
+[WARNING] .binding.zoneminder\ESH-INF\config\server-config.xml:[3]
+There were whitespace characters used for indentation. Please use tab characters instead
+[WARNING] .binding.zoneminder\ESH-INF\thing\bridge-server.xml:[3]
+There were whitespace characters used for indentation. Please use tab characters instead
+[WARNING] .binding.zoneminder\ESH-INF\thing\thing-monitor.xml:[3]
+There were whitespace characters used for indentation. Please use tab characters instead
+[ERROR] .binding.zoneminder\META-INF\MANIFEST.MF:[0]
+The jar file lib/javax.ws.rs-api-2.0.1.jar is present in the lib folder but is not present in the MANIFEST.MF file
+[WARNING] .binding.zoneminder\OSGI-INF\ZoneMinderHandlerFactory.xml:[3]
+There were whitespace characters used for indentation. Please use tab characters instead
+[WARNING] .binding.zoneminder\pom.xml:[2]
+There were whitespace characters used for indentation. Please use tab characters instead
+[WARNING] org.openhab.binding.zoneminder.handler.ZoneMinderServerBridgeHandler.java:[254]
+Avoid catching NullPointerException; consider removing the cause of the NPE.
+[WARNING] org.openhab.binding.zoneminder.handler.ZoneMinderServerBridgeHandler.java:[547]
+Avoid catching NullPointerException; consider removing the cause of the NPE.
+[WARNING] org.openhab.binding.zoneminder.handler.ZoneMinderServerBridgeHandler.java:[937]
+Avoid catching NullPointerException; consider removing the cause of the NPE.
+[WARNING] org.openhab.binding.zoneminder.handler.ZoneMinderServerBridgeHandler.java:[1042]
+Avoid catching NullPointerException; consider removing the cause of the NPE.
+[WARNING] org.openhab.binding.zoneminder.handler.ZoneMinderServerBridgeHandler.java:[1161]
+Avoid catching NullPointerException; consider removing the cause of the NPE.
+[INFO] Detailed report can be found at: file:///D:\Development\openHAB\zoneminder\openhab2-zoneminder\git\openhab2-addons\addons\binding\org.openhab.binding.zoneminder\target\code-analysis\report.html
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD FAILURE
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 29.567 s
+[INFO] Finished at: 2018-02-03T15:07:41+01:00
+[INFO] Final Memory: 62M/711M
+[INFO] ------------------------------------------------------------------------
+[ERROR] Failed to execute goal org.openhab.tools.sat:sat-plugin:0.4.1:report (default) on project org.openhab.binding.zoneminder:
+[ERROR] Code Analysis Tool has found 1 error(s)!
+[ERROR] Please fix the errors and rerun the build.
+[ERROR] -> [Help 1]
+[ERROR]
+[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
+[ERROR] Re-run Maven using the -X switch to enable full debug logging.
+[ERROR]
+[ERROR] For more information about the errors and possible solutions, please read the following articles:
+[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
diff --git a/addons/binding/org.openhab.binding.zoneminder/pom.xml b/addons/binding/org.openhab.binding.zoneminder/pom.xml
index 7ebb2c65ac7a9..e9c7c067ff16c 100644
--- a/addons/binding/org.openhab.binding.zoneminder/pom.xml
+++ b/addons/binding/org.openhab.binding.zoneminder/pom.xml
@@ -15,3 +15,4 @@
ZoneMinder Binding
+
\ No newline at end of file
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/ZoneMinderConstants.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/ZoneMinderConstants.java
index 471b2b81f64a6..9c538f4564d65 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/ZoneMinderConstants.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/ZoneMinderConstants.java
@@ -8,7 +8,7 @@
*/
package org.openhab.binding.zoneminder;
-import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
/**
@@ -17,21 +17,28 @@
*
* @author Martin S. Eskildsen - Initial contribution
*/
-@NonNullByDefault
public class ZoneMinderConstants {
+ @NonNull
public static final String BINDING_ID = "zoneminder";
// ZoneMinder Server Bridge
+ @NonNull
public static final String BRIDGE_ZONEMINDER_SERVER = "server";
// ZoneMinder Monitor thing
+ @NonNull
public static final String THING_ZONEMINDER_MONITOR = "monitor";
+ // ZoneMinder PTZControl thing
+ @NonNull
+ public static final String THING_ZONEMINDER_PTZCONTROL = "ptzcontrol";
// ZoneMinder Server displayable name
+ @NonNull
public static final String ZONEMINDER_SERVER_NAME = "ZoneMinder Server";
// ZoneMinder Monitor displayable name
+ @NonNull
public static final String ZONEMINDER_MONITOR_NAME = "ZoneMinder Monitor";
/*
@@ -39,10 +46,12 @@ public class ZoneMinderConstants {
*/
// Thing Type UID for Server
+ @NonNull
public static final ThingTypeUID THING_TYPE_BRIDGE_ZONEMINDER_SERVER = new ThingTypeUID(BINDING_ID,
BRIDGE_ZONEMINDER_SERVER);
// Shared channel for all bridges / things
+ @NonNull
public static final String CHANNEL_ONLINE = "online";
// Channel Id's for the ZoneMinder Server
@@ -50,13 +59,52 @@ public class ZoneMinderConstants {
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";
+ @NonNull
+ public static final String PARAM_PROTOCOL = "protocol";
+ @NonNull
+ public static final String PARAM_HOST = "host";
+ @NonNull
+ public static final String PARAM_HTTP_PORT = "portHttp";
+ @NonNull
+ public static final String PARAM_TELNET_PORT = "portTelnet";
+
+ @NonNull
+ public static final String PARAM_USER = "user";
+ @NonNull
+ public static final String PARAM_URL_PASSWORD = "password";
+
+ @NonNull
+ public static final String PARAM_URL_SITE = "urlSite";
+ @NonNull
+ public static final String PARAM_URL_API = "urlApi";
+
+ @NonNull
+ public static final String PARAM_REFRESH_DISKUSAGE = "diskUsageRefresh";
+
+ @NonNull
+ public static final String PARAM_REFRESH_NORMAL = "refreshNormal";
+ @NonNull
+ public static final String PARAM_REFRESH_LOW = "refreshLow";
+ @NonNull
+ public static final String PARAM_AUTODICOVER = "autodiscover";
+
+ @NonNull
+ public static final String CONFIG_VALUE_REFRESH_BATCH = "batch";
+ @NonNull
+ public static final String CONFIG_VALUE_REFRESH_LOW = "low";
+ @NonNull
+ public static final String CONFIG_VALUE_REFRESH_NORMAL = "normal";
+ @NonNull
+ public static final String CONFIG_VALUE_REFRESH_HIGH = "high";
+ @NonNull
+ public static final String CONFIG_VALUE_REFRESH_ALARM = "alarm";
+ @NonNull
+ public static final String CONFIG_VALUE_REFRESH_DISABLED = "disabled";
// Default values for Monitor parameters
+ @NonNull
public static final Integer DEFAULT_HTTP_PORT = 80;
+ @NonNull
public static final Integer DEFAULT_TELNET_PORT = 6802;
/*
@@ -64,38 +112,76 @@ public class ZoneMinderConstants {
*/
// Thing Type UID for Monitor
+ @NonNull
public static final ThingTypeUID THING_TYPE_THING_ZONEMINDER_MONITOR = new ThingTypeUID(BINDING_ID,
THING_ZONEMINDER_MONITOR);
/*
* Channel Id's for the ZoneMinder Monitor
*/
+ @NonNull
public static final String CHANNEL_MONITOR_ENABLED = "enabled";
+ @NonNull
public static final String CHANNEL_MONITOR_FORCE_ALARM = "force-alarm";
+ @NonNull
public static final String CHANNEL_MONITOR_EVENT_STATE = "alarm";
+ @NonNull
public static final String CHANNEL_MONITOR_EVENT_CAUSE = "event-cause";
+ @NonNull
public static final String CHANNEL_MONITOR_RECORD_STATE = "recording";
+ @NonNull
+ public static final String CHANNEL_MONITOR_MOTION_EVENT = "motion-event";
+ @NonNull
public static final String CHANNEL_MONITOR_DETAILED_STATUS = "detailed-status";
+ @NonNull
public static final String CHANNEL_MONITOR_FUNCTION = "function";
+ @NonNull
public static final String CHANNEL_MONITOR_CAPTURE_DAEMON_STATE = "capture-daemon";
+ @NonNull
public static final String CHANNEL_MONITOR_ANALYSIS_DAEMON_STATE = "analysis-daemon";
+ @NonNull
public static final String CHANNEL_MONITOR_FRAME_DAEMON_STATE = "frame-daemon";
+ @NonNull
+ public static final String CHANNEL_MONITOR_STILL_IMAGE = "image";
+ @NonNull
+ public static final String CHANNEL_MONITOR_VIDEOURL = "videourl";
// 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";
+ @NonNull
+ public static final String PARAMETER_MONITOR_ID = "id";
+ @NonNull
+ public static final String PARAMETER_MONITOR_TRIGGER_TIMEOUT = "triggerTimeout";
+ @NonNull
+ public static final String PARAMETER_MONITOR_EVENTTEXT = "eventText";
+ @NonNull
+ public static final String PARAMETER_MONITOR_IMAGE_REFRESH = "imageRefresh";
// Default values for Monitor parameters
+ @NonNull
public static final Integer PARAMETER_MONITOR_TRIGGER_TIMEOUT_DEFAULTVALUE = 60;
public static final String PARAMETER_MONITOR_EVENTNOTE_DEFAULTVALUE = "openHAB triggered event";
// ZoneMinder Event types
+ @NonNull
public static final String MONITOR_EVENT_NONE = "";
+ @NonNull
public static final String MONITOR_EVENT_SIGNAL = "Signal";
+ @NonNull
public static final String MONITOR_EVENT_MOTION = "Motion";
+ @NonNull
public static final String MONITOR_EVENT_FORCED_WEB = "Forced Web";
+ @NonNull
public static final String MONITOR_EVENT_OPENHAB = "openHAB";
+ // Thing Type UID for PTZ Control
+ @NonNull
+ public static final ThingTypeUID THING_TYPE_THING_ZONEMINDER_PTZCONTROL = new ThingTypeUID(BINDING_ID,
+ THING_ZONEMINDER_PTZCONTROL);
+ /*
+ * Dyncamic Channel Id's for the ZoneMinder PTZ Control
+ */
+ @NonNull
+ public static final String CHANNEL_PTZCONTROL_PRESET = "Presets";
+
}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/ZoneMinderProperties.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/ZoneMinderProperties.java
index 0122921f5dc3e..2e8267b50d25a 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/ZoneMinderProperties.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/ZoneMinderProperties.java
@@ -14,14 +14,16 @@
*/
public class ZoneMinderProperties {
public static final String PROPERTY_ID = "Id";
+ public static final String PROPERTY_NAME = "Name";
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_USE_AUTH_HASH = "Allow Auth. Hash";
public static final String PROPERTY_SERVER_TRIGGERS_ENABLED = "Triggers enabled";
+ public static final String PROPERTY_SERVER_FRAME_SERVER = "Use Frame Server";
- 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";
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderHandler.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/IZoneMinderHandler.java
similarity index 79%
rename from addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderHandler.java
rename to addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/IZoneMinderHandler.java
index 19cbceea5762c..96b1ac5b7557d 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderHandler.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/IZoneMinderHandler.java
@@ -13,15 +13,15 @@
import org.eclipse.smarthome.core.thing.ChannelUID;
-import name.eskildsen.zoneminder.IZoneMinderConnectionInfo;
+import name.eskildsen.zoneminder.IZoneMinderConnectionHandler;
import name.eskildsen.zoneminder.exception.ZoneMinderUrlNotFoundException;
/**
* Interface for ZoneMinder handlers.
*
- * @author Martin S. Eskildsen
+ * @author Martin S. Eskildsen - Initial contribution
*/
-public interface ZoneMinderHandler {
+public interface IZoneMinderHandler {
String getZoneMinderId();
@@ -30,11 +30,11 @@ public interface ZoneMinderHandler {
*/
String getLogIdentifier();
- void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection);
+ void updateAvaliabilityStatus(IZoneMinderConnectionHandler connection);
void updateChannel(ChannelUID channel);
- void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionInfo connection)
+ void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionHandler connection)
throws IllegalArgumentException, GeneralSecurityException, IOException, ZoneMinderUrlNotFoundException;
void onBridgeDisconnected(ZoneMinderServerBridgeHandler bridge);
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderBaseThingHandler.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderBaseThingHandler.java
index ce049f2c8798c..01a1afb5463a0 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderBaseThingHandler.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderBaseThingHandler.java
@@ -8,13 +8,12 @@
*/
package org.openhab.binding.zoneminder.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.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.StringType;
import org.eclipse.smarthome.core.thing.Bridge;
@@ -30,15 +29,12 @@
import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.UnDefType;
import org.openhab.binding.zoneminder.ZoneMinderConstants;
-import org.openhab.binding.zoneminder.internal.DataRefreshPriorityEnum;
+import org.openhab.binding.zoneminder.internal.RefreshPriority;
import org.openhab.binding.zoneminder.internal.config.ZoneMinderThingConfig;
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;
+import name.eskildsen.zoneminder.IZoneMinderConnectionHandler;
/**
* The {@link ZoneMinderBaseThingHandler} is responsible for handling commands, which are
@@ -46,46 +42,43 @@
*
* @author Martin S. Eskildsen - Initial contribution
*/
-public abstract class ZoneMinderBaseThingHandler extends BaseThingHandler implements ZoneMinderHandler {
+public abstract class ZoneMinderBaseThingHandler extends BaseThingHandler implements IZoneMinderHandler {
+ // https://www.eclipse.org/smarthome/documentation/development/bindings/thing-handler.html
+ private final ReentrantLock lockRefresh = new ReentrantLock();
+ private final ReentrantLock lockAlarm = new ReentrantLock();
/** Logger for the Thing. */
private Logger logger = LoggerFactory.getLogger(ZoneMinderBaseThingHandler.class);
/** Bridge Handler for the Thing. */
- public ZoneMinderServerBridgeHandler zoneMinderBridgeHandler = null;
+ public ZoneMinderServerBridgeHandler zoneMinderBridgeHandler;
/** This refresh status. */
- private boolean thingRefreshed = false;
+ private AtomicInteger thingRefresh = new AtomicInteger(1);
- /** Unique Id of the thing in zoneminder. */
- private String zoneMinderId;
+ private long alarmTimeoutTimestamp = 0;
- /** ZoneMidner ConnectionInfo */
- private IZoneMinderConnectionInfo zoneMinderConnection = null;
-
- private Lock lockSession = new ReentrantLock();
- private IZoneMinderSession zoneMinderSession = null;
+ /** ZoneMinder ConnectionHandler */
+ private IZoneMinderConnectionHandler zoneMinderConnection;
/** Configuration from openHAB */
protected ZoneMinderThingConfig configuration;
- private DataRefreshPriorityEnum _refreshPriority = DataRefreshPriorityEnum.SCHEDULED;
-
- protected boolean isOnline() {
+ private RefreshPriority refreshPriority = RefreshPriority.PRIORITY_NORMAL;
- if (zoneMinderSession == null) {
- return false;
- }
-
- if (!zoneMinderSession.isConnected()) {
- return false;
+ protected boolean isThingOnline() {
+ try {
+ if ((thing.getStatus() == ThingStatus.ONLINE) && getZoneMinderBridgeHandler().isOnline()) {
+ return true;
+ }
+ } catch (Exception ex) {
+ logger.error("{}: context='isThingOnline' Exception occurred", getLogIdentifier(), ex);
}
-
- return true;
+ return false;
}
- public DataRefreshPriorityEnum getRefreshPriority() {
- return _refreshPriority;
+ public RefreshPriority getThingRefreshPriority() {
+ return refreshPriority;
}
public ZoneMinderBaseThingHandler(Thing thing) {
@@ -100,104 +93,179 @@ public ZoneMinderBaseThingHandler(Thing thing) {
*/
@Override
public void initialize() {
-
- updateStatus(ThingStatus.ONLINE);
- try {
-
- } catch (Exception ex) {
- logger.error("{}: BridgeHandler failed to initialize. Exception='{}'", getLogIdentifier(), ex.getMessage());
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR);
- } finally {
- }
+ updateStatus(ThingStatus.OFFLINE);
}
protected boolean isConnected() {
- if (zoneMinderSession == null) {
+ if ((getThing().getStatus() != ThingStatus.ONLINE) || (zoneMinderConnection == null)
+ || (getZoneMinderBridgeHandler() == null)) {
return false;
}
- return zoneMinderSession.isConnected();
+ return getZoneMinderBridgeHandler().isConnected();
+ }
+
+ protected IZoneMinderConnectionHandler aquireSession() {
+ return aquireSessionInternal(false);
}
- protected IZoneMinderSession aquireSession() {
- lockSession.lock();
- return zoneMinderSession;
+ protected IZoneMinderConnectionHandler aquireSessionWait() {
+ return aquireSessionInternal(false);
+ }
+
+ private IZoneMinderConnectionHandler aquireSessionInternal(boolean timeout) {
+ boolean result = true;
+ if (result) {
+ return zoneMinderConnection;
+ }
+
+ return null;
}
protected void releaseSession() {
- lockSession.unlock();
+ // lockSession.unlock();
+ }
+
+ protected boolean forceStartAlarmRefresh() {
+ lockAlarm.lock();
+ try {
+ if (refreshPriority != RefreshPriority.PRIORITY_ALARM) {
+ logger.debug("{}: context='startAlarmRefresh' Starting ALARM refresh...", getLogIdentifier());
+ refreshPriority = RefreshPriority.PRIORITY_ALARM;
+
+ // If already activated and called again, it is the event from ZoneMidner that was triggered from
+ // openHAB
+ alarmTimeoutTimestamp = -1;
+ }
+ } finally {
+ lockAlarm.unlock();
+ }
+ return true;
}
/**
* Method to start a priority data refresh task.
*/
- protected boolean startPriorityRefresh() {
-
- logger.info("[MONITOR-{}]: Starting High Priority Refresh", getZoneMinderId());
- _refreshPriority = DataRefreshPriorityEnum.HIGH_PRIORITY;
+ protected boolean startAlarmRefresh(long timeout) {
+ lockAlarm.lock();
+ try {
+ if (refreshPriority != RefreshPriority.PRIORITY_ALARM) {
+ logger.debug("{}: context='startAlarmRefresh' Starting ALARM refresh...", getLogIdentifier());
+ refreshPriority = RefreshPriority.PRIORITY_ALARM;
+ alarmTimeoutTimestamp = System.currentTimeMillis() + timeout * 1000;
+ }
+ } finally {
+ lockAlarm.unlock();
+ }
return true;
}
+ protected void tryStopAlarmRefresh() {
+ lockAlarm.lock();
+ try {
+ if ((alarmTimeoutTimestamp == -1) || (refreshPriority != RefreshPriority.PRIORITY_ALARM)) {
+ return;
+ }
+ if (alarmTimeoutTimestamp < System.currentTimeMillis()) {
+ logger.debug("{}: context='tryStopAlarmRefresh' - Alarm refresh timed out - stopping alarm refresh ...",
+ getLogIdentifier());
+ refreshPriority = RefreshPriority.PRIORITY_NORMAL;
+
+ alarmTimeoutTimestamp = 0;
+ }
+ } finally {
+ lockAlarm.unlock();
+ }
+ }
+
/**
* Method to stop the data Refresh task.
*/
- protected void stopPriorityRefresh() {
- logger.info("{}: Stopping Priority Refresh for Monitor", getLogIdentifier());
- _refreshPriority = DataRefreshPriorityEnum.SCHEDULED;
+ protected void forceStopAlarmRefresh() {
+ lockAlarm.lock();
+ try {
+ if (refreshPriority == RefreshPriority.PRIORITY_ALARM) {
+ logger.debug("{}: context='forceStopAlarmRefresh' Stopping ALARM refresh...", getLogIdentifier());
+ refreshPriority = RefreshPriority.PRIORITY_NORMAL;
+ alarmTimeoutTimestamp = 0;
+ }
+ } finally {
+ lockAlarm.unlock();
+ }
+ }
+
+ protected void onThingStatusChanged(ThingStatus thingStatus) {
}
@Override
public void dispose() {
-
}
/**
* Helper method for getting ChannelUID from ChannelId.
*
*/
- public ChannelUID getChannelUIDFromChannelId(String id) {
+
+ public ChannelUID getChannelUIDFromChannelId(@NonNull String id) {
Channel ch = thing.getChannel(id);
+ if (ch == null) {
+ return null;
+ }
return ch.getUID();
}
- protected abstract void onFetchData();
+ protected abstract void onFetchData(RefreshPriority refreshPriority);
/**
* 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()) {
+ public final void refreshThing(RefreshPriority refreshPriority) {
+ boolean isLocked = false;
+ try {
+ if (!isConnected()) {
+ return;
+ }
- logger.debug("{}: refreshThing(): Bridge '{}' Found for Thing '{}'!", getLogIdentifier(),
- getThing().getUID(), this.getThing().getUID());
+ if (refreshPriority == RefreshPriority.PRIORITY_ALARM) {
+ if (!lockRefresh.tryLock()) {
+ logger.warn(
+ "{}: context='refreshThing' Failed to obtain refresh lock for '{}' - refreshThing skipped!",
+ getLogIdentifier(), getThing().getUID());
+ isLocked = false;
+ return;
+ }
+ } else {
+ lockRefresh.lock();
+ }
+ isLocked = true;
- onFetchData();
+ if (getZoneMinderBridgeHandler() != null) {
+ onFetchData(refreshPriority);
+ } else {
+ logger.warn(
+ "{}: context='refreshThing' - BridgeHandler was not accessible for '{}', skipping refreshThing",
+ getLogIdentifier(), getThing().getUID());
}
- }
- Thing thing = getThing();
- List channels = thing.getChannels();
- logger.debug("{}: refreshThing(): Refreshing Thing - {}", getLogIdentifier(), thing.getUID());
+ if (!isThingRefreshed()) {
+ Thing thing = getThing();
+ List channels = thing.getChannels();
+ logger.debug("{}: context=refreshThing': Refreshing Channels for '{}'", getLogIdentifier(),
+ thing.getUID());
- for (Channel channel : channels) {
- updateChannel(channel.getUID());
+ for (Channel channel : channels) {
+ updateChannel(channel.getUID());
+ }
+ this.channelRefreshDone();
+ }
+ } catch (Exception ex) {
+ logger.error("{}: context='refreshThing' - Exception when refreshing '{}' ", getLogIdentifier(),
+ getThing().getUID(), ex);
+ } finally {
+ if (isLocked) {
+ lockRefresh.unlock();
+ }
}
-
- this.setThingRefreshed(true);
- logger.debug("[{}: refreshThing(): Thing Refreshed - {}", getLogIdentifier(), thing.getUID());
-
}
/**
@@ -205,18 +273,16 @@ public final synchronized void refreshThing(IZoneMinderSession session, DataRefr
*
* @return zoneMinderBridgeHandler
*/
- public synchronized ZoneMinderServerBridgeHandler getZoneMinderBridgeHandler() {
-
+ public /* synchronized */ZoneMinderServerBridgeHandler getZoneMinderBridgeHandler() {
if (this.zoneMinderBridgeHandler == null) {
-
Bridge bridge = getBridge();
if (bridge == null) {
- logger.debug("{}: getZoneMinderBridgeHandler(): Unable to get bridge!", getLogIdentifier());
+ logger.warn("{}: context='getZoneMinderBridgeHandler' - Unable to get bridge!", getLogIdentifier());
return null;
}
- logger.debug("{}: getZoneMinderBridgeHandler(): Bridge for '{}' - '{}'", getLogIdentifier(),
+ logger.debug("{}: context='getZoneMinderBridgeHandler' Bridge for '{}' - '{}'", getLogIdentifier(),
getThing().getUID(), bridge.getUID());
ThingHandler handler = null;
try {
@@ -229,7 +295,8 @@ public synchronized ZoneMinderServerBridgeHandler getZoneMinderBridgeHandler() {
if (handler instanceof ZoneMinderServerBridgeHandler) {
this.zoneMinderBridgeHandler = (ZoneMinderServerBridgeHandler) handler;
} else {
- logger.debug("{}: getZoneMinderBridgeHandler(): Unable to get bridge handler!", getLogIdentifier());
+ logger.debug("{}: context='getZoneMinderBridgeHandler' Unable to get bridge handler!",
+ getLogIdentifier());
}
}
@@ -243,11 +310,9 @@ public synchronized ZoneMinderServerBridgeHandler getZoneMinderBridgeHandler() {
*/
@Override
public void updateChannel(ChannelUID channel) {
- OnOffType onOffType;
-
switch (channel.getId()) {
case ZoneMinderConstants.CHANNEL_ONLINE:
- updateState(channel, getChannelBoolAsOnOffState(isOnline()));
+ updateState(channel, getChannelBoolAsOnOffState(isThingOnline()));
break;
default:
logger.error(
@@ -261,33 +326,13 @@ 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();
- }
+ public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
+ super.bridgeStatusChanged(bridgeStatusInfo);
}
@Override
public void onBridgeDisconnected(ZoneMinderServerBridgeHandler bridge) {
-
- if (bridge.getThing().getUID().equals(getThing().getBridgeUID())) {
-
- this.setThingRefreshed(false);
- }
-
- lockSession.lock();
- try {
- zoneMinderSession = null;
-
- } finally {
- lockSession.unlock();
- }
-
+ zoneMinderConnection = null;
}
/**
@@ -316,7 +361,8 @@ public Channel getChannel(ChannelUID channelUID) {
* @return thingRefresh
*/
public boolean isThingRefreshed() {
- return thingRefreshed;
+ return (thingRefresh.get() > 0) ? false : true;
+ // return (thingRefresh > 0) ? false : true;
}
/**
@@ -324,8 +370,15 @@ public boolean isThingRefreshed() {
*
* @param {boolean} refreshed Sets status refreshed of thing
*/
- public void setThingRefreshed(boolean refreshed) {
- this.thingRefreshed = refreshed;
+ public void requestChannelRefresh() {
+ thingRefresh.incrementAndGet();
+ // this.thingRefresh = this.thingRefresh + 1;
+ }
+
+ public void channelRefreshDone() {
+ if (thingRefresh.decrementAndGet() < 0) {
+ thingRefresh.set(0);
+ }
}
protected abstract String getZoneMinderThingType();
@@ -367,7 +420,8 @@ protected State getChannelStringAsStringState(String channelValue) {
}
} catch (Exception ex) {
- logger.error("{}", ex.getMessage());
+
+ logger.error("{}: Exception occurred in 'getChannelStringAsStringState' ", getLogIdentifier(), ex);
}
return state;
@@ -383,25 +437,28 @@ protected State getChannelBoolAsOnOffState(boolean value) {
}
} catch (Exception ex) {
- logger.error("{}: Exception occurred in 'getChannelBoolAsOnOffState()' (Exception='{}')",
- getLogIdentifier(), ex.getMessage());
+ logger.error("{}: Exception occurred in 'getChannelBoolAsOnOffState()' ", getLogIdentifier(), ex);
}
return state;
}
+ @Override
+ public void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionHandler connection) {
+ zoneMinderConnection = connection;
+ }
+
@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)) {
+ // Status changed
+ if (!curStatusInfo.getStatus().equals(thingStatus) || !curStatusInfo.getStatusDetail().equals(statusDetail)
+ || !curDescription.equals(statusDescription)) {
// Update Status correspondingly
if ((thingStatus == ThingStatus.OFFLINE) && (statusDetail != ThingStatusDetail.NONE)) {
logger.info("{}: Thing status changed from '{}' to '{}' (DetailedStatus='{}', Description='{}')",
@@ -412,7 +469,8 @@ protected void updateThingStatus(ThingStatus thingStatus, ThingStatusDetail stat
thingStatus);
updateStatus(thingStatus);
}
+
+ onThingStatusChanged(thingStatus);
}
}
-
}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderServerBridgeHandler.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderServerBridgeHandler.java
index 3a68a6bd0c5b9..ea19d7a22e5b9 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderServerBridgeHandler.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderServerBridgeHandler.java
@@ -10,6 +10,9 @@
import java.io.IOException;
import java.math.BigDecimal;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Hashtable;
@@ -19,9 +22,9 @@
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
-import javax.security.auth.login.FailedLoginException;
-
import org.apache.commons.lang.StringUtils;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.config.discovery.DiscoveryService;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.OnOffType;
@@ -33,7 +36,6 @@
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.ThingStatusInfo;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
-import org.eclipse.smarthome.core.thing.ThingUID;
import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.RefreshType;
@@ -41,7 +43,8 @@
import org.eclipse.smarthome.core.types.UnDefType;
import org.openhab.binding.zoneminder.ZoneMinderConstants;
import org.openhab.binding.zoneminder.ZoneMinderProperties;
-import org.openhab.binding.zoneminder.internal.DataRefreshPriorityEnum;
+import org.openhab.binding.zoneminder.internal.RefreshPriority;
+import org.openhab.binding.zoneminder.internal.ZoneMinderConnectionStatus;
import org.openhab.binding.zoneminder.internal.config.ZoneMinderBridgeServerConfig;
import org.openhab.binding.zoneminder.internal.discovery.ZoneMinderDiscoveryService;
import org.osgi.framework.ServiceRegistration;
@@ -50,28 +53,35 @@
import com.google.common.collect.Sets;
-import name.eskildsen.zoneminder.IZoneMinderConnectionInfo;
-import name.eskildsen.zoneminder.IZoneMinderDaemonStatus;
-import name.eskildsen.zoneminder.IZoneMinderDiskUsage;
-import name.eskildsen.zoneminder.IZoneMinderHostLoad;
-import name.eskildsen.zoneminder.IZoneMinderHostVersion;
-import name.eskildsen.zoneminder.IZoneMinderMonitorData;
+import name.eskildsen.zoneminder.IZoneMinderConnectionHandler;
+import name.eskildsen.zoneminder.IZoneMinderEventSession;
import name.eskildsen.zoneminder.IZoneMinderServer;
-import name.eskildsen.zoneminder.IZoneMinderSession;
import name.eskildsen.zoneminder.ZoneMinderFactory;
-import name.eskildsen.zoneminder.api.config.ZoneMinderConfig;
-import name.eskildsen.zoneminder.api.config.ZoneMinderConfigEnum;
+import name.eskildsen.zoneminder.common.ZoneMinderConfigEnum;
+import name.eskildsen.zoneminder.data.IMonitorDataGeneral;
+import name.eskildsen.zoneminder.data.IZoneMinderDaemonStatus;
+import name.eskildsen.zoneminder.data.IZoneMinderDiskUsage;
+import name.eskildsen.zoneminder.data.IZoneMinderHostLoad;
+import name.eskildsen.zoneminder.data.IZoneMinderHostVersion;
+import name.eskildsen.zoneminder.data.ZoneMinderConfig;
+import name.eskildsen.zoneminder.exception.ZoneMinderApiNotEnabledException;
+import name.eskildsen.zoneminder.exception.ZoneMinderAuthenticationException;
+import name.eskildsen.zoneminder.exception.ZoneMinderException;
+import name.eskildsen.zoneminder.exception.ZoneMinderGeneralException;
+import name.eskildsen.zoneminder.exception.ZoneMinderInvalidData;
+import name.eskildsen.zoneminder.exception.ZoneMinderResponseException;
import name.eskildsen.zoneminder.exception.ZoneMinderUrlNotFoundException;
/**
* Handler for a ZoneMinder Server.
*
- * @author Martin S. Eskildsen
+ * @author Martin S. Eskildsen - Initial contribution
*
*/
-public class ZoneMinderServerBridgeHandler extends BaseBridgeHandler implements ZoneMinderHandler {
+public class ZoneMinderServerBridgeHandler extends BaseBridgeHandler implements IZoneMinderHandler {
public static final int TELNET_TIMEOUT = 5000;
+ static final int HTTP_TIMEOUT = 5000;
public static final Set SUPPORTED_THING_TYPES = Sets
.newHashSet(ZoneMinderConstants.THING_TYPE_BRIDGE_ZONEMINDER_SERVER);
@@ -79,31 +89,39 @@ public class ZoneMinderServerBridgeHandler extends BaseBridgeHandler implements
/**
* Logger
*/
- private final Logger logger = LoggerFactory.getLogger(getClass());
+ private Logger logger = LoggerFactory.getLogger(getClass());
+
+ private ZoneMinderConnectionStatus zmConnectStatus = ZoneMinderConnectionStatus.UNINITIALIZED;
+ private ZoneMinderConnectionStatus lastSucceededStatus = ZoneMinderConnectionStatus.UNINITIALIZED;
- private ZoneMinderDiscoveryService discoveryService = null;
- private ServiceRegistration discoveryRegistration = null;
+ private RefreshPriority forcedPriority = RefreshPriority.UNKNOWN;
- private ScheduledFuture> taskWatchDog = null;
- private int refreshFrequency = 0;
- private int refreshCycleCount = 0;
+ private ZoneMinderDiscoveryService discoveryService;
+ private ServiceRegistration discoveryRegistration;
+
+ private ScheduledFuture> taskWatchDog;
+ private Integer refreshCycleCount = 0;
/** Connection status for the bridge. */
private boolean connected = false;
- private ThingStatus curBridgeStatus = ThingStatus.UNKNOWN;
-
- protected boolean _online = false;
private Runnable watchDogRunnable = new Runnable() {
- private int watchDogCount = -1;
+ private int watchDogCount = 0;
@Override
public void run() {
-
try {
- updateAvaliabilityStatus(zoneMinderConnection);
+ updateAvaliabilityStatus(getZoneMinderConnection());
+
+ // Only Discover if Bridge is online
+ if (thing.getStatusInfo().getStatus() != ThingStatus.ONLINE) {
+ return;
+ }
- if ((discoveryService != null) && (getBridgeConfig().getAutodiscoverThings() == true)) {
+ // Check if autodiscovery is enabled
+ boolean bAutoDiscover = getBridgeConfig().getAutodiscoverThings();
+
+ if ((discoveryService != null) && bAutoDiscover) {
watchDogCount++;
// Run every two minutes
if ((watchDogCount % 8) == 0) {
@@ -111,8 +129,11 @@ public void run() {
watchDogCount = 0;
}
}
+
} catch (Exception exception) {
- logger.error("[WATCHDOG]: Server run(): Exception: {}", exception.getMessage());
+ StackTraceElement ste = exception.getStackTrace()[0];
+ logger.error("[WATCHDOG]: Server run(): StackTrace: File='{}', Line='{}', Method='{}'",
+ ste.getFileName(), ste.getLineNumber(), ste.getMethodName(), exception);
}
}
};
@@ -123,112 +144,70 @@ public void run() {
private String channelCpuLoad = "";
private String channelDiskUsage = "";
- private Boolean isInitialized = false;
+ private boolean initialized = false;
- private IZoneMinderSession zoneMinderSession = null;
- private IZoneMinderConnectionInfo zoneMinderConnection = null;
+ private IZoneMinderEventSession zoneMinderEventSession;
+ private IZoneMinderConnectionHandler zoneMinderConnection;
private ScheduledFuture> taskRefreshData = null;
- private ScheduledFuture> taskPriorityRefreshData = null;
-
- private Runnable refreshDataRunnable = () -> {
- try {
- boolean fetchDiskUsage = false;
-
- if (!isOnline()) {
- logger.debug("{}: Bridge '{}' is noit online skipping refresh", getLogIdentifier(), thing.getUID());
- }
-
- refreshCycleCount++;
- int iMaxCycles;
- boolean resetCount = false;
- boolean doRefresh = false;
+ private IZoneMinderConnectionHandler getZoneMinderConnection() {
+ return zoneMinderConnection;
+ }
- // Disk Usage is disabled
- if (getBridgeConfig().getRefreshIntervalLowPriorityTask() == 0) {
- iMaxCycles = getBridgeConfig().getRefreshInterval();
- resetCount = true;
- doRefresh = true;
- } else {
- iMaxCycles = getBridgeConfig().getRefreshIntervalLowPriorityTask() * 60;
- doRefresh = true;
- if ((refreshCycleCount * refreshFrequency) >= (getBridgeConfig().getRefreshIntervalLowPriorityTask()
- * 60)) {
- fetchDiskUsage = true;
- resetCount = true;
+ private Runnable refreshDataRunnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (!isConnected()) {
+ return;
+ }
+ refreshCycleCount++;
+ int intervalBatch = 3600;
+ int intervalLow = getBridgeConfig().getRefreshIntervalLow();
+ int intervalNormal = getBridgeConfig().getRefreshIntervalNormal();
+ int intervalHigh = 5;
+
+ RefreshPriority cyclePriority = RefreshPriority.PRIORITY_ALARM;
+
+ // boolean isBatch = ((refreshCycleCount % intervalBatch) == 0);
+ boolean isLow = ((refreshCycleCount % intervalLow) == 0);
+ boolean isNormal = ((refreshCycleCount % intervalNormal) == 0);
+ boolean isHigh = ((refreshCycleCount % intervalHigh) == 0);
+
+ if (isLow) {
+ cyclePriority = RefreshPriority.PRIORITY_BATCH;
+ } else if (isLow) {
+ cyclePriority = RefreshPriority.PRIORITY_LOW;
+ } else if (isNormal) {
+ cyclePriority = RefreshPriority.PRIORITY_NORMAL;
+ } else if (isHigh) {
+ cyclePriority = RefreshPriority.PRIORITY_HIGH;
}
- }
- logger.debug(
- "{}: Running Refresh data task count='{}', freq='{}', max='{}', interval='{}', intervalLow='{}'",
- getLogIdentifier(), refreshCycleCount, refreshFrequency, iMaxCycles,
- getBridgeConfig().getRefreshInterval(), getBridgeConfig().getRefreshIntervalLowPriorityTask());
+ refreshThing(cyclePriority);
- if (doRefresh) {
- if (resetCount == true) {
+ if ((refreshCycleCount >= intervalLow) && (refreshCycleCount >= intervalNormal)
+ && (refreshCycleCount >= intervalHigh) && (refreshCycleCount >= intervalBatch)) {
refreshCycleCount = 0;
}
- logger.debug("{}: 'refreshDataRunnable()': (diskUsage='{}')", getLogIdentifier(), fetchDiskUsage);
-
- refreshThing(zoneMinderSession, fetchDiskUsage);
- }
- } catch (Exception exception) {
- logger.error("{}: monitorRunnable::run(): Exception: ", getLogIdentifier(), exception);
- }
- };
-
- private Runnable refreshPriorityDataRunnable = () -> {
- try {
- // Make sure priority updates is done
- for (Thing thing : getThing().getThings()) {
- try {
- if (thing.getThingTypeUID().equals(ZoneMinderConstants.THING_TYPE_THING_ZONEMINDER_MONITOR)) {
- Thing thingMonitor = thing;
-
- ZoneMinderBaseThingHandler thingHandler = (ZoneMinderBaseThingHandler) thing.getHandler();
- if (thingHandler != null) {
-
- if (thingHandler.getRefreshPriority() == DataRefreshPriorityEnum.HIGH_PRIORITY) {
- logger.debug("[MONITOR-{}]: RefreshPriority is High Priority",
- thingHandler.getZoneMinderId());
- thingHandler.refreshThing(zoneMinderSession, DataRefreshPriorityEnum.HIGH_PRIORITY);
- }
- } else {
- logger.debug(
- "[MONITOR]: refreshThing not called for monitor, since thingHandler is 'null'");
- }
- }
- } catch (NullPointerException ex) {
- // This isn't critical (unless it comes over and over). There seems to be a bug so that a
- // null
- // pointer exception is coming every now and then.
- // HAve to find the reason for that. Until thenm, don't Spamm
- logger.error("[MONITOR]: Method 'refreshThing()' for Bridge failed for thing='{}' - Exception: ",
- thing.getUID(), ex);
- } catch (Exception ex) {
- logger.error("[MONITOR]: Method 'refreshThing()' for Bridge failed for thing='{}' - Exception: ",
- thing.getUID(), ex);
- }
+ } catch (Exception exception) {
+ logger.error("{}: monitorRunnable::run()", getLogIdentifier(), exception);
}
- } catch (Exception exception) {
- logger.error("[MONITOR]: monitorRunnable::run(): Exception: ", exception);
}
};
/**
* Constructor
*
- *
- * @param bridge
- * Bridge object representing a ZoneMinder Server
+ * @param bridge Bridge object representing a ZoneMinder Server
*/
public ZoneMinderServerBridgeHandler(Bridge bridge) {
super(bridge);
- logger.info("{}: Starting ZoneMinder Server Bridge Handler (Bridge='{}')", getLogIdentifier(),
- bridge.getBridgeUID());
+ logger.info("{}: context='constructor' Starting ZoneMinder Server Bridge Handler (Bridge='{}')",
+ getLogIdentifier(), bridge.getBridgeUID());
}
/**
@@ -236,65 +215,54 @@ public ZoneMinderServerBridgeHandler(Bridge bridge) {
*/
@Override
public void initialize() {
- logger.debug("[BRIDGE]: About to initialize bridge " + ZoneMinderConstants.BRIDGE_ZONEMINDER_SERVER);
try {
- updateStatus(ThingStatus.OFFLINE);
- logger.info("BRIDGE: ZoneMinder Server Bridge Handler Initialized");
- logger.debug("BRIDGE: HostName: {}", getBridgeConfig().getHostName());
- logger.debug("BRIDGE: Protocol: {}", getBridgeConfig().getProtocol());
- logger.debug("BRIDGE: Port HTTP(S) {}", getBridgeConfig().getHttpPort());
- logger.debug("BRIDGE: Port Telnet {}", getBridgeConfig().getTelnetPort());
- logger.debug("BRIDGE: Server Path {}", getBridgeConfig().getServerBasePath());
- logger.debug("BRIDGE: User: {}", getBridgeConfig().getUserName());
- logger.debug("BRIDGE: Refresh interval: {}", getBridgeConfig().getRefreshInterval());
- logger.debug("BRIDGE: Low prio. refresh: {}", getBridgeConfig().getRefreshIntervalLowPriorityTask());
- logger.debug("BRIDGE: Autodiscovery: {}", getBridgeConfig().getAutodiscoverThings());
-
- closeConnection();
-
- zoneMinderConnection = ZoneMinderFactory.CreateConnection(getBridgeConfig().getProtocol(),
- getBridgeConfig().getHostName(), getBridgeConfig().getHttpPort(), getBridgeConfig().getTelnetPort(),
- getBridgeConfig().getServerBasePath(), getBridgeConfig().getUserName(),
- getBridgeConfig().getPassword(), 3000);
+ zoneMinderConnection = null;
taskRefreshData = null;
- taskPriorityRefreshData = null;
- } catch (Exception ex) {
- logger.error("[BRIDGE]: 'ZoneMinderServerBridgeHandler' failed to initialize. Exception='{}'",
- ex.getMessage());
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR);
- } finally {
+ updateStatus(ThingStatus.OFFLINE);
+
+ ZoneMinderBridgeServerConfig config = getBridgeConfig();
+ logger.info("{}: ZoneMinder Server Bridge Handler Initialized", getLogIdentifier());
+ logger.debug("{}: HostName: {}", getLogIdentifier(), config.getHost());
+ logger.debug("{}: Protocol: {}", getLogIdentifier(), config.getProtocol());
+ logger.debug("{}: Port HTTP(S) {}", getLogIdentifier(), config.getHttpPort());
+ logger.debug("{}: Port Telnet {}", getLogIdentifier(), config.getTelnetPort());
+ logger.debug("{}: Portal Path {}", getLogIdentifier(), config.getServerBasePath());
+ logger.debug("{}: API Path {}", getLogIdentifier(), config.getServerApiPath());
+ logger.debug("{}: Refresh interval: {}", getLogIdentifier(), config.getRefreshIntervalNormal());
+ logger.debug("{}: Low prio. refresh: {}", getLogIdentifier(), config.getRefreshIntervalLow());
+ logger.debug("{}: Autodiscovery: {}", getLogIdentifier(), config.getAutodiscoverThings());
+
startWatchDogTask();
- isInitialized = true;
- }
- }
+ initialized = true;
+ return;
+ } catch (Exception ex) {
+ if (zoneMinderConnection == null) {
+ logger.error(
+ "{}: 'ZoneMinderServerBridgeHandler' general configuration error occurred. Failed to initialize.",
+ getLogIdentifier(), ex);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
+ } else {
+ logger.error("{}: 'ZoneMinderServerBridgeHandler' failed to initialize", getLogIdentifier(), ex);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR);
+ }
- /**
- * Method to find the lowest possible refresh rate (based on configuration)
- *
- * @param refreshRate
- * @return
- */
- protected int calculateCommonRefreshFrequency(int refreshRate) {
- // Check if 30, 15, 10 or 5 seconds is possible
- if ((refreshRate % 30) == 0) {
- return 30;
- } else if ((refreshRate % 15) == 0) {
- return 15;
- } else if ((refreshRate % 10) == 0) {
- return 10;
- } else if ((refreshRate % 5) == 0) {
- return 5;
}
- // Hmm, didn't find a obvious shared value. Run every second...
- return 1;
+ initialized = false;
+
+ }
+ protected IZoneMinderConnectionHandler aquireSession() {
+ return zoneMinderConnection;
+ }
+
+ protected void releaseSession() {
}
protected void startWatchDogTask() {
- taskWatchDog = startTask(watchDogRunnable, 0, 15, TimeUnit.SECONDS);
+ taskWatchDog = startTask(watchDogRunnable, 5, 1, TimeUnit.SECONDS);
}
protected void stopWatchDogTask() {
@@ -302,32 +270,47 @@ protected void stopWatchDogTask() {
taskWatchDog = null;
}
+ @Override
+ public void handleConfigurationUpdate(Map configurationParameters) {
+ try {
+ setConnected(false);
+ zoneMinderConnection = null;
+ setConnectionStatus(ZoneMinderConnectionStatus.UNINITIALIZED);
+ } catch (IllegalArgumentException | GeneralSecurityException | IOException | ZoneMinderUrlNotFoundException e) {
+ logger.error("{}: context='handleConfigurationUpdate'", getLogIdentifier(), e.getCause());
+ }
+ super.handleConfigurationUpdate(configurationParameters);
+ }
+
+ @Override
+ protected void updateConfiguration(Configuration configuration) {
+ super.updateConfiguration(configuration);
+ // Inform thing handlers of connection
+ }
+
/**
*/
@Override
public void dispose() {
- try {
- logger.debug("{}: Stop polling of ZoneMinder Server API", getLogIdentifier());
+ logger.debug("{}: context='dispose' Stop polling of ZoneMinder Server API", getLogIdentifier());
- logger.info("{}: Stopping Discovery service", getLogIdentifier());
- // Remove the discovery service
- if (discoveryService != null) {
- discoveryService.deactivate();
- discoveryService = null;
- }
+ logger.info("{}: context='dispose' Stopping Discovery service", getLogIdentifier());
+ // Remove the discovery service
+ if (discoveryService != null) {
+ discoveryService.deactivate();
+ discoveryService = null;
+ }
- if (discoveryRegistration != null) {
- discoveryRegistration.unregister();
- discoveryRegistration = null;
- }
+ if (discoveryRegistration != null) {
+ discoveryRegistration.unregister();
+ discoveryRegistration = null;
+ }
- logger.info("{}: Stopping WatchDog task", getLogIdentifier());
- stopWatchDogTask();
+ logger.info("{}: context='dispose' Stopping WatchDog task", getLogIdentifier());
+ stopWatchDogTask();
- logger.info("{}: Stopping refresh data task", getLogIdentifier());
- stopTask(taskRefreshData);
- } catch (Exception ex) {
- }
+ logger.info("{}: context='dispose' Stopping refresh data task", getLogIdentifier());
+ stopTask(taskRefreshData);
}
protected String getThingId() {
@@ -336,33 +319,21 @@ protected String getThingId() {
@Override
public String getZoneMinderId() {
-
return getThing().getUID().getAsString();
}
- @Override
- public void channelLinked(ChannelUID channelUID) {
- // can be overridden by subclasses
- ThingUID s1 = getThing().getUID();
- ThingTypeUID s2 = getThing().getThingTypeUID();
- logger.debug("{}: Channel '{}' was linked to '{}'", getLogIdentifier(), channelUID.getAsString(),
- this.thing.getThingTypeUID());
- }
-
- @Override
- public void channelUnlinked(ChannelUID channelUID) {
- // can be overridden by subclasses
- logger.debug("{}: Channel '{}' was unlinked from '{}'", getLogIdentifier(), channelUID.getAsString(),
- this.thing.getThingTypeUID());
- }
-
- protected ArrayList getMonitors(IZoneMinderSession session) {
-
+ protected ArrayList getMonitors(IZoneMinderConnectionHandler session)
+ throws ZoneMinderAuthenticationException {
if (isConnected()) {
- return ZoneMinderFactory.getServerProxy(session).getMonitors();
- }
+ try {
+ return ZoneMinderFactory.getServerProxy(session).getMonitors();
+ } catch (ZoneMinderGeneralException | ZoneMinderResponseException | ZoneMinderInvalidData ex) {
+ logger.error("{}: context='getMonitors' Exception {}", getLogIdentifier(), ex.getMessage(),
+ ex.getCause());
- return new ArrayList();
+ }
+ }
+ return new ArrayList<>();
}
@@ -375,12 +346,12 @@ protected ZoneMinderBridgeServerConfig getBridgeConfig() {
*/
public ZoneMinderBaseThingHandler getZoneMinderThingHandlerFromZoneMinderId(ThingTypeUID thingTypeUID,
String zoneMinderId) {
-
// Inform thing handlers of connection
List things = getThing().getThings();
for (Thing thing : things) {
ZoneMinderBaseThingHandler thingHandler = (ZoneMinderBaseThingHandler) thing.getHandler();
+
if ((thingHandler.getZoneMinderId().equals(zoneMinderId))
&& (thing.getThingTypeUID().equals(thingTypeUID))) {
return thingHandler;
@@ -394,84 +365,121 @@ public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("{}: Update '{}' with '{}'", getLogIdentifier(), channelUID.getAsString(), command.toString());
}
- protected synchronized void refreshThing(IZoneMinderSession session, boolean fetchDiskUsage) {
+ protected /* synchronized */ void refreshThing(RefreshPriority refresh) {
+ IZoneMinderServer zoneMinderServerProxy = null;
+ RefreshPriority curPriority = RefreshPriority.DISABLED;
- logger.debug("{}: 'refreshThing()': Thing='{}'!", getLogIdentifier(), this.getThing().getUID());
+ // logger.debug("{}: 'refreshThing()': Thing='{}'!", getLogIdentifier(), this.getThing().getUID());
List channels = getThing().getChannels();
List things = getThing().getThings();
- IZoneMinderServer zoneMinderServerProxy = ZoneMinderFactory.getServerProxy(session);
- if (zoneMinderServerProxy == null) {
- logger.warn("{}: Could not obtain ZonerMinderServerProxy ", getLogIdentifier());
+ try {
+ if (forcedPriority == RefreshPriority.UNKNOWN) {
+ return;
+ } else if (forcedPriority == RefreshPriority.DISABLED) {
+ curPriority = refresh;
+ } else {
+ curPriority = forcedPriority;
+ forcedPriority = RefreshPriority.DISABLED;
+ }
- // Make sure old data is cleared
- channelCpuLoad = "";
- channelDiskUsage = "";
+ zoneMinderServerProxy = ZoneMinderFactory.getServerProxy(aquireSession());
+ if (zoneMinderServerProxy == null) {
+ logger.warn("{}: Could not obtain ZonerMinderServerProxy ", getLogIdentifier());
- } else if (isConnected()) {
- /*
- * Fetch data for Bridge
- */
- IZoneMinderHostLoad hostLoad = null;
- try {
- hostLoad = zoneMinderServerProxy.getHostCpuLoad();
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- zoneMinderServerProxy.getHttpUrl(), zoneMinderServerProxy.getHttpResponseCode(),
- zoneMinderServerProxy.getHttpResponseMessage());
+ // Make sure old data is cleared
+ channelCpuLoad = "";
+ channelDiskUsage = "";
- } catch (FailedLoginException | ZoneMinderUrlNotFoundException | IOException ex) {
- logger.error("{}: Exception thrown in call to ZoneMinderHostLoad: ", getLogIdentifier(), ex);
- }
+ } else if (isConnected()) {
+ /*
+ * Fetch data for Bridge
+ */
+ if (curPriority.isPriorityActive(RefreshPriority.PRIORITY_NORMAL)) {
+ IZoneMinderHostLoad hostLoad = null;
+ try {
+ hostLoad = zoneMinderServerProxy.getHostCpuLoad();
+ logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
+ hostLoad.getHttpRequestUrl(), hostLoad.getHttpStatus(),
+ hostLoad.getHttpResponseMessage());
+
+ } catch (ZoneMinderUrlNotFoundException | IOException ex) {
+ logger.error("{}: Exception thrown in call to ZoneMinderHostLoad ('{}')", getLogIdentifier(),
+ ex.getMessage());
+ } catch (ZoneMinderException ex) {
+ logger.error(
+ "{}: context='refreshThing' error in call to 'getHostCpuLoad' ExceptionClass='{}' - Message='{}'",
+ getLogIdentifier(), ex.getClass().getCanonicalName(), ex.getMessage(), ex.getCause());
+ }
- if (hostLoad == null) {
- logger.warn("{}: ZoneMinderHostLoad dataset could not be obtained (received 'null')",
- getLogIdentifier());
- } else if (hostLoad.getHttpResponseCode() != 200) {
- logger.warn(
- "BRIDGE [{}]: ZoneMinderHostLoad dataset could not be obtained (HTTP Response: Code='{}', Message='{}')",
- getThingId(), hostLoad.getHttpResponseCode(), hostLoad.getHttpResponseMessage());
+ if (hostLoad == null) {
+ logger.warn("{}: ZoneMinderHostLoad dataset could not be obtained (received 'null')",
+ getLogIdentifier());
+ } else if (hostLoad.getHttpStatus() != HttpStatus.OK_200) {
+ logger.warn(
+ "{}: ZoneMinderHostLoad dataset could not be obtained (HTTP Response: Code='{}', Message='{}')",
+ getLogIdentifier(), hostLoad.getHttpStatus(), hostLoad.getHttpResponseMessage());
- } else {
- channelCpuLoad = hostLoad.getCpuLoad().toString();
- }
+ } else {
+ channelCpuLoad = hostLoad.getCpuLoad().toString();
+ }
- if (fetchDiskUsage) {
- IZoneMinderDiskUsage diskUsage = null;
- try {
- diskUsage = zoneMinderServerProxy.getHostDiskUsage();
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- zoneMinderServerProxy.getHttpUrl(), zoneMinderServerProxy.getHttpResponseCode(),
- zoneMinderServerProxy.getHttpResponseMessage());
- } catch (Exception ex) {
- logger.error("{}: Exception thrown in call to ZoneMinderDiskUsage: ", getLogIdentifier(), ex);
- }
+ if (curPriority.isPriorityActive(getBridgeConfig().getDiskUsageRefresh())) {
+ IZoneMinderDiskUsage diskUsage = null;
+ try {
+ diskUsage = zoneMinderServerProxy.getHostDiskUsage();
+ logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
+ diskUsage.getHttpRequestUrl(), diskUsage.getHttpStatus(),
+ diskUsage.getHttpResponseMessage());
+ } catch (Exception ex) {
+ logger.error(
+ "{}: context='refreshThing' Exception thrown in call to ZoneMinderDiskUsage ('{}')",
+ getLogIdentifier(), ex.getMessage());
+ } catch (ZoneMinderException ex) {
+ logger.error(
+ "{}: context='refreshThing' error in call to 'getHostDiskUsage' ExceptionClass='{}' - Message='{}'",
+ getLogIdentifier(), ex.getClass().getCanonicalName(), ex.getMessage(),
+ ex.getCause());
+ }
- if (diskUsage == null) {
- logger.warn("{}: ZoneMinderDiskUsage dataset could not be obtained (received 'null')",
- getLogIdentifier());
- } else if (hostLoad.getHttpResponseCode() != 200) {
- logger.warn(
- "{}: ZoneMinderDiskUsage dataset could not be obtained (HTTP Response: Code='{}', Message='{}')",
- getLogIdentifier(), hostLoad.getHttpResponseCode(), hostLoad.getHttpResponseMessage());
+ if (diskUsage == null) {
+ logger.warn(
+ "{}: context='refreshThing' ZoneMinderDiskUsage dataset could not be obtained (received 'null')",
+ getLogIdentifier());
+ } else if (diskUsage.getHttpStatus() != HttpStatus.OK_200) {
+ logger.warn(
+ "{}: context='refreshThing' ZoneMinderDiskUsage dataset could not be obtained (HTTP Response: Code='{}', Message='{}')",
+ getLogIdentifier(), diskUsage.getHttpStatus(), diskUsage.getHttpResponseMessage());
- } else {
- channelDiskUsage = diskUsage.getDiskUsage();
+ } else {
+ channelDiskUsage = diskUsage.getDiskUsage();
+ }
+ }
}
+ } else {
+ // Make sure old data is cleared
+ channelCpuLoad = "";
+ channelDiskUsage = "";
+ }
+ } catch (Exception ex) {
+ logger.error("{}: context='refreshThing' tag='exception' Exception thrown when refreshing bridge='{}'",
+ getLogIdentifier(), getThing().getBridgeUID(), ex);
+ } finally {
+ if (zoneMinderServerProxy != null) {
+ releaseSession();
}
- } else {
- _online = false;
- // Make sure old data is cleared
- channelCpuLoad = "";
- channelDiskUsage = "";
}
/*
* Update all channels on Bridge
*/
for (Channel channel : channels) {
- updateChannel(channel.getUID());
+
+ if (isLinked(channel.getUID().getId())) {
+ updateChannel(channel.getUID());
+ }
}
/*
@@ -479,26 +487,18 @@ protected synchronized void refreshThing(IZoneMinderSession session, boolean fet
*/
for (Thing thing : things) {
try {
-
if (thing.getThingTypeUID().equals(ZoneMinderConstants.THING_TYPE_THING_ZONEMINDER_MONITOR)) {
- Thing thingMonitor = thing;
ZoneMinderBaseThingHandler thingHandler = (ZoneMinderBaseThingHandler) thing.getHandler();
- thingHandler.refreshThing(session, DataRefreshPriorityEnum.SCHEDULED);
+ if (thingHandler != null) {
+ thingHandler.refreshThing(curPriority);
+ }
}
-
- } catch (NullPointerException ex) {
- // This isn't critical (unless it comes over and over). There seems to be a bug so that a null
- // pointer exception is coming every now and then.
- // HAve to find the reason for that. Until thenm, don't Spamm
- logger.debug("{}: Method 'refreshThing()' for Bridge {} failed for thing='{}' - Exception='{}'",
- getLogIdentifier(), this.getZoneMinderId(), thing.getUID(), ex.getMessage());
-
- // Other exceptions has to be shown as errors
} catch (Exception ex) {
- logger.error("{}: Method 'refreshThing()' for Bridge {} failed for thing='{}' - Exception='{}'",
- getLogIdentifier(), this.getZoneMinderId(), thing.getUID(), ex.getMessage());
+ logger.error("{}: context='refreshThing' tag='exception' Exception thrown when refreshing thing='{}'",
+ getLogIdentifier(), thing.getUID(), ex.getCause());
}
+
}
}
@@ -511,63 +511,50 @@ public synchronized Boolean isConnected() {
}
public boolean isOnline() {
- return _online;
- }
-
- private synchronized boolean getConnected() {
- return this.connected;
+ ThingStatusInfo statusInfo = getThing().getStatusInfo();
+ return (statusInfo.getStatus() == ThingStatus.ONLINE) ? true : false;
}
/**
* Set connection status.
*
* @param connected
+ * @throws ZoneMinderUrlNotFoundException
+ * @throws IOException
+ * @throws GeneralSecurityException
+ * @throws IllegalArgumentException
*/
- private synchronized void setConnected(boolean connected) {
-
+ private void setConnected(boolean connected)
+ throws IllegalArgumentException, GeneralSecurityException, IOException, ZoneMinderUrlNotFoundException {
if (this.connected != connected) {
- if (connected) {
- try {
- zoneMinderSession = ZoneMinderFactory.CreateSession(zoneMinderConnection);
- } catch (FailedLoginException | IllegalArgumentException | IOException
- | ZoneMinderUrlNotFoundException e) {
- logger.error("BRIDGE [{}]: Call to setConencted failed with exception '{}'", getThingId(),
- e.getMessage());
- }
- } else {
- zoneMinderSession = null;
- }
- this.connected = connected;
-
- }
+ try {
+ if (connected) {
+ try {
+ if (zoneMinderEventSession == null) {
+ zoneMinderEventSession = ZoneMinderFactory.CreateEventSession(zoneMinderConnection);
+ }
- }
+ } catch (Exception ex) {
+ zoneMinderEventSession = null;
+ return;
+ }
- /**
- * Set channel 'bridge_connection'.
- *
- * @param connected
- */
- private void setBridgeConnectionStatus(boolean connected) {
- logger.debug(" {}: setBridgeConnection(): Set Bridge to {}", getLogIdentifier(),
- connected ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
-
- Bridge bridge = getBridge();
- if (bridge != null) {
- ThingStatus status = bridge.getStatus();
- logger.debug("{}: Bridge ThingStatus is: {}", getLogIdentifier(), status);
+ } else {
+ if (zoneMinderEventSession != null) {
+ zoneMinderEventSession.unsubscribeAllMonitorEvents();
+ }
+ zoneMinderConnection = null;
+ zoneMinderEventSession = null;
+ }
+ } finally {
+ this.connected = connected;
+ if (connected) {
+ onConnected();
+ } else {
+ onDisconnected();
+ }
+ }
}
-
- setConnected(connected);
- }
-
- /**
- * Set channel 'bridge_connection'.
- *
- * @param connected
- */
- private boolean getBridgeConnectionStatus() {
- return getConnected();
}
/**
@@ -578,10 +565,10 @@ private boolean getBridgeConnectionStatus() {
* @throws GeneralSecurityException
* @throws IllegalArgumentException
*/
- public void onConnected() {
- logger.debug("BRIDGE [{}]: onConnected(): Bridge Connected!", getThingId());
- setConnected(true);
- onBridgeConnected(this, zoneMinderConnection);
+ public void onConnected()
+ throws IllegalArgumentException, GeneralSecurityException, IOException, ZoneMinderUrlNotFoundException {
+ logger.debug("{}: [{}]: onConnected(): Bridge Connected!", getLogIdentifier(), getThingId());
+ onBridgeConnected(this, getZoneMinderConnection());
// Inform thing handlers of connection
List things = getThing().getThings();
@@ -591,23 +578,24 @@ public void onConnected() {
if (thingHandler != null) {
try {
- thingHandler.onBridgeConnected(this, zoneMinderConnection);
- } catch (IllegalArgumentException | GeneralSecurityException | IOException
- | ZoneMinderUrlNotFoundException e) {
- logger.error("{}: onConnected() failed - Exceprion: {}", getLogIdentifier(), e.getMessage());
+ thingHandler.onBridgeConnected(this, getZoneMinderConnection());
+ } catch (IllegalArgumentException e) {
+ logger.error("{}: context='onConnected' failed - Exceprion: {}", getLogIdentifier(),
+ e.getMessage());
}
- logger.debug("{}: onConnected(): Bridge - {}, Thing - {}, Thing Handler - {}", getLogIdentifier(),
- thing.getBridgeUID(), thing.getUID(), thingHandler);
+ logger.debug("{}: context='onConnected': Bridge - {}, Thing - {}, Thing Handler - {}",
+ getLogIdentifier(), thing.getBridgeUID(), thing.getUID(), thingHandler);
}
}
+
}
/**
* Runs when disconnected.
*/
private void onDisconnected() {
- logger.debug("{}: onDisconnected(): Bridge Disconnected!", getLogIdentifier());
- setConnected(false);
+ logger.debug("{}: context='onDisconnected': Bridge Disconnected!", getLogIdentifier());
+
onBridgeDisconnected(this);
// Inform thing handlers of disconnection
@@ -618,276 +606,692 @@ private void onDisconnected() {
if (thingHandler != null) {
thingHandler.onBridgeDisconnected(this);
- logger.debug("{}: onDisconnected(): Bridge - {}, Thing - {}, Thing Handler - {}", getLogIdentifier(),
- thing.getBridgeUID(), thing.getUID(), thingHandler);
+ logger.debug("{}: context='onDisconnected': Bridge - {}, Thing - {}, Thing Handler - {}",
+ getLogIdentifier(), thing.getBridgeUID(), thing.getUID(), thingHandler);
}
}
}
- @Override
- public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
+ private int initRetriesCount = 0;
+ private static int initMaxRevoverableRetries = 5;
+ private static int initMaxUnrecoverableRetries = 5;
+ private ZoneMinderConnectionStatus verifyBindingConfiguration(ThingStatus currentStatus) {
+ String context = "verifyBindingConfiguration";
ThingStatus newStatus = ThingStatus.OFFLINE;
ThingStatusDetail statusDetail = ThingStatusDetail.NONE;
String statusDescription = "";
- boolean _isOnline = false;
+ ZoneMinderConnectionStatus status = ZoneMinderConnectionStatus.BINDING_CONFIG_INVALID;
+ ZoneMinderBridgeServerConfig config = null;
+ try {
+ // Is it a retry loop? (Is this step already verified?)
+ // Or is there an unrecoverable error?
+ if ((getLastSucceededStatus().greatherThanEqual(ZoneMinderConnectionStatus.BINDING_CONFIG_LOAD_PASSED))
+ || (getLastSucceededStatus().hasUnrecoverableError())) {
+ return getLastSucceededStatus();
+ }
- ThingStatus prevStatus = getThing().getStatus();
+ // get Bridge Config
+ config = getBridgeConfig();
+
+ // Check if server Bridge configuration is valid
+ if (config == null) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "Configuration not found";
+ updateStatus(newStatus, statusDetail, statusDescription);
+
+ logger.error("{}: context='{}' state='{}' check='FAILED' - {}", getLogIdentifier(), context,
+ newStatus.toString(), statusDescription);
+
+ return status;
+
+ } else if (config.getHost() == null) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "Host not configured";
+
+ updateStatus(newStatus, statusDetail, statusDescription);
+
+ logger.error("{}: context='{}' state='{}' check='FAILED' - {}", getLogIdentifier(), context,
+ newStatus.toString(), statusDescription);
+
+ return status;
+ } else if (config.getProtocol() == null) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "Unknown protocol in configuration";
+
+ updateStatus(newStatus, statusDetail, statusDescription);
+
+ logger.error("{}: context='{}' state='{}' check='FAILED' - {}", getLogIdentifier(), context,
+ newStatus.toString(), statusDescription);
+ return status;
+ }
+
+ else if (config.getHttpPort() == null) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "HTTP port invalid in configuration";
+
+ updateStatus(newStatus, statusDetail, statusDescription);
+
+ logger.error("{}: context='{}' state='{}' check='FAILED' - {}", getLogIdentifier(), context,
+ newStatus.toString(), statusDescription);
+ return status;
+
+ }
+
+ else if (config.getTelnetPort() == null) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "Telnet port invalid in configuration";
+ updateStatus(newStatus, statusDetail, statusDescription);
+ logger.error("{}: context='{}' state='{}' check='FAILED' - {}", getLogIdentifier(), context,
+ newStatus.toString(), statusDescription);
+ return status;
+
+ }
+
+ // Configuration verified
+ status = ZoneMinderConnectionStatus.BINDING_CONFIG_LOAD_PASSED;
+
+ logger.debug("{}: context='{}' state='{}' check='PASSED'", getLogIdentifier(), context,
+ newStatus.toString());
+
+ } catch (Exception ex) {
+ logger.error("{}: context='{}' state='{}' check='FAILED' tag='exception'", getLogIdentifier(), context,
+ newStatus.toString(), ex);
+
+ }
+ return status;
+ }
+
+ private ZoneMinderConnectionStatus validateConfig(ZoneMinderBridgeServerConfig config) {
+ String context = "validateConfig";
+ ThingStatus newStatus = ThingStatus.OFFLINE;
+ ThingStatusDetail statusDetail = ThingStatusDetail.NONE;
+ String statusDescription = "";
+
+ ZoneMinderConnectionStatus status = ZoneMinderConnectionStatus.GENERAL_ERROR;
+
+ // Is it a retry loop? (Is this step already verified?)
+ // Or is there an unrecoverable error?
+ if ((getLastSucceededStatus().greatherThanEqual(ZoneMinderConnectionStatus.BINDING_CONFIG_VALIDATE_PASSED))
+ || (getLastSucceededStatus().hasUnrecoverableError())) {
+ return getLastSucceededStatus();
+ }
+
+ // Check if something is responding give host and port HTTP
try {
- // Just perform a health check to see if we are still connected
- if (prevStatus == ThingStatus.ONLINE) {
- if (zoneMinderSession == null) {
- newStatus = ThingStatus.ONLINE;
- statusDetail = ThingStatusDetail.NONE;
- statusDescription = "";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
- } else if (!zoneMinderSession.isConnected()) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.COMMUNICATION_ERROR;
- statusDescription = "Session lost connection to ZoneMinder Server";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
+ // Check Socket
+ Socket socket = new Socket();
+ socket.connect(new InetSocketAddress(config.getHost(), config.getHttpPort()), 5000);
+ if (socket.isConnected()) {
+ socket.close();
+ }
- return;
- }
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.NONE;
+ statusDescription = "Connecting to ZoneMinder Server";
+ updateStatus(newStatus, statusDetail, statusDescription);
- IZoneMinderServer serverProxy = ZoneMinderFactory.getServerProxy(zoneMinderSession);
- IZoneMinderDaemonStatus daemonStatus = serverProxy.getHostDaemonCheckState();
+ status = ZoneMinderConnectionStatus.BINDING_CONFIG_VALIDATE_PASSED;
+ logger.debug("{}: context='{}' previousState='OFFLINE' Socket connection to ZM Website (PASSED)",
+ getLogIdentifier(), context);
- // If service isn't running OR we revceived a http responsecode other than 200, assume we are offline
- if ((!daemonStatus.getStatus()) || (daemonStatus.getHttpResponseCode() != 200)) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.COMMUNICATION_ERROR;
- statusDescription = "ZoneMinder Server Daemon not running";
+ } catch (UnknownHostException e) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "Unknown host - Check configuration";
+ status = ZoneMinderConnectionStatus.BINDING_CONNECTION_INVALID;
+ logger.warn(
+ "{}: context='{}' tag='exception' previousState='OFFLINE' UnknowHostException when connecting to ZoneMinder Server.",
+ getLogIdentifier(), context, e);
+ } catch (IOException e) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "Could not contact host - Check configuration";
+ updateStatus(newStatus, statusDetail, statusDescription);
+
+ status = ZoneMinderConnectionStatus.BINDING_CONNECTION_TIMEOUT;
+ logger.warn(
+ "{}: context='validateConfig' tag='exception' previousState='OFFLINE' Socket connection Timeout.",
+ getLogIdentifier(), e);
+ }
+ return status;
+ }
- logger.debug("{}: {} (state='{}' and ResponseCode='{}')", getLogIdentifier(), statusDescription,
- daemonStatus.getStatus(), daemonStatus.getHttpResponseCode());
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
+ private ZoneMinderConnectionStatus getLastSucceededStatus() {
+ return lastSucceededStatus;
+ }
+
+ private ZoneMinderConnectionStatus getConnectionStatus() {
+ return zmConnectStatus;
+ }
+
+ private void setConnectionStatus(ZoneMinderConnectionStatus newStatus) {
+ zmConnectStatus = newStatus;
+ if (!newStatus.isErrorState()) {
+ lastSucceededStatus = newStatus;
+ }
+ }
+
+ private ZoneMinderConnectionStatus validateConnection(ZoneMinderBridgeServerConfig config) {
+ String context = "validateConnection";
+ ThingStatus newStatus = ThingStatus.OFFLINE;
+ ThingStatusDetail statusDetail = ThingStatusDetail.NONE;
+ String statusDescription = "";
+
+ ZoneMinderConnectionStatus status = ZoneMinderConnectionStatus.BINDING_CONNECTION_INVALID;
+
+ // Is it a retry loop? (Is this step already verified?)
+ // Or is there an unrecoverable error?
+ if ((getLastSucceededStatus().greatherThanEqual(ZoneMinderConnectionStatus.ZONEMINDER_CONNECTION_CREATED))
+ || (getLastSucceededStatus().hasUnrecoverableError())) {
+ return getLastSucceededStatus();
+ }
+
+ try {
+ aquireSession();
+
+ if (getZoneMinderConnection() == null) {
+ zoneMinderConnection = ZoneMinderFactory.CreateConnection(config.getProtocol(), config.getHost(),
+ config.getHttpPort(), config.getTelnetPort(), config.getUserName(), config.getPassword(),
+ config.getStreamingUser(), config.getStreamingPassword(), config.getServerBasePath(),
+ config.getServerApiPath(), HTTP_TIMEOUT);
+
+ logger.debug(
+ "{}: context='{}' - ZoneMinderFactory.CreateConnection() called (Protocol='{}', Host='{}', HttpPort='{}', SocketPort='{}', Path='{}', API='{}')",
+ getLogIdentifier(), context, config.getProtocol(), config.getHost(), config.getHttpPort(),
+ config.getTelnetPort(), config.getServerBasePath(), config.getServerApiPath());
+
+ }
+
+ } catch (ZoneMinderAuthenticationException authenticationException) {
+ String detailedMessage = "";
+ setConnectionStatus(ZoneMinderConnectionStatus.BINDING_CONFIG_INVALID);
+
+ if (authenticationException.getStackTrace() != null) {
+ if (authenticationException.getStackTrace().length > 0) {
+ StackTraceElement ste = authenticationException.getStackTrace()[0];
+ detailedMessage = String.format(" StackTrace='%s'", ste.toString());
}
- // TODO:: Check other things without being harsh????
+ }
+ logger.error(
+ "{}: context='{}' check='FAILED' - Failed to login to ZoneMinder Server. Check provided usercredentials (Exception='{}', {})",
+ getLogIdentifier(), context, authenticationException.getMessage(), detailedMessage,
+ authenticationException);
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "Login to ZoneMinder Server failed. Check provided usercredentials";
+ updateStatus(newStatus, statusDetail, statusDescription);
+ status = ZoneMinderConnectionStatus.SERVER_CREDENTIALS_INVALID;
+ return status;
+
+ } catch (ZoneMinderApiNotEnabledException e) {
+ setConnectionStatus(ZoneMinderConnectionStatus.SERVER_API_DISABLED);
+ logger.error(
+ "{}: context='{}' check='FAILED' - ZoneMinder Server API is not enabled. Enable option in ZoneMinder Server Settings and restart openHAB Binding.",
+ getLogIdentifier(), context, e);
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "ZoneMinder Server 'OPT_USE_API' not enabled";
+ updateStatus(newStatus, statusDetail, statusDescription);
+ status = ZoneMinderConnectionStatus.SERVER_API_DISABLED;
+ return status;
+
+ } catch (ZoneMinderException | Exception e) {
+ logger.error(
+ "{}: context='{}' check='FAILED' - General error when creating ConnectionInfo. Retrying next cycle...",
+ getLogIdentifier(), context, e);
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "ZoneMinder Server Connection error";
+ updateStatus(newStatus, statusDetail, statusDescription);
+ status = ZoneMinderConnectionStatus.GENERAL_ERROR;
+ return status;
- newStatus = ThingStatus.ONLINE;
+ } finally {
+ releaseSession();
+ }
+
+ // Check that we have a connection
+ if (getZoneMinderConnection() != null) {
+ logger.debug("{}: context='{}' previousState='OFFLINE' ZoneMinder Connection check (PASSED)",
+ getLogIdentifier(), context);
+ status = ZoneMinderConnectionStatus.ZONEMINDER_CONNECTION_CREATED;
+ } else {
+ zoneMinderConnection = null;
+ status = ZoneMinderConnectionStatus.BINDING_CONNECTION_INVALID;
+ logger.warn("{}: context='{}' check='FAILED' - Failed to obtain ZoneMinder Connection. Retrying next cycle",
+ getLogIdentifier(), context);
+ }
+
+ return status;
+ }
+
+ public ZoneMinderConnectionStatus validateZoneMinderServerConfig() {
+ IZoneMinderConnectionHandler curSession = null;
+ String context = "validateZoneMinderServerConfig";
+ ThingStatus newStatus = ThingStatus.OFFLINE;
+ ThingStatusDetail statusDetail = ThingStatusDetail.NONE;
+ String statusDescription = "";
+ ZoneMinderConnectionStatus status = ZoneMinderConnectionStatus.GENERAL_ERROR;
+
+ IZoneMinderServer serverProxy = null;
+ try {
+ curSession = aquireSession();
+ if (curSession == null) {
+ logger.error(
+ "{}: context='{}' check='FAILED' - Could not verify ZoneMinder Server Config. Session failed to connect.",
+ getLogIdentifier(), context);
+
+ status = ZoneMinderConnectionStatus.GENERAL_ERROR;
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "Session not available";
+ updateStatus(newStatus, statusDetail, statusDescription);
+ return status;
+ }
+
+ serverProxy = ZoneMinderFactory.getServerProxy(curSession);
+
+ IZoneMinderDaemonStatus daemonStatus = serverProxy.getHostDaemonCheckState();
+
+ // Check if server API can be accessed
+ if (!daemonStatus.getStatus()) {
+ logger.error("{}: context='{}' check='FAILED' - Bridge OFFLINE because server Daemon is not running",
+ getLogIdentifier(), context);
+ status = ZoneMinderConnectionStatus.SERVER_DAEMON_NOT_RUNNING;
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "ZoneMinder Server Daemon not running";
+ updateStatus(newStatus, statusDetail, statusDescription);
+
+ }
+
+ // Verify that 'OPT_TRIGGER' is set to true in ZoneMinder
+ else if (!serverProxy.isTriggerOptionEnabled()) {
+ logger.error(
+ "{}: context='{}' check='FAILED' - Bridge OFFLINE because ZoneMinder Server option 'OPT_TRIGGERS' not enabled",
+ getLogIdentifier(), context);
+ status = ZoneMinderConnectionStatus.SERVER_OPT_TRIGGERS_DISABLED;
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "ZoneMinder Server option 'OPT_TRIGGERS' not enabled";
+ updateStatus(newStatus, statusDetail, statusDescription);
+
+ } else {
+ // Seems like everything is as we want it :-)
+ logger.debug("{}: context='{}' check='PASSED' - ZoneMinder ", getLogIdentifier(), context);
+ status = ZoneMinderConnectionStatus.ZONEMINDER_SERVER_CONFIG_PASSED;
+
+ }
+
+ } catch (ZoneMinderException | Exception ex) {
+ if (ex.getMessage() != null) {
+ logger.error(
+ "{}: context='{}' check='FAILED' - ZoneMinder Server configuration failed to verify. (Exception='{}')",
+ getLogIdentifier(), context, ex.getMessage(), ex.getCause());
+ } else {
+ logger.error("{}: context='{}' check='FAILED' - ZoneMinder Server configuration failed to verify.",
+ getLogIdentifier(), context, ex.getCause());
+ }
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "ZoneMinder Server configuration not verified ";
+ updateStatus(newStatus, statusDetail, statusDescription);
+
+ } finally {
+ releaseSession();
+ }
+ return status;
+ }
+
+ private void initializeAvaliabilityStatus(IZoneMinderConnectionHandler conn) {
+ String context = "initializeAvaliabilityStatus";
+ ZoneMinderBridgeServerConfig config = null;
+
+ ThingStatus newStatus = ThingStatus.OFFLINE;
+ ThingStatusDetail statusDetail = ThingStatusDetail.NONE;
+ String statusDescription = "";
+ ThingStatus currentStatus = getThing().getStatus();
+
+ // Only continue if handler is initialized and status is OFFLINE
+ if ((currentStatus != ThingStatus.OFFLINE) || (!initialized)) {
+ return;
+ }
+
+ /********************************
+ *
+ * Retry handling
+ *
+ *******************************/
+ // An unrecoverable error in the Binding Configuration was found. OR a recoverable has failed and is no
+ // unrecoverable (try again later)
+ if (getConnectionStatus().hasUnrecoverableError() || (initRetriesCount > initMaxRevoverableRetries)) {
+ initRetriesCount++;
+
+ // Reset unrecoverable error and try from beginning
+ if (initRetriesCount > initMaxRevoverableRetries + initMaxUnrecoverableRetries) {
+ initRetriesCount = 0;
+ zoneMinderConnection = null;
+ zoneMinderEventSession = null;
+ setConnectionStatus(ZoneMinderConnectionStatus.UNINITIALIZED);
+
+ // Clear old error information
+ newStatus = ThingStatus.OFFLINE;
statusDetail = ThingStatusDetail.NONE;
- statusDescription = "";
+ statusDescription = "Retrying to connect";
+ updateStatus(newStatus, statusDetail, statusDescription);
+
+ logger.debug("{}: context='{}' state='{}' - Retrying initialization after unrecoverable error",
+ getLogIdentifier(), context, newStatus.toString());
+
}
- // If we are OFFLINE, check everything
- else if (prevStatus == ThingStatus.OFFLINE) {
+ return;
- // Just wait until we are finished initializing
- if (isInitialized == false) {
- _online = _isOnline;
- return;
- }
+ } else if (getConnectionStatus().hasRecoverableError()) {
+ initRetriesCount++;
+ logger.debug("{}: context='{}' state='{}' - Retrying initialization (Last Error='{}', Retries='{}')",
+ getLogIdentifier(), context, newStatus.toString(), getConnectionStatus().toString(),
+ initRetriesCount);
- ZoneMinderBridgeServerConfig config = getBridgeConfig();
+ }
- // Check if server Bridge configuration is valid
- if (config == null) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
- statusDescription = "Configuration not found";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
+ /***********************************
+ *
+ * Verify Binding Configuration
+ *
+ ***********************************/
+ setConnectionStatus(verifyBindingConfiguration(currentStatus));
+ if (!getConnectionStatus().hasPassed(ZoneMinderConnectionStatus.BINDING_CONFIG_LOAD_PASSED)) {
+ return;
+ }
- } else if (config.getHostName() == null) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
- statusDescription = "Host not found in configuration";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
- } else if (config.getProtocol() == null) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
- statusDescription = "Unknown protocol in configuration";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
- }
+ // Great the Bridge Config is valid get started
+ config = getBridgeConfig();
- else if (config.getHttpPort() == null) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
- statusDescription = "Invalid HTTP port";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
- }
+ /***********************************
+ *
+ * Validate Binding Configuration
+ *
+ ***********************************/
+ setConnectionStatus(validateConfig(config));
- else if (config.getTelnetPort() == null) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
- statusDescription = "Invalid telnet port";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
- } else if (!ZoneMinderFactory.isZoneMinderUrl(connection)) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
- statusDescription = "URL not a ZoneMinder Server";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
- }
+ // Check that Status corresponds actual state
+ if (!getConnectionStatus().hasPassed(ZoneMinderConnectionStatus.BINDING_CONFIG_VALIDATE_PASSED)) {
+ return;
+ }
- if (!isZoneMinderLoginValid(connection)) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
- statusDescription = "Cannot access ZoneMinder Server. Check provided usercredentials";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
- }
+ /***********************************
+ *
+ * VALIDATE ZONEMINDER CONNECTION (API + AUTHENTICATION)
+ *
+ ***********************************/
+ setConnectionStatus(validateConnection(config));
- /*
- * Now we will try to establish a session
- */
+ // A previous step failed.
+ if (!getConnectionStatus().hasPassed(ZoneMinderConnectionStatus.ZONEMINDER_CONNECTION_CREATED)) {
+ return;
+ }
+
+ /***********************************
+ *
+ * VALIDATE ZONEMINDER HTTP Session
+ *
+ ***********************************/
+ zmConnectStatus = ZoneMinderConnectionStatus.ZONEMINDER_SESSION_CREATED;
+ // A previous step failed.
+ if (!getConnectionStatus().hasPassed(ZoneMinderConnectionStatus.ZONEMINDER_SESSION_CREATED)) {
+ return;
+ }
+
+ /***********************************
+ *
+ * VALIDATE ZONEMINDER HTTP Session
+ *
+ ***********************************/
+ setConnectionStatus(validateZoneMinderServerConfig());
+ if (!getConnectionStatus().hasPassed(ZoneMinderConnectionStatus.ZONEMINDER_SERVER_CONFIG_PASSED)) {
+ return;
+ }
+
+ /***********************************
+ *
+ * Everything looks fine -> GO ONLINE
+ *
+ ***********************************/
- IZoneMinderSession curSession = null;
+ zmConnectStatus = ZoneMinderConnectionStatus.INITIALIZED;
+ // _zoneMinderSession = curSession;
+ newStatus = ThingStatus.ONLINE;
+ statusDetail = ThingStatusDetail.NONE;
+ statusDescription = "";
+
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, true);
+ logger.debug("{}: context='{}' Successfully established session to ZoneMinder Server.", getLogIdentifier(),
+ context);
+
+ }
+
+ @Override
+ public void updateAvaliabilityStatus(IZoneMinderConnectionHandler conn) {
+ String context = "updateAvaliabilityStatus";
+ IZoneMinderConnectionHandler curSession = null;
+ ThingStatus newStatus = ThingStatus.OFFLINE;
+ ThingStatusDetail statusDetail = ThingStatusDetail.NONE;
+ String statusDescription = "";
+
+ ThingStatus prevStatus = getThing().getStatus();
+ try {
+ // Just perform a health check to see if we are still connected
+ if (prevStatus == ThingStatus.ONLINE) {
try {
- curSession = ZoneMinderFactory.CreateSession(connection);
- } catch (FailedLoginException | IllegalArgumentException | IOException
- | ZoneMinderUrlNotFoundException ex) {
- logger.error("{}: Create Session failed with exception {}", getLogIdentifier(), ex.getMessage());
-
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.COMMUNICATION_ERROR;
- statusDescription = "Failed to connect. (Check Log)";
- if (curBridgeStatus != ThingStatus.OFFLINE) {
- logger.error("{}: Bridge OFFLINE because of '{}' Exception='{}'", getLogIdentifier(),
- statusDescription, ex.getMessage());
+ curSession = aquireSession();
+
+ if (curSession == null) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.COMMUNICATION_ERROR;
+ statusDescription = "Session lost connection to ZoneMinder Server";
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, false);
+ return;
+ } else if (!curSession.isConnected()) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.COMMUNICATION_ERROR;
+ statusDescription = "Session lost connection to ZoneMinder Server";
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, false);
+ return;
}
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
- }
- IZoneMinderServer serverProxy = ZoneMinderFactory.getServerProxy(curSession);
-
- // Check if server API can be accessed
- if (!serverProxy.isApiEnabled()) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
- statusDescription = "ZoneMinder Server 'OPT_USE_API' not enabled";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
- } else if (!serverProxy.getHostDaemonCheckState().getStatus()) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
- statusDescription = "ZoneMinder Server Daemon not running";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
+ else if (!curSession.isAuthenticated()) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.COMMUNICATION_ERROR;
+ statusDescription = "Not authenticated";
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, false);
+ return;
+ }
+
+ IZoneMinderServer serverProxy = ZoneMinderFactory.getServerProxy(curSession);
+ IZoneMinderHostVersion hostVersion = null;
+ try {
+ hostVersion = serverProxy.getHostVersion();
+ } catch (ZoneMinderException ex) {
+ hostVersion = null;
+ }
+
+ if ((hostVersion == null) || (hostVersion.getHttpStatus() >= 400)) {
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.COMMUNICATION_ERROR;
+ statusDescription = "Connection to ZoneMinder Server was lost";
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, false);
+
+ logger.error("{}: Lost connection to ZoneMinder server.", getLogIdentifier());
+
+ setConnected(false);
+ }
+
+ // Check if ZoneMinder Server Daemon is running
+ if (!serverProxy.isDaemonRunning()) {
+ logger.error("{}: context='{}' Bridge OFFLINE because ZoneMinder Server Daemon stopped",
+ getLogIdentifier(), context);
+ zmConnectStatus = ZoneMinderConnectionStatus.SERVER_DAEMON_NOT_RUNNING;
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "ZoneMinder Server Daemon stopped";
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, false);
+ // setConnected(false);
+ return;
+ }
+ // Verify that 'OPT_TRIGGER' is set to true in ZoneMinder
+ else if (!serverProxy.isTriggerOptionEnabled()) {
+ logger.error(
+ "{}: context='{}' Bridge OFFLINE because ZoneMinder Server OPT_TRIGGER was disabled",
+ getLogIdentifier(), context);
+ zmConnectStatus = ZoneMinderConnectionStatus.SERVER_OPT_TRIGGERS_DISABLED;
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "Option external triggers 'OPT_TRIGGERS' was disabled";
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, false);
+ return;
+ }
+ // Check if ZoneMinder Server API can be accessed
+ else if (!serverProxy.isApiEnabled()) {
+ logger.error("{}: context='{}' Bridge OFFLINE because ZoneMinder Server API was disabled",
+ getLogIdentifier(), context);
+ zmConnectStatus = ZoneMinderConnectionStatus.SERVER_API_DISABLED;
+ newStatus = ThingStatus.OFFLINE;
+ statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
+ statusDescription = "ZoneMinder Server API was disabled";
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, false);
+ return;
+ }
+
+ } finally {
+ releaseSession();
}
- // Verify that 'OPT_TRIGGER' is set to true in ZoneMinder
- else if (!serverProxy.isTriggerOptionEnabled()) {
- newStatus = ThingStatus.OFFLINE;
- statusDetail = ThingStatusDetail.CONFIGURATION_ERROR;
- statusDescription = "ZoneMinder Server option 'OPT_TRIGGERS' not enabled";
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
- return;
- } else {
- // Seems like everything is as we want it :-)
- _isOnline = true;
+
+ newStatus = ThingStatus.ONLINE;
+ statusDetail = ThingStatusDetail.NONE;
+ statusDescription = "";
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, true);
+
+ // Ask all child things to update their Availability Status
+ for (Thing thing : getThing().getThings()) {
+ ZoneMinderBaseThingHandler thingHandler = (ZoneMinderBaseThingHandler) thing.getHandler();
+ if (thingHandler instanceof ZoneMinderThingMonitorHandler) {
+ try {
+ thingHandler.updateAvaliabilityStatus(getZoneMinderConnection());
+ } catch (Exception ex) {
+ logger.debug("{}: Failed to call 'updateAvailabilityStatus()' for '{}'", getLogIdentifier(),
+ thingHandler.getThing().getUID());
+ }
+ }
}
- if (_isOnline == true) {
- zoneMinderSession = curSession;
- _online = _isOnline;
+ } else if (prevStatus == ThingStatus.OFFLINE) {
+ initializeAvaliabilityStatus(conn);
+
+ if (getConnectionStatus() == ZoneMinderConnectionStatus.INITIALIZED) {
newStatus = ThingStatus.ONLINE;
statusDetail = ThingStatusDetail.NONE;
statusDescription = "";
-
- } else {
- zoneMinderSession = null;
- _online = _isOnline;
- newStatus = ThingStatus.OFFLINE;
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, true);
}
}
-
} catch (Exception ex) {
+ // Hmmm We shouldn't really end here.
+ logger.error(
+ "{}: context='updateAvailablilityStatus' Exception occurred in updateAvailabilityStatus Exception='{}'",
+ getLogIdentifier(), ex.getMessage(), ex.getCause());
+ zmConnectStatus = ZoneMinderConnectionStatus.GENERAL_ERROR;
newStatus = ThingStatus.OFFLINE;
statusDetail = ThingStatusDetail.COMMUNICATION_ERROR;
- logger.error("{}: Exception occurred in updateAvailabilityStatus Exception='{}'", getLogIdentifier(),
- ex.getMessage());
- statusDescription = "Error occurred (Check log)";
-
- }
- updateBridgeStatus(newStatus, statusDetail, statusDescription);
-
- // Ask child things to update their Availability Status
- for (Thing thing : getThing().getThings()) {
- ZoneMinderBaseThingHandler thingHandler = (ZoneMinderBaseThingHandler) thing.getHandler();
- if (thingHandler instanceof ZoneMinderThingMonitorHandler) {
- try {
- thingHandler.updateAvaliabilityStatus(connection);
- } catch (Exception ex) {
- logger.debug("{}: Failed to call 'updateAvailabilityStatus()' for '{}'", getLogIdentifier(),
- thingHandler.getThing().getUID());
- }
- }
-
+ statusDescription = "General error occurred (Check log)";
+ updateBridgeStatus(newStatus, statusDetail, statusDescription, true);
}
}
- protected void updateBridgeStatus(ThingStatus newStatus, ThingStatusDetail statusDetail, String statusDescription) {
+ protected void updateBridgeStatus(ThingStatus newStatus, ThingStatusDetail statusDetail, String statusDescription,
+ boolean updateConnection) {
ThingStatusInfo curStatusInfo = thing.getStatusInfo();
String curDescription = StringUtils.isBlank(curStatusInfo.getDescription()) ? ""
: curStatusInfo.getDescription();
// Status changed
if ((curStatusInfo.getStatus() != newStatus) || (curStatusInfo.getStatusDetail() != statusDetail)
- || (curDescription != statusDescription)) {
-
- // if (thing.getStatus() != newStatus) {
- logger.info("{}: Bridge status changed from '{}' to '{}'", getLogIdentifier(), thing.getStatus(),
- newStatus);
-
- if ((newStatus == ThingStatus.ONLINE) && (curStatusInfo.getStatus() != ThingStatus.ONLINE)) {
- try {
- setBridgeConnectionStatus(true);
- onConnected();
- } catch (IllegalArgumentException e) {
- // Just ignore that here
- }
- } else if ((newStatus == ThingStatus.OFFLINE) && (curStatusInfo.getStatus() != ThingStatus.OFFLINE)) {
- try {
- setBridgeConnectionStatus(false);
- onDisconnected();
- } catch (IllegalArgumentException e) {
- // Just ignore that here
- }
-
+ || (!curDescription.equals(statusDescription))) {
+ if (!curStatusInfo.getStatus().equals(newStatus)) {
+ logger.info("{}: context='updateBridgeStatus' Bridge status changed from '{}' to '{}'",
+ getLogIdentifier(), thing.getStatus(), newStatus);
}
+
// Update Status correspondingly
if ((newStatus == ThingStatus.OFFLINE) && (statusDetail != ThingStatusDetail.NONE)) {
updateStatus(newStatus, statusDetail, statusDescription);
+
+ forcedPriority = RefreshPriority.UNKNOWN;
+ if (updateConnection) {
+ try {
+ setConnected(false);
+ } catch (IllegalArgumentException | GeneralSecurityException | IOException
+ | ZoneMinderUrlNotFoundException e) {
+ logger.error(
+ "{}: context='updateBridgeStatus' Exception occurred when changing connected status",
+ getLogIdentifier(), e);
+ }
+ }
} else {
updateStatus(newStatus);
+ forcedPriority = RefreshPriority.PRIORITY_BATCH;
+ if (updateConnection) {
+ try {
+ setConnected(true);
+ } catch (IllegalArgumentException | GeneralSecurityException | IOException
+ | ZoneMinderUrlNotFoundException e) {
+ logger.error(
+ "{}: context='updateBridgeStatus' Exception occurred when changing connected status",
+ getLogIdentifier(), e);
+ }
+ }
}
- curBridgeStatus = newStatus;
- }
- }
-
- protected boolean isZoneMinderLoginValid(IZoneMinderConnectionInfo connection) {
- try {
- return ZoneMinderFactory.validateLogin(connection);
- } catch (Exception e) {
- return false;
+ // Ask all child things to update their Availability Status, since Bridge has changed
+ for (Thing thing : getThing().getThings()) {
+ ZoneMinderBaseThingHandler thingHandler = (ZoneMinderBaseThingHandler) thing.getHandler();
+ if (thingHandler instanceof ZoneMinderThingMonitorHandler) {
+ try {
+ thingHandler.updateAvaliabilityStatus(getZoneMinderConnection());
+ } catch (Exception ex) {
+ logger.debug(
+ "{}: context='updateBridgeStatus' Failed to call 'updateAvailabilityStatus' for '{}' (Exception='{}')",
+ getLogIdentifier(), thingHandler.getThing().getUID(), ex.getMessage());
+ }
+ }
+ }
}
-
}
@Override
public void updateChannel(ChannelUID channel) {
State state = null;
try {
-
switch (channel.getId()) {
case ZoneMinderConstants.CHANNEL_ONLINE:
updateState(channel, (isOnline() ? OnOffType.ON : OnOffType.OFF));
break;
case ZoneMinderConstants.CHANNEL_SERVER_DISKUSAGE:
- state = getServerDiskUsageState();
+ if (getBridgeConfig().getDiskUsageRefresh() != RefreshPriority.DISABLED) {
+ state = getServerDiskUsageState();
+ } else {
+ state = UnDefType.UNDEF;
+ }
break;
case ZoneMinderConstants.CHANNEL_SERVER_CPULOAD:
@@ -901,58 +1305,91 @@ public void updateChannel(ChannelUID channel) {
}
if (state != null) {
- logger.debug("{}: BridgeHandler.updateChannel(): Updating channel '{}' to state='{}'",
- getLogIdentifier(), channel.getId(), state.toString());
updateState(channel.getId(), state);
}
} catch (Exception ex) {
-
- logger.error("{}: Error when 'updateChannel()' was called for thing='{}' (Exception='{}'",
+ logger.error(
+ "{}: context='updateChannel' Error when 'updateChannel()' was called for thing='{}' (Exception='{}'",
getLogIdentifier(), channel.getId(), ex.getMessage());
+ }
+ }
+
+ public void subscribeMonitorEvents(ZoneMinderThingMonitorHandler monitorHandler) {
+ try {
+ if (zoneMinderEventSession != null) {
+ logger.info("{}: context='SubscribeMonitorEvents' thing='monitor' id='{}'", getLogIdentifier(),
+ monitorHandler.getZoneMinderId());
+
+ zoneMinderEventSession.subscribeMonitorEvents(zoneMinderConnection, monitorHandler.getZoneMinderId(),
+ monitorHandler);
+ } else {
+ logger.warn(
+ "{}: context='SubscribeMonitorEvents' thing='monitor' id='{}' - Could not subscribe to monitor events, because EventSession not initialisaed",
+ getLogIdentifier(), monitorHandler.getZoneMinderId());
+ }
+ } catch (IllegalArgumentException | GeneralSecurityException | IOException | ZoneMinderUrlNotFoundException e) {
+ logger.error(
+ "{}: context='SubscribeMonitorEvents' - Exception occurred when subscribing for MonitorEvents. Exception='{}'",
+ getLogIdentifier(), e.getMessage());
}
}
- protected boolean openConnection() {
- boolean connected = false;
- if (isConnected() == false) {
- logger.debug("{}: Connecting Bridge to ZoneMinder Server", getLogIdentifier());
+ public void unsubscribeMonitorEvents(ZoneMinderThingMonitorHandler monitorHandler) {
+ try {
+ if (zoneMinderEventSession != null) {
+ zoneMinderEventSession.unsubscribeMonitorEvents(monitorHandler.getZoneMinderId(), monitorHandler);
- try {
- if (isConnected()) {
- closeConnection();
- }
- setConnected(connected);
+ logger.info("{}: context='UnsubscribeMonitorEvents' thing='monitor' id='{}'", getLogIdentifier(),
+ monitorHandler.getZoneMinderId());
- logger.info("{}: Connecting to ZoneMinder Server (result='{}'", getLogIdentifier(), connected);
+ } else {
+ logger.warn(
+ "{}: context='UnsubscribeMonitorEvents' thing='monitor' id='{}' - Could not unsubscribe to monitor events, because EventSession not initialisaed",
+ getLogIdentifier(), monitorHandler.getZoneMinderId());
+ }
+ } catch (Exception ex) {
+ logger.error(
+ "{}: context='SubscribeMonitorEvents' - Exception occurred when subscribing for MonitorEvents.",
+ getLogIdentifier(), ex);
+ }
- } catch (Exception exception) {
- logger.error("{}: openConnection(): Exception: ", getLogIdentifier(), exception);
- setConnected(false);
- } finally {
- if (isConnected() == false) {
- closeConnection();
- }
+ }
+
+ public void activateForceAlarm(String monitorId, Integer priority, String reason, String note, String showText,
+ Integer timeoutSeconds) {
+ try {
+ if (zoneMinderEventSession != null) {
+ zoneMinderEventSession.activateForceAlarm(monitorId, priority, reason, note, showText, timeoutSeconds);
+ } else {
+ logger.error("{}: context='activateForceAlarm' No EventSession active for Monitor with Id='{}'",
+ getLogIdentifier(), monitorId);
}
+ } catch (IOException ex) {
+ logger.error("{}: context='activateForceAlarm' tag='exception' - Call to activeForceAlarm failed",
+ getLogIdentifier(), ex);
}
- return isConnected();
+
}
- synchronized void closeConnection() {
+ public void deactivateForceAlarm(String monitorId) {
try {
- logger.debug("{}: closeConnection(): Closed HTTP Connection!", getLogIdentifier());
- setConnected(false);
+ if (zoneMinderEventSession != null) {
+ zoneMinderEventSession.deactivateForceAlarm(monitorId);
+ } else {
+ logger.error("{}: context='deactivateForceAlarm' No EventSession active for Monitor with Id='{}'",
+ getLogIdentifier(), monitorId);
+ }
- } catch (Exception exception) {
- logger.error("{}: closeConnection(): Error closing connection - {}", getLogIdentifier(),
- exception.getMessage());
+ } catch (Exception ex) {
+ logger.error("{}: context='deactivateForceAlarm' tag='exception' - Call to deactiveForceAlarm failed",
+ getLogIdentifier(), ex);
}
}
protected State getServerCpuLoadState() {
-
State state = UnDefType.UNDEF;
try {
@@ -962,14 +1399,13 @@ protected State getServerCpuLoadState() {
} catch (Exception ex) {
// Deliberately kept as debug info!
- logger.debug("{}: Exception='{}'", getLogIdentifier(), ex.getMessage());
+ logger.debug("{}: context='getServerCpuLoadState' Exception='{}'", getLogIdentifier(), ex.getMessage());
}
return state;
}
protected State getServerDiskUsageState() {
-
State state = UnDefType.UNDEF;
try {
@@ -978,21 +1414,56 @@ protected State getServerDiskUsageState() {
}
} catch (Exception ex) {
// Deliberately kept as debug info!
- logger.debug("{}: Exception {}", getLogIdentifier(), ex.getMessage());
+ logger.debug("{}: context='getServerDiskUsageState' Exception {}", getLogIdentifier(), ex.getMessage());
}
return state;
}
@Override
- public void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionInfo connection) {
- logger.info("{}: Brigde went ONLINE", getLogIdentifier());
+ public void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionHandler connection) {
+ IZoneMinderConnectionHandler session = null;
+ try {
+ session = aquireSession();
+
+ IZoneMinderServer serverProxy = ZoneMinderFactory.getServerProxy(session);
+ ZoneMinderConfig cfgPathZms = serverProxy.getConfig(ZoneMinderConfigEnum.ZM_PATH_ZMS);
+ ZoneMinderConfig cfgOptFrameServer = serverProxy.getConfig(ZoneMinderConfigEnum.ZM_OPT_FRAME_SERVER);
+ logger.debug("{}: context='onBridgeConnected' Api Enabled : {}", getLogIdentifier(),
+ zoneMinderConnection.isApiEnabled());
+ logger.debug("{}: context='onBridgeConnected' Authentication Enabled : {}", getLogIdentifier(),
+ zoneMinderConnection.isAuthenticationEnabled());
+ logger.debug("{}: context='onBridgeConnected' AuthHash Allowed : {}", getLogIdentifier(),
+ zoneMinderConnection.getAuthenticationHashAllowed());
+ if (zoneMinderConnection.getAuthenticationHashAllowed()) {
+ logger.debug("{}: context='onBridgeConnected' AuthHash Relay : {}", getLogIdentifier(),
+ zoneMinderConnection.getAuthenticationHashReleayMethod().toString());
+ }
+ logger.debug("{}: context='onBridgeConnected' Portal URI: {}", getLogIdentifier(),
+ zoneMinderConnection.getPortalUri().toString());
+ logger.debug("{}: context='onBridgeConnected' API URI: {}", getLogIdentifier(),
+ zoneMinderConnection.getApiUri().toString());
+ logger.debug("{}: context='onBridgeConnected' ZMS URI: {}", getLogIdentifier(),
+ cfgPathZms.getValueAsString());
+ logger.debug("{}: context='onBridgeConnected' FrameServer: {}", getLogIdentifier(),
+ cfgOptFrameServer.getvalueAsBoolean());
+ } catch (ZoneMinderException | Exception ex) {
+ logger.error(
+ "{}: context='onBridgeConnected' Exception occurred when calling 'onBridgeConencted()' Message='{}'",
+ getLogIdentifier(), ex.getMessage(), ex.getCause());
+
+ } finally {
+ if (session != null) {
+ releaseSession();
+ }
+ }
try {
// Start the discovery service
if (discoveryService == null) {
discoveryService = new ZoneMinderDiscoveryService(this, 30);
}
+
discoveryService.activate();
if (discoveryRegistration == null) {
@@ -1001,45 +1472,29 @@ public void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderC
discoveryService, new Hashtable());
}
} catch (Exception e) {
- logger.error("BRIDGE [{}]: Exception occurred when starting discovery service Exception='{}'", getThingId(),
- e.getMessage());
+ logger.error("{}: context='onBridgeConnected' Exception occurred when starting discovery service",
+ getLogIdentifier(), e.getCause());
}
- if (taskRefreshData == null) {
-
- // Perform first refresh manually (we want to force update of DiskUsage)
- boolean updateDiskUsage = (getBridgeConfig().getRefreshIntervalLowPriorityTask() > 0) ? true : false;
- refreshThing(zoneMinderSession, updateDiskUsage);
-
- if (getBridgeConfig().getRefreshIntervalLowPriorityTask() != 0) {
- refreshFrequency = calculateCommonRefreshFrequency(getBridgeConfig().getRefreshInterval());
- } else {
- refreshFrequency = getBridgeConfig().getRefreshInterval();
- }
- logger.info("BRIDGE [{}]: Calculated refresh inetrval to '{}'", getThingId(), refreshFrequency);
-
- if (taskRefreshData != null) {
- taskRefreshData.cancel(true);
- taskRefreshData = null;
- }
-
- // Start job to handle next updates
- taskRefreshData = startTask(refreshDataRunnable, refreshFrequency, refreshFrequency, TimeUnit.SECONDS);
+ try {
+ // Update properties
+ updateServerProperties();
+ } catch (Exception e) {
+ logger.error(
+ "{}: method='onBridgeConnected' context='updateServerProperties' Exception occurred when starting discovery service",
+ getLogIdentifier(), e.getCause());
- if (taskPriorityRefreshData != null) {
- taskPriorityRefreshData.cancel(true);
- taskPriorityRefreshData = null;
- }
+ }
- // Only start if Priority Frequency is higher than ordinary
- if (refreshFrequency > 1) {
- taskPriorityRefreshData = startTask(refreshPriorityDataRunnable, 0, 1, TimeUnit.SECONDS);
- }
+ if (taskRefreshData != null) {
+ taskRefreshData.cancel(true);
+ taskRefreshData = null;
}
- // Update properties
- updateMonitorProperties(zoneMinderSession);
+ // Start job to handle next updates
+ taskRefreshData = startTask(refreshDataRunnable, 1, 1, TimeUnit.SECONDS);
+
}
@Override
@@ -1056,13 +1511,6 @@ public void onBridgeDisconnected(ZoneMinderServerBridgeHandler bridge) {
logger.debug("{}: Stopping DataRefresh task", getLogIdentifier());
}
- // Stopping High priority thread while OFFLINE
- if (taskPriorityRefreshData != null) {
- taskPriorityRefreshData.cancel(true);
- taskPriorityRefreshData = null;
- logger.debug("{}: Stopping Priority DataRefresh task", getLogIdentifier());
- }
-
// Make sure everything gets refreshed
for (Channel ch : getThing().getChannels()) {
handleCommand(ch.getUID(), RefreshType.REFRESH);
@@ -1085,7 +1533,7 @@ public void onBridgeDisconnected(ZoneMinderServerBridgeHandler bridge) {
* Method to start a data refresh task.
*/
protected ScheduledFuture> startTask(Runnable command, long delay, long interval, TimeUnit unit) {
- logger.debug("BRIDGE [{}]: Starting ZoneMinder Bridge Monitor Task. Command='{}'", getThingId(),
+ logger.debug("{}: Starting ZoneMinder Bridge Monitor Task. Command='{}'", getLogIdentifier(),
command.toString());
if (interval == 0) {
return null;
@@ -1106,56 +1554,69 @@ protected void stopTask(ScheduledFuture> task) {
}
} catch (Exception ex) {
}
-
}
- public ArrayList getMonitors() {
- if (isOnline()) {
-
- IZoneMinderServer serverProxy = ZoneMinderFactory.getServerProxy(zoneMinderSession);
- ArrayList result = serverProxy.getMonitors();
+ public ArrayList getMonitors() {
+ if (isConnected()) {
+ IZoneMinderServer serverProxy = null;
+ try {
+ serverProxy = ZoneMinderFactory.getServerProxy(aquireSession());
+ ArrayList result = serverProxy.getMonitors();
+ return result;
+ } catch (ZoneMinderGeneralException | ZoneMinderResponseException | ZoneMinderInvalidData
+ | ZoneMinderAuthenticationException ex) {
+ logger.error("{}: context='getMonitors' Exception occurred", getLogIdentifier(), ex.getCause());
- return result;
+ } finally {
+ if (serverProxy != null) {
+ releaseSession();
+ }
+ }
}
- return new ArrayList();
+ return new ArrayList<>();
}
- /*
- * This is experimental
- * Try to add different properties
- */
- private void updateMonitorProperties(IZoneMinderSession session) {
+ private void updateServerProperties() {
+ if (!isConnected()) {
+ return;
+ }
+
// Update property information about this device
Map properties = editProperties();
- IZoneMinderServer serverProxy = ZoneMinderFactory.getServerProxy(session);
+ IZoneMinderConnectionHandler session = null;
IZoneMinderHostVersion hostVersion = null;
try {
+ session = aquireSession();
+ IZoneMinderServer serverProxy = ZoneMinderFactory.getServerProxy(session);
+
hostVersion = serverProxy.getHostVersion();
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- serverProxy.getHttpUrl(), serverProxy.getHttpResponseCode(), serverProxy.getHttpResponseMessage());
+ if (hostVersion.getHttpStatus() != HttpStatus.OK_200) {
+ return;
+ }
ZoneMinderConfig configUseApi = serverProxy.getConfig(ZoneMinderConfigEnum.ZM_OPT_USE_API);
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- serverProxy.getHttpUrl(), serverProxy.getHttpResponseCode(), serverProxy.getHttpResponseMessage());
ZoneMinderConfig configUseAuth = serverProxy.getConfig(ZoneMinderConfigEnum.ZM_OPT_USE_AUTH);
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- serverProxy.getHttpUrl(), serverProxy.getHttpResponseCode(), serverProxy.getHttpResponseMessage());
-
ZoneMinderConfig configTrigerrs = serverProxy.getConfig(ZoneMinderConfigEnum.ZM_OPT_TRIGGERS);
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- configUseApi.getHttpUrl(), configUseApi.getHttpResponseCode(),
- configUseApi.getHttpResponseMessage());
+ ZoneMinderConfig configAllowHashLogin = serverProxy.getConfig(ZoneMinderConfigEnum.ZM_AUTH_HASH_LOGINS);
+ ZoneMinderConfig configFrameServer = serverProxy.getConfig(ZoneMinderConfigEnum.ZM_OPT_FRAME_SERVER);
properties.put(ZoneMinderProperties.PROPERTY_SERVER_VERSION, hostVersion.getVersion());
properties.put(ZoneMinderProperties.PROPERTY_SERVER_API_VERSION, hostVersion.getApiVersion());
properties.put(ZoneMinderProperties.PROPERTY_SERVER_USE_API, configUseApi.getValueAsString());
properties.put(ZoneMinderProperties.PROPERTY_SERVER_USE_AUTHENTIFICATION, configUseAuth.getValueAsString());
+ properties.put(ZoneMinderProperties.PROPERTY_SERVER_USE_AUTH_HASH, configAllowHashLogin.getValueAsString());
properties.put(ZoneMinderProperties.PROPERTY_SERVER_TRIGGERS_ENABLED, configTrigerrs.getValueAsString());
- } catch (FailedLoginException | ZoneMinderUrlNotFoundException | IOException e) {
- logger.warn("{}: Exception occurred when updating monitor properties (Exception='{}'", getLogIdentifier(),
- e.getMessage());
+ properties.put(ZoneMinderProperties.PROPERTY_SERVER_FRAME_SERVER, configFrameServer.getValueAsString());
+
+ } catch (ZoneMinderUrlNotFoundException | IOException | ZoneMinderGeneralException | ZoneMinderResponseException
+ | ZoneMinderInvalidData | ZoneMinderAuthenticationException e) {
+ logger.warn("{}: Exception occurred when updating monitor properties", getLogIdentifier(), e);
+ } finally {
+ if (session != null) {
+ releaseSession();
+ }
}
// Must loop over the new properties since we might have added data
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderThingMonitorHandler.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderThingMonitorHandler.java
index 306ad59298796..0217b73920ab6 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderThingMonitorHandler.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderThingMonitorHandler.java
@@ -8,19 +8,13 @@
*/
package org.openhab.binding.zoneminder.handler;
-import java.io.IOException;
import java.math.BigDecimal;
-import java.security.GeneralSecurityException;
+import java.net.MalformedURLException;
import java.util.Map;
import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.security.auth.login.FailedLoginException;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.thing.Bridge;
-import org.eclipse.smarthome.core.thing.Channel;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatus;
@@ -32,26 +26,36 @@
import org.eclipse.smarthome.core.types.UnDefType;
import org.openhab.binding.zoneminder.ZoneMinderConstants;
import org.openhab.binding.zoneminder.ZoneMinderProperties;
-import org.openhab.binding.zoneminder.internal.DataRefreshPriorityEnum;
+import org.openhab.binding.zoneminder.internal.RefreshPriority;
import org.openhab.binding.zoneminder.internal.config.ZoneMinderThingMonitorConfig;
+import org.openhab.binding.zoneminder.internal.state.ChannelStateChangeSubscriber;
+import org.openhab.binding.zoneminder.internal.state.MonitorThingState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Sets;
-import name.eskildsen.zoneminder.IZoneMinderConnectionInfo;
-import name.eskildsen.zoneminder.IZoneMinderDaemonStatus;
-import name.eskildsen.zoneminder.IZoneMinderEventData;
+import name.eskildsen.zoneminder.IZoneMinderConnectionHandler;
import name.eskildsen.zoneminder.IZoneMinderEventSubscriber;
import name.eskildsen.zoneminder.IZoneMinderMonitor;
-import name.eskildsen.zoneminder.IZoneMinderMonitorData;
-import name.eskildsen.zoneminder.IZoneMinderSession;
+import name.eskildsen.zoneminder.IZoneMinderServer;
import name.eskildsen.zoneminder.ZoneMinderFactory;
-import name.eskildsen.zoneminder.api.event.ZoneMinderEvent;
+import name.eskildsen.zoneminder.api.monitor.ZoneMinderMonitorStatus;
import name.eskildsen.zoneminder.api.telnet.ZoneMinderTriggerEvent;
+import name.eskildsen.zoneminder.common.ZoneMinderConfigEnum;
import name.eskildsen.zoneminder.common.ZoneMinderMonitorFunctionEnum;
-import name.eskildsen.zoneminder.common.ZoneMinderMonitorStatusEnum;
-import name.eskildsen.zoneminder.exception.ZoneMinderUrlNotFoundException;
+import name.eskildsen.zoneminder.data.IMonitorDataGeneral;
+import name.eskildsen.zoneminder.data.IMonitorDataStillImage;
+import name.eskildsen.zoneminder.data.IZoneMinderDaemonStatus;
+import name.eskildsen.zoneminder.data.IZoneMinderEventData;
+import name.eskildsen.zoneminder.data.ZoneMinderConfig;
+import name.eskildsen.zoneminder.exception.ZoneMinderAuthHashNotEnabled;
+import name.eskildsen.zoneminder.exception.ZoneMinderAuthenticationException;
+import name.eskildsen.zoneminder.exception.ZoneMinderException;
+import name.eskildsen.zoneminder.exception.ZoneMinderGeneralException;
+import name.eskildsen.zoneminder.exception.ZoneMinderInvalidData;
+import name.eskildsen.zoneminder.exception.ZoneMinderResponseException;
+import name.eskildsen.zoneminder.internal.ZoneMinderContentResponse;
/**
* The {@link ZoneMinderThingMonitorHandler} is responsible for handling commands, which are
@@ -59,7 +63,8 @@
*
* @author Martin S. Eskildsen - Initial contribution
*/
-public class ZoneMinderThingMonitorHandler extends ZoneMinderBaseThingHandler implements IZoneMinderEventSubscriber {
+public class ZoneMinderThingMonitorHandler extends ZoneMinderBaseThingHandler
+ implements ChannelStateChangeSubscriber, IZoneMinderEventSubscriber {
public static final Set SUPPORTED_THING_TYPES = Sets
.newHashSet(ZoneMinderConstants.THING_TYPE_THING_ZONEMINDER_MONITOR);
@@ -68,32 +73,19 @@ public class ZoneMinderThingMonitorHandler extends ZoneMinderBaseThingHandler im
private static final int MAX_MONITOR_STATUS_WATCH_COUNT = 3;
/** Make sure we can log errors, warnings or what ever somewhere */
- private Logger logger = LoggerFactory.getLogger(ZoneMinderThingMonitorHandler.class);
+ private final Logger logger = LoggerFactory.getLogger(ZoneMinderThingMonitorHandler.class);
+ private RefreshPriority forcedPriority = RefreshPriority.DISABLED;
private String lastMonitorStatus = MONITOR_STATUS_NOT_INIT;
private Integer monitorStatusMatchCount = 3;
private ZoneMinderThingMonitorConfig config;
- private Boolean _running = false;
-
- private ZoneMinderEvent curEvent = null;
+ MonitorThingState dataConverter = new MonitorThingState(this);
- /**
- * Channels
- */
- private ZoneMinderMonitorFunctionEnum channelFunction = ZoneMinderMonitorFunctionEnum.NONE;
- private Boolean channelEnabled = false;
- private boolean channelRecordingState = false;
- private boolean channelAlarmedState = false;
- private String channelEventCause = "";
- private ZoneMinderMonitorStatusEnum channelMonitorStatus = ZoneMinderMonitorStatusEnum.UNKNOWN;
- private boolean channelDaemonCapture = false;
- private boolean channelDaemonAnalysis = false;
- private boolean channelDaemonFrame = false;
- private boolean channelForceAlarm = false;
-
- private int forceAlarmManualState = -1;
+ private long lastRefreshGeneralData = 0;
+ private long lastRefreshStillImage = 0;
+ private boolean frameDaemonActive = false;
public ZoneMinderThingMonitorHandler(Thing thing) {
super(thing);
@@ -103,6 +95,15 @@ public ZoneMinderThingMonitorHandler(Thing thing) {
@Override
public void dispose() {
+ try {
+ ZoneMinderServerBridgeHandler bridge = getZoneMinderBridgeHandler();
+ logger.info("{}: Unsubscribing from Monitor Events: {}", getLogIdentifier(),
+ bridge.getThing().getUID().getAsString());
+ bridge.unsubscribeMonitorEvents(this);
+
+ } catch (Exception ex) {
+ logger.error("{}: Exception occurred when calling 'onBridgeDisonnected()'.", getLogIdentifier(), ex);
+ }
}
@Override
@@ -117,63 +118,119 @@ public String getZoneMinderId() {
}
@Override
- public void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionInfo connection)
- throws IllegalArgumentException, GeneralSecurityException, IOException, ZoneMinderUrlNotFoundException {
-
+ public void onBridgeConnected(ZoneMinderServerBridgeHandler bridge, IZoneMinderConnectionHandler connection) {
try {
- logger.info("{}: Bridge '{}' connected", getLogIdentifier(), bridge.getThing().getUID().getAsString());
+ logger.debug("{}: 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.info("{}: Add subsription for Monitor Events: {}", getLogIdentifier(),
+ bridge.getThing().getUID().getAsString());
+ bridge.subscribeMonitorEvents(this);
+
+ IZoneMinderServer serverProxy = ZoneMinderFactory.getServerProxy(connection);
+ ZoneMinderConfig cfg = serverProxy.getConfig(ZoneMinderConfigEnum.ZM_OPT_FRAME_SERVER);
+ frameDaemonActive = cfg.getvalueAsBoolean();
+ } catch (ZoneMinderGeneralException | ZoneMinderResponseException | ZoneMinderAuthenticationException
+ | ZoneMinderInvalidData ex) {
+ logger.error("{}: context='onBridgeConnected' error in call to 'getServerProxy' - Message='{}'",
+ getLogIdentifier(), ex.getMessage(), ex.getCause());
+
+ } catch (MalformedURLException e) {
+ logger.error("{}: context='onBridgeConnected' error in call to 'getServerProxy' - Message='{}' (Exception)",
+ getLogIdentifier(), e.getMessage(), e.getCause());
+ }
- 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);
+ @Override
+ public void onBridgeDisconnected(ZoneMinderServerBridgeHandler bridge) {
+ try {
+ logger.debug("{}: Bridge '{}' disconnected", getLogIdentifier(), bridge.getThing().getUID().getAsString());
- } catch (Exception ex) {
- logger.error("{}: Exception occurred when calling 'onBridgeConencted()'. Exception='{}'",
- getLogIdentifier(), ex.getMessage());
+ super.onBridgeDisconnected(bridge);
- } finally {
- releaseSession();
+ } catch (Exception ex) {
+ logger.error("{}: Exception occurred when calling 'onBridgeDisonencted()'.", getLogIdentifier(), ex);
}
}
@Override
- public void onBridgeDisconnected(ZoneMinderServerBridgeHandler bridge) {
- try {
- logger.info("{}: Bridge '{}' disconnected", getLogIdentifier(), bridge.getThing().getUID().getAsString());
+ public void onThingStatusChanged(ThingStatus thingStatus) {
+ if (thingStatus == ThingStatus.ONLINE) {
+ IZoneMinderConnectionHandler connection = null;
+ try {
+ connection = aquireSessionWait();
+ IZoneMinderMonitor monitor = ZoneMinderFactory.getMonitorProxy(connection, config.getZoneMinderId());
+ IMonitorDataGeneral 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());
+ } catch (ZoneMinderInvalidData | ZoneMinderAuthenticationException | ZoneMinderGeneralException
+ | ZoneMinderResponseException ex) {
+ logger.error("{}: context='onThingStatusChanged' error in call to 'getMonitorData' - Message='{}'",
+ getLogIdentifier(), ex.getMessage(), ex.getCause());
+
+ } finally {
+ if (connection != null) {
+ releaseSession();
+ }
+ }
- logger.info("{}: Unsubscribing from Monitor Events: {}", getLogIdentifier(),
- bridge.getThing().getUID().getAsString());
- ZoneMinderFactory.UnsubscribeMonitorEvents(config.getZoneMinderId(), this);
+ try {
+ updateMonitorProperties();
- logger.debug("{}: Calling parent onBridgeConnected()", getLogIdentifier());
- super.onBridgeDisconnected(bridge);
+ } catch (Exception ex) {
+ logger.error(
+ "{}: context='onThingStatusChanged' - Exception occurred when calling 'updateMonitorPropoerties()'. Exception='{}'",
+ getLogIdentifier(), ex.getMessage());
+
+ }
+ }
+ }
+ @Override
+ public void channelLinked(ChannelUID channelUID) {
+ try {
+ if (!channelUID.getId().equals(ZoneMinderConstants.CHANNEL_ONLINE)) {
+ dataConverter.subscribe(channelUID);
+ }
+ super.channelLinked(channelUID);
+
+ logger.info("{}: context='channelLinked' - Unlinking from channel '{}'", getLogIdentifier(),
+ channelUID.getAsString());
} catch (Exception ex) {
- logger.error("{}: Exception occurred when calling 'onBridgeDisonencted()'. Exception='{}'",
- getLogIdentifier(), ex.getMessage());
+ logger.info("{}: context='channelUnlinked' - Exception when Unlinking from channel '{}' - EXCEPTION)'{}'",
+ getLogIdentifier(), channelUID.getAsString(), ex.getMessage());
}
}
+ @Override
+ public void channelUnlinked(ChannelUID channelUID) {
+ try {
+ dataConverter.unsubscribe(channelUID);
+ super.channelUnlinked(channelUID);
+ logger.info("{}: context='channelUnlinked' - Unlinking from channel '{}'", getLogIdentifier(),
+ channelUID.getAsString());
+ } catch (Exception ex) {
+ logger.info("{}: context='channelUnlinked' - Exception when Unlinking from channel '{}' - EXCEPTION)'{}'",
+ getLogIdentifier(), channelUID.getAsString(), ex.getMessage());
+
+ }
+ }
+
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
+ IZoneMinderMonitor monitorProxy = null;
try {
-
logger.debug("{}: Channel '{}' in monitor '{}' received command='{}'", getLogIdentifier(), channelUID,
getZoneMinderId(), command);
@@ -185,112 +242,193 @@ public void handleCommand(ChannelUID channelUID, Command command) {
// 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();
+ IZoneMinderConnectionHandler connection = null;
+ try {
+ // Force Alarm can only be activated when Function is either NODECT or MODECT
+ if ((dataConverter.getMonitorFunction() == ZoneMinderMonitorFunctionEnum.MODECT)
+ || (dataConverter.getMonitorFunction() == ZoneMinderMonitorFunctionEnum.NODECT)) {
+ logger.debug(
+ "{}: 'handleCommand' => CHANNEL_MONITOR_FORCE_ALARM: Command '{}' received for monitor '{}'",
+ getLogIdentifier(), command, channelUID.getId());
+
+ if ((command == OnOffType.OFF) || (command == OnOffType.ON)) {
+ dataConverter.setMonitorForceAlarmInternal((command == OnOffType.ON) ? true : false);
+ String eventText = getConfigValueAsString(
+ ZoneMinderConstants.PARAMETER_MONITOR_EVENTTEXT);
+
+ BigDecimal eventTimeout = getConfigValueAsBigDecimal(
+ ZoneMinderConstants.PARAMETER_MONITOR_TRIGGER_TIMEOUT);
+
+ try {
+ connection = aquireSession();
+ if (connection == null) {
+ logger.error(
+ "{}: context='handleCommand' tags='ForceAlarm' - Command='{}' failed to obtain session",
+ getLogIdentifier(), command);
+ return;
+ }
+ monitorProxy = ZoneMinderFactory.getMonitorProxy(connection, getZoneMinderId());
+
+ if (command == OnOffType.ON) {
+ logger.info("{}: Activate 'ForceAlarm' to '{}' (Reason='{}', Timeout='{}')",
+ getLogIdentifier(), command, eventText, eventTimeout.intValue());
+
+ getZoneMinderBridgeHandler().activateForceAlarm(getZoneMinderId(), 255,
+ ZoneMinderConstants.MONITOR_EVENT_OPENHAB, eventText, "",
+ eventTimeout.intValue());
+
+ dataConverter.setMonitorForceAlarmInternal(true);
+
+ // Force a refresh
+ startAlarmRefresh(eventTimeout.intValue());
+
+ }
+
+ else if (command == OnOffType.OFF) {
+ logger.debug("{}: Cancel 'ForceAlarm'", getLogIdentifier());
+
+ getZoneMinderBridgeHandler().deactivateForceAlarm(getZoneMinderId());
+ dataConverter.setMonitorForceAlarmInternal(false);
+ // Stop Alarm Refresh
+ forceStopAlarmRefresh();
+
+ }
+ fetchMonitorGeneralData(monitorProxy);
+
+ } catch (Exception ex) {
+ logger.error(
+ "{}: Context='handleCommand' Channel='{}' EXCEPTION: Call to 'ForceAlarm' Command='{}' failed",
+ getLogIdentifier(), channelUID.getId(), command, ex);
+ }
}
+ } else {
+ logger.warn(
+ "{}: context='handleCommand' tag='CHANNEL_MONITOR_FORCE_ALARM' is inactive when function is not 'MODECT' or 'NODECT'",
+ getLogIdentifier());
- } finally {
+ }
+ } catch (Exception ex) {
+ logger.error("{}: context='handleCommand' tag='CHANNEL_MONITOR_FORCE_ALARM'",
+ getLogIdentifier());
+ } finally {
+ if (monitorProxy != null) {
+ monitorProxy = null;
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();
-
+ requestChannelRefresh();
}
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();
- }
+ try {
+ logger.debug(
+ "{}:context='handleCommand' tag='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);
+
+ ZoneMinderContentResponse zmcr = null;
+ try {
+ monitorProxy = ZoneMinderFactory.getMonitorProxy(aquireSession(), getZoneMinderId());
+ if (monitorProxy == null) {
+ logger.error(
+ "{}: Connection to ZoneMinder Server was lost when handling command '{}'. Restart openHAB",
+ getLogIdentifier(), command);
+ return;
+ }
+ zmcr = monitorProxy.SetEnabled(newState);
+ logger.debug("{}: ResponseCode='{}' ResponseMessage='{}' URL='{}'", getLogIdentifier(),
+ zmcr.getHttpStatus(), zmcr.getHttpResponseMessage(), zmcr.getHttpRequestUrl());
+
+ } catch (ZoneMinderException ex) {
+ logger.error(
+ "{}: context='handleCommand' error in call to 'SetEnabled' ExceptionClass='{}' - Message='{}'",
+ getLogIdentifier(), ex.getClass().getCanonicalName(), ex.getMessage(),
+ ex.getCause());
+ } finally {
+ if (monitorProxy != null) {
+ monitorProxy = null;
+ releaseSession();
+ }
+ }
- channelEnabled = newState;
+ dataConverter.setMonitorEnabled(newState);
- logger.info("{}: Setting enabled to '{}'", getLogIdentifier(), command);
- }
+ logger.info(
+ "{}: context='handleCommand' tags='enabled' - Successfully changed function setting to '{}'",
+ getLogIdentifier(), command);
+ }
+ } catch (Exception ex) {
+ logger.error("{}: Exception in 'handleCommand' => 'CHANNEL_MONITOR_ENABLE' Exception='{}'",
+ getLogIdentifier(), ex.getMessage());
- handleCommand(channelUID, RefreshType.REFRESH);
+ } finally {
+ requestChannelRefresh();
+ }
break;
case ZoneMinderConstants.CHANNEL_MONITOR_FUNCTION:
- String commandString = "";
- if (ZoneMinderMonitorFunctionEnum.isValid(command.toString())) {
+ try {
+ logger.debug(
+ "{}: context='handleCommand' tag='CHANNEL_MONITOR_FUNCTION' Command '{}' received for monitor '{}'",
+ getLogIdentifier(), command, channelUID.getId());
+
+ String commandString = "";
+ if (ZoneMinderMonitorFunctionEnum.isValid(command.toString())) {
+ commandString = ZoneMinderMonitorFunctionEnum.getEnum(command.toString()).toString();
+ ZoneMinderContentResponse zmcr = null;
+ try {
+ // Change Function for camera in ZoneMinder
+ monitorProxy = ZoneMinderFactory.getMonitorProxy(aquireSession(), getZoneMinderId());
+ if (monitorProxy == null) {
+ logger.error(
+ "{}: Connection to ZoneMinder Server was lost when handling command '{}'. Restart openHAB",
+ getLogIdentifier(), command);
+ return;
+ }
+
+ zmcr = monitorProxy.SetFunction(commandString);
+
+ logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
+ zmcr.getHttpRequestUrl(), zmcr.getHttpStatus(), zmcr.getHttpResponseMessage());
+
+ fetchMonitorGeneralData(monitorProxy);
+ fetchMonitorDaemonStatus(true, true, monitorProxy);
+
+ } catch (ZoneMinderAuthenticationException | ZoneMinderGeneralException
+ | ZoneMinderResponseException ex) {
+ } finally {
+ if (monitorProxy != null) {
+ monitorProxy = null;
+ releaseSession();
+ }
+ }
- commandString = ZoneMinderMonitorFunctionEnum.getEnum(command.toString()).toString();
- ZoneMinderServerBridgeHandler bridge = getZoneMinderBridgeHandler();
+ dataConverter.setMonitorFunction(ZoneMinderMonitorFunctionEnum.getEnum(command.toString()));
- IZoneMinderMonitor monitorProxy = ZoneMinderFactory.getMonitorProxy(aquireSession(),
- getZoneMinderId());
- try {
- monitorProxy.SetFunction(commandString);
- } finally {
- releaseSession();
- }
+ logger.debug(
+ "{}: context='handleCommand' tags='function' - Successfully changed function setting to '{}'",
+ getLogIdentifier(), commandString);
- // Make sure local copy is set to new value
- channelFunction = ZoneMinderMonitorFunctionEnum.getEnum(command.toString());
+ } else {
+ logger.error(
+ "{}: Value '{}' for monitor channel is not valid. Accepted values is: 'None', 'Monitor', 'Modect', Record', 'Mocord', 'Nodect'",
+ getLogIdentifier(), commandString);
+ }
+ } catch (Exception ex) {
+ logger.error("{}: Exception in 'handleCommand' => 'CHANNEL_MONITOR_FUNCTION'",
+ getLogIdentifier(), ex.getCause());
- logger.info("{}: Setting function to '{}'", getLogIdentifier(), commandString);
+ } finally {
+ requestChannelRefresh();
- } 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.
@@ -310,19 +448,28 @@ else if (command == OnOffType.OFF) {
break;
}
} catch (Exception ex) {
- logger.error("{}: handleCommand: Command='{}' failed for channel='{}' Exception='{}'", getLogIdentifier(),
- command, channelUID.getId(), ex.getMessage());
+ logger.error("{}: handleCommand: Command='{}' failed for channel='{}'", getLogIdentifier(), command,
+ channelUID.getId(), ex);
}
}
@Override
public void initialize() {
-
try {
- super.initialize();
this.config = getMonitorConfig();
- logger.info("{}: ZoneMinder Monitor Handler Initialized", getLogIdentifier());
- logger.debug("{}: Monitor Id: {}", getLogIdentifier(), config.getZoneMinderId());
+
+ super.initialize();
+ logger.info("{}: context='initialize' Monitor Handler Initialized", getLogIdentifier());
+
+ dataConverter.addChannel(getChannelUIDFromChannelId(ZoneMinderConstants.CHANNEL_MONITOR_FORCE_ALARM));
+ dataConverter.addChannel(getChannelUIDFromChannelId(ZoneMinderConstants.CHANNEL_MONITOR_EVENT_CAUSE));
+ dataConverter.addChannel(getChannelUIDFromChannelId(ZoneMinderConstants.CHANNEL_MONITOR_RECORD_STATE));
+ dataConverter.addChannel(getChannelUIDFromChannelId(ZoneMinderConstants.CHANNEL_MONITOR_MOTION_EVENT));
+ dataConverter.addChannel(getChannelUIDFromChannelId(ZoneMinderConstants.CHANNEL_MONITOR_DETAILED_STATUS));
+ dataConverter.addChannel(getChannelUIDFromChannelId(ZoneMinderConstants.CHANNEL_MONITOR_ENABLED));
+ dataConverter.addChannel(getChannelUIDFromChannelId(ZoneMinderConstants.CHANNEL_MONITOR_FUNCTION));
+ dataConverter.addChannel(getChannelUIDFromChannelId(ZoneMinderConstants.CHANNEL_MONITOR_EVENT_STATE));
+
} catch (Exception ex) {
logger.error("{}: Exception occurred when calling 'initialize()'. Exception='{}'", getLogIdentifier(),
ex.getMessage());
@@ -332,24 +479,73 @@ public void initialize() {
@Override
public void onTrippedForceAlarm(ZoneMinderTriggerEvent event) {
try {
- logger.info("{}: Received forceAlarm for monitor {}", getLogIdentifier(), event.getMonitorId());
- Channel channel = this.getThing().getChannel(ZoneMinderConstants.CHANNEL_MONITOR_DETAILED_STATUS);
- Channel chEventCause = this.getThing().getChannel(ZoneMinderConstants.CHANNEL_MONITOR_EVENT_CAUSE);
+ logger.debug("{}: context='onTrippedForceAlarm' Received forceAlarm for monitor {}", getLogIdentifier(),
+ event.getMonitorId());
+
+ if (!isThingOnline()) {
+ logger.warn("{}: context='onTrippedForceAlarm' Skipping event '{}', because Thing is 'OFFLINE'",
+ getLogIdentifier(), event.toString());
+ return;
+ }
+
+ IZoneMinderEventData eventData = null;
// Set Current Event to actual event
if (event.getState()) {
- startPriorityRefresh();
+ IZoneMinderConnectionHandler connection = null;
+ try {
+ connection = aquireSession();
+ IZoneMinderMonitor monitorProxy = ZoneMinderFactory.getMonitorProxy(connection, getZoneMinderId());
+ eventData = monitorProxy.getEventById(event.getEventId());
+
+ logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
+ eventData.getHttpRequestUrl(), eventData.getHttpStatus(),
+ eventData.getHttpResponseMessage());
+
+ } catch (Exception ex) {
+ logger.error(
+ "{}: context='onTrippedForceAlarm' tag='session' Exception occurred when aquiring session - Exception='{}'",
+ getLogIdentifier(), ex.getMessage());
+
+ } catch (ZoneMinderInvalidData | ZoneMinderAuthenticationException | ZoneMinderGeneralException
+ | ZoneMinderResponseException ex) {
+ logger.error(
+ "{}: context='onTrippedForceAlarm' error in call to 'getMonitorProxy' ExceptionClass='{}' - Message='{}'",
+ getLogIdentifier(), ex.getClass().getCanonicalName(), ex.getMessage(), ex.getCause());
+ } finally {
+ if (connection != null) {
+ releaseSession();
+ }
+
+ }
+ dataConverter.disableRefresh();
+ dataConverter.setMonitorForceAlarmExternal(event.getState());
+ dataConverter.setMonitorEventData(eventData);
+ dataConverter.enableRefresh();
+
+ forceStartAlarmRefresh();
} else {
- curEvent = null;
+ dataConverter.disableRefresh();
+
+ dataConverter.setMonitorForceAlarmExternal(event.getState());
+ dataConverter.setMonitorEventData(null);
+ dataConverter.enableRefresh();
+ forceStopAlarmRefresh();
}
+
} catch (Exception ex) {
- logger.error("{}: Exception occurred inTrippedForceAlarm() Exception='{}'", getLogIdentifier(),
- ex.getMessage());
+ logger.error("{}: context='onTrippedForceAlarm' Exception occurred inTrippedForceAlarm() Exception='{}'",
+ getLogIdentifier(), ex.getMessage());
}
}
+ @Override
+ protected void updateState(ChannelUID channelUID, State state) {
+ super.updateState(channelUID, state);
+ }
+
protected ZoneMinderThingMonitorConfig getMonitorConfig() {
return this.getConfigAs(ZoneMinderThingMonitorConfig.class);
}
@@ -359,41 +555,9 @@ protected String getZoneMinderThingType() {
return ZoneMinderConstants.THING_ZONEMINDER_MONITOR;
}
- private Boolean isDaemonRunning(Boolean daemonStatus, String daemonStatusText) {
- Boolean result = false;
-
- Pattern pattern = Pattern
- .compile("[0-9]{2}/[0-9]{2}/[0-9]{2}\\s+([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]");
-
- Matcher matcher = pattern.matcher(daemonStatusText);
-
- if (matcher.find()) {
-
- String currentMonitorStatus = daemonStatusText.substring(matcher.start(), matcher.end());
- if (lastMonitorStatus.equals(currentMonitorStatus)) {
- monitorStatusMatchCount++;
- } else if (lastMonitorStatus.equals(MONITOR_STATUS_NOT_INIT)) {
- // We have just started, so we will assume that the monitor is running (don't set match count
- // to Zero)
- monitorStatusMatchCount++;
- lastMonitorStatus = daemonStatusText.substring(matcher.start(), matcher.end());
- } else {
- monitorStatusMatchCount = 0;
- lastMonitorStatus = daemonStatusText.substring(matcher.start(), matcher.end());
- }
- }
-
- else {
- monitorStatusMatchCount = 0;
- lastMonitorStatus = "";
- logger.debug("MONITOR-{}: Online(): No match found in status text.", getLogIdentifier());
- }
- return daemonStatus;
- }
-
@Override
- public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
- // Assume succes
+ public void updateAvaliabilityStatus(IZoneMinderConnectionHandler connection) {
+ // Assume success
ThingStatus newThingStatus = ThingStatus.ONLINE;
ThingStatusDetail thingStatusDetailed = ThingStatusDetail.NONE;
String thingStatusDescription = "";
@@ -401,20 +565,9 @@ public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
ThingStatus curThingStatus = this.getThing().getStatus();
boolean connectionStatus = false;
+
// Is connected to ZoneMinder and thing is ONLINE
if (isConnected() && curThingStatus == ThingStatus.ONLINE) {
- updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
- return;
- }
-
- try {
- connectionStatus = 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;
}
@@ -425,14 +578,14 @@ public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
// 1. Is there a Bridge assigned?
if (getBridge() == null) {
msg = String.format("No Bridge assigned to monitor '%s'", thing.getUID());
- logger.error("{}: {}", getLogIdentifier(), msg);
+ logger.error("{}: context='updateAvailabilityStatus' {}", 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)",
+ logger.debug(
+ "{}: context='updateAvailabilityStatus' ThingAvailability: Thing '{}' has Bridge '{}' defined (Check PASSED)",
getLogIdentifier(), thing.getUID(), getBridge().getBridgeUID());
}
@@ -442,12 +595,12 @@ public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
newThingStatus = ThingStatus.OFFLINE;
thingStatusDetailed = ThingStatusDetail.BRIDGE_OFFLINE;
thingStatusDescription = msg;
- updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
- logger.error("{}: {}", getLogIdentifier(), msg);
+ logger.error("{}: context='updateAvailabilityStatus' {}", getLogIdentifier(), msg);
return;
} else {
- logger.debug("{}: ThingAvailability: Bridge '{}' is ONLINE (Check PASSED)", getLogIdentifier(),
- getBridge().getBridgeUID());
+ logger.debug(
+ "{}: context='updateAvailabilityStatus' ThingAvailability: Bridge '{}' is ONLINE (Check PASSED)",
+ getLogIdentifier(), getBridge().getBridgeUID());
}
// 3. Is Configuration OK?
@@ -456,12 +609,12 @@ public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
newThingStatus = ThingStatus.OFFLINE;
thingStatusDetailed = ThingStatusDetail.CONFIGURATION_ERROR;
thingStatusDescription = msg;
- updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
- logger.error("{}: {}", getLogIdentifier(), msg);
+ logger.error("{}: context='updateAvailabilityStatus' {}", getLogIdentifier(), msg);
return;
} else {
- logger.debug("{}: ThingAvailability: Thing '{}' has valid configuration (Check PASSED)",
+ logger.debug(
+ "{}: context='updateAvailabilityStatus' ThingAvailability: Thing '{}' has valid configuration (Check PASSED)",
getLogIdentifier(), thing.getUID());
}
@@ -471,39 +624,27 @@ public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
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)",
+ logger.debug(
+ "{}: context='updateAvailabilityStatus' 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;
- }
-
+ // Consider also looking at Analysis and Frame Daemons (only if they are supposed to be running)
+ IZoneMinderConnectionHandler curSession = connection;
if (curSession != null) {
monitorProxy = ZoneMinderFactory.getMonitorProxy(curSession, getZoneMinderId());
captureDaemon = monitorProxy.getCaptureDaemonStatus();
+ logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
+ captureDaemon.getHttpRequestUrl(), captureDaemon.getHttpStatus(),
+ captureDaemon.getHttpResponseMessage());
+
}
if (captureDaemon == null) {
@@ -511,7 +652,6 @@ public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
newThingStatus = ThingStatus.OFFLINE;
thingStatusDetailed = ThingStatusDetail.COMMUNICATION_ERROR;
thingStatusDescription = msg;
- updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
logger.error("{}: {}", getLogIdentifier(), msg);
return;
} else if (!captureDaemon.getStatus()) {
@@ -519,25 +659,24 @@ public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
newThingStatus = ThingStatus.OFFLINE;
thingStatusDetailed = ThingStatusDetail.COMMUNICATION_ERROR;
thingStatusDescription = msg;
- updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
logger.error("{}: {}", getLogIdentifier(), msg);
return;
}
newThingStatus = ThingStatus.ONLINE;
-
- } catch (Exception exception) {
+ forcedPriority = RefreshPriority.PRIORITY_BATCH;
+ } catch (ZoneMinderException | 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());
+ logger.error("{}: context='updateAvailabilityStatus' Exception occurred '{}'", getLogIdentifier(),
+ exception.getMessage());
return;
+ } finally {
+ updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
}
-
- updateThingStatus(newThingStatus, thingStatusDetailed, thingStatusDescription);
}
/*
@@ -549,53 +688,32 @@ public void updateAvaliabilityStatus(IZoneMinderConnectionInfo connection) {
*/
@Override
public void updateChannel(ChannelUID channel) {
- State state = null;
+ State state = UnDefType.UNDEF;
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;
+ return;
+
+ case ZoneMinderConstants.CHANNEL_MONITOR_ENABLED:
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_MOTION_EVENT:
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);
+ case ZoneMinderConstants.CHANNEL_MONITOR_STILL_IMAGE:
+ state = null;
break;
+ case ZoneMinderConstants.CHANNEL_MONITOR_VIDEOURL:
+ state = dataConverter.getVideoUrl();
+ break;
default:
logger.warn("{}: updateChannel(): Monitor '{}': No handler defined for channel='{}'",
getLogIdentifier(), thing.getLabel(), channel.getAsString());
@@ -605,14 +723,11 @@ public void updateChannel(ChannelUID 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.toString(), state.toString(), ex.getMessage());
+ logger.error("{}: context='updateChannel' Error when updating channelId='{}' state='{}'",
+ getLogIdentifier(), channel.toString(), state.toString(), ex);
}
}
@@ -624,265 +739,451 @@ public void updateStatus(ThingStatus status) {
}
- 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;
+ private long getLastRefreshGeneralData() {
+ return lastRefreshGeneralData;
+ }
- case PRE_ALARM:
- alarmedDetailedState = true;
- recordingDetailedState = true;
- channelForceAlarm = false;
- break;
+ private long getLastRefreshStillImage() {
+ return lastRefreshStillImage;
+ }
- case ALARM:
- alarmedDetailedState = true;
- recordingDetailedState = true;
- channelForceAlarm = true;
- break;
+ private boolean refreshGeneralData() {
+ long now = System.currentTimeMillis();
+ long lastUpdate = getLastRefreshGeneralData();
- case ALERT:
- alarmedDetailedState = true;
- recordingDetailedState = true;
- channelForceAlarm = false;
- break;
+ // Normal refresh interval
+ int interval = 10000;
- case RECORDING:
- alarmedDetailedState = false;
- recordingDetailedState = true;
- channelForceAlarm = false;
- break;
+ if (!isInitialized()) {
+ return true;
}
- logger.debug(
- "{}: Recalculate channel states based on Detailed State: DetailedState='{}' -> alarmState='{}', recordingState='{}'",
- getLogIdentifier(), channelMonitorStatus.name(), alarmedDetailedState, recordingDetailedState);
+ if (dataConverter.isAlarmed()) {
+ // Alarm refresh interval
+ interval = 1000;
+ }
+ return ((now - lastUpdate) > interval) ? true : false;
+ }
- // Check if Force alarm was initialed from openHAB
- if (forceAlarmManualState == 0) {
- if (channelForceAlarm) {
- channelForceAlarm = false;
- } else {
- forceAlarmManualState = -1;
- }
- } else if (forceAlarmManualState == 1) {
+ private boolean refreshStillImage() {
+ RefreshPriority priority;
+ long now = System.currentTimeMillis();
+ long lastUpdate = getLastRefreshStillImage();
- if (channelForceAlarm == false) {
- channelForceAlarm = true;
- } else {
- forceAlarmManualState = -1;
- }
+ // Normal refresh interval
+ int interval = 10000;
+ if (!isInitialized()) {
+ return true;
+ }
+ if (dataConverter.isAlarmed()) {
+ priority = getMonitorConfig().getImageRefreshEvent();
+ } else {
+ priority = getMonitorConfig().getImageRefreshIdle();
}
+ switch (priority) {
+ case DISABLED:
+ return false;
+
+ case PRIORITY_BATCH:
+ interval = 1000 * 60 * 60;
+ break;
+
+ case PRIORITY_LOW:
+ interval = 1000 * 60;
+ break;
+
+ case PRIORITY_NORMAL:
+ interval = 1000 * 10;
+ break;
- // Now we can conclude on the Alarmed and Recording channel state
- channelRecordingState = (recordingFunction && recordingDetailedState && channelEnabled);
- channelAlarmedState = (alarmedFunction && alarmedDetailedState && channelEnabled);
+ case PRIORITY_HIGH:
+ interval = 1000 * 5;
+ break;
+ case PRIORITY_ALARM:
+ interval = 1000;
+ break;
+ default:
+ return false;
+ }
+ return ((now - lastUpdate) > interval) ? true : false;
}
@Override
- protected void onFetchData() {
+ protected void onFetchData(RefreshPriority cyclePriority) {
+ IZoneMinderConnectionHandler session = null;
+ IMonitorDataGeneral data = null;
- IZoneMinderSession session = null;
+ boolean refreshChannels = false;
- session = aquireSession();
- try {
- IZoneMinderMonitor monitorProxy = ZoneMinderFactory.getMonitorProxy(session, getZoneMinderId());
+ if (getThing().getStatus() != ThingStatus.ONLINE) {
+ return;
+ }
- IZoneMinderMonitorData data = null;
- IZoneMinderDaemonStatus captureDaemon = null;
- IZoneMinderDaemonStatus analysisDaemon = null;
- IZoneMinderDaemonStatus frameDaemon = null;
+ RefreshPriority curRefreshPriority = RefreshPriority.DISABLED;
- data = monitorProxy.getMonitorData();
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(),
- monitorProxy.getHttpResponseMessage());
+ if (forcedPriority == RefreshPriority.UNKNOWN) {
+ return;
+ }
- captureDaemon = monitorProxy.getCaptureDaemonStatus();
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(),
- monitorProxy.getHttpResponseMessage());
+ if (forcedPriority == RefreshPriority.DISABLED) {
+ curRefreshPriority = cyclePriority;
+ } else {
+ curRefreshPriority = forcedPriority;
+ forcedPriority = RefreshPriority.DISABLED;
+ }
- analysisDaemon = monitorProxy.getAnalysisDaemonStatus();
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(),
- monitorProxy.getHttpResponseMessage());
+ session = null;
+ try {
+ session = aquireSession();
+ if (session == null) {
+ logger.warn("{}: Failed to aquire session for refresh, refresh loop for monitor will be skipped.",
+ getLogIdentifier());
+ return;
+ }
- frameDaemon = monitorProxy.getFrameDaemonStatus();
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(),
- monitorProxy.getHttpResponseMessage());
+ } catch (Exception ex) {
+ logger.error("{}: Exception occurred when aquiring exception. Refresh loop for monitor will be skipped.",
+ getLogIdentifier(), ex.getCause());
+ return;
+ }
- if ((data.getHttpResponseCode() != 200) || (captureDaemon.getHttpResponseCode() != 200)
- || (analysisDaemon.getHttpResponseCode() != 200) || (frameDaemon.getHttpResponseCode() != 200)) {
+ IZoneMinderMonitor monitorProxy = ZoneMinderFactory.getMonitorProxy(session, getZoneMinderId());
+ dataConverter.disableRefresh();
+ /**************************
+ *
+ * Perform refresh of monitor data
+ **************************/
- if (data.getHttpResponseCode() != 200) {
- logger.warn("{}: HTTP Response MonitorData: Code='{}', Message'{}'", getLogIdentifier(),
- data.getHttpResponseCode(), data.getHttpResponseMessage());
+ if (refreshGeneralData()) {
+ refreshChannels = true;
+ fetchMonitorGeneralData(monitorProxy);
- 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());
+ fetchMonitorDaemonStatus(true, true, monitorProxy);
+ }
+ if (isLinked(ZoneMinderConstants.CHANNEL_MONITOR_STILL_IMAGE)) {
+ try {
+ if (refreshStillImage()) {
+ lastRefreshStillImage = System.currentTimeMillis();
+ IMonitorDataStillImage monitorImage = monitorProxy.getMonitorStillImage(config.getImageScale(),
+ 1000, null);
+ logger.debug("{}: context='onFetchData' tag='image' URL='{}' ResponseCode='{}'", getLogIdentifier(),
+ monitorImage.getHttpRequestUrl(), monitorImage.getHttpStatus());
+
+ dataConverter.setMonitorStillImage(monitorImage.getImage());
}
- if (analysisDaemon.getHttpResponseCode() != 200) {
- channelDaemonAnalysis = false;
+ } catch (MalformedURLException mue) {
+ logger.error(
+ "{}: context='onFetchData' NalformedURL Exception occurred when calling to 'getMonitorStillImage'",
+ getLogIdentifier(), mue.getCause());
+ dataConverter.setMonitorStillImage(null);
+ } catch (Exception ex) {
+ logger.error("{}: context='onFetchData' error in call to 'getMonitorStillImage'", getLogIdentifier(),
+ ex.getCause());
+ dataConverter.setMonitorStillImage(null);
+ } catch (ZoneMinderException ex) {
+ logger.error(
+ "{}: context='onFetchData' error in call to 'getMonitorStillImage' ExceptionClass='{}' - Message='{}'",
+ getLogIdentifier(), ex.getClass().getCanonicalName(), ex.getMessage(), ex.getCause());
+ }
+ } else {
+ dataConverter.setMonitorStillImage(null);
- 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 = "";
- }
+ if (curRefreshPriority.isPriorityActive(RefreshPriority.PRIORITY_LOW))
- 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;
+ {
+ try {
+ if (dataConverter != null) {
+ String str = monitorProxy.getMonitorStreamingPath(config.getImageScale(), 1000, null);
+ dataConverter.setMonitorVideoUrl(str);
}
+ } catch (MalformedURLException e1) {
+ logger.error("{}: MalformedURLException occurred when calling 'getMonitorStreamingPath()'",
+ getLogIdentifier(), e1.getCause());
+
+ } catch (ZoneMinderGeneralException zmge) {
+ logger.error(
+ "{}: context='onFetchData' error in call to 'getMonitorStreamingPath' Exception='{}', Message='{}",
+ getLogIdentifier(), zmge.getClass().getCanonicalName(), zmge.getMessage(), zmge.getCause());
+ } catch (ZoneMinderResponseException zmre) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getMonitorStreamingPath' Exception='{}', Message='{} - Http: Status='{}', Mesage='{}'",
+ getLogIdentifier(), zmre.getClass().getCanonicalName(), zmre.getMessage(), zmre.getHttpStatus(),
+ zmre.getHttpMessage(), zmre.getCause());
+ } catch (ZoneMinderAuthHashNotEnabled zmahne) {
+ logger.error(
+ "{}: context='onFetchData' error in call to 'getMonitorStreamingPath' Exception='{}', Message='{}'",
+ getLogIdentifier(), zmahne.getClass().getCanonicalName(), zmahne.getMessage(),
+ zmahne.getCause());
}
- } finally {
+ }
+
+ if (session != null) {
releaseSession();
+ session = null;
}
+ dataConverter.enableRefresh();
+ if (refreshChannels) {
+ logger.debug("{}: context='onFetchData' - Data has changed, channels need refreshing", getLogIdentifier());
+ requestChannelRefresh();
+ }
+ tryStopAlarmRefresh();
+ }
- RecalculateChannelStates();
+ void fetchMonitorGeneralData(IZoneMinderMonitor proxy) {
+ IZoneMinderMonitor monitorProxy = proxy;
+ boolean doRelase = false;
+ if (monitorProxy == null) {
+ doRelase = true;
+ monitorProxy = ZoneMinderFactory.getMonitorProxy(aquireSession(), getZoneMinderId());
+ }
- if ((channelForceAlarm == false) && (channelAlarmedState == false)
- && (DataRefreshPriorityEnum.HIGH_PRIORITY == getRefreshPriority())) {
- stopPriorityRefresh();
+ try {
+ IMonitorDataGeneral generalData = monitorProxy.getMonitorData();
+ logger.debug("{}: context='onFetchData' tag='monitorData' URL='{}' ResponseCode='{}' ResponseMessage='{}'",
+ getLogIdentifier(), generalData.getHttpRequestUrl(), generalData.getHttpStatus(),
+ generalData.getHttpResponseMessage());
+
+ dataConverter.setMonitorGeneralData(generalData);
+ } catch (ZoneMinderInvalidData zmid) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getMonitorData' Exception='{}' Response='{}', Message='{}'",
+ getLogIdentifier(), zmid.getClass().getCanonicalName(), zmid.getResponseString(), zmid.getMessage(),
+ zmid.getCause());
+ } catch (ZoneMinderAuthenticationException | ZoneMinderGeneralException | ZoneMinderResponseException zme) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getMonitorData' Exception='{}' Message='{}'",
+ getLogIdentifier(), zme.getClass().getCanonicalName(), zme.getMessage(), zme.getCause());
}
+ try {
+ ZoneMinderMonitorStatus status = monitorProxy.getMonitorDetailedStatus();
+
+ logger.debug(
+ "{}: context='onFetchData' tag='detailedStatus' URL='{}' ResponseCode='{}' ResponseMessage='{}'",
+ getLogIdentifier(), status.getHttpRequestUrl(), status.getHttpStatus(),
+ status.getHttpResponseMessage());
+
+ dataConverter.setMonitorDetailedStatus(status.getStatus());
+ } catch (ZoneMinderInvalidData zmid) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getMonitorDetailedStatus' Exception='{}', Message='{}', Response='{}'",
+ getLogIdentifier(), zmid.getClass().getCanonicalName(), zmid.getMessage(), zmid.getResponseString(),
+ zmid.getCause());
+ } catch (ZoneMinderAuthenticationException | ZoneMinderGeneralException | ZoneMinderResponseException zme) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getMonitorDetailedStatus' Exception='{}' Message='{}'",
+ getLogIdentifier(), zme.getClass().getCanonicalName(), zme.getMessage(), zme.getCause());
+ } finally {
+ if (doRelase) {
+ releaseSession();
+ }
+ }
+ lastRefreshGeneralData = System.currentTimeMillis();
}
- protected State getDetailedStatus() {
- State state = UnDefType.UNDEF;
+ void fetchMonitorDaemonStatus(boolean fetchCapture, boolean fetchAnalysisFrame, IZoneMinderMonitor proxy) {
+ IZoneMinderMonitor monitorProxy = proxy;
+ boolean fetchFrame = false;
+ boolean doRelase = false;
+ if (monitorProxy == null) {
+ doRelase = true;
+ monitorProxy = ZoneMinderFactory.getMonitorProxy(aquireSession(), getZoneMinderId());
+ }
try {
- if (channelMonitorStatus == ZoneMinderMonitorStatusEnum.UNKNOWN) {
- state = getChannelStringAsStringState("");
- } else {
- state = getChannelStringAsStringState(channelMonitorStatus.toString());
+ State stateCapture = UnDefType.UNDEF;
+ State stateAnalysis = UnDefType.UNDEF;
+ State stateFrame = UnDefType.UNDEF;
+
+ IZoneMinderDaemonStatus captureDaemon = null;
+ IZoneMinderDaemonStatus analysisDaemon = null;
+ IZoneMinderDaemonStatus frameDaemon = null;
+
+ if (isLinked(ZoneMinderConstants.CHANNEL_MONITOR_CAPTURE_DAEMON_STATE)) {
+ try {
+ if (fetchCapture) {
+ captureDaemon = monitorProxy.getCaptureDaemonStatus();
+ logger.debug(
+ "{}: context='fetchMonitorDaemonStatus' tag='captureDaemon' URL='{}' ResponseCode='{}' ResponseMessage='{}'",
+ getLogIdentifier(), captureDaemon.getHttpRequestUrl(), captureDaemon.getHttpStatus(),
+ captureDaemon.getHttpResponseMessage());
+ stateCapture = (captureDaemon.getStatus() ? OnOffType.ON : OnOffType.OFF);
+ }
+ } catch (ZoneMinderResponseException zmre) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getCaptureDaemonStatus' - Http: Status='{}', Message='{}', ExceptionMessage='{}', Exception='{}', Message={}'",
+ getLogIdentifier(), zmre.getHttpStatus(), zmre.getHttpMessage(), zmre.getExceptionMessage(),
+ zmre.getClass().getCanonicalName(), zmre.getMessage(), zmre.getCause());
+ } catch (ZoneMinderInvalidData zmid) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getCaptureDaemonStatus' - Response='{}', Exception='{}', Message={}'",
+ getLogIdentifier(), zmid.getResponseString(), zmid.getClass().getCanonicalName(),
+ zmid.getMessage(), zmid.getCause());
+
+ } catch (ZoneMinderGeneralException | ZoneMinderAuthenticationException zme) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getCaptureDaemonStatus' - Exception='{}', Message={}' ",
+ getLogIdentifier(), zme.getClass().getCanonicalName(), zme.getMessage(), zme.getCause());
+ } finally {
+ if (captureDaemon != null) {
+ dataConverter.setMonitorCaptureDaemonStatus(stateCapture);
+ }
+
+ }
}
- } catch (Exception ex) {
- logger.debug("{}", ex.getMessage());
- }
+ if (isLinked(ZoneMinderConstants.CHANNEL_MONITOR_ANALYSIS_DAEMON_STATE)) {
+ try {
+ stateAnalysis = UnDefType.UNDEF;
+ if (fetchAnalysisFrame) {
+ analysisDaemon = monitorProxy.getAnalysisDaemonStatus();
+ logger.debug(
+ "{}: context='onFetchData' tag='analysisDaemon' URL='{}' ResponseCode='{}' ResponseMessage='{}'",
+ getLogIdentifier(), analysisDaemon.getHttpRequestUrl(), analysisDaemon.getHttpStatus(),
+ analysisDaemon.getHttpResponseMessage());
+
+ stateAnalysis = (analysisDaemon.getStatus() ? OnOffType.ON : OnOffType.OFF);
+ fetchFrame = true;
+ }
- return state;
+ } catch (ZoneMinderResponseException zmre) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getAnalysisDaemonStatus' - Http: Status='{}', Message='{}', ExceptionMessage='{}', Exception='{}'",
+ getLogIdentifier(), zmre.getHttpStatus(), zmre.getHttpMessage(), zmre.getExceptionMessage(),
+ zmre.getClass().getCanonicalName(), zmre.getCause());
+ } catch (ZoneMinderInvalidData zmid) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getAnalysisDaemonStatus' - Response='{}', Exception='{}'",
+ getLogIdentifier(), zmid.getResponseString(), zmid.getClass().getCanonicalName(),
+ zmid.getCause());
+
+ } catch (ZoneMinderGeneralException | ZoneMinderAuthenticationException zme) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getAnalysisDaemonStatus' - Exception='{}' ",
+ getLogIdentifier(), zme.getClass().getCanonicalName(), zme.getCause());
+ } catch (Exception ex) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' tag='exception' error in call to 'getAnalysisDaemonStatus' - Exception='{}'",
+ getLogIdentifier(), ex.getClass().getCanonicalName(), ex);
+ } finally {
+ dataConverter.setMonitorAnalysisDaemonStatus(stateAnalysis);
+ }
+ }
+
+ if (isLinked(ZoneMinderConstants.CHANNEL_MONITOR_FRAME_DAEMON_STATE)) {
+ try {
+ stateFrame = UnDefType.UNDEF;
+ if ((fetchFrame) && frameDaemonActive) {
+ frameDaemon = monitorProxy.getFrameDaemonStatus();
+ logger.debug(
+ "{}: context='fetchMonitorDaemonStatus' tag='frameDaemon' URL='{}' ResponseCode='{}' ResponseMessage='{}'",
+ getLogIdentifier(), frameDaemon.getHttpRequestUrl(), frameDaemon.getHttpStatus(),
+ frameDaemon.getHttpResponseMessage());
+
+ if (frameDaemon != null) {
+ stateFrame = ((frameDaemon.getStatus() && analysisDaemon.getStatus()) ? OnOffType.ON
+ : OnOffType.OFF);
+ }
+ }
+ } catch (ZoneMinderResponseException zmre) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getFrameDaemonStatus' - Http: Status='{}', Message='{}', ExceptionMessage'{}', Exception='{}'",
+ getLogIdentifier(), zmre.getHttpStatus(), zmre.getHttpMessage(), zmre.getExceptionMessage(),
+ zmre.getClass().getCanonicalName(), zmre.getCause());
+ } catch (ZoneMinderInvalidData zmid) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getFrameDaemonStatus' - Response='{}', Exception='{}'",
+ getLogIdentifier(), zmid.getResponseString(), zmid.getClass().getCanonicalName(),
+ zmid.getCause());
+
+ } catch (ZoneMinderGeneralException | ZoneMinderAuthenticationException zme) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' error in call to 'getFrameDaemonStatus' - Exception='{}'",
+ getLogIdentifier(), zme.getClass().getCanonicalName(), zme.getCause());
+ } catch (Exception ex) {
+ logger.error(
+ "{}: context='fetchMonitorDaemonStatus' tag='exception' error in call to 'getFrameDaemonStatus' - Exception='{}'",
+ getLogIdentifier(), ex.getClass().getCanonicalName(), ex);
+ } finally {
+ dataConverter.setMonitorFrameDaemonStatus(stateFrame);
+ }
+ }
+
+ } finally {
+ if (doRelase) {
+ releaseSession();
+ }
+ }
}
/*
* This is experimental
* Try to add different properties
*/
- private void updateMonitorProperties(IZoneMinderSession session) {
+ private void updateMonitorProperties() {
logger.debug("{}: Update Monitor Properties", getLogIdentifier());
// Update property information about this device
Map properties = editProperties();
- IZoneMinderMonitor monitorProxy = ZoneMinderFactory.getMonitorProxy(session, getZoneMinderId());
- IZoneMinderMonitorData monitorData = monitorProxy.getMonitorData();
- logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
- monitorProxy.getHttpUrl(), monitorProxy.getHttpResponseCode(), monitorProxy.getHttpResponseMessage());
+ IZoneMinderMonitor monitorProxy = null;
+ IMonitorDataGeneral monitorData = null;
+ IZoneMinderConnectionHandler session = null;
+ try {
+ session = aquireSession();
+
+ if (session == null) {
+ logger.error("{}: context='updateMonitorProperties' Unable to aquire session.", getLogIdentifier());
+ return;
+ }
+ monitorProxy = ZoneMinderFactory.getMonitorProxy(session, getZoneMinderId());
+ monitorData = monitorProxy.getMonitorData();
+ logger.debug("{}: URL='{}' ResponseCode='{}' ResponseMessage='{}'", getLogIdentifier(),
+ monitorData.getHttpRequestUrl(), monitorData.getHttpStatus(), monitorData.getHttpResponseMessage());
- properties.put(ZoneMinderProperties.PROPERTY_ID, getLogIdentifier());
- properties.put(ZoneMinderProperties.PROPERTY_MONITOR_NAME, monitorData.getName());
+ } catch (Exception e) {
+ logger.error("{}: Exception occurred when updating monitor properties - Message:{}", getLogIdentifier(),
+ e.getMessage());
- properties.put(ZoneMinderProperties.PROPERTY_MONITOR_SOURCETYPE, monitorData.getSourceType().name());
+ } catch (ZoneMinderException ex) {
+ logger.error(
+ "{}: context='onFetchData' error in call to 'getMonitorData' ExceptionClass='{}' - Message='{}'",
+ getLogIdentifier(), ex.getClass().getCanonicalName(), ex.getMessage(), ex.getCause());
+ } finally {
+ if (session != null) {
+ releaseSession();
+ }
+ }
- 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());
+ if (monitorData != null) {
+ properties.put(ZoneMinderProperties.PROPERTY_ID, getLogIdentifier());
+ properties.put(ZoneMinderProperties.PROPERTY_NAME, monitorData.getName());
- properties.put(ZoneMinderProperties.PROPERTY_MONITOR_IMAGE_WIDTH, monitorData.getWidth());
- properties.put(ZoneMinderProperties.PROPERTY_MONITOR_IMAGE_HEIGHT, monitorData.getHeight());
+ 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 originalProperties = editProperties();
for (String property : properties.keySet()) {
if ((originalProperties.get(property) == null
- || originalProperties.get(property).equals(properties.get(property)) == false)) {
+ || !originalProperties.get(property).equals(properties.get(property)))) {
update = true;
break;
}
}
- if (update == true) {
- logger.debug("{}: Properties synchronised", getLogIdentifier());
+ if (update) {
+ logger.debug("{}: context='updateMonitorProperties' Properties synchronised", getLogIdentifier());
updateProperties(properties);
}
}
@@ -893,14 +1194,28 @@ public String getLogIdentifier() {
try {
if (config != null) {
-
result = String.format("[MONITOR-%s]", config.getZoneMinderId().toString());
}
} catch (Exception ex) {
result = "[MONITOR]";
}
-
return result;
}
+
+ @Override
+ public void onStateChanged(ChannelUID channelUID, State state) {
+ logger.debug("{}: context='onStateChanged' channel='{}' - State changed to '{}'", getLogIdentifier(),
+ channelUID.getAsString(), state.toString());
+ updateState(channelUID.getId(), state);
+ }
+
+ @Override
+ public void onRefreshDisabled() {
+ }
+
+ @Override
+ public void onRefreshEnabled() {
+ }
+
}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderThingType.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderThingType.java
index b8771a14a021f..a3c950154efdc 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderThingType.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/handler/ZoneMinderThingType.java
@@ -11,7 +11,7 @@
/**
* Enumerator for each Bridge and Thing
*
- * @author Martin S. Eskildsen
+ * @author Martin S. Eskildsen - Initial contribution
*/
public enum ZoneMinderThingType {
ZoneMinderServerBridge,
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/DataRefreshPriorityEnum.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/DataRefreshPriorityEnum.java
deleted file mode 100644
index ff968f1bfc42d..0000000000000
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/DataRefreshPriorityEnum.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Copyright (c) 2010-2018 by the respective copyright holders.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- */
-package org.openhab.binding.zoneminder.internal;
-
-/**
- *
- * @author Martin S. Eskildsen - Initial contribution
- */
-public enum DataRefreshPriorityEnum {
- SCHEDULED,
- HIGH_PRIORITY;
-}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/RefreshPriority.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/RefreshPriority.java
new file mode 100644
index 0000000000000..abace17b0fd5f
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/RefreshPriority.java
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.zoneminder.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.openhab.binding.zoneminder.ZoneMinderConstants;
+
+/**
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+public enum RefreshPriority {
+ PRIORITY_BATCH(1),
+ PRIORITY_LOW(2),
+ PRIORITY_NORMAL(3),
+ PRIORITY_HIGH(4),
+ PRIORITY_ALARM(10),
+ DISABLED(0),
+ UNKNOWN(-1);
+
+ private int value;
+ private static Map map = new HashMap<>();
+
+ private RefreshPriority(int value) {
+ this.value = value;
+ }
+
+ public static RefreshPriority valueOf(int pageType) {
+ return (RefreshPriority) map.get(pageType);
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static RefreshPriority fromConfigValue(String value) {
+ if (value.equalsIgnoreCase(ZoneMinderConstants.CONFIG_VALUE_REFRESH_DISABLED)) {
+ return DISABLED;
+ } else if (value.equalsIgnoreCase(ZoneMinderConstants.CONFIG_VALUE_REFRESH_BATCH)) {
+ return RefreshPriority.PRIORITY_BATCH;
+ } else if (value.equalsIgnoreCase(ZoneMinderConstants.CONFIG_VALUE_REFRESH_LOW)) {
+ return RefreshPriority.PRIORITY_LOW;
+ } else if (value.equalsIgnoreCase(ZoneMinderConstants.CONFIG_VALUE_REFRESH_NORMAL)) {
+ return RefreshPriority.PRIORITY_NORMAL;
+ } else if (value.equalsIgnoreCase(ZoneMinderConstants.CONFIG_VALUE_REFRESH_HIGH)) {
+ return RefreshPriority.PRIORITY_HIGH;
+ } else if (value.equalsIgnoreCase(ZoneMinderConstants.CONFIG_VALUE_REFRESH_ALARM)) {
+ return RefreshPriority.PRIORITY_ALARM;
+ }
+ return UNKNOWN;
+
+ }
+
+ public boolean isEqual(RefreshPriority refrenceVal) {
+ if (value == refrenceVal.getValue()) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isLessThan(RefreshPriority refrenceVal) {
+ if (value < refrenceVal.getValue()) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isGreaterThan(RefreshPriority refrenceVal) {
+ if (value > refrenceVal.getValue()) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isPriorityActive(RefreshPriority refrenceVal) {
+ if (value <= refrenceVal.getValue()) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/ZoneMinderConnectionStatus.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/ZoneMinderConnectionStatus.java
new file mode 100644
index 0000000000000..74d3128409101
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/ZoneMinderConnectionStatus.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.openhab.binding.zoneminder.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The {@link ZoneMinderConnectionStatus} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+public enum ZoneMinderConnectionStatus {
+ GENERAL_ERROR(-99),
+ BINDING_CONFIG_INVALID(-98),
+ BINDING_CONNECTION_INVALID(-97),
+ BINDING_SESSION_INVALID(-96),
+
+ SERVER_CREDENTIALS_INVALID(-89),
+ SERVER_API_DISABLED(-88),
+ SERVER_OPT_TRIGGERS_DISABLED(-86),
+ ERROR_RECOVERABLE(-20),
+ SERVER_DAEMON_NOT_RUNNING(-19),
+ BINDING_CONNECTION_TIMEOUT(-1),
+ UNINITIALIZED(0),
+ BINDING_CONFIG_LOAD_PASSED(1),
+ BINDING_CONFIG_VALIDATE_PASSED(2),
+ ZONEMINDER_CONNECTION_CREATED(3),
+ ZONEMINDER_API_ACCESS_PASSED(4),
+ ZONEMINDER_SESSION_CREATED(5),
+ ZONEMINDER_SERVER_CONFIG_PASSED(6),
+ INITIALIZED(10);
+
+ private int value;
+ private static Map map = new HashMap<>();
+
+ private ZoneMinderConnectionStatus(int value) {
+ this.value = value;
+ }
+
+ public static ZoneMinderConnectionStatus valueOf(int pageType) {
+ return (ZoneMinderConnectionStatus) map.get(pageType);
+ }
+
+ public boolean lessThan(ZoneMinderConnectionStatus reference) {
+ return (getValue() < reference.getValue()) ? true : false;
+ }
+
+ public boolean greatherThan(ZoneMinderConnectionStatus reference) {
+ return (getValue() > reference.getValue()) ? true : false;
+ }
+
+ public boolean greatherThanEqual(ZoneMinderConnectionStatus reference) {
+ return (getValue() >= reference.getValue()) ? true : false;
+ }
+
+ public boolean isErrorState() {
+ return lessThan(UNINITIALIZED);
+ }
+
+ public boolean hasUnrecoverableError() {
+ return lessThan(ERROR_RECOVERABLE);
+ }
+
+ public boolean hasPassed(ZoneMinderConnectionStatus reference) {
+ return greatherThanEqual(reference);
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public boolean hasRecoverableError() {
+ return isErrorState() && !hasUnrecoverableError();
+ }
+}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderBridgeServerConfig.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderBridgeServerConfig.java
index c7190eaa07fac..c8a7287eef0d3 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderBridgeServerConfig.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderBridgeServerConfig.java
@@ -9,63 +9,70 @@
package org.openhab.binding.zoneminder.internal.config;
import org.openhab.binding.zoneminder.ZoneMinderConstants;
+import org.openhab.binding.zoneminder.internal.RefreshPriority;
/**
* Configuration data according to zoneminderserver.xml
*
- * @author Martin S. Eskildsen
+ * @author Martin S. Eskildsen - Initial contribution
*
*/
public class ZoneMinderBridgeServerConfig extends ZoneMinderConfig {
- private String hostname;
- private Integer http_port;
- private Integer telnet_port;
+ private Integer portHttp;
+ private Integer portTelnet;
private String protocol;
+ private String host;
- private String urlpath;
+ private String urlSite;
+ private String urlApi;
private String user;
private String password;
- private Integer refresh_interval;
- private Integer refresh_interval_disk_usage;
- private Boolean autodiscover_things;
+ private Integer refreshNormal;
+ private Integer refreshLow;
+ private String diskUsageRefresh;
+ private Boolean autodiscover;
+
+ private Boolean useSpecificUserStreaming;
+ private String streamingUser;
+ private String streamingPassword;
@Override
public String getConfigId() {
return ZoneMinderConstants.BRIDGE_ZONEMINDER_SERVER;
}
- public String getHostName() {
- return hostname;
+ public String getHost() {
+ return host;
}
- public void setHostName(String hostName) {
- this.hostname = hostName;
+ public void setHostName(String host) {
+ this.host = host;
}
public Integer getHttpPort() {
- if ((http_port == null) || (http_port == 0)) {
+ if ((portHttp == null) || (portHttp == 0)) {
if (getProtocol().equalsIgnoreCase("http")) {
- http_port = 80;
+ portHttp = 80;
} else {
- http_port = 443;
+ portHttp = 443;
}
}
- return http_port;
+ return portHttp;
}
public void setHttpPort(Integer port) {
- this.http_port = port;
+ this.portHttp = port;
}
public Integer getTelnetPort() {
- return telnet_port;
+ return portTelnet;
}
public void setTelnetPort(Integer telnetPort) {
- this.telnet_port = telnetPort;
+ this.portTelnet = telnetPort;
}
public String getProtocol() {
@@ -77,11 +84,19 @@ public void setProtocol(String protocol) {
}
public String getServerBasePath() {
- return urlpath;
+ return urlSite;
}
public void setServerBasePath(String urlpath) {
- this.urlpath = urlpath;
+ this.urlSite = urlpath;
+ }
+
+ public String getServerApiPath() {
+ return urlApi;
+ }
+
+ public void setServerApiPath(String apiPath) {
+ this.urlApi = apiPath;
}
public String getUserName() {
@@ -100,28 +115,49 @@ public void setPassword(String password) {
this.password = password;
}
- public Integer getRefreshInterval() {
- return refresh_interval;
+ public Integer getRefreshIntervalNormal() {
+ return this.refreshNormal;
}
- public void setRefreshInterval(Integer refreshInterval) {
- this.refresh_interval = refreshInterval;
+ public void setRefreshIntervalNormal(Integer refreshInterval) {
+ this.refreshNormal = refreshInterval;
}
- public Integer getRefreshIntervalLowPriorityTask() {
- return refresh_interval_disk_usage;
+ public Integer getRefreshIntervalLow() {
+ return this.refreshLow;
}
- public void setRefreshIntervalDiskUsage(Integer refreshIntervalDiskUsage) {
- this.refresh_interval_disk_usage = refreshIntervalDiskUsage;
+ public void setRefreshIntervalDiskUsage(Integer refreshInterval) {
+ this.refreshLow = refreshInterval;
}
public Boolean getAutodiscoverThings() {
- return autodiscover_things;
+ return autodiscover;
}
public void setAutodiscoverThings(Boolean autodiscoverThings) {
- this.autodiscover_things = autodiscoverThings;
+ this.autodiscover = autodiscoverThings;
+ }
+
+ public RefreshPriority getDiskUsageRefresh() {
+ return getRefreshPriorityEnum(diskUsageRefresh);
}
+ public Boolean getUseSpecificUserStreaming() {
+ return useSpecificUserStreaming;
+ }
+
+ public String getStreamingUser() {
+ if (!getUseSpecificUserStreaming()) {
+ return getUserName();
+ }
+ return streamingUser;
+ }
+
+ public String getStreamingPassword() {
+ if (!getUseSpecificUserStreaming()) {
+ return getPassword();
+ }
+ return streamingPassword;
+ }
}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderConfig.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderConfig.java
index 0ca0820dd3ec4..50e3cf3cd3d89 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderConfig.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderConfig.java
@@ -8,11 +8,21 @@
*/
package org.openhab.binding.zoneminder.internal.config;
+import org.openhab.binding.zoneminder.internal.RefreshPriority;
+
/**
* base class containing Configuration in openHAB
*
- * @author Martin S. Eskildsen
+ * @author Martin S. Eskildsen - Initial contribution
*/
public abstract class ZoneMinderConfig {
public abstract String getConfigId();
+
+ protected RefreshPriority getRefreshPriorityEnum(String configValue) {
+ RefreshPriority priority = RefreshPriority.fromConfigValue(configValue);
+ if (priority != RefreshPriority.UNKNOWN) {
+ return priority;
+ }
+ return RefreshPriority.UNKNOWN;
+ }
}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderThingMonitorConfig.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderThingMonitorConfig.java
index e702fa64f9aa1..b08b0307dbe20 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderThingMonitorConfig.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/config/ZoneMinderThingMonitorConfig.java
@@ -9,6 +9,7 @@
package org.openhab.binding.zoneminder.internal.config;
import org.openhab.binding.zoneminder.ZoneMinderConstants;
+import org.openhab.binding.zoneminder.internal.RefreshPriority;
/**
* Specific configuration class for Monitor COnfig.
@@ -18,7 +19,19 @@
public class ZoneMinderThingMonitorConfig extends ZoneMinderThingConfig {
// Parameters
- private Integer monitorId;
+ private Integer id;
+ private Integer triggerTimeout;
+ private String eventText;
+ private String imageRefreshIdle;
+ private String imageRefreshEvent;
+ // private String daemonRefresh;
+ private Integer imageScale;
+
+ // private Integer max_image_size;
+
+ // private Boolean enable_image_updates;
+ // private String video_encoding;
+ // private Integer video_framerate;
@Override
public String getConfigId() {
@@ -26,11 +39,64 @@ public String getConfigId() {
}
public String getId() {
- return monitorId.toString();
+ return id.toString();
}
@Override
public String getZoneMinderId() {
- return monitorId.toString();
+ return id.toString();
}
-}
+
+ public RefreshPriority getImageRefreshIdle() {
+ return getRefreshPriorityEnum(imageRefreshIdle);
+ }
+
+ public RefreshPriority getImageRefreshEvent() {
+ return getRefreshPriorityEnum(imageRefreshEvent);
+ }
+
+ /*
+ * public RefreshPriority getDaemonRefresh() {
+ * return getRefreshPriorityEnum(daemonRefresh);
+ * }
+ */
+ public Integer getImageScale() {
+ return imageScale;
+ }
+
+ /*
+ * public Integer getMaxImageSize() {
+ * return max_image_size;
+ * }
+ *
+ * public void setMaxImageSize(Integer size) {
+ * this.max_image_size = size;
+ * }
+ */
+ /*
+ * public Boolean getEnableImageUpdates() {
+ * return enable_image_updates;
+ * }
+ *
+ * public void setEnableImageUpdates(Boolean enable_image_updates) {
+ * this.enable_image_updates = enable_image_updates;
+ * }
+ */
+ /*
+ * public String getVideoEncoding() {
+ * return video_encoding;
+ * }
+ *
+ * public void setVideoEncoding(String video_encoding) {
+ * this.video_encoding = video_encoding;
+ * }
+ *
+ * public Integer getVideoFramerate() {
+ * return video_framerate;
+ * }
+ *
+ * public void setVideoFramerate(Integer video_framerate) {
+ * this.video_framerate = video_framerate;
+ * }
+ *
+ */}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/discovery/ZoneMinderDiscoveryService.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/discovery/ZoneMinderDiscoveryService.java
index bf62a4fb14d6a..cb22a90b0f2ac 100644
--- a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/discovery/ZoneMinderDiscoveryService.java
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/discovery/ZoneMinderDiscoveryService.java
@@ -25,7 +25,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import name.eskildsen.zoneminder.IZoneMinderMonitorData;
+import name.eskildsen.zoneminder.data.IMonitorDataGeneral;
/**
*
@@ -65,12 +65,15 @@ public Set getSupportedThingTypes() {
@Override
public void startBackgroundDiscovery() {
logger.debug("[DISCOVERY]: Performing background discovery scan for {}", serverHandler.getThing().getUID());
+
+ // removeOlderResults(getTimestampOfLastScan());
discoverMonitors();
}
@Override
public void startScan() {
logger.debug("[DISCOVERY]: Starting discovery scan for {}", serverHandler.getThing().getUID());
+
discoverMonitors();
}
@@ -84,55 +87,67 @@ protected synchronized void stopScan() {
super.stopScan();
}
- protected String BuildMonitorLabel(String id, String name) {
+ private 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);
+ for (IMonitorDataGeneral monitorData : serverHandler.getMonitors()) {
+ DiscoveryResult curDiscoveryResult = null;
+ ThingUID thingUID = getMonitorThingUID(monitorData);
+
+ // Avoid issue #5143 in Eclipse SmartHome
+ DiscoveryResult existingResult = discoveryServiceCallback.getExistingDiscoveryResult(thingUID);
+ if ((existingResult != null) && (existingResult.getThingUID() != thingUID)) {
+ existingResult = null;
+ }
+
+ if (existingResult != null) {
+ logger.debug("[DISCOVERY]: Monitor with Id='{}' and Name='{}' with ThingUID='{}' already discovered",
+ monitorData.getId(), monitorData.getName(), thingUID);
+
+ } else if (discoveryServiceCallback.getExistingThing(thingUID) != null) {
+ logger.debug("[DISCOVERY]: Monitor with Id='{}' and Name='{}' with ThingUID='{}' already added",
+ monitorData.getId(), monitorData.getName(), thingUID);
+ } else {
+ curDiscoveryResult = createMonitorDiscoveryResult(thingUID, monitorData);
+
+ }
+
+ if (curDiscoveryResult != null) {
+ logger.info("[DISCOVERY]: Monitor with Id='{}' and Name='{}' added to Inbox with ThingUID='{}'",
+ monitorData.getId(), monitorData.getName(), thingUID);
+ thingDiscovered(curDiscoveryResult);
+ }
}
}
- private boolean monitorThingExists(ThingUID newThingUID) {
- return serverHandler.getThingByUID(newThingUID) != null ? true : false;
- }
+ private ThingUID getMonitorThingUID(IMonitorDataGeneral monitor) {
+ ThingUID bridgeUID = serverHandler.getThing().getUID();
+ String monitorUID = String.format("%s-%s", ZoneMinderConstants.THING_ZONEMINDER_MONITOR, monitor.getId());
+
+ return new ThingUID(ZoneMinderConstants.THING_TYPE_THING_ZONEMINDER_MONITOR, bridgeUID, monitorUID);
- /**
- * 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) {
+ protected DiscoveryResult createMonitorDiscoveryResult(ThingUID monitorUID, IMonitorDataGeneral monitorData) {
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 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);
- }
+
+ Map properties = new HashMap<>(0);
+ properties.put(ZoneMinderConstants.PARAMETER_MONITOR_ID, Integer.valueOf(monitorData.getId()));
+ properties.put(ZoneMinderConstants.PARAMETER_MONITOR_TRIGGER_TIMEOUT,
+ ZoneMinderConstants.PARAMETER_MONITOR_TRIGGER_TIMEOUT_DEFAULTVALUE);
+ properties.put(ZoneMinderConstants.PARAMETER_MONITOR_EVENTTEXT, ZoneMinderConstants.MONITOR_EVENT_OPENHAB);
+
+ return DiscoveryResultBuilder.create(monitorUID).withProperties(properties).withBridge(bridgeUID)
+ .withLabel(buildMonitorLabel(monitorData.getId(), monitorData.getName())).build();
+
} catch (Exception ex) {
- logger.error("[DISCOVERY]: Error occurred when calling 'monitorAdded' from Discovery. Exception={}",
- ex.getMessage());
+ logger.error(
+ "[DISCOVERY]: Error occurred when calling 'monitorAdded' from Discovery. Id='{}', Name='{}', ThingUID='{}'",
+ monitorData.getId(), monitorData.getName(), monitorUID, ex.getCause());
}
-
+ return null;
}
}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelOnOffType.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelOnOffType.java
new file mode 100644
index 0000000000000..ceb3f4bf7b599
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelOnOffType.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.openhab.binding.zoneminder.internal.state;
+
+import javax.activation.UnsupportedDataTypeException;
+
+import org.eclipse.smarthome.core.library.types.OnOffType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.types.State;
+import org.eclipse.smarthome.core.types.UnDefType;
+
+/**
+ * The {@link ChannelOnOffType} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+
+public class ChannelOnOffType extends GenericChannelState {
+
+ protected ChannelOnOffType(ChannelUID channelUID, GenericThingState thing,
+ ChannelStateChangeSubscriber subscriber) {
+ super(channelUID, thing, subscriber);
+ }
+
+ @Override
+ protected State convert(Object _state) throws UnsupportedDataTypeException {
+ State newState = UnDefType.UNDEF;
+ if (_state instanceof String) {
+ String value = (String) _state;
+ if (((String) _state).equalsIgnoreCase("ON")) {
+ newState = OnOffType.ON;
+ } else if (((String) _state).equalsIgnoreCase("OFF")) {
+ newState = OnOffType.OFF;
+ } else {
+ throw new UnsupportedDataTypeException();
+ }
+ } else if (_state instanceof Boolean) {
+ newState = ((Boolean) _state) ? OnOffType.ON : OnOffType.OFF;
+ } else if (_state instanceof OnOffType) {
+ newState = (OnOffType) _state;
+ } else if (_state instanceof UnDefType) {
+ newState = (UnDefType) _state;
+ } else {
+ throw new UnsupportedDataTypeException();
+ }
+ return newState;
+ }
+
+}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelRawType.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelRawType.java
new file mode 100644
index 0000000000000..d776e6359b9a1
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelRawType.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.zoneminder.internal.state;
+
+import java.io.ByteArrayOutputStream;
+
+import javax.activation.UnsupportedDataTypeException;
+
+import org.eclipse.smarthome.core.library.types.RawType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.types.State;
+import org.eclipse.smarthome.core.types.UnDefType;
+
+/**
+ * The {@link ChannelRawType} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+public class ChannelRawType extends GenericChannelState {
+
+ protected ChannelRawType(ChannelUID channelUID, GenericThingState thing, ChannelStateChangeSubscriber subscriber) {
+ super(channelUID, thing, subscriber);
+ }
+
+ @Override
+ protected State convert(Object _state) throws UnsupportedDataTypeException {
+ State newState = UnDefType.UNDEF;
+
+ State state = UnDefType.UNDEF;
+ if (_state instanceof ByteArrayOutputStream) {
+ // ByteArrayOutputStream baos = (ByteArrayOutputStream) _state;
+ newState = new RawType(((ByteArrayOutputStream) _state).toByteArray(), "image/jpeg");
+ }
+
+ else if (_state instanceof RawType) {
+ newState = (RawType) _state;
+ } else if (_state instanceof UnDefType) {
+ newState = (UnDefType) _state;
+ } else {
+ throw new UnsupportedDataTypeException();
+ }
+ return newState;
+
+ }
+
+}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelState.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelState.java
new file mode 100644
index 0000000000000..d1a25e9c8a7fa
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelState.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.openhab.binding.zoneminder.internal.state;
+
+import javax.activation.UnsupportedDataTypeException;
+
+import org.eclipse.smarthome.core.types.State;
+
+/**
+ * The {@link ChannelState} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+interface ChannelState {
+
+ public void subscribe();
+
+ public void unsubscribe();
+
+ public State getState();
+
+ // private State statePublished = UnDefType.NULL;
+ // private Type dataType = UnDefType.class;
+
+ public void setState(Object state) throws UnsupportedDataTypeException;
+
+ public void setState(Object state, boolean update) throws UnsupportedDataTypeException;
+
+}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelStateChangePublisher.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelStateChangePublisher.java
new file mode 100644
index 0000000000000..a1e2778768ac9
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelStateChangePublisher.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.zoneminder.internal.state;
+
+import org.eclipse.smarthome.core.thing.ChannelUID;
+
+/**
+ * The {@link GenericThingState} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+public interface ChannelStateChangePublisher {
+ /*
+ * public void subscribeStringType(ChannelUID channelUID, ChannelStateChangeSubscriber subscriber);
+ *
+ * public void subscribeOnOffType(ChannelUID channelUID, ChannelStateChangeSubscriber subscriber);
+ *
+ * public void subscribeNumberType(ChannelUID channelUID, ChannelStateChangeSubscriber subscriber);
+ */
+ // public void subscribeRawType(ChannelUID channelUID, ChannelStateChangeSubscriber subscriber);
+
+ public GenericChannelState createChannelSubscription(
+ ChannelUID channelUID /*
+ * ,
+ * ChannelStateChangeSubscriber subscriber
+ */);
+
+ public void addChannel(ChannelUID channelUID/* , ChannelStateChangeSubscriber subscriber */);
+
+ public void subscribe(ChannelUID channelUID/* , ChannelStateChangeSubscriber subscriber */);
+
+ public void unsubscribe(ChannelUID channelUID);
+
+ public void disableRefresh();
+
+ public void enableRefresh();
+
+ public boolean allowRefresh();
+}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelStateChangeSubscriber.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelStateChangeSubscriber.java
new file mode 100644
index 0000000000000..a88fb59dd3d86
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelStateChangeSubscriber.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.zoneminder.internal.state;
+
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.types.State;
+
+/**
+ * The {@link GenericThingState} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+public interface ChannelStateChangeSubscriber {
+ void onStateChanged(ChannelUID channelUID, State state);
+
+ void onRefreshDisabled();
+
+ void onRefreshEnabled();
+}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelStringType.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelStringType.java
new file mode 100644
index 0000000000000..e96e512344bb6
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/ChannelStringType.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.zoneminder.internal.state;
+
+import javax.activation.UnsupportedDataTypeException;
+
+import org.eclipse.smarthome.core.library.types.StringType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.types.State;
+import org.eclipse.smarthome.core.types.UnDefType;
+
+/**
+ * The {@link GenericThingState} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+public class ChannelStringType extends GenericChannelState {
+
+ protected ChannelStringType(ChannelUID channelUID, GenericThingState thing,
+ ChannelStateChangeSubscriber subscriber) {
+ super(channelUID, thing, subscriber);
+ }
+
+ @Override
+ protected State convert(Object _state) throws UnsupportedDataTypeException {
+ State newState = UnDefType.UNDEF;
+
+ if (_state instanceof String) {
+ newState = new StringType((String) _state);
+ } else if (_state instanceof StringType) {
+ newState = (StringType) _state;
+
+ } else if (_state instanceof UnDefType) {
+ newState = (UnDefType) _state;
+ } else {
+ throw new UnsupportedDataTypeException();
+ }
+ return newState;
+ }
+
+}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/GenericChannelState.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/GenericChannelState.java
new file mode 100644
index 0000000000000..a0fb1ed407fcd
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/GenericChannelState.java
@@ -0,0 +1,111 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.zoneminder.internal.state;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.activation.UnsupportedDataTypeException;
+
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.types.State;
+import org.eclipse.smarthome.core.types.UnDefType;
+
+/**
+ * The {@link GenericThingState} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+public abstract class GenericChannelState implements ChannelState {
+
+ private AtomicBoolean isDirty = new AtomicBoolean(false);
+
+ private ChannelUID channelUID;
+ private GenericThingState thing = null;
+ private ChannelStateChangeSubscriber subscriber = null;
+ private State state = UnDefType.NULL;
+ private int countSubscription = 0;
+
+ protected GenericChannelState(ChannelUID channelUID, GenericThingState thing,
+ ChannelStateChangeSubscriber subscriber) {
+ this.channelUID = channelUID;
+ this.thing = thing;
+ this.subscriber = subscriber;
+ }
+
+ @Override
+ public void subscribe() {
+ countSubscription++;
+ }
+
+ @Override
+ public void unsubscribe() {
+ if (countSubscription > 0) {
+ countSubscription--;
+ }
+
+ }
+
+ @Override
+ public State getState() {
+ return state;
+ }
+
+ @Override
+ public void setState(Object objState) throws UnsupportedDataTypeException {
+ setState(objState, true);
+ }
+
+ @Override
+ public void setState(Object objState, boolean update) throws UnsupportedDataTypeException {
+ State newState = convert(objState);
+ boolean changed = false;
+
+ if (!(state.toString().equals(newState.toString()))) {
+ changed = true;
+ state = newState;
+ // Set Dirty flag
+ setDirtyFlag();
+
+ thing.onChannelChanged(channelUID);
+ }
+
+ if (update && changed) {
+ // Try to udpate
+ flushChanges();
+ }
+ }
+
+ public void flushChanges() {
+ flushChanges(false);
+ }
+
+ public void flushChanges(boolean force) {
+ if (!isDirty.get() && !force) {
+ return;
+ }
+
+ if (thing.allowRefresh() || force) {
+ subscriber.onStateChanged(channelUID, state);
+ // Clear dirtyflag
+ clearDirtyFlag();
+ }
+ }
+
+ public void setDirtyFlag() {
+ isDirty.lazySet(true);
+ }
+
+ public void clearDirtyFlag() {
+ isDirty.set(false);
+ }
+
+ protected abstract State convert(Object state) throws UnsupportedDataTypeException;
+
+}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/GenericThingState.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/GenericThingState.java
new file mode 100644
index 0000000000000..bcfd201499dda
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/GenericThingState.java
@@ -0,0 +1,182 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.openhab.binding.zoneminder.internal.state;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.smarthome.core.library.types.OnOffType;
+import org.eclipse.smarthome.core.library.types.RawType;
+import org.eclipse.smarthome.core.library.types.StringType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.types.State;
+import org.eclipse.smarthome.core.types.UnDefType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link GenericThingState} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+public abstract class GenericThingState implements ChannelStateChangePublisher {
+
+ private Logger logger = LoggerFactory.getLogger(GenericThingState.class);
+
+ final AtomicBoolean allowRefresh = new AtomicBoolean(true);
+
+ private ChannelStateChangeSubscriber subscriber = null;
+
+ // Keeps track of current channel refresh status of subscribed channels
+ private Map subscriptions = new ConcurrentHashMap();
+
+ public GenericThingState(ChannelStateChangeSubscriber subscriber) {
+ this.subscriber = subscriber;
+ }
+
+ protected abstract void recalculate();
+
+ public void onChannelChanged(ChannelUID channelUID) {
+ }
+
+ @Override
+ public void addChannel(ChannelUID channelUID) {
+ try {
+ if (!subscriptions.containsKey(channelUID.getId())) {
+ subscriptions.put(channelUID.getId(), createChannelSubscription(channelUID));
+ }
+ } catch (
+
+ Exception ex) {
+ logger.error("{}: context='subscribe' - Exception occurred when subscribing to channel '{}'", "",
+ channelUID.getId());
+ }
+ }
+
+ protected GenericChannelState createSubscriptionStringType(ChannelUID channelUID) {
+ return new ChannelStringType(channelUID, this, subscriber);
+
+ }
+
+ protected GenericChannelState createSubscriptionOnOffType(ChannelUID channelUID) {
+ return new ChannelOnOffType(channelUID, this, subscriber);
+ }
+
+ protected GenericChannelState getChannelStateHandler(String channelId) {
+ return subscriptions.get(channelId);
+
+ }
+
+ public GenericChannelState getChannelStateHandler(ChannelUID channelUID) {
+ return getChannelStateHandler(channelUID.getId());
+
+ }
+
+ protected GenericChannelState createSubscriptionRawType(ChannelUID channelUID) {
+ return new ChannelRawType(channelUID, this, subscriber);
+ }
+
+ @Override
+ public void subscribe(ChannelUID channelUID/* , ChannelStateChangeSubscriber subscriber */) {
+ try {
+ if (getChannelStateHandler(channelUID) == null) {
+ addChannel(channelUID/* , subscriber */);
+ }
+ getChannelStateHandler(channelUID).subscribe();
+
+ } catch (
+
+ Exception ex) {
+ logger.error("{}: context='subscribe' - Exception occurred when subscribing to channel '{}'", "",
+ channelUID.getId(), ex);
+ }
+ }
+
+ @Override
+ public void unsubscribe(ChannelUID channelUID) {
+ try {
+ if (getChannelStateHandler(channelUID) != null) {
+ getChannelStateHandler(channelUID).subscribe();
+ }
+ } catch (Exception ex) {
+ logger.error("{}: context='unsubscribe' - Exception occurred when subscribing to channel '{}'", "",
+ channelUID.getId());
+ }
+ }
+
+ @Override
+ public void disableRefresh() {
+ allowRefresh.compareAndSet(true, false);
+ }
+
+ @Override
+ public void enableRefresh() {
+ if (allowRefresh.compareAndSet(false, true)) {
+ for (Map.Entry entry : subscriptions.entrySet()) {
+ String key = entry.getKey().toString();
+ GenericChannelState channel = entry.getValue();
+ channel.flushChanges();
+ }
+ }
+ }
+
+ @Override
+ public boolean allowRefresh() {
+ return allowRefresh.get();
+ }
+
+ public void forceUpdate(boolean _recalculate) {
+ if (_recalculate) {
+ recalculate();
+ }
+
+ for (Map.Entry entry : subscriptions.entrySet()) {
+ String key = entry.getKey().toString();
+ GenericChannelState channel = entry.getValue();
+ channel.flushChanges(true);
+ }
+ }
+
+ /**
+ *
+ * OLD STUFF Needs cleaning
+ *
+ */
+
+ protected State getStringAsStringState(String value) {
+ State state = UnDefType.UNDEF;
+
+ if (value != null) {
+ state = new StringType(value);
+ }
+
+ return state;
+
+ }
+
+ protected State getBooleanAsOnOffState(boolean value) {
+ State state = UnDefType.UNDEF;
+ state = value ? OnOffType.ON : OnOffType.OFF;
+ return state;
+ }
+
+ protected State getImageByteArrayAsRawType(ByteArrayOutputStream baos) {
+ State state = UnDefType.UNDEF;
+ if (baos != null) {
+ state = new RawType(baos.toByteArray(), "image/jpeg");
+ }
+
+ return state;
+ }
+
+}
diff --git a/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/MonitorThingState.java b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/MonitorThingState.java
new file mode 100644
index 0000000000000..9df154c5002b4
--- /dev/null
+++ b/addons/binding/org.openhab.binding.zoneminder/src/main/java/org/openhab/binding/zoneminder/internal/state/MonitorThingState.java
@@ -0,0 +1,537 @@
+/**
+ * Copyright (c) 2010-2018 by the respective copyright holders.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.openhab.binding.zoneminder.internal.state;
+
+import java.io.ByteArrayOutputStream;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.activation.UnsupportedDataTypeException;
+
+import org.eclipse.smarthome.core.library.types.OnOffType;
+import org.eclipse.smarthome.core.library.types.RawType;
+import org.eclipse.smarthome.core.library.types.StringType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.types.State;
+import org.eclipse.smarthome.core.types.UnDefType;
+import org.openhab.binding.zoneminder.ZoneMinderConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import name.eskildsen.zoneminder.api.telnet.ZoneMinderTriggerEvent;
+import name.eskildsen.zoneminder.common.ZoneMinderMonitorFunctionEnum;
+import name.eskildsen.zoneminder.common.ZoneMinderMonitorStatusEnum;
+import name.eskildsen.zoneminder.data.IMonitorDataGeneral;
+import name.eskildsen.zoneminder.data.IZoneMinderEventData;
+
+/**
+ * The {@link MonitorThingState} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Martin S. Eskildsen - Initial contribution
+ */
+public class MonitorThingState extends GenericThingState {
+
+ private Logger logger = LoggerFactory.getLogger(MonitorThingState.class);
+
+ private boolean isDirty;
+ private String logIdentifier = "";
+
+ private IZoneMinderEventData activeEvent = null;
+ private ZoneMinderTriggerEvent curTriggerEvent = null;
+
+ /*
+ * Used in recalculate
+ */
+ AtomicBoolean recordingFunction = new AtomicBoolean(false);
+ AtomicBoolean recordingDetailedState = new AtomicBoolean(false);
+ AtomicBoolean alarmedFunction = new AtomicBoolean(false);
+ AtomicBoolean alarmedDetailedState = new AtomicBoolean(false);
+
+ // Monitor properties
+
+ // Video Url
+ private State channelVideoUrl;
+
+ boolean bRecalculating = false;
+
+ /*
+ * public MonitorThingState(String id, ChannelStateChangeSubscriber subscriber) {
+ * super(subscriber);
+ * logIdentifier = id;
+ * initialize();
+ * }
+ */
+ protected void initialize() {
+ isDirty = true;
+ }
+
+ public MonitorThingState(ChannelStateChangeSubscriber subscriber) {
+ super(subscriber);
+
+ }
+
+ @Override
+ public GenericChannelState createChannelSubscription(ChannelUID channelUID) {
+ GenericChannelState channelState = null;
+ try {
+ switch (channelUID.getId()) {
+ case ZoneMinderConstants.CHANNEL_MONITOR_DETAILED_STATUS:
+ case ZoneMinderConstants.CHANNEL_MONITOR_EVENT_CAUSE:
+ case ZoneMinderConstants.CHANNEL_MONITOR_FUNCTION:
+ channelState = createSubscriptionStringType(channelUID);
+ break;
+
+ case ZoneMinderConstants.CHANNEL_MONITOR_STILL_IMAGE:
+ channelState = createSubscriptionRawType(channelUID);
+ break;
+ default:
+ channelState = createSubscriptionOnOffType(channelUID);
+ break;
+ }
+
+ } catch (Exception ex) {
+ logger.error("{}: context='subscribe' - Exception occurred when subscribing to channel '{}'", "",
+ channelUID.getId());
+ }
+ return channelState;
+ }
+
+ public boolean isDirty() {
+ return isDirty;
+ }
+
+ public boolean isAlarmed() {
+ State stateEnabled = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_EVENT_STATE).getState();
+ return ((alarmedDetailedState.get() || (stateEnabled == OnOffType.ON)) ? true : false);
+
+ }
+
+ private boolean isEnabled() {
+ State stateEnabled = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_ENABLED).getState();
+ if (stateEnabled == OnOffType.ON) {
+ return true;
+ }
+ return false;
+ }
+
+ public ZoneMinderMonitorFunctionEnum getMonitorFunction() {
+ State stateFunction = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_FUNCTION).getState();
+ return ZoneMinderMonitorFunctionEnum.getEnum(stateFunction.toString());
+ }
+
+ public String getMonitorEventCause() {
+ State stateEventCause = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_EVENT_CAUSE).getState();
+ return stateEventCause.toString();
+ }
+
+ public boolean getMonitorEventMotion() {
+ State stateEventMotion = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_MOTION_EVENT).getState();
+ return false;
+
+ }
+
+ public ZoneMinderMonitorStatusEnum getMonitorDetailedStatus() {
+ State stateStatus = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_DETAILED_STATUS).getState();
+ ZoneMinderMonitorStatusEnum result = ZoneMinderMonitorStatusEnum.UNKNOWN;
+
+ if (stateStatus == UnDefType.NULL || stateStatus == UnDefType.UNDEF) {
+ return ZoneMinderMonitorStatusEnum.UNKNOWN;
+ }
+
+ try {
+ result = ZoneMinderMonitorStatusEnum.getEnumFromName(stateStatus.toString());
+ } catch (Exception ex) {
+ logger.error(
+ "{}: context='getMonitorDetailedStatus' Exception occurred when calling getMonitorDetailedStatus",
+ logIdentifier, ex);
+
+ }
+ return result;
+ }
+
+ public void setMonitorTriggerEvent(ZoneMinderTriggerEvent event) {
+ isDirty = true;
+ curTriggerEvent = event;
+ }
+
+ public void setMonitorFunction(ZoneMinderMonitorFunctionEnum monitorFunction) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_FUNCTION);
+ if (gcs != null) {
+ try {
+ gcs.setState(monitorFunction.toString());
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorFunction' Exception occurred when updating capture-daemon channel",
+ logIdentifier, e);
+ }
+ }
+ }
+
+ public void setMonitorEventCause(State state) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_EVENT_CAUSE);
+ if (gcs != null) {
+ try {
+ gcs.setState(state);
+ } catch (UnsupportedDataTypeException e) {
+ logger.error(
+ "{}: context='setMonitorEventCause' Exception occurred when updating capture-daemon channel",
+ logIdentifier, e);
+
+ }
+ }
+
+ }
+
+ public void setMonitorEventMotion(State state) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_MOTION_EVENT);
+
+ if (gcs != null) {
+ try {
+ gcs.setState(state);
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorEnabled' Exception occurred when updating capture-daemon channel",
+ logIdentifier, e);
+ }
+ }
+
+ }
+
+ public void setMonitorGeneralData(IMonitorDataGeneral monitorData) {
+ if (monitorData != null) {
+ setMonitorFunction(monitorData.getFunction());
+ setMonitorEnabled(monitorData.getEnabled());
+ }
+ }
+
+ public void setMonitorEnabled(boolean state) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_ENABLED);
+
+ try {
+ if (gcs != null) {
+ gcs.setState(state);
+ }
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorEnabled' Exception occurred when calling setMonitorEnabled",
+ logIdentifier, e);
+
+ } catch (Exception ex) {
+ logger.error(
+ "{}: context='setMonitorEnabled' tag='exception' Exception occurredwhen calling setMonitorEnabled",
+ logIdentifier, ex);
+ }
+
+ }
+
+ public void setMonitorRecording(boolean state) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_RECORD_STATE);
+ if (gcs != null) {
+ try {
+ gcs.setState(state);
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorRecortding' Exception occurred", logIdentifier, e);
+ }
+ }
+
+ }
+
+ public void setMonitorEventState(boolean state) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_EVENT_STATE);
+ if (gcs != null) {
+ try {
+ gcs.setState(state);
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorEventState' Exception occurred", logIdentifier, e);
+ }
+ }
+ }
+
+ public void setMonitorForceAlarmInternal(boolean state) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_FORCE_ALARM);
+ if (gcs != null) {
+ try {
+ gcs.setState(state, true);
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorForceAlarmInternal' Exception occurred", logIdentifier, e);
+
+ }
+ }
+
+ }
+
+ public void setMonitorForceAlarmExternal(boolean state) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_FORCE_ALARM);
+ if (gcs != null) {
+ try {
+ gcs.setState(state);
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorForceAlarmExternal' Exception occurred", logIdentifier, e);
+
+ }
+ }
+
+ }
+
+ public void setMonitorEventData(IZoneMinderEventData eventData) {
+ // If it is set to null ignore since set back to idle from alarm is handled internally
+ if (eventData == null) {
+ return;
+ }
+
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_EVENT_CAUSE);
+ if (gcs != null) {
+ try {
+ if (!activeEvent.equals(eventData)) {
+ activeEvent = eventData;
+ gcs.setState(eventData.getCause());
+ }
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorEventData' Exception occurred", logIdentifier, e);
+ }
+ }
+ }
+
+ public void setMonitorDetailedStatus(ZoneMinderMonitorStatusEnum status) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_DETAILED_STATUS);
+ if (gcs != null) {
+ try {
+ gcs.setState(status.toString());
+
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorDetailedStatus' Exception occurred", logIdentifier, e);
+
+ }
+ }
+ }
+
+ public void setMonitorCaptureDaemonStatus(State state) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_CAPTURE_DAEMON_STATE);
+ if (gcs != null) {
+ try {
+ gcs.setState(state);
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorStillImage' Exception occurred", logIdentifier, e);
+
+ }
+ }
+ }
+
+ public void setMonitorAnalysisDaemonStatus(State state) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_ANALYSIS_DAEMON_STATE);
+ if (gcs != null) {
+ try {
+ gcs.setState(state);
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorAnalysisDaemonStatus' Exception occurred", logIdentifier, e);
+
+ }
+ }
+ }
+
+ public void setMonitorFrameDaemonStatus(State state) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_FRAME_DAEMON_STATE);
+ if (gcs != null) {
+ try {
+ gcs.setState(state);
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorFrameDaemonStatus' Exception occurred", logIdentifier, e);
+
+ }
+ }
+ }
+
+ public void setMonitorFrameDaemonStatus(String status) {
+ getStringAsStringState(status);
+ }
+
+ public void setMonitorStillImage(ByteArrayOutputStream baos) {
+ GenericChannelState gcs = getChannelStateHandler(ZoneMinderConstants.CHANNEL_MONITOR_STILL_IMAGE);
+ if (gcs != null) {
+ try {
+ if (baos != null) {
+ gcs.setState(baos);
+ } else {
+ gcs.setState(UnDefType.UNDEF);
+ }
+ } catch (UnsupportedDataTypeException e) {
+ logger.error("{}: context='setMonitorStillImage' Exception occurred", logIdentifier, e);
+
+ }
+ }
+
+ }
+
+ public void setMonitorVideoUrl(String url) {
+ channelVideoUrl = new StringType(url);
+ }
+
+ public State getVideoUrl() {
+ return channelVideoUrl;
+ }
+
+ @Override
+ public void onChannelChanged(ChannelUID channelUID) {
+ switch (channelUID.getId()) {
+ case ZoneMinderConstants.CHANNEL_MONITOR_ENABLED:
+ case ZoneMinderConstants.CHANNEL_MONITOR_FUNCTION:
+ case ZoneMinderConstants.CHANNEL_MONITOR_DETAILED_STATUS:
+ case ZoneMinderConstants.CHANNEL_MONITOR_FORCE_ALARM:
+ recalculate();
+ break;
+ }
+
+ }
+
+ @Override
+ protected void recalculate() {
+ try {
+ ZoneMinderMonitorFunctionEnum monitorFunction = getMonitorFunction();
+ ZoneMinderMonitorStatusEnum monitorStatus = getMonitorDetailedStatus();
+
+ // Calculate based on state of Function
+ switch (monitorFunction) {
+ case NONE:
+ case MONITOR:
+ alarmedFunction.set(false);
+ recordingFunction.set(false);
+ break;
+
+ case MODECT:
+ alarmedFunction.set(true);
+ recordingFunction.set(true);
+ break;
+ case RECORD:
+ alarmedFunction.set(false);
+ recordingFunction.set(true);
+ break;
+ case MOCORD:
+ alarmedFunction.set(true);
+ recordingFunction.set(true);
+ break;
+ case NODECT:
+ alarmedFunction.set(false);
+ recordingFunction.set(true);
+ break;
+ default:
+ recordingFunction.set((activeEvent != null) ? true : false);
+ }
+ logger.debug(
+ "{}: Recalculate channel states based on Function: Function='{}' -> alarmState='{}', recordingState='{}'",
+ logIdentifier, monitorFunction, alarmedFunction, recordingFunction);
+
+ // Calculated based on detailed Monitor Status
+ switch (monitorStatus) {
+ case IDLE:
+ alarmedDetailedState.set(false);
+ recordingDetailedState.set(false);
+ break;
+
+ case PRE_ALARM:
+ case ALARM:
+ case ALERT:
+ alarmedDetailedState.set(true);
+ recordingDetailedState.set(true);
+ break;
+
+ case RECORDING:
+ alarmedDetailedState.set(false);
+ recordingDetailedState.set(true);
+ break;
+ case UNKNOWN:
+ default:
+ alarmedDetailedState.set(false);
+ recordingDetailedState.set(false);
+ break;
+
+ }
+ logger.debug(
+ "{}: Recalculate channel states based on Detailed State: DetailedState='{}' -> alarmState='{}', recordingState='{}'",
+ logIdentifier, monitorStatus.name(), alarmedDetailedState, recordingDetailedState);
+
+ if (monitorStatus == ZoneMinderMonitorStatusEnum.IDLE && !alarmedDetailedState.get()
+ && activeEvent != null) {
+ activeEvent = null;
+ }
+
+ updateEventChannels();
+
+ // Now we can conclude on the Alarmed and Recording channel state
+ setMonitorRecording((recordingFunction.get() && recordingDetailedState.get() && isEnabled()));
+ setMonitorEventState((alarmedFunction.get() && alarmedDetailedState.get() && isEnabled()));
+
+ switch (getMonitorDetailedStatus()) {
+ case UNKNOWN:
+ setMonitorEventCause(UnDefType.UNDEF);
+ setMonitorEventMotion(UnDefType.UNDEF);
+ break;
+
+ case PRE_ALARM:
+ case ALARM:
+ case ALERT:
+ if (activeEvent != null) {
+ setMonitorEventCause(new StringType(activeEvent.getCause()));
+ setMonitorEventMotion(
+ activeEvent.getCause().equalsIgnoreCase("motion") ? OnOffType.ON : OnOffType.OFF);
+ } else {
+ setMonitorEventMotion(OnOffType.OFF);
+ }
+ break;
+
+ case IDLE:
+ case RECORDING:
+ default:
+ setMonitorEventCause(new StringType(""));
+ setMonitorEventMotion(OnOffType.OFF);
+ break;
+ }
+ } catch (Exception ex) {
+ logger.error("{}: context='recalculate' Exception occurred", logIdentifier, ex);
+ } finally {
+ isDirty = false;
+ }
+ }
+
+ protected State getChannelByteArrayAsRawType(ByteArrayOutputStream image) {
+ State state = UnDefType.UNDEF;
+ try {
+ if (image != null) {
+ state = new RawType(image.toByteArray(), "image/jpeg");
+ }
+
+ } catch (Exception ex) {
+ logger.error("{}: Exception occurred in 'getChannelByteArrayAsRawType()'", logIdentifier, ex);
+ }
+
+ return state;
+ }
+
+ private void updateEventChannels() {
+ switch (getMonitorDetailedStatus()) {
+ case UNKNOWN:
+ setMonitorEventCause(UnDefType.UNDEF);
+ setMonitorEventMotion(UnDefType.UNDEF);
+ break;
+
+ case PRE_ALARM:
+ case ALARM:
+ case ALERT:
+ if (activeEvent != null) {
+ setMonitorEventCause(new StringType(activeEvent.getCause()));
+ setMonitorEventMotion(
+ activeEvent.getCause().toLowerCase().contains("motion") ? OnOffType.ON : OnOffType.OFF);
+ }
+ break;
+
+ case IDLE:
+ case RECORDING:
+ default:
+ setMonitorEventCause(new StringType(""));
+ setMonitorEventMotion(OnOffType.OFF);
+ break;
+ }
+ }
+}
\ No newline at end of file