Repository navigation
fix(api): add rriotid, categoryId, category code and agreements to /api/v5/product - #207
Merged
Lash-L merged 2 commits intoOct 30, 2026
Conversation
…pi/v5/product
Opening a device in the Android app failed with error 21020 ("device
initialization failed") and the device plugin never reached the map. The app
database showed why: rr_product.rriotid was empty, rr_category.code was empty
and rr_product.agreements was null.
- rriotid: the app's API model (Product) reads the IoT product id under the
JSON name "rriotid" (the DB entity calls the same field productId). The
product lookup "select ... where rriotid=?" found nothing without it. The
cloud /api/v5/product response carries this field.
- categoryId: links the product to its category entry.
- category.code: CategoryEntity.code is mapped into Product.code, which the
device plugin receives as deviceCategory via PluginSDKModule.getConstants().
- agreements: PluginSDKModule.getProductAgreements returned null and the
plugin's privacy check never continued to fetchDeviceLocation(). An empty
list means "no product specific agreement required".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Android app's Product serializer knows picurl, cardpicurl, mediumCardpicurl, resetwifipicurl, pluginPicUrl and pictures. "cardPicUrl" (capital P) is not one of them, so the card picture was never set; the cloud response uses the lower-case name as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Looks good, TY |
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.
Problem
In the Android app (4.60.06), opening a device failed with error 21020 "device initialization failed". Once that was fixed, the device plugin never got as far as requesting the map. The app's local Room database (
rr-app-database) showed four gaps in what/api/v5/productdelivers:rr_product.rriotid = ''rriotidmissingcategoryIdmissingrr_category.code = ''codemissing in the category objectrr_product.agreements = 'null'agreementsmissingDetails from the app's serializers and mappers:
rriotid: The API modelProductreads the IoT product id under the JSON namerriotid. The DB entityProductEntitycalls the same fieldproductId, stored in the columnrriotid. The lookupselect * from rr_product where uid=? and rriotid=?therefore found nothing. That gaveProductEntity.DEFAULTand error 21020. The real cloud/api/v5/productresponse carriesrriotid. The value is the same id that home data puts indevices[].productId.category.code: The mapperProductAndCategory → ProductsetsProduct.codefromCategoryEntity.code.PluginSDKModule.getConstants()then passes it to the device plugin asdeviceCategory. With an empty code, the app did not enter its device layer at all: noget_statusorget_room_mappingwas sent to the robot until this was set.agreements:PluginSDKModule.getProductAgreementsreturnednull. The plugin's privacy check never continued tofetchDeviceLocation(), so the map was never requested. An empty list means "no product-specific agreement required".The second commit fixes a field-name typo.
Product$$serializerknowspicurl,cardpicurl,mediumCardpicurl,resetwifipicurl,pluginPicUrlandpictures. The server setcardPicUrl(capital P), which the app ignores. The cloud also usescardpicurl.Fix
routes/api/product_service.py:"rriotid": <IoT product id>,"categoryId": <category id>,"agreements": []"code": <category name>(e.g.robot.vacuum.cleaner)cardPicUrl→cardpicurlThe numeric
idis unchanged. It has to stay numeric: putting the string id there leaves the product table empty.Tests
tests/test_product_response.pyrriotid,categoryIdandagreements: []coderriotidmatches the home data device'sproductIdFull suite: passing.
Live check (Oct 2026): verified together with the other fixes of this series (all based on current
main) against the Android app 4.60.06 and a real Q7 Max (roborock.vacuum.a38). The device page opened without error 21020, the map and room names loaded. The product entry carried noproductId,codeorscope, and the app did not need them.Notes
endpoint_rules.pystill contains older copies of_normalize_devices,_build_web_stateand_build_product_response. Nothing calls them; the live code is inroutes/user/devices/service.pyandroutes/api/product_service.py. I left them alone, but they are easy to patch by mistake. For example, addingdevice["model"]there has no effect.pluginPicUrlis still set to the plain icon URL. In the cloud it is eithernullor a JSON string such as{"pluginPic": "...", "pluginPicWithDock": "..."}. I did not change that here.🤖 Generated with Claude Code