Skip to content

feat: roll back to stable firmware from device info page#6296

Merged
mdmohsin7 merged 13 commits into
mainfrom
feat/rollback-to-stable-firmware
Apr 4, 2026
Merged

feat: roll back to stable firmware from device info page#6296
mdmohsin7 merged 13 commits into
mainfrom
feat/rollback-to-stable-firmware

Conversation

@mdmohsin7
Copy link
Copy Markdown
Member

@mdmohsin7 mdmohsin7 commented Apr 3, 2026

Summary

  • Backend: Refactored /v2/firmware/latest to extract shared logic into helpers (_get_release_prefix, _find_candidate_releases, _extract_firmware_response). Added new /v2/firmware/stable endpoint that returns the latest stable firmware for a device model regardless of current version.
  • App: Added "Roll Back to Stable Firmware" action in the device info page (between Product Update and SD Card Sync). Only visible when the connected device's firmware version differs from the latest stable version.
  • Firmware Update page: Accepts isRollback flag — when true, fetches from the stable endpoint and always allows installation with rollback-specific UI text.
  • L10n: 8 new keys with real translations across all 34 locales.

Test plan

  • Connect a device running custom/non-stable firmware → verify "Roll Back to Stable Firmware" option appears in device info
  • Connect a device running the latest stable firmware → verify rollback option does NOT appear
  • Tap rollback → verify it fetches stable firmware details and shows install button
  • Complete rollback install → verify DFU process works same as regular firmware update
  • Verify /v2/firmware/latest still works unchanged for regular update checks
  • Verify /v2/firmware/stable?device_model=Omi+DevKit+2 returns latest stable release

🤖 Generated with Claude Code

…/stable endpoint

Extract version filtering, prefix mapping, and response building into reusable
helpers. Add new /v2/firmware/stable endpoint that returns the latest stable
firmware for a device regardless of current version, enabling rollback from
custom firmware.
Add isRollback flag that fetches from stable endpoint and uses
rollback-specific UI text for title, loading, and install button.
Shows only when device firmware differs from latest stable version.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 3, 2026

Greptile Summary

This PR adds a "Roll Back to Stable Firmware" option in the device info page, backed by a new /v2/firmware/stable backend endpoint. The backend refactor cleanly extracts shared release-filtering logic into helpers (_get_release_prefix, _find_candidate_releases, _extract_firmware_response) and the Flutter side branches on an isRollback flag in FirmwareUpdate to fetch from the stable endpoint and skip the "is newer?" gate. The implementation is straightforward and the retry/error-handling patterns match the existing firmware update flow.

Confidence Score: 4/5

Safe to merge with minor cleanup — no blocking logic errors, but the stable endpoint can return a pre-release tag as "stable" firmware and three l10n keys are defined but never used.

Both findings are P2: the pre-release leak is a correctness concern for the new "stable" endpoint (though it mirrors the pre-existing behavior of /v2/firmware/latest), and the unused l10n keys indicate a confirmation dialog was designed but not wired up. Neither blocks the primary user path, but the pre-release issue is worth addressing before shipping the stable endpoint broadly.

backend/routers/firmware.py (_find_candidate_releases pre-release filtering) and app/lib/l10n/app_en.arb (unused rollbackConfirmTitle/Message/alreadyOnStableFirmware keys)

Important Files Changed

Filename Overview
backend/routers/firmware.py Refactored shared logic into helpers and added /v2/firmware/stable endpoint; endpoint may return pre-release as "stable" since prerelease flag is not filtered
app/lib/pages/home/device.dart Adds rollback menu item; visibility logic correctly guards on connectedDevice, non-empty stable version, and version mismatch
app/lib/pages/home/firmware_update.dart Adds isRollback flag to branch between stable and latest fetch paths; UI text and shouldUpdate logic are correct for rollback flow
app/lib/providers/device_provider.dart Adds latestStableFirmwareVersion state with v-prefix stripped; fetched inside shouldUpdateFirmware with its own try-catch so failures are non-fatal
app/lib/l10n/app_en.arb 8 new l10n keys added; rollbackConfirmTitle, rollbackConfirmMessage, and alreadyOnStableFirmware are defined but never referenced in UI code

Sequence Diagram

sequenceDiagram
    participant App as Flutter App
    participant DP as DeviceProvider
    participant BE as Backend
    participant GH as GitHub Releases

    App->>DP: connect device
    DP->>BE: GET /v2/firmware/latest
    BE->>GH: fetch releases (cached 5min)
    GH-->>BE: releases[]
    BE-->>DP: {version, zip_url, ...}
    DP->>BE: GET /v2/firmware/stable?device_model=X
    BE->>GH: fetch releases (cache hit)
    GH-->>BE: releases[]
    BE-->>DP: {version, zip_url, ...}
    DP-->>App: latestStableFirmwareVersion set

    Note over App: Show rollback button if firmwareRevision != latestStableFirmwareVersion

    App->>App: navigate FirmwareUpdate(isRollback=true)
    App->>BE: GET /v2/firmware/stable?device_model=X
    BE-->>App: stable firmware details
    App-->>App: show Install Stable Firmware button
    App->>App: DFU install (same flow as regular update)
