pyzm package

API

Classes returned by the API

Monitors

Holds a list of Monitors for a ZM configuration Given monitors are fairly static, maintains a cache of monitors which can be overriden

class pyzm.helpers.Monitors.Monitors(api=None)

Bases: pyzm.helpers.Base.Base

add(options={})

Adds a new monitor

Parameters:options (dict) –

Set of attributes that define the monitor:

{
    'function': string # function of monitor
    'name': string # name of monitor
    'enabled': boolean
    'protocol': string
    'host': string
    'port': int
    'path': string
    'width': int
    'height': int
    'raw': {
        # Any other monitor value that is not exposed above. Example:
        'Monitor[Colours]': '4',
        'Monitor[Method]': 'simple'
    }

}
Returns:json response of API request
Return type:json
find(id=None, name=None)

Given an id or name, returns matching monitor object

Parameters:
  • id (int, optional) – MonitorId of monitor. Defaults to None.
  • name (string, optional) – Monitor name of monitor. Defaults to None.
Returns:

Matching monitor object

Return type:

pyzm.helpers.Monitor

list()

Monitor

Each Monitor will hold a single ZoneMinder Monitor. It is basically a bunch of getters for each access to event data. If you don’t see a specific getter, just use the generic get function to get the full object

class pyzm.helpers.Monitor.Monitor(api=None, monitor=None)

Bases: pyzm.helpers.Base.Base

arm()

Arms monitor (forces alarm)

Returns:API response
Return type:json
delete()

Deletes monitor

Returns:API response
Return type:json
dimensions()

Returns width and height of monitor

Returns:as below:
{
    'width': int,
    'height': int
}
Return type:dict
disarm()

Disarm monito (removes alarm)

Returns:API response
Return type:json
enabled()

True if monitor is enabled

Returns:Enabled or not
Return type:bool
eventcount(options={})

Returns count of events for monitor

Parameters:options (dict, optional) – Same as options for pyzm.helpers.Event. Defaults to {}.
Returns:count
Return type:int
events(options={})

Returns events associated to the monitor, subject to filters in options

Parameters:options (dict, optional) – Same as options for pyzm.helpers.Event. Defaults to {}.
Returns:pyzm.helpers.Events
function()

returns monitor function

Returns:monitor function
Return type:string
get()

Returns monitor object

Returns:Monitor object
Return type:pyzm.helpers.Monitor
id()

Returns monitor Id

Returns:Monitor Id
Return type:int
name()

Returns monitor name

Returns:monitor name
Return type:string
set_parameter(options={})

Changes monitor parameters

Parameters:options (dict, optional) –

As below. Defaults to {}:

{
    'function': string # function of monitor
    'name': string # name of monitor
    'enabled': boolean
    'raw': {
        # Any other monitor value that is not exposed above. Example:
        'Monitor[Colours]': '4',
        'Monitor[Method]': 'simple'
    }

}
Returns:API Response
Return type:json
status()
Returns status of monitor, as reported by zmdc
TBD: crappy return, need to normalize
Returns:API response
Return type:json
type()

Returns monitor type

Returns:Monitor type
Return type:string

States

Holds a list of States for a ZM configuration Given states are fairly static, maintains a cache of states which can be overriden

class pyzm.helpers.States.States(api=None)

Bases: pyzm.helpers.Base.Base

find(id=None, name=None)

Return a state object that matches either and id or a

Parameters:
  • id (int, optional) – Id of state. Defaults to None.
  • name (string, optional) – name of state. Defaults to None.
Returns:

State object that matches

Return type:

pyzm.helpers.State

list()

Returns list of state objects

Returns:list of state objects
Return type:list of pyzm.helpers.State

State

Each State will hold a single ZoneMinder State. It is basically a bunch of getters for each access to event data. If you don’t see a specific getter, just use the generic get function to get the full object

class pyzm.helpers.State.State(api=None, state=None)

Bases: pyzm.helpers.Base.Base

active()

whether this state is active or not

