@camera.ui/sdk 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +3 -3
  3. package/dist/camera/events.js +2 -0
  4. package/dist/camera/index.js +3 -1
  5. package/dist/external.js +7 -0
  6. package/dist/index.d.ts +7132 -4248
  7. package/dist/index.js +3 -11
  8. package/dist/internal/contract-validators.js +21 -0
  9. package/dist/internal/index.d.ts +915 -0
  10. package/dist/internal/index.js +9 -0
  11. package/dist/internal/sensor-triggers.js +2 -0
  12. package/dist/internal/shared-utils.js +86 -0
  13. package/dist/internal/streaming-internal.js +1 -0
  14. package/dist/manager/index.js +1 -1
  15. package/dist/observable/index.js +419 -0
  16. package/dist/plugin/api.js +21 -0
  17. package/dist/plugin/contract.js +101 -114
  18. package/dist/plugin/helper.js +277 -0
  19. package/dist/plugin/index.js +4 -1
  20. package/dist/plugin/interfaces.js +51 -1
  21. package/dist/plugin/notifier.js +23 -0
  22. package/dist/plugin/oauth.js +1 -0
  23. package/dist/sensor/audio.js +103 -81
  24. package/dist/sensor/base.js +350 -318
  25. package/dist/sensor/battery.js +73 -59
  26. package/dist/sensor/classifier.js +117 -0
  27. package/dist/sensor/clip.js +30 -0
  28. package/dist/sensor/contact.js +37 -18
  29. package/dist/sensor/detection.js +4 -0
  30. package/dist/sensor/doorbell.js +52 -38
  31. package/dist/sensor/face.js +71 -86
  32. package/dist/sensor/garage.js +121 -0
  33. package/dist/sensor/humidity.js +52 -0
  34. package/dist/sensor/index.js +17 -11
  35. package/dist/sensor/leak.js +52 -0
  36. package/dist/sensor/licensePlate.js +70 -79
  37. package/dist/sensor/light.js +82 -38
  38. package/dist/sensor/lock.js +99 -0
  39. package/dist/sensor/motion.js +85 -70
  40. package/dist/sensor/object.js +73 -94
  41. package/dist/sensor/occupancy.js +52 -0
  42. package/dist/sensor/ptz.js +114 -100
  43. package/dist/sensor/securitySystem.js +98 -0
  44. package/dist/sensor/siren.js +75 -43
  45. package/dist/sensor/smoke.js +52 -0
  46. package/dist/sensor/spec.js +1 -0
  47. package/dist/sensor/switch.js +72 -0
  48. package/dist/sensor/temperature.js +52 -0
  49. package/dist/storage/index.js +1 -2
  50. package/dist/types.js +1 -0
  51. package/docs/.vitepress/config.ts +77 -0
  52. package/docs/.vitepress/theme/index.ts +5 -0
  53. package/docs/.vitepress/theme/style.css +117 -0
  54. package/docs/index.md +16 -0
  55. package/docs/logo.png +0 -0
  56. package/docs/public/apple-touch-icon.png +0 -0
  57. package/docs/public/favicon-16.ico +0 -0
  58. package/docs/public/favicon.ico +0 -0
  59. package/docs/public/logo.svg +1 -0
  60. package/examples/README.md +7 -0
  61. package/examples/getting-started.md +535 -0
  62. package/package.json +36 -23
  63. package/scripts/build-example-docs.mjs +62 -0
  64. package/tsconfig.node.json +3 -2
  65. package/typedoc.json +42 -0
  66. package/dist/sensor/guards.js +0 -133
  67. package/dist/sensor/types.js +0 -46
  68. package/dist/service/base.js +0 -96
  69. package/dist/service/index.js +0 -3
  70. /package/dist/camera/{types.js → enums.js} +0 -0
  71. /package/dist/{manager/types.js → camera/frames.js} +0 -0
  72. /package/dist/{plugin/types.js → internal/camera-config-internal.js} +0 -0
  73. /package/dist/{service/services.js → internal/camera-enums.js} +0 -0
  74. /package/dist/{service/types.js → internal/camera-wire.js} +0 -0
  75. /package/dist/{storage/schema.js → internal/manager-rpc.js} +0 -0
  76. /package/dist/{storage/storages.js → internal/sensor-rpc.js} +0 -0
