@mega-yfue/eufy-sdk 0.5.0-beta.9 → 0.5.0-beta.90

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.
Files changed (65) hide show
  1. package/dist/client/device-registry.d.ts +24 -2
  2. package/dist/client/eufy-mega.d.ts +73 -8
  3. package/dist/client/types.d.ts +1 -1
  4. package/dist/core/contracts.d.ts +96 -41
  5. package/dist/core/store.d.ts +4 -0
  6. package/dist/core/types.d.ts +2 -0
  7. package/dist/index.js +4152 -719
  8. package/dist/index.js.map +4 -4
  9. package/dist/model/capabilities/arming.d.ts +39 -4
  10. package/dist/model/capabilities/battery.d.ts +6 -1
  11. package/dist/model/capabilities/camera.d.ts +61 -18
  12. package/dist/model/capabilities/dp-catalog.d.ts +4 -3
  13. package/dist/model/capabilities/index.d.ts +17 -4
  14. package/dist/model/capabilities/keypad.d.ts +20 -23
  15. package/dist/model/capabilities/light.d.ts +3 -0
  16. package/dist/model/capabilities/lock.d.ts +42 -16
  17. package/dist/model/capabilities/motion.d.ts +17 -2
  18. package/dist/model/capabilities/mower.d.ts +230 -0
  19. package/dist/model/capabilities/rtsp.d.ts +16 -3
  20. package/dist/model/capabilities/smart-drop.d.ts +20 -0
  21. package/dist/model/capabilities/suction.d.ts +5 -5
  22. package/dist/model/capabilities/types.d.ts +10 -0
  23. package/dist/model/capabilities/vacuum-clean.d.ts +19 -13
  24. package/dist/model/classify.d.ts +1 -2
  25. package/dist/model/device-family.d.ts +24 -0
  26. package/dist/model/param-dictionary.d.ts +6 -0
  27. package/dist/model/param-namespace.d.ts +1 -1
  28. package/dist/model/types.d.ts +20 -12
  29. package/dist/transport/abortable.d.ts +8 -0
  30. package/dist/transport/http/mega-client.d.ts +43 -2
  31. package/dist/transport/mqtt/broker-discovery.d.ts +2 -1
  32. package/dist/transport/mqtt/command-router.d.ts +3 -2
  33. package/dist/transport/p2p/audio-frame.d.ts +14 -0
  34. package/dist/transport/p2p/codec.d.ts +32 -0
  35. package/dist/transport/p2p/command-router.d.ts +93 -31
  36. package/dist/transport/p2p/fmp4.d.ts +12 -2
  37. package/dist/transport/p2p/keyed-payload.d.ts +112 -0
  38. package/dist/transport/p2p/live-trace.d.ts +25 -2
  39. package/dist/transport/p2p/media.d.ts +3 -5
  40. package/dist/transport/p2p/p2p-session.d.ts +81 -12
  41. package/dist/transport/p2p/readable-egress.d.ts +3 -0
  42. package/dist/transport/p2p/recording-download.d.ts +4 -3
  43. package/dist/transport/p2p/shared-live-source.d.ts +44 -56
  44. package/dist/transport/p2p/talkback.d.ts +21 -10
  45. package/dist/transport/p2p/video.d.ts +2 -0
  46. package/dist/transport/push/push-client.d.ts +5 -0
  47. package/dist/transport/rtc/call-live.d.ts +41 -0
  48. package/dist/transport/rtc/command-router.d.ts +145 -0
  49. package/dist/transport/rtc/live.d.ts +76 -0
  50. package/dist/transport/rtc/peer.d.ts +122 -0
  51. package/dist/transport/rtc/portal-keepalive.d.ts +11 -0
  52. package/dist/transport/rtc/portal-packet.d.ts +72 -0
  53. package/dist/transport/rtc/ptcs-framer.d.ts +86 -0
  54. package/dist/transport/rtc/scall-sdp.d.ts +50 -0
  55. package/dist/transport/rtc/session.d.ts +99 -0
  56. package/dist/transport/rtc/signaling.d.ts +139 -0
  57. package/dist/transport/token-echo.d.ts +8 -0
  58. package/dist/transport/tuya/account.d.ts +8 -5
  59. package/dist/transport/tuya/client.d.ts +19 -5
  60. package/dist/transport/tuya/command-router.d.ts +10 -14
  61. package/dist/transport/tuya/dp-codec.d.ts +2 -23
  62. package/dist/transport/tuya/et3.d.ts +22 -0
  63. package/dist/transport/tuya/request.d.ts +18 -8
  64. package/dist/transport/tuya/sign.d.ts +7 -0
  65. package/package.json +7 -6
