ZoneMinder Binding in Marketplace (Beta)

Looks like it doesn’t work for ZM 1.32.0 :confused:

This has been reported in Github too. I plan to look into another workaround, but I’ve been focused on JSR223-Jython modules.

@mr_eskildsen With the latest ESH changes to how the inbox works (I’m on build 1374), my openhab.log now is being spammed with messages like this every 10-15 seconds. Is there any way to disable discovery? Alternatively, would you consider reducing some of the INFO level logging to DEBUG?

I can change my logging level to WARN in the meantime, but that’s probably not a good long term solution.

2018-09-28 07:00:19.070 [INFO ] [discovery.ZoneMinderDiscoveryService] - [DISCOVERY]: Monitor with Id='1' and Name='AAAA' added to Inbox with ThingUID='zoneminder:monitor:zm:monitor-1'
2018-09-28 07:00:19.071 [INFO ] [discovery.ZoneMinderDiscoveryService] - [DISCOVERY]: Monitor with Id='2' and Name='BBBB' added to Inbox with ThingUID='zoneminder:monitor:zm:monitor-2'
2018-09-28 07:00:19.072 [INFO ] [discovery.ZoneMinderDiscoveryService] - [DISCOVERY]: Monitor with Id='3' and Name='CCCC' added to Inbox with ThingUID='zoneminder:monitor:zm:monitor-3'
2018-09-28 07:00:19.072 [INFO ] [discovery.ZoneMinderDiscoveryService] - [DISCOVERY]: Monitor with Id='4' and Name='DDDD' added to Inbox with ThingUID='zoneminder:monitor:zm:monitor-4'
2018-09-28 07:00:19.073 [INFO ] [discovery.ZoneMinderDiscoveryService] - [DISCOVERY]: Monitor with Id='7' and Name='EEEE' added to Inbox with ThingUID='zoneminder:monitor:zm:monitor-7'

Sounds like a good idea. Unfortunately I am bit stucked with the Binding. I haven’t looked at it lately, I hope to get the time to finish the pullrequest soon, this one would be obvious to handle

@mr_eskildsen Not sure of you are still maintaining the binding…

When forcing an alarm, I see this error in the log file.

2018-12-13 11:53:54.209 [ERROR] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]:  context='onTrippedForceAlarm' Exception occurred inTrippedForceAlarm() Exception='null'

In debug mode, this is what I see leading up to the error.

