@camera.ui/sdk 0.0.22 → 0.0.25

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.
@@ -12,17 +12,17 @@ declare const DETECTION_LABELS: readonly ["motion", "person", "vehicle", "animal
12
12
  /** Union of the built-in detection label strings. */
13
13
  type DetectionLabel = (typeof DETECTION_LABELS)[number];
14
14
  /**
15
- * Bounding box of a detection. All coordinates are normalized to 01
15
+ * Bounding box of a detection. All coordinates are normalized to 0-1
16
16
  * (fraction of frame dimensions), so they are independent of resolution.
17
17
  */
18
18
  interface BoundingBox {
19
- /** X coordinate of the top-left corner (01). */
19
+ /** X coordinate of the top-left corner (0-1). */
20
20
  x: number;
21
- /** Y coordinate of the top-left corner (01). */
21
+ /** Y coordinate of the top-left corner (0-1). */
22
22
  y: number;
23
- /** Width as a fraction of frame width (01). */
23
+ /** Width as a fraction of frame width (0-1). */
24
24
  width: number;
25
- /** Height as a fraction of frame height (01). */
25
+ /** Height as a fraction of frame height (0-1). */
26
26
  height: number;
27
27
  }
28
28
 
@@ -71,7 +71,7 @@ declare enum AudioProperty {
71
71
  * @internal
72
72
  */
73
73
  declare enum BatteryProperty {
74
- /** Battery level percentage (0100) */
74
+ /** Battery level percentage (0-100) */
75
75
  Level = "level",
76
76
  /** Current charging state */
77
77
  Charging = "charging",
@@ -131,7 +131,7 @@ declare enum GarageProperty {
131
131
  * @internal
132
132
  */
133
133
  declare enum HumidityProperty {
134
- /** Current relative humidity (0100%) */
134
+ /** Current relative humidity (0-100%) */
135
135
  Current = "current"
136
136
  }
137
137
 
@@ -165,7 +165,7 @@ declare enum LicensePlateProperty {
165
165
  declare enum LightProperty {
166
166
  /** Whether the light is on */
167
167
  On = "on",
168
- /** Brightness level (0100) */
168
+ /** Brightness level (0-100) */
169
169
  Brightness = "brightness"
170
170
  }
171
171
 
@@ -238,7 +238,9 @@ declare enum PTZProperty {
238
238
  /** Target preset to move to */
239
239
  TargetPreset = "targetPreset",
240
240
  /** Relative displacement move command (write-only) */
241
- RelativeMove = "relativeMove"
241
+ RelativeMove = "relativeMove",
242
+ /** Move to the home position (write-only command, carries no state) */
243
+ Home = "home"
242
244
  }
243
245
 
244
246
  /**
@@ -261,7 +263,7 @@ declare enum SecuritySystemProperty {
261
263
  declare enum SirenProperty {
262
264
  /** Whether the siren is currently active */
263
265
  Active = "active",
264
- /** Volume level (0100) */
266
+ /** Volume level (0-100) */
265
267
  Volume = "volume"
266
268
  }
267
269
 
@@ -360,7 +362,7 @@ declare enum SensorType {
360
362
  Contact = "contact",
361
363
  /** Temperature sensor (°C) */
362
364
  Temperature = "temperature",
363
- /** Humidity sensor (0100%) */
365
+ /** Humidity sensor (0-100%) */
364
366
  Humidity = "humidity",
365
367
  /** Occupancy/presence sensor */
366
368
  Occupancy = "occupancy",
@@ -1,3 +1,4 @@
1
+ import { SensorType } from '../sensor/base.js';
1
2
  import { PluginCapability, PluginInterface, PluginRole } from './contract.js';
2
3
  /**
3
4
  * Check the structural validity of an unknown contract object — required
@@ -25,31 +26,7 @@ export function getContractValidationErrors(contract) {
25
26
  }
26
27
  const c = contract;
27
28
  const validRoles = Object.values(PluginRole);
28
- // Import SensorType values dynamically to avoid circular dependency
29
- const validSensorTypes = [
30
- 'motion',
31
- 'object',
32
- 'audio',
33
- 'face',
34
- 'licensePlate',
35
- 'classifier',
36
- 'contact',
37
- 'temperature',
38
- 'humidity',
39
- 'occupancy',
40
- 'smoke',
41
- 'leak',
42
- 'light',
43
- 'siren',
44
- 'switch',
45
- 'lock',
46
- 'garage',
47
- 'ptz',
48
- 'securitySystem',
49
- 'doorbell',
50
- 'battery',
51
- 'clip',
52
- ];
29
+ const validSensorTypes = Object.values(SensorType);
53
30
  // Check role
54
31
  if (c.role === undefined) {
55
32
  errors.push('Missing required field: "role"');
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor } from './meta.js';
2
3
  /** Built-in audio label types recognized across the system. */
3
4
  export const BASE_AUDIO_LABELS = [
4
5
  'doorbell',
@@ -138,3 +139,13 @@ export class AudioSensor extends Sensor {
138
139
  export class AudioDetectorSensor extends AudioSensor {
139
140
  _requiresFrames = true;
140
141
  }
142
+ /** Registry metadata for {@link AudioSensor}. */
143
+ export const audioMeta = defineSensor({
144
+ type: SensorType.Audio,
145
+ category: SensorCategory.Sensor,
146
+ assignmentKey: 'audio',
147
+ multiProvider: false,
148
+ isDetectionType: true,
149
+ properties: Object.values(AudioProperty),
150
+ semantics: null,
151
+ });
@@ -26,7 +26,7 @@ export var SensorType;
26
26
  SensorType["Contact"] = "contact";
27
27
  /** Temperature sensor (°C) */
28
28
  SensorType["Temperature"] = "temperature";
29
- /** Humidity sensor (0100%) */
29
+ /** Humidity sensor (0-100%) */
30
30
  SensorType["Humidity"] = "humidity";
31
31
  /** Occupancy/presence sensor */
32
32
  SensorType["Occupancy"] = "occupancy";
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor, SensorDomain } from './meta.js';
2
3
  /** Optional capabilities for battery info sensors */
3
4
  export var BatteryCapability;
4
5
  (function (BatteryCapability) {
@@ -14,7 +15,7 @@ export var BatteryCapability;
14
15
  */
15
16
  export var BatteryProperty;
16
17
  (function (BatteryProperty) {
17
- /** Battery level percentage (0100) */
18
+ /** Battery level percentage (0-100) */
18
19
  BatteryProperty["Level"] = "level";
19
20
  /** Current charging state */
20
21
  BatteryProperty["Charging"] = "charging";
@@ -63,7 +64,7 @@ export class BatteryInfo extends Sensor {
63
64
  /**
64
65
  * Report a new battery level (percentage). Clamped to [0, 100].
65
66
  *
66
- * @param value - Battery level percentage in the range 0100.
67
+ * @param value - Battery level percentage in the range 0-100.
67
68
  *
68
69
  * @example
69
70
  * ```ts
@@ -117,3 +118,22 @@ export class BatteryInfo extends Sensor {
117
118
  // No-op — battery state is reported by the plugin, not set externally.
118
119
  }
119
120
  }
121
+ /** Registry metadata for {@link BatteryInfo}. */
122
+ export const batteryMeta = defineSensor({
123
+ type: SensorType.Battery,
124
+ category: SensorCategory.Info,
125
+ assignmentKey: 'battery',
126
+ multiProvider: false,
127
+ isDetectionType: false,
128
+ properties: Object.values(BatteryProperty),
129
+ shortcutable: true,
130
+ propertyCapabilities: { [BatteryProperty.Charging]: BatteryCapability.Charging, [BatteryProperty.Low]: BatteryCapability.LowBattery },
131
+ semantics: {
132
+ domain: SensorDomain.Measurement,
133
+ stateProperty: BatteryProperty.Level,
134
+ commandProperty: BatteryProperty.Level,
135
+ deviceClass: 'battery',
136
+ unit: '%',
137
+ diagnostic: true,
138
+ },
139
+ });
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor } from './meta.js';
2
3
  /**
3
4
  * Property names of a classifier sensor.
4
5
  *
@@ -115,3 +116,13 @@ export class ClassifierSensor extends Sensor {
115
116
  export class ClassifierDetectorSensor extends ClassifierSensor {
116
117
  _requiresFrames = true;
117
118
  }
119
+ /** Registry metadata for {@link ClassifierSensor}. */
120
+ export const classifierMeta = defineSensor({
121
+ type: SensorType.Classifier,
122
+ category: SensorCategory.Sensor,
123
+ assignmentKey: 'classifier',
124
+ multiProvider: true,
125
+ isDetectionType: true,
126
+ properties: Object.values(ClassifierProperty),
127
+ semantics: null,
128
+ });
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor } from './meta.js';
2
3
  /**
3
4
  * CLIP detector sensor that receives video frames and generates semantic
4
5
  * embeddings. Extend this class and implement {@link detectEmbeddings} to
@@ -28,3 +29,13 @@ export class ClipDetectorSensor extends Sensor {
28
29
  // No-op — clip detector has no state.
29
30
  }
30
31
  }
32
+ /** Registry metadata for {@link ClipDetectorSensor}. */
33
+ export const clipMeta = defineSensor({
34
+ type: SensorType.Clip,
35
+ category: SensorCategory.Sensor,
36
+ assignmentKey: 'clip',
37
+ multiProvider: false,
38
+ isDetectionType: true,
39
+ properties: [],
40
+ semantics: null,
41
+ });
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor, SensorDomain } from './meta.js';
2
3
  /**
3
4
  * Properties for contact sensors
4
5
  *
@@ -50,3 +51,21 @@ export class ContactSensor extends Sensor {
50
51
  // No-op — contact state is reported by the plugin, not set externally.
51
52
  }
52
53
  }
54
+ /** Registry metadata for {@link ContactSensor}. */
55
+ export const contactMeta = defineSensor({
56
+ type: SensorType.Contact,
57
+ category: SensorCategory.Sensor,
58
+ assignmentKey: 'contact',
59
+ multiProvider: true,
60
+ isDetectionType: false,
61
+ properties: Object.values(ContactProperty),
62
+ shortcutable: true,
63
+ cascadeTrigger: { property: ContactProperty.Detected, value: true, sustained: true },
64
+ virtual: { properties: { [ContactProperty.Detected]: false } },
65
+ semantics: {
66
+ domain: SensorDomain.Binary,
67
+ stateProperty: ContactProperty.Detected,
68
+ commandProperty: ContactProperty.Detected,
69
+ deviceClass: 'opening',
70
+ },
71
+ });
@@ -1,4 +1,6 @@
1
+ /** Object-detection labels the detector groups its classes into. */
2
+ export const OBJECT_DETECTION_LABELS = ['person', 'vehicle', 'animal', 'package'];
1
3
  /** Built-in detection label types recognized across the system. */
2
- export const DETECTION_LABELS = ['motion', 'person', 'vehicle', 'animal', 'package', 'audio'];
4
+ export const DETECTION_LABELS = ['motion', ...OBJECT_DETECTION_LABELS, 'audio'];
3
5
  /** Detection attribute types used to mark sub-detections (face, license plate, ...). */
4
6
  export const DETECTION_ATTRIBUTES = ['face', 'license_plate'];
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor, SensorDomain } from './meta.js';
2
3
  /**
3
4
  * Properties for doorbell triggers
4
5
  *
@@ -75,3 +76,21 @@ export class DoorbellTrigger extends Sensor {
75
76
  super._cleanup();
76
77
  }
77
78
  }
79
+ /** Registry metadata for {@link DoorbellTrigger}. */
80
+ export const doorbellMeta = defineSensor({
81
+ type: SensorType.Doorbell,
82
+ category: SensorCategory.Trigger,
83
+ assignmentKey: 'doorbell',
84
+ multiProvider: true,
85
+ isDetectionType: false,
86
+ properties: Object.values(DoorbellProperty),
87
+ shortcutable: true,
88
+ cascadeTrigger: { property: DoorbellProperty.Ring, value: true, sustained: false },
89
+ virtual: { properties: { [DoorbellProperty.Ring]: false } },
90
+ semantics: {
91
+ domain: SensorDomain.Binary,
92
+ stateProperty: DoorbellProperty.Ring,
93
+ commandProperty: DoorbellProperty.Ring,
94
+ icon: 'mdi:doorbell',
95
+ },
96
+ });
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor } from './meta.js';
2
3
  /**
3
4
  * Property names of a face detection sensor.
4
5
  *
@@ -107,3 +108,13 @@ export class FaceSensor extends Sensor {
107
108
  export class FaceDetectorSensor extends FaceSensor {
108
109
  _requiresFrames = true;
109
110
  }
111
+ /** Registry metadata for {@link FaceSensor}. */
112
+ export const faceMeta = defineSensor({
113
+ type: SensorType.Face,
114
+ category: SensorCategory.Sensor,
115
+ assignmentKey: 'face',
116
+ multiProvider: false,
117
+ isDetectionType: true,
118
+ properties: Object.values(FaceProperty),
119
+ semantics: null,
120
+ });
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor, SensorDomain } from './meta.js';
2
3
  /** Garage door states (HomeKit-compatible values) */
3
4
  export var GarageState;
4
5
  (function (GarageState) {
@@ -119,3 +120,28 @@ export class GarageControl extends Sensor {
119
120
  // Unknown / non-writable property (incl. currentState, obstructionDetected) — ignored.
120
121
  }
121
122
  }
123
+ /** Registry metadata for {@link GarageControl}. */
124
+ export const garageMeta = defineSensor({
125
+ type: SensorType.Garage,
126
+ category: SensorCategory.Control,
127
+ assignmentKey: 'garage',
128
+ multiProvider: true,
129
+ isDetectionType: false,
130
+ properties: Object.values(GarageProperty),
131
+ shortcutable: true,
132
+ cascadeTrigger: { property: GarageProperty.CurrentState, value: 0, sustained: true },
133
+ virtual: { properties: { [GarageProperty.CurrentState]: 1, [GarageProperty.TargetState]: 1 } },
134
+ semantics: {
135
+ domain: SensorDomain.Cover,
136
+ stateProperty: GarageProperty.CurrentState,
137
+ commandProperty: GarageProperty.TargetState,
138
+ deviceClass: 'garage',
139
+ states: {
140
+ open: GarageState.Open,
141
+ closed: GarageState.Closed,
142
+ opening: GarageState.Opening,
143
+ closing: GarageState.Closing,
144
+ stopped: GarageState.Stopped,
145
+ },
146
+ },
147
+ });
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor, SensorDomain } from './meta.js';
2
3
  /**
3
4
  * Properties for humidity sensors
4
5
  *
@@ -6,7 +7,7 @@ import { Sensor, SensorType, SensorCategory } from './base.js';
6
7
  */
7
8
  export var HumidityProperty;
8
9
  (function (HumidityProperty) {
9
- /** Current relative humidity (0100%) */
10
+ /** Current relative humidity (0-100%) */
10
11
  HumidityProperty["Current"] = "current";
11
12
  })(HumidityProperty || (HumidityProperty = {}));
12
13
  /** Humidity info sensor. Reports current relative humidity in %. */
@@ -23,7 +24,7 @@ export class HumidityInfo extends Sensor {
23
24
  /**
24
25
  * Report a new humidity reading. Clamped to [0, 100] %.
25
26
  *
26
- * @param value - Relative humidity percentage in the range 0100.
27
+ * @param value - Relative humidity percentage in the range 0-100.
27
28
  *
28
29
  * @example
29
30
  * ```ts
@@ -50,3 +51,21 @@ export class HumidityInfo extends Sensor {
50
51
  // No-op — humidity is reported by the plugin, not set externally.
51
52
  }
52
53
  }
54
+ /** Registry metadata for {@link HumidityInfo}. */
55
+ export const humidityMeta = defineSensor({
56
+ type: SensorType.Humidity,
57
+ category: SensorCategory.Info,
58
+ assignmentKey: 'humidity',
59
+ multiProvider: true,
60
+ isDetectionType: false,
61
+ properties: Object.values(HumidityProperty),
62
+ shortcutable: true,
63
+ virtual: { properties: { [HumidityProperty.Current]: 50 } },
64
+ semantics: {
65
+ domain: SensorDomain.Measurement,
66
+ stateProperty: HumidityProperty.Current,
67
+ commandProperty: HumidityProperty.Current,
68
+ deviceClass: 'humidity',
69
+ unit: '%',
70
+ },
71
+ });
@@ -12,6 +12,8 @@ export * from './humidity.js';
12
12
  export * from './leak.js';
13
13
  export * from './licensePlate.js';
14
14
  export * from './light.js';
15
+ export * from './meta.js';
16
+ export * from './registry.js';
15
17
  export * from './lock.js';
16
18
  export * from './motion.js';
17
19
  export * from './object.js';
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor, SensorDomain } from './meta.js';
2
3
  /**
3
4
  * Properties for leak sensors
4
5
  *
@@ -50,3 +51,21 @@ export class LeakSensor extends Sensor {
50
51
  // No-op — leak state is reported by the plugin, not set externally.
51
52
  }
52
53
  }
54
+ /** Registry metadata for {@link LeakSensor}. */
55
+ export const leakMeta = defineSensor({
56
+ type: SensorType.Leak,
57
+ category: SensorCategory.Sensor,
58
+ assignmentKey: 'leak',
59
+ multiProvider: true,
60
+ isDetectionType: false,
61
+ properties: Object.values(LeakProperty),
62
+ shortcutable: true,
63
+ cascadeTrigger: { property: LeakProperty.Detected, value: true, sustained: true },
64
+ virtual: { properties: { [LeakProperty.Detected]: false } },
65
+ semantics: {
66
+ domain: SensorDomain.Binary,
67
+ stateProperty: LeakProperty.Detected,
68
+ commandProperty: LeakProperty.Detected,
69
+ deviceClass: 'moisture',
70
+ },
71
+ });
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor } from './meta.js';
2
3
  /**
3
4
  * Property names of a license plate detection sensor.
4
5
  *
@@ -105,3 +106,13 @@ export class LicensePlateSensor extends Sensor {
105
106
  export class LicensePlateDetectorSensor extends LicensePlateSensor {
106
107
  _requiresFrames = true;
107
108
  }
109
+ /** Registry metadata for {@link LicensePlateSensor}. */
110
+ export const licensePlateMeta = defineSensor({
111
+ type: SensorType.LicensePlate,
112
+ category: SensorCategory.Sensor,
113
+ assignmentKey: 'licensePlate',
114
+ multiProvider: false,
115
+ isDetectionType: true,
116
+ properties: Object.values(LicensePlateProperty),
117
+ semantics: null,
118
+ });
@@ -1,8 +1,9 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor, SensorDomain } from './meta.js';
2
3
  /** Optional capabilities for light controls */
3
4
  export var LightCapability;
4
5
  (function (LightCapability) {
5
- /** Light supports brightness adjustment (0100) */
6
+ /** Light supports brightness adjustment (0-100) */
6
7
  LightCapability["Brightness"] = "brightness";
7
8
  })(LightCapability || (LightCapability = {}));
8
9
  /**
@@ -14,7 +15,7 @@ export var LightProperty;
14
15
  (function (LightProperty) {
15
16
  /** Whether the light is on */
16
17
  LightProperty["On"] = "on";
17
- /** Brightness level (0100) */
18
+ /** Brightness level (0-100) */
18
19
  LightProperty["Brightness"] = "brightness";
19
20
  })(LightProperty || (LightProperty = {}));
20
21
  /**
@@ -72,7 +73,7 @@ export class LightControl extends Sensor {
72
73
  * Set brightness. Override to drive hardware and call `await super.setBrightness(value)`
73
74
  * after the hardware call succeeds. The default implementation clamps the value to [0, 100].
74
75
  *
75
- * @param value - Brightness level in the range 0100.
76
+ * @param value - Brightness level in the range 0-100.
76
77
  *
77
78
  * @example
78
79
  * ```ts
@@ -108,3 +109,24 @@ export class LightControl extends Sensor {
108
109
  // Unknown / non-writable property — ignored.
109
110
  }
110
111
  }
112
+ /** Registry metadata for {@link LightControl}. */
113
+ export const lightMeta = defineSensor({
114
+ type: SensorType.Light,
115
+ category: SensorCategory.Control,
116
+ assignmentKey: 'light',
117
+ multiProvider: true,
118
+ isDetectionType: false,
119
+ properties: Object.values(LightProperty),
120
+ shortcutable: true,
121
+ cascadeTrigger: { property: LightProperty.On, value: true, sustained: true },
122
+ propertyCapabilities: { [LightProperty.Brightness]: LightCapability.Brightness },
123
+ virtual: {
124
+ properties: { [LightProperty.On]: false, [LightProperty.Brightness]: 100 },
125
+ capabilities: [LightCapability.Brightness],
126
+ },
127
+ semantics: {
128
+ domain: SensorDomain.Light,
129
+ stateProperty: LightProperty.On,
130
+ commandProperty: LightProperty.On,
131
+ },
132
+ });
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor, SensorDomain } from './meta.js';
2
3
  /** Lock states (HomeKit-compatible values) */
