New Zoneminder Binding for Zoneminder versions >= 1.34.0

Thanks for your help Mark. Seems I have the file downloaded correctly as below.

That doesn’t look right. The file should be about 45k. What does it show when you run

file org.openhab.binding.zm-2.5.3-SNAPSHOT.jar

The most current version looks like this:

mark@server1:/opt/openhab2/addons$ ls -l org.openhab.binding.zm-2.5.3-SNAPSHOT.jar
-rw-r--r-- 1 mark mark 45676 Mar 18 07:33 org.openhab.binding.zm-2.5.3-SNAPSHOT.jar

mark@server1:/opt/openhab2/addons$ file org.openhab.binding.zm-2.5.3-SNAPSHOT.jar
org.openhab.binding.zm-2.5.3-SNAPSHOT.jar: Zip archive data, at least v1.0 to extract

BTW, I just pushed a new version that has some updated documentation explaining authenticated versus non-authenticated installation.

Edit: I suppose it would be helpful if I included a link to the README. :roll_eyes:

Sorted now. Downloaded using a different method and now have it all work. Thanks.

1 Like

Found another issue now. I’m getting logs of this in my openhab.log file.

2020-03-18 16:08:35.090 [INFO ] [.binding.zm.internal.handler.Monitor] - Monitor object contains invalid monthEvents
2020-03-18 16:08:41.673 [INFO ] [.binding.zm.internal.handler.Monitor] - Monitor object contains invalid hourEvents
2020-03-18 16:08:41.673 [INFO ] [.binding.zm.internal.handler.Monitor] - Monitor object contains invalid dayEvents
2020-03-18 16:08:41.673 [INFO ] [.binding.zm.internal.handler.Monitor] - Monitor object contains invalid totalEvents

I’ve disabled auto discovery and that’s not made any difference.

Thanks again for getting this binding back into a position where we can start to use it again.

Hmm. That’s interesting. Aside from those errors, everything else should be working ok. Correct?

Can you put the binding into TRACE mode, then post the JSON that’s returned from the zoneminder server? If you’re rather not post it publicly, you could PM me.

That’s ok. I wouldn’t expect that to make a difference.

Thanks @mhilbush for your help. Yes everything works fine.

I removed and re-setup everything, including the binding, and the error is no longer in the openhab.log. So not sure what was happening.

Me either. But I do see one thing that could cause it, so I’ll put in a defensive check for that. I’ll probably also reduce the log level of that message to DEBUG.

Thank you @mhilbush for this updated binding!

Are you actively working on it again? I did try to get into the code of the previous bindings, but as i’m not a good Java dev and the plugins got refactored in between, i was absolutely lost.

That said, i wonder how hard it could be to implement a write mode on the ‘function’ channel.
My use case is to switch between Monitor and Modect depending if i am at home or away.

I looked into your zoneminder branch and saw this may be an ‘action’ to add, but i am not sure to understand things well enough to do it myself and PR the change.

Edit: My bad, it seems to be implemented, i can see the POST request on the zoneminder server, but for some reason, my monitor state doesn’t get updated :frowning:

My binding is a complete rewrite. I started from scratch and implemented it using the 2.0 API. As a result, my binding is much simpler (and hopefully more reliable).

Yes, sending a command to the function channel should allow you to change the monitor function. I say should because I haven’t tested it yet. It’s quite possible that I’m doing something wrong.

I also notice that I should define some state options on the function channel. That would make it easier to use a Selection widget in Basic UI or HABpanel.

I’ll take a closer loot at this today.

1 Like

@el00ruobuob I did a quick test from the command line (using curl) and I’m able to change the function and enabled state of a monitor. Perhaps I’m doing something wrong in the binding.

1 Like

Yep, I’m doing something wrong in the binding…

Bridge: Http POST to 'http://xxxxx/zm/api/monitors/5.json' returned: {"message":"Error Array\n(\n)\n"} in 6 ms

Edit: I was sending the wrong content type in the POST. Should be fixed shortly.

Edit: It’s fixed now. Version number changed so make sure to remove 2.5.3 and replace with 2.5.4.

Also added state options to the function channel, so now you can use a Selection widget in Basic UI and HABpanel. :wink:

Edit: I also added state options to the enable channel.

Now my HABpanel looks like this.

zm

1 Like

Thank you, you’re very fast.
I made my research in the meantime and found a content-type issue:

