@camstack/addon-provider-tuya 0.2.64 → 0.2.66

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
@@ -8373,7 +8373,8 @@ var CameraSwitchAuthoritySchema = discriminatedUnion("kind", [
8373
8373
  var CameraSwitchUnavailableReasonSchema = _enum([
8374
8374
  "no-provider",
8375
8375
  "source-unreachable",
8376
- "not-configured"
8376
+ "not-configured",
8377
+ "device-disabled"
8377
8378
  ]);
8378
8379
  /**
8379
8380
  * One switch, resolved for one camera.
@@ -13880,7 +13881,12 @@ var ConfigEntrySchema = object({
13880
13881
  value: unknown(),
13881
13882
  description: string().optional()
13882
13883
  });
13883
- var LinkedDevicesModeSchema = _enum(["auto", "manual"]);
13884
+ /**
13885
+ * Only `manual` since D356: the operator picks, nothing links itself. The
13886
+ * field survives on the wire because a viewer already OTA'd parses it —
13887
+ * drop it once no shipped client reads `mode`.
13888
+ */
13889
+ var LinkedDevicesModeSchema = _enum(["manual"]);
13884
13890
  /** One resolved linked device — the compact projection consumers need. */
13885
13891
  var LinkedDeviceSchema = object({
13886
13892
  deviceId: number(),
@@ -24408,12 +24414,20 @@ var BatteryStatusSchema = object({
24408
24414
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
24409
24415
  * Reolink-specific for the Solar Panel 2 accessory (will become
24410
24416
  * common on other battery cams). `'none'` means running on battery
24411
- * alone.
24417
+ * alone — a NEGATIVE the firmware actually reported.
24418
+ *
24419
+ * `'unknown'` is the absence of an answer: the provider has not read the
24420
+ * power fields yet, or the firmware reported neither. Before it existed,
24421
+ * two unreadable fields produced `'none'`, and a camera nobody had reached
24422
+ * was drawn "on battery alone" — the same D315 defect `percentage` closed
24423
+ * by going nullable. Consumers SKIP it (no charger state published, no
24424
+ * glyph, no HomeKit ChargingState) rather than coerce it either way.
24412
24425
  */
24413
24426
  charging: _enum([
24414
24427
  "dc",
24415
24428
  "solar",
24416
- "none"
24429
+ "none",
24430
+ "unknown"
24417
24431
  ]),
24418
24432
  /**
24419
24433
  * True when the camera firmware has gone into low-power mode. Battery
@@ -24503,7 +24517,7 @@ onStatusChanged: { data: object({
24503
24517
  kind: "push",
24504
24518
  empty: {
24505
24519
  percentage: 0,
24506
- charging: "none",
24520
+ charging: "unknown",
24507
24521
  sleeping: false,
24508
24522
  lastUpdated: 0
24509
24523
  }
@@ -33919,8 +33933,17 @@ var BaseDeviceProvider = class extends BaseAddon {
33919
33933
  async onRestoreDevices(savedDevices) {
33920
33934
  const restored = /* @__PURE__ */ new Set();
33921
33935
  const failures = [];
33936
+ const liveStableIds = new Set((await this.ctx.kernel.devices.getAll()).map((device) => device.stableId));
33922
33937
  const attemptRestore = async (saved) => {
33923
33938
  if (restored.has(saved.id)) return;
33939
+ if (liveStableIds.has(saved.stableId)) {
33940
+ this.ctx.logger.debug("Restore row already live — not dialled again", { tags: {
33941
+ deviceId: saved.id,
33942
+ stableId: saved.stableId
33943
+ } });
33944
+ restored.add(saved.id);
33945
+ return;
33946
+ }
33924
33947
  const Class = this.deviceClasses[saved.type];
33925
33948
  if (!Class) throw new Error(`no device class registered for type "${saved.type}"`);
33926
33949
  if (saved.parentDeviceId !== null && !restored.has(saved.parentDeviceId)) throw new Error(`parent device ${saved.parentDeviceId} not restored`);
package/dist/addon.mjs CHANGED
@@ -8372,7 +8372,8 @@ var CameraSwitchAuthoritySchema = discriminatedUnion("kind", [
8372
8372
  var CameraSwitchUnavailableReasonSchema = _enum([
8373
8373
  "no-provider",
8374
8374
  "source-unreachable",
8375
- "not-configured"
8375
+ "not-configured",
8376
+ "device-disabled"
8376
8377
  ]);
8377
8378
  /**
8378
8379
  * One switch, resolved for one camera.
@@ -13879,7 +13880,12 @@ var ConfigEntrySchema = object({
13879
13880
  value: unknown(),
13880
13881
  description: string().optional()
13881
13882
  });
13882
- var LinkedDevicesModeSchema = _enum(["auto", "manual"]);
13883
+ /**
13884
+ * Only `manual` since D356: the operator picks, nothing links itself. The
13885
+ * field survives on the wire because a viewer already OTA'd parses it —
13886
+ * drop it once no shipped client reads `mode`.
13887
+ */
13888
+ var LinkedDevicesModeSchema = _enum(["manual"]);
13883
13889
  /** One resolved linked device — the compact projection consumers need. */
13884
13890
  var LinkedDeviceSchema = object({
13885
13891
  deviceId: number(),
@@ -24407,12 +24413,20 @@ var BatteryStatusSchema = object({
24407
24413
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
24408
24414
  * Reolink-specific for the Solar Panel 2 accessory (will become
24409
24415
  * common on other battery cams). `'none'` means running on battery
24410
- * alone.
24416
+ * alone — a NEGATIVE the firmware actually reported.
24417
+ *
24418
+ * `'unknown'` is the absence of an answer: the provider has not read the
24419
+ * power fields yet, or the firmware reported neither. Before it existed,
24420
+ * two unreadable fields produced `'none'`, and a camera nobody had reached
24421
+ * was drawn "on battery alone" — the same D315 defect `percentage` closed
24422
+ * by going nullable. Consumers SKIP it (no charger state published, no
24423
+ * glyph, no HomeKit ChargingState) rather than coerce it either way.
24411
24424
  */
24412
24425
  charging: _enum([
24413
24426
  "dc",
24414
24427
  "solar",
24415
- "none"
24428
+ "none",
24429
+ "unknown"
24416
24430
  ]),
24417
24431
  /**
24418
24432
  * True when the camera firmware has gone into low-power mode. Battery
@@ -24502,7 +24516,7 @@ onStatusChanged: { data: object({
24502
24516
  kind: "push",
24503
24517
  empty: {
24504
24518
  percentage: 0,
24505
- charging: "none",
24519
+ charging: "unknown",
24506
24520
  sleeping: false,
24507
24521
  lastUpdated: 0
24508
24522
  }
@@ -33918,8 +33932,17 @@ var BaseDeviceProvider = class extends BaseAddon {
33918
33932
  async onRestoreDevices(savedDevices) {
33919
33933
  const restored = /* @__PURE__ */ new Set();
33920
33934
  const failures = [];
33935
+ const liveStableIds = new Set((await this.ctx.kernel.devices.getAll()).map((device) => device.stableId));
33921
33936
  const attemptRestore = async (saved) => {
33922
33937
  if (restored.has(saved.id)) return;
33938
+ if (liveStableIds.has(saved.stableId)) {
33939
+ this.ctx.logger.debug("Restore row already live — not dialled again", { tags: {
33940
+ deviceId: saved.id,
33941
+ stableId: saved.stableId
33942
+ } });
33943
+ restored.add(saved.id);
33944
+ return;
33945
+ }
33923
33946
  const Class = this.deviceClasses[saved.type];
33924
33947
  if (!Class) throw new Error(`no device class registered for type "${saved.type}"`);
33925
33948
  if (saved.parentDeviceId !== null && !restored.has(saved.parentDeviceId)) throw new Error(`parent device ${saved.parentDeviceId} not restored`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-tuya",
3
- "version": "0.2.64",
3
+ "version": "0.2.66",
4
4
  "description": "Tuya / Smart Life device-provider addon for CamStack — account-onboarded (Tuya IoT cloud fetch of device localKeys) + LOCAL DP control via the @apocaliss92/nodetuya encrypted-LAN client, exposing switch / water-heater-family kettle entities",
5
5
  "keywords": [
6
6
  "camstack",