3
4
  export var LockState;
4
5
  (function (LockState) {
@@ -97,3 +98,21 @@ export class LockControl extends Sensor {
97
98
  // Unknown / non-writable property (incl. currentState) — ignored.
98
99
  }
99
100
  }
101
+ /** Registry metadata for {@link LockControl}. */
102
+ export const lockMeta = defineSensor({
103
+ type: SensorType.Lock,
104
+ category: SensorCategory.Control,
105
+ assignmentKey: 'lock',
106
+ multiProvider: true,
107
+ isDetectionType: false,
108
+ properties: Object.values(LockProperty),
109
+ shortcutable: true,
110
+ cascadeTrigger: { property: LockProperty.CurrentState, value: 1, sustained: true },
111
+ virtual: { properties: { [LockProperty.CurrentState]: 0, [LockProperty.TargetState]: 0 } },
112
+ semantics: {
113
+ domain: SensorDomain.Lock,
114
+ stateProperty: LockProperty.CurrentState,
115
+ commandProperty: LockProperty.TargetState,
116
+ states: { locked: LockState.Secured, unlocked: LockState.Unsecured },
117
+ },
118
+ });
@@ -0,0 +1,35 @@
1
+ /** The kind of thing a sensor is, used by consumers to pick how to render it. */
2
+ export var SensorDomain;
3
+ (function (SensorDomain) {
4
+ SensorDomain["Binary"] = "binary";
5
+ SensorDomain["Measurement"] = "measurement";
6
+ SensorDomain["Switch"] = "switch";
7
+ SensorDomain["Light"] = "light";
8
+ SensorDomain["Siren"] = "siren";
9
+ SensorDomain["Lock"] = "lock";
10
+ SensorDomain["Cover"] = "cover";
11
+ SensorDomain["Alarm"] = "alarm";
12
+ })(SensorDomain || (SensorDomain = {}));
13
+ /**
14
+ * Declares the metadata for a sensor type: how it is assigned, scheduled, and
15
+ * optionally created as a virtual sensor.
16
+ *
17
+ * @param meta - The sensor's metadata.
18
+ *
19
+ * @returns The same metadata, with `type` and `assignmentKey` preserved as literal
20
+ * types so the registry can be checked for completeness and its keys derived.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * export const lightMeta = defineSensor({
25
+ * type: SensorType.Light,
26
+ * category: SensorCategory.Control,
27
+ * assignmentKey: 'light',
28
+ * multiProvider: true,
29
+ * isDetectionType: false,
30
+ * });
31
+ * ```
32
+ */
33
+ export function defineSensor(meta) {
34
+ return meta;
35
+ }
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor } from './meta.js';
2
3
  /**
3
4
  * Property names of a motion sensor.
4
5
  *
@@ -118,3 +119,13 @@ export class MotionSensor extends Sensor {
118
119
  export class MotionDetectorSensor extends MotionSensor {
119
120
  _requiresFrames = true;
120
121
  }
122
+ /** Registry metadata for {@link MotionSensor}. */
123
+ export const motionMeta = defineSensor({
124
+ type: SensorType.Motion,
125
+ category: SensorCategory.Sensor,
126
+ assignmentKey: 'motion',
127
+ multiProvider: false,
128
+ isDetectionType: true,
129
+ properties: Object.values(MotionProperty),
130
+ semantics: null,
131
+ });
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor } from './meta.js';
2
3
  /**
3
4
  * Property names of an object detection sensor.
4
5
  *
@@ -114,3 +115,13 @@ export class ObjectSensor extends Sensor {
114
115
  export class ObjectDetectorSensor extends ObjectSensor {
115
116
  _requiresFrames = true;
116
117
  }
118
+ /** Registry metadata for {@link ObjectSensor}. */
119
+ export const objectMeta = defineSensor({
120
+ type: SensorType.Object,
121
+ category: SensorCategory.Sensor,
122
+ assignmentKey: 'object',
123
+ multiProvider: false,
124
+ isDetectionType: true,
125
+ properties: Object.values(ObjectProperty),
126
+ semantics: null,
127
+ });
@@ -1,4 +1,5 @@
1
1
  import { Sensor, SensorType, SensorCategory } from './base.js';
2
+ import { defineSensor, SensorDomain } from './meta.js';
2
3
  /**
3
4
  * Properties for occupancy sensors
4
5
  *
@@ -50,3 +51,21 @@ export class OccupancySensor extends Sensor {
50
51
  // No-op — occupancy state is reported by the plugin, not set externally.
51
52
  }
52
53
  }
54
+ /** Registry metadata for {@link OccupancySensor}. */
55
+ export const occupancyMeta = defineSensor({
56
+ type: SensorType.Occupancy,
57
+ category: SensorCategory.Sensor,
58
+ assignmentKey: 'occupancy',
59
+ multiProvider: true,
60
+ isDetectionType: false,
61
+ properties: Object.values(OccupancyProperty),
62
+ shortcutable: true,
63
+ cascadeTrigger: { property: OccupancyProperty.Detected, value: true, sustained: true },
64
+ virtual: { properties: { [OccupancyProperty.Detected]: false } },
65
+ semantics: {
66
+ domain: SensorDomain.Binary,
67
+ stateProperty: OccupancyProperty.Detected,
68
+ commandProperty: OccupancyProperty.Detected,
69
+ deviceClass: 'occupancy',
70
+ },
71
+ });