### From OpenHab module
13:45:57.179611 IP (tos 0x0, ttl 63, id 64336, offset 0, flags [DF], proto TCP (6), length 469)
    <openhab_ip>.54718 > <zoneminder_ip>.80: Flags [P.], cksum 0x8f12 (correct), seq 715:1132, ack 36002, win 720, options [nop,nop,TS val 4140860431 ecr 978996503], length 417: HTTP, length: 417
        POST /zm/api/monitors/5.json?token=<my_token> HTTP/1.1
        Accept-Encoding: gzip
        User-Agent: Jetty/9.4.20.v20190813
        Content-Type: text/plain
        Host: <zoneminder_hostname>.<my_domain>
        Content-Length: 24

        Monitor[Function]=Modect[!http]
13:45:57.179650 IP (tos 0x0, ttl 64, id 63855, offset 0, flags [DF], proto TCP (6), length 52)
    <zoneminder_ip>.80 > <openhab_ip>.54718: Flags [.], cksum 0x8cd2 (incorrect -> 0xb592), seq 36002, ack 1132, win 482, options [nop,nop,TS val 979000776 ecr 4140860431], length 0
13:45:57.192278 IP (tos 0x0, ttl 64, id 63856, offset 0, flags [DF], proto TCP (6), length 240)
    <zoneminder_ip>.80 > <openhab_ip>.54718: Flags [P.], cksum 0x8d8e (incorrect -> 0x7dca), seq 36002:36190, ack 1132, win 482, options [nop,nop,TS val 979000788 ecr 4140860431], length 188: HTTP, length: 188
        HTTP/1.1 200 OK
        Date: Sat, 21 Mar 2020 12:45:57 GMT
        Server: Apache/2.4.29 (Ubuntu)
        Content-Length: 33
        Content-Type: application/json; charset=UTF-8

        {"message":"Error Array\n(\n)\n"}[!http]
13:45:57.192898 IP (tos 0x0, ttl 63, id 64337, offset 0, flags [DF], proto TCP (6), length 52)
    <openhab_ip>.54718 > <zoneminder_ip>.80: Flags [.], cksum 0xb3b9 (correct), seq 1132, ack 36190, win 742, options [nop,nop,TS val 4140860444 ecr 979000788], length 0

### From Curl
13:57:33.985657 IP (tos 0x0, ttl 63, id 36485, offset 0, flags [DF], proto TCP (6), length 447)
    <openhab_ip>.58292 > <zoneminder_ip>.80: Flags [P.], cksum 0x9027 (correct), seq 1:396, ack 1, win 502, options [nop,nop,TS val 4141557235 ecr 979697571], length 395: HTTP, length: 395
        POST /zm/api/monitors/5.json?token=<my_token> HTTP/1.1
        Host: <zoneminder_ip>
        User-Agent: curl/7.58.0
        Accept: */*
        Content-Length: 24
        Content-Type: application/x-www-form-urlencoded

        Monitor[Function]=Modect[!http]
13:57:33.985688 IP (tos 0x0, ttl 64, id 4432, offset 0, flags [DF], proto TCP (6), length 52)
    <zoneminder_ip>.80 > <openhab_ip>.58292: Flags [.], cksum 0x8cd2 (incorrect -> 0xadfb), seq 1, ack 396, win 487, options [nop,nop,TS val 979697572 ecr 4141557235], length 0
13:57:34.637752 IP (tos 0x0, ttl 64, id 4433, offset 0, flags [DF], proto TCP (6), length 226)
    <zoneminder_ip>.80 > <openhab_ip>.58292: Flags [P.], cksum 0x8d80 (incorrect -> 0xd449), seq 1:175, ack 396, win 487, options [nop,nop,TS val 979698224 ecr 4141557235], length 174: HTTP, length: 174
        HTTP/1.1 200 OK
        Date: Sat, 21 Mar 2020 12:57:33 GMT
        Server: Apache/2.4.29 (Ubuntu)
        Content-Length: 19
        Content-Type: application/json; charset=UTF-8

        {"message":"Saved"}[!http]
13:57:34.638240 IP (tos 0x0, ttl 63, id 36486, offset 0, flags [DF], proto TCP (6), length 52)
    <openhab_ip>.58292 > <zoneminder_ip>.80: Flags [.], cksum 0xa827 (correct), seq 396, ack 175, win 501, options [nop,nop,TS val 4141557887 ecr 979698224], length 0

### From Curl with content-type set to text/plain
13:58:22.088953 IP (tos 0x0, ttl 63, id 74, offset 0, flags [DF], proto TCP (6), length 424)
    <openhab_ip>.58544 > <zoneminder_ip>.80: Flags [P.], cksum 0xd41b (correct), seq 1:373, ack 1, win 502, options [nop,nop,TS val 4141605338 ecr 979745674], length 372: HTTP, length: 372
        POST /zm/api/monitors/5.json?token=<my_token> HTTP/1.1
        Host: <zoneminder_ip>
        User-Agent: curl/7.58.0
        Accept: */*
        Content-Type: text/plain
        Content-Length: 24

        Monitor[Function]=Modect[!http]
