@camstack/addon-provider-amcrest 0.2.130 → 0.2.131

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 (3) hide show
  1. package/dist/addon.js +121 -58
  2. package/dist/addon.mjs +121 -58
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -10510,6 +10510,57 @@ var ClipSearchStrictnessSchema = _enum([
10510
10510
  "balanced",
10511
10511
  "strict"
10512
10512
  ]);
10513
+ new Set([
10514
+ {
10515
+ id: "person",
10516
+ name: "Person"
10517
+ },
10518
+ {
10519
+ id: "vehicle",
10520
+ name: "Vehicle"
10521
+ },
10522
+ {
10523
+ id: "animal",
10524
+ name: "Animal"
10525
+ },
10526
+ {
10527
+ id: "package",
10528
+ name: "Package"
10529
+ }
10530
+ ].map((l) => l.id));
10531
+ var COCO_TO_MACRO = {
10532
+ mapping: {
10533
+ person: "person",
10534
+ bicycle: "vehicle",
10535
+ car: "vehicle",
10536
+ motorcycle: "vehicle",
10537
+ airplane: "vehicle",
10538
+ bus: "vehicle",
10539
+ train: "vehicle",
10540
+ truck: "vehicle",
10541
+ boat: "vehicle",
10542
+ bird: "animal",
10543
+ cat: "animal",
10544
+ dog: "animal",
10545
+ horse: "animal",
10546
+ sheep: "animal",
10547
+ cow: "animal",
10548
+ elephant: "animal",
10549
+ bear: "animal",
10550
+ zebra: "animal",
10551
+ giraffe: "animal",
10552
+ suitcase: "package",
10553
+ backpack: "package",
10554
+ handbag: "package"
10555
+ },
10556
+ preserveOriginal: false
10557
+ };
10558
+ /** Steps a root detector may declare it fills. */
10559
+ var FILLABLE_STEP_IDS = [
10560
+ "animal-classifier",
10561
+ "vehicle-classifier",
10562
+ "package-detection"
10563
+ ];
10513
10564
  var MODEL_FORMATS = [
10514
10565
  "onnx",
10515
10566
  "coreml",
@@ -10642,6 +10693,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
10642
10693
  /** True when the weights or their data forbid commercial use. */
10643
10694
  nonCommercial: boolean().optional()
10644
10695
  }));
