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,6 +246,8 @@ motion:
|
||||
# Enables dynamic contrast improvement. This should help improve night detections at the cost of making motion detection more sensitive
|
||||
# for daytime.
|
||||
improve_contrast: False
|
||||
# Optional: Delay when updating camera motion through MQTT from ON -> OFF (default: shown below).
|
||||
mqtt_off_delay: 30
|
||||
|
||||
# Optional: Record configuration
|
||||
# NOTE: Can be overridden at the camera level
|
||||
|
@ -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`.
|
||||
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`
|
||||
|
||||
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(
|
||||
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):
|
||||
|
@ -1,29 +1,24 @@
|
||||
import base64
|
||||
import copy
|
||||
import datetime
|
||||
import hashlib
|
||||
import itertools
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import queue
|
||||
import threading
|
||||
import time
|
||||
from collections import Counter, defaultdict
|
||||
from statistics import mean, median
|
||||
from statistics import median
|
||||
from typing import Callable
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
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 (
|
||||
SharedMemoryFrameManager,
|
||||
calculate_region,
|
||||
draw_box_with_label,
|
||||
draw_timestamp,
|
||||
load_labels,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -652,6 +647,7 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
self.stop_event = stop_event
|
||||
self.camera_states: dict[str, CameraState] = {}
|
||||
self.frame_manager = SharedMemoryFrameManager()
|
||||
self.last_motion_updates: dict[str, int] = {}
|
||||
|
||||
def start(camera, obj: TrackedObject, current_frame_time):
|
||||
self.event_queue.put(("start", camera, obj.to_dict()))
|
||||
@ -844,6 +840,33 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
|
||||
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):
|
||||
# TODO: need a lock here
|
||||
camera_state = self.camera_states[camera]
|
||||
@ -879,6 +902,8 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
frame_time, current_tracked_objects, motion_boxes, regions
|
||||
)
|
||||
|
||||
self.should_mqtt_motion(camera, motion_boxes)
|
||||
|
||||
tracked_objects = [
|
||||
o.to_dict() for o in camera_state.tracked_objects.values()
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user