@camstack/addon-provider-reolink 1.2.126 → 1.2.127

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.
package/dist/addon.js CHANGED
@@ -22078,6 +22078,14 @@ var MotionSourceEnum = _enum([
22078
22078
  */
22079
22079
  var MotionSourcesSchema = array(MotionSourceEnum);
22080
22080
  /**
22081
+ * Which root detectors a camera runs. Deliberately the SAME vocabulary
22082
+ * post-analysis already tags every detection with (`DetectionSource`) rather
22083
+ * than a second spelling of the same two ideas — the value an operator picks
22084
+ * here is the value that comes back on the track, the overlay and the debug
22085
+ * row.
22086
+ */
22087
+ var DetectionSourcesSchema = array(DetectionSourceSchema);
22088
+ /**
22081
22089
  * Input shape for `pipeline-runner.reportMotion` cap method. Exported
22082
22090
  * so cap-side consumers (the orchestrator forward, the runner addon's
22083
22091
  * cap implementation, tests) can reuse the type instead of redeclaring
@@ -22228,6 +22236,35 @@ var RunnerCameraConfigSchema = object({
22228
22236
  * events; the orchestrator forwards to `reportMotion`.
22229
22237
  */
22230
22238
  motionSources: MotionSourcesSchema.default(["analyzer"]),
22239
+ /**
22240
+ * WHICH root detector runs for this camera. The detection counterpart of
22241
+ * {@link motionSources}, same shape and same discipline: a per-camera list
22242
+ * of sources the system understands, vendor-agnostic, owned here.
22243
+ *
22244
+ * - `pipeline` — this runner's own root step on decoded pixels (`steps`).
22245
+ * - `onboard` — the CAMERA's own detector, admitted only when it is named
22246
+ * here. Its boxes reach post-analysis on the same
22247
+ * `PipelineInferenceResult` payload as the pipeline's, so an onboard-born
22248
+ * track gets the same tracker, the same overlay and the same detail
22249
+ * subtree (face / plate / embedding).
22250
+ *
22251
+ * `['onboard']` alone is the REPLACEMENT: this runner's root step does not
22252
+ * run, and that is where a camera with a usable onboard detector buys back
22253
+ * its share of the accelerator. It saves the root inference, not the decode
22254
+ * — the detail subtree still needs pixels to cut crops from.
22255
+ *
22256
+ * A camera whose onboard detections carry no geometry cannot serve as a root
22257
+ * step at all (there is nothing to track), and the cap that knows this says
22258
+ * so on `native-object-detection.getOptions().geometry`. On Reolink that is
22259
+ * every battery camera: the boxes ride a sub-stream a battery camera never
22260
+ * attaches, so such a camera stays on `['pipeline']` and its onboard AI is
22261
+ * worth exactly what it already is — a wake signal with a class.
22262
+ *
22263
+ * Defaults to `['pipeline']`, which is byte-for-byte today's behaviour: a
22264
+ * vendor never turns a detector on for the operator, and neither does a
22265
+ * default.
22266
+ */
22267
+ detectionSources: DetectionSourcesSchema.default(["pipeline"]),
22231
22268
  pipelineEnabled: boolean().default(true),
22232
22269
  /** Ordered tree of video steps. Absent → runner skips video detection. */
22233
22270
  steps: array(PipelineStepInputSchema).readonly().optional(),
@@ -29344,31 +29381,38 @@ var NativeObjectDetectionStatusSchema = object({
29344
29381
  /**
29345
29382
  * Whether forwarding of onboard AI detections is enabled for this device.
29346
29383
  *
29347
- * The COLD-START default is the provider's, and it is not one value for
29348
- * every camera: a mains camera carries the boxed side-channel and its
29349
- * detections are usable subjects, so it defaults ON; a battery camera never
29350
- * attaches that channel, so the same toggle would buy it nothing but a write
29351
- * it defaults OFF and an operator who wants it turns it on knowing what it
29352
- * costs. {@link NativeObjectDetectionOptionsSchema.geometry} is how the UI
29353
- * says which of the two a camera is.
29384
+ * Cold-start OFF on every camera. A vendor does not decide which detector a
29385
+ * camera runs that is the operator's choice, and it is made where every
29386
+ * other detection choice is made. `geometry` on
29387
+ * {@link NativeObjectDetectionOptionsSchema} is how the form says what the
29388
+ * choice would buy this particular camera.
29354
29389
  */
29355
29390
  enabled: boolean()
29356
29391
  });
29357
29392
  /**
29358
- * What a camera's onboard detections actually CARRY.
29393
+ * WHEN a camera's onboard detections carry geometry.
29359
29394
  *
29360
- * `boxed` — the firmware ships a bounding box with the class, so a detection is
29361
- * a subject the pipeline can track, crop and score.
29362
- * `flag-only` — the firmware ships the class and nothing else. The pipeline
29363
- * needs geometry to make a subject out of it, so such a push reaches the
29364
- * tracker as motion and no further. On Reolink this is every battery camera:
29365
- * the boxes ride the BcMedia sub-stream, which a battery camera never attaches.
29395
+ * - `boxed` — always. The provider holds a standing channel for the boxes, so
29396
+ * a detection is a trackable subject whenever the camera sees one.
29397
+ * - `while-streaming` — only while some stream of this camera is already open.
29398
+ * The boxes ride the video's own side-channel rather than a feed of their
29399
+ * own, so they cost nothing and they exist only when something is pulling.
29400
+ * On Reolink this is every BATTERY camera: a persistent second feed is real
29401
+ * radio drain, but a camera that is awake is awake precisely because
29402
+ * something is in front of it, and its stream is already being pulled.
29403
+ * - `flag-only` — never. The firmware ships the class and nothing else; the
29404
+ * pipeline needs geometry to make a subject, so such a push reaches the
29405
+ * tracker as motion and no further.
29366
29406
  *
29367
29407
  * Reported and not inferred, because the operator's question in front of the
29368
- * toggle is "what do I get", and "a class with no box" and "a subject" are
29369
- * different answers (D14: the derived form is only as honest as `getOptions`).
29408
+ * picker is "what do I get", and these are three different answers (D14: the
29409
+ * derived form is only as honest as `getOptions`).
29370
29410
  */
29371
- var NativeObjectGeometryEnum = _enum(["boxed", "flag-only"]);
29411
+ var NativeObjectGeometryEnum = _enum([
29412
+ "boxed",
29413
+ "while-streaming",
29414
+ "flag-only"
29415
+ ]);
29372
29416
  var NativeObjectDetectionOptionsSchema = object({
29373
29417
  /** Classes this firmware can detect — the same list the status reports. */
29374
29418
  supportedClasses: array(NativeObjectClassEnum).readonly(),
@@ -29385,11 +29429,6 @@ var nativeObjectDetectionCapability = {
29385
29429
  deviceNative: true,
29386
29430
  mode: "singleton",
29387
29431
  deviceTypes: [DeviceType.Camera],
29388
- deviceConfig: { ui: {
29389
- kind: "derived-form",
29390
- builderId: "native-object-detection",
29391
- tab: "motion"
29392
- } },
29393
29432
  methods: {
29394
29433
  getOptions: method(object({ deviceId: number() }), NativeObjectDetectionOptionsSchema),
29395
29434
  setSettings: method(object({
@@ -152481,10 +152520,8 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
152481
152520
  * yet (e.g. fresh device, no config cached).
152482
152521
  * - `lastByClass`: updated in `handleSimpleEvent` every time an AI-class
152483
152522
  * event fires, regardless of the `enabled` flag.
152484
- * - `enabled`: operator toggle. Cold-start default is the camera's power
152485
- * source ON for a mains camera (its detections carry boxes and become
152486
- * subjects), OFF for a battery one (no boxed side-channel, so the toggle
152487
- * would buy it nothing). See `buildEmptyState`.
152523
+ * - `enabled`: operator toggle, cold-start OFF on every camera. A vendor
152524
+ * never turns a detector on for the operator; see `buildEmptyState`.
152488
152525
  *
152489
152526
  * Follows the trampoline pattern from `registerStreamParamsCap` — no
152490
152527
  * parallel private fields; all state lives in the kernel runtimeState
@@ -152512,7 +152549,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
152512
152549
  const CAP_NAME = "native-object-detection";
152513
152550
  const buildSupportedClasses = () => buildSupportedNativeClasses(this.config.get("deviceCache")?.aiDetectTypes, isNativeObjectClass).filter(isNativeObjectClass);
152514
152551
  const buildEmptyState = () => ({
152515
- enabled: !this.isBattery,
152552
+ enabled: false,
152516
152553
  lastByClass: {},
152517
152554
  supportedClasses: buildSupportedClasses(),
152518
152555
  lastFetchedAt: 0
@@ -152544,7 +152581,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
152544
152581
  };
152545
152582
  return {
152546
152583
  supportedClasses: buildSupportedClasses(),
152547
- geometry: this.isBattery ? "flag-only" : "boxed"
152584
+ geometry: this.isBattery ? "while-streaming" : "boxed"
152548
152585
  };
152549
152586
  },
152550
152587
  setSettings: async ({ deviceId, settings }) => {
@@ -154185,14 +154222,22 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
154185
154222
  });
154186
154223
  } catch {}
154187
154224
  this.objectDetectionsSubscribed = false;
154188
- if (this.isBattery) {
154189
- this.ctx.logger.debug("Reolink objectDetections subscribe skipped — battery cam", { meta: { reason } });
154190
- return;
154191
- }
154192
154225
  if (!isNativeObjectForwardingEnabled(this.runtimeState.getCapState("native-object-detection"))) {
154193
154226
  this.ctx.logger.debug("Reolink objectDetections subscribe skipped — cap disabled", { meta: { reason } });
154194
154227
  return;
154195
154228
  }
154229
+ if (this.isBattery) {
154230
+ api.onDetection(this.handleObjectDetectionsBound);
154231
+ this.objectDetectionsSubscribed = true;
154232
+ this.ctx.logger.info("Reolink onboard boxes ride the open stream (battery cam)", {
154233
+ tags: { deviceId: this.id },
154234
+ meta: {
154235
+ reason,
154236
+ channel
154237
+ }
154238
+ });
154239
+ return;
154240
+ }
154196
154241
  if (!api.client.isSocketConnected() || !api.client.loggedIn) {
154197
154242
  this.ctx.logger.debug("Reolink objectDetections subscribe skipped — socket not ready", { meta: {
154198
154243
  reason,
@@ -154218,6 +154263,11 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
154218
154263
  */
154219
154264
  async unsubscribeObjectDetections(api) {
154220
154265
  if (!this.objectDetectionsSubscribed) return;
154266
+ if (this.isBattery) {
154267
+ api.offDetection(this.handleObjectDetectionsBound);
154268
+ this.objectDetectionsSubscribed = false;
154269
+ return;
154270
+ }
154221
154271
  try {
154222
154272
  await api.offObjectDetections(this.handleObjectDetectionsBound, {
154223
154273
  channel: this.getChannel(),
@@ -154247,6 +154297,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
154247
154297
  */
154248
154298
  handleObjectDetections(event) {
154249
154299
  if (!isNativeObjectForwardingEnabled(this.runtimeState.getCapState("native-object-detection"))) return;
154300
+ if (event.channel !== this.getChannel()) return;
154250
154301
  if (event.boxes.length === 0) return;
154251
154302
  const now = Date.now();
154252
154303
  const payload = mapDetectionEvent(event, this.id, now);
package/dist/addon.mjs CHANGED
@@ -22073,6 +22073,14 @@ var MotionSourceEnum = _enum([
22073
22073
  */
22074
22074
  var MotionSourcesSchema = array(MotionSourceEnum);
22075
22075
  /**
22076
+ * Which root detectors a camera runs. Deliberately the SAME vocabulary
22077
+ * post-analysis already tags every detection with (`DetectionSource`) rather
22078
+ * than a second spelling of the same two ideas — the value an operator picks
22079
+ * here is the value that comes back on the track, the overlay and the debug
22080
+ * row.
22081
+ */
22082
+ var DetectionSourcesSchema = array(DetectionSourceSchema);
22083
+ /**
22076
22084
  * Input shape for `pipeline-runner.reportMotion` cap method. Exported
22077
22085
  * so cap-side consumers (the orchestrator forward, the runner addon's
22078
22086
  * cap implementation, tests) can reuse the type instead of redeclaring
@@ -22223,6 +22231,35 @@ var RunnerCameraConfigSchema = object({
22223
22231
  * events; the orchestrator forwards to `reportMotion`.
22224
22232
  */
22225
22233
  motionSources: MotionSourcesSchema.default(["analyzer"]),
22234
+ /**
22235
+ * WHICH root detector runs for this camera. The detection counterpart of
22236
+ * {@link motionSources}, same shape and same discipline: a per-camera list
22237
+ * of sources the system understands, vendor-agnostic, owned here.
22238
+ *
22239
+ * - `pipeline` — this runner's own root step on decoded pixels (`steps`).
22240
+ * - `onboard` — the CAMERA's own detector, admitted only when it is named
22241
+ * here. Its boxes reach post-analysis on the same
22242
+ * `PipelineInferenceResult` payload as the pipeline's, so an onboard-born
22243
+ * track gets the same tracker, the same overlay and the same detail
22244
+ * subtree (face / plate / embedding).
22245
+ *
22246
+ * `['onboard']` alone is the REPLACEMENT: this runner's root step does not
22247
+ * run, and that is where a camera with a usable onboard detector buys back
22248
+ * its share of the accelerator. It saves the root inference, not the decode
22249
+ * — the detail subtree still needs pixels to cut crops from.
22250
+ *
22251
+ * A camera whose onboard detections carry no geometry cannot serve as a root
22252
+ * step at all (there is nothing to track), and the cap that knows this says
22253
+ * so on `native-object-detection.getOptions().geometry`. On Reolink that is
22254
+ * every battery camera: the boxes ride a sub-stream a battery camera never
22255
+ * attaches, so such a camera stays on `['pipeline']` and its onboard AI is
22256
+ * worth exactly what it already is — a wake signal with a class.
22257
+ *
22258
+ * Defaults to `['pipeline']`, which is byte-for-byte today's behaviour: a
22259
+ * vendor never turns a detector on for the operator, and neither does a
22260
+ * default.
22261
+ */
22262
+ detectionSources: DetectionSourcesSchema.default(["pipeline"]),
22226
22263
  pipelineEnabled: boolean().default(true),
22227
22264
  /** Ordered tree of video steps. Absent → runner skips video detection. */
22228
22265
  steps: array(PipelineStepInputSchema).readonly().optional(),
@@ -29339,31 +29376,38 @@ var NativeObjectDetectionStatusSchema = object({
29339
29376
  /**
29340
29377
  * Whether forwarding of onboard AI detections is enabled for this device.
29341
29378
  *
29342
- * The COLD-START default is the provider's, and it is not one value for
29343
- * every camera: a mains camera carries the boxed side-channel and its
29344
- * detections are usable subjects, so it defaults ON; a battery camera never
29345
- * attaches that channel, so the same toggle would buy it nothing but a write
29346
- * it defaults OFF and an operator who wants it turns it on knowing what it
29347
- * costs. {@link NativeObjectDetectionOptionsSchema.geometry} is how the UI
29348
- * says which of the two a camera is.
29379
+ * Cold-start OFF on every camera. A vendor does not decide which detector a
29380
+ * camera runs that is the operator's choice, and it is made where every
29381
+ * other detection choice is made. `geometry` on
29382
+ * {@link NativeObjectDetectionOptionsSchema} is how the form says what the
29383
+ * choice would buy this particular camera.
29349
29384
  */
29350
29385
  enabled: boolean()
29351
29386
  });
29352
29387
  /**
29353
- * What a camera's onboard detections actually CARRY.
29388
+ * WHEN a camera's onboard detections carry geometry.
29354
29389
  *
29355
- * `boxed` — the firmware ships a bounding box with the class, so a detection is
29356
- * a subject the pipeline can track, crop and score.
29357
- * `flag-only` — the firmware ships the class and nothing else. The pipeline
29358
- * needs geometry to make a subject out of it, so such a push reaches the
29359
- * tracker as motion and no further. On Reolink this is every battery camera:
29360
- * the boxes ride the BcMedia sub-stream, which a battery camera never attaches.
29390
+ * - `boxed` — always. The provider holds a standing channel for the boxes, so
29391
+ * a detection is a trackable subject whenever the camera sees one.
29392
+ * - `while-streaming` — only while some stream of this camera is already open.
29393
+ * The boxes ride the video's own side-channel rather than a feed of their
29394
+ * own, so they cost nothing and they exist only when something is pulling.
29395
+ * On Reolink this is every BATTERY camera: a persistent second feed is real
29396
+ * radio drain, but a camera that is awake is awake precisely because
29397
+ * something is in front of it, and its stream is already being pulled.
29398
+ * - `flag-only` — never. The firmware ships the class and nothing else; the
29399
+ * pipeline needs geometry to make a subject, so such a push reaches the
29400
+ * tracker as motion and no further.
29361
29401
  *
29362
29402
  * Reported and not inferred, because the operator's question in front of the
29363
- * toggle is "what do I get", and "a class with no box" and "a subject" are
29364
- * different answers (D14: the derived form is only as honest as `getOptions`).
29403
+ * picker is "what do I get", and these are three different answers (D14: the
29404
+ * derived form is only as honest as `getOptions`).
29365
29405
  */
29366
- var NativeObjectGeometryEnum = _enum(["boxed", "flag-only"]);
29406
+ var NativeObjectGeometryEnum = _enum([
29407
+ "boxed",
29408
+ "while-streaming",
29409
+ "flag-only"
29410
+ ]);
29367
29411
  var NativeObjectDetectionOptionsSchema = object({
29368
29412
  /** Classes this firmware can detect — the same list the status reports. */
29369
29413
  supportedClasses: array(NativeObjectClassEnum).readonly(),
@@ -29380,11 +29424,6 @@ var nativeObjectDetectionCapability = {
29380
29424
  deviceNative: true,
29381
29425
  mode: "singleton",
29382
29426
  deviceTypes: [DeviceType.Camera],
29383
- deviceConfig: { ui: {
29384
- kind: "derived-form",
29385
- builderId: "native-object-detection",
29386
- tab: "motion"
29387
- } },
29388
29427
  methods: {
29389
29428
  getOptions: method(object({ deviceId: number() }), NativeObjectDetectionOptionsSchema),
29390
29429
  setSettings: method(object({
@@ -152476,10 +152515,8 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
152476
152515
  * yet (e.g. fresh device, no config cached).
152477
152516
  * - `lastByClass`: updated in `handleSimpleEvent` every time an AI-class
152478
152517
  * event fires, regardless of the `enabled` flag.
152479
- * - `enabled`: operator toggle. Cold-start default is the camera's power
152480
- * source ON for a mains camera (its detections carry boxes and become
152481
- * subjects), OFF for a battery one (no boxed side-channel, so the toggle
152482
- * would buy it nothing). See `buildEmptyState`.
152518
+ * - `enabled`: operator toggle, cold-start OFF on every camera. A vendor
152519
+ * never turns a detector on for the operator; see `buildEmptyState`.
152483
152520
  *
152484
152521
  * Follows the trampoline pattern from `registerStreamParamsCap` — no
152485
152522
  * parallel private fields; all state lives in the kernel runtimeState
@@ -152507,7 +152544,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
152507
152544
  const CAP_NAME = "native-object-detection";
152508
152545
  const buildSupportedClasses = () => buildSupportedNativeClasses(this.config.get("deviceCache")?.aiDetectTypes, isNativeObjectClass).filter(isNativeObjectClass);
152509
152546
  const buildEmptyState = () => ({
152510
- enabled: !this.isBattery,
152547
+ enabled: false,
152511
152548
  lastByClass: {},
152512
152549
  supportedClasses: buildSupportedClasses(),
152513
152550
  lastFetchedAt: 0
@@ -152539,7 +152576,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
152539
152576
  };
152540
152577
  return {
152541
152578
  supportedClasses: buildSupportedClasses(),
152542
- geometry: this.isBattery ? "flag-only" : "boxed"
152579
+ geometry: this.isBattery ? "while-streaming" : "boxed"
152543
152580
  };
152544
152581
  },
152545
152582
  setSettings: async ({ deviceId, settings }) => {
@@ -154180,14 +154217,22 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
154180
154217
  });
154181
154218
  } catch {}
154182
154219
  this.objectDetectionsSubscribed = false;
154183
- if (this.isBattery) {
154184
- this.ctx.logger.debug("Reolink objectDetections subscribe skipped — battery cam", { meta: { reason } });
154185
- return;
154186
- }
154187
154220
  if (!isNativeObjectForwardingEnabled(this.runtimeState.getCapState("native-object-detection"))) {
154188
154221
  this.ctx.logger.debug("Reolink objectDetections subscribe skipped — cap disabled", { meta: { reason } });
154189
154222
  return;
154190
154223
  }
154224
+ if (this.isBattery) {
154225
+ api.onDetection(this.handleObjectDetectionsBound);
154226
+ this.objectDetectionsSubscribed = true;
154227
+ this.ctx.logger.info("Reolink onboard boxes ride the open stream (battery cam)", {
154228
+ tags: { deviceId: this.id },
154229
+ meta: {
154230
+ reason,
154231
+ channel
154232
+ }
154233
+ });
154234
+ return;
154235
+ }
154191
154236
  if (!api.client.isSocketConnected() || !api.client.loggedIn) {
154192
154237
  this.ctx.logger.debug("Reolink objectDetections subscribe skipped — socket not ready", { meta: {
154193
154238
  reason,
@@ -154213,6 +154258,11 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
154213
154258
  */
154214
154259
  async unsubscribeObjectDetections(api) {
154215
154260
  if (!this.objectDetectionsSubscribed) return;
154261
+ if (this.isBattery) {
154262
+ api.offDetection(this.handleObjectDetectionsBound);
154263
+ this.objectDetectionsSubscribed = false;
154264
+ return;
154265
+ }
154216
154266
  try {
154217
154267
  await api.offObjectDetections(this.handleObjectDetectionsBound, {
154218
154268
  channel: this.getChannel(),
@@ -154242,6 +154292,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
154242
154292
  */
154243
154293
  handleObjectDetections(event) {
154244
154294
  if (!isNativeObjectForwardingEnabled(this.runtimeState.getCapState("native-object-detection"))) return;
154295
+ if (event.channel !== this.getChannel()) return;
154245
154296
  if (event.boxes.length === 0) return;
154246
154297
  const now = Date.now();
154247
154298
  const payload = mapDetectionEvent(event, this.id, now);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-reolink",
3
- "version": "1.2.126",
3
+ "version": "1.2.127",
4
4
  "description": "Reolink camera device provider addon for CamStack — native Baichuan protocol",
5
5
  "keywords": [
6
6
  "camstack",