Loading

Reviews (1): Last reviewed commit: "chore(l10n): regenerate localization dar..." | Re-trigger Greptile

Comment thread app/lib/l10n/app_en.arb
Comment on lines +10710 to 10722
"noStableFirmwareFound": "Could not find a stable firmware version for your device.",
"@noStableFirmwareFound": {
"description": "Error message when no stable firmware is available"
},
"installStableFirmware": "Install Stable Firmware",
"@installStableFirmware": {
"description": "Button text to install the stable firmware"
},
"alreadyOnStableFirmware": "You are already on the latest stable version.",
"@alreadyOnStableFirmware": {
"description": "Message when device is already on the latest stable firmware"
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Three l10n keys defined but never used in code

rollbackConfirmTitle, rollbackConfirmMessage, and alreadyOnStableFirmware are translated across all 34 locales but are never referenced anywhere in the Dart UI code (confirmed via search). rollbackConfirmTitle/rollbackConfirmMessage suggest a confirmation dialog before rollback was planned but never wired up — tapping "Roll Back to Stable Firmware" in device.dart navigates directly to FirmwareUpdate with no pre-flight confirmation. Either implement the dialog using these keys (which would be better UX before a DFU install) or remove the dead strings to avoid localization bloat.

Comment on lines +276 to +298
@router.get("/v2/firmware/stable")
async def get_stable_version(device_model: str):
"""Return the latest stable firmware for a device, regardless of current version.

Used for rolling back to the official stable firmware after flashing custom firmware.
"""
device = _get_device_by_model_number(device_model)
if not device:
raise HTTPException(status_code=404, detail="Device not found")

releases = await get_omi_github_releases("github_releases_omi", tag_filter=FIRMWARE_TAG_PATTERN)
if not releases:
raise HTTPException(status_code=404, detail="No releases found for the repository")

release_prefix = _get_release_prefix(device)
candidates = _find_candidate_releases(releases, release_prefix)

if not candidates:
raise HTTPException(status_code=404, detail="No stable firmware found for your device.")

candidates.sort(key=lambda r: r.get("published_at", ""), reverse=True)
return _extract_firmware_response(device, candidates[0])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Stable endpoint may return a GitHub pre-release

_find_candidate_releases only skips draft releases and those missing published_at or tag_name. It does not check the prerelease field from the GitHub API. If the most recently published release matching the prefix is a pre-release (e.g. a beta or RC), the /v2/firmware/stable endpoint would return it as "stable firmware" for rollback. The existing /v2/firmware/latest shares this gap, but the stakes are higher here because the endpoint is specifically branded "stable". Consider adding if release.get("prerelease"): continue inside _find_candidate_releases when current_firmware_tuple is None (or unconditionally if the intent is to treat all non-draft, non-pre-release tags as stable).

Uses rollbackConfirmTitle and rollbackConfirmMessage l10n keys.
Keep both rollback firmware keys and main's new audioSavedLocally/willSyncAutomatically keys.
Regenerate localization dart files.
@mdmohsin7 mdmohsin7 merged commit adf9c8c into main Apr 4, 2026
2 checks passed
@mdmohsin7 mdmohsin7 deleted the feat/rollback-to-stable-firmware branch April 4, 2026 10:15
Glucksberg pushed a commit to Glucksberg/omi-local that referenced this pull request Apr 28, 2026
…re#6296)

## Summary
- **Backend**: Refactored `/v2/firmware/latest` to extract shared logic
into helpers (`_get_release_prefix`, `_find_candidate_releases`,
`_extract_firmware_response`). Added new `/v2/firmware/stable` endpoint
that returns the latest stable firmware for a device model regardless of
current version.
- **App**: Added "Roll Back to Stable Firmware" action in the device
info page (between Product Update and SD Card Sync). Only visible when
the connected device's firmware version differs from the latest stable
version.
- **Firmware Update page**: Accepts `isRollback` flag — when true,
fetches from the stable endpoint and always allows installation with
rollback-specific UI text.
- **L10n**: 8 new keys with real translations across all 34 locales.

## Test plan
- [x] Connect a device running custom/non-stable firmware → verify "Roll
Back to Stable Firmware" option appears in device info
- [ ] Connect a device running the latest stable firmware → verify
rollback option does NOT appear
- [x] Tap rollback → verify it fetches stable firmware details and shows
install button
- [x] Complete rollback install → verify DFU process works same as
regular firmware update
- [x] Verify `/v2/firmware/latest` still works unchanged for regular
update checks
- [x] Verify `/v2/firmware/stable?device_model=Omi+DevKit+2` returns
latest stable release

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant