@apocaliss92/nodedreame 1.11.10 → 1.12.0

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/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { fetch } from 'undici';
2
2
  import { z } from 'zod';
3
+ import { EventEmitter } from 'node:events';
3
4
 
4
5
  /** Public name of this library. */
5
6
  declare const LIBRARY_NAME = "nodedreame";
@@ -36,6 +37,47 @@ declare class DreameTransportError extends DreameError {
36
37
  /** Supported Dreame cloud regions. */
37
38
  type DreameRegion = 'eu' | 'us' | 'cn' | 'ru' | 'sg' | 'in' | 'de' | 'tw';
38
39
 
40
+ /**
41
+ * Connectivity / diagnostic info distilled from a device-list record.
42
+ *
43
+ * Scope note: the Dreame cloud device record exposes reachability + identity +
44
+ * the assigned MQTT broker, but NOT Wi-Fi RSSI / SSID / local IP — those are
45
+ * native-firmware (miIO-style) details the cloud API does not return for these
46
+ * vacuums. So `signalStrength`/`ssid`/`ip` are intentionally absent here; this
47
+ * surfaces everything the cloud actually provides.
48
+ */
49
+ /** The device's assigned MQTT broker endpoint (from `bindDomain`). */
50
+ interface BrokerEndpoint {
51
+ readonly host: string;
52
+ readonly port: number | null;
53
+ }
54
+ interface DeviceConnectivity {
55
+ /** Whether the cloud considers the device online (LWT/online flag). */
56
+ readonly online: boolean;
57
+ /** Physical link type reported by the cloud (e.g. `"WIFI"`), or null. */
58
+ readonly connectionType: string | null;
59
+ /** Device MAC address, or null. */
60
+ readonly mac: string | null;
61
+ /** Assigned MQTT broker (`bindDomain` split into host/port), or null. */
62
+ readonly broker: BrokerEndpoint | null;
63
+ /** Cloud region the device is bound to (e.g. `"eu"`), or null. */
64
+ readonly region: string | null;
65
+ /** Cloud media/IoT vendor (e.g. `"ali"`), or null. */
66
+ readonly cloudVendor: string | null;
67
+ /** Firmware version (`ver`), or null. */
68
+ readonly firmwareVersion: string | null;
69
+ /** Serial number (`sn`), or null. */
70
+ readonly serialNumber: string | null;
71
+ /** Sub-model code, or null. */
72
+ readonly subModel: string | null;
73
+ /** Battery percentage 0–100 from the cloud snapshot, or null. */
74
+ readonly battery: number | null;
75
+ /** Latest MIoT status int from the cloud snapshot, or null. */
76
+ readonly statusCode: number | null;
77
+ }
78
+ /** Parse the connectivity view from a raw device-list record. */
79
+ declare function parseConnectivity(raw: Record<string, unknown>): DeviceConnectivity;
80
+
39
81
  interface DreameSession {
40
82
  accessToken: string;
41
83
  refreshToken?: string | undefined;
@@ -55,6 +97,8 @@ interface DreameDevice {
55
97
  firmwareVersion?: string;
56
98
  serialNumber?: string;
57
99
  cloudState?: DreameCloudState;
100
+ /** Connectivity/diagnostic view distilled from the cloud record. */
101
+ connectivity?: DeviceConnectivity;
58
102
  }
59
103
  /** Cloud-cached subset of device state distilled from the device-list response. */
60
104
  interface DreameCloudState {
@@ -169,6 +213,8 @@ declare class TypedEmitter<Events extends Record<string, unknown[]>> {
169
213
  once<K extends keyof Events & string>(event: K, listener: (...args: Events[K]) => void): this;
170
214
  off<K extends keyof Events & string>(event: K, listener: (...args: Events[K]) => void): this;
171
215
  emit<K extends keyof Events & string>(event: K, ...args: Events[K]): boolean;
216
+ /** Number of listeners registered for `event`. */
217
+ listenerCount<K extends keyof Events & string>(event: K): number;
172
218
  removeAllListeners(): this;
173
219
  }
174
220
 
@@ -179,6 +225,14 @@ interface PropertyChange {
179
225
  piid: number;
180
226
  value: unknown;
181
227
  }
228
+ /**
229
+ * True when `err` (or an error in its `cause` chain) is an MQTT CONNACK
230
+ * auth-refusal. mqtt.js raises an `ErrorWithReasonCode` carrying a numeric
231
+ * `code`: MQTT 3.1.1 uses 4 (bad user/pass) / 5 (not authorized); MQTT 5 uses
232
+ * 134 / 135. We also match the human-readable message as a belt-and-braces
233
+ * fallback in case the code is not surfaced through a wrapper.
234
+ */
235
+ declare function isAuthRefusedError(err: unknown): boolean;
182
236
 
183
237
  /**
184
238
  * A read-only set of capability tokens a device model supports. Phase 2 ships
@@ -294,7 +348,7 @@ interface PushLike {
294
348
  }
295
349
  /** Injectable collaborators — defaults wire the real transport + command layer. */
296
350
  interface BaseDeviceDeps {
297
- createPush(device: DreameDevice, session: DreameSession, region: DreameRegion): PushLike;
351
+ createPush(device: DreameDevice, session: DreameSession, region: DreameRegion, onAuthFailure?: () => Promise<DreameSession>): PushLike;
298
352
  getProperties(base: CommonInput, props: MiotProp[]): Promise<PropertyResult[]>;
299
353
  /** Read the cloud-cached (shadow) values WITHOUT waking the device. */
300
354
  getCachedProperties(base: CommonInput, props: MiotProp[]): Promise<PropertyResult[]>;
@@ -316,6 +370,12 @@ interface BaseDeviceInput {
316
370
  region: DreameRegion;
317
371
  /** Always reads the LATEST session — the facade owns the variable. */
318
372
  sessionRef: () => DreameSession;
373
+ /**
374
+ * Force-refresh callback handed to the underlying push so it can self-heal a
375
+ * broker CONNACK auth-refusal (stale token) by minting a fresh session.
376
+ * Wired by the facade to `Nodreame.reauthenticate()`.
377
+ */
378
+ onAuthFailure?: () => Promise<DreameSession>;
319
379
  deps?: BaseDeviceDeps;
320
380
  /** Eager-seed the cache on `start()`. Default true. */
321
381
  fetchInitialValues?: boolean;
@@ -376,6 +436,12 @@ interface CreateDeviceArgs {
376
436
  device: DreameDevice;
377
437
  region: DreameRegion;
378
438
  sessionRef: () => DreameSession;
439
+ /**
440
+ * Force-refresh callback handed down to the device's MQTT push so it can
441
+ * self-heal a broker CONNACK auth-refusal (stale token). Bound by the facade
442
+ * to {@link Nodreame.reauthenticate}.
443
+ */
444
+ onAuthFailure?: () => Promise<DreameSession>;
379
445
  }
380
446
  /** Injectable collaborators — defaults wire the real P1 modules. */
381
447
  interface NodreameDeps {
@@ -419,6 +485,15 @@ declare class Nodreame extends TypedEmitter<NodreameEvents> {
419
485
  login(): Promise<DreameSession>;
420
486
  /** Return a valid session, refreshing proactively within the leeway window. */
421
487
  ensureSession(): Promise<DreameSession>;
488
+ /**
489
+ * Force a session refresh REGARDLESS of the current expiry, then propagate the
490
+ * new token to every live device push. Wired as each push's `onAuthFailure`:
491
+ * when a broker refuses a CONNECT because it considers the token stale (even
492
+ * though {@link ensureSession} still thinks it valid — e.g. server-side early
493
+ * revocation or clock skew), this mints a genuinely fresh token instead of
494
+ * replaying the rejected one.
495
+ */
496
+ reauthenticate(): Promise<DreameSession>;
422
497
  /** Discover devices and build a live handle per device. */
423
498
  discoverDevices(): Promise<readonly BaseDevice[]>;
424
499
  /** Tear everything down: close every device push and clear timers. */
@@ -901,6 +976,268 @@ declare class VacuumCapabilityResolver implements CapabilityResolver {
901
976
  resolve(model: string): DeviceCapabilities;
902
977
  }
903
978
 
979
+ /**
980
+ * MIoT surface of the Dreame camera service (SIID 10001), reversed byte-exact
981
+ * from the r2538z (X50) React-Native plugin `Monitor` model. Every camera
982
+ * control the app issues is a MIoT `action` on this service; the values below
983
+ * are the verbatim aiid/piid maps from the bundle.
984
+ */
985
+ /** The camera/monitor service id. Same across the X40/X50 vacuum class. */
986
+ declare const MONITOR_SIID = 10001;
987
+ /** Action instance ids on {@link MONITOR_SIID}. */
988
+ declare const MONITOR_AIID: {
989
+ /** Stream lifecycle + keep-alive (monitor start/end, keep_alive). */
990
+ readonly CAMERA_OPERATE: 1;
991
+ /** Two-way intercom start/end. */
992
+ readonly VOICE_OPERATE: 2;
993
+ /** Generic property-scoped operations. */
994
+ readonly PROPERTY_OPERATE: 3;
995
+ /** Privacy access-code gate (launch/verify/set/reset). */
996
+ readonly ACCESS_CODE_OPERATE: 4;
997
+ /** Video-vendor SDK init / switch. */
998
+ readonly VIDEO_VENDOR: 7;
999
+ };
1000
+ /** Property instance ids on {@link MONITOR_SIID}. */
1001
+ declare const MONITOR_PIID: {
1002
+ readonly MONITOR_STATUS: 1;
1003
+ readonly MONITOR_AUDIO_STATUS: 2;
1004
+ readonly MONITOR_RECORD_STATUS: 4;
1005
+ readonly TAKE_PHOTO: 5;
1006
+ readonly KEEP_ALIVE: 6;
1007
+ readonly MONITOR_FAULTS: 7;
1008
+ readonly FILL_LIGHT_SET: 9;
1009
+ readonly CAMERA_LIGHT_SWITCH: 10;
1010
+ readonly VIDEO_VENDOR_STATUS: 11;
1011
+ readonly GET_PROPERTY: 99;
1012
+ readonly PERSON_DATA: 110;
1013
+ readonly VIDEO_OBSTACLE_SWITCH: 111;
1014
+ readonly VIDEO_OBSTACLE_DATA: 112;
1015
+ readonly MONITOR_TASK_STATUS: 103;
1016
+ readonly UPLOAD_STATUS: 1003;
1017
+ readonly GET_ACCESS_CODE: 1100;
1018
+ readonly SET_ACCESS_CODE: 1101;
1019
+ readonly VERIFY_ACCESS_CODE: 1102;
1020
+ readonly MONITOR_REST_MODE: 1103;
1021
+ readonly SET_ACCESS_HOT_STATUS: 1104;
1022
+ readonly MONITOR_SPACE: 2003;
1023
+ };
1024
+ /**
1025
+ * The `token` field the `startMonitor` action expects, keyed by vendor. Aliyun
1026
+ * LinkVisual uses the literal `"alify"`; Tencent uses `"tx"`. (Agora passes an
1027
+ * RTC access token instead and is not modelled here.)
1028
+ */
1029
+ declare const MONITOR_VENDOR_TOKEN: Record<'ali' | 'tx', string>;
1030
+ /**
1031
+ * The vacuum work service (SIID 4). The camera has no gimbal — "PTZ" and the
1032
+ * camera-adjacent controls (remote drive, go-to-point, person-follow) drive the
1033
+ * robot itself through this service.
1034
+ */
1035
+ declare const VACUUM_SIID = 4;
1036
+ declare const VACUUM_MOVE: {
1037
+ /** Remote-drive state property (set_properties), sent ~1 Hz while held. */
1038
+ readonly REMOTE_STATE_PIID: 15;
1039
+ /** Work-mode action instance (go-to-point, cruise, person-follow start). */
1040
+ readonly WORK_AIID: 1;
1041
+ /** Work-mode stop action instance (person-follow stop). */
1042
+ readonly STOP_AIID: 2;
1043
+ /** piid carrying the work-mode selector value in the WORK action. */
1044
+ readonly MODE_PIID: 1;
1045
+ /** piid carrying the point-info JSON in the WORK action. */
1046
+ readonly POINT_PIID: 10;
1047
+ /** Work-mode selector values. */
1048
+ readonly MODE_SPOT: 23;
1049
+ readonly MODE_CRUISE: 22;
1050
+ readonly MODE_PERSON_FOLLOW: 26;
1051
+ readonly MODE_SPOT_CLEAN: 20;
1052
+ /** Auto-switch setter property (fill-light auto/full toggle lives here). */
1053
+ readonly AUTO_SWITCH_PIID: 50;
1054
+ };
1055
+ /** Pet-teasing sound clips playable via {@link VOICE_PLAY_SOUND_AIID}. */
1056
+ declare const PET_SOUNDS: {
1057
+ readonly meow: 684;
1058
+ readonly bark: 685;
1059
+ readonly footsteps: 686;
1060
+ readonly purring: 687;
1061
+ readonly tickTock: 688;
1062
+ };
1063
+ type PetSound = keyof typeof PET_SOUNDS;
1064
+ /** Common whole-robot actions (usable as camera presets). */
1065
+ declare const VACUUM_ACTIONS: {
1066
+ readonly startClean: {
1067
+ readonly siid: 2;
1068
+ readonly aiid: 1;
1069
+ };
1070
+ readonly pauseClean: {
1071
+ readonly siid: 2;
1072
+ readonly aiid: 2;
1073
+ };
1074
+ readonly stopClean: {
1075
+ readonly siid: 4;
1076
+ readonly aiid: 2;
1077
+ };
1078
+ readonly dockWash: {
1079
+ readonly siid: 4;
1080
+ readonly aiid: 4;
1081
+ };
1082
+ readonly autoEmpty: {
1083
+ readonly siid: 15;
1084
+ readonly aiid: 1;
1085
+ };
1086
+ };
1087
+ type VacuumActionKey = keyof typeof VACUUM_ACTIONS;
1088
+
1089
+ /**
1090
+ * Per-session correlation token, exactly as the app's `Monitor.updateSession()`:
1091
+ * `MD5(accountId + "_" + epochMillis)`. Pass an explicit `now` for deterministic
1092
+ * tests. `accountId` is the Dreame account uid.
1093
+ */
1094
+ declare function makeMonitorSession(accountId: string, now?: number): string;
1095
+ /** SHA-256 hex of a privacy access code, as `Monitor.verifyAccessCode` sends it. */
1096
+ declare function hashAccessCode(code: string): string;
1097
+ /**
1098
+ * Remote-drive value (siid 4 / piid 15), sent ~1 Hz while a direction is held.
1099
+ * `spdv` = forward speed (200 fwd, 0 stop), `spdw` = turn (45 left, -45 right,
1100
+ * 180 turn-around, 0 straight). Pass an explicit `now` for deterministic tests.
1101
+ */
1102
+ declare function remoteDriveValue(spdv: number, spdw: number, now?: number): string;
1103
+ /** Named remote-drive directions, mapping to (spdv, spdw). */
1104
+ declare const DRIVE_DIRECTIONS: {
1105
+ readonly forward: readonly [200, 0];
1106
+ readonly left: readonly [0, 45];
1107
+ readonly right: readonly [0, -45];
1108
+ readonly turnAround: readonly [0, 180];
1109
+ readonly stop: readonly [0, 0];
1110
+ };
1111
+ type DriveDirection = keyof typeof DRIVE_DIRECTIONS;
1112
+
1113
+ /**
1114
+ * MIoT device transport the controller drives — satisfied by a nodedreame device
1115
+ * handle (VacuumDevice). `setProperty` is optional so callAction-only fakes still
1116
+ * satisfy the interface; the robot-drive helpers require it.
1117
+ */
1118
+ interface MonitorActionCaller {
1119
+ callAction(siid: number, aiid: number, input: unknown[]): Promise<unknown>;
1120
+ setProperty?(write: {
1121
+ siid: number;
1122
+ piid: number;
1123
+ value: unknown;
1124
+ }): Promise<unknown>;
1125
+ }
1126
+ /** Minimal relay minter — satisfied by {@link DreameVideoSession}. */
1127
+ interface RelayMinter {
1128
+ getStreamInfo(iotId: string, opts?: {
1129
+ encrypted?: boolean;
1130
+ wakeTimeoutMs?: number;
1131
+ pollMs?: number;
1132
+ }): Promise<{
1133
+ relayUrl: string | null;
1134
+ }>;
1135
+ }
1136
+ interface DreameCameraControllerInput {
1137
+ /** MIoT action transport (the device handle). */
1138
+ readonly device: MonitorActionCaller;
1139
+ /** Aliyun relay minter (a {@link DreameVideoSession}). */
1140
+ readonly relay: RelayMinter;
1141
+ /** LinkVisual channel id for this device (`iotId`). */
1142
+ readonly iotId: string;
1143
+ /** Dreame account uid — seeds the per-session correlation token. */
1144
+ readonly accountId: string;
1145
+ /** Video vendor. Only `ali` mints an RTMP relay; defaults to `ali`. */
1146
+ readonly vendor?: 'ali' | 'tx';
1147
+ /** Privacy access code (PIN) set at pairing, if any. Required to wake a coded camera. */
1148
+ readonly accessCode?: string;
1149
+ /** Aliyun region code the device reports as `area`; defaults to `'4'`. */
1150
+ readonly area?: string;
1151
+ /** Keep-alive cadence in ms (app default 10s). */
1152
+ readonly keepAliveIntervalMs?: number;
1153
+ /** Max time to wait for the relay to come up while the device wakes. */
1154
+ readonly wakeTimeoutMs?: number;
1155
+ /** Reported when a keep-alive tick fails (the stream is likely dying). */
1156
+ readonly onKeepAliveError?: (err: unknown) => void;
1157
+ /** Optional line logger (nodelink-style). Defaults to no-op. */
1158
+ readonly log?: (line: string) => void;
1159
+ }
1160
+ /** A live camera stream: the pullable relay URL plus the device's per-stream key. */
1161
+ interface CameraStreamHandle {
1162
+ /** Plain RTMP relay URL (H.264 + AAC). Single stream; re-open for another consumer. */
1163
+ readonly rtmpUrl: string;
1164
+ /** Device-generated per-session encryption key echoed by `startMonitor`. */
1165
+ readonly encryptionKey: string | null;
1166
+ }
1167
+ declare class DreameCameraController {
1168
+ #private;
1169
+ constructor(input: DreameCameraControllerInput);
1170
+ /** True while a monitor session is active (between {@link open} and {@link close}). */
1171
+ get isOpen(): boolean;
1172
+ /**
1173
+ * Run the full cold-start sequence and return a live relay URL. Starts the
1174
+ * keep-alive loop; the caller MUST {@link close} when done to release the
1175
+ * device. Throws if the monitor cannot be started or no relay comes up.
1176
+ */
1177
+ open(): Promise<CameraStreamHandle>;
1178
+ /**
1179
+ * Mint a FRESH single-use RTMP relay URL for the already-open monitor. Each
1180
+ * consumer needs its own relay URL, so call this once per ffmpeg/consumer.
1181
+ * Throws if the stream is not open.
1182
+ */
1183
+ mintRelayUrl(): Promise<string>;
1184
+ /** Start the two-way intercom session (control plane only; see module docs on mic uplink). */
1185
+ startIntercom(opts?: {
1186
+ needRecordSound?: boolean;
1187
+ videoCall?: boolean;
1188
+ }): Promise<unknown>;
1189
+ /** Stop the two-way intercom session. */
1190
+ stopIntercom(): Promise<unknown>;
1191
+ /** Set the fill-light brightness (40–100 = manual %, below 40 / 101 = auto). */
1192
+ setFillLight(value: number): Promise<unknown>;
1193
+ /**
1194
+ * Device-side snapshot: the robot captures a still and uploads it to cloud
1195
+ * storage (read the result back from the `uploadStatus` property). Prefer a
1196
+ * frame-grab from the live stream for an instant image.
1197
+ */
1198
+ takePhoto(): Promise<unknown>;
1199
+ /**
1200
+ * Remote-drive the robot ("PTZ" substitute — the camera is fixed, the robot
1201
+ * moves). `spdv` = forward speed, `spdw` = turn; send repeatedly (~1 Hz) while
1202
+ * a direction is held, then `stop`. Only valid while the stream is open.
1203
+ */
1204
+ drive(spdv: number, spdw: number): Promise<unknown>;
1205
+ /** Remote-drive by named direction (forward/left/right/turnAround/stop). */
1206
+ driveDirection(direction: DriveDirection): Promise<unknown>;
1207
+ /** Start person-follow mode (robot tracks a detected person). */
1208
+ startPersonFollow(): Promise<unknown>;
1209
+ /**
1210
+ * Universal stop for the current work mode — stops person-follow, spot-clean,
1211
+ * go-to-point, cruise, etc. (siid 4 / aiid 2).
1212
+ */
1213
+ stopWork(): Promise<unknown>;
1214
+ /** Stop person-follow mode (alias for {@link stopWork}). */
1215
+ stopPersonFollow(): Promise<unknown>;
1216
+ /** Spot-clean the robot's current position (WorkMode SpotClean). */
1217
+ spotClean(): Promise<unknown>;
1218
+ /** Play one of the robot's sound clips (e.g. pet sounds) by id. */
1219
+ playSound(soundId: number): Promise<unknown>;
1220
+ /** Play a named pet-teasing sound (meow/bark/footsteps/purring/tickTock). */
1221
+ playPetSound(sound: PetSound): Promise<unknown>;
1222
+ /** Run a common whole-robot action (startClean/pauseClean/stopClean/dockWash/autoEmpty). */
1223
+ runVacuumAction(action: VacuumActionKey): Promise<unknown>;
1224
+ /** Find-pet: cruise the home looking for the pet. */
1225
+ findPet(): Promise<unknown>;
1226
+ /** Send the robot to a map point (`spoint` current, `tpoint` targets). */
1227
+ goToPoint(spoint: number[][], tpoint: number[][]): Promise<unknown>;
1228
+ /** Toggle the fill light between auto (`full=false`) and full-on (`full=true`). */
1229
+ setFillLightAuto(full: boolean): Promise<unknown>;
1230
+ /**
1231
+ * Send the robot back to its dock to charge ("go home"). Works regardless of
1232
+ * stream state — usable as a standalone command or a PTZ "home" preset.
1233
+ */
1234
+ returnToDock(): Promise<unknown>;
1235
+ /** Locate the robot — it beeps. Works regardless of stream state. */
1236
+ locate(): Promise<unknown>;
1237
+ /** Stop the keep-alive loop and release the monitor on the device. Idempotent. */
1238
+ close(): Promise<void>;
1239
+ }
1240
+
904
1241
  /**
905
1242
  * Public types for the live-map decoder.
906
1243
  *
@@ -1215,6 +1552,19 @@ interface VacuumMap {
1215
1552
  */
1216
1553
  cleanedArea: MapCleanedAreaOverlay | null;
1217
1554
  }
1555
+ /**
1556
+ * Optional decode hints. The AES key is per-blob (it arrives appended to
1557
+ * the OSS object name with a comma, or via the OLD_MAP_DATA multiplexed
1558
+ * format); the IV is per-model (lives in Tasshack's `device_info` table)
1559
+ * and must be supplied here since node-dreame doesn't ship a per-model
1560
+ * IV lookup.
1561
+ */
1562
+ interface VacuumMapDecodeOptions {
1563
+ /** AES-256-CBC key — 32 ASCII hex chars from `sha256(<rawKey>)[0:32]`. */
1564
+ key?: string;
1565
+ /** AES-256-CBC IV — 16 ASCII bytes, model-specific. */
1566
+ iv?: string;
1567
+ }
1218
1568
 
1219
1569
  /**
1220
1570
  * Raster PNG renderer for a decoded `VacuumMap`.
@@ -1276,6 +1626,34 @@ interface RenderVacuumPngOptions {
1276
1626
  }
1277
1627
  declare function renderVacuumPng(map: VacuumMap, opts?: RenderVacuumPngOptions): Buffer;
1278
1628
 
1629
+ interface WifiSignalMap {
1630
+ readonly dimensions: MapDimensions;
1631
+ /** Robot pose from the frame header, or null when absent. */
1632
+ readonly robot: MapPose | null;
1633
+ /** Charging-dock pose from the frame header, or null when absent. */
1634
+ readonly dock: MapPose | null;
1635
+ /** Raw per-cell nibble (`pixel & 15`), row-major (width*height). */
1636
+ readonly cells: Uint8Array;
1637
+ /** Signal bars (1–4) at a world point, 0 = unreached, or null = no Wi-Fi data / off-map. */
1638
+ signalAt(worldX: number, worldY: number): number | null;
1639
+ /** Signal bars at the robot's own position (or null when unknown). */
1640
+ readonly currentSignal: number | null;
1641
+ }
1642
+ /** Decode a Wi-Fi map blob (raw string/Buffer or already-inflated) into signal cells + geometry. */
1643
+ declare function decodeWifiSignalMap(input: string | Buffer, opts?: VacuumMapDecodeOptions): WifiSignalMap;
1644
+ interface RenderWifiSignalPngOptions {
1645
+ /** Upscale factor (each map cell → scale×scale px). Default 4. */
1646
+ scale?: number;
1647
+ /** Draw a marker at the robot position. Default true. */
1648
+ markRobot?: boolean;
1649
+ }
1650
+ /**
1651
+ * Render a simple Wi-Fi coverage heatmap PNG (weakest→strongest blue, unreached
1652
+ * grey, no-data transparent), with an optional robot marker — a ready-to-show
1653
+ * image for consumers.
1654
+ */
1655
+ declare function renderWifiSignalPng(map: WifiSignalMap, opts?: RenderWifiSignalPngOptions): Buffer;
1656
+
1279
1657
  /**
1280
1658
  * Resolve a Dreame OSS object name (advertised via the PATH push,
1281
1659
  * `siid 6 piid 3`) to a signed download URL and fetch the blob.
@@ -1368,6 +1746,26 @@ interface VacuumGetMapInput {
1368
1746
  /** Caller-supplied AbortSignal. */
1369
1747
  signal?: AbortSignal;
1370
1748
  }
1749
+ /** Input to {@link VacuumDevice.getWifiSignalMap} / {@link VacuumDevice.getCurrentSignal}. */
1750
+ interface WifiSignalMapInput {
1751
+ /** Request the last stored map first (default true). `false` = read what's advertised. */
1752
+ requestFresh?: boolean;
1753
+ /** Poll interval (ms) while waiting for the OSS object to be advertised. Default 2500. */
1754
+ pollMs?: number;
1755
+ /** Max wait (ms) for the map to become available. Default 20000. */
1756
+ maxWaitMs?: number;
1757
+ /** Inject the signed-blob fetcher (tests pass a fake). */
1758
+ fetcher?: OssFetcherLike;
1759
+ /** Optional AES key/iv for an encrypted blob (hex). */
1760
+ key?: string;
1761
+ iv?: string;
1762
+ /** Override the API host (defaults from the device region). */
1763
+ host?: string;
1764
+ /** Per-request timeout override in ms. */
1765
+ timeoutMs?: number;
1766
+ /** Caller-supplied AbortSignal. */
1767
+ signal?: AbortSignal;
1768
+ }
1371
1769
  /** A typed Dreame-vacuum handle (state + capability-gated commands). */
1372
1770
  declare class VacuumDevice extends BaseDevice<VacuumDeviceEvents> {
1373
1771
  #private;
@@ -1608,6 +2006,29 @@ declare class VacuumDevice extends BaseDevice<VacuumDeviceEvents> {
1608
2006
  * `applyVacuumPFrame` merge primitive ships separately for that work.
1609
2007
  */
1610
2008
  getMap(input: VacuumGetMapInput): Promise<VacuumMap>;
2009
+ /**
2010
+ * Fetch the robot's Wi-Fi signal map — the last stored coverage heatmap, with
2011
+ * NO robot movement. Requests it (map service `wifiMap` action, siid 6 aiid 4),
2012
+ * polls `PropWifiMap` (6/15) for the OSS object it advertises, fetches + decodes
2013
+ * it into a per-cell signal grid + geometry + robot/dock poses. The signal at
2014
+ * any world point (incl. the robot's own position) is a lookup — see
2015
+ * {@link WifiSignalMap.signalAt} / {@link WifiSignalMap.currentSignal}.
2016
+ *
2017
+ * Pass `requestFresh: false` to skip the request and read whatever is already
2018
+ * advertised. Throws if no Wi-Fi map exists yet (never run on this device).
2019
+ */
2020
+ getWifiSignalMap(input?: WifiSignalMapInput): Promise<WifiSignalMap>;
2021
+ /**
2022
+ * Render the Wi-Fi signal map as a simple PNG heatmap image (weakest→strongest,
2023
+ * unreached grey, robot marker) — ready to display. Convenience over
2024
+ * {@link getWifiSignalMap} + {@link renderWifiSignalPng}.
2025
+ */
2026
+ getWifiSignalImage(input?: WifiSignalMapInput & RenderWifiSignalPngOptions): Promise<Buffer>;
2027
+ /**
2028
+ * The one-call "current Wi-Fi signal": fetches the signal map and returns the
2029
+ * bars (1–4, 0 = unreached) at the robot's own position, or null when unknown.
2030
+ */
2031
+ getCurrentSignal(input?: WifiSignalMapInput): Promise<number | null>;
1611
2032
  /** Drop the P-frame merge base so the next I-frame re-seeds the stream. */
1612
2033
  resetMapStream(): void;
1613
2034
  /**
@@ -1624,6 +2045,37 @@ declare class VacuumDevice extends BaseDevice<VacuumDeviceEvents> {
1624
2045
  * frame on every push during a live clean.
1625
2046
  */
1626
2047
  fetchLatestMapStreaming(opts?: Omit<VacuumGetMapInput, 'filename'>): Promise<VacuumMap | null>;
2048
+ /**
2049
+ * Build a {@link DreameCameraController} for this device's camera, wired to
2050
+ * both planes it needs: the MIoT action transport (this device handle) and a
2051
+ * fresh Aliyun {@link DreameVideoSession} for the relay. Call
2052
+ * `controller.open()` to autonomously cold-start the stream and get a pullable
2053
+ * RTMP URL, then `controller.close()` to release it.
2054
+ *
2055
+ * The camera's per-session privacy gate means a coded camera needs its PIN:
2056
+ * pass `accessCode` (the code set at pairing). `iotId` is resolved from the
2057
+ * device's cloud video profile when not supplied.
2058
+ */
2059
+ createCameraController(opts?: {
2060
+ /** LinkVisual channel id; resolved from the cloud profile when omitted. */
2061
+ iotId?: string;
2062
+ /** Privacy PIN set at pairing (required to wake a coded camera). */
2063
+ accessCode?: string;
2064
+ /** Video vendor; defaults to `ali` (the only vendor that mints an RTMP relay). */
2065
+ vendor?: 'ali' | 'tx';
2066
+ /** Aliyun region code reported as `area`; defaults to `'4'`. */
2067
+ area?: string;
2068
+ /** Keep-alive cadence in ms (default 10s). */
2069
+ keepAliveIntervalMs?: number;
2070
+ /** Max time to wait for the relay while the device wakes. */
2071
+ wakeTimeoutMs?: number;
2072
+ /** Reported when a keep-alive tick fails. */
2073
+ onKeepAliveError?: (err: unknown) => void;
2074
+ /** Optional nodelink-style line logger. */
2075
+ log?: (line: string) => void;
2076
+ /** Reuse an existing relay minter (e.g. a shared {@link DreameVideoSession}). */
2077
+ relay?: RelayMinter;
2078
+ }): Promise<DreameCameraController>;
1627
2079
  /** Props worth seeding on start() / polling — exported for the facade. */
1628
2080
  static readonly DEFAULT_PROPS: readonly [{
1629
2081
  readonly siid: 2;
@@ -2274,13 +2726,13 @@ declare const DeviceDumpSchema: z.ZodObject<{
2274
2726
  type: z.ZodOptional<z.ZodString>;
2275
2727
  }, "strip", z.ZodTypeAny, {
2276
2728
  model: string;
2277
- type?: string | undefined;
2278
2729
  region?: string | undefined;
2730
+ type?: string | undefined;
2279
2731
  firmware?: string | undefined;
2280
2732
  }, {
2281
2733
  model: string;
2282
- type?: string | undefined;
2283
2734
  region?: string | undefined;
2735
+ type?: string | undefined;
2284
2736
  firmware?: string | undefined;
2285
2737
  }>;
2286
2738
  observations: z.ZodObject<{
@@ -2438,8 +2890,8 @@ declare const DeviceDumpSchema: z.ZodObject<{
2438
2890
  libraryVersion: string;
2439
2891
  device: {
2440
2892
  model: string;
2441
- type?: string | undefined;
2442
2893
  region?: string | undefined;
2894
+ type?: string | undefined;
2443
2895
  firmware?: string | undefined;
2444
2896
  };
2445
2897
  observations: {
@@ -2485,8 +2937,8 @@ declare const DeviceDumpSchema: z.ZodObject<{
2485
2937
  libraryVersion: string;
2486
2938
  device: {
2487
2939
  model: string;
2488
- type?: string | undefined;
2489
2940
  region?: string | undefined;
2941
+ type?: string | undefined;
2490
2942
  firmware?: string | undefined;
2491
2943
  };
2492
2944
  observations: {
@@ -2598,4 +3050,670 @@ declare function createDumper(target: DumperDevice, options?: DumperOptions): Du
2598
3050
  */
2599
3051
  declare function createClientDumper(client: Nodreame, options?: DumperOptions): Dumper[];
2600
3052
 
2601
- export { AI_FEATURE_BIT, AI_FEATURE_JSON_KEY, AUTO_SWITCH_JSON_KEY, type AiDetectionRaw, type AutoSwitchKey, type AutoSwitchRaw, BaseDevice, type BaseDeviceEvents, type BatchDeviceDataFetcher, type CapabilityResolver, ChargingStatus, type CleanOpts, CleaningMode, type ConsumableReading, type ConsumableSpec, type CreateDeviceArgs, DefaultCapabilityResolver, type DeviceCapabilities, type DeviceDump, type DeviceEvent, type DreameAiFeature, DreameApiError, DreameAuthError, type DreameCloudState, type DreameConsumableKey, type DreameDevice, DreameDeviceOfflineError, DreameError, type DreameRegion, type DreameSession, DreameTransportError, type DumperOptions, LIBRARY_NAME, MODEL_CAPABILITIES as MOWER_MODEL_CAPABILITIES, MOWER_TASK_SUBSTATES, type MapBoundingBox, type MapCleanedAreaOverlay, type MapColorScheme, type MapDimensions, type MapFrameType, type MapLayer, type MapLayerType, type MapLowLyingArea, type MapObstacle, type MapPath, type MapPathType, type MapPoint, type MapPose, type MapRestrictedArea, type MapRoom, type MapRoomWall, type MapRun, type MapSegment, type MapStorey, type MapVirtualWall, type MapWallsInfo, type MiotAction, MiotError, type MiotProp, MiotState, type MowerAvailableMap, type MowerCapabilities, MowerCapabilityResolver, MowerChargingStatus, type MowerConsumableKey, type MowerConsumableReading, type MowerContour, MowerControlAction, type MowerControlState, MowerDevice, type MowerDeviceInput, MowerFault, type MowerFaultSeverity, type MowerHeartbeat, type MowerMap, type MowerMapBoundary, type MowerMowPath, type MowerMowingProgress, type MowerPathEntry, type MowerPoint, type MowerSpotArea, MowerStatus, type MowerTaskDescriptor, MowerTaskStatus, type MowerTaskSubState, type MowerZone, Nodreame, type NodreameDeps, type NodreameEvents, type NodreameOptions, type OssFetchInput, type OssFetcherLike, type PropertyChangedEvent, type PropertyResult, type PropertyState, type PropertyWrite, type RenderMowerSvgOptions, type RenderVacuumPngOptions, type StateChangedEvent, SuctionLevel, TaskStatus, VACUUM_CONSUMABLES, MODEL_CAPABILITIES$1 as VACUUM_MODEL_CAPABILITIES, type VacuumCapabilities, VacuumCapabilityResolver, VacuumDevice, type VacuumGetMapInput, type VacuumMap, WaterVolume, consumableSpec, createClientDumper, createDumper, decodeAiFeature, decodeAutoSwitch, decodeAutoSwitchAll, encodeAiFeatureWrite, encodeAutoSwitchWrite, extractMowerConsumableValues, getMowerCapabilities, getVacuumCapabilities, isDreameConsumableKey, mowerConsumableIndex, mowerFaultSeverity, parseMowerConsumables, parseMowerHeartbeat, parseMowingProgress, renderMowerSvg, renderVacuumPng, resolveCapabilities, supportedAutoSwitchKeys };
3053
+ /**
3054
+ * Public types for the video control-plane. The Dreamehome cloud fronts several
3055
+ * camera backends ("vendors"); a device advertises which ones it supports and
3056
+ * which one it is currently provisioned on. This module models only the
3057
+ * control-plane (token + session negotiation); the media transport per vendor
3058
+ * is built on top of it.
3059
+ */
3060
+ /** Camera backend a device streams through. `tx` = Tencent, `ali` = Aliyun LinkVisual. */
3061
+ type VideoVendor = 'tx' | 'ali';
3062
+ /** Short-lived token minted by `tx/user/accesstoken`, used by the video endpoints. */
3063
+ interface VideoAccessToken {
3064
+ /** Opaque bearer for the third-video service (distinct from the account token). */
3065
+ readonly token: string;
3066
+ /** Numeric video-service user id, as a string. */
3067
+ readonly userId: string | null;
3068
+ /** Epoch-ms at which {@link token} expires (converted from the cloud's epoch-seconds). */
3069
+ readonly expiresAt: number;
3070
+ }
3071
+ /**
3072
+ * A device's video profile, derived from its cloud record. Tells you whether the
3073
+ * device has a camera, which vendors it supports, which one it is on now, and —
3074
+ * when on Aliyun — its LinkVisual `iotId` (the id every LinkVisual call needs).
3075
+ */
3076
+ interface DeviceVideoProfile {
3077
+ /** Dreame device id (the `did`). */
3078
+ readonly did: string;
3079
+ /** Model code, e.g. `dreame.vacuum.r2538z`. */
3080
+ readonly model: string;
3081
+ /** Human product name, e.g. `X50 Ultra Complete`. */
3082
+ readonly displayName: string | null;
3083
+ /** True when the device exposes a camera stream (`permit === "video"`). */
3084
+ readonly videoCapable: boolean;
3085
+ /** The vendor the device is currently provisioned on (`''` in the record → null). */
3086
+ readonly currentVendor: VideoVendor | null;
3087
+ /** Vendors the device can use, in cloud-declared order. */
3088
+ readonly supportedVendors: readonly VideoVendor[];
3089
+ /** True when the cloud picks the vendor dynamically at session time. */
3090
+ readonly dynamicVendor: boolean;
3091
+ /** Aliyun LinkVisual device id, when the device is on (or has been on) Aliyun. */
3092
+ readonly iotId: string | null;
3093
+ /** Whether the device is online. */
3094
+ readonly online: boolean;
3095
+ }
3096
+
3097
+ /** Shared inputs for every video control-plane call. Mirrors `listDevices`. */
3098
+ interface VideoRequestInput {
3099
+ session: DreameSession;
3100
+ region: DreameRegion;
3101
+ ctx?: RequestContext;
3102
+ country?: string;
3103
+ lang?: string;
3104
+ apiHost?: string;
3105
+ fetchImpl?: FetchImpl;
3106
+ signal?: AbortSignal;
3107
+ timeoutMs?: number;
3108
+ }
3109
+ /**
3110
+ * Mint the short-lived third-video access token. Required as a body field by the
3111
+ * device-scoped video calls (getIdentity, getP2PInfo, …).
3112
+ */
3113
+ declare function getVideoAccessToken(input: VideoRequestInput): Promise<VideoAccessToken>;
3114
+ /**
3115
+ * Fetch the Aliyun authCode blob (`getAuthCodeV3`). This opaque hex string is the
3116
+ * material exchanged with Aliyun IoT to obtain a LinkVisual identity — the first
3117
+ * step of the Aliyun media path.
3118
+ */
3119
+ declare function getAliyunAuthCode(input: VideoRequestInput): Promise<string>;
3120
+ /**
3121
+ * Fetch the account's video `familyId` (used to scope some vendor calls). This
3122
+ * endpoint requires the third-video access token in the body — pass one via
3123
+ * `videoToken`, otherwise a fresh one is minted with {@link getVideoAccessToken}.
3124
+ */
3125
+ declare function getVideoFamilyId(input: VideoRequestInput & {
3126
+ videoToken?: string;
3127
+ }): Promise<string>;
3128
+ /**
3129
+ * Resolve a device's video profile (vendor, supported vendors, Aliyun iotId,
3130
+ * capability) from its cloud record. `did` is the Dreame device id.
3131
+ */
3132
+ declare function getDeviceVideoProfile(input: VideoRequestInput & {
3133
+ did: string;
3134
+ }): Promise<DeviceVideoProfile>;
3135
+
3136
+ /** A device record as returned by `device/info` (`data` = single record). */
3137
+ declare const DeviceInfoRecordSchema: z.ZodObject<{
3138
+ did: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3139
+ model: z.ZodOptional<z.ZodString>;
3140
+ customName: z.ZodOptional<z.ZodString>;
3141
+ vendor: z.ZodOptional<z.ZodString>;
3142
+ online: z.ZodOptional<z.ZodBoolean>;
3143
+ lwt: z.ZodOptional<z.ZodNumber>;
3144
+ property: z.ZodOptional<z.ZodString>;
3145
+ bindDomain: z.ZodOptional<z.ZodString>;
3146
+ deviceInfo: z.ZodOptional<z.ZodObject<{
3147
+ model: z.ZodOptional<z.ZodString>;
3148
+ displayName: z.ZodOptional<z.ZodString>;
3149
+ permit: z.ZodOptional<z.ZodString>;
3150
+ videoDynamicVendor: z.ZodOptional<z.ZodBoolean>;
3151
+ defaultVendors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
3152
+ productId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3153
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
3154
+ model: z.ZodOptional<z.ZodString>;
3155
+ displayName: z.ZodOptional<z.ZodString>;
3156
+ permit: z.ZodOptional<z.ZodString>;
3157
+ videoDynamicVendor: z.ZodOptional<z.ZodBoolean>;
3158
+ defaultVendors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
3159
+ productId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3160
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
3161
+ model: z.ZodOptional<z.ZodString>;
3162
+ displayName: z.ZodOptional<z.ZodString>;
3163
+ permit: z.ZodOptional<z.ZodString>;
3164
+ videoDynamicVendor: z.ZodOptional<z.ZodBoolean>;
3165
+ defaultVendors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
3166
+ productId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3167
+ }, z.ZodTypeAny, "passthrough">>>;
3168
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
3169
+ did: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3170
+ model: z.ZodOptional<z.ZodString>;
3171
+ customName: z.ZodOptional<z.ZodString>;
3172
+ vendor: z.ZodOptional<z.ZodString>;
3173
+ online: z.ZodOptional<z.ZodBoolean>;
3174
+ lwt: z.ZodOptional<z.ZodNumber>;
3175
+ property: z.ZodOptional<z.ZodString>;
3176
+ bindDomain: z.ZodOptional<z.ZodString>;
3177
+ deviceInfo: z.ZodOptional<z.ZodObject<{
3178
+ model: z.ZodOptional<z.ZodString>;
3179
+ displayName: z.ZodOptional<z.ZodString>;
3180
+ permit: z.ZodOptional<z.ZodString>;
3181
+ videoDynamicVendor: z.ZodOptional<z.ZodBoolean>;
3182
+ defaultVendors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
3183
+ productId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3184
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
3185
+ model: z.ZodOptional<z.ZodString>;
3186
+ displayName: z.ZodOptional<z.ZodString>;
3187
+ permit: z.ZodOptional<z.ZodString>;
3188
+ videoDynamicVendor: z.ZodOptional<z.ZodBoolean>;
3189
+ defaultVendors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
3190
+ productId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3191
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
3192
+ model: z.ZodOptional<z.ZodString>;
3193
+ displayName: z.ZodOptional<z.ZodString>;
3194
+ permit: z.ZodOptional<z.ZodString>;
3195
+ videoDynamicVendor: z.ZodOptional<z.ZodBoolean>;
3196
+ defaultVendors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
3197
+ productId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3198
+ }, z.ZodTypeAny, "passthrough">>>;
3199
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
3200
+ did: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3201
+ model: z.ZodOptional<z.ZodString>;
3202
+ customName: z.ZodOptional<z.ZodString>;
3203
+ vendor: z.ZodOptional<z.ZodString>;
3204
+ online: z.ZodOptional<z.ZodBoolean>;
3205
+ lwt: z.ZodOptional<z.ZodNumber>;
3206
+ property: z.ZodOptional<z.ZodString>;
3207
+ bindDomain: z.ZodOptional<z.ZodString>;
3208
+ deviceInfo: z.ZodOptional<z.ZodObject<{
3209
+ model: z.ZodOptional<z.ZodString>;
3210
+ displayName: z.ZodOptional<z.ZodString>;
3211
+ permit: z.ZodOptional<z.ZodString>;
3212
+ videoDynamicVendor: z.ZodOptional<z.ZodBoolean>;
3213
+ defaultVendors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
3214
+ productId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3215
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
3216
+ model: z.ZodOptional<z.ZodString>;
3217
+ displayName: z.ZodOptional<z.ZodString>;
3218
+ permit: z.ZodOptional<z.ZodString>;
3219
+ videoDynamicVendor: z.ZodOptional<z.ZodBoolean>;
3220
+ defaultVendors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
3221
+ productId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3222
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
3223
+ model: z.ZodOptional<z.ZodString>;
3224
+ displayName: z.ZodOptional<z.ZodString>;
3225
+ permit: z.ZodOptional<z.ZodString>;
3226
+ videoDynamicVendor: z.ZodOptional<z.ZodBoolean>;
3227
+ defaultVendors: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
3228
+ productId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
3229
+ }, z.ZodTypeAny, "passthrough">>>;
3230
+ }, z.ZodTypeAny, "passthrough">>;
3231
+ type DeviceInfoRecord = z.infer<typeof DeviceInfoRecordSchema>;
3232
+
3233
+ /**
3234
+ * Derive a {@link DeviceVideoProfile} from a raw device record. Pure — no I/O —
3235
+ * so it is unit-testable against captured records. `videoCapable` is true when
3236
+ * the cloud marks the device `permit: "video"` or lists any supported vendor.
3237
+ */
3238
+ declare function toVideoProfile(record: DeviceInfoRecord): DeviceVideoProfile;
3239
+
3240
+ /**
3241
+ * Aliyun API Gateway ("x-ca") request signing, HmacSHA1. Used by the LinkVisual
3242
+ * video endpoints the Dreamehome app talks to (living-account + api-iot hosts).
3243
+ *
3244
+ * The string to sign is:
3245
+ * METHOD\n Accept\n Content-MD5\n Content-Type\n Date\n <signed-headers-block> <resource>
3246
+ * where the signed-headers block is `Name:Value\n` for each header named in
3247
+ * `X-Ca-Signature-Headers`, sorted case-insensitively, and `resource` is the
3248
+ * path plus, for form bodies, the `?`-joined sorted form params.
3249
+ *
3250
+ * Verified byte-for-byte against a captured connect.json request (see tests).
3251
+ */
3252
+ interface SignedRequest {
3253
+ headers: Record<string, string>;
3254
+ body: string;
3255
+ }
3256
+ interface SignInput {
3257
+ method: 'POST' | 'GET';
3258
+ host: string;
3259
+ path: string;
3260
+ appKey: string;
3261
+ appSecret: string;
3262
+ /** JSON payload → sent as the raw body with a Content-MD5. */
3263
+ json?: unknown;
3264
+ /** Form fields → sent as application/x-www-form-urlencoded and folded into the resource. */
3265
+ form?: Record<string, string>;
3266
+ /** Extra x-ca headers to sign (e.g. `{ 'X-Ca-Stage': 'RELEASE' }`). */
3267
+ extraCaHeaders?: Record<string, string>;
3268
+ /** Overrides for deterministic tests. */
3269
+ nonce?: string;
3270
+ timestamp?: number;
3271
+ date?: string;
3272
+ }
3273
+ /** Build the x-ca headers + body for a request. */
3274
+ declare function signApiGatewayRequest(input: SignInput): SignedRequest;
3275
+
3276
+ /** LinkVisual live-stream descriptor returned by /vision/customer/stream/query. */
3277
+ interface StreamInfo {
3278
+ /** Connection strategies the cloud offers, e.g. ["Direct","Relay","NAT"]. */
3279
+ typeList: string[];
3280
+ /** RTMP relay URL. Plain (playable directly) when requested with relayEncrypted:false. */
3281
+ relayUrl: string | null;
3282
+ /** AES key/iv for the relay payload — present (non-empty) only when relayEncrypted:true. */
3283
+ relayDecryptKey: {
3284
+ iv: string;
3285
+ key: string;
3286
+ } | null;
3287
+ /** P2P (Direct/NAT) parameters: STUN/TURN + the WebSocket signaling URL. */
3288
+ p2pInfo: {
3289
+ stunUrl?: string;
3290
+ alterStunUrl?: string;
3291
+ signalUrl?: string;
3292
+ portDetectStunUrlList?: string[];
3293
+ } | null;
3294
+ supportVisionPtz?: boolean;
3295
+ }
3296
+ interface StreamQueryInput {
3297
+ /** Aliyun IoT region id, e.g. `eu-central-1`. */
3298
+ regionId: string;
3299
+ /** Short-lived IoT identity token (from createSessionByAuthCode). */
3300
+ iotToken: string;
3301
+ /** LinkVisual device id. */
3302
+ iotId: string;
3303
+ /**
3304
+ * When false (default) the relay RTMP carries a PLAIN (unencrypted) FLV, so it
3305
+ * can be handed straight to ffmpeg. When true the payload is AES-encrypted and
3306
+ * `relayDecryptKey` is returned.
3307
+ */
3308
+ relayEncrypted?: boolean;
3309
+ /** 0 = HD main stream (default). */
3310
+ streamType?: number;
3311
+ appKey?: string;
3312
+ appSecret?: string;
3313
+ fetchImpl?: FetchImpl;
3314
+ signal?: AbortSignal;
3315
+ }
3316
+ /**
3317
+ * Query the LinkVisual live stream for a device. Returns the relay RTMP URL and
3318
+ * P2P parameters. Note: each returned relay token is single-use — request a
3319
+ * fresh one per consumer.
3320
+ */
3321
+ declare function streamQuery(input: StreamQueryInput): Promise<StreamInfo>;
3322
+
3323
+ /** Aliyun OpenAccount session from loginbyoauth. */
3324
+ interface OaSession {
3325
+ sid: string;
3326
+ refreshToken: string;
3327
+ openId: string;
3328
+ }
3329
+ /** Aliyun IoT session (the iotToken used by every LinkVisual call). */
3330
+ interface IotSession {
3331
+ iotToken: string;
3332
+ refreshToken: string;
3333
+ identityId: string;
3334
+ /** Epoch-ms at which iotToken expires. */
3335
+ expiresAt: number;
3336
+ }
3337
+ interface LoginByOauthInput {
3338
+ authCode: string;
3339
+ regionId: string;
3340
+ deviceId?: string;
3341
+ utdid?: string;
3342
+ fetchImpl?: FetchImpl;
3343
+ }
3344
+ /** Exchange the Dreame authCode for an Aliyun OpenAccount session (step 2). */
3345
+ declare function loginByOauth(input: LoginByOauthInput): Promise<OaSession>;
3346
+ interface CreateIotSessionInput {
3347
+ /** The OpenAccount `sid` from {@link loginByOauth}. */
3348
+ sid: string;
3349
+ regionId: string;
3350
+ fetchImpl?: FetchImpl;
3351
+ }
3352
+ /** Exchange the OA `sid` for an Aliyun IoT session / iotToken (step 3). */
3353
+ declare function createIotSession(input: CreateIotSessionInput): Promise<IotSession>;
3354
+
3355
+ /** Aliyun IoT region id per Dreame region. Only `eu-central-1` is verified live. */
3356
+ declare const ALIYUN_REGION_ID: Record<DreameRegion, string>;
3357
+
3358
+ interface DreameVideoSessionInput {
3359
+ /** An authenticated Dreame account session (from `Nodreame`). */
3360
+ session: DreameSession;
3361
+ region: DreameRegion;
3362
+ fetchImpl?: FetchImpl;
3363
+ }
3364
+ /**
3365
+ * High-level video session for a Dreame account. Establishes and caches the
3366
+ * Aliyun IoT identity (iotToken), and mints fresh LinkVisual RTMP stream URLs
3367
+ * on demand. Each returned relay URL is single-use — call {@link getStreamInfo}
3368
+ * (or {@link getRtmpUrl}) once per consumer.
3369
+ *
3370
+ * The plain (unencrypted) relay URL is a standard RTMP stream: hand it straight
3371
+ * to ffmpeg / scrypted / camstack. No local muxing or RTSP server required here.
3372
+ */
3373
+ declare class DreameVideoSession {
3374
+ #private;
3375
+ constructor(input: DreameVideoSessionInput);
3376
+ /** The resolved Aliyun IoT region id (e.g. `eu-central-1`). */
3377
+ get regionId(): string;
3378
+ /** Mint (or reuse) a valid Aliyun IoT session, refreshing before expiry. */
3379
+ ensureIotSession(): Promise<IotSession>;
3380
+ /**
3381
+ * Mint a fresh LinkVisual stream descriptor for a device. `encrypted:false`
3382
+ * (default) yields a plain RTMP relay URL directly playable by ffmpeg.
3383
+ *
3384
+ * A camera that has been idle reports "device offline" until the query wakes
3385
+ * its video agent via the LinkVisual cloud. This transparently retries on that
3386
+ * (up to `wakeTimeoutMs`, default 30s) so a single call returns a live stream;
3387
+ * pass `wakeTimeoutMs: 0` to fail fast instead.
3388
+ */
3389
+ getStreamInfo(iotId: string, opts?: {
3390
+ encrypted?: boolean;
3391
+ wakeTimeoutMs?: number;
3392
+ pollMs?: number;
3393
+ }): Promise<StreamInfo>;
3394
+ /**
3395
+ * Convenience: mint a fresh plain RTMP relay URL for a device, or `null` when
3396
+ * the device is not currently streaming (no relay available).
3397
+ */
3398
+ getRtmpUrl(iotId: string): Promise<string | null>;
3399
+ }
3400
+
3401
+ /**
3402
+ * Parsers for the robot's on-device AI detections, pushed as camera-service
3403
+ * properties (subscribe to `propertyChanged` for SIID 10001):
3404
+ * - piid 110 (`personFollow` / PERSON_DATA): a tracked-person bounding box
3405
+ * - piid 112 (`videoObstacleData`): a list of obstacle boxes
3406
+ *
3407
+ * The overlay for obstacle boxes is gated on `set_properties siid 28 piid 13 = 1`.
3408
+ * Payloads are JSON strings; these parsers are lenient (return `null` on garbage)
3409
+ * and normalize timestamps (the device reports nanoseconds).
3410
+ */
3411
+ /** A normalized detection box. Coordinates are passed through as-reported. */
3412
+ interface DetectionBox {
3413
+ readonly x: number;
3414
+ readonly y: number;
3415
+ readonly w: number;
3416
+ readonly h: number;
3417
+ /** Optional label/class if the payload carries one. */
3418
+ readonly label?: string;
3419
+ /** Optional confidence if the payload carries one. */
3420
+ readonly score?: number;
3421
+ }
3422
+ interface PersonFollowDetection {
3423
+ /** Detection time in epoch milliseconds (converted from the device's ns). */
3424
+ readonly timestampMs: number;
3425
+ readonly box: DetectionBox | null;
3426
+ }
3427
+ interface ObstacleDetection {
3428
+ readonly timestampMs: number;
3429
+ readonly boxes: readonly DetectionBox[];
3430
+ }
3431
+ /** Parse a `personFollow` (piid 110) payload into a normalized detection. */
3432
+ declare function parsePersonFollow(value: unknown): PersonFollowDetection | null;
3433
+ /** Parse a `videoObstacleData` (piid 112) payload into normalized boxes. */
3434
+ declare function parseObstacleData(value: unknown): ObstacleDetection | null;
3435
+
3436
+ type AmfValue = number | boolean | string | null | undefined | AmfValue[] | {
3437
+ [key: string]: AmfValue;
3438
+ };
3439
+
3440
+ declare const LV_STATUS: {
3441
+ readonly REQUEST_AUDIO_TYPE: "NetStream.RequestAudioType";
3442
+ readonly FORCE_IFRAME_START: "NetStream.ForceIFrame.Start";
3443
+ readonly PING_START: "NetStream.Ping.Start";
3444
+ readonly PING_RESPONSE: "NetStream.Ping.Response";
3445
+ readonly PRE_CONNECT: "NetStream.PreConnect";
3446
+ readonly KEEPALIVE: "NetStream.Keepalive";
3447
+ readonly SERVER_INFO: "NetStream.ServerInfo";
3448
+ readonly TRANSFER_DATA: "NetStream.TransferData";
3449
+ readonly PLAY_START: "NetStream.Play.Start";
3450
+ /** Server signals the talk (intercom uplink) channel is ready. */
3451
+ readonly TALK_READY: "NetStream.TalkReady";
3452
+ };
3453
+ /**
3454
+ * FLV audio tag header byte for the intercom uplink: G.711 A-law, 8 kHz, 16-bit,
3455
+ * mono — `(7<<4)|(0<<2)|(1<<1)|0` = 0x72. Verified against liblvmedia SetTalkInfo.
3456
+ */
3457
+ declare const TALK_AUDIO_HEADER_G711A = 114;
3458
+ interface StatusEvent {
3459
+ code: string;
3460
+ level: string;
3461
+ description: string;
3462
+ fields: {
3463
+ [key: string]: AmfValue;
3464
+ };
3465
+ transactionId: number;
3466
+ }
3467
+ interface VideoAccessUnitEvent {
3468
+ data: Buffer;
3469
+ isKeyframe: boolean;
3470
+ videoType: 'H264';
3471
+ microseconds: number;
3472
+ time?: number;
3473
+ }
3474
+ interface AudioInfoEvent {
3475
+ codec: 'aac' | 'g711a' | 'g711u' | 'unknown';
3476
+ sampleRate: number;
3477
+ channels: number;
3478
+ }
3479
+ interface LvRtmpClientOptions {
3480
+ /** relayUrl from stream/query, e.g. rtmp://host:8000/live?token=..&session=../<key>_0 */
3481
+ url: string;
3482
+ /** Appended to app/tcUrl as "&cacheDuration=N" when not already present (the app always sends 3000). */
3483
+ cacheDurationMs?: number;
3484
+ /** Send the onStatus NetStream.RequestAudioType {audio_type:"1"} right after play (app does). */
3485
+ requestAudioType?: boolean;
3486
+ /** Send NetStream.Ping.Start after the first server message and then periodically (app does). */
3487
+ ping?: boolean;
3488
+ pingIntervalMs?: number;
3489
+ /** Also send NetStream.ForceIFrame.Start once playing (the app sends it when it starts an MP4 record). */
3490
+ forceIFrameOnStart?: boolean;
3491
+ connectTimeoutMs?: number;
3492
+ log?: (line: string) => void;
3493
+ }
3494
+ interface Endpoint {
3495
+ host: string;
3496
+ port: number;
3497
+ app: string;
3498
+ tcUrl: string;
3499
+ playpath: string;
3500
+ }
3501
+ /**
3502
+ * Split like librtmp/ffmpeg do: playpath = last path segment, app = everything between host and it
3503
+ * (query string included). Verified against the app's connect/play in both pcaps.
3504
+ */
3505
+ declare function parseRelayUrl(url: string, cacheDurationMs: number): Endpoint;
3506
+ type Events = {
3507
+ connected: [];
3508
+ status: [StatusEvent];
3509
+ command: [string, AmfValue[]];
3510
+ metadata: [{
3511
+ [key: string]: AmfValue;
3512
+ }];
3513
+ audio: [{
3514
+ timestamp: number;
3515
+ body: Buffer;
3516
+ }];
3517
+ video: [{
3518
+ timestamp: number;
3519
+ body: Buffer;
3520
+ }];
3521
+ videoAccessUnit: [VideoAccessUnitEvent];
3522
+ audioFrame: [Buffer];
3523
+ audioInfo: [AudioInfoEvent];
3524
+ error: [Error];
3525
+ close: [];
3526
+ };
3527
+ declare class LvRtmpClient extends EventEmitter<Events> {
3528
+ private readonly opts;
3529
+ private readonly endpoint;
3530
+ private socket;
3531
+ private handshakeBuf;
3532
+ private handshakeDone;
3533
+ private c1Time;
3534
+ private reader;
3535
+ private transactionId;
3536
+ private bytesIn;
3537
+ private bytesAcked;
3538
+ private ackWindow;
3539
+ private pingTimer;
3540
+ private firstMessageSeen;
3541
+ private avcConfig;
3542
+ private aacConfig;
3543
+ private closed;
3544
+ constructor(options: LvRtmpClientOptions);
3545
+ /** Open TCP, write C0+C1 and the pipelined connect/play/RequestAudioType. Resolves once written. */
3546
+ connect(): Promise<void>;
3547
+ close(): void;
3548
+ /** onStatus encoder — byte-exact replica of liblvmedia IOT_RTMP_SendMessage (csid 3, fmt 1, ts 0). */
3549
+ buildStatus(code: string, extra?: readonly [string, string]): Buffer;
3550
+ sendStatus(code: string, extra?: readonly [string, string]): void;
3551
+ forceIFrame(): void;
3552
+ private buildC0C1;
3553
+ private buildConnect;
3554
+ private buildPlay;
3555
+ /** Exposed for the byte-exact self-test against the pcap. */
3556
+ buildOpeningSequence(): Buffer[];
3557
+ /**
3558
+ * Push one intercom (talk-back) audio frame UPSTREAM to the device — an RTMP
3559
+ * type-8 audio message on the talk chunk stream (csid 4, msid 1), exactly as
3560
+ * liblvmedia's `IOT_RTMP_SendAudio` does. `payload` is the raw codec audio
3561
+ * (default framing = G.711 A-law); `tsMs` is a running millisecond timestamp.
3562
+ * Only meaningful after the server sends {@link LV_STATUS.TALK_READY}.
3563
+ */
3564
+ sendAudioFrame(payload: Buffer, tsMs: number, header?: number): void;
3565
+ private write;
3566
+ private sendAck;
3567
+ private sendPingResponse;
3568
+ private startPinging;
3569
+ private onData;
3570
+ private onHandshake;
3571
+ private dispatch;
3572
+ private onUserControl;
3573
+ private onCommand;
3574
+ private onDataMessage;
3575
+ private onAudio;
3576
+ private onVideo;
3577
+ private fail;
3578
+ private onClose;
3579
+ }
3580
+
3581
+ /**
3582
+ * End-to-end camera media pipeline: autonomously cold-start the LinkVisual
3583
+ * monitor, connect to the resulting RTMP relay, and re-emit demuxed elementary
3584
+ * frames — H.264 access units (Annex-B, SPS/PPS prepended on keyframes) and AAC
3585
+ * (ADTS) — plus lifecycle events.
3586
+ *
3587
+ * This is the reusable frame feed for any external consumer (scrypted's RFC4571
3588
+ * muxer, camstack, a file writer). It owns the {@link DreameCameraController}
3589
+ * lifecycle: {@link start} opens the monitor and connects; {@link stop} closes
3590
+ * the relay socket and releases the monitor on the device.
3591
+ */
3592
+
3593
+ /** The subset of {@link LvRtmpClient} the pipeline drives — injectable for tests. */
3594
+ interface FrameSource {
3595
+ connect(): Promise<void>;
3596
+ close(): void;
3597
+ on(event: 'videoAccessUnit', cb: (e: VideoAccessUnitEvent) => void): void;
3598
+ on(event: 'audioFrame', cb: (buf: Buffer) => void): void;
3599
+ on(event: 'audioInfo', cb: (info: AudioInfoEvent) => void): void;
3600
+ on(event: 'status', cb: (e: StatusEvent) => void): void;
3601
+ on(event: 'error', cb: (err: Error) => void): void;
3602
+ on(event: 'close', cb: () => void): void;
3603
+ /** Push an intercom (talk-back) audio frame upstream. */
3604
+ sendAudioFrame(payload: Buffer, tsMs: number, header?: number): void;
3605
+ }
3606
+ /** Factory for the RTMP frame source; defaults to a real {@link LvRtmpClient}. */
3607
+ type FrameSourceFactory = (url: string) => FrameSource;
3608
+ interface DreameCameraStreamEvents {
3609
+ /** Emitted once the relay is connected; carries the (single-use) RTMP URL. */
3610
+ started: [{
3611
+ rtmpUrl: string;
3612
+ }];
3613
+ /** One H.264 access unit (Annex-B). */
3614
+ videoAccessUnit: [VideoAccessUnitEvent];
3615
+ /** One audio frame (AAC in ADTS, or raw G.711). */
3616
+ audioFrame: [Buffer];
3617
+ /** Audio format, emitted once known. */
3618
+ audioInfo: [AudioInfoEvent];
3619
+ /** Emitted after the pipeline is fully torn down. */
3620
+ stopped: [];
3621
+ error: [Error];
3622
+ [event: string]: unknown[];
3623
+ }
3624
+ interface DreameCameraStreamInput {
3625
+ /** A controller for the target camera (not yet opened). */
3626
+ controller: DreameCameraController;
3627
+ /** Override the RTMP client (tests inject a fake). */
3628
+ clientFactory?: FrameSourceFactory;
3629
+ /** Forwarded to {@link LvRtmpClient}: send NetStream.RequestAudioType after play. */
3630
+ requestAudioType?: boolean;
3631
+ /** Forwarded to {@link LvRtmpClient}: send periodic NetStream.Ping. */
3632
+ ping?: boolean;
3633
+ /** Optional line logger for the RTMP client. */
3634
+ log?: (line: string) => void;
3635
+ }
3636
+ declare class DreameCameraStream extends TypedEmitter<DreameCameraStreamEvents> {
3637
+ #private;
3638
+ constructor(input: DreameCameraStreamInput);
3639
+ /** True while frames are flowing. */
3640
+ get isRunning(): boolean;
3641
+ /**
3642
+ * Cold-start the monitor, connect to the relay, and begin emitting frames.
3643
+ * Resolves once connected. Throws (and cleans up) if the monitor or relay
3644
+ * connection fails.
3645
+ */
3646
+ start(): Promise<{
3647
+ rtmpUrl: string;
3648
+ }>;
3649
+ /** Close the relay connection and release the monitor. Idempotent. */
3650
+ stop(): Promise<void>;
3651
+ /**
3652
+ * Open the two-way intercom: send the MIoT start, then resolve once the relay
3653
+ * signals the talk channel is ready (so it's safe to {@link sendTalkPcm}).
3654
+ * Rejects if not ready within `timeoutMs`.
3655
+ */
3656
+ startTalk(opts?: {
3657
+ needRecordSound?: boolean;
3658
+ videoCall?: boolean;
3659
+ timeoutMs?: number;
3660
+ }): Promise<void>;
3661
+ /** Resolve when the talk channel is ready (or reject on timeout). */
3662
+ whenTalkReady(timeoutMs?: number): Promise<void>;
3663
+ /**
3664
+ * Encode 16-bit LE mono PCM (8 kHz) to G.711 A-law and push it upstream.
3665
+ * `tsMs` defaults to a running clock advanced by the frame duration.
3666
+ */
3667
+ sendTalkPcm(pcm16le: Buffer, tsMs?: number): void;
3668
+ /** Push raw A-law audio upstream (advancing the running talk clock). */
3669
+ sendTalkAlaw(alaw: Buffer, tsMs?: number): void;
3670
+ /** Close the two-way intercom (MIoT stop). */
3671
+ stopTalk(): Promise<void>;
3672
+ }
3673
+
3674
+ /**
3675
+ * G.711 A-law codec (ITU-T G.711) — the intercom uplink format for Dreame
3676
+ * cameras (8 kHz, mono, 16-bit PCM in). Pure functions, no state.
3677
+ */
3678
+ /** Encode one 16-bit signed PCM sample to an A-law byte. */
3679
+ declare function pcm16ToALaw(sample: number): number;
3680
+ /**
3681
+ * Encode a buffer of little-endian 16-bit PCM samples to A-law bytes
3682
+ * (one output byte per input sample).
3683
+ */
3684
+ declare function pcm16leToALaw(pcm: Buffer): Buffer;
3685
+
3686
+ interface AvcConfig {
3687
+ sps: Buffer[];
3688
+ pps: Buffer[];
3689
+ nalLengthSize: number;
3690
+ }
3691
+ interface AacConfig {
3692
+ objectType: number;
3693
+ samplingFrequencyIndex: number;
3694
+ channelConfiguration: number;
3695
+ }
3696
+ /** Parse an AVCDecoderConfigurationRecord (FLV AVC sequence header payload). */
3697
+ declare function parseAvcConfig(rec: Buffer): AvcConfig;
3698
+ /** Length-prefixed NALUs -> Annex-B. Prepends SPS/PPS when `prependParams` is set (for keyframes). */
3699
+ declare function avccToAnnexB(data: Buffer, cfg: AvcConfig, prependParams: boolean): Buffer;
3700
+ declare function parseAacConfig(asc: Buffer): AacConfig;
3701
+ declare function aacSampleRate(cfg: AacConfig): number;
3702
+ /** Wrap one raw AAC frame in a 7-byte ADTS header. */
3703
+ declare function aacToAdts(raw: Buffer, cfg: AacConfig): Buffer;
3704
+
3705
+ interface ListDevicesInput {
3706
+ session: DreameSession;
3707
+ region: DreameRegion;
3708
+ ctx?: RequestContext;
3709
+ country?: string;
3710
+ lang?: string;
3711
+ apiHost?: string;
3712
+ fetchImpl?: FetchImpl;
3713
+ signal?: AbortSignal;
3714
+ timeoutMs?: number;
3715
+ }
3716
+ /** Enumerate the devices visible to the authenticated account (incl. shared). */
3717
+ declare function listDevices(input: ListDevicesInput): Promise<DreameDevice[]>;
3718
+
3719
+ export { AI_FEATURE_BIT, AI_FEATURE_JSON_KEY, ALIYUN_REGION_ID, AUTO_SWITCH_JSON_KEY, type AacConfig, type AiDetectionRaw, type AudioInfoEvent, type AutoSwitchKey, type AutoSwitchRaw, type AvcConfig, BaseDevice, type BaseDeviceEvents, type BatchDeviceDataFetcher, type BrokerEndpoint, type CameraStreamHandle, type CapabilityResolver, ChargingStatus, type CleanOpts, CleaningMode, type ConsumableReading, type ConsumableSpec, type CreateDeviceArgs, DRIVE_DIRECTIONS, DefaultCapabilityResolver, type DetectionBox, type DeviceCapabilities, type DeviceConnectivity, type DeviceDump, type DeviceEvent, type DeviceVideoProfile, type DreameAiFeature, DreameApiError, DreameAuthError, DreameCameraController, type DreameCameraControllerInput, DreameCameraStream, type DreameCameraStreamEvents, type DreameCameraStreamInput, type DreameCloudState, type DreameConsumableKey, type DreameDevice, DreameDeviceOfflineError, DreameError, type DreameRegion, type DreameSession, DreameTransportError, DreameVideoSession, type DreameVideoSessionInput, type DriveDirection, type DumperOptions, type FrameSource, type FrameSourceFactory, type IotSession, LIBRARY_NAME, LV_STATUS, type ListDevicesInput, LvRtmpClient, type LvRtmpClientOptions, MONITOR_AIID, MONITOR_PIID, MONITOR_SIID, MONITOR_VENDOR_TOKEN, MODEL_CAPABILITIES as MOWER_MODEL_CAPABILITIES, MOWER_TASK_SUBSTATES, type MapBoundingBox, type MapCleanedAreaOverlay, type MapColorScheme, type MapDimensions, type MapFrameType, type MapLayer, type MapLayerType, type MapLowLyingArea, type MapObstacle, type MapPath, type MapPathType, type MapPoint, type MapPose, type MapRestrictedArea, type MapRoom, type MapRoomWall, type MapRun, type MapSegment, type MapStorey, type MapVirtualWall, type MapWallsInfo, type MiotAction, MiotError, type MiotProp, MiotState, type MonitorActionCaller, type MowerAvailableMap, type MowerCapabilities, MowerCapabilityResolver, MowerChargingStatus, type MowerConsumableKey, type MowerConsumableReading, type MowerContour, MowerControlAction, type MowerControlState, MowerDevice, type MowerDeviceInput, MowerFault, type MowerFaultSeverity, type MowerHeartbeat, type MowerMap, type MowerMapBoundary, type MowerMowPath, type MowerMowingProgress, type MowerPathEntry, type MowerPoint, type MowerSpotArea, MowerStatus, type MowerTaskDescriptor, MowerTaskStatus, type MowerTaskSubState, type MowerZone, Nodreame, type NodreameDeps, type NodreameEvents, type NodreameOptions, type OaSession, type ObstacleDetection, type OssFetchInput, type OssFetcherLike, PET_SOUNDS, type PersonFollowDetection, type PetSound, type PropertyChangedEvent, type PropertyResult, type PropertyState, type PropertyWrite, type RelayMinter, type RenderMowerSvgOptions, type RenderVacuumPngOptions, type RenderWifiSignalPngOptions, type StateChangedEvent, type StatusEvent, type StreamInfo, type StreamQueryInput, SuctionLevel, TALK_AUDIO_HEADER_G711A, TaskStatus, VACUUM_ACTIONS, VACUUM_CONSUMABLES, MODEL_CAPABILITIES$1 as VACUUM_MODEL_CAPABILITIES, VACUUM_MOVE, VACUUM_SIID, type VacuumActionKey, type VacuumCapabilities, VacuumCapabilityResolver, VacuumDevice, type VacuumGetMapInput, type VacuumMap, type VideoAccessToken, type VideoAccessUnitEvent, type VideoRequestInput, type VideoVendor, WaterVolume, type WifiSignalMap, type WifiSignalMapInput, aacSampleRate, aacToAdts, avccToAnnexB, consumableSpec, createClientDumper, createDumper, createIotSession, decodeAiFeature, decodeAutoSwitch, decodeAutoSwitchAll, decodeWifiSignalMap, encodeAiFeatureWrite, encodeAutoSwitchWrite, extractMowerConsumableValues, getAliyunAuthCode, getDeviceVideoProfile, getMowerCapabilities, getVacuumCapabilities, getVideoAccessToken, getVideoFamilyId, hashAccessCode, isAuthRefusedError, isDreameConsumableKey, listDevices, loginByOauth, makeMonitorSession, mowerConsumableIndex, mowerFaultSeverity, parseAacConfig, parseAvcConfig, parseConnectivity, parseMowerConsumables, parseMowerHeartbeat, parseMowingProgress, parseObstacleData, parsePersonFollow, parseRelayUrl, pcm16ToALaw, pcm16leToALaw, remoteDriveValue, renderMowerSvg, renderVacuumPng, renderWifiSignalPng, resolveCapabilities, signApiGatewayRequest, streamQuery, supportedAutoSwitchKeys, toVideoProfile };