Returns:True if active
Return type:bool
definition()

Returns the description text of this state

Returns:description
Return type:string
get()

Returns raw state object

Returns:raw state object
Return type:pyzm.helpers.State
id()

Id of this state

Returns:id of this state
Return type:int
name()

Name of this state

Returns:name of this state
Return type:string

Base

All classes derive from this Base class. It implements some common functions that apply across all. For now, this basically holds a pointer to the logging function to invoke to log messages including a simple console based print function if none is provided

class pyzm.helpers.Base.Base

Bases: object

class pyzm.helpers.Base.ConsoleLog

Bases: object

console based logging function that is used if no logging handler is passed

Debug(level, message, caller=None)
Error(message, caller=None)
Fatal(message, caller=None)
Info(message, caller=None)
Panic(message, caller=None)
Warning(message, caller=None)
get_level()
set_level(level)

Logging

ZMLog

Implements a python implementation of ZoneMinder’s logging system You could use this to connect it to the APIs if you want

pyzm.ZMLog.Debug(level=1, message=None, caller=None)

Debug level ZM message

Parameters:
  • level (int) – ZM Debug level
  • message (string) – Message to log
  • caller (stack frame info, optional) – Used to log caller id/line #. Picked up automatically if none. Defaults to None.
pyzm.ZMLog.Error(message=None, caller=None)

Error level ZM message

Parameters:
  • message (string) – Message to log
  • caller (stack frame info, optional) – Used to log caller id/line #. Picked up automatically if none. Defaults to None.
pyzm.ZMLog.Fatal(message=None, caller=None)

Fatal level ZM message. Quits after logging

Parameters:
  • message (string) – Message to log
  • caller (stack frame info, optional) – Used to log caller id/line #. Picked up automatically if none. Defaults to None.
pyzm.ZMLog.Info(message=None, caller=None)

Info level ZM message

Parameters:
  • message (string) – Message to log
  • caller (stack frame info, optional) – Used to log caller id/line #. Picked up automatically if none. Defaults to None.
pyzm.ZMLog.Panic(message=None, caller=None)

Panic level ZM message. Quits after logging

Parameters:
  • message (string) – Message to log
  • caller (stack frame info, optional) – Used to log caller id/line #. Picked up automatically if none. Defaults to None.
pyzm.ZMLog.Warning(message=None, caller=None)

Warning level ZM message

Parameters:
  • message (string) – Message to log
  • caller (stack frame info, optional) – Used to log caller id/line #. Picked up automatically if none. Defaults to None.
pyzm.ZMLog.close()

Closes all handles. Invoke this before you exit your app

pyzm.ZMLog.get_config()

Returns configuration of ZM logger

Returns:config params
Return type:dict
pyzm.ZMLog.init(name=None, override={})

Initializes the ZM logging system. It follows ZM logging principles and ties into appropriate ZM logging levels. Like the rest of ZM, it can write to files, syslog and the ZM DB.

To make it simpler to override, you can pass various options in the override dict. When passed, they will override any ZM setting