2018-12-13 11:53:53.100 [DEBUG] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]: Channel 'zoneminder:monitor:zm:monitor-3:force-alarm' in monitor '3' received command='ON'
2018-12-13 11:53:53.100 [DEBUG] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]: 'handleCommand' => CHANNEL_MONITOR_FORCE_ALARM: Command 'ON' received for monitor 'force-alarm'
2018-12-13 11:53:53.100 [DEBUG] [der.internal.state.MonitorThingState] - : Recalculate channel states based on Function: Function='Nodect' -> alarmState='false', recordingState='true'
2018-12-13 11:53:53.100 [DEBUG] [der.internal.state.MonitorThingState] - : Recalculate channel states based on Detailed State: DetailedState='IDLE' -> alarmState='false', recordingState='false'
2018-12-13 11:53:53.100 [DEBUG] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]: context='onStateChanged' channel='zoneminder:monitor:zm:monitor-3:force-alarm' - State changed to 'ON'
2018-12-13 11:53:53.100 [INFO ] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]: Activate 'ForceAlarm' to 'ON' (Reason='openHAB', Timeout='60')
2018-12-13 11:53:53.101 [DEBUG] [r.handler.ZoneMinderBaseThingHandler] - [MONITOR-3]: context='startAlarmRefresh' Starting ALARM refresh...
2018-12-13 11:53:53.201 [DEBUG] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]: context='onFetchData' tag='monitorData' URL='http://hostname/zm/api/monitors/3.json' ResponseCode='200' ResponseMessage='OK'
2018-12-13 11:53:53.302 [DEBUG] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]: context='onFetchData' tag='detailedStatus' URL='http://hostname/zm/api/monitors/alarm/id:3/command:status.json' ResponseCode='200' ResponseMessage='OK'
2018-12-13 11:53:53.302 [DEBUG] [der.internal.state.MonitorThingState] - : Recalculate channel states based on Function: Function='Nodect' -> alarmState='false', recordingState='true'
2018-12-13 11:53:53.303 [DEBUG] [der.internal.state.MonitorThingState] - : Recalculate channel states based on Detailed State: DetailedState='PRE_ALARM' -> alarmState='true', recordingState='true'
2018-12-13 11:53:53.303 [DEBUG] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]: context='onStateChanged' channel='zoneminder:monitor:zm:monitor-3:recording' - State changed to 'ON'
2018-12-13 11:53:53.304 [DEBUG] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]: context='onStateChanged' channel='zoneminder:monitor:zm:monitor-3:detailed-status' - State changed to 'Pre-Alarm'
2018-12-13 11:53:54.107 [DEBUG] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]: context='onTrippedForceAlarm' Received forceAlarm for monitor 3
2018-12-13 11:53:54.135 [DEBUG] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-7]: context='onFetchData' tag='monitorData' URL='http://hostname/zm/api/monitors/7.json' ResponseCode='200' ResponseMessage='OK'
2018-12-13 11:53:54.208 [DEBUG] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]: URL='http://hostname/zm/api/events/index/Id:3494.json?page=1' ResponseCode='200' ResponseMessage='OK'
2018-12-13 11:53:54.209 [ERROR] [andler.ZoneMinderThingMonitorHandler] - [MONITOR-3]:  context='onTrippedForceAlarm' Exception occurred inTrippedForceAlarm() Exception='null'

It also would be great to get these discovery messages set to debug mode to eliminate the log spamming.

Another thing I noticed…

If I try to change the ForceAlarm timeout config parameter to 0 to disable the timeout, the change is not applied. In fact, setting it to any value has no effect. It remains at the default of 60.

You’re not alone. I get these whenever the alarm channel is triggered. I don’t use force alarm.

2018-12-13 12:00:33.543 [ERROR] [org.openhab.binding.zoneminder.handler.ZoneMinderThingMonitorHandler] - [MONITOR-11]:  context='onTrippedForceAlarm' Exception occurred inTrippedForceAlarm() Exception='null'

Yeah, I started to use my motion detectors to trigger rules that use the force alarm channel to turn recording ON and OFF. I got disenchanted with the quality of Zoneminder’s motion detection. I know it’s quite powerful, but no amount of tuning and tweaking would prevent lighting changes, rain, snow, etc. from triggering the motion detection. I was starting to hate waking up to dozens of bogus events just because it rained heavily during the night. I suppose it can be done, but it’s beyond me. :roll_eyes:

If I could figure out how to pull the PR into my local openhab2-addons repo, I’d make a few changes to reduce the logging level, fix the config changes, and handle some of these exceptions differently.

I would be glad if somebody could help finishing the pull request. Right now I don’t have the time for finalising it. I also see the need for a major rework, first of all since ZM API seems to change, but also to make the Binding more clean.

Yes… I know what you mean. I’ve got mine close to not annoying, but still a battle, especially on sunny days with clouds. Couple weeks ago a blustery snow storm made me disable one of the cameras. Setting brightness and contrast levels helped me a bit with motion detection, but reduced the quality of the images. There’s still more to tweak, but hard to get all scenarios to work with one set of settings. I haven’t tried automating them yet…

I’ve been tempted to jump in, but I have a few other OH related things in the queue. If nobody has snatched it when I get done, then I’ll gladly help out!

I pulled the PR into my local repo. I’m going to take a look at what’s necessary to wrap it up.

2 Likes

Here is another error that often comes up…

