@camstack/addon-provider-reolink 1.2.88 → 1.2.89

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 +108 -24
  2. package/dist/addon.mjs +108 -24
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -7592,7 +7592,8 @@ var CameraSwitchAuthoritySchema = discriminatedUnion("kind", [
7592
7592
  var CameraSwitchUnavailableReasonSchema = _enum([
7593
7593
  "no-provider",
7594
7594
  "source-unreachable",
7595
- "not-configured"
7595
+ "not-configured",
7596
+ "device-disabled"
7596
7597
  ]);
7597
7598
  /**
7598
7599
  * One switch, resolved for one camera.
@@ -24325,12 +24326,20 @@ var BatteryStatusSchema = object({
24325
24326
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
24326
24327
  * Reolink-specific for the Solar Panel 2 accessory (will become
24327
24328
  * common on other battery cams). `'none'` means running on battery
24328
- * alone.
24329
+ * alone — a NEGATIVE the firmware actually reported.
24330
+ *
24331
+ * `'unknown'` is the absence of an answer: the provider has not read the
24332
+ * power fields yet, or the firmware reported neither. Before it existed,
24333
+ * two unreadable fields produced `'none'`, and a camera nobody had reached
24334
+ * was drawn "on battery alone" — the same D315 defect `percentage` closed
24335
+ * by going nullable. Consumers SKIP it (no charger state published, no
24336
+ * glyph, no HomeKit ChargingState) rather than coerce it either way.
24329
24337
  */
24330
24338
  charging: _enum([
24331
24339
  "dc",
24332
24340
  "solar",
24333
- "none"
24341
+ "none",
24342
+ "unknown"
24334
24343
  ]),
24335
24344
  /**
24336
24345
  * True when the camera firmware has gone into low-power mode. Battery
@@ -24420,7 +24429,7 @@ onStatusChanged: { data: object({
24420
24429
  kind: "push",
24421
24430
  empty: {
24422
24431
  percentage: 0,
24423
- charging: "none",
24432
+ charging: "unknown",
24424
24433
  sleeping: false,
24425
24434
  lastUpdated: 0
24426
24435
  }
@@ -34128,8 +34137,17 @@ var BaseDeviceProvider = class extends BaseAddon {
34128
34137
  async onRestoreDevices(savedDevices) {
34129
34138
  const restored = /* @__PURE__ */ new Set();
34130
34139
  const failures = [];
34140
+ const liveStableIds = new Set((await this.ctx.kernel.devices.getAll()).map((device) => device.stableId));
34131
34141
  const attemptRestore = async (saved) => {
34132
34142
  if (restored.has(saved.id)) return;
34143
+ if (liveStableIds.has(saved.stableId)) {
34144
+ this.ctx.logger.debug("Restore row already live — not dialled again", { tags: {
34145
+ deviceId: saved.id,
34146
+ stableId: saved.stableId
34147
+ } });
34148
+ restored.add(saved.id);
34149
+ return;
34150
+ }
34133
34151
  const Class = this.deviceClasses[saved.type];
34134
34152
  if (!Class) throw new Error(`no device class registered for type "${saved.type}"`);
34135
34153
  if (saved.parentDeviceId !== null && !restored.has(saved.parentDeviceId)) throw new Error(`parent device ${saved.parentDeviceId} not restored`);
@@ -231801,13 +231819,15 @@ var reolinkDebugActions = defineCustomActions({ debugRawRead: customAction(RawRe
231801
231819
  * passato da `adapterStatus: 1` a `0`, con `chargeStatus: 0` da entrambe le
231802
231820
  * parti — cioè `chargeStatus` da solo NON distingue i due stati.
231803
231821
  *
231804
- * ⚠️ Questa funzione non sa ancora dire "non lo so": `BatteryStatus['charging']`
231805
- * non ha un valore `unknown`, quindi due campi illeggibili producono `'none'`,
231806
- * che è un valore NEGATIVO al posto di un non-noto. È il difetto D315 che
231807
- * `percentage` ha già chiuso (è `nullable`) e questo campo no; chiuderlo tocca
231808
- * `battery.cap.ts`, cioè la closure del server, e vive nel proprio lavoro.
231822
+ * Due campi assenti NON sono `'none'`: `'none'` è un negativo che il firmware
231823
+ * ha detto ("nessun adattatore, cella ferma"), l'assenza di entrambi è
231824
+ * `'unknown'` lo stesso confine che `percentage` ha chiuso diventando
231825
+ * `nullable` (D315). Il chiamante (`mapBatteryInfo`) non arriva qui con un
231826
+ * push che non parla di alimentazione: `reportsPowerSource` lo filtra prima e
231827
+ * conserva la convinzione precedente.
231809
231828
  */
231810
231829
  function deriveChargingSource(adapterStatus, chargeStatus) {
231830
+ if (adapterStatus === void 0 && chargeStatus === void 0) return "unknown";
231811
231831
  const adapter = (adapterStatus ?? "").toLowerCase();
231812
231832
  const charge = (chargeStatus ?? "").toLowerCase();
231813
231833
  if (adapter.includes("solar")) return "solar";
@@ -236946,7 +236966,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
236946
236966
  mapBatteryInfo(info) {
236947
236967
  return {
236948
236968
  percentage: typeof info.batteryPercent === "number" ? Math.max(0, Math.min(100, Math.round(info.batteryPercent))) : this.state.battery.percentage ?? null,
236949
- charging: reportsPowerSource(info) ? deriveChargingSource(info.adapterStatus, info.chargeStatus) : this.state.battery.charging ?? "none",
236969
+ charging: reportsPowerSource(info) ? deriveChargingSource(info.adapterStatus, info.chargeStatus) : this.state.battery.charging ?? "unknown",
236950
236970
  sleeping: info.sleeping === true || this.sleeping,
236951
236971
  lastUpdated: Date.now()
236952
236972
  };
@@ -243003,6 +243023,69 @@ function asDebugSocketFlags(value) {
243003
243023
  return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
243004
243024
  }
243005
243025
  //#endregion
243026
+ //#region src/hub-battery-fields.ts
243027
+ /**
243028
+ * The hub boundary for the per-channel battery power fields.
243029
+ *
243030
+ * The Reolink hub/NVR reports `chargeStatus` and `adapterStatus` as NUMBERS
243031
+ * (0/1/2); the standalone camera path reports the same facts as strings, and
243032
+ * `deriveChargingSource` (`battery-charging.ts`) speaks only the string
243033
+ * vocabulary. This module is the translation, and — the part that was
243034
+ * missing — it NAMES a code it cannot translate instead of dropping the field
243035
+ * silently. A dropped field reads as "the push said nothing about power", so
243036
+ * a new firmware value would have kept the previous belief forever, with not
243037
+ * one log line. The ledger lets the hub warn once per (device, field, code).
243038
+ */
243039
+ var CHARGE_STATUS_BY_CODE = {
243040
+ 0: "none",
243041
+ 1: "charging",
243042
+ 2: "chargeComplete"
243043
+ };
243044
+ var ADAPTER_STATUS_BY_CODE = {
243045
+ 0: "none",
243046
+ 1: "dc",
243047
+ 2: "solarPanel"
243048
+ };
243049
+ function mapOne(field, value, byCode) {
243050
+ if (value === void 0 || value === null) return {};
243051
+ if (typeof value === "string") return { mapped: value };
243052
+ if (typeof value === "number") {
243053
+ const mapped = byCode[value];
243054
+ if (mapped !== void 0) return { mapped };
243055
+ }
243056
+ return { unmapped: {
243057
+ field,
243058
+ value
243059
+ } };
243060
+ }
243061
+ /** Translate one channel's raw CGI power fields; never throws. */
243062
+ function mapHubBatteryPower(cgi) {
243063
+ const charge = mapOne("chargeStatus", cgi?.["chargeStatus"], CHARGE_STATUS_BY_CODE);
243064
+ const adapter = mapOne("adapterStatus", cgi?.["adapterStatus"], ADAPTER_STATUS_BY_CODE);
243065
+ return {
243066
+ fields: {
243067
+ ...charge.mapped !== void 0 ? { chargeStatus: charge.mapped } : {},
243068
+ ...adapter.mapped !== void 0 ? { adapterStatus: adapter.mapped } : {}
243069
+ },
243070
+ unmapped: [...charge.unmapped !== void 0 ? [charge.unmapped] : [], ...adapter.unmapped !== void 0 ? [adapter.unmapped] : []]
243071
+ };
243072
+ }
243073
+ /**
243074
+ * Remembers which (device, field, code) triples were already reported, so a
243075
+ * polled read warns once per finding and not once per tick. Unbounded only in
243076
+ * theory: the key space is a few cameras times two fields times the handful of
243077
+ * codes a firmware can invent.
243078
+ */
243079
+ var UnmappedCodeLedger = class {
243080
+ seen = /* @__PURE__ */ new Set();
243081
+ firstSeen(deviceId, field, value) {
243082
+ const key = `${deviceId}:${field}:${String(value)}`;
243083
+ if (this.seen.has(key)) return false;
243084
+ this.seen.add(key);
243085
+ return true;
243086
+ }
243087
+ };
243088
+ //#endregion
243006
243089
  //#region src/reolink-hub.ts
243007
243090
  var HUB_DISCOVERY_REFRESH_TIMEOUT_MS = 8e3;
243008
243091
  /**
@@ -243064,6 +243147,8 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
243064
243147
  /** One-shot: the raw per-channel battery payload is logged once per
243065
243148
  * process so the firmware's charge-field naming is on record. */
243066
243149
  batteryShapeLogged = false;
243150
+ /** Firmware power codes this hub could not translate — warned once each. */
243151
+ unmappedBatteryCodes = new UnmappedCodeLedger();
243067
243152
  /** Channels the last successful discovery refresh listed as present but
243068
243153
  * NOT adopted — their pushes are expected drops (debug), not faults. */
243069
243154
  knownUnadoptedChannels = /* @__PURE__ */ new Set();
@@ -243544,10 +243629,21 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
243544
243629
  const child = all.find((d) => d.id === deviceId);
243545
243630
  if (!(child instanceof ReolinkCamera)) continue;
243546
243631
  const cgi = info.entries[0];
243632
+ const power = mapHubBatteryPower(cgi);
243633
+ for (const { field, value } of power.unmapped) {
243634
+ if (!this.unmappedBatteryCodes.firstSeen(deviceId, field, value)) continue;
243635
+ this.ctx.logger.warn("Reolink Hub: unmapped battery power code — field dropped", {
243636
+ tags: { deviceId },
243637
+ meta: {
243638
+ channel: Number(chKey),
243639
+ field,
243640
+ value
243641
+ }
243642
+ });
243643
+ }
243547
243644
  child.applyHubBatteryInfo({
243548
243645
  batteryPercent: info.batteryLevel,
243549
- ...mapHubChargeStatus(cgi?.["chargeStatus"]) !== void 0 ? { chargeStatus: mapHubChargeStatus(cgi?.["chargeStatus"]) } : {},
243550
- ...mapHubAdapterStatus(cgi?.["adapterStatus"]) !== void 0 ? { adapterStatus: mapHubAdapterStatus(cgi?.["adapterStatus"]) } : {}
243646
+ ...power.fields
243551
243647
  });
243552
243648
  }
243553
243649
  } catch (err) {
@@ -243988,18 +244084,6 @@ function discoveredStatusFor(d) {
243988
244084
  * chargeStatus: 0 none · 1 charging · 2 charge complete
243989
244085
  * adapterStatus: 0 none · 1 DC adapter · 2 solar panel
243990
244086
  */
243991
- function mapHubChargeStatus(value) {
243992
- if (typeof value === "string") return value;
243993
- if (value === 0) return "none";
243994
- if (value === 1) return "charging";
243995
- if (value === 2) return "chargeComplete";
243996
- }
243997
- function mapHubAdapterStatus(value) {
243998
- if (typeof value === "string") return value;
243999
- if (value === 0) return "none";
244000
- if (value === 1) return "dc";
244001
- if (value === 2) return "solarPanel";
244002
- }
244003
244087
  //#endregion
244004
244088
  //#region src/creation-schema.ts
244005
244089
  /**
package/dist/addon.mjs CHANGED
@@ -7587,7 +7587,8 @@ var CameraSwitchAuthoritySchema = discriminatedUnion("kind", [
7587
7587
  var CameraSwitchUnavailableReasonSchema = _enum([
7588
7588
  "no-provider",
7589
7589
  "source-unreachable",
7590
- "not-configured"
7590
+ "not-configured",
7591
+ "device-disabled"
7591
7592
  ]);
7592
7593
  /**
7593
7594
  * One switch, resolved for one camera.
@@ -24320,12 +24321,20 @@ var BatteryStatusSchema = object({
24320
24321
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
24321
24322
  * Reolink-specific for the Solar Panel 2 accessory (will become
24322
24323
  * common on other battery cams). `'none'` means running on battery
24323
- * alone.
24324
+ * alone — a NEGATIVE the firmware actually reported.
24325
+ *
24326
+ * `'unknown'` is the absence of an answer: the provider has not read the
24327
+ * power fields yet, or the firmware reported neither. Before it existed,
24328
+ * two unreadable fields produced `'none'`, and a camera nobody had reached
24329
+ * was drawn "on battery alone" — the same D315 defect `percentage` closed
24330
+ * by going nullable. Consumers SKIP it (no charger state published, no
24331
+ * glyph, no HomeKit ChargingState) rather than coerce it either way.
24324
24332
  */
24325
24333
  charging: _enum([
24326
24334
  "dc",
24327
24335
  "solar",
24328
- "none"
24336
+ "none",
24337
+ "unknown"
24329
24338
  ]),
24330
24339
  /**
24331
24340
  * True when the camera firmware has gone into low-power mode. Battery
@@ -24415,7 +24424,7 @@ onStatusChanged: { data: object({
24415
24424
  kind: "push",
24416
24425
  empty: {
24417
24426
  percentage: 0,
24418
- charging: "none",
24427
+ charging: "unknown",
24419
24428
  sleeping: false,
24420
24429
  lastUpdated: 0
24421
24430
  }
@@ -34123,8 +34132,17 @@ var BaseDeviceProvider = class extends BaseAddon {
34123
34132
  async onRestoreDevices(savedDevices) {
34124
34133
  const restored = /* @__PURE__ */ new Set();
34125
34134
  const failures = [];
34135
+ const liveStableIds = new Set((await this.ctx.kernel.devices.getAll()).map((device) => device.stableId));
34126
34136
  const attemptRestore = async (saved) => {
34127
34137
  if (restored.has(saved.id)) return;
34138
+ if (liveStableIds.has(saved.stableId)) {
34139
+ this.ctx.logger.debug("Restore row already live — not dialled again", { tags: {
34140
+ deviceId: saved.id,
34141
+ stableId: saved.stableId
34142
+ } });
34143
+ restored.add(saved.id);
34144
+ return;
34145
+ }
34128
34146
  const Class = this.deviceClasses[saved.type];
34129
34147
  if (!Class) throw new Error(`no device class registered for type "${saved.type}"`);
34130
34148
  if (saved.parentDeviceId !== null && !restored.has(saved.parentDeviceId)) throw new Error(`parent device ${saved.parentDeviceId} not restored`);
@@ -231781,13 +231799,15 @@ var reolinkDebugActions = defineCustomActions({ debugRawRead: customAction(RawRe
231781
231799
  * passato da `adapterStatus: 1` a `0`, con `chargeStatus: 0` da entrambe le
231782
231800
  * parti — cioè `chargeStatus` da solo NON distingue i due stati.
231783
231801
  *
231784
- * ⚠️ Questa funzione non sa ancora dire "non lo so": `BatteryStatus['charging']`
231785
- * non ha un valore `unknown`, quindi due campi illeggibili producono `'none'`,
231786
- * che è un valore NEGATIVO al posto di un non-noto. È il difetto D315 che
231787
- * `percentage` ha già chiuso (è `nullable`) e questo campo no; chiuderlo tocca
231788
- * `battery.cap.ts`, cioè la closure del server, e vive nel proprio lavoro.
231802
+ * Due campi assenti NON sono `'none'`: `'none'` è un negativo che il firmware
231803
+ * ha detto ("nessun adattatore, cella ferma"), l'assenza di entrambi è
231804
+ * `'unknown'` lo stesso confine che `percentage` ha chiuso diventando
231805
+ * `nullable` (D315). Il chiamante (`mapBatteryInfo`) non arriva qui con un
231806
+ * push che non parla di alimentazione: `reportsPowerSource` lo filtra prima e
231807
+ * conserva la convinzione precedente.
231789
231808
  */
231790
231809
  function deriveChargingSource(adapterStatus, chargeStatus) {
231810
+ if (adapterStatus === void 0 && chargeStatus === void 0) return "unknown";
231791
231811
  const adapter = (adapterStatus ?? "").toLowerCase();
231792
231812
  const charge = (chargeStatus ?? "").toLowerCase();
231793
231813
  if (adapter.includes("solar")) return "solar";
@@ -236926,7 +236946,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
236926
236946
  mapBatteryInfo(info) {
236927
236947
  return {
236928
236948
  percentage: typeof info.batteryPercent === "number" ? Math.max(0, Math.min(100, Math.round(info.batteryPercent))) : this.state.battery.percentage ?? null,
236929
- charging: reportsPowerSource(info) ? deriveChargingSource(info.adapterStatus, info.chargeStatus) : this.state.battery.charging ?? "none",
236949
+ charging: reportsPowerSource(info) ? deriveChargingSource(info.adapterStatus, info.chargeStatus) : this.state.battery.charging ?? "unknown",
236930
236950
  sleeping: info.sleeping === true || this.sleeping,
236931
236951
  lastUpdated: Date.now()
236932
236952
  };
@@ -242983,6 +243003,69 @@ function asDebugSocketFlags(value) {
242983
243003
  return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
242984
243004
  }
242985
243005
  //#endregion
243006
+ //#region src/hub-battery-fields.ts
243007
+ /**
243008
+ * The hub boundary for the per-channel battery power fields.
243009
+ *
243010
+ * The Reolink hub/NVR reports `chargeStatus` and `adapterStatus` as NUMBERS
243011
+ * (0/1/2); the standalone camera path reports the same facts as strings, and
243012
+ * `deriveChargingSource` (`battery-charging.ts`) speaks only the string
243013
+ * vocabulary. This module is the translation, and — the part that was
243014
+ * missing — it NAMES a code it cannot translate instead of dropping the field
243015
+ * silently. A dropped field reads as "the push said nothing about power", so
243016
+ * a new firmware value would have kept the previous belief forever, with not
243017
+ * one log line. The ledger lets the hub warn once per (device, field, code).
243018
+ */
243019
+ var CHARGE_STATUS_BY_CODE = {
243020
+ 0: "none",
243021
+ 1: "charging",
243022
+ 2: "chargeComplete"
243023
+ };
243024
+ var ADAPTER_STATUS_BY_CODE = {
243025
+ 0: "none",
243026
+ 1: "dc",
243027
+ 2: "solarPanel"
243028
+ };
243029
+ function mapOne(field, value, byCode) {
243030
+ if (value === void 0 || value === null) return {};
243031
+ if (typeof value === "string") return { mapped: value };
243032
+ if (typeof value === "number") {
243033
+ const mapped = byCode[value];
243034
+ if (mapped !== void 0) return { mapped };
243035
+ }
243036
+ return { unmapped: {
243037
+ field,
243038
+ value
243039
+ } };
243040
+ }
243041
+ /** Translate one channel's raw CGI power fields; never throws. */
243042
+ function mapHubBatteryPower(cgi) {
243043
+ const charge = mapOne("chargeStatus", cgi?.["chargeStatus"], CHARGE_STATUS_BY_CODE);
243044
+ const adapter = mapOne("adapterStatus", cgi?.["adapterStatus"], ADAPTER_STATUS_BY_CODE);
243045
+ return {
243046
+ fields: {
243047
+ ...charge.mapped !== void 0 ? { chargeStatus: charge.mapped } : {},
243048
+ ...adapter.mapped !== void 0 ? { adapterStatus: adapter.mapped } : {}
243049
+ },
243050
+ unmapped: [...charge.unmapped !== void 0 ? [charge.unmapped] : [], ...adapter.unmapped !== void 0 ? [adapter.unmapped] : []]
243051
+ };
243052
+ }
243053
+ /**
243054
+ * Remembers which (device, field, code) triples were already reported, so a
243055
+ * polled read warns once per finding and not once per tick. Unbounded only in
243056
+ * theory: the key space is a few cameras times two fields times the handful of
243057
+ * codes a firmware can invent.
243058
+ */
243059
+ var UnmappedCodeLedger = class {
243060
+ seen = /* @__PURE__ */ new Set();
243061
+ firstSeen(deviceId, field, value) {
243062
+ const key = `${deviceId}:${field}:${String(value)}`;
243063
+ if (this.seen.has(key)) return false;
243064
+ this.seen.add(key);
243065
+ return true;
243066
+ }
243067
+ };
243068
+ //#endregion
242986
243069
  //#region src/reolink-hub.ts
242987
243070
  var HUB_DISCOVERY_REFRESH_TIMEOUT_MS = 8e3;
242988
243071
  /**
@@ -243044,6 +243127,8 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
243044
243127
  /** One-shot: the raw per-channel battery payload is logged once per
243045
243128
  * process so the firmware's charge-field naming is on record. */
243046
243129
  batteryShapeLogged = false;
243130
+ /** Firmware power codes this hub could not translate — warned once each. */
243131
+ unmappedBatteryCodes = new UnmappedCodeLedger();
243047
243132
  /** Channels the last successful discovery refresh listed as present but
243048
243133
  * NOT adopted — their pushes are expected drops (debug), not faults. */
243049
243134
  knownUnadoptedChannels = /* @__PURE__ */ new Set();
@@ -243524,10 +243609,21 @@ var ReolinkHub = class ReolinkHub extends BaseDevice {
243524
243609
  const child = all.find((d) => d.id === deviceId);
243525
243610
  if (!(child instanceof ReolinkCamera)) continue;
243526
243611
  const cgi = info.entries[0];
243612
+ const power = mapHubBatteryPower(cgi);
243613
+ for (const { field, value } of power.unmapped) {
243614
+ if (!this.unmappedBatteryCodes.firstSeen(deviceId, field, value)) continue;
243615
+ this.ctx.logger.warn("Reolink Hub: unmapped battery power code — field dropped", {
243616
+ tags: { deviceId },
243617
+ meta: {
243618
+ channel: Number(chKey),
243619
+ field,
243620
+ value
243621
+ }
243622
+ });
243623
+ }
243527
243624
  child.applyHubBatteryInfo({
243528
243625
  batteryPercent: info.batteryLevel,
243529
- ...mapHubChargeStatus(cgi?.["chargeStatus"]) !== void 0 ? { chargeStatus: mapHubChargeStatus(cgi?.["chargeStatus"]) } : {},
243530
- ...mapHubAdapterStatus(cgi?.["adapterStatus"]) !== void 0 ? { adapterStatus: mapHubAdapterStatus(cgi?.["adapterStatus"]) } : {}
243626
+ ...power.fields
243531
243627
  });
243532
243628
  }
243533
243629
  } catch (err) {
@@ -243968,18 +244064,6 @@ function discoveredStatusFor(d) {
243968
244064
  * chargeStatus: 0 none · 1 charging · 2 charge complete
243969
244065
  * adapterStatus: 0 none · 1 DC adapter · 2 solar panel
243970
244066
  */
243971
- function mapHubChargeStatus(value) {
243972
- if (typeof value === "string") return value;
243973
- if (value === 0) return "none";
243974
- if (value === 1) return "charging";
243975
- if (value === 2) return "chargeComplete";
243976
- }
243977
- function mapHubAdapterStatus(value) {
243978
- if (typeof value === "string") return value;
243979
- if (value === 0) return "none";
243980
- if (value === 1) return "dc";
243981
- if (value === 2) return "solarPanel";
243982
- }
243983
244067
  //#endregion
243984
244068
  //#region src/creation-schema.ts
243985
244069
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-reolink",
3
- "version": "1.2.88",
3
+ "version": "1.2.89",
4
4
  "description": "Reolink camera device provider addon for CamStack — native Baichuan protocol",
5
5
  "keywords": [
6
6
  "camstack",