homebridge-roborock-matter 3.26.0 → 3.27.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/CHANGELOG.md +26 -0
- package/README.md +2 -2
- package/package.json +1 -1
- package/roborockLib/roborockAPI.js +65 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.27.0
|
|
4
|
+
|
|
5
|
+
**The scene resource named its one write verb, and it is the one that deletes. So the search moves off that resource and onto its siblings — asked safely, and this time with controls, so the round either finds the route or proves there is nothing left to find.**
|
|
6
|
+
|
|
7
|
+
3.26.0 asked `user/scene/<id>` which methods it accepts. Issue #22's reporter ran it and the answer came back on the first try:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
OPTIONS user/scene/<id> → "" — the resource allows: DELETE,OPTIONS
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
That is an answer, and not one of the two the thread had planned for. The plan said an `Allow` naming a write verb means the next step is a promised no-op, and a missing `Allow` means we are near the end of what can be measured from outside. What arrived names exactly one method that changes anything, and it removes a schedule rather than toggling one. There is no write there to put behind a HomeKit switch, and a destructive verb is not something to try against someone's live account to see what happens.
|
|
14
|
+
|
|
15
|
+
**What that rules out is the resource, not the feature.** The plugin's own scene-run path reaches `user/scene/<id>/execute`, so sub-resources under a scene id exist and carry verbs the scene itself does not. This release asks the same safe question of the routes that are left:
|
|
16
|
+
|
|
17
|
+
- `user/scene` — the collection, where a REST API most often keeps an update
|
|
18
|
+
- `user/scene/<id>/enable` — the literal candidate for the nested `TIMER` flag the reporter's app flips
|
|
19
|
+
|
|
20
|
+
**And of two controls, which is the part that makes the answers mean anything.** An `Allow` header on its own is not evidence:
|
|
21
|
+
|
|
22
|
+
- `user/scene/device/<duid>` — a **positive** control. This same probe run already read it successfully, so it is mapped beyond doubt. If `OPTIONS` cannot describe even that, the instrument does not see routes and no other answer in the set is worth reading. It is also why the control is this route and not `/execute`: a control must not be a path whose real verb starts a robot.
|
|
23
|
+
- `user/scene/<id>/no-such-subresource-control` — a **negative** control. If a path with nothing behind it also answers with an `Allow` header, the server answers everything and every positive here is an artefact.
|
|
24
|
+
|
|
25
|
+
Together they bound the search instead of extending it: this round either names a route or shows that no later round would.
|
|
26
|
+
|
|
27
|
+
Everything that made the probe safe to ship is unchanged and still bound by tests — silent unless debug logging is on, safe methods only, once per robot per session, cannot throw into the poll it rides on, and only the `Allow` header is taken from a response rather than the header block, which carries session material. A source guard now also pins the two properties that would otherwise fail invisibly: every candidate is narrowed to a safe method at one point, and the negative control cannot be dropped.
|
|
28
|
+
|
|
3
29
|
## 3.26.0
|
|
4
30
|
|
|
5
31
|
**The refused route answered, and what it said was that the route exists — just not for the verb we asked with. So this release asks it which verb it does take, without attempting one.**
|
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ This is the most feature-packed, most thoroughly engineered Roborock plugin for
|
|
|
37
37
|
- 📍 **See where it's cleaning — live.** Apple Home shows _"Cleaning — Kitchen"_ with the room the robot is actually inside, updating as it moves from room to room. Works even for cleans started from the robot's button or the Roborock app. No other Homebridge plugin does this.
|
|
38
38
|
- 🧭 **One robot, one tile — and as many robots as you own.** Sign in once and your whole fleet comes along: every vacuum on your account appears as its own clean, native accessory in Apple Home. No clutter of fake fans and helper switches, and rooms appear with the names you gave them in the Roborock app.
|
|
39
39
|
- ⚡ **Fast and reliable.** Commands go directly to the robot over your own network whenever possible, with the Roborock cloud as automatic backup — and built-in diagnostics in the settings if you ever want to look under the hood.
|
|
40
|
-
- 🛡️ **Verified by Homebridge.** Reviewed and endorsed by the Homebridge team.
|
|
40
|
+
- 🛡️ **Verified by Homebridge.** Reviewed and endorsed by the Homebridge team. 1862 automated tests, zero known vulnerabilities, no analytics, and a startup designed to never crash your Homebridge — even when your Wi-Fi or the Roborock cloud has a bad day.
|
|
41
41
|
|
|
42
42
|
## Features
|
|
43
43
|
|
|
@@ -258,7 +258,7 @@ The complete path — robot → plugin → Homebridge → matter.js store — wa
|
|
|
258
258
|
|
|
259
259
|
## Contributing
|
|
260
260
|
|
|
261
|
-
Model reports, diagnostics exports, and pull requests are very welcome. The codebase ships with
|
|
261
|
+
Model reports, diagnostics exports, and pull requests are very welcome. The codebase ships with 1862 tests (protocol fixtures verified against the [python-roborock](https://github.com/Python-roborock/python-roborock) reference), strict TypeScript checking, and CI across Node 22/24 × Homebridge 1.11/2.x — `npm test` before you push and you're set.
|
|
262
262
|
|
|
263
263
|
## Support the project
|
|
264
264
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-roborock-matter",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.27.0",
|
|
4
4
|
"description": "The most complete Roborock plugin for Apple Home. Supports the entire Roborock lineup — from the classic S-series to the new 2025 Q7 series that no other plugin can control. Sign in with your Roborock account and get native start/stop, room cleaning, suction levels, battery, and live 'cleaning in the kitchen' room tracking. Verified by Homebridge.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -299,6 +299,15 @@ const B01_STATUS_FORCED_GAP_MS = 1500;
|
|
|
299
299
|
const B01_STATUS_ACTIVE_GAP_MS = 12000;
|
|
300
300
|
const B01_STATUS_IDLE_GAP_MS = 25000;
|
|
301
301
|
|
|
302
|
+
// The last path segment of the cloud schedule probe's negative control.
|
|
303
|
+
//
|
|
304
|
+
// The probe asks candidate routes which methods they take. An `Allow` header
|
|
305
|
+
// coming back is only evidence if a route that CANNOT exist stays silent, so
|
|
306
|
+
// one deliberately unmappable path is asked the same question. It is a fixed
|
|
307
|
+
// literal rather than a random string so that the same reading is reproducible
|
|
308
|
+
// across restarts and legible in a log a user pastes into an issue.
|
|
309
|
+
const ABSENT_ROUTE_PROBE_SEGMENT = "no-such-subresource-control";
|
|
310
|
+
|
|
302
311
|
// How many keys of an arbitrary diagnostic object survive compaction.
|
|
303
312
|
const DIAGNOSTIC_KEY_LIMIT = 30;
|
|
304
313
|
|
|
@@ -4845,6 +4854,62 @@ class Roborock {
|
|
|
4845
4854
|
{ label: "sceneMethods", path: scenePath, method: "options" },
|
|
4846
4855
|
results
|
|
4847
4856
|
);
|
|
4857
|
+
|
|
4858
|
+
// And that question was answered: the resource allows DELETE and
|
|
4859
|
+
// OPTIONS. It is an answer, and not one of the two the thread's own
|
|
4860
|
+
// decision rule anticipated. The singular scene resource takes exactly
|
|
4861
|
+
// one method that changes anything, and it destroys a schedule rather
|
|
4862
|
+
// than toggling one — so there is no write here to put behind a HomeKit
|
|
4863
|
+
// switch, and a destructive verb aimed at a stranger's live account to
|
|
4864
|
+
// see what happens is not a measurement this project will take.
|
|
4865
|
+
//
|
|
4866
|
+
// That rules out the resource, not the feature. Our own `executeScene`
|
|
4867
|
+
// reaches `user/scene/{id}/execute`, so sub-resources under a scene id
|
|
4868
|
+
// demonstrably exist and carry verbs the scene itself does not. Whether
|
|
4869
|
+
// one of them is the toggle is the last question this instrument can
|
|
4870
|
+
// ask, and it is asked WITH CONTROLS, because on its own an `Allow`
|
|
4871
|
+
// header proves nothing:
|
|
4872
|
+
//
|
|
4873
|
+
// - `user/scene` — the collection, where a REST API most often keeps
|
|
4874
|
+
// an update;
|
|
4875
|
+
// - `user/scene/{id}/enable` — the literal candidate for the nested
|
|
4876
|
+
// flag the reporter's app flips;
|
|
4877
|
+
// - `user/scene/device/{duid}` — the POSITIVE control. This run has
|
|
4878
|
+
// ALREADY read it successfully, so it is mapped beyond doubt. If
|
|
4879
|
+
// OPTIONS cannot describe even that, the instrument does not see
|
|
4880
|
+
// routes and every other answer in this set is noise. It is also
|
|
4881
|
+
// why the control is this route and not `/execute`: a control must
|
|
4882
|
+
// not be a path whose real verb runs a robot.
|
|
4883
|
+
// - a path that cannot exist — the NEGATIVE control. If THAT comes
|
|
4884
|
+
// back with an Allow header, the server answers everything and no
|
|
4885
|
+
// positive here means anything.
|
|
4886
|
+
//
|
|
4887
|
+
// Together they bound the search rather than extend it: this round
|
|
4888
|
+
// either names a route or shows that no later round would.
|
|
4889
|
+
//
|
|
4890
|
+
// Asking costs nothing that could alter a schedule, and that is
|
|
4891
|
+
// measured rather than assumed: the OPTIONS of the scene resource came
|
|
4892
|
+
// back with an EMPTY body and an Allow header, which is a servlet
|
|
4893
|
+
// container answering the request itself instead of handing it to the
|
|
4894
|
+
// handler behind the path.
|
|
4895
|
+
for (const candidate of [
|
|
4896
|
+
{ label: "sceneCollectionMethods", path: "user/scene" },
|
|
4897
|
+
{ label: "sceneEnableMethods", path: `${scenePath}/enable` },
|
|
4898
|
+
{
|
|
4899
|
+
label: "mappedRouteControl",
|
|
4900
|
+
path: `user/scene/device/${duid}`,
|
|
4901
|
+
},
|
|
4902
|
+
{
|
|
4903
|
+
label: "absentRouteControl",
|
|
4904
|
+
path: `${scenePath}/${ABSENT_ROUTE_PROBE_SEGMENT}`,
|
|
4905
|
+
},
|
|
4906
|
+
]) {
|
|
4907
|
+
await this.probeOneCloudScheduleRoute(
|
|
4908
|
+
duid,
|
|
4909
|
+
{ ...candidate, method: "options" },
|
|
4910
|
+
results
|
|
4911
|
+
);
|
|
4912
|
+
}
|
|
4848
4913
|
}
|
|
4849
4914
|
|
|
4850
4915
|
await this.updateRoborockDiagnostics(
|