homebridge-roborock-matter 3.4.1 → 3.4.2
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 +10 -0
- package/package.json +1 -1
- package/roborockLib/lib/b01Q7Adapter.js +26 -0
- package/roborockLib/roborockAPI.js +73 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.4.2
|
|
4
|
+
|
|
5
|
+
**Q7-series robots are no longer asked for things they cannot answer.** Every restart, each Q7-generation robot (`roborock.vacuum.sc05`, `ss07`, and the rest of the B01 family) logged an unsupported-method notice — most visibly for `get_water_box_custom_mode`, and also for `get_timer` and `get_carpet_clean_mode`. The message blamed the robot, and the robot was never involved: the plugin's own send path rejects v1-only requests for B01 devices before anything reaches the network, and the poller then recorded that self-rejection as though the robot had answered it.
|
|
6
|
+
|
|
7
|
+
- **The periodic poller now consults the dialect before asking.** For a B01 robot it skips exactly the requests that have neither a Q7 translation nor a neutral placeholder, and says so once per robot at debug level instead of once per robot as a notice. Classic S- and Q-series robots poll precisely as before.
|
|
8
|
+
- **The check derives from the translation table itself**, not from a hand-written list of method names — a second list would drift the first time a translation was added, and the drift would only ever show up as noise in somebody's log.
|
|
9
|
+
- **The poll-profile line stops promising a water-box probe it will not perform** on a robot whose water tank is filled by hand and has no electronic level to read.
|
|
10
|
+
- **A test enumerates the rule rather than the three reported methods:** for a B01 robot, no periodic poll may be one the dialect cannot answer. Probes added later are covered without anyone having to remember this.
|
|
11
|
+
- Also fixed: the B01 full-chain simulation ran under Jest's 5-second default, which quietly made suite-wide CPU load an implicit assertion — it began failing on an unrelated new test file. Its wall-clock time was never what it set out to verify.
|
|
12
|
+
|
|
3
13
|
## 3.4.1
|
|
4
14
|
|
|
5
15
|
**The Matter fault attribute is withdrawn.** Wazza151 ran three controlled tests on an S8 Pro Ultra with a genuinely empty clean water tank ([#5](https://github.com/mathiashornbek/homebridge-roborock-matter/issues/5)) and the result was unambiguous: Apple Home drew no warning with the fault published beside a Charging state, drew no warning with it published beside a forced Error state either, and the tile went into a stuck "Updating…" that needed a manual poke to clear. Everything off, and the tile behaved perfectly.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-roborock-matter",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.2",
|
|
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": {
|
|
@@ -714,6 +714,31 @@ function neutralResponse(method) {
|
|
|
714
714
|
return factory ? { value: factory() } : undefined;
|
|
715
715
|
}
|
|
716
716
|
|
|
717
|
+
/**
|
|
718
|
+
* True when a v1-shaped request has *any* answer on a Q7 robot — a real
|
|
719
|
+
* translation or a neutral placeholder. Everything else is rejected by the
|
|
720
|
+
* send choke point in messageQueueHandler with a B01_METHOD_UNSUPPORTED
|
|
721
|
+
* error, so the periodic poller can consult this instead of asking for
|
|
722
|
+
* something the plugin already knows will fail.
|
|
723
|
+
*
|
|
724
|
+
* Derived from the same two sources the choke point uses, deliberately: a
|
|
725
|
+
* separate hand-written list would drift the first time a translation is
|
|
726
|
+
* added, and the drift would only show up as noise in a user's log.
|
|
727
|
+
* @param {string} method
|
|
728
|
+
* @returns {boolean}
|
|
729
|
+
*/
|
|
730
|
+
function canAnswerV1Method(method) {
|
|
731
|
+
if (NEUTRAL_RESPONSES.has(method)) {
|
|
732
|
+
return true;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
try {
|
|
736
|
+
return Boolean(translateOutgoing(method, []));
|
|
737
|
+
} catch {
|
|
738
|
+
return false;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
717
742
|
/**
|
|
718
743
|
* Map a Q7 `prop.get` status payload to v1-shaped status fields.
|
|
719
744
|
* Fixture reference: {"status":4,"quantity":87,"fault":0,...}
|
|
@@ -796,5 +821,6 @@ module.exports = {
|
|
|
796
821
|
createB01MessageId,
|
|
797
822
|
translateOutgoing,
|
|
798
823
|
neutralResponse,
|
|
824
|
+
canAnswerV1Method,
|
|
799
825
|
mapStatusToV1,
|
|
800
826
|
};
|
|
@@ -201,6 +201,7 @@ class Roborock {
|
|
|
201
201
|
// repeated warnings for requests they will never answer.
|
|
202
202
|
this.unsupportedPollCommands = new Set();
|
|
203
203
|
this.loggedPollProfiles = new Set();
|
|
204
|
+
this.skippedDialectPolls = new Set();
|
|
204
205
|
this.baseURL = options.baseURL || "usiot.roborock.com";
|
|
205
206
|
|
|
206
207
|
this.userData = options.userData || null;
|
|
@@ -2470,6 +2471,29 @@ class Roborock {
|
|
|
2470
2471
|
return true;
|
|
2471
2472
|
}
|
|
2472
2473
|
|
|
2474
|
+
/**
|
|
2475
|
+
* Poll one v1 parameter, unless the robot speaks a dialect that has no
|
|
2476
|
+
* answer for it. Every periodic probe goes through here so the rule holds
|
|
2477
|
+
* for probes added later, not just the three that were reported.
|
|
2478
|
+
* @param {string} duid @param {any} vacuum @param {string} method
|
|
2479
|
+
* @param {boolean} isB01
|
|
2480
|
+
* @returns {Promise<any>}
|
|
2481
|
+
*/
|
|
2482
|
+
async pollParameter(duid, vacuum, method, isB01) {
|
|
2483
|
+
if (isB01 && !b01Q7Adapter.canAnswerV1Method(method)) {
|
|
2484
|
+
const key = `${duid}:${method}`;
|
|
2485
|
+
if (!this.skippedDialectPolls.has(key)) {
|
|
2486
|
+
this.skippedDialectPolls.add(key);
|
|
2487
|
+
this.log.debug(
|
|
2488
|
+
`Not polling '${method}' for ${this.describeDevice(duid)}: the Q7/B01 dialect has no equivalent request, so the robot could only ever reject it.`
|
|
2489
|
+
);
|
|
2490
|
+
}
|
|
2491
|
+
return undefined;
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
return vacuum.getParameter(duid, method);
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2473
2497
|
startMainUpdateInterval(duid, online) {
|
|
2474
2498
|
if (!this.hasInitializedVacuum(duid)) {
|
|
2475
2499
|
return;
|
|
@@ -2628,18 +2652,26 @@ class Roborock {
|
|
|
2628
2652
|
this.log.debug(`Latest data requested`);
|
|
2629
2653
|
|
|
2630
2654
|
if (this.isSupportedVacuumModel(robotModel)) {
|
|
2655
|
+
// Q7-series robots speak the B01 dialect, where a good half of the v1
|
|
2656
|
+
// poll chain has no equivalent request at all. Asking anyway produced
|
|
2657
|
+
// an "unsupported" notice per robot per restart for a request the
|
|
2658
|
+
// plugin itself rejected before it ever reached the robot.
|
|
2659
|
+
const isB01 = b01Q7Adapter.isB01Protocol(
|
|
2660
|
+
await this.getRobotVersion(duid)
|
|
2661
|
+
);
|
|
2662
|
+
|
|
2631
2663
|
const refreshedServiceAreaRooms =
|
|
2632
2664
|
await this.refreshMatterServiceAreaRoomMappings(duid, vacuum);
|
|
2633
2665
|
|
|
2634
2666
|
if (!refreshedServiceAreaRooms) {
|
|
2635
|
-
await
|
|
2667
|
+
await this.pollParameter(duid, vacuum, "get_room_mapping", isB01);
|
|
2636
2668
|
}
|
|
2637
2669
|
|
|
2638
|
-
await
|
|
2670
|
+
await this.pollParameter(duid, vacuum, "get_consumable", isB01);
|
|
2639
2671
|
|
|
2640
|
-
await
|
|
2672
|
+
await this.pollParameter(duid, vacuum, "get_server_timer", isB01);
|
|
2641
2673
|
|
|
2642
|
-
await
|
|
2674
|
+
await this.pollParameter(duid, vacuum, "get_timer", isB01);
|
|
2643
2675
|
|
|
2644
2676
|
await this.checkForNewFirmware(duid);
|
|
2645
2677
|
|
|
@@ -2657,13 +2689,28 @@ class Roborock {
|
|
|
2657
2689
|
//do nothing
|
|
2658
2690
|
break;
|
|
2659
2691
|
case "roborock.vacuum.s6":
|
|
2660
|
-
await
|
|
2692
|
+
await this.pollParameter(duid, vacuum, "get_carpet_mode", isB01);
|
|
2661
2693
|
break;
|
|
2662
2694
|
case "roborock.vacuum.a27":
|
|
2663
|
-
await
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2695
|
+
await this.pollParameter(
|
|
2696
|
+
duid,
|
|
2697
|
+
vacuum,
|
|
2698
|
+
"get_dust_collection_switch_status",
|
|
2699
|
+
isB01
|
|
2700
|
+
);
|
|
2701
|
+
await this.pollParameter(duid, vacuum, "get_wash_towel_mode", isB01);
|
|
2702
|
+
await this.pollParameter(
|
|
2703
|
+
duid,
|
|
2704
|
+
vacuum,
|
|
2705
|
+
"get_smart_wash_params",
|
|
2706
|
+
isB01
|
|
2707
|
+
);
|
|
2708
|
+
await this.pollParameter(
|
|
2709
|
+
duid,
|
|
2710
|
+
vacuum,
|
|
2711
|
+
"app_get_dryer_setting",
|
|
2712
|
+
isB01
|
|
2713
|
+
);
|
|
2667
2714
|
break;
|
|
2668
2715
|
default: {
|
|
2669
2716
|
// No dedicated poll profile for this model: derive it from the
|
|
@@ -2675,18 +2722,31 @@ class Roborock {
|
|
|
2675
2722
|
const carpetSupported = featureList
|
|
2676
2723
|
? Boolean(featureList.isCarpetSupported)
|
|
2677
2724
|
: true;
|
|
2725
|
+
const waterBoxProbe =
|
|
2726
|
+
!isB01 ||
|
|
2727
|
+
b01Q7Adapter.canAnswerV1Method("get_water_box_custom_mode");
|
|
2678
2728
|
const profileKey = `${duid}:${robotModel}`;
|
|
2679
2729
|
if (!this.loggedPollProfiles.has(profileKey)) {
|
|
2680
2730
|
this.loggedPollProfiles.add(profileKey);
|
|
2681
2731
|
this.log.info(
|
|
2682
|
-
`No dedicated poll profile for model '${robotModel}'; using ${featureList ? "capability-derived" : "generic"} polls (carpet=${carpetSupported ? "yes" : "no"}, water-box probe
|
|
2732
|
+
`No dedicated poll profile for model '${robotModel}'; using ${featureList ? "capability-derived" : "generic"} polls (carpet=${carpetSupported ? "yes" : "no"}, water-box probe=${waterBoxProbe ? "yes" : "no, the Q7/B01 dialect has no such request"}). Requests the robot reports as unsupported are disabled automatically. If states look wrong for this model, please open a model report issue on GitHub.`
|
|
2683
2733
|
);
|
|
2684
2734
|
}
|
|
2685
2735
|
if (carpetSupported) {
|
|
2686
|
-
await
|
|
2687
|
-
await
|
|
2736
|
+
await this.pollParameter(duid, vacuum, "get_carpet_mode", isB01);
|
|
2737
|
+
await this.pollParameter(
|
|
2738
|
+
duid,
|
|
2739
|
+
vacuum,
|
|
2740
|
+
"get_carpet_clean_mode",
|
|
2741
|
+
isB01
|
|
2742
|
+
);
|
|
2688
2743
|
}
|
|
2689
|
-
await
|
|
2744
|
+
await this.pollParameter(
|
|
2745
|
+
duid,
|
|
2746
|
+
vacuum,
|
|
2747
|
+
"get_water_box_custom_mode",
|
|
2748
|
+
isB01
|
|
2749
|
+
);
|
|
2690
2750
|
}
|
|
2691
2751
|
}
|
|
2692
2752
|
} else {
|