Repository navigation
Answer the official app's firmware calls with the cloud's real update information - #254
Draft
virtitnerd wants to merge 10 commits into
Draft
virtitnerd wants to merge 10 commits into
virtitnerd wants to merge 10 commits into
Conversation
The cloud lists newer models (e.g. roborock.vacuum.a226) under a string product id, so the import never fetched their app plugin and /api/v5/product answered with a hashed id that matches no plugin. The app then fails with "device initialization failed". The import now fetches the cloud's /api/v5/product to map models to their numeric id, and fetches /api/v1/appplugin for both type 2 (Android) and type 1 (iOS), which get different zips. The appplugin route answers iOS requests from the iOS catalog, falling back to the existing one. Fixes Python-roborock#221
The snapshot keeps the cloud login and the plugin catalogs fetched at sign-in, and the plugin routes serve those. Newer robots can need newer plugins than the snapshot holds, so CloudImportManager.refresh_plugin_catalogs asks the cloud again with the stored login and replaces only the catalogs. The sign-in now also stores the device identifier the cloud ties the login to. A rejected login or an empty answer leaves the snapshot as it was. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
POST /admin/api/cloud/refresh-plugins re-reads them with the stored login, taking an optional platform type. GET /admin/api/cloud/plugins shows what is stored without a cloud request. Both return each plugin's version, API level and download URL. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The refresh calls the same _fetch_plugin_catalogs as the sign-in import, so it gets whatever that fetches, instead of carrying its own platform type. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The firmware check is a Hawk-signed IoT call, so it uses the rriot credentials the sign-in stored. The refresh and the check now share one helper for loading that login. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
GET /ota/firmware/<duid>/updatev2 returns what the cloud says, so the official app and LocalRock can show an available update and its notes. POST /ota/device/<duid>/upgrade used to answer success and do nothing; it is now refused with a clear error, since installing a firmware needs the command the cloud pushes to the robot, which is not known yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ture The app checks with GET /ota/firmware/updatev2?duids=...&lang=..., reads progress from /ota/firmware/upgrade/status?duids=..., and installs with POST /ota/device/<duid>/upgrade (or /upgrade/latest-stable). The check and the progress are now read from the cloud, both upgrade forms are refused, and the older path-style check still works. These routes answer from the stored cloud login, so they now need the same Hawk signature as the /user/ routes instead of being open. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The app sends the firmware check and the progress read within milliseconds of each other and gives them the same timestamp and nonce. The replay check keys on timestamp and nonce, not the path, so the second request was refused and the Firmware Update screen showed a network error until the app retried. The signature and its age are still verified for these read-only GETs; only the repeated-nonce refusal is skipped. Everything else, including the upgrade POST, keeps it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
GET /admin/api/cloud/firmware asks the cloud about each robot in the home data the sign-in stored, including robots that are not paired to this server, so an available update can be seen before pairing. A failure for one robot is reported on its row without hiding the rest. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Depends on: #253
Depends on the plugin catalog refresh PR for the cloud client helpers, and through it on #224. The top six
commits are the new ones.
Why
The server answered the official app's firmware calls with a generic success, so the app could never see that a robot
had an update. The routes the app really uses turned out to be
GET /ota/firmware/<duid>/updatev2,GET /ota/firmware/updatev2?duids=...andGET /ota/firmware/upgrade/status?duids=....What
The server reads the update information from Roborock's cloud with the stored login and returns it, so the app shows
the real version and release notes. These routes require the app's signature, and a read is never refused as a
replayed signature (the app repeats them). The upgrade call is still refused with an error instead of pretending to
start.
GET /admin/api/cloud/firmwarelists every robot's status on the account for scripts.Testing
tests/test_ota_firmware.pycovers both URL styles, the signature requirement and the replay case, with a fakecloud. Full suite: 480 passed. Checked against the iOS app, which now shows the real version for a Qrevo Pro and a
Qrevo Curv 2 Flow.
Notes
Needs the cloud login the server stored at sign-in. Without it the check is reported as unavailable.