2018-12-14 05:19:42.359 [ERROR] [org.openhab.binding.zoneminder.handler.ZoneMinderServerBridgeHandler] - [BRIDGE (99ec8cf6)]: context='validateConnection' check='FAILED' - General error when creating ConnectionInfo. Retrying next cycle...
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 12 path $
        at com.google.gson.JsonParser.parse(JsonParser.java:65) ~[21:com.google.gson:2.7.0.v20170129-0911]
        at com.google.gson.JsonParser.parse(JsonParser.java:45) ~[21:com.google.gson:2.7.0.v20170129-0911]
        at name.eskildsen.zoneminder.jetty.JettyConnectionInfo.fetchContentResponse(JettyConnectionInfo.java:159) ~[200:org.openhab.binding.zoneminder:2.3.0.201805211219]
        at name.eskildsen.zoneminder.jetty.JettyConnectionInfo.doItSync(JettyConnectionInfo.java:75) ~[200:org.openhab.binding.zoneminder:2.3.0.201805211219]
        at name.eskildsen.zoneminder.jetty.JettyConnectionInfo.onConnect(JettyConnectionInfo.java:227) ~[200:org.openhab.binding.zoneminder:2.3.0.201805211219]
        at name.eskildsen.zoneminder.internal.GenericConnectionHandler.connect(GenericConnectionHandler.java:141) ~[200:org.openhab.binding.zoneminder:2.3.0.201805211219]
        at name.eskildsen.zoneminder.ZoneMinderFactory.CreateConnection(ZoneMinderFactory.java:34) ~[200:org.openhab.binding.zoneminder:2.3.0.201805211219]
        at org.openhab.binding.zoneminder.handler.ZoneMinderServerBridgeHandler.validateConnection(ZoneMinderServerBridgeHandler.java:801) [200:org.openhab.binding.zoneminder:2.3.0.201805211219]
        at org.openhab.binding.zoneminder.handler.ZoneMinderServerBridgeHandler.initializeAvaliabilityStatus(ZoneMinderServerBridgeHandler.java:1036) [200:org.openhab.binding.zoneminder:2.3.0.201805211219]
        at org.openhab.binding.zoneminder.handler.ZoneMinderServerBridgeHandler.updateAvaliabilityStatus(ZoneMinderServerBridgeHandler.java:1197) [200:org.openhab.binding.zoneminder:2.3.0.201805211219]
        at org.openhab.binding.zoneminder.handler.ZoneMinderServerBridgeHandler$1.run(ZoneMinderServerBridgeHandler.java:114) [200:org.openhab.binding.zoneminder:2.3.0.201805211219]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:?]
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:?]
        at java.lang.Thread.run(Thread.java:748) [?:?]
Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 12 path $
        at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1559) ~[?:?]
        at com.google.gson.stream.JsonReader.checkLenient(JsonReader.java:1401) ~[?:?]
        at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:542) ~[?:?]
        at com.google.gson.stream.JsonReader.peek(JsonReader.java:425) ~[?:?]
        at com.google.gson.JsonParser.parse(JsonParser.java:60) ~[?:?]
        ... 17 more

This evening, I did some maintenance on our server that runs Zoneminder and did a DNF update. I had forgotten that the binding wasn’t working with the updated ZM. You can guess what happened :roll_eyes:. Since my wife fixed it last time…

… she looked at it again. Good news! Using the previous changes, the binding works and the fix is simple. If you update ZM, the configuration files are dropped into /etc/zm/zm.conf.rpmnew so that they do not overwrite your existing configuration. Included in the updated configuration is a fix to remove a deprecation warning in the JSON response that is causing the error in the binding. Apply the new conf and you’ll be working again.

So, if you upgrade (we’re on 1.32.3) and see this, update your configuration…

