Commit Graph

211 Commits

Author SHA1 Message Date
Sebastian Norling
da1ecf8e0a refactor(event/stream): address API and classifier review findings
Parallel expert review of the four-commit scaffold surfaced 13 actionable
items split across API design, ONVIF domain accuracy, Go idiomaticity and
test rigor. This change addresses them before the Stream type lands, when
the public surface is still cheap to move.

API shape (hard-to-reverse before tagging)
------------------------------------------
* Rename EventKind -> Kind and EventState -> State to avoid the
  stream.EventKind / stream.EventState stutter when imported.
* Restructure Event for non-lossy decode:
  - Source string and RawValue string replaced with Source/Data maps so
    multi-item ONVIF Source and Data lists (e.g. AXIS AOA emitting
    active+classType+confidence; DigitalInput carrying InputToken+
    LogicalState) are preserved.
  - Add DeviceID so a single channel can fan in events from multiple
    cameras.
  - Add DeviceTime parsed from wsnt:UtcTime alongside the local
    observation Timestamp. The earlier doc-comment decision to bake-in
    'drop UtcTime' was a policy disguised as an API; expose both and let
    callers choose.

Classifier accuracy (ONVIF domain audit)
----------------------------------------
* Introduce KindImageQuality for tns1:VideoSource/ImageTooDark|Bright|
  Blurry. These are imaging-quality alarms that integrators route
  separately because they fire on sunset/dawn/condensation, not tamper.
  Previously mis-classified as KindTampering.
* Add tns1:VideoSource/GlobalSceneChange -> KindTampering, which is the
  real lens-cover signal on firmwares without TamperDetector.
* Anchor the TamperDetector rule to 'TamperDetector/Tamper' so a
  hypothetical 'TamperDetectorLog' path cannot match.
* Narrow MyRuleDetector from container-match to an explicit whitelist
  (HumanDetect, VehicleDetect, PeopleDetect, ObjectsInside, FaceDetect).
  Bosch publishes Counter and Occupancy under MyRuleDetector too; those
  must not classify as ObjectDetected.
* Add the AXIS Guard suite (MotionGuard, FenceGuard, LoiteringGuard) ->
  KindMotion. Common on AXIS deployments configured with these apps
  instead of basic VMD.
* Drop the bogus Device1ScenarioANY test fixture; AOA uses numeric
  scenarios (Device1Scenario1, Device1Scenario2). The 'ANY' suffix was a
  borrow from the older Guard suite's Camera1ProfileANY pattern.
* Document the edge-trigger semantics of LineDetector/Crossed in the rule
  comment so decoder consumers do not expect a State boolean.

Tests
-----
* String tests now use t.Run subtests so failures name the case.
* TestKindStringsAreUnique guards against accidental String() aliasing
  when adding new kinds.
* TestEventFieldAssignmentRoundTrip exercises the new field set
  including DeviceID, Source/Data maps and DeviceTime.
* Canonicalisation table now covers: double slash, colon-only segment,
  trailing colon, multi-colon-in-segment, leading/trailing slash,
  no-colon passthrough. Locks the actual behaviour so future refactors
  see regressions.
* False-positive negatives: Counter and Occupancy under MyRuleDetector,
  AudioEncoderConfiguration, RelayFailure, DigitalInputConfiguration,
  TamperDetectorLog, MotionRecording/Started — all assert KindUnknown.
* TestClassifyRuleOrder_ObjectAnalyticsBeforeGenericObjects pins the
  ordering invariant called out by the architect reviewer.

Documentation
-------------
* doc.go trimmed so it does not advertise NewStream / Events / Errors /
  Close before those identifiers exist — the godoc reader will no longer
  see dead names. Re-expanded when the Stream type lands.

Deferred to the Stream commit
-----------------------------
* PropertyUnknown vs PropertyUnset disambiguation — kept as
  PropertyUnknown for now with a clarified doc comment; revisit when the
  decoder needs to distinguish 'absent on wire' from 'unparseable'.
* Classifier pluggability (WithClassifier option) — meaningful only once
  there is a Stream; revisit at that commit.
2026-05-21 14:25:59 +02:00
Sebastian Norling
4da4842f61 test(event/stream): adopt testify to match existing lib style
The rest of github.com/kerberos-io/onvif uses stretchr/testify (assert,
require) consistently — Device_test.go, event/type_test.go,
media2/types_test.go, ws-discovery/networking_test.go. Migrate the two
new test files in event/stream from stdlib t.Errorf to the same testify
convention so the package fits in without local style variation.

