* Add CI scripts for iOS Qt 5.15.2 build process
Introduced three CI scripts: ci_post_clone.sh for setting up Qt 5.15.2 and patched libraries, ci_pre_xcodebuild.sh for running qmake and restoring WatchOS references, and ci_post_xcodebuild.sh for post-build verification and artifact logging. These scripts automate the iOS build environment setup and validation for QDomyos-Zwift.
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Enforce exact Qt 5.15.2 install and Xcode Cloud fixes
Update CI scripts to strictly require and verify Qt 5.15.2, using aqt or Homebrew with version pinning. Add robust error handling for incorrect Qt versions, ensure patched Bluetooth libraries are present, and improve messaging. In pre-xcodebuild, verify Qt version, add Xcode Cloud build location fixes via xcconfig and pbxproj edits, and enhance error handling for project configuration.
* Update ci_post_clone.sh
* Use local Homebrew formula for Qt 5.15.2 installation
Updated the CI post-clone script to install Qt 5.15.2 using a local Homebrew formula instead of downloading it from an external source. Added the qt5.rb formula to the repository under ci-scripts/homebrew-formulas for reproducible and reliable builds.
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Update ci_post_clone.sh
* Initial commit
Project files added to set up the initial codebase.
* Update project.pbxproj
* Revert "Update project.pbxproj"
This reverts commit f17455cfe7.
* Revert "Initial commit"
This reverts commit 91c30cc8b1.
* relative paths
* relative paths
* porting from aradar xcode project
* Update project.pbxproj
* Add Xcode workspace configuration files
Added initial Xcode workspace files including contents.xcworkspacedata, IDEWorkspaceChecks.plist, and SwiftPM Package.resolved for project setup and dependency management.
* Update project.pbxproj
* Update project.pbxproj
* Update project.pbxproj
* Create PrivacyInfo.xcprivacy
* Create PrivacyInfo.xcprivacy
* Revert "Create PrivacyInfo.xcprivacy"
This reverts commit 5a8fb9dee5.
* Revert "Update project.pbxproj"
This reverts commit e160c9bf6e.
* Reapply "Update project.pbxproj"
This reverts commit 1cf0092c57.
* Revert "Create PrivacyInfo.xcprivacy"
This reverts commit e0ede5d42d.
* Revert "Update project.pbxproj"
This reverts commit e160c9bf6e.
* Revert "Update project.pbxproj"
This reverts commit f8025155cc.
* Revert "Update project.pbxproj"
This reverts commit ac4d5f5fc0.
* Revert "Add Xcode workspace configuration files"
This reverts commit a3aacc002b.
* Revert "Update project.pbxproj"
This reverts commit d5e68987e6.
* Revert "porting from aradar xcode project"
This reverts commit 21f489b86d.
* Revert "relative paths"
This reverts commit 2002677955.
* Revert "relative paths"
This reverts commit 4da17e3ae9.
* trying to don't change the full directory structure
* Update _ci_pre_xcodebuild.sh
* Update project.pbxproj
* Persist and load Qt environment for CI scripts
ci_post_clone.sh now saves the Qt environment variables to a persistent file (/tmp/qt_env.sh) after installation or detection. ci_pre_xcodebuild.sh is renamed and updated to load this environment file, ensuring consistent Qt configuration across CI steps. Additional debug output is added for troubleshooting.
* Update ci_pre_xcodebuild.sh
* Update project.pbxproj
* Update ci_pre_xcodebuild.sh
* Update ci_pre_xcodebuild.sh
* debug
* Update ci_post_clone.sh
* Update project.pbxproj
* Update project.pbxproj
* Update ci_pre_xcodebuild.sh
* Update project.pbxproj
* Update project.pbxproj
* Update qdomyos-zwift.pri
* Update qdomyos-zwift.pri
* Update qdomyos-zwift.pri
* Update qdomyos-zwift.pro
* Update qdomyos-zwift.pri
* Update qdomyos-zwift.pri
* fake xcode
* foxing
* Revert "foxing"
This reverts commit 5dd813b2f5.
* Update ci_pre_xcodebuild.sh
* Update ci_pre_xcodebuild.sh
* signing
* Update qdomyos-zwift.pro
* Update ci_pre_xcodebuild.sh
* Update ci_pre_xcodebuild.sh
* Update ci_pre_xcodebuild.sh
* Update ci_pre_xcodebuild.sh
* Update ci_pre_xcodebuild.sh
* Update ci_pre_xcodebuild.sh
* relative path
* Update project.pbxproj
* Update project.pbxproj
* moc relative
* signing
* root project
* Update qdomyos-zwift.pro
* Update ci_pre_xcodebuild.sh
* Update ci_pre_xcodebuild.sh
* Fix Xcode Cloud build: symlink to correct project with code signing
qmake regenerates src/qdomyoszwift.xcodeproj without code signing during
make, causing build failures. After make completes, we now:
- Delete the corrupted project in src/
- Create symlink to the correct project in build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/
- xcodebuild now uses the project with proper code signing configuration
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix: Create fake xcodebuild BEFORE make to prevent circular failure
The previous fix failed because:
1. make was calling xcodebuild with corrupted project
2. xcodebuild failed due to code signing
3. make exited with error
4. Script never reached symlink creation (circular problem)
This fix:
1. Creates fake xcodebuild BEFORE make starts
2. make completes successfully (fake xcodebuild returns success)
3. Script continues and creates symlink to correct project
4. Removes fake xcodebuild from PATH
5. Real xcodebuild (from Xcode Cloud) uses symlinked project with code signing
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix: Use absolute paths to avoid git repo not found error
Problems fixed:
1. Script not executable - added chmod +x
2. cd .. after make went to wrong directory → git repo not found
3. find ../src failed after make → wrong directory
Solution:
- Save PROJECT_ROOT absolute path at start
- Use "$PROJECT_ROOT" instead of cd ..
- Use "$PROJECT_ROOT/src" instead of ../src
- Made script executable (755)
Now script can find git repo and source files regardless of where make leaves us.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Add missing QZWidgetExtension.entitlements from master
Xcode build was failing with:
"Build input file cannot be found: QZWidgetExtension.entitlements"
This file exists in master but was missing from xcode-cloud-scripts branch.
Copied from master to fix the build error.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Resolve merge conflict: use master version of settings.local.json
* Copy ALL Qt-generated files from src/ to build directory
Problem: qmake/make generates files (moc_*.cpp, qrc_*.cpp,
qmltyperegistrations, etc.) in src/ but Xcode expects them in
build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/
Solution: After make completes, copy all generated files to build directory:
- MOC files (moc_*.cpp, moc_*.cpp.json)
- QRC files (qrc_*.cpp)
- Object files (*.o, *.a)
- QML type registrations (*_qmltyperegistrations.*)
- Metatypes (*_metatypes.json, *.qmltypes)
- Plugin imports (*_plugin_import.cpp)
This matches the local build directory structure.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix file copy timing - move AFTER git restore
Critical bug fix: The file copy from src/ to build/ was happening BEFORE
git checkout, which was then wiping out the copied files.
Changes:
- Move file copy to AFTER git checkout to preserve generated files
- Add -print flag to show which files are being copied
- Add verification step to confirm qdomyoszwift_qmltyperegistrations.cpp exists
This ensures Qt-generated files (MOC, QML type registrations, etc.) are
properly available in the build directory for Xcode to find them.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix qmltyperegistrations filename mismatch
Critical fix: qmake generates qdomyos-zwift_qmltyperegistrations.cpp (with hyphen)
but Xcode project expects qdomyoszwift_qmltyperegistrations.cpp (no hyphen).
Added:
- Copy/rename step to create the non-hyphenated version Xcode expects
- Handle both .cpp and .o files
- Verification output to confirm file exists
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Add symlink for Qt path compatibility - fix httpserver module
The Qt archive contains .pri files with hardcoded absolute paths from
local development machine (/Users/cagnulein/Qt/5.15.2/).
When extracted on Xcode Cloud to /tmp/Qt-5.15.2/, qmake can't find
httpserver and other modules because it looks in the original path.
Solution: Create symlink from original path to Xcode Cloud path so
qmake can find all modules including httpserver.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix hardcoded paths in .pri files instead of using symlinks
Replace sudo symlink approach (requires password) with direct path
replacement in .pri files using sed.
- Find all .pri files in Qt installation
- Replace /Users/cagnulein/Qt/5.15.2 with /tmp/Qt-5.15.2
- Verify httpserver module .pri file is findable after fix
This allows qmake to find httpserver and other modules without
requiring elevated privileges.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix Qt library relative paths in Xcode project
The Xcode project contains relative paths to Qt libraries like:
../../Qt/5.15.2/ios/qml/Qt/labs/calendar/libqtlabscalendarplugin.a
These relative paths don't resolve correctly on Xcode Cloud.
Solution: After git restore, use sed to replace relative Qt paths
with absolute paths pointing to /tmp/Qt-5.15.2/ios/
This fixes the "library 'qtlabscalendarplugin' not found" error.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Add Qt/labs/calendar to library search paths
The qtlabscalendarplugin library exists but wasn't in the linker's
search paths, causing "library not found" error.
Changes:
- Add ls verification to confirm library file exists
- Add /tmp/Qt-5.15.2/ios/qml/Qt/labs/calendar to LIBRARY_SEARCH_PATHS
- Add debugging output to show calendar path references
This ensures the linker can find libqtlabscalendarplugin.a during linking.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Add all necessary Qt library search paths
Instead of adding only calendar path, add ALL common Qt iOS library
paths that might be missing from the committed Xcode project:
- Qt/labs/* (calendar, platform)
- QtCharts, QtWebView, QtPositioning, QtLocation, QtMultimedia
- plugins/* (platforms, webview, texttospeech, geoservices,
sqldrivers, mediaservice, playlistformats, audio)
This should fix "library not found" errors for qios_debug and other
Qt libraries that qmake expects to find in these directories.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Replace debug Qt libraries with release versions
The Qt package only contains release libraries, not debug versions.
The Xcode project has some references to _debug libraries which causes
the linker to look for debug versions of ALL Qt libraries, including
qios_debug which doesn't exist.
Solution: Use sed to replace all _debug library references with release
versions:
- lib*_debug.a -> lib*.a (file references)
- -l*_debug -> -l* (linker flags)
This fixes "library 'qios_debug' not found" and similar errors.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Change all scheme configurations to Release
Xcode Cloud was building in Debug mode, looking for debug Qt libraries
(_debug suffix) which don't exist in the Qt package (only release libs).
Changed all scheme actions to use Release configuration:
- TestAction: Debug -> Release
- LaunchAction: Debug -> Release
- AnalyzeAction: Debug -> Release
- ArchiveAction: already Release
This ensures Xcode Cloud builds with release Qt libraries.
qDebug output will still work in Release builds.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Download and install missing qmldbg libraries
The Qt package is missing libqmldbg_debugger.a and
libqmldbg_nativedebugger.a which are needed for linking.
Solution: Download the missing libraries from GitHub release and
install them in /tmp/Qt-5.15.2/ios/plugins/qmltooling/
This fixes "Library 'qmldbg_debugger' not found" error.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fail build if qmldbg libraries are not found
- Add exit 1 after error messages if files are not found
- Show contents after zip extraction for debugging
- Create target directory before moving files
If the required libraries cannot be installed, the build must fail
immediately rather than continuing without them.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Download both qmldbg library files separately
- Download libqmldbg_debugger.a.zip (new file with correct version)
- Download libqmldbg_debugger.zip (has nativedebugger files)
- Use _debug version of nativedebugger as fallback if release not found
- Show all extracted files for debugging
- Fail fast if required files are missing
This ensures both libqmldbg_debugger.a and libqmldbg_nativedebugger.a
are properly installed.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Reorganize Xcode Cloud CI configuration to use dynamic project modifications
This commit reorganizes the CI setup to keep project files clean and apply all modifications via CI scripts:
Changes:
1. ci_post_clone.sh: Added secret.h generation from Xcode Cloud environment variables
- Generates secret.h with STRAVA_SECRET_KEY, PELOTON_SECRET_KEY, SMTP credentials, etc.
- Generates cesium-key.js if CESIUMKEY environment variable is provided
- Matches the pattern used in GitHub workflows
2. ci_pre_xcodebuild.sh: Enhanced with comprehensive project file modifications
- Added path fixes for local development paths -> Xcode Cloud paths
- Added scheme modification from Debug to Release configuration
- Preserved existing fixes: _debug suffix removal, library search paths, qmltyperegistrations
3. project.pbxproj and qdomyoszwift.xcscheme: Reverted to master branch versions
- Project files now stay clean in the repository
- All environment-specific modifications done dynamically in CI scripts
4. ci_post_xcodebuild.sh: Removed (no longer needed)
Benefits:
- Clean project files in repository (easier to maintain and review)
- All CI-specific modifications isolated in CI scripts
- Easier to debug and update CI configuration
- Consistent with GitHub workflow patterns
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix legacy build locations error by removing SYMROOT in CI script
After reverting project.pbxproj to master, SYMROOT settings were restored
causing: "Packages are not supported when using legacy build locations"
Solution: Remove SYMROOT and OBJROOT lines dynamically in ci_pre_xcodebuild.sh
instead of committing the change to project.pbxproj.
This keeps project files clean while fixing the Swift package compatibility issue.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Create workspace settings to disable legacy build locations
The error "Packages are not supported when using legacy build locations"
requires both:
1. Removing SYMROOT from project.pbxproj
2. Creating WorkspaceSettings.xcsettings and IDEWorkspaceChecks.plist
These workspace files force Xcode to use the modern build system and
disable legacy build locations, enabling Swift Package Manager support.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Move legacy build locations fix to ci_post_clone.sh
Xcode Cloud executes scripts in this order:
1. ci_post_clone.sh
2. xcodebuild -resolvePackageDependencies (was failing here)
3. ci_pre_xcodebuild.sh (never reached)
The workspace settings and SYMROOT removal must happen in ci_post_clone.sh
BEFORE Xcode Cloud tries to resolve package dependencies.
This fixes: "Packages are not supported when using legacy build locations"
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix absolute paths for resource files (Default-568h@2x.png)
After reverting project.pbxproj to master, resource files like
Default-568h@2x.png have absolute paths from local development machine:
/Users/cagnulein/qdomyos-zwift/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/
These paths don't exist on Xcode Cloud. Convert them to relative paths:
qdomyoszwift.xcodeproj/Default-568h@2x.png
Added fix to both ci_post_clone.sh and ci_pre_xcodebuild.sh to ensure
paths are correct throughout the build process.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix resource file paths and sourceTree for LaunchScreen.storyboard
Resource files have both absolute paths and sourceTree = "<absolute>"
which prevents Xcode Cloud from finding them.
Changed the fix to:
1. Convert absolute paths to relative (remove local machine prefix)
2. Change sourceTree from "<absolute>" to "<group>"
This allows Xcode to find resource files relative to their group
in the project structure.
Fixes: Default-568h@2x.png, LaunchScreen.storyboard, and other resources
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix sed syntax to keep quotes in resource file paths
The sed was removing quotes from paths causing parse errors:
path = Default-568h@2x.png (WRONG - causes parse error)
Fixed to maintain quotes:
path = "Default-568h@2x.png" (CORRECT)
This prevents "project is damaged and cannot be opened" error.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Use SOURCE_ROOT for resource file paths instead of <group>
Changed sourceTree from <group> to SOURCE_ROOT with full relative path:
- path = "build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/Default-568h@2x.png"
- sourceTree = SOURCE_ROOT
On Xcode Cloud, SOURCE_ROOT = /Volumes/workspace/repository/, so files
will be found at the correct location.
Tested locally before committing to verify sed produces valid output.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix all paths to match working version exactly
Tested locally to ensure output matches the working version exactly.
All key files verified:
✓ Default-568h@2x.png: MATCH
✓ LaunchScreen.storyboard: MATCH
✓ Qt5Core: MATCH
✓ virtualbike.cpp: MATCH
Path fixes applied in correct order:
1. Qt paths: /Users/cagnulein/Qt/5.15.2/ios/ -> /tmp/Qt-5.15.2/ios/
2. Source paths: /Users/cagnulein/qdomyos-zwift/src/ -> ../src/
3. General: /Users/cagnulein/qdomyos-zwift/ -> /Volumes/workspace/repository/
4. sourceTree fix: ../src/* files use <group> not <absolute>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Revert project files to updated master
Previous revert used outdated master missing sportstechrower and filesearcher.
Now reverting to updated master that includes all recent files.
Tested locally - all files match working version:
✓ sportstechrower.cpp: MATCH
✓ filesearcher.cpp: MATCH
✓ Default-568h@2x.png: MATCH
✓ virtualbike.cpp: MATCH
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix QZWidget extension version to match app version
Changed MARKETING_VERSION from 1.0 to 2.20 for QZWidgetExtension
to fix error: CFBundleShortVersionString Mismatch
App version: 2.20
Widget version: 2.20 (was 1.0)
Build number (1285) should be configured in Xcode Cloud dashboard.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Use echo instead of heredoc for secret.h generation
Changed from heredoc (cat << EOF) to echo statements to match
GitHub workflow exactly. This should fix potential escaping issues
with environment variables like PELOTON_SECRET_KEY.
Now identical to GitHub workflow approach.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Add permissions for Bash commands in settings
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* Implement C++ FileSearcher for fast recursive training file search
Replaced slow QML-based recursive search with native C++ implementation
for significantly improved performance when searching training files.
Changes:
- Added FileSearcher C++ class (filesearcher.h/cpp) with recursive
directory scanning using QDir
- Exposed FileSearcher to QML via QML context in main.cpp
- Updated TrainingProgramsListJS.qml to use C++ searcher instead of
iterating FolderListModel with timers and workarounds
- Search now completes instantly instead of requiring multiple event
loop iterations and status polling
- Maintains all functionality from previous QML implementation:
* Recursive search through all subfolders
* Case-insensitive pattern matching
* Display of relative paths in search results
* Seamless switching between search and browse modes
This C++ implementation eliminates the iOS-specific workarounds and
complex timer-based polling that was required with the pure QML solution.
Ticket #4305 (replaces #4307)
https://claude.ai/code/session_016M39Bq6UXKekXcf2HjD2gm
* Update project.pbxproj
* Update project.pbxproj
* Update project.pbxproj
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Add PM5 Concept2 protocol support to virtual rower
Adds a new experimental setting "Virtual Rower as PM5" that enables
the virtual rower to emulate a Concept2 PM5 monitor using the
proprietary PM5 BLE protocol instead of FTMS. This provides
compatibility with apps like Mywhoosh that only support PM5 rowers.
When enabled, the virtual rower:
- Advertises as "PM5 430000000" with Concept2 proprietary service UUIDs
- Implements PM5 Rowing Service (CE060030) with characteristics:
- General Status (CE060031): elapsed time, distance, workout state
- Additional Status (CE060032): speed, stroke rate, HR, pace, power
- Additional Status 2 (CE060033): calories, split data
- Sends data in PM5 format with proper units and encoding
The setting is only visible when "Virtual Rower" is enabled.
Uses OR logic: when PM5 mode is enabled, only PM5 protocol is sent
(FTMS is disabled).
https://claude.ai/code/session_01XWBgRPWze8Mb7DEEm4oXiF
* Add complete PM5 BLE services for better compatibility
Expands PM5 emulation with all required services:
- Generic Access Service (0x1800): device name, appearance, connection params
- PM5 Device Information (CE060010): model, serial, HW/FW revision, manufacturer
- PM5 Control Service (CE060020): CSAFE command receive/transmit
- PM5 Rowing Service (CE060030): additional stroke data characteristics
Also adds Discovery Service UUID (CE060000) to advertising for proper
PM5 device identification by apps like Mywhoosh.
https://claude.ai/code/session_01XWBgRPWze8Mb7DEEm4oXiF
* Fix PM5 advertising on Android and optimize UUID handling
- Add startAdvertisingRowerPM5() method in BleAdvertiser.java that
uses the PM5 discovery service UUID (CE060000) instead of FTMS
- Call the correct advertising method based on pm5Mode flag
- Reduce advertised UUIDs to only discovery service (128-bit UUIDs
are large, other services are discovered after connection)
https://claude.ai/code/session_01XWBgRPWze8Mb7DEEm4oXiF
* Remove 128-bit UUID from PM5 advertising to fix visibility
128-bit UUIDs are too large for the BLE advertising packet (31 bytes max).
PM5 will now advertise with device name only. Apps will discover the
PM5 services after establishing a connection.
https://claude.ai/code/session_01XWBgRPWze8Mb7DEEm4oXiF
* Put PM5 UUID in scan response like real PM5 devices
OpenRowingMonitor puts the discovery UUID (CE060000) in the scan
response, not the advertising data. This allows the device name
to fit in the advertising packet while still being discoverable
by PM5-compatible apps.
- Advertising data: device name only
- Scan response: PM5 discovery service UUID (CE060000)
https://claude.ai/code/session_01XWBgRPWze8Mb7DEEm4oXiF
* Add PM5 Stroke Data characteristic with workPerStroke for power
- Add buildPM5StrokeData() function that sends:
- workPerStroke (Joules) at bytes 16-17 - key for power calculation
- strokeCount at bytes 18-19 - for cadence tracking
- driveLength, driveTime, recoveryTime, strokeDistance
- peakDriveForce, averageDriveForce
- Send Stroke Data characteristic (CE060035) in rowerProvider()
- This should enable Mywhoosh to properly read power from the PM5
https://claude.ai/code/session_01XWBgRPWze8Mb7DEEm4oXiF
* Add PM5 Additional Stroke Data characteristic (CE060036)
- Add buildPM5AdditionalStrokeData() function with:
- Stroke Power (bytes 3-4) - direct watts value
- Stroke Calories (bytes 5-6)
- Stroke Count (bytes 7-8)
- Work Per Stroke (bytes 15-16) - Joules
- Send Additional Stroke Data in rowerProvider()
- This characteristic has Stroke Power directly which Mywhoosh may need
https://claude.ai/code/session_01XWBgRPWze8Mb7DEEm4oXiF
* Add PM5 Multiplexed Info characteristic (CE060080) support
Some PM5 clients (like Mywhoosh) may only subscribe to the multiplexed
characteristic instead of individual ones. Now sending all data via
CE060080 with proper ID prefixes:
- 0x31: General Status
- 0x32: Additional Status
- 0x33: Additional Status 2
- 0x35: Stroke Data
- 0x36: Additional Stroke Data
https://claude.ai/code/session_01XWBgRPWze8Mb7DEEm4oXiF
* Add PM5 Concept2 protocol support for iOS Swift virtual rower
- Add PM5 UUIDs and service constants to virtualrower.swift
- Add PM5 services setup (Device Info, Control, Rowing)
- Add PM5 data building functions matching Android implementation:
- General Status (CE060031)
- Additional Status (CE060032)
- Additional Status 2 (CE060033)
- Stroke Data (CE060035)
- Additional Stroke Data (CE060036)
- Multiplexed Info (CE060080)
- Add PM5 mode initialization via constructor parameter
- Update lockscreen.h/mm with virtualrower_ios_pm5() function
- Modify virtualrower.cpp to use PM5 init on iOS when enabled
https://claude.ai/code/session_01XWBgRPWze8Mb7DEEm4oXiF
* fixing ios?
* Update project.pbxproj
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Fix iOS QML scrolling issue when interacting with metrics box
The metrics container drag/resize functionality was causing page scrolling
on iOS within the QML WebView instead of allowing box manipulation.
Changes:
- Add { passive: false } to touchstart event listeners to ensure preventDefault() works on iOS
- Add stopPropagation() to startDrag() and handleMove() to prevent event bubbling
- Add CSS rules to body/html to disable scrolling and overscroll behavior
- Prevent default touch actions on the entire viewport
This ensures that touch events on the metrics box are properly captured
and don't trigger page scrolling on iOS devices.
* Remove overly aggressive CSS that blocked map interaction
The previous fix prevented page scrolling but also disabled
Cesium map interaction (pan, zoom, rotate). The touch-action: none
on metricsContainer combined with passive: false listeners and
stopPropagation() should be sufficient to prevent scrolling only
when interacting with the metrics box.
* Add z-index and chart following functionality for metrics box
Changes:
- Add z-index: 1000 to metricsContainer and 999 to chartContainer to ensure
they appear above the Cesium map and properly capture touch events
- Add touch-action: none to inner .metrics div and chartContainer for better
touch event handling on iOS/Android
- Implement updateChartPosition() to make the elevation chart follow the
metrics box when dragging or resizing
- Chart maintains 10px left offset and bottom alignment with metrics box
- Chart position updates during drag, resize, and on page load
This ensures the metrics box and chart can be interacted with on mobile
devices without interfering with the Cesium map underneath.
* Fix touch event handling to prevent Cesium interference
The previous implementation had critical issues:
1. Global document touchmove listeners were always active, capturing
all touch events including those on the Cesium map
2. Resize handle detection using e.target was unreliable on touch devices
Changes:
- Remove permanently-active global listeners on document
- Add/remove global listeners dynamically only when drag/resize starts/ends
- Implement isInResizeHandle() function using coordinate-based detection
instead of e.target checking (checks if touch is in bottom-right 20x20px)
- Consolidate mousedown/touchstart handlers on container to use the same
coordinate-based logic for determining drag vs resize
This ensures:
- Cesium map remains fully interactive when not touching metrics box
- Resize handle works reliably on touch devices
- No event leakage between UI elements and the map
* Improve touch handling with larger resize handle and better event checks
Changes to fix touch interaction issues:
1. Resize Handle Improvements (50x50px instead of 20x20px):
- Increased size from 20x20 to 50x50 pixels for easier touch targeting
- Added visible resize icon (⤡) with better contrast
- More opaque background for better visibility
2. Event Listener Safety:
- Added isInsideContainer() check to verify touch starts in container
- Added early return in handleMove() if not dragging/resizing
- Always remove listeners in endDragOrResize() to prevent leaks
- Added touchcancel event handling for system interruptions
- Fixed logic to check wasResizing before accessing it
3. Better State Management:
- Always reset isDragging/isResizing before removing listeners
- Only save state if actually was dragging or resizing
- Prevents stale listener references
This should fix:
- Difficulty grabbing resize handle on touch devices
- Box moving when interacting with Cesium map
- Event listeners remaining active when they shouldn't
* Update project.pbxproj
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Add Thinkrider VS200 controller support for gear shifting
Implements support for the Thinkrider VS200 remote controller,
enabling gear up/down functionality similar to Zwift Click.
Uses service UUID 0000fea0 and detects button patterns for
shift up (f3050301fc) and shift down (f3050300fb).
https://claude.ai/code/session_01DK5qQY9wKyHTKfYhAkGECS
* Update allSettingsCount to 857 for thinkrider_controller setting
https://claude.ai/code/session_01DK5qQY9wKyHTKfYhAkGECS
* Update project.pbxproj
* Update project.pbxproj
* Update project.pbxproj
* Add device discovery wait for Thinkrider and create separate settings section
- Add thinkriderDeviceAvaiable() function for discovery wait logic
- Add thinkriderDeviceFound checks in bluetooth constructor and deviceDiscovered
- Create separate "Thinkrider Options" accordion section in settings.qml
- Remove Thinkrider from Zwift Devices Options section
https://claude.ai/code/session_01DK5qQY9wKyHTKfYhAkGECS
* Update project.pbxproj
* Update bluetooth.cpp
* Update project.pbxproj
---------
Co-authored-by: Claude <noreply@anthropic.com>
Corrected type casting for packet data extraction in GetSpeedFromPacket and GetDistanceFromPacket to ensure proper uint16_t conversion. Updated debug logging in characteristicChanged to improve output formatting.
Updated the Bluetooth device discovery logic to use case-insensitive matching for Echelon Rower device names by converting names to uppercase before comparison. This ensures devices with varying name cases are correctly detected.
* Add treadmill_direct_distance setting to read distance directly from treadmill
This adds a new setting that allows users to read the distance directly from
the treadmill instead of calculating it from speed. Some treadmills report
distance more accurately than the speed-based calculation.
The setting is named generically (treadmill_direct_distance) so it can be
used with any treadmill that supports distance reporting via FTMS
characteristics (0x2AD2, 0x2ACD, 0x2ACE).
When enabled, speed-based distance increments are disabled in the update()
function and in all characteristicChanged() handlers.
* Use odometer directly for session distance when treadmill_direct_distance enabled
When the treadmill_direct_distance setting is enabled, the SessionLine
records now use the device's odometer value directly instead of the
speed-based currentDistance1s calculation.
This ensures consistency between the main Distance metric and the session
recording data when using direct distance from the treadmill.
* Update project.pbxproj
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Fix iOS Bluetooth crashes by removing nested event loops
This commit eliminates QEventLoop::exec() calls in Bluetooth write
operations for domyostreadmill and wahookickrsnapbike devices, which
were causing crashes on iOS due to nested event loop incompatibilities.
Changes:
- Replaced synchronous loop.exec() with async queue-based system
- Implemented WriteRequest queue with processWriteQueue() method
- Added timeout management with QTimer for async operations
- Updated characteristicWritten/packetReceived handlers for queue processing
- Removed all #ifdef Q_OS_IOS conditionals in wahookickrsnapbike
- Unified Bluetooth handling code across all platforms using pure Qt
The new architecture:
1. writeCharacteristic() enqueues write requests instead of blocking
2. processWriteQueue() handles requests sequentially
3. Completion signals (characteristicWritten/packetReceived) trigger next item
4. Timeout handling prevents queue stalls without blocking main thread
This eliminates the problematic pattern of calling loop.exec() from
within the main event loop, which was causing watchdog timeouts and
crashes on iOS. The solution is cross-platform compatible and improves
responsiveness on all platforms.
Fixes iOS crash issues related to nested event loops in Bluetooth operations.
* Update project.pbxproj
* fixing crash
* Update project.pbxproj
* removed unused code
* removed ios_wahookickrsnapbike reference
---------
Co-authored-by: Claude <noreply@anthropic.com>