@apocaliss92/nodedreame 1.11.6 → 1.11.10
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 +114 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +114 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -88,7 +88,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
88
88
|
|
|
89
89
|
// src/support/version.ts
|
|
90
90
|
var LIBRARY_NAME = "nodedreame";
|
|
91
|
-
var LIBRARY_VERSION = "1.11.
|
|
91
|
+
var LIBRARY_VERSION = "1.11.10";
|
|
92
92
|
|
|
93
93
|
// src/transport/errors.ts
|
|
94
94
|
var DreameError = class extends Error {
|
|
@@ -387,6 +387,11 @@ var CachedPropsResponseSchema = import_zod.z.object({
|
|
|
387
387
|
msg: import_zod.z.string().nullish(),
|
|
388
388
|
data: import_zod.z.array(CachedPropEntrySchema).optional()
|
|
389
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();
|
|
390
395
|
var SendCommandResponseSchema = import_zod.z.object({
|
|
391
396
|
code: import_zod.z.number().optional(),
|
|
392
397
|
msg: import_zod.z.string().nullish(),
|
|
@@ -647,6 +652,29 @@ async function callAction(base, action, opts = {}) {
|
|
|
647
652
|
const res = await sendCommand({ ...base, ...opts, method: "action", params });
|
|
648
653
|
return res.data?.result ?? res.result ?? res;
|
|
649
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
|
+
}
|
|
650
678
|
function extractResultArray(res, context) {
|
|
651
679
|
const raw = Array.isArray(res.data?.result) ? res.data.result : Array.isArray(res.result) ? res.result : null;
|
|
652
680
|
if (raw === null) {
|
|
@@ -2151,6 +2179,43 @@ function parseFrame(inflated) {
|
|
|
2151
2179
|
return { header, tail };
|
|
2152
2180
|
}
|
|
2153
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
|
+
|
|
2154
2219
|
// src/models/vacuum/map/pixel-grid.ts
|
|
2155
2220
|
function classifyPixelFsm1(byte) {
|
|
2156
2221
|
if (byte === 0) {
|
|
@@ -2296,7 +2361,9 @@ function collectSegments(layers, dim, tail) {
|
|
|
2296
2361
|
};
|
|
2297
2362
|
segs.push({
|
|
2298
2363
|
id,
|
|
2299
|
-
|
|
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),
|
|
2300
2367
|
bbox,
|
|
2301
2368
|
centroid,
|
|
2302
2369
|
neighbours: meta?.nei_id ?? [],
|
|
@@ -2307,13 +2374,6 @@ function collectSegments(layers, dim, tail) {
|
|
|
2307
2374
|
}
|
|
2308
2375
|
return segs;
|
|
2309
2376
|
}
|
|
2310
|
-
function safeBase64ToUtf8(s) {
|
|
2311
|
-
try {
|
|
2312
|
-
return Buffer.from(s, "base64").toString("utf8");
|
|
2313
|
-
} catch {
|
|
2314
|
-
return null;
|
|
2315
|
-
}
|
|
2316
|
-
}
|
|
2317
2377
|
|
|
2318
2378
|
// src/models/vacuum/map/path.ts
|
|
2319
2379
|
var PATH_TYPE_FROM_OP = {
|
|
@@ -4109,7 +4169,8 @@ var TASK_OPCODE = {
|
|
|
4109
4169
|
ALL_AREA: 100,
|
|
4110
4170
|
EDGE: 101,
|
|
4111
4171
|
ZONE: 102,
|
|
4112
|
-
SPOT: 103
|
|
4172
|
+
SPOT: 103,
|
|
4173
|
+
SET_CURRENT_MAP: 200
|
|
4113
4174
|
};
|
|
4114
4175
|
function buildResumePayload() {
|
|
4115
4176
|
return { m: "a", p: 0, o: 5 };
|
|
@@ -4126,6 +4187,9 @@ function buildEdgePayload(contourIds) {
|
|
|
4126
4187
|
function buildSpotPayload(spotAreaIds) {
|
|
4127
4188
|
return { m: "a", p: 0, o: TASK_OPCODE.SPOT, d: { area: [...spotAreaIds] } };
|
|
4128
4189
|
}
|
|
4190
|
+
function buildSetCurrentMapPayload(mapIndex) {
|
|
4191
|
+
return { m: "a", p: 0, o: TASK_OPCODE.SET_CURRENT_MAP, d: { idx: mapIndex } };
|
|
4192
|
+
}
|
|
4129
4193
|
function buildGetConsumablePayload() {
|
|
4130
4194
|
return { m: "g", t: "CMS" };
|
|
4131
4195
|
}
|
|
@@ -4887,11 +4951,15 @@ var DEFAULT_HEIGHT = 1200;
|
|
|
4887
4951
|
var DEFAULT_PADDING = 50;
|
|
4888
4952
|
var BACKGROUND = "#f5f5f0";
|
|
4889
4953
|
var MAP_BOUNDARY = "#006400";
|
|
4890
|
-
var MOWING_PATH = "#
|
|
4954
|
+
var MOWING_PATH = "#32cd32";
|
|
4891
4955
|
var NAV_PATH = "#b4b4b4";
|
|
4892
4956
|
var OBSTACLE_STROKE = "#ff4d00";
|
|
4893
4957
|
var OBSTACLE_FILL = "#ff4d0065";
|
|
4894
4958
|
var TEXT_COLOR = "#000000";
|
|
4959
|
+
var ZONE_LABEL_COLOR = "#3c3c3c";
|
|
4960
|
+
function escapeXml(s) {
|
|
4961
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4962
|
+
}
|
|
4895
4963
|
var ZONE_COLORS = [
|
|
4896
4964
|
["#a4d291c8", "#86be73"],
|
|
4897
4965
|
["#a0c8dcc8", "#82aac8"],
|
|
@@ -5014,7 +5082,6 @@ function renderMowerSvg(map, opts = {}) {
|
|
|
5014
5082
|
return lines.join("\n");
|
|
5015
5083
|
}
|
|
5016
5084
|
const bounds = calculateBounds(allPoints);
|
|
5017
|
-
const multiZone = map.zones.length > 1;
|
|
5018
5085
|
for (const navPath of map.paths) {
|
|
5019
5086
|
const dashed = svgPathFromSegments(
|
|
5020
5087
|
[navPath.path],
|
|
@@ -5031,9 +5098,6 @@ function renderMowerSvg(map, opts = {}) {
|
|
|
5031
5098
|
}
|
|
5032
5099
|
}
|
|
5033
5100
|
map.zones.forEach((zone, i) => {
|
|
5034
|
-
if (!multiZone) {
|
|
5035
|
-
return;
|
|
5036
|
-
}
|
|
5037
5101
|
const palette = ZONE_COLORS[i % ZONE_COLORS.length];
|
|
5038
5102
|
const [fill, outline] = palette ?? ZONE_COLORS[0] ?? ["#cccccc", "#888888"];
|
|
5039
5103
|
const poly = svgPolygon(zone.path, bounds, width, height, padding, fill, outline);
|
|
@@ -5042,7 +5106,7 @@ function renderMowerSvg(map, opts = {}) {
|
|
|
5042
5106
|
}
|
|
5043
5107
|
});
|
|
5044
5108
|
map.zones.forEach((zone, i) => {
|
|
5045
|
-
const outline =
|
|
5109
|
+
const outline = ZONE_COLORS[i % ZONE_COLORS.length]?.[1] ?? MAP_BOUNDARY;
|
|
5046
5110
|
const boundary = svgPathFromSegments(
|
|
5047
5111
|
[zone.path],
|
|
5048
5112
|
bounds,
|
|
@@ -5086,6 +5150,22 @@ function renderMowerSvg(map, opts = {}) {
|
|
|
5086
5150
|
lines.push(poly);
|
|
5087
5151
|
}
|
|
5088
5152
|
}
|
|
5153
|
+
for (const zone of map.zones) {
|
|
5154
|
+
if (zone.name.length === 0 || zone.path.length === 0) {
|
|
5155
|
+
continue;
|
|
5156
|
+
}
|
|
5157
|
+
let sumX = 0;
|
|
5158
|
+
let sumY = 0;
|
|
5159
|
+
for (const p of zone.path) {
|
|
5160
|
+
sumX += p.x;
|
|
5161
|
+
sumY += p.y;
|
|
5162
|
+
}
|
|
5163
|
+
const centroid = { x: sumX / zone.path.length, y: sumY / zone.path.length };
|
|
5164
|
+
const { px, py } = coordToPixel(centroid, bounds, width, height, padding);
|
|
5165
|
+
lines.push(
|
|
5166
|
+
`<text x="${px}" y="${py}" font-family="Arial, sans-serif" font-size="20" font-weight="bold" fill="${ZONE_LABEL_COLOR}" text-anchor="middle" dominant-baseline="middle">${escapeXml(zone.name)}</text>`
|
|
5167
|
+
);
|
|
5168
|
+
}
|
|
5089
5169
|
lines.push("</svg>");
|
|
5090
5170
|
return lines.join("\n");
|
|
5091
5171
|
}
|
|
@@ -5116,7 +5196,10 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
|
|
|
5116
5196
|
capabilities: input.capabilities ?? new MowerCapabilityResolver().resolve(input.device.model)
|
|
5117
5197
|
});
|
|
5118
5198
|
this.#caps = getMowerCapabilities(input.device.model);
|
|
5119
|
-
this.#fetchBatch = input.getBatchDeviceDatas ??
|
|
5199
|
+
this.#fetchBatch = input.getBatchDeviceDatas ?? ((did, props) => getBatchDeviceDatas(
|
|
5200
|
+
{ session: this.currentSession(), region: this.region, did },
|
|
5201
|
+
props
|
|
5202
|
+
));
|
|
5120
5203
|
}
|
|
5121
5204
|
/** Rich, mower-specific capability record. */
|
|
5122
5205
|
get mowerCapabilities() {
|
|
@@ -5295,6 +5378,20 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
|
|
|
5295
5378
|
}
|
|
5296
5379
|
return this.#sendTask(buildSpotPayload(spotAreaIds.map((s) => Math.trunc(s))));
|
|
5297
5380
|
}
|
|
5381
|
+
/**
|
|
5382
|
+
* Switch the mower's ACTIVE map (2:50 o:200). Takes a map *id* (as carried by
|
|
5383
|
+
* {@link MowerMap.availableMaps}/`currentMapId`) and resolves it to the
|
|
5384
|
+
* firmware's map *index* via the last-fetched map; falls back to treating the
|
|
5385
|
+
* id as the index when no map has been fetched yet. Mirrors the donor
|
|
5386
|
+
* `set_current_map`. Capability-gated on `canMap`.
|
|
5387
|
+
*/
|
|
5388
|
+
async setCurrentMap(mapId) {
|
|
5389
|
+
this.#requireCap(this.#caps.canMap, "setCurrentMap", "map switching");
|
|
5390
|
+
const id = Math.trunc(mapId);
|
|
5391
|
+
const entry = this.#lastMap?.availableMaps.find((m) => m.mapId === id);
|
|
5392
|
+
const index = entry?.mapIndex ?? id;
|
|
5393
|
+
return this.#sendTask(buildSetCurrentMapPayload(index));
|
|
5394
|
+
}
|
|
5298
5395
|
// -- CMS consumables ----------------------------------------------------
|
|
5299
5396
|
/**
|
|
5300
5397
|
* Read the raw CMS consumable counters `[blade, brush, robot]` (minutes used),
|