@mega-yfue/eufy-sdk 0.6.0-beta.4 → 0.6.0-beta.41
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 +6 -0
- package/dist/client/eufy-mega.d.ts +103 -14
- package/dist/client/push-repeats.d.ts +10 -0
- package/dist/client/types.d.ts +12 -9
- package/dist/core/contracts.d.ts +28 -14
- package/dist/core/store.d.ts +12 -1
- package/dist/core/types.d.ts +4 -2
- package/dist/index.js +3362 -2446
- package/dist/index.js.map +4 -4
- package/dist/model/capabilities/access.d.ts +3 -2
- package/dist/model/capabilities/arming.d.ts +2 -1
- package/dist/model/capabilities/battery.d.ts +8 -7
- package/dist/model/capabilities/camera.d.ts +13 -2
- package/dist/model/capabilities/doorbell.d.ts +15 -3
- package/dist/model/capabilities/index.d.ts +1 -1
- package/dist/model/capabilities/members.d.ts +3 -1
- package/dist/model/capabilities/motion.d.ts +16 -2
- package/dist/model/capabilities/mower.d.ts +3 -2
- package/dist/model/capabilities/ptz.d.ts +11 -5
- package/dist/model/capabilities/vacuum-clean.d.ts +23 -0
- package/dist/model/device-family.d.ts +3 -1
- package/dist/model/device-types.d.ts +1 -0
- package/dist/transport/http/mega-client.d.ts +18 -5
- package/dist/transport/mqtt/biz-stream.d.ts +22 -25
- package/dist/transport/p2p/audio-frame.d.ts +13 -0
- package/dist/transport/p2p/codec.d.ts +8 -2
- package/dist/transport/p2p/command-router.d.ts +48 -13
- package/dist/transport/p2p/database-wire.d.ts +30 -0
- package/dist/transport/p2p/level2-settle.d.ts +9 -0
- package/dist/transport/p2p/live-stream.d.ts +34 -7
- package/dist/transport/p2p/live-trace.d.ts +7 -5
- package/dist/transport/p2p/p2p-session.d.ts +112 -16
- package/dist/transport/p2p/readable-egress.d.ts +3 -1
- package/dist/transport/p2p/recording-download.d.ts +109 -13
- package/dist/transport/p2p/shared-live-source.d.ts +9 -3
- package/dist/transport/p2p/video.d.ts +12 -6
- package/dist/transport/push/store.d.ts +7 -6
- package/dist/transport/rtc/command-router.d.ts +86 -9
- package/dist/transport/rtc/live.d.ts +4 -1
- package/dist/transport/rtc/portal-packet.d.ts +3 -13
- package/dist/transport/rtc/session.d.ts +19 -2
- package/dist/transport/stored-image-cache.d.ts +14 -0
- package/package.json +1 -1
|
@@ -76,9 +76,10 @@ export declare function setJsonRaw(cmd: number, data: Record<string, unknown>, c
|
|
|
76
76
|
export declare function setPayload(cmd: number, payload: Record<string, unknown>, ctx: CommandContext, mValue3?: number, channel?: number, form?: ScalarForm): Command;
|
|
77
77
|
/**
|
|
78
78
|
* Set a station-scoped scalar (132-byte body, no channel field) on an EXPLICIT channel — for the
|
|
79
|
-
* HomeBase's own controls on the station broadcast channel 255 (alarm/speaker volume 1235).
|
|
79
|
+
* HomeBase's own controls on the station broadcast channel 255 (alarm/speaker volume 1235). Level-2
|
|
80
|
+
* only, unless `form` is `"auto"`, which seals it at the session's own level.
|
|
80
81
|
*/
|
|
81
|
-
export declare function setStationScalar(cmd: number, value: number, channel: number): Command;
|
|
82
|
+
export declare function setStationScalar(cmd: number, value: number, channel: number, form?: "auto"): Command;
|
|
82
83
|
/**
|
|
83
84
|
* A one-line device descriptor for error messages — carries every identifier needed to reproduce or
|
|
84
85
|
* triage from a log later (deviceType, model T-code, full serial, channel, codec), so a "capability
|
|
@@ -77,7 +77,8 @@ export declare const ARMING_CMD: {
|
|
|
77
77
|
* was captured on holds a level-2 key and seals it level-2, while an own-session camera that never
|
|
78
78
|
* negotiates one carries the same envelope level-1. See `armingCommand`.
|
|
79
79
|
*
|
|
80
|
-
* A T8410C
|
|
80
|
+
* A T8410C and a T8410 take the mode as a direct frame instead of this envelope; see
|
|
81
|
+
* {@link DIRECT_ARMING_MODELS} and {@link BROADCAST_ARMING_MODELS}.
|
|
81
82
|
*/
|
|
82
83
|
readonly SET_ARMING: 1224;
|
|
83
84
|
/**
|
|
@@ -128,12 +128,9 @@ export declare const CELL_PARAMS: readonly number[];
|
|
|
128
128
|
*/
|
|
129
129
|
export declare function isChargingState(v: string | number | boolean): boolean;
|
|
130
130
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* Each write is gated on the device reporting the param it reads back, because "has a battery" is much
|
|
135
|
-
* weaker evidence than "speaks this setting": an entry sensor reports a level (1101) and nothing else,
|
|
136
|
-
* and handing it a power-source frame it never accepts would look like success.
|
|
131
|
+
* The published `battery` table: the full camera surface, minus every member on the `sensor` codec —
|
|
132
|
+
* a sensor's 1101 is a non-cell sentinel and it has none of the camera power reads, so it exposes no
|
|
133
|
+
* battery entity (see {@link notOnSensor}). Every getter, setter and description derives from this.
|
|
137
134
|
*
|
|
138
135
|
* Exported but NOT published: each entry states its wire id and the evidence it was confirmed on,
|
|
139
136
|
* which the reference site does not carry.
|
|
@@ -144,6 +141,9 @@ export declare const BATTERY_MEMBERS: {
|
|
|
144
141
|
* The headline percentage, and this capability's detection evidence: reporting 1101 is what proves a
|
|
145
142
|
* device is battery-powered, which is also the fact `MediaProvider` reads to decide a stream needs a
|
|
146
143
|
* power budget. Published flat as `battery` — `level` alone is claimed by `suction` too.
|
|
144
|
+
*
|
|
145
|
+
* Withheld on a device that resolved `lock`, whose own `battery` member reads the same param 1101 and
|
|
146
|
+
* owns the `battery` property there, so the two do not both claim it.
|
|
147
147
|
*/
|
|
148
148
|
readonly level: {
|
|
149
149
|
readonly param: 1101;
|
|
@@ -152,6 +152,7 @@ export declare const BATTERY_MEMBERS: {
|
|
|
152
152
|
readonly unit: "%";
|
|
153
153
|
readonly kind: "percent";
|
|
154
154
|
readonly provenance: "verified";
|
|
155
|
+
readonly available: (ctx: AvailabilityContext) => boolean;
|
|
155
156
|
readonly description: "Battery level 0-100 (verified: param 1101).";
|
|
156
157
|
};
|
|
157
158
|
/**
|
|
@@ -170,7 +171,7 @@ export declare const BATTERY_MEMBERS: {
|
|
|
170
171
|
/**
|
|
171
172
|
* 1293 is the READABLE indicator (6445 is write-only/cloud-hidden). Verified live on a T8124R via an
|
|
172
173
|
* app-toggle before/after diff: 0 = Battery, 1 = External Solar Panel. Values beyond 0/1 (some models
|
|
173
|
-
* report 5)
|
|
174
|
+
* report 5) read as `undefined` — `enumValues` holds only the two that are confirmed.
|
|
174
175
|
*
|
|
175
176
|
* The write is a `1350` SET_PAYLOAD, inner cmd 1293, `{charge_mode:N}`, `mValue3` 0 (the app uses 0,
|
|
176
177
|
* not the cmd id), and the setter accepts a NAME as well as the index the getter answers.
|
|
@@ -263,6 +263,8 @@ export type CameraActions = Surface<typeof CAMERA_MEMBERS> & {
|
|
|
263
263
|
};
|
|
264
264
|
/** T8442 has a binary night-vision wire, unlike cameras with the three-mode 1277 control. */
|
|
265
265
|
declare function isT8442(ctx: AvailabilityContext): boolean;
|
|
266
|
+
/** A C30/C31 has reported no 1716 and no doorbell LED write was tried on it, so it keeps 1045. */
|
|
267
|
+
declare const doorbellLed: (ctx: AvailabilityContext) => boolean;
|
|
266
268
|
/**
|
|
267
269
|
* Every `camera` feature, declared once. The property schema, the typed getters, the derived setters,
|
|
268
270
|
* the intent routes, the media methods and the descriptions all come out of this table.
|
|
@@ -439,6 +441,10 @@ export declare const CAMERA_MEMBERS: {
|
|
|
439
441
|
* sensor omits it, and the wire accepts the value regardless — the device's own reported set is the
|
|
440
442
|
* only statement of which of the three it has. `coerceEnumValue` rejects a value outside
|
|
441
443
|
* {@link NightVision} rather than coercing it. The payload key on the wire is `night_sion`.
|
|
444
|
+
*
|
|
445
|
+
* 1277 carries more than these three on some models: the V6 app's per-model mappings put modes on
|
|
446
|
+
* 3, 5, 6 and 8 as well, and which model takes which mapping is not in the app bundle. A reported value
|
|
447
|
+
* outside the published options reads as `undefined` rather than as an unnamed number.
|
|
442
448
|
*/
|
|
443
449
|
readonly nightVision: {
|
|
444
450
|
readonly param: 1277;
|
|
@@ -475,6 +481,8 @@ export declare const CAMERA_MEMBERS: {
|
|
|
475
481
|
*
|
|
476
482
|
* `transaction` is part of the frame that was captured, so it is sent. The recording sibling's own
|
|
477
483
|
* confirmed frame carries no such field; neither is inferred from the other.
|
|
484
|
+
*
|
|
485
|
+
* Not offered where the device reports the doorbell's own live-view quality (1705).
|
|
478
486
|
*/
|
|
479
487
|
readonly streamingQuality: {
|
|
480
488
|
readonly accepts: StreamingQualityName;
|
|
@@ -483,7 +491,7 @@ export declare const CAMERA_MEMBERS: {
|
|
|
483
491
|
readonly kind: "enum";
|
|
484
492
|
readonly enumValues: Readonly<Record<number, string>>;
|
|
485
493
|
readonly provenance: "verified";
|
|
486
|
-
readonly available:
|
|
494
|
+
readonly available: (ctx: AvailabilityContext) => boolean;
|
|
487
495
|
readonly args: readonly [{
|
|
488
496
|
readonly name: "quality";
|
|
489
497
|
readonly kind: "enum";
|
|
@@ -560,13 +568,14 @@ export declare const CAMERA_MEMBERS: {
|
|
|
560
568
|
readonly readAvailable: (ctx: AvailabilityContext) => boolean;
|
|
561
569
|
readonly readAliases: readonly [{
|
|
562
570
|
readonly paramType: 1716;
|
|
563
|
-
readonly available:
|
|
571
|
+
readonly available: typeof doorbellLed;
|
|
564
572
|
}];
|
|
565
573
|
readonly requiresRead: true;
|
|
566
574
|
readonly description: "Camera status LED. Video doorbells report the same state under their button-ring LED parameter.";
|
|
567
575
|
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
568
576
|
};
|
|
569
577
|
readonly views: import("./members.js").ProvidedMember<"media", (() => readonly number[]) | undefined>;
|
|
578
|
+
readonly outputResolutions: import("./members.js").ProvidedMember<"media", (() => readonly "1080p"[]) | undefined>;
|
|
570
579
|
/**
|
|
571
580
|
* Media is not a property: it returns DATA rather than moving state, its options are richer than a
|
|
572
581
|
* value, and it exists only on a device bound to a provider. Each is declared once, with its
|
|
@@ -596,8 +605,10 @@ export declare const CAMERA_MEMBERS: {
|
|
|
596
605
|
timeoutMs?: number;
|
|
597
606
|
skipKeyframes?: number;
|
|
598
607
|
} | undefined) => Promise<Buffer<ArrayBufferLike>>)>;
|
|
608
|
+
/** The T8530 serves its live feed as a Readable too. */
|
|
599
609
|
readonly openReadable: import("./members.js").ProvidedMember<"media", false | ((opts?: Parameters<NonNullable<MediaProvider["openReadable"]>>[0]) => Promise<import("node:stream").Readable>) | undefined>;
|
|
600
610
|
readonly recordFragments: import("./members.js").ProvidedMember<"media", false | ((opts?: Parameters<NonNullable<MediaProvider["recordFragments"]>>[0]) => import("../../core/contracts.js").FragmentRecordingHandle) | undefined>;
|
|
611
|
+
/** A T8530 is offered the download behind a HomeBase 3 alone. */
|
|
601
612
|
readonly downloadRecording: import("./members.js").ProvidedMember<"media", false | ((opts: Parameters<NonNullable<MediaProvider["downloadRecording"]>>[0]) => Promise<import("../../core/contracts.js").RecordingDownload>) | undefined>;
|
|
602
613
|
/**
|
|
603
614
|
* Push audio from the host to this camera's speaker. Gated on the **speaker** param specifically —
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type Surface } from "./members.js";
|
|
2
|
-
import type { CapabilityModule } from "./types.js";
|
|
2
|
+
import type { AvailabilityContext, CapabilityModule } from "./types.js";
|
|
3
|
+
/** No doorbell write has been tried on a C30/C31, so only their ring event binds. */
|
|
4
|
+
declare const writable: (ctx: AvailabilityContext) => boolean;
|
|
3
5
|
/**
|
|
4
6
|
* The P2P **feature-command ids** this doorbell capability drives. Capability-owned wire vocabulary
|
|
5
7
|
* (transport forwards `cmd.param` opaquely; full id→name catalog in the generated
|
|
@@ -191,6 +193,7 @@ export declare const DOORBELL_MEMBERS: {
|
|
|
191
193
|
*/
|
|
192
194
|
readonly chimeSwitch: {
|
|
193
195
|
readonly param: 1702;
|
|
196
|
+
readonly available: typeof writable;
|
|
194
197
|
readonly type: "bool";
|
|
195
198
|
readonly kind: "boolean";
|
|
196
199
|
readonly provenance: "verified";
|
|
@@ -203,6 +206,7 @@ export declare const DOORBELL_MEMBERS: {
|
|
|
203
206
|
*/
|
|
204
207
|
readonly mechanicalChimeSwitch: {
|
|
205
208
|
readonly param: 1703;
|
|
209
|
+
readonly available: typeof writable;
|
|
206
210
|
readonly type: "bool";
|
|
207
211
|
readonly kind: "boolean";
|
|
208
212
|
readonly provenance: "verified";
|
|
@@ -212,6 +216,7 @@ export declare const DOORBELL_MEMBERS: {
|
|
|
212
216
|
/** Same reasoning and the same capture session as {@link DOORBELL_MEMBERS.mechanicalChimeSwitch}. */
|
|
213
217
|
readonly wdrSwitch: {
|
|
214
218
|
readonly param: 1704;
|
|
219
|
+
readonly available: typeof writable;
|
|
215
220
|
readonly type: "bool";
|
|
216
221
|
readonly kind: "boolean";
|
|
217
222
|
readonly provenance: "verified";
|
|
@@ -242,6 +247,7 @@ export declare const DOORBELL_MEMBERS: {
|
|
|
242
247
|
*/
|
|
243
248
|
readonly dingdongVolume: {
|
|
244
249
|
readonly param: 1717;
|
|
250
|
+
readonly available: typeof writable;
|
|
245
251
|
readonly type: "number";
|
|
246
252
|
readonly unit: "%";
|
|
247
253
|
readonly kind: "percent";
|
|
@@ -259,6 +265,7 @@ export declare const DOORBELL_MEMBERS: {
|
|
|
259
265
|
*/
|
|
260
266
|
readonly dingdongRingtone: {
|
|
261
267
|
readonly param: 1718;
|
|
268
|
+
readonly available: typeof writable;
|
|
262
269
|
readonly type: "number";
|
|
263
270
|
readonly kind: "enum";
|
|
264
271
|
readonly enumValues: Record<number, string>;
|
|
@@ -313,7 +320,9 @@ export declare const DOORBELL_MEMBERS: {
|
|
|
313
320
|
* reads {@link DOORBELL_MEMBERS.videoQuality} and {@link DOORBELL_MEMBERS.highCompressionEncoding}
|
|
314
321
|
* and passes what it wants, instead of the SDK guessing from a stale copy.
|
|
315
322
|
*/
|
|
316
|
-
readonly setVideoQuality: import("./members.js").MethodMember<(quality: DoorbellVideoQualityValue, highCompression: boolean) => Promise<void
|
|
323
|
+
readonly setVideoQuality: import("./members.js").MethodMember<(quality: DoorbellVideoQualityValue, highCompression: boolean) => Promise<void>> & {
|
|
324
|
+
available: (ctx: import("./types.js").CommandContext) => boolean;
|
|
325
|
+
};
|
|
317
326
|
/**
|
|
318
327
|
* A config blob the device reports WHOLE, so it is typed `string` and handed back unparsed — three
|
|
319
328
|
* settings live inside it (motion notifications, ring notifications, notification style) and the SDK
|
|
@@ -339,7 +348,9 @@ export declare const DOORBELL_MEMBERS: {
|
|
|
339
348
|
*/
|
|
340
349
|
readonly playQuickResponse: import("./members.js").MethodMember<(voiceId: number, opts?: {
|
|
341
350
|
engage?: boolean;
|
|
342
|
-
}) => Promise<void
|
|
351
|
+
}) => Promise<void>> & {
|
|
352
|
+
available: (ctx: import("./types.js").CommandContext) => boolean;
|
|
353
|
+
};
|
|
343
354
|
/**
|
|
344
355
|
* Fetch the doorbell's quick-response list — a P2P request/reply query that returns data, so it
|
|
345
356
|
* exists only on a device bound to a media provider that offers one.
|
|
@@ -352,3 +363,4 @@ export declare const DOORBELL_MEMBERS: {
|
|
|
352
363
|
}) => Promise<QuickResponse[]>) | undefined>;
|
|
353
364
|
};
|
|
354
365
|
export declare const DOORBELL: CapabilityModule;
|
|
366
|
+
export {};
|
|
@@ -388,7 +388,7 @@ export interface DeviceEventMap {
|
|
|
388
388
|
* with the type. (Only capabilities whose module defines `actions()` appear.)
|
|
389
389
|
*/
|
|
390
390
|
export interface DeviceActionMap {
|
|
391
|
-
/** Pan/tilt/zoom control: `rotate(dir, step)` + `left`/`right`/`up`/`down`, `zoom`, preset() namespace (goto/preview/save/setDefault/delete/list/image). */
|
|
391
|
+
/** Pan/tilt/zoom control: `rotate(dir, step)` + `left`/`right`/`up`/`down`, `rotate360`, `zoom`, preset() namespace (goto/preview/save/setDefault/delete/list/image). */
|
|
392
392
|
ptz: PtzActions;
|
|
393
393
|
/** Floodlight/spotlight: `on`/`off`/`set`, `setBrightness`/`setColorTemp`/`setEnabled`, `setAutoSpotlight`. */
|
|
394
394
|
light: LightActions;
|
|
@@ -576,12 +576,14 @@ export declare function memberWrite(name: string, m: ValueMember, value: boolean
|
|
|
576
576
|
* is stored as a decoded object. Handing either through a getter typed `number` is the one lie this
|
|
577
577
|
* table exists to prevent.
|
|
578
578
|
*
|
|
579
|
+
* A number outside `values`, the options published for this device, answers `undefined`.
|
|
580
|
+
*
|
|
579
581
|
* Exported so the ONE narrowing the getters use is also the one a property-change announcement carries.
|
|
580
582
|
* A second conversion of the wire value is precisely how a payload comes to disagree with the getter
|
|
581
583
|
* beside it, which would defeat the point of announcing the change at all.
|
|
582
584
|
* @internal
|
|
583
585
|
*/
|
|
584
|
-
export declare function narrow(type: PropertyValueType, read: CapabilityStateReader, prop: string): boolean | number | string | undefined;
|
|
586
|
+
export declare function narrow(type: PropertyValueType, read: CapabilityStateReader, prop: string, values?: Record<number, string>): boolean | number | string | undefined;
|
|
585
587
|
/**
|
|
586
588
|
* Both presence gates at once: the params a member requires, and its own {@link ValueMember.available}.
|
|
587
589
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Surface } from "./members.js";
|
|
2
|
-
import type { CapabilityModule, CommandContext } from "./types.js";
|
|
2
|
+
import type { AvailabilityContext, CapabilityModule, CommandContext } from "./types.js";
|
|
3
3
|
import type { Command } from "../../core/contracts.js";
|
|
4
4
|
/**
|
|
5
5
|
* The P2P **feature-command ids** this motion capability drives. Capability-owned wire vocabulary
|
|
@@ -125,6 +125,13 @@ export declare const MOTION_CMD: {
|
|
|
125
125
|
* as a `1700` control payload carrying an index rather than the `1350` envelope its siblings take.
|
|
126
126
|
*/
|
|
127
127
|
readonly INDOOR_SENSITIVITY_INDEX: 6041;
|
|
128
|
+
/**
|
|
129
|
+
* Motion detection on-off on a T8410 (app `CMD_INDOOR_DET_SET_MOTION_DETECT_ENABLE`). `1700` control
|
|
130
|
+
* payload `{"commandType":6040,"data":{"enable":0,"quality":0,"status":0|1,"value":0}}`.
|
|
131
|
+
*
|
|
132
|
+
* ⚠️ Replay + readback confirmed on a standalone and a HomeBase 3-attached T8410, NOT byte-captured.
|
|
133
|
+
*/
|
|
134
|
+
readonly INDOOR_MOTION_ENABLE: 6040;
|
|
128
135
|
/**
|
|
129
136
|
* Detection sensitivity a solo camera REPORTS (app `SET_MOTION_DETECTION_SENSITIVITY_SOLO`). It does
|
|
130
137
|
* not accept writes on this id — the write goes to {@link MOTION_SENSITIVITY}, which is why a scale
|
|
@@ -187,6 +194,8 @@ export declare function decodeAiDetectType(value: number): AiDetectFlags;
|
|
|
187
194
|
* `ai_detect_type` field of the JSON object form. Answers `undefined` for any other shape.
|
|
188
195
|
*/
|
|
189
196
|
declare function decodeAiDetectTypeParam(raw: unknown): number | undefined;
|
|
197
|
+
/** A T8410, whose motion switch is {@link MOTION_CMD.INDOOR_MOTION_ENABLE} rather than {@link MOTION_CMD.CAMERA_PIR}. */
|
|
198
|
+
declare function isT8410(ctx: AvailabilityContext): boolean;
|
|
190
199
|
/**
|
|
191
200
|
* Decode a `radar_wd_switch` (2706, loitering) read the way the app does:
|
|
192
201
|
* `typeof v === "object" ? v.radar_wd_switch : v`. The device may store it as a JSON object
|
|
@@ -227,7 +236,12 @@ export declare const MOTION_MEMBERS: {
|
|
|
227
236
|
readonly type: "bool";
|
|
228
237
|
readonly kind: "boolean";
|
|
229
238
|
readonly provenance: "verified";
|
|
230
|
-
readonly
|
|
239
|
+
readonly readAvailable: (ctx: AvailabilityContext) => boolean;
|
|
240
|
+
readonly readAliases: readonly [{
|
|
241
|
+
readonly paramType: 6040;
|
|
242
|
+
readonly available: typeof isT8410;
|
|
243
|
+
}];
|
|
244
|
+
readonly description: string;
|
|
231
245
|
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
232
246
|
readonly writeAs: "setDetection";
|
|
233
247
|
};
|
|
@@ -34,9 +34,9 @@ export declare const MOWER_DP: {
|
|
|
34
34
|
readonly SPARSE_LAWN_OPTIMIZATION: 141;
|
|
35
35
|
};
|
|
36
36
|
/** The `net_media_type` (DP 134) range, as the schema lists it. */
|
|
37
|
-
|
|
37
|
+
declare const MOWER_NETWORKS: readonly ["None", "Wifi", "Cellular"];
|
|
38
38
|
/** The mower's network link (DP 134). */
|
|
39
|
-
|
|
39
|
+
type MowerNetwork = (typeof MOWER_NETWORKS)[number];
|
|
40
40
|
/**
|
|
41
41
|
* Every `mower` read, declared once.
|
|
42
42
|
*
|
|
@@ -228,3 +228,4 @@ export declare const MOWER_MEMBERS: {
|
|
|
228
228
|
export type MowerActions = Surface<typeof MOWER_MEMBERS>;
|
|
229
229
|
/** `mower` — robot-mower state from its Tuya data points. */
|
|
230
230
|
export declare const MOWER: CapabilityModule;
|
|
231
|
+
export {};
|
|
@@ -5,7 +5,7 @@ import type { Command } from "../../core/contracts.js";
|
|
|
5
5
|
* The P2P **feature-command ids** this pan-tilt capability drives. Capability-owned wire vocabulary
|
|
6
6
|
* (transport forwards `cmd.param` opaquely; full id→name catalog in the generated
|
|
7
7
|
* `transport/p2p/commands.ts`). Distinct from the {@link PTZ_ROTATE} direction map below (which is
|
|
8
|
-
* `rotate_type`
|
|
8
|
+
* `rotate_type` 0..4, not a command id).
|
|
9
9
|
*
|
|
10
10
|
* Ids + envelopes are taken from the V6 app's own command builders (the `Set*Parser`/`*PositionsParser`
|
|
11
11
|
* classes in the decompiled JS), which is this project's wire ground truth — NOT a third-party
|
|
@@ -135,9 +135,11 @@ export declare const PtzDirection: {
|
|
|
135
135
|
readonly down: "down";
|
|
136
136
|
};
|
|
137
137
|
export type PtzDirection = (typeof PtzDirection)[keyof typeof PtzDirection];
|
|
138
|
-
/** Pan-tilt rotate
|
|
139
|
-
* stays internal to the capability. Confirmed on hardware (T8425): 1=left, 2=right, 3=up, 4=down.
|
|
138
|
+
/** Pan-tilt rotate motion → `rotate_type` (the on-wire code). Not re-exported by the barrel —
|
|
139
|
+
* stays internal to the capability. Confirmed on hardware (T8425): 1=left, 2=right, 3=up, 4=down.
|
|
140
|
+
* `sweep` (0) is a full 360° pan (room scan), from the app's 360 button. */
|
|
140
141
|
export declare const PTZ_ROTATE: {
|
|
142
|
+
readonly sweep: 0;
|
|
141
143
|
readonly left: 1;
|
|
142
144
|
readonly right: 2;
|
|
143
145
|
readonly up: 3;
|
|
@@ -145,7 +147,7 @@ export declare const PTZ_ROTATE: {
|
|
|
145
147
|
};
|
|
146
148
|
/**
|
|
147
149
|
* Pan-tilt rotate as a transport-neutral {@link Command}. CONFIRMED wire command (captured on
|
|
148
|
-
* T8425 ch3 during live-view): `{"commandType":6030,"data":{"cmd_type":1,"rotate_type":
|
|
150
|
+
* T8425 ch3 during live-view): `{"commandType":6030,"data":{"cmd_type":1,"rotate_type":0..4,
|
|
149
151
|
* "zoom":1.0}}` under the generic control wrapper `1700` on the camera channel. `cmd_type:1` =
|
|
150
152
|
* move; `zoom` defaults to 1.0.
|
|
151
153
|
*
|
|
@@ -153,7 +155,7 @@ export declare const PTZ_ROTATE: {
|
|
|
153
155
|
* resolver picks the encryption level by topology (standalone → L1, HomeBase → L2). A PT cam can be
|
|
154
156
|
* either, so the level is NOT fixed here.
|
|
155
157
|
*/
|
|
156
|
-
export declare function rotateCommand(direction:
|
|
158
|
+
export declare function rotateCommand(direction: keyof typeof PTZ_ROTATE, ctx: CommandContext, zoom?: number): Command;
|
|
157
159
|
/**
|
|
158
160
|
* Digital-zoom as a transport-neutral {@link Command}. The V6 app's `SetPictureZoomParser` builds a
|
|
159
161
|
* `SET_PAYLOAD` (1350) sub-command `COMMAND_DUAL_CAMERA_ZOOM` with the crop-window payload
|
|
@@ -266,6 +268,10 @@ export declare const PTZ_MEMBERS: {
|
|
|
266
268
|
readonly up: import("./members.js").MethodMember<() => Promise<void>>;
|
|
267
269
|
/** Rotate one step down. */
|
|
268
270
|
readonly down: import("./members.js").MethodMember<() => Promise<void>>;
|
|
271
|
+
/** Pan a full 360° (room scan). */
|
|
272
|
+
readonly rotate360: import("./members.js").MethodMember<() => Promise<void>> & {
|
|
273
|
+
available: (ctx: CommandContext) => boolean;
|
|
274
|
+
};
|
|
269
275
|
/**
|
|
270
276
|
* Zoom rides a SECOND (telephoto) lens, so it is offered only where the device shows zoom evidence —
|
|
271
277
|
* otherwise `dev.ptz()?.zoom` would be a silent no-op on a single-lens pan-tilt camera.
|
|
@@ -280,6 +280,16 @@ export declare function encodeSelectZonesClean(mapId: number, zones: readonly Va
|
|
|
280
280
|
* @internal
|
|
281
281
|
*/
|
|
282
282
|
export declare function encodeSceneClean(sceneId: number): string;
|
|
283
|
+
/**
|
|
284
|
+
* Build one of the two DP 153 writes the vendor app sends when its map view opens: the time in
|
|
285
|
+
* microseconds, and on the second write field 2 set to `1`.
|
|
286
|
+
*
|
|
287
|
+
* Captured from the vendor app on the device's `cmd/…/req` leg, three times with the same layout. The
|
|
288
|
+
* product catalogue lists DP 153 as uplink-only (`WorkStatus`); the vendor app writes this message to it
|
|
289
|
+
* all the same. {@link VACUUM_CLEAN_MEMBERS.requestMap} dispatches both.
|
|
290
|
+
* @internal
|
|
291
|
+
*/
|
|
292
|
+
export declare function encodeMapWatch(nowMs: number, watching: boolean): string;
|
|
283
293
|
/**
|
|
284
294
|
* Build a whole-floor auto clean carrying an `AutoClean` payload of one pass.
|
|
285
295
|
* @internal
|
|
@@ -1986,6 +1996,19 @@ export declare const VACUUM_CLEAN_MEMBERS: {
|
|
|
1986
1996
|
readonly startScene: import("./members.js").MethodMember<(sceneId: number) => Promise<void>> & {
|
|
1987
1997
|
available: (ctx: import("./types.js").CommandContext) => boolean;
|
|
1988
1998
|
};
|
|
1999
|
+
/**
|
|
2000
|
+
* Ask the robot to push its whole map — plane, room outline, room list and restricted zones — on the
|
|
2001
|
+
* map stream, as the vendor app does when its map view opens: two DP 153 writes, the time and then the
|
|
2002
|
+
* time with field 2 set (see {@link encodeMapWatch}).
|
|
2003
|
+
*
|
|
2004
|
+
* A docked robot sends no map of its own accord, so this is how its room ids and names become
|
|
2005
|
+
* readable without a clean. The map arrives on the stream like any other, not as this call's result.
|
|
2006
|
+
*
|
|
2007
|
+
* WATCHED: sent to a docked robot, it pushed its whole map within a second.
|
|
2008
|
+
*/
|
|
2009
|
+
readonly requestMap: import("./members.js").MethodMember<() => Promise<void>> & {
|
|
2010
|
+
available: (ctx: import("./types.js").CommandContext) => boolean;
|
|
2011
|
+
};
|
|
1989
2012
|
/**
|
|
1990
2013
|
* State the cleaning settings a run uses — `CleanParamRequest.clean_param` over DP 154.
|
|
1991
2014
|
*
|
|
@@ -52,10 +52,12 @@ export declare const isHomeBase: (ctx: FamilyContext) => boolean;
|
|
|
52
52
|
export declare const isStation9000: (ctx: FamilyContext) => boolean;
|
|
53
53
|
/** T8N00 NVR, identified by its reported model. */
|
|
54
54
|
export declare const isNvrT8N00: (ctx: FamilyContext) => boolean;
|
|
55
|
-
/**
|
|
55
|
+
/** A camera attached to a T8N00 whose media the NVR's call serves. */
|
|
56
56
|
export declare const isNvrMediaCamera: (ctx: FamilyContext) => boolean;
|
|
57
57
|
/** PoE S4 camera with independently streamed fixed and movable optical views. */
|
|
58
58
|
export declare const isNvrDualLensCamera: (ctx: FamilyContext) => boolean;
|
|
59
|
+
/** NVR cameras verified to support an explicit 1080p live output. */
|
|
60
|
+
export declare const isNvrFullHdCamera: (ctx: FamilyContext) => boolean;
|
|
59
61
|
/** Video Doorbell C31 (T8223) or C30 (T8224), streamed by the app over the portal `call` route. */
|
|
60
62
|
export declare const isCallDoorbell: (ctx: FamilyContext) => boolean;
|
|
61
63
|
/** Wired doorbell (DeviceType.DOORBELL). */
|
|
@@ -112,6 +112,7 @@ export declare const DeviceType: {
|
|
|
112
112
|
readonly LOCK_85D0: 202;
|
|
113
113
|
readonly LOCK_85V0: 203;
|
|
114
114
|
readonly LOCK_85P0: 209;
|
|
115
|
+
readonly WALL_LIGHT_CAM_T86C1: 298;
|
|
115
116
|
readonly NVR_S4_MAX: 300;
|
|
116
117
|
readonly CAMERA_POE_S4: 301;
|
|
117
118
|
readonly WALL_LIGHT_CAM_81A0: 10005;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type SessionEntry } from "../../core/crypto.js";
|
|
2
2
|
import { type SessionStore } from "../../core/store.js";
|
|
3
3
|
import { type Logger } from "../../core/logger.js";
|
|
4
|
+
import type { EufyDevice } from "../../core/types.js";
|
|
4
5
|
import type { SecureMqttCredentials } from "../mqtt/secure-mqtt.js";
|
|
5
6
|
export type RegionShard = "eu-pr" | "us-pr";
|
|
6
7
|
/**
|
|
@@ -211,6 +212,8 @@ export declare class MegaHttpClient {
|
|
|
211
212
|
private region;
|
|
212
213
|
/** The host `estimate_domain` answered, persisted with the session. */
|
|
213
214
|
private estimatedDomain;
|
|
215
|
+
/** The in-flight (then settled, so cached) RTC-sign shard request from {@link portalShard}. */
|
|
216
|
+
private portalShardInFlight?;
|
|
214
217
|
private bootstrapDomain?;
|
|
215
218
|
private sessionKey?;
|
|
216
219
|
/** Per-host ECDH session keys for non-mega gateways (e.g. eufylife) keyed by host. */
|
|
@@ -282,11 +285,19 @@ export declare class MegaHttpClient {
|
|
|
282
285
|
/** The active region shard (e.g. `"eu-pr"`, `"us-pr"`), set after {@link login} or a region override. */
|
|
283
286
|
get regionShard(): RegionShard;
|
|
284
287
|
/**
|
|
285
|
-
* The shard the
|
|
286
|
-
*
|
|
287
|
-
* like `ie-pr`, whose accounts need the IE sign host and cluster.
|
|
288
|
+
* The shard the estimated domain names (`…-ie-…`/`…-ie.` → `ie-pr`), else {@link regionShard}. The
|
|
289
|
+
* eu/us classification cannot name shards like `ie-pr`.
|
|
288
290
|
*/
|
|
289
291
|
get rtcShard(): string;
|
|
292
|
+
/**
|
|
293
|
+
* The shard the RTC signalling signs on, from `estimate_domain` asked with the portal's WEB identity
|
|
294
|
+
* (`Model-Type: WEB`, `App-Name: eufy_mega`) — the identity the sign itself is sent with, which can name
|
|
295
|
+
* a different shard than the PHONE identity does for one account. The in-flight request is shared by
|
|
296
|
+
* concurrent first callers, and once it settles to a shard the resolved promise is the cache; a call
|
|
297
|
+
* that fails or names no shard answers {@link rtcShard}, clears the field and is asked again next time.
|
|
298
|
+
*/
|
|
299
|
+
portalShard(): Promise<string>;
|
|
300
|
+
private fetchPortalShard;
|
|
290
301
|
/**
|
|
291
302
|
* The credentials the RTC signalling needs; `undefined` while logged out. The sign is refused
|
|
292
303
|
* ("gtoken not equal userid") unless its gtoken is the one every authed HTTP call carries.
|
|
@@ -333,6 +344,8 @@ export declare class MegaHttpClient {
|
|
|
333
344
|
* raw text. Never throws on HTTP status (the callers classify the envelope themselves). 20s timeout.
|
|
334
345
|
*/
|
|
335
346
|
private httpPost;
|
|
347
|
+
/** POST `estimate_domain` with the given identity headers. */
|
|
348
|
+
private estimateDomainRequest;
|
|
336
349
|
/** Step 1: discover the account's region shard (and the bootstrap host). */
|
|
337
350
|
estimateDomain(): Promise<void>;
|
|
338
351
|
/**
|
|
@@ -354,11 +367,11 @@ export declare class MegaHttpClient {
|
|
|
354
367
|
/** Authed call to a mega service host: app-{service}-{region}.eufy.com. */
|
|
355
368
|
post<T = unknown>(service: string, path: string, body?: unknown, headerOverrides?: Record<string, string>): Promise<T>;
|
|
356
369
|
/**
|
|
357
|
-
* Fetch the per-station DSK key
|
|
370
|
+
* Fetch the per-station DSK key using each station's reported cloud category. Mirrors
|
|
358
371
|
* the legacy `get_dsk_keys` body shape on the mega devicerelation service.
|
|
359
372
|
* The P2P *local* lookup path does not need this; only the cloud path does.
|
|
360
373
|
*/
|
|
361
|
-
getDskKeys(
|
|
374
|
+
getDskKeys(stations: ReadonlyArray<Pick<EufyDevice, "sn" | "category">>, priorDsks?: Record<string, string>): Promise<Record<string, {
|
|
362
375
|
dskKey: string;
|
|
363
376
|
expiration: number;
|
|
364
377
|
}>>;
|
|
@@ -12,44 +12,41 @@ export declare const BIZ_PROTOCOL: {
|
|
|
12
12
|
readonly LIVE_PHOTO: 43;
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
|
-
* The channels a map frame
|
|
15
|
+
* The channels a map frame arrives on, by id, as a robot's own frames identify them.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* *decodes* a channel's bytes must therefore prefer a device-declared mapping when one has been seen;
|
|
23
|
-
* this table is the default to fall back on, not an authority.
|
|
17
|
+
* Each id is paired with the `stream.proto` message whose field layout its frames carry, which is not
|
|
18
|
+
* the field-number order of `Metadata.ChanIds`: the cell plane (`Map`) arrives on 2, its room outline
|
|
19
|
+
* on 4, the room list on 5, the restricted zones on 6, the robot's pose (`DynamicData`) on 7, the map's
|
|
20
|
+
* `MapDescription` on 60 and a whole `MapBackup` on 68. A `Metadata` frame would declare a device's own numbering; none has been seen,
|
|
21
|
+
* so none is read, and this table is the numbering every frame is read by.
|
|
24
22
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
23
|
+
* Only channels whose message is identified are listed. A channel whose frames carry too little to
|
|
24
|
+
* identify, or that carries a message nothing here reads, is absent.
|
|
25
|
+
*
|
|
26
|
+
* Channel 0 is not in `ChanIds` at all: the app hard-codes it, routing it to a scene-data event rather
|
|
27
|
+
* than a map one, and asks for the scene list on it by number.
|
|
28
28
|
*/
|
|
29
29
|
export declare const BIZ_CHANNEL: {
|
|
30
30
|
/** Scene (room-group) data. Hard-coded in the app, not part of `ChanIds`. */
|
|
31
31
|
readonly SCENES: 0;
|
|
32
|
-
readonly
|
|
33
|
-
readonly
|
|
34
|
-
readonly
|
|
35
|
-
readonly
|
|
36
|
-
readonly
|
|
37
|
-
readonly
|
|
38
|
-
readonly
|
|
39
|
-
readonly OBSTACLE_INFO: 8;
|
|
40
|
-
readonly MAP_DATA: 9;
|
|
41
|
-
readonly CRUISE_DATA: 10;
|
|
32
|
+
readonly MAP_DATA: 2;
|
|
33
|
+
readonly ROOM_OUTLINE: 4;
|
|
34
|
+
readonly ROOM_PARAMS: 5;
|
|
35
|
+
readonly RESTRICTED_ZONE: 6;
|
|
36
|
+
readonly DYNAMIC_DATA: 7;
|
|
37
|
+
readonly MAP_DESCRIPTION: 60;
|
|
38
|
+
readonly MAP_BACKUP: 68;
|
|
42
39
|
};
|
|
43
|
-
/** A channel's name under the
|
|
40
|
+
/** A channel's name under the {@link BIZ_CHANNEL} numbering. */
|
|
44
41
|
export type BizChannel = keyof typeof BIZ_CHANNEL;
|
|
45
42
|
/**
|
|
46
|
-
* Name a channel id under the
|
|
47
|
-
*
|
|
43
|
+
* Name a channel id under the {@link BIZ_CHANNEL} numbering, or `undefined` for an id it does not list.
|
|
44
|
+
* Not a substitute for a device-declared mapping where one exists.
|
|
48
45
|
*/
|
|
49
46
|
export declare function bizChannelName(id: number): BizChannel | undefined;
|
|
50
47
|
/** One frame off the map stream, unwrapped as far as its bytes but not decoded. */
|
|
51
48
|
export interface BizMapFrame {
|
|
52
|
-
/** Which channel the bytes belong to. Compare against {@link BIZ_CHANNEL}
|
|
49
|
+
/** Which channel the bytes belong to. Compare against {@link BIZ_CHANNEL}. */
|
|
53
50
|
readonly channelId: number;
|
|
54
51
|
/**
|
|
55
52
|
* The vendor's `clear_type`. Forwarded, not interpreted: the app passes it straight through to its
|
|
@@ -12,3 +12,16 @@ export declare const AUDIO_TYPE_OFFSET = 5;
|
|
|
12
12
|
* itself when a stream produces no audio at all, to feed its decoder silence.
|
|
13
13
|
*/
|
|
14
14
|
export declare const AUDIO_CODECS: Readonly<Record<number, AudioCodec>>;
|
|
15
|
+
/**
|
|
16
|
+
* Whether an audio frame is sealed: after its header, a 16-byte GCM tag and a 12-byte nonce precede the
|
|
17
|
+
* `u32@0` bytes its header declares, where a frame in the clear carries those bytes straight after the header.
|
|
18
|
+
* A stream whose keyframes wrap their media key in an ECIES envelope seals its audio this way, measured on
|
|
19
|
+
* HomeBase recordings and on HomeBase 3 live streams answering a P-256 start.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isSealedAudio(frame: Buffer): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* The payload of a sealed audio frame ({@link isSealedAudio}), opened with AES-256-GCM under `mediaKey`, the
|
|
24
|
+
* media key of the keyframe before it, with the video frames' AAD. Answers `undefined` for a frame that is not
|
|
25
|
+
* sealed or does not authenticate under that key.
|
|
26
|
+
*/
|
|
27
|
+
export declare function openSealedAudio(frame: Buffer, mediaKey: Buffer): Buffer | undefined;
|
|
@@ -94,6 +94,12 @@ export declare function p2pCommandEncryptionKey(stationSn: string, p2pDid: strin
|
|
|
94
94
|
export declare function decryptP2PData(data: Buffer, key: Buffer): Buffer;
|
|
95
95
|
/** The `cipher_id` named in a decrypted `CMD_GATEWAYINFO` (1100) payload (uint16 LE @0). */
|
|
96
96
|
export declare function gatewayInfoCipherId(gwPayload: Buffer): number;
|
|
97
|
+
/**
|
|
98
|
+
* Whether a `CMD_GATEWAYINFO` (1100) reply is a level-2 refusal: int32 LE `GATEWAY_LEVEL2_REFUSED` (`99 ff
|
|
99
|
+
* ff ff`) in place of a cipher. {@link gatewayInfoCipherId} reads those bytes as `cipher_id` 65433. Any other
|
|
100
|
+
* opening is not a refusal.
|
|
101
|
+
*/
|
|
102
|
+
export declare function gatewayInfoRefused(gwPayload: Buffer): boolean;
|
|
97
103
|
/** Options for {@link eciesUnwrap}. */
|
|
98
104
|
export interface EciesUnwrapOptions {
|
|
99
105
|
/**
|
|
@@ -224,8 +230,8 @@ export declare function buildRawCommandPayload(data: Buffer, channel?: number, s
|
|
|
224
230
|
export declare function buildAckPayload(dataTypeHeader: Buffer, seqNo: number): Buffer;
|
|
225
231
|
/** Parse the 16-byte data-frame header that follows the "XZYH" magic. */
|
|
226
232
|
export declare function parseDataFrameHeader(frame: Buffer): P2PDataFrameHeader;
|
|
227
|
-
/**
|
|
228
|
-
export declare function parseLookupAddr(msg: Buffer): Address;
|
|
233
|
+
/** A LOOKUP_ADDR message's leading address record, or `undefined` for a message too short to carry it. */
|
|
234
|
+
export declare function parseLookupAddr(msg: Buffer): Address | undefined;
|
|
229
235
|
/** The relay servers a LIST_REQ_ACK names, in the order listed, without the unspecified address; records past the message's end are dropped. */
|
|
230
236
|
export declare function parseRelayList(msg: Buffer): Address[];
|
|
231
237
|
/** A RLY_PORT_ACK's mark and relay port, or `undefined` for a message too short to carry them. */
|