My Multiserver Setup: ZM, ZMES, DB

Add any particular hints or tricks you have found to help with your ZoneMinder experience.
Post Reply
spottaaja1
Posts: 4
Joined: Thu Jul 07, 2022 6:30 pm

My Multiserver Setup: ZM, ZMES, DB

Post by spottaaja1 »

Hello!

Just wanted to share my setup if someone would find it useful.

I have three ZM servers setup so that one hosts the database, one the cameras and one acts as the event server:
zmservers.png
zmservers.png (20.76 KiB) Viewed 300 times
All filters, audits and such run on ES so that CAMS is dedicated to capturing and motion detection.

Servers are "Linux zoneminder 5.10.0-15-amd64 #1 SMP Debian 5.10.120-1 (2022-06-09) x86_64 GNU/Linux" and run as virtual machines on oVirt cluster.
zmovirt.png
zmovirt.png (7.16 KiB) Viewed 300 times
Some tweaks I had to make to make things work:

1. Made a trigger filter for ES:
mlfilter.png
mlfilter.png (40.88 KiB) Viewed 300 times
The command is:

Code: Select all

/var/lib/zmeventnotification/bin/zm_event_start_wrapper.sh %EI% "" %MN% %EC%
2. Tweaked (made quick'n'dirty ugly hacks to) zm_detect.py to tag analysed Events with "ML:"

Code: Select all

 inserted @ row 476
    if args.get('notes'):
        url = '{}/events/{}.json'.format(g.config['api_portal'], args['eventid'])
        try:
            ev = zmapi._make_request(url=url,  type='get')
        except Exception as e:
            g.logger.Error ('Error during event notes retrieval: {}'.format(str(e)))
            g.logger.Debug(2,traceback.format_exc())
            exit(0) # Let's continue with zmdetect

        new_notes = 'ML:'
        if ev.get('event',{}).get('Event',{}).get('Notes'):
            old_notes = ev['event']['Event']['Notes']
            new_notes = new_notes + old_notes
            g.logger.Debug (1,'Replacing old note:{} with new note:{}'.format(old_notes, new_notes))

        payload = {}
        payload['Event[Notes]'] = new_notes
        try:
            ev = zmapi._make_request(url=url, payload=payload, type='put')
        except Exception as e:
            g.logger.Error ('Error during notes update: {}'.format(str(e)))
            g.logger.Debug(2,traceback.format_exc())

Code: Select all

 modified @ row 534
        if args.get('notes'):
            url = '{}/events/{}.json'.format(g.config['api_portal'], args['eventid'])
            try:
                ev = zmapi._make_request(url=url,  type='get')
            except Exception as e:
                g.logger.Error ('Error during event notes retrieval: {}'.format(str(e)))
                g.logger.Debug(2,traceback.format_exc())
                exit(0) # Let's continue with zmdetect

            new_notes = pred
            if ev.get('event',{}).get('Event',{}).get('Notes'):
                old_notes = ev['event']['Event']['Notes']
                old_notes_split = old_notes.split('ML:')
                old_d = old_notes_split[0] # old detection
                try:
                    old_m = old_notes_split[1]
                except IndexError:
                    old_m = ''
                new_notes = 'ML:' + pred + old_m
                g.logger.Debug (1,'Replacing old note:{} with new note:{}'.format(old_notes, new_notes))

            payload = {}
            payload['Event[Notes]'] = new_notes
            try:
                ev = zmapi._make_request(url=url, payload=payload, type='put')
            except Exception as e:
                g.logger.Error ('Error during notes update: {}'.format(str(e)))
                g.logger.Debug(2,traceback.format_exc())
Now Events in DB get tagged with Machine Learning detections in the Notes field:

Code: Select all

Motion
ML:[s] detected:person:86% Motion: Walkway, Deck, Yard
Once I'm confident that the ML detection is robust enough, I'll create a filter that deletes all events except the ones with detections. This should declutter the event list.
spottaaja1
Posts: 4
Joined: Thu Jul 07, 2022 6:30 pm

Re: My Multiserver Setup: ZM, ZMES, DB

Post by spottaaja1 »

The wrapper I wrote for the Machine Learning filter is just to return 0 (=success) so the log wouldn't show errors all the time as the original returns 1 if nothing is detected:

Code: Select all

#!/bin/bash

OUTPUT=$(/var/lib/zmeventnotification/bin/zm_event_start.sh "$@")
exit 0
I can click the Notes field to see the ML detection:
mlevent.png
mlevent.png (235.27 KiB) Viewed 297 times
Would be interested in ZM mod / tweak / hack / how-to that would enable alert / ML image replay, so that it would replace the original frames with the alert/ML frames when playing back on screen.
ezbncs
Posts: 2
Joined: Tue Jun 28, 2022 9:35 am
Location: Minnesota

Re: My Multiserver Setup: ZM, ZMES, DB

Post by ezbncs »

spottaaja1 wrote: Sun Jul 10, 2022 11:23 am Hello!

Just wanted to share my setup if someone would find it useful.

I have three ZM servers setup so that one hosts the database, one the cameras and one acts as the event server:

Pretty cool and thank you I still need to tweak it some on my end. I did a couple of things different as I was getting a error on execution. Warning I know very little about linux or wildcard searches so this may not work for others but it worked for me. I thought it was a little easier edit on my end to do it this way. I didn't mean to step on your toes spottaaja1 as you gave the idea and 99.9% of the code thank you again.

filter.jpg
filter.jpg (449.78 KiB) Viewed 76 times

I kept everything else the same but removed the "Server Filter is Running On" filter and that fixed my error I am guessing it maybe because I only run 1 server again not to good with linux.

output.jpg
output.jpg (129.21 KiB) Viewed 76 times

The other change I made instead of editing the code as original post did I just searched for [s] and added ML: as a prefix to [s] [a] and [x]. I found it on line 455/567 in nano your line may be different.

Original

Code: Select all

    if matched_data['frame_id'] == 'snapshot':
        prefix = '[s] '
    elif matched_data['frame_id'] == 'alarm':
        prefix = '[a] '
    else:
        prefix = '[x] '

Editted

Code: Select all

    if matched_data['frame_id'] == 'snapshot':
        prefix = 'ML: [s] '
    elif matched_data['frame_id'] == 'alarm':
        prefix = 'ML: [a] '
    else:
        prefix = 'ML: [x] '
Life what's that now back to zoneminder and motion detection hell.
Post Reply