@mega-yfue/eufy-sdk 0.5.0-beta.21 → 0.5.0-beta.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/eufy-mega.d.ts +3 -2
- package/dist/core/types.d.ts +2 -0
- package/dist/index.js +166 -54
- package/dist/index.js.map +2 -2
- package/dist/model/capabilities/arming.d.ts +31 -4
- package/dist/model/capabilities/dp-catalog.d.ts +4 -3
- package/dist/model/capabilities/suction.d.ts +5 -5
- package/dist/model/classify.d.ts +1 -2
- package/dist/model/device-family.d.ts +2 -0
- package/dist/transport/p2p/command-router.d.ts +1 -1
- package/dist/transport/p2p/p2p-session.d.ts +15 -1
- package/dist/transport/rtc/command-router.d.ts +5 -2
- package/dist/transport/rtc/peer.d.ts +4 -1
- package/dist/transport/rtc/session.d.ts +1 -1
- package/dist/transport/rtc/signaling.d.ts +4 -2
- package/package.json +1 -1
|
@@ -79,7 +79,8 @@ export declare const ARMING_CMD: {
|
|
|
79
79
|
*/
|
|
80
80
|
readonly SET_ARMING: 1224;
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
82
|
+
* One guard mode's per-device action table (app `CMD_SET_ALL_ACTION`), which carries the alarm delays
|
|
83
|
+
* and each device's actions in that mode. ✅ WIRE CAPTURED live on a T8030 (
|
|
83
84
|
* 2026-07-23, both directions): a **bare
|
|
84
85
|
* JSON frame, no `1350`/`1700` envelope** — outer P2P cmd IS `1255` itself, station channel 255,
|
|
85
86
|
* plaintext `{account_id, count_down_alarm:{channel_list,delay_time},
|
|
@@ -96,15 +97,23 @@ export declare const ARMING_CMD: {
|
|
|
96
97
|
* corresponding GET command (`1310`/inner cmd `40003`, sent by the app right before editing) always
|
|
97
98
|
* replied `{count:0,data:null}` in every capture — genuinely empty, not a decrypt failure (confirmed
|
|
98
99
|
* via the same bidirectional decrypt this finding used) — so the app does NOT read the current
|
|
99
|
-
* config this way;
|
|
100
|
-
* channel in or out of an existing list isn't possible without risking
|
|
100
|
+
* config this way; a T8010 reports it on its own params instead, see below. Without a working GET,
|
|
101
|
+
* safely PATCHING just one channel in or out of an existing list isn't possible without risking
|
|
102
|
+
* clobbering the rest — so
|
|
101
103
|
* this ships as a caller-supplies-everything write instead of guessing a merge.
|
|
102
104
|
* `devices`/`siren_sensor_action` are even less understood (raw per-device action codes, meaning
|
|
103
105
|
* unconfirmed) and MUST come from a value independently read/captured for the target mode —
|
|
104
106
|
* see `AlarmDelayConfig`'s field docs.
|
|
107
|
+
*
|
|
108
|
+
* ✅ On a T8010 the app writes the same command for the Device Control screen: header channel 0, the
|
|
109
|
+
* whole table of the mode `{mode_id, devices, count_down_alarm, count_down_arm}`, acked by an all-zero
|
|
110
|
+
* 1255 reply. The T8010 reports each table on its own params, Home on 1157 and Away on 1158, and the
|
|
111
|
+
* reported table follows a write within 15 s. See {@link DEVICE_NOTIFY_FLAG}.
|
|
105
112
|
*/
|
|
106
|
-
readonly
|
|
113
|
+
readonly SET_ALL_ACTION: 1255;
|
|
107
114
|
};
|
|
115
|
+
/** The guard modes whose device notification is read and written: both replayed on a T8010. */
|
|
116
|
+
export type DeviceNotificationMode = Extract<AlarmDelayMode, "home" | "away">;
|
|
108
117
|
/**
|
|
109
118
|
* Alarm-delay durations the app's OWN picker UI offers — `AlarmDelaySeconds` is both the const
|
|
110
119
|
* value-object (`AlarmDelaySeconds.sec45`) and the union type of its values, so callers pass the
|
|
@@ -225,6 +234,24 @@ export declare const ARMING_MEMBERS: {
|
|
|
225
234
|
* would be the same unverified guess `setMode` refuses.
|
|
226
235
|
*/
|
|
227
236
|
readonly setAlarmDelayConfig: import("./members.js").MethodMember<(mode: AlarmDelayMode, config: AlarmDelayConfig) => Promise<void>>;
|
|
237
|
+
/**
|
|
238
|
+
* Whether the device on `channel` sends a push notification in `mode`: its {@link DEVICE_NOTIFY_FLAG}
|
|
239
|
+
* in the action table the station reports for that mode. `undefined` where the station reports no table
|
|
240
|
+
* or the table does not list `channel`. A device's channel is `EufyDevice.channel`.
|
|
241
|
+
*/
|
|
242
|
+
readonly deviceNotification: import("./members.js").MethodMember<(mode: DeviceNotificationMode, channel: number) => boolean | undefined> & {
|
|
243
|
+
available: (ctx: CommandContext) => boolean;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Turn the push notification of the device on `channel` on or off in `mode` (cmd
|
|
247
|
+
* {@link ARMING_CMD.SET_ALL_ACTION}): the station's reported table written back with that one flag
|
|
248
|
+
* changed. Rejects, sending nothing, where the table does not list `channel`. A write builds on the last
|
|
249
|
+
* one sent for that mode until the station reports a table observed 15 s after it, so a second write does
|
|
250
|
+
* not revert it; a write whose dispatch rejects is not built on.
|
|
251
|
+
*/
|
|
252
|
+
readonly setDeviceNotification: import("./members.js").MethodMember<(mode: DeviceNotificationMode, channel: number, on: boolean) => Promise<void>> & {
|
|
253
|
+
available: (ctx: CommandContext) => boolean;
|
|
254
|
+
};
|
|
228
255
|
};
|
|
229
256
|
/**
|
|
230
257
|
* `arming` — guard/arming mode. `armingMode` (see {@link ARMING_CMD.SET_ARMING}) has a verified read/write
|
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
/** The parsed DP capability catalog for one product SKU. */
|
|
16
16
|
export interface DpCatalog {
|
|
17
17
|
/**
|
|
18
|
-
* For enum-type DPs: the
|
|
19
|
-
*
|
|
18
|
+
* For enum-type DPs: the range members exactly as the catalog lists them, as strings — value names
|
|
19
|
+
* (`"Quiet"`) or numeric strings (`"0"`), whichever the SKU's catalog uses. What a member means is
|
|
20
|
+
* the reading capability's to decide. Absent for non-enum DPs (bool, raw, integer, string).
|
|
20
21
|
*/
|
|
21
|
-
readonly enumRanges: ReadonlyMap<number, readonly
|
|
22
|
+
readonly enumRanges: ReadonlyMap<number, readonly string[]>;
|
|
22
23
|
}
|
|
23
24
|
/** Returned whenever the API call fails or the response shape is not recognised. */
|
|
24
25
|
export declare const EMPTY_DP_CATALOG: DpCatalog;
|
|
@@ -15,7 +15,7 @@ export declare const SUCTION_DP: {
|
|
|
15
15
|
* Suction levels — the app's `SuctionEnum` (`getSuctionEnumByValue`). This is a **fixed** value→label
|
|
16
16
|
* map with **no model argument**: a given int means the same thing on every RoboVac. What varies per
|
|
17
17
|
* model is only **availability** — a device's `get_product_data_point` range may expose a narrower
|
|
18
|
-
* subset (the T2351 catalog lists
|
|
18
|
+
* subset (the T2351 catalog lists `Quiet`–`Max`) — so the `suction` property stays a raw int rather than being
|
|
19
19
|
* constrained per device, and {@link suctionLevelName} names a reported level.
|
|
20
20
|
*
|
|
21
21
|
* `BoostIQ` (4) is a real suction level in this scale. The separate `boostIq`
|
|
@@ -45,11 +45,11 @@ export declare function suctionLevelName(value: number): string | undefined;
|
|
|
45
45
|
export type SuctionActions = Surface<typeof SUCTION_MEMBERS> & {
|
|
46
46
|
/**
|
|
47
47
|
* The suction levels this device supports, sourced from the per-SKU `get_product_data_point` catalog
|
|
48
|
-
* range for DP 158. Narrower than the full six {@link SuctionLevel} values on many models — a T2351
|
|
49
|
-
*
|
|
48
|
+
* range for DP 158. Narrower than the full six {@link SuctionLevel} values on many models — a T2351's
|
|
49
|
+
* catalog lists `Quiet`, `Standard`, `Turbo` and `Max`, which answers `[0, 1, 2, 3]`.
|
|
50
50
|
*
|
|
51
|
-
* `undefined` when the catalog is absent
|
|
52
|
-
* `setSuctionLevel` is installed (AIoT vacuums).
|
|
51
|
+
* `undefined` when the catalog is absent, does not cover DP 158, or lists only members outside the
|
|
52
|
+
* known scale. Only meaningful on devices where `setSuctionLevel` is installed (AIoT vacuums).
|
|
53
53
|
*/
|
|
54
54
|
readonly supportedLevels?: readonly SuctionLevelValue[];
|
|
55
55
|
};
|
package/dist/model/classify.d.ts
CHANGED
|
@@ -56,8 +56,7 @@ export declare function codecForType(deviceType: number): Codec | undefined;
|
|
|
56
56
|
* - `T74xx` → **lock** (SmartSafe 7400-series).
|
|
57
57
|
* - `T80xx` / `T8001` / `T8002` / `T8010` / `T8030` / `T8023` / `T8025` → **station**
|
|
58
58
|
* (HomeBase / HomeBase 2 / 3 / Mini), `T9000` (the app's own model registry files it as family
|
|
59
|
-
* `STATION_9000`, the one station family outside the T8 band), and `T8N00` (NVR)
|
|
60
|
-
* NVR) → station.
|
|
59
|
+
* `STATION_9000`, the one station family outside the T8 band), and `T8N00` (NVR) → station.
|
|
61
60
|
* - `T89xx` (entry/motion/water/siren sensors, e.g. T8900/T8910/T8920) → **sensor**.
|
|
62
61
|
* - `T87xx` keypad (`T8960`) → **keypad**.
|
|
63
62
|
* - any other `T8…` security T-code → **camera** (the default security family).
|
|
@@ -45,6 +45,8 @@ export declare const isFloodLight: (ctx: FamilyContext) => boolean;
|
|
|
45
45
|
export declare const isHomeBase: (ctx: FamilyContext) => boolean;
|
|
46
46
|
/** HomeBase S1 Pro (`STATION_9000`), the station the app drives over its WebRTC control channel. */
|
|
47
47
|
export declare const isStation9000: (ctx: FamilyContext) => boolean;
|
|
48
|
+
/** T8N00 NVR, identified by its reported model. */
|
|
49
|
+
export declare const isNvrT8N00: (ctx: FamilyContext) => boolean;
|
|
48
50
|
/** Wired doorbell (DeviceType.DOORBELL). */
|
|
49
51
|
export declare const isWiredDoorbell: (ctx: FamilyContext) => boolean;
|
|
50
52
|
/**
|
|
@@ -695,7 +695,7 @@ export declare class P2PCommandRouter {
|
|
|
695
695
|
* **`set-json-raw` intent** — bare JSON, no envelope: outer P2P cmd = `outerCmd` itself, plaintext
|
|
696
696
|
* exactly `{account_id,...data}` (`session.sendRawLevel2` with no wrapper). Reversed from a live
|
|
697
697
|
* capture of the app's own SET_SNOOZE_TIME (1271) frame — see `param-dictionary.ts`'s `1271` entry
|
|
698
|
-
* (`snoozeTime`); the alarm-delay config (1255, `arming.ts`'s `ARMING_CMD.
|
|
698
|
+
* (`snoozeTime`); the alarm-delay config (1255, `arming.ts`'s `ARMING_CMD.SET_ALL_ACTION`) reuses
|
|
699
699
|
* the same bare-JSON shape.
|
|
700
700
|
*/
|
|
701
701
|
private sendJsonRaw;
|
|
@@ -611,6 +611,18 @@ export declare class P2PSession extends EventEmitter {
|
|
|
611
611
|
accountId?: string;
|
|
612
612
|
channel?: number;
|
|
613
613
|
}): void;
|
|
614
|
+
/**
|
|
615
|
+
* Read a date-ranged page of `history_record_info` from the station. The reply's `data` array groups
|
|
616
|
+
* recording rows with companion tables; each group retains its `table_name` and `payload`.
|
|
617
|
+
* `startTime` is `"0"` for the newest page or the oldest row's `yyyyMMddHHmmss` cursor for older rows.
|
|
618
|
+
*/
|
|
619
|
+
queryRecordPage(opts: {
|
|
620
|
+
accountId?: string;
|
|
621
|
+
startDate: string;
|
|
622
|
+
endDate: string;
|
|
623
|
+
startTime?: string;
|
|
624
|
+
count?: number;
|
|
625
|
+
}): Promise<unknown[]>;
|
|
614
626
|
/**
|
|
615
627
|
* Query one on-station table and answer its rows, once the reply is whole.
|
|
616
628
|
*
|
|
@@ -618,13 +630,15 @@ export declare class P2PSession extends EventEmitter {
|
|
|
618
630
|
* several frames whose decrypted text is a fragment of one document, so the fragments are
|
|
619
631
|
* accumulated here and scanned after each one. Answers that document's `data` rows. Rejects when
|
|
620
632
|
* `signal` aborts, and when `timeoutMs` (default {@link DB_TABLE_TIMEOUT_MS}) elapses with no
|
|
621
|
-
* complete reply
|
|
633
|
+
* complete reply, and when the station answers a non-zero `mIntRet`.
|
|
622
634
|
*
|
|
623
635
|
* One read at a time per session: while one is accumulating, every {@link queryDatabase} on the
|
|
624
636
|
* session throws, so a second reply cannot land in this buffer.
|
|
625
637
|
*/
|
|
626
638
|
readDatabase(table: string, opts?: {
|
|
627
639
|
accountId?: string;
|
|
640
|
+
innerCmd?: number;
|
|
641
|
+
query?: Record<string, unknown>;
|
|
628
642
|
timeoutMs?: number;
|
|
629
643
|
signal?: AbortSignal;
|
|
630
644
|
}): Promise<unknown[]>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* RTC command router: drives a
|
|
3
|
-
* of P2P.
|
|
2
|
+
* RTC command router: drives a station over the portal's WebRTC data channel instead of P2P.
|
|
4
3
|
*
|
|
5
4
|
* The T9000 answers no P2P lookup, but it accepts the portal's control channel: sign → WS join → scall →
|
|
6
5
|
* SDP answer → ICE over the relay the hub grants → DTLS → SCTP data channels, with commands riding
|
|
@@ -26,6 +25,10 @@ export interface RtcIdentity {
|
|
|
26
25
|
}
|
|
27
26
|
/** Where a command goes: the station's session, and whether it addresses the station or a device on it. */
|
|
28
27
|
export interface RtcRoute {
|
|
28
|
+
/** The station's signaling exchange; defaults to compact SDP. */
|
|
29
|
+
signalingMode?: "call" | "scall";
|
|
30
|
+
/** Candidate policy used by the station's exchange; defaults to relay-only. */
|
|
31
|
+
iceTransportPolicy?: "relay" | "all";
|
|
29
32
|
stationSn: string;
|
|
30
33
|
/**
|
|
31
34
|
* The station's `member.admin_user_id`, the account the session and the payload name; the logged-in
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* then audio, idr, video, notify, download). Every one carries PTCS-framed portal packets; which logical
|
|
8
8
|
* channel a reassembled frame belongs to is the PTCS header's channel, not the data channel it rode on.
|
|
9
9
|
*
|
|
10
|
-
* ICE
|
|
10
|
+
* ICE defaults to relay-only. The T9000 grants a TURN allocation in its `scall 100` reply and completes DTLS only
|
|
11
11
|
* over the relay pair; on a host pair ICE connects and the DTLS handshake never completes. The peer
|
|
12
12
|
* plays the DTLS client (`active`) and opens its channels on the client's even SCTP stream ids, which
|
|
13
13
|
* is what the hub pairs with.
|
|
@@ -28,6 +28,8 @@ export interface TurnConfig {
|
|
|
28
28
|
export type NativePeerFactory = (name: string, config: RtcConfig) => PeerConnection;
|
|
29
29
|
export interface RtcPeerOptions {
|
|
30
30
|
createPeer?: NativePeerFactory;
|
|
31
|
+
/** Candidate policy for the station's exchange; the default is relay-only. */
|
|
32
|
+
iceTransportPolicy?: "relay" | "all";
|
|
31
33
|
logger?: Logger;
|
|
32
34
|
}
|
|
33
35
|
export interface RtcPeerEvents {
|
|
@@ -51,6 +53,7 @@ export declare class RtcPeer extends EventEmitter<RtcPeerEvents> {
|
|
|
51
53
|
private readonly wireTally;
|
|
52
54
|
private commandOpen;
|
|
53
55
|
private remoteSet;
|
|
56
|
+
private remoteMid;
|
|
54
57
|
private handlingOffer;
|
|
55
58
|
private channelsCreated;
|
|
56
59
|
private gatheringDone;
|
|
@@ -50,7 +50,7 @@ export declare class RtcSession extends EventEmitter<RtcSessionEvents> {
|
|
|
50
50
|
constructor(opts: RtcSessionOptions);
|
|
51
51
|
get isConnected(): boolean;
|
|
52
52
|
/**
|
|
53
|
-
* Start the sequence; resolves once
|
|
53
|
+
* Start the sequence; resolves once the call is sent. `connected` fires when the channel opens. A session
|
|
54
54
|
* closed by the time the sign fetch or the auth completes rejects instead of opening the socket or
|
|
55
55
|
* placing the call.
|
|
56
56
|
*/
|
|
@@ -68,6 +68,8 @@ export interface SignalingSocketInit {
|
|
|
68
68
|
}
|
|
69
69
|
export type SignalingSocketFactory = (url: string, init: SignalingSocketInit) => SignalingSocket;
|
|
70
70
|
export interface RtcSignalingOptions {
|
|
71
|
+
/** Full SDP (`call`) or compact SDP (`scall`, the default). */
|
|
72
|
+
signalingMode?: "call" | "scall";
|
|
71
73
|
/** The mega session's auth token. */
|
|
72
74
|
authToken: string;
|
|
73
75
|
/** The `gtoken` header value the mega session's authed HTTP calls carry. */
|
|
@@ -124,8 +126,8 @@ export declare class RtcSignalingClient extends EventEmitter<RtcSignalingEvents>
|
|
|
124
126
|
sendSession(dataType: string, payload?: Record<string, unknown>): void;
|
|
125
127
|
sendCall(): void;
|
|
126
128
|
sendAck(): void;
|
|
127
|
-
/** The SDP answer,
|
|
128
|
-
sendInfoSdp(
|
|
129
|
+
/** The SDP answer, encoded for the negotiated call format, in an `info`. */
|
|
130
|
+
sendInfoSdp(sdp: string): void;
|
|
129
131
|
/** Trickle a candidate on the session's channel, like its SDP answer. An empty candidate ends them. */
|
|
130
132
|
sendInfoCandidate(candidate: string): void;
|
|
131
133
|
sendHangup(): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mega-yfue/eufy-sdk",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
3
|
+
"version": "0.5.0-beta.23",
|
|
4
4
|
"description": "One typed TypeScript client for the Anker eufy v6 cloud — capability-driven devices, realtime events over P2P/MQTT/push, and live media",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "mega-yfue",
|