mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
25 Commits
android-pa
...
android_CI
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e48af4e864 | ||
|
|
e990a27f65 | ||
|
|
4c88304be0 | ||
|
|
4c1d39d68c | ||
|
|
efc92f72b2 | ||
|
|
424e21a8fa | ||
|
|
51bc2ffb48 | ||
|
|
7cfd1ba93b | ||
|
|
c01e5ccb14 | ||
|
|
dd495f1a76 | ||
|
|
458c44758e | ||
|
|
78e3a33596 | ||
|
|
77a9fc718a | ||
|
|
be12859343 | ||
|
|
d201919b55 | ||
|
|
138a42c2e6 | ||
|
|
bbe69f3f60 | ||
|
|
b95b3a5018 | ||
|
|
fb0cbb74a5 | ||
|
|
deed6019ab | ||
|
|
7636f768f1 | ||
|
|
cdf8a95e30 | ||
|
|
13389afe77 | ||
|
|
8acfb6b764 | ||
|
|
4244ce79a0 |
51
.github/workflows/main.yml
vendored
51
.github/workflows/main.yml
vendored
@@ -138,8 +138,7 @@ jobs:
|
||||
cp "C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/libstdc++-6.dll" .
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../windows/zwift-incline.py .
|
||||
cp ../../windows/zwift-workout.py .
|
||||
cp ../../windows/*.py .
|
||||
mkdir adb
|
||||
mkdir python
|
||||
Copy-Item -Path C:\hostedtoolcache\windows\Python\3.10.11\x64 -Destination python -Recurse
|
||||
@@ -514,7 +513,7 @@ jobs:
|
||||
- name: Install Qt Android
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '5.15.2'
|
||||
version: '5.15.0'
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android'
|
||||
@@ -528,6 +527,9 @@ jobs:
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '11'
|
||||
|
||||
- name: patching qt for bluetooth
|
||||
run: cp qt-patches/android/5.15.0/jar/*.* ${{ github.workspace }}/output/android/Qt/5.15.0/android/jar/
|
||||
|
||||
- name: Set Android NDK 21 && build
|
||||
run: |
|
||||
@@ -539,6 +541,12 @@ jobs:
|
||||
echo "y" | $SDKMANAGER "ndk;21.4.7075529"
|
||||
export ANDROID_NDK="${ANDROID_SDK_ROOT}/ndk-bundle"
|
||||
export ANDROID_NDK_ROOT="${ANDROID_NDK}"
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_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
|
||||
cd ..
|
||||
|
||||
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK
|
||||
rm -rf /usr/local/lib/android/sdk/ndk/25.1.8937393
|
||||
@@ -547,6 +555,43 @@ jobs:
|
||||
- name: Build APK (not usable for production due to unpatched QT library)
|
||||
run: cd src; androiddeployqt --input android-qdomyos-zwift-deployment-settings.json --output ${{ github.workspace }}/output/android/ --android-platform android-31 --gradle --aab
|
||||
|
||||
- uses: r0adkll/sign-android-release@v1
|
||||
name: Sign app APK
|
||||
# ID used to access action output
|
||||
id: sign_app
|
||||
with:
|
||||
releaseDirectory: ${{ github.workspace }}/output/android/build/outputs/apk/debug/
|
||||
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||
alias: ${{ secrets.ALIAS }}
|
||||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||
env:
|
||||
# override default build-tools version (29.0.3) -- optional
|
||||
BUILD_TOOLS_VERSION: "30.0.2"
|
||||
|
||||
- uses: r0adkll/sign-android-release@v1
|
||||
name: Sign app AAB
|
||||
# ID used to access action output
|
||||
id: sign_aab
|
||||
with:
|
||||
releaseDirectory: ${{ github.workspace }}/output/android/build/outputs/bundle/debug/
|
||||
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||
alias: ${{ secrets.ALIAS }}
|
||||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||
env:
|
||||
# override default build-tools version (29.0.3) -- optional
|
||||
BUILD_TOOLS_VERSION: "30.0.2"
|
||||
|
||||
- uses: r0adkll/upload-google-play@v1
|
||||
with:
|
||||
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
|
||||
packageName: org.cagnulen.qdomyoszwift
|
||||
releaseFiles: ${{steps.sign_aab.outputs.signedReleaseFile}}
|
||||
track: internal
|
||||
status: draft
|
||||
inAppUpdatePriority: 2
|
||||
|
||||
ios-build:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: macos-latest
|
||||
|
||||
BIN
qt-patches/android/5.15.0/jar/QtAndroidBluetooth.jar
Normal file
BIN
qt-patches/android/5.15.0/jar/QtAndroidBluetooth.jar
Normal file
Binary file not shown.
@@ -317,7 +317,7 @@ HomeForm{
|
||||
|
||||
videoPlaybackHalf.seek(rootItem.videoPosition)
|
||||
videoPlaybackHalf.play()
|
||||
videoPlaybackHalf.muted = true
|
||||
videoPlaybackHalf.muted = rootItem.currentCoordinateValid
|
||||
} else {
|
||||
videoPlaybackHalf.stop()
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ Item {
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
|
||||
/*Button {
|
||||
Button {
|
||||
id: restoreButton
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -101,7 +101,8 @@ Item {
|
||||
text: "Restore Purchases"
|
||||
onClicked: {
|
||||
console.log("restoring...");
|
||||
toast.show("Restoring...");
|
||||
iapStore.restorePurchases();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.13.97" android:versionCode="613" 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.13.99" android:versionCode="615" 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 -->
|
||||
|
||||
@@ -3202,6 +3202,9 @@ void homeform::StopRequested() {
|
||||
|
||||
void homeform::Stop() {
|
||||
QSettings settings;
|
||||
|
||||
m_startRequested = false;
|
||||
|
||||
qDebug() << QStringLiteral("Stop pressed - paused") << paused << QStringLiteral("stopped") << stopped;
|
||||
|
||||
if (stopped) {
|
||||
@@ -5959,6 +5962,10 @@ void homeform::sendMail() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SMTP_SERVER
|
||||
textMessage += QStringLiteral("\n\nSMTP server: ") + QString(STRINGIFY(SMTP_SERVER));
|
||||
#endif
|
||||
|
||||
text.setText(textMessage);
|
||||
message.addPart(&text);
|
||||
|
||||
|
||||
@@ -737,7 +737,7 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
ItemDelegate {
|
||||
text: "version 2.13.97"
|
||||
text: "version 2.13.99"
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,7 @@ void proformbike::writeCharacteristic(uint8_t *data, uint8_t data_len, const QSt
|
||||
gattCommunicationChannelService->writeCharacteristic(gattWriteCharacteristic, *writeBuffer);
|
||||
|
||||
if (!disable_log) {
|
||||
emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') +
|
||||
QStringLiteral(" // ") + info);
|
||||
emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') + QStringLiteral(" // ") + info);
|
||||
}
|
||||
|
||||
loop.exec();
|
||||
@@ -519,6 +518,9 @@ void proformbike::update() {
|
||||
.toBool();
|
||||
bool proform_bike_sb =
|
||||
settings.value(QZSettings::proform_bike_sb, QZSettings::default_proform_bike_sb).toBool();
|
||||
bool proform_bike_PFEVEX71316_1 =
|
||||
settings.value(QZSettings::proform_bike_PFEVEX71316_1, QZSettings::default_proform_bike_PFEVEX71316_1)
|
||||
.toBool();
|
||||
|
||||
uint8_t noOpData1[] = {0xfe, 0x02, 0x19, 0x03};
|
||||
uint8_t noOpData2[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x07, 0x15, 0x02, 0x00,
|
||||
@@ -587,6 +589,16 @@ void proformbike::update() {
|
||||
0x0d, 0x02, 0x00, 0x07, 0xbc, 0x90, 0x70,
|
||||
0x00, 0x00, 0x00, 0x40, 0x19, 0x00};
|
||||
|
||||
// proform_bike_PFEVEX71316_1
|
||||
uint8_t noOpData2_proform_bike_PFEVEX71316_1[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x08, 0x15, 0x02, 0x00,
|
||||
0x0f, 0xb6, 0x10, 0x30, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t noOpData3_proform_bike_PFEVEX71316_1[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t noOpData5_proform_bike_PFEVEX71316_1[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x08, 0x13, 0x02, 0x00,
|
||||
0x0d, 0x09, 0x8e, 0x41, 0x00, 0x00, 0x40, 0x50, 0x00, 0x80};
|
||||
uint8_t noOpData6_proform_bike_PFEVEX71316_1[] = {0xff, 0x05, 0x18, 0x00, 0x00, 0x81, 0xab, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
switch (counterPoll) {
|
||||
case 0:
|
||||
if (nordictrack_gx_2_7 || proform_hybrid_trainer_PFEL03815 || proform_bike_sb) {
|
||||
@@ -613,6 +625,9 @@ void proformbike::update() {
|
||||
else if (proform_bike_sb)
|
||||
writeCharacteristic(noOpData2_proform_bike_sb, sizeof(noOpData2_proform_bike_sb),
|
||||
QStringLiteral("noOp"));
|
||||
else if (proform_bike_PFEVEX71316_1)
|
||||
writeCharacteristic(noOpData2_proform_bike_PFEVEX71316_1, sizeof(noOpData2_proform_bike_PFEVEX71316_1),
|
||||
QStringLiteral("noOp"));
|
||||
else
|
||||
writeCharacteristic(noOpData2, sizeof(noOpData2), QStringLiteral("noOp"));
|
||||
break;
|
||||
@@ -634,6 +649,9 @@ void proformbike::update() {
|
||||
else if (proform_bike_sb)
|
||||
writeCharacteristic(noOpData3_proform_bike_sb, sizeof(noOpData3_proform_bike_sb),
|
||||
QStringLiteral("noOp"));
|
||||
else if (proform_bike_PFEVEX71316_1)
|
||||
writeCharacteristic(noOpData3_proform_bike_PFEVEX71316_1, sizeof(noOpData3_proform_bike_PFEVEX71316_1),
|
||||
QStringLiteral("noOp"));
|
||||
else
|
||||
writeCharacteristic(noOpData3, sizeof(noOpData3), QStringLiteral("noOp"));
|
||||
break;
|
||||
@@ -665,6 +683,9 @@ void proformbike::update() {
|
||||
} else if (proform_bike_sb)
|
||||
writeCharacteristic(noOpData5_proform_bike_sb, sizeof(noOpData5_proform_bike_sb),
|
||||
QStringLiteral("noOp"));
|
||||
else if (proform_bike_PFEVEX71316_1)
|
||||
writeCharacteristic(noOpData5_proform_bike_PFEVEX71316_1, sizeof(noOpData5_proform_bike_PFEVEX71316_1),
|
||||
QStringLiteral("noOp"));
|
||||
else
|
||||
writeCharacteristic(noOpData5, sizeof(noOpData5), QStringLiteral("noOp"));
|
||||
break;
|
||||
@@ -677,6 +698,9 @@ void proformbike::update() {
|
||||
else if (proform_cycle_trainer_400)
|
||||
writeCharacteristic(noOpData6_proform_cycle_trainer_400, sizeof(noOpData6_proform_cycle_trainer_400),
|
||||
QStringLiteral("noOp"));
|
||||
else if (proform_bike_PFEVEX71316_1)
|
||||
writeCharacteristic(noOpData6_proform_bike_PFEVEX71316_1, sizeof(noOpData6_proform_bike_PFEVEX71316_1),
|
||||
QStringLiteral("noOp"));
|
||||
else
|
||||
writeCharacteristic(noOpData6, sizeof(noOpData6), QStringLiteral("noOp"));
|
||||
break;
|
||||
@@ -704,7 +728,8 @@ void proformbike::update() {
|
||||
counterPoll++;
|
||||
if (counterPoll > 6) {
|
||||
counterPoll = 0;
|
||||
} else if (counterPoll == 6 && (proform_tour_de_france_clc || proform_cycle_trainer_400) &&
|
||||
} else if (counterPoll == 6 &&
|
||||
(proform_tour_de_france_clc || proform_cycle_trainer_400 || proform_bike_PFEVEX71316_1) &&
|
||||
requestResistance == -1) {
|
||||
// this bike sends the frame noOpData7 only when it needs to change the resistance
|
||||
counterPoll = 0;
|
||||
@@ -818,6 +843,8 @@ void proformbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
.value(QZSettings::proform_hybrid_trainer_PFEL03815, QZSettings::default_proform_hybrid_trainer_PFEL03815)
|
||||
.toBool();
|
||||
bool proform_bike_sb = settings.value(QZSettings::proform_bike_sb, QZSettings::default_proform_bike_sb).toBool();
|
||||
bool proform_bike_PFEVEX71316_1 =
|
||||
settings.value(QZSettings::proform_bike_PFEVEX71316_1, QZSettings::default_proform_bike_PFEVEX71316_1).toBool();
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
|
||||
@@ -864,6 +891,43 @@ void proformbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
Cadence = ((uint8_t)newValue.at(2));
|
||||
}
|
||||
}
|
||||
} else if (proform_bike_PFEVEX71316_1) {
|
||||
if (newValue.length() == 20 && newValue.at(0) == 0x00 && newValue.at(1) == 0x12 && newValue.at(2) == 0x01 &&
|
||||
newValue.at(3) == 0x04 && newValue.at(4) == 0x02 && newValue.at(5) == 0x2f && newValue.at(6) == 0x08 &&
|
||||
newValue.at(7) == 0x2f && newValue.at(8) == 0x02 && newValue.at(9) == 0x02 && newValue.at(10) == 0x00 &&
|
||||
newValue.at(11) == 0x00 && newValue.at(14) == 0x5a) {
|
||||
m_watt = ((uint16_t)(((uint8_t)newValue.at(13)) << 8) + (uint16_t)((uint8_t)newValue.at(12)));
|
||||
} else if (newValue.length() == 20 && newValue.at(0) == 0x00 && newValue.at(1) == 0x12 &&
|
||||
newValue.at(2) == 0x01 && newValue.at(3) == 0x04 && newValue.at(4) == 0x02 &&
|
||||
newValue.at(5) == 0x2f && newValue.at(6) == 0x08 && newValue.at(7) == 0x2f &&
|
||||
newValue.at(8) == 0x02 && newValue.at(9) == 0x02 && newValue.at(10) != 0x00 &&
|
||||
newValue.at(11) != 0x00 && newValue.at(14) == 0x5a) {
|
||||
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = ((double)((uint16_t)(((uint8_t)newValue.at(13)) << 8) + (uint16_t)((uint8_t)newValue.at(12))) /
|
||||
100.0);
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
|
||||
double incline =
|
||||
((double)((int16_t)(((int8_t)newValue.at(11)) << 8) + (int16_t)((uint8_t)newValue.at(10))) / 100.0);
|
||||
|
||||
if ((uint16_t)(qAbs(incline) * 10) % 5 == 0) {
|
||||
Inclination = incline;
|
||||
emit debug(QStringLiteral("Current Inclination: ") + QString::number(incline));
|
||||
} else {
|
||||
emit debug(QStringLiteral("Filtering bad inclination"));
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = ((uint8_t)newValue.at(18));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (newValue.length() != 20 || newValue.at(0) != 0x00 || newValue.at(1) != 0x12 || newValue.at(2) != 0x01 ||
|
||||
@@ -1268,7 +1332,9 @@ void proformbike::btinit() {
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
} else if (settings.value(QZSettings::proform_tdf_10, QZSettings::default_proform_tdf_10).toBool()) {
|
||||
} else if (settings.value(QZSettings::proform_tdf_10, QZSettings::default_proform_tdf_10).toBool() ||
|
||||
settings.value(QZSettings::proform_bike_PFEVEX71316_1, QZSettings::default_proform_bike_PFEVEX71316_1)
|
||||
.toBool()) {
|
||||
max_resistance = 26;
|
||||
|
||||
uint8_t initData1[] = {0xfe, 0x02, 0x08, 0x02};
|
||||
@@ -1314,19 +1380,36 @@ void proformbike::btinit() {
|
||||
writeCharacteristic(initData9, sizeof(initData9), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
|
||||
uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x08, 0x28, 0x90, 0x04,
|
||||
0x00, 0x40, 0x0c, 0xca, 0x9e, 0x64, 0x38, 0xf6, 0xda, 0xa8};
|
||||
uint8_t initData11[] = {0x01, 0x12, 0x74, 0x42, 0x26, 0x0c, 0xf0, 0xae, 0xb2, 0x90,
|
||||
0x7c, 0x5a, 0x2e, 0x34, 0x08, 0xe6, 0xea, 0xf8, 0xc4, 0xd2};
|
||||
uint8_t initData12[] = {0xff, 0x08, 0xd6, 0xdc, 0xe0, 0x88, 0x02, 0x00, 0x00, 0x0e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
if (settings.value(QZSettings::proform_bike_PFEVEX71316_1, QZSettings::default_proform_bike_PFEVEX71316_1)
|
||||
.toBool()) {
|
||||
uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x08, 0x28, 0x90, 0x04,
|
||||
0x00, 0xc1, 0x58, 0xfd, 0x90, 0x31, 0xd0, 0x75, 0x28, 0xc1};
|
||||
uint8_t initData11[] = {0x01, 0x12, 0x78, 0x2d, 0xc0, 0x71, 0x20, 0xf5, 0x88, 0x41,
|
||||
0x18, 0xdd, 0x90, 0x51, 0x10, 0xd5, 0x88, 0x41, 0x38, 0xed};
|
||||
uint8_t initData12[] = {0xff, 0x08, 0xa0, 0x91, 0x40, 0x88, 0x02, 0x00, 0x00, 0x21,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
writeCharacteristic(initData10, sizeof(initData10), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(initData11, sizeof(initData11), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(initData10, sizeof(initData10), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(initData11, sizeof(initData11), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
} else {
|
||||
uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x08, 0x28, 0x90, 0x04,
|
||||
0x00, 0x40, 0x0c, 0xca, 0x9e, 0x64, 0x38, 0xf6, 0xda, 0xa8};
|
||||
uint8_t initData11[] = {0x01, 0x12, 0x74, 0x42, 0x26, 0x0c, 0xf0, 0xae, 0xb2, 0x90,
|
||||
0x7c, 0x5a, 0x2e, 0x34, 0x08, 0xe6, 0xea, 0xf8, 0xc4, 0xd2};
|
||||
uint8_t initData12[] = {0xff, 0x08, 0xd6, 0xdc, 0xe0, 0x88, 0x02, 0x00, 0x00, 0x0e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
writeCharacteristic(initData10, sizeof(initData10), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(initData11, sizeof(initData11), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false);
|
||||
QThread::msleep(400);
|
||||
}
|
||||
} else {
|
||||
|
||||
uint8_t initData1[] = {0xfe, 0x02, 0x08, 0x02};
|
||||
|
||||
@@ -812,4 +812,4 @@ INCLUDEPATH += purchasing/inapp
|
||||
|
||||
WINRT_MANIFEST = AppxManifest.xml
|
||||
|
||||
VERSION = 2.13.97
|
||||
VERSION = 2.13.99
|
||||
|
||||
@@ -663,8 +663,10 @@ const QString QZSettings::proform_bike_sb = QStringLiteral("proform_bike_sb");
|
||||
const QString QZSettings::fakedevice_rower = QStringLiteral("fakedevice_rower");
|
||||
const QString QZSettings::zwift_ocr_climb_portal = QStringLiteral("zwift_ocr_climb_portal");
|
||||
const QString QZSettings::poll_device_time = QStringLiteral("poll_device_time");
|
||||
const QString QZSettings::proform_bike_PFEVEX71316_1 = QStringLiteral("proform_bike_PFEVEX71316_1");
|
||||
const QString QZSettings::schwinn_bike_resistance_v3 = QStringLiteral("schwinn_bike_resistance_v3");
|
||||
|
||||
const uint32_t allSettingsCount = 555;
|
||||
const uint32_t allSettingsCount = 557;
|
||||
|
||||
QVariant allSettings[allSettingsCount][2] = {
|
||||
{QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles},
|
||||
@@ -1226,6 +1228,8 @@ QVariant allSettings[allSettingsCount][2] = {
|
||||
{QZSettings::fakedevice_rower, QZSettings::default_fakedevice_rower},
|
||||
{QZSettings::zwift_ocr_climb_portal, QZSettings::default_zwift_ocr_climb_portal},
|
||||
{QZSettings::poll_device_time, QZSettings::default_poll_device_time},
|
||||
{QZSettings::proform_bike_PFEVEX71316_1, QZSettings::default_proform_bike_PFEVEX71316_1},
|
||||
{QZSettings::schwinn_bike_resistance_v3, QZSettings::default_schwinn_bike_resistance_v3},
|
||||
};
|
||||
|
||||
void QZSettings::qDebugAllSettings(bool showDefaults) {
|
||||
|
||||
@@ -1860,6 +1860,12 @@ class QZSettings {
|
||||
static const QString poll_device_time;
|
||||
static constexpr int default_poll_device_time = 200;
|
||||
|
||||
static const QString proform_bike_PFEVEX71316_1;
|
||||
static constexpr bool default_proform_bike_PFEVEX71316_1 = false;
|
||||
|
||||
static const QString schwinn_bike_resistance_v3;
|
||||
static constexpr bool default_schwinn_bike_resistance_v3 = false;
|
||||
|
||||
/**
|
||||
* @brief Write the QSettings values using the constants from this namespace.
|
||||
* @param showDefaults Optionally indicates if the default should be shown with the key.
|
||||
|
||||
@@ -555,6 +555,8 @@ resistance_t schwinnic4bike::pelotonToBikeResistance(int pelotonResistance) {
|
||||
QSettings settings;
|
||||
bool schwinn_bike_resistance_v2 =
|
||||
settings.value(QZSettings::schwinn_bike_resistance_v2, QZSettings::default_schwinn_bike_resistance_v2).toBool();
|
||||
bool schwinn_bike_resistance_v3 =
|
||||
settings.value(QZSettings::schwinn_bike_resistance_v3, QZSettings::default_schwinn_bike_resistance_v3).toBool();
|
||||
if (!schwinn_bike_resistance_v2) {
|
||||
if (pelotonResistance > 54)
|
||||
return pelotonResistance;
|
||||
@@ -563,6 +565,12 @@ resistance_t schwinnic4bike::pelotonToBikeResistance(int pelotonResistance) {
|
||||
|
||||
// y = 0,04x2 - 1,32x + 11,8
|
||||
return ((0.04 * pow(pelotonResistance, 2)) - (1.32 * pelotonResistance) + 11.8);
|
||||
} else if (schwinn_bike_resistance_v3) {
|
||||
// y = 0,0007x3 - 0,0763x2 + 4,1619x - 75,788
|
||||
if (pelotonResistance < 30)
|
||||
return 0;
|
||||
|
||||
return qRound((0.0007 * pow(pelotonResistance, 3)) - (0.0763 * pow(pelotonResistance, 2)) + (4.1619 * pelotonResistance) + 75.788);
|
||||
} else {
|
||||
if (pelotonResistance > 20)
|
||||
return (((double)pelotonResistance - 20.0) * 1.25);
|
||||
|
||||
@@ -807,6 +807,10 @@ import QtQuick.Dialogs 1.0
|
||||
// from version 2.13.96
|
||||
property bool zwift_ocr_climb_portal: false
|
||||
property int poll_device_time: 200
|
||||
|
||||
// from version 2.13.99
|
||||
property bool proform_bike_PFEVEX71316_1: false
|
||||
property bool schwinn_bike_resistance_v3: false
|
||||
}
|
||||
|
||||
function paddingZeros(text, limit) {
|
||||
@@ -2211,7 +2215,7 @@ import QtQuick.Dialogs 1.0
|
||||
}
|
||||
SwitchDelegate {
|
||||
id: schwinnBikeResistanceV2Delegate
|
||||
text: qsTr("Resistance Alternative Calc.")
|
||||
text: qsTr("Res. Alternative Calc. v2")
|
||||
spacing: 0
|
||||
bottomPadding: 0
|
||||
topPadding: 0
|
||||
@@ -2223,6 +2227,19 @@ import QtQuick.Dialogs 1.0
|
||||
Layout.fillWidth: true
|
||||
onClicked: settings.schwinn_bike_resistance_v2 = checked
|
||||
}
|
||||
SwitchDelegate {
|
||||
text: qsTr("Res. Alternative Calc. v3")
|
||||
spacing: 0
|
||||
bottomPadding: 0
|
||||
topPadding: 0
|
||||
rightPadding: 0
|
||||
leftPadding: 0
|
||||
clip: false
|
||||
checked: settings.schwinn_bike_resistance_v3
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
onClicked: settings.schwinn_bike_resistance_v3 = checked
|
||||
}
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Label {
|
||||
@@ -2804,6 +2821,19 @@ import QtQuick.Dialogs 1.0
|
||||
Layout.fillWidth: true
|
||||
onClicked: { settings.proform_tdf_10 = checked; window.settings_restart_to_apply = true; }
|
||||
}
|
||||
SwitchDelegate {
|
||||
text: qsTr("TDF 1.0 PFEVEX71316.1")
|
||||
spacing: 0
|
||||
bottomPadding: 0
|
||||
topPadding: 0
|
||||
rightPadding: 0
|
||||
leftPadding: 0
|
||||
clip: false
|
||||
checked: settings.proform_bike_PFEVEX71316_1
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
onClicked: { settings.proform_bike_PFEVEX71316_1 = checked; window.settings_restart_to_apply = true; }
|
||||
}
|
||||
SwitchDelegate {
|
||||
id: nordictrackGX27odelegate
|
||||
text: qsTr("NordicTrack GX 2.7")
|
||||
@@ -4166,7 +4196,7 @@ import QtQuick.Dialogs 1.0
|
||||
}
|
||||
|
||||
SwitchDelegate {
|
||||
text: qsTr("Zwift Treadmill Auto Inclination")
|
||||
text: qsTr("Zwift Treadmill Climb Portal")
|
||||
spacing: 0
|
||||
bottomPadding: 0
|
||||
topPadding: 0
|
||||
|
||||
@@ -234,7 +234,10 @@ void wahookickrsnapbike::update() {
|
||||
uint8_t b[20];
|
||||
memcpy(b, a.constData(), a.length());
|
||||
writeCharacteristic(b, a.length(), "setResistance", false, true);
|
||||
} else if (virtualBike && virtualBike->ftmsDeviceConnected() && lastGearValue != gears()) {
|
||||
inclinationChanged(lastGrade, lastGrade);
|
||||
}
|
||||
lastGearValue = gears();
|
||||
requestResistance = -1;
|
||||
}
|
||||
if (requestStart != -1) {
|
||||
@@ -789,8 +792,9 @@ void wahookickrsnapbike::controllerStateChanged(QLowEnergyController::Controller
|
||||
|
||||
void wahookickrsnapbike::inclinationChanged(double grade, double percentage) {
|
||||
Q_UNUSED(percentage);
|
||||
lastGrade = grade;
|
||||
emit debug(QStringLiteral("writing inclination ") + QString::number(grade));
|
||||
QByteArray a = setSimGrade(grade);
|
||||
QByteArray a = setSimGrade(grade + gears());
|
||||
uint8_t b[20];
|
||||
memcpy(b, a.constData(), a.length());
|
||||
writeCharacteristic(b, a.length(), "setSimGrade", false, true);
|
||||
|
||||
@@ -83,6 +83,8 @@ class wahookickrsnapbike : public bike {
|
||||
|
||||
uint8_t sec1Update = 0;
|
||||
QByteArray lastPacket;
|
||||
double lastGearValue = -1;
|
||||
double lastGrade = 0;
|
||||
QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
QDateTime lastGoodCadence = QDateTime::currentDateTime();
|
||||
uint8_t firstStateChanged = 0;
|
||||
|
||||
@@ -23,10 +23,13 @@ screenshot_np = np.array(screenshot)
|
||||
|
||||
# Crop image to incline area
|
||||
screenwidth, screenheight = screenshot.size
|
||||
|
||||
# Values for Zwift climb portal incline
|
||||
col1 = int(screenwidth/3000 * 2822)
|
||||
row1 = int(screenheight/2000 * 218)
|
||||
col2 = int(screenwidth/3000 * 2980)
|
||||
row2 = int(screenheight/2000 * 302)
|
||||
|
||||
cropped_np = screenshot_np[row1:row2, col1:col2]
|
||||
|
||||
# Convert numpy array to PIL image
|
||||
|
||||
@@ -23,10 +23,13 @@ screenshot_np = np.array(screenshot)
|
||||
|
||||
# Crop image to incline area
|
||||
screenwidth, screenheight = screenshot.size
|
||||
|
||||
# Values for Zwift regular incline
|
||||
col1 = int(screenwidth/3000 * 2800)
|
||||
row1 = int(screenheight/2000 * 75)
|
||||
col2 = screenwidth
|
||||
row2 = int(screenheight/2000 * 200)
|
||||
|
||||
cropped_np = screenshot_np[row1:row2, col1:col2]
|
||||
|
||||
# Convert numpy array to PIL image
|
||||
|
||||
@@ -67,6 +67,7 @@ void zwiftworkout::convertTag(double thresholdSecPerKm, const QString &sportType
|
||||
double OnPower = 1;
|
||||
double OffPower = 1;
|
||||
int Pace = -1;
|
||||
int Cadence = -1;
|
||||
repeat = va_arg(args, uint32_t);
|
||||
if (repeat <= 0)
|
||||
repeat = 1;
|
||||
@@ -75,6 +76,7 @@ void zwiftworkout::convertTag(double thresholdSecPerKm, const QString &sportType
|
||||
OnPower = va_arg(args, double);
|
||||
OffPower = va_arg(args, double);
|
||||
Pace = va_arg(args, int);
|
||||
Cadence = va_arg(args, int);
|
||||
for (uint32_t i = 0; i < repeat; i++) {
|
||||
trainrow row;
|
||||
if (!durationAsDistance(sportType, durationType))
|
||||
@@ -100,6 +102,8 @@ void zwiftworkout::convertTag(double thresholdSecPerKm, const QString &sportType
|
||||
} else {
|
||||
row.power = OffPower * settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble();
|
||||
}
|
||||
if(Cadence != -1)
|
||||
row.cadence = Cadence;
|
||||
qDebug() << "TrainRow" << row.toString();
|
||||
list.append(row);
|
||||
}
|
||||
@@ -108,10 +112,12 @@ void zwiftworkout::convertTag(double thresholdSecPerKm, const QString &sportType
|
||||
double PowerLow = 1;
|
||||
double PowerHigh = 1;
|
||||
int Pace = -1;
|
||||
int Cadence = -1;
|
||||
Duration = va_arg(args, uint32_t);
|
||||
PowerLow = va_arg(args, double);
|
||||
PowerHigh = va_arg(args, double);
|
||||
Pace = va_arg(args, int);
|
||||
Cadence = va_arg(args, int);
|
||||
if (sportType.toLower().contains(QStringLiteral("run")) && !durationAsDistance(sportType, durationType)) {
|
||||
double speed = speedFromPace(Pace);
|
||||
int speedDelta = qAbs(qCeil((((60.0 / speed) * 60.0) * (PowerHigh - PowerLow)) * 10)) + 1;
|
||||
@@ -147,6 +153,8 @@ void zwiftworkout::convertTag(double thresholdSecPerKm, const QString &sportType
|
||||
} else {
|
||||
row.distance = 0.001;
|
||||
}
|
||||
if(Cadence != -1)
|
||||
row.cadence = Cadence;
|
||||
if (PowerHigh > PowerLow) {
|
||||
if (!sportType.toLower().contains(QStringLiteral("run"))) {
|
||||
row.power = (PowerLow + (((PowerHigh - PowerLow) / Duration) * i)) *
|
||||
@@ -187,12 +195,14 @@ void zwiftworkout::convertTag(double thresholdSecPerKm, const QString &sportType
|
||||
double Power = 1;
|
||||
double Incline = -100;
|
||||
int Pace = -1;
|
||||
int Cadence = -1;
|
||||
trainrow row;
|
||||
|
||||
Duration = va_arg(args, uint32_t);
|
||||
Power = va_arg(args, double);
|
||||
Pace = va_arg(args, int);
|
||||
Incline = va_arg(args, double);
|
||||
Cadence = va_arg(args, int);
|
||||
|
||||
if (sportType.toLower().contains(QStringLiteral("run")) && Duration != 1) {
|
||||
if (thresholdSecPerKm != 0) {
|
||||
@@ -216,6 +226,9 @@ void zwiftworkout::convertTag(double thresholdSecPerKm, const QString &sportType
|
||||
row.inclination = Incline * 100;
|
||||
}
|
||||
|
||||
if(Cadence != -1)
|
||||
row.cadence = Cadence;
|
||||
|
||||
qDebug() << "TrainRow" << row.toString();
|
||||
list.append(row);
|
||||
}
|
||||
@@ -264,6 +277,7 @@ QList<trainrow> zwiftworkout::loadJSON(const QString &input, QString *descriptio
|
||||
double OnPower = 1;
|
||||
double OffPower = 1;
|
||||
int Pace = -1;
|
||||
int Cadence = -1;
|
||||
repeat = element[QStringLiteral("Repeat")].toInt();
|
||||
if (!repeat)
|
||||
repeat = 1;
|
||||
@@ -274,8 +288,11 @@ QList<trainrow> zwiftworkout::loadJSON(const QString &input, QString *descriptio
|
||||
if (element.contains(QStringLiteral("pace"))) {
|
||||
Pace = element[QStringLiteral("pace")].toInt();
|
||||
}
|
||||
if (element.contains(QStringLiteral("Cadence"))) {
|
||||
Cadence = element[QStringLiteral("Cadence")].toInt();
|
||||
}
|
||||
convertTag(0.0, sportType, durationType, list, type.toUtf8().constData(), repeat, OnDuration,
|
||||
OffDuration, OnPower, OffPower, Pace);
|
||||
OffDuration, OnPower, OffPower, Pace, Cadence);
|
||||
} else if (type == QStringLiteral("FreeRide")) {
|
||||
uint32_t Duration = 1;
|
||||
// double FlatRoad = 1;
|
||||
@@ -288,19 +305,24 @@ QList<trainrow> zwiftworkout::loadJSON(const QString &input, QString *descriptio
|
||||
double PowerLow = 1;
|
||||
double PowerHigh = 1;
|
||||
int Pace = -1;
|
||||
int Cadence = -1;
|
||||
Duration = element[QStringLiteral("Duration")].toDouble();
|
||||
PowerLow = element[QStringLiteral("PowerLow")].toDouble();
|
||||
PowerHigh = element[QStringLiteral("PowerHigh")].toDouble();
|
||||
if (element.contains(QStringLiteral("pace"))) {
|
||||
Pace = element[QStringLiteral("pace")].toInt();
|
||||
}
|
||||
if (element.contains(QStringLiteral("Cadence"))) {
|
||||
Cadence = element[QStringLiteral("Cadence")].toInt();
|
||||
}
|
||||
convertTag(0.0, sportType, durationType, list, type.toUtf8().constData(), Duration, PowerLow,
|
||||
PowerHigh, Pace);
|
||||
PowerHigh, Pace, Cadence);
|
||||
} else if (type == QStringLiteral("SteadyState")) {
|
||||
uint32_t Duration = 1;
|
||||
double Power = 1;
|
||||
int Pace = -1;
|
||||
double Incline = -100;
|
||||
int Cadence = -1;
|
||||
|
||||
Duration = element[QStringLiteral("Duration")].toDouble();
|
||||
if (element.contains(QStringLiteral("pace"))) {
|
||||
@@ -313,7 +335,10 @@ QList<trainrow> zwiftworkout::loadJSON(const QString &input, QString *descriptio
|
||||
if (element.contains(QStringLiteral("Incline"))) {
|
||||
Incline = element[QStringLiteral("Incline")].toDouble();
|
||||
}
|
||||
convertTag(0.0, sportType, durationType, list, type.toUtf8().constData(), Duration, Power, Pace, Incline);
|
||||
if (element.contains(QStringLiteral("Cadence"))) {
|
||||
Cadence = element[QStringLiteral("Cadence")].toInt();
|
||||
}
|
||||
convertTag(0.0, sportType, durationType, list, type.toUtf8().constData(), Duration, Power, Pace, Incline, Cadence);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,6 +388,7 @@ QList<trainrow> zwiftworkout::load(const QByteArray &input, QString *description
|
||||
double OnPower = 1;
|
||||
double OffPower = 1;
|
||||
int Pace = -1;
|
||||
int Cadence = -1;
|
||||
if (atts.hasAttribute(QStringLiteral("Repeat"))) {
|
||||
repeat = atts.value(QStringLiteral("Repeat")).toUInt();
|
||||
}
|
||||
@@ -381,9 +407,12 @@ QList<trainrow> zwiftworkout::load(const QByteArray &input, QString *description
|
||||
if (atts.hasAttribute(QStringLiteral("pace"))) {
|
||||
Pace = atts.value(QStringLiteral("pace")).toUInt();
|
||||
}
|
||||
if (atts.hasAttribute(QStringLiteral("Cadence"))) {
|
||||
Cadence = atts.value(QStringLiteral("Cadence")).toUInt();
|
||||
}
|
||||
|
||||
convertTag(thresholdSecPerKm, sportType, durationType, list, name.toUtf8().constData(), repeat,
|
||||
OnDuration, OffDuration, OnPower, OffPower, Pace);
|
||||
OnDuration, OffDuration, OnPower, OffPower, Pace, Cadence);
|
||||
} else if (name.contains(QStringLiteral("FreeRide"))) {
|
||||
uint32_t Duration = 1;
|
||||
// double FlatRoad = 1;
|
||||
@@ -403,6 +432,8 @@ QList<trainrow> zwiftworkout::load(const QByteArray &input, QString *description
|
||||
double PowerLow = 1;
|
||||
double PowerHigh = 1;
|
||||
int Pace = -1;
|
||||
int Cadence = -1;
|
||||
|
||||
if (atts.hasAttribute(QStringLiteral("Duration"))) {
|
||||
Duration = atts.value(QStringLiteral("Duration")).toDouble();
|
||||
}
|
||||
@@ -415,14 +446,18 @@ QList<trainrow> zwiftworkout::load(const QByteArray &input, QString *description
|
||||
if (atts.hasAttribute(QStringLiteral("pace"))) {
|
||||
Pace = atts.value(QStringLiteral("pace")).toUInt();
|
||||
}
|
||||
if (atts.hasAttribute(QStringLiteral("Cadence"))) {
|
||||
Cadence = atts.value(QStringLiteral("Cadence")).toUInt();
|
||||
}
|
||||
|
||||
convertTag(thresholdSecPerKm, sportType, durationType, list, name.toUtf8().constData(), Duration,
|
||||
PowerLow, PowerHigh, Pace);
|
||||
PowerLow, PowerHigh, Pace, Cadence);
|
||||
} else if (name.contains(QStringLiteral("SteadyState"))) {
|
||||
uint32_t Duration = 1;
|
||||
double Power = 1;
|
||||
int Pace = -1;
|
||||
double Incline = -100;
|
||||
int Cadence = -1;
|
||||
|
||||
if (atts.hasAttribute(QStringLiteral("Duration"))) {
|
||||
Duration = atts.value(QStringLiteral("Duration")).toDouble();
|
||||
@@ -439,8 +474,11 @@ QList<trainrow> zwiftworkout::load(const QByteArray &input, QString *description
|
||||
if (atts.hasAttribute(QStringLiteral("Incline"))) {
|
||||
Incline = atts.value(QStringLiteral("Incline")).toDouble();
|
||||
}
|
||||
if (atts.hasAttribute(QStringLiteral("Cadence"))) {
|
||||
Cadence = atts.value(QStringLiteral("Cadence")).toUInt();
|
||||
}
|
||||
convertTag(thresholdSecPerKm, sportType, durationType, list, name.toUtf8().constData(), Duration, Power,
|
||||
Pace, Incline);
|
||||
Pace, Incline, Cadence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user