2019-05-23 19:20:05.365 [ERROR] [org.openhab.binding.zoneminder.internal.handler.ZoneMinderServerBridgeHandler] - [BRIDGE (99ec8cf6)]: context='validateConnection' check='FAILED' - Error creating ConnectionInfo. Retrying next cycle...
name.eskildsen.zoneminder.exception.ZoneMinderInvalidData: Error occurred when converting response to class.
        at name.eskildsen.zoneminder.jetty.JettyConnectionInfo.fetchDataAsJson(JettyConnectionInfo.java:355) ~[205:org.openhab.binding.zoneminder:2.4.0.201812161831]
        at name.eskildsen.zoneminder.jetty.JettyConnectionInfo.onConnect(JettyConnectionInfo.java:288) ~[205:org.openhab.binding.zoneminder:2.4.0.201812161831]
        at name.eskildsen.zoneminder.internal.GenericConnectionHandler.connect(GenericConnectionHandler.java:141) ~[205:org.openhab.binding.zoneminder:2.4.0.201812161831]
        at name.eskildsen.zoneminder.ZoneMinderFactory.CreateConnection(ZoneMinderFactory.java:34) ~[205:org.openhab.binding.zoneminder:2.4.0.201812161831]
        at org.openhab.binding.zoneminder.internal.handler.ZoneMinderServerBridgeHandler.validateConnection(ZoneMinderServerBridgeHandler.java:782) [205:org.openhab.binding.zoneminder:2.4.0.201812161831]
        at org.openhab.binding.zoneminder.internal.handler.ZoneMinderServerBridgeHandler.initializeAvaliabilityStatus(ZoneMinderServerBridgeHandler.java:998) [205:org.openhab.binding.zoneminder:2.4.0.201812161831]
        at org.openhab.binding.zoneminder.internal.handler.ZoneMinderServerBridgeHandler.updateAvaliabilityStatus(ZoneMinderServerBridgeHandler.java:1139) [205:org.openhab.binding.zoneminder:2.4.0.201812161831]
        at org.openhab.binding.zoneminder.internal.handler.ZoneMinderServerBridgeHandler$1.run(ZoneMinderServerBridgeHandler.java:117) [205:org.openhab.binding.zoneminder:2.4.0.201812161831]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:?]
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:?]
        at java.lang.Thread.run(Thread.java:748) [?:?]
Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 7 path $
        at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1568) ~[?:?]
        at com.google.gson.stream.JsonReader.checkLenient(JsonReader.java:1409) ~[?:?]
        at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:542) ~[?:?]
        at com.google.gson.stream.JsonReader.peek(JsonReader.java:425) ~[?:?]
        at com.google.gson.JsonParser.parse(JsonParser.java:60) ~[?:?]
        at com.google.gson.JsonParser.parse(JsonParser.java:45) ~[?:?]
        at name.eskildsen.zoneminder.jetty.JettyConnectionInfo.fetchDataAsJson(JettyConnectionInfo.java:352) ~[?:?]
        ... 14 more

Scott

Thanks for updating on this thread. I have completed the sql inserts and updated the config as described in the fix and I’m still seeing the same “Error occurred when converting response to class” being logged. I was using the 2.4 release of the binding and switched to the market version which appears to be the 2.3 version binding.

I’m unsure if I had actually updated zoneminder to 1.32.3 or if it was fresh reinstall. In either case I’m not seeing a difference in the rpm.save file for the zm.conf so I’m not sure which config item I would look for to supress the json warning.

If anyone has had luck getting the binding to work with 1.32.3 please enlighten me. I know a rewrite is likely necessary long term but I’d love to try to use this with my current set up.

I’m using a version from @mhilbush. I thought this was the same as the version in the marketplace, with some minor fixes that Mark had done, but it looks like there’s more to it than that!

Mark, do you plan on taking this further, or maybe you could post the jar?

I dunno. I back-burned it in order to work on some other things. I need to assess how much work it will be to bring it to conclusion. Posting the jar would suggest I’m ready to support it, and I haven’t made that decision yet…

That’s unfortunate. Could you help refresh my memory… you forked mr_eskildsen’s branch with the changes from the PR that never got merged, right? I guess I could start there, but it would be missing the additional fixes you’ve made. Could you at least please put your fork in GH so that we don’t lose those fixes? I’m still completely immersed in automation, but I’ll put that down to get the official ZM binding working again.

