@mega-yfue/eufy-sdk 0.2.0-beta.4 → 0.2.0-beta.6
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 +212 -4
- package/dist/index.js.map +3 -3
- package/dist/model/capabilities/display.d.ts +85 -0
- package/dist/model/capabilities/index.d.ts +5 -1
- package/dist/model/capabilities/types.d.ts +9 -2
- package/dist/model/capabilities/vacuum-clean.d.ts +74 -25
- package/dist/model/param-dictionary.d.ts +24 -0
- package/dist/model/param-namespace.d.ts +1 -1
- package/dist/model/types.d.ts +5 -5
- package/package.json +1 -1
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",
|
|
@@ -9748,6 +9865,70 @@ function toNumberArray(arr) {
|
|
|
9748
9865
|
return result;
|
|
9749
9866
|
}
|
|
9750
9867
|
|
|
9868
|
+
// dist/model/capabilities/display.js
|
|
9869
|
+
var DISPLAY_PARAM = { BATTERY: 8001, SOFTWARE_VERSION: 8003 };
|
|
9870
|
+
var DISPLAY_MEMBERS = {
|
|
9871
|
+
/**
|
|
9872
|
+
* Battery level, 0-100.
|
|
9873
|
+
*
|
|
9874
|
+
* **On this capability rather than on `battery`, and that is the line partition doing its job.** The
|
|
9875
|
+
* security-line `battery` capability reads param 1101 and a Smart Display's charge is 8001 in its own
|
|
9876
|
+
* id space — two wires that happen to mean the same thing. One capability reading both would be a claim
|
|
9877
|
+
* that the two ecosystems share a param space, so a consumer reads a display's charge through
|
|
9878
|
+
* `dev.display()` and a camera's through `dev.battery()`.
|
|
9879
|
+
*
|
|
9880
|
+
* `verified` rather than `mega`: the id is in the device's cloud record, but the NAME came from the
|
|
9881
|
+
* maintainer's own knowledge of the hardware rather than from the cloud data-point list, and `"100"`
|
|
9882
|
+
* fits brightness, volume or charge equally.
|
|
9883
|
+
*
|
|
9884
|
+
* The scale is `percent` on the reading itself, not on convention alone: a full charge reads `255` on a
|
|
9885
|
+
* 0-255 scale and `1000` on a 0-1000 one, so `"100"` on a charged unit is positive evidence for 0-100
|
|
9886
|
+
* rather than merely consistent with it. What nobody has done is watch it MOVE, which is why a value
|
|
9887
|
+
* frozen at 100 would not yet be distinguishable from a healthy one.
|
|
9888
|
+
*/
|
|
9889
|
+
battery: {
|
|
9890
|
+
param: DISPLAY_PARAM.BATTERY,
|
|
9891
|
+
type: "number",
|
|
9892
|
+
unit: "%",
|
|
9893
|
+
kind: "percent",
|
|
9894
|
+
provenance: "verified",
|
|
9895
|
+
description: "Battery level, 0-100 (param 8001)."
|
|
9896
|
+
},
|
|
9897
|
+
/**
|
|
9898
|
+
* Version-shaped, and that shape is the whole of the evidence — hence `guessed`, and hence no typed
|
|
9899
|
+
* getter: a caller reading this off a bound object cannot see the label.
|
|
9900
|
+
*
|
|
9901
|
+
* `unexposed` rather than absent, so the schema still carries its type and that label and
|
|
9902
|
+
* `getProperty("softwareVersion")` still answers. `dev.info()?.firmwareVersion` is the field to trust
|
|
9903
|
+
* where the cloud record carries one; on this display it does not, which is the only reason 8003 is
|
|
9904
|
+
* named at all.
|
|
9905
|
+
*/
|
|
9906
|
+
softwareVersion: {
|
|
9907
|
+
param: DISPLAY_PARAM.SOFTWARE_VERSION,
|
|
9908
|
+
type: "string",
|
|
9909
|
+
kind: "text",
|
|
9910
|
+
provenance: "guessed",
|
|
9911
|
+
unexposed: true,
|
|
9912
|
+
description: "Version-shaped string (param 8003), meaning unconfirmed \u2014 prefer `info.firmwareVersion`."
|
|
9913
|
+
}
|
|
9914
|
+
};
|
|
9915
|
+
var DISPLAY = {
|
|
9916
|
+
capability: "display",
|
|
9917
|
+
line: "display",
|
|
9918
|
+
description: "Smart Display battery level (param 8001, display namespace).",
|
|
9919
|
+
members: DISPLAY_MEMBERS,
|
|
9920
|
+
properties: propertiesOf(DISPLAY_MEMBERS),
|
|
9921
|
+
/**
|
|
9922
|
+
* Claimed by CODEC, not by an evidence param.
|
|
9923
|
+
*
|
|
9924
|
+
* 8001 is in the device's cloud record, so the ordinary evidence gate would install the getter anyway
|
|
9925
|
+
* — but the capability should attach to a Smart Display that has reported nothing yet too, because a
|
|
9926
|
+
* device on this line has no other capability to carry it. The line partition keeps this off
|
|
9927
|
+
* everything else: `display` is the only codec in the `display` line.
|
|
9928
|
+
*/
|
|
9929
|
+
detection: { codecs: ["display"] }
|
|
9930
|
+
};
|
|
9931
|
+
|
|
9751
9932
|
// dist/model/capabilities/locate.js
|
|
9752
9933
|
var LOCATE_DP = 160;
|
|
9753
9934
|
var LEGACY_LOCATE_DP = TUYA_VACUUM_DP.LOOK_FOR_SWEEPER;
|
|
@@ -9876,6 +10057,7 @@ var MODULES = [
|
|
|
9876
10057
|
VACUUM_DOCK,
|
|
9877
10058
|
SUCTION,
|
|
9878
10059
|
LOCATE,
|
|
10060
|
+
DISPLAY,
|
|
9879
10061
|
INFO
|
|
9880
10062
|
];
|
|
9881
10063
|
var BY_CAP = new Map(MODULES.map((m) => [m.capability, m]));
|
|
@@ -9920,7 +10102,7 @@ var CODEC_LINE = {
|
|
|
9920
10102
|
mower: "clean",
|
|
9921
10103
|
light: "life",
|
|
9922
10104
|
printer: "print",
|
|
9923
|
-
display: "
|
|
10105
|
+
display: "display"
|
|
9924
10106
|
};
|
|
9925
10107
|
function lineAllows(module, codec) {
|
|
9926
10108
|
const line = module.line ?? "security";
|
|
@@ -12020,6 +12202,28 @@ var CLEAN_PARAMS = {
|
|
|
12020
12202
|
provenance: "mega"
|
|
12021
12203
|
}
|
|
12022
12204
|
};
|
|
12205
|
+
var DISPLAY_PARAMS = {
|
|
12206
|
+
8001: {
|
|
12207
|
+
name: "battery",
|
|
12208
|
+
type: "number",
|
|
12209
|
+
provenance: "verified"
|
|
12210
|
+
},
|
|
12211
|
+
8003: {
|
|
12212
|
+
name: "softwareVersion",
|
|
12213
|
+
type: "string",
|
|
12214
|
+
provenance: "guessed"
|
|
12215
|
+
},
|
|
12216
|
+
8005: {
|
|
12217
|
+
name: "modelName",
|
|
12218
|
+
type: "string",
|
|
12219
|
+
provenance: "mega"
|
|
12220
|
+
},
|
|
12221
|
+
8006: {
|
|
12222
|
+
name: "modelCode",
|
|
12223
|
+
type: "string",
|
|
12224
|
+
provenance: "mega"
|
|
12225
|
+
}
|
|
12226
|
+
};
|
|
12023
12227
|
|
|
12024
12228
|
// dist/model/life-params.js
|
|
12025
12229
|
var LIFE_PARAMS = {
|
|
@@ -12047,7 +12251,10 @@ var TABLES = {
|
|
|
12047
12251
|
// 3D-printer (ankermake) id space — empty until a live capture confirms the param↔semantic map
|
|
12048
12252
|
// (printer-support plan Stage 3). Present so the printer codec resolves to its OWN namespace rather
|
|
12049
12253
|
// than falling through to `security` and decoding another line's dictionary.
|
|
12050
|
-
print: {}
|
|
12254
|
+
print: {},
|
|
12255
|
+
// Smart Display (T87Ax) — ids 8001-8006, four of them named. Same reason as `print`: its own
|
|
12256
|
+
// dictionary rather than a corner of another line's.
|
|
12257
|
+
display: DISPLAY_PARAMS
|
|
12051
12258
|
};
|
|
12052
12259
|
function paramDef(ns, paramType) {
|
|
12053
12260
|
return TABLES[ns][paramType];
|
|
@@ -12062,7 +12269,7 @@ var NAMESPACE_BY_CODEC = {
|
|
|
12062
12269
|
mower: "clean",
|
|
12063
12270
|
light: "life",
|
|
12064
12271
|
printer: "print",
|
|
12065
|
-
display: "
|
|
12272
|
+
display: "display"
|
|
12066
12273
|
};
|
|
12067
12274
|
function namespaceForCodec(codec) {
|
|
12068
12275
|
return NAMESPACE_BY_CODEC[codec];
|
|
@@ -25424,6 +25631,7 @@ export {
|
|
|
25424
25631
|
CusPushEvent,
|
|
25425
25632
|
CusPushMode,
|
|
25426
25633
|
DEFAULT_KEEPALIVE_MS,
|
|
25634
|
+
DISPLAY_MEMBERS,
|
|
25427
25635
|
DOCK_ACTIVITIES,
|
|
25428
25636
|
DOCK_KINDS,
|
|
25429
25637
|
DOORBELL_MEMBERS,
|