No production-code change; no behaviour change.
2026-05-21 14:11:46 +02:00
Sebastian Norling
f679aab0d5 feat(event/stream): cross-reference vendor topic strings with public docs
Cross-checked each topic string against public sources before adding the
rule, and inlined the citation next to the rule it supports so future
maintainers can audit the table:

  * Hikvision motion: CellMotionDetector/Motion (Hikvision PDF on third
    party motion troubleshooting) plus the VideoSource/MotionAlarm
    fallback emitted by newer firmware.
  * Hikvision tamper-class scene change: VideoSource/ImageTooDark|Bright|
    Blurry — present in the ONVIF topic namespace; treated as Tampering
    for routing.
  * Bosch motion: VideoAnalytics/MotionAlarm (Bosch metadata/IVA PDF) —
    NOT VideoSource/MotionAlarm. The earlier 'tnsbosch:MotionAlarm' guess
    in PR #194 was wrong; Bosch uses standard tns1 namespace under
    VideoAnalytics.
  * Hanwha (Samsung Wisenet): VideoAnalytics/tnssamsung:MotionDetection,
    VideoAnalytics/tnssamsung:TamperingDetection,
    AudioAnalytics/tnssamsung:SoundDetection — confirmed via HA #66493
    capture.
  * Avigilon: per-segment-namespaced serialisation
    (tns1:Device/tns1:Trigger/tns1:Relay) folded by canonicalization.
    Documented in Avigilon's own ONVIF subscription guide.
  * Object analytics: LineDetector/Crossed, FieldDetector/ObjectsInside
    and the MyRuleDetector container for vendor rule names (Bosch IVA,
    Dahua SMD) — sourced from ONVIF Analytics Service Spec v22.06.
  * AXIS Object Analytics: prefix match on ObjectAnalytics/ to absorb
    the dynamic Device1Scenario<N> suffixes (AXIS counting-data docs).

Empirical topic table cross-checked with openvideolibs/onvif-parsers
(Apache-2.0), the package the Home Assistant ONVIF integration imports —
referenced from the package doc-comment.

Test cases now cover the verified topic for every supported vendor plus
case-sensitivity and canonicalization. No code change for callers: the
public API is still just Classify(topic) -> EventKind.
2026-05-21 14:10:07 +02:00
Sebastian Norling
2cc266714e feat(event/stream): classify vendor topics to normalized EventKind
Adds a Classify function that maps ONVIF topic strings to EventKind so the
agent does not need to know AXIS vs Hikvision vs Bosch topic conventions.

The classifier canonicalizes topics by stripping XML-namespace prefixes from
each path segment, which collapses vendor variants like
'tns1:Device/tnssamsung:DigitalInput' and 'tns1:Device/Trigger/DigitalInput'
to a single matchable form.

Motion coverage on day one:
  * tns1:VideoSource/MotionAlarm  (AXIS, Bosch, Dahua, ...)
  * tns1:VideoAnalytics/<vendor>:MotionAlarm
  * tns1:RuleEngine/CellMotionDetector/Motion  (ONVIF standard, Hikvision)
  * tns1:RuleEngine/MotionRegionDetector/Motion  (AXIS region rule)
  * tnsaxis:CameraApplicationPlatform/ObjectAnalytics/...

Also covers Tamper, DigitalInput, Relay (DigitalOutput), object analytics
and audio alarms, so the same Stream can replace the agent's ad-hoc digital
I/O polling without losing coverage.
2026-05-21 13:59:22 +02:00
Sebastian Norling
ce67879ee5 feat(event/stream): scaffold package with normalized event types
Introduces a new event/stream sub-package that will host the long-running,
channel-based consumer for ONVIF device events. This commit only lays down
the value types — EventKind, EventState, PropertyOperation and the Event
struct — together with Stringer methods and zero-value tests.