13:58:22.088988 IP (tos 0x0, ttl 64, id 33354, offset 0, flags [DF], proto TCP (6), length 52)
    <zoneminder_ip>.80 > <openhab_ip>.58544: Flags [.], cksum 0x8cd2 (incorrect -> 0xd808), seq 1, ack 373, win 487, options [nop,nop,TS val 979745675 ecr 4141605338], length 0
13:58:22.099868 IP (tos 0x0, ttl 64, id 33355, offset 0, flags [DF], proto TCP (6), length 240)
    <zoneminder_ip>.80 > <openhab_ip>.58544: Flags [P.], cksum 0x8d8e (incorrect -> 0xa046), seq 1:189, ack 373, win 487, options [nop,nop,TS val 979745685 ecr 4141605338], length 188: HTTP, length: 188
        HTTP/1.1 200 OK
        Date: Sat, 21 Mar 2020 12:58:22 GMT
        Server: Apache/2.4.29 (Ubuntu)
        Content-Length: 33
        Content-Type: application/json; charset=UTF-8

        {"message":"Error Array\n(\n)\n"}[!http]
13:58:22.100398 IP (tos 0x0, ttl 63, id 75, offset 0, flags [DF], proto TCP (6), length 52)
    <openhab_ip>.58544 > <zoneminder_ip>.80: Flags [.], cksum 0xd729 (correct), seq 373, ack 189, win 501, options [nop,nop,TS val 4141605349 ecr 979745685], length 0

I just tried your new release and its working like a charm.
Thank you so much!

1 Like

Glad that solved it. Let me know if you run into any other issues, or have suggestions for improvement.

Well, at the moment it’s doing what i needed to do.
But if you want to do more, you could look into retrieving the last event for each monitor, with some basic fields:

curl 'http://<zm_ip>/zm/api/events/index/MonitorId:9.json?sort=StartTime&direction=desc&limit=1&token=<token>' | json_pp
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   983  100   983    0     0  61437      0 --:--:-- --:--:-- --:--:-- 61437
{
   "pagination" : {
      "current" : 1,
      "queryScope" : null,
      "page" : 1,
      "nextPage" : true,
      "options" : {
         "direction" : "desc",
         "order" : {
            "Event.StartTime" : "desc"
         },
         "sort" : "StartTime",
         "limit" : 1
      },
      "pageCount" : 45,
      "prevPage" : false,
      "paramType" : "querystring",
      "count" : 45,
      "limit" : 1,
      "order" : {
         "Event.StartTime" : "desc"
      }
   },
   "events" : [
      {
         "Event" : {
            "AvgScore" : "2",
            "StorageId" : "0",
            "Uploaded" : "0",
            "EndTime" : "2020-03-21 13:30:36",
            "StateId" : "1",
            "SecondaryStorageId" : "0",
            "Locked" : false,
            "Cause" : "Motion",
            "Notes" : "[a] detected:person:100% Motion: All",
            "Width" : "1920",
            "MaxScoreFrameId" : "6030182",
            "Length" : "30.59",
            "MaxScore" : "3",
            "Executed" : "0",
            "Videoed" : "0",
            "DiskSpace" : "4629009",
            "StartTime" : "2020-03-21 13:30:05",
            "Height" : "1080",
            "FileSystemPath" : "/var/cache/zoneminder/events/9/2020-03-21/71297",
            "SaveJPEGs" : "2",
            "AlarmFrames" : "2",
            "MonitorId" : "9",
            "Frames" : "47",
            "Emailed" : "0",
            "Name" : "Event- 71297",
            "Scheme" : "Medium",
            "Messaged" : "0",
            "Archived" : "0",
            "Orientation" : "ROTATE_0",
            "Id" : "71297",
            "TotScore" : "5",
            "DefaultVideo" : "71297-video.mp4"
         }
      }
   ]
}

It could be interesting to store the last event ‘StartTime’, ‘EndTime’, ‘Cause’ & ‘Notes’.

Here, the ‘Notes’ is filled by zmeventnotification which do object detection on the alarm frames and reports its findings (only ‘person’ in my usecase).

My use case: i’m using the alarm binding, and triggers alarms based on the detected persons, curently through an mqtt topic for each monitor. Having this natively could be nice.

