@mega-yfue/eufy-sdk 0.6.0-beta.40 → 0.6.0-beta.42
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/device-registry.d.ts +22 -0
- package/dist/index.js +585 -176
- package/dist/index.js.map +4 -4
- package/dist/model/capabilities/index.d.ts +1 -0
- package/dist/model/capabilities/members.d.ts +18 -3
- package/dist/model/capabilities/motion.d.ts +16 -2
- package/dist/model/capabilities/rtsp.d.ts +1 -10
- package/dist/model/capabilities/thing-description.d.ts +137 -0
- package/dist/model/capabilities/types.d.ts +9 -0
- package/dist/model/inspect.d.ts +3 -0
- package/dist/model/types.d.ts +3 -0
- package/dist/transport/http/mega-client.d.ts +12 -0
- package/dist/transport/rtc/command-router.d.ts +7 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -47,10 +47,10 @@ function decryptBody(b64, shareKeyHex) {
|
|
|
47
47
|
return Buffer.concat([decipher.update(raw.subarray(16)), decipher.final()]);
|
|
48
48
|
}
|
|
49
49
|
function signRequest(shareKeyHex, ts, once, encBodyB64) {
|
|
50
|
-
const
|
|
50
|
+
const parts2 = [ts, once];
|
|
51
51
|
if (encBodyB64)
|
|
52
|
-
|
|
53
|
-
return createHmac("sha256", signKey(shareKeyHex)).update(
|
|
52
|
+
parts2.push(encBodyB64);
|
|
53
|
+
return createHmac("sha256", signKey(shareKeyHex)).update(parts2.join("+"), "utf-8").digest("hex");
|
|
54
54
|
}
|
|
55
55
|
function prepareKeyExchange(localKeyHex = EUFY_MEGA_LOCAL_KEY_HEX) {
|
|
56
56
|
const localKey = Buffer.from(localKeyHex, "hex");
|
|
@@ -411,8 +411,8 @@ function randomPhoneModel(seed) {
|
|
|
411
411
|
const rnd = rng(seed);
|
|
412
412
|
const pick = (a) => a[Math.floor(rnd() * a.length)];
|
|
413
413
|
const brand = pick(Object.keys(PHONE_MODELS));
|
|
414
|
-
const
|
|
415
|
-
return `${brand}${pick(
|
|
414
|
+
const parts2 = PHONE_MODELS[brand];
|
|
415
|
+
return `${brand}${pick(parts2.first)}${pick(parts2.second)}`.trim();
|
|
416
416
|
}
|
|
417
417
|
function randomUserAgent(seed, model) {
|
|
418
418
|
const rnd = rng(seed);
|
|
@@ -1052,10 +1052,10 @@ function getIdSuffix(p2pDid) {
|
|
|
1052
1052
|
const match = p2pDid.match(/^[A-Z]+-(\d+)-[A-Z]+$/);
|
|
1053
1053
|
if (match?.length === 2) {
|
|
1054
1054
|
const num1 = Number.parseInt(match[1][0]);
|
|
1055
|
-
const
|
|
1055
|
+
const num22 = Number.parseInt(match[1][1]);
|
|
1056
1056
|
const num3 = Number.parseInt(match[1][3]);
|
|
1057
1057
|
const num4 = Number.parseInt(match[1][5]);
|
|
1058
|
-
result = num1 +
|
|
1058
|
+
result = num1 + num22 + num3;
|
|
1059
1059
|
if (num3 < 5)
|
|
1060
1060
|
result = result + num3;
|
|
1061
1061
|
result = result + num4;
|
|
@@ -1735,6 +1735,10 @@ var MegaHttpClient = class {
|
|
|
1735
1735
|
get regionShard() {
|
|
1736
1736
|
return this.region;
|
|
1737
1737
|
}
|
|
1738
|
+
/** The account's country code as configured (e.g. `"FR"`), the one logins are sent with. */
|
|
1739
|
+
get countryCode() {
|
|
1740
|
+
return this.cfg.countryCode;
|
|
1741
|
+
}
|
|
1738
1742
|
/**
|
|
1739
1743
|
* The shard the estimated domain names (`…-ie-…`/`…-ie.` → `ie-pr`), else {@link regionShard}. The
|
|
1740
1744
|
* eu/us classification cannot name shards like `ie-pr`.
|
|
@@ -2069,6 +2073,21 @@ ${this.auth_?.authToken ?? ""}`;
|
|
|
2069
2073
|
getProductDataPoint(code) {
|
|
2070
2074
|
return this.post("things", "/app/things/get_product_data_point", { code });
|
|
2071
2075
|
}
|
|
2076
|
+
/**
|
|
2077
|
+
* Fetch the **thing descriptions** of the given product codes from the mega `things` service: per
|
|
2078
|
+
* product, every named property with its type and offered values, its actions and events. The v6 app
|
|
2079
|
+
* fetches the same list for the products an account holds and reads each setting's options from it.
|
|
2080
|
+
* Product-level data, not account data. `codeTimeMap` names, per product code, the `update_time` of the
|
|
2081
|
+
* description already held: a product whose description has not changed since comes back with that
|
|
2082
|
+
* `update_time` and no properties, one that has (or is not named) comes back in full. Returns the raw
|
|
2083
|
+
* `data`.
|
|
2084
|
+
*/
|
|
2085
|
+
getThingsList(productCodes, codeTimeMap = {}) {
|
|
2086
|
+
return this.post("things", "/app/things/get_things_list", {
|
|
2087
|
+
product_codes: productCodes,
|
|
2088
|
+
code_time_map: codeTimeMap
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2072
2091
|
/**
|
|
2073
2092
|
* Fetch the **live param list** from the mega `devicemanage` service. Body keys off a
|
|
2074
2093
|
* `device_sns` ARRAY (a bare `device_sn` 400s with "type mismatch"). Each returned entry is
|
|
@@ -2105,10 +2124,10 @@ ${this.auth_?.authToken ?? ""}`;
|
|
|
2105
2124
|
* host it points at is unconfirmed, and this client's binary path (`downloadMediaResource`) is
|
|
2106
2125
|
* host-allowlisted by design.
|
|
2107
2126
|
*/
|
|
2108
|
-
getCleanRecords(deviceSn,
|
|
2127
|
+
getCleanRecords(deviceSn, num3 = 20, page = 1) {
|
|
2109
2128
|
return this.post("clean", "/app/clean/get_device_clean_record_list", {
|
|
2110
2129
|
device_sn: deviceSn,
|
|
2111
|
-
num:
|
|
2130
|
+
num: num3,
|
|
2112
2131
|
page
|
|
2113
2132
|
});
|
|
2114
2133
|
}
|
|
@@ -2123,11 +2142,11 @@ ${this.auth_?.authToken ?? ""}`;
|
|
|
2123
2142
|
* APK, and the extracted `.so` set contains no clean-native module. Handing over bytes a caller can
|
|
2124
2143
|
* take elsewhere is the honest surface; a decode here would be invention.
|
|
2125
2144
|
*/
|
|
2126
|
-
getDeviceMapList(deviceSn, channelId = 0,
|
|
2145
|
+
getDeviceMapList(deviceSn, channelId = 0, num3 = 1, page = 1, lastOffset = 0) {
|
|
2127
2146
|
return this.post("clean", "/app/clean/get_device_map_list", {
|
|
2128
2147
|
device_sn: deviceSn,
|
|
2129
2148
|
channel_id: channelId,
|
|
2130
|
-
num:
|
|
2149
|
+
num: num3,
|
|
2131
2150
|
page,
|
|
2132
2151
|
last_offset: lastOffset
|
|
2133
2152
|
});
|
|
@@ -2650,15 +2669,15 @@ function subscribeTopics(device) {
|
|
|
2650
2669
|
return [secureTopic(device, "res")];
|
|
2651
2670
|
}
|
|
2652
2671
|
function parseSecureTopic(topic) {
|
|
2653
|
-
const
|
|
2654
|
-
if (
|
|
2672
|
+
const parts2 = topic.split("/");
|
|
2673
|
+
if (parts2.length < 5)
|
|
2655
2674
|
return void 0;
|
|
2656
|
-
const [root, category, model, sn] =
|
|
2675
|
+
const [root, category, model, sn] = parts2;
|
|
2657
2676
|
if (root !== "cmd" && root !== "synq" && root !== "biz" && root !== "dt")
|
|
2658
2677
|
return void 0;
|
|
2659
2678
|
if (!category || !model || !sn)
|
|
2660
2679
|
return void 0;
|
|
2661
|
-
return { root, category, model, sn, tail:
|
|
2680
|
+
return { root, category, model, sn, tail: parts2.slice(4).join("/") };
|
|
2662
2681
|
}
|
|
2663
2682
|
function solixDeviceTopics(appName, productCode, deviceSn) {
|
|
2664
2683
|
const dt = `dt/${appName}/${productCode}/${deviceSn}`;
|
|
@@ -3403,8 +3422,17 @@ function provided(needs, build, description, requiredCapabilities) {
|
|
|
3403
3422
|
function hasRequiredCapabilities(member, capabilities) {
|
|
3404
3423
|
return !member.requiredCapabilities?.some((capability) => !capabilities?.has(capability));
|
|
3405
3424
|
}
|
|
3425
|
+
function thingEnum(m, ctx) {
|
|
3426
|
+
const named = m.enumValues;
|
|
3427
|
+
const property2 = named && m.thing?.map((id) => ctx.things?.properties[id]).find(Boolean);
|
|
3428
|
+
if (!named || !property2)
|
|
3429
|
+
return void 0;
|
|
3430
|
+
const wire = property2.type === "bool" ? [0, 1] : property2.members.map((x) => Number(x.wireValue ?? NaN));
|
|
3431
|
+
const options = Object.fromEntries(wire.filter((v) => v in named).map((v) => [v, named[v]]));
|
|
3432
|
+
return Object.keys(options).length ? options : void 0;
|
|
3433
|
+
}
|
|
3406
3434
|
function resolvedEnum(m, ctx) {
|
|
3407
|
-
const dynamic = ctx ? m.enumValuesFor?.(ctx) : void 0;
|
|
3435
|
+
const dynamic = ctx ? m.enumValuesFor?.(ctx) ?? thingEnum(m, ctx) : void 0;
|
|
3408
3436
|
return dynamic ? { values: dynamic, dynamic: true } : { values: m.enumValues, dynamic: false };
|
|
3409
3437
|
}
|
|
3410
3438
|
function propertiesOf(members, ctx) {
|
|
@@ -3525,6 +3553,46 @@ function wasReported(m, from, ctx) {
|
|
|
3525
3553
|
function installs(m, ctx) {
|
|
3526
3554
|
return reports(m.requires, ctx) && (!m.requiresRead || reads(m, ctx)) && (!m.available || m.available(ctx));
|
|
3527
3555
|
}
|
|
3556
|
+
function kindRoutable(kind, ctx) {
|
|
3557
|
+
return !ctx.refusedCommandKinds?.has(kind);
|
|
3558
|
+
}
|
|
3559
|
+
function probeValues(m, ctx) {
|
|
3560
|
+
if (m.type === "bool")
|
|
3561
|
+
return [false, true];
|
|
3562
|
+
const { values } = resolvedEnum(m, ctx);
|
|
3563
|
+
const keys = values ? Object.keys(values).map(Number) : void 0;
|
|
3564
|
+
if (m.type === "string")
|
|
3565
|
+
return keys && values ? keys.map((k) => values[k]) : [""];
|
|
3566
|
+
if (m.type === "enum")
|
|
3567
|
+
return keys ?? [0];
|
|
3568
|
+
return keys ?? [m.min ?? 0];
|
|
3569
|
+
}
|
|
3570
|
+
function writeRoutable(m, ctx) {
|
|
3571
|
+
if (!ctx.refusedCommandKinds)
|
|
3572
|
+
return true;
|
|
3573
|
+
for (const value of probeValues(m, ctx)) {
|
|
3574
|
+
let kind;
|
|
3575
|
+
try {
|
|
3576
|
+
kind = m.write?.(value, ctx)?.kind;
|
|
3577
|
+
} catch {
|
|
3578
|
+
return true;
|
|
3579
|
+
}
|
|
3580
|
+
if (kind === void 0 || kindRoutable(kind, ctx))
|
|
3581
|
+
return true;
|
|
3582
|
+
}
|
|
3583
|
+
return false;
|
|
3584
|
+
}
|
|
3585
|
+
function actionRoutable(m, ctx) {
|
|
3586
|
+
if (!ctx.refusedCommandKinds)
|
|
3587
|
+
return true;
|
|
3588
|
+
let kind;
|
|
3589
|
+
try {
|
|
3590
|
+
kind = m.action(ctx).kind;
|
|
3591
|
+
} catch {
|
|
3592
|
+
return true;
|
|
3593
|
+
}
|
|
3594
|
+
return kindRoutable(kind, ctx);
|
|
3595
|
+
}
|
|
3528
3596
|
function bindMembers(members, deps) {
|
|
3529
3597
|
const { ctx, sink, read, rawDp: rawDp2 } = deps;
|
|
3530
3598
|
const out = {};
|
|
@@ -3550,7 +3618,7 @@ function bindMembers(members, deps) {
|
|
|
3550
3618
|
continue;
|
|
3551
3619
|
}
|
|
3552
3620
|
if ("action" in m) {
|
|
3553
|
-
if (installs(m, ctx))
|
|
3621
|
+
if (installs(m, ctx) && actionRoutable(m, ctx))
|
|
3554
3622
|
out[name] = describe(m.description, () => sink.dispatch(m.action(ctx)), {});
|
|
3555
3623
|
continue;
|
|
3556
3624
|
}
|
|
@@ -3567,7 +3635,7 @@ function bindMembers(members, deps) {
|
|
|
3567
3635
|
const get = decode ? () => decode(raw(), rawDp2, ctx) : () => narrow(m.type, read, prop, domain);
|
|
3568
3636
|
Object.defineProperty(out, name, { get, enumerable: true, configurable: true });
|
|
3569
3637
|
}
|
|
3570
|
-
if (!m.write || m.unverified || !installs(m, ctx))
|
|
3638
|
+
if (!m.write || m.unverified || !installs(m, ctx) || !writeRoutable(m, ctx))
|
|
3571
3639
|
continue;
|
|
3572
3640
|
if (m.writeOnly)
|
|
3573
3641
|
unobservable.push(name);
|
|
@@ -3683,73 +3751,6 @@ var VIDEO = {
|
|
|
3683
3751
|
detection: { evidenceParams: [1056], codecs: ["camera"] }
|
|
3684
3752
|
};
|
|
3685
3753
|
|
|
3686
|
-
// dist/model/device-family.js
|
|
3687
|
-
var INDOOR_CAMERA_TYPES = /* @__PURE__ */ new Set([
|
|
3688
|
-
DeviceType.INDOOR_CAMERA,
|
|
3689
|
-
DeviceType.INDOOR_CAMERA_1080,
|
|
3690
|
-
DeviceType.INDOOR_PT_CAMERA,
|
|
3691
|
-
DeviceType.INDOOR_PT_CAMERA_1080,
|
|
3692
|
-
DeviceType.INDOOR_OUTDOOR_CAMERA_1080P,
|
|
3693
|
-
DeviceType.INDOOR_OUTDOOR_CAMERA_1080P_NO_LIGHT,
|
|
3694
|
-
DeviceType.INDOOR_OUTDOOR_CAMERA_2K,
|
|
3695
|
-
DeviceType.INDOOR_COST_DOWN_CAMERA,
|
|
3696
|
-
DeviceType.INDOOR_PT_CAMERA_S350,
|
|
3697
|
-
DeviceType.INDOOR_PT_CAMERA_E30,
|
|
3698
|
-
DeviceType.INDOOR_PT_CAMERA_C210,
|
|
3699
|
-
DeviceType.INDOOR_PT_CAMERA_C220,
|
|
3700
|
-
DeviceType.INDOOR_PT_CAMERA_C220_V2
|
|
3701
|
-
]);
|
|
3702
|
-
var INDOOR_PT_S350_TYPES = /* @__PURE__ */ new Set([
|
|
3703
|
-
DeviceType.INDOOR_PT_CAMERA_S350,
|
|
3704
|
-
DeviceType.INDOOR_PT_CAMERA_E30,
|
|
3705
|
-
DeviceType.INDOOR_PT_CAMERA_C210,
|
|
3706
|
-
DeviceType.INDOOR_PT_CAMERA_C220,
|
|
3707
|
-
DeviceType.INDOOR_PT_CAMERA_C220_V2
|
|
3708
|
-
]);
|
|
3709
|
-
var OUTDOOR_PT_TYPES = /* @__PURE__ */ new Set([
|
|
3710
|
-
DeviceType.OUTDOOR_PT_CAMERA,
|
|
3711
|
-
DeviceType.SOLO_CAMERA_E30,
|
|
3712
|
-
DeviceType.CAMERA_S4,
|
|
3713
|
-
DeviceType.SOLOCAM_E42,
|
|
3714
|
-
DeviceType.CAMERA_4G_S330
|
|
3715
|
-
]);
|
|
3716
|
-
var FLOODLIGHT_TYPES = /* @__PURE__ */ new Set([
|
|
3717
|
-
DeviceType.FLOODLIGHT,
|
|
3718
|
-
DeviceType.FLOODLIGHT_CAMERA_8422,
|
|
3719
|
-
DeviceType.FLOODLIGHT_CAMERA_8423,
|
|
3720
|
-
DeviceType.FLOODLIGHT_CAMERA_8424,
|
|
3721
|
-
DeviceType.FLOODLIGHT_CAMERA_8425,
|
|
3722
|
-
DeviceType.FLOODLIGHT_CAMERA_8426
|
|
3723
|
-
]);
|
|
3724
|
-
var WALL_LIGHT_TYPES = /* @__PURE__ */ new Set([
|
|
3725
|
-
DeviceType.WALL_LIGHT_CAM,
|
|
3726
|
-
DeviceType.WALL_LIGHT_CAM_81A0,
|
|
3727
|
-
DeviceType.WALL_LIGHT_CAM_T86C1
|
|
3728
|
-
]);
|
|
3729
|
-
var HOMEBASE_TYPES = /* @__PURE__ */ new Set([
|
|
3730
|
-
DeviceType.STATION,
|
|
3731
|
-
DeviceType.HB3,
|
|
3732
|
-
DeviceType.STATION_9000,
|
|
3733
|
-
DeviceType.MINIBASE_CHIME,
|
|
3734
|
-
DeviceType.HOMEBASE_MINI
|
|
3735
|
-
]);
|
|
3736
|
-
var has = (set, t) => t !== void 0 && set.has(t);
|
|
3737
|
-
var isIndoorCamera = (ctx) => has(INDOOR_CAMERA_TYPES, ctx.deviceType);
|
|
3738
|
-
var isIndoorCamMini = (ctx) => ctx.deviceType === DeviceType.INDOOR_COST_DOWN_CAMERA;
|
|
3739
|
-
var isIndoorPanTiltS350 = (ctx) => has(INDOOR_PT_S350_TYPES, ctx.deviceType);
|
|
3740
|
-
var isHomeBase = (ctx) => has(HOMEBASE_TYPES, ctx.deviceType);
|
|
3741
|
-
var isStation9000 = (ctx) => ctx.deviceType === DeviceType.STATION_9000;
|
|
3742
|
-
var isNvrT8N00 = (ctx) => ctx.model === "T8N00";
|
|
3743
|
-
var NVR_MEDIA_CAMERA_MODELS = /* @__PURE__ */ new Set(["T8E00", "T8P00", "T8P10", "T8162", "T8410", "T8214"]);
|
|
3744
|
-
var isNvrMediaCamera = (ctx) => ctx.model !== void 0 && NVR_MEDIA_CAMERA_MODELS.has(ctx.model);
|
|
3745
|
-
var isNvrDualLensCamera = (ctx) => ctx.model === "T8E00";
|
|
3746
|
-
var isNvrFullHdCamera = (ctx) => ctx.model === "T8E00" || ctx.model === "T8P00";
|
|
3747
|
-
var isCallDoorbell = (ctx) => ctx.model === "T8223" || ctx.model === "T8224";
|
|
3748
|
-
var isAiotVacuum = (ctx) => ctx.category !== "eufy_home_tuya";
|
|
3749
|
-
var isTuyaVacuum = (ctx) => ctx.category === "eufy_home_tuya";
|
|
3750
|
-
var isVideoSmartLock = (ctx) => ctx.deviceType === DeviceType.LOCK_8530;
|
|
3751
|
-
var isClassicWifiLock = (ctx) => ctx.deviceType === DeviceType.LOCK_WIFI && typeof ctx.serial === "string" && ctx.serial.startsWith("T8520") && ctx.serial.charAt(6) === "2";
|
|
3752
|
-
|
|
3753
3754
|
// dist/model/capabilities/rtsp.js
|
|
3754
3755
|
var RTSP_PARAM = {
|
|
3755
3756
|
/**
|
|
@@ -3805,7 +3806,7 @@ var RtspRecordingMode = {
|
|
|
3805
3806
|
Continuous: 1
|
|
3806
3807
|
};
|
|
3807
3808
|
function publishable(ctx) {
|
|
3808
|
-
return
|
|
3809
|
+
return kindRoutable("set-param", ctx);
|
|
3809
3810
|
}
|
|
3810
3811
|
function publishCommand(on, ctx) {
|
|
3811
3812
|
return setScalar(RTSP_PARAM.STREAM_SWITCH, on ? 1 : 0, ctx);
|
|
@@ -3831,8 +3832,7 @@ var RTSP_MEMBERS = {
|
|
|
3831
3832
|
provenance: "apk",
|
|
3832
3833
|
description: "Whether this camera's stream is published over RTSP (1145 NAS_STREAM_SWITHC). Name from the apk; the WRITE is verified live on a HomeBase-attached doorbell and two indoor cameras, both directions (DESCRIBE 404\u2192200 with a real SDP, and back).",
|
|
3833
3834
|
write: (v, ctx) => publishCommand(asBool(v), ctx),
|
|
3834
|
-
aliases: { publish: true, withdraw: false }
|
|
3835
|
-
available: publishable
|
|
3835
|
+
aliases: { publish: true, withdraw: false }
|
|
3836
3836
|
},
|
|
3837
3837
|
/**
|
|
3838
3838
|
* The device-reported RTSP URL — the full `rtsp://user:pass@host/path`, carrying the credentials the
|
|
@@ -4231,6 +4231,13 @@ var MOTION_CMD = {
|
|
|
4231
4231
|
* as a `1700` control payload carrying an index rather than the `1350` envelope its siblings take.
|
|
4232
4232
|
*/
|
|
4233
4233
|
INDOOR_SENSITIVITY_INDEX: 6041,
|
|
4234
|
+
/**
|
|
4235
|
+
* Motion detection on-off on a T8410 (app `CMD_INDOOR_DET_SET_MOTION_DETECT_ENABLE`). `1700` control
|
|
4236
|
+
* payload `{"commandType":6040,"data":{"enable":0,"quality":0,"status":0|1,"value":0}}`.
|
|
4237
|
+
*
|
|
4238
|
+
* ⚠️ Replay + readback confirmed on a standalone and a HomeBase 3-attached T8410, NOT byte-captured.
|
|
4239
|
+
*/
|
|
4240
|
+
INDOOR_MOTION_ENABLE: 6040,
|
|
4234
4241
|
/**
|
|
4235
4242
|
* Detection sensitivity a solo camera REPORTS (app `SET_MOTION_DETECTION_SENSITIVITY_SOLO`). It does
|
|
4236
4243
|
* not accept writes on this id — the write goes to {@link MOTION_SENSITIVITY}, which is why a scale
|
|
@@ -4362,6 +4369,9 @@ function sensitivityCommand(step, scale, ctx) {
|
|
|
4362
4369
|
return setPayload(scale.writeId, { sensitivity: value, channel: ctx.channel }, ctx, 0, void 0, "auto");
|
|
4363
4370
|
}
|
|
4364
4371
|
var EXIT_TEST_MODE_VALUE = 808464384;
|
|
4372
|
+
function isT8410(ctx) {
|
|
4373
|
+
return ctx.model === "T8410";
|
|
4374
|
+
}
|
|
4365
4375
|
function requireFamily(action, ctx, verifiedOn) {
|
|
4366
4376
|
const isSensor = ctx.codec === "sensor";
|
|
4367
4377
|
if (isSensor === (verifiedOn === "sensor"))
|
|
@@ -4399,10 +4409,15 @@ var MOTION_MEMBERS = {
|
|
|
4399
4409
|
type: "bool",
|
|
4400
4410
|
kind: "boolean",
|
|
4401
4411
|
provenance: "verified",
|
|
4402
|
-
|
|
4412
|
+
readAvailable: (ctx) => !isT8410(ctx),
|
|
4413
|
+
readAliases: [{ paramType: MOTION_CMD.INDOOR_MOTION_ENABLE, available: isT8410 }],
|
|
4414
|
+
description: "Motion/PIR detection enabled (verified: param 1011 = CAMERA_PIR; a T8410 reads and writes INDOOR_MOTION_ENABLE 6040 instead).",
|
|
4403
4415
|
write: (v, ctx) => {
|
|
4404
4416
|
requireFamily("motionDetection", ctx, "camera");
|
|
4405
|
-
|
|
4417
|
+
const on = asBool(v) ? 1 : 0;
|
|
4418
|
+
if (!isT8410(ctx))
|
|
4419
|
+
return setScalar(MOTION_CMD.CAMERA_PIR, on, ctx, "direct-binary");
|
|
4420
|
+
return setJson(MOTION_CMD.INDOOR_MOTION_ENABLE, { enable: 0, quality: 0, status: on, value: 0 }, ctx);
|
|
4406
4421
|
},
|
|
4407
4422
|
writeAs: "setDetection"
|
|
4408
4423
|
},
|
|
@@ -4766,8 +4781,8 @@ function decodePowerSource(raw) {
|
|
|
4766
4781
|
return String(raw);
|
|
4767
4782
|
}
|
|
4768
4783
|
}
|
|
4769
|
-
const
|
|
4770
|
-
return Number.isFinite(
|
|
4784
|
+
const num3 = Number(raw);
|
|
4785
|
+
return Number.isFinite(num3) ? num3 : String(raw);
|
|
4771
4786
|
}
|
|
4772
4787
|
function recordSetting(param, value, ctx) {
|
|
4773
4788
|
return setStationScalar(param, value, ctx.channel);
|
|
@@ -5268,6 +5283,73 @@ var CONTACT = {
|
|
|
5268
5283
|
}
|
|
5269
5284
|
};
|
|
5270
5285
|
|
|
5286
|
+
// dist/model/device-family.js
|
|
5287
|
+
var INDOOR_CAMERA_TYPES = /* @__PURE__ */ new Set([
|
|
5288
|
+
DeviceType.INDOOR_CAMERA,
|
|
5289
|
+
DeviceType.INDOOR_CAMERA_1080,
|
|
5290
|
+
DeviceType.INDOOR_PT_CAMERA,
|
|
5291
|
+
DeviceType.INDOOR_PT_CAMERA_1080,
|
|
5292
|
+
DeviceType.INDOOR_OUTDOOR_CAMERA_1080P,
|
|
5293
|
+
DeviceType.INDOOR_OUTDOOR_CAMERA_1080P_NO_LIGHT,
|
|
5294
|
+
DeviceType.INDOOR_OUTDOOR_CAMERA_2K,
|
|
5295
|
+
DeviceType.INDOOR_COST_DOWN_CAMERA,
|
|
5296
|
+
DeviceType.INDOOR_PT_CAMERA_S350,
|
|
5297
|
+
DeviceType.INDOOR_PT_CAMERA_E30,
|
|
5298
|
+
DeviceType.INDOOR_PT_CAMERA_C210,
|
|
5299
|
+
DeviceType.INDOOR_PT_CAMERA_C220,
|
|
5300
|
+
DeviceType.INDOOR_PT_CAMERA_C220_V2
|
|
5301
|
+
]);
|
|
5302
|
+
var INDOOR_PT_S350_TYPES = /* @__PURE__ */ new Set([
|
|
5303
|
+
DeviceType.INDOOR_PT_CAMERA_S350,
|
|
5304
|
+
DeviceType.INDOOR_PT_CAMERA_E30,
|
|
5305
|
+
DeviceType.INDOOR_PT_CAMERA_C210,
|
|
5306
|
+
DeviceType.INDOOR_PT_CAMERA_C220,
|
|
5307
|
+
DeviceType.INDOOR_PT_CAMERA_C220_V2
|
|
5308
|
+
]);
|
|
5309
|
+
var OUTDOOR_PT_TYPES = /* @__PURE__ */ new Set([
|
|
5310
|
+
DeviceType.OUTDOOR_PT_CAMERA,
|
|
5311
|
+
DeviceType.SOLO_CAMERA_E30,
|
|
5312
|
+
DeviceType.CAMERA_S4,
|
|
5313
|
+
DeviceType.SOLOCAM_E42,
|
|
5314
|
+
DeviceType.CAMERA_4G_S330
|
|
5315
|
+
]);
|
|
5316
|
+
var FLOODLIGHT_TYPES = /* @__PURE__ */ new Set([
|
|
5317
|
+
DeviceType.FLOODLIGHT,
|
|
5318
|
+
DeviceType.FLOODLIGHT_CAMERA_8422,
|
|
5319
|
+
DeviceType.FLOODLIGHT_CAMERA_8423,
|
|
5320
|
+
DeviceType.FLOODLIGHT_CAMERA_8424,
|
|
5321
|
+
DeviceType.FLOODLIGHT_CAMERA_8425,
|
|
5322
|
+
DeviceType.FLOODLIGHT_CAMERA_8426
|
|
5323
|
+
]);
|
|
5324
|
+
var WALL_LIGHT_TYPES = /* @__PURE__ */ new Set([
|
|
5325
|
+
DeviceType.WALL_LIGHT_CAM,
|
|
5326
|
+
DeviceType.WALL_LIGHT_CAM_81A0,
|
|
5327
|
+
DeviceType.WALL_LIGHT_CAM_T86C1
|
|
5328
|
+
]);
|
|
5329
|
+
var HOMEBASE_TYPES = /* @__PURE__ */ new Set([
|
|
5330
|
+
DeviceType.STATION,
|
|
5331
|
+
DeviceType.HB3,
|
|
5332
|
+
DeviceType.STATION_9000,
|
|
5333
|
+
DeviceType.MINIBASE_CHIME,
|
|
5334
|
+
DeviceType.HOMEBASE_MINI
|
|
5335
|
+
]);
|
|
5336
|
+
var has = (set, t) => t !== void 0 && set.has(t);
|
|
5337
|
+
var isIndoorCamera = (ctx) => has(INDOOR_CAMERA_TYPES, ctx.deviceType);
|
|
5338
|
+
var isIndoorCamMini = (ctx) => ctx.deviceType === DeviceType.INDOOR_COST_DOWN_CAMERA;
|
|
5339
|
+
var isIndoorPanTiltS350 = (ctx) => has(INDOOR_PT_S350_TYPES, ctx.deviceType);
|
|
5340
|
+
var isHomeBase = (ctx) => has(HOMEBASE_TYPES, ctx.deviceType);
|
|
5341
|
+
var isStation9000 = (ctx) => ctx.deviceType === DeviceType.STATION_9000;
|
|
5342
|
+
var isNvrT8N00 = (ctx) => ctx.model === "T8N00";
|
|
5343
|
+
var NVR_MEDIA_CAMERA_MODELS = /* @__PURE__ */ new Set(["T8E00", "T8P00", "T8P10", "T8162", "T8410", "T8214"]);
|
|
5344
|
+
var isNvrMediaCamera = (ctx) => ctx.model !== void 0 && NVR_MEDIA_CAMERA_MODELS.has(ctx.model);
|
|
5345
|
+
var isNvrDualLensCamera = (ctx) => ctx.model === "T8E00";
|
|
5346
|
+
var isNvrFullHdCamera = (ctx) => ctx.model === "T8E00" || ctx.model === "T8P00";
|
|
5347
|
+
var isCallDoorbell = (ctx) => ctx.model === "T8223" || ctx.model === "T8224";
|
|
5348
|
+
var isAiotVacuum = (ctx) => ctx.category !== "eufy_home_tuya";
|
|
5349
|
+
var isTuyaVacuum = (ctx) => ctx.category === "eufy_home_tuya";
|
|
5350
|
+
var isVideoSmartLock = (ctx) => ctx.deviceType === DeviceType.LOCK_8530;
|
|
5351
|
+
var isClassicWifiLock = (ctx) => ctx.deviceType === DeviceType.LOCK_WIFI && typeof ctx.serial === "string" && ctx.serial.startsWith("T8520") && ctx.serial.charAt(6) === "2";
|
|
5352
|
+
|
|
5271
5353
|
// dist/model/capabilities/audio.js
|
|
5272
5354
|
var AUDIO_CMD = {
|
|
5273
5355
|
/**
|
|
@@ -6042,10 +6124,10 @@ function isT8442(ctx) {
|
|
|
6042
6124
|
function usesHomeBasePowerPayload(ctx) {
|
|
6043
6125
|
if (!isT8410HomeBase3(ctx) || !ctx.firmwareVersion || !/^\d+(?:\.\d+){2,3}$/.test(ctx.firmwareVersion))
|
|
6044
6126
|
return false;
|
|
6045
|
-
const
|
|
6127
|
+
const version2 = ctx.firmwareVersion.split(".").map(Number);
|
|
6046
6128
|
const minimum = [2, 3, 1, 0];
|
|
6047
6129
|
for (let i = 0; i < minimum.length; i++) {
|
|
6048
|
-
const difference = (
|
|
6130
|
+
const difference = (version2[i] ?? 0) - minimum[i];
|
|
6049
6131
|
if (difference !== 0)
|
|
6050
6132
|
return difference > 0;
|
|
6051
6133
|
}
|
|
@@ -7198,17 +7280,17 @@ var SMART_LIGHT = {
|
|
|
7198
7280
|
const params = reportFrom(signal);
|
|
7199
7281
|
if (!params)
|
|
7200
7282
|
return null;
|
|
7201
|
-
const
|
|
7283
|
+
const num3 = (id) => params[id] === void 0 ? void 0 : Number(params[id]);
|
|
7202
7284
|
const bool = (id) => params[id] === void 0 ? void 0 : params[id] === "1";
|
|
7203
7285
|
return {
|
|
7204
7286
|
event: "smartLightState",
|
|
7205
7287
|
payload: {
|
|
7206
7288
|
power: bool(LIGHT_PARAM.POWER),
|
|
7207
|
-
brightness:
|
|
7208
|
-
lightLength:
|
|
7209
|
-
effectId:
|
|
7289
|
+
brightness: num3(LIGHT_PARAM.BRIGHTNESS),
|
|
7290
|
+
lightLength: num3(LIGHT_PARAM.LENGTH),
|
|
7291
|
+
effectId: num3(LIGHT_PARAM.EFFECT_ID),
|
|
7210
7292
|
colorGradient: bool(LIGHT_PARAM.COLOR_GRADIENT),
|
|
7211
|
-
cloudEffectId:
|
|
7293
|
+
cloudEffectId: num3(LIGHT_PARAM.CLOUD_EFFECT_ID)
|
|
7212
7294
|
}
|
|
7213
7295
|
};
|
|
7214
7296
|
},
|
|
@@ -9229,11 +9311,11 @@ function decodeDoNotDisturbTime(raw, codec, field) {
|
|
|
9229
9311
|
const point = codec.nested(window.value)?.find((f) => f.field === field);
|
|
9230
9312
|
if (point?.kind !== "bytes")
|
|
9231
9313
|
return void 0;
|
|
9232
|
-
const
|
|
9233
|
-
if (!
|
|
9314
|
+
const parts2 = codec.nested(point.value);
|
|
9315
|
+
if (!parts2)
|
|
9234
9316
|
return void 0;
|
|
9235
9317
|
const at = (n) => {
|
|
9236
|
-
const hit =
|
|
9318
|
+
const hit = parts2.find((f) => f.field === n);
|
|
9237
9319
|
return hit?.kind === "int" ? Number(hit.value) : 0;
|
|
9238
9320
|
};
|
|
9239
9321
|
return `${String(at(UNDISTURBED_FIELD.HOUR)).padStart(2, "0")}:${String(at(UNDISTURBED_FIELD.MINUTE)).padStart(2, "0")}`;
|
|
@@ -11227,12 +11309,12 @@ function parseDpCatalog(raw) {
|
|
|
11227
11309
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
11228
11310
|
return EMPTY_DP_CATALOG;
|
|
11229
11311
|
const r = raw;
|
|
11230
|
-
const
|
|
11231
|
-
if (!Array.isArray(
|
|
11312
|
+
const list2 = r.data_point_list;
|
|
11313
|
+
if (!Array.isArray(list2) || list2.length === 0)
|
|
11232
11314
|
return EMPTY_DP_CATALOG;
|
|
11233
11315
|
let found = 0;
|
|
11234
11316
|
const enumRanges = /* @__PURE__ */ new Map();
|
|
11235
|
-
for (const entry of
|
|
11317
|
+
for (const entry of list2) {
|
|
11236
11318
|
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
11237
11319
|
continue;
|
|
11238
11320
|
const e = entry;
|
|
@@ -11537,14 +11619,14 @@ function mergeProperties(caps, ctx) {
|
|
|
11537
11619
|
return merged;
|
|
11538
11620
|
}
|
|
11539
11621
|
function hintHaystack(rec) {
|
|
11540
|
-
const
|
|
11622
|
+
const parts2 = [rec.model, rec.category];
|
|
11541
11623
|
const loose = rec;
|
|
11542
11624
|
for (const key of ["name", "device_name", "alias", "product_name"]) {
|
|
11543
11625
|
const v = loose[key];
|
|
11544
11626
|
if (typeof v === "string")
|
|
11545
|
-
|
|
11627
|
+
parts2.push(v);
|
|
11546
11628
|
}
|
|
11547
|
-
return
|
|
11629
|
+
return parts2.filter((p) => typeof p === "string").join(" ");
|
|
11548
11630
|
}
|
|
11549
11631
|
var CODEC_LINE = {
|
|
11550
11632
|
station: "security",
|
|
@@ -11588,7 +11670,7 @@ function detectCapabilities(rec, codec) {
|
|
|
11588
11670
|
matched = d.deviceTypes.includes(rec.deviceType);
|
|
11589
11671
|
}
|
|
11590
11672
|
if (!matched && d.modelHints && haystack.length > 0) {
|
|
11591
|
-
matched = d.modelHints.some((
|
|
11673
|
+
matched = d.modelHints.some((re2) => re2.test(haystack));
|
|
11592
11674
|
}
|
|
11593
11675
|
if (!matched && d.codecs && codec !== void 0) {
|
|
11594
11676
|
matched = d.codecs.includes(codec);
|
|
@@ -11775,9 +11857,9 @@ function memberCommand(m, action, value, ctx) {
|
|
|
11775
11857
|
for (const [name, member] of Object.entries(m.members ?? {})) {
|
|
11776
11858
|
if (!("type" in member))
|
|
11777
11859
|
continue;
|
|
11778
|
-
const
|
|
11860
|
+
const property2 = member.property ?? name;
|
|
11779
11861
|
const aliased = member.aliases?.[action];
|
|
11780
|
-
const claims = action ===
|
|
11862
|
+
const claims = action === property2 || member.intentNames?.includes(action) === true;
|
|
11781
11863
|
if (!claims && aliased === void 0)
|
|
11782
11864
|
continue;
|
|
11783
11865
|
if (member.unverified) {
|
|
@@ -11785,7 +11867,10 @@ function memberCommand(m, action, value, ctx) {
|
|
|
11785
11867
|
}
|
|
11786
11868
|
if (!member.write || !installs(member, ctx))
|
|
11787
11869
|
continue;
|
|
11788
|
-
|
|
11870
|
+
const cmd = memberWrite(name, member, claims ? value : aliased, ctx);
|
|
11871
|
+
if (!kindRoutable(cmd.kind, ctx))
|
|
11872
|
+
continue;
|
|
11873
|
+
return cmd;
|
|
11789
11874
|
}
|
|
11790
11875
|
return void 0;
|
|
11791
11876
|
}
|
|
@@ -11985,6 +12070,7 @@ function resolveProperties(rec, codec, capabilities) {
|
|
|
11985
12070
|
category: rec.category,
|
|
11986
12071
|
capabilities: new Set(capabilities),
|
|
11987
12072
|
paramIds,
|
|
12073
|
+
things: rec.things,
|
|
11988
12074
|
stationSerial: rec.parentSn
|
|
11989
12075
|
});
|
|
11990
12076
|
}
|
|
@@ -14320,11 +14406,11 @@ function parseCleanRecords(raw) {
|
|
|
14320
14406
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
14321
14407
|
return EMPTY_CLEAN_RECORD_PAGE;
|
|
14322
14408
|
const r = raw;
|
|
14323
|
-
const
|
|
14324
|
-
if (!Array.isArray(
|
|
14409
|
+
const list2 = r.clean_record_list;
|
|
14410
|
+
if (!Array.isArray(list2))
|
|
14325
14411
|
return EMPTY_CLEAN_RECORD_PAGE;
|
|
14326
14412
|
const records = [];
|
|
14327
|
-
for (const entry of
|
|
14413
|
+
for (const entry of list2) {
|
|
14328
14414
|
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
14329
14415
|
continue;
|
|
14330
14416
|
const e = entry;
|
|
@@ -14386,17 +14472,17 @@ function parseCleanRecordDetail(blob, codec) {
|
|
|
14386
14472
|
const fields = codec.nested(Buffer.from(body));
|
|
14387
14473
|
if (!fields)
|
|
14388
14474
|
return void 0;
|
|
14389
|
-
const
|
|
14475
|
+
const num3 = (field) => {
|
|
14390
14476
|
const found = fields.find((f) => f.field === field);
|
|
14391
14477
|
return found?.kind === "int" ? Number(found.value) : 0;
|
|
14392
14478
|
};
|
|
14393
14479
|
const reason = fields.find((f) => f.field === DETAIL_FIELD.FINISH_REASON);
|
|
14394
14480
|
return {
|
|
14395
|
-
startTime:
|
|
14396
|
-
endTime:
|
|
14397
|
-
duration:
|
|
14398
|
-
area:
|
|
14399
|
-
cleanType:
|
|
14481
|
+
startTime: num3(DETAIL_FIELD.START_TIME),
|
|
14482
|
+
endTime: num3(DETAIL_FIELD.END_TIME),
|
|
14483
|
+
duration: num3(DETAIL_FIELD.DURATION),
|
|
14484
|
+
area: num3(DETAIL_FIELD.AREA),
|
|
14485
|
+
cleanType: num3(DETAIL_FIELD.CLEAN_TYPE),
|
|
14400
14486
|
// An absent reason is the enum's zero member, which is `completed` — the ordinary way a run ends.
|
|
14401
14487
|
finishReason: reason === void 0 ? CLEAN_FINISH_REASONS[0] : reason.kind === "int" ? CLEAN_FINISH_REASONS[Number(reason.value)] : void 0
|
|
14402
14488
|
};
|
|
@@ -14889,6 +14975,7 @@ function inspectParams(rec, sn) {
|
|
|
14889
14975
|
},
|
|
14890
14976
|
suggestedRegistry: { model, entry, exists: !!MODEL_REGISTRY[model.toUpperCase()] },
|
|
14891
14977
|
registrySnippet: buildRegistrySnippet(model, entry),
|
|
14978
|
+
things: rec.things,
|
|
14892
14979
|
dictionarySnippet: buildDictSnippet(model, unknown)
|
|
14893
14980
|
};
|
|
14894
14981
|
}
|
|
@@ -15183,9 +15270,9 @@ function sceneNum(v) {
|
|
|
15183
15270
|
return void 0;
|
|
15184
15271
|
}
|
|
15185
15272
|
function solarbankSceneReadings(scene) {
|
|
15186
|
-
const
|
|
15273
|
+
const list2 = scene.solarbank_info?.solarbank_list ?? [];
|
|
15187
15274
|
const out = [];
|
|
15188
|
-
for (const sb of
|
|
15275
|
+
for (const sb of list2) {
|
|
15189
15276
|
const deviceSn = typeof sb.device_sn === "string" ? sb.device_sn : void 0;
|
|
15190
15277
|
if (!deviceSn)
|
|
15191
15278
|
continue;
|
|
@@ -16413,11 +16500,11 @@ var CMD_CAMERA_INFO = 1103;
|
|
|
16413
16500
|
var GCM_AAD = Buffer.from("eufy security");
|
|
16414
16501
|
var LEVEL2_SEQ_BASE = 16909056;
|
|
16415
16502
|
function paramReport(payload) {
|
|
16416
|
-
const
|
|
16417
|
-
if (!Array.isArray(
|
|
16503
|
+
const list2 = payload?.params;
|
|
16504
|
+
if (!Array.isArray(list2))
|
|
16418
16505
|
return void 0;
|
|
16419
16506
|
const out = {};
|
|
16420
|
-
for (const entry of
|
|
16507
|
+
for (const entry of list2) {
|
|
16421
16508
|
const p = entry;
|
|
16422
16509
|
if (typeof p?.param_type !== "number" || p.param_value == null)
|
|
16423
16510
|
continue;
|
|
@@ -16426,11 +16513,11 @@ function paramReport(payload) {
|
|
|
16426
16513
|
return Object.keys(out).length ? out : void 0;
|
|
16427
16514
|
}
|
|
16428
16515
|
function channelReport(payload) {
|
|
16429
|
-
const
|
|
16430
|
-
if (!Array.isArray(
|
|
16516
|
+
const list2 = payload?.params;
|
|
16517
|
+
if (!Array.isArray(list2))
|
|
16431
16518
|
return void 0;
|
|
16432
16519
|
const out = {};
|
|
16433
|
-
for (const entry of
|
|
16520
|
+
for (const entry of list2) {
|
|
16434
16521
|
const p = entry;
|
|
16435
16522
|
if (typeof p?.dev_type !== "number" || typeof p.param_type !== "number" || p.param_value == null)
|
|
16436
16523
|
continue;
|
|
@@ -18251,19 +18338,19 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
18251
18338
|
if (!this.connectAddress)
|
|
18252
18339
|
throw new Error("not connected");
|
|
18253
18340
|
const channel = opts.channel ?? 0;
|
|
18254
|
-
const
|
|
18341
|
+
const keyed2 = opts.key !== void 0;
|
|
18255
18342
|
const inner = opts.rawValue ?? {
|
|
18256
|
-
...
|
|
18343
|
+
...keyed2 ? { key: opts.key } : {},
|
|
18257
18344
|
account_id: opts.accountId ?? "",
|
|
18258
18345
|
cmd: subCmd,
|
|
18259
18346
|
mChannel: channel,
|
|
18260
18347
|
mValue3: 0,
|
|
18261
18348
|
...opts.omitPayload ? {} : { payload }
|
|
18262
18349
|
};
|
|
18263
|
-
const value =
|
|
18350
|
+
const value = keyed2 ? JSON.stringify(inner).replace(/=/g, "\\u003d") : JSON.stringify(inner);
|
|
18264
18351
|
const body = Buffer.concat([
|
|
18265
18352
|
buildCommandHeader(this.seqNumber, opts.wrapCmd ?? CMD_SET_PAYLOAD),
|
|
18266
|
-
buildStringCommandPayload(value, channel,
|
|
18353
|
+
buildStringCommandPayload(value, channel, keyed2 ? void 0 : this.level1Key, 1)
|
|
18267
18354
|
]);
|
|
18268
18355
|
this.seqNumber = this.seqNumber + 1 & 65535;
|
|
18269
18356
|
this.logger.debug(`[p2p] ${this.cfg.stationSn} sendSetPayload subCmd=${subCmd}`);
|
|
@@ -22076,15 +22163,15 @@ var Fmp4Muxer = class {
|
|
|
22076
22163
|
avcC() {
|
|
22077
22164
|
const ps = this.params;
|
|
22078
22165
|
const sps = ps.sps[0] ?? Buffer.alloc(4);
|
|
22079
|
-
const
|
|
22166
|
+
const parts2 = [
|
|
22080
22167
|
Buffer.from([1, sps[1] ?? 66, sps[2] ?? 0, sps[3] ?? 30, 255, 224 | ps.sps.length])
|
|
22081
22168
|
];
|
|
22082
22169
|
for (const s of ps.sps)
|
|
22083
|
-
|
|
22084
|
-
|
|
22170
|
+
parts2.push(u16(s.length), s);
|
|
22171
|
+
parts2.push(Buffer.from([ps.pps.length]));
|
|
22085
22172
|
for (const p of ps.pps)
|
|
22086
|
-
|
|
22087
|
-
return Buffer.concat(
|
|
22173
|
+
parts2.push(u16(p.length), p);
|
|
22174
|
+
return Buffer.concat(parts2);
|
|
22088
22175
|
}
|
|
22089
22176
|
hvcC() {
|
|
22090
22177
|
const ps = this.params;
|
|
@@ -22128,10 +22215,10 @@ var Fmp4Muxer = class {
|
|
|
22128
22215
|
const push = (nalType, nals) => {
|
|
22129
22216
|
if (!nals.length)
|
|
22130
22217
|
return;
|
|
22131
|
-
const
|
|
22218
|
+
const parts2 = [Buffer.from([128 | nalType]), u16(nals.length)];
|
|
22132
22219
|
for (const n of nals)
|
|
22133
|
-
|
|
22134
|
-
arrays.push(Buffer.concat(
|
|
22220
|
+
parts2.push(u16(n.length), n);
|
|
22221
|
+
arrays.push(Buffer.concat(parts2));
|
|
22135
22222
|
};
|
|
22136
22223
|
push(32, ps.vps);
|
|
22137
22224
|
push(33, ps.sps);
|
|
@@ -22173,11 +22260,11 @@ var Fmp4Muxer = class {
|
|
|
22173
22260
|
*/
|
|
22174
22261
|
trun(samples) {
|
|
22175
22262
|
const flags = 1793;
|
|
22176
|
-
const
|
|
22263
|
+
const parts2 = [u32(flags), u32(samples.length), u32(0)];
|
|
22177
22264
|
for (const s of samples) {
|
|
22178
|
-
|
|
22265
|
+
parts2.push(u32(s.duration), u32(s.data.length), u32(s.keyframe ? 33554432 : 16842752));
|
|
22179
22266
|
}
|
|
22180
|
-
return box("trun", Buffer.concat(
|
|
22267
|
+
return box("trun", Buffer.concat(parts2));
|
|
22181
22268
|
}
|
|
22182
22269
|
hasAudioTrack() {
|
|
22183
22270
|
return !!this.audioCodec && !this.audioDisabled;
|
|
@@ -24730,10 +24817,10 @@ var H264Depacketizer = class {
|
|
|
24730
24817
|
}
|
|
24731
24818
|
if (marker) {
|
|
24732
24819
|
if (!this.broken && !this.fu && this.nals.length) {
|
|
24733
|
-
const
|
|
24820
|
+
const parts2 = [];
|
|
24734
24821
|
for (const n of this.nals)
|
|
24735
|
-
|
|
24736
|
-
this.onUnit(Buffer.concat(
|
|
24822
|
+
parts2.push(START_CODE, n);
|
|
24823
|
+
this.onUnit(Buffer.concat(parts2), timestamp);
|
|
24737
24824
|
}
|
|
24738
24825
|
this.nals = [];
|
|
24739
24826
|
this.fu = void 0;
|
|
@@ -24887,18 +24974,18 @@ var PtcsReassembler = class {
|
|
|
24887
24974
|
if (p.lastIndex === void 0)
|
|
24888
24975
|
return true;
|
|
24889
24976
|
let total = 0;
|
|
24890
|
-
const
|
|
24977
|
+
const parts2 = [];
|
|
24891
24978
|
for (let i = 0; i <= p.lastIndex; i++) {
|
|
24892
24979
|
const c = p.chunks.get(i);
|
|
24893
24980
|
if (!c)
|
|
24894
24981
|
return true;
|
|
24895
|
-
|
|
24982
|
+
parts2.push(c);
|
|
24896
24983
|
total += c.length;
|
|
24897
24984
|
}
|
|
24898
24985
|
this.partials.delete(key);
|
|
24899
24986
|
if (total !== p.frameLength)
|
|
24900
24987
|
return false;
|
|
24901
|
-
this.onFrame(Buffer.concat(
|
|
24988
|
+
this.onFrame(Buffer.concat(parts2, total), p.channel);
|
|
24902
24989
|
return true;
|
|
24903
24990
|
}
|
|
24904
24991
|
/** Drop frames that stopped arriving; call periodically. */
|
|
@@ -25871,6 +25958,11 @@ var StationStreamBusyError = class extends Error {
|
|
|
25871
25958
|
this.name = "StationStreamBusyError";
|
|
25872
25959
|
}
|
|
25873
25960
|
};
|
|
25961
|
+
var RTC_CONTROL_COMMAND_KINDS = /* @__PURE__ */ new Set([
|
|
25962
|
+
"set-payload",
|
|
25963
|
+
"set-json"
|
|
25964
|
+
]);
|
|
25965
|
+
var isRtcControlCommand = (cmd) => RTC_CONTROL_COMMAND_KINDS.has(cmd.kind);
|
|
25874
25966
|
var RtcCommandRouter = class {
|
|
25875
25967
|
deps;
|
|
25876
25968
|
sessions = /* @__PURE__ */ new Map();
|
|
@@ -25884,7 +25976,7 @@ var RtcCommandRouter = class {
|
|
|
25884
25976
|
this.deps = deps;
|
|
25885
25977
|
}
|
|
25886
25978
|
async dispatchCommand(route, cmd) {
|
|
25887
|
-
if (cmd
|
|
25979
|
+
if (!isRtcControlCommand(cmd)) {
|
|
25888
25980
|
throw new Error(`rtc: ${cmd.kind} is not routable over the RTC control channel (only set-payload or set-json)`);
|
|
25889
25981
|
}
|
|
25890
25982
|
if (route.mediaTrack)
|
|
@@ -28447,10 +28539,10 @@ var McsParser = class extends EventEmitter12 {
|
|
|
28447
28539
|
}
|
|
28448
28540
|
}
|
|
28449
28541
|
onVersion() {
|
|
28450
|
-
const
|
|
28542
|
+
const version2 = this.data.readInt8(0);
|
|
28451
28543
|
this.data = this.data.subarray(1);
|
|
28452
|
-
if (
|
|
28453
|
-
throw new Error(`MCS: wrong protocol version ${
|
|
28544
|
+
if (version2 < 38)
|
|
28545
|
+
throw new Error(`MCS: wrong protocol version ${version2}`);
|
|
28454
28546
|
this.onTag();
|
|
28455
28547
|
}
|
|
28456
28548
|
onTag() {
|
|
@@ -29140,7 +29232,272 @@ function mediaFailureTag(error) {
|
|
|
29140
29232
|
return Number.isInteger(status) && status >= 100 && status <= 599 ? { cause, status } : { cause };
|
|
29141
29233
|
}
|
|
29142
29234
|
|
|
29235
|
+
// dist/model/capabilities/thing-description.js
|
|
29236
|
+
var APP_SDK_VERSION = "2.3.3.1";
|
|
29237
|
+
var SUFFIXED_STATION_PREFIXES = ["T8010", "T8020", "T8021", "T8023"];
|
|
29238
|
+
function re(pattern, value) {
|
|
29239
|
+
if (!pattern || !value)
|
|
29240
|
+
return true;
|
|
29241
|
+
if (pattern.length > 512 || value.length > 2048)
|
|
29242
|
+
return false;
|
|
29243
|
+
try {
|
|
29244
|
+
const insensitive = pattern.includes("(?i)");
|
|
29245
|
+
return new RegExp(pattern.replaceAll("(?i)", ""), insensitive ? "i" : "").test(value);
|
|
29246
|
+
} catch {
|
|
29247
|
+
return false;
|
|
29248
|
+
}
|
|
29249
|
+
}
|
|
29250
|
+
var parts = (v) => v.split(".");
|
|
29251
|
+
var intOf = (s) => {
|
|
29252
|
+
const t = (s ?? "0").replace(/[a-zA-Z]+$/, "");
|
|
29253
|
+
return /^[+-]?\d+$/.test(t) ? Number(t) : void 0;
|
|
29254
|
+
};
|
|
29255
|
+
var numericPrefix = (p) => {
|
|
29256
|
+
const i = p.findIndex((s) => intOf(s) === void 0);
|
|
29257
|
+
return i < 0 ? p.length : i;
|
|
29258
|
+
};
|
|
29259
|
+
function versionAbove(a, b) {
|
|
29260
|
+
const pa = parts(a);
|
|
29261
|
+
const pb = parts(b);
|
|
29262
|
+
const n = Math.max(numericPrefix(pa), numericPrefix(pb));
|
|
29263
|
+
for (let i = 0; i < n; i++) {
|
|
29264
|
+
const d = (intOf(pa[i]) ?? 0) - (intOf(pb[i]) ?? 0);
|
|
29265
|
+
if (d !== 0)
|
|
29266
|
+
return d > 0;
|
|
29267
|
+
}
|
|
29268
|
+
const ta = pa.slice(n);
|
|
29269
|
+
const tb = pb.slice(n);
|
|
29270
|
+
if (!ta.length || !tb.length)
|
|
29271
|
+
return ta.length > 0 && !tb.length;
|
|
29272
|
+
const lastInt = (t) => t.findLastIndex((s) => /^[+-]?\d+$/.test(s));
|
|
29273
|
+
const ia = lastInt(ta);
|
|
29274
|
+
const ib = lastInt(tb);
|
|
29275
|
+
const head = (t, i) => (i >= 0 ? t.slice(0, i) : t).join(".");
|
|
29276
|
+
if (head(ta, ia) !== head(tb, ib))
|
|
29277
|
+
return false;
|
|
29278
|
+
return (ia >= 0 ? Number(ta[ia]) : 0) > (ib >= 0 ? Number(tb[ib]) : 0);
|
|
29279
|
+
}
|
|
29280
|
+
function versionEqual(a, b) {
|
|
29281
|
+
const pa = parts(a);
|
|
29282
|
+
const pb = parts(b);
|
|
29283
|
+
const n = Math.max(numericPrefix(pa), numericPrefix(pb));
|
|
29284
|
+
for (let i = 0; i < n; i++)
|
|
29285
|
+
if ((intOf(pa[i]) ?? 0) !== (intOf(pb[i]) ?? 0))
|
|
29286
|
+
return false;
|
|
29287
|
+
return pa.slice(n).join(".") === pb.slice(n).join(".");
|
|
29288
|
+
}
|
|
29289
|
+
function version(current, qualifier, target) {
|
|
29290
|
+
switch (qualifier) {
|
|
29291
|
+
case "<":
|
|
29292
|
+
return versionAbove(target, current);
|
|
29293
|
+
case "<=":
|
|
29294
|
+
return versionAbove(target, current) || versionEqual(current, target);
|
|
29295
|
+
case "=":
|
|
29296
|
+
return versionEqual(current, target);
|
|
29297
|
+
case "!=":
|
|
29298
|
+
return !versionEqual(current, target);
|
|
29299
|
+
case ">=":
|
|
29300
|
+
return versionAbove(current, target) || versionEqual(current, target);
|
|
29301
|
+
case ">":
|
|
29302
|
+
return versionAbove(current, target);
|
|
29303
|
+
case "RE":
|
|
29304
|
+
return re(target, current);
|
|
29305
|
+
default:
|
|
29306
|
+
return false;
|
|
29307
|
+
}
|
|
29308
|
+
}
|
|
29309
|
+
function compare(current, qualifier, target) {
|
|
29310
|
+
if (qualifier === "RE")
|
|
29311
|
+
return re(target, current);
|
|
29312
|
+
switch (qualifier) {
|
|
29313
|
+
case "=":
|
|
29314
|
+
return current === target;
|
|
29315
|
+
case "!=":
|
|
29316
|
+
return current !== target;
|
|
29317
|
+
case "<":
|
|
29318
|
+
return current < target;
|
|
29319
|
+
case "<=":
|
|
29320
|
+
return current <= target;
|
|
29321
|
+
case ">=":
|
|
29322
|
+
return current >= target;
|
|
29323
|
+
case ">":
|
|
29324
|
+
return current > target;
|
|
29325
|
+
default:
|
|
29326
|
+
return false;
|
|
29327
|
+
}
|
|
29328
|
+
}
|
|
29329
|
+
function cameraInfo(facts, qualifier, value) {
|
|
29330
|
+
let spec;
|
|
29331
|
+
try {
|
|
29332
|
+
spec = JSON.parse(value);
|
|
29333
|
+
} catch {
|
|
29334
|
+
return false;
|
|
29335
|
+
}
|
|
29336
|
+
const reported = typeof spec?.param === "number" ? facts.params?.[spec.param] : void 0;
|
|
29337
|
+
if (reported === void 0)
|
|
29338
|
+
return false;
|
|
29339
|
+
if (qualifier === "equals")
|
|
29340
|
+
return typeof spec.value === "string" && spec.value === reported;
|
|
29341
|
+
if (qualifier === "RE")
|
|
29342
|
+
return typeof spec.regex === "string" && re(spec.regex, reported);
|
|
29343
|
+
return false;
|
|
29344
|
+
}
|
|
29345
|
+
function condition(c, facts) {
|
|
29346
|
+
const station = facts.stationSerial ?? facts.serial ?? "";
|
|
29347
|
+
switch (c.type) {
|
|
29348
|
+
case "device_version":
|
|
29349
|
+
return version(facts.firmwareVersion ?? "", c.qualifier, c.value);
|
|
29350
|
+
case "parent_version": {
|
|
29351
|
+
const v = facts.stationFirmwareVersion ?? "";
|
|
29352
|
+
const clean = SUFFIXED_STATION_PREFIXES.some((p) => station.startsWith(p)) ? v.replace(/[^0-9.][^.]*/g, "") : v;
|
|
29353
|
+
return version(clean, c.qualifier, c.value);
|
|
29354
|
+
}
|
|
29355
|
+
case "parent_sn":
|
|
29356
|
+
return re(c.value, station);
|
|
29357
|
+
case "device_sn":
|
|
29358
|
+
return re(c.value, facts.serial ?? "");
|
|
29359
|
+
case "user_country":
|
|
29360
|
+
return re(c.value, facts.country ?? "");
|
|
29361
|
+
case "user_domain":
|
|
29362
|
+
return re(c.value, "");
|
|
29363
|
+
case "sdk_version":
|
|
29364
|
+
return version(APP_SDK_VERSION, c.qualifier, c.value);
|
|
29365
|
+
case "associated_field":
|
|
29366
|
+
case "parent_associated_field":
|
|
29367
|
+
return compare("", c.qualifier, c.value);
|
|
29368
|
+
case "user_permission":
|
|
29369
|
+
return c.qualifier === "in";
|
|
29370
|
+
case "camera_info":
|
|
29371
|
+
return cameraInfo(facts, c.qualifier, c.value);
|
|
29372
|
+
default:
|
|
29373
|
+
return false;
|
|
29374
|
+
}
|
|
29375
|
+
}
|
|
29376
|
+
function conditionsPass(list2, facts) {
|
|
29377
|
+
return list2.length === 0 || list2.some((entry) => entry.every((c) => condition(c, facts)));
|
|
29378
|
+
}
|
|
29379
|
+
var bare = (identifier) => {
|
|
29380
|
+
const i = identifier.toLowerCase().indexOf("__v");
|
|
29381
|
+
return i > 0 ? identifier.slice(0, i) : identifier;
|
|
29382
|
+
};
|
|
29383
|
+
function resolveThing(td, facts) {
|
|
29384
|
+
const properties = /* @__PURE__ */ Object.create(null);
|
|
29385
|
+
const keys = Object.keys(td.properties);
|
|
29386
|
+
for (const base of new Set(keys.map(bare))) {
|
|
29387
|
+
let chosen = base;
|
|
29388
|
+
let most = -1;
|
|
29389
|
+
for (const key of keys) {
|
|
29390
|
+
if (key === base || bare(key) !== base)
|
|
29391
|
+
continue;
|
|
29392
|
+
const p2 = td.properties[key];
|
|
29393
|
+
if (p2.readConditions.length === 0 || !conditionsPass(p2.readConditions, facts))
|
|
29394
|
+
continue;
|
|
29395
|
+
const count2 = p2.readConditions.reduce((n, entry) => n + entry.length, 0);
|
|
29396
|
+
if (count2 > most)
|
|
29397
|
+
[chosen, most] = [key, count2];
|
|
29398
|
+
}
|
|
29399
|
+
const p = td.properties[chosen];
|
|
29400
|
+
if (!p || !conditionsPass(p.availableConditions, facts))
|
|
29401
|
+
continue;
|
|
29402
|
+
properties[base] = conditionsPass(p.writeConditions, facts) ? p : { ...p, accessMode: "R" };
|
|
29403
|
+
}
|
|
29404
|
+
const available = (entries) => {
|
|
29405
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
29406
|
+
for (const [k, v] of Object.entries(entries))
|
|
29407
|
+
if (conditionsPass(v.availableConditions, facts))
|
|
29408
|
+
out[k] = v;
|
|
29409
|
+
return out;
|
|
29410
|
+
};
|
|
29411
|
+
return { ...td, properties, actions: available(td.actions), events: available(td.events) };
|
|
29412
|
+
}
|
|
29413
|
+
var str3 = (v) => typeof v === "string" ? v : v == null ? "" : String(v);
|
|
29414
|
+
var optStr = (v) => v == null || v === "" ? void 0 : str3(v);
|
|
29415
|
+
var num2 = (v) => {
|
|
29416
|
+
const n = typeof v === "number" ? v : typeof v === "string" && v.trim() !== "" ? Number(v) : NaN;
|
|
29417
|
+
return Number.isFinite(n) ? n : void 0;
|
|
29418
|
+
};
|
|
29419
|
+
var list = (v) => Array.isArray(v) ? v.filter((x) => x && typeof x === "object") : [];
|
|
29420
|
+
function conditions(v) {
|
|
29421
|
+
return list(v?.condition_list).map((entry) => list(entry.conditions).map((c) => ({
|
|
29422
|
+
type: str3(c.type),
|
|
29423
|
+
qualifier: str3(c.qualifier),
|
|
29424
|
+
value: str3(c.value),
|
|
29425
|
+
...c.prop_id ? { propId: str3(c.prop_id) } : {}
|
|
29426
|
+
})));
|
|
29427
|
+
}
|
|
29428
|
+
function keyed(entries, parse) {
|
|
29429
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
29430
|
+
for (const e of entries)
|
|
29431
|
+
if (typeof e.identifier === "string" && e.identifier)
|
|
29432
|
+
out[e.identifier] = parse(e);
|
|
29433
|
+
return out;
|
|
29434
|
+
}
|
|
29435
|
+
function property(p) {
|
|
29436
|
+
const specs = p.data_type?.specs ?? {};
|
|
29437
|
+
return {
|
|
29438
|
+
identifier: p.identifier,
|
|
29439
|
+
accessMode: str3(p.access_mode),
|
|
29440
|
+
type: str3(p.data_type?.type),
|
|
29441
|
+
members: list(specs.eunmList).map((m) => ({
|
|
29442
|
+
value: str3(m.value),
|
|
29443
|
+
...m.associatedValue != null ? { wireValue: str3(m.associatedValue) } : {},
|
|
29444
|
+
desc: str3(m.desc),
|
|
29445
|
+
isDefault: m.isDefault === 1 || m.isDefault === true
|
|
29446
|
+
})),
|
|
29447
|
+
...optStr(specs.defaultValue) !== void 0 ? { defaultValue: str3(specs.defaultValue) } : {},
|
|
29448
|
+
...num2(specs.min) !== void 0 ? { min: num2(specs.min) } : {},
|
|
29449
|
+
...num2(specs.max) !== void 0 ? { max: num2(specs.max) } : {},
|
|
29450
|
+
...num2(specs.step) !== void 0 ? { step: num2(specs.step) } : {},
|
|
29451
|
+
...optStr(specs.unit) !== void 0 ? { unit: str3(specs.unit) } : {},
|
|
29452
|
+
readConditions: conditions(p.read_conditions),
|
|
29453
|
+
writeConditions: conditions(p.write_conditions),
|
|
29454
|
+
availableConditions: conditions(p.available_conditions)
|
|
29455
|
+
};
|
|
29456
|
+
}
|
|
29457
|
+
function parseThingsList(raw) {
|
|
29458
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
29459
|
+
for (const t of list(raw?.things_list)) {
|
|
29460
|
+
const profile = t.profile ?? {};
|
|
29461
|
+
const code = profile.product_code;
|
|
29462
|
+
if (typeof code !== "string" || !code)
|
|
29463
|
+
continue;
|
|
29464
|
+
out[code] = {
|
|
29465
|
+
productCode: code,
|
|
29466
|
+
version: str3(t.version),
|
|
29467
|
+
updateTime: num2(t.update_time) ?? 0,
|
|
29468
|
+
largeVersion: num2(t.large_version) ?? 0,
|
|
29469
|
+
largeVersionUpdateTime: num2(t.large_version_update_time) ?? 0,
|
|
29470
|
+
bundle: {
|
|
29471
|
+
id: str3(profile.plugin_id),
|
|
29472
|
+
path: str3(profile.plugin_path),
|
|
29473
|
+
zipId: str3(profile.plugin_id_zip),
|
|
29474
|
+
zipPath: str3(profile.plugin_path_zip)
|
|
29475
|
+
},
|
|
29476
|
+
properties: keyed(list(t.properties), property),
|
|
29477
|
+
actions: keyed(list(t.actions), (a) => ({
|
|
29478
|
+
identifier: a.identifier,
|
|
29479
|
+
...optStr(a.input_data?.type) ? { inputType: str3(a.input_data.type) } : {},
|
|
29480
|
+
...optStr(a.output_data?.type) ? { outputType: str3(a.output_data.type) } : {},
|
|
29481
|
+
availableConditions: conditions(a.available_conditions)
|
|
29482
|
+
})),
|
|
29483
|
+
events: keyed(list(t.events), (e) => ({
|
|
29484
|
+
identifier: e.identifier,
|
|
29485
|
+
eventType: str3(e.event_type),
|
|
29486
|
+
...optStr(e.output_data?.type) ? { outputType: str3(e.output_data.type) } : {},
|
|
29487
|
+
...optStr(e.output_data?.specs?.defaultValue) ? { defaultValue: str3(e.output_data.specs.defaultValue) } : {},
|
|
29488
|
+
availableConditions: conditions(e.available_conditions)
|
|
29489
|
+
}))
|
|
29490
|
+
};
|
|
29491
|
+
}
|
|
29492
|
+
return out;
|
|
29493
|
+
}
|
|
29494
|
+
|
|
29143
29495
|
// dist/client/device-registry.js
|
|
29496
|
+
function recordString(raw, key) {
|
|
29497
|
+
const nested = raw.deviceParams?.[key];
|
|
29498
|
+
const v = typeof nested === "string" && nested ? nested : raw[key];
|
|
29499
|
+
return typeof v === "string" && v ? v : void 0;
|
|
29500
|
+
}
|
|
29144
29501
|
function mergeParams(raw, params, paramUpdatedAt) {
|
|
29145
29502
|
for (const p of raw ?? []) {
|
|
29146
29503
|
if (!p || p.param_type == null || p.param_value == null)
|
|
@@ -29211,6 +29568,8 @@ var DeviceRegistry = class {
|
|
|
29211
29568
|
deviceCapsCache = /* @__PURE__ */ new Map();
|
|
29212
29569
|
/** Per-serial cloud data points of an AIoT robot, joined beneath the params in {@link record} — see {@link loadCloudDps}. */
|
|
29213
29570
|
cloudDps = /* @__PURE__ */ new Map();
|
|
29571
|
+
/** Per-product-code thing description — see {@link loadThings}; `undefined` for a code the cloud returned none for. */
|
|
29572
|
+
things = /* @__PURE__ */ new Map();
|
|
29214
29573
|
/** Per-serial realtime state, keyed by param id in the device's own namespace (see {@link DeviceRecord.dpParams}). */
|
|
29215
29574
|
dpParams = /* @__PURE__ */ new Map();
|
|
29216
29575
|
/** Callers blocked in {@link awaitRealtimeState}, released by the device's first report. */
|
|
@@ -29324,6 +29683,7 @@ var DeviceRegistry = class {
|
|
|
29324
29683
|
}
|
|
29325
29684
|
}
|
|
29326
29685
|
await this.loadCloudDps(seen);
|
|
29686
|
+
await this.loadThings(seen);
|
|
29327
29687
|
this.lastRefreshPartial = partial;
|
|
29328
29688
|
if (partial) {
|
|
29329
29689
|
for (const prev of this.devices)
|
|
@@ -29450,6 +29810,45 @@ var DeviceRegistry = class {
|
|
|
29450
29810
|
this.cloudDps.set(sn, dps);
|
|
29451
29811
|
}
|
|
29452
29812
|
}
|
|
29813
|
+
/**
|
|
29814
|
+
* The device's product description resolved for this device ({@link resolveThing}): against its serial
|
|
29815
|
+
* and firmware (`main_sw_version`), the station it is reached through and that station's firmware, the
|
|
29816
|
+
* account's country and its reported params.
|
|
29817
|
+
*/
|
|
29818
|
+
thingsFor(dev, station, params) {
|
|
29819
|
+
const td = this.things.get(dev.model ?? "");
|
|
29820
|
+
if (!td)
|
|
29821
|
+
return void 0;
|
|
29822
|
+
const firmware = (d) => recordString(d?.raw ?? {}, "main_sw_version");
|
|
29823
|
+
return resolveThing(td, {
|
|
29824
|
+
serial: dev.sn,
|
|
29825
|
+
firmwareVersion: firmware(dev),
|
|
29826
|
+
stationSerial: station,
|
|
29827
|
+
stationFirmwareVersion: firmware(this.devices.find((d) => d.sn === station)),
|
|
29828
|
+
country: this.mega.countryCode,
|
|
29829
|
+
params
|
|
29830
|
+
});
|
|
29831
|
+
}
|
|
29832
|
+
/**
|
|
29833
|
+
* Fetch, once per start, the thing description of each product code the account has, in one
|
|
29834
|
+
* `get_things_list` call. A failed call is logged and asked again on the next refresh.
|
|
29835
|
+
*/
|
|
29836
|
+
async loadThings(seen) {
|
|
29837
|
+
const codes = [...new Set([...seen.values()].map((d) => d.model ?? ""))].filter((c) => c && !this.things.has(c));
|
|
29838
|
+
if (!codes.length)
|
|
29839
|
+
return;
|
|
29840
|
+
let parsed;
|
|
29841
|
+
try {
|
|
29842
|
+
parsed = parseThingsList(await this.mega.getThingsList(codes));
|
|
29843
|
+
} catch (e) {
|
|
29844
|
+
if (e instanceof SessionExpiredError)
|
|
29845
|
+
throw e;
|
|
29846
|
+
this.logger.debug(`[registry] thing descriptions unavailable: ${e?.message ?? e}`);
|
|
29847
|
+
return;
|
|
29848
|
+
}
|
|
29849
|
+
for (const code of codes)
|
|
29850
|
+
this.things.set(code, parsed[code]);
|
|
29851
|
+
}
|
|
29453
29852
|
/**
|
|
29454
29853
|
* Resolve a serial to a {@link DeviceRecord} with current params: starts from the device-list params, then
|
|
29455
29854
|
* overlays a fresh `get_device_param_list` when that call is available to this account. An AIoT robot's
|
|
@@ -29514,7 +29913,8 @@ var DeviceRegistry = class {
|
|
|
29514
29913
|
parentSn: station === sn ? void 0 : station,
|
|
29515
29914
|
params,
|
|
29516
29915
|
paramUpdatedAt,
|
|
29517
|
-
dpParams: this.dpParams.get(sn)
|
|
29916
|
+
dpParams: this.dpParams.get(sn),
|
|
29917
|
+
things: this.thingsFor(dev, station, params)
|
|
29518
29918
|
};
|
|
29519
29919
|
}
|
|
29520
29920
|
/**
|
|
@@ -29783,11 +30183,6 @@ var PushRepeats = class {
|
|
|
29783
30183
|
};
|
|
29784
30184
|
|
|
29785
30185
|
// dist/client/eufy-mega.js
|
|
29786
|
-
function recordString(raw, key) {
|
|
29787
|
-
const nested = raw.deviceParams?.[key];
|
|
29788
|
-
const v = typeof nested === "string" && nested ? nested : raw[key];
|
|
29789
|
-
return typeof v === "string" && v ? v : void 0;
|
|
29790
|
-
}
|
|
29791
30186
|
function adminUserIdFrom(raw) {
|
|
29792
30187
|
const member = (raw ?? {}).member;
|
|
29793
30188
|
const id = member?.admin_user_id;
|
|
@@ -29808,6 +30203,16 @@ var PUSH_RETRY_MIN_MS = 3e4;
|
|
|
29808
30203
|
var PUSH_RETRY_MAX_MS = 6e5;
|
|
29809
30204
|
var STATION_REOPEN_MIN_MS = 5e3;
|
|
29810
30205
|
var STATION_REOPEN_MAX_MS = 3e5;
|
|
30206
|
+
var PORTAL_COMMAND_KINDS = /* @__PURE__ */ new Set([
|
|
30207
|
+
"set-payload",
|
|
30208
|
+
"set-json",
|
|
30209
|
+
"set-param",
|
|
30210
|
+
"set-json-raw",
|
|
30211
|
+
"p2p-station-scalar",
|
|
30212
|
+
"p2p-int-string",
|
|
30213
|
+
"p2p-privacy-burst"
|
|
30214
|
+
]);
|
|
30215
|
+
var RTC_CONTROL_REFUSED_KINDS = new Set([...PORTAL_COMMAND_KINDS].filter((kind) => !RTC_CONTROL_COMMAND_KINDS.has(kind)));
|
|
29811
30216
|
var RealtimeStartupSupersededError = class extends Error {
|
|
29812
30217
|
};
|
|
29813
30218
|
var RefreshWindowClosedError = class extends Error {
|
|
@@ -31919,6 +32324,8 @@ var EufyMega = class _EufyMega extends EventEmitter14 {
|
|
|
31919
32324
|
const parentRaw = parent?.raw;
|
|
31920
32325
|
const resolved = resolveDevice(rec);
|
|
31921
32326
|
const dpCatalog = (resolved.codec === "vacuum" || resolved.codec === "mower") && rec.model ? await this.fetchDpCatalog(rec.model) : void 0;
|
|
32327
|
+
const rtcRoute = this.rtcRouteFor(sn);
|
|
32328
|
+
const refusedCommandKinds = !rtcRoute ? void 0 : rtcRoute.mediaTrack ? PORTAL_COMMAND_KINDS : RTC_CONTROL_REFUSED_KINDS;
|
|
31922
32329
|
return {
|
|
31923
32330
|
channel,
|
|
31924
32331
|
timezone: recordString(parentRaw ?? {}, "time_zone"),
|
|
@@ -31939,6 +32346,7 @@ var EufyMega = class _EufyMega extends EventEmitter14 {
|
|
|
31939
32346
|
macAddress: recordString(raw, "wifi_mac"),
|
|
31940
32347
|
updateAvailable: raw.needUpdate === true || raw.needUpdate === 1 || raw.needUpdate === "1",
|
|
31941
32348
|
paramIds: new Set([...Object.keys(rec.params), ...Object.keys(rec.dpParams ?? {})].map(Number)),
|
|
32349
|
+
things: rec.things,
|
|
31942
32350
|
capabilities: new Set(resolved.capabilities),
|
|
31943
32351
|
// Member identity for ff09-* command devices (see core/contracts Ff09Identity).
|
|
31944
32352
|
adminUserId: typeof member.admin_user_id === "string" ? member.admin_user_id : void 0,
|
|
@@ -31950,6 +32358,7 @@ var EufyMega = class _EufyMega extends EventEmitter14 {
|
|
|
31950
32358
|
// Topology as the record states it: a parent that isn't the device itself means HomeBase-attached.
|
|
31951
32359
|
homeBaseAttached: !!raw.parent_sn && raw.parent_sn !== dev.sn,
|
|
31952
32360
|
stationDeviceType: this.stationDeviceTypeOf(sn),
|
|
32361
|
+
refusedCommandKinds,
|
|
31953
32362
|
dpCatalog
|
|
31954
32363
|
};
|
|
31955
32364
|
}
|
|
@@ -32458,8 +32867,8 @@ var SolixClient = class _SolixClient {
|
|
|
32458
32867
|
*/
|
|
32459
32868
|
async getSites() {
|
|
32460
32869
|
const data = await this.authed("POST", SOLIX_ENDPOINTS.getSiteList, {});
|
|
32461
|
-
const
|
|
32462
|
-
return
|
|
32870
|
+
const list2 = data?.site_list ?? [];
|
|
32871
|
+
return list2.filter((s) => typeof s?.site_id === "string" && s.site_id.length > 0);
|
|
32463
32872
|
}
|
|
32464
32873
|
/** Per-user AWS-IoT MQTT credentials (cert/key/endpoint/thing) for the real-time device plane. */
|
|
32465
32874
|
async getUserMqttInfo() {
|
|
@@ -32727,21 +33136,21 @@ function solixStateReadings(frame) {
|
|
|
32727
33136
|
continue;
|
|
32728
33137
|
const type = value[0];
|
|
32729
33138
|
const pl = value.subarray(1);
|
|
32730
|
-
let
|
|
33139
|
+
let num3;
|
|
32731
33140
|
if (type === 5 && pl.length >= 4)
|
|
32732
|
-
|
|
33141
|
+
num3 = pl.readFloatLE(0);
|
|
32733
33142
|
else if (type === 2 && pl.length >= 2)
|
|
32734
|
-
|
|
33143
|
+
num3 = pl.readUInt16LE(0);
|
|
32735
33144
|
else if (type === 1 && pl.length >= 1)
|
|
32736
|
-
|
|
33145
|
+
num3 = pl[0];
|
|
32737
33146
|
else if (type === 3 && pl.length >= 2)
|
|
32738
|
-
|
|
32739
|
-
if (
|
|
33147
|
+
num3 = pl[1];
|
|
33148
|
+
if (num3 === void 0)
|
|
32740
33149
|
continue;
|
|
32741
|
-
out[`state_${tag2.toString(16)}`] =
|
|
33150
|
+
out[`state_${tag2.toString(16)}`] = num3;
|
|
32742
33151
|
const name = SOLIX_STATE_FIELD_NAMES[tag2];
|
|
32743
33152
|
if (name)
|
|
32744
|
-
out[name] =
|
|
33153
|
+
out[name] = num3;
|
|
32745
33154
|
}
|
|
32746
33155
|
return out;
|
|
32747
33156
|
}
|
|
@@ -33027,9 +33436,9 @@ var SolixMqtt = class extends EventEmitter15 {
|
|
|
33027
33436
|
const frame = decodeSolixParamFrame(buf);
|
|
33028
33437
|
if (!frame)
|
|
33029
33438
|
return;
|
|
33030
|
-
const
|
|
33031
|
-
const productCode =
|
|
33032
|
-
let deviceSn = frame.deviceSn ??
|
|
33439
|
+
const parts2 = topic.split("/");
|
|
33440
|
+
const productCode = parts2[2] ?? "";
|
|
33441
|
+
let deviceSn = frame.deviceSn ?? parts2[3] ?? "";
|
|
33033
33442
|
if (!this.watched.has(deviceSn)) {
|
|
33034
33443
|
const ofProduct = [...this.watched.values()].filter((d) => d.product_code === productCode);
|
|
33035
33444
|
if (ofProduct.length === 1)
|
|
@@ -33067,9 +33476,9 @@ var SolixMqtt = class extends EventEmitter15 {
|
|
|
33067
33476
|
values.displayTimeoutIndex = a5[1];
|
|
33068
33477
|
if (Object.keys(values).length === 0)
|
|
33069
33478
|
return;
|
|
33070
|
-
const
|
|
33071
|
-
const productCode =
|
|
33072
|
-
let deviceSn = frame.deviceSn ??
|
|
33479
|
+
const parts2 = topic.split("/");
|
|
33480
|
+
const productCode = parts2[2] ?? "";
|
|
33481
|
+
let deviceSn = frame.deviceSn ?? parts2[3] ?? "";
|
|
33073
33482
|
if (!this.watched.has(deviceSn)) {
|
|
33074
33483
|
const ofProduct = [...this.watched.values()].filter((d) => d.product_code === productCode);
|
|
33075
33484
|
if (ofProduct.length === 1)
|