The intent is to give callers a vendor-neutral surface (Motion, DigitalInput,
etc.) so they do not need to special-case AXIS, Hikvision, Avigilon, Hanwha,
Bosch or Dahua topic strings. Decoding, topic classification and the Stream
type itself land in follow-up commits.
2026-05-21 13:57:21 +02:00
Cédric Verstraeten
a732b9fa82 Merge pull request #3 from Desivy/add-UtcTime-parsing
Add UtcTime attribute to MessageDescription struct
2025-05-20 14:26:20 +02:00
Cédric Verstraeten
03101ec271 Remove custom color settings from VSCode configuration 2025-05-20 10:14:19 +00:00
Cédric Verstraeten
4fc5593195 Add Dockerfile and devcontainer.json for development environment setup 2025-05-20 12:13:39 +02:00
stefan van der lee
9f92238275 Add UtcTime attribute to MessageDescription struct 2025-04-28 18:02:14 +02:00
Cédric Verstraeten
a7815a692c Merge pull request #2 from kerberos-io/fix/only-close-open-server-response
Fix server response closing
v1.0.0
2025-01-19 10:37:10 +01:00
Cedric Verstraeten
d80b15daf0 Merge branch 'master' into fix/only-close-open-server-response 2025-01-19 10:28:29 +01:00
Cedric Verstraeten
9ca534b5bb correct workflow structure 2025-01-19 10:19:22 +01:00
Cedric Verstraeten
ede8b81fc8 Update Device.go 2025-01-19 09:58:53 +01:00
Cédric Verstraeten
76463bb61a Merge pull request #1 from kerberos-io/fix/call-method-do-memleak
Call method do memleak
v0.0.18
2025-01-18 09:21:06 +01:00
Cedric Verstraeten
ca27d2a9d8 Merge branch 'master' into fix/call-method-do-memleak 2025-01-18 09:12:21 +01:00
Cedric Verstraeten
f3f03cc827 add pr description workflow 2025-01-18 09:12:05 +01:00
Cedric Verstraeten
542f83433b Update Device.go 2025-01-18 09:09:33 +01:00
Cedric Verstraeten
6fc6d9a99e reuse main http client + resolved memory leak (close previous response) before creating new one. v0.0.17 2025-01-16 21:43:28 +01:00
Cedric Verstraeten
ee8a919932 support for latest hikivision ONVIF 19.12 v0.0.16 2024-08-21 16:07:06 +02:00
Cedric Verstraeten
d1b78fa51a make array of relayoutputs and digitalinputs v0.0.15 2024-08-20 09:00:32 +02:00
Cedric Verstraeten
4c9f12fc97 add v0.0.14 2023-12-25 21:31:14 +01:00
Cédric Verstraeten
04f0dfbc03 Delete Imaging/types.go v0.0.13 2023-12-25 21:29:06 +01:00
Cedric Verstraeten
add8ae2bad Revert "disable imaging"
This reverts commit 6c5db5fed6.
2023-12-25 21:26:55 +01:00
Cedric Verstraeten
6c5db5fed6 disable imaging v0.0.12 2023-12-25 21:21:12 +01:00
Cedric Verstraeten
ba8bcf19bb inputs method added v0.0.11 v0.0.10 2023-12-25 20:57:16 +01:00
Cedric Verstraeten
8902e4e789 upgrade onvif library 2023-12-18 20:16:21 +01:00
Cedric Verstraeten
71b6d48393 diz memory leak + import v0.0.9 2023-12-06 20:38:25 +01:00
Cedric Verstraeten
bb5a87b253 Merge remote-tracking branch 'upstream/master' v0.0.8 2023-12-06 19:45:28 +01:00
Edward
217f1231c5 Merge pull request #38 from sunjirui/imaging-setting-change
The Parameters in ImagingSettings20 becomes optional
2023-09-21 14:52:22 +08:00
Cedric Verstraeten
7903bf2710 makes presets an array, we have more than a single preset v0.0.7 2023-08-30 11:01:24 +02:00
Cedric Verstraeten
c037b63bad Fix for ONVIF preset (json) v0.0.6 2023-08-24 12:36:15 +02:00
sunjirui
b424ee7bfe changed ImagingSettings20 2023-08-07 19:18:45 +08:00
Edward
88cd86f4fc Merge pull request #31 from stefan-kiss/ptz-profiles-fix
changed Preset field to slice in GetPresetsResponse
2023-05-02 02:11:51 +08:00
Edward
03ecb66210 Merge pull request #27 from tarancss/fix-memleak-and-events
Fix memory leak and events
2023-05-02 02:10:33 +08:00
Cédric Verstraeten
23e1c0b1bc Update onvif.go v0.0.5 2023-01-25 14:10:53 +01:00
Cedric Verstraeten
9d65ca2b49 add new types for independent zoom and pan tilt v0.0.4 2022-12-23 08:55:22 +01:00
Kiss Stefan
5c4360a924 changed Preset field to slice in GetPresetsResponse 2022-12-11 14:00:19 +02:00
tarancss
1a23395c53 remove debug logs 2022-09-17 01:24:52 +02:00
tarancss
8677b3be7e fix memory leak and events 2022-09-17 01:18:56 +02:00
tarancss
4f0536a933 fix subscribe response 2022-08-14 18:15:33 +02:00
Edward
bc3226e9ec Merge pull request #22 from jfsmig/fixes-ws-discovery-20220510
Misc. fixes in the WS discovery
2022-07-26 14:39:05 +08:00
Edward
d8d0fc383a Merge pull request #21 from spring-lab/master
fix ptz.types.SetPreset.PresetToken is optional
2022-07-26 14:31:40 +08:00
Jean-Francois Smigielski
9e25a0109e api: use juju/errors and zerolog 2022-05-11 10:05:57 +02:00
Jean-Francois Smigielski
47d91cba88 networking: use juju/errors and zerolog 2022-05-11 10:05:57 +02:00
Jean-Francois Smigielski
72a3540cc3 Let the example code use the generated SDK methods
Also introduces zerolog for pretty traces and juju/errors to annotate the errors
and track their origin.
2022-05-11 10:05:57 +02:00
Jean-Francois Smigielski
7d78e6b76e Provide a sdk package with 1 call per method
Modify the template in ./sdk/codegen/main.go

Use "go generate" from ./sdk/{ptz,media,device} to regenerate the files.
2022-05-11 10:05:57 +02:00
Jean-Francois Smigielski
6f1154fc4d ws-discovery: Return an error instead of printing & ignoring 2022-05-10 13:21:27 +02:00
Jean-Francois Smigielski
9b5df9ac2c Avoid non-error debug on stdout 2022-05-09 09:13:30 +02:00
Jean-Francois Smigielski
2569cf83bf Use a random ssource port in ws-discovery 2022-05-09 00:58:06 +02:00
Spring
be3347f029 fix ptz.types.SetPreset.PresetToken is optional 2022-04-24 09:53:18 +08:00