homebridge-roborock-matter 3.1.0 → 3.2.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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.2.0
4
+
5
+ Field feedback on the Q7 series: the live room in Apple Home lagged badly behind the robot. One run took 90 seconds to name the first room; another took seven minutes.
6
+
7
+ - **The first room of a run now appears as soon as the robot is seen cleaning.** Two throttles were stacking. The status poll backed off to 45 seconds while the robot looked idle, so a clean started from the Roborock app or a schedule was invisible for up to that long; then the live-room map fetch applied its own 20-second gap on top, counted from the last attempt rather than from the start of the run. The idle poll is now 25 seconds, the map gap is 10 seconds, and the transition from idle to cleaning clears the gap so the first fetch goes out immediately. Steady-state pacing during a run is unchanged in spirit — the map payload is still an order of magnitude heavier than a status read and is still paced deliberately.
8
+ - **A robot that cannot place itself on the map now says so.** When the robot's position doesn't fall inside any known room outline, the plugin used to return silently at debug level. That is the most likely explanation for a run going minutes without a room — in the field a Q7 spent seven minutes doing exactly this — and it was indistinguishable from the feature being broken. Repeated misses are now reported at a level you can actually see, with a count.
9
+
10
+ ## 3.1.1
11
+
12
+ - **The Apple Home Features checkbox still said "Returning status".** 3.1.0 renamed the setting in the config schema but not in the plugin's own settings UI, which is the one most people actually see — so the first person to install it reasonably wondered whether the update had applied at all. Both now read **Dock & Returning status**, and the description spells out that Emptying and Washing only appear while the dock is genuinely doing that, and that mop drying has no Matter equivalent.
13
+
3
14
  ## 3.1.0
4
15
 
5
16
  Driven by two open model reports, plus the parts of the 3.0.2 audit that were too large to rush. Nothing here requires re-pairing unless you turn on the dock statuses below.
@@ -206,11 +206,15 @@
206
206
  <label class="checkbox">
207
207
  <input id="enable-matter-extended-states" type="checkbox" />
208
208
  <span>
209
- Returning status
209
+ Dock &amp; Returning status
210
210
  <small
211
- >Shows the extended Matter Returning state while the robot heads back
212
- to the dock. Off by default for maximum Apple Home
213
- compatibility.</small
211
+ >Shows the extended Matter states: Returning to the dock, Emptying the
212
+ dust bin, Washing the mop, and Updating maps. Requires removing and
213
+ re-pairing the robot in Apple Home once. Which of them Apple Home
214
+ draws is Apple's decision, and Emptying/Washing only appear while the
215
+ dock is actually doing that. Mop drying has no equivalent in the
216
+ Matter vacuum specification, so it cannot be reported. Off by default
217
+ for maximum Apple Home compatibility.</small
214
218
  >
215
219
  </span>
216
220
  </label>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-roborock-matter",