Yeah, I’ve been thinking about how best to handle events. Haven’t quite sorted it out in my head just yet. Was thinking about an action that would get the last n events for a monitor. But then you’d need to parse the json response. Although thought about some channels for the “last” event, but it’s a bit difficult to do because the current API requires you to poll for events, therefore, it’s possible to miss event(s) depending on the polling frequency.

What’s the alarm binding? I’m not familiar with such a binding.

Can you explain a little more what it is you would like to see done natively?

This: openhab-addons/addons/binding/org.openhab.binding.alarm/README.md at alarm-1.1.2 · gerrieg/openhab-addons · GitHub

It’s a “logical” binding that let you use openhab as an alarm controller.
You just need to work with rules to feed the zones (triggering them), and then do some other stuff if the alarm is triggered (in my case, sending text messages and notifying amazon echo devices).
It’s just a toolbox that helps to configure an alarm by reducing the amount of rules that would be required to handle it “alone”.

At the moment, i feed my zones based on an update on an MQTT topic.
It means i need to have zoneminder (zmeventnotification) feeding the channel, and openhab reading the channel, while if the event info were updated natively on openhab - indeed with the polling frequency issue - i could just configure my rules to feed the zone when the event ID is updated and the Notes contains the keyword ‘person’ with a relevant confidence level.
It would remove an extra step (MQTT) in the process, and as a result (presumably) improve the reliability.

Here’s, for exemple, how i feed a zone today:

// Triggering an External Zone 1 alarm
rule "ExtZone1"
when
  Item ZoneminderMQTT_CameraGarage1MQTT received update or
  Item ZoneminderMQTT_CameraJardin1MQTT received update
then
  if (AlarmControllerExterieur_Status.state == "EXTERNALLY_ARMED" || AlarmControllerExterieur_Status.state == "INTERNALLY_ARMED") {
    if (triggeringItem.state.toString.contains("person") ) {
      AlarmControllerExterieur_AlarmZone1.sendCommand(OPEN)
      ext_zone1_Triggers += " " + triggeringItem.label.toString + ","
    }
  }
end

It could be updated to something like this, for each monitor:

// Triggering an External Zone 1 alarm (Garage)
rule "ExtZone1_Garage"
when
  Item CameraGarage1_EventID received update or
  Item CameraGarage1_EventNotes received update
then
  if (AlarmControllerExterieur_Status.state == "EXTERNALLY_ARMED" || AlarmControllerExterieur_Status.state == "INTERNALLY_ARMED") {
    if (CameraGarage1_EventNotes.toString.contains("person") ) {
      AlarmControllerExterieur_AlarmZone1.sendCommand(OPEN)
      ext_zone1_Triggers += " " + triggeringItem.label.toString + ","
    }
  }
end

But this was just an improvement idea. As i wrote earlier, the current binding is totally fine as it is now.

@el00ruobuob I figured out the query to get the most recent event id, so I’m going to add a new channel(s) for the last event. It still requires polling, but as long as you have a short polling interval (I use 5 seconds), it should not be an issue.

I’m adding channels to the monitor thing for the last event. The event object from Zoneminder contains the following:

      "Event": {
        "Id": "2702",
        "MonitorId": "1",
        "StorageId": "0",
        "SecondaryStorageId": "0",
        "Name": "Event- 2702",
        "Cause": "Forced Web",
        "StartTime": "2020-03-20 10:40:52",
        "EndTime": "2020-03-20 10:43:58",
        "Width": "1280",
        "Height": "720",
        "Length": "185.36",
        "Frames": "1343",
        "AlarmFrames": "1143",
        "DefaultVideo": "",
        "SaveJPEGs": "3",
        "TotScore": "291465",
        "AvgScore": "255",
        "MaxScore": "255",
        "Archived": "0",
        "Videoed": "0",
        "Uploaded": "0",
        "Emailed": "0",
        "Messaged": "0",
        "Executed": "0",
        "Notes": "Forced Web: ",
        "StateId": "1",
        "Orientation": "ROTATE_0",
        "DiskSpace": "193039675",
        "Scheme": "Medium",
        "Locked": false,
        "MaxScoreFrameId": "557771",
        "FileSystemPath": "/zoneminder/events/1/2020-03-20/2702"

I’m planning to add the following channels.

   String eventId
   String eventName
   String eventCause
   DateTime eventStart
   DateTime eventEnd
   Number eventFrames
   Number eventAlarmFrames
   Number:Time eventLength

Can anyone make a case for anything else?

1 Like

Thank you @mhilbush for this Binding.
Finally got this working after a lot of failed tries with the other zoneminder bindings.

1 Like