mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Send mqtt message when motion is detected (#3152)
* Send mqtt message when motion is detected * Use object processing instead of passing mqtt client around * Cleanup * Formatting * add comment * Make off delay configurable. * Handle updating each camera based on config off delay * Formatting * Update docker-compose.yml * Fix processing issue * Update mqtt docs * Update main config docs * Make sure multiple True values aren't published for the same motion * Make sure multiple True values aren't published for the same motion * Update payload to fit existing HA standard values * Update docs to fit new values * Update docs * Update motion topic * Use datetime.datetime and remove unused imports * Cast to int * Clarify motion detector behavior in docs * Fix typo Co-authored-by: Blake Blackshear <blakeb@blakeshome.com>
This commit is contained in:
parent
90bff605fa
commit
de244d6873
@ -246,12 +246,14 @@ motion:
|
|||||||
# Enables dynamic contrast improvement. This should help improve night detections at the cost of making motion detection more sensitive
|
# Enables dynamic contrast improvement. This should help improve night detections at the cost of making motion detection more sensitive
|
||||||
# for daytime.
|
# for daytime.
|
||||||
improve_contrast: False
|
improve_contrast: False
|
||||||
|
# Optional: Delay when updating camera motion through MQTT from ON -> OFF (default: shown below).
|
||||||
|
mqtt_off_delay: 30
|
||||||
|
|
||||||
# Optional: Record configuration
|
# Optional: Record configuration
|
||||||
# NOTE: Can be overridden at the camera level
|
# NOTE: Can be overridden at the camera level
|
||||||
record:
|
record:
|
||||||
# Optional: Enable recording (default: shown below)
|
# Optional: Enable recording (default: shown below)
|
||||||
# WARNING: If recording is disabled in the config, turning it on via
|
# WARNING: If recording is disabled in the config, turning it on via
|
||||||
# the UI or MQTT later will have no effect.
|
# the UI or MQTT later will have no effect.
|
||||||
# WARNING: Frigate does not currently support limiting recordings based
|
# WARNING: Frigate does not currently support limiting recordings based
|
||||||
# on available disk space automatically. If using recordings,
|
# on available disk space automatically. If using recordings,
|
||||||
|
@ -123,6 +123,12 @@ Topic with current state of snapshots for a camera. Published values are `ON` an
|
|||||||
Topic to turn motion detection for a camera on and off. Expected values are `ON` and `OFF`.
|
Topic to turn motion detection for a camera on and off. Expected values are `ON` and `OFF`.
|
||||||
NOTE: Turning off motion detection will fail if detection is not disabled.
|
NOTE: Turning off motion detection will fail if detection is not disabled.
|
||||||
|
|
||||||
|
### `frigate/<camera_name>/motion`
|
||||||
|
|
||||||
|
Whether camera_name is currently detecting motion. Expected values are `ON` and `OFF`.
|
||||||
|
NOTE: After motion is initially detected, `ON` will be set until no motion has
|
||||||
|
been detected for `mqtt_off_delay` seconds (30 by default).
|
||||||
|
|
||||||
### `frigate/<camera_name>/motion/state`
|
### `frigate/<camera_name>/motion/state`
|
||||||
|
|
||||||
Topic with current state of motion detection for a camera. Published values are `ON` and `OFF`.
|
Topic with current state of motion detection for a camera. Published values are `ON` and `OFF`.
|
||||||
|
@ -134,6 +134,10 @@ class MotionConfig(FrigateBaseModel):
|
|||||||
mask: Union[str, List[str]] = Field(
|
mask: Union[str, List[str]] = Field(
|
||||||
default="", title="Coordinates polygon for the motion mask."
|
default="", title="Coordinates polygon for the motion mask."
|
||||||
)
|
)
|
||||||
|
mqtt_off_delay: int = Field(
|
||||||
|
default=30,
|
||||||
|
title="Delay for updating MQTT with no motion detected.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RuntimeMotionConfig(MotionConfig):
|
class RuntimeMotionConfig(MotionConfig):
|
||||||
|
@ -1,29 +1,24 @@
|
|||||||
import base64
|
import base64
|
||||||
import copy
|
|
||||||
import datetime
|
import datetime
|
||||||
import hashlib
|
|
||||||
import itertools
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import queue
|
import queue
|
||||||
import threading
|
import threading
|
||||||
import time
|
|
||||||
from collections import Counter, defaultdict
|
from collections import Counter, defaultdict
|
||||||
from statistics import mean, median
|
from statistics import median
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from frigate.config import CameraConfig, SnapshotsConfig, RecordConfig, FrigateConfig
|
from frigate.config import CameraConfig, SnapshotsConfig, RecordConfig, FrigateConfig
|
||||||
from frigate.const import CACHE_DIR, CLIPS_DIR, RECORD_DIR
|
from frigate.const import CLIPS_DIR
|
||||||
from frigate.util import (
|
from frigate.util import (
|
||||||
SharedMemoryFrameManager,
|
SharedMemoryFrameManager,
|
||||||
calculate_region,
|
calculate_region,
|
||||||
draw_box_with_label,
|
draw_box_with_label,
|
||||||
draw_timestamp,
|
draw_timestamp,
|
||||||
load_labels,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -652,6 +647,7 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
self.stop_event = stop_event
|
self.stop_event = stop_event
|
||||||
self.camera_states: dict[str, CameraState] = {}
|
self.camera_states: dict[str, CameraState] = {}
|
||||||
self.frame_manager = SharedMemoryFrameManager()
|
self.frame_manager = SharedMemoryFrameManager()
|
||||||
|
self.last_motion_updates: dict[str, int] = {}
|
||||||
|
|
||||||
def start(camera, obj: TrackedObject, current_frame_time):
|
def start(camera, obj: TrackedObject, current_frame_time):
|
||||||
self.event_queue.put(("start", camera, obj.to_dict()))
|
self.event_queue.put(("start", camera, obj.to_dict()))
|
||||||
@ -844,6 +840,33 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def should_mqtt_motion(self, camera, motion_boxes):
|
||||||
|
# publish if motion is currently being detected
|
||||||
|
if motion_boxes:
|
||||||
|
# only send True if motion hasn't been detected recently
|
||||||
|
if self.last_motion_updates.get(camera, 0) == 0:
|
||||||
|
self.client.publish(
|
||||||
|
f"{self.topic_prefix}/{camera}/motion",
|
||||||
|
"ON",
|
||||||
|
retain=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
# always updated latest motion
|
||||||
|
self.last_motion_updates[camera] = int(datetime.datetime.now().timestamp())
|
||||||
|
elif not motion_boxes and self.last_motion_updates.get(camera, 0) != 0:
|
||||||
|
mqtt_delay = self.config.cameras[camera].motion.mqtt_off_delay
|
||||||
|
now = int(datetime.datetime.now().timestamp())
|
||||||
|
|
||||||
|
# If no motion, make sure the off_delay has passed
|
||||||
|
if now - self.last_motion_updates.get(camera, 0) >= mqtt_delay:
|
||||||
|
self.client.publish(
|
||||||
|
f"{self.topic_prefix}/{camera}/motion",
|
||||||
|
"OFF",
|
||||||
|
retain=False,
|
||||||
|
)
|
||||||
|
# reset the last_motion so redundant `off` commands aren't sent
|
||||||
|
self.last_motion_updates[camera] = 0
|
||||||
|
|
||||||
def get_best(self, camera, label):
|
def get_best(self, camera, label):
|
||||||
# TODO: need a lock here
|
# TODO: need a lock here
|
||||||
camera_state = self.camera_states[camera]
|
camera_state = self.camera_states[camera]
|
||||||
@ -879,6 +902,8 @@ class TrackedObjectProcessor(threading.Thread):
|
|||||||
frame_time, current_tracked_objects, motion_boxes, regions
|
frame_time, current_tracked_objects, motion_boxes, regions
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.should_mqtt_motion(camera, motion_boxes)
|
||||||
|
|
||||||
tracked_objects = [
|
tracked_objects = [
|
||||||
o.to_dict() for o in camera_state.tracked_objects.values()
|
o.to_dict() for o in camera_state.tracked_objects.values()
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user