@mega-yfue/eufy-sdk 0.0.4 → 0.1.0-beta.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.
Files changed (143) hide show
  1. package/README.md +31 -12
  2. package/dist/client/device-registry.d.ts +343 -0
  3. package/dist/client/eufy-mega.d.ts +872 -0
  4. package/dist/client/index.d.ts +1 -6
  5. package/dist/client/map-channels.d.ts +22 -0
  6. package/dist/client/types.d.ts +383 -0
  7. package/dist/core/contracts.d.ts +898 -0
  8. package/dist/core/crypto.d.ts +98 -0
  9. package/dist/core/index.d.ts +9 -7
  10. package/dist/core/logger.d.ts +53 -0
  11. package/dist/core/lz4-block.d.ts +35 -0
  12. package/dist/core/raw-dp-hex.d.ts +32 -0
  13. package/dist/core/raw-dp-writer.d.ts +83 -0
  14. package/dist/core/store.d.ts +43 -0
  15. package/dist/core/types.d.ts +169 -0
  16. package/dist/core/util.d.ts +78 -0
  17. package/dist/index.d.ts +4 -7
  18. package/dist/index.js +25526 -14
  19. package/dist/index.js.map +7 -1
  20. package/dist/model/capabilities/access.d.ts +127 -0
  21. package/dist/model/capabilities/arming.d.ts +201 -0
  22. package/dist/model/capabilities/audio.d.ts +154 -0
  23. package/dist/model/capabilities/battery.d.ts +363 -0
  24. package/dist/model/capabilities/camera.d.ts +564 -0
  25. package/dist/model/capabilities/co.d.ts +40 -0
  26. package/dist/model/capabilities/contact.d.ts +133 -0
  27. package/dist/model/capabilities/doorbell.d.ts +345 -0
  28. package/dist/model/capabilities/dp-catalog.d.ts +38 -0
  29. package/dist/model/capabilities/index.d.ts +561 -0
  30. package/dist/model/capabilities/info.d.ts +28 -0
  31. package/dist/model/capabilities/keypad.d.ts +61 -0
  32. package/dist/model/capabilities/leak.d.ts +43 -0
  33. package/dist/model/capabilities/light.d.ts +174 -0
  34. package/dist/model/capabilities/locate.d.ts +63 -0
  35. package/dist/model/capabilities/lock.d.ts +242 -0
  36. package/dist/model/capabilities/manifest.d.ts +107 -0
  37. package/dist/model/capabilities/members.d.ts +647 -0
  38. package/dist/model/capabilities/motion.d.ts +377 -0
  39. package/dist/model/capabilities/person-detection.d.ts +8 -0
  40. package/dist/model/capabilities/ptz.d.ts +289 -0
  41. package/dist/model/capabilities/rtsp.d.ts +221 -0
  42. package/dist/model/capabilities/siren.d.ts +218 -0
  43. package/dist/model/capabilities/smart-light.d.ts +172 -0
  44. package/dist/model/capabilities/smoke.d.ts +40 -0
  45. package/dist/model/capabilities/snapshot.d.ts +6 -0
  46. package/dist/model/capabilities/storage.d.ts +11 -0
  47. package/dist/model/capabilities/suction.d.ts +104 -0
  48. package/dist/model/capabilities/types.d.ts +484 -0
  49. package/dist/model/capabilities/vacuum-clean.d.ts +1946 -0
  50. package/dist/model/capabilities/vacuum-dock.d.ts +208 -0
  51. package/dist/model/capabilities/video.d.ts +6 -0
  52. package/dist/model/classify.d.ts +78 -0
  53. package/dist/model/clean-record-detail.d.ts +65 -0
  54. package/dist/model/clean-records.d.ts +69 -0
  55. package/dist/model/device-family.d.ts +73 -0
  56. package/dist/model/device-types.d.ts +123 -0
  57. package/dist/model/device.d.ts +265 -0
  58. package/dist/model/index.d.ts +29 -4
  59. package/dist/model/infer.d.ts +23 -0
  60. package/dist/model/inspect.d.ts +61 -0
  61. package/dist/model/life-params.d.ts +21 -0
  62. package/dist/model/map-pixels.d.ts +70 -0
  63. package/dist/model/param-dictionary.d.ts +28 -0
  64. package/dist/model/param-namespace.d.ts +21 -0
  65. package/dist/model/proto-read.d.ts +53 -0
  66. package/dist/model/push-events.d.ts +147 -0
  67. package/dist/model/registry.d.ts +54 -0
  68. package/dist/model/types.d.ts +301 -0
  69. package/dist/model/vacuum-map-store.d.ts +92 -0
  70. package/dist/model/vacuum-map.d.ts +286 -0
  71. package/dist/model/vacuum-scenes.d.ts +76 -0
  72. package/dist/model/vacuum-schedules.d.ts +85 -0
  73. package/dist/transport/dp-preset.d.ts +102 -0
  74. package/dist/transport/ff09.d.ts +444 -0
  75. package/dist/transport/ffmpeg.d.ts +86 -0
  76. package/dist/transport/http/decodeImageV1.d.ts +20 -0
  77. package/dist/transport/http/decodeImageV2.d.ts +19 -0
  78. package/dist/transport/http/index.d.ts +5 -0
  79. package/dist/transport/http/light-catalog.d.ts +62 -0
  80. package/dist/transport/http/media-download.d.ts +14 -0
  81. package/dist/transport/http/mega-client.d.ts +514 -0
  82. package/dist/transport/http/phone-model.d.ts +21 -0
  83. package/dist/transport/index.d.ts +10 -7
  84. package/dist/transport/mqtt/app-client-id.d.ts +16 -0
  85. package/dist/transport/mqtt/availability.d.ts +14 -0
  86. package/dist/transport/mqtt/bare-ip-tls.d.ts +46 -0
  87. package/dist/transport/mqtt/biz-stream.d.ts +98 -0
  88. package/dist/transport/mqtt/broker-discovery.d.ts +55 -0
  89. package/dist/transport/mqtt/clean-codec.d.ts +14 -0
  90. package/dist/transport/mqtt/command-router.d.ts +285 -0
  91. package/dist/transport/mqtt/dp-codec.d.ts +58 -0
  92. package/dist/transport/mqtt/dp-color.d.ts +14 -0
  93. package/dist/transport/mqtt/engine.d.ts +16 -0
  94. package/dist/transport/mqtt/index.d.ts +5 -0
  95. package/dist/transport/mqtt/secure-mqtt.d.ts +107 -0
  96. package/dist/transport/mqtt/topics.d.ts +80 -0
  97. package/dist/transport/p2p/adts.d.ts +91 -0
  98. package/dist/transport/p2p/annexb.d.ts +124 -0
  99. package/dist/transport/p2p/codec.d.ts +166 -0
  100. package/dist/transport/p2p/command-router.d.ts +655 -0
  101. package/dist/transport/p2p/commands.d.ts +550 -0
  102. package/dist/transport/p2p/envelope.d.ts +46 -0
  103. package/dist/transport/p2p/fmp4.d.ts +89 -0
  104. package/dist/transport/p2p/fragment-recording.d.ts +33 -0
  105. package/dist/transport/p2p/index.d.ts +13 -0
  106. package/dist/transport/p2p/lan-ip.d.ts +25 -0
  107. package/dist/transport/p2p/live-stream.d.ts +223 -0
  108. package/dist/transport/p2p/live-trace.d.ts +123 -0
  109. package/dist/transport/p2p/media.d.ts +105 -0
  110. package/dist/transport/p2p/p2p-session.d.ts +620 -0
  111. package/dist/transport/p2p/readable-egress.d.ts +27 -0
  112. package/dist/transport/p2p/session-manager.d.ts +154 -0
  113. package/dist/transport/p2p/shared-live-source.d.ts +431 -0
  114. package/dist/transport/p2p/talkback.d.ts +187 -0
  115. package/dist/transport/p2p/video.d.ts +150 -0
  116. package/dist/transport/p2p/write-commands.d.ts +21 -0
  117. package/dist/transport/protobuf.d.ts +5 -0
  118. package/dist/transport/push/fcm.d.ts +23 -0
  119. package/dist/transport/push/index.d.ts +6 -0
  120. package/dist/transport/push/message-tags.d.ts +26 -0
  121. package/dist/transport/push/parser.d.ts +27 -0
  122. package/dist/transport/push/proto.d.ts +11 -0
  123. package/dist/transport/push/push-client.d.ts +64 -0
  124. package/dist/transport/push/store.d.ts +23 -0
  125. package/dist/transport/push/types.d.ts +180 -0
  126. package/dist/transport/raw-dp.d.ts +6 -0
  127. package/dist/transport/stored-image-cache.d.ts +23 -0
  128. package/dist/transport/tuya/account.d.ts +44 -0
  129. package/dist/transport/tuya/client.d.ts +89 -0
  130. package/dist/transport/tuya/command-router.d.ts +79 -0
  131. package/dist/transport/tuya/dp-codec.d.ts +56 -0
  132. package/dist/transport/tuya/index.d.ts +28 -0
  133. package/dist/transport/tuya/request.d.ts +157 -0
  134. package/dist/transport/tuya/sign.d.ts +64 -0
  135. package/package.json +12 -13
  136. package/dist/client/index.js +0 -2
  137. package/dist/client/index.js.map +0 -1
  138. package/dist/core/index.js +0 -2
  139. package/dist/core/index.js.map +0 -1
  140. package/dist/model/index.js +0 -2
  141. package/dist/model/index.js.map +0 -1
  142. package/dist/transport/index.js +0 -2
  143. package/dist/transport/index.js.map +0 -1
