diff --git a/machinery/go.mod b/machinery/go.mod index 2630af7..1364d91 100644 --- a/machinery/go.mod +++ b/machinery/go.mod @@ -24,7 +24,7 @@ require ( github.com/gorilla/websocket v1.5.3 github.com/kellydunn/golang-geo v0.7.0 github.com/kerberos-io/joy4 v1.0.64 - github.com/kerberos-io/onvif v1.2.1 + github.com/kerberos-io/onvif v1.2.2 github.com/minio/minio-go/v6 v6.0.57 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 diff --git a/machinery/go.sum b/machinery/go.sum index be9ddaa..8e11c52 100644 --- a/machinery/go.sum +++ b/machinery/go.sum @@ -774,8 +774,8 @@ github.com/kellydunn/golang-geo v0.7.0 h1:A5j0/BvNgGwY6Yb6inXQxzYwlPHc6WVZR+Mrar github.com/kellydunn/golang-geo v0.7.0/go.mod h1:YYlQPJ+DPEzrHx8kT3oPHC/NjyvCCXE+IuKGKdrjrcU= github.com/kerberos-io/joy4 v1.0.64 h1:gTUSotHSOhp9mNqEecgq88tQHvpj7TjmrvPUsPm0idg= github.com/kerberos-io/joy4 v1.0.64/go.mod h1:nZp4AjvKvTOXRrmDyAIOw+Da+JA5OcSo/JundGfOlFU= -github.com/kerberos-io/onvif v1.2.1 h1:+vxyHPylt0ufK8gv7FL+KzhJUeComMGrTmP5KxT2YEc= -github.com/kerberos-io/onvif v1.2.1/go.mod h1:XSgEQXmEDjUQTbdXvsaRJt6Az8YPGj7L+j5iXKEGijU= +github.com/kerberos-io/onvif v1.2.2 h1:QnxITps7xvAVD2abWRsa3+p9QexjKESQQldUFMx/mYA= +github.com/kerberos-io/onvif v1.2.2/go.mod h1:XSgEQXmEDjUQTbdXvsaRJt6Az8YPGj7L+j5iXKEGijU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= diff --git a/machinery/src/computervision/main.go b/machinery/src/computervision/main.go index d4c9d77..b588d46 100644 --- a/machinery/src/computervision/main.go +++ b/machinery/src/computervision/main.go @@ -24,17 +24,12 @@ func ProcessMotion(motionCursor *packets.QueueCursor, configuration *models.Conf var motionRectangle models.MotionRectangle var motionRectangles []models.MotionRectangle - // Resolve the motion sensitivity (pixel-change threshold): - // nil (unset) -> default 150 - // 0 -> motion detection DISABLED (temporary off switch from the UI) - // > 0 -> trigger when the number of changed pixels exceeds it + // Resolve the motion sensitivity (pixel-change threshold). Nil, zero, and + // negative values use the historical default so older configurations keep + // recording after an upgrade. pixelThreshold := 150 - motionDisabled := false - if config.Capture.PixelChangeThreshold != nil { + if config.Capture.PixelChangeThreshold != nil && *config.Capture.PixelChangeThreshold > 0 { pixelThreshold = *config.Capture.PixelChangeThreshold - if pixelThreshold <= 0 { - motionDisabled = true - } } // In motion mode we always run detection. In CONTINUOUS mode recording is // 24/7 so motion detection is normally skipped, BUT if a motion region is @@ -45,11 +40,7 @@ func ProcessMotion(motionCursor *packets.QueueCursor, configuration *models.Conf continuousMode := config.Capture.Continuous == "true" hasMotionRegion := config.Region != nil && len(config.Region.Polygon) > 0 - if motionDisabled { - - log.Log.Warning("computervision.main.ProcessMotion(): motion detection is DISABLED because pixelChangeThreshold is set to 0 or less (nil/unset would default to 150). If motion detection is expected to be running, set capture.pixelChangeThreshold to a positive value (150 recommended) or AGENT_CAPTURE_PIXEL_CHANGE, then restart/update the agent.") - - } else if continuousMode && !hasMotionRegion { + if continuousMode && !hasMotionRegion { log.Log.Info("computervision.main.ProcessMotion(): continuous recording enabled and no motion region configured, so no motion detection required.") @@ -236,9 +227,9 @@ func ProcessMotion(motionCursor *packets.QueueCursor, configuration *models.Conf // a reference square of sqrt(threshold) px (in this MOTION // frame's pixel space) so the user can visually gauge how // large a moving object must be before it is detected. - "pixelChangeThreshold": pixelThreshold, + "pixelChangeThreshold": pixelThreshold, + }, }, - }, } payload, err := models.PackageMQTTMessage(configuration, message) if err == nil { diff --git a/machinery/src/config/main.go b/machinery/src/config/main.go index 7ae1418..2886c92 100644 --- a/machinery/src/config/main.go +++ b/machinery/src/config/main.go @@ -651,13 +651,12 @@ func applyAgentEnvVars(configuration *models.Configuration, prefix string, apply } } - // Motion sensitivity: nil/unset must still resolve to the default (150), not - // be left nil. An explicit 0 (temporary "disable motion detection" switch - // from the UI) is a real, non-nil value and must NOT be touched here. Only - // applied for the effective configuration (applyDefaults), not for the - // separate global/custom views, so a missing value in one layer can still be - // inherited from the other instead of being masked by this default. - if applyDefaults && configuration.Config.Capture.PixelChangeThreshold == nil { + // Motion sensitivity historically used 0 to mean "use the default". Preserve + // that behaviour for configurations created before this field became a + // pointer, and also recover invalid negative values. Only apply this to the + // effective configuration so missing values can still be inherited between + // the separate global and custom layers. + if applyDefaults && (configuration.Config.Capture.PixelChangeThreshold == nil || *configuration.Config.Capture.PixelChangeThreshold <= 0) { defaultPixelChangeThreshold := 150 configuration.Config.Capture.PixelChangeThreshold = &defaultPixelChangeThreshold } diff --git a/machinery/src/config/main_test.go b/machinery/src/config/main_test.go new file mode 100644 index 0000000..8970c59 --- /dev/null +++ b/machinery/src/config/main_test.go @@ -0,0 +1,40 @@ +package config + +import ( + "testing" + + "github.com/kerberos-io/agent/machinery/src/models" +) + +func TestApplyAgentEnvVarsPixelChangeThresholdDefault(t *testing.T) { + tests := []struct { + name string + threshold *int + want int + }{ + {name: "missing", want: 150}, + {name: "legacy zero", threshold: intPointer(0), want: 150}, + {name: "negative", threshold: intPointer(-1), want: 150}, + {name: "positive", threshold: intPointer(275), want: 275}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + configuration := &models.Configuration{} + configuration.Config.Capture.PixelChangeThreshold = test.threshold + + applyAgentEnvVars(configuration, "TEST_", true) + + if configuration.Config.Capture.PixelChangeThreshold == nil { + t.Fatal("PixelChangeThreshold is nil after applying defaults") + } + if got := *configuration.Config.Capture.PixelChangeThreshold; got != test.want { + t.Fatalf("PixelChangeThreshold = %d, want %d", got, test.want) + } + }) + } +} + +func intPointer(value int) *int { + return &value +}