@apocaliss92/nodedreame 1.10.0 → 1.11.1
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 +202 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -1
- package/dist/index.d.ts +46 -1
- package/dist/index.js +199 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -69,9 +69,12 @@ __export(index_exports, {
|
|
|
69
69
|
decodeAutoSwitchAll: () => decodeAutoSwitchAll,
|
|
70
70
|
encodeAiFeatureWrite: () => encodeAiFeatureWrite,
|
|
71
71
|
encodeAutoSwitchWrite: () => encodeAutoSwitchWrite,
|
|
72
|
+
extractMowerConsumableValues: () => extractMowerConsumableValues,
|
|
72
73
|
getMowerCapabilities: () => getMowerCapabilities,
|
|
73
74
|
getVacuumCapabilities: () => getVacuumCapabilities,
|
|
74
75
|
isDreameConsumableKey: () => isDreameConsumableKey,
|
|
76
|
+
mowerConsumableIndex: () => mowerConsumableIndex,
|
|
77
|
+
parseMowerConsumables: () => parseMowerConsumables,
|
|
75
78
|
renderMowerSvg: () => renderMowerSvg,
|
|
76
79
|
renderVacuumPng: () => renderVacuumPng,
|
|
77
80
|
resolveCapabilities: () => resolveCapabilities,
|
|
@@ -81,7 +84,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
81
84
|
|
|
82
85
|
// src/support/version.ts
|
|
83
86
|
var LIBRARY_NAME = "nodedreame";
|
|
84
|
-
var LIBRARY_VERSION = "1.
|
|
87
|
+
var LIBRARY_VERSION = "1.11.1";
|
|
85
88
|
|
|
86
89
|
// src/transport/errors.ts
|
|
87
90
|
var DreameError = class extends Error {
|
|
@@ -697,6 +700,7 @@ var DreamePush = class extends TypedEmitter {
|
|
|
697
700
|
#region;
|
|
698
701
|
#connect;
|
|
699
702
|
#backoffMs;
|
|
703
|
+
#keepaliveSeconds;
|
|
700
704
|
#rejectUnauthorized;
|
|
701
705
|
#topic;
|
|
702
706
|
#client = null;
|
|
@@ -717,6 +721,7 @@ var DreamePush = class extends TypedEmitter {
|
|
|
717
721
|
this.#region = input.region;
|
|
718
722
|
this.#connect = input.connect ?? defaultConnect;
|
|
719
723
|
this.#backoffMs = input.reconnectBackoffMs ?? 5e3;
|
|
724
|
+
this.#keepaliveSeconds = input.keepaliveSeconds ?? 60;
|
|
720
725
|
this.#rejectUnauthorized = input.rejectUnauthorized ?? false;
|
|
721
726
|
this.#topic = buildStatusTopic(this.#device, this.#session.uid, this.#region);
|
|
722
727
|
this.#onClose = () => {
|
|
@@ -774,6 +779,7 @@ var DreamePush = class extends TypedEmitter {
|
|
|
774
779
|
reconnectPeriod: 0,
|
|
775
780
|
// we drive reconnect ourselves
|
|
776
781
|
connectTimeout: 15e3,
|
|
782
|
+
keepalive: this.#keepaliveSeconds,
|
|
777
783
|
rejectUnauthorized: this.#rejectUnauthorized,
|
|
778
784
|
clean: true
|
|
779
785
|
});
|
|
@@ -781,25 +787,37 @@ var DreamePush = class extends TypedEmitter {
|
|
|
781
787
|
client.on("message", (_topic, payload) => this.#handleMessage(payload));
|
|
782
788
|
client.on("error", (err) => this.emit("error", err));
|
|
783
789
|
client.on("close", this.#onClose);
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
790
|
+
try {
|
|
791
|
+
await new Promise((resolve, reject) => {
|
|
792
|
+
const onConnect = () => {
|
|
793
|
+
client.removeListener("error", onError);
|
|
794
|
+
client.subscribe(this.#topic, { qos: 0 }, (err) => {
|
|
795
|
+
if (err) {
|
|
796
|
+
reject(new DreameTransportError(`mqtt subscribe failed: ${err.message}`, err));
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
this.emit("connect");
|
|
800
|
+
resolve();
|
|
801
|
+
});
|
|
802
|
+
};
|
|
803
|
+
const onError = (err) => {
|
|
804
|
+
client.removeListener("connect", onConnect);
|
|
805
|
+
reject(new DreameTransportError(`mqtt connect failed: ${err.message}`, err));
|
|
806
|
+
};
|
|
807
|
+
client.once("connect", onConnect);
|
|
808
|
+
client.once("error", onError);
|
|
809
|
+
});
|
|
810
|
+
} catch (err) {
|
|
811
|
+
client.removeListener("close", this.#onClose);
|
|
812
|
+
try {
|
|
813
|
+
client.end(true, {}, () => void 0);
|
|
814
|
+
} catch {
|
|
815
|
+
}
|
|
816
|
+
if (this.#client === client) {
|
|
817
|
+
this.#client = null;
|
|
818
|
+
}
|
|
819
|
+
throw err;
|
|
820
|
+
}
|
|
803
821
|
}
|
|
804
822
|
#scheduleReconnect() {
|
|
805
823
|
if (this.#closed || this.#reconnectTimer) {
|
|
@@ -3931,6 +3949,19 @@ function buildEdgePayload(contourIds) {
|
|
|
3931
3949
|
function buildSpotPayload(spotAreaIds) {
|
|
3932
3950
|
return { m: "a", p: 0, o: TASK_OPCODE.SPOT, d: { area: [...spotAreaIds] } };
|
|
3933
3951
|
}
|
|
3952
|
+
function buildGetConsumablePayload() {
|
|
3953
|
+
return { m: "g", t: "CMS" };
|
|
3954
|
+
}
|
|
3955
|
+
function buildSetConsumablePayload(values) {
|
|
3956
|
+
const normalized = values.map((v) => Math.trunc(v));
|
|
3957
|
+
if (normalized.length !== 3) {
|
|
3958
|
+
throw new RangeError(`CMS values must contain exactly 3 counters; got ${normalized.length}`);
|
|
3959
|
+
}
|
|
3960
|
+
if (normalized.some((v) => v < 0)) {
|
|
3961
|
+
throw new RangeError(`CMS values cannot be negative; got ${JSON.stringify(normalized)}`);
|
|
3962
|
+
}
|
|
3963
|
+
return { m: "s", t: "CMS", d: { value: normalized } };
|
|
3964
|
+
}
|
|
3934
3965
|
|
|
3935
3966
|
// src/models/mower/enums.ts
|
|
3936
3967
|
var MowerStatus = /* @__PURE__ */ ((MowerStatus2) => {
|
|
@@ -4122,6 +4153,104 @@ function parseControlStatus(value) {
|
|
|
4122
4153
|
zones
|
|
4123
4154
|
};
|
|
4124
4155
|
}
|
|
4156
|
+
var MOWER_CONSUMABLES = [
|
|
4157
|
+
{ key: "blade", index: 0, totalMinutes: 6e3 },
|
|
4158
|
+
{ key: "brush", index: 1, totalMinutes: 3e4 },
|
|
4159
|
+
{ key: "maintenance", index: 2, totalMinutes: 3600 }
|
|
4160
|
+
];
|
|
4161
|
+
function mowerConsumableIndex(item) {
|
|
4162
|
+
switch (item.trim().toLowerCase()) {
|
|
4163
|
+
case "blade":
|
|
4164
|
+
case "blades":
|
|
4165
|
+
return 0;
|
|
4166
|
+
case "brush":
|
|
4167
|
+
case "cleaning_brush":
|
|
4168
|
+
return 1;
|
|
4169
|
+
case "robot":
|
|
4170
|
+
case "maintenance":
|
|
4171
|
+
case "robot_maintenance":
|
|
4172
|
+
return 2;
|
|
4173
|
+
default:
|
|
4174
|
+
return null;
|
|
4175
|
+
}
|
|
4176
|
+
}
|
|
4177
|
+
function toInt(v) {
|
|
4178
|
+
if (typeof v === "number" && Number.isFinite(v)) {
|
|
4179
|
+
return Math.trunc(v);
|
|
4180
|
+
}
|
|
4181
|
+
if (typeof v === "string") {
|
|
4182
|
+
const n = Number(v);
|
|
4183
|
+
return Number.isFinite(n) ? Math.trunc(n) : null;
|
|
4184
|
+
}
|
|
4185
|
+
return null;
|
|
4186
|
+
}
|
|
4187
|
+
function extractCustomActionData(result) {
|
|
4188
|
+
if (!isRecord2(result)) {
|
|
4189
|
+
return null;
|
|
4190
|
+
}
|
|
4191
|
+
if (Array.isArray(result["value"])) {
|
|
4192
|
+
return result;
|
|
4193
|
+
}
|
|
4194
|
+
if (isRecord2(result["d"])) {
|
|
4195
|
+
return result["d"];
|
|
4196
|
+
}
|
|
4197
|
+
const out = result["out"];
|
|
4198
|
+
if (!Array.isArray(out)) {
|
|
4199
|
+
return null;
|
|
4200
|
+
}
|
|
4201
|
+
for (const entry of out) {
|
|
4202
|
+
if (!isRecord2(entry)) {
|
|
4203
|
+
continue;
|
|
4204
|
+
}
|
|
4205
|
+
const r = entry["r"];
|
|
4206
|
+
const code = entry["code"];
|
|
4207
|
+
const rError = r !== void 0 && r !== null && r !== 0;
|
|
4208
|
+
const codeError = code !== void 0 && code !== null && code !== 0;
|
|
4209
|
+
if (rError && codeError) {
|
|
4210
|
+
continue;
|
|
4211
|
+
}
|
|
4212
|
+
if (isRecord2(entry["d"])) {
|
|
4213
|
+
return entry["d"];
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
return null;
|
|
4217
|
+
}
|
|
4218
|
+
function extractMowerConsumableValues(result) {
|
|
4219
|
+
const data = extractCustomActionData(result);
|
|
4220
|
+
if (data === null) {
|
|
4221
|
+
return null;
|
|
4222
|
+
}
|
|
4223
|
+
const values = data["value"];
|
|
4224
|
+
if (!Array.isArray(values) || values.length < 3) {
|
|
4225
|
+
return null;
|
|
4226
|
+
}
|
|
4227
|
+
const out = [];
|
|
4228
|
+
for (const v of values.slice(0, 3)) {
|
|
4229
|
+
const n = toInt(v);
|
|
4230
|
+
if (n === null) {
|
|
4231
|
+
return null;
|
|
4232
|
+
}
|
|
4233
|
+
out.push(n);
|
|
4234
|
+
}
|
|
4235
|
+
return out;
|
|
4236
|
+
}
|
|
4237
|
+
function parseMowerConsumables(result) {
|
|
4238
|
+
const values = extractMowerConsumableValues(result);
|
|
4239
|
+
if (values === null) {
|
|
4240
|
+
return null;
|
|
4241
|
+
}
|
|
4242
|
+
return MOWER_CONSUMABLES.map((c) => {
|
|
4243
|
+
const used = values[c.index] ?? 0;
|
|
4244
|
+
const remaining = c.totalMinutes - used;
|
|
4245
|
+
const pct = Math.max(0, Math.min(100, Math.round(remaining / c.totalMinutes * 1e3) / 10));
|
|
4246
|
+
return {
|
|
4247
|
+
key: c.key,
|
|
4248
|
+
usedMinutes: used,
|
|
4249
|
+
totalMinutes: c.totalMinutes,
|
|
4250
|
+
remainingPercent: pct
|
|
4251
|
+
};
|
|
4252
|
+
});
|
|
4253
|
+
}
|
|
4125
4254
|
|
|
4126
4255
|
// src/models/mower/capabilities.ts
|
|
4127
4256
|
var FALLBACK2 = {
|
|
@@ -4887,6 +5016,56 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
|
|
|
4887
5016
|
}
|
|
4888
5017
|
return this.#sendTask(buildSpotPayload(spotAreaIds.map((s) => Math.trunc(s))));
|
|
4889
5018
|
}
|
|
5019
|
+
// -- CMS consumables ----------------------------------------------------
|
|
5020
|
+
/**
|
|
5021
|
+
* Read the raw CMS consumable counters `[blade, brush, robot]` (minutes used),
|
|
5022
|
+
* via the SCHEDULING_TASK (2:50) custom-action getter `{m:'g',t:'CMS'}`. This
|
|
5023
|
+
* is a LIVE device action (it wakes the mower); rejects with
|
|
5024
|
+
* {@link DreameDeviceOfflineError} when the mower is unreachable. Returns null
|
|
5025
|
+
* if the response is malformed.
|
|
5026
|
+
*/
|
|
5027
|
+
async getConsumableValues() {
|
|
5028
|
+
const result = await this.callAction(
|
|
5029
|
+
MOWER_PROP.SCHEDULING_TASK.siid,
|
|
5030
|
+
MOWER_PROP.SCHEDULING_TASK.piid,
|
|
5031
|
+
[buildGetConsumablePayload()]
|
|
5032
|
+
);
|
|
5033
|
+
return extractMowerConsumableValues(result);
|
|
5034
|
+
}
|
|
5035
|
+
/**
|
|
5036
|
+
* Read the CMS consumables as typed readings (blade/brush/maintenance) with
|
|
5037
|
+
* remaining %. LIVE action — see {@link getConsumableValues}. Returns null on
|
|
5038
|
+
* a malformed response.
|
|
5039
|
+
*/
|
|
5040
|
+
async getConsumables() {
|
|
5041
|
+
const result = await this.callAction(
|
|
5042
|
+
MOWER_PROP.SCHEDULING_TASK.siid,
|
|
5043
|
+
MOWER_PROP.SCHEDULING_TASK.piid,
|
|
5044
|
+
[buildGetConsumablePayload()]
|
|
5045
|
+
);
|
|
5046
|
+
return parseMowerConsumables(result);
|
|
5047
|
+
}
|
|
5048
|
+
/**
|
|
5049
|
+
* Reset one CMS consumable counter to zero. Reads the current counters, zeroes
|
|
5050
|
+
* the selected one (leaving the others), and writes them back via the
|
|
5051
|
+
* `{m:'s',t:'CMS',d:{value:[…]}}` setter. LIVE action. Throws on an unknown
|
|
5052
|
+
* item or when the current counters cannot be read.
|
|
5053
|
+
*/
|
|
5054
|
+
async resetConsumable(item) {
|
|
5055
|
+
const index = mowerConsumableIndex(item);
|
|
5056
|
+
if (index === null) {
|
|
5057
|
+
throw new DreameError(`resetConsumable: unknown consumable item "${item}"`);
|
|
5058
|
+
}
|
|
5059
|
+
const current = await this.getConsumableValues();
|
|
5060
|
+
if (current === null) {
|
|
5061
|
+
throw new DreameError("resetConsumable: failed to read current CMS counters");
|
|
5062
|
+
}
|
|
5063
|
+
const next = [...current];
|
|
5064
|
+
next[index] = 0;
|
|
5065
|
+
await this.callAction(MOWER_PROP.SCHEDULING_TASK.siid, MOWER_PROP.SCHEDULING_TASK.piid, [
|
|
5066
|
+
buildSetConsumablePayload(next)
|
|
5067
|
+
]);
|
|
5068
|
+
}
|
|
4890
5069
|
/**
|
|
4891
5070
|
* Seed the cache from the CLOUD SHADOW (last-known values) WITHOUT waking the
|
|
4892
5071
|
* mower — reads {@link MowerDevice.DEFAULT_PROPS} from the cloud-cached
|
|
@@ -5589,9 +5768,12 @@ function createClientDumper(client, options) {
|
|
|
5589
5768
|
decodeAutoSwitchAll,
|
|
5590
5769
|
encodeAiFeatureWrite,
|
|
5591
5770
|
encodeAutoSwitchWrite,
|
|
5771
|
+
extractMowerConsumableValues,
|
|
5592
5772
|
getMowerCapabilities,
|
|
5593
5773
|
getVacuumCapabilities,
|
|
5594
5774
|
isDreameConsumableKey,
|
|
5775
|
+
mowerConsumableIndex,
|
|
5776
|
+
parseMowerConsumables,
|
|
5595
5777
|
renderMowerSvg,
|
|
5596
5778
|
renderVacuumPng,
|
|
5597
5779
|
resolveCapabilities,
|