Correct.

Sure, but I’m traveling right now and may not get to it for a few days.

It also will require the inclusion of the private interface lib, zoneminder4j, which I looked at, but never got around to building. It throws NPEs occasionally, which are hard to deal with in the binding.

2 Likes

The Workaround needs to be slightly modified with latest Zoneminder releases.
The Config table Id 225 & 226 have been used for other stuffs, so the DB update should use different Ids. I append 1000 to them for safety, and it works fine:

use zm; #Assuming your zoneminder database is actually named zm
INSERT INTO `Config` VALUES (1225,'ZM_PATH_ZMS','/cgi-bin/nph-zms','string','/cgi-bin/nph-zms','relative/path/to/somewhere','(?^:^((?:[^/].*)?)/?$)',' $1 ','Web path to zms streaming server',' The ZoneMinder streaming server is required to send streamed images to your browser. It will be installed into the cgi-bin path given at configuration time. This option determines what the web path to the server is rather than the local path on your machine. Ordinarily the streaming server runs in parser-header mode however if you experience problems with streaming you can change this to non-parsed-header (nph) mode by changing \'zms\' to \'nph-zms\'. ','hidden',0,NULL);
INSERT INTO `Config` VALUES (1226,'ZM_OPT_FRAME_SERVER','0','boolean','no','yes|no','(?^i:^([yn]))',' ($1 =~ /^y/) ? \"yes\" : \"no\" ','Should analysis farm out the writing of images to disk',' In some circumstances it is possible for a slow disk to take so long writing images to disk that it causes the analysis daemon to fall behind especially during high frame rate events. Setting this option to yes enables a frame server daemon (zmf) which will be sent the images from the analysis daemon and will do the actual writing of images itself freeing up the analysis daemon to get on with other things. Should this transmission fail or other permanent or transient error occur, this function will fall back to the analysis daemon. ','system',0,NULL);

Note that the path, this time, is mine. It should be updated according to your installation. Issue a locate nph-zms to find the relative directory from zoneminder directory.

1 Like

Hi,

Sometimes, despite of the workaround, OpenHab failed to connect to the zoneminder server.
It looks like the plugin doesn’t get that it is not authenticated anymore.
Hopefully, reloading the plugin (or saving its configuration in PaperUI) solves the problem.
But as this was a pain to maintain for my purpose (i use an alarm thing to set cams to Modect when away and Monitor while ar home), here is a little rule for a workaround:

rule "Zoneminder Watchdog"
when
  Time cron "0 * * * * ?"
then
  logInfo("Zoneminder Watchdog", "Checking Zoneminder state")
  // Check the logs for the error message
  var log1 = executeCommandLine("grep 'Unable to authenticate in ZoneMinder' /var/log/openhab2/openhab.log | grep getMonitorData | tail -1", 1000)
  // Check again after 15 seconds - depending on your experience with the logs.
  // I had logs comming every 10 seconds on my setup
  Thread::sleep(15000)
  var log2 = executeCommandLine("grep 'Unable to authenticate in ZoneMinder' /var/log/openhab2/openhab.log | grep getMonitorData | tail -1", 1000)
  // If log lines are different (if there was a new 'Unable to authenticate...' log within 15 seconds) restart the plugin through openhab-cli
  if (log1 != log2) {
    logWarn("Zoneminder Watchdog", "Zoneminder Down, restarting...")
    executeCommandLine("openhab-cli console 'bundle:restart org.openhab.binding.zoneminder'",1000)
    // After 10 seconds, just to let everything come up properly, i then just reapplied my Monitor or Modect mode to the cams.
    Thread::sleep(10000)
    // Do whatever you want, or remove this sleep timer.
  } else {
    logInfo("Zoneminder Watchdog", "Zoneminder UP.")
  }
end

I hope it would help some of you.

1 Like