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:
-
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:
-
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
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
toTrue
orFalse
. When set toTrue
, we use OpenCV’s frame reading logic and whenFalse
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
-