@apocaliss92/nodedreame 1.11.5 → 1.11.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +209 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -1
- package/dist/index.d.ts +53 -1
- package/dist/index.js +207 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -75,8 +75,10 @@ __export(index_exports, {
|
|
|
75
75
|
getVacuumCapabilities: () => getVacuumCapabilities,
|
|
76
76
|
isDreameConsumableKey: () => isDreameConsumableKey,
|
|
77
77
|
mowerConsumableIndex: () => mowerConsumableIndex,
|
|
78
|
+
mowerFaultSeverity: () => mowerFaultSeverity,
|
|
78
79
|
parseMowerConsumables: () => parseMowerConsumables,
|
|
79
80
|
parseMowerHeartbeat: () => parseMowerHeartbeat,
|
|
81
|
+
parseMowingProgress: () => parseMowingProgress,
|
|
80
82
|
renderMowerSvg: () => renderMowerSvg,
|
|
81
83
|
renderVacuumPng: () => renderVacuumPng,
|
|
82
84
|
resolveCapabilities: () => resolveCapabilities,
|
|
@@ -86,7 +88,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
86
88
|
|
|
87
89
|
// src/support/version.ts
|
|
88
90
|
var LIBRARY_NAME = "nodedreame";
|
|
89
|
-
var LIBRARY_VERSION = "1.11.
|
|
91
|
+
var LIBRARY_VERSION = "1.11.9";
|
|
90
92
|
|
|
91
93
|
// src/transport/errors.ts
|
|
92
94
|
var DreameError = class extends Error {
|
|
@@ -385,6 +387,11 @@ var CachedPropsResponseSchema = import_zod.z.object({
|
|
|
385
387
|
msg: import_zod.z.string().nullish(),
|
|
386
388
|
data: import_zod.z.array(CachedPropEntrySchema).optional()
|
|
387
389
|
}).passthrough();
|
|
390
|
+
var BatchDeviceDataResponseSchema = import_zod.z.object({
|
|
391
|
+
code: import_zod.z.number().optional(),
|
|
392
|
+
msg: import_zod.z.string().nullish(),
|
|
393
|
+
data: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
394
|
+
}).passthrough();
|
|
388
395
|
var SendCommandResponseSchema = import_zod.z.object({
|
|
389
396
|
code: import_zod.z.number().optional(),
|
|
390
397
|
msg: import_zod.z.string().nullish(),
|
|
@@ -645,6 +652,29 @@ async function callAction(base, action, opts = {}) {
|
|
|
645
652
|
const res = await sendCommand({ ...base, ...opts, method: "action", params });
|
|
646
653
|
return res.data?.result ?? res.result ?? res;
|
|
647
654
|
}
|
|
655
|
+
async function getBatchDeviceDatas(base, props, opts = {}) {
|
|
656
|
+
const ctx = base.ctx ?? RequestContext.from({ ...base, host: base.apiHost });
|
|
657
|
+
const signal = opts.signal ?? base.signal;
|
|
658
|
+
const timeoutMs = opts.timeoutMs ?? base.timeoutMs;
|
|
659
|
+
const raw = await httpPostJsonBody({
|
|
660
|
+
ctx,
|
|
661
|
+
path: "/dreame-user-iot/iotuserdata/getDeviceData",
|
|
662
|
+
accessToken: base.session.accessToken,
|
|
663
|
+
body: { did: base.did, model: props },
|
|
664
|
+
context: "batch device data",
|
|
665
|
+
...signal !== void 0 ? { signal } : {},
|
|
666
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
667
|
+
});
|
|
668
|
+
const parsed = BatchDeviceDataResponseSchema.parse(raw);
|
|
669
|
+
if (parsed.code !== void 0 && parsed.code !== 0) {
|
|
670
|
+
throw new DreameApiError(
|
|
671
|
+
`batch device data rejected: code=${parsed.code} msg=${parsed.msg ?? "?"}`,
|
|
672
|
+
200,
|
|
673
|
+
parsed
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
return parsed.data ?? {};
|
|
677
|
+
}
|
|
648
678
|
function extractResultArray(res, context) {
|
|
649
679
|
const raw = Array.isArray(res.data?.result) ? res.data.result : Array.isArray(res.result) ? res.result : null;
|
|
650
680
|
if (raw === null) {
|
|
@@ -2149,6 +2179,43 @@ function parseFrame(inflated) {
|
|
|
2149
2179
|
return { header, tail };
|
|
2150
2180
|
}
|
|
2151
2181
|
|
|
2182
|
+
// src/models/vacuum/map/segment-types.ts
|
|
2183
|
+
var SEGMENT_TYPE_CODE_TO_NAME = {
|
|
2184
|
+
0: "Room",
|
|
2185
|
+
1: "Living Room",
|
|
2186
|
+
2: "Primary Bedroom",
|
|
2187
|
+
3: "Study",
|
|
2188
|
+
4: "Kitchen",
|
|
2189
|
+
5: "Dining Hall",
|
|
2190
|
+
6: "Bathroom",
|
|
2191
|
+
7: "Balcony",
|
|
2192
|
+
8: "Corridor",
|
|
2193
|
+
9: "Utility Room",
|
|
2194
|
+
10: "Closet",
|
|
2195
|
+
11: "Meeting Room",
|
|
2196
|
+
12: "Office",
|
|
2197
|
+
13: "Fitness Area",
|
|
2198
|
+
14: "Recreation Area",
|
|
2199
|
+
15: "Secondary Bedroom"
|
|
2200
|
+
};
|
|
2201
|
+
function safeBase64ToUtf8(s) {
|
|
2202
|
+
try {
|
|
2203
|
+
return Buffer.from(s, "base64").toString("utf8");
|
|
2204
|
+
} catch {
|
|
2205
|
+
return null;
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
function resolveSegmentName(type, index, customName) {
|
|
2209
|
+
if (type !== void 0 && type !== 0 && SEGMENT_TYPE_CODE_TO_NAME[type] !== void 0) {
|
|
2210
|
+
const base = SEGMENT_TYPE_CODE_TO_NAME[type];
|
|
2211
|
+
return index !== void 0 && index > 0 ? `${base} ${index + 1}` : base;
|
|
2212
|
+
}
|
|
2213
|
+
if (typeof customName === "string" && customName.length > 0) {
|
|
2214
|
+
return safeBase64ToUtf8(customName);
|
|
2215
|
+
}
|
|
2216
|
+
return null;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2152
2219
|
// src/models/vacuum/map/pixel-grid.ts
|
|
2153
2220
|
function classifyPixelFsm1(byte) {
|
|
2154
2221
|
if (byte === 0) {
|
|
@@ -2294,7 +2361,9 @@ function collectSegments(layers, dim, tail) {
|
|
|
2294
2361
|
};
|
|
2295
2362
|
segs.push({
|
|
2296
2363
|
id,
|
|
2297
|
-
|
|
2364
|
+
// Mirror the donor: a room-type code (≠0) yields a localized default name
|
|
2365
|
+
// (e.g. "Kitchen"), else the user's custom base64 name, else null.
|
|
2366
|
+
name: resolveSegmentName(meta?.type, meta?.index, meta?.name),
|
|
2298
2367
|
bbox,
|
|
2299
2368
|
centroid,
|
|
2300
2369
|
neighbours: meta?.nei_id ?? [],
|
|
@@ -2305,13 +2374,6 @@ function collectSegments(layers, dim, tail) {
|
|
|
2305
2374
|
}
|
|
2306
2375
|
return segs;
|
|
2307
2376
|
}
|
|
2308
|
-
function safeBase64ToUtf8(s) {
|
|
2309
|
-
try {
|
|
2310
|
-
return Buffer.from(s, "base64").toString("utf8");
|
|
2311
|
-
} catch {
|
|
2312
|
-
return null;
|
|
2313
|
-
}
|
|
2314
|
-
}
|
|
2315
2377
|
|
|
2316
2378
|
// src/models/vacuum/map/path.ts
|
|
2317
2379
|
var PATH_TYPE_FROM_OP = {
|
|
@@ -2857,18 +2919,27 @@ function decodeVacuumMap(input, opts = {}) {
|
|
|
2857
2919
|
const pixelGrid = inflated.subarray(pixelStart, pixelEnd);
|
|
2858
2920
|
const canDecodePixels = header.frameType === "I" && pixelGrid.length === header.width * header.height;
|
|
2859
2921
|
const layers = canDecodePixels ? decodePixelGridFsm1(pixelGrid, header.width, header.height) : [];
|
|
2860
|
-
const segments = canDecodePixels ? collectSegments(layers, dimensions, tail) : [];
|
|
2861
2922
|
const paths = parsePathTr(tail.tr ?? "");
|
|
2862
2923
|
const obstacles = parseObstacles(tail.ai_obstacle ?? []);
|
|
2863
2924
|
let geometry = parseTailGeometry(tail);
|
|
2864
|
-
|
|
2925
|
+
let segTail = tail;
|
|
2926
|
+
const outerHasNames = Object.values(tail.seg_inf ?? {}).some(
|
|
2927
|
+
(m) => typeof m?.name === "string" && m.name.length > 0
|
|
2928
|
+
);
|
|
2929
|
+
if ((!isGeometryComplete(geometry) || !outerHasNames) && typeof tail.rism === "string" && tail.rism.length > 0) {
|
|
2865
2930
|
try {
|
|
2866
2931
|
const innerInflated = unwrapEnvelope(tail.rism);
|
|
2867
2932
|
const { tail: innerTail } = parseFrame(innerInflated);
|
|
2868
|
-
|
|
2933
|
+
if (!isGeometryComplete(geometry)) {
|
|
2934
|
+
geometry = coalesceGeometry(geometry, parseTailGeometry(innerTail));
|
|
2935
|
+
}
|
|
2936
|
+
if (!outerHasNames && innerTail.seg_inf) {
|
|
2937
|
+
segTail = mergeSegInfNames(tail, innerTail.seg_inf);
|
|
2938
|
+
}
|
|
2869
2939
|
} catch {
|
|
2870
2940
|
}
|
|
2871
2941
|
}
|
|
2942
|
+
const segments = canDecodePixels ? collectSegments(layers, dimensions, segTail) : [];
|
|
2872
2943
|
const cleanedArea = typeof tail.decmap === "string" ? parseCleanedAreaOverlay(tail.decmap) : null;
|
|
2873
2944
|
return {
|
|
2874
2945
|
mapId: header.mapId,
|
|
@@ -2892,6 +2963,18 @@ function applyVacuumPFrame(prev, pframe, opts = {}) {
|
|
|
2892
2963
|
const merged = typeof prev === "string" || typeof pframe === "string" ? mergePFrameEnvelope(prev, pframe, opts.prev, opts.pframe) : mergePFrame(prev, pframe);
|
|
2893
2964
|
return { buffer: merged, data: decodeVacuumMap(merged) };
|
|
2894
2965
|
}
|
|
2966
|
+
function mergeSegInfNames(tail, innerSegInf) {
|
|
2967
|
+
const outer = tail.seg_inf ?? {};
|
|
2968
|
+
const ids = /* @__PURE__ */ new Set([...Object.keys(outer), ...Object.keys(innerSegInf)]);
|
|
2969
|
+
const merged = {};
|
|
2970
|
+
for (const id of ids) {
|
|
2971
|
+
const o = outer[id] ?? {};
|
|
2972
|
+
const inner = innerSegInf[id] ?? {};
|
|
2973
|
+
const name = typeof o.name === "string" && o.name.length > 0 ? o.name : inner.name;
|
|
2974
|
+
merged[id] = { ...inner, ...o, ...name !== void 0 ? { name } : {} };
|
|
2975
|
+
}
|
|
2976
|
+
return { ...tail, seg_inf: merged };
|
|
2977
|
+
}
|
|
2895
2978
|
function mergeDimensions(header, tail) {
|
|
2896
2979
|
const left = tail.origin?.[0] ?? header.left;
|
|
2897
2980
|
const top = tail.origin?.[1] ?? header.top;
|
|
@@ -3052,8 +3135,12 @@ function renderVacuumPng(map, opts = {}) {
|
|
|
3052
3135
|
const byType = opts.colorObstaclesByType !== false;
|
|
3053
3136
|
for (const ob of map.obstacles) {
|
|
3054
3137
|
const p = worldToPx(ob.x, ob.y, dim, scale);
|
|
3055
|
-
const
|
|
3056
|
-
|
|
3138
|
+
const r = Math.max(2, scale * 2);
|
|
3139
|
+
if (byType) {
|
|
3140
|
+
drawObstacleShape(png, p.x, p.y, r, ob.type, obstacleColor(ob.type));
|
|
3141
|
+
} else {
|
|
3142
|
+
drawDiamond(png, p.x, p.y, r, pal.obstacle);
|
|
3143
|
+
}
|
|
3057
3144
|
}
|
|
3058
3145
|
}
|
|
3059
3146
|
if (opts.showCharger !== false && map.dock !== null) {
|
|
@@ -3214,6 +3301,32 @@ function obstacleColor(type) {
|
|
|
3214
3301
|
const hue = Math.abs(Math.trunc(type)) * 47 % 360;
|
|
3215
3302
|
return hsvToRgba(hue, 0.85, 0.95);
|
|
3216
3303
|
}
|
|
3304
|
+
function drawSquare(png, cx, cy, r, color) {
|
|
3305
|
+
fillRect(png, cx - r, cy - r, cx + r, cy + r, color);
|
|
3306
|
+
}
|
|
3307
|
+
function drawTriangle(png, cx, cy, r, color) {
|
|
3308
|
+
for (let dy = -r; dy <= r; dy += 1) {
|
|
3309
|
+
const w = Math.round((dy + r) / (2 * r) * r);
|
|
3310
|
+
for (let dx = -w; dx <= w; dx += 1) {
|
|
3311
|
+
setPixel(png, cx + dx, cy + dy, color);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
function drawObstacleShape(png, cx, cy, r, type, color) {
|
|
3316
|
+
switch (Math.abs(Math.trunc(type)) % 4) {
|
|
3317
|
+
case 0:
|
|
3318
|
+
drawDiamond(png, cx, cy, r, color);
|
|
3319
|
+
return;
|
|
3320
|
+
case 1:
|
|
3321
|
+
drawSquare(png, cx, cy, r, color);
|
|
3322
|
+
return;
|
|
3323
|
+
case 2:
|
|
3324
|
+
drawTriangle(png, cx, cy, r, color);
|
|
3325
|
+
return;
|
|
3326
|
+
default:
|
|
3327
|
+
drawDisk(png, cx, cy, r, color);
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3217
3330
|
var FURNITURE_LINE = [150, 110, 200, 235];
|
|
3218
3331
|
function paintFurnitureZone(png, points, dim, scale) {
|
|
3219
3332
|
if (points.length < 2) return;
|
|
@@ -4056,7 +4169,8 @@ var TASK_OPCODE = {
|
|
|
4056
4169
|
ALL_AREA: 100,
|
|
4057
4170
|
EDGE: 101,
|
|
4058
4171
|
ZONE: 102,
|
|
4059
|
-
SPOT: 103
|
|
4172
|
+
SPOT: 103,
|
|
4173
|
+
SET_CURRENT_MAP: 200
|
|
4060
4174
|
};
|
|
4061
4175
|
function buildResumePayload() {
|
|
4062
4176
|
return { m: "a", p: 0, o: 5 };
|
|
@@ -4073,6 +4187,9 @@ function buildEdgePayload(contourIds) {
|
|
|
4073
4187
|
function buildSpotPayload(spotAreaIds) {
|
|
4074
4188
|
return { m: "a", p: 0, o: TASK_OPCODE.SPOT, d: { area: [...spotAreaIds] } };
|
|
4075
4189
|
}
|
|
4190
|
+
function buildSetCurrentMapPayload(mapIndex) {
|
|
4191
|
+
return { m: "a", p: 0, o: TASK_OPCODE.SET_CURRENT_MAP, d: { idx: mapIndex } };
|
|
4192
|
+
}
|
|
4076
4193
|
function buildGetConsumablePayload() {
|
|
4077
4194
|
return { m: "g", t: "CMS" };
|
|
4078
4195
|
}
|
|
@@ -4198,6 +4315,12 @@ var MowerFault = /* @__PURE__ */ ((MowerFault2) => {
|
|
|
4198
4315
|
MowerFault2[MowerFault2["TopCoverOpen"] = 73] = "TopCoverOpen";
|
|
4199
4316
|
return MowerFault2;
|
|
4200
4317
|
})(MowerFault || {});
|
|
4318
|
+
function mowerFaultSeverity(code) {
|
|
4319
|
+
if (code === null) return "info";
|
|
4320
|
+
if (code >= 1 && code <= 30 || code === 37 || code === 73) return "error";
|
|
4321
|
+
if (code >= 31 && code <= 36 || code >= 38 && code <= 45) return "warning";
|
|
4322
|
+
return "info";
|
|
4323
|
+
}
|
|
4201
4324
|
|
|
4202
4325
|
// src/models/mower/decode.ts
|
|
4203
4326
|
function isRecord2(v) {
|
|
@@ -4408,6 +4531,37 @@ function parseMowerHeartbeat(value) {
|
|
|
4408
4531
|
const taskSubState = mainState === HEARTBEAT_MAIN_STATE_MOWING ? MOWER_TASK_SUBSTATES[subStateRaw - HEARTBEAT_SUBSTATE_BASE] ?? null : null;
|
|
4409
4532
|
return { rawBattery, mainState, subStateRaw, taskSubState };
|
|
4410
4533
|
}
|
|
4534
|
+
var POSE_SENTINEL = 206;
|
|
4535
|
+
function poseBytes(value) {
|
|
4536
|
+
if (!Array.isArray(value)) return null;
|
|
4537
|
+
const bytes = [];
|
|
4538
|
+
for (const b of value) {
|
|
4539
|
+
if (typeof b !== "number") return null;
|
|
4540
|
+
bytes.push(b);
|
|
4541
|
+
}
|
|
4542
|
+
return bytes;
|
|
4543
|
+
}
|
|
4544
|
+
function parseMowingProgress(value) {
|
|
4545
|
+
const bytes = poseBytes(value);
|
|
4546
|
+
if (bytes === null || bytes.length < 11) return null;
|
|
4547
|
+
const last = bytes[bytes.length - 1];
|
|
4548
|
+
const head = bytes[0];
|
|
4549
|
+
let offset = null;
|
|
4550
|
+
if (head !== POSE_SENTINEL && last === POSE_SENTINEL) {
|
|
4551
|
+
offset = 0;
|
|
4552
|
+
} else if (head === POSE_SENTINEL && last === POSE_SENTINEL && bytes.length >= 33) {
|
|
4553
|
+
offset = 22;
|
|
4554
|
+
}
|
|
4555
|
+
if (offset === null || offset + 10 > bytes.length) return null;
|
|
4556
|
+
const rawPercent = (bytes[offset + 2] ?? 0) | (bytes[offset + 3] ?? 0) << 8;
|
|
4557
|
+
const total = (bytes[offset + 4] ?? 0) | (bytes[offset + 5] ?? 0) << 8 | (bytes[offset + 6] ?? 0) << 16;
|
|
4558
|
+
const finish = (bytes[offset + 7] ?? 0) | (bytes[offset + 8] ?? 0) << 8 | (bytes[offset + 9] ?? 0) << 16;
|
|
4559
|
+
return {
|
|
4560
|
+
progressPercent: rawPercent ? Math.min(100, rawPercent / 100) : 0,
|
|
4561
|
+
currentAreaSqm: finish / 100,
|
|
4562
|
+
totalAreaSqm: total / 100
|
|
4563
|
+
};
|
|
4564
|
+
}
|
|
4411
4565
|
|
|
4412
4566
|
// src/models/mower/capabilities.ts
|
|
4413
4567
|
var FALLBACK2 = {
|
|
@@ -5026,7 +5180,10 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
|
|
|
5026
5180
|
capabilities: input.capabilities ?? new MowerCapabilityResolver().resolve(input.device.model)
|
|
5027
5181
|
});
|
|
5028
5182
|
this.#caps = getMowerCapabilities(input.device.model);
|
|
5029
|
-
this.#fetchBatch = input.getBatchDeviceDatas ??
|
|
5183
|
+
this.#fetchBatch = input.getBatchDeviceDatas ?? ((did, props) => getBatchDeviceDatas(
|
|
5184
|
+
{ session: this.currentSession(), region: this.region, did },
|
|
5185
|
+
props
|
|
5186
|
+
));
|
|
5030
5187
|
}
|
|
5031
5188
|
/** Rich, mower-specific capability record. */
|
|
5032
5189
|
get mowerCapabilities() {
|
|
@@ -5107,6 +5264,25 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
|
|
|
5107
5264
|
get coverageTargetPct() {
|
|
5108
5265
|
return this.task?.coverageTarget ?? null;
|
|
5109
5266
|
}
|
|
5267
|
+
/**
|
|
5268
|
+
* Live mowing PROGRESS decoded from the POSE_COVERAGE (1:4) task block —
|
|
5269
|
+
* `{progressPercent, currentAreaSqm, totalAreaSqm}` — or null when 1:4 carries
|
|
5270
|
+
* no task block (idle / pose-only frame). This is the byte-accurate progress
|
|
5271
|
+
* the Dreamehome app shows (vs {@link coverageTargetPct}, the task TARGET).
|
|
5272
|
+
*/
|
|
5273
|
+
get mowingProgress() {
|
|
5274
|
+
return parseMowingProgress(
|
|
5275
|
+
this.getProperty(MOWER_PROP.POSE_COVERAGE.siid, MOWER_PROP.POSE_COVERAGE.piid)?.value
|
|
5276
|
+
);
|
|
5277
|
+
}
|
|
5278
|
+
/** Mowing completion percent (0..100) from {@link mowingProgress}, or null. */
|
|
5279
|
+
get mowingProgressPct() {
|
|
5280
|
+
return this.mowingProgress?.progressPercent ?? null;
|
|
5281
|
+
}
|
|
5282
|
+
/** Severity of the current DEVICE_CODE (2:2) — info / warning / error. */
|
|
5283
|
+
get faultSeverity() {
|
|
5284
|
+
return mowerFaultSeverity(this.faultRaw);
|
|
5285
|
+
}
|
|
5110
5286
|
/** Parsed per-zone control status (2:56), or null. */
|
|
5111
5287
|
get controlStatus() {
|
|
5112
5288
|
return parseControlStatus(
|
|
@@ -5186,6 +5362,20 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
|
|
|
5186
5362
|
}
|
|
5187
5363
|
return this.#sendTask(buildSpotPayload(spotAreaIds.map((s) => Math.trunc(s))));
|
|
5188
5364
|
}
|
|
5365
|
+
/**
|
|
5366
|
+
* Switch the mower's ACTIVE map (2:50 o:200). Takes a map *id* (as carried by
|
|
5367
|
+
* {@link MowerMap.availableMaps}/`currentMapId`) and resolves it to the
|
|
5368
|
+
* firmware's map *index* via the last-fetched map; falls back to treating the
|
|
5369
|
+
* id as the index when no map has been fetched yet. Mirrors the donor
|
|
5370
|
+
* `set_current_map`. Capability-gated on `canMap`.
|
|
5371
|
+
*/
|
|
5372
|
+
async setCurrentMap(mapId) {
|
|
5373
|
+
this.#requireCap(this.#caps.canMap, "setCurrentMap", "map switching");
|
|
5374
|
+
const id = Math.trunc(mapId);
|
|
5375
|
+
const entry = this.#lastMap?.availableMaps.find((m) => m.mapId === id);
|
|
5376
|
+
const index = entry?.mapIndex ?? id;
|
|
5377
|
+
return this.#sendTask(buildSetCurrentMapPayload(index));
|
|
5378
|
+
}
|
|
5189
5379
|
// -- CMS consumables ----------------------------------------------------
|
|
5190
5380
|
/**
|
|
5191
5381
|
* Read the raw CMS consumable counters `[blade, brush, robot]` (minutes used),
|
|
@@ -5286,6 +5476,7 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
|
|
|
5286
5476
|
/** Props worth seeding on start() / polling — exported for the facade. */
|
|
5287
5477
|
static DEFAULT_PROPS = [
|
|
5288
5478
|
MOWER_PROP.HEARTBEAT,
|
|
5479
|
+
MOWER_PROP.POSE_COVERAGE,
|
|
5289
5480
|
MOWER_PROP.STATUS,
|
|
5290
5481
|
MOWER_PROP.DEVICE_CODE,
|
|
5291
5482
|
MOWER_PROP.BATTERY,
|
|
@@ -5945,8 +6136,10 @@ function createClientDumper(client, options) {
|
|
|
5945
6136
|
getVacuumCapabilities,
|
|
5946
6137
|
isDreameConsumableKey,
|
|
5947
6138
|
mowerConsumableIndex,
|
|
6139
|
+
mowerFaultSeverity,
|
|
5948
6140
|
parseMowerConsumables,
|
|
5949
6141
|
parseMowerHeartbeat,
|
|
6142
|
+
parseMowingProgress,
|
|
5950
6143
|
renderMowerSvg,
|
|
5951
6144
|
renderVacuumPng,
|
|
5952
6145
|
resolveCapabilities,
|