3
- "version": "3.1.0",
3
+ "version": "3.2.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": {
@@ -39,8 +39,11 @@ const B01_LIVE_ROOM_CLEAR_V1_STATES = new Set([3, 8]);
39
39
 
40
40
  // Minimum gap between live-room map fetch attempts while cleaning. The map
41
41
  // payload is an order of magnitude heavier than get_status, so it rides a
42
- // slower cadence than the ~12s active status polls.
43
- const B01_LIVE_ROOM_MIN_FETCH_GAP_MS = 20000;
42
+ // slower cadence than the active status polls — but 20s meant a robot could
43
+ // walk through a whole small room before Apple Home named it, which is the
44
+ // opposite of what a "live" room display is for. 10s keeps the map traffic
45
+ // modest while making the room track the robot closely enough to be useful.
46
+ const B01_LIVE_ROOM_MIN_FETCH_GAP_MS = 10000;
44
47
 
45
48
  // Scheduler granularity for the classic (v1-protocol) status refresh. The
46
49
  // refresh itself is throttled per robot inside vacuum.getParameter, so this
@@ -3605,7 +3608,8 @@ class Roborock {
3605
3608
  //
3606
3609
  // The 1-second poll tick relies on getParameter's internal throttling for
3607
3610
  // classic robots; this path must throttle itself or every tick becomes a
3608
- // cloud request. Periodic refreshes run at most every 45s, forced
3611
+ // cloud request. Periodic refreshes are paced by the adaptive cadence
3612
+ // below, forced
3609
3613
  // refreshes (post-command, robot pushes) at most every 1.5s, and
3610
3614
  // concurrent callers share one in-flight request.
3611
3615
  if (!this._b01StatusState) {
@@ -3630,9 +3634,14 @@ class Roborock {
3630
3634
  // Adaptive cadence: while the robot is actively working (cleaning,
3631
3635
  // returning, docking) every 15s loop tick is allowed through so state
3632
3636
  // transitions reach Matter controllers within seconds; at rest the
3633
- // conservative 45s cloud cadence applies.
3637
+ // conservative cadence below applies.
3634
3638
  const isActive = B01_ACTIVE_V1_STATES.has(refreshState.lastKnownV1State);
3635
- const minimumGapMs = options.force ? 1500 : isActive ? 12000 : 45000;
3639
+ // 45s while idle was the dominant part of the delay before a run showed
3640
+ // up at all: a clean started from the Roborock app or a schedule is
3641
+ // invisible to the plugin until the next poll gets through. 25s halves
3642
+ // that worst case for one extra request per robot per minute while
3643
+ // parked, which is negligible next to the active cadence.
3644
+ const minimumGapMs = options.force ? 1500 : isActive ? 12000 : 25000;
3636
3645
  if (Date.now() - refreshState.lastAttemptAt < minimumGapMs) {
3637
3646
  return null;
3638
3647
  }
@@ -3646,6 +3655,23 @@ class Roborock {
3646
3655
  []
3647
3656
  );
3648
3657
  const v1Status = b01Q7Adapter.mapStatusToV1(data);
3658
+ // A run that has just started is the moment the user is watching, and
3659
+ // it was also the slowest: the live-room fetch below rides its own
3660
+ // throttle, counted from the last attempt, so the first room of a run
3661
+ // could wait a further gap on top of the poll that noticed the robot
3662
+ // at all. Clearing the stamp on the idle -> active transition makes
3663
+ // that first fetch immediate; the throttle still paces every fetch
3664
+ // after it.
3665
+ const wasFetching = B01_LIVE_ROOM_FETCH_V1_STATES.has(
3666
+ refreshState.lastKnownV1State
3667
+ );
3668
+ const isFetching = B01_LIVE_ROOM_FETCH_V1_STATES.has(v1Status.state);
3669
+ if (isFetching && !wasFetching) {
3670
+ const liveState = this._b01LiveRoomState?.get(duid);
3671
+ if (liveState) {
3672
+ liveState.lastAttemptAt = 0;
3673
+ }
3674
+ }
3649
3675
  refreshState.lastKnownV1State = v1Status.state;
3650
3676
  refreshState.lastV1Status = v1Status;
3651
3677
 
@@ -3970,11 +3996,24 @@ class Roborock {
3970
3996
  liveState.consecutiveFailures = 0;
3971
3997
 
3972
3998
  if (roomId === null) {
3973
- this.log.debug(
3974
- `Live room for ${duid}: robot pose is outside every room outline (or pose/geometry missing from the map payload).`
3975
- );
3999
+ // Debug-only used to make this invisible, and it is the single most
4000
+ // likely reason a run goes minutes without naming a room: in the
4001
+ // field a Q7 took 7 minutes to report its first room while every
4002
+ // attempt in between resolved to nothing and said so only at debug
4003
+ // level. Count the misses and say something at a level the user
4004
+ // actually sees, so "no room yet" is distinguishable from "the
4005
+ // feature is broken".
4006
+ liveState.unresolvedPoseCount =
4007
+ (liveState.unresolvedPoseCount || 0) + 1;
4008
+ const message = `Live room for ${duid}: the robot's position did not fall inside any known room outline (attempt ${liveState.unresolvedPoseCount} this run). The map may still be building, or the robot may be between rooms.`;
4009
+ if (liveState.unresolvedPoseCount % 5 === 0) {
4010
+ this.log.info(message);
4011
+ } else {
4012
+ this.log.debug(message);
4013
+ }
3976
4014
  return liveState.current;
3977
4015
  }
4016
+ liveState.unresolvedPoseCount = 0;
3978
4017
 
3979
4018
  const roomName =
3980
4019
  parsed.rooms.find((room) => room.roomId === roomId)?.roomName ||