From 53bc0e710c8ee40f0b98d785eb26cc6d20fd1a78 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Tue, 3 Mar 2026 13:31:39 -0600 Subject: [PATCH 1/8] backend --- frigate/config/camera/motion.py | 9 ++++++++- frigate/motion/improved_motion.py | 20 +++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/frigate/config/camera/motion.py b/frigate/config/camera/motion.py index b6877693b..fd699b7e1 100644 --- a/frigate/config/camera/motion.py +++ b/frigate/config/camera/motion.py @@ -24,10 +24,17 @@ class MotionConfig(FrigateBaseModel): lightning_threshold: float = Field( default=0.8, title="Lightning threshold", - description="Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0).", + description="Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0). This does not prevent motion detection entirely; it merely causes the detector to stop analyzing additional frames once the threshold is exceeded. Motion-based recordings are still created during these events.", ge=0.3, le=1.0, ) + skip_motion_threshold: float = Field( + default=1.0, + title="Skip motion threshold", + description="If more than this fraction of the image changes in a single frame, the detector will return no motion boxes and immediately recalibrate. This can save CPU and reduce false positives during lightning, storms, etc., but may miss real events such as a PTZ camera auto‑tracking an object. The trade‑off is between dropping a few megabytes of recordings versus reviewing a couple short clips. Range 0.0 to 1.0.", + ge=0.0, + le=1.0, + ) improve_contrast: bool = Field( default=True, title="Improve contrast", diff --git a/frigate/motion/improved_motion.py b/frigate/motion/improved_motion.py index a8f2ab12c..c91b585f8 100644 --- a/frigate/motion/improved_motion.py +++ b/frigate/motion/improved_motion.py @@ -176,11 +176,29 @@ class ImprovedMotionDetector(MotionDetector): motion_boxes = [] pct_motion = 0 + # skip motion entirely if the scene change percentage exceeds configured + # threshold. this is useful to ignore lighting storms, IR mode switches, + # etc. rather than registering them as brief motion and then recalibrating. + # note: skipping means the frame is dropped and **no recording will be + # created**, which could hide a legitimate object if the camera is actively + # auto‑tracking. the alternative is to allow motion and accept a small + # recording that can be reviewed in the timeline. + if pct_motion > self.config.skip_motion_threshold: + # force a recalibration so we transition to the new background + self.calibrating = True + return [] + # once the motion is less than 5% and the number of contours is < 4, assume its calibrated if pct_motion < 0.05 and len(motion_boxes) <= 4: self.calibrating = False - # if calibrating or the motion contours are > 80% of the image area (lightning, ir, ptz) recalibrate + # if calibrating or the motion contours are > 80% of the image area + # (lightning, ir, ptz) recalibrate. the lightning threshold does **not** + # stop motion detection entirely; it simply halts additional processing for + # the current frame once the percentage crosses the threshold. this helps + # reduce false positive object detections and CPU usage during high‑motion + # events. recordings continue to be generated because users expect data + # while a PTZ camera is moving. if self.calibrating or pct_motion > self.config.lightning_threshold: self.calibrating = True From 4efffda34d576540062acf46d897a3470011e6fd Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Tue, 3 Mar 2026 13:31:49 -0600 Subject: [PATCH 2/8] frontend --- web/src/components/config-form/section-configs/motion.ts | 3 +++ web/src/types/frigateConfig.ts | 1 + 2 files changed, 4 insertions(+) diff --git a/web/src/components/config-form/section-configs/motion.ts b/web/src/components/config-form/section-configs/motion.ts index 0acdc0d99..c2b64178d 100644 --- a/web/src/components/config-form/section-configs/motion.ts +++ b/web/src/components/config-form/section-configs/motion.ts @@ -8,6 +8,7 @@ const motion: SectionConfigOverrides = { "enabled", "threshold", "lightning_threshold", + "skip_motion_threshold", "improve_contrast", "contour_area", "delta_alpha", @@ -22,6 +23,7 @@ const motion: SectionConfigOverrides = { hiddenFields: ["enabled_in_config", "mask", "raw_mask"], advancedFields: [ "lightning_threshold", + "skip_motion_threshold", "delta_alpha", "frame_alpha", "frame_height", @@ -33,6 +35,7 @@ const motion: SectionConfigOverrides = { "enabled", "threshold", "lightning_threshold", + "skip_motion_threshold", "improve_contrast", "contour_area", "delta_alpha", diff --git a/web/src/types/frigateConfig.ts b/web/src/types/frigateConfig.ts index dc3554940..d49368846 100644 --- a/web/src/types/frigateConfig.ts +++ b/web/src/types/frigateConfig.ts @@ -106,6 +106,7 @@ export interface CameraConfig { frame_height: number; improve_contrast: boolean; lightning_threshold: number; + skip_motion_threshold: number; mask: { [maskId: string]: { friendly_name?: string; From 598f7c16d6e22abca08ef7a7af197e329ff737ba Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Tue, 3 Mar 2026 13:31:57 -0600 Subject: [PATCH 3/8] i18n --- web/public/locales/en/config/cameras.json | 9 +++++++-- web/public/locales/en/config/global.json | 6 +++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/web/public/locales/en/config/cameras.json b/web/public/locales/en/config/cameras.json index bbb8d4b45..5880d30c3 100644 --- a/web/public/locales/en/config/cameras.json +++ b/web/public/locales/en/config/cameras.json @@ -264,7 +264,11 @@ }, "lightning_threshold": { "label": "Lightning threshold", - "description": "Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0)." + "description": "Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0). This does not prevent motion detection entirely; it merely causes the detector to stop analyzing additional frames once the threshold is exceeded. Motion-based recordings are still created during these events." + }, + "skip_motion_threshold": { + "label": "Skip motion threshold", + "description": "If more than this fraction of the image changes in a single frame, the detector will return no motion boxes and immediately recalibrate. This can save CPU and reduce false positives during lightning, storms, etc., but may miss real events such as a PTZ camera auto‑tracking an object. The trade‑off is between dropping a few megabytes of recordings versus reviewing a couple short clips. Range 0.0 to 1.0." }, "improve_contrast": { "label": "Improve contrast", @@ -864,7 +868,8 @@ "description": "A user-friendly name for the zone, displayed in the Frigate UI. If not set, a formatted version of the zone name will be used." }, "enabled": { - "label": "Whether this zone is active. Disabled zones are ignored at runtime." + "label": "Enabled", + "description": "Enable or disable this zone. Disabled zones are ignored at runtime." }, "enabled_in_config": { "label": "Keep track of original state of zone." diff --git a/web/public/locales/en/config/global.json b/web/public/locales/en/config/global.json index 1bda2ab44..5268c1b02 100644 --- a/web/public/locales/en/config/global.json +++ b/web/public/locales/en/config/global.json @@ -1391,7 +1391,11 @@ }, "lightning_threshold": { "label": "Lightning threshold", - "description": "Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0)." + "description": "Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0). This does not prevent motion detection entirely; it merely causes the detector to stop analyzing additional frames once the threshold is exceeded. Motion-based recordings are still created during these events." + }, + "skip_motion_threshold": { + "label": "Skip motion threshold", + "description": "If more than this fraction of the image changes in a single frame, the detector will return no motion boxes and immediately recalibrate. This can save CPU and reduce false positives during lightning, storms, etc., but may miss real events such as a PTZ camera auto‑tracking an object. The trade‑off is between dropping a few megabytes of recordings versus reviewing a couple short clips. Range 0.0 to 1.0." }, "improve_contrast": { "label": "Improve contrast", From 7801d3dec7ae383ef167cc5df97e006cf177fd66 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Tue, 3 Mar 2026 13:32:31 -0600 Subject: [PATCH 4/8] docs --- docs/docs/configuration/motion_detection.md | 36 +++++++++++++++++++++ docs/docs/configuration/reference.md | 11 ++++--- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/docs/docs/configuration/motion_detection.md b/docs/docs/configuration/motion_detection.md index c22491fd0..4369fae33 100644 --- a/docs/docs/configuration/motion_detection.md +++ b/docs/docs/configuration/motion_detection.md @@ -92,6 +92,40 @@ motion: lightning_threshold: 0.8 ``` +## Skip Motion On Large Scene Changes + +```yaml +# default skip_motion_threshold: +motion: + # Optional: Fraction of the frame that must change in a single update + # before Frigate will completely ignore any motion in that frame. + # Values range between 0.0 and 1.0, where 1.0 (the default) means + # the feature is disabled. Setting this to 0.7 would cause Frigate to + # **skip** reporting motion boxes when more than 70% of the image + # appears to change (e.g. during lightning storms, IR/color mode + # switches, or other sudden lighting events). + skip_motion_threshold: 1.0 +``` + +This option is handy when you want to prevent large transient changes from +triggering recordings or object detection. It differs from `lightning_threshold` +because it completely suppresses motion instead of just forcing a recalibration. + +> **Note on trade‑offs:** when the skip threshold is exceeded, **no motion is +> reported** for that frame. That means you can miss something important like +> a PTZ camera auto‑tracking an object or seeing activity while the camera is +> moving. If you prefer to guarantee that every frame is saved, leave motion +> enabled and accept a couple of recordings that may contain mostly scene noise; +> they typically only take up a few megabytes and are very quick to scan in the +> timeline UI. + +:::note + +This setting only affects whether motion boxes are returned; recordings and +other downstream logic will still use the current warm‑up/calibration state. + +::: + :::warning Some cameras like doorbell cameras may have missed detections when someone walks directly in front of the camera and the lightning_threshold causes motion detection to be re-calibrated. In this case, it may be desirable to increase the `lightning_threshold` to ensure these objects are not missed. @@ -105,3 +139,5 @@ Lightning threshold does not stop motion based recordings from being saved. ::: Large changes in motion like PTZ moves and camera switches between Color and IR mode should result in a pause in object detection. This is done via the `lightning_threshold` configuration. It is defined as the percentage of the image used to detect lightning or other substantial changes where motion detection needs to recalibrate. Increasing this value will make motion detection more likely to consider lightning or IR mode changes as valid motion. Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching a doorbell camera. + +> **Clarification:** the lightning threshold does **not** stop motion from being detected entirely. Instead it prevents the detector from running additional motion analysis after the first frame exceeds the threshold. The goal is to reduce false positive object detections and motion usage during high‑motion periods (e.g. a storm or a PTZ camera sweep) without interfering with recordings; recordings are still saved because users expect their PTZ cameras to record while moving. diff --git a/docs/docs/configuration/reference.md b/docs/docs/configuration/reference.md index 3efc4f0ed..4a33c90ca 100644 --- a/docs/docs/configuration/reference.md +++ b/docs/docs/configuration/reference.md @@ -480,12 +480,15 @@ motion: # Increasing this value will make motion detection less sensitive and decreasing it will make motion detection more sensitive. # The value should be between 1 and 255. threshold: 30 - # Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection - # needs to recalibrate. (default: shown below) + # Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection needs + # to recalibrate and motion checks stop for that frame. Recordings are unaffected. (default: shown below) # Increasing this value will make motion detection more likely to consider lightning or ir mode changes as valid motion. - # Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching - # a doorbell camera. + # Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching a doorbell camera. lightning_threshold: 0.8 + # Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection needs to recalibrate + # When this threshold is exceeded the frame is entirely skipped for motion processing and **no motion recording** is retained. + # Use with care on PTZ cameras or other situations where you require guaranteed frame capture. + skip_motion_threshold: 1.0 # Optional: Minimum size in pixels in the resized motion image that counts as motion (default: shown below) # Increasing this value will prevent smaller areas of motion from being detected. Decreasing will # make motion detection more sensitive to smaller moving objects. From a8b0df69b95282a20e355e66943a1fb76c95fc92 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Tue, 3 Mar 2026 13:33:00 -0600 Subject: [PATCH 5/8] add test --- frigate/test/test_motion_detector.py | 91 ++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 frigate/test/test_motion_detector.py diff --git a/frigate/test/test_motion_detector.py b/frigate/test/test_motion_detector.py new file mode 100644 index 000000000..8dd2cdfaa --- /dev/null +++ b/frigate/test/test_motion_detector.py @@ -0,0 +1,91 @@ +import unittest + +import numpy as np + +from frigate.config.camera.motion import MotionConfig +from frigate.motion.improved_motion import ImprovedMotionDetector + + +class TestImprovedMotionDetector(unittest.TestCase): + def setUp(self): + # small frame for testing; actual frames are grayscale + self.frame_shape = (100, 100) # height, width + self.config = MotionConfig() + # motion detector assumes a rasterized_mask attribute exists on config + # when update_mask() is called; add one manually by bypassing pydantic. + object.__setattr__( + self.config, + "rasterized_mask", + np.ones((self.frame_shape[0], self.frame_shape[1]), dtype=np.uint8), + ) + + # create minimal PTZ metrics stub to satisfy detector checks + class _Stub: + def __init__(self, value=False): + self.value = value + + def is_set(self): + return bool(self.value) + + class DummyPTZ: + def __init__(self): + self.autotracker_enabled = _Stub(False) + self.motor_stopped = _Stub(False) + self.stop_time = _Stub(0) + + self.detector = ImprovedMotionDetector( + self.frame_shape, self.config, fps=30, ptz_metrics=DummyPTZ() + ) + + # establish a baseline frame (all zeros) + base_frame = np.zeros( + (self.frame_shape[0], self.frame_shape[1]), dtype=np.uint8 + ) + self.detector.detect(base_frame) + + def _half_change_frame(self) -> np.ndarray: + """Produce a frame where roughly half of the pixels are different.""" + frame = np.zeros((self.frame_shape[0], self.frame_shape[1]), dtype=np.uint8) + # flip the top half to white + frame[: self.frame_shape[0] // 2, :] = 255 + return frame + + def test_skip_motion_threshold_default(self): + """With the default (1.0) setting, motion should still be reported.""" + frame = self._half_change_frame() + boxes = self.detector.detect(frame) + self.assertTrue( + boxes, "Expected motion boxes when skip threshold is at default" + ) + + def test_skip_motion_threshold_applied(self): + """Setting a low skip threshold should prevent any boxes from being returned.""" + # change the config and update the detector reference + self.config.skip_motion_threshold = 0.4 + self.detector.config = self.config + self.detector.update_mask() + + frame = self._half_change_frame() + boxes = self.detector.detect(frame) + self.assertEqual( + boxes, + [], + "Motion boxes should be empty when scene change exceeds skip threshold", + ) + + def test_skip_motion_threshold_does_not_affect_calibration(self): + """Even when skipping, the detector should go into calibrating state.""" + self.config.skip_motion_threshold = 0.4 + self.detector.config = self.config + self.detector.update_mask() + + frame = self._half_change_frame() + _ = self.detector.detect(frame) + self.assertTrue( + self.detector.calibrating, + "Detector should be in calibrating state after skip event", + ) + + +if __name__ == "__main__": + unittest.main() From 00d0ac6e095f09b3eaef5eef649057d1ac598363 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 4 Mar 2026 10:42:58 -0600 Subject: [PATCH 6/8] clean up --- docs/docs/configuration/motion_detection.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/docs/configuration/motion_detection.md b/docs/docs/configuration/motion_detection.md index 4369fae33..5e122b1fe 100644 --- a/docs/docs/configuration/motion_detection.md +++ b/docs/docs/configuration/motion_detection.md @@ -53,7 +53,6 @@ Watching the motion boxes in the debug view, increase the threshold until you on ### Contour Area ```yaml -# default contour_area value motion: # Optional: Minimum size in pixels in the resized motion image that counts as motion (default: shown below) # Increasing this value will prevent smaller areas of motion from being detected. Decreasing will @@ -82,7 +81,6 @@ However, if the preferred day settings do not work well at night it is recommend ## Tuning For Large Changes In Motion ```yaml -# default lightning_threshold: motion: # Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection # needs to recalibrate. (default: shown below) @@ -95,7 +93,6 @@ motion: ## Skip Motion On Large Scene Changes ```yaml -# default skip_motion_threshold: motion: # Optional: Fraction of the frame that must change in a single update # before Frigate will completely ignore any motion in that frame. From 30969d4cd9ca12791e92fb6cd95f43351b86292e Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 4 Mar 2026 11:27:57 -0600 Subject: [PATCH 7/8] clean up motion detection docs --- docs/docs/configuration/motion_detection.md | 48 +++++++-------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/docs/docs/configuration/motion_detection.md b/docs/docs/configuration/motion_detection.md index 5e122b1fe..df04933c2 100644 --- a/docs/docs/configuration/motion_detection.md +++ b/docs/docs/configuration/motion_detection.md @@ -38,7 +38,6 @@ Remember that motion detection is just used to determine when object detection s The threshold value dictates how much of a change in a pixels luminance is required to be considered motion. ```yaml -# default threshold value motion: # Optional: The threshold passed to cv2.threshold to determine if a pixel is different enough to be counted as motion. (default: shown below) # Increasing this value will make motion detection less sensitive and decreasing it will make motion detection more sensitive. @@ -80,17 +79,29 @@ However, if the preferred day settings do not work well at night it is recommend ## Tuning For Large Changes In Motion +### Lightning Threshold + ```yaml motion: # Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection # needs to recalibrate. (default: shown below) - # Increasing this value will make motion detection more likely to consider lightning or ir mode changes as valid motion. + # Increasing this value will make motion detection more likely to consider lightning or IR mode changes as valid motion. # Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching # a doorbell camera. lightning_threshold: 0.8 ``` -## Skip Motion On Large Scene Changes +Large changes in motion like PTZ moves and camera switches between Color and IR mode should result in a pause in object detection. `lightning_threshold` defines the percentage of the image used to detect these substantial changes. Increasing this value makes motion detection more likely to treat large changes (like IR mode switches) as valid motion. Decreasing it makes motion detection more likely to ignore large amounts of motion, such as a person approaching a doorbell camera. + +Note that `lightning_threshold` does **not** stop motion-based recordings from being saved — it only prevents additional motion analysis after the threshold is exceeded, reducing false positive object detections during high-motion periods (e.g. storms or PTZ sweeps) without interfering with recordings. + +:::warning + +Some cameras, like doorbell cameras, may have missed detections when someone walks directly in front of the camera and the `lightning_threshold` causes motion detection to recalibrate. In this case, it may be desirable to increase the `lightning_threshold` to ensure these objects are not missed. + +::: + +### Skip Motion On Large Scene Changes ```yaml motion: @@ -104,37 +115,10 @@ motion: skip_motion_threshold: 1.0 ``` -This option is handy when you want to prevent large transient changes from -triggering recordings or object detection. It differs from `lightning_threshold` -because it completely suppresses motion instead of just forcing a recalibration. - -> **Note on trade‑offs:** when the skip threshold is exceeded, **no motion is -> reported** for that frame. That means you can miss something important like -> a PTZ camera auto‑tracking an object or seeing activity while the camera is -> moving. If you prefer to guarantee that every frame is saved, leave motion -> enabled and accept a couple of recordings that may contain mostly scene noise; -> they typically only take up a few megabytes and are very quick to scan in the -> timeline UI. - -:::note - -This setting only affects whether motion boxes are returned; recordings and -other downstream logic will still use the current warm‑up/calibration state. - -::: +This option is handy when you want to prevent large transient changes from triggering recordings or object detection. It differs from `lightning_threshold` because it completely suppresses motion instead of just forcing a recalibration. :::warning -Some cameras like doorbell cameras may have missed detections when someone walks directly in front of the camera and the lightning_threshold causes motion detection to be re-calibrated. In this case, it may be desirable to increase the `lightning_threshold` to ensure these objects are not missed. +When the skip threshold is exceeded, **no motion is reported** for that frame. That means you can miss something important, like a PTZ camera auto-tracking an object or activity while the camera is moving. If you prefer to guarantee that every frame is saved, leave motion enabled and accept occasional recordings containing scene noise — they typically only take up a few megabytes and are quick to scan in the timeline UI. ::: - -:::note - -Lightning threshold does not stop motion based recordings from being saved. - -::: - -Large changes in motion like PTZ moves and camera switches between Color and IR mode should result in a pause in object detection. This is done via the `lightning_threshold` configuration. It is defined as the percentage of the image used to detect lightning or other substantial changes where motion detection needs to recalibrate. Increasing this value will make motion detection more likely to consider lightning or IR mode changes as valid motion. Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching a doorbell camera. - -> **Clarification:** the lightning threshold does **not** stop motion from being detected entirely. Instead it prevents the detector from running additional motion analysis after the first frame exceeds the threshold. The goal is to reduce false positive object detections and motion usage during high‑motion periods (e.g. a storm or a PTZ camera sweep) without interfering with recordings; recordings are still saved because users expect their PTZ cameras to record while moving. From 4a6f8b43b3c8dabda6eed55f0e114fb51b18bf44 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 4 Mar 2026 11:35:41 -0600 Subject: [PATCH 8/8] formatting --- docs/docs/configuration/motion_detection.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/docs/configuration/motion_detection.md b/docs/docs/configuration/motion_detection.md index df04933c2..a1937595a 100644 --- a/docs/docs/configuration/motion_detection.md +++ b/docs/docs/configuration/motion_detection.md @@ -83,11 +83,14 @@ However, if the preferred day settings do not work well at night it is recommend ```yaml motion: - # Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection - # needs to recalibrate. (default: shown below) - # Increasing this value will make motion detection more likely to consider lightning or IR mode changes as valid motion. - # Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching - # a doorbell camera. + # Optional: The percentage of the image used to detect lightning or + # other substantial changes where motion detection needs to + # recalibrate. (default: shown below) + # Increasing this value will make motion detection more likely + # to consider lightning or IR mode changes as valid motion. + # Decreasing this value will make motion detection more likely + # to ignore large amounts of motion such as a person + # approaching a doorbell camera. lightning_threshold: 0.8 ```