@mega-yfue/eufy-sdk 0.2.0-beta.3 → 0.2.0-beta.5
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.js
CHANGED
|
@@ -7737,6 +7737,89 @@ var ModeCtrlMethod = {
|
|
|
7737
7737
|
STOP_SMART_FOLLOW: 18,
|
|
7738
7738
|
START_GLOBAL_CRUISE: 20
|
|
7739
7739
|
};
|
|
7740
|
+
var ModeCtrlParamMethod = {
|
|
7741
|
+
/** `START_SELECT_ROOMS_CLEAN` — clean the named rooms of a named map. */
|
|
7742
|
+
SELECT_ROOMS: { method: 1, param: 4 },
|
|
7743
|
+
/** `START_SELECT_ZONES_CLEAN` — clean the given rectangles of a named map. */
|
|
7744
|
+
SELECT_ZONES: { method: 2, param: 5 },
|
|
7745
|
+
/** `START_GOTO_CLEAN` — drive to a point and clean around it. */
|
|
7746
|
+
GOTO: { method: 4, param: 7 },
|
|
7747
|
+
/** `START_SCENE_CLEAN` — run a saved scene by its id. */
|
|
7748
|
+
SCENE: { method: 24, param: 14 }
|
|
7749
|
+
};
|
|
7750
|
+
var SELECT_ROOMS_FIELD = {
|
|
7751
|
+
/** `rooms` — repeated, one entry per room. */
|
|
7752
|
+
ROOMS: 1,
|
|
7753
|
+
/** `clean_times` — how many passes to make. */
|
|
7754
|
+
CLEAN_TIMES: 2,
|
|
7755
|
+
/** `map_id` — WHICH saved map the room ids belong to. */
|
|
7756
|
+
MAP_ID: 3,
|
|
7757
|
+
/** `id` within a `Room`. */
|
|
7758
|
+
ROOM_ID: 1,
|
|
7759
|
+
/** `order` within a `Room` — the sequence to visit them in. */
|
|
7760
|
+
ROOM_ORDER: 2
|
|
7761
|
+
};
|
|
7762
|
+
var SELECT_ZONES_FIELD = {
|
|
7763
|
+
/** `zones` — repeated, one entry per rectangle. */
|
|
7764
|
+
ZONES: 1,
|
|
7765
|
+
/** `map_id` — which saved map the coordinates belong to. */
|
|
7766
|
+
MAP_ID: 2,
|
|
7767
|
+
/** `quadrangle` within a `Zone` — its four corners. */
|
|
7768
|
+
QUADRANGLE: 1,
|
|
7769
|
+
/** `clean_times` within a `Zone`. */
|
|
7770
|
+
ZONE_CLEAN_TIMES: 2,
|
|
7771
|
+
/** `x` within a `Point`, SIGNED centimetres. */
|
|
7772
|
+
POINT_X: 1,
|
|
7773
|
+
/** `y` within a `Point`, SIGNED centimetres. */
|
|
7774
|
+
POINT_Y: 2
|
|
7775
|
+
};
|
|
7776
|
+
var SCENE_CLEAN_ID = 1;
|
|
7777
|
+
function encodeModeCtrlParam(method2, paramField, build) {
|
|
7778
|
+
return rawDp((w) => {
|
|
7779
|
+
if (method2 !== 0)
|
|
7780
|
+
w.int(MODE_CTRL_FIELD.METHOD, method2);
|
|
7781
|
+
w.int(MODE_CTRL_FIELD.SEQ, nextModeCtrlSeq());
|
|
7782
|
+
w.sub(paramField, build);
|
|
7783
|
+
});
|
|
7784
|
+
}
|
|
7785
|
+
function encodeSelectRoomsClean(mapId, rooms, cleanTimes = 1) {
|
|
7786
|
+
const { method: method2, param } = ModeCtrlParamMethod.SELECT_ROOMS;
|
|
7787
|
+
return encodeModeCtrlParam(method2, param, (p) => {
|
|
7788
|
+
for (const room of rooms) {
|
|
7789
|
+
p.sub(SELECT_ROOMS_FIELD.ROOMS, (r) => {
|
|
7790
|
+
r.int(SELECT_ROOMS_FIELD.ROOM_ID, room.id);
|
|
7791
|
+
if (room.order !== void 0)
|
|
7792
|
+
r.int(SELECT_ROOMS_FIELD.ROOM_ORDER, room.order);
|
|
7793
|
+
});
|
|
7794
|
+
}
|
|
7795
|
+
p.int(SELECT_ROOMS_FIELD.CLEAN_TIMES, cleanTimes);
|
|
7796
|
+
p.int(SELECT_ROOMS_FIELD.MAP_ID, mapId);
|
|
7797
|
+
});
|
|
7798
|
+
}
|
|
7799
|
+
function encodeSelectZonesClean(mapId, zones) {
|
|
7800
|
+
const { method: method2, param } = ModeCtrlParamMethod.SELECT_ZONES;
|
|
7801
|
+
return encodeModeCtrlParam(method2, param, (p) => {
|
|
7802
|
+
for (const zone of zones) {
|
|
7803
|
+
p.sub(SELECT_ZONES_FIELD.ZONES, (z) => {
|
|
7804
|
+
z.sub(SELECT_ZONES_FIELD.QUADRANGLE, (q) => {
|
|
7805
|
+
for (const [i, corner] of zone.corners.entries()) {
|
|
7806
|
+
q.sub(i + 1, (pt) => {
|
|
7807
|
+
pt.sint(SELECT_ZONES_FIELD.POINT_X, corner.x);
|
|
7808
|
+
pt.sint(SELECT_ZONES_FIELD.POINT_Y, corner.y);
|
|
7809
|
+
});
|
|
7810
|
+
}
|
|
7811
|
+
});
|
|
7812
|
+
if (zone.cleanTimes !== void 0)
|
|
7813
|
+
z.int(SELECT_ZONES_FIELD.ZONE_CLEAN_TIMES, zone.cleanTimes);
|
|
7814
|
+
});
|
|
7815
|
+
}
|
|
7816
|
+
p.int(SELECT_ZONES_FIELD.MAP_ID, mapId);
|
|
7817
|
+
});
|
|
7818
|
+
}
|
|
7819
|
+
function encodeSceneClean(sceneId) {
|
|
7820
|
+
const { method: method2, param } = ModeCtrlParamMethod.SCENE;
|
|
7821
|
+
return encodeModeCtrlParam(method2, param, (p) => p.int(SCENE_CLEAN_ID, sceneId));
|
|
7822
|
+
}
|
|
7740
7823
|
var modeCtrlSeq = 111;
|
|
7741
7824
|
function nextModeCtrlSeq() {
|
|
7742
7825
|
return ++modeCtrlSeq;
|
|
@@ -9572,7 +9655,41 @@ var VACUUM_CLEAN_MEMBERS = {
|
|
|
9572
9655
|
/** Return to the dock via ModeCtrlRequest method 6 (DP 152). AIoT only — Tuya write unverified. */
|
|
9573
9656
|
returnToDock: method(({ sink }) => () => sink.dispatch(aiotDp(VACUUM_DP.MODE_CTRL, encodeModeCtrl(ModeCtrlMethod.START_GOHOME, nextModeCtrlSeq()))), "Return to the dock (ModeCtrlRequest method 6 over DP 152).", isAiotVacuum),
|
|
9574
9657
|
/** Pause the current cleaning task via ModeCtrlRequest method 13 (DP 152). AIoT only — Tuya write unverified. */
|
|
9575
|
-
pauseCleaning: method(({ sink }) => () => sink.dispatch(aiotDp(VACUUM_DP.MODE_CTRL, encodeModeCtrl(ModeCtrlMethod.PAUSE_TASK, nextModeCtrlSeq()))), "Pause the current cleaning task (ModeCtrlRequest method 13 over DP 152).", isAiotVacuum)
|
|
9658
|
+
pauseCleaning: method(({ sink }) => () => sink.dispatch(aiotDp(VACUUM_DP.MODE_CTRL, encodeModeCtrl(ModeCtrlMethod.PAUSE_TASK, nextModeCtrlSeq()))), "Pause the current cleaning task (ModeCtrlRequest method 13 over DP 152).", isAiotVacuum),
|
|
9659
|
+
/**
|
|
9660
|
+
* Run a saved cleaning scene by its id (ModeCtrlRequest method 24 over DP 152).
|
|
9661
|
+
*
|
|
9662
|
+
* The id is the device's own, as {@link VACUUM_CLEAN_MEMBERS.scenes} reports it — `VacuumScene.id`
|
|
9663
|
+
* off the `SceneResponse` on DP 180. A scene the device reports invalid stays reportable and running
|
|
9664
|
+
* it is still a well-formed request; `VacuumScene.invalidReason` says why the device will refuse.
|
|
9665
|
+
*
|
|
9666
|
+
* Frame shape is byte-proven against the shared outer `ModeCtrlRequest`, and method 24 has been
|
|
9667
|
+
* WATCHED: run on a T2351, it started the named scene.
|
|
9668
|
+
*/
|
|
9669
|
+
startScene: method(({ sink }) => (sceneId) => sink.dispatch(aiotDp(VACUUM_DP.MODE_CTRL, encodeSceneClean(sceneId))), "Run a saved cleaning scene by its id (ModeCtrlRequest method 24 over DP 152).", isAiotVacuum),
|
|
9670
|
+
/**
|
|
9671
|
+
* Clean the named rooms of a named map (ModeCtrlRequest method 1 over DP 152).
|
|
9672
|
+
*
|
|
9673
|
+
* `mapId` has no default and that is deliberate: room ids are per map, so assuming the map a
|
|
9674
|
+
* single-floor home would have sends a two-floor home's ids against the wrong floor. `SceneInfo.mapid`
|
|
9675
|
+
* on DP 180 and a scheduled rooms-clean's `map_id` are the two real map ids the device reports.
|
|
9676
|
+
*
|
|
9677
|
+
* `cleanTimes` is how many passes to make over the set; rooms with no `order` are visited in the
|
|
9678
|
+
* order given.
|
|
9679
|
+
*
|
|
9680
|
+
* Frame shape is byte-proven against the shared outer `ModeCtrlRequest`, and method 1 has been
|
|
9681
|
+
* WATCHED: run on a T2351, it cleaned the rooms named.
|
|
9682
|
+
*/
|
|
9683
|
+
cleanRooms: method(({ sink }) => (mapId, rooms, cleanTimes = 1) => sink.dispatch(aiotDp(VACUUM_DP.MODE_CTRL, encodeSelectRoomsClean(mapId, rooms, cleanTimes))), "Clean the named rooms of a named map (ModeCtrlRequest method 1 over DP 152).", isAiotVacuum),
|
|
9684
|
+
/**
|
|
9685
|
+
* Clean the given rectangles of a named map (ModeCtrlRequest method 2 over DP 152).
|
|
9686
|
+
*
|
|
9687
|
+
* Corners are SIGNED centimetres in the map's own frame, whose origin sits wherever the robot first
|
|
9688
|
+
* mapped from — negative coordinates are ordinary and are ZigZag-encoded, not written as plain
|
|
9689
|
+
* varints. Same `mapId` reasoning as {@link VACUUM_CLEAN_MEMBERS.cleanRooms}, and the same evidence:
|
|
9690
|
+
* method 2 was run on a T2351 and cleaned the rectangles given.
|
|
9691
|
+
*/
|
|
9692
|
+
cleanZones: method(({ sink }) => (mapId, zones) => sink.dispatch(aiotDp(VACUUM_DP.MODE_CTRL, encodeSelectZonesClean(mapId, zones))), "Clean the given rectangles of a named map (ModeCtrlRequest method 2 over DP 152).", isAiotVacuum)
|
|
9576
9693
|
};
|
|
9577
9694
|
var VACUUM_CLEAN = {
|
|
9578
9695
|
capability: "vacuum_clean",
|
|
@@ -16417,10 +16534,12 @@ var LiveStream = class extends EventEmitter3 {
|
|
|
16417
16534
|
if (!this.listening || this.kaTimer)
|
|
16418
16535
|
return;
|
|
16419
16536
|
if (this.opts.reassertWanted?.() === false) {
|
|
16537
|
+
this.trace({ phase: "channel-silent", silentMs: stallMs, outcome: "declined" });
|
|
16420
16538
|
this.logger.debug(`[live ch${this.channel}] no own media for ${stallMs}ms, and its owner does not want this channel re-asserted \u2014 staying quiet`);
|
|
16421
16539
|
this.armStallWatch();
|
|
16422
16540
|
return;
|
|
16423
16541
|
}
|
|
16542
|
+
this.trace({ phase: "channel-silent", silentMs: stallMs, outcome: "reasserted" });
|
|
16424
16543
|
this.logger.debug(`[live ch${this.channel}] no own media for ${stallMs}ms \u2014 re-asserting this camera's channel`);
|
|
16425
16544
|
this.sendStart();
|
|
16426
16545
|
this.kaTimer = setInterval(() => this.sendStart(), keepAliveMs);
|
|
@@ -16641,10 +16760,12 @@ async function captureSnapshotFromShared(source, opts = {}) {
|
|
|
16641
16760
|
const timeoutMs = opts.timeoutMs ?? 2e4;
|
|
16642
16761
|
const collectMs = opts.collectMs ?? 1500;
|
|
16643
16762
|
const skip = opts.skipKeyframes ?? 1;
|
|
16763
|
+
opts.signal?.throwIfAborted();
|
|
16644
16764
|
const consumer = source.attach();
|
|
16645
16765
|
const primed = consumer.primed;
|
|
16766
|
+
let burst;
|
|
16646
16767
|
try {
|
|
16647
|
-
|
|
16768
|
+
burst = await new Promise((resolve, reject) => {
|
|
16648
16769
|
const bufs = [];
|
|
16649
16770
|
let sets = source.parameterSets;
|
|
16650
16771
|
let codec = "h264";
|
|
@@ -16679,6 +16800,10 @@ async function captureSnapshotFromShared(source, opts = {}) {
|
|
|
16679
16800
|
cleanup();
|
|
16680
16801
|
reject(new LiveSnapshotUnavailableError("source-failed", `source ended before a keyframe (state: ${source.state})`));
|
|
16681
16802
|
};
|
|
16803
|
+
const onAbandoned = () => {
|
|
16804
|
+
cleanup();
|
|
16805
|
+
reject(opts.signal?.reason);
|
|
16806
|
+
};
|
|
16682
16807
|
const cleanup = () => {
|
|
16683
16808
|
clearTimeout(timer);
|
|
16684
16809
|
if (settle)
|
|
@@ -16686,19 +16811,21 @@ async function captureSnapshotFromShared(source, opts = {}) {
|
|
|
16686
16811
|
consumer.off("video", onVideo);
|
|
16687
16812
|
consumer.off("error", onError);
|
|
16688
16813
|
consumer.off("stop", onStop);
|
|
16814
|
+
opts.signal?.removeEventListener("abort", onAbandoned);
|
|
16689
16815
|
};
|
|
16690
16816
|
consumer.on("video", onVideo);
|
|
16691
16817
|
consumer.on("error", onError);
|
|
16692
16818
|
consumer.on("stop", onStop);
|
|
16693
|
-
|
|
16694
|
-
return await annexbToJpeg(primeForDecode(burst.h264, burst.sets, burst.codec), {
|
|
16695
|
-
logger: opts.logger ?? noopLogger,
|
|
16696
|
-
level: opts.ffmpegLevel,
|
|
16697
|
-
executable: opts.ffmpegPath
|
|
16819
|
+
opts.signal?.addEventListener("abort", onAbandoned, { once: true });
|
|
16698
16820
|
});
|
|
16699
16821
|
} finally {
|
|
16700
16822
|
consumer.detach();
|
|
16701
16823
|
}
|
|
16824
|
+
return annexbToJpeg(primeForDecode(burst.h264, burst.sets, burst.codec), {
|
|
16825
|
+
logger: opts.logger ?? noopLogger,
|
|
16826
|
+
level: opts.ffmpegLevel,
|
|
16827
|
+
executable: opts.ffmpegPath
|
|
16828
|
+
});
|
|
16702
16829
|
}
|
|
16703
16830
|
async function recordClip(session, seconds, opts = {}) {
|
|
16704
16831
|
const timeoutMs = opts.timeoutMs ?? 2e4;
|
|
@@ -19271,12 +19398,12 @@ var P2PCommandRouter = class _P2PCommandRouter {
|
|
|
19271
19398
|
return {
|
|
19272
19399
|
snapshotLive: async (opts) => {
|
|
19273
19400
|
const source = await this.sharedLiveSourceFor(sn, opts ?? {});
|
|
19274
|
-
return
|
|
19401
|
+
return captureSnapshotFromShared(source, {
|
|
19275
19402
|
...opts,
|
|
19276
19403
|
logger: this.deps.logger ?? noopLogger,
|
|
19277
19404
|
ffmpegLevel: this.deps.ffmpegLogLevel,
|
|
19278
19405
|
ffmpegPath: this.deps.ffmpegPath
|
|
19279
|
-
})
|
|
19406
|
+
});
|
|
19280
19407
|
},
|
|
19281
19408
|
live: async (opts) => {
|
|
19282
19409
|
const source = await this.sharedLiveSourceFor(sn, opts);
|