@apocaliss92/nodedreame 1.0.0 → 1.1.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.
- package/dist/index.cjs +101 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +101 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -351,6 +351,16 @@ var PropertyResultSchema = import_zod.z.object({
|
|
|
351
351
|
value: import_zod.z.unknown().optional(),
|
|
352
352
|
code: import_zod.z.number().optional()
|
|
353
353
|
}).passthrough();
|
|
354
|
+
var CachedPropEntrySchema = import_zod.z.object({
|
|
355
|
+
key: import_zod.z.string(),
|
|
356
|
+
value: import_zod.z.unknown().optional(),
|
|
357
|
+
updateDate: import_zod.z.number().optional()
|
|
358
|
+
}).passthrough();
|
|
359
|
+
var CachedPropsResponseSchema = import_zod.z.object({
|
|
360
|
+
code: import_zod.z.number().optional(),
|
|
361
|
+
msg: import_zod.z.string().optional(),
|
|
362
|
+
data: import_zod.z.array(CachedPropEntrySchema).optional()
|
|
363
|
+
}).passthrough();
|
|
354
364
|
var SendCommandResponseSchema = import_zod.z.object({
|
|
355
365
|
code: import_zod.z.number().optional(),
|
|
356
366
|
msg: import_zod.z.string().optional(),
|
|
@@ -540,6 +550,57 @@ async function getProperties(base, props, opts = {}) {
|
|
|
540
550
|
const res = await sendCommand({ ...base, ...opts, method: "get_properties", params });
|
|
541
551
|
return extractResultArray(res, "get_properties");
|
|
542
552
|
}
|
|
553
|
+
async function getCachedProperties(base, props, opts = {}) {
|
|
554
|
+
const ctx = base.ctx ?? RequestContext.from({ ...base, host: base.apiHost });
|
|
555
|
+
const keys = props.map((p) => `${p.siid}.${p.piid}`).join(",");
|
|
556
|
+
const signal = opts.signal ?? base.signal;
|
|
557
|
+
const timeoutMs = opts.timeoutMs ?? base.timeoutMs;
|
|
558
|
+
const raw = await httpPostJsonBody({
|
|
559
|
+
ctx,
|
|
560
|
+
path: "/dreame-user-iot/iotstatus/props",
|
|
561
|
+
accessToken: base.session.accessToken,
|
|
562
|
+
body: { did: base.did, keys },
|
|
563
|
+
context: "cached properties",
|
|
564
|
+
...signal !== void 0 ? { signal } : {},
|
|
565
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
566
|
+
});
|
|
567
|
+
const parsed = CachedPropsResponseSchema.parse(raw);
|
|
568
|
+
if (parsed.code !== void 0 && parsed.code !== 0) {
|
|
569
|
+
throw new DreameApiError(
|
|
570
|
+
`cached properties rejected: code=${parsed.code} msg=${parsed.msg ?? "?"}`,
|
|
571
|
+
200,
|
|
572
|
+
parsed
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
return (parsed.data ?? []).flatMap((entry) => {
|
|
576
|
+
const [siidStr, piidStr] = entry.key.split(".");
|
|
577
|
+
const siid = Number(siidStr);
|
|
578
|
+
const piid = Number(piidStr);
|
|
579
|
+
if (!Number.isFinite(siid) || !Number.isFinite(piid)) {
|
|
580
|
+
return [];
|
|
581
|
+
}
|
|
582
|
+
const result = { siid, piid, value: coerceShadowValue(entry.value) };
|
|
583
|
+
if (entry.updateDate !== void 0) {
|
|
584
|
+
result.updateDate = entry.updateDate;
|
|
585
|
+
}
|
|
586
|
+
return [result];
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
function coerceShadowValue(value) {
|
|
590
|
+
if (typeof value !== "string") {
|
|
591
|
+
return value;
|
|
592
|
+
}
|
|
593
|
+
if (value === "true") {
|
|
594
|
+
return true;
|
|
595
|
+
}
|
|
596
|
+
if (value === "false") {
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
if (value.trim() !== "" && Number.isFinite(Number(value))) {
|
|
600
|
+
return Number(value);
|
|
601
|
+
}
|
|
602
|
+
return value;
|
|
603
|
+
}
|
|
543
604
|
async function setProperties(base, writes, opts = {}) {
|
|
544
605
|
const params = writes.map((p) => ({
|
|
545
606
|
did: base.did,
|
|
@@ -917,6 +978,7 @@ function defaultBaseDeviceDeps() {
|
|
|
917
978
|
return {
|
|
918
979
|
createPush: (device, session, region) => new DreamePush({ device, session, region }),
|
|
919
980
|
getProperties: (base, props) => getProperties(base, props),
|
|
981
|
+
getCachedProperties: (base, props) => getCachedProperties(base, props),
|
|
920
982
|
setProperties: (base, writes) => setProperties(base, writes),
|
|
921
983
|
callAction: (base, action) => callAction(base, action)
|
|
922
984
|
};
|
|
@@ -1005,6 +1067,23 @@ var BaseDevice = class extends TypedEmitter {
|
|
|
1005
1067
|
async refreshProperties(props) {
|
|
1006
1068
|
this.#assertOpen();
|
|
1007
1069
|
const results = await this.#deps.getProperties(this.#base(), props);
|
|
1070
|
+
this.#seedFromResults(results);
|
|
1071
|
+
return results;
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Read the CLOUD-CACHED (shadow) values of `props` WITHOUT waking the device,
|
|
1075
|
+
* update the cache, and emit `propertyChanged`/`stateChanged` just like
|
|
1076
|
+
* {@link refreshProperties} — but sourced from the cloud shadow endpoint, so
|
|
1077
|
+
* it works for standby/offline robots (and never surfaces a false 80001).
|
|
1078
|
+
*/
|
|
1079
|
+
async refreshCachedProperties(props) {
|
|
1080
|
+
this.#assertOpen();
|
|
1081
|
+
const results = await this.#deps.getCachedProperties(this.#base(), props);
|
|
1082
|
+
this.#seedFromResults(results);
|
|
1083
|
+
return results;
|
|
1084
|
+
}
|
|
1085
|
+
/** Mirror a PropertyResult[] into the cache + emit the change events. */
|
|
1086
|
+
#seedFromResults(results) {
|
|
1008
1087
|
const changes = [];
|
|
1009
1088
|
for (const r of results) {
|
|
1010
1089
|
if (typeof r.siid === "number" && typeof r.piid === "number") {
|
|
@@ -1014,7 +1093,6 @@ var BaseDevice = class extends TypedEmitter {
|
|
|
1014
1093
|
if (changes.length > 0) {
|
|
1015
1094
|
this.#onProperties(changes);
|
|
1016
1095
|
}
|
|
1017
|
-
return results;
|
|
1018
1096
|
}
|
|
1019
1097
|
/** Write a property to the device. */
|
|
1020
1098
|
async setProperty(write) {
|
|
@@ -2408,7 +2486,7 @@ var TASK = enumLookup([
|
|
|
2408
2486
|
12 /* TransientPauseEdge */,
|
|
2409
2487
|
14 /* NeedsIntervention */
|
|
2410
2488
|
]);
|
|
2411
|
-
var VacuumDevice = class extends BaseDevice {
|
|
2489
|
+
var VacuumDevice = class _VacuumDevice extends BaseDevice {
|
|
2412
2490
|
#caps;
|
|
2413
2491
|
#lastMap = null;
|
|
2414
2492
|
constructor(input) {
|
|
@@ -2623,6 +2701,16 @@ var VacuumDevice = class extends BaseDevice {
|
|
|
2623
2701
|
const points = [[Math.round(point.x), Math.round(point.y), repeats, fan, water]];
|
|
2624
2702
|
return this.#startCustom(CUSTOM_CLEAN_MODE.SPOT, { points });
|
|
2625
2703
|
}
|
|
2704
|
+
/**
|
|
2705
|
+
* Seed the cache from the CLOUD SHADOW (last-known values) WITHOUT waking the
|
|
2706
|
+
* robot — reads {@link VacuumDevice.DEFAULT_PROPS} from the cloud-cached
|
|
2707
|
+
* endpoint. After it resolves, every typed getter (status/battery/suction/
|
|
2708
|
+
* water/cleaningMode/error/charging…) reflects the cached values, so a
|
|
2709
|
+
* standby/docked vacuum reports its state exactly as the Dreamehome app does.
|
|
2710
|
+
*/
|
|
2711
|
+
async refreshFromCache() {
|
|
2712
|
+
await this.refreshCachedProperties([..._VacuumDevice.DEFAULT_PROPS]);
|
|
2713
|
+
}
|
|
2626
2714
|
// -- maps ---------------------------------------------------------------
|
|
2627
2715
|
/** The most-recently-decoded map, or `null` until {@link getMap} succeeds. */
|
|
2628
2716
|
get lastMap() {
|
|
@@ -3455,7 +3543,7 @@ var STATUS = enumLookup(
|
|
|
3455
3543
|
var CHARGING2 = enumLookup(
|
|
3456
3544
|
Object.values(MowerChargingStatus).filter((v) => typeof v === "number")
|
|
3457
3545
|
);
|
|
3458
|
-
var MowerDevice = class extends BaseDevice {
|
|
3546
|
+
var MowerDevice = class _MowerDevice extends BaseDevice {
|
|
3459
3547
|
#caps;
|
|
3460
3548
|
#fetchBatch;
|
|
3461
3549
|
#lastMap = null;
|
|
@@ -3595,6 +3683,16 @@ var MowerDevice = class extends BaseDevice {
|
|
|
3595
3683
|
}
|
|
3596
3684
|
return this.#sendTask(buildSpotPayload(spotAreaIds.map((s) => Math.trunc(s))));
|
|
3597
3685
|
}
|
|
3686
|
+
/**
|
|
3687
|
+
* Seed the cache from the CLOUD SHADOW (last-known values) WITHOUT waking the
|
|
3688
|
+
* mower — reads {@link MowerDevice.DEFAULT_PROPS} from the cloud-cached
|
|
3689
|
+
* endpoint. After it resolves, every typed getter (status/battery/charging/
|
|
3690
|
+
* coverage/task/controlAction…) reflects the cached values, so a docked/
|
|
3691
|
+
* standby mower reports its state exactly as the Dreamehome app does.
|
|
3692
|
+
*/
|
|
3693
|
+
async refreshFromCache() {
|
|
3694
|
+
await this.refreshCachedProperties([..._MowerDevice.DEFAULT_PROPS]);
|
|
3695
|
+
}
|
|
3598
3696
|
// -- maps ---------------------------------------------------------------
|
|
3599
3697
|
/** The most-recently-parsed map, or `null` until {@link getMap} succeeds. */
|
|
3600
3698
|
get lastMap() {
|