@@ -0,0 +1,1946 @@
1
+ import type { RawDpCodec } from "../../core/contracts.js";
2
+ import type { ParamValue } from "../types.js";
3
+ import type { AvailabilityContext, CapabilityModule } from "./types.js";
4
+ import { isTuyaVacuum } from "../device-family.js";
5
+ import { type Surface } from "./members.js";
6
+ import { type VacuumScene } from "../vacuum-scenes.js";
7
+ import { type VacuumSchedule } from "../vacuum-schedules.js";
8
+ /**
9
+ * RoboVac Tuya **DP ids** this capability reads — the "clean" namespace (ids ~150-180, from the cloud
10
+ * `get_product_data_point` schema). Named here so each DP is referenced by meaning rather than a magic
11
+ * number, the same way the P2P capabilities name their feature-command ids (`CAMERA_CMD`, `LIGHT_CMD`).
12
+ * Values confirmed against a live T2351 DP dump.
13
+ */
14
+ /**
15
+ * Which protobuf message each Raw DP carries, in each direction — the product catalogue's own
16
+ * `下发`(downlink) / `上报`(uplink) note per data point, transcribed.
17
+ *
18
+ * The single most useful thing the catalogue gives that a DP number alone does not: a DP is Raw, and
19
+ * knowing WHICH message it frames is what makes it decodable. Recorded here rather than rediscovered,
20
+ * and deliberately as data rather than as code — nothing dispatches on it.
21
+ *
22
+ * Two entries are the vendor's own dead ends: DP 150 is marked "预留。不使用。" — reserved, NOT used —
23
+ * and 165/175 are reserved with no message at all. Do not build on them.
24
+ */
25
+ export declare const VACUUM_DP_MESSAGE: Readonly<Record<number, {
26
+ readonly send?: string;
27
+ readonly report?: string;
28
+ }>>;
29
+ export declare const VACUUM_DP: {
30
+ /** Power on/off (DP 151 power switch, Bool). */
31
+ readonly POWER: 151;
32
+ /** WorkStatus (DP 153 work status, Raw protobuf) — carries the activity in field #2 (see {@link decodeVacuumActivity}). */
33
+ readonly WORK_STATUS: 153;
34
+ /** ModeCtrlRequest (DP 152, Raw protobuf) — carries the mode-control command (start/pause/dock). */
35
+ readonly MODE_CTRL: 152;
36
+ /** CleanParam (DP 154 clean params, Raw protobuf) — carries the cleaning type (see {@link decodeCleanType}). */
37
+ readonly CLEAN_PARAM: 154;
38
+ /** Speaker volume 0-100 (DP 161, Value). */
39
+ readonly VOLUME: 161;
40
+ /**
41
+ * LanguageResponse (DP 162, Raw protobuf) — the VOICE PACK, not a locale (see {@link decodeLanguageField}).
42
+ * Named for the vendor's own `language` code, which is what the catalogue calls it.
43
+ */
44
+ readonly LANGUAGE: 162;
45
+ /** Battery level 0-100 (DP 163, Value) — a clean-namespace DP, NOT the security param 1101. */
46
+ readonly BATTERY: 163;
47
+ /** UndisturbedResponse (DP 157, Raw protobuf) — the do-not-disturb window (see {@link decodeDoNotDisturb}). */
48
+ readonly DO_NOT_DISTURB: 157;
49
+ /** CleanStatistics (DP 167, Raw protobuf) — session and lifetime totals (see {@link decodeCleanStat}). */
50
+ readonly CLEAN_STATS: 167;
51
+ /** Remote-control direction (DP 155, Enum: Brake/Forward/Back/Left/Right). Steering, not a ModeCtrl verb. */
52
+ readonly REMOTE_CTRL: 155;
53
+ /** `pause_job` (DP 156, Bool) — resume an interrupted job after charging. The vendor's 断点续扫. */
54
+ readonly RESUME_CLEAN: 156;
55
+ /** `timing` (DP 164, Raw) — TimerRequest/TimerResponse. THIS is where schedules live. */
56
+ readonly TIMING: 164;
57
+ /** SceneResponse (DP 180, Raw protobuf) — the saved cleaning scenes, and a source of real map ids. */
58
+ readonly SCENES: 180;
59
+ /** ConsumableRuntime (DP 168, Raw protobuf) — hours used per replaceable part (see {@link decodeConsumableHours}). */
60
+ readonly CONSUMABLES: 168;
61
+ /** UnisettingResponse (DP 176, Raw protobuf) — the device-wide setting toggles (see {@link decodeUnisetting}). */
62
+ readonly SETTINGS: 176;
63
+ /** ErrorCode (DP 177 fault alert, Raw protobuf) — the robot's faults and warnings (see {@link decodeVacuumFault}). */
64
+ readonly FAULT_ALERT: 177;
65
+ };
66
+ /**
67
+ * Tuya DP ids for the `eufy_home_tuya` vacuum category (X8 Pro, X-series, and future Tuya clean-line models).
68
+ *
69
+ * Full schema sourced from `thing.m.device.ref.info.list` v5.4 for product `wahqax6ifjgs1c4n`
70
+ * (schemaInfo.schema, 39 DPs). Only the DPs with confirmed read-side values from a live
71
+ * `thing.m.device.dp.get` call are included here. Write direction for all DPs is unverified —
72
+ * no live publishDps capture has been made yet.
73
+ *
74
+ * **The one table for this line.** Every id the Tuya clean line uses is spelled here and nowhere else,
75
+ * including DP 103, which the `locate` capability reads and writes. One line spelled twice is how two
76
+ * tables come to disagree while each stays individually plausible.
77
+ *
78
+ * **Checked against `jeppesens/eufy-clean`'s `LEGACY_DPS_MAP`** and nothing came back to port. Its nine
79
+ * ids — 2, 3, 5, 15, 101, 102, 103, 104, 106 — are all here, all live-confirmed on a real X8 Pro, and
80
+ * all carry their enum value sets, which that map does not. Its `SCALAR_DPS` table is a different
81
+ * matter and deliberately untouched: that is a separate device class reusing these numbers for
82
+ * unrelated things (153 is a brush-detangle trigger there and the work status here), so it must be told
83
+ * apart by value SHAPE, never by DP number.
84
+ * @internal
85
+ */
86
+ export declare const TUYA_VACUUM_DP: {
87
+ /** Power on/off (DP 1, Bool). */
88
+ readonly POWER: 1;
89
+ /** Play/pause toggle (DP 2, Bool rw) — true = start, false = pause. */
90
+ readonly PLAY_PAUSE: 2;
91
+ /** Manual direction jog (DP 3, Enum: "forward"|"back"|"left"|"right"). */
92
+ readonly DIRECTION: 3;
93
+ /** Cleaning mode (DP 5, Enum: "auto"|"room"|"zone"|"spot"|"fast_mapping"). Live-confirmed "auto". */
94
+ readonly MODE: 5;
95
+ /** Work status (DP 15, Enum string) — the high-level activity. Live-confirmed "Sleeping". */
96
+ readonly WORK_STATUS: 15;
97
+ /** Return to dock (DP 101, Bool rw). */
98
+ readonly GO_HOME: 101;
99
+ /** Suction/cleaning strength (DP 102, Enum: "Off"|"Quiet"|"Standard"|"Turbo"|"Max"). Live-confirmed "Off". */
100
+ readonly CLEANING_STRENGTH: 102;
101
+ /**
102
+ * Find-robot beep (DP 103, `look_for_sweeper`, Bool). Live-confirmed.
103
+ *
104
+ * Read and written by the `locate` capability, which owns the feature across both clean lines —
105
+ * named here so this table is the one place the Tuya line's ids are spelled.
106
+ */
107
+ readonly LOOK_FOR_SWEEPER: 103;
108
+ /** Battery level 0-100 (DP 104, Value ro). */
109
+ readonly BATTERY_LEVEL: 104;
110
+ /** Mop water flow (DP 105, Enum: "Dry"|"Low"|"Mid"|"High"). Live-confirmed "Mid". */
111
+ readonly MOP_WATER: 105;
112
+ /** Fault code, 0 = ok (DP 106, Value ro). */
113
+ readonly FAULT_REPORT: 106;
114
+ /** Do-not-disturb / forbid mode (DP 107, Bool). Live-confirmed false. */
115
+ readonly FORBID_MODE: 107;
116
+ /** Session cleaning time in seconds (DP 109, Value). Live-confirmed 4200 (= 70 min). */
117
+ readonly CLEAR_TIME: 109;
118
+ /** Session cleaned area in m² (DP 110, Value). Live-confirmed 54. */
119
+ readonly CLEAR_AREA: 110;
120
+ /** Speaker loudness 0-100 (DP 111, Value). Live-confirmed 38. */
121
+ readonly LOUDNESS: 111;
122
+ /** Configured cleaning type (DP 113, Enum: "Sweep"|"SweepMop"|"Mop"). Live-confirmed "Sweep". */
123
+ readonly CLEAN_TYPE: 113;
124
+ /** Total lifetime cleaning time in seconds (DP 119, Value). */
125
+ readonly CLEAR_TOTAL_TIME: 119;
126
+ /** Total lifetime cleaned area in m² (DP 120, Value). */
127
+ readonly CLEAR_TOTAL_AREA: 120;
128
+ /** Water tank attached (DP 127, Bool ro). */
129
+ readonly WATER_TANK_STATUS: 127;
130
+ /** Mop pad attached (DP 129, Bool ro). */
131
+ readonly MOP_STATUS: 129;
132
+ /** WiFi RSSI in dBm (DP 134, Value). */
133
+ readonly RSSI: 134;
134
+ };
135
+ /**
136
+ * `thing.m.device.ref.info.list` v5.4 `schemaInfo.schema` confirmed values for DP 15 (status).
137
+ *
138
+ * Exported but not published — `VacuumActivity` is the
139
+ * union that matters externally.
140
+ * @internal
141
+ */
142
+ export declare const TUYA_WORK_STATUS_VALUES: readonly ["standby", "Running", "Sleeping", "Recharge", "Charging", "completed", "Goto", "Locating", "Collecting", "RollAutoCleaning", "CC_Recharge", "CC_Charging"];
143
+ /**
144
+ * Confirmed values for DP 5 (mode) from schemaInfo.schema.
145
+ * @internal
146
+ */
147
+ export declare const TUYA_WORK_MODES: readonly ["auto", "room", "zone", "spot", "fast_mapping"];
148
+ /** @internal */
149
+ export type TuyaWorkMode = (typeof TUYA_WORK_MODES)[number];
150
+ /**
151
+ * Confirmed values for DP 102 (cleaning_strength) from schemaInfo.schema. Live-confirmed "Off".
152
+ * @internal
153
+ */
154
+ export declare const TUYA_CLEANING_STRENGTHS: readonly ["Off", "Quiet", "Standard", "Turbo", "Max"];
155
+ /** @internal */
156
+ export type TuyaCleaningStrength = (typeof TUYA_CLEANING_STRENGTHS)[number];
157
+ /**
158
+ * Confirmed values for DP 105 (MopWater) from schemaInfo.schema. Live-confirmed "Mid".
159
+ * @internal
160
+ */
161
+ export declare const TUYA_MOP_WATER_LEVELS: readonly ["Dry", "Low", "Mid", "High"];
162
+ /** @internal */
163
+ export type TuyaMopWaterLevel = (typeof TUYA_MOP_WATER_LEVELS)[number];
164
+ /**
165
+ * Confirmed values for DP 113 (CleanType) from schemaInfo.schema. Live-confirmed "Sweep".
166
+ * @internal
167
+ */
168
+ export declare const TUYA_CLEAN_TYPES: readonly ["Sweep", "SweepMop", "Mop"];
169
+ /** @internal */
170
+ export type TuyaCleanType = (typeof TUYA_CLEAN_TYPES)[number];
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.
174
+ */
175
+ 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
+ /** Live-verified on a T2351. */
179
+ readonly START_GOHOME: 6;
180
+ /** Live-verified on a T2351. */
181
+ readonly PAUSE_TASK: 13;
182
+ readonly START_SPOT_CLEAN: 3;
183
+ readonly START_RC_CLEAN: 5;
184
+ readonly START_FAST_MAPPING: 9;
185
+ readonly START_GOWASH: 10;
186
+ readonly STOP_TASK: 12;
187
+ /** Live-verified on a T2351: the app's Resume sends method 14, seq continuing the shared counter. */
188
+ readonly RESUME_TASK: 14;
189
+ readonly STOP_GOHOME: 15;
190
+ readonly STOP_RC_CLEAN: 16;
191
+ readonly STOP_GOWASH: 17;
192
+ readonly STOP_SMART_FOLLOW: 18;
193
+ readonly START_GLOBAL_CRUISE: 20;
194
+ };
195
+ /**
196
+ * The methods that carry a `Param` oneof — room, zone, goto, schedule, cruise and scene cleans.
197
+ *
198
+ * Deliberately absent from {@link ModeCtrlMethod}. Each needs an argument the caller has to supply and
199
+ * this SDK cannot yet answer: a room or zone id comes from map data, which is not decodable here, and a
200
+ * coordinate is signed centimetres in a frame no capture has pinned. Listing their numbers beside the
201
+ * parameterless ones would invite a caller to send one with an empty payload, which is a valid frame
202
+ * meaning something nobody intended.
203
+ */
204
+ /**
205
+ * Encode a `ModeCtrlRequest` protobuf (DP 152) as a DP value: `varint(bodyLen) ++ {method:1, seq:2}`.
206
+ *
207
+ * Built on {@link RawDpWriter} rather than hand-rolled bytes. The frame is unchanged and the existing
208
+ * byte-level test is what proves it — that test was written against a live T2351 capture, so it holds
209
+ * the writer to the wire rather than to this function's own idea of the wire.
210
+ *
211
+ * Method 0 (START_AUTO_CLEAN) is omitted rather than written as an explicit zero, per the proto3
212
+ * default-field rule and confirmed on that same capture. The writer deliberately does not apply that
213
+ * rule itself: whether an explicit zero and an absent field mean the same thing is the
214
+ * message's business, not the encoder's.
215
+ * @internal
216
+ */
217
+ /**
218
+ * The area-selecting `ModeCtrlRequest` methods, and the `Param` field each one's payload rides in.
219
+ *
220
+ * Kept apart from {@link ModeCtrlMethod} because these are a different kind of thing: a parameterless
221
+ * verb is complete on its own, whereas each of these is meaningless without an argument the caller has
222
+ * to supply. Sending one with an empty payload is a well-formed frame that means something nobody
223
+ * intended, which is exactly why the numbers do not sit beside the others.
224
+ */
225
+ export declare const ModeCtrlParamMethod: {
226
+ /** `START_SELECT_ROOMS_CLEAN` — clean the named rooms of a named map. */
227
+ readonly SELECT_ROOMS: {
228
+ readonly method: 1;
229
+ readonly param: 4;
230
+ };
231
+ /** `START_SELECT_ZONES_CLEAN` — clean the given rectangles of a named map. */
232
+ readonly SELECT_ZONES: {
233
+ readonly method: 2;
234
+ readonly param: 5;
235
+ };
236
+ /** `START_GOTO_CLEAN` — drive to a point and clean around it. */
237
+ readonly GOTO: {
238
+ readonly method: 4;
239
+ readonly param: 7;
240
+ };
241
+ /** `START_SCENE_CLEAN` — run a saved scene by its id. */
242
+ readonly SCENE: {
243
+ readonly method: 24;
244
+ readonly param: 14;
245
+ };
246
+ };
247
+ /** One room to clean, and where it falls in the running order. */
248
+ export interface VacuumRoomTarget {
249
+ /** The room's id, as the device's own map data names it. */
250
+ readonly id: number;
251
+ /** Where this room falls in the run. Omitted rooms are visited in the order given. */
252
+ readonly order?: number;
253
+ }
254
+ /** One rectangular zone to clean, as four corners in centimetres. */
255
+ export interface VacuumZoneTarget {
256
+ /** The four corners, in centimetres, in the device's own map frame. Exactly four points. */
257
+ readonly corners: readonly {
258
+ readonly x: number;
259
+ readonly y: number;
260
+ }[];
261
+ /** How many passes to make over this zone. */
262
+ readonly cleanTimes?: number;
263
+ }
264
+ /**
265
+ * Build a room-select clean for a named map.
266
+ *
267
+ * `mapId` is required and has no default, deliberately. The obvious shortcut is to assume the map a
268
+ * single-floor home would have; on a two-floor home that silently sends the robot's ids against the
269
+ * wrong floor's map. A caller that cannot name the map cannot safely make this call, and saying so is
270
+ * better than picking for them.
271
+ * @internal
272
+ */
273
+ export declare function encodeSelectRoomsClean(mapId: number, rooms: readonly VacuumRoomTarget[], cleanTimes?: number): string;
274
+ /**
275
+ * Build a zone-select clean for a named map. Same `mapId` reasoning as {@link encodeSelectRoomsClean}.
276
+ * @internal
277
+ */
278
+ export declare function encodeSelectZonesClean(mapId: number, zones: readonly VacuumZoneTarget[]): string;
279
+ /** Build a scene clean, which needs only the scene's own id. @internal */
280
+ export declare function encodeSceneClean(sceneId: number): string;
281
+ export declare function encodeModeCtrl(method: number, seq: number): string;
282
+ /**
283
+ * Every value {@link VacuumActivity} can take, as data — the read's declared domain, so the schema a
284
+ * caller reads and the type it compiles against are the same list rather than two that can drift.
285
+ *
286
+ * Exported but not published — `VacuumActivity` is the union a
287
+ * reader of the reference needs, and it states the same members.
288
+ * @internal
289
+ */
290
+ export declare const VACUUM_ACTIVITIES: readonly ["idle", "error", "docked", "cleaning", "returning", "paused", "unknown"];
291
+ /**
292
+ * The robot's high-level activity — what `dev.vacuumClean()?.activity` reports. `"unknown"` covers a
293
+ * status the SDK can't classify yet. `"cleaning"` is the widest member: it also covers mapping,
294
+ * cruising and manual remote driving, which the wire distinguishes and this union does not.
295
+ */
296
+ export type VacuumActivity = (typeof VACUUM_ACTIVITIES)[number];
297
+ /**
298
+ * Decode a DP 15 string to a {@link VacuumActivity} for the X8 Pro. Returns `"unknown"` for any
299
+ * value absent from the confirmed schema set, so every valid raw string from the device yields
300
+ * a typed result rather than `undefined`.
301
+ * @internal
302
+ */
303
+ export declare function decodeTuyaWorkStatus(raw: ParamValue | undefined): VacuumActivity;
304
+ /**
305
+ * `WorkStatus.Charging.state` — whether a charge is running, finished, or faulted.
306
+ *
307
+ * `DOING` is the enum's zero and so is absent from the wire, which is why the CONTAINER's presence is
308
+ * the signal that the robot is on contacts at all: an absent `charging` message means it is not
309
+ * charging, and a present-but-empty one means it is charging normally.
310
+ */
311
+ export declare const CHARGE_STATES: readonly ["charging", "charged", "fault"];
312
+ export type ChargeState = (typeof CHARGE_STATES)[number];
313
+ /**
314
+ * `WorkStatus.Trigger.Source` — who or what caused the state the robot is now in.
315
+ *
316
+ * Worth surfacing rather than inferring: an automation that reacts to "returning to dock" behaves
317
+ * differently when the robot did it because a schedule fired, because someone pressed the button on
318
+ * its lid, or because it ran low on battery. `"unknown"` is the vendor's own zero and is what a robot
319
+ * reports just after boot, so it is a real answer rather than a decode failure.
320
+ */
321
+ export declare const TRIGGER_SOURCES: readonly ["unknown", "app", "button", "schedule", "robot", "remote"];
322
+ export type TriggerSource = (typeof TRIGGER_SOURCES)[number];
323
+ /**
324
+ * Decode the charge state out of a `WorkStatus` (DP 153).
325
+ *
326
+ * `undefined` means the robot is NOT charging — the vendor omits the whole message rather than sending
327
+ * a "not charging" value, so absence is the answer and not a gap. A present message with no `state`
328
+ * reads as `"charging"`, the enum's zero.
329
+ * @internal
330
+ */
331
+ export declare function decodeChargeState(raw: ParamValue | undefined, codec: RawDpCodec | undefined): ChargeState | undefined;
332
+ /**
333
+ * Decode what triggered the current state out of a `WorkStatus` (DP 153).
334
+ * @internal
335
+ */
336
+ export declare function decodeTriggerSource(raw: ParamValue | undefined, codec: RawDpCodec | undefined): TriggerSource | undefined;
337
+ /**
338
+ * Every value {@link VacuumCleanType} can take — the read's declared domain, see `VACUUM_ACTIVITIES`.
339
+ *
340
+ * Exported but not published, like `VACUUM_ACTIVITIES`.
341
+ * @internal
342
+ */
343
+ export declare const VACUUM_CLEAN_TYPES: readonly ["sweep", "mop", "sweepAndMop", "sweepThenMop"];
344
+ /**
345
+ * What the robot is **set** to do with a surface — `dev.vacuumClean()?.cleanType`. This is the setting,
346
+ * not what a job in progress is doing; the two disagree while a change is being applied.
347
+ *
348
+ * `mop` and `sweepAndMop` are verified on a real robot. `sweepThenMop` comes from the vendor's own
349
+ * enumeration and has not been observed on a device yet. `"sweep"` also covers **"no type stated"** —
350
+ * a robot that states none is indistinguishable from one set to sweep-only, and this read cannot tell
351
+ * them apart.
352
+ */
353
+ export type VacuumCleanType = (typeof VACUUM_CLEAN_TYPES)[number];
354
+ /**
355
+ * `mop_mode.level` — how much water the mop lays down.
356
+ *
357
+ * Confirmed on a live T2351: setting the app's water level to High reported `mop_mode { level: 2 }`.
358
+ */
359
+ export declare const MOP_LEVELS: readonly ["low", "middle", "high"];
360
+ export type MopLevel = (typeof MOP_LEVELS)[number];
361
+ /** `clean_carpet.strategy` — what the robot does when it meets a carpet. */
362
+ export declare const CARPET_STRATEGIES: readonly ["autoRaise", "avoid", "ignore"];
363
+ export type CarpetStrategy = (typeof CARPET_STRATEGIES)[number];
364
+ /**
365
+ * `clean_extent.value` — how far past the mapped edge a job reaches.
366
+ *
367
+ * **Not the app's display order.** The app lists these differently, so the raw index and the app's own
368
+ * position for it disagree; the names here follow the wire, which is the only order this SDK can vouch
369
+ * for.
370
+ */
371
+ export declare const CLEAN_EXTENTS: readonly ["normal", "narrow", "quick"];
372
+ export type CleanExtent = (typeof CLEAN_EXTENTS)[number];
373
+ /**
374
+ * Read one setting out of the CONFIGURED `CleanParam` (DP 154), by its field number.
375
+ *
376
+ * The generalisation of {@link decodeCleanType}, and it reads the same container for the same reason:
377
+ * a report taken mid-change carries a different value in `clean_param`(1) and `running_clean_param`(4),
378
+ * and the SETTING is the stable answer.
379
+ *
380
+ * **How the inner value is found, and why it is not a second field number.** The vendor wraps each
381
+ * setting in its own single-field message — `CleanType{value}`, `CleanCarpet{strategy}`,
382
+ * `CleanExtent{value}` — where the wrapper's name and its field's name differ per setting but the
383
+ * shape does not. Rather than assert a number for each inner field, this takes the FIRST varint the
384
+ * wrapper carries. The 1→1→1 nesting is live-proven for `clean_type`; taking the first scalar is what
385
+ * extends that to its siblings without claiming a number for any of them.
386
+ *
387
+ * The cost is stated rather than hidden: a wrapper that ever carries more than one scalar would read
388
+ * its first, so this is only used for the settings documented as single-valued. `mop_mode`(4) carries
389
+ * both a level and a corner-clean flag and is deliberately NOT read here for that reason.
390
+ *
391
+ * A present-but-empty wrapper answers `0` — proto3 omits a zero, so the enum's zero member and "the
392
+ * wrapper said nothing" are the same bytes. An absent wrapper is `undefined`: the device did not state
393
+ * this setting at all.
394
+ * @internal
395
+ */
396
+ export declare function decodeCleanParamValue(raw: ParamValue | undefined, codec: RawDpCodec | undefined, field: number, inner?: number): number | undefined;
397
+ /**
398
+ * Decode the cleaning type out of a `CleanParam` (DP 154) Raw-DP value.
399
+ *
400
+ * Reads the CONFIGURED container, not the running one: a report mid-change carries a different type in
401
+ * each, and the setting is the stable answer. Every level is presence-checked rather than defaulted —
402
+ * the vendor wraps each enum in its own single-field message precisely so that a wrapper's presence
403
+ * says "this was stated", and an absent wrapper yields `undefined` rather than a fabricated `"sweep"`.
404
+ *
405
+ * **Known ambiguity, unresolvable on the wire.** The protocol omits zero-valued fields, so an empty
406
+ * `CleanType{}` and an explicit `SWEEP_ONLY` are the same bytes. Both read as `"sweep"`. A robot that
407
+ * states no type therefore looks like a sweeping robot, and nothing in the payload can distinguish
408
+ * them — resolving it needs a capture of one device with a known-non-sweep setting at rest.
409
+ * @internal
410
+ */
411
+ export declare function decodeCleanType(raw: ParamValue | undefined, codec: RawDpCodec | undefined): VacuumCleanType | TuyaCleanType | undefined;
412
+ /**
413
+ * Decode the robot's current fault code from either clean line.
414
+ *
415
+ * The two lines carry the same meaning on different wires, so this discriminates on the value's SHAPE
416
+ * the way {@link decodeCleanType} does: the legacy Tuya line reports DP 106 as a plain integer, the
417
+ * AIoT line reports DP 177 as an `ErrorCode` protobuf.
418
+ *
419
+ * `error` is preferred over `warn`: a fault that stops the robot is the more urgent answer when both
420
+ * are listed. Only the FIRST code of the winning list is answered — the property is one number, and a
421
+ * caller needing the whole set needs a shape this schema cannot express (see the module's members).
422
+ *
423
+ * `0` means the device stated no fault. `undefined` means it did not state one at all — an unbound
424
+ * device, or a payload that does not decode — and the two are deliberately different.
425
+ * @internal
426
+ */
427
+ export declare function decodeVacuumFault(raw: ParamValue | undefined, codec: RawDpCodec | undefined): number | undefined;
428
+ /**
429
+ * Decode one end of the do-not-disturb window as `"HH:MM"`, or `undefined`.
430
+ *
431
+ * One string rather than two numbers per end: four properties for one window is four pieces to
432
+ * reassemble, and they are meaningless apart. `undefined` means no window is configured at
433
+ * all — distinct from `"00:00"`, which is midnight and a real setting.
434
+ *
435
+ * The times are the ROBOT's own clock, with no zone attached. The vendor sends none here, unlike a
436
+ * schedule, which carries the phone's UTC offset per timer.
437
+ * @internal
438
+ */
439
+ export declare function decodeDoNotDisturbTime(raw: ParamValue | undefined, codec: RawDpCodec | undefined, field: number): string | undefined;
440
+ /**
441
+ * Decode the do-not-disturb switch from either clean line.
442
+ *
443
+ * Discriminates on the value's SHAPE, as {@link decodeCleanType} and {@link decodeVacuumFault} do: the
444
+ * Tuya line reports DP 107 as a plain bool, the AIoT line reports DP 157 as an `UndisturbedResponse`.
445
+ *
446
+ * A present-but-empty `Switch` reads as `false` rather than as missing — proto3 omits a zero-valued
447
+ * field, so "switched off" and "said nothing about the switch" are the same bytes once the container
448
+ * around them is there. An absent CONTAINER is still `undefined`: that is the device not answering.
449
+ * @internal
450
+ */
451
+ export declare function decodeDoNotDisturb(raw: ParamValue | undefined, codec: RawDpCodec | undefined): boolean | undefined;
452
+ /**
453
+ * Decode the live in-window flag from an `UndisturbedResponse` (DP 157).
454
+ *
455
+ * The companion to {@link decodeDoNotDisturb}, which reports whether the feature is switched ON. This
456
+ * one reports whether the quiet window is open RIGHT NOW — two different questions the same DP answers,
457
+ * which is why this member reads its sibling's payload instead of claiming a wire of its own.
458
+ *
459
+ * **`active` is `Switch`-wrapped** — confirmed on a live T2351, which inside its quiet window reports
460
+ * `active { value: 1 }` beside `undisturbed { sw { value: 1 }, begin { hour: 9 }, end { hour: 23 } }`.
461
+ * The bare-varint branch is kept regardless: it costs one comparison, and a reader that accepts both
462
+ * cannot be broken by a firmware that changes its mind.
463
+ *
464
+ * The AIoT line only. On the Tuya line DP 107 is a plain bool carrying the SWITCH, and no wire there
465
+ * states the window — so a non-protobuf value answers `undefined` rather than borrowing the switch.
466
+ *
467
+ * An absent `active` beside a present `undisturbed` reads as `false`: proto3 omits a zero, so "the
468
+ * window is not open" and "said nothing about it" are the same bytes once the message is recognisable.
469
+ * An absent `undisturbed` is `undefined` — the payload is not one of these at all.
470
+ * @internal
471
+ */
472
+ export declare function decodeDoNotDisturbActive(raw: ParamValue | undefined, codec: RawDpCodec | undefined): boolean | undefined;
473
+ /**
474
+ * Read one figure out of a `CleanStatistics` (DP 167), or take a plain number as it stands.
475
+ *
476
+ * Both clean lines answer through this. The legacy Tuya line puts each figure on its own DP as a bare
477
+ * integer; the AIoT line buries all of them in one message. The value's SHAPE says which arrived — the
478
+ * same discrimination {@link decodeCleanType} and {@link decodeVacuumFault} use to span the two lines on
479
+ * one property, and the reason these figures need only one name each rather than one per platform.
480
+ *
481
+ * A present-but-empty container reads as `0`: a robot that has just started a run has cleaned no area,
482
+ * and proto3 omits the zero. An absent container is `undefined` — this device does not report it.
483
+ *
484
+ * **The plain-number passthrough belongs to a member that owns its own Tuya DP**, where that DP carries
485
+ * exactly the figure being asked for. A member with no wire of its own must not use it: its owner may
486
+ * have been installed by a read ALIAS, and it would then be handed another figure entirely — the Tuya
487
+ * DP 109 session duration reported as a lifetime run count. Such a member screens the value first; see
488
+ * `lifetimeCleanCount`.
489
+ * @internal
490
+ */
491
+ export declare function decodeCleanStat(raw: ParamValue | undefined, codec: RawDpCodec | undefined, container: number, field: number): number | undefined;
492
+ /**
493
+ * Decode one `Switch`-wrapped toggle out of a `UnisettingResponse` (DP 176).
494
+ *
495
+ * Every toggle in this message is the same two-level shape — a single-field `Switch` wrapper whose
496
+ * `value` is the bool — so one reader serves all of them and each member only names its field number.
497
+ *
498
+ * **Response numbers only.** The REQUEST counterpart numbers the same settings differently and only
499
+ * `children_lock` sits at 1 in both, so {@link UNISETTING_FIELD} is a read-side table and a writer of
500
+ * this DP must never borrow it. That is the trap this whole message carries; see the constant's doc.
501
+ *
502
+ * A present-but-empty `Switch` reads as `false`: proto3 omits a zero, so "off" and "said nothing about
503
+ * this toggle" are the same bytes once the wrapper is there. An absent wrapper is `undefined` — the
504
+ * device did not report the setting at all.
505
+ * @internal
506
+ */
507
+ export declare function decodeUnisetting(raw: ParamValue | undefined, codec: RawDpCodec | undefined, field: number): boolean | undefined;
508
+ /**
509
+ * Read one top-level `string` field out of a `DeviceInfo` (DP 169).
510
+ *
511
+ * An absent or empty field answers `undefined`: proto3 omits an empty string, so "this robot did not
512
+ * say" and "it said nothing" are the same bytes, and an empty SSID is not a network name.
513
+ * @internal
514
+ */
515
+ export declare function decodeRobotInfoText(raw: ParamValue | undefined, codec: RawDpCodec | undefined, field: number): string | undefined;
516
+ /**
517
+ * Read the robot's hardware revision out of a `DeviceInfo` (DP 169) — a plain integer, unlike every
518
+ * other field of this message.
519
+ * @internal
520
+ */
521
+ export declare function decodeRobotHardware(raw: ParamValue | undefined, codec: RawDpCodec | undefined): number | undefined;
522
+ /** `LanguageResponse.State` — where a voice-pack download has got to. */
523
+ export declare const VOICE_PACK_STATES: readonly ["idle", "updating", "success", "failure"];
524
+ export type VoicePackState = (typeof VOICE_PACK_STATES)[number];
525
+ /**
526
+ * Read one varint field out of a `LanguageResponse` (DP 162).
527
+ *
528
+ * A flat message, so one level rather than the two the consumables and settings reports need. A field
529
+ * absent from a payload that DID parse reads as `0`, the proto3 default — for `current_id` that is the
530
+ * vendor's own way of saying the robot is on the pack it shipped with. An unparseable payload is
531
+ * `undefined`: the device said nothing this can be read from.
532
+ * @internal
533
+ */
534
+ export declare function decodeLanguageField(raw: ParamValue | undefined, codec: RawDpCodec | undefined, field: number): number | undefined;
535
+ /**
536
+ * Read a `Numerical`-wrapped value out of a `UnisettingResponse` (DP 176) as the NUMBER it is.
537
+ *
538
+ * `Numerical { uint32 value = 1 }` and `Switch { bool value = 1 }` are the same two bytes on the wire.
539
+ * So a `Numerical` read through {@link decodeUnisetting} is accepted without complaint and reports
540
+ * "30 minutes" as `true`: nothing errors, nothing looks wrong, and the number is gone.
541
+ * `dust_full_remind` is one of these.
542
+ *
543
+ * A present-but-empty wrapper reads as `0`, which for a duration means the feature is off.
544
+ * @internal
545
+ */
546
+ export declare function decodeUnisettingNumber(raw: ParamValue | undefined, codec: RawDpCodec | undefined, field: number): number | undefined;
547
+ /**
548
+ * Which layers the robot's live map carries, by bit position — the vendor's `LiveMap.StateBit`.
549
+ *
550
+ * A bitmask rather than an enum: the vendor's own comment says the values combine, so a map with a
551
+ * base layer and room outlines reports both bits at once. Published as named bit positions rather than
552
+ * as raw shifts.
553
+ */
554
+ export declare const LIVE_MAP_BITS: {
555
+ readonly base: 0;
556
+ readonly rooms: 1;
557
+ readonly kitchen: 2;
558
+ readonly pet: 3;
559
+ };
560
+ /**
561
+ * Read a `Switch`- or `Active`-wrapped bool out of `UnisettingResponse.unistate` (DP 176).
562
+ *
563
+ * Two levels down rather than one: the toggles sit at the top of the message and these sit inside
564
+ * `unistate`, so the ordinary toggle reader finds nothing here.
565
+ * @internal
566
+ */
567
+ export declare function decodeUnistateFlag(raw: ParamValue | undefined, codec: RawDpCodec | undefined, field: number): boolean | undefined;
568
+ /**
569
+ * Read a bare `uint32` out of `UnisettingResponse.unistate` (DP 176), or one nested a further level
570
+ * inside a wrapper there — `live_map.state_bits` is the only field that needs the second step.
571
+ * @internal
572
+ */
573
+ export declare function decodeUnistateNumber(raw: ParamValue | undefined, codec: RawDpCodec | undefined, field: number, inner?: number): number | undefined;
574
+ /**
575
+ * Read a BARE `uint32` off the top level of a `UnisettingResponse` (DP 176).
576
+ *
577
+ * `ap_signal_strength` is the one field of this message that is not wrapped in anything, so neither of
578
+ * the two readers above reaches it: both step into a sub-message that is not there.
579
+ * @internal
580
+ */
581
+ export declare function decodeUnisettingTopLevel(raw: ParamValue | undefined, codec: RawDpCodec | undefined, field: number): number | undefined;
582
+ /**
583
+ * `ConsumableRequest.Type` — which part a reset clears, in the vendor's REQUEST numbering.
584
+ *
585
+ * **These are not the response's field numbers and must never be swapped for them.** The report puts
586
+ * the side brush at field 1 and the dirty-water tank at 10; the request enumerates from ZERO with no
587
+ * gap, so the side brush is 0 and the dirty-water tank is 7. Nine parts, two numbering schemes, one
588
+ * message pair — the same trap `UNISETTING_FIELD` carries, and the reason a reader's table is never a
589
+ * writer's.
590
+ */
591
+ /** The replaceable parts whose hours-used counter can be reset. */
592
+ export declare const CONSUMABLE_PARTS: readonly ["sideBrush", "rollingBrush", "filter", "scraper", "sensors", "mop", "dustBag", "dirtyWaterTank", "dirtyWaterFilter"];
593
+ export type ConsumablePart = (typeof CONSUMABLE_PARTS)[number];
594
+ /** Part name to the vendor's `ConsumableRequest.Type`, in one table so no index arithmetic can drift. */
595
+ export declare const CONSUMABLE_RESET_TYPE: Readonly<Record<ConsumablePart, number>>;
596
+ /**
597
+ * Build a `ConsumableRequest` (DP 168) clearing the hours on one part.
598
+ *
599
+ * `reset_types` is REPEATED, so the wire shape allows clearing several at once. Only one is offered:
600
+ * a caller replacing two parts can send two frames, and a single-part call is the one that cannot be
601
+ * half-right — an accidental multi-reset silently discards service history the device never
602
+ * recomputes.
603
+ *
604
+ * **Unverified.** The message and its enum are the vendor's own, and the app has the feature
605
+ * (`resetAccessory(deviceId, accessory, callback)` → `resetAccessories`, taking exactly this kind of
606
+ * integer part id), but no capture has shown the frame accepted — so no setter is installed.
607
+ * @internal
608
+ */
609
+ export declare function encodeConsumableReset(part: ConsumablePart): string;
610
+ /**
611
+ * Decode one part's hours-used out of a `ConsumableRuntime` (DP 168).
612
+ *
613
+ * Same two-level shape for every part, so one reader serves all nine and each member names its field.
614
+ *
615
+ * A present-but-empty `Duration` reads as `0`, not as missing: a part fitted and never run has no hours
616
+ * on it, and proto3 omits the zero. An absent `Duration` is `undefined` — this robot does not track
617
+ * that part, which is a real answer for a model that does not have one.
618
+ * @internal
619
+ */
620
+ export declare function decodeConsumableHours(raw: ParamValue | undefined, codec: RawDpCodec | undefined, field: number): number | undefined;
621
+ /**
622
+ * Decode a `WorkStatus` (DP 153) Raw-DP value to a {@link VacuumActivity}. That DP carries a whole
623
+ * protobuf message rather than a scalar, so the payload is read through the injected {@link RawDpCodec}:
624
+ * the codec owns the structure, this owns which field number carries which meaning. `"unknown"` covers
625
+ * every way the answer can be absent — an unbound device (no codec), a malformed payload, no
626
+ * `state` field, or a state value missing from {@link WORK_STATE_ACTIVITY}.
627
+ *
628
+ * `CLEANING` is the one state that is not final on its own; {@link resolveCleaningState} reads the
629
+ * sub-messages beside it to separate cleaning from paused and from a mop cycle on the dock.
630
+ * @internal
631
+ */
632
+ export declare function decodeVacuumActivity(raw: ParamValue | undefined, codec: RawDpCodec | undefined): VacuumActivity;
633
+ /**
634
+ * Bound RoboVac reads and controls — the object returned by `dev.vacuumClean()`.
635
+ *
636
+ * All reads, `setPower`, and the three mode-control verbs are DERIVED from `VACUUM_CLEAN_MEMBERS`.
637
+ * Each getter is present only when the device reports the backing DP. `setPower` and the three
638
+ * mode-control verbs are AIoT-only: no Tuya clean-line write has been confirmed on a device, so none
639
+ * is dispatched.
640
+ *
641
+ * Tuya clean-line read members (`lifetimeCleanTime`, `lifetimeCleanArea`, `waterTank`, `mopPad`)
642
+ * are populated only once the device has reported those DPs over MQTT or the initial Tuya DP poll.
643
+ */
644
+ export type VacuumCleanActions = Surface<typeof VACUUM_CLEAN_MEMBERS>;
645
+ /**
646
+ * Every `vacuum_clean` read plus the writes and mode-control verbs.
647
+ *
648
+ * Every write here is AIoT-only, gated on `isAiotVacuum`: `power` (DP 151) and the three mode-control
649
+ * verbs (`startCleaning`, `returnToDock`, `pauseCleaning`, all DP 152 `ModeCtrlRequest`). DP 151 and
650
+ * DP 152 belong to the shared AIoT product schema rather than to a device's reported param set, so
651
+ * gating them on a reported DP would hide them on real hardware. No legacy Tuya clean-line write is
652
+ * dispatched at all — that direction has no live `publishDps` capture behind it.
653
+ *
654
+ * Each AIoT mode-control verb carries its own `seq` counter per bind (the T2351 accepts per-closure
655
+ * counters — two separately-obtained action objects both starting at 112 do not cause the device to
656
+ * complain, so the seq is not enforced as globally monotonic).
657
+ *
658
+ * DP-gated READS: `doNotDisturb` (DP 107, Bool ro) and `rssi` (DP 134, WiFi signal strength) are
659
+ * installed only when the device has reported those DPs. The `locate` action (DP 160) is owned by the
660
+ * `locate` capability module.
661
+ *
662
+ * Exported but NOT published: each entry states its wire id and the evidence it was confirmed on,
663
+ * which the reference site does not carry.
664
+ * @internal
665
+ */
666
+ export declare const VACUUM_CLEAN_MEMBERS: {
667
+ /**
668
+ * The robot's power switch, and NOT a way to start a job — `startCleaning` is that.
669
+ * DP 151 belongs to the shared AIoT product DP schema every clean-line device speaks, so the write
670
+ * is gated on the confirmed AIoT platform (category-based via `isAiotVacuum`) rather than on a
671
+ * reported DP — no equivalent power DP is confirmed on the legacy Tuya clean line.
672
+ */
673
+ readonly power: {
674
+ readonly param: 151;
675
+ readonly type: "bool";
676
+ readonly kind: "boolean";
677
+ readonly provenance: "mega";
678
+ readonly description: "Power on/off (DP 151 power switch, cloud get_product_data_point).";
679
+ readonly write: (v: string | number | boolean, _ctx: import("./types.js").CommandContext) => import("../../core/contracts.js").Command;
680
+ readonly available: (ctx: AvailabilityContext) => boolean;
681
+ };
682
+ /** Stored as the raw structured payload; the activity is decoded out of it at read time. */
683
+ readonly activity: {
684
+ readonly param: 153;
685
+ readonly type: "string";
686
+ readonly provenance: "mega";
687
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => "cleaning" | "docked" | "error" | "idle" | "paused" | "returning" | "unknown";
688
+ readonly decodedKind: "enum";
689
+ readonly decodedValues: readonly ["idle", "error", "docked", "cleaning", "returning", "paused", "unknown"];
690
+ readonly description: string;
691
+ };
692
+ /**
693
+ * The robot's own speaker loudness — its spoken prompts and chimes, nothing to do with suction noise.
694
+ * Confirmed writable via `get_product_data_point` (`writable: true`); no live publishDps capture yet.
695
+ * Reaches the getters only via `decodeState`, since the robot's cloud record carries no DPs at all.
696
+ */
697
+ readonly volume: {
698
+ readonly param: 161;
699
+ readonly type: "number";
700
+ readonly unit: "%";
701
+ readonly kind: "percent";
702
+ readonly provenance: "mega";
703
+ readonly description: "Speaker volume 0-100 (DP 161, Value ro). AIoT clean line.";
704
+ readonly available: (ctx: AvailabilityContext) => boolean;
705
+ };
706
+ /**
707
+ * Charge percentage — DP 163 for the AIoT clean line; DP 104 for the legacy Tuya (G-series/X8)
708
+ * via a `readAliases` entry gated on {@link isTuyaVacuum}. Deliberately NOT the security param 1101
709
+ * the `battery` capability reads, so a robot's charge is here rather than on `dev.battery()`.
710
+ * Read-only, populated only once a realtime report lands.
711
+ */
712
+ readonly battery: {
713
+ readonly param: 163;
714
+ readonly type: "number";
715
+ readonly unit: "%";
716
+ readonly kind: "percent";
717
+ readonly provenance: "mega";
718
+ readonly readAliases: readonly [{
719
+ readonly paramType: 104;
720
+ readonly available: typeof isTuyaVacuum;
721
+ }];
722
+ readonly description: "Battery level 0-100 (DP 163 AIoT / DP 104 Tuya). NOTE: clean namespace — not param 1101.";
723
+ };
724
+ /**
725
+ * Which voice pack the robot is speaking — the vendor's own numbered id, not a locale.
726
+ *
727
+ * DP 162 carries a `LanguageResponse`, not a locale code — a base64 protobuf message rather than a
728
+ * language tag. The DP is Raw in both directions, confirmed against the schema and the product
729
+ * catalogue.
730
+ *
731
+ * The id alone is what the device reports; which voice it corresponds to is a vendor table keyed by
732
+ * firmware, and this SDK does not carry one. There is no setter either: selecting a pack means
733
+ * sending a `LanguageRequest.Desc` carrying a CDN url and an md5 the device verifies, which is not a
734
+ * descriptor this SDK can construct.
735
+ */
736
+ readonly voicePack: {
737
+ readonly param: 162;
738
+ readonly type: "number";
739
+ readonly kind: "identifier";
740
+ readonly provenance: "mega";
741
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
742
+ readonly decodedKind: "identifier";
743
+ readonly description: "The voice pack in use — LanguageResponse.current_id (DP 162, Raw protobuf). AIoT clean line.";
744
+ readonly available: (ctx: AvailabilityContext) => boolean;
745
+ };
746
+ /**
747
+ * The voice pack the robot fell back to, which is the one its firmware shipped with. Differs from
748
+ * {@link VACUUM_CLEAN_MEMBERS.voicePack} exactly when someone has chosen another.
749
+ */
750
+ readonly defaultVoicePack: {
751
+ readonly readsFrom: "voicePack";
752
+ readonly type: "number";
753
+ readonly kind: "identifier";
754
+ readonly provenance: "mega";
755
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
756
+ readonly decodedKind: "identifier";
757
+ readonly description: "The firmware's own voice pack — LanguageResponse.default_id (DP 162, Raw protobuf).";
758
+ };
759
+ /**
760
+ * How a voice-pack change is going. A pack is downloaded from a CDN and md5-checked by the device, so
761
+ * a selection is not instant and can fail — this is the field that says which happened.
762
+ */
763
+ readonly voicePackState: {
764
+ readonly readsFrom: "voicePack";
765
+ readonly type: "string";
766
+ readonly provenance: "mega";
767
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => "failure" | "idle" | "success" | "updating" | undefined;
768
+ readonly decodedKind: "enum";
769
+ readonly decodedValues: readonly string[];
770
+ readonly description: "Voice-pack download state — LanguageResponse.state (DP 162, Raw protobuf).";
771
+ };
772
+ /**
773
+ * The installed voice pack's version, as the device counts it. Meaningful only against the vendor's
774
+ * own catalogue for the same pack id; on its own it is a number that changes when a pack is updated.
775
+ */
776
+ readonly voicePackVersion: {
777
+ readonly readsFrom: "voicePack";
778
+ readonly type: "number";
779
+ readonly kind: "scalar";
780
+ readonly provenance: "mega";
781
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
782
+ readonly decodedKind: "scalar";
783
+ readonly description: "Installed voice-pack version — LanguageResponse.version (DP 162, Raw protobuf).";
784
+ };
785
+ /**
786
+ * The SETTING for what to do with a surface, not what a running job is doing — the two disagree while
787
+ * a change is being applied. Stored as the raw structured payload (`type: "string"`), with the field
788
+ * lifted out by `decode`: the injected codec turns the DP into a field tree and this capability names
789
+ * which field means what, which is why the transport never has to know DP 154. The decode's own
790
+ * return type wins on the surface, so the getter answers the named `VacuumCleanType` union.
791
+ * For Tuya devices, DP 113 (Enum: "Sweep"|"SweepMop"|"Mop") is read via a `readAliases` entry.
792
+ */
793
+ readonly cleanType: {
794
+ readonly param: 154;
795
+ readonly type: "string";
796
+ readonly provenance: "mega";
797
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => "Mop" | "Sweep" | "SweepMop" | "mop" | "sweep" | "sweepAndMop" | "sweepThenMop" | undefined;
798
+ readonly decodedKind: "enum";
799
+ readonly decodedValues: readonly string[];
800
+ readonly readAliases: readonly [{
801
+ readonly paramType: 113;
802
+ readonly available: typeof isTuyaVacuum;
803
+ }];
804
+ readonly description: "Configured cleaning type from CleanParam.clean_type (DP 154 AIoT protobuf) or DP 113 Tuya Enum.";
805
+ };
806
+ /**
807
+ * What the robot does when it meets a carpet — raise the mop, drive around, or carry on over it.
808
+ *
809
+ * Reads its sibling's DP 154 payload: `clean_carpet` sits beside `clean_type` in the one `CleanParam`
810
+ * the device reports, so there is one param and several readings of it.
811
+ */
812
+ readonly carpetStrategy: {
813
+ readonly readsFrom: "cleanType";
814
+ readonly type: "string";
815
+ readonly provenance: "mega";
816
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => "autoRaise" | "avoid" | "ignore" | undefined;
817
+ readonly decodedKind: "enum";
818
+ readonly decodedValues: readonly string[];
819
+ readonly description: "Carpet strategy from CleanParam.clean_carpet (DP 154 AIoT, Raw protobuf).";
820
+ };
821
+ /**
822
+ * How far past the mapped edge a job reaches.
823
+ *
824
+ * The index order is the WIRE's, not the app's display order, so a raw index disagrees with the app's
825
+ * own position for it. This read answers the NAME.
826
+ */
827
+ readonly cleanExtent: {
828
+ readonly readsFrom: "cleanType";
829
+ readonly type: "string";
830
+ readonly provenance: "mega";
831
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => "narrow" | "normal" | "quick" | undefined;
832
+ readonly decodedKind: "enum";
833
+ readonly decodedValues: readonly string[];
834
+ readonly description: "Clean extent from CleanParam.clean_extent (DP 154 AIoT, Raw protobuf). Wire order, not app order.";
835
+ };
836
+ /**
837
+ * Whether the robot is left to its own judgement about a room — suction and water chosen per surface
838
+ * rather than held at what the user set.
839
+ */
840
+ readonly smartMode: {
841
+ readonly readsFrom: "cleanType";
842
+ readonly type: "bool";
843
+ readonly kind: "boolean";
844
+ readonly provenance: "mega";
845
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
846
+ readonly decodedKind: "boolean";
847
+ readonly description: "Smart mode from CleanParam.smart_mode_sw (DP 154 AIoT, Raw protobuf).";
848
+ };
849
+ /**
850
+ * How much water the mop lays down — the AIoT line's own scale.
851
+ *
852
+ * Distinct from `mopWater`, which is the Tuya line's DP 105 and reports `Dry`/`Low`/`Mid`/`High`.
853
+ * The two are NOT merged under one name: this scale has three members and that one has four, so any
854
+ * mapping between them would be invented rather than read.
855
+ */
856
+ readonly mopLevel: {
857
+ readonly readsFrom: "cleanType";
858
+ readonly type: "string";
859
+ readonly provenance: "verified";
860
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => "high" | "low" | "middle" | undefined;
861
+ readonly decodedKind: "enum";
862
+ readonly decodedValues: readonly string[];
863
+ readonly description: "Mop water level from CleanParam.mop_mode.level (DP 154 AIoT). Captured on a live T2351.";
864
+ };
865
+ /**
866
+ * Whether the robot makes an extra pass along edges while mopping — the app calls it edge-hug
867
+ * mopping. Sits beside {@link VACUUM_CLEAN_MEMBERS.mopLevel} in the same `mop_mode`, which is why
868
+ * this read names its inner field rather than taking the first scalar it finds.
869
+ */
870
+ readonly mopCornerClean: {
871
+ readonly readsFrom: "cleanType";
872
+ readonly type: "bool";
873
+ readonly kind: "boolean";
874
+ readonly provenance: "verified";
875
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
876
+ readonly decodedKind: "boolean";
877
+ readonly description: "Edge-hug mopping from CleanParam.mop_mode.corner_clean (DP 154 AIoT). Captured on a live T2351.";
878
+ };
879
+ /**
880
+ * How many passes one job makes over the same floor. `0` is the device stating no repeat rather than
881
+ * a robot that will not clean.
882
+ */
883
+ readonly cleanTimes: {
884
+ readonly readsFrom: "cleanType";
885
+ readonly type: "number";
886
+ readonly kind: "scalar";
887
+ readonly provenance: "mega";
888
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
889
+ readonly decodedKind: "scalar";
890
+ readonly description: "Passes per job from CleanParam.clean_times (DP 154 AIoT, Raw protobuf).";
891
+ };
892
+ /**
893
+ * The robot's current fault, as a numeric code. `0` is no fault; `undefined` is a device that has not
894
+ * said, which is not the same thing.
895
+ *
896
+ * One number for both clean lines: the AIoT line reports an `ErrorCode` message on DP 177 carrying a
897
+ * list of faults and a list of warnings, and the legacy Tuya line reports a plain integer on DP 106.
898
+ * {@link decodeVacuumFault} answers the first fault, or the first warning when there is no fault.
899
+ *
900
+ * The code's MEANING is the vendor's own table and is not interpreted here.
901
+ *
902
+ * The DP 106 alias is DELIBERATELY ungated, unlike `battery` and `cleanType` which gate their
903
+ * legacy aliases on `isTuyaVacuum`. A fault is the one reading worth surfacing even when the
904
+ * family classification is wrong or absent, and {@link decodeVacuumFault} discriminates on the
905
+ * value's SHAPE rather than on the family — so a device carrying DP 106 decodes sanely whichever
906
+ * line it turns out to be on. The asymmetry is the point, not an oversight.
907
+ */
908
+ readonly errorCode: {
909
+ readonly param: 177;
910
+ readonly type: "number";
911
+ readonly provenance: "mega";
912
+ readonly readAliases: readonly [{
913
+ readonly paramType: 106;
914
+ }];
915
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
916
+ readonly decodedKind: "scalar";
917
+ readonly description: string;
918
+ };
919
+ /**
920
+ * High-level activity for the X8 Pro Tuya clean line (DP 15, Enum string). Decoded from the device's
921
+ * `status` string to a {@link VacuumActivity} via `decodeTuyaWorkStatus`. Live-confirmed "Sleeping"
922
+ * at rest. `"unknown"` covers any value absent from the schema-confirmed set.
923
+ *
924
+ * Distinct from {@link activity} (DP 153, protobuf), which the AIoT T2351 reports instead.
925
+ */
926
+ readonly workStatus: {
927
+ readonly param: 15;
928
+ readonly type: "string";
929
+ readonly provenance: "mega";
930
+ readonly decode: (raw: unknown) => "cleaning" | "docked" | "error" | "idle" | "paused" | "returning" | "unknown";
931
+ readonly decodedKind: "enum";
932
+ readonly decodedValues: readonly ["idle", "error", "docked", "cleaning", "returning", "paused", "unknown"];
933
+ readonly description: "High-level activity from DP 15 (status, Enum). X8 Pro Tuya clean line. Live-confirmed Sleeping.";
934
+ };
935
+ /**
936
+ * Cleaning mode (DP 5, Enum string). Live-confirmed "auto". Distinct from the AIoT suction/mode
937
+ * controls. Write direction is unverified — no live publishDps capture.
938
+ *
939
+ * Known values from schemaInfo.schema: `TUYA_WORK_MODES`.
940
+ */
941
+ readonly workMode: {
942
+ readonly param: 5;
943
+ readonly type: "string";
944
+ readonly provenance: "mega";
945
+ readonly decode: (raw: unknown) => TuyaWorkMode | undefined;
946
+ readonly decodedKind: "enum";
947
+ readonly decodedValues: readonly ["auto", "room", "zone", "spot", "fast_mapping"];
948
+ readonly description: "Cleaning mode from DP 5 (mode, Enum). X8 Pro Tuya clean line. Live-confirmed auto. Write unverified.";
949
+ };
950
+ /**
951
+ * Suction / cleaning strength (DP 102, Enum string). Live-confirmed "Off" at rest.
952
+ * Write direction is unverified — no live publishDps capture.
953
+ *
954
+ * Known values from schemaInfo.schema: `TUYA_CLEANING_STRENGTHS`.
955
+ */
956
+ readonly cleaningStrength: {
957
+ readonly param: 102;
958
+ readonly type: "string";
959
+ readonly provenance: "mega";
960
+ readonly decode: (raw: unknown) => TuyaCleaningStrength | undefined;
961
+ readonly decodedKind: "enum";
962
+ readonly decodedValues: readonly ["Off", "Quiet", "Standard", "Turbo", "Max"];
963
+ readonly description: "Suction/cleaning strength from DP 102 (cleaning_strength, Enum). X8 Pro Tuya clean line. Live-confirmed Off. Write unverified.";
964
+ };
965
+ /**
966
+ * Mop water flow level (DP 105, Enum string). Live-confirmed "Mid" at rest.
967
+ * Write direction is unverified — no live publishDps capture.
968
+ *
969
+ * Known values from schemaInfo.schema: `TUYA_MOP_WATER_LEVELS`.
970
+ */
971
+ readonly mopWater: {
972
+ readonly param: 105;
973
+ readonly type: "string";
974
+ readonly provenance: "mega";
975
+ readonly decode: (raw: unknown) => TuyaMopWaterLevel | undefined;
976
+ readonly decodedKind: "enum";
977
+ readonly decodedValues: readonly ["Dry", "Low", "Mid", "High"];
978
+ readonly description: "Mop water flow level from DP 105 (MopWater, Enum). X8 Pro Tuya clean line. Live-confirmed Mid. Write unverified.";
979
+ };
980
+ /**
981
+ * Session cleaning duration in seconds (DP 109, Value). Live-confirmed 4200 (= 70 min) at rest.
982
+ * Read-only — no write is expected for a session counter.
983
+ */
984
+ readonly clearTime: {
985
+ readonly param: 167;
986
+ readonly type: "number";
987
+ readonly unit: "s";
988
+ readonly kind: "seconds";
989
+ readonly provenance: "mega";
990
+ readonly readAliases: readonly [{
991
+ readonly paramType: 109;
992
+ readonly available: typeof isTuyaVacuum;
993
+ }];
994
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
995
+ readonly decodedKind: "seconds";
996
+ readonly description: string;
997
+ };
998
+ /**
999
+ * Session cleaned area in m² (DP 110, Value). Live-confirmed 54 at rest. Read-only.
1000
+ */
1001
+ readonly clearArea: {
1002
+ readonly param: 110;
1003
+ readonly readsFrom: "clearTime";
1004
+ readonly type: "number";
1005
+ readonly kind: "scalar";
1006
+ readonly provenance: "mega";
1007
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1008
+ readonly decodedKind: "scalar";
1009
+ readonly description: string;
1010
+ };
1011
+ /**
1012
+ * Speaker loudness 0-100 (DP 111, Value). Live-confirmed 38.
1013
+ * Distinct from {@link volume} (DP 161), which the AIoT T2351 reports.
1014
+ */
1015
+ readonly loudness: {
1016
+ readonly param: 111;
1017
+ readonly type: "number";
1018
+ readonly unit: "%";
1019
+ readonly kind: "percent";
1020
+ readonly provenance: "mega";
1021
+ readonly description: "Speaker loudness 0-100 from DP 111 (Loudness). X8 Pro Tuya clean line. Live-confirmed.";
1022
+ };
1023
+ /**
1024
+ * Lifetime total cleaning time in seconds (DP 119, Value). Counts across all sessions.
1025
+ * Confirmed from `thing.m.device.ref.info.list` v5.4 schemaInfo.schema (X8 Pro,
1026
+ * product `wahqax6ifjgs1c4n`). Read-only accumulator — no write expected.
1027
+ */
1028
+ readonly lifetimeCleanTime: {
1029
+ readonly param: 119;
1030
+ readonly readsFrom: "clearTime";
1031
+ readonly type: "number";
1032
+ readonly unit: "s";
1033
+ readonly kind: "seconds";
1034
+ readonly provenance: "mega";
1035
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1036
+ readonly decodedKind: "seconds";
1037
+ readonly description: string;
1038
+ };
1039
+ /**
1040
+ * Lifetime total cleaned area in m² (DP 120, Value). Counts across all sessions.
1041
+ * Confirmed from `thing.m.device.ref.info.list` v5.4 schemaInfo.schema (X8 Pro,
1042
+ * product `wahqax6ifjgs1c4n`). Read-only accumulator — no write expected.
1043
+ */
1044
+ readonly lifetimeCleanArea: {
1045
+ readonly param: 120;
1046
+ readonly readsFrom: "clearTime";
1047
+ readonly type: "number";
1048
+ readonly kind: "scalar";
1049
+ readonly provenance: "mega";
1050
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1051
+ readonly decodedKind: "scalar";
1052
+ readonly description: string;
1053
+ };
1054
+ /**
1055
+ * How many runs the robot has completed in its lifetime.
1056
+ *
1057
+ * AIoT only — it rides inside the same `CleanStatistics` the two figures above read, and the Tuya
1058
+ * clean line has no DP for it. So this one borrows without a wire of its own, where its siblings keep
1059
+ * theirs and only fall back to the payload.
1060
+ */
1061
+ readonly lifetimeCleanCount: {
1062
+ readonly readsFrom: "clearTime";
1063
+ readonly type: "number";
1064
+ readonly kind: "scalar";
1065
+ readonly provenance: "mega";
1066
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1067
+ readonly decodedKind: "scalar";
1068
+ readonly description: "Completed runs in the robot's lifetime — CleanStatistics.user_total.clean_count (DP 167 AIoT).";
1069
+ readonly available: (ctx: AvailabilityContext) => boolean;
1070
+ };
1071
+ /**
1072
+ * Water tank attached (DP 127, Bool ro). Confirmed from `thing.m.device.ref.info.list` v5.4.
1073
+ * `true` when the water tank is mounted; `false` when removed. Read-only sensor — the device
1074
+ * reports this, the app does not write it.
1075
+ */
1076
+ readonly waterTank: {
1077
+ readonly param: 127;
1078
+ readonly type: "bool";
1079
+ readonly kind: "boolean";
1080
+ readonly provenance: "mega";
1081
+ readonly description: "Water tank attached (DP 127, Bool ro). X8 Pro Tuya clean line. Schema-confirmed.";
1082
+ };
1083
+ /**
1084
+ * Mop pad attached (DP 129, Bool ro). Confirmed from `thing.m.device.ref.info.list` v5.4.
1085
+ * `true` when the mop pad is mounted; `false` when removed. Read-only sensor.
1086
+ */
1087
+ readonly mopPad: {
1088
+ readonly param: 129;
1089
+ readonly type: "bool";
1090
+ readonly kind: "boolean";
1091
+ readonly provenance: "mega";
1092
+ readonly description: "Mop pad attached (DP 129, Bool ro). X8 Pro Tuya clean line. Schema-confirmed.";
1093
+ };
1094
+ /**
1095
+ * Child lock — when on, the robot ignores its physical buttons.
1096
+ *
1097
+ * AIoT clean line only; no equivalent is confirmed on the Tuya schema, so there is no read alias.
1098
+ */
1099
+ readonly childLock: {
1100
+ readonly param: 176;
1101
+ readonly type: "bool";
1102
+ readonly kind: "boolean";
1103
+ readonly provenance: "mega";
1104
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1105
+ readonly decodedKind: "boolean";
1106
+ readonly description: "Child lock from UnisettingResponse.children_lock (DP 176 commonSettings, Raw protobuf).";
1107
+ readonly available: (ctx: AvailabilityContext) => boolean;
1108
+ };
1109
+ /**
1110
+ * Whether a cruise resumes by itself after the robot has charged, rather than ending at the dock.
1111
+ */
1112
+ readonly cruiseContinue: {
1113
+ readonly readsFrom: "childLock";
1114
+ readonly type: "bool";
1115
+ readonly kind: "boolean";
1116
+ readonly provenance: "mega";
1117
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1118
+ readonly decodedKind: "boolean";
1119
+ readonly description: "Resume a cruise after charging — UnisettingResponse.cruise_continue_sw (DP 176, Raw protobuf).";
1120
+ };
1121
+ /**
1122
+ * Whether the robot keeps more than one saved map — a house with more than one floor needs this on.
1123
+ */
1124
+ readonly multiMap: {
1125
+ readonly readsFrom: "childLock";
1126
+ readonly type: "bool";
1127
+ readonly kind: "boolean";
1128
+ readonly provenance: "mega";
1129
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1130
+ readonly decodedKind: "boolean";
1131
+ readonly description: "Multi-map storage — UnisettingResponse.multi_map_sw (DP 176, Raw protobuf).";
1132
+ };
1133
+ /**
1134
+ * The obstacle-recognition camera. Off means the robot navigates without it, not that it is broken.
1135
+ */
1136
+ readonly aiSee: {
1137
+ readonly readsFrom: "childLock";
1138
+ readonly type: "bool";
1139
+ readonly kind: "boolean";
1140
+ readonly provenance: "mega";
1141
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1142
+ readonly decodedKind: "boolean";
1143
+ readonly description: "Obstacle-recognition camera — UnisettingResponse.ai_see (DP 176, Raw protobuf).";
1144
+ };
1145
+ /**
1146
+ * The vendor's `water_level_sw`. Named after the wire rather than given a friendlier name: what it
1147
+ * switches is not stated anywhere this SDK can point at, and a guessed name would be a claim.
1148
+ */
1149
+ readonly waterLevelSwitch: {
1150
+ readonly readsFrom: "childLock";
1151
+ readonly type: "bool";
1152
+ readonly kind: "boolean";
1153
+ readonly provenance: "mega";
1154
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1155
+ readonly decodedKind: "boolean";
1156
+ readonly description: "UnisettingResponse.water_level_sw (DP 176, Raw protobuf). Vendor name kept — its meaning is unconfirmed.";
1157
+ };
1158
+ /**
1159
+ * Whether the robot offers restricted-area suggestions after a run — the prompts that ask to fence
1160
+ * off a spot it got stuck in.
1161
+ */
1162
+ readonly suggestRestricted: {
1163
+ readonly readsFrom: "childLock";
1164
+ readonly type: "bool";
1165
+ readonly kind: "boolean";
1166
+ readonly provenance: "mega";
1167
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1168
+ readonly decodedKind: "boolean";
1169
+ readonly description: "Restricted-area suggestions — UnisettingResponse.suggest_restricted (DP 176, Raw protobuf).";
1170
+ };
1171
+ /**
1172
+ * Extra corner passes while mopping. Slower runs, cleaner corners.
1173
+ */
1174
+ readonly deepMopCorner: {
1175
+ readonly readsFrom: "childLock";
1176
+ readonly type: "bool";
1177
+ readonly kind: "boolean";
1178
+ readonly provenance: "mega";
1179
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1180
+ readonly decodedKind: "boolean";
1181
+ readonly description: "Deep corner mopping — UnisettingResponse.deep_mop_corner_sw (DP 176, Raw protobuf).";
1182
+ };
1183
+ /**
1184
+ * How long the robot waits before warning that its dust bag is full, in MINUTES.
1185
+ *
1186
+ * `dust_full_remind` is a `Numerical`, not a `Switch`, and the two are the same two bytes on the
1187
+ * wire — `{ value = 1 }` either way — so reading it as a boolean reports a thirty-minute setting as
1188
+ * `true` with nothing to show anything went wrong. `0` means the reminder is off.
1189
+ */
1190
+ readonly dustFullRemindMinutes: {
1191
+ readonly readsFrom: "childLock";
1192
+ readonly type: "number";
1193
+ readonly unit: "min";
1194
+ readonly kind: "scalar";
1195
+ readonly provenance: "mega";
1196
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1197
+ readonly decodedKind: "scalar";
1198
+ readonly description: string;
1199
+ };
1200
+ /**
1201
+ * Whether the robot steers around pet mess rather than through it.
1202
+ */
1203
+ readonly poopAvoidance: {
1204
+ readonly readsFrom: "childLock";
1205
+ readonly type: "bool";
1206
+ readonly kind: "boolean";
1207
+ readonly provenance: "mega";
1208
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1209
+ readonly decodedKind: "boolean";
1210
+ readonly description: "Pet-mess avoidance — UnisettingResponse.poop_avoidance_sw (DP 176, Raw protobuf).";
1211
+ };
1212
+ /**
1213
+ * The pet-owner profile, which changes how the robot treats obstacles and how often it cleans.
1214
+ */
1215
+ readonly petMode: {
1216
+ readonly readsFrom: "childLock";
1217
+ readonly type: "bool";
1218
+ readonly kind: "boolean";
1219
+ readonly provenance: "mega";
1220
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1221
+ readonly decodedKind: "boolean";
1222
+ readonly description: "Pet mode — UnisettingResponse.pet_mode_sw (DP 176, Raw protobuf).";
1223
+ };
1224
+ /**
1225
+ * Whether the robot holds a map it can actually clean from — at least one with room outlines.
1226
+ *
1227
+ * The precondition for every area-select frame: a room or zone clean sent at a robot with no valid
1228
+ * map is a request it cannot honour, and this is the device's own answer rather than an inference
1229
+ * from whether a scene happens to name one.
1230
+ */
1231
+ readonly hasValidMap: {
1232
+ readonly readsFrom: "childLock";
1233
+ readonly type: "bool";
1234
+ readonly kind: "boolean";
1235
+ readonly provenance: "mega";
1236
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1237
+ readonly decodedKind: "boolean";
1238
+ readonly description: "Whether a usable map exists — UnisettingResponse.unistate.map_valid (DP 176, Raw protobuf).";
1239
+ };
1240
+ /**
1241
+ * Which layers the live map carries, as the vendor's own bitmask — see {@link LIVE_MAP_BITS}.
1242
+ *
1243
+ * A bitfield rather than an enum because the vendor says so outright: the values combine, and a map
1244
+ * with a base layer and room outlines reports both at once.
1245
+ */
1246
+ readonly mapLayers: {
1247
+ readonly readsFrom: "childLock";
1248
+ readonly type: "number";
1249
+ readonly kind: "bitfield";
1250
+ readonly provenance: "mega";
1251
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1252
+ readonly decodedKind: "bitfield";
1253
+ readonly description: "Live-map layers as a bitmask — UnisettingResponse.unistate.live_map.state_bits (DP 176, Raw protobuf).";
1254
+ };
1255
+ /**
1256
+ * The cleaning-strategy version the robot is running. A bare number the vendor gives no scale for —
1257
+ * diagnostic, and meaningful only against another reading of the same robot.
1258
+ */
1259
+ readonly cleanStrategyVersion: {
1260
+ readonly readsFrom: "childLock";
1261
+ readonly type: "number";
1262
+ readonly kind: "scalar";
1263
+ readonly provenance: "mega";
1264
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1265
+ readonly decodedKind: "scalar";
1266
+ readonly description: "Cleaning-strategy version — UnisettingResponse.unistate.clean_strategy_version (DP 176, Raw protobuf).";
1267
+ };
1268
+ /**
1269
+ * WiFi signal strength as a PERCENTAGE, 0-100 — the AIoT line's own reading.
1270
+ *
1271
+ * Distinct from `rssi`, which is the Tuya line's DP 134 in dBm and absent on this hardware. Reported
1272
+ * as the vendor states it: eufy-clean converts this to
1273
+ * a dBm-looking number with `(value / 2) - 100`, which is a plausible-looking figure with no basis in
1274
+ * anything the device sends.
1275
+ */
1276
+ readonly wifiSignal: {
1277
+ readonly readsFrom: "childLock";
1278
+ readonly type: "number";
1279
+ readonly unit: "%";
1280
+ readonly kind: "percent";
1281
+ readonly provenance: "mega";
1282
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1283
+ readonly decodedKind: "percent";
1284
+ readonly description: "WiFi signal strength 0-100% — UnisettingResponse.ap_signal_strength (DP 176, Raw protobuf).";
1285
+ };
1286
+ /**
1287
+ * Whether the robot captures stills while cleaning.
1288
+ */
1289
+ readonly livePhoto: {
1290
+ readonly readsFrom: "childLock";
1291
+ readonly type: "bool";
1292
+ readonly kind: "boolean";
1293
+ readonly provenance: "mega";
1294
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1295
+ readonly decodedKind: "boolean";
1296
+ readonly description: "Capture stills while cleaning — UnisettingResponse.live_photo_sw (DP 176, Raw protobuf).";
1297
+ };
1298
+ /**
1299
+ * Smart-follow mode. Numbered 13 in the response and 12 in the request — the widest gap in a message
1300
+ * whose two directions disagree about almost every field.
1301
+ */
1302
+ readonly smartFollow: {
1303
+ readonly readsFrom: "childLock";
1304
+ readonly type: "bool";
1305
+ readonly kind: "boolean";
1306
+ readonly provenance: "mega";
1307
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1308
+ readonly decodedKind: "boolean";
1309
+ readonly description: "Smart-follow mode — UnisettingResponse.smart_follow_sw (DP 176, Raw protobuf).";
1310
+ };
1311
+ /**
1312
+ * Hours run on the current side brush.
1313
+ *
1314
+ * The owner of DP 168 — the other eight counters read their own field out of this same payload, which
1315
+ * is why they declare `readsFrom` rather than a wire of their own. Hours USED, counting up: the
1316
+ * vendor sends no life expectancy, so a percentage remaining is a calibration rather than a number
1317
+ * this SDK can invent.
1318
+ */
1319
+ readonly sideBrushHours: {
1320
+ readonly param: 168;
1321
+ readonly type: "number";
1322
+ readonly unit: "h";
1323
+ readonly kind: "hours";
1324
+ readonly provenance: "mega";
1325
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1326
+ readonly decodedKind: "hours";
1327
+ readonly description: "Side-brush hours used — ConsumableRuntime.side_brush (DP 168 consumables, Raw protobuf).";
1328
+ readonly available: (ctx: AvailabilityContext) => boolean;
1329
+ };
1330
+ /**
1331
+ * Hours run on the current rolling brush.
1332
+ */
1333
+ readonly rollingBrushHours: {
1334
+ readonly readsFrom: "sideBrushHours";
1335
+ readonly type: "number";
1336
+ readonly unit: "h";
1337
+ readonly kind: "hours";
1338
+ readonly provenance: "mega";
1339
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1340
+ readonly decodedKind: "hours";
1341
+ readonly description: "Rolling-brush hours used — ConsumableRuntime.rolling_brush (DP 168, Raw protobuf).";
1342
+ };
1343
+ /**
1344
+ * Hours run on the current filter mesh.
1345
+ */
1346
+ readonly filterHours: {
1347
+ readonly readsFrom: "sideBrushHours";
1348
+ readonly type: "number";
1349
+ readonly unit: "h";
1350
+ readonly kind: "hours";
1351
+ readonly provenance: "mega";
1352
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1353
+ readonly decodedKind: "hours";
1354
+ readonly description: "Filter-mesh hours used — ConsumableRuntime.filter_mesh (DP 168, Raw protobuf).";
1355
+ };
1356
+ /**
1357
+ * Hours run on the current scraper.
1358
+ */
1359
+ readonly scraperHours: {
1360
+ readonly readsFrom: "sideBrushHours";
1361
+ readonly type: "number";
1362
+ readonly unit: "h";
1363
+ readonly kind: "hours";
1364
+ readonly provenance: "mega";
1365
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1366
+ readonly decodedKind: "hours";
1367
+ readonly description: "Scraper hours used — ConsumableRuntime.scrape (DP 168, Raw protobuf).";
1368
+ };
1369
+ /**
1370
+ * Hours since the sensors were last cleaned.
1371
+ */
1372
+ readonly sensorHours: {
1373
+ readonly readsFrom: "sideBrushHours";
1374
+ readonly type: "number";
1375
+ readonly unit: "h";
1376
+ readonly kind: "hours";
1377
+ readonly provenance: "mega";
1378
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1379
+ readonly decodedKind: "hours";
1380
+ readonly description: "Hours since the sensors were cleaned — ConsumableRuntime.sensor (DP 168, Raw protobuf).";
1381
+ };
1382
+ /**
1383
+ * Hours run on the current mop pad.
1384
+ */
1385
+ readonly mopHours: {
1386
+ readonly readsFrom: "sideBrushHours";
1387
+ readonly type: "number";
1388
+ readonly unit: "h";
1389
+ readonly kind: "hours";
1390
+ readonly provenance: "mega";
1391
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1392
+ readonly decodedKind: "hours";
1393
+ readonly description: "Mop-pad hours used — ConsumableRuntime.mop (DP 168, Raw protobuf).";
1394
+ };
1395
+ /**
1396
+ * Hours since the dust bag was last changed.
1397
+ */
1398
+ readonly dustBagHours: {
1399
+ readonly readsFrom: "sideBrushHours";
1400
+ readonly type: "number";
1401
+ readonly unit: "h";
1402
+ readonly kind: "hours";
1403
+ readonly provenance: "mega";
1404
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1405
+ readonly decodedKind: "hours";
1406
+ readonly description: "Dust-bag hours used — ConsumableRuntime.dustbag (DP 168, Raw protobuf).";
1407
+ };
1408
+ /**
1409
+ * Hours since the waste-water tank was last emptied. Field 10, not 8 — the vendor leaves 8 and 9
1410
+ * unused and closing that gap would read the wrong counter.
1411
+ */
1412
+ readonly dirtyWaterTankHours: {
1413
+ readonly readsFrom: "sideBrushHours";
1414
+ readonly type: "number";
1415
+ readonly unit: "h";
1416
+ readonly kind: "hours";
1417
+ readonly provenance: "mega";
1418
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1419
+ readonly decodedKind: "hours";
1420
+ readonly description: "Waste-water-tank hours — ConsumableRuntime.dirty_watertank (DP 168, Raw protobuf).";
1421
+ };
1422
+ /**
1423
+ * Hours run on the waste-water filter.
1424
+ */
1425
+ readonly dirtyWaterFilterHours: {
1426
+ readonly readsFrom: "sideBrushHours";
1427
+ readonly type: "number";
1428
+ readonly unit: "h";
1429
+ readonly kind: "hours";
1430
+ readonly provenance: "mega";
1431
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1432
+ readonly decodedKind: "hours";
1433
+ readonly description: "Waste-water-filter hours — ConsumableRuntime.dirty_waterfilter (DP 168, Raw protobuf).";
1434
+ };
1435
+ /**
1436
+ * Do-not-disturb — when on, the robot suppresses its voice announcements.
1437
+ *
1438
+ * Reports whether the feature is SWITCHED ON, not whether the quiet window happens to be open right
1439
+ * now; `UndisturbedResponse` carries that as a separate `active` flag which this deliberately skips.
1440
+ */
1441
+ readonly doNotDisturb: {
1442
+ readonly param: 157;
1443
+ readonly type: "bool";
1444
+ readonly kind: "boolean";
1445
+ readonly provenance: "mega";
1446
+ readonly readAliases: readonly [{
1447
+ readonly paramType: 107;
1448
+ readonly available: typeof isTuyaVacuum;
1449
+ }];
1450
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1451
+ readonly decodedKind: "boolean";
1452
+ readonly description: string;
1453
+ readonly available: (ctx: AvailabilityContext) => boolean;
1454
+ };
1455
+ /**
1456
+ * Whether the do-not-disturb window is open RIGHT NOW — the live flag, not the switch beside it.
1457
+ *
1458
+ * `doNotDisturb` answers whether the feature is switched on; this answers whether the quiet window is
1459
+ * in force. The two disagree for most of the day.
1460
+ *
1461
+ * Reads its sibling's payload rather than a wire of its own: `active` and `sw` are two fields of the
1462
+ * one `UndisturbedResponse` the device reports on DP 157, so there is one param and two readings of
1463
+ * it. AIoT only — the Tuya line's DP 107 carries the switch and says nothing about the window.
1464
+ */
1465
+ readonly doNotDisturbActive: {
1466
+ readonly readsFrom: "doNotDisturb";
1467
+ readonly type: "bool";
1468
+ readonly kind: "boolean";
1469
+ readonly provenance: "mega";
1470
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => boolean | undefined;
1471
+ readonly decodedKind: "boolean";
1472
+ readonly description: "Whether the do-not-disturb window is open now — Undisturbed.active (DP 157 AIoT, Raw protobuf).";
1473
+ readonly available: (ctx: AvailabilityContext) => boolean;
1474
+ };
1475
+ /**
1476
+ * When quiet hours start, as `"HH:MM"` on the robot's own clock.
1477
+ *
1478
+ * The window itself, which neither `doNotDisturb` (the switch) nor `doNotDisturbActive` (the live
1479
+ * flag) states. `undefined` means no window is configured; `"00:00"` is midnight and real.
1480
+ */
1481
+ readonly doNotDisturbStart: {
1482
+ readonly readsFrom: "doNotDisturb";
1483
+ readonly type: "string";
1484
+ readonly kind: "text";
1485
+ readonly provenance: "mega";
1486
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => string | undefined;
1487
+ readonly decodedKind: "text";
1488
+ readonly description: "Quiet hours start, HH:MM — Undisturbed.begin (DP 157 AIoT, Raw protobuf).";
1489
+ readonly available: (ctx: AvailabilityContext) => boolean;
1490
+ };
1491
+ /** When quiet hours end, as `"HH:MM"` on the robot's own clock. */
1492
+ readonly doNotDisturbEnd: {
1493
+ readonly readsFrom: "doNotDisturb";
1494
+ readonly type: "string";
1495
+ readonly kind: "text";
1496
+ readonly provenance: "mega";
1497
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => string | undefined;
1498
+ readonly decodedKind: "text";
1499
+ readonly description: "Quiet hours end, HH:MM — Undisturbed.end (DP 157 AIoT, Raw protobuf).";
1500
+ readonly available: (ctx: AvailabilityContext) => boolean;
1501
+ };
1502
+ /**
1503
+ * Whether the robot is taking a charge, and how that is going.
1504
+ *
1505
+ * `undefined` is the answer for a robot that is not charging: the vendor omits the whole `charging`
1506
+ * message rather than sending a "no" value, so absence IS the reading. `"fault"` is the vendor's
1507
+ * `ABNORMAL` — contacts touching but no charge flowing, which is the state a user needs told about
1508
+ * and which `activity` alone reports as a contented `"docked"`.
1509
+ */
1510
+ readonly chargeState: {
1511
+ readonly readsFrom: "activity";
1512
+ readonly type: "string";
1513
+ readonly provenance: "mega";
1514
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => "charged" | "charging" | "fault" | undefined;
1515
+ readonly decodedKind: "enum";
1516
+ readonly decodedValues: readonly string[];
1517
+ readonly description: "Charge state — WorkStatus.charging (DP 153, Raw protobuf). Absent while not charging.";
1518
+ readonly available: (ctx: AvailabilityContext) => boolean;
1519
+ };
1520
+ /**
1521
+ * What put the robot in the state it is in — an app, the button on its lid, a schedule, its own
1522
+ * judgement, or the remote.
1523
+ *
1524
+ * The difference between "it went home" and "it went home because the battery ran low", which the
1525
+ * activity alone cannot express. `"unknown"` is the vendor's own zero and what a robot reports just
1526
+ * after boot, so it is an answer rather than a gap.
1527
+ */
1528
+ readonly triggerSource: {
1529
+ readonly readsFrom: "activity";
1530
+ readonly type: "string";
1531
+ readonly provenance: "mega";
1532
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => "app" | "button" | "remote" | "robot" | "schedule" | "unknown" | undefined;
1533
+ readonly decodedKind: "enum";
1534
+ readonly decodedValues: readonly string[];
1535
+ readonly description: "What caused the current state — WorkStatus.trigger.source (DP 153, Raw protobuf).";
1536
+ readonly available: (ctx: AvailabilityContext) => boolean;
1537
+ };
1538
+ /**
1539
+ * How many schedules the robot holds — the owner of DP 164.
1540
+ *
1541
+ * The device reports its timers in full on every change, so a count is a real reading of that report
1542
+ * rather than a summary of one: zero means no schedules are set, and `undefined` means this robot has
1543
+ * not reported the DP at all. The schedules themselves are a list, which no property can be, so they
1544
+ * are read through {@link VACUUM_CLEAN_MEMBERS.schedules} beside this.
1545
+ */
1546
+ readonly scheduleCount: {
1547
+ readonly param: 164;
1548
+ readonly type: "number";
1549
+ readonly kind: "scalar";
1550
+ readonly provenance: "mega";
1551
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1552
+ readonly decodedKind: "scalar";
1553
+ readonly description: "How many schedules the robot holds — TimerResponse.timers (DP 164, Raw protobuf).";
1554
+ readonly available: (ctx: AvailabilityContext) => boolean;
1555
+ };
1556
+ /**
1557
+ * How many of those schedules will actually fire — switched on, and still pointing at something that
1558
+ * exists.
1559
+ *
1560
+ * A timer whose scene or map was deleted is kept and reported `valid: false` rather than removed, so
1561
+ * "three schedules" and "three schedules that work" are genuinely different numbers.
1562
+ */
1563
+ readonly activeScheduleCount: {
1564
+ readonly readsFrom: "scheduleCount";
1565
+ readonly type: "number";
1566
+ readonly kind: "scalar";
1567
+ readonly provenance: "mega";
1568
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1569
+ readonly decodedKind: "scalar";
1570
+ readonly description: "How many schedules are on and usable — TimerInfo.status (DP 164, Raw protobuf).";
1571
+ };
1572
+ /**
1573
+ * The schedules themselves, decoded from the same DP 164 report the two counts above read.
1574
+ *
1575
+ * A query rather than a property: its value is a list, and the property schema holds scalars. It
1576
+ * answers from state already received — the robot pushes its whole timer list on boot and after any
1577
+ * change — so this sends nothing and cannot fail against a device that is merely asleep.
1578
+ */
1579
+ readonly schedules: {
1580
+ readonly method: (deps: import("./members.js").MemberDeps) => () => readonly VacuumSchedule[] | undefined;
1581
+ readonly description: string;
1582
+ readonly available: ((ctx: import("./types.js").CommandContext) => boolean) & ((ctx: import("./types.js").CommandContext) => boolean);
1583
+ readonly args?: readonly import("./types.js").ActionArgSpec[];
1584
+ readonly answers: true;
1585
+ };
1586
+ /**
1587
+ * How many cleaning scenes the robot holds — the owner of DP 180.
1588
+ *
1589
+ * A scene is a saved routine over rooms or zones. The robot reports the LIST here; the tasks inside
1590
+ * a scene are only ever sent to it, never reported back, so this counts what the device publishes.
1591
+ */
1592
+ readonly sceneCount: {
1593
+ readonly param: 180;
1594
+ readonly type: "number";
1595
+ readonly kind: "scalar";
1596
+ readonly provenance: "mega";
1597
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1598
+ readonly decodedKind: "scalar";
1599
+ readonly description: "How many cleaning scenes the robot holds — SceneResponse.infos (DP 180, Raw protobuf).";
1600
+ readonly available: (ctx: AvailabilityContext) => boolean;
1601
+ };
1602
+ /**
1603
+ * How many of those scenes can still run. A scene whose map was deleted or no longer matches is kept
1604
+ * and reported invalid rather than removed, so the two counts differ for a real reason — and
1605
+ * `scenes()` says which reason, per scene.
1606
+ */
1607
+ readonly usableSceneCount: {
1608
+ readonly readsFrom: "sceneCount";
1609
+ readonly type: "number";
1610
+ readonly kind: "scalar";
1611
+ readonly provenance: "mega";
1612
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1613
+ readonly decodedKind: "scalar";
1614
+ readonly description: "How many scenes can still run — SceneInfo.valid (DP 180, Raw protobuf).";
1615
+ };
1616
+ /**
1617
+ * The scenes themselves, decoded from the same DP 180 report the two counts read.
1618
+ *
1619
+ * Answers from state already received, like `schedules` — the robot pushes its whole scene list on
1620
+ * boot and after any change, so this sends nothing.
1621
+ *
1622
+ * **Where a real map id comes from.** Each scene names the map its rooms belong to, and so does a
1623
+ * scheduled rooms-clean. Not from multi-map management on DP 172: the vendor's own `multi_maps.proto`
1624
+ * sends a map list over p2p rather than the data point.
1625
+ */
1626
+ readonly scenes: {
1627
+ readonly method: (deps: import("./members.js").MemberDeps) => () => readonly VacuumScene[] | undefined;
1628
+ readonly description: string;
1629
+ readonly available: ((ctx: import("./types.js").CommandContext) => boolean) & ((ctx: import("./types.js").CommandContext) => boolean);
1630
+ readonly args?: readonly import("./types.js").ActionArgSpec[];
1631
+ readonly answers: true;
1632
+ };
1633
+ /**
1634
+ * The network name the robot is joined to — `DeviceInfo.wifi_name` (DP 169).
1635
+ *
1636
+ * Reads a payload the DOCK capability owns. `DeviceInfo` is one message carrying the robot's network
1637
+ * facts beside the dock's firmware version, and the one-owner rule is per product line, so DP 169 has
1638
+ * a single owner — `vacuumDock().dockFirmwareVersion` — and these four members borrow it by name.
1639
+ * Putting them on the dock object instead would have filed the robot's IP under the wrong thing.
1640
+ *
1641
+ * Reported when the robot comes online and again when its IP changes, so it is as current as the last
1642
+ * such report and absent on a robot that has not reconnected since binding.
1643
+ */
1644
+ readonly wifiSsid: {
1645
+ readonly readsFrom: {
1646
+ readonly property: "dockFirmwareVersion";
1647
+ readonly param: 169;
1648
+ };
1649
+ readonly type: "string";
1650
+ readonly kind: "text";
1651
+ readonly provenance: "mega";
1652
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => string | undefined;
1653
+ readonly decodedKind: "text";
1654
+ readonly description: "The WiFi network the robot is on — DeviceInfo.wifi_name (DP 169, Raw protobuf).";
1655
+ };
1656
+ /** The robot's address on that network — `DeviceInfo.wifi_ip` (DP 169). */
1657
+ readonly wifiIp: {
1658
+ readonly readsFrom: {
1659
+ readonly property: "dockFirmwareVersion";
1660
+ readonly param: 169;
1661
+ };
1662
+ readonly type: "string";
1663
+ readonly kind: "text";
1664
+ readonly provenance: "mega";
1665
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => string | undefined;
1666
+ readonly decodedKind: "text";
1667
+ readonly description: "The robot's IP on its WiFi network — DeviceInfo.wifi_ip (DP 169, Raw protobuf).";
1668
+ };
1669
+ /** The robot's MAC address — `DeviceInfo.device_mac` (DP 169). */
1670
+ readonly macAddress: {
1671
+ readonly readsFrom: {
1672
+ readonly property: "dockFirmwareVersion";
1673
+ readonly param: 169;
1674
+ };
1675
+ readonly type: "string";
1676
+ readonly kind: "identifier";
1677
+ readonly provenance: "mega";
1678
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => string | undefined;
1679
+ readonly decodedKind: "identifier";
1680
+ readonly description: "The robot's MAC address — DeviceInfo.device_mac (DP 169, Raw protobuf).";
1681
+ };
1682
+ /**
1683
+ * The robot's hardware revision — `DeviceInfo.hardware` (DP 169). A bare integer the vendor gives no
1684
+ * scale for; it distinguishes two builds of one model, not one model from another.
1685
+ */
1686
+ readonly hardwareVersion: {
1687
+ readonly readsFrom: {
1688
+ readonly property: "dockFirmwareVersion";
1689
+ readonly param: 169;
1690
+ };
1691
+ readonly type: "number";
1692
+ readonly kind: "scalar";
1693
+ readonly provenance: "mega";
1694
+ readonly decode: (raw: unknown, codec: RawDpCodec | undefined) => number | undefined;
1695
+ readonly decodedKind: "scalar";
1696
+ readonly description: "The robot's hardware revision — DeviceInfo.hardware (DP 169, Raw protobuf).";
1697
+ };
1698
+ /**
1699
+ * WiFi RSSI in dBm (DP 134, Value ro). Schema-confirmed from `thing.m.device.ref.info.list` v5.4.
1700
+ * Negative integer; closer to zero is stronger.
1701
+ */
1702
+ readonly rssi: {
1703
+ readonly param: 134;
1704
+ readonly type: "number";
1705
+ readonly unit: "dBm";
1706
+ readonly kind: "dbm";
1707
+ readonly provenance: "mega";
1708
+ readonly description: "WiFi RSSI in dBm (DP 134, Value ro). Schema-confirmed.";
1709
+ readonly available: (ctx: AvailabilityContext) => boolean;
1710
+ };
1711
+ /**
1712
+ * The ModeCtrl verbs whose METHOD NUMBER is not yet captured.
1713
+ *
1714
+ * Each shares its frame with the three verified verbs above — same message, same two fields, same
1715
+ * encoder — so what is unconfirmed is the number alone. That still keeps them `unverified`: a wrong
1716
+ * number is a different command arriving at real hardware, and an AIoT DP write is fire-and-forget,
1717
+ * so a mistake looks exactly like success. They are declared so the capability documents what the
1718
+ * robot accepts, and one capture per verb is all that stands between them and a working setter.
1719
+ */
1720
+ /**
1721
+ * Tell the robot a replaceable part is new, clearing its hours.
1722
+ *
1723
+ * The other half of the consumables feature: nine counters are read, and this is the write that
1724
+ * clears one.
1725
+ *
1726
+ * **Unverified, so no setter is installed.** The message, the field and the enum are the vendor's
1727
+ * own, and the app has the feature — `resetAccessory(deviceId, accessory, callback)` calling
1728
+ * through to `resetAccessories`, taking exactly this kind of integer part id. What is missing is a
1729
+ * capture showing the frame accepted, and an AIoT DP write is fire-and-forget, so a wrong one would
1730
+ * look like success while quietly discarding service history the device never recomputes.
1731
+ */
1732
+ readonly resetConsumable: {
1733
+ readonly type: "string";
1734
+ readonly kind: "enum";
1735
+ readonly enumValues: {
1736
+ [k: string]: "dirtyWaterFilter" | "dirtyWaterTank" | "dustBag" | "filter" | "mop" | "rollingBrush" | "scraper" | "sensors" | "sideBrush";
1737
+ };
1738
+ readonly writeOnly: true;
1739
+ readonly unverified: true;
1740
+ readonly write: (value: string | number | boolean) => import("../../core/contracts.js").Command;
1741
+ readonly available: (ctx: AvailabilityContext) => boolean;
1742
+ readonly provenance: "mega";
1743
+ readonly description: string;
1744
+ };
1745
+ /**
1746
+ * End the current job outright, as opposed to {@link VACUUM_CLEAN_MEMBERS.pauseCleaning}, which
1747
+ * leaves it resumable.
1748
+ */
1749
+ readonly stopCleaning: {
1750
+ readonly type: "bool";
1751
+ readonly kind: "boolean";
1752
+ readonly writeOnly: true;
1753
+ readonly unverified: true;
1754
+ readonly write: () => import("../../core/contracts.js").Command;
1755
+ readonly available: (ctx: AvailabilityContext) => boolean;
1756
+ readonly provenance: "mega";
1757
+ readonly description: "Stop the current job (ModeCtrlRequest method 12 over DP 152). Method number not captured — unverified.";
1758
+ };
1759
+ /**
1760
+ * Carry on with a paused job rather than starting a new one — the counterpart to
1761
+ * {@link VACUUM_CLEAN_MEMBERS.pauseCleaning}.
1762
+ */
1763
+ readonly resumeCleaning: import("./members.js").MethodMember<() => Promise<void>> & {
1764
+ available: (ctx: import("./types.js").CommandContext) => boolean;
1765
+ };
1766
+ /**
1767
+ * Send the robot to the dock to wash its mops. Distinct from the dock's own `washMops`, which asks
1768
+ * the STATION to run its cycle: this one moves the robot there first.
1769
+ */
1770
+ readonly startWashingMops: {
1771
+ readonly type: "bool";
1772
+ readonly kind: "boolean";
1773
+ readonly writeOnly: true;
1774
+ readonly unverified: true;
1775
+ readonly write: () => import("../../core/contracts.js").Command;
1776
+ readonly available: (ctx: AvailabilityContext) => boolean;
1777
+ readonly provenance: "mega";
1778
+ readonly description: "Go and wash the mops (ModeCtrlRequest method 10 over DP 152). Method number not captured — unverified.";
1779
+ };
1780
+ /**
1781
+ * Call off a mop-wash trip in progress.
1782
+ */
1783
+ readonly stopWashingMops: {
1784
+ readonly type: "bool";
1785
+ readonly kind: "boolean";
1786
+ readonly writeOnly: true;
1787
+ readonly unverified: true;
1788
+ readonly write: () => import("../../core/contracts.js").Command;
1789
+ readonly available: (ctx: AvailabilityContext) => boolean;
1790
+ readonly provenance: "mega";
1791
+ readonly description: "Stop washing the mops (ModeCtrlRequest method 17 over DP 152). Method number not captured — unverified.";
1792
+ };
1793
+ /**
1794
+ * Call off a return-to-dock in progress, leaving the robot where it is.
1795
+ */
1796
+ readonly stopReturnToDock: {
1797
+ readonly type: "bool";
1798
+ readonly kind: "boolean";
1799
+ readonly writeOnly: true;
1800
+ readonly unverified: true;
1801
+ readonly write: () => import("../../core/contracts.js").Command;
1802
+ readonly available: (ctx: AvailabilityContext) => boolean;
1803
+ readonly provenance: "mega";
1804
+ readonly description: "Stop returning to the dock (ModeCtrlRequest method 15 over DP 152). Method number not captured — unverified.";
1805
+ };
1806
+ /**
1807
+ * Clean the robot's immediate surroundings. Takes no target — the spot is wherever it is standing,
1808
+ * which is why this one needs no `Param` and its area-selecting cousins do.
1809
+ */
1810
+ readonly startSpotClean: {
1811
+ readonly type: "bool";
1812
+ readonly kind: "boolean";
1813
+ readonly writeOnly: true;
1814
+ readonly unverified: true;
1815
+ readonly write: () => import("../../core/contracts.js").Command;
1816
+ readonly available: (ctx: AvailabilityContext) => boolean;
1817
+ readonly provenance: "mega";
1818
+ readonly description: "Spot-clean where the robot stands (ModeCtrlRequest method 3 over DP 152). Method number not captured — unverified.";
1819
+ };
1820
+ /**
1821
+ * Run a fast mapping pass without cleaning — how a robot learns a floor it has not seen.
1822
+ */
1823
+ readonly startMapping: {
1824
+ readonly type: "bool";
1825
+ readonly kind: "boolean";
1826
+ readonly writeOnly: true;
1827
+ readonly unverified: true;
1828
+ readonly write: () => import("../../core/contracts.js").Command;
1829
+ readonly available: (ctx: AvailabilityContext) => boolean;
1830
+ readonly provenance: "mega";
1831
+ readonly description: "Run a fast mapping pass (ModeCtrlRequest method 9 over DP 152). Method number not captured — unverified.";
1832
+ };
1833
+ /**
1834
+ * Patrol the whole map without cleaning — the camera-equipped models use this to look around.
1835
+ */
1836
+ readonly startCruise: {
1837
+ readonly type: "bool";
1838
+ readonly kind: "boolean";
1839
+ readonly writeOnly: true;
1840
+ readonly unverified: true;
1841
+ readonly write: () => import("../../core/contracts.js").Command;
1842
+ readonly available: (ctx: AvailabilityContext) => boolean;
1843
+ readonly provenance: "mega";
1844
+ readonly description: "Start a global cruise (ModeCtrlRequest method 20 over DP 152). Method number not captured — unverified.";
1845
+ };
1846
+ /**
1847
+ * Enter remote-control cleaning, where the app drives. The SDK offers no steering wire, so this is
1848
+ * only half a feature until one exists — declared for completeness of the vocabulary.
1849
+ */
1850
+ readonly startRemoteControl: {
1851
+ readonly type: "bool";
1852
+ readonly kind: "boolean";
1853
+ readonly writeOnly: true;
1854
+ readonly unverified: true;
1855
+ readonly write: () => import("../../core/contracts.js").Command;
1856
+ readonly available: (ctx: AvailabilityContext) => boolean;
1857
+ readonly provenance: "mega";
1858
+ readonly description: "Enter remote-control cleaning (ModeCtrlRequest method 5 over DP 152). Method number not captured — unverified.";
1859
+ };
1860
+ /**
1861
+ * Leave remote-control mode.
1862
+ *
1863
+ * **Uses `STOP_TASK`, not `STOP_RC_CLEAN`.** The product catalogue's own note on DP 155 spells the
1864
+ * flow out: enter with `START_RC_CLEAN` or any direction, leave with
1865
+ * `ModeCtrlRequest.method.STOP_TASK`. `STOP_RC_CLEAN`(16) exists in the enum but is not what the app
1866
+ * sends to exit.
1867
+ */
1868
+ readonly stopRemoteControl: {
1869
+ readonly type: "bool";
1870
+ readonly kind: "boolean";
1871
+ readonly writeOnly: true;
1872
+ readonly unverified: true;
1873
+ readonly write: () => import("../../core/contracts.js").Command;
1874
+ readonly available: (ctx: AvailabilityContext) => boolean;
1875
+ readonly provenance: "mega";
1876
+ readonly description: string;
1877
+ };
1878
+ /**
1879
+ * Steer the robot while it is in remote-control mode — DP 155, an enum of directions rather than a
1880
+ * `ModeCtrlRequest`.
1881
+ *
1882
+ * `brake` stops the current movement without leaving remote-control mode; the catalogue's note says
1883
+ * the app sends it on key-release. Leaving the mode entirely is
1884
+ * {@link VACUUM_CLEAN_MEMBERS.stopRemoteControl}.
1885
+ *
1886
+ * Sending any direction also ENTERS remote control, so no separate start is needed.
1887
+ */
1888
+ readonly remoteControlDirection: {
1889
+ readonly param: 155;
1890
+ readonly type: "string";
1891
+ readonly kind: "enum";
1892
+ readonly writeOnly: true;
1893
+ readonly unverified: true;
1894
+ readonly enumValues: {
1895
+ readonly 0: "Brake";
1896
+ readonly 1: "Forward";
1897
+ readonly 2: "Back";
1898
+ readonly 3: "Left";
1899
+ readonly 4: "Right";
1900
+ };
1901
+ readonly write: (v: string | number | boolean) => import("../../core/contracts.js").Command;
1902
+ readonly available: (ctx: AvailabilityContext) => boolean;
1903
+ readonly provenance: "mega";
1904
+ readonly description: string;
1905
+ };
1906
+ /**
1907
+ * Whether the robot resumes an interrupted job after charging, rather than treating the next start
1908
+ * as a fresh run. The vendor calls this 断点续扫 — "resume from the break point".
1909
+ */
1910
+ readonly resumeClean: {
1911
+ readonly param: 156;
1912
+ readonly type: "bool";
1913
+ readonly kind: "boolean";
1914
+ readonly provenance: "mega";
1915
+ readonly description: "Resume an interrupted job after charging (DP 156 pause_job, Bool).";
1916
+ readonly available: (ctx: AvailabilityContext) => boolean;
1917
+ };
1918
+ /**
1919
+ * Stop smart-follow mode. There is no start verb in the vendor's parameterless set — the mode is
1920
+ * switched on through `smartFollow` in the DP 176 settings, and only stopped from here.
1921
+ */
1922
+ readonly stopSmartFollow: {
1923
+ readonly type: "bool";
1924
+ readonly kind: "boolean";
1925
+ readonly writeOnly: true;
1926
+ readonly unverified: true;
1927
+ readonly write: () => import("../../core/contracts.js").Command;
1928
+ readonly available: (ctx: AvailabilityContext) => boolean;
1929
+ readonly provenance: "mega";
1930
+ readonly description: "Stop smart-follow mode (ModeCtrlRequest method 18 over DP 152). Method number not captured — unverified.";
1931
+ };
1932
+ /** Start an auto-clean run via ModeCtrlRequest method 0 (DP 152). AIoT only — Tuya write unverified. */
1933
+ readonly startCleaning: import("./members.js").MethodMember<() => Promise<void>> & {
1934
+ available: (ctx: import("./types.js").CommandContext) => boolean;
1935
+ };
1936
+ /** Return to the dock via ModeCtrlRequest method 6 (DP 152). AIoT only — Tuya write unverified. */
1937
+ readonly returnToDock: import("./members.js").MethodMember<() => Promise<void>> & {
1938
+ available: (ctx: import("./types.js").CommandContext) => boolean;
1939
+ };
1940
+ /** Pause the current cleaning task via ModeCtrlRequest method 13 (DP 152). AIoT only — Tuya write unverified. */
1941
+ readonly pauseCleaning: import("./members.js").MethodMember<() => Promise<void>> & {
1942
+ available: (ctx: import("./types.js").CommandContext) => boolean;
1943
+ };
1944
+ };
1945
+ /** `vacuum_clean` — core RoboVac scalar state + decoded activity: power, activity, volume, battery. */
1946
+ export declare const VACUUM_CLEAN: CapabilityModule;