@@ -182,6 +182,11 @@ export interface AiDetectFlags {
182
182
  export declare function encodeAiDetectType(flags: AiDetectFlags): number;
183
183
  /** Decode an `ai_detect_type` bitmask → which detection types are on. */
184
184
  export declare function decodeAiDetectType(value: number): AiDetectFlags;
185
+ /**
186
+ * The `ai_detect_type` bitmask from a stored 1298 value: the bare number, or the numeric
187
+ * `ai_detect_type` field of the JSON object form. Answers `undefined` for any other shape.
188
+ */
189
+ declare function decodeAiDetectTypeParam(raw: unknown): number | undefined;
185
190
  /**
186
191
  * Decode a `radar_wd_switch` (2706, loitering) read the way the app does:
187
192
  * `typeof v === "object" ? v.radar_wd_switch : v`. The device may store it as a JSON object
@@ -245,11 +250,15 @@ export declare const MOTION_MEMBERS: {
245
250
  * 1298 holds the detailed AI-type BITMASK (live-observed: `0x30000` enabled-base | type bits, e.g. a
246
251
  * T8425 reads `0x3000f`). Cams also report 1299 (`hbAiDetectType`) but that is a separate, simpler
247
252
  * value (1) — NOT this bitmask, so 1298 is the read/write id.
253
+ *
254
+ * The value arrives in two shapes, both read by the app's 1298 parser: a bare bitmask, or a JSON
255
+ * object carrying the same bitmask as `ai_detect_type` (see {@link decodeAiDetectTypeParam}).
248
256
  */
249
257
  readonly aiDetectType: {
250
258
  readonly param: 1298;
251
- readonly type: "number";
252
- readonly kind: "bitfield";
259
+ readonly type: "string";
260
+ readonly decode: typeof decodeAiDetectTypeParam;
261
+ readonly decodedKind: "bitfield";
253
262
  readonly provenance: "verified";
254
263
  readonly description: string;
255
264
  readonly write: (v: string | number | boolean, ctx: CommandContext) => Command | undefined;
@@ -271,6 +280,10 @@ export declare const MOTION_MEMBERS: {
271
280
  * The raw sensitivity an indoor camera reports, on the one id whose write takes a `1700` control
272
281
  * payload carrying an index rather than the `1350` envelope its siblings use — a frame-shape
273
282
  * difference `sensitivityCommand` resolves from the scale. `unexposed` like its three siblings.
283
+ *
284
+ * Some devices report 6041 as a base64 JSON list of per-sensor entries
285
+ * (`{"list":[{"sensor_id":…,"sensitivity":…}]}`) rather than a scalar. That value is stored verbatim
286
+ * and this getter answers `undefined` for it: only the scalar form is confirmed to be this step.
274
287
  */
275
288
  readonly indoorSensitivity: {
276
289
  readonly param: 6041;
@@ -279,6 +292,7 @@ export declare const MOTION_MEMBERS: {
279
292
  readonly provenance: "verified";
280
293
  readonly unexposed: true;
281
294
  readonly description: "Raw sensitivity an indoor camera reports (verified: param 6041).";
295
+ readonly decode: (raw: unknown) => number | undefined;
282
296
  };
283
297
  /**
284
298
  * The raw sensitivity on the INVERTED seven-step camera scale — a HIGHER number is LESS sensitive, so
@@ -374,3 +388,4 @@ export declare const MOTION_MEMBERS: {
374
388
  };
375
389
  };
376
390
  export declare const MOTION: CapabilityModule;
391
+ export {};
@@ -0,0 +1,230 @@
1
+ import { type Surface } from "./members.js";
2
+ import type { CapabilityModule } from "./types.js";
3
+ /**
4
+ * Robot-mower Tuya **DP ids** — the E15's Tuya product schema (`thing.m.device.ref.info.list` v5.4,
5
+ * `schemaInfo.schema`, product `bvxrcjxom787vnit`), each id also reported by a live E15. The product
6
+ * is built on Tuya's robot-vacuum template, so ids below 101 carry that template's codes; the mower's
7
+ * own data points are 101-146.
8
+ *
9
+ * Only scalar data points are named here. The Raw ones (`robot_status` 107, `battery_status` 108,
10
+ * `map_info` 113, the `*_control` commands 103-106, …) are protobuf messages whose field layout no
11
+ * source in hand states, and 102 (`device_infomation`) and 142 (`gps_info`) carry the device's network
12
+ * identity and position.
13
+ * @internal
14
+ */
15
+ export declare const MOWER_DP: {
16
+ readonly BATTERY: 8;
17
+ readonly VOLUME: 26;
18
+ readonly CHILD_LOCK: 47;
19
+ readonly RAIN_AUTO_RETURN: 101;
20
+ readonly WIFI_SIGNAL: 109;
21
+ readonly MOW_HEIGHT: 110;
22
+ readonly SAVE_MAP_PROGRESS: 118;
23
+ readonly STATION_USED_TIME: 125;
24
+ readonly BLADE_USED_TIME: 126;
25
+ readonly EDGE_TRIM: 128;
26
+ readonly WORK_ANGLE_ENABLED: 130;
27
+ readonly WORK_ANGLE: 131;
28
+ readonly SMART_NO_GO_ZONES: 132;
29
+ readonly BIRD_VIEW_CAPTURE: 133;
30
+ readonly NETWORK: 134;
31
+ readonly CELLULAR_ENABLED: 137;
32
+ readonly EDGE_DISTANCE: 139;
33
+ readonly GPS_ANTI_THEFT: 140;
34
+ readonly SPARSE_LAWN_OPTIMIZATION: 141;
35
+ };
36
+ /** The `net_media_type` (DP 134) range, as the schema lists it. */
37
+ export declare const MOWER_NETWORKS: readonly ["None", "Wifi", "Cellular"];
38
+ /** The mower's network link (DP 134). */
39
+ export type MowerNetwork = (typeof MOWER_NETWORKS)[number];
40
+ /**
41
+ * Every `mower` read, declared once.
42
+ *
43
+ * All read-only. Several of these data points are `rw` in the schema, but no write has been captured
44
+ * against a mower, and the vendor app drives the mower through named pass-through commands rather than
45
+ * by publishing these DPs, so no setter is installed.
46
+ *
47
+ * Exported but NOT published: each entry states its wire id, which the reference site does not carry.
48
+ * @internal
49
+ */
50
+ export declare const MOWER_MEMBERS: {
51
+ /** Charge percentage (DP 8, `battery_percentage`). */
52
+ readonly battery: {
53
+ readonly param: 8;
54
+ readonly type: "number";
55
+ readonly unit: "%";
56
+ readonly kind: "percent";
57
+ readonly provenance: "mega";
58
+ readonly description: "Battery level 0-100 (DP 8, battery_percentage). Read-only.";
59
+ };
60
+ /** Speaker volume (DP 26, `volume_set`). */
61
+ readonly volume: {
62
+ readonly param: 26;
63
+ readonly type: "number";
64
+ readonly unit: "%";
65
+ readonly kind: "percent";
66
+ readonly provenance: "mega";
67
+ readonly description: "Speaker volume 0-100 (DP 26, volume_set). Read-only.";
68
+ };
69
+ /** Whether the child lock is on (DP 47, `child_lock`). */
70
+ readonly childLock: {
71
+ readonly param: 47;
72
+ readonly type: "bool";
73
+ readonly kind: "boolean";
74
+ readonly provenance: "mega";
75
+ readonly description: "Child lock on (DP 47, child_lock). Read-only.";
76
+ };
77
+ /** Whether the mower returns to its station when it detects rain (DP 101, `rain_auto_return`). */
78
+ readonly rainAutoReturn: {
79
+ readonly param: 101;
80
+ readonly type: "bool";
81
+ readonly kind: "boolean";
82
+ readonly provenance: "mega";
83
+ readonly description: "Return to the station when rain is detected (DP 101, rain_auto_return). Read-only.";
84
+ };
85
+ /** Wi-Fi signal strength as a percentage (DP 109, `wifi_signal_strength`), not a dBm reading. */
86
+ readonly wifiSignal: {
87
+ readonly param: 109;
88
+ readonly type: "number";
89
+ readonly unit: "%";
90
+ readonly kind: "percent";
91
+ readonly provenance: "mega";
92
+ readonly description: "Wi-Fi signal strength 0-100 % (DP 109, wifi_signal_strength). Read-only.";
93
+ };
94
+ /** Cutting height in millimetres (DP 110, `mow_height`), 25-75. */
95
+ readonly cutHeight: {
96
+ readonly param: 110;
97
+ readonly type: "number";
98
+ readonly unit: "mm";
99
+ readonly kind: "millimetres";
100
+ readonly min: 25;
101
+ readonly max: 75;
102
+ readonly provenance: "mega";
103
+ readonly description: "Cutting height 25-75 mm (DP 110, mow_height). Read-only.";
104
+ };
105
+ /** Progress of saving the map (DP 118, `save_map_process`). */
106
+ readonly mapSaveProgress: {
107
+ readonly param: 118;
108
+ readonly type: "number";
109
+ readonly unit: "%";
110
+ readonly kind: "percent";
111
+ readonly provenance: "mega";
112
+ readonly description: "Map-save progress 0-100 % (DP 118, save_map_process). Read-only.";
113
+ };
114
+ /** Total base-station use in minutes (DP 125, `base_station_used_time`). */
115
+ readonly stationUsedTime: {
116
+ readonly param: 125;
117
+ readonly type: "number";
118
+ readonly unit: "min";
119
+ readonly kind: "minutes";
120
+ readonly provenance: "mega";
121
+ readonly description: "Base-station use in minutes (DP 125, base_station_used_time). Read-only.";
122
+ };
123
+ /** Total cutting-blade use in minutes (DP 126, `mow_blade_used_time`). */
124
+ readonly bladeUsedTime: {
125
+ readonly param: 126;
126
+ readonly type: "number";
127
+ readonly unit: "min";
128
+ readonly kind: "minutes";
129
+ readonly provenance: "mega";
130
+ readonly description: "Cutting-blade use in minutes (DP 126, mow_blade_used_time). Read-only.";
131
+ };
132
+ /** Whether edge trimming is on (DP 128, `edge_trim`). */
133
+ readonly edgeTrim: {
134
+ readonly param: 128;
135
+ readonly type: "bool";
136
+ readonly kind: "boolean";
137
+ readonly provenance: "mega";
138
+ readonly description: "Edge trimming on (DP 128, edge_trim). Read-only.";
139
+ };
140
+ /** Whether a fixed mowing angle is in use (DP 130, `enable_work_angle`); the angle is `workAngle`. */
141
+ readonly workAngleEnabled: {
142
+ readonly param: 130;
143
+ readonly type: "bool";
144
+ readonly kind: "boolean";
145
+ readonly provenance: "mega";
146
+ readonly description: "Fixed mowing angle in use (DP 130, enable_work_angle). Read-only.";
147
+ };
148
+ /** The mowing angle in degrees, -90 to 90 (DP 131, `work_angle`). */
149
+ readonly workAngle: {
150
+ readonly param: 131;
151
+ readonly type: "number";
152
+ readonly unit: "°";
153
+ readonly kind: "degrees";
154
+ readonly min: -90;
155
+ readonly max: 90;
156
+ readonly provenance: "mega";
157
+ readonly description: "Mowing angle -90 to 90 degrees (DP 131, work_angle). Read-only.";
158
+ };
159
+ /** Whether smart no-go zones are on (DP 132, `enable_smart_forbid_zone`). */
160
+ readonly smartNoGoZones: {
161
+ readonly param: 132;
162
+ readonly type: "bool";
163
+ readonly kind: "boolean";
164
+ readonly provenance: "mega";
165
+ readonly description: "Smart no-go zones on (DP 132, enable_smart_forbid_zone). Read-only.";
166
+ };
167
+ /** Whether bird's-eye-view capture is on (DP 133, `enable_bird_view_capture`). */
168
+ readonly birdViewCapture: {
169
+ readonly param: 133;
170
+ readonly type: "bool";
171
+ readonly kind: "boolean";
172
+ readonly provenance: "mega";
173
+ readonly description: "Bird's-eye-view capture on (DP 133, enable_bird_view_capture). Read-only.";
174
+ };
175
+ /**
176
+ * The network link in use (DP 134, `net_media_type`). Answers `undefined` for a value outside the
177
+ * schema's range.
178
+ */
179
+ readonly network: {
180
+ readonly param: 134;
181
+ readonly type: "string";
182
+ readonly provenance: "mega";
183
+ readonly decode: (raw: unknown) => MowerNetwork | undefined;
184
+ readonly decodedKind: "enum";
185
+ readonly decodedValues: readonly ["None", "Wifi", "Cellular"];
186
+ readonly description: "Network link: None, Wifi or Cellular (DP 134, net_media_type). Read-only.";
187
+ };
188
+ /** Whether the cellular link is enabled (DP 137, `enable_cellular`). */
189
+ readonly cellularEnabled: {
190
+ readonly param: 137;
191
+ readonly type: "bool";
192
+ readonly kind: "boolean";
193
+ readonly provenance: "mega";
194
+ readonly description: "Cellular link enabled (DP 137, enable_cellular). Read-only.";
195
+ };
196
+ /** Edge-following distance in millimetres (DP 139, `follow_edge_distance`), signed. */
197
+ readonly edgeDistance: {
198
+ readonly param: 139;
199
+ readonly type: "number";
200
+ readonly unit: "mm";
201
+ readonly kind: "millimetres";
202
+ readonly min: -10000;
203
+ readonly max: 10000;
204
+ readonly provenance: "mega";
205
+ readonly description: "Edge-following distance in mm, signed (DP 139, follow_edge_distance). Read-only.";
206
+ };
207
+ /** Whether GPS anti-theft is on (DP 140, `gps_location_check`). */
208
+ readonly gpsAntiTheft: {
209
+ readonly param: 140;
210
+ readonly type: "bool";
211
+ readonly kind: "boolean";
212
+ readonly provenance: "mega";
213
+ readonly description: "GPS anti-theft on (DP 140, gps_location_check). Read-only.";
214
+ };
215
+ /** Whether sparse-lawn optimisation is on (DP 141, `sparse_lawn_optimization`). */
216
+ readonly sparseLawnOptimization: {
217
+ readonly param: 141;
218
+ readonly type: "bool";
219
+ readonly kind: "boolean";
220
+ readonly provenance: "mega";
221
+ readonly description: "Sparse-lawn optimisation on (DP 141, sparse_lawn_optimization). Read-only.";
222
+ };
223
+ };
224
+ /**
225
+ * Bound mower reads — the object returned by `dev.mower()`. Each getter is present only once the
226
+ * mower has reported its data point.
227
+ */
228
+ export type MowerActions = Surface<typeof MOWER_MEMBERS>;
229
+ /** `mower` — robot-mower state from its Tuya data points. */
230
+ export declare const MOWER: CapabilityModule;
@@ -1,6 +1,6 @@
1
1
  import type { Command } from "../../core/contracts.js";
2
2
  import { type Surface } from "./members.js";
3
- import type { CapabilityModule, CommandContext } from "./types.js";
3
+ import type { AvailabilityContext, CapabilityModule, CommandContext } from "./types.js";
4
4
  /** The state params this capability owns — its OWN vocabulary, used by no other capability. */
5
5
  export declare const RTSP_PARAM: {
6
6
  /**
@@ -93,6 +93,13 @@ export type RtspRecordingModeValue = (typeof RtspRecordingMode)[keyof typeof Rts
93
93
  * and the served effect on each endpoint with an RTSP `DESCRIBE`: 401 = challenged, 200 = open.
94
94
  */
95
95
  export type RtspActions = Surface<typeof RTSP_MEMBERS>;
96
+ /**
97
+ * Whether the publish switch has a wire to this camera. A HomeBase S1 Pro (`STATION_9000`) carries an
98
+ * attached camera's commands over its WebRTC control channel, which takes only the `1350` and `1700`
99
+ * envelopes; the switch is a plain scalar, and no other frame for it is captured there. Gating the
100
+ * `published` member drops its read with its setter, since one availability decision covers both.
101
+ */
102
+ declare function publishable(ctx: AvailabilityContext): boolean;
96
103
  /**
97
104
  * Every `rtsp` feature, declared once.
98
105
  *
@@ -127,6 +134,7 @@ export declare const RTSP_MEMBERS: {
127
134
  readonly publish: true;
128
135
  readonly withdraw: false;
129
136
  };
137
+ readonly available: typeof publishable;
130
138
  };
131
139
  /**
132
140
  * The device-reported RTSP URL — the full `rtsp://user:pass@host/path`, carrying the credentials the
@@ -179,9 +187,13 @@ export declare const RTSP_MEMBERS: {
179
187
  readonly description: string;
180
188
  };
181
189
  /** Persistently publish this camera's stream. The enabling caller owns withdrawing it when done. */
182
- readonly publish: import("./members.js").MethodMember<() => Promise<void>>;
190
+ readonly publish: import("./members.js").MethodMember<() => Promise<void>> & {
191
+ available: (ctx: CommandContext) => boolean;
192
+ };
183
193
  /** Withdraw this camera's persistent publication; consumer retries do not ask the SDK to republish it. */
184
- readonly withdraw: import("./members.js").MethodMember<() => Promise<void>>;
194
+ readonly withdraw: import("./members.js").MethodMember<() => Promise<void>> & {
195
+ available: (ctx: CommandContext) => boolean;
196
+ };
185
197
  /**
186
198
  * Store credentials and request authentication on this camera's stream. Served enforcement is
187
199
  * topology-dependent and must be verified with `DESCRIBE` (401 = challenged, 200 = open).
@@ -219,3 +231,4 @@ export declare const RTSP_MEMBERS: {
219
231
  * rather than a model table.
220
232
  */
221
233
  export declare const RTSP: CapabilityModule;
234
+ export {};
@@ -0,0 +1,20 @@
1
+ import { type Surface } from "./members.js";
2
+ import type { CapabilityModule } from "./types.js";
3
+ /**
4
+ * Every `smart_drop` feature, declared once.
5
+ *
6
+ * Exported but NOT published: each entry states its wire id and the evidence it was confirmed on,
7
+ * which the reference site does not carry.
8
+ * @internal
9
+ */
10
+ export declare const SMART_DROP_MEMBERS: {
11
+ /**
12
+ * Opens the lid with `SET_PAYLOAD` 2100 at level 2. Verified on a standalone T8790, whose cipher has
13
+ * only an RSA key: the frame sealed AES-128-ECB opened the lid, the same frame at level 1 did not.
14
+ */
15
+ readonly openLid: import("./members.js").MethodMember<() => Promise<void>>;
16
+ };
17
+ /** Bound SmartDrop controls — the object returned by `dev.smartDrop()`. */
18
+ export type SmartDropActions = Surface<typeof SMART_DROP_MEMBERS>;
19
+ /** `smart_drop` — a standalone SmartDrop (T8790) parcel box: open the lid. */
20
+ export declare const SMART_DROP: CapabilityModule;
@@ -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 0-3) — so the `suction` property stays a raw int rather than being
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
- * reports `[0, 1, 2, 3]`.
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 or does not cover DP 158. Only meaningful on devices where
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
  };
@@ -60,6 +60,8 @@ export type ProductLine = "security" | "life" | "clean" | "print" | "display" |
60
60
  * `p2p-frame` shape of {@link InboundSignal}.
61
61
  */
62
62
  export interface CapabilityFrame {
63
+ /** Cloud device type resolved from the reporting station/channel. */
64
+ deviceType?: number;
63
65
  stationSn: string;
64
66
  commandId: number;
65
67
  channel: number;
@@ -247,8 +249,16 @@ export interface AvailabilityContext {
247
249
  homeBaseAttached?: boolean;
248
250
  /** Serial of the covering station, when the device record names one. */
249
251
  stationSerial?: string;
252
+ /**
253
+ * The vendor DeviceType of the station the device hangs off, when it is attached
254
+ * and the station's record states one. Answers which station family a command addressed to an
255
+ * attached device is carried through.
256
+ */
257
+ stationDeviceType?: number;
250
258
  }
251
259
  export interface CommandContext extends AvailabilityContext {
260
+ /** Vendor-formatted timezone reported by the station; never inferred from the host. */
261
+ timezone?: string;
252
262
  /** Device channel (0 for standalone, `device_channel` on a HomeBase). */
253
263
  channel: number;
254
264
  /** eufy DeviceType, when known. */
@@ -169,12 +169,11 @@ export declare const TUYA_CLEAN_TYPES: readonly ["Sweep", "SweepMop", "Mop"];
169
169
  /** @internal */
170
170
  export type TuyaCleanType = (typeof TUYA_CLEAN_TYPES)[number];
171
171
  /**
172
- * `ModeCtrlRequest.method` values for DP 152. Live-verified on T2351: START_AUTO_CLEAN → 0
173
- * (omitted from the wire when zero), START_GOHOME → 6, PAUSE_TASK → 13.
172
+ * `ModeCtrlRequest.method` values for DP 152. Live-verified on T2351: START_GOHOME → 6,
173
+ * PAUSE_TASK → 13. An auto clean is `START_AUTO_CLEAN` (0) with a payload — see
174
+ * {@link ModeCtrlParamMethod}.
174
175
  */
175
176
  export declare const ModeCtrlMethod: {
176
- /** Live-verified on a T2351. Zero, so it is omitted from the wire per the proto3 default rule. */
177
- readonly START_AUTO_CLEAN: 0;
178
177
  /** Live-verified on a T2351. */
179
178
  readonly START_GOHOME: 6;
180
179
  /** Live-verified on a T2351. */
@@ -202,9 +201,11 @@ export declare const ModeCtrlMethod: {
202
201
  * its argument in the signature: {@link VACUUM_CLEAN_MEMBERS.startScene},
203
202
  * {@link VACUUM_CLEAN_MEMBERS.cleanRooms} and {@link VACUUM_CLEAN_MEMBERS.cleanZones}.
204
203
  *
205
- * The outer frame these ride in is byte-verified on a live T2351, and `SCENE`, `SELECT_ROOMS` and
206
- * `SELECT_ZONES` have each since been RUN on a T2351 and did what they name — so their numbers rest on
207
- * observed behaviour rather than on the vendor's definition alone.
204
+ * The outer frame these ride in is byte-verified on a live T2351, and `AUTO`, `SCENE`, `SELECT_ROOMS`
205
+ * and `SELECT_ZONES` have each since been RUN on a T2351 and did what they name — so their numbers rest
206
+ * on observed behaviour rather than on the vendor's definition alone. `AUTO` is RUN with its payload:
207
+ * the vendor's definition calls `AutoClean.clean_times` valid only when non-zero, and the T2351 did
208
+ * not start on method 0 sent without it.
208
209
  *
209
210
  * That distinction is the whole point of checking, and this is the one place it is argued: an AIoT
210
211
  * data-point write is fire-and-forget, so a wrong number would be a different command arriving and
@@ -215,6 +216,11 @@ export declare const ModeCtrlMethod: {
215
216
  * scene id and a map id both arrive on DP 180.
216
217
  */
217
218
  export declare const ModeCtrlParamMethod: {
219
+ /** `START_AUTO_CLEAN` with an `AutoClean` payload — clean the whole floor. */
220
+ readonly AUTO: {
221
+ readonly method: 0;
222
+ readonly param: 3;
223
+ };
218
224
  /** `START_SELECT_ROOMS_CLEAN` — clean the named rooms of a named map. */
219
225
  readonly SELECT_ROOMS: {
220
226
  readonly method: 1;
@@ -274,17 +280,17 @@ export declare function encodeSelectZonesClean(mapId: number, zones: readonly Va
274
280
  * @internal
275
281
  */
276
282
  export declare function encodeSceneClean(sceneId: number): string;
283
+ /**
284
+ * Build a whole-floor auto clean carrying an `AutoClean` payload of one pass.
285
+ * @internal
286
+ */
287
+ export declare function encodeAutoClean(): string;
277
288
  /**
278
289
  * Encode a `ModeCtrlRequest` protobuf (DP 152) as a DP value: `varint(bodyLen) ++ {method:1, seq:2}`.
279
290
  *
280
291
  * Built on {@link RawDpWriter} rather than hand-rolled bytes. The frame is unchanged and the existing
281
292
  * byte-level test is what proves it — that test was written against a live T2351 capture, so it holds
282
293
  * the writer to the wire rather than to this function's own idea of the wire.
283
- *
284
- * Method 0 (START_AUTO_CLEAN) is omitted rather than written as an explicit zero, per the proto3
285
- * default-field rule and confirmed on that same capture. The writer deliberately does not apply that
286
- * rule itself: whether an explicit zero and an absent field mean the same thing is the
287
- * message's business, not the encoder's.
288
294
  * @internal
289
295
  */
290
296
  export declare function encodeModeCtrl(method: number, seq: number): string;
@@ -1955,7 +1961,7 @@ export declare const VACUUM_CLEAN_MEMBERS: {
1955
1961
  readonly provenance: "mega";
1956
1962
  readonly description: "Stop smart-follow mode (ModeCtrlRequest method 18 over DP 152). Method number not captured — unverified.";
1957
1963
  };
1958
- /** Start an auto-clean run via ModeCtrlRequest method 0 (DP 152). AIoT only — Tuya write unverified. */
1964
+ /** Start an auto-clean run via ModeCtrlRequest method 0 with one `AutoClean` pass (DP 152). AIoT only — Tuya write unverified. */
1959
1965
  readonly startCleaning: import("./members.js").MethodMember<() => Promise<void>> & {
1960
1966
  available: (ctx: import("./types.js").CommandContext) => boolean;
1961
1967
  };
@@ -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) / `T8E00` (PoE
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).
@@ -11,6 +11,11 @@ export interface FamilyContext {
11
11
  * `"eufy_home_tuya"` devices are on the ThingClips/Tuya Cloud platform, not Anker AIoT MQTT.
12
12
  */
13
13
  category?: string;
14
+ /**
15
+ * Full device serial, when known. The one family split that no type number expresses: the vendor
16
+ * reuses one DeviceType across generations of a product and distinguishes them by serial.
17
+ */
18
+ serial?: string;
14
19
  }
15
20
  /** Indoor cams, incl. indoor pan/tilt + S350/E30/C-series + mini. */
16
21
  export declare const INDOOR_CAMERA_TYPES: ReadonlySet<number>;
@@ -43,6 +48,16 @@ export declare const isOutdoorPanTilt: (ctx: FamilyContext) => boolean;
43
48
  export declare const isFloodLight: (ctx: FamilyContext) => boolean;
44
49
  /** HomeBase-family hub (has a speaker/alarm) — a station EXCLUDING the NVRs, per `HOMEBASE_TYPES`. */
45
50
  export declare const isHomeBase: (ctx: FamilyContext) => boolean;
51
+ /** HomeBase S1 Pro (`STATION_9000`), the station the app drives over its WebRTC control channel. */
52
+ export declare const isStation9000: (ctx: FamilyContext) => boolean;
53
+ /** T8N00 NVR, identified by its reported model. */
54
+ export declare const isNvrT8N00: (ctx: FamilyContext) => boolean;
55
+ /** PoE cameras whose media is served by their NVR's portal call. */
56
+ export declare const isNvrMediaCamera: (ctx: FamilyContext) => boolean;
57
+ /** PoE S4 camera with independently streamed fixed and movable optical views. */
58
+ export declare const isNvrDualLensCamera: (ctx: FamilyContext) => boolean;
59
+ /** Video Doorbell C31 (T8223), identified by its reported model. */
60
+ export declare const isDoorbellT8223: (ctx: FamilyContext) => boolean;
46
61
  /** Wired doorbell (DeviceType.DOORBELL). */
47
62
  export declare const isWiredDoorbell: (ctx: FamilyContext) => boolean;
48
63
  /**
@@ -72,3 +87,12 @@ export declare const isAiotVacuum: (ctx: FamilyContext) => boolean;
72
87
  * vacuums receive the same write actions as AIoT ones, routed by the facade's `routeCommand`.
73
88
  */
74
89
  export declare const isTuyaVacuum: (ctx: FamilyContext) => boolean;
90
+ /** Video Smart Lock S330, identified by its distinct cloud device type. */
91
+ export declare const isVideoSmartLock: (ctx: FamilyContext) => boolean;
92
+ /**
93
+ * The classic Wi-Fi smart lock — the unit whose actuation rides a per-command ECDH-wrapped key rather than
94
+ * the shared `ff09` frame: DeviceType 51 with a serial in the `T8520` range whose seventh character is `2`,
95
+ * the one range driven on hardware. The DeviceType alone does not identify it, since later units share the
96
+ * number and take the `ff09` frame, and a device whose serial is unknown is not guessed either way.
97
+ */
98
+ export declare const isClassicWifiLock: (ctx: FamilyContext) => boolean;
@@ -9,6 +9,7 @@
9
9
  * `types.ts`.
10
10
  * - CLEAN_PARAMS — RoboVac Tuya DP space (ids 1 and above), names from the cloud
11
11
  * `get_product_data_point` data_point_list, hence provenance `mega`.
12
+ * - MOWER_PARAMS — robot-mower Tuya DP space, names from the mower's Tuya product schema.
12
13
  *
13
14
  * Which models reported an id, and the capture that named it, are in the commit that adds the entry.
14
15
  */
@@ -50,3 +51,8 @@ export declare const CLEAN_PARAMS: Record<number, ParamDef>;
50
51
  * display settings screen, one control at a time, params diffed after each.
51
52
  */
52
53
  export declare const DISPLAY_PARAMS: Record<number, ParamDef>;
54
+ /**
55
+ * Robot-mower Tuya DP space — names from the E15's Tuya product schema (`schemaInfo.schema`), each id
56
+ * also reported by a live E15. Only the scalar data points the `mower` capability reads are listed.
57
+ */
58
+ export declare const MOWER_PARAMS: Record<number, ParamDef>;
@@ -14,7 +14,7 @@
14
14
  import type { Codec } from "./types.js";
15
15
  import { type ParamDef } from "./param-dictionary.js";
16
16
  /** The param id spaces this SDK models. */
17
- export type ParamNamespace = "security" | "clean" | "life" | "print" | "display";
17
+ export type ParamNamespace = "security" | "clean" | "mower" | "life" | "print" | "display";
18
18
  /** Look up a param def in the given namespace. */
19
19
  export declare function paramDef(ns: ParamNamespace, paramType: number): ParamDef | undefined;
20
20
  /** The param namespace a device's ids live in, from its codec, via the module-local `NAMESPACE_BY_CODEC` table. */
@@ -39,7 +39,7 @@ export type Codec = "station" | "camera" | "sensor" | "lock" | "keypad" | "vacuu
39
39
  * it maps to a {@link CapabilityModule} that owns its property schema. Extend this union as
40
40
  * new capabilities are modelled — adding one never requires a subclass.
41
41
  */
42
- export type Capability = "video" | "snapshot" | "motion" | "person_detection" | "battery" | "light" | "ptz" | "doorbell" | "contact" | "leak" | "smoke" | "co" | "siren" | "lock" | "keypad" | "arming" | "storage" | "rtsp" | "camera" | "audio" | "vacuum_clean" | "vacuum_dock" | "suction" | "locate" | "smart_light" | "display" | "info";
42
+ export type Capability = "video" | "snapshot" | "motion" | "person_detection" | "battery" | "light" | "ptz" | "doorbell" | "contact" | "leak" | "smoke" | "co" | "siren" | "lock" | "keypad" | "arming" | "storage" | "rtsp" | "camera" | "audio" | "vacuum_clean" | "vacuum_dock" | "suction" | "locate" | "mower" | "smart_drop" | "smart_light" | "display" | "info";
43
43
  /** Value type of a property. */
44
44
  export type PropertyValueType = "bool" | "number" | "string" | "enum";
45
45
  /**
@@ -52,11 +52,12 @@ export type PropertyValueType = "bool" | "number" | "string" | "enum";
52
52
  * one as the other is wrong in a way no type check catches.
53
53
  *
54
54
  * - `boolean` — an on/off state (always paired with `type: "bool"`).
55
- * - `percent` / `celsius` / `dbm` / `seconds` / `hours` / `megabytes` / `degrees` — a measured quantity
56
- * in the unit the device reports it in; each pairs with the matching `unit`. Values are
57
- * never converted on the way out — a converted reading is an invented one. `seconds` and `hours`
58
- * are separate kinds for exactly that reason: a robot reports a run in seconds and a consumable's
59
- * wear in hours, and normalising one into the other would publish a number the device never sent.
55
+ * - `percent` / `celsius` / `dbm` / `seconds` / `hours` / `minutes` / `millimetres` / `megabytes` /
56
+ * `degrees` — a measured quantity in the unit the device reports it in; each pairs with the
57
+ * matching `unit`. Values are never converted on the way out — a converted reading is an invented
58
+ * one. `seconds`, `minutes` and `hours` are separate kinds for exactly that reason: a robot reports
59
+ * a run in seconds, a mower its blade wear in minutes and a vacuum's consumable wear in hours, and
60
+ * normalising one into another would publish a number the device never sent.
60
61
  * - `scalar` — a plain number in no unit at all: a step on a ladder, a mode index, a raw level, a
61
62
  * segment count. Ordered and comparable, but its range and direction are the device's, so nothing
62
63
  * but the device says what a given value means.
@@ -83,7 +84,7 @@ export type PropertyValueType = "bool" | "number" | "string" | "enum";
83
84
  * decodes them and are exported beside that decoder; unlike an enum's options they are not carried
84
85
  * here, which is a gap this vocabulary does not close on its own.
85
86
  */
86
- export declare const KNOWN_VALUE_KINDS: readonly ["boolean", "percent", "celsius", "dbm", "seconds", "hours", "megabytes", "degrees", "scalar", "bitfield", "enum", "identifier", "timestamp", "text"];
87
+ export declare const KNOWN_VALUE_KINDS: readonly ["boolean", "percent", "celsius", "dbm", "seconds", "hours", "minutes", "millimetres", "megabytes", "degrees", "scalar", "bitfield", "enum", "identifier", "timestamp", "text"];
87
88
  /** One of the kinds this version models — the closed half of {@link ValueKind}. */
88
89
  export type KnownValueKind = (typeof KNOWN_VALUE_KINDS)[number];
89
90
  /**
@@ -106,7 +107,8 @@ export declare function isKnownValueKind(kind: ValueKind): kind is KnownValueKin
106
107
  /**
107
108
  * How much a param's name and meaning can be trusted, most-trusted first. This is the one definition;
108
109
  * the param dictionary and every `provenance` field use it.
109
- * - `mega` — the vendor's cloud names it: its data-point catalog (`get_product_data_point`), or a
110
+ * - `mega` — the vendor's cloud names it: its data-point catalog (`get_product_data_point`), the
111
+ * Tuya product schema of an `eufy_home_tuya` device (`thing.m.device.ref.info.list`), or a
110
112
  * reported value that matches what the cloud record already says (a model name or code).
111
113
  * - `verified` — confirmed on a real device by this project: our own capture or observation, or
112
114
  * identified by someone who has the hardware.
@@ -140,6 +142,11 @@ export interface PropertySpec {
140
142
  kind?: ValueKind;
141
143
  /** Whether the value can be written back to the device (a setter exists). */
142
144
  writable: boolean;
145
+ /**
146
+ * Whether the device has reported this value: its own param, a read alias, or the payload it reads
147
+ * from. `false` means it never has. Absent when the manifest was built without the device's params.
148
+ */
149
+ reported?: boolean;
143
150
  /** Allowed values for `type: "enum"` (raw → label). */
144
151
  enumValues?: Record<number, string>;
145
152
  /**
@@ -170,10 +177,11 @@ export interface PropertySpec {
170
177
  * consumable counters are `"number"` over one base64 string, and reading the value as a number is
171
178
  * exactly what must NOT happen at ingest.
172
179
  *
173
- * Storage already keeps such a value intact — a non-numeric string cannot be coerced to a number, so
174
- * it is passed through. What this flag changes is that the pass-through stops being reported as a
175
- * mistake: a robot reporting ten Raw DPs on every push logged ten warnings a time saying its
176
- * properties were misdeclared, which is how a real warning goes unread.
180
+ * Storage keeps such a value intact: a non-numeric string passes a `number` coercion unchanged, and
181
+ * on a `bool` property a string that is not a boolean wire form (`"0"`, `"1"`, `"true"`, `"false"`)
182
+ * is kept rather than read as `false`. The pass-through is not reported as a mistake: a robot
183
+ * reporting ten Raw DPs on every push logged ten warnings a time saying its properties were
184
+ * misdeclared, which is how a real warning goes unread.
177
185
  */
178
186
  raw?: true;
179
187
  /**
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Settle `work` as it settles, or reject the moment `signal` aborts, whichever comes first.
3
+ *
4
+ * The underlying wait is left to finish on its own: it may be shared work other callers are waiting on, so a
5
+ * caller abandoning its own call does not cancel the work itself. This abandons WAITING, which is the only
6
+ * part that belonged to the caller.
7
+ */
8
+ export declare function abortable<T>(work: Promise<T>, signal?: AbortSignal): Promise<T>;