Parameters:
  • name (string, optional) – Name to be used while writing logs. If not specified, it will use the process name. Defaults to None.
  • override (dict, optional) –

    Various parameters that can supercede standard ZM logs. Defaults to {}. The parameters that can be overriden are:

    {
        'dump_console': False,
        'conf_path': '/etc/zm',
        'dbuser' : None,
        'dbpassword' : None,
        'dbhost' : None,
        'webuser': 'www-data',
        'webgroup': 'www-data',
        'dbname' : None,
        'logpath' : '/var/log/zm',
        'log_level_syslog' : 0,
        'log_level_file' : 0,
        'log_level_db' : 0,
        'log_debug' : 0,
        'log_level_debug' : 1,
        'log_debug_target' : '',
        'log_debug_file' :'',
        'server_id': 0,
        'driver': 'mysql+mysqlconnector'
    }
    
    You can also pass environment variables (supports .env files too):
    - PYZM_CONFPATH : path to zm.conf. Default is /etc/zm. Note that if you have a conf file, the values below
                      will automatically be picked up from the conf. You can choose to override them by using
                      the variables below
    
    - PYZM_DBUSER: ZM DB user
    - PYZM_DBPASSWORD : ZM DB password
    - PYZM_DBHOST: ZM DB host
    - PYZM_DBNAME  ZM DB Name
    - PYZM_WEBUSER: web user
    - PYZM_WEBGROUP: web group
    - PYZM_LOGPATH: path to ZM logs
    - PYZM_SYSLOGLEVEL
    - PYZM_FILELOGLEVEL
    - PYZM_DBLOGLEVEL
    - PYZM_LOGDEBUG
    - PYZM_LOGDEBUGLEVEL
    - PYZM_LOGDEBUGTARGET
    - PYZM_LOGDEBUGFILE
    - PYZM_SERVERID
    
    These are specific to pyzm:
    - PYZM_DUMPCONSOLE: If True will print logs to terminal
    - PYZM_DBDRIVER: Switch the driver pyzm uses to connect to the DB
    
    The order of priority is:
    
    - pyzm_overrides takes priority over env variables
    - env variables (supports .env file) take priority over ZM config files
    - ZM config files is used for whatever is not overriden above
    
pyzm.ZMLog.set_level(level)
pyzm.ZMLog.sig_intr(sig, frame)
pyzm.ZMLog.sig_log_rot(sig, frame)

Event Notification

ZMEventNotification

Implements a python implementation of the ZM ES server.

class pyzm.ZMEventNotification.ZMEventNotification(options)
__init__(options)

Instantiates a thread that connects to the ZM Notification Server

Parameters:options (dict) –

As below:

{
    'url': string # websocket url
    'user': string # zm user name
    'password': string # zm password
    'allow_untrusted': boolean # set to true for self-signed certs
    'on_es_message': callback function when a message is received
    'on_es_close': callback function when the connection is closed
    'on_es_error': callback function when an error occurs
}
Raises:ValueError – if no server is provided
connect()

Connect to the ES

disconnect()

Disconnect from the ES

send(msg)

Send message to ES

Parameters:msg (dict) – message to send. The message should follow a control structure as specified in The ES developer guide

Memory

ZMMemory

Wrapper to access SHM for Monitor status

class pyzm.ZMMemory.ZMMemory(api=None, path='/dev/shm', mid=None)
__init__(api=None, path='/dev/shm', mid=None)

Initialize self. See help(type(self)) for accurate signature.

alarm_state()

Returns alarm state

Returns:as below:
{
    'id': int # state id
    'state': string # name of state
}
Return type:dict
cause()

Returns alarm and trigger cause as applicable

Returns:as below:
{
    'alarm_cause': string
    'trigger_cause': string
}
Return type:dict
close()

Closes the handle

get()

returns raw shared and trigger data as a dict

Returns:raw shared and trigger data
{
    'shared_data': dict, # of shared data,
    'trigger_data': dict # trigger data
}
Return type:dict
get_shared_data()

Returns just the shared data

Returns:shared data
Return type:dict
get_trigger_data()

Returns just the trigger data

Returns:trigger data
Return type:dict
is_alarmed()

True if monitor is currently alarmed

Returns:True if monitor is currently alarmed
Return type:bool
is_valid()

True if the memory handle is valid

Returns:True if memory handle is valid
Return type:bool
last_event()

Returns last event ID

Returns:last event id
Return type:int
reload()

Reloads monitor information. Call after you get an invalid memory report

Raises:ValueError – if no monitor is provided
trigger()

Returns trigger information

Returns:as below:
{
    'trigger_text': string,
    'trigger_showtext': string,
    'trigger_cause': string,
    'trigger:state' {
        'id': int,
        'state': string
    }
}
Return type:dict

Machine Learning

DetectSequence

Primary entry point to invoke machine learning classes in pyzm It is recommended you only use DetectSequence methods and not lower level interfaces as they may change drastically.

