homebridge-roborock-matter 3.0.0 → 3.0.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 +26 -1
- package/dist/platform.js +23 -2
- package/dist/platform.js.map +1 -1
- package/homebridge-ui/public/index.js +1 -1
- package/package.json +1 -1
- package/roborockLib/lib/deviceFeatures.js +14 -2
- package/roborockLib/lib/localConnector.js +43 -12
- package/roborockLib/lib/message.js +14 -2
- package/roborockLib/lib/messageQueueHandler.js +11 -1
- package/roborockLib/lib/roborock_mqtt_connector.js +118 -14
- package/roborockLib/roborockAPI.js +108 -43
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.0.2
|
|
4
|
+
|
|
5
|
+
A full read of the codebase turned up defects that no test covered and that the logs had been reporting for weeks without anyone reading them properly. Two of these could end the Homebridge process; one meant a headline feature had never worked in any released version. Nothing here requires re-pairing.
|
|
6
|
+
|
|
7
|
+
- **A malformed UDP packet can no longer take Homebridge down.** The discovery socket is bound to `0.0.0.0:58866` and receives whatever the network broadcasts at it — the Roborock phone app doing its own discovery, a port scanner, a truncated retransmit. Neither the binary parser nor `JSON.parse` was guarded, and a synchronous throw inside a dgram handler is an uncaught exception. One stray datagram from any host on the LAN was enough to stop the bridge, and because such senders are usually periodic, to keep stopping it.
|
|
8
|
+
- **The MQTT startup watchdog no longer crashes the process it was written to rescue.** After 30 seconds without a broker connection it called `restart()` on the adapter — a method this class has never had. The resulting TypeError inside an async timer is an unhandled rejection, which Node terminates on. The one situation it was meant to handle, a Pi that boots before the network is up, was therefore the one situation guaranteed to kill the bridge. It now logs a clear, throttled warning and lets the client keep reconnecting, and the timer is tracked and cancelled on shutdown.
|
|
9
|
+
- **LAN discovery works for the first time.** `decryptECB` called the PKCS#7 helper without `this.`, so every broadcast raised a ReferenceError that the surrounding `catch` swallowed and turned into `null`. Robots were only ever reached locally when the cloud happened to report their IP; otherwise they stayed cloud-only, with slower commands and no resilience to a Roborock outage. Startup also spent its full five-second discovery window on a result that could not contain anything.
|
|
10
|
+
- **Q7-series clean mode and suction now reach the robot.** Both commands were dispatched through an allow-list that contained neither of them, so they fell through to `Command set_clean_type not found.` and nothing was sent. The log line has been there since 13 July. They now take the same path the classic models already used, which also reports genuinely unsupported commands instead of discarding them silently.
|
|
11
|
+
- **Cloud commands no longer time out after doing exactly what was asked.** The protocol-102 handler tried to detect a secure request by comparing the result to the string `"ok"`, but the wire format is the array `["ok"]`, and `["ok"] != "ok"` is false. Every ordinary cloud command that acknowledges this way — start, stop, pause, dock, suction, room clean — was left pending until the ten-second timeout and then reported as failed in Apple Home, while the robot had already carried it out. Secure requests are now tracked by an explicit flag, and a secure request that fails resolves instead of hanging.
|
|
12
|
+
- **A cloud hiccup can no longer unregister every robot.** When the home-data fetch fails, startup logs the error and continues, so the device list reads as empty — and stale-accessory cleanup then removed every Matter accessory. Matter locks the mode list at commissioning, so that meant re-pairing the entire fleet, and a restart did not undo it. Cleanup is now skipped unless the API is initialised and actually returned robots, and a `result`-less cloud response no longer overwrites the cached device list on disk.
|
|
13
|
+
- **Mop modes are no longer offered on robots that cannot mop.** Two capability entries were written as bare arrays where every neighbouring entry ends in `.includes(robotModel)` — and an array, empty or not, is truthy. Both were therefore true for every robot, which is why dry-only models (S4, S4 Max, S5, S6 Pure) showed Mop and Vacuum + Mop plus a water-level control, and had `set_water_box_custom_mode` fired at hardware with no tank.
|
|
14
|
+
- **Fixed a corrupt header on robots reporting protocol version `\x81S\x19`.** The version is three raw bytes, but it was written as UTF-8, which encodes `0x81` as two bytes; the sequence number then overwrote the overflow. Both the version and the sequence number went out wrong, so those robots ignored every message. The decode side already used latin1.
|
|
15
|
+
- A local reconnect failure can no longer surface as an unhandled rejection, and the byte-identical copy of the MQTT connector at the repository root — dead code that was being hand-synced with the real one, and had already drifted — is gone.
|
|
16
|
+
- Full suite: 315 tests, 36 new. Each new test was checked to fail against the previous code and pass against this one.
|
|
17
|
+
|
|
18
|
+
## 3.0.1
|
|
19
|
+
|
|
20
|
+
Follow-up to 3.0.0 after measuring a real restart instead of trusting the reasoning. Two things needed fixing, one of them mine.
|
|
21
|
+
|
|
22
|
+
- **Startup now genuinely finishes in ~2 seconds instead of ~7.** 3.0.0 moved LAN discovery off the critical path but still waited for its full 5-second broadcast window before declaring startup finished, so the total barely moved — the claim in the 3.0.0 notes ("~8 s before, ~3 s after") was wrong, and the corrected numbers are below. Local transport is an optimisation over the cloud path, not a prerequisite for it, so it now attaches in the background after the robots are already live in Apple Home.
|
|
23
|
+
- **Fixed: the first cloud request could fail on a cold start.** `get_network_info` was issued about a second after the MQTT handshake began and failed with "Cloud connection not available" — visible in real logs for a cloud-transported robot. Startup now waits for the broker session to actually come up (up to 10 s, then continues regardless) before the first requests, instead of relying on an unrelated delay to cover the gap.
|
|
24
|
+
- The diagnostics export is no longer headed `homebridge-roborock-vacuum2 diagnostic report` — a leftover from the fork that made reports confusing to read.
|
|
25
|
+
|
|
26
|
+
Measured on a three-robot fleet (two Q7, one S8 Pro Ultra), "Starting adapter" to "Lets go!!!!!!!": 6–7 s on 2.9.x and 3.0.0, ~2 s on 3.0.1.
|
|
27
|
+
|
|
3
28
|
## 3.0.0
|
|
4
29
|
|
|
5
30
|
Startup and refresh pass: Homebridge restarts are noticeably faster, and a status refresh that had never actually run now does. Nothing here requires re-pairing — existing setups keep working exactly as they are.
|
|
6
31
|
|
|
7
|
-
- **
|
|
32
|
+
- **LAN discovery moved off the critical path.** It listens for robot broadcasts for a fixed 5-second window, and startup used to sit and wait for it before even creating the devices. Device setup and network probes now run inside that window instead. (The wall-clock win landed in 3.0.1 — see above; this release only reordered the work.)
|
|
8
33
|
- **Multi-robot startup no longer costs extra time.** Each robot's first status read and network probe used to run one after another; they now run at once, so three robots start as quickly as one. New tests pin the concurrency down so it cannot silently regress.
|
|
9
34
|
- **A dead status refresh has been repaired.** The periodic `get_status` refresh for classic (S/Q-series) robots was gated on a config key this plugin never sets, which made the condition permanently false — the refresh promised by the code has never run in any released version. It now polls each robot at most once a minute (forced refreshes are unaffected), so a dropped MQTT push self-corrects within a minute instead of waiting up to three for the slow full poll.
|
|
10
35
|
- **~86,000 needless timer wake-ups per robot per day removed.** With the refresh properly throttled, the 1-second scheduler tick that served it is now 15 seconds — same refresh rate, a fraction of the idle CPU on Raspberry Pi class hardware.
|
package/dist/platform.js
CHANGED
|
@@ -402,8 +402,29 @@ class RoborockPlatform {
|
|
|
402
402
|
if (!matter || typeof matter.unregisterPlatformAccessories !== "function") {
|
|
403
403
|
return;
|
|
404
404
|
}
|
|
405
|
-
|
|
406
|
-
|
|
405
|
+
// A failed startup surfaces here as "the account has no robots": when
|
|
406
|
+
// getHomeDetail() throws (Roborock maintenance, a rate-limited response,
|
|
407
|
+
// or plain DNS failure — EAI_AGAIN hit this log twice in three weeks) the
|
|
408
|
+
// error is caught and logged, but the discovery callback still runs, so
|
|
409
|
+
// getVacuumList() returns an empty array. Treating that as "everything is
|
|
410
|
+
// stale" unregisters every Matter accessory, and because Matter locks the
|
|
411
|
+
// mode list at commissioning, the user then has to re-pair every single
|
|
412
|
+
// robot — a destructive, non-recoverable outcome triggered by one bad
|
|
413
|
+
// cloud response. Leaving a genuinely removed robot in place until the
|
|
414
|
+
// next successful discovery is by far the cheaper mistake.
|
|
415
|
+
if (!this.roborockAPI.isInited()) {
|
|
416
|
+
this.log.debug("Skipping stale-accessory cleanup: the Roborock API is not initialised yet, so the device list cannot be trusted.");
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const knownDevices = this.roborockAPI.getVacuumList();
|
|
420
|
+
if (!Array.isArray(knownDevices) || knownDevices.length === 0) {
|
|
421
|
+
this.log.warn("Skipping stale-accessory cleanup: the Roborock account reported no robots. " +
|
|
422
|
+
"This is almost always a temporary cloud or network failure, and unregistering " +
|
|
423
|
+
"the Matter accessories here would force you to re-pair every robot. If you have " +
|
|
424
|
+
"genuinely removed all robots from your account, remove the accessories manually.");
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const currentMatterUuids = new Set(knownDevices
|
|
407
428
|
.filter((device) => this.isSupportedDevice(this.roborockAPI.getProductAttribute(device.duid, "model")))
|
|
408
429
|
.map((device) => this.generateMatterUuid(device.duid)));
|
|
409
430
|
const staleAccessories = this.matterAccessories.filter((accessory) => !currentMatterUuids.has(accessory.UUID));
|
package/dist/platform.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -982,7 +982,7 @@ async function copyDiagnosticsReport() {
|
|
|
982
982
|
function buildDiagnosticsReport(result) {
|
|
983
983
|
const hasToken = Boolean(result.hasEncryptedToken || state.hasEncryptedToken);
|
|
984
984
|
const lines = [
|
|
985
|
-
"homebridge-roborock-
|
|
985
|
+
"homebridge-roborock-matter diagnostic report",
|
|
986
986
|
`generatedAt: ${result.generatedAt || "unknown"}`,
|
|
987
987
|
`pluginVersion: ${result.pluginVersion || "unknown"}`,
|
|
988
988
|
`nodeVersion: ${result.nodeVersion || "unknown"}`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-roborock-matter",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.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": {
|
|
@@ -811,10 +811,22 @@ class deviceFeatures {
|
|
|
811
811
|
].includes(robotModel),
|
|
812
812
|
// this isn't the correct way to use this. This code must be from a different robot
|
|
813
813
|
// isVoiceControlSupported: !!(parseInt(`0x${this.featuresStr || "0"}`.slice(-10, -9)) & 2),
|
|
814
|
+
// These two were written as bare arrays while every other model list in
|
|
815
|
+
// this object ends in `.includes(robotModel)`. An array is truthy in JS
|
|
816
|
+
// — an EMPTY array included — and the gate below is
|
|
817
|
+
// `if (featureList[feature])`, so both were unconditionally true for
|
|
818
|
+
// every robot. isElectronicWaterBoxSupported feeds isSupportedWaterMode,
|
|
819
|
+
// which is what makes canMop and canControlWater true, so Apple Home
|
|
820
|
+
// offered Mop and Vacuum + Mop plus a water-level control on dry-only
|
|
821
|
+
// robots (S4, S4 Max, S5, S6 Pure) and fired set_water_box_custom_mode
|
|
822
|
+
// at hardware with no tank. The three model allowlists above exist
|
|
823
|
+
// precisely to prevent that.
|
|
814
824
|
isVoiceControlSupported: [
|
|
815
825
|
"roborock.vacuum.a27", // S7 MaxV (Ultra)
|
|
816
|
-
],
|
|
817
|
-
|
|
826
|
+
].includes(robotModel),
|
|
827
|
+
// No model is known to need this yet. Add models to the array and keep
|
|
828
|
+
// the .includes(robotModel) call if that changes.
|
|
829
|
+
isElectronicWaterBoxSupported: [].includes(robotModel),
|
|
818
830
|
isCleanRouteFastModeSupported:
|
|
819
831
|
this.featuresStr &&
|
|
820
832
|
!!(256 & parseInt("0x" + this.featuresStr.slice(-8))),
|
|
@@ -103,9 +103,22 @@ class localConnector {
|
|
|
103
103
|
scheduleReconnect(duid, ip, delayMs = LOCAL_RECONNECT_DELAY_MS) {
|
|
104
104
|
this.clearReconnectTimer(duid);
|
|
105
105
|
const { setTimer } = getTimerFns(this.adapter);
|
|
106
|
-
|
|
106
|
+
// createClient can reject before its own try/catch takes over (the
|
|
107
|
+
// awaited diagnostics write happens first, and the failure handler awaits
|
|
108
|
+
// more of them). A bare timer callback that rejects is an unhandled
|
|
109
|
+
// rejection, which Node terminates the process for by default — so a full
|
|
110
|
+
// SD card at the moment a reconnect fires would take Homebridge down.
|
|
111
|
+
// Reconnect failures are expected and already logged inside createClient;
|
|
112
|
+
// swallowing them here only prevents the crash.
|
|
113
|
+
const timer = setTimer(() => {
|
|
107
114
|
this.reconnectTimers.delete(duid);
|
|
108
|
-
|
|
115
|
+
Promise.resolve()
|
|
116
|
+
.then(() => this.createClient(duid, ip))
|
|
117
|
+
.catch((error) => {
|
|
118
|
+
this.adapter.log.debug(
|
|
119
|
+
`Local reconnect attempt for ${duid} failed: ${error?.message || error}`
|
|
120
|
+
);
|
|
121
|
+
});
|
|
109
122
|
}, delayMs);
|
|
110
123
|
this.reconnectTimers.set(duid, timer);
|
|
111
124
|
}
|
|
@@ -508,19 +521,37 @@ class localConnector {
|
|
|
508
521
|
return new Promise((resolve, reject) => {
|
|
509
522
|
const devices = {};
|
|
510
523
|
|
|
524
|
+
// The discovery socket is bound to 0.0.0.0 and receives whatever any
|
|
525
|
+
// host on the LAN broadcasts to this port — the Roborock phone app doing
|
|
526
|
+
// its own discovery, a port scanner, a malformed retransmit. Neither
|
|
527
|
+
// `localMessageParser.parse` (binary-parser throws RangeError on a short
|
|
528
|
+
// or over-declared buffer) nor `JSON.parse` is total, and a synchronous
|
|
529
|
+
// throw inside a dgram handler is an uncaught exception that takes
|
|
530
|
+
// Homebridge down with it. One stray datagram must never do that, so
|
|
531
|
+
// every unparseable packet is skipped instead.
|
|
511
532
|
server.on("message", (msg) => {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
this.
|
|
533
|
+
let parsedDecodedMessage;
|
|
534
|
+
|
|
535
|
+
try {
|
|
536
|
+
const parsedMessage = localMessageParser.parse(msg);
|
|
537
|
+
const decodedMessage = this.decryptECB(
|
|
538
|
+
parsedMessage.payload,
|
|
539
|
+
BROADCAST_TOKEN
|
|
540
|
+
); // this might be decryptCBC for A01. Haven't checked this yet
|
|
541
|
+
|
|
542
|
+
if (decodedMessage == null) {
|
|
543
|
+
this.adapter.log.debug(`getLocalDevices: decodedMessage is null`);
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
parsedDecodedMessage = JSON.parse(decodedMessage);
|
|
548
|
+
} catch (error) {
|
|
549
|
+
this.adapter.log.debug(
|
|
550
|
+
`getLocalDevices: ignoring a malformed discovery datagram (${msg?.length ?? 0} bytes): ${error?.message || error}`
|
|
551
|
+
);
|
|
520
552
|
return;
|
|
521
553
|
}
|
|
522
554
|
|
|
523
|
-
const parsedDecodedMessage = JSON.parse(decodedMessage);
|
|
524
555
|
this.adapter.log.debug(
|
|
525
556
|
`getLocalDevices parsedDecodedMessage: ${JSON.stringify(parsedDecodedMessage)}`
|
|
526
557
|
);
|
|
@@ -604,7 +635,7 @@ class localConnector {
|
|
|
604
635
|
decipher.update(input),
|
|
605
636
|
decipher.final(),
|
|
606
637
|
]);
|
|
607
|
-
const unpadded = safeRemovePkcs7(decryptedBuf);
|
|
638
|
+
const unpadded = this.safeRemovePkcs7(decryptedBuf);
|
|
608
639
|
|
|
609
640
|
// 若原協定內容是 UTF-8,這裡再轉字串;否則直接回傳 Buffer 讓上層處理
|
|
610
641
|
return unpadded.toString("utf8");
|
|
@@ -119,7 +119,13 @@ class message {
|
|
|
119
119
|
|
|
120
120
|
if (protocol == 1) {
|
|
121
121
|
const msg = Buffer.alloc(23);
|
|
122
|
-
|
|
122
|
+
// latin1, not the UTF-8 default: the protocol version is three raw
|
|
123
|
+
// bytes, and one of the versions this file handles explicitly is
|
|
124
|
+
// "\x81S\x19". UTF-8 encodes 0x81 as two bytes (c2 81), so write()
|
|
125
|
+
// returned 4 and produced `c2 81 53 19`; the writeUint32BE below then
|
|
126
|
+
// overwrote the fourth byte, leaving a corrupt version AND a wrong
|
|
127
|
+
// sequence number. _decodeMsg already reads it back with latin1.
|
|
128
|
+
msg.write(version, "latin1");
|
|
123
129
|
msg.writeUint32BE(currentSeq, 3);
|
|
124
130
|
msg.writeUint32BE(currentRandom, 7);
|
|
125
131
|
msg.writeUint32BE(timestamp, 11);
|
|
@@ -185,7 +191,13 @@ class message {
|
|
|
185
191
|
|
|
186
192
|
if (encrypted) {
|
|
187
193
|
const msg = Buffer.alloc(23 + encrypted.length);
|
|
188
|
-
|
|
194
|
+
// latin1, not the UTF-8 default: the protocol version is three raw
|
|
195
|
+
// bytes, and one of the versions this file handles explicitly is
|
|
196
|
+
// "\x81S\x19". UTF-8 encodes 0x81 as two bytes (c2 81), so write()
|
|
197
|
+
// returned 4 and produced `c2 81 53 19`; the writeUint32BE below then
|
|
198
|
+
// overwrote the fourth byte, leaving a corrupt version AND a wrong
|
|
199
|
+
// sequence number. _decodeMsg already reads it back with latin1.
|
|
200
|
+
msg.write(version, "latin1");
|
|
189
201
|
msg.writeUint32BE(currentSeq, 3);
|
|
190
202
|
msg.writeUint32BE(currentRandom, 7);
|
|
191
203
|
msg.writeUint32BE(timestamp, 11);
|
|
@@ -31,6 +31,9 @@ function getRequestTimeout(method, requestTimeoutMs) {
|
|
|
31
31
|
* @property {(value: unknown) => void} resolve
|
|
32
32
|
* @property {(reason?: unknown) => void} reject
|
|
33
33
|
* @property {ReturnType<typeof setTimeout>} timeout
|
|
34
|
+
* @property {boolean} [secure] True for requests whose protocol-102 reply is
|
|
35
|
+
* only an acknowledgement, with the real payload arriving on protocol 301.
|
|
36
|
+
* @property {string} [method] The Roborock method, kept for diagnostics.
|
|
34
37
|
*/
|
|
35
38
|
|
|
36
39
|
/**
|
|
@@ -322,11 +325,18 @@ class messageQueueHandler {
|
|
|
322
325
|
}
|
|
323
326
|
}, requestTimeout);
|
|
324
327
|
|
|
325
|
-
// Store request with resolve and reject functions
|
|
328
|
+
// Store request with resolve and reject functions.
|
|
329
|
+
// `secure` travels with the entry so the MQTT receiver can tell a
|
|
330
|
+
// secure request (whose protocol-102 reply is only an ack — the real
|
|
331
|
+
// payload arrives on protocol 301) from an ordinary one (whose 102
|
|
332
|
+
// reply IS the result). It used to guess by comparing the result to
|
|
333
|
+
// the string "ok", which silently never matched.
|
|
326
334
|
this.adapter.pendingRequests.set(messageID, {
|
|
327
335
|
resolve,
|
|
328
336
|
reject,
|
|
329
337
|
timeout,
|
|
338
|
+
secure,
|
|
339
|
+
method,
|
|
330
340
|
});
|
|
331
341
|
|
|
332
342
|
if (useCloudConnection) {
|
|
@@ -39,6 +39,39 @@ let rriot;
|
|
|
39
39
|
let photoGzipChunks = [];
|
|
40
40
|
let photoChunkID = 0;
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* True when a protocol-102 result is a bare "command accepted" acknowledgement
|
|
44
|
+
* rather than real data. Roborock sends this as the single-element array
|
|
45
|
+
* ["ok"]; some firmware answers with the bare string.
|
|
46
|
+
* @param {unknown} result
|
|
47
|
+
* @returns {boolean}
|
|
48
|
+
*/
|
|
49
|
+
function isOkAcknowledgement(result) {
|
|
50
|
+
if (result === "ok") {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
return Array.isArray(result) && result.length === 1 && result[0] === "ok";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Decide whether a protocol-102 reply completes a pending request.
|
|
58
|
+
*
|
|
59
|
+
* Only a secure request answered with a bare acknowledgement keeps waiting —
|
|
60
|
+
* its real payload arrives on protocol 301. Everything else resolves here,
|
|
61
|
+
* including a secure request that came back with an error, which would
|
|
62
|
+
* otherwise hang until the request timeout.
|
|
63
|
+
*
|
|
64
|
+
* @param {{secure?: boolean}|undefined} pending
|
|
65
|
+
* @param {unknown} result
|
|
66
|
+
* @returns {boolean}
|
|
67
|
+
*/
|
|
68
|
+
function shouldResolveOn102(pending, result) {
|
|
69
|
+
if (!pending) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return !(pending.secure === true && isOkAcknowledgement(result));
|
|
73
|
+
}
|
|
74
|
+
|
|
42
75
|
function payloadStartsWith(payload, value) {
|
|
43
76
|
return (
|
|
44
77
|
Buffer.isBuffer(payload) &&
|
|
@@ -76,6 +109,7 @@ class roborock_mqtt_connector {
|
|
|
76
109
|
this.adapter = adapter;
|
|
77
110
|
|
|
78
111
|
this.connected = false;
|
|
112
|
+
this.initialConnectTimeout = null;
|
|
79
113
|
|
|
80
114
|
// NOTE: this class previously generated its own RSA-2048 keypair here,
|
|
81
115
|
// but nothing ever read it — the protocol keypair lives in message.js
|
|
@@ -101,9 +135,27 @@ class roborock_mqtt_connector {
|
|
|
101
135
|
}
|
|
102
136
|
|
|
103
137
|
async initMQTT_Subscribe() {
|
|
104
|
-
|
|
105
|
-
|
|
138
|
+
// This used to invoke a `restart` method on the adapter, which the
|
|
139
|
+
// Roborock class has never had — so on the one path it was written for
|
|
140
|
+
// (the broker
|
|
141
|
+
// neither connecting nor emitting `reconnect` within 30 s, e.g. a Pi that
|
|
142
|
+
// boots before the network is up, or a SYN black-holed by a firewall) it
|
|
143
|
+
// threw a TypeError inside an async timer. That is an unhandled rejection,
|
|
144
|
+
// which terminates the Homebridge process under Node's default policy —
|
|
145
|
+
// the exact opposite of the intended recovery. mqtt.js already retries on
|
|
146
|
+
// its own reconnectPeriod, so the correct behaviour here is to say so
|
|
147
|
+
// clearly and let it keep trying. The handle is stored and unref'd so
|
|
148
|
+
// shutdown can cancel it instead of firing into a torn-down adapter.
|
|
149
|
+
this.clearInitialConnectTimeout();
|
|
150
|
+
this.initialConnectTimeout = setTimeout(() => {
|
|
151
|
+
this.initialConnectTimeout = null;
|
|
152
|
+
this.logConnectionIssue(
|
|
153
|
+
`The Roborock MQTT broker has not answered within 30 seconds of startup. The client keeps reconnecting in the background; robots stay on cloud fallback until the session is up.`
|
|
154
|
+
);
|
|
106
155
|
}, 30000);
|
|
156
|
+
if (typeof this.initialConnectTimeout?.unref === "function") {
|
|
157
|
+
this.initialConnectTimeout.unref();
|
|
158
|
+
}
|
|
107
159
|
|
|
108
160
|
await client.on("connect", (result) => {
|
|
109
161
|
if (typeof result != "undefined") {
|
|
@@ -114,7 +166,7 @@ class roborock_mqtt_connector {
|
|
|
114
166
|
);
|
|
115
167
|
}
|
|
116
168
|
});
|
|
117
|
-
|
|
169
|
+
this.clearInitialConnectTimeout();
|
|
118
170
|
|
|
119
171
|
this.connected = true;
|
|
120
172
|
if (this._connectionIssueActive) {
|
|
@@ -157,7 +209,7 @@ class roborock_mqtt_connector {
|
|
|
157
209
|
);
|
|
158
210
|
}
|
|
159
211
|
});
|
|
160
|
-
|
|
212
|
+
this.clearInitialConnectTimeout();
|
|
161
213
|
this.adapter.log.debug(`MQTT connection reconnect attempt.`);
|
|
162
214
|
});
|
|
163
215
|
|
|
@@ -169,6 +221,17 @@ class roborock_mqtt_connector {
|
|
|
169
221
|
});
|
|
170
222
|
}
|
|
171
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Cancel the startup watchdog. Safe to call when it is not armed, and
|
|
226
|
+
* called from shutdown so the timer cannot outlive the adapter.
|
|
227
|
+
*/
|
|
228
|
+
clearInitialConnectTimeout() {
|
|
229
|
+
if (this.initialConnectTimeout) {
|
|
230
|
+
clearTimeout(this.initialConnectTimeout);
|
|
231
|
+
this.initialConnectTimeout = null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
172
235
|
/**
|
|
173
236
|
* Warn about a connection problem at most once per 5 minutes per message,
|
|
174
237
|
* and remember that an outage is in progress so the next successful
|
|
@@ -306,16 +369,23 @@ class roborock_mqtt_connector {
|
|
|
306
369
|
}
|
|
307
370
|
}
|
|
308
371
|
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
372
|
+
// Secure requests (get_map_v1 and friends) answer protocol 102 with
|
|
373
|
+
// a bare acknowledgement and deliver the real payload on protocol
|
|
374
|
+
// 301, so those must stay pending. Everything else is resolved here.
|
|
375
|
+
//
|
|
376
|
+
// This used to be `if (dps.result != "ok")`, which is always true:
|
|
377
|
+
// the wire format is the ARRAY ["ok"], and `["ok"] != "ok"` is false
|
|
378
|
+
// only after ToPrimitive — so the guard never fired for the case it
|
|
379
|
+
// was written for, and instead swallowed the completion of every
|
|
380
|
+
// ordinary cloud command that answers ["ok"] (app_start, app_stop,
|
|
381
|
+
// app_pause, app_charge, set_custom_mode, app_segment_clean, ...).
|
|
382
|
+
// Those requests then sat until the 10 s timeout and failed in Apple
|
|
383
|
+
// Home even though the robot had already carried them out.
|
|
384
|
+
const pending = this.adapter.pendingRequests.get(dps.id);
|
|
385
|
+
if (shouldResolveOn102(pending, dps.result)) {
|
|
386
|
+
this.adapter.clearTimeout(pending.timeout);
|
|
387
|
+
this.adapter.pendingRequests.delete(dps.id);
|
|
388
|
+
pending.resolve(dps.result);
|
|
319
389
|
}
|
|
320
390
|
// protocol 300 seems to be for get_photo 0 only. get_photo 0 is for large images. 1 is for small images.
|
|
321
391
|
} else if (data.protocol == 300) {
|
|
@@ -493,6 +563,38 @@ class roborock_mqtt_connector {
|
|
|
493
563
|
return this.connected;
|
|
494
564
|
}
|
|
495
565
|
|
|
566
|
+
/**
|
|
567
|
+
* Resolve once the MQTT session is usable, or after `timeoutMs` regardless.
|
|
568
|
+
*
|
|
569
|
+
* The broker handshake takes a few seconds, and cloud requests issued
|
|
570
|
+
* before it completes fail outright with "Cloud connection not available".
|
|
571
|
+
* Startup used to get away with this because an unrelated fixed delay
|
|
572
|
+
* happened to sit in front of the first requests; waiting on the real
|
|
573
|
+
* signal makes that timing explicit rather than accidental. Resolving on
|
|
574
|
+
* timeout (instead of rejecting) keeps a slow or offline broker from
|
|
575
|
+
* blocking startup — callers fall back to their own error handling.
|
|
576
|
+
*
|
|
577
|
+
* @param {number} [timeoutMs=10000]
|
|
578
|
+
* @returns {Promise<boolean>} whether the connection came up in time
|
|
579
|
+
*/
|
|
580
|
+
async waitUntilConnected(timeoutMs = 10000) {
|
|
581
|
+
if (this.connected) {
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const deadline = Date.now() + timeoutMs;
|
|
586
|
+
while (!this.connected && Date.now() < deadline) {
|
|
587
|
+
await new Promise((resolve) => {
|
|
588
|
+
const timer = setTimeout(resolve, 100);
|
|
589
|
+
if (typeof timer?.unref === "function") {
|
|
590
|
+
timer.unref();
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return this.connected;
|
|
596
|
+
}
|
|
597
|
+
|
|
496
598
|
async ensureConnected() {
|
|
497
599
|
if (client && this.connected) {
|
|
498
600
|
this.adapter.log.debug("MQTT health check passed. Reconnect skipped.");
|
|
@@ -574,4 +676,6 @@ module.exports = {
|
|
|
574
676
|
parseProtocol301Header,
|
|
575
677
|
parsePhotoPayload,
|
|
576
678
|
payloadStartsWith,
|
|
679
|
+
isOkAcknowledgement,
|
|
680
|
+
shouldResolveOn102,
|
|
577
681
|
};
|
|
@@ -1410,6 +1410,18 @@ class Roborock {
|
|
|
1410
1410
|
const homedata = await this.api.get(`v2/user/homes/${homeId}`);
|
|
1411
1411
|
const homedataResult = homedata.data.result;
|
|
1412
1412
|
|
|
1413
|
+
// Guard the persisted copy the same way updateHomeData already does.
|
|
1414
|
+
// Roborock occasionally answers 200 with an envelope that carries no
|
|
1415
|
+
// `result` (maintenance windows, rate limiting). Writing that through
|
|
1416
|
+
// stores `{"ack":true}` over the cached device list on disk, so the
|
|
1417
|
+
// next restart starts from a destroyed HomeData as well — turning a
|
|
1418
|
+
// transient cloud hiccup into a persistent failure.
|
|
1419
|
+
if (!homedataResult) {
|
|
1420
|
+
throw new Error(
|
|
1421
|
+
`The Roborock cloud returned no home data for home ${homeId}. Keeping the previously cached device list.`
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1413
1425
|
await this.setStateAsync("HomeData", {
|
|
1414
1426
|
val: JSON.stringify(homedataResult),
|
|
1415
1427
|
ack: true,
|
|
@@ -1505,52 +1517,26 @@ class Roborock {
|
|
|
1505
1517
|
await this.updateHomeData(homeId);
|
|
1506
1518
|
|
|
1507
1519
|
await this.createDevices();
|
|
1508
|
-
await this.getNetworkInfo();
|
|
1509
1520
|
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
) {
|
|
1518
|
-
this.localDevices[duid] = ip;
|
|
1519
|
-
}
|
|
1520
|
-
});
|
|
1521
|
-
this.log.debug(
|
|
1522
|
-
`localDevices: ${JSON.stringify(this.localDevices)}`
|
|
1523
|
-
);
|
|
1524
|
-
|
|
1525
|
-
for (const device of localKeyDevices) {
|
|
1526
|
-
if (
|
|
1527
|
-
!Object.prototype.hasOwnProperty.call(
|
|
1528
|
-
this.localDevices,
|
|
1529
|
-
device.duid
|
|
1530
|
-
)
|
|
1531
|
-
) {
|
|
1532
|
-
await this.updateTransportDiagnostics(device.duid, {
|
|
1533
|
-
localDiscoveryState: "not-discovered",
|
|
1534
|
-
lastTransportReason: "missing-local-ip",
|
|
1535
|
-
});
|
|
1536
|
-
}
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
for (const device in this.localDevices) {
|
|
1540
|
-
const duid = device;
|
|
1541
|
-
const ip = this.localDevices[device];
|
|
1542
|
-
|
|
1543
|
-
await this.updateTransportDiagnostics(duid, {
|
|
1544
|
-
localIp: ip,
|
|
1545
|
-
localDiscoveryState: "discovered",
|
|
1546
|
-
});
|
|
1547
|
-
await this.localConnector.createClient(duid, ip);
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1521
|
+
// Cloud requests fail outright until the MQTT session is up, and
|
|
1522
|
+
// the very first ones (the per-robot network probe, then each
|
|
1523
|
+
// robot's initial poll) used to be issued a second after the
|
|
1524
|
+
// broker handshake started. Wait for the real signal instead of
|
|
1525
|
+
// hoping an unrelated delay covers it; a broker that never comes
|
|
1526
|
+
// up releases the wait and the requests fail as they would have.
|
|
1527
|
+
await this.rr_mqtt_connector.waitUntilConnected();
|
|
1550
1528
|
|
|
1529
|
+
await this.getNetworkInfo();
|
|
1551
1530
|
await this.initializeDeviceUpdates();
|
|
1531
|
+
|
|
1552
1532
|
this.bInited = true;
|
|
1553
1533
|
this.log.info(`Starting adapter finished. Lets go!!!!!!!`);
|
|
1534
|
+
|
|
1535
|
+
// LAN attach runs to completion in the background. Everything above
|
|
1536
|
+
// works over the cloud, and the transport layer already falls back
|
|
1537
|
+
// to it, so holding accessory registration hostage to a fixed-length
|
|
1538
|
+
// broadcast listen only delayed the Apple Home tiles.
|
|
1539
|
+
void this.attachLocalTransports(localDiscovery, localKeyDevices);
|
|
1554
1540
|
} else {
|
|
1555
1541
|
this.log.info(
|
|
1556
1542
|
`Most likely failed to login. Deleting UserData to force new login!`
|
|
@@ -1567,6 +1553,59 @@ class Roborock {
|
|
|
1567
1553
|
}
|
|
1568
1554
|
}
|
|
1569
1555
|
|
|
1556
|
+
/**
|
|
1557
|
+
* Merge LAN-discovered robots and open their local TCP connections.
|
|
1558
|
+
*
|
|
1559
|
+
* Deliberately runs after startup has completed: local transport is an
|
|
1560
|
+
* optimisation over the cloud path, not a prerequisite for it.
|
|
1561
|
+
*
|
|
1562
|
+
* @param {Promise<Record<string, string>>} localDiscovery
|
|
1563
|
+
* @param {Array<{duid: string}>} localKeyDevices
|
|
1564
|
+
*/
|
|
1565
|
+
async attachLocalTransports(localDiscovery, localKeyDevices) {
|
|
1566
|
+
if (this.isCloudOnlyModeEnabled()) {
|
|
1567
|
+
return;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
try {
|
|
1571
|
+
const discoveredDevices = await localDiscovery;
|
|
1572
|
+
|
|
1573
|
+
// merge udp discovered devices with local devices found via mqtt
|
|
1574
|
+
Object.entries(discoveredDevices).forEach(([duid, ip]) => {
|
|
1575
|
+
if (!Object.prototype.hasOwnProperty.call(this.localDevices, duid)) {
|
|
1576
|
+
this.localDevices[duid] = ip;
|
|
1577
|
+
}
|
|
1578
|
+
});
|
|
1579
|
+
this.log.debug(`localDevices: ${JSON.stringify(this.localDevices)}`);
|
|
1580
|
+
|
|
1581
|
+
for (const device of this.normalizeArray(localKeyDevices)) {
|
|
1582
|
+
if (
|
|
1583
|
+
!Object.prototype.hasOwnProperty.call(this.localDevices, device.duid)
|
|
1584
|
+
) {
|
|
1585
|
+
await this.updateTransportDiagnostics(device.duid, {
|
|
1586
|
+
localDiscoveryState: "not-discovered",
|
|
1587
|
+
lastTransportReason: "missing-local-ip",
|
|
1588
|
+
});
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
for (const duid in this.localDevices) {
|
|
1593
|
+
const ip = this.localDevices[duid];
|
|
1594
|
+
|
|
1595
|
+
await this.updateTransportDiagnostics(duid, {
|
|
1596
|
+
localIp: ip,
|
|
1597
|
+
localDiscoveryState: "discovered",
|
|
1598
|
+
});
|
|
1599
|
+
await this.localConnector.createClient(duid, ip);
|
|
1600
|
+
}
|
|
1601
|
+
} catch (error) {
|
|
1602
|
+
// Local transport is best-effort; the cloud path stays available.
|
|
1603
|
+
this.log.debug(
|
|
1604
|
+
`Local transport attach failed; continuing on cloud transport: ${error?.message || error}`
|
|
1605
|
+
);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1570
1609
|
async stopService() {
|
|
1571
1610
|
try {
|
|
1572
1611
|
this.flushPendingPersistedStates();
|
|
@@ -2081,15 +2120,32 @@ class Roborock {
|
|
|
2081
2120
|
if (
|
|
2082
2121
|
this.getVacuumDeviceInfo(duid, "pv") === b01Q7Adapter.B01_PROTOCOL_VERSION
|
|
2083
2122
|
) {
|
|
2123
|
+
// These used to go through startCommand(), whose SIMPLE_VACUUM_COMMANDS
|
|
2124
|
+
// allow-list contains neither `set_clean_type` nor `set_custom_mode` —
|
|
2125
|
+
// so both fell through to `Command ... not found.` and nothing was ever
|
|
2126
|
+
// sent to the robot. Mathias' own Homebridge log has carried that line
|
|
2127
|
+
// since 2026-07-13. runMatterSettingCommand is the same path the classic
|
|
2128
|
+
// (non-B01) branch below already uses: it goes straight to
|
|
2129
|
+
// vacuum.command and reports unsupported results as errors.
|
|
2130
|
+
//
|
|
2131
|
+
// The value stays wrapped in an array on purpose. Matter clean mode 0 is
|
|
2132
|
+
// a valid selection (vacuum), and vacuum.command's default branch tests
|
|
2133
|
+
// `if (value && ...)` — a bare 0 is falsy and would silently be sent as
|
|
2134
|
+
// an empty parameter list, which b01Q7Adapter then drops entirely.
|
|
2084
2135
|
if (Number.isInteger(settings?.cleanMode)) {
|
|
2085
2136
|
try {
|
|
2086
|
-
await this.
|
|
2137
|
+
await this.runMatterSettingCommand(
|
|
2087
2138
|
duid,
|
|
2088
2139
|
"set_clean_type",
|
|
2089
2140
|
[settings.cleanMode],
|
|
2090
2141
|
commandOptions
|
|
2091
2142
|
);
|
|
2092
2143
|
} catch (error) {
|
|
2144
|
+
this.rememberUnsupportedMatterSettingCommand(
|
|
2145
|
+
duid,
|
|
2146
|
+
"set_clean_type",
|
|
2147
|
+
error
|
|
2148
|
+
);
|
|
2093
2149
|
this.log.debug(
|
|
2094
2150
|
`B01 clean-type command failed for ${duid}; continuing with the start command. ${error.message || error}`
|
|
2095
2151
|
);
|
|
@@ -2099,13 +2155,18 @@ class Roborock {
|
|
|
2099
2155
|
const fanPower = settings?.fanPower;
|
|
2100
2156
|
if (Number.isInteger(fanPower) && fanPower !== 105) {
|
|
2101
2157
|
try {
|
|
2102
|
-
await this.
|
|
2158
|
+
await this.runMatterSettingCommand(
|
|
2103
2159
|
duid,
|
|
2104
2160
|
"set_custom_mode",
|
|
2105
2161
|
[fanPower],
|
|
2106
2162
|
commandOptions
|
|
2107
2163
|
);
|
|
2108
2164
|
} catch (error) {
|
|
2165
|
+
this.rememberUnsupportedMatterSettingCommand(
|
|
2166
|
+
duid,
|
|
2167
|
+
"set_custom_mode",
|
|
2168
|
+
error
|
|
2169
|
+
);
|
|
2109
2170
|
this.log.debug(
|
|
2110
2171
|
`B01 suction command failed for ${duid}; continuing with the start command. ${error.message || error}`
|
|
2111
2172
|
);
|
|
@@ -2743,6 +2804,10 @@ class Roborock {
|
|
|
2743
2804
|
|
|
2744
2805
|
this.localConnector.clearLocalDevicedTimeout();
|
|
2745
2806
|
|
|
2807
|
+
// The MQTT startup watchdog is armed in initMQTT_Subscribe and would
|
|
2808
|
+
// otherwise survive shutdown and fire into a torn-down adapter.
|
|
2809
|
+
this.rr_mqtt_connector?.clearInitialConnectTimeout?.();
|
|
2810
|
+
|
|
2746
2811
|
for (const duid in this.vacuums) {
|
|
2747
2812
|
this.clearInterval(this.vacuums[duid].getStatusIntervalHandle);
|
|
2748
2813
|
this.clearInterval(this.vacuums[duid].mainUpdateIntervalHandle);
|