diff --git a/docs/docs/integrations/mqtt.md b/docs/docs/integrations/mqtt.md index 57bf9a9fbb..cdf4fb637e 100644 --- a/docs/docs/integrations/mqtt.md +++ b/docs/docs/integrations/mqtt.md @@ -118,6 +118,15 @@ Topic to turn snapshots for a camera on and off. Expected values are `ON` and `O Topic with current state of snapshots for a camera. Published values are `ON` and `OFF`. +### `frigate//motion/set` + +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//motion/state` + +Topic with current state of motion detection for a camera. Published values are `ON` and `OFF`. + ### `frigate//improve_contrast/set` Topic to turn improve_contrast for a camera on and off. Expected values are `ON` and `OFF`. diff --git a/frigate/app.py b/frigate/app.py index 9cb315bb4f..7de8512340 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -91,6 +91,7 @@ def init_config(self) -> None: "detection_enabled": mp.Value( "i", self.config.cameras[camera_name].detect.enabled ), + "motion_enabled": mp.Value("i", True), "improve_contrast_enabled": mp.Value( "i", self.config.cameras[camera_name].motion.improve_contrast ), diff --git a/frigate/mqtt.py b/frigate/mqtt.py index e96bb674e3..7f215bceb7 100644 --- a/frigate/mqtt.py +++ b/frigate/mqtt.py @@ -78,6 +78,12 @@ def on_detect_command(client, userdata, message): logger.info(f"Turning on detection for {camera_name} via mqtt") camera_metrics[camera_name]["detection_enabled"].value = True detect_settings.enabled = True + + if not camera_metrics[camera_name]["motion_enabled"].value: + logger.info( + f"Turning on motion for {camera_name} due to detection being enabled." + ) + camera_metrics[camera_name]["motion_enabled"].value = True elif payload == "OFF": if camera_metrics[camera_name]["detection_enabled"].value: logger.info(f"Turning off detection for {camera_name} via mqtt") @@ -89,6 +95,32 @@ def on_detect_command(client, userdata, message): state_topic = f"{message.topic[:-4]}/state" client.publish(state_topic, payload, retain=True) + def on_motion_command(client, userdata, message): + payload = message.payload.decode() + logger.debug(f"on_motion_toggle: {message.topic} {payload}") + + camera_name = message.topic.split("/")[-3] + + if payload == "ON": + if not camera_metrics[camera_name]["motion_enabled"].value: + logger.info(f"Turning on motion for {camera_name} via mqtt") + camera_metrics[camera_name]["motion_enabled"].value = True + elif payload == "OFF": + if camera_metrics[camera_name]["detection_enabled"].value: + logger.error( + f"Turning off motion is not allowed when detection is enabled." + ) + return + + if camera_metrics[camera_name]["motion_enabled"].value: + logger.info(f"Turning off motion for {camera_name} via mqtt") + camera_metrics[camera_name]["motion_enabled"].value = False + else: + logger.warning(f"Received unsupported value at {message.topic}: {payload}") + + state_topic = f"{message.topic[:-4]}/state" + client.publish(state_topic, payload, retain=True) + def on_improve_contrast_command(client, userdata, message): payload = message.payload.decode() logger.debug(f"on_improve_contrast_toggle: {message.topic} {payload}") @@ -156,6 +188,9 @@ def on_connect(client, userdata, flags, rc): client.message_callback_add( f"{mqtt_config.topic_prefix}/{name}/detect/set", on_detect_command ) + client.message_callback_add( + f"{mqtt_config.topic_prefix}/{name}/motion/set", on_motion_command + ) client.message_callback_add( f"{mqtt_config.topic_prefix}/{name}/improve_contrast/set", on_improve_contrast_command, diff --git a/frigate/types.py b/frigate/types.py index d65c601fb5..f582c6c0f7 100644 --- a/frigate/types.py +++ b/frigate/types.py @@ -14,6 +14,7 @@ class CameraMetricsTypes(TypedDict): detection_frame: Synchronized ffmpeg_pid: Synchronized frame_queue: Queue + motion_enabled: Synchronized improve_contrast_enabled: Synchronized process: Optional[Process] process_fps: Synchronized diff --git a/frigate/video.py b/frigate/video.py index c16d0fe744..c7fc62ad50 100755 --- a/frigate/video.py +++ b/frigate/video.py @@ -361,6 +361,7 @@ def receiveSignal(signalNumber, frame): frame_queue = process_info["frame_queue"] detection_enabled = process_info["detection_enabled"] + motion_enabled = process_info["motion_enabled"] improve_contrast_enabled = process_info["improve_contrast_enabled"] frame_shape = config.frame_shape @@ -393,6 +394,7 @@ def receiveSignal(signalNumber, frame): objects_to_track, object_filters, detection_enabled, + motion_enabled, stop_event, ) @@ -479,6 +481,7 @@ def process_frames( objects_to_track: list[str], object_filters, detection_enabled: mp.Value, + motion_enabled: mp.Value, stop_event, exit_on_empty: bool = False, ): @@ -512,8 +515,8 @@ def process_frames( logger.info(f"{camera_name}: frame {frame_time} is not in memory store.") continue - # look for motion - motion_boxes = motion_detector.detect(frame) + # look for motion if enabled + motion_boxes = motion_detector.detect(frame) if motion_enabled.value else [] regions = [] diff --git a/process_clip.py b/process_clip.py index 5699985264..f93bd2726f 100644 --- a/process_clip.py +++ b/process_clip.py @@ -115,6 +115,7 @@ def process_frames( } detection_enabled = mp.Value("d", 1) + motion_enabled = mp.Value("d", True) stop_event = mp.Event() model_shape = (self.config.model.height, self.config.model.width) @@ -133,6 +134,7 @@ def process_frames( objects_to_track, object_filters, detection_enabled, + motion_enabled, stop_event, exit_on_empty=True, )