@camstack/addon-provider-tuya 0.2.60 → 0.2.61
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 +37 -1
- package/dist/addon.mjs +37 -1
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -13593,7 +13593,26 @@ var DiscoveryCandidateSchema = object({
|
|
|
13593
13593
|
* identity ahead of adoption. Rendering metadata (unit, precision)
|
|
13594
13594
|
* flows live through the cap STATUS SLICE after adoption.
|
|
13595
13595
|
*/
|
|
13596
|
-
sourceInfo: SourceInfoSchema.optional()
|
|
13596
|
+
sourceInfo: SourceInfoSchema.optional(),
|
|
13597
|
+
/**
|
|
13598
|
+
* Set when this candidate is a device the provider ALREADY owns.
|
|
13599
|
+
*
|
|
13600
|
+
* A scan cannot generally produce the identity a device was onboarded under
|
|
13601
|
+
* (Reolink keys on `mac-<mac>`, learned at adopt time), so a stableId
|
|
13602
|
+
* comparison never matches and an owned device looks addable. Re-adopting one
|
|
13603
|
+
* overwrites its config with scan-derived values — that is how a Home Hub's
|
|
13604
|
+
* Baichuan port was overwritten with its ONVIF port, taking the hub and its
|
|
13605
|
+
* three child cameras offline for four hours.
|
|
13606
|
+
*
|
|
13607
|
+
* A provider that can recognise its own devices says so here. Absent means
|
|
13608
|
+
* "not recognised", which is not the same as "known to be new" — a provider
|
|
13609
|
+
* that cannot tell simply never sets it.
|
|
13610
|
+
*/
|
|
13611
|
+
alreadyOnboarded: boolean().optional(),
|
|
13612
|
+
/** Numeric id of the device this candidate was matched to. Set with `alreadyOnboarded`. */
|
|
13613
|
+
onboardedDeviceId: number().optional(),
|
|
13614
|
+
/** Operator-facing name of the matched device, so the UI can say WHICH one it is. */
|
|
13615
|
+
onboardedName: string().optional()
|
|
13597
13616
|
});
|
|
13598
13617
|
/**
|
|
13599
13618
|
* Flat device summary returned by `createDevice` / `adoptDiscoveredDevice`.
|
|
@@ -33839,6 +33858,22 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
33839
33858
|
* failed — logged at ERROR with `tags.deviceId` and surfaced via
|
|
33840
33859
|
* `getStatus().error`.
|
|
33841
33860
|
*/
|
|
33861
|
+
/**
|
|
33862
|
+
* Repair a row's PERSISTED config blob immediately before it is restored.
|
|
33863
|
+
* Default: no-op — most providers have nothing to heal.
|
|
33864
|
+
*
|
|
33865
|
+
* This exists because a restored device self-hydrates from the DB: `create()`
|
|
33866
|
+
* passes `{}` and `BaseDevice` parses the stored blob against the device
|
|
33867
|
+
* schema. A blob that lost a REQUIRED field therefore fails restore forever,
|
|
33868
|
+
* and no later pass revisits it — a hub-adopted Reolink camera whose blob had
|
|
33869
|
+
* been emptied failed all four bounded attempts against fields
|
|
33870
|
+
* (`host`, `password`) it inherits from its parent and never dials itself.
|
|
33871
|
+
*
|
|
33872
|
+
* Implementations get every saved row, so a child can read its parent's blob.
|
|
33873
|
+
* A heal that throws is treated like any other restore failure: retried under
|
|
33874
|
+
* the bound, then reported — never swallowed.
|
|
33875
|
+
*/
|
|
33876
|
+
async healSavedConfig(_saved, _allSaved) {}
|
|
33842
33877
|
async onRestoreDevices(savedDevices) {
|
|
33843
33878
|
const restored = /* @__PURE__ */ new Set();
|
|
33844
33879
|
const failures = [];
|
|
@@ -33847,6 +33882,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
33847
33882
|
const Class = this.deviceClasses[saved.type];
|
|
33848
33883
|
if (!Class) throw new Error(`no device class registered for type "${saved.type}"`);
|
|
33849
33884
|
if (saved.parentDeviceId !== null && !restored.has(saved.parentDeviceId)) throw new Error(`parent device ${saved.parentDeviceId} not restored`);
|
|
33885
|
+
await this.healSavedConfig(saved, savedDevices);
|
|
33850
33886
|
await this.ctx.kernel.devices.create(saved.stableId, Class, {}, saved.parentDeviceId);
|
|
33851
33887
|
restored.add(saved.id);
|
|
33852
33888
|
};
|
package/dist/addon.mjs
CHANGED
|
@@ -13592,7 +13592,26 @@ var DiscoveryCandidateSchema = object({
|
|
|
13592
13592
|
* identity ahead of adoption. Rendering metadata (unit, precision)
|
|
13593
13593
|
* flows live through the cap STATUS SLICE after adoption.
|
|
13594
13594
|
*/
|
|
13595
|
-
sourceInfo: SourceInfoSchema.optional()
|
|
13595
|
+
sourceInfo: SourceInfoSchema.optional(),
|
|
13596
|
+
/**
|
|
13597
|
+
* Set when this candidate is a device the provider ALREADY owns.
|
|
13598
|
+
*
|
|
13599
|
+
* A scan cannot generally produce the identity a device was onboarded under
|
|
13600
|
+
* (Reolink keys on `mac-<mac>`, learned at adopt time), so a stableId
|
|
13601
|
+
* comparison never matches and an owned device looks addable. Re-adopting one
|
|
13602
|
+
* overwrites its config with scan-derived values — that is how a Home Hub's
|
|
13603
|
+
* Baichuan port was overwritten with its ONVIF port, taking the hub and its
|
|
13604
|
+
* three child cameras offline for four hours.
|
|
13605
|
+
*
|
|
13606
|
+
* A provider that can recognise its own devices says so here. Absent means
|
|
13607
|
+
* "not recognised", which is not the same as "known to be new" — a provider
|
|
13608
|
+
* that cannot tell simply never sets it.
|
|
13609
|
+
*/
|
|
13610
|
+
alreadyOnboarded: boolean().optional(),
|
|
13611
|
+
/** Numeric id of the device this candidate was matched to. Set with `alreadyOnboarded`. */
|
|
13612
|
+
onboardedDeviceId: number().optional(),
|
|
13613
|
+
/** Operator-facing name of the matched device, so the UI can say WHICH one it is. */
|
|
13614
|
+
onboardedName: string().optional()
|
|
13596
13615
|
});
|
|
13597
13616
|
/**
|
|
13598
13617
|
* Flat device summary returned by `createDevice` / `adoptDiscoveredDevice`.
|
|
@@ -33838,6 +33857,22 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
33838
33857
|
* failed — logged at ERROR with `tags.deviceId` and surfaced via
|
|
33839
33858
|
* `getStatus().error`.
|
|
33840
33859
|
*/
|
|
33860
|
+
/**
|
|
33861
|
+
* Repair a row's PERSISTED config blob immediately before it is restored.
|
|
33862
|
+
* Default: no-op — most providers have nothing to heal.
|
|
33863
|
+
*
|
|
33864
|
+
* This exists because a restored device self-hydrates from the DB: `create()`
|
|
33865
|
+
* passes `{}` and `BaseDevice` parses the stored blob against the device
|
|
33866
|
+
* schema. A blob that lost a REQUIRED field therefore fails restore forever,
|
|
33867
|
+
* and no later pass revisits it — a hub-adopted Reolink camera whose blob had
|
|
33868
|
+
* been emptied failed all four bounded attempts against fields
|
|
33869
|
+
* (`host`, `password`) it inherits from its parent and never dials itself.
|
|
33870
|
+
*
|
|
33871
|
+
* Implementations get every saved row, so a child can read its parent's blob.
|
|
33872
|
+
* A heal that throws is treated like any other restore failure: retried under
|
|
33873
|
+
* the bound, then reported — never swallowed.
|
|
33874
|
+
*/
|
|
33875
|
+
async healSavedConfig(_saved, _allSaved) {}
|
|
33841
33876
|
async onRestoreDevices(savedDevices) {
|
|
33842
33877
|
const restored = /* @__PURE__ */ new Set();
|
|
33843
33878
|
const failures = [];
|
|
@@ -33846,6 +33881,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
33846
33881
|
const Class = this.deviceClasses[saved.type];
|
|
33847
33882
|
if (!Class) throw new Error(`no device class registered for type "${saved.type}"`);
|
|
33848
33883
|
if (saved.parentDeviceId !== null && !restored.has(saved.parentDeviceId)) throw new Error(`parent device ${saved.parentDeviceId} not restored`);
|
|
33884
|
+
await this.healSavedConfig(saved, savedDevices);
|
|
33849
33885
|
await this.ctx.kernel.devices.create(saved.stableId, Class, {}, saved.parentDeviceId);
|
|
33850
33886
|
restored.add(saved.id);
|
|
33851
33887
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-tuya",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.61",
|
|
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",
|