@camstack/addon-provider-reolink 1.2.175 → 1.2.176

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 +136 -49
  2. package/dist/addon.mjs +136 -49
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -11101,6 +11101,57 @@ var ClipSearchStrictnessSchema = _enum([
11101
11101
  "balanced",
11102
11102
  "strict"
11103
11103
  ]);
11104
+ new Set([
11105
+ {
11106
+ id: "person",
11107
+ name: "Person"
11108
+ },
11109
+ {
11110
+ id: "vehicle",
11111
+ name: "Vehicle"
11112
+ },
11113
+ {
11114
+ id: "animal",
11115
+ name: "Animal"
11116
+ },
11117
+ {
11118
+ id: "package",
11119
+ name: "Package"
11120
+ }
11121
+ ].map((l) => l.id));
11122
+ var COCO_TO_MACRO = {
11123
+ mapping: {
11124
+ person: "person",
11125
+ bicycle: "vehicle",
11126
+ car: "vehicle",
11127
+ motorcycle: "vehicle",
11128
+ airplane: "vehicle",
11129
+ bus: "vehicle",
11130
+ train: "vehicle",
11131
+ truck: "vehicle",
11132
+ boat: "vehicle",
11133
+ bird: "animal",
11134
+ cat: "animal",
11135
+ dog: "animal",
11136
+ horse: "animal",
11137
+ sheep: "animal",
11138
+ cow: "animal",
11139
+ elephant: "animal",
11140
+ bear: "animal",
11141
+ zebra: "animal",
11142
+ giraffe: "animal",
11143
+ suitcase: "package",
11144
+ backpack: "package",
11145
+ handbag: "package"
11146
+ },
11147
+ preserveOriginal: false
11148
+ };
11149
+ /** Steps a root detector may declare it fills. */
11150
+ var FILLABLE_STEP_IDS = [
11151
+ "animal-classifier",
11152
+ "vehicle-classifier",
11153
+ "package-detection"
11154
+ ];
11104
11155
  var MODEL_FORMATS = [
11105
11156
  "onnx",
11106
11157
  "coreml",
@@ -11233,6 +11284,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
11233
11284
  /** True when the weights or their data forbid commercial use. */
11234
11285
  nonCommercial: boolean().optional()
11235
11286
  }));
