@mega-yfue/eufy-sdk 0.5.0-beta.50 → 0.5.0-beta.52
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/client/eufy-mega.d.ts +7 -2
- package/dist/index.js +115 -56
- package/dist/index.js.map +4 -4
- package/dist/transport/tuya/account.d.ts +8 -5
- package/dist/transport/tuya/client.d.ts +19 -5
- package/dist/transport/tuya/command-router.d.ts +10 -14
- package/dist/transport/tuya/et3.d.ts +22 -0
- package/dist/transport/tuya/request.d.ts +18 -8
- package/dist/transport/tuya/sign.d.ts +7 -0
- package/package.json +1 -1
|
@@ -454,8 +454,9 @@ export declare class EufyMega extends EventEmitter {
|
|
|
454
454
|
*
|
|
455
455
|
* Side-effect: registers `eufy_home_tuya` devices with the Tuya command router so
|
|
456
456
|
* the command dispatcher can resolve a eufy SN → Tuya devId without a separate lookup.
|
|
457
|
-
* The Tuya id is
|
|
458
|
-
* `
|
|
457
|
+
* The Tuya id is the first non-empty `tuya_uuid`, `tuya_virtual_id`, `tuya_device_id` or
|
|
458
|
+
* `virtualId` on the raw cloud record, else the device's serial: the app keys its Tuya device by
|
|
459
|
+
* the eufy device id, and a record that carries none of those fields is read under its serial.
|
|
459
460
|
*
|
|
460
461
|
* A partial cloud outage still resolves, with the devices that answered plus the ones already known — but a
|
|
461
462
|
* session the cloud has rejected REJECTS, with {@link SessionExpiredError}. An empty list would be
|
|
@@ -790,6 +791,10 @@ export declare class EufyMega extends EventEmitter {
|
|
|
790
791
|
/**
|
|
791
792
|
* Subscribe the devices on one credential scope; a failing subscribe is reported, not fatal (one
|
|
792
793
|
* unreachable device must not stop the rest of the roster from coming up).
|
|
794
|
+
*
|
|
795
|
+
* A Tuya clean-line device's DPs are also read from the Tuya cloud, whether or not its subscribe
|
|
796
|
+
* succeeded: the cloud read is a separate plane, and the broker can refuse a subscribe for a device
|
|
797
|
+
* whose DPs the Tuya cloud still serves.
|
|
793
798
|
*/
|
|
794
799
|
private subscribeMqttDevices;
|
|
795
800
|
/**
|
package/dist/index.js
CHANGED
|
@@ -25210,7 +25210,7 @@ var MqttCommandRouter = class _MqttCommandRouter {
|
|
|
25210
25210
|
|
|
25211
25211
|
// dist/transport/tuya/account.js
|
|
25212
25212
|
import { createCipheriv as createCipheriv5 } from "node:crypto";
|
|
25213
|
-
var TUYA_USERNAME_PREFIX = "
|
|
25213
|
+
var TUYA_USERNAME_PREFIX = "eh-";
|
|
25214
25214
|
var TUYA_PASSWORD_KEY = Buffer.from([
|
|
25215
25215
|
36,
|
|
25216
25216
|
78,
|
|
@@ -25398,10 +25398,13 @@ var StubSigner = class {
|
|
|
25398
25398
|
}
|
|
25399
25399
|
};
|
|
25400
25400
|
var TUYA_SIGN_K = "com.oceanwing.battery.cam_16:6C:23:45:57:B7:76:CA:D8:AC:94:C9:79:37:9E:48:DF:38:7D:4D:8F:96:A3:43:DF:40:FC:D9:05:BF:F6:86_dn9erpyp7nmeuvah8ktghqsgpay87maa_pt585qhmt75hwcynchnps9dnxh9suhwd";
|
|
25401
|
+
function resolveSignKey(override) {
|
|
25402
|
+
return override ?? process.env.TUYA_SIGN_KEY ?? TUYA_SIGN_K;
|
|
25403
|
+
}
|
|
25401
25404
|
var HmacSigner = class {
|
|
25402
25405
|
key;
|
|
25403
25406
|
constructor(key) {
|
|
25404
|
-
this.key = key
|
|
25407
|
+
this.key = resolveSignKey(key);
|
|
25405
25408
|
}
|
|
25406
25409
|
sign(preimage) {
|
|
25407
25410
|
return createHmac4("sha256", this.key).update(preimage, "utf-8").digest("hex");
|
|
@@ -25410,7 +25413,37 @@ var HmacSigner = class {
|
|
|
25410
25413
|
var TUYA_CHKEY = "7cbfe6d8";
|
|
25411
25414
|
|
|
25412
25415
|
// dist/transport/tuya/client.js
|
|
25413
|
-
import { randomBytes as
|
|
25416
|
+
import { randomBytes as randomBytes5, createHash as createHash6, createPublicKey, publicEncrypt, constants as constants2 } from "node:crypto";
|
|
25417
|
+
|
|
25418
|
+
// dist/transport/tuya/et3.js
|
|
25419
|
+
import { createCipheriv as createCipheriv6, createDecipheriv as createDecipheriv8, createHmac as createHmac5, randomBytes as randomBytes4 } from "node:crypto";
|
|
25420
|
+
import { gunzipSync } from "node:zlib";
|
|
25421
|
+
function deriveBodyKey(requestId, ecode) {
|
|
25422
|
+
const k = resolveSignKey();
|
|
25423
|
+
const msg = ecode === null ? k : `${k}_${ecode}`;
|
|
25424
|
+
const hex = createHmac5("sha256", requestId).update(msg, "utf-8").digest("hex");
|
|
25425
|
+
return Buffer.from(hex.slice(0, 16), "ascii");
|
|
25426
|
+
}
|
|
25427
|
+
function encryptBody2(key, json) {
|
|
25428
|
+
const nonce = randomBytes4(12);
|
|
25429
|
+
const cipher = createCipheriv6("aes-128-gcm", key, nonce);
|
|
25430
|
+
const ciphertext = Buffer.concat([cipher.update(Buffer.from(json, "utf-8")), cipher.final()]);
|
|
25431
|
+
return Buffer.concat([nonce, ciphertext, cipher.getAuthTag()]).toString("base64");
|
|
25432
|
+
}
|
|
25433
|
+
function decryptReply(key, resultB64) {
|
|
25434
|
+
const blob = Buffer.from(resultB64, "base64");
|
|
25435
|
+
if (blob.length < 12 + 16) {
|
|
25436
|
+
throw new Error("tuya et=3 reply too short to hold a 12-byte nonce + 16-byte tag");
|
|
25437
|
+
}
|
|
25438
|
+
const nonce = blob.subarray(0, 12);
|
|
25439
|
+
const tag2 = blob.subarray(blob.length - 16);
|
|
25440
|
+
const ciphertext = blob.subarray(12, blob.length - 16);
|
|
25441
|
+
const decipher = createDecipheriv8("aes-128-gcm", key, nonce);
|
|
25442
|
+
decipher.setAuthTag(tag2);
|
|
25443
|
+
const plain = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
25444
|
+
const text2 = plain.length >= 2 && plain[0] === 31 && plain[1] === 139 ? gunzipSync(plain) : plain;
|
|
25445
|
+
return text2.toString("utf-8");
|
|
25446
|
+
}
|
|
25414
25447
|
|
|
25415
25448
|
// dist/transport/tuya/request.js
|
|
25416
25449
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
@@ -25465,8 +25498,9 @@ function buildApiParams(action, opts) {
|
|
|
25465
25498
|
nd: env.nd,
|
|
25466
25499
|
deviceCoreVersion: env.deviceCoreVersion
|
|
25467
25500
|
};
|
|
25468
|
-
if (action.postData !== void 0)
|
|
25469
|
-
params.postData = action.postData;
|
|
25501
|
+
if (action.postData !== void 0) {
|
|
25502
|
+
params.postData = env.et === "3" ? encryptBody2(deriveBodyKey(params.requestId, opts.session.ecode ?? null), action.postData) : action.postData;
|
|
25503
|
+
}
|
|
25470
25504
|
const sign = opts.signer.sign(buildSignPreimage(params));
|
|
25471
25505
|
return { ...params, sign };
|
|
25472
25506
|
}
|
|
@@ -25486,16 +25520,16 @@ async function sendApiRequest(params, opts = {}) {
|
|
|
25486
25520
|
}
|
|
25487
25521
|
function buildPublishDpsAction(devId, gwId, dps) {
|
|
25488
25522
|
return {
|
|
25489
|
-
a: "
|
|
25523
|
+
a: "smartlife.m.device.dp.publish",
|
|
25490
25524
|
v: "2.0",
|
|
25491
25525
|
postData: JSON.stringify({ gwId, devId, dps: JSON.stringify(dps) })
|
|
25492
25526
|
};
|
|
25493
25527
|
}
|
|
25494
|
-
function buildGetDeviceDpsAction(devId
|
|
25528
|
+
function buildGetDeviceDpsAction(devId) {
|
|
25495
25529
|
return {
|
|
25496
|
-
a: "
|
|
25497
|
-
v: "
|
|
25498
|
-
postData: JSON.stringify({ devId
|
|
25530
|
+
a: "smartlife.m.device.dp.get",
|
|
25531
|
+
v: "1.0",
|
|
25532
|
+
postData: JSON.stringify({ devId })
|
|
25499
25533
|
};
|
|
25500
25534
|
}
|
|
25501
25535
|
function buildUsernameTokenGetAction(countryCode, username) {
|
|
@@ -25509,7 +25543,15 @@ function buildPasswordLoginRegAction(countryCode, uid, passwd, token) {
|
|
|
25509
25543
|
return {
|
|
25510
25544
|
a: "smartlife.m.user.uid.password.login.reg",
|
|
25511
25545
|
v: "1.0",
|
|
25512
|
-
postData: JSON.stringify({
|
|
25546
|
+
postData: JSON.stringify({
|
|
25547
|
+
countryCode,
|
|
25548
|
+
uid,
|
|
25549
|
+
passwd,
|
|
25550
|
+
token,
|
|
25551
|
+
ifencrypt: 1,
|
|
25552
|
+
createGroup: true,
|
|
25553
|
+
options: '{"group": 1}'
|
|
25554
|
+
})
|
|
25513
25555
|
};
|
|
25514
25556
|
}
|
|
25515
25557
|
function buildUidTokenCreateAction(countryCode, uid) {
|
|
@@ -25522,7 +25564,7 @@ function buildUidTokenCreateAction(countryCode, uid) {
|
|
|
25522
25564
|
|
|
25523
25565
|
// dist/transport/tuya/client.js
|
|
25524
25566
|
function genDeviceId() {
|
|
25525
|
-
return
|
|
25567
|
+
return randomBytes5(22).toString("hex");
|
|
25526
25568
|
}
|
|
25527
25569
|
function rsaEncryptPassword(password, publicKeyDecimal, exponentDecimal) {
|
|
25528
25570
|
const bigintToBuffer = (n) => {
|
|
@@ -25572,9 +25614,29 @@ var TuyaClient = class {
|
|
|
25572
25614
|
buildRequest(action) {
|
|
25573
25615
|
return buildApiParams(action, { session: this.session, signer: this.signer, env: this.env });
|
|
25574
25616
|
}
|
|
25575
|
-
/**
|
|
25617
|
+
/**
|
|
25618
|
+
* Build + POST an action, returning the parsed envelope. Requires a working signer.
|
|
25619
|
+
*
|
|
25620
|
+
* On an `et=3` reply the envelope's `result` is a base64 AES-128-GCM blob, not an object; this
|
|
25621
|
+
* decrypts it (keyed off the request's `requestId` and the session's `ecode`) and returns the
|
|
25622
|
+
* decrypted inner envelope, so callers read `result` as an object regardless. A non-string `result`
|
|
25623
|
+
* (an error, or an already-plain reply) passes through untouched.
|
|
25624
|
+
*/
|
|
25576
25625
|
async call(action) {
|
|
25577
|
-
|
|
25626
|
+
const params = this.buildRequest(action);
|
|
25627
|
+
const env = await sendApiRequest(params, { endpoint: this.endpoint, http: this.http });
|
|
25628
|
+
return this.decodeReply(env, params.requestId);
|
|
25629
|
+
}
|
|
25630
|
+
/**
|
|
25631
|
+
* Decode an et=3 reply. When `result` is a non-empty string it is the encrypted blob: decrypt and
|
|
25632
|
+
* parse it (a wrong key or tampered blob fails the GCM tag in {@link decryptReply} and throws). The
|
|
25633
|
+
* plaintext is itself the standard `{success, t, result}` envelope, which becomes the returned one.
|
|
25634
|
+
*/
|
|
25635
|
+
decodeReply(env, requestId) {
|
|
25636
|
+
if (typeof env.result !== "string" || env.result === "")
|
|
25637
|
+
return env;
|
|
25638
|
+
const key = deriveBodyKey(requestId, this.session.ecode ?? null);
|
|
25639
|
+
return JSON.parse(decryptReply(key, env.result));
|
|
25578
25640
|
}
|
|
25579
25641
|
/**
|
|
25580
25642
|
* Log into the Tuya cloud from a eufy user id (wire-confirmed from the eufy Security app).
|
|
@@ -25607,7 +25669,7 @@ var TuyaClient = class {
|
|
|
25607
25669
|
const encPasswd = rsaEncryptPassword(password, publicKey, exponent);
|
|
25608
25670
|
const loginRes = await this.call(buildPasswordLoginRegAction(account.countryCode, account.username, encPasswd, token));
|
|
25609
25671
|
if (loginRes.success && loginRes.result?.sid && loginRes.result?.uid) {
|
|
25610
|
-
return { sid: loginRes.result.sid, uid: loginRes.result.uid };
|
|
25672
|
+
return { sid: loginRes.result.sid, uid: loginRes.result.uid, ecode: loginRes.result.ecode };
|
|
25611
25673
|
}
|
|
25612
25674
|
if ((loginRes.errorCode ?? loginRes.errorMsg) === "USER_PASSWD_WRONG")
|
|
25613
25675
|
return "PASSWD_WRONG";
|
|
@@ -25619,18 +25681,19 @@ var TuyaClient = class {
|
|
|
25619
25681
|
if (result === "PASSWD_WRONG") {
|
|
25620
25682
|
throw new Error("tuya login: USER_PASSWD_WRONG on both derived password and fallback '12345678'");
|
|
25621
25683
|
}
|
|
25622
|
-
this.session = { ...this.session, sid: result.sid };
|
|
25623
|
-
return result;
|
|
25684
|
+
this.session = { ...this.session, sid: result.sid, ecode: result.ecode };
|
|
25685
|
+
return { sid: result.sid, uid: result.uid };
|
|
25624
25686
|
}
|
|
25625
25687
|
/**
|
|
25626
|
-
* READ
|
|
25627
|
-
* Builds the request without needing a working signer; the signer is
|
|
25688
|
+
* READ a device's current data-points (`smartlife.m.device.dp.get`). The envelope's `result` is a
|
|
25689
|
+
* flat `{ "<dpId>": value }` map. Builds the request without needing a working signer; the signer is
|
|
25690
|
+
* only exercised on send.
|
|
25628
25691
|
*/
|
|
25629
|
-
async getDeviceDps(devId
|
|
25630
|
-
return this.call(buildGetDeviceDpsAction(devId
|
|
25692
|
+
async getDeviceDps(devId) {
|
|
25693
|
+
return this.call(buildGetDeviceDpsAction(devId));
|
|
25631
25694
|
}
|
|
25632
25695
|
/**
|
|
25633
|
-
* CONTROL: publish data-points to a device (`
|
|
25696
|
+
* CONTROL: publish data-points to a device (`smartlife.m.device.dp.publish`). `dps` is
|
|
25634
25697
|
* `{ "<dpId>": <value> }`. `gwId` is the gateway/parent id (equals `devId` for a standalone gw).
|
|
25635
25698
|
*
|
|
25636
25699
|
* ⚠️ UNVERIFIED write — refuses to send by default. The `dp.publish` param shape
|
|
@@ -25718,9 +25781,9 @@ var TuyaCommandRouter = class {
|
|
|
25718
25781
|
/** Promise that resolves once Tuya login has completed. Reset by {@link bind}. */
|
|
25719
25782
|
loginOnce = null;
|
|
25720
25783
|
/**
|
|
25721
|
-
* eufy SN → Tuya device ids, populated
|
|
25722
|
-
* The
|
|
25723
|
-
* `
|
|
25784
|
+
* eufy SN → Tuya device ids, populated via {@link registerDevice} once the device list loads.
|
|
25785
|
+
* The Tuya id is the record's first non-empty `tuya_uuid` / `tuya_virtual_id` / `tuya_device_id` /
|
|
25786
|
+
* `virtualId`, or the device's serial when the record carries none of them.
|
|
25724
25787
|
*/
|
|
25725
25788
|
snMap = /* @__PURE__ */ new Map();
|
|
25726
25789
|
constructor(config = {}) {
|
|
@@ -25742,10 +25805,10 @@ var TuyaCommandRouter = class {
|
|
|
25742
25805
|
this.loginOnce = null;
|
|
25743
25806
|
}
|
|
25744
25807
|
/**
|
|
25745
|
-
* Register a eufy SN → Tuya devId mapping
|
|
25746
|
-
*
|
|
25747
|
-
*
|
|
25748
|
-
*
|
|
25808
|
+
* Register a eufy SN → Tuya devId mapping for an `eufy_home_tuya` device. `devId` is the record's
|
|
25809
|
+
* first non-empty `tuya_uuid` / `tuya_virtual_id` / `tuya_device_id` / `virtualId`, or the device's
|
|
25810
|
+
* serial when the record carries none of them. `gwId` defaults to `devId` — standalone devices
|
|
25811
|
+
* share the two.
|
|
25749
25812
|
*/
|
|
25750
25813
|
registerDevice(sn, devId, gwId = devId) {
|
|
25751
25814
|
this.snMap.set(sn, { devId, gwId });
|
|
@@ -25769,13 +25832,9 @@ var TuyaCommandRouter = class {
|
|
|
25769
25832
|
return this.loginOnce;
|
|
25770
25833
|
}
|
|
25771
25834
|
/**
|
|
25772
|
-
*
|
|
25773
|
-
* the
|
|
25774
|
-
*
|
|
25775
|
-
*
|
|
25776
|
-
* The response shape from `getDeviceDps` is not yet pinned from a live capture. The defensive
|
|
25777
|
-
* extraction tries both `result.dps` (a nested map) and bare `result` (a flat map), and returns
|
|
25778
|
-
* `null` when neither yields a non-empty record.
|
|
25835
|
+
* Read a device's current DPs from the Tuya cloud (`smartlife.m.device.dp.get`) and answer the DP
|
|
25836
|
+
* map: the reply's flat `result`, kept to integer DP keys with scalar values. Answers `null` for an
|
|
25837
|
+
* unregistered device, a failed reply, or a reply with no DPs.
|
|
25779
25838
|
*/
|
|
25780
25839
|
async fetchDps(sn) {
|
|
25781
25840
|
const ids = this.snMap.get(sn);
|
|
@@ -25785,12 +25844,8 @@ var TuyaCommandRouter = class {
|
|
|
25785
25844
|
const res = await this.client.getDeviceDps(ids.devId);
|
|
25786
25845
|
if (!res.success || !res.result)
|
|
25787
25846
|
return null;
|
|
25788
|
-
const
|
|
25789
|
-
|
|
25790
|
-
return nested;
|
|
25791
|
-
}
|
|
25792
|
-
const flat = parseTuyaDpEvent(res.result);
|
|
25793
|
-
return flat ? flat : null;
|
|
25847
|
+
const dps = parseTuyaDpEvent(res.result);
|
|
25848
|
+
return dps ? dps : null;
|
|
25794
25849
|
}
|
|
25795
25850
|
/**
|
|
25796
25851
|
* Route an `aiot-dp` {@link Command} to the Tuya REST API.
|
|
@@ -25809,7 +25864,7 @@ var TuyaCommandRouter = class {
|
|
|
25809
25864
|
await this.ensureLoggedIn();
|
|
25810
25865
|
const ids = this.snMap.get(sn);
|
|
25811
25866
|
if (!ids) {
|
|
25812
|
-
throw new Error(`TuyaCommandRouter: no Tuya device id registered for ${sn}. Ensure getDevices() was called
|
|
25867
|
+
throw new Error(`TuyaCommandRouter: no Tuya device id registered for ${sn}. Ensure getDevices() was called; it registers every eufy_home_tuya device under its Tuya id or its serial.`);
|
|
25813
25868
|
}
|
|
25814
25869
|
await this.client.publishDps(ids.devId, ids.gwId, { [cmd.dp]: cmd.value }, { allowUnverified: this.allowUnverified });
|
|
25815
25870
|
}
|
|
@@ -26647,7 +26702,7 @@ var PushClient = class _PushClient extends EventEmitter12 {
|
|
|
26647
26702
|
};
|
|
26648
26703
|
|
|
26649
26704
|
// dist/transport/push/fcm.js
|
|
26650
|
-
import { randomBytes as
|
|
26705
|
+
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
26651
26706
|
import { setTimeout as sleep3 } from "node:timers/promises";
|
|
26652
26707
|
var FCM = {
|
|
26653
26708
|
PROJECT_ID: "batterycam-3250a",
|
|
@@ -26660,7 +26715,7 @@ var FCM = {
|
|
|
26660
26715
|
SDK_VERSION: "a:16.3.1"
|
|
26661
26716
|
};
|
|
26662
26717
|
function generateFid() {
|
|
26663
|
-
const b =
|
|
26718
|
+
const b = randomBytes6(17);
|
|
26664
26719
|
b[0] = 112 + b[0] % 16;
|
|
26665
26720
|
return b.toString("base64url").slice(0, 22);
|
|
26666
26721
|
}
|
|
@@ -28617,8 +28672,9 @@ var EufyMega = class extends EventEmitter13 {
|
|
|
28617
28672
|
*
|
|
28618
28673
|
* Side-effect: registers `eufy_home_tuya` devices with the Tuya command router so
|
|
28619
28674
|
* the command dispatcher can resolve a eufy SN → Tuya devId without a separate lookup.
|
|
28620
|
-
* The Tuya id is
|
|
28621
|
-
* `
|
|
28675
|
+
* The Tuya id is the first non-empty `tuya_uuid`, `tuya_virtual_id`, `tuya_device_id` or
|
|
28676
|
+
* `virtualId` on the raw cloud record, else the device's serial: the app keys its Tuya device by
|
|
28677
|
+
* the eufy device id, and a record that carries none of those fields is read under its serial.
|
|
28622
28678
|
*
|
|
28623
28679
|
* A partial cloud outage still resolves, with the devices that answered plus the ones already known — but a
|
|
28624
28680
|
* session the cloud has rejected REJECTS, with {@link SessionExpiredError}. An empty list would be
|
|
@@ -28630,9 +28686,7 @@ var EufyMega = class extends EventEmitter13 {
|
|
|
28630
28686
|
if (dev.category !== "eufy_home_tuya")
|
|
28631
28687
|
continue;
|
|
28632
28688
|
const raw = dev.raw ?? {};
|
|
28633
|
-
|
|
28634
|
-
if (devId)
|
|
28635
|
-
this.tuya.registerDevice(dev.sn, devId);
|
|
28689
|
+
this.tuya.registerDevice(dev.sn, tuyaDevIdFrom(raw) ?? dev.sn);
|
|
28636
28690
|
}
|
|
28637
28691
|
return devices;
|
|
28638
28692
|
}
|
|
@@ -29300,21 +29354,25 @@ var EufyMega = class extends EventEmitter13 {
|
|
|
29300
29354
|
/**
|
|
29301
29355
|
* Subscribe the devices on one credential scope; a failing subscribe is reported, not fatal (one
|
|
29302
29356
|
* unreachable device must not stop the rest of the roster from coming up).
|
|
29357
|
+
*
|
|
29358
|
+
* A Tuya clean-line device's DPs are also read from the Tuya cloud, whether or not its subscribe
|
|
29359
|
+
* succeeded: the cloud read is a separate plane, and the broker can refuse a subscribe for a device
|
|
29360
|
+
* whose DPs the Tuya cloud still serves.
|
|
29303
29361
|
*/
|
|
29304
29362
|
async subscribeMqttDevices(scope, transport) {
|
|
29305
29363
|
for (const d of this.getMqttDevices().filter((dev) => mqttScopeFor(dev) === scope)) {
|
|
29306
29364
|
try {
|
|
29307
29365
|
await transport.subscribeDevice(d);
|
|
29308
29366
|
await this.sendRealtimeInit(d.sn);
|
|
29309
|
-
if (d.category === "eufy_home_tuya") {
|
|
29310
|
-
this.tuya.fetchDps(d.sn).then((dps) => {
|
|
29311
|
-
if (dps)
|
|
29312
|
-
this.tuyaDpRouter.deliver(d.sn, dps);
|
|
29313
|
-
}).catch((e) => this.reportError(e));
|
|
29314
|
-
}
|
|
29315
29367
|
} catch (e) {
|
|
29316
29368
|
this.reportError(e);
|
|
29317
29369
|
}
|
|
29370
|
+
if (d.category === "eufy_home_tuya") {
|
|
29371
|
+
this.tuya.fetchDps(d.sn).then((dps) => {
|
|
29372
|
+
if (dps)
|
|
29373
|
+
this.tuyaDpRouter.deliver(d.sn, dps);
|
|
29374
|
+
}).catch((e) => this.reportError(e));
|
|
29375
|
+
}
|
|
29318
29376
|
}
|
|
29319
29377
|
}
|
|
29320
29378
|
/**
|
|
@@ -30787,6 +30845,7 @@ __export(tuya_exports, {
|
|
|
30787
30845
|
genDeviceId: () => genDeviceId,
|
|
30788
30846
|
isoToDialCode: () => isoToDialCode,
|
|
30789
30847
|
resolveCountryCode: () => resolveCountryCode,
|
|
30848
|
+
resolveSignKey: () => resolveSignKey,
|
|
30790
30849
|
sendApiRequest: () => sendApiRequest,
|
|
30791
30850
|
swapMd5: () => swapMd5,
|
|
30792
30851
|
tuyaUsername: () => tuyaUsername
|