mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
7 Commits
treadmill-
...
fixing_tra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04d37e0a68 | ||
|
|
b5890ea818 | ||
|
|
83627f5397 | ||
|
|
2b8af5d777 | ||
|
|
3f6b284468 | ||
|
|
1be9e2620d | ||
|
|
805981df4d |
246
.github/workflows/main.yml
vendored
246
.github/workflows/main.yml
vendored
@@ -89,7 +89,7 @@ jobs:
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
install: mingw-w64-x86_64-toolchain mingw-w64-x86_64-qt5-webview mingw-w64-x86_64-protobuf mingw-w64-x86_64-abseil-cpp
|
||||
install: mingw-w64-x86_64-toolchain mingw-w64-x86_64-qt5-webview
|
||||
msystem: mingw64
|
||||
release: false
|
||||
|
||||
@@ -128,7 +128,7 @@ jobs:
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
@@ -137,10 +137,6 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
#cp "C:/mingw64/bin/libabsl*.*" .
|
||||
#cp "C:/mingw64/lib/libabsl*.*" .
|
||||
#cp "C:/mingw64/bin/libproto*.*" .
|
||||
#cp "C:/mingw64/lib/libproto*.*" .
|
||||
qmake
|
||||
make -j8
|
||||
cd src/debug
|
||||
@@ -152,11 +148,6 @@ jobs:
|
||||
cp "C:/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/mingw64/bin/libstdc++-6.dll" .
|
||||
cp "C:/mingw64/bin/zlib1.dll" .
|
||||
cp "C:/mingw64/bin/libabsl*.*" .
|
||||
cp "C:/mingw64/lib/libabsl*.*" .
|
||||
cp "C:/mingw64/bin/libproto*.*" .
|
||||
cp "C:/mingw64/lib/libproto*.*" .
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../windows/*.py .
|
||||
@@ -173,10 +164,6 @@ jobs:
|
||||
|
||||
- name: Build without python
|
||||
run: |
|
||||
#cp "C:/mingw64/bin/libabsl*.*" .
|
||||
#cp "C:/mingw64/lib/libabsl*.*" .
|
||||
#cp "C:/mingw64/bin/libproto*.*" .
|
||||
#cp "C:/mingw64/lib/libproto*.*" .
|
||||
qmake
|
||||
make -j8
|
||||
cd src/debug
|
||||
@@ -188,11 +175,6 @@ jobs:
|
||||
cp "C:/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/mingw64/bin/libstdc++-6.dll" .
|
||||
cp "C:/mingw64/bin/zlib1.dll" .
|
||||
cp "C:/mingw64/bin/libabsl*.*" .
|
||||
cp "C:/mingw64/lib/libabsl*.*" .
|
||||
cp "C:/mingw64/bin/libproto*.*" .
|
||||
cp "C:/mingw64/lib/libproto*.*" .
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
@@ -323,7 +305,7 @@ jobs:
|
||||
# qmake
|
||||
# cd src
|
||||
# echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
# echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
|
||||
# echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" > secret.h
|
||||
# echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
# echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
# echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
@@ -427,14 +409,14 @@ jobs:
|
||||
path: "src/qthttpserver"
|
||||
|
||||
- name: Install packages required to run QZ inside workflow
|
||||
run: sudo apt update -y && sudo apt-get install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qtquickcontrols2-5-dev libqt5bluetooth5 libqt5widgets5 libqt5positioning5 libqt5xml5 qtconnectivity5-dev qtpositioning5-dev libqt5charts5-dev libqt5charts5 libqt5networkauth5-dev libqt5serialbus* libqt5websockets5* libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev cmake protobuf-compiler libprotobuf-dev
|
||||
run: sudo apt update -y && sudo apt-get install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qtquickcontrols2-5-dev libqt5bluetooth5 libqt5widgets5 libqt5positioning5 libqt5xml5 qtconnectivity5-dev qtpositioning5-dev libqt5charts5-dev libqt5charts5 libqt5networkauth5-dev libqt5websockets5* libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '5.15.2'
|
||||
host: 'linux'
|
||||
modules: 'qtnetworkauth qtcharts qtserial'
|
||||
modules: 'qtnetworkauth qtcharts'
|
||||
cache: 'true'
|
||||
cache-key-prefix: 'install-qt-action-linux'
|
||||
|
||||
@@ -626,7 +608,7 @@ jobs:
|
||||
export ANDROID_NDK_ROOT="${ANDROID_NDK}"
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
@@ -730,7 +712,7 @@ jobs:
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
@@ -841,7 +823,7 @@ jobs:
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
@@ -1029,7 +1011,7 @@ jobs:
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
@@ -1124,7 +1106,7 @@ jobs:
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
@@ -1172,7 +1154,7 @@ jobs:
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
image: tonistiigi/binfmt:master
|
||||
image: tonistiigi/binfmt:qemu-v7.0.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
@@ -1183,7 +1165,7 @@ jobs:
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
@@ -1212,204 +1194,15 @@ jobs:
|
||||
|
||||
- name: Rename binary
|
||||
run: mv src/qdomyos-zwift src/qdomyos-zwift-64bit
|
||||
|
||||
window-msvc2022-build:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {python: true}
|
||||
- {python: false}
|
||||
|
||||
steps:
|
||||
- name: Checkout PR code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: refs/pull/1508/head
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.7
|
||||
- name: download python and paddleocr
|
||||
run: |
|
||||
python -VV
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade setuptools
|
||||
python -m pip install "protobuf<=3.20.2,>=3.1.0"
|
||||
python -m pip install paddlepaddle==2.5.1
|
||||
python -m pip install paddleocr
|
||||
python -m pip install imutils
|
||||
python -m pip install "Pillow<10.0.0"
|
||||
python -m pip install opencv-python
|
||||
python -m pip install numpy
|
||||
python -m pip install pywin32
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '6.8.2'
|
||||
host: 'windows'
|
||||
modules: 'qtnetworkauth qtcharts qtconnectivity qtspeech qtpositioning qtwebsockets qtlocation qtmultimedia'
|
||||
target: "desktop"
|
||||
arch: win64_msvc2022_64
|
||||
dir: "${{github.workspace}}/qt/"
|
||||
install-deps: "true"
|
||||
cache: 'true'
|
||||
cache-key-prefix: 'install-qt-action-windows'
|
||||
|
||||
- name: Install MSVC compiler
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
# 14.1 is for vs2017, 14.2 is vs2019, following the upstream vcpkg build from Qv2ray-deps repo
|
||||
#toolset: 14.2
|
||||
arch: x64
|
||||
|
||||
# - name: download 3rd party files for qthttpserver
|
||||
# run: |
|
||||
# cp qHttpServerBin/5.15.2/headers/* src/qthttpserver/src/3rdparty/http-parser/
|
||||
|
||||
# - name: Build qthttpserver
|
||||
# run: |
|
||||
# cd src\qthttpserver
|
||||
# qmake
|
||||
# nmake
|
||||
# nmake install
|
||||
# cd ../..
|
||||
|
||||
- name: Secrets
|
||||
if: github.ref == 'refs/heads/master'
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
cd ..
|
||||
|
||||
- name: Clone vcpkg
|
||||
run: git clone https://github.com/microsoft/vcpkg.git
|
||||
working-directory: ${{ runner.workspace }}
|
||||
|
||||
- name: Bootstrap vcpkg
|
||||
run: .\vcpkg\bootstrap-vcpkg.bat
|
||||
working-directory: ${{ runner.workspace }}
|
||||
|
||||
- name: Create vcpkg.json
|
||||
working-directory: ${{ runner.workspace }}
|
||||
run: |
|
||||
echo '{
|
||||
"name": "qdomyos-zwift",
|
||||
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
|
||||
"dependencies": [
|
||||
"protobuf",
|
||||
"protobuf-c",
|
||||
"abseil"
|
||||
],
|
||||
"builtin-baseline": "8c2fcacefba009d63672f9d137f192765e632c9f"
|
||||
}' > vcpkg.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\vcpkg\vcpkg install --triplet x64-windows --x-install-root=D:\a\qdomyos-zwift\vcpkg\installed
|
||||
working-directory: ${{ runner.workspace }}
|
||||
|
||||
- name: Build
|
||||
Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\lib\*.* -Destination . -Verbose
|
||||
Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\lib\*.* -Destination src/ -Verbose
|
||||
Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\include\* -Destination src/ -Recurse -Verbose
|
||||
run: |
|
||||
qmake
|
||||
nmake
|
||||
cd src/debug
|
||||
mkdir output
|
||||
mkdir appx
|
||||
cp qdomyos-zwift.* output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../windows/*.py .
|
||||
cp ../../windows/*.bat .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\bin\*.* -Destination . -Verbose
|
||||
mkdir adb
|
||||
mkdir python
|
||||
Copy-Item -Path C:\hostedtoolcache\windows\Python\3.7.9\x64 -Destination python -Recurse
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
cd appx
|
||||
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
|
||||
if: matrix.config.python
|
||||
|
||||
|
||||
- name: Build without python
|
||||
# Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\lib\*.* -Destination . -Verbose
|
||||
# Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\lib\*.* -Destination src/ -Verbose
|
||||
# Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\include\* -Destination src/ -Recurse -Verbose
|
||||
run: |
|
||||
qmake
|
||||
nmake
|
||||
cd src/debug
|
||||
mkdir output
|
||||
mkdir appx
|
||||
cp qdomyos-zwift.* output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp "C:/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/mingw64/bin/libstdc++-6.dll" .
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\bin\*.* -Destination . -Verbose
|
||||
mkdir adb
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
cd appx
|
||||
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
|
||||
if: matrix.config.python == false
|
||||
|
||||
- name: patching qt for bluetooth
|
||||
run: cp qt-patches/windows/5.15.2/binary/msvc2019/*.* ${{ github.workspace }}/src/debug/output/
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-msvc2022-binary.zip
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-msvc2022-binary-no-python.zip
|
||||
if: ${{ ! matrix.config.python }}
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-msvc2022-binary
|
||||
path: windows-msvc2022-binary.zip
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-msvc2022-binary-no-python
|
||||
path: windows-msvc2022-binary-no-python.zip
|
||||
if: ${{ ! matrix.config.python }}
|
||||
|
||||
upload_to_release:
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name == 'schedule'
|
||||
needs: [linux-x86-build, window-msvc2019-build, window-msvc2022-build, ios-build, window-build, android-build, raspberry-pi-build]
|
||||
needs: [linux-x86-build, window-msvc2019-build, ios-build, window-build, android-build, raspberry-pi-build] # Specify the job dependencies
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Update nightly release
|
||||
uses: andelf/nightly-release@main
|
||||
env:
|
||||
@@ -1427,23 +1220,14 @@ jobs:
|
||||
of new complex code, the stability of the program may suffer compared to
|
||||
official releases, so **use it with caution**!
|
||||
|
||||
## Windows Builds:
|
||||
- **windows-msvc2019**: Recommended for Windows 10
|
||||
- **windows-msvc2022**: Recommended for Windows 11 (experimental, QT6)
|
||||
- **windows**: MinGW build (alternative version)
|
||||
|
||||
## Other Platforms:
|
||||
- **fdroid-android-trial**: Android build
|
||||
- **raspberry-pi-binary**: Raspberry Pi build
|
||||
|
||||
__Please help us improve QZ by reporting any issues you encounter!__ :wink:
|
||||
files: |
|
||||
windows-msvc2019-binary-no-python/*
|
||||
windows-msvc2019-binary/*
|
||||
windows-msvc2022-binary-no-python/*
|
||||
windows-msvc2022-binary/*
|
||||
windows-msvc2019-ai-server-binary/*
|
||||
windows-binary-no-python/*
|
||||
windows-binary/*
|
||||
fdroid-android-trial/*
|
||||
raspberry-pi-binary/qdomyos-zwift-32bit
|
||||
#raspberry-pi-64bit-binary/qdomyos-zwift-64bit
|
||||
#2024-10-22-raspios-bookworm-arm64-lite.img.xz
|
||||
|
||||
@@ -4255,7 +4255,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1037;
|
||||
CURRENT_PROJECT_VERSION = 1035;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1";
|
||||
@@ -4449,7 +4449,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1037;
|
||||
CURRENT_PROJECT_VERSION = 1035;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -4679,7 +4679,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1037;
|
||||
CURRENT_PROJECT_VERSION = 1035;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -4775,7 +4775,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1037;
|
||||
CURRENT_PROJECT_VERSION = 1035;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = YES;
|
||||
@@ -4867,7 +4867,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1037;
|
||||
CURRENT_PROJECT_VERSION = 1035;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
|
||||
ENABLE_BITCODE = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -4983,7 +4983,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1037;
|
||||
CURRENT_PROJECT_VERSION = 1035;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
|
||||
ENABLE_BITCODE = YES;
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
//#if defined(Q_OS_LINUX)
|
||||
#if 1
|
||||
#include "ConsoleReader.h"
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static struct termios oldSettings;
|
||||
static struct termios newSettings;
|
||||
|
||||
/* Initialize new terminal i/o settings */
|
||||
void initTermios(int echo) {
|
||||
tcgetattr(0, &oldSettings); /* grab old terminal i/o settings */
|
||||
newSettings = oldSettings; /* make new settings same as old settings */
|
||||
newSettings.c_lflag &= ~ICANON; /* disable buffered i/o */
|
||||
newSettings.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
|
||||
tcsetattr(0, TCSANOW, &newSettings); /* use these new terminal i/o settings now */
|
||||
}
|
||||
|
||||
/* Restore old terminal i/o settings */
|
||||
void resetTermios(void) { tcsetattr(0, TCSANOW, &oldSettings); }
|
||||
|
||||
/* Read 1 character without echo */
|
||||
char getch(void) { return getchar(); }
|
||||
|
||||
ConsoleReader::ConsoleReader(bluetooth *bt) {
|
||||
bluetoothManager = bt;
|
||||
initTermios(0);
|
||||
}
|
||||
|
||||
ConsoleReader::~ConsoleReader() { resetTermios(); }
|
||||
|
||||
void ConsoleReader::run() {
|
||||
forever {
|
||||
char key = getch();
|
||||
qDebug() << "key pressed" << key;
|
||||
if (key == 'q') {
|
||||
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
double speed = ((treadmill *)bluetoothManager->device())->currentSpeed().value();
|
||||
((treadmill *)bluetoothManager->device())->changeSpeed(speed + 0.5);
|
||||
}
|
||||
} else if (key == 'w') {
|
||||
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
double speed = ((treadmill *)bluetoothManager->device())->currentSpeed().value();
|
||||
((treadmill *)bluetoothManager->device())->changeSpeed(speed - 0.5);
|
||||
}
|
||||
} else if (key == 'a') {
|
||||
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
double inclination = ((treadmill *)bluetoothManager->device())->currentInclination().value();
|
||||
((treadmill *)bluetoothManager->device())->changeInclination(inclination + 0.5, inclination + 0.5);
|
||||
}
|
||||
} else if (key == 's') {
|
||||
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
double inclination = ((treadmill *)bluetoothManager->device())->currentInclination().value();
|
||||
((treadmill *)bluetoothManager->device())->changeInclination(inclination - 0.5, inclination - 0.5);
|
||||
}
|
||||
} else if (key == '1') {
|
||||
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
((treadmill *)bluetoothManager->device())->changeSpeed(5);
|
||||
}
|
||||
} else if (key == '2') {
|
||||
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
double inclination = ((treadmill *)bluetoothManager->device())->currentInclination().value();
|
||||
((treadmill *)bluetoothManager->device())->changeInclination(inclination + 0.5, inclination + 0.5);
|
||||
}
|
||||
} else if (key == '3') {
|
||||
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
((treadmill *)bluetoothManager->device())->changeSpeed(10);
|
||||
}
|
||||
} else if (key == '4') {
|
||||
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
double speed = ((treadmill *)bluetoothManager->device())->currentSpeed().value();
|
||||
((treadmill *)bluetoothManager->device())->changeSpeed(speed - 0.5);
|
||||
}
|
||||
} else if (key == '5') {
|
||||
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
double inclination = ((treadmill *)bluetoothManager->device())->currentInclination().value();
|
||||
((treadmill *)bluetoothManager->device())->changeInclination(inclination - 0.5, inclination - 0.5);
|
||||
}
|
||||
} else if (key == '6') {
|
||||
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
double speed = ((treadmill *)bluetoothManager->device())->currentSpeed().value();
|
||||
((treadmill *)bluetoothManager->device())->changeSpeed(speed + 0.5);
|
||||
}
|
||||
}
|
||||
emit KeyPressed(key);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef CONSOLEREADER_H
|
||||
#define CONSOLEREADER_H
|
||||
|
||||
#include "bluetooth.h"
|
||||
#include <QThread>
|
||||
|
||||
class ConsoleReader : public QThread {
|
||||
Q_OBJECT
|
||||
signals:
|
||||
void KeyPressed(char ch);
|
||||
|
||||
public:
|
||||
ConsoleReader(bluetooth *bt);
|
||||
~ConsoleReader();
|
||||
void run();
|
||||
|
||||
private:
|
||||
bluetooth *bluetoothManager;
|
||||
};
|
||||
|
||||
#endif /* CONSOLEREADER_H */
|
||||
@@ -23,13 +23,6 @@ HomeForm {
|
||||
signal plus_clicked(string name)
|
||||
signal minus_clicked(string name)
|
||||
signal largeButton_clicked(string name)
|
||||
signal keyPressed(int key)
|
||||
|
||||
Keys.onPressed: (event)=> {
|
||||
console.log("Keys.onPressed " + event.key)
|
||||
// Emit a signal with the pressed key
|
||||
keyPressed(event.key)
|
||||
}
|
||||
|
||||
Settings {
|
||||
id: settings
|
||||
|
||||
@@ -9,15 +9,11 @@ import QtQuick.Layouts 1.3
|
||||
import QtWebView 1.1
|
||||
|
||||
Item {
|
||||
id: pelotonAuthPage
|
||||
anchors.fill: parent
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
visible: true
|
||||
|
||||
// Signal to notify the parent stack when we want to go back
|
||||
signal goBack()
|
||||
|
||||
WebView {
|
||||
anchors.fill: parent
|
||||
height: parent.height
|
||||
@@ -31,11 +27,7 @@ Item {
|
||||
parent: Overlay.overlay
|
||||
enabled: rootItem.pelotonPopupVisible
|
||||
onEnabledChanged: { if(rootItem.pelotonPopupVisible) popupPelotonConnectedWeb.open() }
|
||||
onClosed: {
|
||||
rootItem.pelotonPopupVisible = false;
|
||||
// Attempt to go back to the previous view after the popup is closed
|
||||
goBack();
|
||||
}
|
||||
onClosed: { rootItem.pelotonPopupVisible = false; }
|
||||
|
||||
x: Math.round((parent.width - width) / 2)
|
||||
y: Math.round((parent.height - height) / 2)
|
||||
@@ -53,7 +45,6 @@ Item {
|
||||
{
|
||||
NumberAnimation { property: "opacity"; from: 1.0; to: 0.0 }
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
Label {
|
||||
@@ -63,18 +54,5 @@ Item {
|
||||
text: qsTr("Your Peloton account is now connected!<br><br>Restart the app to apply this!")
|
||||
}
|
||||
}
|
||||
|
||||
// Add a MouseArea to capture clicks anywhere on the popup
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
popupPelotonConnectedWeb.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Component is being completed
|
||||
Component.onCompleted: {
|
||||
console.log("WebPelotonAuth loaded")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import Qt.labs.settings 1.0
|
||||
|
||||
Page {
|
||||
id: wizardPage
|
||||
objectName: "wizardPage"
|
||||
|
||||
property int currentStep: 0
|
||||
property var selectedOptions: ({})
|
||||
@@ -336,7 +335,7 @@ Page {
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("Connect to Peloton")
|
||||
text: qsTr("Peloton Login")
|
||||
font.pixelSize: 24
|
||||
font.bold: true
|
||||
color: "white"
|
||||
@@ -344,38 +343,56 @@ Page {
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("Click the button below to connect your Peloton account")
|
||||
text: qsTr("Username")
|
||||
font.pixelSize: 20
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
width: stackViewLocal.width * 0.8
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.bold: true
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Image {
|
||||
TextField {
|
||||
id: pelotonUsernameTextField
|
||||
text: settings.peloton_username
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
source: "icons/icons/Button_Connect_Rect_DarkMode.png"
|
||||
fillMode: Image.PreserveAspectFit
|
||||
width: parent.width * 0.8
|
||||
Layout.fillHeight: false
|
||||
onAccepted: settings.peloton_username = text
|
||||
onActiveFocusChanged: if(this.focus) this.cursorPosition = this.text.length
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
stackViewLocal.push("WebPelotonAuth.qml")
|
||||
stackViewLocal.currentItem.goBack.connect(function() {
|
||||
stackViewLocal.pop();
|
||||
stackViewLocal.push(pelotonDifficultyComponent)
|
||||
})
|
||||
peloton_connect_clicked()
|
||||
}
|
||||
}
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("Password")
|
||||
font.pixelSize: 20
|
||||
font.bold: true
|
||||
color: "white"
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: pelotonPasswordTextField
|
||||
text: settings.peloton_password
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.fillHeight: false
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
inputMethodHints: Qt.ImhHiddenText
|
||||
echoMode: TextInput.PasswordEchoOnEdit
|
||||
onAccepted: settings.peloton_password = text
|
||||
onActiveFocusChanged: if(this.focus) this.cursorPosition = this.text.length
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: 50
|
||||
}
|
||||
|
||||
WizardButton {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("Next")
|
||||
onClicked: {
|
||||
settings.peloton_username = pelotonUsernameTextField.text;
|
||||
settings.peloton_password = pelotonPasswordTextField.text;
|
||||
stackViewLocal.push(pelotonDifficultyComponent)
|
||||
}
|
||||
}
|
||||
|
||||
WizardButton {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("Back")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<manifest package="org.cagnulen.qdomyoszwift" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionName="2.18.22" android:versionCode="1045" android:installLocation="auto">
|
||||
<manifest package="org.cagnulen.qdomyoszwift" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionName="2.18.20" android:versionCode="1020" android:installLocation="auto">
|
||||
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default permissions. -->
|
||||
<!-- %%INSERT_PERMISSIONS -->
|
||||
|
||||
@@ -112,7 +112,6 @@ void bluetooth::finished() {
|
||||
QString nordictrack_2950_ip =
|
||||
settings.value(QZSettings::nordictrack_2950_ip, QZSettings::default_nordictrack_2950_ip).toString();
|
||||
QString tdf_10_ip = settings.value(QZSettings::tdf_10_ip, QZSettings::default_tdf_10_ip).toString();
|
||||
bool gpio_treadmill = settings.value(QStringLiteral("gpio_treadmill"), false).toBool();
|
||||
QString proform_elliptical_ip = settings.value(QZSettings::proform_elliptical_ip, QZSettings::default_proform_elliptical_ip).toString();
|
||||
bool fake_bike =
|
||||
settings.value(QZSettings::applewatch_fakedevice, QZSettings::default_applewatch_fakedevice).toBool();
|
||||
@@ -122,7 +121,7 @@ void bluetooth::finished() {
|
||||
bool fakedevice_treadmill =
|
||||
settings.value(QZSettings::fakedevice_treadmill, QZSettings::default_fakedevice_treadmill).toBool();
|
||||
// wifi devices on windows
|
||||
if (!nordictrack_2950_ip.isEmpty() || !tdf_10_ip.isEmpty() || fake_bike || fakedevice_elliptical || fakedevice_rower || fakedevice_treadmill || !proform_elliptical_ip.isEmpty() || antbike || gpio_treadmill) {
|
||||
if (!nordictrack_2950_ip.isEmpty() || !tdf_10_ip.isEmpty() || fake_bike || fakedevice_elliptical || fakedevice_rower || fakedevice_treadmill || !proform_elliptical_ip.isEmpty() || antbike) {
|
||||
// faking a bluetooth device
|
||||
qDebug() << "faking a bluetooth device for nordictrack_2950_ip";
|
||||
deviceDiscovered(QBluetoothDeviceInfo());
|
||||
@@ -449,7 +448,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
powerSensorName.startsWith(QStringLiteral("Disabled")) || power_as_bike || power_as_treadmill;
|
||||
bool eliteRizerFound = eliteRizerName.startsWith(QStringLiteral("Disabled"));
|
||||
bool eliteSterzoSmartFound = eliteSterzoSmartName.startsWith(QStringLiteral("Disabled"));
|
||||
bool gpio_treadmill = settings.value(QStringLiteral("gpio_treadmill"), false).toBool();
|
||||
bool fake_bike =
|
||||
settings.value(QZSettings::applewatch_fakedevice, QZSettings::default_applewatch_fakedevice).toBool();
|
||||
bool fakedevice_elliptical =
|
||||
@@ -684,23 +682,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(fakeBike);
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
} else if (gpio_treadmill && !gpioTreadmill) {
|
||||
discoveryAgent->stop();
|
||||
gpioTreadmill = new gpiotreadmill(pollDeviceTime, noConsole, noHeartService, 0.8, 0);
|
||||
emit deviceConnected(b);
|
||||
connect(gpioTreadmill, &bluetoothdevice::connectedAndDiscovered, this,
|
||||
&bluetooth::connectedAndDiscovered);
|
||||
connect(gpioTreadmill, &gpiotreadmill::debug, this, &bluetooth::debug);
|
||||
connect(gpioTreadmill, &gpiotreadmill::inclinationChanged, this, &bluetooth::inclinationChanged);
|
||||
// connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart()));
|
||||
// connect(this, SIGNAL(searchingStop()), gpioTreadmill, SLOT(searchingStop())); //NOTE: Commented due
|
||||
// to #358
|
||||
if (!discoveryAgent->isActive()) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(gpioTreadmill);
|
||||
#endif
|
||||
} else if (fakedevice_elliptical && !fakeElliptical) {
|
||||
this->stopDiscovery();
|
||||
fakeElliptical = new fakeelliptical(noWriteResistance, noHeartService, false);
|
||||
@@ -1422,7 +1403,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
b.name().toUpper().startsWith(QStringLiteral("WLT-EP-")) || // Flow elliptical
|
||||
(b.name().toUpper().startsWith("SCHWINN 810")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-MC")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("ANPIUS-")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("KS-HD-Z1D"))) || // Kingsmith WalkingPad Z1
|
||||
(b.name().toUpper().startsWith(QStringLiteral("NOBLEPRO CONNECT")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // FTMS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("TT8")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) ||
|
||||
@@ -1653,7 +1633,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
(b.name().toUpper().startsWith("NEO BIKE SMART")) ||
|
||||
(b.name().toUpper().startsWith("ZDRIVE")) ||
|
||||
(b.name().toUpper().startsWith("TUNTURI E60-")) ||
|
||||
(b.name().toUpper().startsWith("TUNTURI F40-")) ||
|
||||
(b.name().toUpper().startsWith("JFBK5.0")) ||
|
||||
(b.name().toUpper().startsWith("NEO 3M ")) ||
|
||||
(b.name().toUpper().startsWith("JFBK7.0")) ||
|
||||
@@ -1669,8 +1648,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
(b.name().toUpper().startsWith("LYDSTO")) ||
|
||||
(b.name().toUpper().startsWith("CYCLO_")) ||
|
||||
(b.name().toUpper().startsWith("LCR")) ||
|
||||
(b.name().toUpper().startsWith("XCX-")) ||
|
||||
(b.name().toUpper().startsWith("L-") && b.name().length() == 11) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("FIT-BK-"))) ||
|
||||
(b.name().toUpper().startsWith("VFSPINBIKE")) ||
|
||||
(b.name().toUpper().startsWith("GLT") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) ||
|
||||
@@ -1813,7 +1790,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
b.name().toUpper().startsWith(QStringLiteral("I-ROWER")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("YOROTO-RW-")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("SF-RW")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("ROGUE CONSOLE ")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("DFIT-L-R")) ||
|
||||
!b.name().compare(ftms_rower, Qt::CaseInsensitive) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("PM5")) &&
|
||||
@@ -3243,13 +3219,6 @@ void bluetooth::restart() {
|
||||
delete fakeBike;
|
||||
fakeBike = nullptr;
|
||||
}
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
if (gpioTreadmill) {
|
||||
|
||||
delete gpioTreadmill;
|
||||
gpioTreadmill = nullptr;
|
||||
}
|
||||
#endif
|
||||
if (fakeElliptical) {
|
||||
|
||||
delete fakeElliptical;
|
||||
@@ -3712,10 +3681,6 @@ bluetoothdevice *bluetooth::device() {
|
||||
return powerTreadmill;
|
||||
} else if (fakeBike) {
|
||||
return fakeBike;
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
} else if (gpioTreadmill) {
|
||||
return gpioTreadmill;
|
||||
#endif
|
||||
} else if (fakeElliptical) {
|
||||
return fakeElliptical;
|
||||
} else if (fakeRower) {
|
||||
|
||||
@@ -101,9 +101,6 @@
|
||||
#include "devices/proformwifitreadmill/proformwifitreadmill.h"
|
||||
#include "devices/schwinn170bike/schwinn170bike.h"
|
||||
#include "devices/schwinnic4bike/schwinnic4bike.h"
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
#include "gpiotreadmill.h"
|
||||
#endif
|
||||
#include "signalhandler.h"
|
||||
#include "devices/skandikawiribike/skandikawiribike.h"
|
||||
#include "devices/smartrowrower/smartrowrower.h"
|
||||
@@ -210,9 +207,6 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
trxappgateusbelliptical *trxappgateusbElliptical = nullptr;
|
||||
echelonconnectsport *echelonConnectSport = nullptr;
|
||||
yesoulbike *yesoulBike = nullptr;
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
gpiotreadmill *gpioTreadmill = nullptr;
|
||||
#endif
|
||||
flywheelbike *flywheelBike = nullptr;
|
||||
nordictrackelliptical *nordictrackElliptical = nullptr;
|
||||
nordictrackifitadbtreadmill *nordictrackifitadbTreadmill = nullptr;
|
||||
|
||||
@@ -475,9 +475,9 @@ void bluetoothdevice::setGPXFile(QString filename) {
|
||||
}
|
||||
}
|
||||
|
||||
void bluetoothdevice::setHeartZone(double hz) {
|
||||
void bluetoothdevice::setHeartZone(double hz) {
|
||||
HeartZone = hz;
|
||||
if(isPaused() == false && currentHeart().value() > 0) {
|
||||
if(isPaused() == false) {
|
||||
hz = hz - 1;
|
||||
if(hz >= maxHeartZone() ) {
|
||||
hrZonesSeconds[maxHeartZone() - 1].setValue(hrZonesSeconds[maxHeartZone() - 1].value() + 1);
|
||||
|
||||
@@ -129,17 +129,14 @@ void ftmsbike::init() {
|
||||
if (initDone)
|
||||
return;
|
||||
|
||||
if(ICSE) {
|
||||
uint8_t write[] = {FTMS_REQUEST_CONTROL};
|
||||
bool ret = writeCharacteristic(write, sizeof(write), "requestControl", false, true);
|
||||
write[0] = {FTMS_RESET};
|
||||
ret = writeCharacteristic(write, sizeof(write), "reset", false, true);
|
||||
}
|
||||
|
||||
uint8_t write[] = {FTMS_REQUEST_CONTROL};
|
||||
bool ret = writeCharacteristic(write, sizeof(write), "requestControl", false, true);
|
||||
write[0] = {FTMS_START_RESUME};
|
||||
ret = writeCharacteristic(write, sizeof(write), "start simulation", false, true);
|
||||
if(resistance_lvl_mode && DIRETO_XR) {
|
||||
setWheelDiameter(2070.0);
|
||||
} else {
|
||||
write[0] = {FTMS_START_RESUME};
|
||||
ret = writeCharacteristic(write, sizeof(write), "start simulation", false, true);
|
||||
}
|
||||
|
||||
if(ret) {
|
||||
initDone = true;
|
||||
@@ -148,6 +145,10 @@ void ftmsbike::init() {
|
||||
}
|
||||
|
||||
ftmsbike::~ftmsbike() {
|
||||
// Set wheel circumference back to 2070 when object is destroyed
|
||||
if (DIRETO_XR) {
|
||||
setWheelDiameter(2070.0);
|
||||
}
|
||||
}
|
||||
|
||||
void ftmsbike::zwiftPlayInit() {
|
||||
@@ -275,8 +276,6 @@ void ftmsbike::update() {
|
||||
|
||||
if (initRequest) {
|
||||
zwiftPlayInit();
|
||||
if(ICSE)
|
||||
requestResistance = 1; // to force the engine to send every second a target inclination
|
||||
initRequest = false;
|
||||
} else if (bluetoothDevice.isValid() &&
|
||||
m_control->state() == QLowEnergyController::DiscoveredState //&&
|
||||
@@ -320,16 +319,24 @@ void ftmsbike::update() {
|
||||
(requestPower == 0 || requestPower == -1)) {
|
||||
init();
|
||||
|
||||
forceResistance(requestResistance + (gears() * 5));
|
||||
if(DIRETO_XR && gears_zwift_ratio)
|
||||
setWheelDiameter(wheelCircumference::gearsToWheelDiameter(gears()));
|
||||
else {
|
||||
forceResistance(requestResistance + (gears() * 5));
|
||||
if(DIRETO_XR)
|
||||
Resistance = requestResistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!ICSE)
|
||||
requestResistance = -1;
|
||||
requestResistance = -1;
|
||||
}
|
||||
|
||||
if((virtualBike && virtualBike->ftmsDeviceConnected()) && lastGearValue != gears() && lastRawRequestedInclinationValue != -100 && lastPacketFromFTMS.length() >= 7) {
|
||||
qDebug() << "injecting fake ftms frame in order to send the new gear value ASAP" << lastPacketFromFTMS.toHex(' ');
|
||||
ftmsCharacteristicChanged(QLowEnergyCharacteristic(), lastPacketFromFTMS);
|
||||
if(DIRETO_XR && gears_zwift_ratio) {
|
||||
setWheelDiameter(wheelCircumference::gearsToWheelDiameter(gears()));
|
||||
} else {
|
||||
qDebug() << "injecting fake ftms frame in order to send the new gear value ASAP" << lastPacketFromFTMS.toHex(' ');
|
||||
ftmsCharacteristicChanged(QLowEnergyCharacteristic(), lastPacketFromFTMS);
|
||||
}
|
||||
}
|
||||
|
||||
if(zwiftPlayService && gears_zwift_ratio && lastGearValue != gears()) {
|
||||
@@ -948,18 +955,7 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
|
||||
qDebug() << s->serviceUuid() << QStringLiteral("connected!");
|
||||
|
||||
if (ICSE) {
|
||||
QBluetoothUuid ftmsService((quint16)0x1826);
|
||||
QBluetoothUuid CSCService((quint16)0x1816);
|
||||
if (s->serviceUuid() != ftmsService && s->serviceUuid() != CSCService) {
|
||||
qDebug() << QStringLiteral("ICSE bike wants to be subscribed only to FTMS and CSC services in order "
|
||||
"to send metrics")
|
||||
<< s->serviceUuid();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::hammer_racer_s, QZSettings::default_hammer_racer_s).toBool() || SCH_190U || DOMYOS || SMB1) {
|
||||
if (settings.value(QZSettings::hammer_racer_s, QZSettings::default_hammer_racer_s).toBool() || ICSE || SCH_190U || DOMYOS || SMB1) {
|
||||
QBluetoothUuid ftmsService((quint16)0x1826);
|
||||
if (s->serviceUuid() != ftmsService) {
|
||||
qDebug() << QStringLiteral("hammer racer bike wants to be subscribed only to FTMS service in order "
|
||||
@@ -1019,7 +1015,7 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
}
|
||||
|
||||
QBluetoothUuid _zwiftPlayWriteCharControlPointId(QStringLiteral("00000003-19ca-4651-86e5-fa29dcdd09d1"));
|
||||
if (c.uuid() == _zwiftPlayWriteCharControlPointId) {
|
||||
if (c.uuid() == _zwiftPlayWriteCharControlPointId && !DIRETO_XR) {
|
||||
qDebug() << QStringLiteral("Zwift Play service and Control Point found");
|
||||
zwiftPlayWriteChar = c;
|
||||
zwiftPlayService = s;
|
||||
@@ -1162,9 +1158,7 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
} else if(b.at(0) == FTMS_SET_TARGET_POWER && zwiftPlayService != nullptr && gears_zwift_ratio) {
|
||||
qDebug() << "discarding";
|
||||
return;
|
||||
}
|
||||
// gears on erg mode is quite useless and it's confusing
|
||||
/* else if(b.at(0) == FTMS_SET_TARGET_POWER && b.length() > 2) {
|
||||
} else if(b.at(0) == FTMS_SET_TARGET_POWER && b.length() > 2) {
|
||||
lastPacketFromFTMS.clear();
|
||||
for(int i=0; i<b.length(); i++)
|
||||
lastPacketFromFTMS.append(b.at(i));
|
||||
@@ -1176,7 +1170,7 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
b[1] = power & 0xFF;
|
||||
b[2] = power >> 8;
|
||||
qDebug() << "applying gears mod" << gears() << gearsZwiftRatio() << power;
|
||||
}*/
|
||||
}
|
||||
|
||||
writeCharacteristic((uint8_t*)b.data(), b.length(), "injectWrite ", false, true);
|
||||
}
|
||||
@@ -1385,7 +1379,7 @@ double ftmsbike::maxGears() {
|
||||
QSettings settings;
|
||||
bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool();
|
||||
|
||||
if((zwiftPlayService != nullptr) && gears_zwift_ratio) {
|
||||
if((zwiftPlayService != nullptr || DIRETO_XR) && gears_zwift_ratio) {
|
||||
wheelCircumference::GearTable g;
|
||||
return g.maxGears;
|
||||
} else if(WATTBIKE) {
|
||||
@@ -1399,7 +1393,7 @@ double ftmsbike::minGears() {
|
||||
QSettings settings;
|
||||
bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool();
|
||||
|
||||
if((zwiftPlayService != nullptr) && gears_zwift_ratio ) {
|
||||
if((zwiftPlayService != nullptr || DIRETO_XR) && gears_zwift_ratio ) {
|
||||
return 1;
|
||||
} else if(WATTBIKE) {
|
||||
return 1;
|
||||
|
||||
@@ -212,7 +212,6 @@ void nordictrackifitadbbike::processPendingDatagrams() {
|
||||
uint16_t port;
|
||||
bool freemotion_coachbike_b22_7 = settings.value(QZSettings::freemotion_coachbike_b22_7, QZSettings::default_freemotion_coachbike_b22_7).toBool();
|
||||
while (socket->hasPendingDatagrams()) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QByteArray datagram;
|
||||
datagram.resize(socket->pendingDatagramSize());
|
||||
socket->readDatagram(datagram.data(), datagram.size(), &sender, &port);
|
||||
@@ -291,7 +290,7 @@ void nordictrackifitadbbike::processPendingDatagrams() {
|
||||
if (settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
|
||||
bool proform_studio_NTEX71021 =
|
||||
@@ -345,8 +344,8 @@ void nordictrackifitadbbike::processPendingDatagrams() {
|
||||
qDebug() << QString::number(ret) + " >> " + message;
|
||||
}
|
||||
// since the motor of the bike is slow, let's filter the inclination changes to more than 4 seconds
|
||||
else if (lastInclinationChanged.secsTo(now) > inclination_delay_seconds) {
|
||||
lastInclinationChanged = now;
|
||||
else if (lastInclinationChanged.secsTo(QDateTime::currentDateTime()) > inclination_delay_seconds) {
|
||||
lastInclinationChanged = QDateTime::currentDateTime();
|
||||
if (nordictrack_ifit_adb_remote) {
|
||||
bool erg_mode = settings.value(QZSettings::zwift_erg, QZSettings::default_zwift_erg).toBool();
|
||||
if (requestInclination != -100 && erg_mode && requestResistance != -100) {
|
||||
@@ -432,18 +431,18 @@ void nordictrackifitadbbike::processPendingDatagrams() {
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * weight * 3.5) / 200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
// KCal = (((uint16_t)((uint8_t)newValue.at(15)) << 8) + (uint16_t)((uint8_t) newValue.at(14)));
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
|
||||
if (Cadence.value() > 0) {
|
||||
CrankRevs++;
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
|
||||
@@ -189,16 +189,25 @@ void proformbike::forceResistance(resistance_t requestResistance) {
|
||||
writeCharacteristic((uint8_t *)res2, sizeof(res2), QStringLiteral("resistance2"), false, false);
|
||||
writeCharacteristic((uint8_t *)res3, sizeof(res3), QStringLiteral("resistance3"), false, true);
|
||||
} else if (proform_xbike) {
|
||||
const uint8_t res1[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x84, 0x03, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3920
|
||||
const uint8_t res2[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x6c, 0x07, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt994
|
||||
const uint8_t res3[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x54, 0x0b, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1325
|
||||
const uint8_t res4[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x3c, 0x0f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1636
|
||||
const uint8_t res5[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x24, 0x13, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1786
|
||||
const uint8_t res6[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x0c, 0x17, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1905
|
||||
const uint8_t res7[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xf4, 0x1a, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2015
|
||||
const uint8_t res8[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xdc, 0x1e, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2134
|
||||
const uint8_t res9[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xc4, 0x22, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2209
|
||||
const uint8_t res10[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xac, 0x26, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2293
|
||||
const uint8_t res1[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x6c, 0x07, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt994
|
||||
const uint8_t res2[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x54, 0x0b, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1325
|
||||
const uint8_t res3[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x3c, 0x0f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1636
|
||||
const uint8_t res4[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x24, 0x13, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1786
|
||||
const uint8_t res5[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x0c, 0x17, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1905
|
||||
const uint8_t res6[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xf4, 0x1a, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2015
|
||||
const uint8_t res7[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xdc, 0x1e, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2134
|
||||
const uint8_t res8[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xc4, 0x22, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2209
|
||||
const uint8_t res9[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xac, 0x26, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2293
|
||||
const uint8_t res10[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xdc, 0x1e, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3007
|
||||
const uint8_t res11[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x0c, 0x17, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3502
|
||||
const uint8_t res12[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x24, 0x13, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3578
|
||||
const uint8_t res13[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x3c, 0x0f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3666
|
||||
const uint8_t res14[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x54, 0x0b, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3740
|
||||
const uint8_t res15[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x6c, 0x07, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3824
|
||||
const uint8_t res16[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x84, 0x03, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3920
|
||||
const uint8_t res17[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x02, 0x00, 0x10, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt4208
|
||||
const uint8_t res18[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x02, 0x00, 0x10, 0x01, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt4227
|
||||
const uint8_t res19[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x02, 0x00, 0x10, 0x03, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt4235
|
||||
|
||||
uint8_t noOpData7[] = {0xfe, 0x02, 0x0d, 0x02};
|
||||
writeCharacteristic((uint8_t *)noOpData7, sizeof(noOpData7), QStringLiteral("resrequest"), false, false);
|
||||
@@ -234,6 +243,33 @@ void proformbike::forceResistance(resistance_t requestResistance) {
|
||||
case 10:
|
||||
writeCharacteristic((uint8_t *)res10, sizeof(res10), QStringLiteral("resistance10"), false, true);
|
||||
break;
|
||||
case 11:
|
||||
writeCharacteristic((uint8_t *)res11, sizeof(res11), QStringLiteral("resistance11"), false, true);
|
||||
break;
|
||||
case 12:
|
||||
writeCharacteristic((uint8_t *)res12, sizeof(res12), QStringLiteral("resistance12"), false, true);
|
||||
break;
|
||||
case 13:
|
||||
writeCharacteristic((uint8_t *)res13, sizeof(res13), QStringLiteral("resistance13"), false, true);
|
||||
break;
|
||||
case 14:
|
||||
writeCharacteristic((uint8_t *)res14, sizeof(res14), QStringLiteral("resistance14"), false, true);
|
||||
break;
|
||||
case 15:
|
||||
writeCharacteristic((uint8_t *)res15, sizeof(res15), QStringLiteral("resistance15"), false, true);
|
||||
break;
|
||||
case 16:
|
||||
writeCharacteristic((uint8_t *)res16, sizeof(res16), QStringLiteral("resistance16"), false, true);
|
||||
break;
|
||||
case 17:
|
||||
writeCharacteristic((uint8_t *)res17, sizeof(res17), QStringLiteral("resistance17"), false, true);
|
||||
break;
|
||||
case 18:
|
||||
writeCharacteristic((uint8_t *)res18, sizeof(res18), QStringLiteral("resistance18"), false, true);
|
||||
break;
|
||||
case 19:
|
||||
writeCharacteristic((uint8_t *)res19, sizeof(res19), QStringLiteral("resistance19"), false, true);
|
||||
break;
|
||||
}
|
||||
} else if (proform_hybrid_trainer_PFEL03815 || proform_bike_sb) {
|
||||
const uint8_t res1[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01,
|
||||
@@ -322,7 +358,7 @@ void proformbike::forceResistance(resistance_t requestResistance) {
|
||||
writeCharacteristic((uint8_t *)res16, sizeof(res16), QStringLiteral("resistance16"), false, true);
|
||||
break;
|
||||
}
|
||||
} else if (nordictrack_gx_2_7 || proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0) {
|
||||
} else if (nordictrack_gx_2_7 || proform_bike_225_csx) {
|
||||
const uint8_t res1[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01,
|
||||
0x04, 0xc2, 0x01, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
const uint8_t res2[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01,
|
||||
@@ -732,7 +768,7 @@ void proformbike::forceIncline(double incline) {
|
||||
true);
|
||||
}
|
||||
|
||||
bool proformbike::innerWriteResistance() {
|
||||
void proformbike::innerWriteResistance() {
|
||||
if (requestResistance != -1) {
|
||||
if (requestResistance > max_resistance) {
|
||||
requestResistance = max_resistance;
|
||||
@@ -743,11 +779,9 @@ bool proformbike::innerWriteResistance() {
|
||||
if (requestResistance != currentResistance().value()) {
|
||||
emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance));
|
||||
forceResistance(requestResistance);
|
||||
return true;
|
||||
}
|
||||
requestResistance = -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void proformbike::update() {
|
||||
@@ -880,7 +914,7 @@ void proformbike::update() {
|
||||
|
||||
switch (counterPoll) {
|
||||
case 0:
|
||||
if (nordictrack_gx_2_7 || proform_cycle_trainer_300_ci || proform_hybrid_trainer_PFEL03815 || proform_bike_sb || proform_bike_225_csx || proform_bike_325_csx || proform_xbike || proform_225_csx_PFEX32925_INT_0) {
|
||||
if (nordictrack_gx_2_7 || proform_cycle_trainer_300_ci || proform_hybrid_trainer_PFEL03815 || proform_bike_sb || proform_bike_225_csx || proform_bike_325_csx || proform_xbike) {
|
||||
writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("noOp"));
|
||||
} else if(proform_bike_PFEVEX71316_0) {
|
||||
writeCharacteristic(noOpData1_proform_bike_PFEVEX71316_0, sizeof(noOpData1_proform_bike_PFEVEX71316_0), QStringLiteral("noOp"));
|
||||
@@ -907,7 +941,7 @@ void proformbike::update() {
|
||||
} else if (proform_tour_de_france_clc) {
|
||||
writeCharacteristic(noOpData2_proform_tour_de_france_clc, sizeof(noOpData2_proform_tour_de_france_clc),
|
||||
QStringLiteral("noOp"));
|
||||
} else if (proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0)
|
||||
} else if (proform_bike_225_csx)
|
||||
writeCharacteristic(noOpData2_proform_bike_225_csx, sizeof(noOpData2_proform_bike_225_csx),
|
||||
QStringLiteral("noOp"));
|
||||
else if (proform_cycle_trainer_400)
|
||||
@@ -944,7 +978,7 @@ void proformbike::update() {
|
||||
} else if (proform_cycle_trainer_400) {
|
||||
writeCharacteristic(noOpData3_proform_cycle_trainer_400, sizeof(noOpData3_proform_cycle_trainer_400),
|
||||
QStringLiteral("noOp"));
|
||||
} else if (proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0)
|
||||
} else if (proform_bike_225_csx)
|
||||
writeCharacteristic(noOpData3_proform_bike_225_csx, sizeof(noOpData3_proform_bike_225_csx),
|
||||
QStringLiteral("noOp"));
|
||||
else if (proform_bike_sb)
|
||||
@@ -974,7 +1008,7 @@ void proformbike::update() {
|
||||
} else if (proform_bike_sb || proform_bike_325_csx) {
|
||||
innerWriteResistance();
|
||||
writeCharacteristic(noOpData7, sizeof(noOpData7), QStringLiteral("noOp"));
|
||||
} else if(proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0) {
|
||||
} else if(proform_bike_225_csx) {
|
||||
writeCharacteristic(noOpData1, sizeof(noOpData1), QStringLiteral("noOp"));
|
||||
} else
|
||||
writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("noOp"));
|
||||
@@ -995,7 +1029,7 @@ void proformbike::update() {
|
||||
} else if (proform_bike_325_csx) {
|
||||
writeCharacteristic(noOpData5_proform_bike_325_csx, sizeof(noOpData5_proform_bike_325_csx),
|
||||
QStringLiteral("noOp"));
|
||||
} else if (proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0) {
|
||||
} else if (proform_bike_225_csx) {
|
||||
writeCharacteristic(noOpData5_proform_bike_225_csx, sizeof(noOpData5_proform_bike_225_csx),
|
||||
QStringLiteral("noOp"));
|
||||
} else if (proform_bike_sb)
|
||||
@@ -1015,7 +1049,9 @@ void proformbike::update() {
|
||||
QStringLiteral("noOp"));
|
||||
} else if(proform_bike_PFEVEX71316_0) {
|
||||
writeCharacteristic(noOpData6_proform_bike_PFEVEX71316_0, sizeof(noOpData6_proform_bike_PFEVEX71316_0), QStringLiteral("noOp"), false, true);
|
||||
if (!innerWriteResistance() && requestInclination != -100) {
|
||||
if (requestResistance != -1)
|
||||
innerWriteResistance();
|
||||
else if (requestInclination != -100) {
|
||||
writeCharacteristic(noOpData7, sizeof(noOpData7), QStringLiteral("noOp"));
|
||||
// only 0.5 steps ara available
|
||||
double inc = qRound(requestInclination * 2.0) / 2.0;
|
||||
@@ -1026,9 +1062,9 @@ void proformbike::update() {
|
||||
}
|
||||
requestInclination = -100;
|
||||
}
|
||||
} else if (proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0) {
|
||||
} else if (proform_bike_225_csx) {
|
||||
writeCharacteristic(noOpData6_proform_bike_225_csx, sizeof(noOpData6_proform_bike_225_csx),
|
||||
QStringLiteral("noOp"), false, true);
|
||||
QStringLiteral("noOp"));
|
||||
innerWriteResistance();
|
||||
}
|
||||
else if (proform_cycle_trainer_400)
|
||||
@@ -1064,7 +1100,7 @@ void proformbike::update() {
|
||||
counterPoll++;
|
||||
if (counterPoll > 6) {
|
||||
counterPoll = 0;
|
||||
} else if(counterPoll == 6 && (proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0 || proform_bike_PFEVEX71316_0)) {
|
||||
} else if(counterPoll == 6 && (proform_bike_225_csx || proform_bike_PFEVEX71316_0)) {
|
||||
counterPoll = 0;
|
||||
} else if (counterPoll == 6 &&
|
||||
(proform_tour_de_france_clc || proform_cycle_trainer_400 || proform_bike_PFEVEX71316_1) &&
|
||||
@@ -1575,12 +1611,10 @@ void proformbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
Resistance = 7;
|
||||
m_pelotonResistance = 65;
|
||||
break;
|
||||
case 0x1e:
|
||||
case 0x1f:
|
||||
Resistance = 8;
|
||||
m_pelotonResistance = 75;
|
||||
break;
|
||||
case 0x22:
|
||||
case 0x23:
|
||||
case 0x24:
|
||||
Resistance = 9;
|
||||
@@ -1859,8 +1893,6 @@ void proformbike::btinit() {
|
||||
nordictrack_gx_44_pro = settings.value(QZSettings::nordictrack_gx_44_pro, QZSettings::default_nordictrack_gx_44_pro).toBool();
|
||||
proform_bike_PFEVEX71316_0 = settings.value(QZSettings::proform_bike_PFEVEX71316_0, QZSettings::default_proform_bike_PFEVEX71316_0).toBool();
|
||||
proform_xbike = settings.value(QZSettings::proform_xbike, QZSettings::default_proform_xbike).toBool();
|
||||
proform_225_csx_PFEX32925_INT_0 = settings.value(QZSettings::proform_225_csx_PFEX32925_INT_0, QZSettings::default_proform_225_csx_PFEX32925_INT_0).toBool();
|
||||
|
||||
|
||||
if(nordictrack_GX4_5_bike)
|
||||
max_resistance = 25;
|
||||
@@ -1925,159 +1957,6 @@ void proformbike::btinit() {
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
} else if (proform_225_csx_PFEX32925_INT_0) {
|
||||
max_resistance = 20;
|
||||
|
||||
// Using the packet sequences from the 225 csx.c log file
|
||||
uint8_t init1[] = {0xfe, 0x02, 0x08, 0x02};
|
||||
uint8_t init2[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x81, 0x87,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init3[] = {0xfe, 0x02, 0x08, 0x02};
|
||||
uint8_t init4[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x07, 0x04, 0x80, 0x8b,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init5[] = {0xfe, 0x02, 0x08, 0x02};
|
||||
uint8_t init6[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x07, 0x04, 0x88, 0x93,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init7[] = {0xfe, 0x02, 0x0a, 0x02};
|
||||
uint8_t init8[] = {0xff, 0x0a, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x82, 0x00,
|
||||
0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init9[] = {0xfe, 0x02, 0x0a, 0x02};
|
||||
uint8_t init10[] = {0xff, 0x0a, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x84, 0x00,
|
||||
0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init11[] = {0xfe, 0x02, 0x08, 0x02};
|
||||
uint8_t init12[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x95, 0x9b,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init13[] = {0xfe, 0x02, 0x2c, 0x04};
|
||||
uint8_t init14[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x07, 0x28, 0x90, 0x07,
|
||||
0x01, 0xde, 0x84, 0x20, 0xca, 0x72, 0x28, 0xc4, 0x76, 0x26};
|
||||
uint8_t init15[] = {0x01, 0x12, 0xec, 0x98, 0x42, 0x0a, 0xd0, 0x6c, 0x2e, 0xee,
|
||||
0xd4, 0x90, 0x5a, 0x02, 0xf8, 0xb4, 0x66, 0x56, 0x3c, 0xe8};
|
||||
uint8_t init16[] = {0xff, 0x08, 0xd2, 0xba, 0xa0, 0xa0, 0x02, 0x00, 0x00, 0x4f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init17[] = {0xfe, 0x02, 0x19, 0x03};
|
||||
uint8_t init18[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x07, 0x15, 0x02, 0x0e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init19[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x3d, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init20[] = {0xfe, 0x02, 0x17, 0x03};
|
||||
uint8_t init21[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x07, 0x13, 0x02, 0x0c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init22[] = {0xff, 0x05, 0x00, 0x80, 0x01, 0x00, 0xa9, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init23[] = {0xfe, 0x02, 0x19, 0x03};
|
||||
uint8_t init24[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x07, 0x15, 0x02, 0x00,
|
||||
0x0f, 0x00, 0x10, 0x00, 0xc0, 0x1c, 0x4c, 0x00, 0x00, 0xe0};
|
||||
uint8_t init25[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x5d, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
// Write the initialization sequence
|
||||
writeCharacteristic(init1, sizeof(init1), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init2, sizeof(init2), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init3, sizeof(init3), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init4, sizeof(init4), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init5, sizeof(init5), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init6, sizeof(init6), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init7, sizeof(init7), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init8, sizeof(init8), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init9, sizeof(init9), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init10, sizeof(init10), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init11, sizeof(init11), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init12, sizeof(init12), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init13, sizeof(init13), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init14, sizeof(init14), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init15, sizeof(init15), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init16, sizeof(init16), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init17, sizeof(init17), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init18, sizeof(init18), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init19, sizeof(init19), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init20, sizeof(init20), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init21, sizeof(init21), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init22, sizeof(init22), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init23, sizeof(init23), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init24, sizeof(init24), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init25, sizeof(init25), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
|
||||
uint8_t init26[] = {0xfe, 0x02, 0x17, 0x03};
|
||||
uint8_t init27[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x07, 0x13, 0x02, 0x0c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init28[] = {0xff, 0x05, 0x00, 0x80, 0x01, 0x00, 0xa9, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init29[] = {0xfe, 0x02, 0x17, 0x03};
|
||||
uint8_t init30[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x07, 0x13, 0x02, 0x0c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init31[] = {0xff, 0x05, 0x00, 0x80, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init32[] = {0xfe, 0x02, 0x17, 0x03};
|
||||
uint8_t init33[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x07, 0x13, 0x02, 0x0c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init34[] = {0xff, 0x05, 0x00, 0x80, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init35[] = {0xfe, 0x02, 0x17, 0x03};
|
||||
uint8_t init36[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x07, 0x13, 0x02, 0x00,
|
||||
0x0d, 0x3c, 0x96, 0x31, 0x00, 0x00, 0x40, 0x40, 0x00, 0x80};
|
||||
uint8_t init37[] = {0xff, 0x05, 0x00, 0x00, 0x00, 0x85, 0xb1, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init38[] = {0xfe, 0x02, 0x19, 0x03};
|
||||
uint8_t init39[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x07, 0x15, 0x02, 0x00,
|
||||
0x0f, 0x80, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t init40[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
writeCharacteristic(init26, sizeof(init26), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init27, sizeof(init27), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init28, sizeof(init28), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init29, sizeof(init29), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init30, sizeof(init30), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init31, sizeof(init31), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init32, sizeof(init32), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init33, sizeof(init33), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init34, sizeof(init34), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init35, sizeof(init35), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init36, sizeof(init36), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init37, sizeof(init37), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init38, sizeof(init38), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init39, sizeof(init39), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(init40, sizeof(init40), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
} else if (settings.value(QZSettings::proform_xbike, QZSettings::default_proform_xbike).toBool()) {
|
||||
max_resistance = 10;
|
||||
|
||||
@@ -2807,7 +2686,7 @@ void proformbike::btinit() {
|
||||
writeCharacteristic(noOpData22, sizeof(noOpData22), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
} else if (proform_bike_225_csx) {
|
||||
max_resistance = 20;
|
||||
max_resistance = 10;
|
||||
uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x07, 0x28, 0x90, 0x07, 0x01, 0xd2, 0x74, 0x14, 0xb2, 0x5e, 0x08, 0xa0, 0x5e, 0x0a};
|
||||
uint8_t initData11[] = {0x01, 0x12, 0xbc, 0x6c, 0x1a, 0xc6, 0x90, 0x28, 0xe6, 0xa2, 0x64, 0x24, 0xe2, 0xae, 0x98, 0x50, 0x0e, 0xfa, 0xac, 0x9c};
|
||||
uint8_t initData12[] = {0xff, 0x08, 0x4a, 0x36, 0x20, 0x98, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
@@ -55,7 +55,7 @@ class proformbike : public bike {
|
||||
uint16_t watts() override;
|
||||
void forceResistance(resistance_t requestResistance);
|
||||
void forceIncline(double incline);
|
||||
bool innerWriteResistance();
|
||||
void innerWriteResistance();
|
||||
|
||||
QTimer *refresh;
|
||||
uint8_t counterPoll = 0;
|
||||
@@ -95,7 +95,6 @@ class proformbike : public bike {
|
||||
bool nordictrack_gx_44_pro = false;
|
||||
bool proform_bike_PFEVEX71316_0 = false;
|
||||
bool proform_xbike = false;
|
||||
bool proform_225_csx_PFEX32925_INT_0 = false;
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
lockscreen *h = 0;
|
||||
|
||||
@@ -271,15 +271,11 @@ void wahookickrsnapbike::update() {
|
||||
}
|
||||
|
||||
if (lastGearValue != gears()) {
|
||||
if(KICKR_SNAP) {
|
||||
inclinationChanged(lastGrade, lastGrade);
|
||||
} else {
|
||||
QByteArray a = setWheelCircumference(wheelCircumference::gearsToWheelDiameter(gears()));
|
||||
uint8_t b[20];
|
||||
memcpy(b, a.constData(), a.length());
|
||||
writeCharacteristic(b, a.length(), "setWheelCircumference", false, false);
|
||||
lastGrade = 999; // to force a change
|
||||
}
|
||||
QByteArray a = setWheelCircumference(wheelCircumference::gearsToWheelDiameter(gears()));
|
||||
uint8_t b[20];
|
||||
memcpy(b, a.constData(), a.length());
|
||||
writeCharacteristic(b, a.length(), "setWheelCircumference", false, false);
|
||||
lastGrade = 999; // to force a change
|
||||
}
|
||||
|
||||
lastGearValue = gears();
|
||||
@@ -791,12 +787,8 @@ void wahookickrsnapbike::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
} else if(device.name().toUpper().startsWith("KICKR BIKE")) {
|
||||
KICKR_BIKE = true;
|
||||
qDebug() << "KICKR BIKE workaround activated";
|
||||
} else if(device.name().toUpper().startsWith("KICKR SNAP")) {
|
||||
KICKR_SNAP = true;
|
||||
qDebug() << "KICKR SNAP workaround activated";
|
||||
}
|
||||
|
||||
|
||||
m_control = QLowEnergyController::createCentral(bluetoothDevice, this);
|
||||
connect(m_control, &QLowEnergyController::serviceDiscovered, this, &wahookickrsnapbike::serviceDiscovered);
|
||||
connect(m_control, &QLowEnergyController::discoveryFinished, this, &wahookickrsnapbike::serviceScanDone);
|
||||
@@ -876,10 +868,6 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) {
|
||||
emit debug(QStringLiteral("writing inclination ") + QString::number(grade));
|
||||
QSettings settings;
|
||||
double g = grade;
|
||||
if(KICKR_SNAP) {
|
||||
g += gears() * 0.5;
|
||||
qDebug() << "adding gear offset so " << g;
|
||||
}
|
||||
QByteArray a = setSimGrade(g);
|
||||
uint8_t b[20];
|
||||
memcpy(b, a.constData(), a.length());
|
||||
|
||||
@@ -107,7 +107,6 @@ class wahookickrsnapbike : public bike {
|
||||
|
||||
bool WAHOO_KICKR = false;
|
||||
bool KICKR_BIKE = false;
|
||||
bool KICKR_SNAP = false;
|
||||
|
||||
bool lastCommandErgMode = false;
|
||||
|
||||
|
||||
@@ -1,366 +0,0 @@
|
||||
#include "gpiotreadmill.h"
|
||||
#include "ios/lockscreen.h"
|
||||
#include "keepawakehelper.h"
|
||||
#include "virtualdevices/virtualtreadmill.h"
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
#include <QMetaEnum>
|
||||
#include <QSettings>
|
||||
#include <chrono>
|
||||
//#define Q_OS_RASPI 0
|
||||
#ifdef Q_OS_RASPI
|
||||
#include <wiringPi.h>
|
||||
#else
|
||||
#define OUTPUT 1
|
||||
QModbusReply *gpiotreadmill::lastRequest;
|
||||
QModbusClient *gpiotreadmill::modbusDevice = nullptr;
|
||||
void gpiotreadmill::digitalWrite(int pin, int state) {
|
||||
const int server_address = 255;
|
||||
QModbusDataUnit writeUnit(QModbusDataUnit::Coils, pin, 1);
|
||||
writeUnit.setValue(0, state);
|
||||
if(modbusDevice) {
|
||||
QModbusReply* r = nullptr;
|
||||
int retry = 0;
|
||||
do {
|
||||
qDebug() << "modbus sending retry" << retry++;
|
||||
r = modbusDevice->sendWriteRequest(writeUnit, server_address);
|
||||
} while(r == nullptr);
|
||||
}
|
||||
else
|
||||
qDebug() << "modbusDevice nullptr!";
|
||||
|
||||
qDebug() << QStringLiteral("switch pin ") + QString::number(pin) + QStringLiteral(" to ") + QString::number(state);
|
||||
}
|
||||
|
||||
void pinMode(int pin, int state) {
|
||||
qDebug() << QStringLiteral("init pin ") + QString::number(pin) + QStringLiteral(" to ") + QString::number(state);
|
||||
}
|
||||
|
||||
int wiringPiSetup() {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
|
||||
gpioWorkerThread::gpioWorkerThread(QObject *parent, QString name, uint8_t pinUp, uint8_t pinDown, double step, double currentValue, QSemaphore *semaphore): QThread(parent),
|
||||
name{name}, currentValue{currentValue}, pinUp{pinUp}, pinDown{pinDown}, step{step}, semaphore{semaphore}
|
||||
{
|
||||
pinMode(pinUp, OUTPUT);
|
||||
pinMode(pinDown, OUTPUT);
|
||||
gpiotreadmill::digitalWrite(pinUp, 0);
|
||||
gpiotreadmill::digitalWrite(pinDown, 0);
|
||||
}
|
||||
|
||||
void gpioWorkerThread::setRequestValue(double request)
|
||||
{
|
||||
this->requestValue = request;
|
||||
}
|
||||
|
||||
void gpioWorkerThread::run() {
|
||||
if (requestValue > currentValue) {
|
||||
while (requestValue > currentValue) {
|
||||
qDebug() << QStringLiteral("increasing ") + name + " from " + QString::number(currentValue) + " to " + QString::number(requestValue);
|
||||
semaphore->acquire();
|
||||
gpiotreadmill::digitalWrite(pinUp, 1);
|
||||
QThread::msleep(GPIO_KEEP_MS);
|
||||
gpiotreadmill::digitalWrite(pinUp, 0);
|
||||
QThread::msleep(GPIO_REBOUND_MS);
|
||||
semaphore->release();
|
||||
currentValue += step;
|
||||
if(QThread::currentThread()->isInterruptionRequested()) {
|
||||
qDebug() << "Interrupting set " + name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (requestValue < currentValue) {
|
||||
qDebug() << QStringLiteral("decreasing ") + name + " from " + QString::number(currentValue) + " to " + QString::number(requestValue);
|
||||
semaphore->acquire();
|
||||
gpiotreadmill::digitalWrite(pinDown, 1);
|
||||
QThread::msleep(GPIO_KEEP_MS);
|
||||
gpiotreadmill::digitalWrite(pinDown, 0);
|
||||
QThread::msleep(GPIO_REBOUND_MS);
|
||||
semaphore->release();
|
||||
currentValue -= step;
|
||||
if(QThread::currentThread()->isInterruptionRequested()) {
|
||||
qDebug() << "Interrupting set " + name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
QThread::msleep(50);
|
||||
}
|
||||
|
||||
gpiotreadmill::gpiotreadmill(uint32_t pollDeviceTime, bool noConsole, bool noHeartService, double forceInitSpeed,
|
||||
double forceInitInclination) {
|
||||
m_watt.setType(metric::METRIC_WATT);
|
||||
Speed.setType(metric::METRIC_SPEED);
|
||||
this->noConsole = noConsole;
|
||||
this->noHeartService = noHeartService;
|
||||
|
||||
if (wiringPiSetup() == -1) {
|
||||
qDebug() << QStringLiteral("wiringPiSetup ERROR!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
modbusDevice = new QModbusRtuSerialMaster(this);
|
||||
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
|
||||
"COM4");
|
||||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
|
||||
QSerialPort::Parity::NoParity);
|
||||
modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
|
||||
QSerialPort::Baud9600);
|
||||
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
|
||||
QSerialPort::Data8);
|
||||
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
|
||||
QSerialPort::StopBits::OneStop);
|
||||
|
||||
modbusDevice->setTimeout(50);
|
||||
modbusDevice->setNumberOfRetries(3);
|
||||
|
||||
qDebug() << "modbus Connecting...";
|
||||
|
||||
while (!modbusDevice->connectDevice()) {
|
||||
qDebug() << "modbus Connetion Error. Retrying...";
|
||||
}
|
||||
|
||||
qDebug() << "modbus Connected!";
|
||||
|
||||
|
||||
pinMode(OUTPUT_START, OUTPUT);
|
||||
pinMode(OUTPUT_STOP, OUTPUT);
|
||||
digitalWrite(OUTPUT_START, 0);
|
||||
digitalWrite(OUTPUT_STOP, 0);
|
||||
|
||||
if (forceInitSpeed > 0) {
|
||||
lastSpeed = forceInitSpeed;
|
||||
}
|
||||
|
||||
if (forceInitInclination > 0) {
|
||||
lastInclination = forceInitInclination;
|
||||
}
|
||||
|
||||
semaphore = new QSemaphore(1);
|
||||
speedThread = new gpioWorkerThread(this, "speed", OUTPUT_SPEED_UP, OUTPUT_SPEED_DOWN, SPEED_STEP, forceInitSpeed, semaphore);
|
||||
inclineThread = new gpioWorkerThread(this, "incline", OUTPUT_INCLINE_UP, OUTPUT_INCLINE_DOWN, INCLINATION_STEP, forceInitInclination, semaphore);
|
||||
|
||||
refresh = new QTimer(this);
|
||||
initDone = false;
|
||||
connect(refresh, &QTimer::timeout, this, &gpiotreadmill::update);
|
||||
refresh->start(pollDeviceTime);
|
||||
|
||||
Speed = 0.8;
|
||||
}
|
||||
|
||||
gpiotreadmill::~gpiotreadmill() {
|
||||
speedThread->requestInterruption();
|
||||
speedThread->quit();
|
||||
speedThread->wait();
|
||||
delete speedThread;
|
||||
inclineThread->requestInterruption();
|
||||
inclineThread->quit();
|
||||
inclineThread->wait();
|
||||
delete inclineThread;
|
||||
delete semaphore;
|
||||
modbusDevice->disconnectDevice();
|
||||
}
|
||||
|
||||
void gpiotreadmill::onReadReady() {
|
||||
|
||||
}
|
||||
|
||||
void gpiotreadmill::changeInclinationRequested(double grade, double percentage) {
|
||||
if (percentage < 0)
|
||||
percentage = 0;
|
||||
changeInclination(grade, percentage);
|
||||
}
|
||||
|
||||
void gpiotreadmill::forceSpeed(double requestSpeed) {
|
||||
qDebug() << QStringLiteral("gpiotreadmill.cpp: request set speed ") + QString::number(Speed.value()) + QStringLiteral(" to ") + QString::number(requestSpeed);
|
||||
if (speedThread->isRunning())
|
||||
{
|
||||
speedThread->requestInterruption();
|
||||
speedThread->quit();
|
||||
speedThread->wait();
|
||||
|
||||
}
|
||||
speedThread->setRequestValue(requestSpeed);
|
||||
speedThread->start();
|
||||
|
||||
Speed = requestSpeed; /* we are on the way to the requested speed */
|
||||
}
|
||||
|
||||
void gpiotreadmill::forceIncline(double requestIncline) {
|
||||
qDebug() << QStringLiteral("gpiotreadmill.cpp: request set Incline ") + QString::number(Inclination.value()) + QStringLiteral(" to ") + QString::number(requestIncline);
|
||||
|
||||
if (inclineThread->isRunning())
|
||||
{
|
||||
inclineThread->requestInterruption();
|
||||
inclineThread->quit();
|
||||
inclineThread->wait();
|
||||
|
||||
}
|
||||
inclineThread->setRequestValue(requestIncline);
|
||||
inclineThread->start();
|
||||
|
||||
Inclination = requestIncline; /* we are on the way to the requested incline */
|
||||
}
|
||||
|
||||
void gpiotreadmill::update() {
|
||||
|
||||
QSettings settings;
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!firstInit && !virtualTreadMill && !virtualBike) {
|
||||
bool virtual_device_enabled = settings.value("virtual_device_enabled", true).toBool();
|
||||
bool virtual_device_force_bike = settings.value("virtual_device_force_bike", false).toBool();
|
||||
|
||||
emit connectedAndDiscovered();
|
||||
|
||||
if (virtual_device_enabled) {
|
||||
if (!virtual_device_force_bike) {
|
||||
qDebug() << "creating virtual treadmill interface...";
|
||||
virtualTreadMill = new virtualtreadmill(this, noHeartService);
|
||||
connect(virtualTreadMill, &virtualtreadmill::debug, this, &gpiotreadmill::debug);
|
||||
connect(virtualTreadMill, &virtualtreadmill::changeInclination, this,
|
||||
&gpiotreadmill::changeInclinationRequested);
|
||||
} else {
|
||||
qDebug() <<"creating virtual bike interface...";
|
||||
virtualBike = new virtualbike(this);
|
||||
connect(virtualBike, &virtualbike::changeInclination, this, &gpiotreadmill::changeInclinationRequested);
|
||||
}
|
||||
firstInit = 1;
|
||||
}
|
||||
}
|
||||
// ********************************************************************************************************
|
||||
|
||||
// debug("Domyos Treadmill RSSI " + QString::number(bluetoothDevice.rssi()));
|
||||
|
||||
double heart = 0;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) {
|
||||
|
||||
if (heart == 0) {
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
lockscreen h;
|
||||
long appleWatchHeartRate = h.heartRate();
|
||||
h.setKcal(KCal.value());
|
||||
h.setDistance(Distance.value());
|
||||
Heart = appleWatchHeartRate;
|
||||
qDebug() << "Current Heart from Apple Watch: " << QString::number(appleWatchHeartRate);
|
||||
#endif
|
||||
#endif
|
||||
} else
|
||||
|
||||
Heart = heart;
|
||||
}
|
||||
}
|
||||
|
||||
if (!firstCharacteristicChanged) {
|
||||
if (watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()))
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts(settings.value(QStringLiteral("weight"), 75.0).toFloat())) + 1.19) *
|
||||
settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
Distance += ((Speed.value() / (double)3600.0) /
|
||||
((double)1000.0 / (double)(lastTimeCharacteristicChanged.msecsTo(QDateTime::currentDateTime()))));
|
||||
lastTimeCharacteristicChanged = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
qDebug() << QStringLiteral("Current speed: ") + QString::number(Speed.value());
|
||||
qDebug() << QStringLiteral("Current incline: ") + QString::number(Inclination.value());
|
||||
qDebug() << QStringLiteral("Current heart: ") + QString::number(Heart.value());
|
||||
qDebug() << QStringLiteral("Current KCal: ") + QString::number(KCal.value());
|
||||
qDebug() << QStringLiteral("Current KCal from the machine: ") + QString::number(KCal.value());
|
||||
qDebug() << QStringLiteral("Current Distance: ") + QString::number(Distance.value());
|
||||
qDebug() << QStringLiteral("Current Distance Calculated: ") + QString::number(Distance.value());
|
||||
|
||||
firstCharacteristicChanged = false;
|
||||
|
||||
update_metrics(true, watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()));
|
||||
|
||||
// updating the treadmill console every second
|
||||
if (sec1Update++ >= (1000 / refresh->interval())) {
|
||||
}
|
||||
|
||||
// byte 3 - 4 = elapsed time
|
||||
// byte 17 = inclination
|
||||
{
|
||||
if (requestSpeed != -1) {
|
||||
if (requestSpeed != currentSpeed().value() && requestSpeed >= 0 && requestSpeed <= 22) {
|
||||
qDebug() << QStringLiteral("writing speed ") + QString::number(requestSpeed);
|
||||
|
||||
forceSpeed(requestSpeed);
|
||||
}
|
||||
requestSpeed = -1;
|
||||
}
|
||||
if (requestInclination != -1) {
|
||||
// only 0.5 steps ara avaiable
|
||||
requestInclination = qRound(requestInclination * 2.0) / 2.0;
|
||||
if (requestInclination != currentInclination().value() && requestInclination >= 0 &&
|
||||
requestInclination <= 15) {
|
||||
qDebug() << QStringLiteral("writing incline ") + QString::number(requestInclination);
|
||||
|
||||
forceIncline(requestInclination);
|
||||
}
|
||||
requestInclination = -1;
|
||||
}
|
||||
if (requestStart != -1) {
|
||||
qDebug() << QStringLiteral("starting...");
|
||||
if (lastSpeed == 0.0) {
|
||||
|
||||
lastSpeed = 0.5;
|
||||
}
|
||||
digitalWrite(OUTPUT_START, 1);
|
||||
QThread::msleep(GPIO_KEEP_MS);
|
||||
digitalWrite(OUTPUT_START, 0);
|
||||
requestStart = -1;
|
||||
Speed = 0.8;
|
||||
emit tapeStarted();
|
||||
}
|
||||
if (requestStop != -1) {
|
||||
qDebug() << QStringLiteral("stopping...");
|
||||
digitalWrite(OUTPUT_STOP, 1);
|
||||
QThread::msleep(GPIO_KEEP_MS);
|
||||
digitalWrite(OUTPUT_STOP, 0);
|
||||
requestStop = -1;
|
||||
}
|
||||
if (requestFanSpeed != -1) {
|
||||
qDebug() << QStringLiteral("changing fan speed...");
|
||||
|
||||
requestFanSpeed = -1;
|
||||
}
|
||||
if (requestIncreaseFan != -1) {
|
||||
qDebug() << QStringLiteral("increasing fan speed...");
|
||||
|
||||
requestIncreaseFan = -1;
|
||||
} else if (requestDecreaseFan != -1) {
|
||||
qDebug() << QStringLiteral("decreasing fan speed...");
|
||||
|
||||
requestDecreaseFan = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool gpiotreadmill::connected() { return true; }
|
||||
|
||||
void *gpiotreadmill::VirtualTreadMill() { return virtualTreadMill; }
|
||||
|
||||
void *gpiotreadmill::VirtualDevice() { return VirtualTreadMill(); }
|
||||
|
||||
void gpiotreadmill::searchingStop() { searchStopped = true; }
|
||||
double gpiotreadmill::minStepSpeed() { return 0.1; }
|
||||
@@ -1,140 +0,0 @@
|
||||
#ifndef GPIOTREADMILL_H
|
||||
#define GPIOTREADMILL_H
|
||||
|
||||
#include <QBluetoothDeviceDiscoveryAgent>
|
||||
#include <QtBluetooth/qlowenergyadvertisingdata.h>
|
||||
#include <QtBluetooth/qlowenergyadvertisingparameters.h>
|
||||
#include <QtBluetooth/qlowenergycharacteristic.h>
|
||||
#include <QtBluetooth/qlowenergycharacteristicdata.h>
|
||||
|
||||
#include <QtBluetooth/qlowenergycontroller.h>
|
||||
#include <QtBluetooth/qlowenergydescriptordata.h>
|
||||
#include <QtBluetooth/qlowenergyservice.h>
|
||||
#include <QtBluetooth/qlowenergyservicedata.h>
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#else
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#endif
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qscopedpointer.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QSemaphore>
|
||||
|
||||
#include <QtSerialBus/QModbusClient>
|
||||
#include <QtSerialBus/QModbusDataUnit>
|
||||
#include <QtSerialBus/QModbusReply>
|
||||
#include <QtSerialBus/QModbusRtuSerialMaster>
|
||||
#include <QtSerialPort/QSerialPort>
|
||||
|
||||
#include "devices/treadmill.h"
|
||||
#include "virtualdevices/virtualbike.h"
|
||||
#include "virtualdevices/virtualtreadmill.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
#endif
|
||||
|
||||
class gpioWorkerThread : public QThread
|
||||
{
|
||||
public:
|
||||
explicit gpioWorkerThread(QObject *parent, QString name = "", uint8_t pinUp = 0, uint8_t pinDown = 0, double step = 0.0, double currentValue = 0.0, QSemaphore *semaphore = nullptr);
|
||||
void run();
|
||||
void setRequestValue(double request);
|
||||
private:
|
||||
QString name;
|
||||
double requestValue;
|
||||
double currentValue;
|
||||
uint8_t pinUp;
|
||||
uint8_t pinDown;
|
||||
double step;
|
||||
const uint16_t GPIO_KEEP_MS = 1;
|
||||
const uint16_t GPIO_REBOUND_MS = 175;
|
||||
QSemaphore *semaphore;
|
||||
};
|
||||
|
||||
|
||||
class gpiotreadmill : public treadmill {
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
gpiotreadmill(uint32_t poolDeviceTime = 200, bool noConsole = false, bool noHeartService = false,
|
||||
double forceInitSpeed = 1.0, double forceInitInclination = 0.0);
|
||||
~gpiotreadmill();
|
||||
bool connected();
|
||||
|
||||
void *VirtualTreadMill();
|
||||
void *VirtualDevice();
|
||||
|
||||
static void digitalWrite(int pin, int state);
|
||||
static QModbusReply *lastRequest;
|
||||
static QModbusClient *modbusDevice;
|
||||
|
||||
double minStepSpeed();
|
||||
|
||||
private:
|
||||
bool noConsole = false;
|
||||
bool noHeartService = false;
|
||||
uint32_t pollDeviceTime = 200;
|
||||
bool searchStopped = false;
|
||||
uint8_t sec1Update = 0;
|
||||
uint8_t firstInit = 0;
|
||||
QDateTime lastTimeCharacteristicChanged;
|
||||
bool firstCharacteristicChanged = true;
|
||||
|
||||
QTimer *refresh;
|
||||
virtualtreadmill *virtualTreadMill = nullptr;
|
||||
virtualbike *virtualBike = 0;
|
||||
|
||||
bool initDone = false;
|
||||
bool initRequest = false;
|
||||
|
||||
const uint8_t OUTPUT_SPEED_UP = 0;
|
||||
const uint8_t OUTPUT_SPEED_DOWN = 1;
|
||||
const uint8_t OUTPUT_INCLINE_UP = 2;
|
||||
const uint8_t OUTPUT_INCLINE_DOWN = 3;
|
||||
const uint8_t OUTPUT_START = 4;
|
||||
const uint8_t OUTPUT_STOP = 5;
|
||||
|
||||
const uint16_t GPIO_KEEP_MS = 50;
|
||||
//const uint16_t GPIO_REBOUND_MS = 200;
|
||||
|
||||
const double SPEED_STEP = 0.1;
|
||||
const double INCLINATION_STEP = 1.0;
|
||||
|
||||
void forceSpeed(double requestSpeed);
|
||||
void forceIncline(double requestIncline);
|
||||
gpioWorkerThread* speedThread;
|
||||
gpioWorkerThread* inclineThread;
|
||||
QSemaphore *semaphore; // my treadmill don't like it if the buttons will be pressed simultanly
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
lockscreen *h = 0;
|
||||
#endif
|
||||
|
||||
Q_SIGNALS:
|
||||
void disconnected();
|
||||
void debug(QString string);
|
||||
void speedChanged(double speed);
|
||||
void packetReceived();
|
||||
|
||||
public slots:
|
||||
void searchingStop();
|
||||
|
||||
private slots:
|
||||
|
||||
void changeInclinationRequested(double grade, double percentage);
|
||||
void onReadReady();
|
||||
|
||||
void update();
|
||||
};
|
||||
|
||||
#endif // GPIOTREADMILL_H
|
||||
238
src/homeform.cpp
238
src/homeform.cpp
@@ -447,22 +447,6 @@ homeform::homeform(QQmlApplicationEngine *engine, bluetooth *bl) {
|
||||
settings.value(QZSettings::tile_preset_powerzone_7_label, QZSettings::default_tile_preset_powerzone_7_label).toString(),
|
||||
settings.value(QZSettings::tile_preset_powerzone_7_color, QZSettings::default_tile_preset_powerzone_7_color).toString());
|
||||
|
||||
tile_hr_time_in_zone_1 = new DataObject(QStringLiteral("HR Zone 1+"), QStringLiteral("icons/icons/heart_red.png"),
|
||||
QStringLiteral("0:00:00"), false, QStringLiteral("tile_hr_time_in_zone_1"), valueElapsedFontSize, labelFontSize);
|
||||
|
||||
tile_hr_time_in_zone_2 = new DataObject(QStringLiteral("HR Zone 2+"), QStringLiteral("icons/icons/heart_red.png"),
|
||||
QStringLiteral("0:00:00"), false, QStringLiteral("tile_hr_time_in_zone_2"), valueElapsedFontSize, labelFontSize);
|
||||
|
||||
tile_hr_time_in_zone_3 = new DataObject(QStringLiteral("HR Zone 3+"), QStringLiteral("icons/icons/heart_red.png"),
|
||||
QStringLiteral("0:00:00"), false, QStringLiteral("tile_hr_time_in_zone_3"), valueElapsedFontSize, labelFontSize);
|
||||
|
||||
tile_hr_time_in_zone_4 = new DataObject(QStringLiteral("HR Zone 4+"), QStringLiteral("icons/icons/heart_red.png"),
|
||||
QStringLiteral("0:00:00"), false, QStringLiteral("tile_hr_time_in_zone_4"), valueElapsedFontSize, labelFontSize);
|
||||
|
||||
tile_hr_time_in_zone_5 = new DataObject(QStringLiteral("HR Zone 5"), QStringLiteral("icons/icons/heart_red.png"),
|
||||
QStringLiteral("0:00:00"), false, QStringLiteral("tile_hr_time_in_zone_5"), valueElapsedFontSize, labelFontSize);
|
||||
|
||||
|
||||
if (!settings.value(QZSettings::top_bar_enabled, QZSettings::default_top_bar_enabled).toBool()) {
|
||||
|
||||
m_topBarHeight = 0;
|
||||
@@ -1276,8 +1260,8 @@ void homeform::onToastRequested(QString message) {
|
||||
QStringList homeform::tile_order() {
|
||||
|
||||
QStringList r;
|
||||
r.reserve(65);
|
||||
for (int i = 0; i < 66; i++) {
|
||||
r.reserve(43);
|
||||
for (int i = 0; i < 43; i++) {
|
||||
r.append(QString::number(i));
|
||||
}
|
||||
return r;
|
||||
@@ -1626,37 +1610,7 @@ void homeform::sortTiles() {
|
||||
settings.value(QZSettings::tile_target_zone_order, 24).toInt() == i) {
|
||||
target_zone->setGridId(i);
|
||||
dataList.append(target_zone);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_1_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_1_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_1->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_1);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_2_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_2_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_2->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_2);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_3_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_3_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_3->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_3);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_4_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_4_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_4->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_4);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_5_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_5_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_5->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_5);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::BIKE) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
@@ -2043,38 +1997,7 @@ void homeform::sortTiles() {
|
||||
settings.value(QZSettings::tile_preset_powerzone_7_order, QZSettings::default_tile_preset_powerzone_7_order).toInt() == i) {
|
||||
preset_powerzone_7->setGridId(i);
|
||||
dataList.append(preset_powerzone_7);
|
||||
}
|
||||
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_1_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_1_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_1->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_1);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_2_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_2_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_2->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_2);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_3_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_3_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_3->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_3);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_4_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_4_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_4->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_4);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_5_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_5_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_5->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_5);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ROWING) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
@@ -2367,38 +2290,7 @@ void homeform::sortTiles() {
|
||||
settings.value(QZSettings::tile_gears_order, 51).toInt() == i) {
|
||||
gears->setGridId(i);
|
||||
dataList.append(gears);
|
||||
}
|
||||
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_1_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_1_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_1->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_1);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_2_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_2_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_2->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_2);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_3_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_3_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_3->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_3);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_4_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_4_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_4->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_4);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_5_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_5_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_5->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_5);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::JUMPROPE) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
@@ -2696,37 +2588,6 @@ void homeform::sortTiles() {
|
||||
gears->setGridId(i);
|
||||
dataList.append(gears);
|
||||
}
|
||||
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_1_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_1_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_1->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_1);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_2_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_2_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_2->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_2);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_3_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_3_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_3->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_3);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_4_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_4_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_4->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_4);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_5_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_5_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_5->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_5);
|
||||
}
|
||||
}
|
||||
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ELLIPTICAL) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
@@ -3034,37 +2895,6 @@ void homeform::sortTiles() {
|
||||
pace->setGridId(i);
|
||||
dataList.append(pace);
|
||||
}
|
||||
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_1_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_1_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_1->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_1);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_2_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_2_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_2->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_2);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_3_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_3_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_3->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_3);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_4_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_4_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_4->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_4);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_hr_time_in_zone_5_enabled, false).toBool() &&
|
||||
settings.value(QZSettings::tile_hr_time_in_zone_5_order, 0).toInt() == i) {
|
||||
tile_hr_time_in_zone_5->setGridId(i);
|
||||
dataList.append(tile_hr_time_in_zone_5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3164,7 +2994,6 @@ void homeform::deviceConnected(QBluetoothDeviceInfo b) {
|
||||
QObject::connect(home, SIGNAL(plus_clicked(QString)), this, SLOT(Plus(QString)));
|
||||
QObject::connect(home, SIGNAL(minus_clicked(QString)), this, SLOT(Minus(QString)));
|
||||
QObject::connect(home, SIGNAL(largeButton_clicked(QString)), this, SLOT(LargeButton(QString)));
|
||||
QObject::connect(home, SIGNAL(keyPressed(int)), this, SLOT(keyPressed(int)));
|
||||
|
||||
emit workoutNameChanged(workoutName());
|
||||
emit instructorNameChanged(instructorName());
|
||||
@@ -3202,17 +3031,6 @@ void homeform::deviceConnected(QBluetoothDeviceInfo b) {
|
||||
}
|
||||
}
|
||||
|
||||
void homeform::keyPressed(int key) {
|
||||
if(key == Qt::Key_A)
|
||||
Plus("speed");
|
||||
else if(key == Qt::Key_S)
|
||||
Minus("speed");
|
||||
else if(key == Qt::Key_D)
|
||||
Plus("inclination");
|
||||
else if(key == Qt::Key_F)
|
||||
Minus("inclination");
|
||||
}
|
||||
|
||||
void homeform::deviceFound(const QString &name) {
|
||||
if (name.trimmed().isEmpty()) {
|
||||
return;
|
||||
@@ -4337,34 +4155,6 @@ void homeform::update() {
|
||||
cm_inches_conversion = 0.393701;
|
||||
}
|
||||
|
||||
// Get the time spent in each zone
|
||||
uint32_t seconds_zone1 = bluetoothManager->device()->secondsForHeartZone(0);
|
||||
uint32_t seconds_zone2 = bluetoothManager->device()->secondsForHeartZone(1);
|
||||
uint32_t seconds_zone3 = bluetoothManager->device()->secondsForHeartZone(2);
|
||||
uint32_t seconds_zone4 = bluetoothManager->device()->secondsForHeartZone(3);
|
||||
uint32_t seconds_zone5 = bluetoothManager->device()->secondsForHeartZone(4);
|
||||
|
||||
// Calculate cumulative times (time in this zone or higher)
|
||||
uint32_t seconds_zone1_plus = seconds_zone1 + seconds_zone2 + seconds_zone3 + seconds_zone4 + seconds_zone5;
|
||||
uint32_t seconds_zone2_plus = seconds_zone2 + seconds_zone3 + seconds_zone4 + seconds_zone5;
|
||||
uint32_t seconds_zone3_plus = seconds_zone3 + seconds_zone4 + seconds_zone5;
|
||||
uint32_t seconds_zone4_plus = seconds_zone4 + seconds_zone5;
|
||||
uint32_t seconds_zone5_plus = seconds_zone5; // Zone 5 is already just zone 5
|
||||
|
||||
// Update the UI for each tile
|
||||
tile_hr_time_in_zone_1->setValue(QTime(0, 0, 0).addSecs(seconds_zone1_plus).toString("h:mm:ss"));
|
||||
tile_hr_time_in_zone_2->setValue(QTime(0, 0, 0).addSecs(seconds_zone2_plus).toString("h:mm:ss"));
|
||||
tile_hr_time_in_zone_3->setValue(QTime(0, 0, 0).addSecs(seconds_zone3_plus).toString("h:mm:ss"));
|
||||
tile_hr_time_in_zone_4->setValue(QTime(0, 0, 0).addSecs(seconds_zone4_plus).toString("h:mm:ss"));
|
||||
tile_hr_time_in_zone_5->setValue(QTime(0, 0, 0).addSecs(seconds_zone5_plus).toString("h:mm:ss"));
|
||||
|
||||
// Set colors based on the zone
|
||||
tile_hr_time_in_zone_1->setValueFontColor(QStringLiteral("lightsteelblue"));
|
||||
tile_hr_time_in_zone_2->setValueFontColor(QStringLiteral("green"));
|
||||
tile_hr_time_in_zone_3->setValueFontColor(QStringLiteral("yellow"));
|
||||
tile_hr_time_in_zone_4->setValueFontColor(QStringLiteral("orange"));
|
||||
tile_hr_time_in_zone_5->setValueFontColor(QStringLiteral("red"));
|
||||
|
||||
emit signalChanged(signal());
|
||||
emit currentSpeedChanged(bluetoothManager->device()->currentSpeed().value());
|
||||
speed->setValue(QString::number(bluetoothManager->device()->currentSpeed().value() * unit_conversion, 'f', 1));
|
||||
@@ -5653,8 +5443,7 @@ void homeform::update() {
|
||||
delta = trainProgram->currentRow().loopTimeHR;
|
||||
}
|
||||
|
||||
if (bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL &&
|
||||
!settings.value(QZSettings::trainprogram_pid_ignore_inclination, QZSettings::default_trainprogram_pid_ignore_inclination).toBool() &&
|
||||
if (bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL &&
|
||||
bluetoothManager->device()->currentInclination().value() != lastInclination && lastWattage != 0) {
|
||||
last_seconds_pid_heart_zone = seconds;
|
||||
|
||||
@@ -7534,15 +7323,12 @@ void homeform::loadSettings(const QUrl &filename) {
|
||||
auto settings2LoadAllKeys = settings2Load.allKeys();
|
||||
for (const QString &s : qAsConst(settings2LoadAllKeys)) {
|
||||
if (!s.contains(QZSettings::cryptoKeySettingsProfiles)) {
|
||||
// peloton refresh token must not be changed because it has one refresh token for peloton user saved locally on the device
|
||||
if(!s.contains(QStringLiteral("peloton_refreshtoken"))) {
|
||||
if (!s.contains(QStringLiteral("password")) && !s.contains(QStringLiteral("token"))) {
|
||||
settings.setValue(s, settings2Load.value(s));
|
||||
} else {
|
||||
SimpleCrypt crypt;
|
||||
crypt.setKey(cryptoKeySettingsProfiles());
|
||||
settings.setValue(s, crypt.decryptToString(settings2Load.value(s).toString()));
|
||||
}
|
||||
if (!s.contains(QStringLiteral("password")) && !s.contains(QStringLiteral("token"))) {
|
||||
settings.setValue(s, settings2Load.value(s));
|
||||
} else {
|
||||
SimpleCrypt crypt;
|
||||
crypt.setKey(cryptoKeySettingsProfiles());
|
||||
settings.setValue(s, crypt.decryptToString(settings2Load.value(s).toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,12 +693,7 @@ class homeform : public QObject {
|
||||
DataObject *preset_powerzone_4;
|
||||
DataObject *preset_powerzone_5;
|
||||
DataObject *preset_powerzone_6;
|
||||
DataObject *preset_powerzone_7;
|
||||
DataObject *tile_hr_time_in_zone_1;
|
||||
DataObject *tile_hr_time_in_zone_2;
|
||||
DataObject *tile_hr_time_in_zone_3;
|
||||
DataObject *tile_hr_time_in_zone_4;
|
||||
DataObject *tile_hr_time_in_zone_5;
|
||||
DataObject *preset_powerzone_7;
|
||||
|
||||
private:
|
||||
static homeform *m_singleton;
|
||||
@@ -840,7 +835,6 @@ class homeform : public QObject {
|
||||
void StopRequested();
|
||||
void Lap();
|
||||
void LargeButton(const QString &);
|
||||
void keyPressed(int key);
|
||||
void volumeDown();
|
||||
void volumeUp();
|
||||
void keyMediaPrevious();
|
||||
|
||||
@@ -17,102 +17,64 @@ QT_USE_NAMESPACE
|
||||
|
||||
- (bool)cacheWriteValue:(const QByteArray &)value for:(NSObject *)obj
|
||||
{
|
||||
// Initial check for null object
|
||||
if (!obj) {
|
||||
qDebug() << "Error: Invalid object (nil)";
|
||||
return false;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
// Safely verify that the object is valid without calling methods on it
|
||||
Class objClass = [obj class];
|
||||
if (!objClass) {
|
||||
qDebug() << "Error: Cannot get class of the object, probably deallocated";
|
||||
@try {
|
||||
// Accesso alle variabili private tramite self
|
||||
OSXBluetooth::CharHash &localCharMap = ((QT_MANGLE_NAMESPACE(OSXBTCentralManager) *)self)->charMap;
|
||||
OSXBluetooth::DescHash &localDescMap = ((QT_MANGLE_NAMESPACE(OSXBTCentralManager) *)self)->descMap;
|
||||
OSXBluetooth::ValueHash &localValuesToWrite = ((QT_MANGLE_NAMESPACE(OSXBTCentralManager) *)self)->valuesToWrite;
|
||||
|
||||
// Verifica validità oggetto
|
||||
if (!obj) {
|
||||
qDebug() << "Error: Invalid object (nil)";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Safe access to private variables
|
||||
@try {
|
||||
// Safely access private variables through self
|
||||
QT_MANGLE_NAMESPACE(OSXBTCentralManager) *selfPtr = (QT_MANGLE_NAMESPACE(OSXBTCentralManager) *)self;
|
||||
if (!selfPtr) {
|
||||
qDebug() << "Error: Invalid self pointer";
|
||||
return false;
|
||||
}
|
||||
|
||||
OSXBluetooth::CharHash &localCharMap = selfPtr->charMap;
|
||||
OSXBluetooth::DescHash &localDescMap = selfPtr->descMap;
|
||||
OSXBluetooth::ValueHash &localValuesToWrite = selfPtr->valuesToWrite;
|
||||
|
||||
// Safely verify object type
|
||||
BOOL isCharacteristic = NO;
|
||||
BOOL isDescriptor = NO;
|
||||
|
||||
// Test with standard CoreBluetooth classes
|
||||
const char *className = class_getName(objClass);
|
||||
if (className) {
|
||||
isCharacteristic = strcmp(className, "CBCharacteristic") == 0;
|
||||
isDescriptor = strcmp(className, "CBDescriptor") == 0;
|
||||
|
||||
// Also check for subclasses
|
||||
if (!isCharacteristic && !isDescriptor) {
|
||||
Class charClass = NSClassFromString(@"CBCharacteristic");
|
||||
Class descClass = NSClassFromString(@"CBDescriptor");
|
||||
|
||||
if (charClass && class_conformsToProtocol(objClass, @protocol(NSObject))) {
|
||||
isCharacteristic = class_getSuperclass(objClass) == charClass;
|
||||
}
|
||||
|
||||
if (descClass && class_conformsToProtocol(objClass, @protocol(NSObject))) {
|
||||
isDescriptor = class_getSuperclass(objClass) == descClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify based on identified type
|
||||
if (isCharacteristic) {
|
||||
CBCharacteristic *ch = (CBCharacteristic *)obj;
|
||||
// Verify using only C functions to avoid Objective-C messages if possible
|
||||
// Verifica tipo oggetto
|
||||
if ([obj isKindOfClass:[CBCharacteristic class]]) {
|
||||
@try {
|
||||
CBCharacteristic *const ch = (CBCharacteristic *)obj;
|
||||
if (!localCharMap.key(ch)) {
|
||||
qDebug() << "Error: Unexpected characteristic, no handle found";
|
||||
return false;
|
||||
}
|
||||
} else if (isDescriptor) {
|
||||
CBDescriptor *d = (CBDescriptor *)obj;
|
||||
} @catch (NSException *e) {
|
||||
qDebug() << "Exception handling characteristic:" << e.reason;
|
||||
return false;
|
||||
}
|
||||
} else if ([obj isKindOfClass:[CBDescriptor class]]) {
|
||||
@try {
|
||||
CBDescriptor *const d = (CBDescriptor *)obj;
|
||||
if (!localDescMap.key(d)) {
|
||||
qDebug() << "Error: Unexpected descriptor, no handle found";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Error: Object is neither a characteristic nor a descriptor";
|
||||
} @catch (NSException *e) {
|
||||
qDebug() << "Exception handling descriptor:" << e.reason;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Existing cache management with protection
|
||||
} else {
|
||||
qDebug() << "Error: Invalid object type, characteristic or descriptor required";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gestione cache esistente
|
||||
@try {
|
||||
if (localValuesToWrite.contains(obj)) {
|
||||
qDebug() << "Warning: Already has a cached value for this object, the value will be replaced";
|
||||
}
|
||||
|
||||
// Safe assignment
|
||||
try {
|
||||
localValuesToWrite[obj] = value;
|
||||
} catch (const std::exception& e) {
|
||||
qDebug() << "C++ exception during cache operation:" << e.what();
|
||||
return false;
|
||||
} catch (...) {
|
||||
qDebug() << "Unknown C++ exception during cache operation";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
localValuesToWrite[obj] = value;
|
||||
} @catch (NSException *e) {
|
||||
qDebug() << "Objective-C exception in cacheWriteValue:" << e.reason;
|
||||
qDebug() << "Exception during cache operation:" << e.reason;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} @catch (NSException *e) {
|
||||
qDebug() << "Unexpected exception in cacheWriteValue:" << e.reason;
|
||||
return false;
|
||||
}
|
||||
|
||||
// This point should never be reached due to previous returns
|
||||
return false;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -73,7 +73,6 @@ bool run_cadence_sensor = false;
|
||||
bool horizon_treadmill_7_8 = false;
|
||||
bool horizon_treadmill_force_ftms = false;
|
||||
bool nordictrack_10_treadmill = false;
|
||||
bool gpiotreadmill = true;
|
||||
bool reebok_fr30_treadmill = false;
|
||||
bool zwift_play = false;
|
||||
bool zwift_click = false;
|
||||
@@ -291,8 +290,6 @@ QCoreApplication *createApplication(int &argc, char *argv[]) {
|
||||
horizon_treadmill_force_ftms = true;
|
||||
if (!qstrcmp(argv[i], "-nordictrack-10-treadmill"))
|
||||
nordictrack_10_treadmill = true;
|
||||
if (!qstrcmp(argv[i], "-gpiotreadmill"))
|
||||
gpiotreadmill = true;
|
||||
if (!qstrcmp(argv[i], "-reebok_fr30_treadmill"))
|
||||
reebok_fr30_treadmill = true;
|
||||
if (!qstrcmp(argv[i], "-zwift_play"))
|
||||
@@ -593,8 +590,6 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
#endif
|
||||
|
||||
settings.setValue(QStringLiteral("gpio_treadmill"), gpiotreadmill);
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::volume_change_gears, QZSettings::default_volume_change_gears).toBool()) {
|
||||
qDebug() << "handling volume keys";
|
||||
|
||||
@@ -844,7 +844,7 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
ItemDelegate {
|
||||
text: "version 2.18.22"
|
||||
text: "version 2.18.20"
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
@@ -878,9 +878,6 @@ ApplicationWindow {
|
||||
width: parent.width
|
||||
onClicked: {
|
||||
stackView.push("WebPelotonAuth.qml")
|
||||
stackView.currentItem.goBack.connect(function() {
|
||||
stackView.pop();
|
||||
})
|
||||
peloton_connect_clicked()
|
||||
drawer.close()
|
||||
}
|
||||
|
||||
111
src/peloton.cpp
111
src/peloton.cpp
@@ -10,13 +10,12 @@
|
||||
#include "homeform.h"
|
||||
#include "peloton.h"
|
||||
#include <chrono>
|
||||
#include <QTimer>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
const bool log_request = true;
|
||||
|
||||
#define RAWHEADER request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json"));request.setHeader(QNetworkRequest::UserAgentHeader, QStringLiteral("qdomyos-zwift"));request.setRawHeader(QByteArray("Authorization"), QByteArray("Bearer ") + getPelotonTokenForUser(QZSettings::peloton_accesstoken, userId, QZSettings::default_peloton_accesstoken).toString().toUtf8());
|
||||
#define RAWHEADER request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json"));request.setHeader(QNetworkRequest::UserAgentHeader, QStringLiteral("qdomyos-zwift"));request.setRawHeader(QByteArray("Authorization"), QByteArray("Bearer ") + settings.value(QZSettings::peloton_accesstoken, QZSettings::default_peloton_accesstoken).toString().toUtf8());
|
||||
|
||||
peloton::peloton(bluetooth *bl, QObject *parent) : QObject(parent) {
|
||||
|
||||
@@ -35,6 +34,13 @@ peloton::peloton(bluetooth *bl, QObject *parent) : QObject(parent) {
|
||||
"img_1646099287_a620f71b3d6740718457b21769a7ed46.png"));
|
||||
*/
|
||||
|
||||
if (!settings.value(QZSettings::peloton_accesstoken, QZSettings::default_peloton_accesstoken)
|
||||
.toString()
|
||||
.length()) {
|
||||
qDebug() << QStringLiteral("invalid peloton credentials");
|
||||
return;
|
||||
}
|
||||
|
||||
rower_pace_offset = 1;
|
||||
|
||||
rower_pace[0].value = -1;
|
||||
@@ -596,13 +602,6 @@ peloton::peloton(bluetooth *bl, QObject *parent) : QObject(parent) {
|
||||
connect(PZP, &powerzonepack::loginState, this, &peloton::pzp_loginState);
|
||||
connect(HFB, &homefitnessbuddy::workoutStarted, this, &peloton::hfb_trainrows);
|
||||
|
||||
if (!settings.value(QZSettings::peloton_accesstoken, QZSettings::default_peloton_accesstoken)
|
||||
.toString()
|
||||
.length()) {
|
||||
qDebug() << QStringLiteral("invalid peloton credentials");
|
||||
return;
|
||||
}
|
||||
|
||||
startEngine();
|
||||
}
|
||||
|
||||
@@ -641,7 +640,6 @@ void peloton::startEngine() {
|
||||
}
|
||||
|
||||
QSettings settings;
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
timer->stop();
|
||||
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::login_onfinish);
|
||||
|
||||
@@ -651,7 +649,7 @@ void peloton::startEngine() {
|
||||
|
||||
RAWHEADER
|
||||
|
||||
//qDebug() << getPelotonTokenForUser(QZSettings::peloton_accesstoken, userId, QZSettings::default_peloton_accesstoken).toString().toLatin1() << request.rawHeader(QByteArray("authorization"));
|
||||
qDebug() << settings.value(QZSettings::peloton_accesstoken, QZSettings::default_peloton_accesstoken).toString().toLatin1() << request.rawHeader(QByteArray("authorization"));
|
||||
|
||||
mgr->get(request);
|
||||
}
|
||||
@@ -670,13 +668,6 @@ void peloton::login_onfinish(QNetworkReply *reply) {
|
||||
} else {
|
||||
qDebug() << QStringLiteral("login_onfinish");
|
||||
}
|
||||
|
||||
// Check if document is empty, and if so, retry after 5 seconds
|
||||
if (document.isEmpty()) {
|
||||
qDebug() << QStringLiteral("login_onfinish: Empty document received, retrying in 5 seconds");
|
||||
QTimer::singleShot(5000, this, &peloton::startEngine);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
|
||||
@@ -690,16 +681,6 @@ void peloton::login_onfinish(QNetworkReply *reply) {
|
||||
user_id = document[QStringLiteral("id")].toString();
|
||||
total_workout = document[QStringLiteral("total_workouts")].toInt();
|
||||
|
||||
QSettings settings;
|
||||
// if it's a new user
|
||||
if(user_id.compare(settings.value(QZSettings::peloton_current_user_id, QZSettings::default_peloton_current_user_id).toString())) {
|
||||
qDebug() << "new peloton user id, saving information...";
|
||||
settings.setValue(QZSettings::peloton_current_user_id, user_id);
|
||||
settings.setValue(getPelotonSettingKey(QZSettings::peloton_refreshtoken, user_id), settings.value(QZSettings::peloton_refreshtoken, QZSettings::default_peloton_refreshtoken).toString());
|
||||
settings.setValue(getPelotonSettingKey(QZSettings::peloton_accesstoken, user_id), settings.value(QZSettings::peloton_accesstoken, QZSettings::default_peloton_accesstoken).toString());
|
||||
}
|
||||
|
||||
|
||||
qDebug() << "user_id" << user_id << "total workout" << total_workout;
|
||||
|
||||
emit loginState(!user_id.isEmpty());
|
||||
@@ -777,8 +758,6 @@ void peloton::summary_onfinish(QNetworkReply *reply) {
|
||||
qDebug() << QStringLiteral("peloton::summary_onfinish");
|
||||
}
|
||||
|
||||
workout_retry_count = 0;
|
||||
|
||||
getWorkout(current_workout_id);
|
||||
}
|
||||
|
||||
@@ -834,20 +813,6 @@ void peloton::workout_onfinish(QNetworkReply *reply) {
|
||||
QByteArray payload = reply->readAll(); // JSON
|
||||
QJsonParseError parseError;
|
||||
workout = QJsonDocument::fromJson(payload, &parseError);
|
||||
|
||||
if (workout.isNull() && workout_retry_count < 3) {
|
||||
workout_retry_count++;
|
||||
qDebug() << "Empty JSON document received, retry attempt" << workout_retry_count;
|
||||
QTimer::singleShot(2000, this, [this]() {
|
||||
getWorkout(current_workout_id);
|
||||
});
|
||||
return;
|
||||
} else if (workout.isNull() && workout_retry_count >= 3) {
|
||||
if(homeform::singleton())
|
||||
homeform::singleton()->setToastRequested("Error: Failed to load workout data after 3 attempts");
|
||||
}
|
||||
workout_retry_count = 0;
|
||||
|
||||
QJsonObject ride = workout.object()[QStringLiteral("ride")].toObject();
|
||||
current_workout_name = ride[QStringLiteral("title")].toString();
|
||||
current_instructor_id = ride[QStringLiteral("instructor_id")].toString();
|
||||
@@ -1297,14 +1262,9 @@ void peloton::ride_onfinish(QNetworkReply *reply) {
|
||||
QJsonArray metrics = segmentObj["metrics"].toArray();
|
||||
QJsonObject offsets = segmentObj["offsets"].toObject();
|
||||
QString segment_type = segmentObj["segment_type"].toString();
|
||||
bool floorSegment = false;
|
||||
|
||||
if(segment_type.startsWith("floor")) { // bootcamp
|
||||
floorSegment = true;
|
||||
}
|
||||
|
||||
// Skip if no metrics or invalid offsets
|
||||
if ((metrics.isEmpty() || offsets.isEmpty()) && !floorSegment)
|
||||
if (metrics.isEmpty() || offsets.isEmpty())
|
||||
continue;
|
||||
|
||||
double speed_lower = -1;
|
||||
@@ -1887,7 +1847,6 @@ double peloton::rowerpaceToSpeed(double pace) {
|
||||
|
||||
void peloton::getInstructor(const QString &instructor_id) {
|
||||
QSettings settings;
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::instructor_onfinish);
|
||||
|
||||
QUrl url(QStringLiteral("https://api-3p.onepeloton.com/api/v1/instructor/") + instructor_id);
|
||||
@@ -1901,7 +1860,6 @@ void peloton::getInstructor(const QString &instructor_id) {
|
||||
|
||||
void peloton::getRide(const QString &ride_id) {
|
||||
QSettings settings;
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::ride_onfinish);
|
||||
|
||||
QUrl url(QStringLiteral("https://api-3p.onepeloton.com/api/v1/ride/") + ride_id +
|
||||
@@ -1916,7 +1874,6 @@ void peloton::getRide(const QString &ride_id) {
|
||||
|
||||
void peloton::getPerformance(const QString &workout) {
|
||||
QSettings settings;
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::performance_onfinish);
|
||||
|
||||
QUrl url(QStringLiteral("https://api-3p.onepeloton.com/api/v1/workout/") + workout +
|
||||
@@ -1931,7 +1888,6 @@ void peloton::getPerformance(const QString &workout) {
|
||||
|
||||
void peloton::getWorkout(const QString &workout) {
|
||||
QSettings settings;
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::workout_onfinish);
|
||||
|
||||
QUrl url(QStringLiteral("https://api-3p.onepeloton.com/api/v1/workout/") + workout);
|
||||
@@ -1945,7 +1901,6 @@ void peloton::getWorkout(const QString &workout) {
|
||||
|
||||
void peloton::getSummary(const QString &workout) {
|
||||
QSettings settings;
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::summary_onfinish);
|
||||
|
||||
QUrl url(QStringLiteral("https://api-3p.onepeloton.com/api/v1/workout/") + workout + QStringLiteral("/summary"));
|
||||
@@ -1960,7 +1915,6 @@ void peloton::getSummary(const QString &workout) {
|
||||
void peloton::getWorkoutList(int num) {
|
||||
Q_UNUSED(num)
|
||||
QSettings settings;
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
// if (num == 0) { //NOTE: clang-analyzer-deadcode.DeadStores
|
||||
// num = this->total_workout;
|
||||
// }
|
||||
@@ -1991,16 +1945,13 @@ void peloton::onPelotonGranted() {
|
||||
pelotonAuthWebVisible = false;
|
||||
emit pelotonWebVisibleChanged(pelotonAuthWebVisible);
|
||||
QSettings settings;
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
savePelotonTokenForUser(QZSettings::peloton_accesstoken, pelotonOAuth->token(), userId);
|
||||
savePelotonTokenForUser(QZSettings::peloton_refreshtoken, pelotonOAuth->refreshToken(), userId);
|
||||
savePelotonTokenForUser(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime(), userId);
|
||||
settings.setValue(QZSettings::peloton_accesstoken, pelotonOAuth->token());
|
||||
settings.setValue(QZSettings::peloton_refreshtoken, pelotonOAuth->refreshToken());
|
||||
settings.setValue(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime());
|
||||
qDebug() << QStringLiteral("peloton authenticathed") << pelotonOAuth->token() << pelotonOAuth->refreshToken();
|
||||
peloton_refreshtoken();
|
||||
if(homeform::singleton())
|
||||
homeform::singleton()->setPelotonPopupVisible(true);
|
||||
if(!timer->isActive())
|
||||
startEngine();
|
||||
}
|
||||
|
||||
void peloton::onPelotonAuthorizeWithBrowser(const QUrl &url) {
|
||||
@@ -2030,12 +1981,11 @@ void peloton::replyDataReceived(const QByteArray &v) {
|
||||
|
||||
QByteArray data;
|
||||
QSettings settings;
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
QString s(v);
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(s.toUtf8());
|
||||
savePelotonTokenForUser(QZSettings::peloton_accesstoken, jsonResponse[QStringLiteral("access_token")], userId);
|
||||
savePelotonTokenForUser(QZSettings::peloton_refreshtoken, jsonResponse[QStringLiteral("refresh_token")], userId);
|
||||
savePelotonTokenForUser(QZSettings::peloton_expires, jsonResponse[QStringLiteral("expires_at")], userId);
|
||||
settings.setValue(QZSettings::peloton_accesstoken, jsonResponse[QStringLiteral("access_token")]);
|
||||
settings.setValue(QZSettings::peloton_refreshtoken, jsonResponse[QStringLiteral("refresh_token")]);
|
||||
settings.setValue(QZSettings::peloton_expires, jsonResponse[QStringLiteral("expires_at")]);
|
||||
|
||||
qDebug() << jsonResponse[QStringLiteral("access_token")] << jsonResponse[QStringLiteral("refresh_token")]
|
||||
<< jsonResponse[QStringLiteral("expires_at")];
|
||||
@@ -2080,7 +2030,6 @@ void peloton::onSslErrors(QNetworkReply *reply, const QList<QSslError> &error) {
|
||||
void peloton::networkRequestFinished(QNetworkReply *reply) {
|
||||
|
||||
QSettings settings;
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
|
||||
// we can handle SSL handshake errors, if we got here then some kind of protocol was agreed
|
||||
if (reply->error() == QNetworkReply::NoError || reply->error() == QNetworkReply::SslHandshakeFailedError) {
|
||||
@@ -2098,9 +2047,9 @@ void peloton::networkRequestFinished(QNetworkReply *reply) {
|
||||
access_token = document[QStringLiteral("access_token")].toString();
|
||||
}
|
||||
|
||||
savePelotonTokenForUser(QZSettings::peloton_accesstoken, access_token, userId);
|
||||
savePelotonTokenForUser(QZSettings::peloton_refreshtoken, refresh_token, userId);
|
||||
savePelotonTokenForUser(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime(), userId);
|
||||
settings.setValue(QZSettings::peloton_accesstoken, access_token);
|
||||
settings.setValue(QZSettings::peloton_refreshtoken, refresh_token);
|
||||
settings.setValue(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime());
|
||||
|
||||
qDebug() << access_token << refresh_token;
|
||||
|
||||
@@ -2191,14 +2140,10 @@ void peloton::peloton_refreshtoken() {
|
||||
QSettings settings;
|
||||
// QUrlQuery params; //NOTE: clazy-unuse-non-tirial-variable
|
||||
|
||||
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
|
||||
if (settings.value(QZSettings::peloton_refreshtoken).toString().isEmpty()) {
|
||||
|
||||
// If no user is logged in yet, just use the regular method
|
||||
if (userId.isEmpty()) {
|
||||
if (settings.value(QZSettings::peloton_refreshtoken).toString().isEmpty()) {
|
||||
peloton_connect();
|
||||
return;
|
||||
}
|
||||
peloton_connect();
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest request(QUrl(QStringLiteral("https://auth.onepeloton.com/oauth/token?")));
|
||||
@@ -2207,7 +2152,7 @@ void peloton::peloton_refreshtoken() {
|
||||
// set params
|
||||
QString data;
|
||||
data += QStringLiteral("client_id=" PELOTON_CLIENT_ID_S);
|
||||
data += QStringLiteral("&refresh_token=") + getPelotonTokenForUser(QZSettings::peloton_refreshtoken, userId).toString();
|
||||
data += QStringLiteral("&refresh_token=") + settings.value(QZSettings::peloton_refreshtoken).toString();
|
||||
data += QStringLiteral("&grant_type=refresh_token");
|
||||
|
||||
// make request
|
||||
@@ -2229,8 +2174,7 @@ void peloton::peloton_refreshtoken() {
|
||||
|
||||
// oops, no dice
|
||||
if (reply->error() != 0) {
|
||||
homeform::singleton()->setToastRequested("Peloton Auth Failed!");
|
||||
qDebug() << QStringLiteral("Got error") << reply->errorString().toStdString().c_str();
|
||||
qDebug() << QStringLiteral("Got error") << reply->errorString().toStdString().c_str();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2249,10 +2193,9 @@ void peloton::peloton_refreshtoken() {
|
||||
QString access_token = document[QStringLiteral("access_token")].toString();
|
||||
QString refresh_token = document[QStringLiteral("refresh_token")].toString();
|
||||
|
||||
qDebug() << "userid: " << userId;
|
||||
savePelotonTokenForUser(QZSettings::peloton_accesstoken, access_token, userId);
|
||||
savePelotonTokenForUser(QZSettings::peloton_refreshtoken, refresh_token, userId);
|
||||
savePelotonTokenForUser(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime(), userId);
|
||||
settings.setValue(QZSettings::peloton_accesstoken, access_token);
|
||||
settings.setValue(QZSettings::peloton_refreshtoken, refresh_token);
|
||||
settings.setValue(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime());
|
||||
|
||||
homeform::singleton()->setToastRequested("Peloton Login OK!");
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ class peloton : public QObject {
|
||||
private:
|
||||
_PELOTON_API current_api = peloton_api;
|
||||
const int peloton_workout_second_resolution = 1;
|
||||
int workout_retry_count = 0;
|
||||
bool peloton_credentials_wrong = false;
|
||||
QNetworkAccessManager *mgr = nullptr;
|
||||
|
||||
@@ -108,22 +107,6 @@ class peloton : public QObject {
|
||||
QNetworkReply *replyPeloton;
|
||||
QAbstractOAuth::ModifyParametersFunction buildModifyParametersFunction(const QUrl &clientIdentifier,
|
||||
const QUrl &clientIdentifierSharedKey);
|
||||
// Save token with user-specific suffix
|
||||
QString getPelotonSettingKey(const QString& baseKey, const QString& userId) {
|
||||
if (userId.isEmpty()) {
|
||||
qDebug() << "ERROR: userid is empty!";
|
||||
return baseKey; // If no user ID, use the default key
|
||||
}
|
||||
return baseKey + "_" + userId;
|
||||
}
|
||||
void savePelotonTokenForUser(const QString& baseKey, const QVariant& value, const QString& userId) {
|
||||
QSettings settings;
|
||||
settings.setValue(getPelotonSettingKey(baseKey, userId), value);
|
||||
}
|
||||
QVariant getPelotonTokenForUser(const QString& baseKey, const QString& userId, const QVariant& defaultValue = "") {
|
||||
QSettings settings;
|
||||
return settings.value(getPelotonSettingKey(baseKey, userId), defaultValue).toString();
|
||||
}
|
||||
|
||||
// rowers
|
||||
double rowerpaceToSpeed(double pace);
|
||||
|
||||
@@ -3,9 +3,6 @@ QT += bluetooth widgets xml positioning quick networkauth websockets texttospeec
|
||||
QTPLUGIN += qavfmediaplayer
|
||||
QT+= charts core-private
|
||||
|
||||
win32: QT += serialport serialbus
|
||||
linux:!android: QT += serialport serialbus
|
||||
|
||||
qtHaveModule(httpserver) {
|
||||
QT += httpserver
|
||||
DEFINES += Q_HTTPSERVER
|
||||
@@ -324,10 +321,6 @@ zwiftworkout.cpp
|
||||
macx: SOURCES += macos/lockscreen.mm
|
||||
!ios: SOURCES += mainwindow.cpp charts.cpp
|
||||
|
||||
#gpio treadmill
|
||||
win32: SOURCES += gpiotreadmill.cpp
|
||||
linux:!android: SOURCES += gpiotreadmill.cpp
|
||||
|
||||
#zwift api
|
||||
msvc {
|
||||
SOURCES += zwift-api/zwift_messages.pb.cc
|
||||
@@ -826,9 +819,6 @@ windows_zwift_incline_paddleocr_thread.h \
|
||||
zwiftworkout.h
|
||||
|
||||
|
||||
win32: HEADERS += gpiotreadmill.h
|
||||
linux:!android: HEADERS += gpiotreadmill.h
|
||||
|
||||
exists(secret.h): HEADERS += secret.h
|
||||
|
||||
!ios: HEADERS += charts.h
|
||||
@@ -965,4 +955,4 @@ INCLUDEPATH += purchasing/inapp
|
||||
|
||||
WINRT_MANIFEST = AppxManifest.xml
|
||||
|
||||
VERSION = 2.18.22
|
||||
VERSION = 2.18.20
|
||||
|
||||
@@ -887,27 +887,8 @@ const QString QZSettings::real_inclination_to_virtual_treamill_bridge = QStringL
|
||||
const QString QZSettings::stryd_inclination_instead_treadmill = QStringLiteral("stryd_inclination_instead_treadmill");
|
||||
const QString QZSettings::domyos_elliptical_fmts = QStringLiteral("domyos_elliptical_fmts");
|
||||
const QString QZSettings::proform_xbike = QStringLiteral("proform_xbike");
|
||||
const QString QZSettings::peloton_current_user_id = QStringLiteral("peloton_current_user_id");
|
||||
const QString QZSettings::default_peloton_current_user_id = QStringLiteral("");
|
||||
const QString QZSettings::proform_225_csx_PFEX32925_INT_0 = QStringLiteral("proform_225_csx_PFEX32925_INT_0");
|
||||
const QString QZSettings::trainprogram_pid_ignore_inclination = QStringLiteral("trainprogram_pid_ignore_inclination");
|
||||
|
||||
const QString QZSettings::tile_hr_time_in_zone_1_enabled = QStringLiteral("tile_hr_time_in_zone_1_enabled");
|
||||
const QString QZSettings::tile_hr_time_in_zone_1_order = QStringLiteral("tile_hr_time_in_zone_1_order");
|
||||
|
||||
const QString QZSettings::tile_hr_time_in_zone_2_enabled = QStringLiteral("tile_hr_time_in_zone_2_enabled");
|
||||
const QString QZSettings::tile_hr_time_in_zone_2_order = QStringLiteral("tile_hr_time_in_zone_2_order");
|
||||
|
||||
const QString QZSettings::tile_hr_time_in_zone_3_enabled = QStringLiteral("tile_hr_time_in_zone_3_enabled");
|
||||
const QString QZSettings::tile_hr_time_in_zone_3_order = QStringLiteral("tile_hr_time_in_zone_3_order");
|
||||
|
||||
const QString QZSettings::tile_hr_time_in_zone_4_enabled = QStringLiteral("tile_hr_time_in_zone_4_enabled");
|
||||
const QString QZSettings::tile_hr_time_in_zone_4_order = QStringLiteral("tile_hr_time_in_zone_4_order");
|
||||
|
||||
const QString QZSettings::tile_hr_time_in_zone_5_enabled = QStringLiteral("tile_hr_time_in_zone_5_enabled");
|
||||
const QString QZSettings::tile_hr_time_in_zone_5_order = QStringLiteral("tile_hr_time_in_zone_5_order");
|
||||
|
||||
const uint32_t allSettingsCount = 746;
|
||||
const uint32_t allSettingsCount = 733;
|
||||
|
||||
QVariant allSettings[allSettingsCount][2] = {
|
||||
{QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles},
|
||||
@@ -1655,20 +1636,6 @@ QVariant allSettings[allSettingsCount][2] = {
|
||||
{QZSettings::stryd_inclination_instead_treadmill, QZSettings::default_stryd_inclination_instead_treadmill},
|
||||
{QZSettings::domyos_elliptical_fmts, QZSettings::default_domyos_elliptical_fmts},
|
||||
{QZSettings::proform_xbike, QZSettings::default_proform_xbike},
|
||||
{QZSettings::peloton_current_user_id, QZSettings::default_peloton_current_user_id},
|
||||
{QZSettings::proform_225_csx_PFEX32925_INT_0, QZSettings::proform_225_csx_PFEX32925_INT_0},
|
||||
{QZSettings::trainprogram_pid_ignore_inclination, QZSettings::default_trainprogram_pid_ignore_inclination},
|
||||
|
||||
{QZSettings::tile_hr_time_in_zone_1_enabled, QZSettings::default_tile_hr_time_in_zone_1_enabled},
|
||||
{QZSettings::tile_hr_time_in_zone_1_order, QZSettings::default_tile_hr_time_in_zone_1_order},
|
||||
{QZSettings::tile_hr_time_in_zone_2_enabled, QZSettings::default_tile_hr_time_in_zone_2_enabled},
|
||||
{QZSettings::tile_hr_time_in_zone_2_order, QZSettings::default_tile_hr_time_in_zone_2_order},
|
||||
{QZSettings::tile_hr_time_in_zone_3_enabled, QZSettings::default_tile_hr_time_in_zone_3_enabled},
|
||||
{QZSettings::tile_hr_time_in_zone_3_order, QZSettings::default_tile_hr_time_in_zone_3_order},
|
||||
{QZSettings::tile_hr_time_in_zone_4_enabled, QZSettings::default_tile_hr_time_in_zone_4_enabled},
|
||||
{QZSettings::tile_hr_time_in_zone_4_order, QZSettings::default_tile_hr_time_in_zone_4_order},
|
||||
{QZSettings::tile_hr_time_in_zone_5_enabled, QZSettings::default_tile_hr_time_in_zone_5_enabled},
|
||||
{QZSettings::tile_hr_time_in_zone_5_order, QZSettings::default_tile_hr_time_in_zone_5_order},
|
||||
};
|
||||
|
||||
void QZSettings::qDebugAllSettings(bool showDefaults) {
|
||||
|
||||
@@ -2399,43 +2399,6 @@ class QZSettings {
|
||||
static const QString proform_xbike;
|
||||
static constexpr bool default_proform_xbike = false;
|
||||
|
||||
static const QString peloton_current_user_id;
|
||||
static const QString default_peloton_current_user_id;
|
||||
static const QString proform_225_csx_PFEX32925_INT_0;
|
||||
static constexpr bool default_proform_225_csx_PFEX32925_INT_0 = false;
|
||||
static const QString trainprogram_pid_ignore_inclination;
|
||||
static constexpr bool default_trainprogram_pid_ignore_inclination = false;
|
||||
|
||||
static const QString tile_hr_time_in_zone_1_enabled;
|
||||
static constexpr bool default_tile_hr_time_in_zone_1_enabled = false;
|
||||
|
||||
static const QString tile_hr_time_in_zone_1_order;
|
||||
static constexpr int default_tile_hr_time_in_zone_1_order = 62;
|
||||
|
||||
static const QString tile_hr_time_in_zone_2_enabled;
|
||||
static constexpr bool default_tile_hr_time_in_zone_2_enabled = false;
|
||||
|
||||
static const QString tile_hr_time_in_zone_2_order;
|
||||
static constexpr int default_tile_hr_time_in_zone_2_order = 63;
|
||||
|
||||
static const QString tile_hr_time_in_zone_3_enabled;
|
||||
static constexpr bool default_tile_hr_time_in_zone_3_enabled = false;
|
||||
|
||||
static const QString tile_hr_time_in_zone_3_order;
|
||||
static constexpr int default_tile_hr_time_in_zone_3_order = 64;
|
||||
|
||||
static const QString tile_hr_time_in_zone_4_enabled;
|
||||
static constexpr bool default_tile_hr_time_in_zone_4_enabled = false;
|
||||
|
||||
static const QString tile_hr_time_in_zone_4_order;
|
||||
static constexpr int default_tile_hr_time_in_zone_4_order = 65;
|
||||
|
||||
static const QString tile_hr_time_in_zone_5_enabled;
|
||||
static constexpr bool default_tile_hr_time_in_zone_5_enabled = false;
|
||||
|
||||
static const QString tile_hr_time_in_zone_5_order;
|
||||
static constexpr int default_tile_hr_time_in_zone_5_order = 66;
|
||||
|
||||
/**
|
||||
* @brief Write the QSettings values using the constants from this namespace.
|
||||
* @param showDefaults Optionally indicates if the default should be shown with the key.
|
||||
|
||||
@@ -238,17 +238,6 @@ ScrollView {
|
||||
property real tile_preset_powerzone_7_value: 7.0
|
||||
property string tile_preset_powerzone_7_label: "Zone 7"
|
||||
property string tile_preset_powerzone_7_color: "red"
|
||||
|
||||
property bool tile_hr_time_in_zone_1_enabled: false
|
||||
property int tile_hr_time_in_zone_1_order: 62
|
||||
property bool tile_hr_time_in_zone_2_enabled: false
|
||||
property int tile_hr_time_in_zone_2_order: 63
|
||||
property bool tile_hr_time_in_zone_3_enabled: false
|
||||
property int tile_hr_time_in_zone_3_order: 64
|
||||
property bool tile_hr_time_in_zone_4_enabled: false
|
||||
property int tile_hr_time_in_zone_4_order: 65
|
||||
property bool tile_hr_time_in_zone_5_enabled: false
|
||||
property int tile_hr_time_in_zone_5_order: 66
|
||||
}
|
||||
|
||||
|
||||
@@ -4782,230 +4771,5 @@ ScrollView {
|
||||
Layout.fillWidth: true
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
AccordionCheckElement {
|
||||
id: hrTimeInZone1EnabledAccordion
|
||||
title: qsTr("Heart Rate Time in Zone 1+")
|
||||
linkedBoolSetting: "tile_hr_time_in_zone_1_enabled"
|
||||
settings: settings
|
||||
accordionContent: RowLayout {
|
||||
spacing: 10
|
||||
Label {
|
||||
id: labelHrTimeInZone1Order
|
||||
text: qsTr("order index:")
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
ComboBox {
|
||||
id: hrTimeInZone1OrderTextField
|
||||
model: rootItem.tile_order
|
||||
displayText: settings.tile_hr_time_in_zone_1_order
|
||||
Layout.fillHeight: false
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onActivated: {
|
||||
displayText = hrTimeInZone1OrderTextField.currentValue
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: okHrTimeInZone1OrderButton
|
||||
text: "OK"
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onClicked: {settings.tile_hr_time_in_zone_1_order = hrTimeInZone1OrderTextField.displayText; toast.show("Setting saved!"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Displays total time spent in heart rate Zone 1 or higher during the session.")
|
||||
font.bold: true
|
||||
font.italic: true
|
||||
font.pixelSize: Qt.application.font.pixelSize - 2
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
AccordionCheckElement {
|
||||
id: hrTimeInZone2EnabledAccordion
|
||||
title: qsTr("Heart Rate Time in Zone 2+")
|
||||
linkedBoolSetting: "tile_hr_time_in_zone_2_enabled"
|
||||
settings: settings
|
||||
accordionContent: RowLayout {
|
||||
spacing: 10
|
||||
Label {
|
||||
id: labelHrTimeInZone2Order
|
||||
text: qsTr("order index:")
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
ComboBox {
|
||||
id: hrTimeInZone2OrderTextField
|
||||
model: rootItem.tile_order
|
||||
displayText: settings.tile_hr_time_in_zone_2_order
|
||||
Layout.fillHeight: false
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onActivated: {
|
||||
displayText = hrTimeInZone2OrderTextField.currentValue
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: okHrTimeInZone2OrderButton
|
||||
text: "OK"
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onClicked: {settings.tile_hr_time_in_zone_2_order = hrTimeInZone2OrderTextField.displayText; toast.show("Setting saved!"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Displays total time spent in heart rate Zone 2 or higher during the session.")
|
||||
font.bold: true
|
||||
font.italic: true
|
||||
font.pixelSize: Qt.application.font.pixelSize - 2
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
AccordionCheckElement {
|
||||
id: hrTimeInZone3EnabledAccordion
|
||||
title: qsTr("Heart Rate Time in Zone 3+")
|
||||
linkedBoolSetting: "tile_hr_time_in_zone_3_enabled"
|
||||
settings: settings
|
||||
accordionContent: RowLayout {
|
||||
spacing: 10
|
||||
Label {
|
||||
id: labelHrTimeInZone3Order
|
||||
text: qsTr("order index:")
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
ComboBox {
|
||||
id: hrTimeInZone3OrderTextField
|
||||
model: rootItem.tile_order
|
||||
displayText: settings.tile_hr_time_in_zone_3_order
|
||||
Layout.fillHeight: false
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onActivated: {
|
||||
displayText = hrTimeInZone3OrderTextField.currentValue
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: okHrTimeInZone3OrderButton
|
||||
text: "OK"
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onClicked: {settings.tile_hr_time_in_zone_3_order = hrTimeInZone3OrderTextField.displayText; toast.show("Setting saved!"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Displays total time spent in heart rate Zone 3 or higher during the session.")
|
||||
font.bold: true
|
||||
font.italic: true
|
||||
font.pixelSize: Qt.application.font.pixelSize - 2
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
AccordionCheckElement {
|
||||
id: hrTimeInZone4EnabledAccordion
|
||||
title: qsTr("Heart Rate Time in Zone 4+")
|
||||
linkedBoolSetting: "tile_hr_time_in_zone_4_enabled"
|
||||
settings: settings
|
||||
accordionContent: RowLayout {
|
||||
spacing: 10
|
||||
Label {
|
||||
id: labelHrTimeInZone4Order
|
||||
text: qsTr("order index:")
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
ComboBox {
|
||||
id: hrTimeInZone4OrderTextField
|
||||
model: rootItem.tile_order
|
||||
displayText: settings.tile_hr_time_in_zone_4_order
|
||||
Layout.fillHeight: false
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onActivated: {
|
||||
displayText = hrTimeInZone4OrderTextField.currentValue
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: okHrTimeInZone4OrderButton
|
||||
text: "OK"
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onClicked: {settings.tile_hr_time_in_zone_4_order = hrTimeInZone4OrderTextField.displayText; toast.show("Setting saved!"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Displays total time spent in heart rate Zone 4 or higher during the session.")
|
||||
font.bold: true
|
||||
font.italic: true
|
||||
font.pixelSize: Qt.application.font.pixelSize - 2
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
AccordionCheckElement {
|
||||
id: hrTimeInZone5EnabledAccordion
|
||||
title: qsTr("Heart Rate Time in Zone 5+")
|
||||
linkedBoolSetting: "tile_hr_time_in_zone_5_enabled"
|
||||
settings: settings
|
||||
accordionContent: RowLayout {
|
||||
spacing: 10
|
||||
Label {
|
||||
id: labelHrTimeInZone5Order
|
||||
text: qsTr("order index:")
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
ComboBox {
|
||||
id: hrTimeInZone5OrderTextField
|
||||
model: rootItem.tile_order
|
||||
displayText: settings.tile_hr_time_in_zone_5_order
|
||||
Layout.fillHeight: false
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onActivated: {
|
||||
displayText = hrTimeInZone5OrderTextField.currentValue
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: okHrTimeInZone5OrderButton
|
||||
text: "OK"
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onClicked: {settings.tile_hr_time_in_zone_5_order = hrTimeInZone5OrderTextField.displayText; toast.show("Setting saved!"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Displays total time spent in heart rate Zone 5 or higher during the session.")
|
||||
font.bold: true
|
||||
font.italic: true
|
||||
font.pixelSize: Qt.application.font.pixelSize - 2
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1111,22 +1111,7 @@ import Qt.labs.platform 1.1
|
||||
|
||||
// 2.18.20
|
||||
property bool domyos_elliptical_fmts: false
|
||||
property bool proform_xbike: false
|
||||
property bool proform_225_csx_PFEX32925_INT_0: false
|
||||
property string peloton_current_user_id: ""
|
||||
|
||||
// 2.18.22
|
||||
property bool trainprogram_pid_ignore_inclination: false
|
||||
property bool tile_hr_time_in_zone_1_enabled: false
|
||||
property int tile_hr_time_in_zone_1_order: 62
|
||||
property bool tile_hr_time_in_zone_2_enabled: false
|
||||
property int tile_hr_time_in_zone_2_order: 63
|
||||
property bool tile_hr_time_in_zone_3_enabled: false
|
||||
property int tile_hr_time_in_zone_3_order: 64
|
||||
property bool tile_hr_time_in_zone_4_enabled: false
|
||||
property int tile_hr_time_in_zone_4_order: 65
|
||||
property bool tile_hr_time_in_zone_5_enabled: false
|
||||
property int tile_hr_time_in_zone_5_order: 66
|
||||
property bool proform_xbike: false
|
||||
}
|
||||
|
||||
function paddingZeros(text, limit) {
|
||||
@@ -3375,8 +3360,7 @@ import Qt.labs.platform 1.1
|
||||
"Proform SB",
|
||||
"Nordictrack GX 4.4 Pro",
|
||||
"TDF 1.0 PFEVEX71316.0",
|
||||
"Proform XBike",
|
||||
"Proform 225 CSX PFEX32925 INT.0"
|
||||
"Proform XBike"
|
||||
]
|
||||
|
||||
// Initialize when the accordion content becomes visible
|
||||
@@ -3410,8 +3394,7 @@ import Qt.labs.platform 1.1
|
||||
settings.proform_bike_sb ? 14 :
|
||||
settings.nordictrack_gx_44_pro ? 15 :
|
||||
settings.proform_bike_PFEVEX71316_0 ? 16 :
|
||||
settings.proform_xbike ? 17 :
|
||||
settings.proform_225_csx_PFEX32925_INT_0 ? 18 : 0;
|
||||
settings.proform_xbike ? 17 : 0;
|
||||
|
||||
console.log("bikeModelComboBox selected model: " + selectedModel);
|
||||
if (selectedModel >= 0) {
|
||||
@@ -3443,7 +3426,6 @@ import Qt.labs.platform 1.1
|
||||
settings.nordictrack_gx_44_pro = false;
|
||||
settings.proform_bike_PFEVEX71316_0 = false;
|
||||
settings.proform_xbike = false;
|
||||
settings.proform_225_csx_PFEX32925_INT_0 = false;
|
||||
|
||||
// Set corresponding setting for selected model
|
||||
switch (currentIndex) {
|
||||
@@ -3464,7 +3446,6 @@ import Qt.labs.platform 1.1
|
||||
case 15: settings.nordictrack_gx_44_pro = true; break;
|
||||
case 16: settings.proform_bike_PFEVEX71316_0 = true; break;
|
||||
case 17: settings.proform_xbike = true; break;
|
||||
case 18: settings.proform_225_csx_PFEX32925_INT_0 = true; break;
|
||||
}
|
||||
|
||||
window.settings_restart_to_apply = true;
|
||||
@@ -5580,33 +5561,6 @@ import Qt.labs.platform 1.1
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
IndicatorOnlySwitch {
|
||||
text: qsTr("PID Ignore Inclination")
|
||||
spacing: 0
|
||||
bottomPadding: 0
|
||||
topPadding: 0
|
||||
rightPadding: 0
|
||||
leftPadding: 0
|
||||
clip: false
|
||||
checked: settings.trainprogram_pid_ignore_inclination
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
onClicked: settings.trainprogram_pid_ignore_inclination = checked
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Enabling this the PID will ignore the inclination changes. Default: Disabled.")
|
||||
font.bold: true
|
||||
font.italic: true
|
||||
font.pixelSize: Qt.application.font.pixelSize - 2
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Label {
|
||||
@@ -11652,23 +11606,11 @@ import Qt.labs.platform 1.1
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Button {
|
||||
id: clearLogs
|
||||
text: "Clear History"
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||
onClicked: rootItem.clearFiles();
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Show Logs Folder"
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onClicked: {
|
||||
toast.show(rootItem.getProfileDir())
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: clearLogs
|
||||
text: "Clear History"
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onClicked: rootItem.clearFiles();
|
||||
}
|
||||
|
||||
Label {
|
||||
|
||||
@@ -586,6 +586,17 @@ void trainprogram::scheduler() {
|
||||
|
||||
QMutexLocker(&this->schedulerMutex);
|
||||
QSettings settings;
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
qint64 msecsElapsed = lastSchedulerCall.msecsTo(now);
|
||||
|
||||
// Reset jitter if it's getting too large
|
||||
if (qAbs(currentTimerJitter) > 5000) {
|
||||
currentTimerJitter = 0;
|
||||
}
|
||||
|
||||
currentTimerJitter += msecsElapsed - 1000;
|
||||
lastSchedulerCall = now;
|
||||
|
||||
// outside the if case about a valid train program because the information for the floating window url should be
|
||||
// sent anyway
|
||||
if (settings.value(QZSettings::peloton_companion_workout_ocr, QZSettings::default_companion_peloton_workout_ocr)
|
||||
@@ -811,6 +822,7 @@ void trainprogram::scheduler() {
|
||||
#endif
|
||||
}
|
||||
|
||||
currentTimerJitter = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -832,6 +844,20 @@ void trainprogram::scheduler() {
|
||||
#endif
|
||||
|
||||
ticks++;
|
||||
qDebug() << QStringLiteral("trainprogram ticks") << ticks << QStringLiteral("currentTimerJitter") << currentTimerJitter;
|
||||
|
||||
if(qAbs(currentTimerJitter) > 1000) {
|
||||
// we are late...
|
||||
if (currentTimerJitter > 1000) {
|
||||
int seconds = currentTimerJitter / 1000;
|
||||
ticks += seconds;
|
||||
currentTimerJitter -= (seconds * 1000);
|
||||
qDebug() << QStringLiteral("fixing jitter!") << seconds << ticks << currentTimerJitter;
|
||||
} else {
|
||||
// negative jitter, reset the counter without touching the ticks
|
||||
currentTimerJitter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
double odometerFromTheDevice = bluetoothManager->device()->odometer();
|
||||
|
||||
@@ -1270,6 +1296,7 @@ void trainprogram::restart() {
|
||||
ticks = 0;
|
||||
offset = 0;
|
||||
currentStep = 0;
|
||||
currentTimerJitter = 0;
|
||||
started = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -168,6 +168,9 @@ private slots:
|
||||
int lastStepTimestampChanged = 0;
|
||||
double lastCurrentStepDistance = 0.0;
|
||||
QTime lastCurrentStepTime = QTime(0, 0, 0);
|
||||
|
||||
int64_t currentTimerJitter = 0;
|
||||
QDateTime lastSchedulerCall = QDateTime::currentDateTime();
|
||||
|
||||
QUdpSocket* pelotonOCRsocket = nullptr;
|
||||
void pelotonOCRcomputeTime(QString t);
|
||||
|
||||
Reference in New Issue
Block a user