class pyzm.ml.detect_sequence.DetectSequence(options={}, global_config={})
__init__(options={}, global_config={})

Initializes ML entry point with various parameters

Parameters:options (-) –

Variety of ML options. Best described by an example as below

options = {
    'general': {
        # sequence of models you want to run for every specified frame
        'model_sequence': 'object,face,alpr' ,
        # If 'yes', will not use portalocks
        'disable_locks':'no',

    },

    # We now specify all the config parameters per model_sequence entry
    'object': {
        'general':{
            # 'first' - When detecting objects, if there are multiple fallbacks, break out
            # the moment we get a match using any object detection library.
            # 'most' - run through all libraries, select one that has most object matches
            # 'most_unique' - run through all libraries, select one that has most unique object matches

            'same_model_sequence_strategy': 'first' # 'first' 'most', 'most_unique', 'union'
            'pattern': '.*' # any pattern
        },

        # within object, this is a sequence of object detection libraries. In this case,
        # First try Coral TPU, if it fails try GPU, and finally, if configured, try AWS Rekognition
        'sequence': [
        {
            # Intel Coral TPU
            'object_weights':'/var/lib/zmeventnotification/models/coral_edgetpu/ssd_mobilenet_v2_coco_quant_postprocess_edgetpu.tflite',
            'object_labels': '/var/lib/zmeventnotification/models/coral_edgetpu/coco_indexed.names',
            'object_min_confidence': 0.3,
            'object_framework':'coral_edgetpu'
        },
        {
            # YoloV4 on GPU if TPU fails (because sequence strategy is 'first')
            'object_config':'/var/lib/zmeventnotification/models/yolov4/yolov4.cfg',
            'object_weights':'/var/lib/zmeventnotification/models/yolov4/yolov4.weights',
            'object_labels': '/var/lib/zmeventnotification/models/yolov4/coco.names',
            'object_min_confidence': 0.3,
            'object_framework':'opencv',
            'object_processor': 'gpu',
            # These are optional below. Default is 416. Change if your model is trained for larger sizes
            'model_width': 416,
            'model_height': 416
        },
        {
            # AWS Rekognition object detection
            # More info: https://medium.com/@michael-ludvig/aws-rekognition-support-for-zoneminder-object-detection-40b71f926a80
            'object_framework': 'aws_rekognition'
            'object_min_confidence': 0.7,
            # AWS region unless configured otherwise, e.g. in ~www-data/.aws/config
            'aws_region': 'us-east-1',
            # AWS credentials from /etc/zm/secrets.ini
            # unless running on EC2 instance with instance IAM role (which is preferable)
            'aws_access_key_id': '!AWS_ACCESS_KEY_ID',
            'aws_secret_access_key': '!AWS_SECRET_ACCESS_KEY',
            # no other parameters are required
        }
        ]
    },

    # We repeat the same exercise with 'face' as it is next in model_sequence
    'face': {
        'general':{
            'same_model_sequence_strategy': 'first'
        },
        'sequence': [{
            # if max_size is specified, not matter what
            # the resize value in stream_options, it will be rescaled down to this
            # value if needed
            'max_size':800,
            'face_detection_framework': 'dlib',
            'known_images_path': '/var/lib/zmeventnotification/known_faces',
            'face_model': 'cnn',
            'face_train_model': 'cnn',
            'face_recog_dist_threshold': 0.6,
            'face_num_jitters': 1,
            'face_upsample_times':1
        }]
    },

    # We repeat the same exercise with 'alpr' as it is next in model_sequence
    'alpr': {
        'general':{
            'same_model_sequence_strategy': 'first',

            # This can be applied to any model. This means, don't run this model
            # unless a previous model detected one of these labels.
            # In this case, I'm not calling ALPR unless we've detected a vehile
            # bacause platerec has an API threshold

            'pre_existing_labels':['car', 'motorbike', 'bus', 'truck', 'boat'],

        },
        'sequence': [{
            'alpr_api_type': 'cloud',
            'alpr_service': 'plate_recognizer',
            'alpr_key': g.config['alpr_key'],
            'platrec_stats': 'no',
            'platerec_min_dscore': 0.1,
            'platerec_min_score': 0.2,
        }]
    }
} # ml_options