10696
+ /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
10697
+ var FillsClassifierEffectSchema = object({
10698
+ stepId: _enum(FILLABLE_STEP_IDS),
10699
+ labelToEffect: record(string(), string()),
10700
+ uncovered: array(string()).readonly()
10701
+ });
10645
10702
  var ModelCatalogEntrySchema = object({
10646
10703
  id: string(),
10647
10704
  name: string(),
@@ -10768,6 +10825,16 @@ var ModelCatalogEntrySchema = object({
10768
10825
  */
10769
10826
  classMap: DetectionCatalogClassMapSchema.optional(),
10770
10827
  /**
10828
+ * The pipeline steps this ROOT detector already does the work of (D715):
10829
+ * its labels name the effect the step exists to produce (`deer` for
10830
+ * `animal-classifier`, `package` for `package-detection`). Derived from the
10831
+ * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
10832
+ * declares none. Whether a declaration is honoured is the step's own
10833
+ * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
10834
+ * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
10835
+ */
10836
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
10837
+ /**
10771
10838
  * The model's CLIP feature-space contract (text encoder, dimension, vector
10772
10839
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
10773
10840
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -18091,51 +18158,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
18091
18158
  kind: "mutation",
18092
18159
  auth: "admin"
18093
18160
  });
18094
- new Set([
18095
- {
18096
- id: "person",
18097
- name: "Person"
18098
- },
18099
- {
18100
- id: "vehicle",
18101
- name: "Vehicle"
18102
- },
18103
- {
18104
- id: "animal",
18105
- name: "Animal"
18106
- },
18107
- {
18108
- id: "package",
18109
- name: "Package"
18110
- }
18111
- ].map((l) => l.id));
18112
- var COCO_TO_MACRO = {
18113
- mapping: {
18114
- person: "person",
18115
- bicycle: "vehicle",
18116
- car: "vehicle",
18117
- motorcycle: "vehicle",
18118
- airplane: "vehicle",
18119
- bus: "vehicle",
18120
- train: "vehicle",
18121
- truck: "vehicle",
18122
- boat: "vehicle",
18123
- bird: "animal",
18124
- cat: "animal",
18125
- dog: "animal",
18126
- horse: "animal",
18127
- sheep: "animal",
18128
- cow: "animal",
18129
- elephant: "animal",
18130
- bear: "animal",
18131
- zebra: "animal",
18132
- giraffe: "animal",
18133
- suitcase: "package",
18134
- backpack: "package",
18135
- handbag: "package"
18136
- },
18137
- preserveOriginal: false
18138
- };
18139
18161
  var AUDIO_MACRO_LABELS = [
18140
18162
  {
18141
18163
  id: "speech",
@@ -18931,6 +18953,8 @@ var NcSystemEventKindSchema = _enum([
18931
18953
  "stream-offline",
18932
18954
  "node-online",
18933
18955
  "node-offline",
18956
+ "node-restarting",
18957
+ "node-updating",
18934
18958
  "node-inference-unavailable",
18935
18959
  "detection-blind",
18936
18960
  "addon-crash-loop",
@@ -23577,7 +23601,8 @@ var PipelineModelOptionSchema = object({
23577
23601
  group: ModelVariantGroupSchema.optional(),
23578
23602
  legacy: boolean().optional(),
23579
23603
  provider: ModelProviderIdSchema.optional(),
23580
- defaultConfidence: number().optional()
23604
+ defaultConfidence: number().optional(),
23605
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
23581
23606
  });
23582
23607
  var ConfigFieldBridge = custom();
23583
23608
  var PipelineAddonSchemaSchema = object({
@@ -33247,7 +33272,8 @@ var MotionStatusSchema = object({
33247
33272
  * writes this slice (not even a boot seed), and neither does the runner's
33248
33273
  * phase machine: its phase is "a session is attached" for every on-motion
33249
33274
  * session, not motion, and it now has its own `DetectionPhaseTransition`.
33250
- * A provider's `isDetected` answers from the hub's slice.
33275
+ * A provider's `isDetected` and `getStatus` answer from the hub's slice
33276
+ * (`hubMotionNativeProvider`).
33251
33277
  * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
33252
33278
  * imports) — the provider pushes both edges itself, from the upstream
33253
33279
  * system's own state change. That is the sensor's own fact.
@@ -53385,6 +53411,8 @@ new Map(Object.entries({
53385
53411
  "detection-blind": "device-events",
53386
53412
  "node-online": "system",
53387
53413
  "node-offline": "system",
53414
+ "node-restarting": "system",
53415
+ "node-updating": "system",
53388
53416
  "node-inference-unavailable": "system",
53389
53417
  "addon-crash-loop": "system",
53390
53418
  "addon-update-available": "system",
@@ -53462,6 +53490,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
53462
53490
  kinds: [
53463
53491
  "node-offline",
53464
53492
  "node-online",
53493
+ "node-restarting",
53465
53494
  "node-inference-unavailable"
53466
53495
  ]
53467
53496
  },
@@ -53483,6 +53512,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
53483
53512
  label: "Server & container updates",
53484
53513
  kinds: [
53485
53514
  "server-update-available",
53515
+ "node-updating",
53486
53516
  "server-updated",
53487
53517
  "wrapper-update-available"
53488
53518
  ]
@@ -53630,6 +53660,7 @@ var STATE_SUMMARY_SECTION_VARS = [
53630
53660
  kinds: [
53631
53661
  "node-offline",
53632
53662
  "node-online",
53663
+ "node-restarting",
53633
53664
  "node-inference-unavailable"
53634
53665
  ]
53635
53666
  },
@@ -53651,6 +53682,7 @@ var STATE_SUMMARY_SECTION_VARS = [
53651
53682
  example: "server 1.2.377 → 1.2.378",
53652
53683
  kinds: [
53653
53684
  "server-update-available",
53685
+ "node-updating",
53654
53686
  "server-updated",
53655
53687
  "wrapper-update-available"
53656
53688
  ]
@@ -54106,10 +54138,9 @@ TimelapseRuleInputSchema.extend({
54106
54138
  createdAt: number(),
54107
54139
  updatedAt: number()
54108
54140
  });
54109
- async function readHubMotionDetected(deviceState, deviceId) {
54110
- let slice;
54141
+ async function readSlice(deviceState, deviceId) {
54111
54142
  try {
54112
- slice = await deviceState.getCapSlice.query({
54143
+ return await deviceState.getCapSlice.query({
54113
54144
  deviceId,
54114
54145
  capName: "motion"
54115
54146
  });
@@ -54117,10 +54148,44 @@ async function readHubMotionDetected(deviceState, deviceId) {
54117
54148
  const reason = err instanceof Error ? err.message : String(err);
54118
54149
  throw new Error(`motion state of device ${deviceId} is unreadable: ${reason}`, { cause: err });
54119
54150
  }
54120
- const detected = slice?.["detected"];
54151
+ }
54152
+ /**
54153
+ * The hub's `motion` slice as a `MotionStatus`, or `null` when nobody has
54154
+ * published it since the hub started. Throws when the hub does not answer or
54155
+ * the slice is malformed — never a made-up "no motion".
54156
+ */
54157
+ async function readHubMotionStatus(deviceState, deviceId) {
54158
+ const slice = await readSlice(deviceState, deviceId);
54159
+ if (slice === null) return null;
54160
+ const parsed = MotionStatusSchema.safeParse(slice);
54161
+ if (!parsed.success) throw new Error(`motion state of device ${deviceId} is malformed on the hub: ${parsed.error.message}`);
54162
+ return parsed.data;
54163
+ }
54164
+ async function readHubMotionDetected(deviceState, deviceId) {
54165
+ const detected = (await readSlice(deviceState, deviceId))?.["detected"];
54121
54166
  if (typeof detected !== "boolean") throw new Error(`motion state of device ${deviceId} is not published yet (unknown)`);
54122
54167
  return detected;
54123
54168
  }
54169
+ /**
54170
+ * The native `motion` provider of a camera whose slice the orchestrator writes
54171
+ * (D696): `isDetected` AND `getStatus`, both from the hub. `owner` names the
54172
+ * provider class in the deviceId-mismatch error.
54173
+ */
54174
+ function hubMotionNativeProvider(deviceState, deviceId, owner) {
54175
+ const ownDevice = (asked) => {
54176
+ if (asked !== deviceId) throw new Error(`${owner}: motion deviceId mismatch, expected ${deviceId}, got ${asked}`);
54177
+ };
54178
+ return {
54179
+ isDetected: async ({ deviceId: asked }) => {
54180
+ ownDevice(asked);
54181
+ return readHubMotionDetected(deviceState, deviceId);
54182
+ },
54183
+ getStatus: async ({ deviceId: asked }) => {
54184
+ ownDevice(asked);
54185
+ return readHubMotionStatus(deviceState, deviceId);
54186
+ }
54187
+ };
54188
+ }
54124
54189
  MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
54125
54190
  function providerMotionEvent(source, data) {
54126
54191
  return createEvent(EventCategory.ProviderMotion, source, data);
@@ -56494,14 +56559,12 @@ var AmcrestCamera = class AmcrestCamera extends BaseDevice {
56494
56559
  }
56495
56560
  /** Register the native `motion` cap. Its mere presence (a `kind:'native'`
56496
56561
  * `motion` binding) is what the orchestrator reads to default a
56497
- * freshly-adopted camera to `motionSources:['onboard']`. `isDetected`
56498
- * answers from the HUB's slice; an unreadable hub, or a slice nobody has
56499
- * published yet, fails the call — never `false` for unknown (D49, D393). */
56562
+ * freshly-adopted camera to `motionSources:['onboard']`. `isDetected` and
56563
+ * `getStatus` answer from the HUB's slice (`hubMotionNativeProvider`); an
56564
+ * unreadable hub fails both — never `false` for unknown (D49, D393). */
56500
56565
  registerMotionCap() {
56501
- this.ctx.registerNativeCap(motionCapability, { isDetected: async ({ deviceId }) => {
56502
- if (deviceId !== this.id) throw new Error(`AmcrestCamera: motion deviceId mismatch, expected ${this.id}, got ${deviceId}`);
56503
- return readHubMotionDetected(this.ctx.api.deviceState, this.id);
56504
- } });
56566
+ const provider = hubMotionNativeProvider(this.ctx.api.deviceState, this.id, "AmcrestCamera");
56567
+ this.ctx.registerNativeCap(motionCapability, provider);
56505
56568
  this.ctx.logger.info("amcrest: motion cap registered", { tags: { deviceId: this.id } });
56506
56569
  }
56507
56570
  /** Reusable event-source identity for every emit on this device. */
package/dist/addon.mjs CHANGED
@@ -10489,6 +10489,57 @@ var ClipSearchStrictnessSchema = _enum([
10489
10489
  "balanced",
10490
10490
  "strict"
10491
10491
  ]);
10492
+ new Set([
10493
+ {
10494
+ id: "person",
10495
+ name: "Person"
10496
+ },
10497
+ {
10498
+ id: "vehicle",
10499
+ name: "Vehicle"
10500
+ },
10501
+ {
10502
+ id: "animal",
10503
+ name: "Animal"
10504
+ },
10505
+ {
10506
+ id: "package",
10507
+ name: "Package"
10508
+ }
10509
+ ].map((l) => l.id));
10510
+ var COCO_TO_MACRO = {
10511
+ mapping: {
10512
+ person: "person",
10513
+ bicycle: "vehicle",
10514
+ car: "vehicle",
10515
+ motorcycle: "vehicle",
10516
+ airplane: "vehicle",
10517
+ bus: "vehicle",
10518
+ train: "vehicle",
10519
+ truck: "vehicle",
10520
+ boat: "vehicle",
10521
+ bird: "animal",
10522
+ cat: "animal",
10523
+ dog: "animal",
10524
+ horse: "animal",
10525
+ sheep: "animal",
10526
+ cow: "animal",
10527
+ elephant: "animal",
10528
+ bear: "animal",
10529
+ zebra: "animal",
10530
+ giraffe: "animal",
10531
+ suitcase: "package",
10532
+ backpack: "package",
10533
+ handbag: "package"
10534
+ },
10535
+ preserveOriginal: false
10536
+ };
10537
+ /** Steps a root detector may declare it fills. */
10538
+ var FILLABLE_STEP_IDS = [
10539
+ "animal-classifier",
10540
+ "vehicle-classifier",
10541
+ "package-detection"
10542
+ ];
10492
10543
  var MODEL_FORMATS = [
10493
10544
  "onnx",
10494
10545
  "coreml",
@@ -10621,6 +10672,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
10621
10672
  /** True when the weights or their data forbid commercial use. */
10622
10673
  nonCommercial: boolean().optional()
10623
10674
  }));
10675
+ /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
10676
+ var FillsClassifierEffectSchema = object({
10677
+ stepId: _enum(FILLABLE_STEP_IDS),
10678
+ labelToEffect: record(string(), string()),
10679
+ uncovered: array(string()).readonly()
10680
+ });
10624
10681
  var ModelCatalogEntrySchema = object({
10625
10682
  id: string(),
10626
10683
  name: string(),
@@ -10747,6 +10804,16 @@ var ModelCatalogEntrySchema = object({
10747
10804
  */
10748
10805
  classMap: DetectionCatalogClassMapSchema.optional(),
10749
10806
  /**
10807
+ * The pipeline steps this ROOT detector already does the work of (D715):
10808
+ * its labels name the effect the step exists to produce (`deer` for
10809
+ * `animal-classifier`, `package` for `package-detection`). Derived from the
10810
+ * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
10811
+ * declares none. Whether a declaration is honoured is the step's own
10812
+ * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
10813
+ * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
10814
+ */
10815
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
10816
+ /**
10750
10817
  * The model's CLIP feature-space contract (text encoder, dimension, vector
10751
10818
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
10752
10819
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -18070,51 +18137,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
18070
18137
  kind: "mutation",
18071
18138
  auth: "admin"
18072
18139
  });
18073
- new Set([
18074
- {
18075
- id: "person",
18076
- name: "Person"
18077
- },
18078
- {
18079
- id: "vehicle",
18080
- name: "Vehicle"
18081
- },
18082
- {
18083
- id: "animal",
18084
- name: "Animal"
18085
- },
18086
- {
18087
- id: "package",
18088
- name: "Package"
18089
- }
18090
- ].map((l) => l.id));
18091
- var COCO_TO_MACRO = {
18092
- mapping: {
18093
- person: "person",
18094
- bicycle: "vehicle",
18095
- car: "vehicle",
18096
- motorcycle: "vehicle",
18097
- airplane: "vehicle",
18098
- bus: "vehicle",
18099
- train: "vehicle",
18100
- truck: "vehicle",
18101
- boat: "vehicle",
18102
- bird: "animal",
18103
- cat: "animal",
18104
- dog: "animal",
18105
- horse: "animal",
18106
- sheep: "animal",
18107
- cow: "animal",
18108
- elephant: "animal",
18109
- bear: "animal",
18110
- zebra: "animal",
18111
- giraffe: "animal",
18112
- suitcase: "package",
18113
- backpack: "package",
18114
- handbag: "package"
18115
- },
18116
- preserveOriginal: false
18117
- };
18118
18140
  var AUDIO_MACRO_LABELS = [
18119
18141
  {
18120
18142
  id: "speech",
@@ -18910,6 +18932,8 @@ var NcSystemEventKindSchema = _enum([
18910
18932
  "stream-offline",
18911
18933
  "node-online",
18912
18934
  "node-offline",
18935
+ "node-restarting",
18936
+ "node-updating",
18913
18937
  "node-inference-unavailable",
18914
18938
  "detection-blind",
18915
18939
  "addon-crash-loop",
@@ -23556,7 +23580,8 @@ var PipelineModelOptionSchema = object({
23556
23580
  group: ModelVariantGroupSchema.optional(),
23557
23581
  legacy: boolean().optional(),
23558
23582
  provider: ModelProviderIdSchema.optional(),
23559
- defaultConfidence: number().optional()
23583
+ defaultConfidence: number().optional(),
23584
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
23560
23585
  });
23561
23586
  var ConfigFieldBridge = custom();
23562
23587
  var PipelineAddonSchemaSchema = object({
@@ -33226,7 +33251,8 @@ var MotionStatusSchema = object({
33226
33251
  * writes this slice (not even a boot seed), and neither does the runner's
33227
33252
  * phase machine: its phase is "a session is attached" for every on-motion
33228
33253
  * session, not motion, and it now has its own `DetectionPhaseTransition`.
33229
- * A provider's `isDetected` answers from the hub's slice.
33254
+ * A provider's `isDetected` and `getStatus` answer from the hub's slice
33255
+ * (`hubMotionNativeProvider`).
33230
33256
  * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
33231
33257
  * imports) — the provider pushes both edges itself, from the upstream
33232
33258
  * system's own state change. That is the sensor's own fact.
@@ -53364,6 +53390,8 @@ new Map(Object.entries({
53364
53390
  "detection-blind": "device-events",
53365
53391
  "node-online": "system",
53366
53392
  "node-offline": "system",
53393
+ "node-restarting": "system",
53394
+ "node-updating": "system",
53367
53395
  "node-inference-unavailable": "system",
53368
53396
  "addon-crash-loop": "system",
53369
53397
  "addon-update-available": "system",
@@ -53441,6 +53469,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
53441
53469
  kinds: [
53442
53470
  "node-offline",
53443
53471
  "node-online",
53472
+ "node-restarting",
53444
53473
  "node-inference-unavailable"
53445
53474
  ]
53446
53475
  },
@@ -53462,6 +53491,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
53462
53491
  label: "Server & container updates",
53463
53492
  kinds: [
53464
53493
  "server-update-available",
53494
+ "node-updating",
53465
53495
  "server-updated",
53466
53496
  "wrapper-update-available"
53467
53497
  ]
@@ -53609,6 +53639,7 @@ var STATE_SUMMARY_SECTION_VARS = [
53609
53639
  kinds: [
53610
53640
  "node-offline",
53611
53641
  "node-online",
53642
+ "node-restarting",
53612
53643
  "node-inference-unavailable"
53613
53644
  ]
53614
53645
  },
@@ -53630,6 +53661,7 @@ var STATE_SUMMARY_SECTION_VARS = [
53630
53661
  example: "server 1.2.377 → 1.2.378",
53631
53662
  kinds: [
53632
53663
  "server-update-available",
53664
+ "node-updating",
53633
53665
  "server-updated",
53634
53666
  "wrapper-update-available"
53635
53667
  ]
@@ -54085,10 +54117,9 @@ TimelapseRuleInputSchema.extend({
54085
54117
  createdAt: number(),
54086
54118
  updatedAt: number()
54087
54119
  });
54088
- async function readHubMotionDetected(deviceState, deviceId) {
54089
- let slice;
54120
+ async function readSlice(deviceState, deviceId) {
54090
54121
  try {
54091
- slice = await deviceState.getCapSlice.query({
54122
+ return await deviceState.getCapSlice.query({
54092
54123
  deviceId,
54093
54124
  capName: "motion"
54094
54125
  });
@@ -54096,10 +54127,44 @@ async function readHubMotionDetected(deviceState, deviceId) {
54096
54127
  const reason = err instanceof Error ? err.message : String(err);
54097
54128
  throw new Error(`motion state of device ${deviceId} is unreadable: ${reason}`, { cause: err });
54098
54129
  }
54099
- const detected = slice?.["detected"];
54130
+ }
54131
+ /**
54132
+ * The hub's `motion` slice as a `MotionStatus`, or `null` when nobody has
54133
+ * published it since the hub started. Throws when the hub does not answer or
54134
+ * the slice is malformed — never a made-up "no motion".
54135
+ */
54136
+ async function readHubMotionStatus(deviceState, deviceId) {
54137
+ const slice = await readSlice(deviceState, deviceId);
54138
+ if (slice === null) return null;
54139
+ const parsed = MotionStatusSchema.safeParse(slice);
54140
+ if (!parsed.success) throw new Error(`motion state of device ${deviceId} is malformed on the hub: ${parsed.error.message}`);
54141
+ return parsed.data;
54142
+ }
54143
+ async function readHubMotionDetected(deviceState, deviceId) {
54144
+ const detected = (await readSlice(deviceState, deviceId))?.["detected"];
54100
54145
  if (typeof detected !== "boolean") throw new Error(`motion state of device ${deviceId} is not published yet (unknown)`);
54101
54146
  return detected;
54102
54147
  }
54148
+ /**
54149
+ * The native `motion` provider of a camera whose slice the orchestrator writes
54150
+ * (D696): `isDetected` AND `getStatus`, both from the hub. `owner` names the
54151
+ * provider class in the deviceId-mismatch error.
54152
+ */
54153
+ function hubMotionNativeProvider(deviceState, deviceId, owner) {
54154
+ const ownDevice = (asked) => {
54155
+ if (asked !== deviceId) throw new Error(`${owner}: motion deviceId mismatch, expected ${deviceId}, got ${asked}`);
54156
+ };
54157
+ return {
54158
+ isDetected: async ({ deviceId: asked }) => {
54159
+ ownDevice(asked);
54160
+ return readHubMotionDetected(deviceState, deviceId);
54161
+ },
54162
+ getStatus: async ({ deviceId: asked }) => {
54163
+ ownDevice(asked);
54164
+ return readHubMotionStatus(deviceState, deviceId);
54165
+ }
54166
+ };
54167
+ }
54103
54168
  MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
54104
54169
  function providerMotionEvent(source, data) {
54105
54170
  return createEvent(EventCategory.ProviderMotion, source, data);
@@ -56473,14 +56538,12 @@ var AmcrestCamera = class AmcrestCamera extends BaseDevice {
56473
56538
  }
56474
56539
  /** Register the native `motion` cap. Its mere presence (a `kind:'native'`
56475
56540
  * `motion` binding) is what the orchestrator reads to default a
56476
- * freshly-adopted camera to `motionSources:['onboard']`. `isDetected`
56477
- * answers from the HUB's slice; an unreadable hub, or a slice nobody has
56478
- * published yet, fails the call — never `false` for unknown (D49, D393). */
56541
+ * freshly-adopted camera to `motionSources:['onboard']`. `isDetected` and
56542
+ * `getStatus` answer from the HUB's slice (`hubMotionNativeProvider`); an
56543
+ * unreadable hub fails both — never `false` for unknown (D49, D393). */
56479
56544
  registerMotionCap() {
56480
- this.ctx.registerNativeCap(motionCapability, { isDetected: async ({ deviceId }) => {
56481
- if (deviceId !== this.id) throw new Error(`AmcrestCamera: motion deviceId mismatch, expected ${this.id}, got ${deviceId}`);
56482
- return readHubMotionDetected(this.ctx.api.deviceState, this.id);
56483
- } });
56545
+ const provider = hubMotionNativeProvider(this.ctx.api.deviceState, this.id, "AmcrestCamera");
56546
+ this.ctx.registerNativeCap(motionCapability, provider);
56484
56547
  this.ctx.logger.info("amcrest: motion cap registered", { tags: { deviceId: this.id } });
56485
56548
  }
56486
56549
  /** Reusable event-source identity for every emit on this device. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-amcrest",
3
- "version": "0.2.130",
3
+ "version": "0.2.131",
4
4
  "description": "Amcrest/Dahua camera device provider addon for CamStack — Dahua CGI over HTTP(S) with digest auth (snapshot, RTSP catalog, PTZ, image/day-night config)",
5
5
  "keywords": [
6
6
  "camstack",