Support multi-repository firmware updates with persistent repository storage#1
Support multi-repository firmware updates with persistent repository storage#1
Conversation
- Added 'repo' field to Info model to capture repository from /json/info - Updated Version and Asset models to include repository field (as "owner/name" string) - Created database migrations (9->10->11) for repository support - Modified ReleaseService to fetch from multiple repositories - Updated DeviceUpdateManager to use repo field with fallback to "wled/WLED" - Changed default repository from "Aircoookie/WLED" to "wled/WLED" - Updated MainViewModel to collect repositories from connected devices - Modified queries and repository methods to filter by repository Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
- Add @Inject annotation to ReleaseService for dependency injection - Update GithubApi.downloadReleaseBinary to use repository from Asset - Add DeviceStateInfo import and clean up type annotation - Remove unused DEFAULT_REPO constants from GithubApi Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
The repo field was added in WLED 0.15.2, not 0.16 as previously documented in the code comment. Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
- Restored UpdateSourceType enum, UpdateSourceDefinition data class, and UpdateSourceRegistry object - Updated getRepositoryFromInfo() to use three-tier fallback strategy: 1. First: Use info.repo field if present (WLED 0.15.2+) 2. Second: Use UpdateSourceRegistry brand pattern matching 3. Third: Default to "wled/WLED" - Updated registry to use "wled/WLED" instead of "Aircoookie/WLED" for consistency - Maintains backward compatibility for devices without repo field - QuinLED devices will be correctly identified via brand matching Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
| val releaseService = ReleaseService(versionWithAssetsRepository) | ||
| releaseService.refreshVersions(githubApi) | ||
| // Always include the default repository | ||
| val repositories = setOf("wled/WLED") |
There was a problem hiding this comment.
@copilot This does not look correct, surely this will only refresh the default repo, when would we be refreshing versions for other repos? Should this not be the default + unique list of repos for discovered devices?
There was a problem hiding this comment.
You're absolutely right! Fixed in commit b89efb4.
DeviceEditViewModel.checkForUpdates() now collects repositories from all connected devices via the injected WebsocketClient map, matching the approach used in MainViewModel.downloadUpdateMetadata(). It gathers the default repository plus unique repositories from all discovered devices before calling refreshVersions().
- Inject WebsocketClient map into DeviceEditViewModel - Update checkForUpdates() to collect repositories from all connected devices - Now matches MainViewModel's approach: default + unique list of repos - Ensures updates are fetched for all device types (QuinLED, MoonModules, etc.) Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
- Changed from collecting all device repositories to just the selected device - Lookup device by macAddress in websocketClients map - Only refresh that specific device's repository plus default fallback - More appropriate for device-specific edit context - MainViewModel still handles refreshing all repositories globally Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
…/ReleaseService.kt Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Will Tatam <will@netmindz.net>
…deviceEdit/DeviceEditViewModel.kt Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Will Tatam <will@netmindz.net>
|
@copilot are you able to address the issues raised on Moustachauve#125 by gemini-code-assist ? |
…lines - Remove all trailing whitespace from DbMigration9To10.kt and ReleaseService.kt - Split FOREIGN KEY constraint in DbMigration9To10.kt to fit 120 char limit - Split long @query annotations in VersionDao.kt to multiline format - All lines now under 120 character limit - All trailing whitespace removed - Code now passes ktlint/spotless formatting checks Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
Fixed in commit c7adcde. The remaining lint issues were:
All files now comply with ktlint/spotless rules:
The code should now pass Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
…/DeviceUpdateService.kt Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Will Tatam <will@netmindz.net>
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](actions/upload-artifact@v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
kotlin The Result: The background check will only query DEFAULT_REPO (wled/WLED), then cache lastUpdateCheckDate in DataStore for the next 24 hours. Because it saves the 24h cooldown, devices using custom repositories will never get their .bin updates fetched automatically. Device Recommendation: Since this is a feature branch that has not yet been merged into dev or main, you should simply delete 11.json, delete DbMigration10To11.kt, and revert version = 11 back to version = 10 in DevicesDatabase.kt. You can safely perform all these migrations cleanly in a single 9 -> 10 step without a redundant bump. Changes
|
Issue 1 - Race Condition Fix: - Added repository field to Device entity with default "wled/WLED" - WebsocketClient now stores repository when device info is received - DeviceFirstContactService stores repository when creating/updating devices - MainViewModel.downloadUpdateMetadata() now queries devices from database instead of websockets - Eliminates race condition where websockets haven't connected yet on app launch - Ensures all device repositories are refreshed during 24h background checks Issue 2 - Remove Redundant Migration: - Deleted DbMigration10To11.kt (was only dropping already-dropped tables) - Deleted schema 11.json (identical to 10.json) - Consolidated all changes into single 9→10 migration - Updated MIGRATION_9_10 to also add repository column to Device2 table - Database version remains at 10 as requested Co-authored-by: netmindz <442066+netmindz@users.noreply.github.com>
Fixed both issues in commit 39bfdda. Issue 1 - Race Condition: Added Issue 2 - Redundant Migration: Deleted The repository field is populated when:
|
… field and modify update logic to handle null info
Support multi-repository firmware updates with proper data migration ✅
WLED ecosystem has multiple forks (MoonModules/WLED-MM, QuinLED custom firmware). App was hardcoded to single repository. WLED 0.15.2+ exposes
repofield in/json/info.Changes
Data model
repo: String?to Info modelrepository: Stringto Device entity with default "wled/WLED" - persists repository information per devicerepository: Stringto Version/Asset entities with composite primary keysdefaultValue = "'wled/WLED'"to Asset.repository to match migration schemaRepository detection - three-tier fallback
Repository persistence
WebsocketClient: Stores repository to Device entity when receiving device infoDeviceFirstContactService: Stores repository when creating/updating devices via APIUpdate contexts
MainViewModel.downloadUpdateMetadata(): Queries devices from database (not websockets) to collect all repositories - fixes race condition where websockets haven't connected on app launchDeviceEditViewModel: Refreshes only selected device's repositoryMigration data preservation
Code quality
DEFAULT_REPOconstant (was duplicated in 3 files)ReleaseServicein DeviceEditViewModel via Hilt DI (was manually instantiated)splitRepository()validationSQL Syntax Fixes
ON UPDATE NO ACTIONandON DELETE CASCADEDefault repository: "Aircoookie/WLED" → "wled/WLED" (canonical post-rename).
Migration Testing
Confirmed successful migration from v9 to v10:
Race Condition Fix
Background update checks now query devices from database instead of relying on active websocket connections. This ensures all device repositories are included in the 24-hour background refresh, even when websockets haven't connected yet on app launch.
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.