- global_config (dict): Used by zm_detect and mlapi to pass
  additional config parameters that may not be present in ml_config
detect_stream(stream, options={}, ml_overrides={})

Implements detection on a video stream

Parameters:
  • stream (string) – location of media (file, url or event ID)
  • ml_overrides (string) – Ignore it. You will almost never need it. zm_detect uses it for ugly foo
  • options (dict, optional) –

    Various options that control the detection process. Defaults to {}:

    • delay (int): Delay in seconds before starting media stream
    • delay_between_frames (int): Delay in seconds between each frame read
    • delay_between_snapshots (int): Delay in seconds between each snapshot frame read (useful if you want to read snapshot multiple times, for example. frameset: [‘snapshot’,’snapshot’,’snapshot’])
    • download (boolean): if True, will download video before analysis. Defaults to False
    • download_dir (string): directory where downloads will be kept (only applies to videos). Default is /tmp
    • start_frame (int): Which frame to start analysis. Default 1.
    • frame_skip: (int): Number of frames to skip in video (example, 3 means process every 3rd frame)
    • max_frames (int): Total number of frames to process before stopping
    • pattern (string): regexp for objects that will be matched. ‘frame_strategy’ key below will be applied to only objects that match this pattern
    • frame_set (string or list): comma separated frames to read. Example ‘alarm,21,31,41,snapshot’ or [‘snapshot’,’alarm’,’1’,’2’] Note that if you are specifying frame IDs and using ZM, remember that ZM has a frame buffer Default is 20, I think. So you may want to start at frame 21.
    • contig_frames_before_error (int): How many contiguous frames should fail before we give up on reading this stream. Default 5
    • max_attempts (int): Only for ZM indirection. How many times to retry a failed frame get. Default 1
    • sleep_between_attempts (int): Only for ZM indirection. Time to wait before re-trying a failed frame
    • disable_ssl_cert_check (bool): If True (default) will allow self-signed certs to work
    • save_frames (boolean): If True, will save frames used in analysis. Default False
    • save_analyzed_frames (boolean): If True, will save analyzed frames (with boxes). Default False
    • save_frames_dir (string): Directory to save analyzed frames. Default /tmp
    • frame_strategy: (string): various conditions to stop matching as below
      • ’most_models’: Match the frame that has matched most models (does not include same model alternatives) (Default)
      • ’first’: Stop at first match
      • ’most’: Match the frame that has the highest number of detected objects
      • ’most_unique’ Match the frame that has the highest number of unique detected objects
    • resize (int): Width to resize image, default 800
    • polygons(object): object # set of polygons that the detected image needs to intersect
    • convert_snapshot_to_fid (bool or ‘yes’): if True/’yes’, will convert ‘snapshot’ to an actual fid. If you are seeing boxes at wrong places for snapshot frames, this may fix it. However, it can also result in frame 404 errors if that frame ID is not yet written to disk. So you may want to add a delay if you enable this. Default is False.
Returns:

representing matched frame, consists of:

  • box (array): list of bounding boxes for matched frame
  • label (array): list of labels for matched frame
  • confidence (array): list of confidences for matched frame
  • id (int): frame id of matched frame
  • img (cv2 image): image grab of matched frame
  • array of objects:
  • list of boxes,labels,confidences of all frames matched

Return type:

  • object

Note:

The same frames are not retrieved depending on whether you set download to True or False. When set to True, we use OpenCV’s frame reading logic and when False we use ZoneMinder’s image.php function which uses time based approximation. Therefore, the retrieve different frame offsets, but I assume they should be reasonably close.

get_ml_options()
set_ml_options(options, force_reload=False)

Use this to change ml options later. Note that models will not be reloaded unless you add force_reload=True