@@ -1,124 +1,109 @@
1
- import { Sensor } from './base.js';
2
- import { SensorCategory, SensorType } from './types.js';
1
+ import { Sensor, SensorType, SensorCategory } from './base.js';
3
2
  /**
4
- * Face sensor property keys
3
+ * Property names of a face detection sensor.
4
+ *
5
+ * @internal
5
6
  */
6
7
  export var FaceProperty;
7
8
  (function (FaceProperty) {
9
+ /** Whether any face is currently detected. */
8
10
  FaceProperty["Detected"] = "detected";
9
- FaceProperty["Faces"] = "faces";
11
+ /** List of detected faces with optional identity, embedding, and thumbnail. */
12
+ FaceProperty["Detections"] = "detections";
10
13
  })(FaceProperty || (FaceProperty = {}));
11
14
  /**
12
- * Face Sensor (Specialized)
15
+ * Face sensor that reports detected faces and optional identity matches.
13
16
  *
14
- * Detects and recognizes faces in camera frames.
15
- * Can optionally receive person regions from ObjectSensor for focused detection.
17
+ * Plugin authors call `reportDetections(list)` to push detected faces.
18
+ * `detected` is auto-derived from the detection list.
16
19
  */
17
20
  export class FaceSensor extends Sensor {
18
21
  type = SensorType.Face;
19
22
  category = SensorCategory.Sensor;
20
- name;
21
23
  constructor(name = 'Face Sensor') {
22
- super();
23
- this.name = name;
24
- // Initialize defaults
25
- this.props.detected = false;
26
- this.props.faces = [];
24
+ super(name);
25
+ this._writeState({
26
+ [FaceProperty.Detected]: false,
27
+ [FaceProperty.Detections]: [],
28
+ });
27
29
  }
28
- // ========== Properties (Getter/Setter Pairs) ==========
29
- /** Whether faces are currently detected */
30
+ /** Whether any face is currently detected. */
30
31
  get detected() {
31
- return this.rawProps.detected;
32
- }
33
- /** Set face detected state */
34
- set detected(value) {
35
- this.props.detected = value;
32
+ return this.props.detected;
36
33
  }
37
- /** Current face detections */
38
- get faces() {
39
- return this.rawProps.faces;
40
- }
41
- /** Set face detections */
42
- set faces(value) {
43
- this.props.faces = value;
34
+ /** Current detection list. */
35
+ get detections() {
36
+ return this.props.detections;
44
37
  }
45
38
  /**
46
- * Update face detection state
39
+ * Report detected faces.
47
40
  *
48
- * @param detected - Whether faces are detected
41
+ * - `reportDetections(true)` — face detected without specifics (e.g. a
42
+ * bare face-event from a discovery provider). The SDK synthesizes a
43
+ * single full-frame face detection without identity.
44
+ * - `reportDetections(true, [...])` — explicit face detections with
45
+ * identity, embedding, and/or thumbnail.
46
+ * - `reportDetections(false)` — clear.
49
47
  *
50
- * @param faces - Array of face detections
51
- */
52
- setFaces(detected, faces = []) {
53
- this.props.detected = detected;
54
- this.props.faces = faces;
55
- }
56
- /** Clear face detection state */
57
- clearFaces() {
58
- this.props.detected = false;
59
- this.props.faces = [];
60
- }
61
- /**
62
- * Get faces with known identity
48
+ * @param detected - Whether any face is currently detected.
49
+ *
50
+ * @param detections - Optional explicit face detections to publish.
63
51
  *
64
- * @returns Array of recognized faces
52
+ * @example
53
+ * ```ts
54
+ * import type { FaceDetection } from '@camera.ui/sdk';
55
+ * sensor.reportDetections(true, [
56
+ * {
57
+ * label: 'person',
58
+ * confidence: 0.94,
59
+ * box: { x: 0.4, y: 0.2, width: 0.15, height: 0.25 },
60
+ * attribute: 'face',
61
+ * identity: 'Alice',
62
+ * } satisfies FaceDetection,
63
+ * ]);
64
+ * sensor.reportDetections(false);
65
+ * ```
65
66
  */
66
- getKnownFaces() {
67
- return this.faces.filter((f) => f.identity !== undefined);
67
+ reportDetections(detected, detections) {
68
+ const list = this._normalizeReportedDetections(detected, detections, 'person', { attribute: 'face' });
69
+ this._writeState({
70
+ [FaceProperty.Detected]: detected,
71
+ [FaceProperty.Detections]: list,
72
+ });
68
73
  }
69
74
  /**
70
- * Get faces without known identity
75
+ * Explicitly clear face detection state (detected = false, detections = []).
71
76
  *
72
- * @returns Array of unrecognized faces
77
+ * @example
78
+ * ```ts
79
+ * sensor.clearDetections();
80
+ * ```
73
81
  */
74
- getUnknownFaces() {
75
- return this.faces.filter((f) => f.identity === undefined);
82
+ clearDetections() {
83
+ this.reportDetections(false);
76
84
  }
77
85
  /**
78
- * Check if specific identity is detected
86
+ * Read-only sensor: external writes are ignored. State is reported via `reportDetections`.
79
87
  *
80
- * @param identity - Identity label to check
88
+ * Called by the cross-process plugin host when a generic property write is received.
89
+ * Face sensors have no externally writable properties, so the parameters are
90
+ * unused (underscore-prefixed) and the call is a no-op.
81
91
  *
82
- * @returns True if identity is detected, false otherwise
92
+ * @param _property - Unused face sensors expose no writable properties.
93
+ *
94
+ * @param _value - Unused — face sensors expose no writable properties.
95
+ *
96
+ * @internal
83
97
  */
84
- hasIdentity(identity) {
85
- return this.faces.some((f) => f.identity === identity);
98
+ updateValue(_property, _value) {
99
+ // No-op face detection state is reported by the plugin, not set externally.
86
100
  }
87
101
  }
88
102
  /**
89
- * Face Detector Sensor (Active Detection)
90
- *
91
- * Use this class for frame-based face detection (face-api.js, DeepFace, etc.)
92
- * The `inputProperties` getter specifies the required input format.
93
- *
94
- * Receives cropped person regions from ObjectDetectorSensor for efficient processing.
95
- *
96
- * @example
97
- * ```typescript
98
- * class FaceAPIDetector extends FaceDetectorSensor {
99
- * get inputProperties(): VideoInputProperties {
100
- * return { width: 160, height: 160, format: 'rgb' };
101
- * }
102
- *
103
- * async detectFaces(frame: VideoFrameData, personRegions?: Detection[]): Promise<FaceResult> {
104
- * const detections = await faceapi.detectAllFaces(frame.data);
105
- * return {
106
- * detected: detections.length > 0,
107
- * faces: detections.map(d => ({
108
- * label: 'face',
109
- * confidence: d.score,
110
- * box: d.box,
111
- * identity: d.identity,
112
- * })),
113
- * };
114
- * }
115
- * }
116
- * ```
103
+ * Face detector that receives video frames from the backend pipeline.
104
+ * Extend this class and implement {@link detectFaces} for face detection
105
+ * and recognition.
117
106
  */
118
107
  export class FaceDetectorSensor extends FaceSensor {
119
- /**
120
- * Indicates this sensor requires video frames for detection.
121
- * Used by the backend to determine streaming requirements.
122
- */
123
108
  _requiresFrames = true;
124
109
  }
@@ -0,0 +1,121 @@
1
+ import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ /** Garage door states (HomeKit-compatible values) */
3
+ export var GarageState;
4
+ (function (GarageState) {
5
+ GarageState[GarageState["Open"] = 0] = "Open";
6
+ GarageState[GarageState["Closed"] = 1] = "Closed";
7
+ GarageState[GarageState["Opening"] = 2] = "Opening";
8
+ GarageState[GarageState["Closing"] = 3] = "Closing";
9
+ GarageState[GarageState["Stopped"] = 4] = "Stopped";
10
+ })(GarageState || (GarageState = {}));
11
+ /**
12
+ * Properties for garage controls
13
+ *
14
+ * @internal
15
+ */
16
+ export var GarageProperty;
17
+ (function (GarageProperty) {
18
+ /** The actual current state of the garage door */
19
+ GarageProperty["CurrentState"] = "currentState";
20
+ /** The desired target state (set by user, transitions to currentState) */
21
+ GarageProperty["TargetState"] = "targetState";
22
+ /** Whether an obstruction is detected */
23
+ GarageProperty["ObstructionDetected"] = "obstructionDetected";
24
+ })(GarageProperty || (GarageProperty = {}));
25
+ /**
26
+ * Garage door control. Override `setTargetState()` to drive hardware and call
27
+ * `await super.setTargetState(value)` once the hardware confirms — the base
28
+ * implementation updates both `targetState` and `currentState`.
29
+ *
30
+ * For long-running transitions (Opening/Closing intermediate states), override
31
+ * `setTargetState` and write `currentState` separately as the door moves.
32
+ */
33
+ export class GarageControl extends Sensor {
34
+ type = SensorType.Garage;
35
+ category = SensorCategory.Control;
36
+ constructor(name = 'Garage') {
37
+ super(name);
38
+ this._writeState({
39
+ [GarageProperty.CurrentState]: GarageState.Closed,
40
+ [GarageProperty.TargetState]: GarageState.Closed,
41
+ [GarageProperty.ObstructionDetected]: false,
42
+ });
43
+ }
44
+ get currentState() {
45
+ return this.props.currentState;
46
+ }
47
+ get targetState() {
48
+ return this.props.targetState;
49
+ }
50
+ get obstructionDetected() {
51
+ return this.props.obstructionDetected;
52
+ }
53
+ /**
54
+ * Set the target state. Override to drive hardware and call
55
+ * `await super.setTargetState(value)` after success — the base implementation
56
+ * syncs both `targetState` and `currentState` to the new value.
57
+ *
58
+ * @param value - Desired target state from the {@link GarageState} enum.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * import { GarageState } from '@camera.ui/sdk';
63
+ * await garage.setTargetState(GarageState.Open);
64
+ * ```
65
+ */
66
+ async setTargetState(value) {
67
+ this._writeState({
68
+ [GarageProperty.TargetState]: value,
69
+ [GarageProperty.CurrentState]: value,
70
+ });
71
+ }
72
+ /**
73
+ * Publish the actual door state. Use this to drive long-running transitions
74
+ * (e.g. Open → Closing → Closed) independently of the user-requested target
75
+ * state. Read-only from cross-process consumers (`updateValue` ignores it).
76
+ *
77
+ * @param value - Current physical door state from the {@link GarageState} enum.
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * import { GarageState } from '@camera.ui/sdk';
82
+ * garage.setCurrentState(GarageState.Closing);
83
+ * ```
84
+ */
85
+ setCurrentState(value) {
86
+ this._writeState({ [GarageProperty.CurrentState]: value });
87
+ }
88
+ /**
89
+ * Publish the obstruction-detected state. Read-only from the consumer side
90
+ * (`updateValue` ignores it) — plugin code calls this when its hardware
91
+ * reports an obstruction sensor change.
92
+ *
93
+ * @param value - True when an obstruction is currently detected.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * garage.setObstructionDetected(true);
98
+ * ```
99
+ */
100
+ setObstructionDetected(value) {
101
+ this._writeState({ [GarageProperty.ObstructionDetected]: value });
102
+ }
103
+ /**
104
+ * Cross-process consumer entry point. Dispatches writable properties
105
+ * to semantic methods so plugin overrides (hardware actions) are honored.
106
+ * `currentState` and `obstructionDetected` are observed-only and not externally writable;
107
+ * only `targetState` may be set.
108
+ *
109
+ * @param property - Property name to write.
110
+ *
111
+ * @param value - New value for the property.
112
+ *
113
+ * @internal
114
+ */
115
+ async updateValue(property, value) {
116
+ if (property === GarageProperty.TargetState) {
117
+ await this.setTargetState(value);
118
+ }
119
+ // Unknown / non-writable property (incl. currentState, obstructionDetected) — ignored.
120
+ }
121
+ }
@@ -0,0 +1,52 @@
1
+ import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ /**
3
+ * Properties for humidity sensors
4
+ *
5
+ * @internal
6
+ */
7
+ export var HumidityProperty;
8
+ (function (HumidityProperty) {
9
+ /** Current relative humidity (0–100%) */
10
+ HumidityProperty["Current"] = "current";
11
+ })(HumidityProperty || (HumidityProperty = {}));
12
+ /** Humidity info sensor. Reports current relative humidity in %. */
13
+ export class HumidityInfo extends Sensor {
14
+ type = SensorType.Humidity;
15
+ category = SensorCategory.Info;
16
+ constructor(name = 'Humidity') {
17
+ super(name);
18
+ this._writeState({ [HumidityProperty.Current]: 50 });
19
+ }
20
+ get current() {
21
+ return this.props.current;
22
+ }
23
+ /**
24
+ * Report a new humidity reading. Clamped to [0, 100] %.
25
+ *
26
+ * @param value - Relative humidity percentage in the range 0–100.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * humidity.setCurrent(63);
31
+ * ```
32
+ */
33
+ setCurrent(value) {
34
+ this._writeState({ [HumidityProperty.Current]: Math.max(0, Math.min(100, value)) });
35
+ }
36
+ /**
37
+ * Read-only sensor: external writes are ignored. Reading via `setCurrent` is plugin-only.
38
+ *
39
+ * Called by the cross-process plugin host when a generic property write is received.
40
+ * Humidity sensors have no externally writable properties, so the parameters are
41
+ * unused (underscore-prefixed) and the call is a no-op.
42
+ *
43
+ * @param _property - Unused — humidity sensors expose no writable properties.
44
+ *
45
+ * @param _value - Unused — humidity sensors expose no writable properties.
46
+ *
47
+ * @internal
48
+ */
49
+ updateValue(_property, _value) {
50
+ // No-op — humidity is reported by the plugin, not set externally.
51
+ }
52
+ }
@@ -1,19 +1,25 @@
1
- // Base
2
- export * from './base.js';
3
- export * from './types.js';
4
- export * from './guards.js';
5
- // Detection Sensors
6
1
  export * from './audio.js';
2
+ export * from './base.js';
3
+ export * from './battery.js';
4
+ export * from './classifier.js';
5
+ export * from './clip.js';
7
6
  export * from './contact.js';
7
+ export * from './detection.js';
8
+ export * from './doorbell.js';
8
9
  export * from './face.js';
10
+ export * from './garage.js';
11
+ export * from './humidity.js';
12
+ export * from './leak.js';
9
13
  export * from './licensePlate.js';
14
+ export * from './light.js';
15
+ export * from './lock.js';
10
16
  export * from './motion.js';
11
17
  export * from './object.js';
12
- // Controls
13
- export * from './light.js';
18
+ export * from './occupancy.js';
14
19
  export * from './ptz.js';
20
+ export * from './securitySystem.js';
15
21
  export * from './siren.js';
16
- // Triggers
17
- export * from './doorbell.js';
18
- // Info
19
- export * from './battery.js';
22
+ export * from './smoke.js';
23
+ export * from './spec.js';
24
+ export * from './switch.js';
25
+ export * from './temperature.js';
@@ -0,0 +1,52 @@
1
+ import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ /**
3
+ * Properties for leak sensors
4
+ *
5
+ * @internal
6
+ */
7
+ export var LeakProperty;
8
+ (function (LeakProperty) {
9
+ /** Whether a leak is detected */
10
+ LeakProperty["Detected"] = "detected";
11
+ })(LeakProperty || (LeakProperty = {}));
12
+ /** Water leak detector sensor */
13
+ export class LeakSensor extends Sensor {
14
+ type = SensorType.Leak;
15
+ category = SensorCategory.Sensor;
16
+ constructor(name = 'Leak Sensor') {
17
+ super(name);
18
+ this._writeState({ [LeakProperty.Detected]: false });
19
+ }
20
+ get detected() {
21
+ return this.props.detected;
22
+ }
23
+ /**
24
+ * Report leak detection state.
25
+ *
26
+ * @param value - True when a leak is currently detected.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * leak.setDetected(true);
31
+ * ```
32
+ */
33
+ setDetected(value) {
34
+ this._writeState({ [LeakProperty.Detected]: value });
35
+ }
36
+ /**
37
+ * Read-only sensor: external writes are ignored. State is reported via `setDetected`.
38
+ *
39
+ * Called by the cross-process plugin host when a generic property write is received.
40
+ * Leak sensors have no externally writable properties, so the parameters are
41
+ * unused (underscore-prefixed) and the call is a no-op.
42
+ *
43
+ * @param _property - Unused — leak sensors expose no writable properties.
44
+ *
45
+ * @param _value - Unused — leak sensors expose no writable properties.
46
+ *
47
+ * @internal
48
+ */
49
+ updateValue(_property, _value) {
50
+ // No-op — leak state is reported by the plugin, not set externally.
51
+ }
52
+ }
@@ -1,116 +1,107 @@
1
- import { Sensor } from './base.js';
2
- import { SensorCategory, SensorType } from './types.js';
1
+ import { Sensor, SensorType, SensorCategory } from './base.js';
3
2
  /**
4
- * License plate sensor property keys
3
+ * Property names of a license plate detection sensor.
4
+ *
5
+ * @internal
5
6
  */
6
7
  export var LicensePlateProperty;
7
8
  (function (LicensePlateProperty) {
9
+ /** Whether any license plate is currently detected. */
8
10
  LicensePlateProperty["Detected"] = "detected";
9
- LicensePlateProperty["Plates"] = "plates";
11
+ /** List of detected plates with OCR text. */
12
+ LicensePlateProperty["Detections"] = "detections";
10
13
  })(LicensePlateProperty || (LicensePlateProperty = {}));
11
14
  /**
12
- * License Plate Sensor (Specialized)
15
+ * License plate sensor that reports detected plates with OCR text.
13
16
  *
14
- * Detects and reads license plates in camera frames.
15
- * Can optionally receive vehicle regions from ObjectSensor for focused detection.
17
+ * Plugin authors call `reportDetections(list)` to push detected plates.
18
+ * `detected` is auto-derived from the detection list.
16
19
  */
17
20
  export class LicensePlateSensor extends Sensor {
18
21
  type = SensorType.LicensePlate;
19
22
  category = SensorCategory.Sensor;
20
- name;
21
23
  constructor(name = 'License Plate Sensor') {
22
- super();
23
- this.name = name;
24
- // Initialize defaults
25
- this.props.detected = false;
26
- this.props.plates = [];
24
+ super(name);
25
+ this._writeState({
26
+ [LicensePlateProperty.Detected]: false,
27
+ [LicensePlateProperty.Detections]: [],
28
+ });
27
29
  }
28
- /** Whether license plates are currently detected */
30
+ /** Whether any license plate is currently detected. */
29
31
  get detected() {
30
- return this.rawProps.detected;
31
- }
32
- /** Set license plate detected state */
33
- set detected(value) {
34
- this.props.detected = value;
32
+ return this.props.detected;
35
33
  }
36
- /** Current license plate detections */
37
- get plates() {
38
- return this.rawProps.plates;
39
- }
40
- /** Set license plate detections */
41
- set plates(value) {
42
- this.props.plates = value;
34
+ /** Current detection list. */
35
+ get detections() {
36
+ return this.props.detections;
43
37
  }
44
38
  /**
45
- * Update license plate detection state
39
+ * Report detected license plates.
40
+ *
41
+ * - `reportDetections(true)` — plate detected without specifics. The SDK
42
+ * synthesizes a single full-frame detection with empty plateText.
43
+ * - `reportDetections(true, [...])` — explicit plate detections with OCR text.
44
+ * - `reportDetections(false)` — clear.
46
45
  *
47
- * @param detected - Whether license plates are detected
46
+ * @param detected - Whether any license plate is currently detected.
48
47
  *
49
- * @param plates - Array of license plate detections
48
+ * @param detections - Optional explicit plate detections to publish.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * import type { LicensePlateDetection } from '@camera.ui/sdk';
53
+ * sensor.reportDetections(true, [
54
+ * {
55
+ * label: 'vehicle',
56
+ * confidence: 0.93,
57
+ * box: { x: 0.2, y: 0.5, width: 0.2, height: 0.08 },
58
+ * attribute: 'license_plate',
59
+ * plateText: 'ABC 1234',
60
+ * } satisfies LicensePlateDetection,
61
+ * ]);
62
+ * sensor.reportDetections(false);
63
+ * ```
50
64
  */
51
- setPlates(detected, plates = []) {
52
- this.props.detected = detected;
53
- this.props.plates = plates;
54
- }
55
- /** Clear license plate detection state */
56
- clearPlates() {
57
- this.props.detected = false;
58
- this.props.plates = [];
65
+ reportDetections(detected, detections) {
66
+ const list = this._normalizeReportedDetections(detected, detections, 'vehicle', { attribute: 'license_plate', plateText: '' });
67
+ this._writeState({
68
+ [LicensePlateProperty.Detected]: detected,
69
+ [LicensePlateProperty.Detections]: list,
70
+ });
59
71
  }
60
72
  /**
61
- * Get plate texts
73
+ * Explicitly clear license plate state (detected = false, detections = []).
62
74
  *
63
- * @returns Array of detected plate texts
75
+ * @example
76
+ * ```ts
77
+ * sensor.clearDetections();
78
+ * ```
64
79
  */
65
- getPlateTexts() {
66
- return this.plates.map((p) => p.plateText);
80
+ clearDetections() {
81
+ this.reportDetections(false);
67
82
  }
68
83
  /**
69
- * Check if specific plate is detected
84
+ * Read-only sensor: external writes are ignored. State is reported via `reportDetections`.
85
+ *
86
+ * Called by the cross-process plugin host when a generic property write is received.
87
+ * License plate sensors have no externally writable properties, so the parameters are
88
+ * unused (underscore-prefixed) and the call is a no-op.
70
89
  *
71
- * @param plateText - Plate text to check
90
+ * @param _property - Unused license plate sensors expose no writable properties.
72
91
  *
73
- * @returns True if plate is detected, false otherwise
92
+ * @param _value - Unused — license plate sensors expose no writable properties.
93
+ *
94
+ * @internal
74
95
  */
75
- hasPlate(plateText) {
76
- return this.plates.some((p) => p.plateText === plateText);
96
+ updateValue(_property, _value) {
97
+ // No-op license plate state is reported by the plugin, not set externally.
77
98
  }
78
99
  }
79
100
  /**
80
- * License Plate Detector Sensor (Active Detection)
81
- *
82
- * Use this class for frame-based license plate detection (OpenALPR, etc.)
83
- * The `inputProperties` getter specifies the required input format.
84
- *
85
- * Receives cropped vehicle regions from ObjectDetectorSensor for efficient processing.
86
- *
87
- * @example
88
- * ```typescript
89
- * class OpenALPRDetector extends LicensePlateDetectorSensor {
90
- * get inputProperties(): VideoInputProperties {
91
- * return { width: 320, height: 160, format: 'rgb' };
92
- * }
93
- *
94
- * async detectLicensePlates(frame: VideoFrameData, vehicleRegions?: Detection[]): Promise<LicensePlateResult> {
95
- * const plates = await this.alpr.recognize(frame.data);
96
- * return {
97
- * detected: plates.length > 0,
98
- * plates: plates.map(p => ({
99
- * label: 'license_plate',
100
- * confidence: p.confidence,
101
- * box: p.box,
102
- * plateText: p.text,
103
- * plateConfidence: p.textConfidence,
104
- * })),
105
- * };
106
- * }
107
- * }
108
- * ```
101
+ * License plate detector that receives video frames from the backend pipeline.
102
+ * Extend this class and implement {@link detectLicensePlates} for plate
103
+ * detection and OCR.
109
104
  */
110
105
  export class LicensePlateDetectorSensor extends LicensePlateSensor {
111
- /**
112
- * Indicates this sensor requires video frames for detection.
113
- * Used by the backend to determine streaming requirements.
114
- */
115
106
  _requiresFrames = true;
116
107
  }