@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.d.cts
CHANGED
|
@@ -2178,6 +2178,14 @@ declare class MowerDevice extends BaseDevice {
|
|
|
2178
2178
|
startMowingEdges(contourIds: number[][]): Promise<unknown>;
|
|
2179
2179
|
/** Spot mowing (2:50 o:103). */
|
|
2180
2180
|
startMowingSpots(spotAreaIds: number[]): Promise<unknown>;
|
|
2181
|
+
/**
|
|
2182
|
+
* Switch the mower's ACTIVE map (2:50 o:200). Takes a map *id* (as carried by
|
|
2183
|
+
* {@link MowerMap.availableMaps}/`currentMapId`) and resolves it to the
|
|
2184
|
+
* firmware's map *index* via the last-fetched map; falls back to treating the
|
|
2185
|
+
* id as the index when no map has been fetched yet. Mirrors the donor
|
|
2186
|
+
* `set_current_map`. Capability-gated on `canMap`.
|
|
2187
|
+
*/
|
|
2188
|
+
setCurrentMap(mapId: number): Promise<unknown>;
|
|
2181
2189
|
/**
|
|
2182
2190
|
* Read the raw CMS consumable counters `[blade, brush, robot]` (minutes used),
|
|
2183
2191
|
* via the SCHEDULING_TASK (2:50) custom-action getter `{m:'g',t:'CMS'}`. This
|
package/dist/index.d.ts
CHANGED
|
@@ -2178,6 +2178,14 @@ declare class MowerDevice extends BaseDevice {
|
|
|
2178
2178
|
startMowingEdges(contourIds: number[][]): Promise<unknown>;
|
|
2179
2179
|
/** Spot mowing (2:50 o:103). */
|
|
2180
2180
|
startMowingSpots(spotAreaIds: number[]): Promise<unknown>;
|
|
2181
|
+
/**
|
|
2182
|
+
* Switch the mower's ACTIVE map (2:50 o:200). Takes a map *id* (as carried by
|
|
2183
|
+
* {@link MowerMap.availableMaps}/`currentMapId`) and resolves it to the
|
|
2184
|
+
* firmware's map *index* via the last-fetched map; falls back to treating the
|
|
2185
|
+
* id as the index when no map has been fetched yet. Mirrors the donor
|
|
2186
|
+
* `set_current_map`. Capability-gated on `canMap`.
|
|
2187
|
+
*/
|
|
2188
|
+
setCurrentMap(mapId: number): Promise<unknown>;
|
|
2181
2189
|
/**
|
|
2182
2190
|
* Read the raw CMS consumable counters `[blade, brush, robot]` (minutes used),
|
|
2183
2191
|
* via the SCHEDULING_TASK (2:50) custom-action getter `{m:'g',t:'CMS'}`. This
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/support/version.ts
|
|
2
2
|
var LIBRARY_NAME = "nodedreame";
|
|
3
|
-
var LIBRARY_VERSION = "1.11.
|
|
3
|
+
var LIBRARY_VERSION = "1.11.10";
|
|
4
4
|
|
|
5
5
|
// src/transport/errors.ts
|
|
6
6
|
var DreameError = class extends Error {
|
|
@@ -299,6 +299,11 @@ var CachedPropsResponseSchema = z.object({
|
|
|
299
299
|
msg: z.string().nullish(),
|
|
300
300
|
data: z.array(CachedPropEntrySchema).optional()
|
|
301
301
|
}).passthrough();
|
|
302
|
+
var BatchDeviceDataResponseSchema = z.object({
|
|
303
|
+
code: z.number().optional(),
|
|
304
|
+
msg: z.string().nullish(),
|
|
305
|
+
data: z.record(z.string(), z.unknown()).optional()
|
|
306
|
+
}).passthrough();
|
|
302
307
|
var SendCommandResponseSchema = z.object({
|
|
303
308
|
code: z.number().optional(),
|
|
304
309
|
msg: z.string().nullish(),
|
|
@@ -559,6 +564,29 @@ async function callAction(base, action, opts = {}) {
|
|
|
559
564
|
const res = await sendCommand({ ...base, ...opts, method: "action", params });
|
|
560
565
|
return res.data?.result ?? res.result ?? res;
|
|
561
566
|
}
|
|
567
|
+
async function getBatchDeviceDatas(base, props, opts = {}) {
|
|
568
|
+
const ctx = base.ctx ?? RequestContext.from({ ...base, host: base.apiHost });
|
|
569
|
+
const signal = opts.signal ?? base.signal;
|
|
570
|
+
const timeoutMs = opts.timeoutMs ?? base.timeoutMs;
|
|
571
|
+
const raw = await httpPostJsonBody({
|
|
572
|
+
ctx,
|
|
573
|
+
path: "/dreame-user-iot/iotuserdata/getDeviceData",
|
|
574
|
+
accessToken: base.session.accessToken,
|
|
575
|
+
body: { did: base.did, model: props },
|
|
576
|
+
context: "batch device data",
|
|
577
|
+
...signal !== void 0 ? { signal } : {},
|
|
578
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
579
|
+
});
|
|
580
|
+
const parsed = BatchDeviceDataResponseSchema.parse(raw);
|
|
581
|
+
if (parsed.code !== void 0 && parsed.code !== 0) {
|
|
582
|
+
throw new DreameApiError(
|
|
583
|
+
`batch device data rejected: code=${parsed.code} msg=${parsed.msg ?? "?"}`,
|
|
584
|
+
200,
|
|
585
|
+
parsed
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
return parsed.data ?? {};
|
|
589
|
+
}
|
|
562
590
|
function extractResultArray(res, context) {
|
|
563
591
|
const raw = Array.isArray(res.data?.result) ? res.data.result : Array.isArray(res.result) ? res.result : null;
|
|
564
592
|
if (raw === null) {
|
|
@@ -2063,6 +2091,43 @@ function parseFrame(inflated) {
|
|
|
2063
2091
|
return { header, tail };
|
|
2064
2092
|
}
|
|
2065
2093
|
|
|
2094
|
+
// src/models/vacuum/map/segment-types.ts
|
|
2095
|
+
var SEGMENT_TYPE_CODE_TO_NAME = {
|
|
2096
|
+
0: "Room",
|
|
2097
|
+
1: "Living Room",
|
|
2098
|
+
2: "Primary Bedroom",
|
|
2099
|
+
3: "Study",
|
|
2100
|
+
4: "Kitchen",
|
|
2101
|
+
5: "Dining Hall",
|
|
2102
|
+
6: "Bathroom",
|
|
2103
|
+
7: "Balcony",
|
|
2104
|
+
8: "Corridor",
|
|
2105
|
+
9: "Utility Room",
|
|
2106
|
+
10: "Closet",
|
|
2107
|
+
11: "Meeting Room",
|
|
2108
|
+
12: "Office",
|
|
2109
|
+
13: "Fitness Area",
|
|
2110
|
+
14: "Recreation Area",
|
|
2111
|
+
15: "Secondary Bedroom"
|
|
2112
|
+
};
|
|
2113
|
+
function safeBase64ToUtf8(s) {
|
|
2114
|
+
try {
|
|
2115
|
+
return Buffer.from(s, "base64").toString("utf8");
|
|
2116
|
+
} catch {
|
|
2117
|
+
return null;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
function resolveSegmentName(type, index, customName) {
|
|
2121
|
+
if (type !== void 0 && type !== 0 && SEGMENT_TYPE_CODE_TO_NAME[type] !== void 0) {
|
|
2122
|
+
const base = SEGMENT_TYPE_CODE_TO_NAME[type];
|
|
2123
|
+
return index !== void 0 && index > 0 ? `${base} ${index + 1}` : base;
|
|
2124
|
+
}
|
|
2125
|
+
if (typeof customName === "string" && customName.length > 0) {
|
|
2126
|
+
return safeBase64ToUtf8(customName);
|
|
2127
|
+
}
|
|
2128
|
+
return null;
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2066
2131
|
// src/models/vacuum/map/pixel-grid.ts
|
|
2067
2132
|
function classifyPixelFsm1(byte) {
|
|
2068
2133
|
if (byte === 0) {
|
|
@@ -2208,7 +2273,9 @@ function collectSegments(layers, dim, tail) {
|
|
|
2208
2273
|
};
|
|
2209
2274
|
segs.push({
|
|
2210
2275
|
id,
|
|
2211
|
-
|
|
2276
|
+
// Mirror the donor: a room-type code (≠0) yields a localized default name
|
|
2277
|
+
// (e.g. "Kitchen"), else the user's custom base64 name, else null.
|
|
2278
|
+
name: resolveSegmentName(meta?.type, meta?.index, meta?.name),
|
|
2212
2279
|
bbox,
|
|
2213
2280
|
centroid,
|
|
2214
2281
|
neighbours: meta?.nei_id ?? [],
|
|
@@ -2219,13 +2286,6 @@ function collectSegments(layers, dim, tail) {
|
|
|
2219
2286
|
}
|
|
2220
2287
|
return segs;
|
|
2221
2288
|
}
|
|
2222
|
-
function safeBase64ToUtf8(s) {
|
|
2223
|
-
try {
|
|
2224
|
-
return Buffer.from(s, "base64").toString("utf8");
|
|
2225
|
-
} catch {
|
|
2226
|
-
return null;
|
|
2227
|
-
}
|
|
2228
|
-
}
|
|
2229
2289
|
|
|
2230
2290
|
// src/models/vacuum/map/path.ts
|
|
2231
2291
|
var PATH_TYPE_FROM_OP = {
|
|
@@ -4021,7 +4081,8 @@ var TASK_OPCODE = {
|
|
|
4021
4081
|
ALL_AREA: 100,
|
|
4022
4082
|
EDGE: 101,
|
|
4023
4083
|
ZONE: 102,
|
|
4024
|
-
SPOT: 103
|
|
4084
|
+
SPOT: 103,
|
|
4085
|
+
SET_CURRENT_MAP: 200
|
|
4025
4086
|
};
|
|
4026
4087
|
function buildResumePayload() {
|
|
4027
4088
|
return { m: "a", p: 0, o: 5 };
|
|
@@ -4038,6 +4099,9 @@ function buildEdgePayload(contourIds) {
|
|
|
4038
4099
|
function buildSpotPayload(spotAreaIds) {
|
|
4039
4100
|
return { m: "a", p: 0, o: TASK_OPCODE.SPOT, d: { area: [...spotAreaIds] } };
|
|
4040
4101
|
}
|
|
4102
|
+
function buildSetCurrentMapPayload(mapIndex) {
|
|
4103
|
+
return { m: "a", p: 0, o: TASK_OPCODE.SET_CURRENT_MAP, d: { idx: mapIndex } };
|
|
4104
|
+
}
|
|
4041
4105
|
function buildGetConsumablePayload() {
|
|
4042
4106
|
return { m: "g", t: "CMS" };
|
|
4043
4107
|
}
|
|
@@ -4799,11 +4863,15 @@ var DEFAULT_HEIGHT = 1200;
|
|
|
4799
4863
|
var DEFAULT_PADDING = 50;
|
|
4800
4864
|
var BACKGROUND = "#f5f5f0";
|
|
4801
4865
|
var MAP_BOUNDARY = "#006400";
|
|
4802
|
-
var MOWING_PATH = "#
|
|
4866
|
+
var MOWING_PATH = "#32cd32";
|
|
4803
4867
|
var NAV_PATH = "#b4b4b4";
|
|
4804
4868
|
var OBSTACLE_STROKE = "#ff4d00";
|
|
4805
4869
|
var OBSTACLE_FILL = "#ff4d0065";
|
|
4806
4870
|
var TEXT_COLOR = "#000000";
|
|
4871
|
+
var ZONE_LABEL_COLOR = "#3c3c3c";
|
|
4872
|
+
function escapeXml(s) {
|
|
4873
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4874
|
+
}
|
|
4807
4875
|
var ZONE_COLORS = [
|
|
4808
4876
|
["#a4d291c8", "#86be73"],
|
|
4809
4877
|
["#a0c8dcc8", "#82aac8"],
|
|
@@ -4926,7 +4994,6 @@ function renderMowerSvg(map, opts = {}) {
|
|
|
4926
4994
|
return lines.join("\n");
|
|
4927
4995
|
}
|
|
4928
4996
|
const bounds = calculateBounds(allPoints);
|
|
4929
|
-
const multiZone = map.zones.length > 1;
|
|
4930
4997
|
for (const navPath of map.paths) {
|
|
4931
4998
|
const dashed = svgPathFromSegments(
|
|
4932
4999
|
[navPath.path],
|
|
@@ -4943,9 +5010,6 @@ function renderMowerSvg(map, opts = {}) {
|
|
|
4943
5010
|
}
|
|
4944
5011
|
}
|
|
4945
5012
|
map.zones.forEach((zone, i) => {
|
|
4946
|
-
if (!multiZone) {
|
|
4947
|
-
return;
|
|
4948
|
-
}
|
|
4949
5013
|
const palette = ZONE_COLORS[i % ZONE_COLORS.length];
|
|
4950
5014
|
const [fill, outline] = palette ?? ZONE_COLORS[0] ?? ["#cccccc", "#888888"];
|
|
4951
5015
|
const poly = svgPolygon(zone.path, bounds, width, height, padding, fill, outline);
|
|
@@ -4954,7 +5018,7 @@ function renderMowerSvg(map, opts = {}) {
|
|
|
4954
5018
|
}
|
|
4955
5019
|
});
|
|
4956
5020
|
map.zones.forEach((zone, i) => {
|
|
4957
|
-
const outline =
|
|
5021
|
+
const outline = ZONE_COLORS[i % ZONE_COLORS.length]?.[1] ?? MAP_BOUNDARY;
|
|
4958
5022
|
const boundary = svgPathFromSegments(
|
|
4959
5023
|
[zone.path],
|
|
4960
5024
|
bounds,
|
|
@@ -4998,6 +5062,22 @@ function renderMowerSvg(map, opts = {}) {
|
|
|
4998
5062
|
lines.push(poly);
|
|
4999
5063
|
}
|
|
5000
5064
|
}
|
|
5065
|
+
for (const zone of map.zones) {
|
|
5066
|
+
if (zone.name.length === 0 || zone.path.length === 0) {
|
|
5067
|
+
continue;
|
|
5068
|
+
}
|
|
5069
|
+
let sumX = 0;
|
|
5070
|
+
let sumY = 0;
|
|
5071
|
+
for (const p of zone.path) {
|
|
5072
|
+
sumX += p.x;
|
|
5073
|
+
sumY += p.y;
|
|
5074
|
+
}
|
|
5075
|
+
const centroid = { x: sumX / zone.path.length, y: sumY / zone.path.length };
|
|
5076
|
+
const { px, py } = coordToPixel(centroid, bounds, width, height, padding);
|
|
5077
|
+
lines.push(
|
|
5078
|
+
`<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>`
|
|
5079
|
+
);
|
|
5080
|
+
}
|
|
5001
5081
|
lines.push("</svg>");
|
|
5002
5082
|
return lines.join("\n");
|
|
5003
5083
|
}
|
|
@@ -5028,7 +5108,10 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
|
|
|
5028
5108
|
capabilities: input.capabilities ?? new MowerCapabilityResolver().resolve(input.device.model)
|
|
5029
5109
|
});
|
|
5030
5110
|
this.#caps = getMowerCapabilities(input.device.model);
|
|
5031
|
-
this.#fetchBatch = input.getBatchDeviceDatas ??
|
|
5111
|
+
this.#fetchBatch = input.getBatchDeviceDatas ?? ((did, props) => getBatchDeviceDatas(
|
|
5112
|
+
{ session: this.currentSession(), region: this.region, did },
|
|
5113
|
+
props
|
|
5114
|
+
));
|
|
5032
5115
|
}
|
|
5033
5116
|
/** Rich, mower-specific capability record. */
|
|
5034
5117
|
get mowerCapabilities() {
|
|
@@ -5207,6 +5290,20 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
|
|
|
5207
5290
|
}
|
|
5208
5291
|
return this.#sendTask(buildSpotPayload(spotAreaIds.map((s) => Math.trunc(s))));
|
|
5209
5292
|
}
|
|
5293
|
+
/**
|
|
5294
|
+
* Switch the mower's ACTIVE map (2:50 o:200). Takes a map *id* (as carried by
|
|
5295
|
+
* {@link MowerMap.availableMaps}/`currentMapId`) and resolves it to the
|
|
5296
|
+
* firmware's map *index* via the last-fetched map; falls back to treating the
|
|
5297
|
+
* id as the index when no map has been fetched yet. Mirrors the donor
|
|
5298
|
+
* `set_current_map`. Capability-gated on `canMap`.
|
|
5299
|
+
*/
|
|
5300
|
+
async setCurrentMap(mapId) {
|
|
5301
|
+
this.#requireCap(this.#caps.canMap, "setCurrentMap", "map switching");
|
|
5302
|
+
const id = Math.trunc(mapId);
|
|
5303
|
+
const entry = this.#lastMap?.availableMaps.find((m) => m.mapId === id);
|
|
5304
|
+
const index = entry?.mapIndex ?? id;
|
|
5305
|
+
return this.#sendTask(buildSetCurrentMapPayload(index));
|
|
5306
|
+
}
|
|
5210
5307
|
// -- CMS consumables ----------------------------------------------------
|
|
5211
5308
|
/**
|
|
5212
5309
|
* Read the raw CMS consumable counters `[blade, brush, robot]` (minutes used),
|