11287
+ /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
11288
+ var FillsClassifierEffectSchema = object({
11289
+ stepId: _enum(FILLABLE_STEP_IDS),
11290
+ labelToEffect: record(string(), string()),
11291
+ uncovered: array(string()).readonly()
11292
+ });
11236
11293
  var ModelCatalogEntrySchema = object({
11237
11294
  id: string(),
11238
11295
  name: string(),
@@ -11359,6 +11416,16 @@ var ModelCatalogEntrySchema = object({
11359
11416
  */
11360
11417
  classMap: DetectionCatalogClassMapSchema.optional(),
11361
11418
  /**
11419
+ * The pipeline steps this ROOT detector already does the work of (D715):
11420
+ * its labels name the effect the step exists to produce (`deer` for
11421
+ * `animal-classifier`, `package` for `package-detection`). Derived from the
11422
+ * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
11423
+ * declares none. Whether a declaration is honoured is the step's own
11424
+ * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
11425
+ * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
11426
+ */
11427
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
11428
+ /**
11362
11429
  * The model's CLIP feature-space contract (text encoder, dimension, vector
11363
11430
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
11364
11431
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -18722,51 +18789,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
18722
18789
  kind: "mutation",
18723
18790
  auth: "admin"
18724
18791
  });
18725
- new Set([
18726
- {
18727
- id: "person",
18728
- name: "Person"
18729
- },
18730
- {
18731
- id: "vehicle",
18732
- name: "Vehicle"
18733
- },
18734
- {
18735
- id: "animal",
18736
- name: "Animal"
18737
- },
18738
- {
18739
- id: "package",
18740
- name: "Package"
18741
- }
18742
- ].map((l) => l.id));
18743
- var COCO_TO_MACRO = {
18744
- mapping: {
18745
- person: "person",
18746
- bicycle: "vehicle",
18747
- car: "vehicle",
18748
- motorcycle: "vehicle",
18749
- airplane: "vehicle",
18750
- bus: "vehicle",
18751
- train: "vehicle",
18752
- truck: "vehicle",
18753
- boat: "vehicle",
18754
- bird: "animal",
18755
- cat: "animal",
18756
- dog: "animal",
18757
- horse: "animal",
18758
- sheep: "animal",
18759
- cow: "animal",
18760
- elephant: "animal",
18761
- bear: "animal",
18762
- zebra: "animal",
18763
- giraffe: "animal",
18764
- suitcase: "package",
18765
- backpack: "package",
18766
- handbag: "package"
18767
- },
18768
- preserveOriginal: false
18769
- };
18770
18792
  var AUDIO_MACRO_LABELS = [
18771
18793
  {
18772
18794
  id: "speech",
@@ -24208,7 +24230,8 @@ var PipelineModelOptionSchema = object({
24208
24230
  group: ModelVariantGroupSchema.optional(),
24209
24231
  legacy: boolean().optional(),
24210
24232
  provider: ModelProviderIdSchema.optional(),
24211
- defaultConfidence: number().optional()
24233
+ defaultConfidence: number().optional(),
24234
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
24212
24235
  });
24213
24236
  var ConfigFieldBridge = custom();
24214
24237
  var PipelineAddonSchemaSchema = object({
@@ -166310,6 +166333,37 @@ function buildSyntheticRfc4571Sdp(input) {
166310
166333
  function buildLazyRfc4571Url(camStreamId) {
166311
166334
  return `lazy:rfc4571:${encodeURIComponent(camStreamId)}`;
166312
166335
  }
166336
+ function createMotionSensorTracker(now = Date.now) {
166337
+ const latest = /* @__PURE__ */ new Map();
166338
+ return {
166339
+ observe(event) {
166340
+ if (event.type !== "motion") return;
166341
+ const sensor = event.motion.source;
166342
+ if (sensor === void 0) return;
166343
+ latest.set(event.channel, {
166344
+ sensor,
166345
+ at: now()
166346
+ });
166347
+ },
166348
+ take(channel) {
166349
+ const entry = latest.get(channel);
166350
+ if (!entry) return null;
166351
+ latest.delete(channel);
166352
+ return now() - entry.at <= 2e3 ? entry.sensor : null;
166353
+ }
166354
+ };
166355
+ }
166356
+ var isMotionSensor = (value) => value === "md" || value === "pir" || value === "unknown";
166357
+ /**
166358
+ * The sensor a simple event states itself, for a library version that forwards
166359
+ * `motion.source` on the simple event; `null` for the versions that do not.
166360
+ */
166361
+ function motionSensorOnSimpleEvent(event) {
166362
+ if (!("motion" in event)) return null;
166363
+ const motion = event.motion;
166364
+ if (typeof motion !== "object" || motion === null || !("source" in motion)) return null;
166365
+ return isMotionSensor(motion.source) ? motion.source : null;
166366
+ }
166313
166367
  //#endregion
166314
166368
  //#region src/reolink-camera.ts
166315
166369
  /**
@@ -166616,6 +166670,16 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
166616
166670
  this.handleSimpleEvent(event);
166617
166671
  };
166618
166672
  /**
166673
+ * MD vs PIR of this camera's own motion pushes. The lib's simple event drops
166674
+ * it, so the raw client `event` is observed — PREPENDED, so the sensor is
166675
+ * recorded before the API maps the same emit into the simple event
166676
+ * (`motion-sensor-source.ts`). Hub children get theirs from the hub.
166677
+ */
166678
+ motionSensors = createMotionSensorTracker();
166679
+ observeRawEventBound = (event) => {
166680
+ this.motionSensors.observe(event);
166681
+ };
166682
+ /**
166619
166683
  * Stable bound handler for `api.onObjectDetections` — created ONCE so
166620
166684
  * every `onObjectDetections` / `offObjectDetections` call uses the
166621
166685
  * SAME function reference (same listener-Set dedup rationale as
@@ -172017,6 +172081,11 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
172017
172081
  this.ctx.logger.debug("Reolink event watchdog re-subscribe failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
172018
172082
  }
172019
172083
  }
172084
+ /** Off-then-prepend, so a re-attached api never carries two observers. */
172085
+ observeMotionSensors(api) {
172086
+ api.client.off("event", this.observeRawEventBound);
172087
+ api.client.prependListener("event", this.observeRawEventBound);
172088
+ }
172020
172089
  /**
172021
172090
  * Subscribe (or re-subscribe) `handleSimpleEventBound` against
172022
172091
  * the Baichuan API. Single-source-of-truth for the listener
@@ -173611,6 +173680,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
173611
173680
  adoptApi(api) {
173612
173681
  this.api = api;
173613
173682
  this.reconnectAttempts = 0;
173683
+ this.observeMotionSensors(api);
173614
173684
  api.client.on("close", () => this.scheduleReconnect("close"));
173615
173685
  api.client.on("error", (err) => {
173616
173686
  this.ctx.logger.warn("Baichuan client error — scheduling reconnect", {
@@ -173758,6 +173828,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
173758
173828
  meta: { error: err instanceof Error ? err.message : String(err) }
173759
173829
  });
173760
173830
  });
173831
+ this.observeMotionSensors(api);
173761
173832
  api.client.on("close", () => this.scheduleReconnect("close"));
173762
173833
  api.client.on("error", (err) => {
173763
173834
  this.ctx.logger.warn("Baichuan client error — scheduling reconnect", {
@@ -173827,8 +173898,9 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
173827
173898
  * when the camera lives under a Hub and inherits the parent's
173828
173899
  * single subscription.
173829
173900
  */
173830
- handleSimpleEvent(event) {
173901
+ handleSimpleEvent(event, routedMotionSensor = null) {
173831
173902
  this.lastEventAt = Date.now();
173903
+ const motionSensor = event.type === "motion" ? motionSensorOnSimpleEvent(event) ?? routedMotionSensor ?? this.motionSensors.take(event.channel) : null;
173832
173904
  this.consecutiveStaleHealthChecks = 0;
173833
173905
  this.nextEventHealthCheckAt = 0;
173834
173906
  this.markPassiveContact();
@@ -173847,7 +173919,8 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
173847
173919
  type: event.type,
173848
173920
  channel: event.channel,
173849
173921
  timestamp: event.timestamp,
173850
- source: event.source
173922
+ source: event.source,
173923
+ ...event.type === "motion" ? { motionSensor } : {}
173851
173924
  } });
173852
173925
  if (event.type === "motion") {
173853
173926
  const now = Date.now();
@@ -174406,6 +174479,17 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
174406
174479
  handleSimpleEventBound = (ev) => {
174407
174480
  this.routeSimpleEvent(ev);
174408
174481
  };
174482
+ /** MD vs PIR per channel, read off the raw client event the lib's simple
174483
+ * event drops (`motion-sensor-source.ts`) and handed to the child. */
174484
+ motionSensors = createMotionSensorTracker();
174485
+ observeRawEventBound = (ev) => {
174486
+ this.motionSensors.observe(ev);
174487
+ };
174488
+ /** Off-then-prepend: recorded before the API maps the same emit. */
174489
+ observeMotionSensors(api) {
174490
+ api.client.off("event", this.observeRawEventBound);
174491
+ api.client.prependListener("event", this.observeRawEventBound);
174492
+ }
174409
174493
  constructor(ctx) {
174410
174494
  super(ctx, reolinkHubSchema, { type: DeviceType.Hub });
174411
174495
  this.registerDeviceDiscovery();
@@ -175169,6 +175253,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
175169
175253
  routeSimpleEvent(ev) {
175170
175254
  const channel = ev?.channel;
175171
175255
  if (typeof channel !== "number") return;
175256
+ const motionSensor = ev.type === "motion" ? this.motionSensors.take(channel) : null;
175172
175257
  const deviceId = this.channelToDeviceId.get(channel);
175173
175258
  if (deviceId === void 0) {
175174
175259
  const last = this.unroutedChannelLoggedAt.get(channel) ?? 0;
@@ -175198,7 +175283,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
175198
175283
  deviceId: child.id,
175199
175284
  name: child.name
175200
175285
  } });
175201
- child.handleSimpleEvent(ev);
175286
+ child.handleSimpleEvent(ev, motionSensor);
175202
175287
  }).catch((err) => {
175203
175288
  this.ctx.logger.debug("Hub simpleEvent dispatch failed", { meta: {
175204
175289
  channel,
@@ -175242,6 +175327,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
175242
175327
  try {
175243
175328
  await api.offSimpleEvent(this.handleSimpleEventBound);
175244
175329
  } catch {}
175330
+ this.observeMotionSensors(api);
175245
175331
  await api.onSimpleEvent(this.handleSimpleEventBound);
175246
175332
  api.client.on("close", () => this.scheduleReconnect("socket-close"));
175247
175333
  api.client.on("error", (err) => {
@@ -175300,6 +175386,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
175300
175386
  this.api = api;
175301
175387
  this.reconnectAttempts = 0;
175302
175388
  this.markOnline(true);
175389
+ this.observeMotionSensors(api);
175303
175390
  api.client.on("close", () => this.scheduleReconnect("socket-close"));
175304
175391
  api.client.on("error", (err) => {
175305
175392
  this.ctx.logger.warn("Reolink Hub adopted socket error", { meta: { error: err instanceof Error ? err.message : String(err) } });
package/dist/addon.mjs CHANGED
@@ -11093,6 +11093,57 @@ var ClipSearchStrictnessSchema = _enum([
11093
11093
  "balanced",
11094
11094
  "strict"
11095
11095
  ]);
11096
+ new Set([
11097
+ {
11098
+ id: "person",
11099
+ name: "Person"
11100
+ },
11101
+ {
11102
+ id: "vehicle",
11103
+ name: "Vehicle"
11104
+ },
11105
+ {
11106
+ id: "animal",
11107
+ name: "Animal"
11108
+ },
11109
+ {
11110
+ id: "package",
11111
+ name: "Package"
11112
+ }
11113
+ ].map((l) => l.id));
11114
+ var COCO_TO_MACRO = {
11115
+ mapping: {
11116
+ person: "person",
11117
+ bicycle: "vehicle",
11118
+ car: "vehicle",
11119
+ motorcycle: "vehicle",
11120
+ airplane: "vehicle",
11121
+ bus: "vehicle",
11122
+ train: "vehicle",
11123
+ truck: "vehicle",
11124
+ boat: "vehicle",
11125
+ bird: "animal",
11126
+ cat: "animal",
11127
+ dog: "animal",
11128
+ horse: "animal",
11129
+ sheep: "animal",
11130
+ cow: "animal",
11131
+ elephant: "animal",
11132
+ bear: "animal",
11133
+ zebra: "animal",
11134
+ giraffe: "animal",
11135
+ suitcase: "package",
11136
+ backpack: "package",
11137
+ handbag: "package"
11138
+ },
11139
+ preserveOriginal: false
11140
+ };
11141
+ /** Steps a root detector may declare it fills. */
11142
+ var FILLABLE_STEP_IDS = [
11143
+ "animal-classifier",
11144
+ "vehicle-classifier",
11145
+ "package-detection"
11146
+ ];
11096
11147
  var MODEL_FORMATS = [
11097
11148
  "onnx",
11098
11149
  "coreml",
@@ -11225,6 +11276,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
11225
11276
  /** True when the weights or their data forbid commercial use. */
11226
11277
  nonCommercial: boolean().optional()
11227
11278
  }));
11279
+ /** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
11280
+ var FillsClassifierEffectSchema = object({
11281
+ stepId: _enum(FILLABLE_STEP_IDS),
11282
+ labelToEffect: record(string(), string()),
11283
+ uncovered: array(string()).readonly()
11284
+ });
11228
11285
  var ModelCatalogEntrySchema = object({
11229
11286
  id: string(),
11230
11287
  name: string(),
@@ -11351,6 +11408,16 @@ var ModelCatalogEntrySchema = object({
11351
11408
  */
11352
11409
  classMap: DetectionCatalogClassMapSchema.optional(),
11353
11410
  /**
11411
+ * The pipeline steps this ROOT detector already does the work of (D715):
11412
+ * its labels name the effect the step exists to produce (`deer` for
11413
+ * `animal-classifier`, `package` for `package-detection`). Derived from the
11414
+ * labelmap by `deriveClassifierFills`, never hand-written; a COCO model
11415
+ * declares none. Whether a declaration is honoured is the step's own
11416
+ * `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
11417
+ * `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
11418
+ */
11419
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
11420
+ /**
11354
11421
  * The model's CLIP feature-space contract (text encoder, dimension, vector
11355
11422
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
11356
11423
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -18714,51 +18781,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
18714
18781
  kind: "mutation",
18715
18782
  auth: "admin"
18716
18783
  });
18717
- new Set([
18718
- {
18719
- id: "person",
18720
- name: "Person"
18721
- },
18722
- {
18723
- id: "vehicle",
18724
- name: "Vehicle"
18725
- },
18726
- {
18727
- id: "animal",
18728
- name: "Animal"
18729
- },
18730
- {
18731
- id: "package",
18732
- name: "Package"
18733
- }
18734
- ].map((l) => l.id));
18735
- var COCO_TO_MACRO = {
18736
- mapping: {
18737
- person: "person",
18738
- bicycle: "vehicle",
18739
- car: "vehicle",
18740
- motorcycle: "vehicle",
18741
- airplane: "vehicle",
18742
- bus: "vehicle",
18743
- train: "vehicle",
18744
- truck: "vehicle",
18745
- boat: "vehicle",
18746
- bird: "animal",
18747
- cat: "animal",
18748
- dog: "animal",
18749
- horse: "animal",
18750
- sheep: "animal",
18751
- cow: "animal",
18752
- elephant: "animal",
18753
- bear: "animal",
18754
- zebra: "animal",
18755
- giraffe: "animal",
18756
- suitcase: "package",
18757
- backpack: "package",
18758
- handbag: "package"
18759
- },
18760
- preserveOriginal: false
18761
- };
18762
18784
  var AUDIO_MACRO_LABELS = [
18763
18785
  {
18764
18786
  id: "speech",
@@ -24200,7 +24222,8 @@ var PipelineModelOptionSchema = object({
24200
24222
  group: ModelVariantGroupSchema.optional(),
24201
24223
  legacy: boolean().optional(),
24202
24224
  provider: ModelProviderIdSchema.optional(),
24203
- defaultConfidence: number().optional()
24225
+ defaultConfidence: number().optional(),
24226
+ fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
24204
24227
  });
24205
24228
  var ConfigFieldBridge = custom();
24206
24229
  var PipelineAddonSchemaSchema = object({
@@ -166302,6 +166325,37 @@ function buildSyntheticRfc4571Sdp(input) {
166302
166325
  function buildLazyRfc4571Url(camStreamId) {
166303
166326
  return `lazy:rfc4571:${encodeURIComponent(camStreamId)}`;
166304
166327
  }
166328
+ function createMotionSensorTracker(now = Date.now) {
166329
+ const latest = /* @__PURE__ */ new Map();
166330
+ return {
166331
+ observe(event) {
166332
+ if (event.type !== "motion") return;
166333
+ const sensor = event.motion.source;
166334
+ if (sensor === void 0) return;
166335
+ latest.set(event.channel, {
166336
+ sensor,
166337
+ at: now()
166338
+ });
166339
+ },
166340
+ take(channel) {
166341
+ const entry = latest.get(channel);
166342
+ if (!entry) return null;
166343
+ latest.delete(channel);
166344
+ return now() - entry.at <= 2e3 ? entry.sensor : null;
166345
+ }
166346
+ };
166347
+ }
166348
+ var isMotionSensor = (value) => value === "md" || value === "pir" || value === "unknown";
166349
+ /**
166350
+ * The sensor a simple event states itself, for a library version that forwards
166351
+ * `motion.source` on the simple event; `null` for the versions that do not.
166352
+ */
166353
+ function motionSensorOnSimpleEvent(event) {
166354
+ if (!("motion" in event)) return null;
166355
+ const motion = event.motion;
166356
+ if (typeof motion !== "object" || motion === null || !("source" in motion)) return null;
166357
+ return isMotionSensor(motion.source) ? motion.source : null;
166358
+ }
166305
166359
  //#endregion
166306
166360
  //#region src/reolink-camera.ts
166307
166361
  /**
@@ -166608,6 +166662,16 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
166608
166662
  this.handleSimpleEvent(event);
166609
166663
  };
166610
166664
  /**
166665
+ * MD vs PIR of this camera's own motion pushes. The lib's simple event drops
166666
+ * it, so the raw client `event` is observed — PREPENDED, so the sensor is
166667
+ * recorded before the API maps the same emit into the simple event
166668
+ * (`motion-sensor-source.ts`). Hub children get theirs from the hub.
166669
+ */
166670
+ motionSensors = createMotionSensorTracker();
166671
+ observeRawEventBound = (event) => {
166672
+ this.motionSensors.observe(event);
166673
+ };
166674
+ /**
166611
166675
  * Stable bound handler for `api.onObjectDetections` — created ONCE so
166612
166676
  * every `onObjectDetections` / `offObjectDetections` call uses the
166613
166677
  * SAME function reference (same listener-Set dedup rationale as
@@ -172009,6 +172073,11 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
172009
172073
  this.ctx.logger.debug("Reolink event watchdog re-subscribe failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
172010
172074
  }
172011
172075
  }
172076
+ /** Off-then-prepend, so a re-attached api never carries two observers. */
172077
+ observeMotionSensors(api) {
172078
+ api.client.off("event", this.observeRawEventBound);
172079
+ api.client.prependListener("event", this.observeRawEventBound);
172080
+ }
172012
172081
  /**
172013
172082
  * Subscribe (or re-subscribe) `handleSimpleEventBound` against
172014
172083
  * the Baichuan API. Single-source-of-truth for the listener
@@ -173603,6 +173672,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
173603
173672
  adoptApi(api) {
173604
173673
  this.api = api;
173605
173674
  this.reconnectAttempts = 0;
173675
+ this.observeMotionSensors(api);
173606
173676
  api.client.on("close", () => this.scheduleReconnect("close"));
173607
173677
  api.client.on("error", (err) => {
173608
173678
  this.ctx.logger.warn("Baichuan client error — scheduling reconnect", {
@@ -173750,6 +173820,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
173750
173820
  meta: { error: err instanceof Error ? err.message : String(err) }
173751
173821
  });
173752
173822
  });
173823
+ this.observeMotionSensors(api);
173753
173824
  api.client.on("close", () => this.scheduleReconnect("close"));
173754
173825
  api.client.on("error", (err) => {
173755
173826
  this.ctx.logger.warn("Baichuan client error — scheduling reconnect", {
@@ -173819,8 +173890,9 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
173819
173890
  * when the camera lives under a Hub and inherits the parent's
173820
173891
  * single subscription.
173821
173892
  */
173822
- handleSimpleEvent(event) {
173893
+ handleSimpleEvent(event, routedMotionSensor = null) {
173823
173894
  this.lastEventAt = Date.now();
173895
+ const motionSensor = event.type === "motion" ? motionSensorOnSimpleEvent(event) ?? routedMotionSensor ?? this.motionSensors.take(event.channel) : null;
173824
173896
  this.consecutiveStaleHealthChecks = 0;
173825
173897
  this.nextEventHealthCheckAt = 0;
173826
173898
  this.markPassiveContact();
@@ -173839,7 +173911,8 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
173839
173911
  type: event.type,
173840
173912
  channel: event.channel,
173841
173913
  timestamp: event.timestamp,
173842
- source: event.source
173914
+ source: event.source,
173915
+ ...event.type === "motion" ? { motionSensor } : {}
173843
173916
  } });
173844
173917
  if (event.type === "motion") {
173845
173918
  const now = Date.now();
@@ -174398,6 +174471,17 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
174398
174471
  handleSimpleEventBound = (ev) => {
174399
174472
  this.routeSimpleEvent(ev);
174400
174473
  };
174474
+ /** MD vs PIR per channel, read off the raw client event the lib's simple
174475
+ * event drops (`motion-sensor-source.ts`) and handed to the child. */
174476
+ motionSensors = createMotionSensorTracker();
174477
+ observeRawEventBound = (ev) => {
174478
+ this.motionSensors.observe(ev);
174479
+ };
174480
+ /** Off-then-prepend: recorded before the API maps the same emit. */
174481
+ observeMotionSensors(api) {
174482
+ api.client.off("event", this.observeRawEventBound);
174483
+ api.client.prependListener("event", this.observeRawEventBound);
174484
+ }
174401
174485
  constructor(ctx) {
174402
174486
  super(ctx, reolinkHubSchema, { type: DeviceType.Hub });
174403
174487
  this.registerDeviceDiscovery();
@@ -175161,6 +175245,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
175161
175245
  routeSimpleEvent(ev) {
175162
175246
  const channel = ev?.channel;
175163
175247
  if (typeof channel !== "number") return;
175248
+ const motionSensor = ev.type === "motion" ? this.motionSensors.take(channel) : null;
175164
175249
  const deviceId = this.channelToDeviceId.get(channel);
175165
175250
  if (deviceId === void 0) {
175166
175251
  const last = this.unroutedChannelLoggedAt.get(channel) ?? 0;
@@ -175190,7 +175275,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
175190
175275
  deviceId: child.id,
175191
175276
  name: child.name
175192
175277
  } });
175193
- child.handleSimpleEvent(ev);
175278
+ child.handleSimpleEvent(ev, motionSensor);
175194
175279
  }).catch((err) => {
175195
175280
  this.ctx.logger.debug("Hub simpleEvent dispatch failed", { meta: {
175196
175281
  channel,
@@ -175234,6 +175319,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
175234
175319
  try {
175235
175320
  await api.offSimpleEvent(this.handleSimpleEventBound);
175236
175321
  } catch {}
175322
+ this.observeMotionSensors(api);
175237
175323
  await api.onSimpleEvent(this.handleSimpleEventBound);
175238
175324
  api.client.on("close", () => this.scheduleReconnect("socket-close"));
175239
175325
  api.client.on("error", (err) => {
@@ -175292,6 +175378,7 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
175292
175378
  this.api = api;
175293
175379
  this.reconnectAttempts = 0;
175294
175380
  this.markOnline(true);
175381
+ this.observeMotionSensors(api);
175295
175382
  api.client.on("close", () => this.scheduleReconnect("socket-close"));
175296
175383
  api.client.on("error", (err) => {
175297
175384
  this.ctx.logger.warn("Reolink Hub adopted socket error", { meta: { error: err instanceof Error ? err.message : String(err) } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-reolink",
3
- "version": "1.2.175",
3
+ "version": "1.2.176",
4
4
  "description": "Reolink camera device provider addon for CamStack — native Baichuan protocol",
5
5
  "keywords": [
6
6
  "camstack",