From 369653bd246a2453067616c99bea943953abc0c7 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 5 Aug 2024 19:07:38 +0200 Subject: [PATCH 001/162] trying to fix again fgchecker (#2503) * trying to fix again fgchecker * adding classes * Update main.yml * Update main.yml * Update main.yml --- .github/workflows/main.yml | 18 +-- src/android/libs/fgchecker-1.1.0.aar | Bin 22351 -> 0 bytes src/android/libs/fgchecker-1.1.0.pom | 17 --- .../com/rvalerio/fgchecker/AppChecker.java | 126 ++++++++++++++++++ .../src/com/rvalerio/fgchecker/Utils.java | 26 ++++ .../fgchecker/detectors/Detector.java | 8 ++ .../fgchecker/detectors/LollipopDetector.java | 34 +++++ .../detectors/PreLollipopDetector.java | 30 +++++ 8 files changed, 233 insertions(+), 26 deletions(-) delete mode 100644 src/android/libs/fgchecker-1.1.0.aar delete mode 100644 src/android/libs/fgchecker-1.1.0.pom create mode 100644 src/android/src/com/rvalerio/fgchecker/AppChecker.java create mode 100644 src/android/src/com/rvalerio/fgchecker/Utils.java create mode 100644 src/android/src/com/rvalerio/fgchecker/detectors/Detector.java create mode 100644 src/android/src/com/rvalerio/fgchecker/detectors/LollipopDetector.java create mode 100644 src/android/src/com/rvalerio/fgchecker/detectors/PreLollipopDetector.java diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 16f55e228..15d48c6a4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -585,7 +585,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: 'temurin' # See 'Supported distributions' for available options - java-version: '11' + java-version: '11.0.23+9' - name: patching qt for bluetooth run: cp qt-patches/android/5.15.0/jar/*.* ${{ github.workspace }}/output/android/Qt/5.15.0/android/jar/ @@ -593,14 +593,6 @@ jobs: - 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 - make -j8 - make install - cd ../.. - - name: Set Android NDK 21 && build run: | # Install NDK 21 after GitHub update @@ -622,6 +614,14 @@ jobs: ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK rm -rf /usr/local/lib/android/sdk/ndk/25.1.8937393 + + # QTHTTPSERVER must use the same NDK + cd src/qthttpserver + qmake + make -j8 + make install + cd ../.. + qmake -spec android-clang 'ANDROID_ABIS=armeabi-v7a arm64-v8a x86 x86_64' 'ANDROID_NDK_ROOT=/usr/local/lib/android/sdk/ndk/21.4.7075529' && make -j4 && make INSTALL_ROOT=${{ github.workspace }}/output/android/ install sed -i '1s|{|{\n "android-extra-libs": "${{ github.workspace }}/android_openssl/no-asm/latest/arm/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/arm/libssl_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/arm64/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/arm64/libssl_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86/libssl_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86_64/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86_64/libssl_1_1.so",|' src/android-qdomyos-zwift-deployment-settings.json cat src/android-qdomyos-zwift-deployment-settings.json diff --git a/src/android/libs/fgchecker-1.1.0.aar b/src/android/libs/fgchecker-1.1.0.aar deleted file mode 100644 index 89666527dfd2b0a2e5ae6c9dfc5b2fdc912d7a43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22351 zcmV)DK*7IIO9KQ7000OG05_=;OBOsMI=%n^06zf$022TJ06}hKa&Kv5O<`_nW@U49 zE_iKhZID5W0x=AQ?*smalDn-gi!8&;c<}CJVeg^MjHT0dXsY=0x2shIH@Cce?~$b2 zU;QjDl-S15!&YuUP|(rXF!gZG4GyQ8|65a0PQGMs(RYG*ddzY*#18}qW>Gp+wQ}v zxkKHViPvo0y?yn08@`SEdEWd9?@Y!tQGUffb|BO(zEh8H48KrI0|W{H00;;GH>na! z^tRU!ZX5sro*@7L3jhEBV{Bn_b7gZbYGHDfd1Y7}UAH9?+@W!rAdS1b1`D2G!QE-x zH3WCJV1Z!4A-FdX92$3r;MRBoNhY~>o|(MgGkI_3)Q_tAQEOH0v-hfX&Q@1Kd;)+& zMMZ^!gQJG~eK5fh!kIgPIb1zW9V}gKoj9zl&222r?JZq7q@10f{r4q^i{0G8)Xhyx z6AKRI_ou&)z`+%3uBfg^;)-QIQI1uT_6e(S}LEiUFJ0B_@tjjyX=`?fgm<1GV4l((#D5umm!RCMc0O& zN#L1?luNql*mhuFYAR#VPWJijeb?rB7;iq1QX5|fLJWkWWssyR?f2yCdYMH~Yru}* zP+JS-y-FZ!mv&rgXO~4!hl0HZ)8m%~LP(2KAZ5OJiG&N-2vRGs37Tj(kO&)Xg2VH< zIr~6R>njfcxEd)(s5ZeNy3%{~261pjpJ1!Yc!ATrr@u0o;u4wt9aK^R8EdS-WRral zYqc)`5$8g^j}|cjCe!yOSXQ*SB<~sJGb1g2!<7{t0Z*JKrN-JeVf?gEC11|vq_~0v zCDVw)G>i0!?-=tNT4lOz~Jr!xVXm8+e@A>DcZ3kb1s4!rUuuSL5G~nbIK5pXf3EpQ-G-SLg>3Z~ZM zxgNpVVfGO&xPC5can>COFz^iI>5a-87=h&f7s z^e|;BCg(J9s3bR>XG5jTN-T*+E2@8vdAg>e@|LZUg@I`!tN|T@__Rl!x_YKi{Pk=i zybHllozBSQ<;ux2M0QmNgG9@R`aaUqS9--m5xv#_&+l8w1Ev2G$!7DNHo z{){9?Yb@e>fn$~j#zn%()R2)wD#f=@Qct28@_QH1`)j^u-CA%zB%*&1H3towcxmPr z>9i*Ste0vTuI1NbuFN!hc9g1VdGe9K8kl{K!5+ryT?Z`Eo`6E2#*Sb@xx<;ou0K{996S{#8;b+q$`1I$FB^A-BTfAlMK| zlF(1?bHFTluWxM>d@OO?c5%8=-3(Y#z6J?kiu3Jh&1Y zzYDPj)PgA`bD{dZ5}eR==YVuCCj1Yyb>ra5_e(bNs7-rTgd97eXt_Rb*;Omq9T@0N zsX?)6t>}IkXe*16=0$<8%N8NR6Rz_PXn|UNY3!~^L##WolT~K|4?Gn)lRw%|@KO0v zX(H4kG#bdrjJ@yxr0*<5dDr$(eg)~|>{))(&o4lN|FV99_FZ* z0i9o#ELtz^Ie&k&odL46bkd!H;>JR^^rktm=Y3O%I$@KSd+HkIz3-I{ae}x~WK8WX zYTab*?MvxZ^r=Z(1$3&Fbp`boznboJINj5vttKclu^v%4y*y%|{Sic85MnjYmlAGW z0$3(JO;#q*o+w0o0I$F>p=J|I4O)q;HA%IA!8ibk-Sk;AM+(o(tfiu-jG`1o^csYQ zQq;A3qsVD9EFIC7k-D?KE6PwYnd+{>3}mCTJHg(Zb88U;`$hmu>W+6$0b)~5rQtxR z@UxLPYi0((nFQ_lRI!Fp?xt?(7K3O9NlVtH%nw8G?DiTlw9;ru)AV6vj4e!kNP&Lb zz){J|tGPFr(D|ry$7s&rD7~;0bCtH|{T;GFK)y5@!#VwUU%JCpIrk)X(!A+rLp(_J zNHDgU#la~3b-dVO@uYz`Ujj+%^E`m?SLYsyc;Y+*vcU2k>-*M&`>^;B!J@4U;lMC^ zbg@y&L>GpXx_VX5pRNlghz#)LXul}4XE&(WYKtd^*#j9k3*HkyxStG)V{sg24qyQj zOlzd?a-BNrp3|!xmF-yUor!Zf$PMbl%EGgStzh-x`oe)B8%N$q-8%*C{&lIeEuA~#rKZyVjq#M?>nHg=6MJi;TZ#|IXXT~72|ypi%T{$7&2{1Zu~D=XD*jXu;)7Oo+-*8eNrnWSp3Nf)fOZp$>L4^y( z?hub_J79Z~0F}&^6U)XLbfV!6x!}Fdw&{3d70>75JIAYSEKA@we$rU$l`9C3S?`Z~ z!`h77j%6x3=E~xiKoyPJDnDF`p{6d)aWEi)Yc1AqOl!AZ6gka_87kO`LMvO2Vxx*> z&(01-uLqs~nw<3^Bx>yo0jSZ|Z^`jt2#lP;9Er-}FU{x}`NB%~bpjC^RjvFE#-^JFqMpdN+d>pd?rTS94K)WCD)qp=4O>;Wkm*vcMZFXi)f6Xm;I3 zT4q~m?cVUTCKnPgvnZ)H>LeEA0qu&6*LA4ut2?GEX2T@rBu4#&&z=X#4N^1wyRTl7-%WA}FEuN*eR)1TG9rvV|V zO9$gL7uJj86Dk(yFS?5^^M#-gon3e%!PKL?%M?1~)`O5(=alcM_DlM0vm+1!RvdSV z`gd6=HT@Swi)x#jIz5T>0o7FWRS|^wEc$ozjSJxRVEJkjL$I-?HfJO)U(V64^Yu}7 z4cMQuio)2Bylt!|&2%38DKPtbRD7v#mOujeaL$*kVrDfLv>XF?KT?!2eVr(~ZS8`* z|E19dPj_Q-?RsC;;aWplR78v0r`*OBmpC%z-Qf);AO#hEqnWMD4-rTY=%L{HS@e21WZ>hJxL>W-7E^ z&AK*wA`!b;~=}n3V{>`c|{@JQXd)PWyJacli zvbFw`k4tVI=H_g^4k35b7GG#GC8RO{>wDG!>?~7n?qss`?rW&$m!0=+>j+I zWdJ$W3?s3=T&JhCCMu7WnkdE^o};`Ia+j+JgRTRfYq5P_i5jPxncdLL7*E|jYd7O+%qfE3b!71D7Rv#h zqHgTKyCL?v@gN50g0usXN;zG7<6kq(p4o!!_tS`~BK+G7bNqRREiBzF&E1_`-8f|a z_thUJT2}R!VF%>MH!6U{pW&Q9>KLe1@llLxo1n~%E28=^Ft&J)d=x+Rx~Ua+R#wNt z1MCUsAeB_|J2eu0YeYurEBA-s6W?xQZsW%4OFn&9xEE{`XX>WEMN>Pu61Y2 zfPTj?4!B@=)y>1yiOQDQ=z1&kaPlqJX=5)TDDVqb52gbmX@~VDx)t4JK#SdGfI-TA zPmc#6d9qt6D9D;B42RBZ!!^s7h3!%=2yY;90E&xA*o4ovl%p!TmYi z;MWPTVgS-D*iXyWq;4i1kddX(ft=-#O!S_TJyFj%_PM%*xLq}Yf_CDwJ* z3nc%{FoJX9v0}Gu)K@MWe9VVRoqJX#c`GR&{QmB)JK2X)v!oHQjHMNG!dSUT*&N)H z1=MU`YZ6}W@f~2Tx!P>X#D0OVFsOZXT+}m`BaHgaUUH#mT4dx)HE&E_>6_LPU^ugA zs1)(0JF9!F#ja@O;%N)FOTZ{TVNP;-LyzT}O^ zLO}%{3gE~hxh86*3@x@>W`gdBKE2jq8(Z8m6vgj!JSD2V#d@2^-*Fqm-*%hDpN;cd zcXmc+`-)VvHl;cfCrmoi@Gc4Qt;bX6W~2}YhE+}r zk3;XFhPC4fYcOrBrhTcAwHq{kVjXg_N7F44OCr75GJ}TD^}-rQ+kl=owp+;8qU*5C zWXD!;r}d@nc9^+2cR6#GqZ(H5&?0C@Y{cNKIDG$uwST!&gBGR^Kv3>8O=&c?mOk{( zVjq^FU+oE0C{Np30*0G!B*Bf zsiY~Pt$3K>;0ye7n1UufPm~HMNWT2*lS@}KJ3+2UaX#f@uI#UbhwTZb6C)0G1oGX3 zHvDO6*@B+(HQ%D1Hh-Va4jxg{56TOY*<8;YlYI&Im741{Z7ePD>M2bw-mZen+u7<1 zO{zxx;kgT6|?yilht ziWl^UV&Utw`l3ovSNIzE#GuO1{*~l#nO22t-YM(*pwdV$v>>L5eM@C^GFYEm=+A2V zr4h!nKZ2?e;ow+N{!Jr<|3)L!T`m7oCUUh`bjW2XzK0uxhlWYMPA_W+ngOHpN=Rng#&slG`9r4e1^7_Al%=j{x$8D1=6X?YGh2>YL;0Q|k@(w;igKd`&8rEeF{ANS_4&N=1HRAB*QLVTFJc?s zDxz8#eaM$gC`XHZikP~erKD~0bP+O>4)H>IwjM2yP538Z;;<_N&Kp%TdKqa}y-cWipku+U-9fr@w_3i~x%gtLK>vwNn`1bW+ zJ46{G`ehPj2IbnB*X8c^^qm?yqATYQySsjSWSQ=YYsoS|Ah6bBbuRGR=52olvlW|c z-0?OV@5&i2U6G#Q+%t&wQj?9GlgJrwPJ9S9&I$1uf@8g5gFlX$!+3r?hL}0 z+BA#MR=+ZcsNl@&Pw+xg7cFkoI#Osd&mb3u03XiL3w{)Ps}0+H^(Y7-xLRw`^T@eG z#UlIEeptat!9*lC*QA+QsdDx~l~?JM@uf;$T;az~0;mbXGykt7a$O-}Il9*rP+0!3 zu5-NM1L=0@0L&*IHeiKdP7y~BN7@0&5`%N%3b zkHRt8F76lEkC)tfFoyTll`AR6+ANC^BFFxn79}f5o&*>ALAPu}NAy zW&+>*)^{~!&?vjHr%x<{qO|W8Kzi6>C?T8EZ0wdeN24=N+dZ1pxiBO(m z8@`Op_d>Fl+rTI!^KIT+(yR;8C9A<`Eb><*%rTntUrLJvXFN|*Ltdnn zwAVQ1`%ScZT`x#<|A5~_&P#QMLnSxlN=tMYIg(6gov~Y!H)A=Vnt-ng36Kwgs z*%Tsz5aQ)gHuHe+Wn?T`vcO7Mans~kMETNr)d%nA)kv|a8!V7ReU*?p0M@z8u5{iV~pmEsk%lsZ(3-icg zWvH(pQA?2}ymL>sAwXBwCgVQom-7pPrQIlTPUG$MOamNYxB>ps8zJNPg4{s@N z@wr)l_Q$DGZi}r<+ps)7$=RrtI65aUZ(mg$pDSGnWe>HvKCE1u;-L86G?+OD<*1CT(->3emQIbB2rUn)ux>VmU6BUDUAGLRCKgvD; zjMhE1R?$WKU%hgMp(ZRDQZS_52LbRfhkZ*k2*TD!wvrD@0JE4(BPVnf0z{76Rs1=;1 z<%WIy(}mz8hDe;%UFS?FzRtU$1s@X2v(+jP1*9x4Ve5duhc6o~)?emqa#3F}%!_e% zIh&TG`Ob}YF%i>G6oVkuOZBd<=RCEq;V$I1_*3_*HZWd$t6CpG61y zuNE0R0s!v+mfi2|GbT7JxPOlSkB%_Xf7jx#PVj$n{N7Drf3ef$I4?>`gaf3Q&!{RP{<_|-oU{$5Bl{~(Mb z`y=5${#gG97zz2;8SUp0{u2;^^4Hz}0#Hi>1PTBE2nYZ-sS-;q4>_kRHvjrUb4y*NQ z_`m=D-x>mFZ#^Iq2l3LiKc;f_hps*C%eL>^6EISTacM8N%U+&)*#RiyK|dQ*_1eK) zU%Te~*DNDnd+w5sjgi#_7CvC#UI4XWQL1*gysZ~$6}UsNzHN_vL)u1g5UXX%5z+VE zJ5lvbdwwsv56$A<81_AGz8@~v2?-5v#p`Ln5CWbYt16nPtT z=xkS7&=>yDwU-a=4;M(K`z+pO;~fwcE$WLr-_(mfTrN^{;#?v5s8&tr$M)DF#i}T< zttF>bv`ZB7@z`D^_wH-jH#7c2Cw_<$f%Ak1x0g4HrCO`8x1K^%7W%O{*Az>;RAIk~ zYtP8b^o9Z}8~bx8z5QV~Mo#Tl;h*GDR{g{ANGqV`qzSL0W2B*atHH`jnV!t4vT3;8 zeKiaEQw(vRzh3ik4FA* zKyKT9Z~C{#*LG0MPN5ysv@GN(yZ%EXj_r$isecSjd$9?-geN@ep~28Vm|e=FoibNE z%Jxb-%QB8frG-QHH|LibA}mEbUS0(}67Hi?_DwbPdUI%GhuY72!EOj5K1or3mgkrL zbq19LH0bW3cTv{c-}?5kJzb8nm&#MozSwOYxEiazh@aZs<6$dv%hkZ8fI%YqJIrUx@B_iOQ;3 z*t7cEggN*z%JczeSJ}CJinXw8yTM40@_J>*N34yd1`Go(i!3! zP?jc$l6`Jzfxy~Xy~^sZvi<1@Q@RjYdkotuOoa%)R_%FyT<7HR5c)c8lVG*1+T&4N zu0sSdINfvqL0+q_xv22~ntjdSt!fXMjX-gesNF{oRV7gqZnrJ~M&gghc2Ha7mA3~1 z){XwP?S_5>Smnah>viq%K@DP}NA|uI9_Xj$<@GrH4@p{jpl5?_4)O7DqWfEZaAHq-c}sD8N9ksZ7A;7^Dqefg8Xq3 z0R7qYuMaxjfFUC(J^0V^fYf&DLH%y^QnK^F22bB1SP_CLDZdWRM|n;3_KDj{L+3Mb zSLt&0FuCPYe@*r-<{@-u1d;5g_OpQ&j))CDx_8w%{$@-h9YiuLABv?E8 z$!iO6y&T2cZx_2uR=I_-C)w6ie0=z+?VA4_S_J7_!N6Q$s};rkF+^=mg$u&XUXSs# z6`hEKgOJ^W4y7#Txw0x7=a-+GE8}N3wF9k3=-lkev3`=4>J@mNAO!&<~*M! z9}l%-9ry)e?u#pXe=L;K|Zt#0F=X#h?b*JV$Xw}fgFT?caYU2~D)bkMWisNKfkAsn; z7Qim4xqepNVf*2gRo386T<4fzuYa@~xW*lN930ayFK;Te9!2|Xn>&c%!#i5OKkpXAC*)D@Wiw;@&Ml3Vz>A_|fVvOBs1u>g4 zf?)?V8|-w4K59XMg!6=r-mz0UiJ!&_oW?p}Z8}MDy>(K>K)QjHZZ$_3zDnE;r@`hL zqkEi+VDmc9F;Hl-QLqeqx{V4{g^z z+@DR2)+@HSGxgpTU4SeOF2=4asom$Spxga}I$2E1LZd!IhL|P~{$0gG24qgoP?PBEx+b&Dscf9HqY9+rN zNNfqle!d~knF!hj$-l@8iqt}=6@C?mdN%8dO$7S=yov@q>t$Zs9}ibE{{$t<9K<*- zqNwZOAXGFyKb39`wymbvqg{uNIZD63#HM(?G?O3_XSSTC+t zOP{-;DdEMeChsb><}8q~*5iJNnf9U_oakOS9@G;1Rw}QdXJ>$@Y{ZG(j;U)K)mzQH zDwwC9T|X&2SbGw7*m+>iw9@MT+lv}82mSiJ{o(X(jlI=Xuho2M&bE`4Il;KjOcn&< z^y``cd<}t-y}}%ikKzI0yM-tY1{1U^r$5^nM+p6wtuq!WOoUW94m(qU-5MR7c7>784L zW*C|N*`bIQ>sD_K-3O~pUYqK#GxoEkRfAfBR60j=HzO!(^pxCVE3m6Aof)L~g4aY- z!92C9NJ|gGswK5v*5YrSCpK?qJ+&NE<~|x~eraGFk|hs#kCJW_?7+itpebt}V+WhE z;!)32?vBDp9s?bJSh)zFvmtH6xZEv=ar`YFcT}!WDLPnRWjDnnWjKi1LG;b#W7|nH z1lckQw|<4~#EDA=5e3Cs!9!)eus!^)+((uo%Y=JuX`{p;z;_*USaBTgkRLh@f0&Ya zW>B{FgMQO9Cba%nc(6(;0^Sht$L6Q3&D8XZ_z%?NSsBDOXN;w9rLlUPb&B1FpmwQ( zK&P?WDYNne?GkGObfv zH~W){42;BK4C--cUiOd)rA84eDA>ZnmCMo_j%EP*^HmOR@|kf-YCZ z&3ZaHM2>wmkW>l(L%x-*=xUv3Fsc3)CiiBmQI!I_@cT+suX6u7Jl~sXLfh?6LvY#+ zg6->hu-HLX-2KI%jlmrx;h}Q+^Ird#YW8_fvR4D|T*yqHGVXY~hm*J*{cDhS+_hvV zsY}r>cbL7LrSOcbze!fmYd$6%YEX`@I(&ecr%-D=doq)Zp9i(kK;2Lih>>!EHfvJr*y90>F z=#7Jrf9-X+3P|D;4ARWQXIM^b-@x>wZI9xC9prwFSe-`UY1>sEg4*r5vNRoez{8k* z;j3d4&2uW;dWfESc1v)lcuTL!PJ2V-tw!tjR#)CjcdD<#{N_BwL09Rky}py}R4&7G zPo;-QmR(t5>FyX^@HHe!2dRv&PBoUjNtGHj4&G$Q zPAn5!mS(#IcOFP(hb4^bU}s|D~5gX<-5j=+)y z*HT^v@rPe2F8Qzk&Jj3Wv0yDhf^mr-mtkD$$DtQWGe4}r#jX7~-1KQ4z~OoeKMwa! zYH9Gf?VE$zxllphIF~W1e`t<98WvY8FHLRv@5`4xN;BNSstiK_l|VzsFtUp&3UG_E ztYQk_lnr<+A{EO7+Zxi6V|Yrhf>@{Engg4lcYIk-Ei#_yRC(|-!_GQe-NAHbT$UAe z&E<0Rji^}~f;z=o*5rhv;Rejs_fVZ`^ALBT5sSOHPQ{jWPC=)NV;8I4-obP#-Fc~e zU3t1pu&c;3FT+fbd~YS9dCogo20fi$L=MNUrdmKdg^xx(gctJcE(49Jt3zOTmF}d! zfM_&=JG||ynv?@KRPUtHCeMtiIEf&S2@ZRSViYJr-ciC;Eo?Jo90Fy`Ig^w(#dR!C zk3iqYB-L30T1F8lqa9N)!%Z;7e{n^4+F*(b*+QmV2>l<|Ii1@_JEf?hn}eEFiSxspDSTcm{c(t8ED8b<3DS`u5^4!D}<)yk#Ky)IRar3~=>J zGgPm>yVSYoX&F@C)u!Oyq=BOqV7J$%fD4Et*7%0kIlG(InTDyep->`m5hHO@=wPix zJsonO-pr*|;#vt~#qxZ+>ZZP`tyg*N9UYwlX+$;)*q2To#nk7zrwosiPl>0Q2wvxu63;TK$U*IYfO^k68wD&BEpT9yqku&s4`(t3s~Y03IEq~h z@i`+!WmwLQFglKNJF3bRTEkbR#aBLKAfsK~0%i+@iY?uGJ>ujj!G1a7&_;s4bA46d zH=!(FJ;q~>hcg%+ahG!hs1L_-u~q?7m1Ww|@>D5tlhg4Gl|pR>XUAlTQ?wXn8GLM+ zoVWWz8!$}zqv0B8j7m#Ppniwo_Dskas{dM4l#?x`!JFSVKQX2DGYht04mN7J9 zp_H~}XvA27_9{hvY|fHl5fcU0QDyxx6k?@7QHyOi#?`HfiDJ&+4PJFp9z!HX>JTY| z7$`7wpvO>%K_benRI)K7VuTjSjHL6xHfAEhNFUG*n+g>Yv-MGEZI((^I=44I>R-zx zwm$%0AN<^yAtYZd^Zm8w3Bz8B$#cuvqXL{fi=o)TO>XrGBy%{VF*gKgc@)hSuZZF} z@@;I=d7+N&65J_%NAP2QLbw_cOLMBTOq|=C(9xu|ERt7CoY??@Q+qk3N}FoBN*gL< zgBEa%n;}i>cH;uZ6_Pp&*gj==#&_#?a>Abc5JR$qo?_+YoJ6BHc5bILo^ybVnV+h6 zX3qK|9Jfi5wU=i0tZ8=@$pS?sr|~lSU(bvfW+MtBJ2y}&{2hS`(4JacO)~@6-#}^@ zAsSZrTSf)^gJ=NFm!M;pL*h#T*UA{yv}8ScOLffY2D9m6!(ov_CoQ$*2u|l0I}SA1 zdDUE}BPaVo%IW5IQZKr%>Jy~_f{eMse=Ru zJb8oZu)bc~EB9A*&)Fc$Fhe-?-Eog@s!GwSp2b2d*=o|pWYjT=j=^EbQWDP8rjrwRfL#M29IRp3*z_e&?l%l<%MH-qLrD%f)^YrrUyb(YZDCLYwlMZclQ}Z!Z6Tmrp z((q$@ewn6lHife#vrB{EP7`ouL^;m;a~7mY^Jx$~nsnlWD_TEiR?$T{VsYkX zmo=|6Fp_Y_7h>C$XPhnCbXsS|86-n;s^TotEDDOQ{!6}1y9P=LPjf1Ninc&7)7-R< z$8XBxEYsYiphM;9$^~kf8E2WmqRrf44ov#wQlD@)nUA<8g$;0!b443m(D z2yU_n5^QFitwxjpfoH~(F9~ zb|yj`>)c|Bb|!ozw-VO~c|5JhwLRu=0@Jvzz1i!o@^m>49X_3H0Gg|80h($QL@iu3 zv#E_rq(l|D_N>uUkj0(90IF-r(@N$+U5Q}3joh_d8*96WX#=FG-#vVOHh&f{F&X~+ z`2724`1^ML`^SHNeSH4)x3BPQH$VIG%ku;LUCe)f`t<8ZR7nXB{^u9?b2b0j7}9Ef zRBW9`aL!(UN?T9&(BC>i`C3 z1lZQn7TOEhU;A4LI9jK|=_?e*y=-Vw@*1!=BVfN}etexDZS00N%4R;`VKSOr&C5_( zbv^%iS{YJ*Rtd$=R+p~@diq1WLH#M>UEj_XJOB+Z<;$Rq^Hz$0MH2P!*rM-p2w2}y z&(OU%0;Y`W349v>9)l>Ax|ZfRj)l;S;3TG7`r!=``L%1$?MY(2*nm*e{rC^_H&sA% ziBP)PZ3)-VCg##`c(QSxI7HBoT2?I_?6`;ycW%B$I1`}ETH&f3bm_Pv@TomPk0XWNYM=NVj#cDps2>$Py4<4ghrw_B*O4 z1vPoaue4fQe^=KY!|MVE?lKlI#T@^xz7ux?)&{zzIsD$D{+!lf)Dz2LWuSx2`Ord9 zNPu1(8)Qh}Z&Wf@0`HSs4>EXApa)lUVUU2Glku5eCgzf1LK_NtbuQr-u(deA^tK?F2vh>e6VL{k^As-e5pc`v z@bp@BQUWj8;U|MHoUbZXmsCRKxetb{Zk;$F%bTvjB*r;YDQcu~xuDO{FufyBZ5NZ5 zE?^v*d(`MqaxR9r(j@={~=9l^rDH2NzzN&7B;Y5m7g1qnfGSj%nC_VX ze1-aZXc{qR`Uu#c8=o~un@j6Si(OEH`n4DR&7`BNZW;XM;H=I)39brM(XCVimVj$e z1uPAW&()iBQUD$7p%;zE>R+6W!~Ctu`rhu3`jnhMIsPa1ru{yH0s#r`E~;CsA1#h z4V(le)9nz2WY7XU;dXI{+YB0jr|5Z*j&{!C`yPL0A%m8nR6Rx18>ucO3sPLP_xRkFxeV5+?qU-W(uhI~N0kM!tkq?(Pq55}U^as-gpp=j9zW=&B0$k=9hLqL z1j8%?O!El|FV(im>+NzG!okVeO}PS=Qv$ASo@2NNk4G!K_MKXhb;2mMXtuB2FZ$#V zu*K2T1$w9HBNI8qZUOduur5?g8Y*TOn^?&+AIZ-6WVvfER|RYJ>_>A5>>Ml&wysh| z>PH|JUgF3zi~RccUR;LRaV2aqH>8A0T+|w)N+kl=)(=C4?FdSJ=5Bw`UkT(-2j?(E zhiL9e+8hRFAB{UBoWn@%q4CFra~P#PJl{#-90u+MCijXWis_yg&S5-XV7f}7N!Jn(3v zdw6KSB!|hxGSB=Oh_uOlM7^E_MB3~gqFyBg9&L7=O>SJTX^BG=(`}A&MQGEtQ0gWXy>!YnN|`Lv;QJz60VyfK{tgSn$#&74 z{rh1UPJk)yW2V5Q>f&djJ(&#z{xQ@?fjqzlwrXRzAI#{8-j=G~5*fWP)xafk24t#) zOXT%TUQ<={l0S{(I*_SCdda_W)4}-(cOqu3j{g)_q4uYX`Icv#DQXzn?#| z<%*R3KNpC;N49}Ym6!s*=(|&Zn%_&M?Q@4Nf0=VCHjrf!L&P6D0}pjaL*fGV_Gi{M zkPmZrNzZmM+dGP}yYLRjshPAJ?(hmvCJKhy?{K~&m)3uWV{uyT4&yeXom+QuhhHMY z>m9~3+Tr}UDqEj-cl16fiK^rsZpT|1X{q%c#!5-=C#0MTnf+AUm<*&Z}?GCG7ZXe?N17C@S4T~Ref^LHlEe;o7$7~ zoCyv%!v2Hk{&GGxsorw2wTI7)x?>*+)7j>{zy{lsvmBBt9~A3FQ@SdR%xiaVGH@CZhFX=+raKKCZ^=I z!PQV5WZ>>A=2QhamgCi^+IdN&LPiDB*bXUZl=nxPdYfcNy$Az$UT#NCYZ(*3OcQ+sS+@>Nj>9pFBT(yEvm zP?&7BQ9)HH%(i-_pi1Rq+q2<L0a>H@&mU1b#nd0&n0P-5q88u2Oeh9g1i> zrx<6sqN1@2Dd9sWe#q`Yr7u3WFE427zM@0rGFwS>LN8HA6#~mq(=rLPLWJ_sP&C5) zepLr2+$N9ceKTa!0jZAg><-r%mg)%a?v~&TPIZKzXNs_gs0gj`ltC6JHxb>>lx4Z! zO?1P~3xB|kZcA0yuWlXIGPgLCZsMf|RBlEW2mB1W~D zwV#jT!XSK4tPgDKtageRcSnv&wx~MUgQuz^l+hiV zHW3;za`yi`t2nJWqu^*2;a7s&2b+kFCDY}Io|%^N$Ef0~_};t-D;;NJsl~UW=vBft zGv7`YfX=KrIk51BrO?eiEPF|FySj&J3%gBNu3E37GNyb*7T762^_9Qo%HJ-7-ST%l zCFSJbrpsWreKHRv=hlooFN?wMiV-i;qS>Yv@Av*Vb#zRkUs`&|p=rD-%d*_GiY>*+ zG;ZKmIGe7HEn*%+Z4u<(;t%7Cx$6BNaP(*cSEAfoniY9wtJp%!*g->>Ecu%y=(a@} zgFY3BDhDMGW`DPwe}@$F4cy9ge>rvo=l2z3B0ce9DPC4Mg_xl&U;_3eE8F}nJ`Dgf z%jGR*%htOXxRWSbi)a$`dR@km>~^WED3+TUTh~!Ek`!CZdwA&O4)^dN6;`h9;XxLx zOrm%s0am6_Ja@(_vnZOqdn?!RBwAx0N7mESaAKt_{%%or)`r~NQO-gFkBqX?xYS!2 zXTna_t&Fo_Pr|K?GiGaME8|T0D>{<`QB#~QVeTOFblI3HAWol10lEPM6ceXQRxzIk z0|ZYY<2(~B!I4D9c`BVPK zr)D4G%xyU<`w(Y#@d??7I0IbB#f@BdI9yxTS0bV(dhfl<=tPM+8NCzTU`+n!_XYX}>d;Rt~&tCtXz1C0W=a};G zsa__RGT0Ke1RWHp*CbBSl{oGnezKBnU8?6A5T=f=Y2eDwA<7|bJn*K#QqsFF;^bM6 z+98;1s{jMI0_Psr&P&ppm9hCSn(dE8&%}$GXDmE*{0iUSd$k!pgk@uJo@T2 z6VW3mg3&lc@9|Zld>!tN-6DEWzfAZR@EWwY?)GR1m-sr42KbQF#iFtiGUV#BlHKrT z$jk@+`a{GzeIG9e)4Xd0o+<46_m%;{Ea2;9rK#>FHQo1&vyOTFGTV>b2U%(-ycOxE zRQFh@<4XWA)>6QnxeDx_KIIBj^luR zjwsvf-i{F)Dl#kY3pNtpcG+_eWtdh9`O<(IF>=Xz0?f+g=>akx1U@6+`Oc~g)44YJ zVyC``i8E5x^WOgr8;KF=?`u8(}M z5{2cyOa>m%Fn+dr!GQOGAYr%WCN|G!c)h}AF^~fwX*?v3<&x}P7vqY@YAgY_p$(LM zjv7qS#|qVtDc5sgYFiZy$Y&>P0&*vx6a3&CmxP~E)V__IXdbg=oO{}Kfv44~d|+YD zsXLc71EE*aPUTJuA(aVmkmhlXM5yj`g0xcvE6o#l-)|JEiYRR7joV}bvy)HM6seUB zo^3XV(wCLY!jr-W3rPaY(p@tKl`+pR&`_XYa#9|%rlSXHnxWi`8Wj{ zv`lr?sod>;+Ah~EwtYcMZm7+E+4M*WMhu*O0yloR^Qy z(YQSGOS%yVB6W~HpD2d`S1uGYit>e*h{JKBc$G{4#Ja-*^CIIJe8$j-fSGJt z$a{{Po_;T2?$QoViQuTo$UA%=$22(`q$a5|#ss#&^2m2YrjkI(@EY*CgZ1zn2_Rcm zG%J^CO?aEAa^~6e@#JK2#K(ku(%@!*xwGRZKS9R?*1H1ZF7Y2frqOrPWxMGh2RH@y z@9A3SlBqkOi>;87Q5!0oX%$31v(j#Ezu%E3e=yMceZH7p_E!URCpaA(^K1+O$U2^^ z{c5TYqw~|Z>NQ<(SmMH+1T zx(Q0C?e;`t=Nz2A%s?K@O2)D|G+?U#Ab*`glUqhYN>j+wwL^RU!?kG#E?oO~HN)iI ztl}K;A}rl~Mr=)7mYTZ5UIeF-El8hMYZS(u1Uy>S=1s^qVppnFGZ8$9<{xY3i`K zex1MVwNTO06c6|7g4cFpb|`eV7oU8tvc3vk!(MD5Q)>^&_YKK)9>Z*87{O2%QrF63 znlm!ij?2tvl&HiY5K^};vD>zADS15kkfh7yLw8rHzax~VWpeA)^H+xhd&#vE_6_H|A(Xv7@G+!tmGE_{~Hkp+-jLxNYc9&b&w?rCFR zA{1Ft+1E;J^zO|D|3YjjYUM0|(*ObkzYC*~b-D%co=ntI-~-f4UXhfrHNlQ!kM77-RA5@9u`dMg5h zMsHZKTz>vr)14I>voR6>QvxQda=fK_OAF6ox%^uYj};oYArSWy3)U@nOrd&<0k>eh z{7=yP3H}`@rg}>Ng9dFZ|3A!T)muIoG;(8^`SQP-UaGfrFlgAuGSlUMHL+l*5BWGizQBmBm@_ASf5PN9Wz+qy*N$u1|8`?{5-# zyQY`EX{Lv`&X+i@r8v%ddNkn?E_NS_mus)Yj2Xo48#e9}{4sZDNE0 z$Vbv7ZOL?Z4ul{XXY4QqNvqbfI|qeEEIB zn7QLp+6^jk^5teb8wZJLZ0yhry0v))7w>|1=`ZkGi@EY_fm&=i&^~G3m*tYG>%k~XF!F}D6 zV;{t>|3cCCp$6^VeHdUe)1vKVxGrpfQ!l97GpKKSX~~&FiXra|y=>q5f+rN%3pFU8 z*98ddxY{mJMf8 zS^=|mg&MMsd7{UhlG9D5kny6;@6yfvA4?_gvdM3HKSUStsYQ5`4D}BT=$xn@!U=fa zD<%lef!Jq09zD^F~Cm zg-H4cTi0*wNh`XGd(?yD=$ohmx;@I_(U!rewjg zw@klLHV8Tdi0(>qu*OE$u&&JR1!>r|BJ2#GNa<;2ZdUjKHT~5*DugU_=E~s*0~}8W z_2Y|TXwqh0@Z**b9pQAcCU<@=_P@{it2#w;-YOP{{6G}Ma(}`XrXZ(XPHA6{V9&;g znlYKC$&l{;?(IL}1B`W&?E387wNTJfjsA+t#&LKWvPzn3PJ6ZhD?8H_d^_0NdhuE) zy85f~cj)UOuL0&E)*OY<4E0mp_p3Vs0qIjWkw0RSN4CuJMYaN)5E0?ULm*va zQxfLnsu#dY{1O4g9JS&xKV}-+q!?d-T0m0J64812{a^As zmfAzyOO&RvYG8YXkPY^Fg+i#k_>9&A696Bi^ye{m>9pIhE7d1K)eJ03pBQ*Ir3_w- zIj(&nZo?USDlcDqTD<=t3Qllsp z!Zy#vJEdXOT0AD-t;&XQ5$W|uWlJ-KvQ-T#yzwCm3)pxlrXUfNK;P59#6?-I_)wff zdndZb_Ge^EN6HNmS5lym3Js^ifDtw5D#!ZzbMe(~#k($o{hQc0Pt0%T`2>r^&MV2P zeV_((vwVVWn2=SeqWz`ct_h&F^Q_t#8@@dfHDq;aKR*<7%jsz;p?Gl|LRImU*OQDk z!(*4ppN2Ni+bVhBiT6n!+8{N0b-=2OJbjU3#-%Ntqstk{kQU~2Kh2wMk_vFF3HWSp zE@y@*9!+c~{q(CLh8w_;?9-+i-l=a;z@{6y=V!SHo_c9w}wiB3fyk&o9_XN0WGI+|W!IwPoHXMeV%f6h7#A^?Y{6)jdC~BV_*|7QFI`) z{!)sq!?kYXLH{wcbYC4 zh)oT&#*!0nJ|;01_DYVyAWpvP1JeuXuS^2^1-vKJwrQZj-BC|Dxw7*LME%9Fr&e^b z5Z^PH{aJ2trCgr6dMCP4R%o~M2lU$gR5kO6&pgWA+4i`ubcx5Et)fUAfcWS#;3)x- z!{w5O5t-L()pr3U+g_mo1#YaA{t*eBJf!0WoSBtc;?MK?n{fx!$s#hiNyYRbs^waX zdP1%O}nFD;pe!he-J$|iAI&U1U|l$G9pAByM143c;H*!ARE4=cR8qB z+`PH`NX+2rY=&5c;E9br?NXaDboKOc(e2Hkx8|0MHd6QGw#w(*%vsgU-+6LUOJocD zVyxExoI1fV)J@;`a6o`JL;l89r-BEykEt9EIj6dij+1k&=35ZIod^ z>x^wdfnGW7kB8x&(O}a=Jddm=`-CZzjU{;Xqe82bMS`QY80>hHW)L-DJ@HY061tSVa=hUxHvxN-*3(j7tOCRaC`w^>V&EOT> zhc9EOO6;i+1V%>R91+;Wqksb}Tvv-83xz`V7+WMV6+TAP z>9u$^qmfu@UKrI~o8ZW_x_tW)?((|7nf~@yo6sZUI7RRGhs3LFbu#Z;Ax4Q1Bk9}= z$y}>P%S|3~2flKBYv=@#*r#28G?jZ)&MGy;sBR7Lw8BTYTSZYIP04{z zmQ)eVcsjBn*(RMU&W%=*cEw){_$Ld7NQl4lY_xs74wVDY?I%%TH3*lc$(=k2HgD{` z=s{(!bM|_#eOah4epy|G9I{Znn9fW~BMhPz(8%|Fgnv%)x@!O}`qLB_E9R^h@f&@5 z^y*RSdMx)0sYT_|%CzuN;{xLzlc+{^w~yWN*s_AV&DpaL^X<>ElufAK%dfDNShPew z60+#pSXjl$egGM5SYvEsX{QXZJ#*BT4x9!8EWh5Yg6LK-G!GmLd8 zmu|vUiw+7{tucGB6mPv88nYC2JrrYWj`4h`e3LtS^( zbXE>vCjm^fKb`J`PwyuG*9rU138e$-;r@?q_fT$*FCG4?kDKj3uXFcJP7c<;JE3Ec zV*cN9tSHZaU4?;n!{3OrYJvW9fxilz{!T|jD-1k9ng1qt`d8v#OA!AghSL2}kofPE zzuV{EDG$;1*+?E1e`{%+U*q+H%neviRFk?vyfCy7!2_lW%e8Hy;zU3~tDaTlLI d-vL1}{uM1P5Z3)W_yOv!K*{AsqbAVM{s+3Zd*uKC diff --git a/src/android/libs/fgchecker-1.1.0.pom b/src/android/libs/fgchecker-1.1.0.pom deleted file mode 100644 index e001f9852..000000000 --- a/src/android/libs/fgchecker-1.1.0.pom +++ /dev/null @@ -1,17 +0,0 @@ - - - 4.0.0 - com.rvalerio - fgchecker - 1.1.0 - aar - - - com.android.support - appcompat-v7 - 26.0.1 - runtime - - - diff --git a/src/android/src/com/rvalerio/fgchecker/AppChecker.java b/src/android/src/com/rvalerio/fgchecker/AppChecker.java new file mode 100644 index 000000000..afa96ba4a --- /dev/null +++ b/src/android/src/com/rvalerio/fgchecker/AppChecker.java @@ -0,0 +1,126 @@ +package com.rvalerio.fgchecker; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; + +import com.rvalerio.fgchecker.detectors.Detector; +import com.rvalerio.fgchecker.detectors.LollipopDetector; +import com.rvalerio.fgchecker.detectors.PreLollipopDetector; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + + + +public class AppChecker { + static final int DEFAULT_TIMEOUT = 1000; + + int timeout = DEFAULT_TIMEOUT; + ScheduledExecutorService service; + Runnable runnable; + Listener unregisteredPackageListener; + Listener anyPackageListener; + Map listeners; + Detector detector; + Handler handler; + + public interface Listener { + void onForeground(String process); + } + + + public AppChecker() { + listeners = new HashMap<>(); + handler = new Handler(Looper.getMainLooper()); + if(Utils.postLollipop()) + detector = new LollipopDetector(); + else + detector = new PreLollipopDetector(); + } + + public AppChecker timeout(int timeout) { + this.timeout = timeout; + return this; + } + + public AppChecker when(String packageName, Listener listener) { + listeners.put(packageName, listener); + return this; + } + + @Deprecated + public AppChecker other(Listener listener) { + return whenOther(listener); + } + + public AppChecker whenOther(Listener listener) { + unregisteredPackageListener = listener; + return this; + } + + public AppChecker whenAny(Listener listener) { + anyPackageListener = listener; + return this; + } + + public void start(Context context) { + runnable = createRunnable(context.getApplicationContext()); + service = new ScheduledThreadPoolExecutor(1); + service.schedule(runnable, timeout, TimeUnit.MILLISECONDS); + } + + public void stop() { + if(service != null) { + service.shutdownNow(); + service = null; + } + runnable = null; + } + + private Runnable createRunnable(final Context context) { + return new Runnable() { + @Override + public void run() { + getForegroundAppAndNotify(context); + service.schedule(createRunnable(context), timeout, TimeUnit.MILLISECONDS); + } + }; + } + + private void getForegroundAppAndNotify(Context context) { + final String foregroundApp = getForegroundApp(context); + boolean foundRegisteredPackageListener = false; + if(foregroundApp != null) { + for (String packageName : listeners.keySet()) { + if (packageName.equalsIgnoreCase(foregroundApp)) { + foundRegisteredPackageListener = true; + callListener(listeners.get(foregroundApp), foregroundApp); + } + } + + if(!foundRegisteredPackageListener && unregisteredPackageListener != null) { + callListener(unregisteredPackageListener, foregroundApp); + } + } + if(anyPackageListener != null) { + callListener(anyPackageListener, foregroundApp); + } + } + + void callListener(final Listener listener, final String packageName) { + handler.post(new Runnable() { + @Override + public void run() { + listener.onForeground(packageName); + } + }); + } + + public String getForegroundApp(Context context) { + return detector.getForegroundApp(context); + } +} \ No newline at end of file diff --git a/src/android/src/com/rvalerio/fgchecker/Utils.java b/src/android/src/com/rvalerio/fgchecker/Utils.java new file mode 100644 index 000000000..db62c4d8a --- /dev/null +++ b/src/android/src/com/rvalerio/fgchecker/Utils.java @@ -0,0 +1,26 @@ +package com.rvalerio.fgchecker; + +import android.annotation.TargetApi; +import android.app.AppOpsManager; +import android.content.Context; +import android.os.Build; + +public class Utils { + private Utils() { + + } + + public static boolean postLollipop() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + public static boolean hasUsageStatsPermission(Context context) { + AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + int mode = appOps.checkOpNoThrow("android:get_usage_stats", + android.os.Process.myUid(), context.getPackageName()); + boolean granted = mode == AppOpsManager.MODE_ALLOWED; + return granted; + } + +} diff --git a/src/android/src/com/rvalerio/fgchecker/detectors/Detector.java b/src/android/src/com/rvalerio/fgchecker/detectors/Detector.java new file mode 100644 index 000000000..d61adf25c --- /dev/null +++ b/src/android/src/com/rvalerio/fgchecker/detectors/Detector.java @@ -0,0 +1,8 @@ +package com.rvalerio.fgchecker.detectors; + + +import android.content.Context; + +public interface Detector { + String getForegroundApp(Context context); +} diff --git a/src/android/src/com/rvalerio/fgchecker/detectors/LollipopDetector.java b/src/android/src/com/rvalerio/fgchecker/detectors/LollipopDetector.java new file mode 100644 index 000000000..6c8eb38da --- /dev/null +++ b/src/android/src/com/rvalerio/fgchecker/detectors/LollipopDetector.java @@ -0,0 +1,34 @@ +package com.rvalerio.fgchecker.detectors; + +import android.annotation.TargetApi; +import android.app.Service; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.os.Build; + +import com.rvalerio.fgchecker.Utils; + +public class LollipopDetector implements Detector { + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public String getForegroundApp(final Context context) { + if(!Utils.hasUsageStatsPermission(context)) + return null; + + String foregroundApp = null; + + UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Service.USAGE_STATS_SERVICE); + long time = System.currentTimeMillis(); + + UsageEvents usageEvents = mUsageStatsManager.queryEvents(time - 1000 * 3600, time); + UsageEvents.Event event = new UsageEvents.Event(); + while (usageEvents.hasNextEvent()) { + usageEvents.getNextEvent(event); + if(event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) { + foregroundApp = event.getPackageName(); + } + } + + return foregroundApp ; + } +} diff --git a/src/android/src/com/rvalerio/fgchecker/detectors/PreLollipopDetector.java b/src/android/src/com/rvalerio/fgchecker/detectors/PreLollipopDetector.java new file mode 100644 index 000000000..0fb74c07c --- /dev/null +++ b/src/android/src/com/rvalerio/fgchecker/detectors/PreLollipopDetector.java @@ -0,0 +1,30 @@ +package com.rvalerio.fgchecker.detectors; + +import android.app.ActivityManager; +import android.app.Service; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; + +public class PreLollipopDetector implements Detector { + @Override + public String getForegroundApp(Context context) { + ActivityManager am = (ActivityManager) context.getSystemService(Service.ACTIVITY_SERVICE); + ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0); + String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName(); + PackageManager pm = context.getPackageManager(); + PackageInfo foregroundAppPackageInfo = null; + try { + foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return null; + } + + String foregroundApp = null; + if(foregroundAppPackageInfo != null) + foregroundApp = foregroundAppPackageInfo.applicationInfo.packageName; + + return foregroundApp; + } +} From 2094222a543278a18a3c149391494013d3384bd2 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 5 Aug 2024 21:06:46 +0200 Subject: [PATCH 002/162] fix typo in the settings --- src/settings.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings.qml b/src/settings.qml index 319929fbe..f4bfcfaf2 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -4151,7 +4151,7 @@ import QtQuick.Dialogs 1.0 ComboBox { id: pelotonTreadmillLevelTextField model: [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ] - displayText: settings.peloton_rower_level + displayText: settings.peloton_treadmill_level Layout.fillHeight: false Layout.alignment: Qt.AlignRight | Qt.AlignVCenter onActivated: { From 71afb2881fbff64ae0019d4dfdabdabe9802c9da Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 6 Aug 2024 07:18:28 +0200 Subject: [PATCH 003/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index a05b47edb..b6c46d351 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 829; + CURRENT_PROJECT_VERSION = 830; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 829; + CURRENT_PROJECT_VERSION = 830; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 829; + CURRENT_PROJECT_VERSION = 830; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 829; + CURRENT_PROJECT_VERSION = 830; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 829; + CURRENT_PROJECT_VERSION = 830; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 829; + CURRENT_PROJECT_VERSION = 830; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 13f9502592b22116ae9b2a3f5a2dc049cf8f0411 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 6 Aug 2024 20:29:16 +0200 Subject: [PATCH 004/162] Unable to connect my Zwift Play to QZ #2458 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/zwift_play/abstractZapDevice.h | 10 +++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index b6c46d351..75fc114c4 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 830; + CURRENT_PROJECT_VERSION = 831; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 830; + CURRENT_PROJECT_VERSION = 831; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 830; + CURRENT_PROJECT_VERSION = 831; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 830; + CURRENT_PROJECT_VERSION = 831; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 830; + CURRENT_PROJECT_VERSION = 831; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 830; + CURRENT_PROJECT_VERSION = 831; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index ca9c10d9a..3ae807e4d 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -92,13 +92,9 @@ class AbstractZapDevice: public QObject { } else { emit minus(); } - }/* else if(bytes.length() > 14 && bytes[11] == 0x30 && bytes[12] == 0x00) { - if(zapType == LEFT) { - emit plus(); - } else { - emit minus(); - } - }*/ + } else if(bytes.length() > 19 && ((uint8_t)bytes[18]) == 0xc8) { + emit plus(); + } break; } From 06f72ba93735270599432ffe25393e36b4ab06bc Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 6 Aug 2024 22:00:36 +0200 Subject: [PATCH 005/162] Unable to connect my Zwift Play to QZ (Issue #2458) --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/ftmsbike/ftmsbike.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 75fc114c4..92184359c 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 831; + CURRENT_PROJECT_VERSION = 832; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 831; + CURRENT_PROJECT_VERSION = 832; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 831; + CURRENT_PROJECT_VERSION = 832; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 831; + CURRENT_PROJECT_VERSION = 832; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 831; + CURRENT_PROJECT_VERSION = 832; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 831; + CURRENT_PROJECT_VERSION = 832; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 0bf1c0c9f..eb901d903 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -840,10 +840,10 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact QByteArray b = newValue; if (gattWriteCharControlPointId.isValid()) { qDebug() << "routing FTMS packet to the bike from virtualbike" << characteristic.uuid() << newValue.toHex(' '); - lastPacketFromFTMS = newValue; // handling gears if (b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS) { + lastPacketFromFTMS = newValue; qDebug() << "applying gears mod" << m_gears; int16_t slope = (((uint8_t)b.at(3)) + (b.at(4) << 8)); if (m_gears != 0) { From 09e51d601375bb7616ecb1a1a2d7bcbef24c6c5d Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 6 Aug 2024 22:26:31 +0200 Subject: [PATCH 006/162] Unable to connect my Zwift Play to QZ (Issue #2458) --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/zwift_play/abstractZapDevice.h | 8 ++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 92184359c..98a765915 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 832; + CURRENT_PROJECT_VERSION = 833; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 832; + CURRENT_PROJECT_VERSION = 833; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 832; + CURRENT_PROJECT_VERSION = 833; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 832; + CURRENT_PROJECT_VERSION = 833; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 832; + CURRENT_PROJECT_VERSION = 833; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 832; + CURRENT_PROJECT_VERSION = 833; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index 3ae807e4d..053b0b9c6 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -94,6 +94,14 @@ class AbstractZapDevice: public QObject { } } else if(bytes.length() > 19 && ((uint8_t)bytes[18]) == 0xc8) { emit plus(); + } else if(bytes.length() > 3 && + (((uint8_t)bytes[3]) == 0xdf) || // right top button + (((uint8_t)bytes[3]) == 0xbf)) { // right bottom button + emit plus(); + } else if(bytes.length() > 3 && + (((uint8_t)bytes[3]) == 0xfd) || // left top button + (((uint8_t)bytes[3]) == 0xfb)) { // left bottom button + emit minus(); } break; From d233f04f67f35bec196bc261bcc916d4bae6a540 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 6 Aug 2024 23:18:56 +0200 Subject: [PATCH 007/162] Unable to connect my Zwift Play to QZ (Issue #2458) --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/ftmsbike/ftmsbike.cpp | 7 +++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 98a765915..c964cf05a 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 833; + CURRENT_PROJECT_VERSION = 834; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 833; + CURRENT_PROJECT_VERSION = 834; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 833; + CURRENT_PROJECT_VERSION = 834; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 833; + CURRENT_PROJECT_VERSION = 834; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 833; + CURRENT_PROJECT_VERSION = 834; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 833; + CURRENT_PROJECT_VERSION = 834; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index eb901d903..643b9d522 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -202,7 +202,7 @@ void ftmsbike::update() { 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"; + qDebug() << "injecting fake ftms frame in order to send the new gear value ASAP" << lastPacketFromFTMS.toHex(' '); ftmsCharacteristicChanged(QLowEnergyCharacteristic(), lastPacketFromFTMS); } @@ -843,7 +843,10 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact // handling gears if (b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS) { - lastPacketFromFTMS = newValue; + lastPacketFromFTMS.clear(); + for(int i=0; i Date: Tue, 6 Aug 2024 23:59:36 +0200 Subject: [PATCH 008/162] Unable to connect my Zwift Play to QZ (Issue #2458) --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/ftmsbike/ftmsbike.cpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index c964cf05a..04898c848 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 834; + CURRENT_PROJECT_VERSION = 836; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 834; + CURRENT_PROJECT_VERSION = 836; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 834; + CURRENT_PROJECT_VERSION = 836; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 834; + CURRENT_PROJECT_VERSION = 836; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 834; + CURRENT_PROJECT_VERSION = 836; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 834; + CURRENT_PROJECT_VERSION = 836; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 643b9d522..7a90382bd 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -844,8 +844,8 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact // handling gears if (b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS) { lastPacketFromFTMS.clear(); - for(int i=0; i Date: Wed, 7 Aug 2024 14:07:10 +0200 Subject: [PATCH 009/162] fixing crash on trainprogram overflow --- src/trainprogram.cpp | 50 +++++++++++++++++++++++++++++--------------- src/trainprogram.h | 1 + 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/trainprogram.cpp b/src/trainprogram.cpp index f2150c3ba..c489ecb03 100644 --- a/src/trainprogram.cpp +++ b/src/trainprogram.cpp @@ -963,6 +963,12 @@ void trainprogram::scheduler() { currentStepDistance += (odometerFromTheDevice - lastOdometer); lastOdometer = odometerFromTheDevice; + + if(currentStep >= rows.length()) { + qDebug() << "currentStep greater than row.length" << currentStep << rows.length(); + end(); + return; + } bool distanceStep = (rows.at(currentStep).distance > 0); distanceEvaluation = (distanceStep && currentStepDistance >= rows.at(currentStep).distance); qDebug() << qSetRealNumberPrecision(10) << QStringLiteral("currentStepDistance") << currentStepDistance @@ -983,6 +989,12 @@ void trainprogram::scheduler() { else currentStep++; + if(currentStep >= rows.length()) { + qDebug() << "currentStep greater than row.length" << currentStep << rows.length(); + end(); + return; + } + calculatedLine = currentStep; rows[currentStep].started = QDateTime::currentDateTime(); @@ -1127,23 +1139,8 @@ void trainprogram::scheduler() { emit changeGeoPosition(p, rows.at(currentStep).azimuth, avgAzimuthNext300Meters()); } } else { - qDebug() << QStringLiteral("trainprogram ends!"); - - // circuit? - if (!isnan(rows.first().latitude) && !isnan(rows.first().longitude) && - QGeoCoordinate(rows.first().latitude, rows.first().longitude) - .distanceTo(bluetoothManager->device()->currentCordinate()) < 50) { - emit lap(); - restart(); - distanceEvaluation = false; - } else { - started = false; - if (settings - .value(QZSettings::trainprogram_stop_at_end, QZSettings::default_trainprogram_stop_at_end) - .toBool()) - emit stop(false); - distanceEvaluation = false; - } + end(); + distanceEvaluation = false; } } else { if (rows.length() > currentStep && rows.at(currentStep).power != -1) { @@ -1210,6 +1207,25 @@ void trainprogram::scheduler() { } while (distanceEvaluation); } +void trainprogram::end() { + QSettings settings; + qDebug() << QStringLiteral("trainprogram ends!"); + + // circuit? + if (!isnan(rows.first().latitude) && !isnan(rows.first().longitude) && + QGeoCoordinate(rows.first().latitude, rows.first().longitude) + .distanceTo(bluetoothManager->device()->currentCordinate()) < 50) { + emit lap(); + restart(); + } else { + started = false; + if (settings + .value(QZSettings::trainprogram_stop_at_end, QZSettings::default_trainprogram_stop_at_end) + .toBool()) + emit stop(false); + } +} + bool trainprogram::overridePowerForCurrentRow(double power) { if (started && currentStep < rows.length() && currentRow().power != -1) { qDebug() << "overriding power from" << rows.at(currentStep).power << "to" << power; diff --git a/src/trainprogram.h b/src/trainprogram.h index b47896f95..0706a1015 100644 --- a/src/trainprogram.h +++ b/src/trainprogram.h @@ -144,6 +144,7 @@ private slots: void zwiftLoginState(bool ok); private: + void end(); mutable QRecursiveMutex schedulerMutex; double avgAzimuthNext300Meters(); QList inclinationNext300Meters(); From 8dd03df9a2be5e34fbeb60dee0fef44df589e207 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 7 Aug 2024 14:23:34 +0200 Subject: [PATCH 010/162] Nordictrack EXP 5i #2502 --- .../proformtreadmill/proformtreadmill.cpp | 87 ++++++++++++++++++- .../proformtreadmill/proformtreadmill.h | 1 + src/qzsettings.cpp | 4 +- src/qzsettings.h | 3 + src/settings.qml | 9 +- 5 files changed, 97 insertions(+), 7 deletions(-) diff --git a/src/devices/proformtreadmill/proformtreadmill.cpp b/src/devices/proformtreadmill/proformtreadmill.cpp index e936d43c5..f569aaf99 100644 --- a/src/devices/proformtreadmill/proformtreadmill.cpp +++ b/src/devices/proformtreadmill/proformtreadmill.cpp @@ -73,7 +73,7 @@ void proformtreadmill::forceIncline(double incline) { if (norditrack_s25i_treadmill) { write[14] = write[11] + write[12] + 0x11; } else if (proform_treadmill_8_0 || proform_treadmill_705_cst || proform_treadmill_705_cst_V78_239 || proform_treadmill_9_0 || proform_treadmill_se || - proform_treadmill_z1300i || proform_treadmill_l6_0s || norditrack_s25_treadmill || proform_8_5_treadmill || proform_2000_treadmill || + proform_treadmill_z1300i || proform_treadmill_l6_0s || norditrack_s25_treadmill || proform_8_5_treadmill || nordictrack_treadmill_exp_5i || proform_2000_treadmill || proform_treadmill_sport_8_5 || proform_treadmill_505_cst || proform_carbon_tl || proform_proshox2 || nordictrack_s20i_treadmill || proform_595i_proshox2 || proform_treadmill_8_7) { write[14] = write[11] + write[12] + 0x12; @@ -100,7 +100,7 @@ void proformtreadmill::forceSpeed(double speed) { if (norditrack_s25i_treadmill) { write[14] = write[11] + write[12] + 0x11; } else if (proform_treadmill_8_0 || proform_treadmill_9_0 || proform_treadmill_se || proform_cadence_lt || - proform_treadmill_z1300i || proform_treadmill_l6_0s || norditrack_s25_treadmill || proform_8_5_treadmill || proform_2000_treadmill || + proform_treadmill_z1300i || proform_treadmill_l6_0s || norditrack_s25_treadmill || proform_8_5_treadmill || nordictrack_treadmill_exp_5i || proform_2000_treadmill || proform_treadmill_sport_8_5 || proform_treadmill_505_cst || proform_treadmill_705_cst || proform_treadmill_705_cst_V78_239 || proform_carbon_tl || proform_proshox2 || nordictrack_s20i_treadmill || proform_595i_proshox2 || proform_treadmill_8_7) { write[14] = write[11] + write[12] + 0x11; @@ -545,7 +545,7 @@ void proformtreadmill::update() { if (counterPoll > 5) { counterPoll = 0; } - } else if (proform_8_5_treadmill) { + } else if (proform_8_5_treadmill || nordictrack_treadmill_exp_5i) { uint8_t noOpData1[] = {0xfe, 0x02, 0x19, 0x03}; uint8_t noOpData2[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x04, 0x15, 0x02, 0x00, 0x0f, 0x80, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t noOpData3[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -1887,7 +1887,7 @@ void proformtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha ((norditrack_s25i_treadmill) && (newValue.at(4) != 0x02 || (newValue.at(5) != 0x2f))) || ((nordictrack_t65s_treadmill || proform_pro_1000_treadmill || nordictrack_t65s_83_treadmill || nordictrack_s30_treadmill || - nordictrack_s20_treadmill || proform_treadmill_se || proform_cadence_lt || proform_8_5_treadmill || proform_carbon_tl || nordictrack_s20i_treadmill || proform_treadmill_8_7) && + nordictrack_s20_treadmill || proform_treadmill_se || proform_cadence_lt || proform_8_5_treadmill || nordictrack_treadmill_exp_5i || proform_carbon_tl || nordictrack_s20i_treadmill || proform_treadmill_8_7) && (newValue.at(4) != 0x02 || newValue.at(5) != 0x2e)) || (((uint8_t)newValue.at(12)) == 0xFF && ((uint8_t)newValue.at(13)) == 0xFF && @@ -1988,6 +1988,7 @@ void proformtreadmill::btinit() { .toBool(); proform_treadmill_z1300i = settings.value(QZSettings::proform_treadmill_z1300i, QZSettings::default_proform_treadmill_z1300i).toBool(); + nordictrack_treadmill_exp_5i = settings.value(QZSettings::nordictrack_treadmill_exp_5i, QZSettings::default_nordictrack_treadmill_exp_5i).toBool(); proform_pro_1000_treadmill = settings.value(QZSettings::proform_pro_1000_treadmill, QZSettings::default_proform_pro_1000_treadmill).toBool(); nordictrack_s20_treadmill = settings.value(QZSettings::nordictrack_s20_treadmill, @@ -3071,6 +3072,84 @@ void proformtreadmill::btinit() { QThread::msleep(sleepms); writeCharacteristic(noOpData6, sizeof(noOpData6), QStringLiteral("init"), false, false); QThread::msleep(sleepms); + } else if (nordictrack_treadmill_exp_5i) { + uint8_t initData1[] = {0xfe, 0x02, 0x08, 0x02}; + uint8_t initData2[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x81, 0x87, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData3[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x04, 0x04, 0x80, 0x88, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData4[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x04, 0x04, 0x88, 0x90, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData5[] = {0xfe, 0x02, 0x0a, 0x02}; + uint8_t initData6[] = {0xff, 0x0a, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x82, 0x00, + 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData7[] = {0xff, 0x0a, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x84, 0x00, + 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData8[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x95, 0x9b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData9[] = {0xfe, 0x02, 0x2c, 0x04}; + uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x04, 0x28, 0x90, 0x07, 0xe0, 0xd5, 0xc8, 0xc1, 0xb8, 0xbd, 0xb0, 0xb1, 0xb0, 0xb5}; + uint8_t initData11[] = {0x01, 0x12, 0xc8, 0xc1, 0xd8, 0xed, 0xe0, 0x11, 0x00, 0x35, 0x28, 0x41, 0x78, 0x9d, 0xb0, 0xd1, 0xf0, 0x15, 0x28, 0x41}; + uint8_t initData12[] = {0xff, 0x08, 0x98, 0xad, 0xc0, 0xa0, 0x02, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t noOpData1[] = {0xfe, 0x02, 0x17, 0x03}; + uint8_t noOpData2[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x04, 0x13, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t noOpData3[] = {0xff, 0x05, 0x00, 0x80, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t noOpData4[] = {0xfe, 0x02, 0x19, 0x03}; + uint8_t noOpData5[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x04, 0x15, 0x02, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t noOpData6[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t noOpData7[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x04, 0x15, 0x02, 0x00, 0x0f, 0x00, 0x10, 0x00, 0xd8, 0x1c, 0x48, 0x00, 0x00, 0xe0}; + uint8_t noOpData8[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData2, sizeof(initData2), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData3, sizeof(initData3), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData4, sizeof(initData4), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData5, sizeof(initData5), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData6, sizeof(initData6), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData5, sizeof(initData5), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData7, sizeof(initData7), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData8, sizeof(initData8), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData9, sizeof(initData9), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData10, sizeof(initData10), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData11, sizeof(initData11), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData1, sizeof(noOpData1), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData2, sizeof(noOpData2), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData3, sizeof(noOpData3), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData5, sizeof(noOpData5), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData6, sizeof(noOpData6), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData7, sizeof(noOpData7), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData8, sizeof(noOpData8), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); } else if (nordictrack_incline_trainer_x7i) { uint8_t initData1[] = {0xfe, 0x02, 0x08, 0x02}; uint8_t initData2[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x81, 0x87, diff --git a/src/devices/proformtreadmill/proformtreadmill.h b/src/devices/proformtreadmill/proformtreadmill.h index 83bcb274f..d34ac10af 100644 --- a/src/devices/proformtreadmill/proformtreadmill.h +++ b/src/devices/proformtreadmill/proformtreadmill.h @@ -96,6 +96,7 @@ class proformtreadmill : public treadmill { bool proform_595i_proshox2 = false; bool proform_treadmill_8_7 = false; bool proform_treadmill_705_cst_V78_239 = false; + bool nordictrack_treadmill_exp_5i = false; #ifdef Q_OS_IOS lockscreen *h = 0; diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index 0277cd570..6c482db8d 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -748,8 +748,9 @@ const QString QZSettings::atletica_lightspeed_treadmill = QStringLiteral("atleti const QString QZSettings::peloton_treadmill_level = QStringLiteral("peloton_treadmill_level"); const QString QZSettings::nordictrackadbbike_resistance = QStringLiteral("nordictrackadbbike_resistance"); const QString QZSettings::proform_treadmill_carbon_t7 = QStringLiteral("proform_treadmill_carbon_t7"); +const QString QZSettings::nordictrack_treadmill_exp_5i = QStringLiteral("nordictrack_treadmill_exp_5i"); -const uint32_t allSettingsCount = 632; +const uint32_t allSettingsCount = 633; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1388,6 +1389,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::peloton_treadmill_level, QZSettings::default_peloton_treadmill_level}, {QZSettings::nordictrackadbbike_resistance, QZSettings::default_nordictrackadbbike_resistance}, {QZSettings::proform_treadmill_carbon_t7, QZSettings::default_proform_treadmill_carbon_t7}, + {QZSettings::nordictrack_treadmill_exp_5i, QZSettings::default_nordictrack_treadmill_exp_5i}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index 33645dedc..c9533d1e2 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2096,6 +2096,9 @@ class QZSettings { static const QString proform_treadmill_carbon_t7; static constexpr bool default_proform_treadmill_carbon_t7 = false; + static const QString nordictrack_treadmill_exp_5i; + static constexpr bool default_nordictrack_treadmill_exp_5i = 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. diff --git a/src/settings.qml b/src/settings.qml index f4bfcfaf2..e3d419538 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -960,6 +960,7 @@ import QtQuick.Dialogs 1.0 property int peloton_treadmill_level: 1 property bool nordictrackadbbike_resistance: false property bool proform_treadmill_carbon_t7: false + property bool nordictrack_treadmill_exp_5i: false } function paddingZeros(text, limit) { @@ -5909,7 +5910,8 @@ import QtQuick.Dialogs 1.0 "Proform/NordicTrack z1300i", "Proform SE", "Proform Cadence LT", "Proform 8.0", "Proform 9.0", "Proform 705 CST", "Nordictrack x14i", "Proform Carbon TL", "Proform Proshox 2", "Nordictrack S20i", "Proform 595i", - "Proform 8.7", "Proform 705 CST V78.239", "Proform Carbon T7" + "Proform 8.7", "Proform 705 CST V78.239", "Proform Carbon T7", + "Nordictrack EXP 5i" ] onCurrentIndexChanged: { @@ -5948,6 +5950,7 @@ import QtQuick.Dialogs 1.0 settings.proform_treadmill_8_7 = false; settings.proform_treadmill_705_cst_V78_239 = false; settings.proform_treadmill_carbon_t7 = false; + settings.nordictrack_treadmill_exp_5i = false; // Imposta il setting corrispondente al modello selezionato switch (currentIndex) { @@ -5983,6 +5986,7 @@ import QtQuick.Dialogs 1.0 case 29: settings.proform_treadmill_8_7 = true; break; case 30: settings.proform_treadmill_705_cst_V78_239 = true; break; case 31: settings.proform_treadmill_carbon_t7 = true; break; + case 32: settings.nordictrack_treadmill_exp_5i = true; break; } } @@ -6019,7 +6023,8 @@ import QtQuick.Dialogs 1.0 settings.proform_595i_proshox2 ? 28 : settings.proform_treadmill_8_7 ? 29 : settings.proform_treadmill_705_cst_V78_239 ? 30 : - settings.proform_treadmill_carbon_t7 ? 31 : -1; + settings.proform_treadmill_carbon_t7 ? 31 : + settings.nordictrack_treadmill_exp_5i ? 32 : -1; console.log("treadmillModelComboBox " + "Component.onCompleted " + selectedModel); From 24fe3c625d789a8fb263c7a7406128bf56749b62 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 9 Aug 2024 15:10:41 +0200 Subject: [PATCH 011/162] Shifter stopped working after Qdomyos #561 https://github.com/doudar/SmartSpin2k/issues/561 --- src/devices/ftmsbike/ftmsbike.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 7a90382bd..bb39d5523 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -226,6 +226,13 @@ void ftmsbike::update() { emit debug(QStringLiteral("stopping...")); // writeCharacteristic(initDataF0C800B8, sizeof(initDataF0C800B8), "stop tape"); requestStop = -1; + + QSettings settings; + if (settings.value(QZSettings::ss2k_peloton, QZSettings::default_ss2k_peloton).toBool()) { + uint8_t write[] = {FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + writeCharacteristic(write, sizeof(write), QStringLiteral("init SS2K")); + } } } } From 3e6c1702899957cbf1e8c8aeb6556dabc88ee874 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 9 Aug 2024 15:21:00 +0200 Subject: [PATCH 012/162] Revert "Virtual iFit - Auto-resistance/incline not working #2467" This reverts commit 3327b8b1e63359b102685a6abc28ef790595dcb2. --- src/virtualdevices/virtualbike.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/virtualdevices/virtualbike.cpp b/src/virtualdevices/virtualbike.cpp index 2b4f7b2bf..52c031607 100644 --- a/src/virtualdevices/virtualbike.cpp +++ b/src/virtualdevices/virtualbike.cpp @@ -778,8 +778,8 @@ void virtualbike::characteristicChanged(const QLowEnergyCharacteristic &characte ((uint8_t)newValue.at(8)) == 0x02) { // ff0f0204020b070b0202041032020a0068000000 qDebug() << "ifit ans 15 stop request"; iFit_timer = 0; - reply1 = QByteArray::fromHex("fe0209020205070502021000ffffffffffffffff"); - reply2 = QByteArray::fromHex("ff0901040205070502021000ffffffffffffffff"); + reply1 = QByteArray::fromHex("fe02090200b40000005802000000000038000000"); + reply2 = QByteArray::fromHex("ff09010402050705020210000000000038000000"); writeCharacteristic(service, characteristic, reply1); writeCharacteristic(service, characteristic, reply2); } else if (newValue.length() > 12 && ((uint8_t)newValue.at(0)) == 0xFF && From 6092bbd3c31c6d330d34f44d34e6dc09a9a7ba0a Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 9 Aug 2024 15:24:17 +0200 Subject: [PATCH 013/162] Virtual iFit - Auto-resistance/incline not working #2467 --- src/virtualdevices/virtualbike.cpp | 10 ++++++++-- src/virtualdevices/virtualbike.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/virtualdevices/virtualbike.cpp b/src/virtualdevices/virtualbike.cpp index 52c031607..7e110e620 100644 --- a/src/virtualdevices/virtualbike.cpp +++ b/src/virtualdevices/virtualbike.cpp @@ -709,10 +709,15 @@ void virtualbike::characteristicChanged(const QLowEnergyCharacteristic &characte } else if (newValue.length() > 8 && ((uint8_t)newValue.at(0)) == 0xFF && ((uint8_t)newValue.at(1)) == 0x07 && ((uint8_t)newValue.at(7)) == 0x10) { qDebug() << "ifit ans 12"; - reply1 = QByteArray::fromHex("fe021c0300b4002200580200000000007e0000b4"); + if(iFit_Stop == false) { + reply1 = QByteArray::fromHex("fe021c0300b4002200580200000000007e0000b4"); + } else { + qDebug() << "ifit ans 12 - with stop request"; + reply1 = QByteArray::fromHex("fe021c0302050705020210000000000036000000"); + iFit_Stop = false; + } reply2 = QByteArray::fromHex("001201040218071802020000ffffffffffffffff"); reply3 = QByteArray::fromHex("ff0a00000000302a00000075ffffffffffffffff"); - writeCharacteristic(service, characteristic, reply1); writeCharacteristic(service, characteristic, reply2); writeCharacteristic(service, characteristic, reply3); @@ -778,6 +783,7 @@ void virtualbike::characteristicChanged(const QLowEnergyCharacteristic &characte ((uint8_t)newValue.at(8)) == 0x02) { // ff0f0204020b070b0202041032020a0068000000 qDebug() << "ifit ans 15 stop request"; iFit_timer = 0; + iFit_Stop = true; reply1 = QByteArray::fromHex("fe02090200b40000005802000000000038000000"); reply2 = QByteArray::fromHex("ff09010402050705020210000000000038000000"); writeCharacteristic(service, characteristic, reply1); diff --git a/src/virtualdevices/virtualbike.h b/src/virtualdevices/virtualbike.h index 05fc1f90b..1d82892f3 100644 --- a/src/virtualdevices/virtualbike.h +++ b/src/virtualdevices/virtualbike.h @@ -79,6 +79,7 @@ class virtualbike : public virtualdevice { qint64 iFit_TSLastFrame = 0; QByteArray iFit_LastFrameReceived; resistance_t iFit_LastResistanceRequested = 0; + bool iFit_Stop = false; bool echelonInitDone = false; void echelonWriteResistance(); From b5c68f5e6c5d315e9b98eb936a9ed1237946835f Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 9 Aug 2024 16:13:38 +0200 Subject: [PATCH 014/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 04898c848..34dbae702 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 836; + CURRENT_PROJECT_VERSION = 837; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 836; + CURRENT_PROJECT_VERSION = 837; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 836; + CURRENT_PROJECT_VERSION = 837; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 836; + CURRENT_PROJECT_VERSION = 837; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 836; + CURRENT_PROJECT_VERSION = 837; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 836; + CURRENT_PROJECT_VERSION = 837; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 6384268afff5a6df802b9c6f14858e3998db1a18 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sat, 10 Aug 2024 20:20:49 +0200 Subject: [PATCH 015/162] Kingsmith WalkingPad Z1 not connecting to QZ (Issue #2506) --- src/devices/bluetooth.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 512faad44..430383bed 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1080,6 +1080,9 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { // X23 King Smith b.name().toUpper().startsWith(QStringLiteral("KS-NACH-MXG")) || + // Kingsmith WalkingPad Z1 + b.name().toUpper().startsWith(QStringLiteral("KS-HD-Z1D")) || + // KingSmith Walking Pad G1 b.name().toUpper().startsWith(QStringLiteral("KS-NGCH-G1C"))) && !kingsmithR2Treadmill && filter) { From a100d4cc96da28536a9d11d45e4a6cccf9f8219c Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sat, 10 Aug 2024 20:28:46 +0200 Subject: [PATCH 016/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 34dbae702..cb28aa66e 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 837; + CURRENT_PROJECT_VERSION = 838; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 837; + CURRENT_PROJECT_VERSION = 838; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 837; + CURRENT_PROJECT_VERSION = 838; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 837; + CURRENT_PROJECT_VERSION = 838; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 837; + CURRENT_PROJECT_VERSION = 838; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 837; + CURRENT_PROJECT_VERSION = 838; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 445e8691f6d62b9252b3457eec025c803a3c0e20 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 12 Aug 2024 09:15:56 +0200 Subject: [PATCH 017/162] Kingsmith WalkingPad Z1 not connecting to QZ (Issue #2506) --- src/devices/bluetooth.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 430383bed..11fdea08b 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1080,9 +1080,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { // X23 King Smith b.name().toUpper().startsWith(QStringLiteral("KS-NACH-MXG")) || - // Kingsmith WalkingPad Z1 - b.name().toUpper().startsWith(QStringLiteral("KS-HD-Z1D")) || - // KingSmith Walking Pad G1 b.name().toUpper().startsWith(QStringLiteral("KS-NGCH-G1C"))) && !kingsmithR2Treadmill && filter) { @@ -1273,6 +1270,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { b.name().toUpper().startsWith(QStringLiteral("LJJ-")) || // LJJ-02351A b.name().toUpper().startsWith(QStringLiteral("WLT-EP-")) || // Flow elliptical (b.name().toUpper().startsWith("SCHWINN 810")) || + (b.name().toUpper().startsWith(QStringLiteral("KS-HD-Z1D"))) || // Kingsmith WalkingPad Z1 (b.name().toUpper().startsWith(QStringLiteral("FIT-")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // sports tech f37s treadmill #2412 (b.name().toUpper().startsWith(QStringLiteral("NOBLEPRO CONNECT")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // FTMS (b.name().toUpper().startsWith(QStringLiteral("TT8")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || From c23b936ecaebc4d3b4dfae35504f4b728481c9cc Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 12 Aug 2024 09:19:36 +0200 Subject: [PATCH 018/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index cb28aa66e..14bb9f7a9 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 838; + CURRENT_PROJECT_VERSION = 839; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 838; + CURRENT_PROJECT_VERSION = 839; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 838; + CURRENT_PROJECT_VERSION = 839; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 838; + CURRENT_PROJECT_VERSION = 839; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 838; + CURRENT_PROJECT_VERSION = 839; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 838; + CURRENT_PROJECT_VERSION = 839; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 4fe2cf6ea6f2f8d04f58a8406c358ae35e96b935 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 12 Aug 2024 11:54:14 +0200 Subject: [PATCH 019/162] Name device change (Issue #2508) --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 +++--- src/devices/dircon/dirconmanager.cpp | 7 ++-- src/qzsettings.cpp | 4 +- src/qzsettings.h | 3 ++ src/settings.qml | 37 +++++++++++++++++++ 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 14bb9f7a9..342c5b5b0 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 839; + CURRENT_PROJECT_VERSION = 840; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 839; + CURRENT_PROJECT_VERSION = 840; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 839; + CURRENT_PROJECT_VERSION = 840; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 839; + CURRENT_PROJECT_VERSION = 840; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 839; + CURRENT_PROJECT_VERSION = 840; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 839; + CURRENT_PROJECT_VERSION = 840; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/dircon/dirconmanager.cpp b/src/devices/dircon/dirconmanager.cpp index 1b3d0babb..85270c5e2 100644 --- a/src/devices/dircon/dirconmanager.cpp +++ b/src/devices/dircon/dirconmanager.cpp @@ -106,11 +106,12 @@ enum { DM_SERV_OP(DM_SERV_ENUMI_OP, 0, 0, 0) DM_SERV_I_NUM }; } \ } \ if (P2.size()) { \ + QString dircon_id = QString("%1").arg(settings.value(QZSettings::dircon_id, \ + QZSettings::default_dircon_id).toInt(), 4, 10, QChar('0')); \ DirconProcessor *processor = new DirconProcessor( \ P2, \ QString(QStringLiteral(NAME)) \ - .replace(QStringLiteral("$uuid_hex$"), \ - QString(QStringLiteral("%1")).arg(DM_MACHINE_##DESC, 4, 10, QLatin1Char('0'))), \ + .replace(QStringLiteral("$uuid_hex$"), dircon_id), \ server_base_port + DM_MACHINE_##DESC, QString(QStringLiteral("%1")).arg(DM_MACHINE_##DESC), mac, \ this); \ QString servdesc; \ @@ -149,7 +150,7 @@ DirconManager::DirconManager(bluetoothdevice *Bike, int8_t bikeResistanceOffset, QSettings settings; DirconProcessorService *service; QList services, proc_services; - bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType(); + bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType(); uint8_t type = dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL ? DM_MACHINE_TYPE_TREADMILL : DM_MACHINE_TYPE_BIKE; qDebug() << "Building Dircom Manager"; diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index 6c482db8d..bbe96f9ac 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -749,8 +749,9 @@ const QString QZSettings::peloton_treadmill_level = QStringLiteral("peloton_trea const QString QZSettings::nordictrackadbbike_resistance = QStringLiteral("nordictrackadbbike_resistance"); const QString QZSettings::proform_treadmill_carbon_t7 = QStringLiteral("proform_treadmill_carbon_t7"); const QString QZSettings::nordictrack_treadmill_exp_5i = QStringLiteral("nordictrack_treadmill_exp_5i"); +const QString QZSettings::dircon_id = QStringLiteral("dircon_id"); -const uint32_t allSettingsCount = 633; +const uint32_t allSettingsCount = 634; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1390,6 +1391,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::nordictrackadbbike_resistance, QZSettings::default_nordictrackadbbike_resistance}, {QZSettings::proform_treadmill_carbon_t7, QZSettings::default_proform_treadmill_carbon_t7}, {QZSettings::nordictrack_treadmill_exp_5i, QZSettings::default_nordictrack_treadmill_exp_5i}, + {QZSettings::dircon_id, QZSettings::default_dircon_id}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index c9533d1e2..41cc7e65e 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2099,6 +2099,9 @@ class QZSettings { static const QString nordictrack_treadmill_exp_5i; static constexpr bool default_nordictrack_treadmill_exp_5i = false; + static const QString dircon_id; + static constexpr int default_dircon_id = 0; + /** * @brief Write the QSettings values using the constants from this namespace. * @param showDefaults Optionally indicates if the default should be shown with the key. diff --git a/src/settings.qml b/src/settings.qml index e3d419538..b4d0ff2d2 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -961,6 +961,7 @@ import QtQuick.Dialogs 1.0 property bool nordictrackadbbike_resistance: false property bool proform_treadmill_carbon_t7: false property bool nordictrack_treadmill_exp_5i: false + property int dircon_id: 0 } function paddingZeros(text, limit) { @@ -9886,6 +9887,42 @@ import QtQuick.Dialogs 1.0 color: Material.color(Material.Lime) } + RowLayout { + spacing: 10 + Label { + text: qsTr("ID:") + Layout.fillWidth: true + } + TextField { + id: dirconIdTextField + text: settings.dircon_id + horizontalAlignment: Text.AlignRight + Layout.fillHeight: false + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + inputMethodHints: Qt.ImhFormattedNumbersOnly + onAccepted: settings.dircon_id = text + onActiveFocusChanged: if(this.focus) this.cursorPosition = this.text.length + } + Button { + text: "OK" + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + onClicked: { settings.dircon_id = dirconIdTextField.text; toast.show("Setting saved!"); window.settings_restart_to_apply = true; } + } + } + + Label { + text: qsTr("If you have multiple QZ instances, you can change the id of the virtual wahoo device. Default: 0") + font.bold: true + font.italic: true + font.pixelSize: 9 + 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 { From b81656c3696058695ec9a68dc487a98c0d8630f2 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 13 Aug 2024 20:46:59 +0200 Subject: [PATCH 020/162] Kingsmith WalkingPad Z1 not connecting to QZ (Issue #2506) --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/bluetooth.cpp | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 342c5b5b0..9b60f0672 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4026,7 +4026,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 840; + CURRENT_PROJECT_VERSION = 841; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4217,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 840; + CURRENT_PROJECT_VERSION = 841; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4444,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 840; + CURRENT_PROJECT_VERSION = 841; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4540,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 840; + CURRENT_PROJECT_VERSION = 841; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4632,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 840; + CURRENT_PROJECT_VERSION = 841; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4746,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 840; + CURRENT_PROJECT_VERSION = 841; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 11fdea08b..5bbd8a0da 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1114,6 +1114,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { b.name().toUpper().startsWith(QStringLiteral("KS-BLC")) || // Walkingpad C2 #1672 b.name().toUpper().startsWith( QStringLiteral("KS-BLR"))) && // Treadmill KingSmith WalkingPad R2 Pro KS-HCR1AA + !(b.name().toUpper().startsWith(QStringLiteral("KS-HD-Z1D"))) && // it's an FTMS one !kingsmithR1ProTreadmill && !kingsmithR2Treadmill && filter) { this->setLastBluetoothDevice(b); From bddd8cfaae70394567e056bfd1b6a2428043180e Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 15 Aug 2024 11:00:13 +0200 Subject: [PATCH 021/162] Update Wizard.qml --- src/Wizard.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Wizard.qml b/src/Wizard.qml index 0b3aa7085..445e6fe99 100644 --- a/src/Wizard.qml +++ b/src/Wizard.qml @@ -839,7 +839,7 @@ Page { Text { Layout.alignment: Qt.AlignHCenter - text: qsTr("Corrent startup phase:\n\n1. close any app that can connect to your Zwift devices\n2. wake up your Zwift devices\n3. wake up your trainer\n4. open qz\n5. now if you change gear on your Zwift device you will see a reaction in the gear tile on qz and so on your trainer.") + text: qsTr("Correct startup phase:\n\n1. close any app that can connect to your Zwift devices\n2. wake up your Zwift devices\n3. wake up your trainer\n4. open qz\n5. now if you change gear on your Zwift device you will see a reaction in the gear tile on qz and so on your trainer.") wrapMode: Text.WordWrap Layout.fillWidth: true width: stackViewLocal.width * 0.8 From fdbb70fd7354e77f8e174b5ad873adfdd3efa584 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 16 Aug 2024 06:24:48 +0200 Subject: [PATCH 022/162] Treadmill incline multiplied on QZ output [BUG] #2511 --- .../horizontreadmill/horizontreadmill.cpp | 93 ++++++++++++++++++- .../horizontreadmill/horizontreadmill.h | 1 + 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/devices/horizontreadmill/horizontreadmill.cpp b/src/devices/horizontreadmill/horizontreadmill.cpp index 4972cb21f..3161319ad 100644 --- a/src/devices/horizontreadmill/horizontreadmill.cpp +++ b/src/devices/horizontreadmill/horizontreadmill.cpp @@ -897,6 +897,7 @@ void horizontreadmill::update() { if (requestInclination != currentInclination().value() && requestInclination >= minInclination && requestInclination <= 15) { + emit debug(QStringLiteral("writing incline ") + QString::number(requestInclination)); forceIncline(requestInclination); } @@ -1301,6 +1302,56 @@ void horizontreadmill::forceIncline(double requestIncline) { writeS[1] = conversion[r]; writeS[2] = conversion1[r]; + } else if(ICONCEPT_FTMS_treadmill) { + if(requestInclination > 0 && requestInclination < 1) { + writeS[1] = 0x3C; + writeS[2] = 0x00; + } else if(requestInclination > 1 && requestInclination < 2) { + writeS[1] = 0x82; + writeS[2] = 0x00; + } else if(requestInclination > 2 && requestInclination < 3) { + writeS[1] = 0xC8; + writeS[2] = 0x00; + } else if(requestInclination > 3 && requestInclination < 4) { + writeS[1] = 0x04; + writeS[2] = 0x01; + } else if(requestInclination > 4 && requestInclination < 5) { + writeS[1] = 0x4A; + writeS[2] = 0x01; + } else if(requestInclination > 5 && requestInclination < 6) { + writeS[1] = 0x90; + writeS[2] = 0x01; + } else if(requestInclination > 6 && requestInclination < 7) { + writeS[1] = 0xCC; + writeS[2] = 0x01; + } else if(requestInclination > 7 && requestInclination < 8) { + writeS[1] = 0x12; + writeS[2] = 0x02; + } else if(requestInclination > 8 && requestInclination < 9) { + writeS[1] = 0x58; + writeS[2] = 0x02; + } else if(requestInclination > 9 && requestInclination < 10) { + writeS[1] = 0x94; + writeS[2] = 0x02; + } else if(requestInclination > 10 && requestInclination < 11) { + writeS[1] = 0xDA; + writeS[2] = 0x02; + } else if(requestInclination > 11 && requestInclination < 12) { + writeS[1] = 0x20; + writeS[2] = 0x03; + } else if(requestInclination > 12 && requestInclination < 13) { + writeS[1] = 0x5C; + writeS[2] = 0x03; + } else if(requestInclination > 13 && requestInclination < 14) { + writeS[1] = 0xA2; + writeS[2] = 0x03; + } else if(requestInclination > 14 && requestInclination < 15) { + writeS[1] = 0xE8; + writeS[2] = 0x03; + } else { + writeS[1] = 0x00; + writeS[2] = 0x00; + } } else { if(HORIZON_78AT_treadmill) requestIncline = requestIncline / 2.0; @@ -1675,7 +1726,7 @@ void horizontreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value())); if (Flags.inclination) { - if(!tunturi_t60_treadmill) + if(!tunturi_t60_treadmill && !ICONCEPT_FTMS_treadmill) Inclination = treadmillInclinationOverride((double)( (int16_t)( ((int16_t)(int8_t)newValue.at(index + 1) << 8) | @@ -1683,6 +1734,41 @@ void horizontreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha ) ) / 10.0); + else if(ICONCEPT_FTMS_treadmill) { + if(newValue.at(index) == 0x3C && newValue.at(index + 1) == 0x00) { + Inclination = 1; + } else if(newValue.at(index) == 0x82 && newValue.at(index + 1) == 0x00) { + Inclination = 2; + } else if(newValue.at(index) == 0xC8 && newValue.at(index + 1) == 0x00) { + Inclination = 3; + } else if(newValue.at(index) == 0x04 && newValue.at(index + 1) == 0x01) { + Inclination = 4; + } else if(newValue.at(index) == 0x4A && newValue.at(index + 1) == 0x01) { + Inclination = 5; + } else if(newValue.at(index) == 0x90 && newValue.at(index + 1) == 0x01) { + Inclination = 6; + } else if(newValue.at(index) == 0xCC && newValue.at(index + 1) == 0x01) { + Inclination = 7; + } else if(newValue.at(index) == 0x12 && newValue.at(index + 1) == 0x02) { + Inclination = 8; + } else if(newValue.at(index) == 0x58 && newValue.at(index + 1) == 0x02) { + Inclination = 9; + } else if(newValue.at(index) == 0x94 && newValue.at(index + 1) == 0x02) { + Inclination = 10; + } else if(newValue.at(index) == 0xDA && newValue.at(index + 1) == 0x02) { + Inclination = 11; + } else if(newValue.at(index) == 0x20 && newValue.at(index + 1) == 0x03) { + Inclination = 12; + } else if(newValue.at(index) == 0x5C && newValue.at(index + 1) == 0x03) { + Inclination = 13; + } else if(newValue.at(index) == 0xA2 && newValue.at(index + 1) == 0x03) { + Inclination = 14; + } else if(newValue.at(index) == 0xE8 && newValue.at(index + 1) == 0x03) { + Inclination = 15; + } else { + Inclination = 0; + } + } index += 4; // the ramo value is useless emit debug(QStringLiteral("Current Inclination: ") + QString::number(Inclination.value())); } @@ -2237,6 +2323,9 @@ void horizontreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device) { } else if(device.name().toUpper().startsWith("HORIZON_7.8AT")) { HORIZON_78AT_treadmill = true; qDebug() << QStringLiteral("HORIZON_7.8AT workaround ON!"); + } else if(device.name().toUpper().startsWith("T01_")) { + ICONCEPT_FTMS_treadmill = true; + qDebug() << QStringLiteral("ICONCEPT_FTMS_treadmill workaround ON!"); } if (device.name().toUpper().startsWith(QStringLiteral("TRX3500"))) { @@ -2956,7 +3045,7 @@ void horizontreadmill::testProfileCRC() { double horizontreadmill::minStepInclination() { QSettings settings; bool toorx_ftms_treadmill = settings.value(QZSettings::toorx_ftms_treadmill, QZSettings::default_toorx_ftms_treadmill).toBool(); - if (kettler_treadmill || trx3500_treadmill || toorx_ftms_treadmill || sole_tt8_treadmill) + if (kettler_treadmill || trx3500_treadmill || toorx_ftms_treadmill || sole_tt8_treadmill || ICONCEPT_FTMS_treadmill) return 1.0; else return 0.5; diff --git a/src/devices/horizontreadmill/horizontreadmill.h b/src/devices/horizontreadmill/horizontreadmill.h index c7326389b..983d15344 100644 --- a/src/devices/horizontreadmill/horizontreadmill.h +++ b/src/devices/horizontreadmill/horizontreadmill.h @@ -97,6 +97,7 @@ class horizontreadmill : public treadmill { bool technogymrun = false; bool disableAutoPause = false; bool HORIZON_78AT_treadmill = false; + bool ICONCEPT_FTMS_treadmill = false; void testProfileCRC(); void updateProfileCRC(); From 430f41e5b95125e7ed458c0887e9c842de3da5a0 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 16 Aug 2024 06:29:51 +0200 Subject: [PATCH 023/162] HARISON-X15 #2517 --- src/devices/bluetooth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 5bbd8a0da..c79b0195e 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1464,6 +1464,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { (b.name().toUpper().startsWith("FLX") && b.name().length() == 10) || (b.name().toUpper().startsWith("CSRB") && b.name().length() == 11) || (b.name().toUpper().startsWith("DU30-")) || // BodyTone du30 + (b.name().toUpper().startsWith("HARISON-X15")) || (b.name().toUpper().startsWith("GLT") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || (b.name().toUpper().startsWith("SPORT01-") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // Labgrey Magnetic Exercise Bike https://www.amazon.co.uk/dp/B0CXMF1NPY?_encoding=UTF8&psc=1&ref=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&ref_=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&social_share=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&skipTwisterOG=1 (b.name().toUpper().startsWith("ZUMO")) || (b.name().toUpper().startsWith("XS08-")) || From 3abf9557135561fe44ae60c5b1c2545d121d213a Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 16 Aug 2024 07:09:33 +0200 Subject: [PATCH 024/162] Pro-form Carbon E7 not connecting #2515 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 22 +- src/devices/bluetooth.cpp | 25 +- src/devices/bluetooth.h | 2 + .../nordictrackifitadbelliptical.cpp | 655 ++++++++++++++++++ .../nordictrackifitadbelliptical.h | 117 ++++ src/qdomyos-zwift.pri | 2 + src/qzsettings.cpp | 5 +- src/qzsettings.h | 3 + src/settings.qml | 36 + 9 files changed, 859 insertions(+), 8 deletions(-) create mode 100644 src/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.cpp create mode 100644 src/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.h diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 9b60f0672..f9f18d00f 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -174,6 +174,8 @@ 8727C7D12B3BF1B8005429EB /* QTelnet.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727C7CF2B3BF1B8005429EB /* QTelnet.cpp */; }; 8727C7D42B3BF1E4005429EB /* moc_QTelnet.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727C7D22B3BF1E4005429EB /* moc_QTelnet.cpp */; }; 8727C7D52B3BF1E4005429EB /* moc_proformtelnetbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727C7D32B3BF1E4005429EB /* moc_proformtelnetbike.cpp */; }; + 872973822C6F13B100D6D9A4 /* moc_nordictrackifitadbelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872973812C6F13B000D6D9A4 /* moc_nordictrackifitadbelliptical.cpp */; }; + 872973852C6F13C400D6D9A4 /* nordictrackifitadbelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872973832C6F13C300D6D9A4 /* nordictrackifitadbelliptical.cpp */; }; 872A20DA28C5EC380037774D /* faketreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872A20D928C5EC380037774D /* faketreadmill.cpp */; }; 872A20DC28C5F5CE0037774D /* moc_faketreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872A20DB28C5F5CE0037774D /* moc_faketreadmill.cpp */; }; 872BAB4E261750EE006A59AB /* libQt5Charts.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 872BAB4D261750EE006A59AB /* libQt5Charts.a */; }; @@ -951,6 +953,9 @@ 8727C7D22B3BF1E4005429EB /* moc_QTelnet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_QTelnet.cpp; sourceTree = ""; }; 8727C7D32B3BF1E4005429EB /* moc_proformtelnetbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_proformtelnetbike.cpp; sourceTree = ""; }; 8729149E2B2B010600565E33 /* qdomyoszwift-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "qdomyoszwift-Bridging-Header.h"; sourceTree = ""; }; + 872973812C6F13B000D6D9A4 /* moc_nordictrackifitadbelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_nordictrackifitadbelliptical.cpp; sourceTree = ""; }; + 872973832C6F13C300D6D9A4 /* nordictrackifitadbelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = nordictrackifitadbelliptical.cpp; path = ../src/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.cpp; sourceTree = ""; }; + 872973842C6F13C400D6D9A4 /* nordictrackifitadbelliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nordictrackifitadbelliptical.h; path = ../src/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.h; sourceTree = ""; }; 872A20D828C5EC380037774D /* faketreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = faketreadmill.h; path = ../src/devices/faketreadmill/faketreadmill.h; sourceTree = ""; }; 872A20D928C5EC380037774D /* faketreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = faketreadmill.cpp; path = ../src/devices/faketreadmill/faketreadmill.cpp; sourceTree = ""; }; 872A20DB28C5F5CE0037774D /* moc_faketreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_faketreadmill.cpp; sourceTree = ""; }; @@ -2058,6 +2063,9 @@ 2EB56BE3C2D93CDAB0C52E67 /* Sources */ = { isa = PBXGroup; children = ( + 872973832C6F13C300D6D9A4 /* nordictrackifitadbelliptical.cpp */, + 872973842C6F13C400D6D9A4 /* nordictrackifitadbelliptical.h */, + 872973812C6F13B000D6D9A4 /* moc_nordictrackifitadbelliptical.cpp */, 873D3C4B2C296B3700770CB9 /* jumprope.cpp */, 873D3C4C2C296B3700770CB9 /* jumprope.h */, 873D3C492C296B0100770CB9 /* moc_jumprope.cpp */, @@ -3325,6 +3333,7 @@ 8768C8C92BBC11C80099DBE1 /* adb_client.c in Compile Sources */, 873063C0259DF2C500DA0F44 /* moc_heartratebelt.cpp in Compile Sources */, DD5ED224478CB82859C61B9F /* fit_buffered_record_mesg_broadcaster.cpp in Compile Sources */, + 872973852C6F13C400D6D9A4 /* nordictrackifitadbelliptical.cpp in Compile Sources */, 87368825259C602800C71C7E /* watchAppStart.swift in Compile Sources */, 87BCE6BF29F28F95001F70EB /* moc_ypooelliptical.cpp in Compile Sources */, 876ED21925C3E9000065F3DC /* moc_ftmsbike.cpp in Compile Sources */, @@ -3347,6 +3356,7 @@ 879F16462847E55C00CE4945 /* proformellipticaltrainer.cpp in Compile Sources */, 8730A3922B404159007E336D /* zwift_protobuf_layer.swift in Compile Sources */, 87917A7728E768D200F8D9AC /* Client.swift in Compile Sources */, + 872973822C6F13B100D6D9A4 /* moc_nordictrackifitadbelliptical.cpp in Compile Sources */, 873824B927E64707004F1B46 /* moc_provider.cpp in Compile Sources */, 8727A47727849EA600019B5D /* paferstreadmill.cpp in Compile Sources */, DF1FD9718B75FA591A7E3D80 /* fit_decode.cpp in Compile Sources */, @@ -4026,7 +4036,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 841; + CURRENT_PROJECT_VERSION = 842; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4217,7 +4227,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 841; + CURRENT_PROJECT_VERSION = 842; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4444,7 +4454,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 841; + CURRENT_PROJECT_VERSION = 842; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4540,7 +4550,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 841; + CURRENT_PROJECT_VERSION = 842; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4632,7 +4642,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 841; + CURRENT_PROJECT_VERSION = 842; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4746,7 +4756,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 841; + CURRENT_PROJECT_VERSION = 842; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index c79b0195e..21e27645a 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -110,6 +110,7 @@ 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(); + 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(); bool fakedevice_elliptical = @@ -118,7 +119,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) { + if (!nordictrack_2950_ip.isEmpty() || !tdf_10_ip.isEmpty() || fake_bike || fakedevice_elliptical || fakedevice_rower || fakedevice_treadmill || !proform_elliptical_ip.isEmpty()) { // faking a bluetooth device qDebug() << "faking a bluetooth device for nordictrack_2950_ip"; deviceDiscovered(QBluetoothDeviceInfo()); @@ -426,6 +427,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { 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(); + QString proform_elliptical_ip = settings.value(QZSettings::proform_elliptical_ip, QZSettings::default_proform_elliptical_ip).toString(); QString computrainerSerialPort = settings.value(QZSettings::computrainer_serialport, QZSettings::default_computrainer_serialport).toString(); QString csaferowerSerialPort = settings.value(QZSettings::csafe_rower, QZSettings::default_csafe_rower).toString(); @@ -774,6 +776,20 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { emit searchingStop(); } this->signalBluetoothDeviceConnected(nordictrackifitadbBike); + } else if (!proform_elliptical_ip.isEmpty() && !nordictrackifitadbElliptical) { + this->stopDiscovery(); + nordictrackifitadbElliptical = new nordictrackifitadbelliptical(noWriteResistance, noHeartService, + bikeResistanceOffset, bikeResistanceGain); + emit deviceConnected(b); + connect(nordictrackifitadbElliptical, &bluetoothdevice::connectedAndDiscovered, this, + &bluetooth::connectedAndDiscovered); + connect(nordictrackifitadbElliptical, &nordictrackifitadbelliptical::debug, this, &bluetooth::debug); + // nordictrackifitadbTreadmill->deviceDiscovered(b); + // connect(this, SIGNAL(searchingStop()), cscBike, SLOT(searchingStop())); //NOTE: Commented due to #358 + if (this->discoveryAgent && !this->discoveryAgent->isActive()) { + emit searchingStop(); + } + this->signalBluetoothDeviceConnected(nordictrackifitadbElliptical); } else if (((csc_as_bike && b.name().startsWith(cscName)) || b.name().toUpper().startsWith(QStringLiteral("JOROTO-BK-"))) && !cscBike && filter) { @@ -2795,6 +2811,11 @@ void bluetooth::restart() { delete nordictrackifitadbBike; nordictrackifitadbBike = nullptr; } + if (nordictrackifitadbElliptical) { + + delete nordictrackifitadbElliptical; + nordictrackifitadbElliptical = nullptr; + } if (powerBike) { delete powerBike; @@ -3213,6 +3234,8 @@ bluetoothdevice *bluetooth::device() { return nordictrackifitadbTreadmill; } else if (nordictrackifitadbBike) { return nordictrackifitadbBike; + } else if (nordictrackifitadbElliptical) { + return nordictrackifitadbElliptical; } else if (powerBike) { return powerBike; } else if (powerTreadmill) { diff --git a/src/devices/bluetooth.h b/src/devices/bluetooth.h index 68b3239b1..48c7442a3 100644 --- a/src/devices/bluetooth.h +++ b/src/devices/bluetooth.h @@ -76,6 +76,7 @@ #include "devices/nautilustreadmill/nautilustreadmill.h" #include "devices/nordictrackelliptical/nordictrackelliptical.h" #include "devices/nordictrackifitadbbike/nordictrackifitadbbike.h" +#include "devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.h" #include "devices/nordictrackifitadbtreadmill/nordictrackifitadbtreadmill.h" #include "devices/npecablebike/npecablebike.h" #include "devices/octaneelliptical/octaneelliptical.h" @@ -193,6 +194,7 @@ class bluetooth : public QObject, public SignalHandler { nordictrackelliptical *nordictrackElliptical = nullptr; nordictrackifitadbtreadmill *nordictrackifitadbTreadmill = nullptr; nordictrackifitadbbike *nordictrackifitadbBike = nullptr; + nordictrackifitadbelliptical *nordictrackifitadbElliptical = nullptr; octaneelliptical *octaneElliptical = nullptr; octanetreadmill *octaneTreadmill = nullptr; pelotonbike *pelotonBike = nullptr; diff --git a/src/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.cpp b/src/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.cpp new file mode 100644 index 000000000..4ce8a42a7 --- /dev/null +++ b/src/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.cpp @@ -0,0 +1,655 @@ +#include "nordictrackifitadbelliptical.h" + +#ifdef Q_OS_ANDROID +#include "keepawakehelper.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::chrono_literals; + +nordictrackifitadbellipticalLogcatAdbThread::nordictrackifitadbellipticalLogcatAdbThread(QString s) { Q_UNUSED(s) } + +void nordictrackifitadbellipticalLogcatAdbThread::run() { + QSettings settings; + QString ip = settings.value(QZSettings::tdf_10_ip, QZSettings::default_tdf_10_ip).toString(); + runAdbCommand("connect " + ip); + + while (1) { + runAdbTailCommand("logcat"); + if(adbCommandPending.length() != 0) { + runAdbCommand(adbCommandPending); + adbCommandPending = ""; + } + msleep(100); + } +} + +QString nordictrackifitadbellipticalLogcatAdbThread::runAdbCommand(QString command) { +#ifdef Q_OS_WINDOWS + QProcess process; + emit debug("adb >> " + command); + process.start("adb/adb.exe", QStringList(command.split(' '))); + process.waitForFinished(-1); // will wait forever until finished + + QString out = process.readAllStandardOutput(); + QString err = process.readAllStandardError(); + + emit debug("adb << OUT " + out); + emit debug("adb << ERR" + err); +#else + QString out; +#endif + return out; +} + +bool nordictrackifitadbellipticalLogcatAdbThread::runCommand(QString command) { + if(adbCommandPending.length() == 0) { + adbCommandPending = command; + return true; + } + return false; +} + +void nordictrackifitadbellipticalLogcatAdbThread::runAdbTailCommand(QString command) { +#ifdef Q_OS_WINDOWS + auto process = new QProcess; + QObject::connect(process, &QProcess::readyReadStandardOutput, [process, this]() { + QString output = process->readAllStandardOutput(); + // qDebug() << "adbLogCat STDOUT << " << output; + QStringList lines = output.split('\n', Qt::SplitBehaviorFlags::SkipEmptyParts); + bool wattFound = false; + bool hrmFound = false; + foreach (QString line, lines) { + if (line.contains("Changed KPH")) { + emit debug(line); + speed = line.split(' ').last().toDouble(); + } else if (line.contains("Changed Grade")) { + emit debug(line); + inclination = line.split(' ').last().toDouble(); + } else if (line.contains("Changed Watts")) { + emit debug(line); + watt = line.split(' ').last().toDouble(); + wattFound = true; + } else if (line.contains("HeartRateDataUpdate")) { + emit debug(line); + QStringList splitted = line.split(' ', Qt::SkipEmptyParts); + if (splitted.length() > 14) { + hrm = splitted[14].toInt(); + hrmFound = true; + } + } + } + emit onSpeedInclination(speed, inclination); + if (wattFound) + emit onWatt(watt); + if (hrmFound) + emit onHRM(hrm); +#ifdef Q_OS_WINDOWS + if(adbCommandPending.length() != 0) { + runAdbCommand(adbCommandPending); + adbCommandPending = ""; + } +#endif + }); + QObject::connect(process, &QProcess::readyReadStandardError, [process, this]() { + auto output = process->readAllStandardError(); + emit debug("adbLogCat ERROR << " + output); + }); + emit debug("adbLogCat >> " + command); + process->start("adb/adb.exe", QStringList(command.split(' '))); + process->waitForFinished(-1); +#endif +} + +nordictrackifitadbelliptical::nordictrackifitadbelliptical(bool noWriteResistance, bool noHeartService, + int8_t bikeResistanceOffset, double bikeResistanceGain) { + QSettings settings; + bool nordictrack_ifit_adb_remote = + settings.value(QZSettings::nordictrack_ifit_adb_remote, QZSettings::default_nordictrack_ifit_adb_remote) + .toBool(); + m_watt.setType(metric::METRIC_WATT); + Speed.setType(metric::METRIC_SPEED); + refresh = new QTimer(this); + this->noWriteResistance = noWriteResistance; + this->noHeartService = noHeartService; + initDone = false; + connect(refresh, &QTimer::timeout, this, &nordictrackifitadbelliptical::update); + ip = settings.value(QZSettings::tdf_10_ip, QZSettings::default_tdf_10_ip).toString(); + refresh->start(200ms); + + socket = new QUdpSocket(this); + bool result = socket->bind(QHostAddress::AnyIPv4, 8002); + qDebug() << result; + processPendingDatagrams(); + connect(socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams())); + + initRequest = true; + + // ******************************************* virtual treadmill init ************************************* + if (!firstStateChanged && !this->hasVirtualDevice()) { + bool virtual_device_enabled = + settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool(); +#ifdef Q_OS_IOS +#ifndef IO_UNDER_QT + bool cadence = + settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool(); + bool ios_peloton_workaround = + settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool(); + if (ios_peloton_workaround && cadence) { + qDebug() << "ios_peloton_workaround activated!"; + h = new lockscreen(); + h->virtualbike_ios(); + } else +#endif +#endif + if (virtual_device_enabled) { + qDebug() << QStringLiteral("creating virtual bike interface..."); + auto virtualBike = + new virtualbike(this, noWriteResistance, noHeartService, bikeResistanceOffset, bikeResistanceGain); + // connect(virtualBike,&virtualbike::debug ,this,&echelonconnectsport::debug); + connect(virtualBike, &virtualbike::changeInclination, this, &nordictrackifitadbelliptical::changeInclination); + this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::PRIMARY); + } + } + firstStateChanged = 1; + // ******************************************************************************************************** + + if (nordictrack_ifit_adb_remote) { +#ifdef Q_OS_ANDROID + QAndroidJniObject IP = QAndroidJniObject::fromString(ip).object(); + QAndroidJniObject::callStaticMethod("org/cagnulen/qdomyoszwift/QZAdbRemote", "createConnection", + "(Ljava/lang/String;Landroid/content/Context;)V", + IP.object(), QtAndroid::androidContext().object()); +#elif defined Q_OS_WIN + logcatAdbThread = new nordictrackifitadbellipticalLogcatAdbThread("logcatAdbThread"); + /*connect(logcatAdbThread, &nordictrackifitadbellipticalLogcatAdbThread::onSpeedInclination, this, + &nordictrackifitadbelliptical::onSpeedInclination); + connect(logcatAdbThread, &nordictrackifitadbellipticalLogcatAdbThread::onWatt, this, + &nordictrackifitadbelliptical::onWatt);*/ + connect(logcatAdbThread, &nordictrackifitadbellipticalLogcatAdbThread::onHRM, this, &nordictrackifitadbelliptical::onHRM); + connect(logcatAdbThread, &nordictrackifitadbellipticalLogcatAdbThread::debug, this, &nordictrackifitadbelliptical::debug); + logcatAdbThread->start(); +#elif defined Q_OS_IOS +#ifndef IO_UNDER_QT + h->adb_connect(ip.toStdString().c_str()); +#endif +#endif + } +} + +bool nordictrackifitadbelliptical::inclinationAvailableByHardware() { + QSettings settings; + bool proform_studio_NTEX71021 = + settings.value(QZSettings::proform_studio_NTEX71021, QZSettings::default_proform_studio_NTEX71021) + .toBool(); + bool nordictrackadbbike_resistance = settings.value(QZSettings::nordictrackadbbike_resistance, QZSettings::default_nordictrackadbbike_resistance).toBool(); + + if(proform_studio_NTEX71021 || nordictrackadbbike_resistance) + return false; + else + return true; +} + +double nordictrackifitadbelliptical::getDouble(QString v) { + QChar d = QLocale().decimalPoint(); + if (d == ',') { + v = v.replace('.', ','); + } + return QLocale().toDouble(v); +} + +void nordictrackifitadbelliptical::processPendingDatagrams() { + qDebug() << "in !"; + QHostAddress sender; + QSettings settings; + uint16_t port; + while (socket->hasPendingDatagrams()) { + QByteArray datagram; + datagram.resize(socket->pendingDatagramSize()); + socket->readDatagram(datagram.data(), datagram.size(), &sender, &port); + lastSender = sender; + qDebug() << "Message From :: " << sender.toString(); + qDebug() << "Port From :: " << port; + qDebug() << "Message :: " << datagram; + + QString ip = settings.value(QZSettings::tdf_10_ip, QZSettings::default_tdf_10_ip).toString(); + QString heartRateBeltName = + settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString(); + double weight = settings.value(QZSettings::weight, QZSettings::default_weight).toFloat(); + bool nordictrackadbbike_resistance = settings.value(QZSettings::nordictrackadbbike_resistance, QZSettings::default_nordictrackadbbike_resistance).toBool(); + + double speed = 0; + double cadence = 0; + double resistance = 0; + double gear = 0; + double watt = 0; + double grade = 0; + QStringList lines = QString::fromLocal8Bit(datagram.data()).split("\n"); + foreach (QString line, lines) { + qDebug() << line; + + if (line.contains(QStringLiteral("Changed KPH")) && !settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) { + QStringList aValues = line.split(" "); + if (aValues.length()) { + speed = getDouble(aValues.last()); + Speed = speed; + } + } else if (line.contains(QStringLiteral("Changed RPM"))) { + QStringList aValues = line.split(" "); + if (aValues.length()) { + cadence = getDouble(aValues.last()); + Cadence = cadence; + Speed = Cadence.value() * + settings.value(QZSettings::cadence_sensor_speed_ratio, QZSettings::default_cadence_sensor_speed_ratio) + .toDouble(); + } + } else if (line.contains(QStringLiteral("Changed CurrentGear"))) { + QStringList aValues = line.split(" "); + if (aValues.length()) { + gear = getDouble(aValues.last()); + if(!nordictrackadbbike_resistance) + Resistance = gear; + gearsAvailable = true; + } + } else if (line.contains(QStringLiteral("Changed Resistance"))) { + QStringList aValues = line.split(" "); + if (aValues.length()) { + resistance = getDouble(aValues.last()); + m_pelotonResistance = (100 / 32) * resistance; + qDebug() << QStringLiteral("Current Peloton Resistance: ") << m_pelotonResistance.value() + << resistance; + if(!gearsAvailable && !nordictrackadbbike_resistance) { + Resistance = resistance; + } + } + } else if (line.contains(QStringLiteral("Changed Watts"))) { + QStringList aValues = line.split(" "); + if (aValues.length()) { + watt = getDouble(aValues.last()); + m_watt = watt; + } + } else if (line.contains(QStringLiteral("Changed Grade"))) { + QStringList aValues = line.split(" "); + if (aValues.length()) { + grade = getDouble(aValues.last()); + Inclination = grade; + } + } + } + + if (settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) { + Speed = metric::calculateSpeedFromPower( + watts(), Inclination.value(), Speed.value(), + fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), 20); + } + + bool proform_studio_NTEX71021 = + settings.value(QZSettings::proform_studio_NTEX71021, QZSettings::default_proform_studio_NTEX71021).toBool(); + bool nordictrack_ifit_adb_remote = + settings.value(QZSettings::nordictrack_ifit_adb_remote, QZSettings::default_nordictrack_ifit_adb_remote) + .toBool(); + double inclination_delay_seconds = settings.value(QZSettings::inclination_delay_seconds, QZSettings::default_inclination_delay_seconds).toDouble(); + + // only resistance + if(proform_studio_NTEX71021 || nordictrackadbbike_resistance) { + if (nordictrack_ifit_adb_remote) { + if (requestResistance != -1) { + if (requestResistance != currentResistance().value()) { + int x1 = 950; + int y2 = (int)(493 - (13.57 * (requestResistance - 1))); + int y1Resistance = (int)(493 - (13.57 * currentResistance().value())); + + if(!proform_studio_NTEX71021) { // s22i default + x1 = 1920 - 75; + y2 = (int)(803 - (23.777 * requestResistance)); + y1Resistance = (int)(803 - (23.777 * currentResistance().value())); + Resistance = requestResistance; + } + + lastCommand = "input swipe " + QString::number(x1) + " " + QString::number(y1Resistance) + " " + + QString::number(x1) + " " + QString::number(y2) + " 200"; + qDebug() << " >> " + lastCommand; +#ifdef Q_OS_ANDROID + QAndroidJniObject command = QAndroidJniObject::fromString(lastCommand).object(); + QAndroidJniObject::callStaticMethod("org/cagnulen/qdomyoszwift/QZAdbRemote", + "sendCommand", "(Ljava/lang/String;)V", + command.object()); +#elif defined(Q_OS_WIN) + if (logcatAdbThread) + logcatAdbThread->runCommand("shell " + lastCommand); +#elif defined Q_OS_IOS +#ifndef IO_UNDER_QT + h->adb_sendcommand(lastCommand.toStdString().c_str()); +#endif +#endif + } + } + + requestResistance = -1; + } + QByteArray message = (QString::number(requestResistance).toLocal8Bit()) + ";"; + requestResistance = -1; + int ret = socket->writeDatagram(message, message.size(), sender, 8003); + 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(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) { + qDebug() << "forcing inclination based on the erg mode resistance request of" << requestResistance; + requestInclination = requestResistance; + requestResistance = -100; + } + if (requestInclination != -100) { + double inc = qRound(requestInclination / 0.5) * 0.5; + if (inc != currentInclination().value()) { + bool proform_studio = settings.value(QZSettings::proform_studio, QZSettings::default_proform_studio).toBool(); + bool proform_tdf_10_0 = settings.value(QZSettings::proform_tdf_10_0, QZSettings::default_proform_tdf_10_0).toBool(); + int x1 = 75; + int y2 = (int)(616.18 - (17.223 * (inc + gears()))); + int y1Resistance = (int)(616.18 - (17.223 * currentInclination().value())); + + if(proform_studio) { + x1 = 1827; + y2 = (int)(806 - (21.375 * (inc + gears()))); + y1Resistance = (int)(806 - (21.375 * currentInclination().value())); + } else if(proform_tdf_10_0) { + x1 = 75; + y2 = (int)(477 - (12.5 * (inc + gears()))); + y1Resistance = (int)(477 - (12.5 * currentInclination().value())); + } + + lastCommand = "input swipe " + QString::number(x1) + " " + QString::number(y1Resistance) + " " + + QString::number(x1) + " " + QString::number(y2) + " 200"; + qDebug() << " >> " + lastCommand; +#ifdef Q_OS_ANDROID + QAndroidJniObject command = QAndroidJniObject::fromString(lastCommand).object(); + QAndroidJniObject::callStaticMethod("org/cagnulen/qdomyoszwift/QZAdbRemote", + "sendCommand", "(Ljava/lang/String;)V", + command.object()); +#elif defined(Q_OS_WIN) + if (logcatAdbThread) + logcatAdbThread->runCommand("shell " + lastCommand); +#elif defined Q_OS_IOS +#ifndef IO_UNDER_QT + h->adb_sendcommand(lastCommand.toStdString().c_str()); +#endif +#endif + // this bike has both inclination and resistance, let's try to handle both + // the Original Poster doesn't want anymore, but maybe it will be useful in the future + /* + if(freemotion_coachbike_b22_7) { + int x1 = 75; + int y2 = (int)(616.18 - (17.223 * (inc + gears()))); + int y1Resistance = (int)(616.18 - (17.223 * currentInclination().value())); + + lastCommand = "input swipe " + QString::number(x1) + " " + QString::number(y1Resistance) + " " + + QString::number(x1) + " " + QString::number(y2) + " 200"; + qDebug() << " >> " + lastCommand; + #ifdef Q_OS_ANDROID + QAndroidJniObject command = QAndroidJniObject::fromString(lastCommand).object(); + QAndroidJniObject::callStaticMethod("org/cagnulen/qdomyoszwift/QZAdbRemote", + "sendCommand", "(Ljava/lang/String;)V", + command.object()); + #elif defined(Q_OS_WIN) + if (logcatAdbThread) + logcatAdbThread->runCommand("shell " + lastCommand); + #elif defined Q_OS_IOS + #ifndef IO_UNDER_QT + h->adb_sendcommand(lastCommand.toStdString().c_str()); + #endif + #endif + } + */ + } + } + + requestInclination = -100; + } + + double r = currentResistance().value() + difficult() + gears(); // the inclination here is like the resistance for the other bikes + QByteArray message = (QString::number(requestInclination).toLocal8Bit()) + ";" + QString::number(r).toLocal8Bit(); + requestInclination = -100; + int ret = socket->writeDatagram(message, message.size(), sender, 8003); + qDebug() << QString::number(ret) + " >> " + message; + } + + if (watts()) + KCal += + ((((0.048 * ((double)watts()) + 1.19) * weight * 3.5) / 200.0) / + (60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo( + 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(QDateTime::currentDateTime()))); + + if (Cadence.value() > 0) { + CrankRevs++; + LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0)); + } + + lastRefreshCharacteristicChanged = QDateTime::currentDateTime(); + +#ifdef Q_OS_ANDROID + if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) + Heart = (uint8_t)KeepAwakeHelper::heart(); + else +#endif + { + if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) { + update_hr_from_external(); + } + } + +#ifdef Q_OS_IOS +#ifndef IO_UNDER_QT + bool cadencep = + settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool(); + bool ios_peloton_workaround = + settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool(); + if (ios_peloton_workaround && cadencep && h && firstStateChanged) { + h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime()); + h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate()); + } +#endif +#endif + + emit debug(QStringLiteral("Current Watt: ") + QString::number(watts())); + emit debug(QStringLiteral("Current Resistance: ") + QString::number(Resistance.value())); + emit debug(QStringLiteral("Current Gear: ") + QString::number(gear)); + emit debug(QStringLiteral("Current Cadence: ") + QString::number(Cadence.value())); + emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value())); + emit debug(QStringLiteral("Current Inclination: ") + QString::number(Inclination.value())); + emit debug(QStringLiteral("Current Calculate Distance: ") + QString::number(Distance.value())); + // debug("Current Distance: " + QString::number(distance)); + } +} + +void nordictrackifitadbelliptical::onHRM(int hrm) { + QSettings settings; + QString heartRateBeltName = + settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString(); + bool disable_hr_frommachinery = + settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool(); + + if ( +#ifdef Q_OS_ANDROID + (!settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) && +#endif + heartRateBeltName.startsWith(QStringLiteral("Disabled")) && !disable_hr_frommachinery) { + + Heart = hrm; + emit debug(QStringLiteral("Current Heart: ") + QString::number(Heart.value())); + } +} + +void nordictrackifitadbelliptical::forceResistance(double resistance) {} + +void nordictrackifitadbelliptical::update() { + + QSettings settings; + update_metrics(false, 0); + + if (initRequest) { + initRequest = false; + emit connectedAndDiscovered(); + } + + // updating the treadmill console every second + if (sec1Update++ == (500 / refresh->interval())) { + sec1Update = 0; + // updateDisplay(elapsed); + } + + if (requestStart != -1) { + emit debug(QStringLiteral("starting...")); + + // btinit(); + + requestStart = -1; + } + if (requestStop != -1) { + emit debug(QStringLiteral("stopping...")); + // writeCharacteristic(initDataF0C800B8, sizeof(initDataF0C800B8), "stop tape"); + requestStop = -1; + } +} + +uint16_t nordictrackifitadbelliptical::watts() { return m_watt.value(); } + +void nordictrackifitadbelliptical::changeInclinationRequested(double grade, double percentage) { + if (percentage < 0) + percentage = 0; + changeInclination(grade, percentage); +} + +bool nordictrackifitadbelliptical::connected() { return true; } + +uint16_t nordictrackifitadbelliptical::wattsFromResistance(double inclination, double cadence) { + // this is for the s22i + double power = 0.0; + + if (inclination == 0.0) { + power = 0.01 * cadence * cadence + -0.25 * cadence + 8.00; + } + else if (inclination == 0.5) { + power = 0.01 * cadence * cadence + -0.15 * cadence + 4.00; + } + else if (inclination == 1.0) { + power = 0.01 * cadence * cadence + -0.50 * cadence + 11.00; + } + else if (inclination == 1.5) { + power = 0.01 * cadence * cadence + -0.50 * cadence + 11.00; + } + else if (inclination == 2.0) { + power = 0.01 * cadence * cadence + -0.40 * cadence + 8.00; + } + else if (inclination == 2.5) { + power = 0.01 * cadence * cadence + 0.15 * cadence + -6.00; + } + else if (inclination == 3.0) { + power = 0.02 * cadence * cadence + -1.10 * cadence + 21.00; + } + else if (inclination == 3.5) { + power = 0.03 * cadence * cadence + -2.10 * cadence + 47.00; + } + else if (inclination == 4.0) { + power = 0.04 * cadence * cadence + -2.45 * cadence + 56.00; + } + else if (inclination == 4.5) { + power = 0.03 * cadence * cadence + -1.90 * cadence + 42.00; + } + else if (inclination == 5.0) { + power = 0.05 * cadence * cadence + -3.70 * cadence + 86.00; + } + else if (inclination == 5.5) { + power = 0.05 * cadence * cadence + -3.80 * cadence + 92.00; + } + else if (inclination == 6.0) { + power = 0.07 * cadence * cadence + -5.10 * cadence + 112.00; + } + else if (inclination == 6.5) { + power = 0.06 * cadence * cadence + -4.20 * cadence + 94.00; + } + else if (inclination == 7.0) { + power = 0.03 * cadence * cadence + -0.40 * cadence + -10.00; + } + else if (inclination == 7.5) { + power = 0.07 * cadence * cadence + -4.60 * cadence + 100.00; + } + else if (inclination == 8.0) { + power = 0.11 * cadence * cadence + -7.75 * cadence + 180.00; + } + else if (inclination == 8.5) { + power = 0.09 * cadence * cadence + -5.75 * cadence + 132.00; + } + else if (inclination == 9.0) { + power = 0.08 * cadence * cadence + -4.40 * cadence + 90.00; + } + else if (inclination == 9.5) { + power = 0.08 * cadence * cadence + -4.60 * cadence + 102.00; + } + else if (inclination == 10.0) { + power = 0.11 * cadence * cadence + -7.30 * cadence + 180.00; + } + else if (inclination == 10.5) { + power = 0.08 * cadence * cadence + -4.00 * cadence + 90.00; + } + else if (inclination == 11.0) { + power = 0.12 * cadence * cadence + -7.40 * cadence + 174.00; + } + else if (inclination == 11.5) { + power = 0.12 * cadence * cadence + -7.40 * cadence + 174.00; + } + else if (inclination == 12.0) { + power = 0.20 * cadence * cadence + -14.70 * cadence + 351.00; + } + else if (inclination == 12.5) { + power = 0.20 * cadence * cadence + -14.75 * cadence + 372.00; + } + else if (inclination == 13.0) { + power = 0.12 * cadence * cadence + -6.30 * cadence + 159.00; + } + else if (inclination == 13.5) { + power = 0.15 * cadence * cadence + -9.00 * cadence + 219.00; + } + else if (inclination == 14.0) { + power = 0.37 * cadence * cadence + -30.60 * cadence + 753.00; + } + else if (inclination == 14.5) { + power = 0.14 * cadence * cadence + -7.30 * cadence + 183.00; + } + else if (inclination == 15.0) { + power = 0.17 * cadence * cadence + -8.85 * cadence + 222.00; + } + else if (inclination == 15.5) { + power = 0.17 * cadence * cadence + -8.85 * cadence + 222.00; + } + else if (inclination == 16.0) { + power = 0.19 * cadence * cadence + -9.75 * cadence + 245.00; + } + else if (inclination == 16.5) { + power = 0.26 * cadence * cadence + -17.45 * cadence + 455.00; + } + else if (inclination == 17.0) { + power = 0.27 * cadence * cadence + -17.90 * cadence + 470.00; + } + else if (inclination == 17.5) { + power = 0.27 * cadence * cadence + -17.90 * cadence + 470.00; + } + else { + qDebug() << "Inclination level not supported"; + } + + return power; +} diff --git a/src/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.h b/src/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.h new file mode 100644 index 000000000..79d38a8d3 --- /dev/null +++ b/src/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.h @@ -0,0 +1,117 @@ +#ifndef NORDICTRACKIFITADBELLIPTICAL_H +#define NORDICTRACKIFITADBELLIPTICAL_H + +#include + +#ifndef Q_OS_ANDROID +#include +#else +#include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "devices/elliptical.h" +#include "virtualdevices/virtualbike.h" + +#ifdef Q_OS_IOS +#include "ios/lockscreen.h" +#endif + +class nordictrackifitadbellipticalLogcatAdbThread : public QThread { + Q_OBJECT + + public: + explicit nordictrackifitadbellipticalLogcatAdbThread(QString s); + bool runCommand(QString command); + + void run() override; + + signals: + void onSpeedInclination(double speed, double inclination); + void debug(QString message); + void onWatt(double watt); + void onHRM(int hrm); + + private: + QString adbCommandPending = ""; + QString runAdbCommand(QString command); + double speed = 0; + double inclination = 0; + double watt = 0; + int hrm = 0; + QString name; + struct adbfile { + QDateTime date; + QString name; + }; + + void runAdbTailCommand(QString command); +}; + +class nordictrackifitadbelliptical : public elliptical { + Q_OBJECT + public: + nordictrackifitadbelliptical(bool noWriteResistance, bool noHeartService, int8_t bikeResistanceOffset, + double bikeResistanceGain); + bool connected() override; + bool inclinationAvailableByHardware() override; + + private: + const resistance_t max_resistance = 17; // max inclination for s22i + void forceResistance(double resistance); + uint16_t watts() override; + double getDouble(QString v); + uint16_t wattsFromResistance(double inclination, double cadence); + + QTimer *refresh; + + uint8_t sec1Update = 0; + QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime(); + QDateTime lastInclinationChanged = QDateTime::currentDateTime(); + uint8_t firstStateChanged = 0; + uint16_t m_watts = 0; + + bool initDone = false; + bool initRequest = false; + + bool noWriteResistance = false; + bool noHeartService = false; + + bool gearsAvailable = false; + + QUdpSocket *socket = nullptr; + QHostAddress lastSender; + + nordictrackifitadbellipticalLogcatAdbThread *logcatAdbThread = nullptr; + + QString lastCommand; + + QString ip; + +#ifdef Q_OS_IOS + lockscreen *h = 0; +#endif + + signals: + void disconnected(); + void debug(QString string); + + private slots: + + void processPendingDatagrams(); + void changeInclinationRequested(double grade, double percentage); + void onHRM(int hrm); + + void update(); +}; + +#endif // NORDICTRACKIFITADBELLIPTICAL_H diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index 252970ae9..82c173c68 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -78,6 +78,7 @@ SOURCES += \ $$PWD/devices/crossrope/crossrope.cpp \ $$PWD/devices/focustreadmill/focustreadmill.cpp \ $$PWD/devices/jumprope.cpp \ + $$PWD/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.cpp \ $$PWD/devices/trxappgateusbelliptical/trxappgateusbelliptical.cpp \ QTelnet.cpp \ devices/bkoolbike/bkoolbike.cpp \ @@ -300,6 +301,7 @@ HEADERS += \ $$PWD/devices/crossrope/crossrope.h \ $$PWD/devices/focustreadmill/focustreadmill.h \ $$PWD/devices/jumprope.h \ + $$PWD/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.h \ $$PWD/devices/trxappgateusbelliptical/trxappgateusbelliptical.h \ $$PWD/ergtable.h \ $$PWD/treadmillErgTable.h \ diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index bbe96f9ac..1733ff3e3 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -750,8 +750,10 @@ const QString QZSettings::nordictrackadbbike_resistance = QStringLiteral("nordic const QString QZSettings::proform_treadmill_carbon_t7 = QStringLiteral("proform_treadmill_carbon_t7"); const QString QZSettings::nordictrack_treadmill_exp_5i = QStringLiteral("nordictrack_treadmill_exp_5i"); const QString QZSettings::dircon_id = QStringLiteral("dircon_id"); +const QString QZSettings::proform_elliptical_ip = QStringLiteral("proform_elliptical_ip"); +const QString QZSettings::default_proform_elliptical_ip = QStringLiteral(""); -const uint32_t allSettingsCount = 634; +const uint32_t allSettingsCount = 635; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1392,6 +1394,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::proform_treadmill_carbon_t7, QZSettings::default_proform_treadmill_carbon_t7}, {QZSettings::nordictrack_treadmill_exp_5i, QZSettings::default_nordictrack_treadmill_exp_5i}, {QZSettings::dircon_id, QZSettings::default_dircon_id}, + {QZSettings::proform_elliptical_ip, QZSettings::default_proform_elliptical_ip}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index 41cc7e65e..e6c5c0de8 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2102,6 +2102,9 @@ class QZSettings { static const QString dircon_id; static constexpr int default_dircon_id = 0; + static const QString proform_elliptical_ip; + static const QString default_proform_elliptical_ip; + /** * @brief Write the QSettings values using the constants from this namespace. * @param showDefaults Optionally indicates if the default should be shown with the key. diff --git a/src/settings.qml b/src/settings.qml index b4d0ff2d2..e40b0118e 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -962,6 +962,7 @@ import QtQuick.Dialogs 1.0 property bool proform_treadmill_carbon_t7: false property bool nordictrack_treadmill_exp_5i: false property int dircon_id: 0 + property string proform_elliptical_ip: "" } function paddingZeros(text, limit) { @@ -7489,6 +7490,41 @@ import QtQuick.Dialogs 1.0 Layout.fillWidth: true onClicked: { settings.nordictrack_elliptical_c7_5 = checked; window.settings_restart_to_apply = true; } } + RowLayout { + spacing: 10 + Label { + text: qsTr("Companion IP:") + Layout.fillWidth: true + } + TextField { + id: proformEllipticalCompanionIPTextField + text: settings.proform_elliptical_ip + horizontalAlignment: Text.AlignRight + Layout.fillHeight: false + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + //inputMethodHints: Qt.ImhFormattedNumbersOnly + onAccepted: settings.proform_elliptical_ip = text + onActiveFocusChanged: if(this.focus) this.cursorPosition = this.text.length + } + Button { + text: "OK" + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + onClicked: { settings.proform_elliptical_ip = proformEllipticalCompanionIPTextField.text; window.settings_restart_to_apply = true; toast.show("Setting saved!"); } + } + } + SwitchDelegate { + text: qsTr("ADB Remote") + spacing: 0 + bottomPadding: 0 + topPadding: 0 + rightPadding: 0 + leftPadding: 0 + clip: false + checked: settings.nordictrack_ifit_adb_remote + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + onClicked: { settings.nordictrack_ifit_adb_remote = checked; window.settings_restart_to_apply = true; } + } } AccordionElement { From 7aab56ea93cf1a765fb4e2f9ca02795ea03efc0d Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 16 Aug 2024 21:46:42 +0200 Subject: [PATCH 025/162] wizard shouldn't show if it's a wifi device --- src/homeform.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/homeform.h b/src/homeform.h index b3dc11eb6..8a9021790 100644 --- a/src/homeform.h +++ b/src/homeform.h @@ -350,7 +350,20 @@ class homeform : public QObject { Q_INVOKABLE bool firstRun() { QSettings settings; - return settings.value(QZSettings::bluetooth_lastdevice_name, QZSettings::default_bluetooth_lastdevice_name).toString().isEmpty(); + 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(); + 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(); + bool fakedevice_elliptical = + settings.value(QZSettings::fakedevice_elliptical, QZSettings::default_fakedevice_elliptical).toBool(); + bool fakedevice_rower = settings.value(QZSettings::fakedevice_rower, QZSettings::default_fakedevice_rower).toBool(); + bool fakedevice_treadmill = + settings.value(QZSettings::fakedevice_treadmill, QZSettings::default_fakedevice_treadmill).toBool(); + + return settings.value(QZSettings::bluetooth_lastdevice_name, QZSettings::default_bluetooth_lastdevice_name).toString().isEmpty() && + nordictrack_2950_ip.isEmpty() && tdf_10_ip.isEmpty() && !fake_bike && !fakedevice_elliptical && !fakedevice_rower && !fakedevice_treadmill && proform_elliptical_ip.isEmpty(); } From e9a446a2e7d8b1bf7fcf58352de22bc34bb73bc6 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 16 Aug 2024 21:52:17 +0200 Subject: [PATCH 026/162] Virtual shifting not working (Issue #2519) --- src/devices/bluetooth.cpp | 2 ++ src/homeform.cpp | 10 +--------- src/homeform.h | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 21e27645a..00eb5719a 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -2550,6 +2550,7 @@ void bluetooth::connectedAndDiscovered() { connect(zwiftClickRemote->playDevice, &ZwiftPlayDevice::plus, (bike*)this->device(), &bike::gearUp); connect(zwiftClickRemote->playDevice, &ZwiftPlayDevice::minus, (bike*)this->device(), &bike::gearDown); zwiftClickRemote->deviceDiscovered(b); + homeform::singleton()->setToastRequested("Zwift Click Connected!"); break; } } @@ -2573,6 +2574,7 @@ void bluetooth::connectedAndDiscovered() { connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::plus, (bike*)this->device(), &bike::gearUp); connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::minus, (bike*)this->device(), &bike::gearDown); zwiftPlayDevice.last()->deviceDiscovered(b); + homeform::singleton()->setToastRequested("Zwift Play/Ride Connected!"); } } } diff --git a/src/homeform.cpp b/src/homeform.cpp index e16f183a2..6d94e2d3c 100644 --- a/src/homeform.cpp +++ b/src/homeform.cpp @@ -856,8 +856,7 @@ void homeform::pelotonLoginState(bool ok) { m_pelotonLoginState = (ok ? 1 : 0); emit pelotonLoginChanged(m_pelotonLoginState); if (!ok) { - setToastRequested("Peloton Login Error!"); - emit toastRequestedChanged(toastRequested()); + setToastRequested("Peloton Login Error!"); } } @@ -867,7 +866,6 @@ void homeform::zwiftLoginState(bool ok) { emit zwiftLoginChanged(m_zwiftLoginState); if (!ok) { setToastRequested("Zwift Login Error!"); - emit toastRequestedChanged(toastRequested()); } } @@ -1130,7 +1128,6 @@ void homeform::trainProgramSignals() { void homeform::onToastRequested(QString message) { setToastRequested(message); - emit toastRequestedChanged(message); } QStringList homeform::tile_order() { @@ -5453,7 +5450,6 @@ void homeform::update() { qDebug() << QStringLiteral("Autolap based on distance"); Lap(); setToastRequested("AutoLap " + QString::number(settings.value(QZSettings::autolap_distance, QZSettings::default_autolap_distance).toDouble(), 'f', 1)); - emit toastRequestedChanged(toastRequested()); } } @@ -6164,7 +6160,6 @@ void homeform::strava_refreshtoken() { if (reply->error() != 0) { qDebug() << QStringLiteral("Got error") << reply->errorString().toStdString().c_str(); setToastRequested("Strava Auth Failed!"); - emit toastRequestedChanged(toastRequested()); return; } @@ -6188,7 +6183,6 @@ void homeform::strava_refreshtoken() { settings.setValue(QZSettings::strava_lastrefresh, QDateTime::currentDateTime()); setToastRequested("Strava Login OK!"); - emit toastRequestedChanged(toastRequested()); } bool homeform::strava_upload_file(const QByteArray &data, const QString &remotename) { @@ -6306,7 +6300,6 @@ bool homeform::strava_upload_file(const QByteArray &data, const QString &remoten void homeform::errorOccurredUploadStrava(QNetworkReply::NetworkError code) { qDebug() << QStringLiteral("strava upload error!") << code; setToastRequested("Strava Upload Failed!"); - emit toastRequestedChanged(toastRequested()); } void homeform::writeFileCompleted() { @@ -6321,7 +6314,6 @@ void homeform::writeFileCompleted() { qDebug() << "reply:" << response; setToastRequested("Strava Upload Completed!"); - emit toastRequestedChanged(toastRequested()); } void homeform::onStravaGranted() { diff --git a/src/homeform.h b/src/homeform.h index 8a9021790..82f705df8 100644 --- a/src/homeform.h +++ b/src/homeform.h @@ -487,7 +487,7 @@ class homeform : public QObject { void videoSeekPosition(int ms); // in realtime void setVideoRate(double rate); void setMapsVisible(bool value); - void setToastRequested(QString value) { m_toastRequested = value; } + void setToastRequested(QString value) { m_toastRequested = value; emit toastRequestedChanged(value); } void setStravaUploadRequested(bool value) { m_stravaUploadRequested = value; } From b826e93644c00873f66891cf646f11969d5991ee Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sat, 17 Aug 2024 10:20:03 +0200 Subject: [PATCH 027/162] New Zwift Play Model #2520 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/bluetooth.cpp | 2 +- src/zwift_play/abstractZapDevice.h | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index f9f18d00f..14e2be2bb 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4036,7 +4036,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 842; + CURRENT_PROJECT_VERSION = 843; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4227,7 +4227,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 842; + CURRENT_PROJECT_VERSION = 843; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4454,7 +4454,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 842; + CURRENT_PROJECT_VERSION = 843; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4550,7 +4550,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 842; + CURRENT_PROJECT_VERSION = 843; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4642,7 +4642,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 842; + CURRENT_PROJECT_VERSION = 843; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4756,7 +4756,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 842; + CURRENT_PROJECT_VERSION = 843; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 00eb5719a..04dfb5a1b 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -2558,7 +2558,7 @@ void bluetooth::connectedAndDiscovered() { if(settings.value(QZSettings::zwift_play, QZSettings::default_zwift_play).toBool()) { for (const QBluetoothDeviceInfo &b : qAsConst(devices)) { - if ((((b.name().toUpper().startsWith("ZWIFT PLAY"))) || b.name().toUpper().startsWith("ZWIFT RIDE")) && zwiftPlayDevice.size() < 2 && this->device() && + if ((((b.name().toUpper().startsWith("ZWIFT PLAY"))) || b.name().toUpper().startsWith("ZWIFT RIDE") || b.name().toUpper().startsWith("ZWIFT SF2")) && zwiftPlayDevice.size() < 2 && this->device() && this->device()->deviceType() == bluetoothdevice::BIKE) { if(b.manufacturerData(2378).size() > 0) { diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index 053b0b9c6..566b3ebba 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -95,12 +95,12 @@ class AbstractZapDevice: public QObject { } else if(bytes.length() > 19 && ((uint8_t)bytes[18]) == 0xc8) { emit plus(); } else if(bytes.length() > 3 && - (((uint8_t)bytes[3]) == 0xdf) || // right top button - (((uint8_t)bytes[3]) == 0xbf)) { // right bottom button + ((((uint8_t)bytes[3]) == 0xdf) || // right top button + (((uint8_t)bytes[3]) == 0xbf))) { // right bottom button emit plus(); } else if(bytes.length() > 3 && - (((uint8_t)bytes[3]) == 0xfd) || // left top button - (((uint8_t)bytes[3]) == 0xfb)) { // left bottom button + ((((uint8_t)bytes[3]) == 0xfd) || // left top button + (((uint8_t)bytes[3]) == 0xfb))) { // left bottom button emit minus(); } break; From f7a2d30554744727510411a0e1e89a50f5ac2336 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sat, 17 Aug 2024 13:30:04 +0200 Subject: [PATCH 028/162] 2.16.68 --- src/android/AndroidManifest.xml | 2 +- src/main.qml | 2 +- src/qdomyos-zwift.pri | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/android/AndroidManifest.xml b/src/android/AndroidManifest.xml index 0b2db42b4..5349e5917 100644 --- a/src/android/AndroidManifest.xml +++ b/src/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + diff --git a/src/main.qml b/src/main.qml index 7c258f052..5f93d1c6c 100644 --- a/src/main.qml +++ b/src/main.qml @@ -777,7 +777,7 @@ ApplicationWindow { } ItemDelegate { - text: "version 2.16.67" + text: "version 2.16.68" width: parent.width } diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index 82c173c68..1b28b2ba2 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -859,4 +859,4 @@ INCLUDEPATH += purchasing/inapp WINRT_MANIFEST = AppxManifest.xml -VERSION = 2.16.67 +VERSION = 2.16.68 From c98bf5ca35d10235720d7a87352fe407ba353810 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sun, 18 Aug 2024 13:49:08 +0200 Subject: [PATCH 029/162] Treadmill incline multiplied on QZ output [BUG] (Issue #2511) --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 +++---- .../horizontreadmill/horizontreadmill.cpp | 32 ++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 14e2be2bb..3e0efc463 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4036,7 +4036,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 843; + CURRENT_PROJECT_VERSION = 844; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4227,7 +4227,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 843; + CURRENT_PROJECT_VERSION = 844; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4454,7 +4454,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 843; + CURRENT_PROJECT_VERSION = 844; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4550,7 +4550,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 843; + CURRENT_PROJECT_VERSION = 844; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4642,7 +4642,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 843; + CURRENT_PROJECT_VERSION = 844; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4756,7 +4756,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 843; + CURRENT_PROJECT_VERSION = 844; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/horizontreadmill/horizontreadmill.cpp b/src/devices/horizontreadmill/horizontreadmill.cpp index 3161319ad..aa3bbde39 100644 --- a/src/devices/horizontreadmill/horizontreadmill.cpp +++ b/src/devices/horizontreadmill/horizontreadmill.cpp @@ -1735,35 +1735,37 @@ void horizontreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha ) / 10.0); else if(ICONCEPT_FTMS_treadmill) { - if(newValue.at(index) == 0x3C && newValue.at(index + 1) == 0x00) { + uint8_t val1 = (uint8_t)newValue.at(index); + uint8_t val2 = (uint8_t)newValue.at(index + 1); + if(val1 == 0x3C && val2 == 0x00) { Inclination = 1; - } else if(newValue.at(index) == 0x82 && newValue.at(index + 1) == 0x00) { + } else if(val1 == 0x82 && val2 == 0x00) { Inclination = 2; - } else if(newValue.at(index) == 0xC8 && newValue.at(index + 1) == 0x00) { + } else if(val1 == 0xC8 && val2 == 0x00) { Inclination = 3; - } else if(newValue.at(index) == 0x04 && newValue.at(index + 1) == 0x01) { + } else if(val1 == 0x04 && val2 == 0x01) { Inclination = 4; - } else if(newValue.at(index) == 0x4A && newValue.at(index + 1) == 0x01) { + } else if(val1 == 0x4A && val2 == 0x01) { Inclination = 5; - } else if(newValue.at(index) == 0x90 && newValue.at(index + 1) == 0x01) { + } else if(val1 == 0x90 && val2 == 0x01) { Inclination = 6; - } else if(newValue.at(index) == 0xCC && newValue.at(index + 1) == 0x01) { + } else if(val1 == 0xCC && val2 == 0x01) { Inclination = 7; - } else if(newValue.at(index) == 0x12 && newValue.at(index + 1) == 0x02) { + } else if(val1 == 0x12 && val2 == 0x02) { Inclination = 8; - } else if(newValue.at(index) == 0x58 && newValue.at(index + 1) == 0x02) { + } else if(val1 == 0x58 && val2 == 0x02) { Inclination = 9; - } else if(newValue.at(index) == 0x94 && newValue.at(index + 1) == 0x02) { + } else if(val1 == 0x94 && val2 == 0x02) { Inclination = 10; - } else if(newValue.at(index) == 0xDA && newValue.at(index + 1) == 0x02) { + } else if(val1 == 0xDA && val2 == 0x02) { Inclination = 11; - } else if(newValue.at(index) == 0x20 && newValue.at(index + 1) == 0x03) { + } else if(val1 == 0x20 && val2 == 0x03) { Inclination = 12; - } else if(newValue.at(index) == 0x5C && newValue.at(index + 1) == 0x03) { + } else if(val1 == 0x5C && val2 == 0x03) { Inclination = 13; - } else if(newValue.at(index) == 0xA2 && newValue.at(index + 1) == 0x03) { + } else if(val1 == 0xA2 && val2 == 0x03) { Inclination = 14; - } else if(newValue.at(index) == 0xE8 && newValue.at(index + 1) == 0x03) { + } else if(val1 == 0xE8 && val2 == 0x03) { Inclination = 15; } else { Inclination = 0; From 73798b87db84ba407d8b6d981d9aca2b0d9c6c98 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 21 Aug 2024 11:17:25 +0200 Subject: [PATCH 030/162] Technogym Group Cycle Connect via ant+ #2528 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 22 +- src/android/src/Garmin.java | 16 ++ src/devices/antbike/antbike.cpp | 197 ++++++++++++++++++ src/devices/antbike/antbike.h | 81 +++++++ src/devices/bluetooth.cpp | 26 ++- src/devices/bluetooth.h | 2 + src/homeform.h | 4 +- src/ios/GarminConnect.swift | 14 ++ src/ios/lockscreen.h | 2 + src/ios/lockscreen.mm | 8 + src/qdomyos-zwift.pri | 2 + src/qzsettings.cpp | 4 +- src/qzsettings.h | 3 + src/settings.qml | 30 +++ 14 files changed, 402 insertions(+), 9 deletions(-) create mode 100644 src/devices/antbike/antbike.cpp create mode 100644 src/devices/antbike/antbike.h diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 3e0efc463..3949b70d8 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -152,6 +152,8 @@ 871189192893CECF006A04D1 /* libqavfmediaplayer.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 871189182893CECC006A04D1 /* libqavfmediaplayer.a */; }; 871235BF26B297670012D0F2 /* kingsmithr1protreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 871235BE26B297660012D0F2 /* kingsmithr1protreadmill.cpp */; }; 871235C126B297720012D0F2 /* moc_kingsmithr1protreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 871235C026B297720012D0F2 /* moc_kingsmithr1protreadmill.cpp */; }; + 8715A3E72C75E6C9009BAC05 /* moc_antbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8715A3E62C75E6C9009BAC05 /* moc_antbike.cpp */; }; + 8715A3EA2C75E6DB009BAC05 /* antbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8715A3E82C75E6DB009BAC05 /* antbike.cpp */; }; 87182A09276BBAF600141463 /* virtualrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87182A08276BBAF600141463 /* virtualrower.cpp */; }; 87182A0B276BBB1200141463 /* moc_virtualrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87182A0A276BBB1200141463 /* moc_virtualrower.cpp */; }; 8718CBA2263063BD004BF4EE /* soleelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8718CB9A263063BC004BF4EE /* soleelliptical.cpp */; }; @@ -918,6 +920,9 @@ 871235BD26B297660012D0F2 /* kingsmithr1protreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = kingsmithr1protreadmill.h; path = ../src/devices/kingsmithr1protreadmill/kingsmithr1protreadmill.h; sourceTree = ""; }; 871235BE26B297660012D0F2 /* kingsmithr1protreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = kingsmithr1protreadmill.cpp; path = ../src/devices/kingsmithr1protreadmill/kingsmithr1protreadmill.cpp; sourceTree = ""; }; 871235C026B297720012D0F2 /* moc_kingsmithr1protreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_kingsmithr1protreadmill.cpp; sourceTree = ""; }; + 8715A3E62C75E6C9009BAC05 /* moc_antbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_antbike.cpp; sourceTree = ""; }; + 8715A3E82C75E6DB009BAC05 /* antbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = antbike.cpp; path = ../src/devices/antbike/antbike.cpp; sourceTree = ""; }; + 8715A3E92C75E6DB009BAC05 /* antbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = antbike.h; path = ../src/devices/antbike/antbike.h; sourceTree = ""; }; 87182A07276BBAF600141463 /* virtualrower.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = virtualrower.h; path = ../src/virtualdevices/virtualrower.h; sourceTree = ""; }; 87182A08276BBAF600141463 /* virtualrower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = virtualrower.cpp; path = ../src/virtualdevices/virtualrower.cpp; sourceTree = ""; }; 87182A0A276BBB1200141463 /* moc_virtualrower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_virtualrower.cpp; sourceTree = ""; }; @@ -2063,6 +2068,9 @@ 2EB56BE3C2D93CDAB0C52E67 /* Sources */ = { isa = PBXGroup; children = ( + 8715A3E82C75E6DB009BAC05 /* antbike.cpp */, + 8715A3E92C75E6DB009BAC05 /* antbike.h */, + 8715A3E62C75E6C9009BAC05 /* moc_antbike.cpp */, 872973832C6F13C300D6D9A4 /* nordictrackifitadbelliptical.cpp */, 872973842C6F13C400D6D9A4 /* nordictrackifitadbelliptical.h */, 872973812C6F13B000D6D9A4 /* moc_nordictrackifitadbelliptical.cpp */, @@ -3417,6 +3425,7 @@ 873824AF27E64706004F1B46 /* moc_characteristicwriteprocessor2ad9.cpp in Compile Sources */, 25F2400F80DAFBD41FE5CC75 /* fit_field.cpp in Compile Sources */, 873824E227E647A8004F1B46 /* dns.cpp in Compile Sources */, + 8715A3EA2C75E6DB009BAC05 /* antbike.cpp in Compile Sources */, 87A3BC27265642A300D302E3 /* moc_echelonrower.cpp in Compile Sources */, 8768C9092BBC12B80099DBE1 /* socket_local_server.c in Compile Sources */, 87EFB56E25BD703D0039DD5A /* proformtreadmill.cpp in Compile Sources */, @@ -3568,6 +3577,7 @@ 8783153C25E8DAFD0007817C /* sportstechbike.cpp in Compile Sources */, 873824E527E647A8004F1B46 /* message.cpp in Compile Sources */, 210F6A0A7E2FA7CDD3CA0084 /* qdomyoszwift_qml_plugin_import.cpp in Compile Sources */, + 8715A3E72C75E6C9009BAC05 /* moc_antbike.cpp in Compile Sources */, 87062644259480A600D06586 /* APIFetcher.swift in Compile Sources */, 8768C8C72BBC11C80099DBE1 /* adb_auth_host.c in Compile Sources */, 87F02E4029178524000DB52C /* octaneelliptical.cpp in Compile Sources */, @@ -4036,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 844; + CURRENT_PROJECT_VERSION = 845; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4227,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 844; + CURRENT_PROJECT_VERSION = 845; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4454,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 844; + CURRENT_PROJECT_VERSION = 845; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4550,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 844; + CURRENT_PROJECT_VERSION = 845; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4642,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 844; + CURRENT_PROJECT_VERSION = 845; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4756,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 844; + CURRENT_PROJECT_VERSION = 845; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/android/src/Garmin.java b/src/android/src/Garmin.java index 6792a9cc0..d5f10916c 100644 --- a/src/android/src/Garmin.java +++ b/src/android/src/Garmin.java @@ -49,12 +49,24 @@ public class Garmin { private static Integer HR = 0; private static Integer FootCad = 0; + private static Double Speed = 0; + private static Integer Power = 0; public static int getHR() { Log.d(TAG, "getHR " + HR); return HR; } + public static int getPower() { + Log.d(TAG, "getPower " + Power); + return Power; + } + + public static double getSpeed() { + Log.d(TAG, "getSpeed " + Speed); + return Speed; + } + public static int getFootCad() { Log.d(TAG, "getFootCad " + FootCad); return FootCad; @@ -232,6 +244,10 @@ public void onMessageReceived(IQDevice device, IQApp app, List message, HR = Integer.parseInt(var[0].replaceAll("\\[", "").replaceAll("\\]", "").replaceAll("\\{", "").replaceAll("\\}", "").replaceAll(" ", "").split("=")[1]); if(var.length > 1) { FootCad = Integer.parseInt(var[1].replaceAll("\\[", "").replaceAll("\\]", "").replaceAll("\\{", "").replaceAll("\\}", "").replaceAll(" ", "").split("=")[1]); + if(var.length > 2) { + Power = Integer.parseInt(var[1].replaceAll("\\[", "").replaceAll("\\]", "").replaceAll("\\{", "").replaceAll("\\}", "").replaceAll(" ", "").split("=")[1]); + Speed = Double.parseDouble(var[1].replaceAll("\\[", "").replaceAll("\\]", "").replaceAll("\\{", "").replaceAll("\\}", "").replaceAll(" ", "").split("=")[1]); + } } Log.d(TAG, "HR " + HR); Log.d(TAG, "FootCad " + FootCad); diff --git a/src/devices/antbike/antbike.cpp b/src/devices/antbike/antbike.cpp new file mode 100644 index 000000000..08bdca810 --- /dev/null +++ b/src/devices/antbike/antbike.cpp @@ -0,0 +1,197 @@ +#include "antbike.h" +#include "virtualdevices/virtualbike.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef Q_OS_ANDROID +#include "keepawakehelper.h" +#include +#endif +#include + +using namespace std::chrono_literals; + +antbike::antbike(bool noWriteResistance, bool noHeartService, bool noVirtualDevice) { + m_watt.setType(metric::METRIC_WATT); + Speed.setType(metric::METRIC_SPEED); + refresh = new QTimer(this); + this->noWriteResistance = noWriteResistance; + this->noHeartService = noHeartService; + this->noVirtualDevice = noVirtualDevice; + initDone = false; + connect(refresh, &QTimer::timeout, this, &antbike::update); + refresh->start(200ms); +} + +void antbike::update() { + QSettings settings; + QString heartRateBeltName = + settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString(); + +#ifdef Q_OS_IOS +#ifndef IO_UNDER_QT + lockscreen hh; + Cadence = hh.getFootCad(); + m_watt = hh.getPower(); + qDebug() << QStringLiteral("Current Garmin Cadence: ") << QString::number(Cadence.value()); + if (settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) { + Speed = metric::calculateSpeedFromPower( + m_watt.value(), 0, Speed.value(), fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), + speedLimit()); + } else { + Speed = hh.getSpeed(); + } +#endif +#endif + +#ifdef Q_OS_ANDROID + Cadence = QAndroidJniObject::callStaticMethod("org/cagnulen/qdomyoszwift/Garmin", "getFootCad", "()I"); + m_watt = QAndroidJniObject::callStaticMethod("org/cagnulen/qdomyoszwift/Garmin", "getPower", "()I"); + if (settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) { + Speed = metric::calculateSpeedFromPower( + m_watt.value(), 0, Speed.value(), fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), + speedLimit()); + } else { + Speed = QAndroidJniObject::callStaticMethod("org/cagnulen/qdomyoszwift/Garmin", "getSpeed", "()D"); + } + qDebug() << QStringLiteral("Current Garmin Cadence: ") << QString::number(Cadence.value()); +#endif + + if (Cadence.value() > 0) { + CrankRevs++; + LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0)); + } + + if (requestInclination != -100) { + Inclination = requestInclination; + emit debug(QStringLiteral("writing incline ") + QString::number(requestInclination)); + requestInclination = -100; + } + + update_metrics(false, watts()); + + Distance += ((Speed.value() / (double)3600.0) / + ((double)1000.0 / (double)(lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())))); + lastRefreshCharacteristicChanged = QDateTime::currentDateTime(); + + // ******************************************* virtual bike init ************************************* + if (!firstStateChanged && !this->hasVirtualDevice() && !noVirtualDevice +#ifdef Q_OS_IOS +#ifndef IO_UNDER_QT + && !h +#endif +#endif + ) { + bool virtual_device_enabled = + settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool(); +#ifdef Q_OS_IOS +#ifndef IO_UNDER_QT + bool cadence = + settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool(); + bool ios_peloton_workaround = + settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool(); + if (ios_peloton_workaround && cadence) { + qDebug() << "ios_peloton_workaround activated!"; + h = new lockscreen(); + h->virtualbike_ios(); + } else +#endif +#endif + if (virtual_device_enabled) { + emit debug(QStringLiteral("creating virtual bike interface...")); + auto virtualBike = new virtualbike(this, noWriteResistance, noHeartService); + connect(virtualBike, &virtualbike::changeInclination, this, &antbike::changeInclinationRequested); + connect(virtualBike, &virtualbike::ftmsCharacteristicChanged, this, &antbike::ftmsCharacteristicChanged); + this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::PRIMARY); + } + } + if (!firstStateChanged) + emit connectedAndDiscovered(); + firstStateChanged = 1; + // ******************************************************************************************************** + + if (!noVirtualDevice) { +#ifdef Q_OS_ANDROID + if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) { + Heart = (uint8_t)KeepAwakeHelper::heart(); + debug("Current Heart: " + QString::number(Heart.value())); + } +#endif + if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) { + update_hr_from_external(); + } +#ifdef Q_OS_IOS +#ifndef IO_UNDER_QT + bool cadence = + settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool(); + bool ios_peloton_workaround = + settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool(); + if (ios_peloton_workaround && cadence && h && firstStateChanged) { + h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime()); + h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate()); + } +#endif +#endif + } + + if (Heart.value()) { + static double lastKcal = 0; + if (KCal.value() < 0) // if the user pressed stop, the KCAL resets the accumulator + lastKcal = abs(KCal.value()); + KCal = metric::calculateKCalfromHR(Heart.average(), elapsed.value()) + lastKcal; + } + + if (requestResistance != -1 && requestResistance != currentResistance().value()) { + Resistance = requestResistance; + m_pelotonResistance = requestResistance; + } +} + +void antbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) { + QByteArray b = newValue; + qDebug() << "routing FTMS packet to the bike from virtualbike" << characteristic.uuid() << newValue.toHex(' '); +} + +void antbike::changeInclinationRequested(double grade, double percentage) { + if (percentage < 0) + percentage = 0; + changeInclination(grade, percentage); +} + +uint16_t antbike::wattsFromResistance(double resistance) { + return _ergTable.estimateWattage(Cadence.value(), resistance); +} + +resistance_t antbike::resistanceFromPowerRequest(uint16_t power) { + //QSettings settings; + //bool toorx_srx_3500 = settings.value(QZSettings::toorx_srx_3500, QZSettings::default_toorx_srx_3500).toBool(); + /*if(toorx_srx_3500)*/ { + qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); + + if (Cadence.value() == 0) + return 1; + + for (resistance_t i = 1; i < maxResistance(); i++) { + if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { + qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) + << wattsFromResistance(i + 1) << power; + return i; + } + } + if (power < wattsFromResistance(1)) + return 1; + else + return maxResistance(); + } /*else { + return power / 10; + }*/ +} + + +uint16_t antbike::watts() { return m_watt.value(); } +bool antbike::connected() { return true; } diff --git a/src/devices/antbike/antbike.h b/src/devices/antbike/antbike.h new file mode 100644 index 000000000..7c9dde21b --- /dev/null +++ b/src/devices/antbike/antbike.h @@ -0,0 +1,81 @@ +#ifndef ANTBIKE_H +#define ANTBIKE_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef Q_OS_ANDROID +#include +#else +#include +#endif +#include +#include +#include +#include + +#include +#include +#include + +#include "devices/bike.h" +#include "ergtable.h" + +#ifdef Q_OS_IOS +#include "ios/lockscreen.h" +#endif + +class antbike : public bike { + Q_OBJECT + public: + antbike(bool noWriteResistance, bool noHeartService, bool noVirtualDevice); + bool connected() override; + uint16_t watts() override; + resistance_t maxResistance() override { return 100; } + resistance_t resistanceFromPowerRequest(uint16_t power) override; + + private: + QTimer *refresh; + + uint8_t sec1Update = 0; + QByteArray lastPacket; + QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime(); + QDateTime lastGoodCadence = QDateTime::currentDateTime(); + uint8_t firstStateChanged = 0; + + bool initDone = false; + bool initRequest = false; + + bool noWriteResistance = false; + bool noHeartService = false; + bool noVirtualDevice = false; + + uint16_t oldLastCrankEventTime = 0; + uint16_t oldCrankRevs = 0; + +#ifdef Q_OS_IOS + lockscreen *h = 0; +#endif + + uint16_t wattsFromResistance(double resistance); + + signals: + void disconnected(); + void debug(QString string); + + private slots: + void changeInclinationRequested(double grade, double percentage); + void update(); + + void ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue); +}; +#endif // ANTBIKE_H diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 04dfb5a1b..aecee2faa 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -107,6 +107,8 @@ void bluetooth::finished() { debug(QStringLiteral("BTLE scanning finished")); QSettings settings; + bool antbike = + settings.value(QZSettings::antbike, QZSettings::default_antbike).toBool(); 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(); @@ -119,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()) { + 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()); @@ -424,6 +426,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { QString proformtdf1ip = settings.value(QZSettings::proformtdf1ip, QZSettings::default_proformtdf1ip).toString(); QString proformtreadmillip = settings.value(QZSettings::proformtreadmillip, QZSettings::default_proformtreadmillip).toString(); + bool antbike_setting = + settings.value(QZSettings::antbike, QZSettings::default_antbike).toBool(); 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(); @@ -734,6 +738,19 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { } this->signalBluetoothDeviceConnected(csafeRower); #endif + } else if (antbike_setting && !antBike) { + this->stopDiscovery(); + antBike = new antbike(noWriteResistance, noHeartService, false); + emit deviceConnected(b); + connect(proformWifiTreadmill, &bluetoothdevice::connectedAndDiscovered, this, + &bluetooth::connectedAndDiscovered); + // connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart())); + connect(antBike, &antbike::debug, this, &bluetooth::debug); + // connect(this, SIGNAL(searchingStop()), cscBike, SLOT(searchingStop())); //NOTE: Commented due to #358 + if (this->discoveryAgent && !this->discoveryAgent->isActive()) { + emit searchingStop(); + } + this->signalBluetoothDeviceConnected(antBike); } else if (!proformtreadmillip.isEmpty() && !proformWifiTreadmill) { this->stopDiscovery(); proformWifiTreadmill = new proformwifitreadmill(noWriteResistance, noHeartService, bikeResistanceOffset, @@ -2793,6 +2810,11 @@ void bluetooth::restart() { delete proformWifiBike; proformWifiBike = nullptr; } + if (antBike) { + + delete antBike; + antBike = nullptr; + } if (proformTelnetBike) { delete proformTelnetBike; @@ -3232,6 +3254,8 @@ bluetoothdevice *bluetooth::device() { return proformTelnetBike; } else if (proformWifiTreadmill) { return proformWifiTreadmill; + } else if (antBike) { + return antBike; } else if (nordictrackifitadbTreadmill) { return nordictrackifitadbTreadmill; } else if (nordictrackifitadbBike) { diff --git a/src/devices/bluetooth.h b/src/devices/bluetooth.h index 48c7442a3..d8f0b86fc 100644 --- a/src/devices/bluetooth.h +++ b/src/devices/bluetooth.h @@ -21,6 +21,7 @@ #include "qzsettings.h" #include "devices/activiotreadmill/activiotreadmill.h" +#include "devices/antbike/antbike.h" #include "devices/apexbike/apexbike.h" #include "devices/bhfitnesselliptical/bhfitnesselliptical.h" #include "devices/bkoolbike/bkoolbike.h" @@ -160,6 +161,7 @@ class bluetooth : public QObject, public SignalHandler { bool useDiscovery = false; QFile *debugCommsLog = nullptr; QBluetoothDeviceDiscoveryAgent *discoveryAgent = nullptr; + antbike *antBike = nullptr; apexbike *apexBike = nullptr; bkoolbike *bkoolBike = nullptr; bhfitnesselliptical *bhFitnessElliptical = nullptr; diff --git a/src/homeform.h b/src/homeform.h index 82f705df8..7bed254dc 100644 --- a/src/homeform.h +++ b/src/homeform.h @@ -361,9 +361,11 @@ class homeform : public QObject { bool fakedevice_rower = settings.value(QZSettings::fakedevice_rower, QZSettings::default_fakedevice_rower).toBool(); bool fakedevice_treadmill = settings.value(QZSettings::fakedevice_treadmill, QZSettings::default_fakedevice_treadmill).toBool(); + bool antbike = + settings.value(QZSettings::antbike, QZSettings::default_antbike).toBool(); return settings.value(QZSettings::bluetooth_lastdevice_name, QZSettings::default_bluetooth_lastdevice_name).toString().isEmpty() && - nordictrack_2950_ip.isEmpty() && tdf_10_ip.isEmpty() && !fake_bike && !fakedevice_elliptical && !fakedevice_rower && !fakedevice_treadmill && proform_elliptical_ip.isEmpty(); + nordictrack_2950_ip.isEmpty() && tdf_10_ip.isEmpty() && !fake_bike && !fakedevice_elliptical && !fakedevice_rower && !fakedevice_treadmill && !antbike && proform_elliptical_ip.isEmpty(); } diff --git a/src/ios/GarminConnect.swift b/src/ios/GarminConnect.swift index eedf5de4a..08e09fd1e 100644 --- a/src/ios/GarminConnect.swift +++ b/src/ios/GarminConnect.swift @@ -26,6 +26,14 @@ extension ConnectIQ { return v.FootCad; } + @objc public func getPower() -> Int { + return v.Power; + } + + @objc public func getSpeed() -> Double { + return v.Speed; + } + @objc public func urlParser(_ url: URL) { v.urlParser(url) } @@ -45,6 +53,8 @@ class GarminConnectSwift: NSObject, IQDeviceEventDelegate, IQAppMessageDelegate public var HR: Int = 0 public var FootCad: Int = 0 + public var Power: Int = 0 + public var Speed: Double = 0 let SwiftDebug = swiftDebug() @@ -126,8 +136,12 @@ class GarminConnectSwift: NSObject, IQDeviceEventDelegate, IQAppMessageDelegate print(dictionary) HR = dictionary[0] as? Int ?? 0 FootCad = dictionary[1] as? Int ?? 0 + Power = dictionary[2] as? Int ?? 0 + Speed = dictionary[3] as? Double ?? 0 print("Garmin HR: \(HR)") print("Garmin Foot Cadence: \(FootCad)") + print("Garmin Power: \(Power)") + print("Garmin Speed: \(Speed)") } } diff --git a/src/ios/lockscreen.h b/src/ios/lockscreen.h index c8dc15e83..4b96c561d 100644 --- a/src/ios/lockscreen.h +++ b/src/ios/lockscreen.h @@ -56,6 +56,8 @@ class lockscreen { void garminconnect_init(); int getHR(); int getFootCad(); + int getPower(); + double getSpeed(); // debug static void debug(const char* debugstring); diff --git a/src/ios/lockscreen.mm b/src/ios/lockscreen.mm index 9120f2a29..ba942f125 100644 --- a/src/ios/lockscreen.mm +++ b/src/ios/lockscreen.mm @@ -259,6 +259,14 @@ return [Garmin getFootCad]; } +int lockscreen::getPower() { + return [Garmin getPower]; +} + +double lockscreen::getSpeed() { + return [Garmin getSpeed]; +} + // getVolume double lockscreen::getVolume() diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index 1b28b2ba2..a787635b5 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -75,6 +75,7 @@ DEFINES += QT_DEPRECATED_WARNINGS IO_UNDER_QT SMTP_BUILD NOMINMAX # include(../qtzeroconf/qtzeroconf.pri) SOURCES += \ + $$PWD/devices/antbike/antbike.cpp \ $$PWD/devices/crossrope/crossrope.cpp \ $$PWD/devices/focustreadmill/focustreadmill.cpp \ $$PWD/devices/jumprope.cpp \ @@ -298,6 +299,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin INCLUDEPATH += fit-sdk/ devices/ HEADERS += \ + $$PWD/devices/antbike/antbike.h \ $$PWD/devices/crossrope/crossrope.h \ $$PWD/devices/focustreadmill/focustreadmill.h \ $$PWD/devices/jumprope.h \ diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index 1733ff3e3..3eb8edad3 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -752,8 +752,9 @@ const QString QZSettings::nordictrack_treadmill_exp_5i = QStringLiteral("nordict const QString QZSettings::dircon_id = QStringLiteral("dircon_id"); const QString QZSettings::proform_elliptical_ip = QStringLiteral("proform_elliptical_ip"); const QString QZSettings::default_proform_elliptical_ip = QStringLiteral(""); +const QString QZSettings::antbike = QStringLiteral("antbike"); -const uint32_t allSettingsCount = 635; +const uint32_t allSettingsCount = 636; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1395,6 +1396,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::nordictrack_treadmill_exp_5i, QZSettings::default_nordictrack_treadmill_exp_5i}, {QZSettings::dircon_id, QZSettings::default_dircon_id}, {QZSettings::proform_elliptical_ip, QZSettings::default_proform_elliptical_ip}, + {QZSettings::antbike, QZSettings::default_antbike}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index e6c5c0de8..0b912beca 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2105,6 +2105,9 @@ class QZSettings { static const QString proform_elliptical_ip; static const QString default_proform_elliptical_ip; + static const QString antbike; + static constexpr bool default_antbike = 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. diff --git a/src/settings.qml b/src/settings.qml index e40b0118e..672df4eb2 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -963,6 +963,9 @@ import QtQuick.Dialogs 1.0 property bool nordictrack_treadmill_exp_5i: false property int dircon_id: 0 property string proform_elliptical_ip: "" + + // from version 2.16.69 + property bool antbike: false } function paddingZeros(text, limit) { @@ -4928,6 +4931,33 @@ import QtQuick.Dialogs 1.0 Layout.fillWidth: true color: Material.color(Material.Lime) } + + SwitchDelegate { + text: qsTr("Ant+ Bike Over Garmin Watch") + spacing: 0 + bottomPadding: 0 + topPadding: 0 + rightPadding: 0 + leftPadding: 0 + clip: false + checked: settings.antbike + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + onClicked: { settings.antbike = checked; window.settings_restart_to_apply = true; } + } + + Label { + text: qsTr("Use your garmin watch to get the ANT+ metrics from a bike") + font.bold: true + font.italic: true + font.pixelSize: 9 + textFormat: Text.PlainText + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + color: Material.color(Material.Lime) + } } } From ee1ed946928a833d307016f7eb616c3fdf5a5ac3 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 21 Aug 2024 11:19:22 +0200 Subject: [PATCH 031/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 3949b70d8..69592c248 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 845; + CURRENT_PROJECT_VERSION = 846; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 845; + CURRENT_PROJECT_VERSION = 846; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 845; + CURRENT_PROJECT_VERSION = 846; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 845; + CURRENT_PROJECT_VERSION = 846; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 845; + CURRENT_PROJECT_VERSION = 846; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 845; + CURRENT_PROJECT_VERSION = 846; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From d8a9e88736fb081a52f0108108b79a2916434896 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 21 Aug 2024 11:43:12 +0200 Subject: [PATCH 032/162] Update Garmin.java --- src/android/src/Garmin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/src/Garmin.java b/src/android/src/Garmin.java index d5f10916c..53c06eafa 100644 --- a/src/android/src/Garmin.java +++ b/src/android/src/Garmin.java @@ -49,7 +49,7 @@ public class Garmin { private static Integer HR = 0; private static Integer FootCad = 0; - private static Double Speed = 0; + private static Double Speed = 0.0; private static Integer Power = 0; public static int getHR() { From 2029579c870ec275cb343f2d1364c1175d9dfc5a Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 21 Aug 2024 12:32:21 +0200 Subject: [PATCH 033/162] Technogym Group Cycle Connect via ant+ #2528 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 +++++------ src/devices/antbike/antbike.cpp | 21 ++++++++++--------- src/ios/GarminConnect.swift | 8 +++---- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 69592c248..403eb0d94 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 846; + CURRENT_PROJECT_VERSION = 847; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 846; + CURRENT_PROJECT_VERSION = 847; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 846; + CURRENT_PROJECT_VERSION = 847; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 846; + CURRENT_PROJECT_VERSION = 847; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 846; + CURRENT_PROJECT_VERSION = 847; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 846; + CURRENT_PROJECT_VERSION = 847; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/antbike/antbike.cpp b/src/devices/antbike/antbike.cpp index 08bdca810..057983913 100644 --- a/src/devices/antbike/antbike.cpp +++ b/src/devices/antbike/antbike.cpp @@ -35,16 +35,17 @@ void antbike::update() { #ifdef Q_OS_IOS #ifndef IO_UNDER_QT - lockscreen hh; - Cadence = hh.getFootCad(); - m_watt = hh.getPower(); - qDebug() << QStringLiteral("Current Garmin Cadence: ") << QString::number(Cadence.value()); - if (settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) { - Speed = metric::calculateSpeedFromPower( - m_watt.value(), 0, Speed.value(), fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), - speedLimit()); - } else { - Speed = hh.getSpeed(); + if(h) { + Cadence = h->getFootCad(); + m_watt = h->getPower(); + qDebug() << QStringLiteral("Current Garmin Cadence: ") << QString::number(Cadence.value()); + if (settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) { + Speed = metric::calculateSpeedFromPower( + m_watt.value(), 0, Speed.value(), fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), + speedLimit()); + } else { + Speed = h->getSpeed(); + } } #endif #endif diff --git a/src/ios/GarminConnect.swift b/src/ios/GarminConnect.swift index 08e09fd1e..54bbe4600 100644 --- a/src/ios/GarminConnect.swift +++ b/src/ios/GarminConnect.swift @@ -138,10 +138,10 @@ class GarminConnectSwift: NSObject, IQDeviceEventDelegate, IQAppMessageDelegate FootCad = dictionary[1] as? Int ?? 0 Power = dictionary[2] as? Int ?? 0 Speed = dictionary[3] as? Double ?? 0 - print("Garmin HR: \(HR)") - print("Garmin Foot Cadence: \(FootCad)") - print("Garmin Power: \(Power)") - print("Garmin Speed: \(Speed)") + SwiftDebug.qtDebug("Garmin HR: \(HR)") + SwiftDebug.qtDebug("Garmin Foot Cadence: \(FootCad)") + SwiftDebug.qtDebug("Garmin Power: \(Power)") + SwiftDebug.qtDebug("Garmin Speed: \(Speed)") } } From e09afb91db5883e19dd80ed99e0894a8705fa569 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 21 Aug 2024 14:35:42 +0200 Subject: [PATCH 034/162] The zwift play controllers don't connect and the app crashes (Issue #2531) --- src/devices/bluetooth.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index aecee2faa..dedcb6dcb 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -2580,11 +2580,14 @@ void bluetooth::connectedAndDiscovered() { if(b.manufacturerData(2378).size() > 0) { qDebug() << "this should be 3 or 2. is it? " << int(b.manufacturerData(2378).at(0)); + zwiftPlayDevice.append(new zwiftclickremote(this->device(), + int(b.manufacturerData(2378).at(0)) == 3 ? AbstractZapDevice::ZWIFT_PLAY_TYPE::LEFT : AbstractZapDevice::ZWIFT_PLAY_TYPE::RIGHT)); } else { qDebug() << "manufacturer not found for ZWIFT CLICK"; + zwiftPlayDevice.append(new zwiftclickremote(this->device(), + zwiftPlayDevice.length() == 0 ? AbstractZapDevice::ZWIFT_PLAY_TYPE::LEFT : AbstractZapDevice::ZWIFT_PLAY_TYPE::RIGHT)); + } - zwiftPlayDevice.append(new zwiftclickremote(this->device(), - int(b.manufacturerData(2378).at(0)) == 3 ? AbstractZapDevice::ZWIFT_PLAY_TYPE::LEFT : AbstractZapDevice::ZWIFT_PLAY_TYPE::RIGHT)); // connect(heartRateBelt, SIGNAL(disconnected()), this, SLOT(restart())); connect(zwiftPlayDevice.last(), &zwiftclickremote::debug, this, &bluetooth::debug); From d4f74c328717e113170d89160b884f1392b294f0 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 21 Aug 2024 14:58:04 +0200 Subject: [PATCH 035/162] Technogym Group Cycle Connect via ant+ #2528 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 +++++------ src/devices/antbike/antbike.cpp | 21 +++++++++---------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 403eb0d94..4fe0f4da2 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 847; + CURRENT_PROJECT_VERSION = 848; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 847; + CURRENT_PROJECT_VERSION = 848; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 847; + CURRENT_PROJECT_VERSION = 848; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 847; + CURRENT_PROJECT_VERSION = 848; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 847; + CURRENT_PROJECT_VERSION = 848; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 847; + CURRENT_PROJECT_VERSION = 848; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/antbike/antbike.cpp b/src/devices/antbike/antbike.cpp index 057983913..71b22a030 100644 --- a/src/devices/antbike/antbike.cpp +++ b/src/devices/antbike/antbike.cpp @@ -35,18 +35,17 @@ void antbike::update() { #ifdef Q_OS_IOS #ifndef IO_UNDER_QT - if(h) { - Cadence = h->getFootCad(); - m_watt = h->getPower(); - qDebug() << QStringLiteral("Current Garmin Cadence: ") << QString::number(Cadence.value()); - if (settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) { - Speed = metric::calculateSpeedFromPower( - m_watt.value(), 0, Speed.value(), fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), - speedLimit()); - } else { - Speed = h->getSpeed(); + lockscreen hh; + Cadence = hh.getFootCad(); + m_watt = hh.getPower(); + qDebug() << QStringLiteral("Current Garmin Cadence: ") << QString::number(Cadence.value()); + if (settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) { + Speed = metric::calculateSpeedFromPower( + m_watt.value(), 0, Speed.value(), fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), + speedLimit()); + } else { + Speed = hh.getSpeed(); } - } #endif #endif From 78101b61912d1afef9c566df099cab8f95acbd43 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 21 Aug 2024 15:25:35 +0200 Subject: [PATCH 036/162] Technogym Group Cycle Connect via ant+ #2528 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/antbike/antbike.cpp | 2 +- src/devices/bluetooth.cpp | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 4fe0f4da2..c8d4a659a 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 848; + CURRENT_PROJECT_VERSION = 849; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 848; + CURRENT_PROJECT_VERSION = 849; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 848; + CURRENT_PROJECT_VERSION = 849; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 848; + CURRENT_PROJECT_VERSION = 849; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 848; + CURRENT_PROJECT_VERSION = 849; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 848; + CURRENT_PROJECT_VERSION = 849; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/antbike/antbike.cpp b/src/devices/antbike/antbike.cpp index 71b22a030..238b389c7 100644 --- a/src/devices/antbike/antbike.cpp +++ b/src/devices/antbike/antbike.cpp @@ -45,7 +45,7 @@ void antbike::update() { speedLimit()); } else { Speed = hh.getSpeed(); - } + } #endif #endif diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index dedcb6dcb..264c7f516 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -742,7 +742,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { this->stopDiscovery(); antBike = new antbike(noWriteResistance, noHeartService, false); emit deviceConnected(b); - connect(proformWifiTreadmill, &bluetoothdevice::connectedAndDiscovered, this, + connect(antBike, &bluetoothdevice::connectedAndDiscovered, this, &bluetooth::connectedAndDiscovered); // connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart())); connect(antBike, &antbike::debug, this, &bluetooth::debug); From f6ffb08ed629891b38991e5094ea49c78efcf86e Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 22 Aug 2024 06:54:25 +0200 Subject: [PATCH 037/162] Add Support for Echelon Stride 6S #2534 --- src/devices/bluetooth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 264c7f516..584438e9a 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1626,6 +1626,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { b.name().toUpper().startsWith(QLatin1String("ECH-UK-")) || b.name().toUpper().startsWith(QLatin1String("ECH-FR-")) || b.name().toUpper().startsWith(QLatin1String("STRIDE-")) || + b.name().toUpper().startsWith(QLatin1String("STRIDE6S-")) || b.name().toUpper().startsWith(QLatin1String("ECH-SD-SPT"))) && !echelonStride && filter) { this->setLastBluetoothDevice(b); From f365fb34230822025b0147cbf4a092c0ccf48ba0 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 22 Aug 2024 07:01:28 +0200 Subject: [PATCH 038/162] Domyos eb 900 still connects but stopped showing pedalling data (Issue #2533) --- src/devices/bluetooth.cpp | 4 ++-- src/devices/ftmsbike/ftmsbike.cpp | 5 +++++ src/qzsettings.cpp | 4 +++- src/qzsettings.h | 3 +++ src/settings.qml | 1 + 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 584438e9a..998269a9c 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -873,7 +873,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { emit searchingStop(); } this->signalBluetoothDeviceConnected(domyosRower); - } else if ((b.name().startsWith(QStringLiteral("Domyos-Bike")) && !deviceHasService(b, QBluetoothUuid((quint16)0x1826))) && + } else if ((b.name().startsWith(QStringLiteral("Domyos-Bike")) && (!deviceHasService(b, QBluetoothUuid((quint16)0x1826)) || settings.value(QZSettings::domyosbike_notfmts, QZSettings::default_domyosbike_notfmts).toBool())) && !b.name().startsWith(QStringLiteral("DomyosBridge")) && !domyosBike && filter) { this->setLastBluetoothDevice(b); this->stopDiscovery(); @@ -1491,7 +1491,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { (b.name().toUpper().startsWith("JAS_C3")) || (b.name().toUpper().startsWith("RAVE WHITE")) || (b.name().toUpper().startsWith("DOMYOS-BIKING-")) || - (b.name().startsWith(QStringLiteral("Domyos-Bike")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || + (b.name().startsWith(QStringLiteral("Domyos-Bike")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && !settings.value(QZSettings::domyosbike_notfmts, QZSettings::default_domyosbike_notfmts).toBool()) || (b.name().toUpper().startsWith("F") && b.name().toUpper().endsWith("ARROW")) || // FI9110 Arrow, https://www.fitnessdigital.it/bicicletta-smart-bike-ion-fitness-arrow-connect/p/10022863/ IO Fitness Arrow (b.name().toUpper().startsWith("ICSE") && b.name().length() == 4) || (b.name().toUpper().startsWith("FLX") && b.name().length() == 10) || diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index bb39d5523..44b8bc930 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -793,6 +793,11 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) { } } + if(gattFTMSService == nullptr && DOMYOS) { + settings.setValue(QZSettings::domyosbike_notfmts, true); + homeform::singleton()->setToastRequested("Domyos bike presents itself like a FTMS but it's not. Restart QZ to apply the fix, thanks."); + } + if (gattFTMSService && gattWriteCharControlPointId.isValid() && settings.value(QZSettings::hammer_racer_s, QZSettings::default_hammer_racer_s).toBool()) { init(); diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index 3eb8edad3..549d7bf5e 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -753,8 +753,9 @@ const QString QZSettings::dircon_id = QStringLiteral("dircon_id"); const QString QZSettings::proform_elliptical_ip = QStringLiteral("proform_elliptical_ip"); const QString QZSettings::default_proform_elliptical_ip = QStringLiteral(""); const QString QZSettings::antbike = QStringLiteral("antbike"); +const QString QZSettings::domyosbike_notfmts = QStringLiteral("domyosbike_notfmts"); -const uint32_t allSettingsCount = 636; +const uint32_t allSettingsCount = 637; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1397,6 +1398,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::dircon_id, QZSettings::default_dircon_id}, {QZSettings::proform_elliptical_ip, QZSettings::default_proform_elliptical_ip}, {QZSettings::antbike, QZSettings::default_antbike}, + {QZSettings::domyosbike_notfmts, QZSettings::default_domyosbike_notfmts}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index 0b912beca..c97273480 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2108,6 +2108,9 @@ class QZSettings { static const QString antbike; static constexpr bool default_antbike = false; + static const QString domyosbike_notfmts; + static constexpr bool default_domyosbike_notfmts = 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. diff --git a/src/settings.qml b/src/settings.qml index 672df4eb2..34ee45039 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -966,6 +966,7 @@ import QtQuick.Dialogs 1.0 // from version 2.16.69 property bool antbike: false + property bool domyosbike_notfmts: false } function paddingZeros(text, limit) { From fc7b043c8f7a0ec63474b09b5e866e87ff479e17 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 22 Aug 2024 07:05:15 +0200 Subject: [PATCH 039/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index c8d4a659a..8175a929c 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 849; + CURRENT_PROJECT_VERSION = 850; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 849; + CURRENT_PROJECT_VERSION = 850; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 849; + CURRENT_PROJECT_VERSION = 850; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 849; + CURRENT_PROJECT_VERSION = 850; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 849; + CURRENT_PROJECT_VERSION = 850; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 849; + CURRENT_PROJECT_VERSION = 850; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From b6c2704e4fc69e55dab1c7104ed56daffbeaf817 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sun, 25 Aug 2024 09:55:16 +0200 Subject: [PATCH 040/162] QZ calculates calories too low inaccurately. (Issue #2537) --- src/devices/ftmsbike/ftmsbike.cpp | 14 ++++++++------ src/devices/ftmsbike/ftmsbike.h | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 44b8bc930..d40d82478 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -359,7 +359,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris } Distance += ((Speed.value() / 3600000.0) * - ((double)lastRefreshCharacteristicChanged.msecsTo(now))); + ((double)lastRefreshCharacteristicChanged2AD2.msecsTo(now))); emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value())); @@ -438,7 +438,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) / 200.0) / (60000.0 / - ((double)lastRefreshCharacteristicChanged.msecsTo( + ((double)lastRefreshCharacteristicChanged2AD2.msecsTo( now)))); //(( (0.048* Output in watts +1.19) * body weight in // kg * 3.5) / 200 ) / 60 @@ -471,6 +471,8 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris if (Flags.remainingTime) { // todo } + + lastRefreshCharacteristicChanged2AD2 = now; } else if (characteristic.uuid() == QBluetoothUuid((quint16)0x2ACE)) { union flags { struct { @@ -532,7 +534,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris index += 3; } else { Distance += ((Speed.value() / 3600000.0) * - ((double)lastRefreshCharacteristicChanged.msecsTo(now))); + ((double)lastRefreshCharacteristicChanged2ACE.msecsTo(now))); } emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value())); @@ -627,7 +629,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) / 200.0) / (60000.0 / - ((double)lastRefreshCharacteristicChanged.msecsTo( + ((double)lastRefreshCharacteristicChanged2ACE.msecsTo( now)))); //(( (0.048* Output in watts +1.19) * body weight in // kg * 3.5) / 200 ) / 60 } @@ -661,6 +663,8 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris if (Flags.remainingTime) { // todo } + + lastRefreshCharacteristicChanged2ACE = now; } else { return; } @@ -670,8 +674,6 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0)); } - lastRefreshCharacteristicChanged = now; - if (heartRateBeltName.startsWith(QStringLiteral("Disabled")) && (!heart || Heart.value() == 0 || disable_hr_frommachinery)) { update_hr_from_external(); diff --git a/src/devices/ftmsbike/ftmsbike.h b/src/devices/ftmsbike/ftmsbike.h index fbcea0293..69d9d1bfc 100644 --- a/src/devices/ftmsbike/ftmsbike.h +++ b/src/devices/ftmsbike/ftmsbike.h @@ -93,7 +93,8 @@ class ftmsbike : public bike { uint8_t sec1Update = 0; QByteArray lastPacket; QByteArray lastPacketFromFTMS; - QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime(); + QDateTime lastRefreshCharacteristicChanged2AD2 = QDateTime::currentDateTime(); + QDateTime lastRefreshCharacteristicChanged2ACE = QDateTime::currentDateTime(); uint8_t firstStateChanged = 0; int8_t bikeResistanceOffset = 4; double bikeResistanceGain = 1.0; From 352aa40d0b858135a48af2dbb64b2d440c9e0aac Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sun, 25 Aug 2024 16:16:58 +0200 Subject: [PATCH 041/162] Add Support for Echelon Stride 6S #2534 --- src/Wizard.qml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Wizard.qml b/src/Wizard.qml index 445e6fe99..53592c93d 100644 --- a/src/Wizard.qml +++ b/src/Wizard.qml @@ -1210,11 +1210,11 @@ Page { Layout.alignment: Qt.AlignHCenter from: settings.miles_unit ? 660 : 300 // 66.0 lbs or 30.0 kg to: settings.miles_unit ? 4400 : 2000 // 440.0 lbs or 200.0 kg - value: settings.weight * 10 + value: settings.miles_unit ? (settings.weight * 2.20462 * 10).toFixed(0) : (settings.weight * 10) stepSize: 1 editable: true - property real realValue: value / 10 + property real realValue: settings.miles_unit ? value / 22.0462 : value / 10 textFromValue: function(value, locale) { return Number(value / 10).toLocaleString(locale, 'f', 1) @@ -1223,6 +1223,10 @@ Page { valueFromText: function(text, locale) { return Number.fromLocaleString(locale, text) * 10 } + + onValueChanged: { + settings.weight = realValue + } } Text { From 10f39dac684b60b76a9893da790f88331ec63a5d Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 26 Aug 2024 08:09:56 +0200 Subject: [PATCH 042/162] version 2.16.69 --- src/android/AndroidManifest.xml | 2 +- src/main.qml | 2 +- src/qdomyos-zwift.pri | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/android/AndroidManifest.xml b/src/android/AndroidManifest.xml index 5349e5917..f278e01fd 100644 --- a/src/android/AndroidManifest.xml +++ b/src/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + diff --git a/src/main.qml b/src/main.qml index 5f93d1c6c..172fc36fc 100644 --- a/src/main.qml +++ b/src/main.qml @@ -777,7 +777,7 @@ ApplicationWindow { } ItemDelegate { - text: "version 2.16.68" + text: "version 2.16.69" width: parent.width } diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index a787635b5..6db9feb9d 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -861,4 +861,4 @@ INCLUDEPATH += purchasing/inapp WINRT_MANIFEST = AppxManifest.xml -VERSION = 2.16.68 +VERSION = 2.16.69 From 4bb4aba1094f7b8d83c8d9ebac96c41a3189b3dd Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 27 Aug 2024 08:23:38 +0200 Subject: [PATCH 043/162] Treadmill stops automatically in Zwift #2539 --- .../trxappgateusbtreadmill/trxappgateusbtreadmill.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp b/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp index 6f34518e7..36ae08c45 100644 --- a/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp +++ b/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp @@ -41,10 +41,13 @@ void trxappgateusbtreadmill::writeCharacteristic(uint8_t *data, uint8_t data_len } writeBuffer = new QByteArray((const char *)data, data_len); +#ifndef Q_OS_IOS if (gattWriteCharacteristic.properties() & QLowEnergyCharacteristic::WriteNoResponse) { gattCommunicationChannelService->writeCharacteristic(gattWriteCharacteristic, *writeBuffer, QLowEnergyService::WriteWithoutResponse); - } else { + } else +#endif + { gattCommunicationChannelService->writeCharacteristic(gattWriteCharacteristic, *writeBuffer); } From 4b74c22f95d10f550252d36b9b38515464ce89cc Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 27 Aug 2024 08:29:50 +0200 Subject: [PATCH 044/162] Hammer Finnlo BF 90 (Issue #2538) --- .../trxappgateusbbike/trxappgateusbbike.cpp | 33 ++++++++++++++----- .../trxappgateusbbike/trxappgateusbbike.h | 1 + 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/devices/trxappgateusbbike/trxappgateusbbike.cpp b/src/devices/trxappgateusbbike/trxappgateusbbike.cpp index 80e585c35..93904e5ac 100644 --- a/src/devices/trxappgateusbbike/trxappgateusbbike.cpp +++ b/src/devices/trxappgateusbbike/trxappgateusbbike.cpp @@ -125,7 +125,7 @@ void trxappgateusbbike::update() { QSettings settings; bool toorx30 = settings.value(QZSettings::toorx_3_0, QZSettings::default_toorx_3_0).toBool(); if (toorx30 == false && - (bike_type == TYPE::IRUNNING || bike_type == TYPE::ICONSOLE || bike_type == TYPE::ICONSOLE_2 || + (bike_type == TYPE::IRUNNING || bike_type == TYPE::IRUNNING_2 || bike_type == TYPE::ICONSOLE || bike_type == TYPE::ICONSOLE_2 || bike_type == TYPE::HERTZ_XR_770 || bike_type == TYPE::HERTZ_XR_770_2)) { const uint8_t noOpData[] = {0xf0, 0xa2, 0x01, 0x01, 0x94}; @@ -453,7 +453,7 @@ void trxappgateusbbike::btinit(bool startTape) { bool toorx30 = settings.value(QZSettings::toorx_3_0, QZSettings::default_toorx_3_0).toBool(); if (toorx30 == false && - (bike_type == TYPE::IRUNNING || bike_type == TYPE::ICONSOLE || bike_type == TYPE::ICONSOLE_2)) { + (bike_type == TYPE::IRUNNING || bike_type == TYPE::IRUNNING_2 || bike_type == TYPE::ICONSOLE || bike_type == TYPE::ICONSOLE_2)) { const uint8_t initData1[] = {0xf0, 0xa0, 0x01, 0x01, 0x92}; const uint8_t initData2[] = {0xf0, 0xa1, 0x01, 0x01, 0x93}; @@ -462,23 +462,23 @@ void trxappgateusbbike::btinit(bool startTape) { const uint8_t initData5[] = {0xf0, 0xa6, 0x01, 0x01, 0x06, 0x9e}; writeCharacteristic((uint8_t *)initData1, sizeof(initData1), QStringLiteral("init"), false, true); - if (bike_type == TYPE::IRUNNING) { + if (bike_type == TYPE::IRUNNING || bike_type == TYPE::IRUNNING_2) { QThread::msleep(400); } writeCharacteristic((uint8_t *)initData2, sizeof(initData2), QStringLiteral("init"), false, true); - if (bike_type == TYPE::IRUNNING) { + if (bike_type == TYPE::IRUNNING || bike_type == TYPE::IRUNNING_2) { QThread::msleep(400); } writeCharacteristic((uint8_t *)initData3, sizeof(initData3), QStringLiteral("init"), false, true); - if (bike_type == TYPE::IRUNNING) { + if (bike_type == TYPE::IRUNNING || bike_type == TYPE::IRUNNING_2) { QThread::msleep(400); } writeCharacteristic((uint8_t *)initData4, sizeof(initData4), QStringLiteral("init"), false, true); - if (bike_type == TYPE::IRUNNING) { + if (bike_type == TYPE::IRUNNING || bike_type == TYPE::IRUNNING_2) { QThread::msleep(400); } writeCharacteristic((uint8_t *)initData5, sizeof(initData5), QStringLiteral("init"), false, true); - if (bike_type == TYPE::IRUNNING) { + if (bike_type == TYPE::IRUNNING || bike_type == TYPE::IRUNNING_2) { QThread::msleep(400); } } else if (bike_type == TYPE::HOP_SPORT_HS_090H) { @@ -849,7 +849,10 @@ void trxappgateusbbike::stateChanged(QLowEnergyService::ServiceState state) { Q_ASSERT(gattNotify1Characteristic.isValid()); if (bike_type == TYPE::IRUNNING || bike_type == TYPE::CHANGYOW) { if (!gattNotify2Characteristic.isValid()) { - bike_type = TYPE::ICONSOLE; + if(bike_type == TYPE::IRUNNING_2) + bike_type = TYPE::ICONSOLE_2; + else + bike_type = TYPE::ICONSOLE; qDebug() << QStringLiteral("ICONSOLE bike found - overrode due to characteristics"); } } @@ -1019,6 +1022,20 @@ void trxappgateusbbike::serviceScanDone(void) { bike_type = TUNTURI_2; uuid = uuid3; } + } else if (bike_type == IRUNNING) { + + bool found = false; + foreach (QBluetoothUuid s, m_control->services()) { + + if (s == QBluetoothUuid::fromString(uuid)) { + found = true; + break; + } + } + if (!found) { + bike_type = IRUNNING_2; + uuid = uuid3; + } } QBluetoothUuid _gattCommunicationChannelServiceId(uuid); diff --git a/src/devices/trxappgateusbbike/trxappgateusbbike.h b/src/devices/trxappgateusbbike/trxappgateusbbike.h index f1f9f1aea..e568b070f 100644 --- a/src/devices/trxappgateusbbike/trxappgateusbbike.h +++ b/src/devices/trxappgateusbbike/trxappgateusbbike.h @@ -112,6 +112,7 @@ class trxappgateusbbike : public bike { REEBOK_2 = 23, BIKZU = 24, TOORX_SRX_500 = 25, + IRUNNING_2 = 26, } TYPE; TYPE bike_type = TRXAPPGATE; From 95f51682c91d55f36fa9ac7cc9e9495bd67ef4b7 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 27 Aug 2024 08:43:53 +0200 Subject: [PATCH 045/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/zwift_play/zwiftclickremote.cpp | 8 ++++++++ src/zwift_play/zwiftclickremote.h | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/zwift_play/zwiftclickremote.cpp b/src/zwift_play/zwiftclickremote.cpp index a1092f9e0..226836c95 100755 --- a/src/zwift_play/zwiftclickremote.cpp +++ b/src/zwift_play/zwiftclickremote.cpp @@ -1,3 +1,4 @@ +#include "homeform.h" #include "zwiftclickremote.h" #include #include @@ -32,6 +33,11 @@ void zwiftclickremote::update() { QByteArray s = playDevice->buildHandshakeStart(); qDebug() << s.length(); writeCharacteristic(gattWrite1Service, &gattWrite1Characteristic, (uint8_t *) s.data(), s.length(), "handshakeStart"); + } else if(initDone) { + countRxTimeout++; + if(countRxTimeout == 5) { + homeform::singleton()->setToastRequested("Zwift device: UPGRADE THE FIRMWARE!"); + } } } @@ -52,6 +58,8 @@ void zwiftclickremote::characteristicChanged(const QLowEnergyCharacteristic &cha Q_UNUSED(characteristic); emit packetReceived(); + countRxTimeout = 0; + qDebug() << QStringLiteral(" << ") << newValue.toHex(' ') << QString(newValue) << characteristic.uuid().Name << characteristic.uuid().toString() << typeZap; if(characteristic.uuid() == QBluetoothUuid(QStringLiteral("00000002-19CA-4651-86E5-FA29DCDD09D1"))) { diff --git a/src/zwift_play/zwiftclickremote.h b/src/zwift_play/zwiftclickremote.h index 47033dac1..0c19e32db 100755 --- a/src/zwift_play/zwiftclickremote.h +++ b/src/zwift_play/zwiftclickremote.h @@ -53,7 +53,9 @@ class zwiftclickremote : public bluetoothdevice { bool initRequest = false; AbstractZapDevice::ZWIFT_PLAY_TYPE typeZap = AbstractZapDevice::NONE; - QTimer *refresh; + QTimer *refresh; + + uint32_t countRxTimeout = 0; signals: void disconnected(); From 8142e753234edd9e11582830b04b28a39dc87efa Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 27 Aug 2024 09:03:13 +0200 Subject: [PATCH 046/162] Skipping gears in Zwift on IOS #2540 --- src/homeform.cpp | 16 ++++++++++++++-- src/qzsettings.cpp | 4 +++- src/qzsettings.h | 3 +++ src/settings.qml | 32 +++++++++++++++++++++++++++++++- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/homeform.cpp b/src/homeform.cpp index 6d94e2d3c..4bde36cb1 100644 --- a/src/homeform.cpp +++ b/src/homeform.cpp @@ -4094,16 +4094,28 @@ void homeform::update() { static double volumeLast = -1; double currentVolume = h.getVolume() * 10.0; qDebug() << "volume" << volumeLast << currentVolume; + QSettings settings; + bool gears_volume_debouncing = settings.value(QZSettings::gears_volume_debouncing, QZSettings::default_gears_volume_debouncing).toBool(); if (volumeLast == -1) qDebug() << "volume init"; else if (volumeLast > currentVolume) { double diff = volumeLast - currentVolume; - for (int i = 0; i < diff; i++) + for (int i = 0; i < diff; i++) { Minus(QStringLiteral("gears")); + if(gears_volume_debouncing) { + i = diff; + break; + } + } } else if (volumeLast < currentVolume) { double diff = currentVolume - volumeLast; - for (int i = 0; i < diff; i++) + for (int i = 0; i < diff; i++) { Plus(QStringLiteral("gears")); + if(gears_volume_debouncing) { + i = diff; + break; + } + } } volumeLast = currentVolume; } diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index 549d7bf5e..411d45c94 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -754,8 +754,9 @@ const QString QZSettings::proform_elliptical_ip = QStringLiteral("proform_ellipt const QString QZSettings::default_proform_elliptical_ip = QStringLiteral(""); const QString QZSettings::antbike = QStringLiteral("antbike"); const QString QZSettings::domyosbike_notfmts = QStringLiteral("domyosbike_notfmts"); +const QString QZSettings::gears_volume_debouncing = QStringLiteral("gears_volume_debouncing"); -const uint32_t allSettingsCount = 637; +const uint32_t allSettingsCount = 638; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1399,6 +1400,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::proform_elliptical_ip, QZSettings::default_proform_elliptical_ip}, {QZSettings::antbike, QZSettings::default_antbike}, {QZSettings::domyosbike_notfmts, QZSettings::default_domyosbike_notfmts}, + {QZSettings::gears_volume_debouncing, QZSettings::default_gears_volume_debouncing}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index c97273480..0eb80a264 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2111,6 +2111,9 @@ class QZSettings { static const QString domyosbike_notfmts; static constexpr bool default_domyosbike_notfmts = false; + static const QString gears_volume_debouncing; + static constexpr bool default_gears_volume_debouncing = 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. diff --git a/src/settings.qml b/src/settings.qml index 34ee45039..6df757be2 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -967,6 +967,9 @@ import QtQuick.Dialogs 1.0 // from version 2.16.69 property bool antbike: false property bool domyosbike_notfmts: false + + // from version 2.16.70 + property bool gears_volume_debouncing: false } function paddingZeros(text, limit) { @@ -8060,7 +8063,7 @@ import QtQuick.Dialogs 1.0 SwitchDelegate { id: volumeChangeGearsDelegate - text: qsTr("Volumes buttons change gears") + text: qsTr("Volume buttons change gears") spacing: 0 bottomPadding: 0 topPadding: 0 @@ -8086,6 +8089,33 @@ import QtQuick.Dialogs 1.0 color: Material.color(Material.Lime) } + SwitchDelegate { + text: qsTr("Volume buttons debouncing") + spacing: 0 + bottomPadding: 0 + topPadding: 0 + rightPadding: 0 + leftPadding: 0 + clip: false + checked: settings.gears_volume_debouncing + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + onClicked: { settings.gears_volume_debouncing = checked; } + } + + Label { + text: qsTr("Debounce the volume buttons, so you will only see 1 gear step if there are 2 or more volume near steps. Default is off.") + font.bold: true + font.italic: true + font.pixelSize: 9 + textFormat: Text.PlainText + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + color: Material.color(Material.Lime) + } + SwitchDelegate { id: powerAvg5s text: qsTr("Power Average 5 sec.") From df928caf997425642b5bb9aa28cea46c16d15ec1 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 27 Aug 2024 09:12:36 +0200 Subject: [PATCH 047/162] Skipping gears in Zwift on IOS #2540 --- src/settings.qml | 27 ++++++++++++++ src/zwift_play/abstractZapDevice.h | 60 ++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/src/settings.qml b/src/settings.qml index 6df757be2..746a1405a 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -9550,6 +9550,33 @@ import QtQuick.Dialogs 1.0 Layout.fillWidth: true color: Material.color(Material.Lime) } + + SwitchDelegate { + text: qsTr("Buttons debouncing") + spacing: 0 + bottomPadding: 0 + topPadding: 0 + rightPadding: 0 + leftPadding: 0 + clip: false + checked: settings.gears_volume_debouncing + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + onClicked: { settings.gears_volume_debouncing = checked; } + } + + Label { + text: qsTr("Debounce the buttons, so you will only see 1 gear step even if you are keep pressing the buttons. Default is off.") + font.bold: true + font.italic: true + font.pixelSize: 9 + textFormat: Text.PlainText + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + color: Material.color(Material.Lime) + } } } diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index 566b3ebba..385154f88 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -4,9 +4,11 @@ #include #include #include +#include //#include "localKeyProvider.h" //#include "zapCrypto.h" #include "zapConstants.h" +#include "qzsettings.h" #ifdef Q_OS_ANDROID #include #include @@ -35,7 +37,12 @@ class AbstractZapDevice: public QObject { int processCharacteristic(const QString& characteristicName, const QByteArray& bytes, ZWIFT_PLAY_TYPE zapType) { if (bytes.isEmpty()) return 0; - qDebug() << zapType << characteristicName << bytes.toHex() ; + QSettings settings; + bool gears_volume_debouncing = settings.value(QZSettings::gears_volume_debouncing, QZSettings::default_gears_volume_debouncing).toBool(); + + qDebug() << zapType << characteristicName << bytes.toHex() << gears_volume_debouncing << risingEdge; + +#define DEBOUNCE (!gears_volume_debouncing || !risingEdge) #ifdef Q_OS_ANDROID_ENCRYPTION QAndroidJniEnvironment env; @@ -58,9 +65,15 @@ class AbstractZapDevice: public QObject { case 0x37: if(bytes.length() == 5) { if(bytes[2] == 0) { - emit plus(); + if(DEBOUNCE) + emit plus(); + risingEdge = true; } else if(bytes[4] == 0) { - emit minus(); + if(DEBOUNCE) + emit minus(); + risingEdge = true; + } else { + risingEdge = false; } } break; @@ -70,16 +83,26 @@ class AbstractZapDevice: public QObject { (((uint8_t)bytes[bytes.length() - 4]) == 0xc8 && zapType == LEFT) ) && bytes[bytes.length() - 3] == 0x01) { if(zapType == LEFT) { - emit plus(); + if(DEBOUNCE) + emit plus(); + risingEdge = true; } else { - emit minus(); + if(DEBOUNCE) + emit minus(); + risingEdge = true; } } else if(bytes.length() > 14 && bytes[11] == 0x30 && bytes[12] == 0x00) { if(zapType == LEFT) { - emit plus(); + if(DEBOUNCE) + emit plus(); + risingEdge = true; } else { - emit minus(); + if(DEBOUNCE) + emit minus(); + risingEdge = true; } + } else { + risingEdge = false; } break; case 0x23: // zwift ride @@ -88,20 +111,32 @@ class AbstractZapDevice: public QObject { (((uint8_t)bytes[12]) == 0xc8 && zapType == LEFT)) ) { if(zapType == LEFT) { - emit plus(); + if(DEBOUNCE) + emit plus(); + risingEdge = true; } else { - emit minus(); + if(DEBOUNCE) + emit minus(); + risingEdge = true; } } else if(bytes.length() > 19 && ((uint8_t)bytes[18]) == 0xc8) { - emit plus(); + if(DEBOUNCE) + emit plus(); + risingEdge = true; } else if(bytes.length() > 3 && ((((uint8_t)bytes[3]) == 0xdf) || // right top button (((uint8_t)bytes[3]) == 0xbf))) { // right bottom button - emit plus(); + if(DEBOUNCE) + emit plus(); + risingEdge = true; } else if(bytes.length() > 3 && ((((uint8_t)bytes[3]) == 0xfd) || // left top button (((uint8_t)bytes[3]) == 0xfb))) { // left bottom button - emit minus(); + if(DEBOUNCE) + emit minus(); + risingEdge = true; + } else { + risingEdge = false; } break; @@ -148,6 +183,7 @@ class AbstractZapDevice: public QObject { private: QByteArray devicePublicKeyBytes; + bool risingEdge = false; signals: void plus(); From 7f0c589c508b09b040cef0ec1c689211cb4a58f3 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 27 Aug 2024 09:34:42 +0200 Subject: [PATCH 048/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 8175a929c..4614f2011 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 850; + CURRENT_PROJECT_VERSION = 852; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 850; + CURRENT_PROJECT_VERSION = 852; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 850; + CURRENT_PROJECT_VERSION = 852; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 850; + CURRENT_PROJECT_VERSION = 852; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 850; + CURRENT_PROJECT_VERSION = 852; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 850; + CURRENT_PROJECT_VERSION = 852; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 4b6da2bb95319c9f0c63014d563c971a8a198e80 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 27 Aug 2024 10:02:14 +0200 Subject: [PATCH 049/162] big gears buttons added --- src/homeform.cpp | 22 +++++++++++++++++++++ src/homeform.h | 2 ++ src/qzsettings.cpp | 6 +++++- src/qzsettings.h | 7 +++++++ src/settings-tiles.qml | 44 ++++++++++++++++++++++++++++++++++++++++++ src/settings.qml | 2 ++ 6 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/homeform.cpp b/src/homeform.cpp index 4bde36cb1..b00f478ba 100644 --- a/src/homeform.cpp +++ b/src/homeform.cpp @@ -276,6 +276,10 @@ homeform::homeform(QQmlApplicationEngine *engine, bluetooth *bl) { QStringLiteral("0"), false, QStringLiteral("strokes_length"), 48, labelFontSize); gears = new DataObject(QStringLiteral("Gears"), QStringLiteral("icons/icons/elevationgain.png"), QStringLiteral("0"), true, QStringLiteral("gears"), 48, labelFontSize); + biggearsPlus = new DataObject(QStringLiteral("GearsPlus"), QStringLiteral("icons/icons/elevationgain.png"), + QStringLiteral("0"), true, QStringLiteral("biggearsplus"), 48, labelFontSize, QStringLiteral("white"), QLatin1String(""), 0, true, "Gear +", QStringLiteral("red")); + biggearsMinus = new DataObject(QStringLiteral("GearsMinus"), QStringLiteral("icons/icons/elevationgain.png"), + QStringLiteral("0"), true, QStringLiteral("biggearsminus"), 48, labelFontSize, QStringLiteral("white"), QLatin1String(""), 0, true, "Gear -", QStringLiteral("green")); pidHR = new DataObject(QStringLiteral("PID Heart"), QStringLiteral("icons/icons/heart_red.png"), QStringLiteral("0"), true, QStringLiteral("pid_hr"), 48, labelFontSize); extIncline = new DataObject(QStringLiteral("Ext.Inclin.(%)"), QStringLiteral("icons/icons/inclination.png"), @@ -1811,6 +1815,18 @@ void homeform::sortTiles() { ergMode->setGridId(i); dataList.append(ergMode); } + + if (settings.value(QZSettings::tile_biggears_enabled, false).toBool() && + settings.value(QZSettings::tile_biggears_order, 54).toInt() == i) { + biggearsPlus->setGridId(i); + dataList.append(biggearsPlus); + } + + if (settings.value(QZSettings::tile_biggears_enabled, false).toBool() && + settings.value(QZSettings::tile_biggears_order, 54).toInt() + 1 == i) { + biggearsMinus->setGridId(i); + dataList.append(biggearsMinus); + } } } else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ROWING) { for (int i = 0; i < 100; i++) { @@ -3104,6 +3120,12 @@ void homeform::LargeButton(const QString &name) { .toDouble()); } } + + if(name.contains(QStringLiteral("biggearsplus"))) { + gearUp(); + } else if(name.contains(QStringLiteral("biggearsminus"))) { + gearDown(); + } } void homeform::Plus(const QString &name) { diff --git a/src/homeform.h b/src/homeform.h index 7bed254dc..b54f6443b 100644 --- a/src/homeform.h +++ b/src/homeform.h @@ -638,6 +638,8 @@ class homeform : public QObject { DataObject *strokesCount; DataObject *wattKg; DataObject *gears; + DataObject *biggearsPlus; + DataObject *biggearsMinus; DataObject *remaningTimeTrainingProgramCurrentRow; DataObject *nextRows; DataObject *mets; diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index 411d45c94..84aba38b7 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -755,8 +755,10 @@ const QString QZSettings::default_proform_elliptical_ip = QStringLiteral(""); const QString QZSettings::antbike = QStringLiteral("antbike"); const QString QZSettings::domyosbike_notfmts = QStringLiteral("domyosbike_notfmts"); const QString QZSettings::gears_volume_debouncing = QStringLiteral("gears_volume_debouncing"); +const QString QZSettings::tile_biggears_enabled = QStringLiteral("tile_biggears_enabled"); +const QString QZSettings::tile_biggears_order = QStringLiteral("tile_biggears_order"); -const uint32_t allSettingsCount = 638; +const uint32_t allSettingsCount = 640; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1401,6 +1403,8 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::antbike, QZSettings::default_antbike}, {QZSettings::domyosbike_notfmts, QZSettings::default_domyosbike_notfmts}, {QZSettings::gears_volume_debouncing, QZSettings::default_gears_volume_debouncing}, + {QZSettings::tile_biggears_enabled, QZSettings::default_tile_biggears_enabled}, + {QZSettings::tile_biggears_order, QZSettings::default_tile_biggears_order}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index 0eb80a264..b32cb26ff 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2114,6 +2114,13 @@ class QZSettings { static const QString gears_volume_debouncing; static constexpr bool default_gears_volume_debouncing = false; + static const QString tile_biggears_enabled; + static constexpr bool default_tile_biggears_enabled = false; + + static const QString tile_biggears_order; + static constexpr int default_tile_biggears_order = 54; + + /** * @brief Write the QSettings values using the constants from this namespace. * @param showDefaults Optionally indicates if the default should be shown with the key. diff --git a/src/settings-tiles.qml b/src/settings-tiles.qml index 6705b8509..6755c1f97 100644 --- a/src/settings-tiles.qml +++ b/src/settings-tiles.qml @@ -193,6 +193,8 @@ ScrollView { property int tile_erg_mode_order: 52 property bool tile_rss_enabled: false property int tile_rss_order: 53 + property bool tile_biggears_enabled: false + property int tile_biggears_order: 54 } @@ -1618,6 +1620,48 @@ ScrollView { color: Material.color(Material.Lime) } + AccordionCheckElement { + title: qsTr("Gears Big Buttons") + linkedBoolSetting: "tile_biggears_enabled" + settings: settings + accordionContent: RowLayout { + spacing: 10 + Label { + text: qsTr("order index:") + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + } + ComboBox { + id: biggearsOrderTextField + model: rootItem.tile_order + displayText: settings.tile_biggears_order + Layout.fillHeight: false + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + onActivated: { + displayText = biggearsOrderTextField.currentValue + } + } + Button { + text: "OK" + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + onClicked: {settings.tile_biggears_order = biggearsOrderTextField.displayText; toast.show("Setting saved!"); } + } + } + } + + Label { + text: qsTr("It shows 2 big gear buttons on the UI") + font.bold: true + font.italic: true + font.pixelSize: 9 + 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: remainingTimeTrainingProgramRowEnabledAccordion title: qsTr("Remaining Time/Row") diff --git a/src/settings.qml b/src/settings.qml index 746a1405a..5c2605a05 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -970,6 +970,8 @@ import QtQuick.Dialogs 1.0 // from version 2.16.70 property bool gears_volume_debouncing: false + property bool tile_biggears_enabled: false + property int tile_biggears_order: 54 } function paddingZeros(text, limit) { From 4f057bb88fdc87c15268e9c03c6e363e9a520c25 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 27 Aug 2024 15:46:07 +0200 Subject: [PATCH 050/162] increasing setting info text --- src/settings-tiles.qml | 76 +++++----- src/settings.qml | 308 ++++++++++++++++++++--------------------- 2 files changed, 192 insertions(+), 192 deletions(-) diff --git a/src/settings-tiles.qml b/src/settings-tiles.qml index 6755c1f97..20b0d8ae8 100644 --- a/src/settings-tiles.qml +++ b/src/settings-tiles.qml @@ -238,7 +238,7 @@ ScrollView { text: qsTr("Speed in kilometers per hour. (To set your speed units to miles, go to Settings > General Options > Use Miles unit in UI).") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -304,7 +304,7 @@ ScrollView { text: qsTr("Bike pedal cadence changes color to indicate how your cadence compares to the cadence called out in Peloton classes. The tile displays the following colors: white if there is no target cadence in the program, red if your cadence is lower than the target, green if your cadence matches the target, and orange if your cadence is higher than the target.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -345,7 +345,7 @@ ScrollView { text: qsTr("Bike pedal cadence in rotations per minute (RPM) or Treadmill cadence if a shoe-mounted cadence sensor or Apple Watch QZ app is used.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -422,7 +422,7 @@ ScrollView { text: qsTr("Estimated calories burned during session, calculated on weight, age, and watts.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -467,7 +467,7 @@ ScrollView { text: qsTr("Estimated distance traveled during the session.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -512,7 +512,7 @@ ScrollView { text: qsTr("Current pace per mile or kilometer (Treadmill, Elliptical and Rower)") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -557,7 +557,7 @@ ScrollView { text: qsTr("Displays your bike’s resistance. The +/- buttons can be used to change resistance, if your bike is compatible.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -602,7 +602,7 @@ ScrollView { text: qsTr("Displays the watts generated by your current effort. Watt is also referred to as output (for example, in Peloton). If your equipment does not communicate watts, QZ will calculate watts using resistance and cadence.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -647,7 +647,7 @@ ScrollView { text: qsTr("Estimation of weight loss during the session.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -693,7 +693,7 @@ ScrollView { text: qsTr("Average watts produced for the session.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -771,7 +771,7 @@ ScrollView { text: qsTr("Percentage of current FTP and current FTP zone.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -848,7 +848,7 @@ ScrollView { text: qsTr("Built-in treadmill fan speed (Treadmill only)") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -893,7 +893,7 @@ ScrollView { text: qsTr("Cumulative power produced during the session in kilojoules.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -938,7 +938,7 @@ ScrollView { text: qsTr("Total time from start of the session.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -983,7 +983,7 @@ ScrollView { text: qsTr("Total time moving during the session.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1028,7 +1028,7 @@ ScrollView { text: qsTr("Allows you to sync resistance and cadence target changes with the Peloton coach’s callouts. If the targets are changing in QZ after the coach’s callouts, use the ‘+’ button to add seconds (essentially speeding QZ up). Use the ‘-’ button to slow QZ down. Use this tile in conjunction with the Remaining Time/Row tile (see below).") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1073,7 +1073,7 @@ ScrollView { text: qsTr("Displays time remaining in Peloton class.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1199,7 +1199,7 @@ ScrollView { text: qsTr("Resistance of your bike converted to the Peloton bike scale of 1 to 100.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1244,7 +1244,7 @@ ScrollView { text: qsTr("Displays target resistance in your bike’s resistance scale. For example, during a Peloton class or Zwift session, you want the resistance displayed in this tile to match the Resistance Tile.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1290,7 +1290,7 @@ ScrollView { text: qsTr("Displays target resistance converted to the Peloton bike scale of 1 to 100. For example, during a Peloton class, you want the resistance displayed in this tile to match the Peloton Resistance Tile.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1335,7 +1335,7 @@ ScrollView { text: qsTr("Displays target cadence.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1380,7 +1380,7 @@ ScrollView { text: qsTr("Displays target output (watts) when this information is provided by third-party apps.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1426,7 +1426,7 @@ ScrollView { text: qsTr("Displays the target power zone when this information is provided by third-party apps.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1566,7 +1566,7 @@ ScrollView { text: qsTr("Calculates your output (watts) divided by your weight. This is the primary metric used by Zwift and similar apps to calculate your virtual speed. NOTE: This is a much better metric to use than Output/Watts when comparing your effort to other users. This is why Peloton’s leaderboard, which uses only Output, is flawed.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1611,7 +1611,7 @@ ScrollView { text: qsTr("Allows you to change resistance while in Auto-Follow Mode.This tile allows you override the target resistance sent by third-party apps. For example, you would use the Gears Tile to increase resistance and generate more watts for sprinting in Zwift.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1653,7 +1653,7 @@ ScrollView { text: qsTr("It shows 2 big gear buttons on the UI") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1698,7 +1698,7 @@ ScrollView { text: qsTr("Displays the time remaining until the next cadence and/or resistance interval.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1743,7 +1743,7 @@ ScrollView { text: qsTr("Displays the next Peloton interval with duration and FTP Zone (in Power Zone classes) or Peloton Resistance (non–Power Zone classes).") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1788,7 +1788,7 @@ ScrollView { text: qsTr("Displays metabolic equivalents (METs), a measurement of energy expenditure and amount of oxygen used by the body compared to the body at rest. (e.g., 4 METS requires the body to use 4 times as much oxygen than when at rest, which means it requires more energy and burns more calories).") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1865,7 +1865,7 @@ ScrollView { text: qsTr("Displays the current time.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1910,7 +1910,7 @@ ScrollView { text: qsTr("(Rower only) Displays the number of strokes rowed.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1955,7 +1955,7 @@ ScrollView { text: qsTr("(Rower only) Displays the stroke length.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2000,7 +2000,7 @@ ScrollView { text: qsTr("(Elite Rizer only) Displays steering angle.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2045,7 +2045,7 @@ ScrollView { text: qsTr("Use this tile to display the target heart rate zone in which you’ve chosen to work out in Settings > Training Program Options.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2090,7 +2090,7 @@ ScrollView { text: qsTr("(Elite Rizer only) Allows control of the incline of external inclination equipment.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2135,7 +2135,7 @@ ScrollView { text: qsTr("(requires a compatible footpod with accelerometer; treadmill only) Displays stride while walking or running.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2180,7 +2180,7 @@ ScrollView { text: qsTr("(requires a compatible footpod with accelerometer; treadmill only) Displays time foot is on contact with ground while walking or running.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2225,7 +2225,7 @@ ScrollView { text: qsTr("(requires a compatible footpod with accelerometer; treadmill only) Displays the up and down movement while walking or running.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter diff --git a/src/settings.qml b/src/settings.qml index 5c2605a05..a623a777a 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -1043,7 +1043,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This changes the size of the tiles that display your metrics. The default is 100%. To fit more tiles on your screen, choose a smaller percentage. To make them larger, choose a percentage over 100%. Do not enter the percent symbol") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1080,7 +1080,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter your weight in kilograms so QZ can more accurately calculate calories burned. NOTE: If you choose to use miles as the unit for distance traveled, you will be asked to enter your weight in pounds (lbs).") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1118,7 +1118,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter your age so that calories burned can be more accurately calculated.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1158,7 +1158,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Select your gender so that calories burned can be more accurately calculated.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1197,7 +1197,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you train to specific output (or watts) levels, for example in Peloton Power Zone classes,and have taken an FTP test (Functional Threshold Power), enter your FTP here. This number is used to calculate your Power Zones (Zones 1 to 7 for Peloton and 1 to 6 for Zwift).") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1233,7 +1233,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you train to specific output (or watts) levels, for example with Stryd,and have taken an CP test (Critical Power Test), enter your CP here. This number is used to calculate your RSS.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1270,7 +1270,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("No need to enter data here. It is for a possible future QZ feature.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1307,7 +1307,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter your email address to receive an automated email with stats and charts when you hit STOP at the end of each workout. Make sure there are no spaces before or after the email address; this is the most common reason the automated email is not sent. Privacy Note: Email addresses are not collected by the developer and are only saved locally on your device.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1335,7 +1335,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn on if you want QZ to display distance traveled in miles. Default is off and set to kilometers.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1363,7 +1363,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn on to set QZ to always open in PAUSE mode. This is important for Peloton classes so that you can sync the start of your QZ workout with the start of the Peloton class. Turn off to have QZ start tracking and timing your workout as soon as it opens.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1391,7 +1391,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on for: - Peloton Bootcamp classes or other workouts that are on and off the bike or treadmill. QZ will continue to track your workout even when you step away from your equipment. - Capturing non-equipment-based workouts, such as yoga or strength training. NOTE: All such workouts are labeled as “Rides” in Strava, but you can edit the label in Strava.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1407,7 +1407,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Zwift users: keep this setting off") font.bold: yes font.italic: yes - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1441,7 +1441,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("(For Android Version 10 and above, this setting cannot be changed. This setting can be changed for Android Version 9 and below and for iOS.) When this setting is turned off, QZ sends heart rate data in a format designed to improve compatibility with third-party apps, such as Zwift and Peloton. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1469,7 +1469,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on to prevent a built-in heart rate monitor (HRM) on your exercise equipment from sending that data to QZ. This allows QZ to connect to your external HRM, such as a chest band or Apple Watch.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1497,7 +1497,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This prevents your bike or treadmill from sending its calories-burned calculation to QZ and defaults to QZ’s more accurate calculation.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1539,7 +1539,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Apple Watch users: leave it disabled! Just open the app on your watch") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1715,7 +1715,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("QZ uses a standard age-based calculation for maximum heart rate and then sets the heart rate zones based on that max heart rate. If you know your actual max heart rate (the highest your heart rate is known to reach), turn this option on and enter your actual max heart rate. Then click OK.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1730,7 +1730,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Choose the percentages for where you want your zones 1-4 to end and click OK.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1852,7 +1852,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Expand the bars to the right to display the options under this setting. These settings are used to calculate power (watts) for bikes that do not have power meters. Instead QZ estimates power from your cadence and heart rate. You can calibrate how QZ calculates your power from heart rate as follows: If you know that at a stable pace you produce 100W of power at a heart rate of 150 BPM and 150W at 170 BPM, you can add these values under Sessions 1 and 2 Watt and HR and QZ will calculate your power based on that trend line.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1892,7 +1892,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("QZ calculates speed based on your pedal cadence (RPMs). Enable this setting if you want your speed to be calculated based on your power output (watts), as Zwift and some other apps do. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1918,7 +1918,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("QZ will remember the last Gears value and it will restore on startup") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1955,7 +1955,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("0.005 = Clinchers\n0.004 = Tubulars\n0.012 = MTB") font.italic: true Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize color: "steelblue" } RowLayout { @@ -1987,7 +1987,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables QZ to include the weight of your bike when calculating speed. For example, if you are competing against yourself on VZfit, adding bike weight will “level the playing field” against your virtual self. If you have set QZ to calculate distance in miles, enter the bike weight in pounds (lbs). Default unit is kilograms (kgs).") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2063,7 +2063,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enable this setting ONLY when using Zwift in ERG (workout) Mode. QZ will communicate the target resistance (or automatically adjust your resistance if your bike has this capability) to match the target watts based on your cadence (RPM). In ERG Mode, the changes in road slope will not affect target resistance, as is the case in Simulation Mode. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2101,7 +2101,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This setting sets your “flat road” in Zwift. All communicated resistance changes will be based on this setting. The value entered is personal preference and will be dependent on your level of fitness. The suggested value for Echelon bikes is between 18 and 20. Default is 4.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2139,7 +2139,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("(for bikes and treadmills when using “treadmill as a bike” setting). This setting scales the resistance from your bike or the speed from your treadmill before sending it to Zwift. Default is 1.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2177,7 +2177,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("In ERG Mode or during a Power Zone workout on Peloton, the app sends a “target output” request. If the output requested doesn’t match your current output (calculated using cadence and resistance level), your target resistance will change to help you get closer to the target output. If the filter is set to higher values, you will get less adjustment of the target resistance and you will have to increase your cadence to match the target output. The Up and Down Watt Filter settings are the upper and lower margin before the adjustment of resistance is communicated. Example: if the up and down filters are set to 10 and the target output is 100 watts, a change of your resistance will only be communicated if your bike produces less than 90 Watts or more than 110 Watts. Default is 10.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2215,7 +2215,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("See above. Default is 10.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2253,7 +2253,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Use this setting to set a minimum target resistance. For example, if you do not want to ride at a resistance below 25, enter a value of 25 and QZ will not set a target resistance below 25. Default is 0.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2291,7 +2291,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Similar to the above, but sets a maximum target resistance. Default is 999.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2329,7 +2329,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("(only for bikes with electronically-controlled resistance): Enter the resistance level you want QZ to set at startup. Default is 1.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2365,7 +2365,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Applies a multiplier to the gears tile. Default is 1.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2404,7 +2404,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you have a generic FTMS bike and the tiles doesn't appear on the main QZ screen, select here the bluetooth name of your bike.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2418,7 +2418,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Expand the bars to the right to display the options under this setting. Select your specific model (if it is listed) and leave all other settings on default. If you encounter problems or have a question about the QZ settings for your equipment, open a support ticket on GitHub or ask the QZ community on the QZ Facebook Group.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2504,7 +2504,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Since this bike doesn't send resistance over bluetooth, QZ is calculating it using cadence and wattage. The result could be a little 'jumpy' and so, with this setting, you can filter the resistance tile value. The unit is a pure resistance level, so putting 5 means that you will see a resistance changes only when the resistance is changing by 5 levels.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3486,7 +3486,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Set 100mm as wheel circumference in settings of ant+ speed sensor") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3512,7 +3512,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on if you need to use ANT+ along with Bluetooth. Power is also sent.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3548,7 +3548,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your speed sent over ANT+. The number you enter as an Offset adds that amount to your speed.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3585,7 +3585,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your speed output sent over ANT+. For example, to use a rower to cycle in Zwift, you could double your speed output to better match your cycling speed. The number you enter is a multiplier applied to your actual speed.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3613,7 +3613,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This setting enables receiving the heart rate from an external HRM over ANT+ instead of from QZ.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3678,7 +3678,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Allows continuous display of the Start/Pause and Stop buttons across the top of the screen during your workouts. Default is on.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3715,7 +3715,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: width of the floating window.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3752,7 +3752,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: height of the floating window.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3789,7 +3789,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: transparency percentage of the floating window.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3817,7 +3817,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: if enabled the floating window will start as soon as the fitness devices is connected.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4066,7 +4066,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter the email address you use to login to Peloton (NOT your leaderboard name). Ensure there are no spaces before or after your email. Click OK.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4105,7 +4105,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter the password you use to login to Peloton. Click OK. If you have entered the correct login credentials and the QZ is able to access your account, you will see a when you reopen QZ. This is a secure login, not accessible by anyone but you.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4145,7 +4145,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Typically, Peloton coaches call out a range for target incline, resistance and/or speed. Use this setting to choose the difficulty of the target QZ communicates. Difficulty level can be set to lower, upper or average. Click OK.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4183,7 +4183,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Difficulty level for peloton treadmill classes. 1 is easy 10 is hard.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4221,7 +4221,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Difficulty level for peloton rower classes. 1 is easy 10 is hard.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4258,7 +4258,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("As of 4/1/2022, this feature is broken due to a Power Zone Pack (PZP) website change. Leave (or change back to) the default of “username” (without quotation marks, all lowercase and all one word) until further notice.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4297,7 +4297,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("As of 4/1/2022, this feature is broken due to a Power Zone Pack (PZP) website change. Leave this setting blank until further notice.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4335,7 +4335,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Conversion gain is a multiplier. Use this setting to align the Peloton resistance calculated by QZ with the relative effort required by your bike. In most cases the default values will be correct.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4373,7 +4373,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Increases the resistance that QZ displays in the Peloton Resistance tile. If QZ’s calculated conversion from your bike’s resistance scale to Peloton’s seems too low, the number you enter here will be added to the calculated resistance without increasing your effort or actual resistance. (Example: If QZ displays Peloton Resistance of 30 and you enter 5, QZ will display 35.)") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4401,7 +4401,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on to send cadence to Peloton over Bluetooth. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4469,7 +4469,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("By default, QZ communicates heart rate to Peloton. Use this setting to change the metric that appears on the Peloton screen.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4509,7 +4509,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Allows you to choose whether you would like the Peloton class air date to display before or after the class title on Strava.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4537,7 +4537,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on if you want QZ to capture a link to the Peloton class and display it in Strava.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4564,7 +4564,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("By default, QZ treats Spin-UPS in Power Zone rides as an increasing ramp to warm you up. You can disable this, to leave the resistance up to you.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4592,7 +4592,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Only for Android where QZ is running on the same Peloton device. This setting enables the AI (Artificial Intelligence) on QZ that will read the peloton workout screen and will adjust the peloton offset in order to stay in sync in realtime with your Peloton workout. A popup about screen recording will appear in order to notify this.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4619,7 +4619,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This setting enables the AI (Artificial Intelligence) on the QZ Companion AI app that will read the peloton workout screen and will adjust the peloton offset in order to stay in sync in realtime with your Peloton workout.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4647,7 +4647,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Only if you are on a real Peloton Bike/Bike+! This will allow QZ to collect metrics from your Bike/Bike+ and send it to Zwift. Peloton Free ride must running.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4694,7 +4694,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter the email address you use to login to Zwift. Ensure there are no spaces before or after your email. Click OK.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4734,7 +4734,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter the password you use to login to Zwift. Click OK.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4770,7 +4770,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Define the number of delay seconds between each inclination change from Zwift. This value can't be less than 5. Default: 5") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4797,7 +4797,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Only for Android and iOS: QZ will read the inclination in real time from the Zwift app and will adjust the inclination on your treadmill. It doesn't work on workout") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4824,7 +4824,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Only for PC where QZ is running on the same Zwift device. This setting enables the AI (Artificial Intelligence) on QZ that will read the Zwift inclination from the Zwift app and will adjust the inclination on your treadmill. A popup about screen recording will appear in order to notify this.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4865,7 +4865,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Only for PC where QZ is running on the same Zwift device. This setting enables the AI (Artificial Intelligence) on QZ that will read the Zwift inclination and speed from the Zwift app during a workout and will adjust the inclination and the speed on your treadmill. A popup about screen recording will appear in order to notify this.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4902,7 +4902,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you want to send metrics to your Garmin device from your Mac, enable this. Otherwise leave it disabled.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4929,7 +4929,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You have to install the QZ Companion App on your Garmin Watch/Computer first.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4956,7 +4956,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Use your garmin watch to get the ANT+ metrics from a bike") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4996,7 +4996,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Treadmill only: enabling this if you want that QZ will stop the tape at the end of the current train program.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5039,7 +5039,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("QZ controls your treadmill or bike to keep you within a chosen Heart Rate Zone. Turn on, set a target heart rate (HR) zone in which to train and click OK. For example, enter 2 to train in HR zone 2 and the treadmill will auto adjust the speed (or resistance on a bike) to maintain your heart rate in zone 2. QZ gradually increases or decreases your speed (or bike resistance) in small increments every 40 seconds to reach and maintain your target HR zone. During a workout, you can display and use the ‘+’ and ‘-’ button on the PID HR Zone tile to change the target HR zone.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5096,7 +5096,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Alternatively to 'PID on Heart Zone' setting you can use this couple of settings in order to specify a HR range.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5133,7 +5133,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter your 1 mile time goal, click OK. This setting will be used when you’re following a training program with the speed control. These settings should also match the Zwift app settings. More info: https://github.com/cagnulein/qdomyos-zwift/issues/609.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5170,7 +5170,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("See 1 Mile Pace above; same except 5 km instead of 1 mile.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5207,7 +5207,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("See 1 Mile Pace above; same except 10 km instead of 1 mile.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5244,7 +5244,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("See 1 Mile Pace above; same except half marathon distance instead of 1 mile.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5281,7 +5281,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("See 1 Mile Pace above; same except marathon distance instead of 1 mile.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5321,7 +5321,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Select the default Pace to be used when the ZWO file does not indicate a precise pace.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5543,7 +5543,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn on and enter your choices for workout time (in minutes and seconds) and the maximum and minimum speed, incline (treadmill), and resistance (bike) and QZ will randomly change your speed and resistance or incline accordingly for the period of time you have selected.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5582,7 +5582,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn on to convert your treadmill output to bike output when riding on Zwift. QZ sends your treadmill metrics to Zwift over Bluetooth so that you can participate as a bike rider. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5610,7 +5610,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on to have QZ control the speed of your treadmill during, for example, Peloton classes based on the coach’s speed callouts. Your speed will be in the low, upper or average range based on your Peloton Options > Difficulty setting. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5638,7 +5638,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on to have QZ go into Pause mode upon opening when using a treadmill. This is for treadmills only. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5666,7 +5666,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Target Speed and Target Incline tile offer a way to increase/decrease the current difficulty with the plus/minus buttons. By default, with this setting disabled, the speed and the inclination change with a 3% gain for every pressure. Switching this ON, QZ will add a 0.1 speed offset or a 0.5 incline offset instead.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5704,7 +5704,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("(Speed Tile) This controls the amount of the increase or decrease in the speed (in kph/mph) when you press the plus or minus button in the Speed Tile. Default is 0.5 kph.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5742,7 +5742,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("(Incline Tile) This controls the amount of the increase or decrease in the inclination when you press the plus or minus button in the Incline Tile. Default is 0.5.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5778,7 +5778,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This overrides the minimum inclination value of your treadmill (in order to reduce the inclination movement). Default is -100") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5814,7 +5814,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This overrides the maximum inclination value of your treadmill (in order to reduce the inclination movement). Default is -100") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5835,7 +5835,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Overrides the default inclination values sent from the treadmill") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5862,7 +5862,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("For treadmills without inclination: turning this on and QZ will transform inclination requests into speed changes.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5901,7 +5901,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you have a generic FTMS bike and the tiles doesn't appear on the main QZ screen, select here the bluetooth name of your bike.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5914,7 +5914,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Expand the bars to the right to display the options under this setting. Select your specific model (if it is listed) and leave all other settings on default. If you encounter problems or have a question about settings for your specific equipment with QZ, click here to open a support ticket on GitHub or ask the QZ community on the QZ Facebook Group.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -6527,7 +6527,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Default: 200. Change this only if you have random issues with speed or inclination (try to put 300)") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7392,7 +7392,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Allows you to force QZ to connect to your FTMS Rower. If you are in doubt, leave this Disabled and send an email to the QZ support. Default is “Disabled.”") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7673,7 +7673,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Allows you to force QZ to connect to your equipment (see “Bluetooth Troubleshooting” below). Default is “Disabled.”") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7711,7 +7711,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your watt output for moving your avatar faster/slower in Zwift or other similar apps as a way of calibrating your equipment. The number you enter as an Offset adds that amount to your watts.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7749,7 +7749,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your watt output for moving your avatar faster/slower in Zwift or other similar apps as a way of calibrating your equipment. For example, to use a rower to cycle in Zwift, you could double your watt output to better match your cycling speed by entering 2. The number you enter is a multiplier applied to your actual watts.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7787,7 +7787,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your speed for moving your avatar faster/slower in Zwift if your equipment outputs speed but not watts. The number you enter as an Offset adds that amount to your speed.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7826,7 +7826,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your speed output for moving your avatar faster/slower in Zwift or other apps as a way of calibrating your equipment if your equipment outputs speed but not watts. For example, to use a rower to cycle in Zwift, you could double your speed output to better match your cycling speed. The number you enter is a multiplier applied to your actual speed.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7864,7 +7864,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your cadence output. The number you enter as an Offset adds that amount to your cadence.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7902,7 +7902,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your cadence output as a way of calibrating your equipment if your equipment outputs cadence but not watts. The number you enter is a multiplier applied to your actual cadence.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7972,7 +7972,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Default is “QZ.” Please leave this set to default so that other Strava users will see the QZ; a tiny bit of advertising that helps promote the app and support its development. If you choose to remove it, please consider contributing to the developer’s Patreon or Buy Me a Coffee accounts or just subscribe to the Swag bag in the left side bar to allow me to continue developing and supporting the app.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7999,7 +7999,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("QZ can open a external browser in order to auth strava to QZ. Default: disabled.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8027,7 +8027,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Append the Virtual Tag to the Strava Activity") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8054,7 +8054,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Append the Date to the Strava Activity as a prefix only for non-peloton workout") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8082,7 +8082,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Allows you to change resistance during auto-follow mode using the volume buttons of the device running QZ, Bluetooth headphones or a Bluetooth remote. Changes made using these external controls will be visible in the Gears tile. This is a VERY USEFUL feature! Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8109,7 +8109,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Debounce the volume buttons, so you will only see 1 gear step if there are 2 or more volume near steps. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8137,7 +8137,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If the power output/watts your equipment sends to QZ is quite variable, this setting will result in smoother Power Zone graphs. This is also helpful for use with Power Meter Pedals. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8165,7 +8165,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables the calculation of watts, even while in Pause mode. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8193,7 +8193,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on if you have a bike with inclination capabilities to fix Zwift’s bug that sends half-negative downhill inclination") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8231,7 +8231,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Inclination Offset and Gain are used to adjust the incline set by Zwift instead of, or in addition to, using the QZ Zwift Gain setting. For example, when Zwift changes the incline to 1%, you can have your treadmill change to 2%. The number you enter as an offset adds to the inclination sent from Zwift or any other 3rd party app. Default is 0.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8269,7 +8269,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("The number you enter as a Gain is a multiplier applied to the inclination sent from Zwift or any other 3rd party app. Default is 1.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8296,7 +8296,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This prevents your fitness device from sending its wattage calculation to QZ and defaults to QZ’s more accurate calculation.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8332,7 +8332,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can trigger auto laps in the FIT file based on distance. Unit: "+ (settings.miles_unit?"Mi":"KM") +" Default: 0 (disabled).") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8368,7 +8368,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This slow down the inclination changes adding a delay between each change. This is not applied to all the model of treadmill/bike. Default is 0.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8402,7 +8402,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Don't touch these settings if your bike works properly!") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8428,7 +8428,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If your bike doesn’t have Bluetooth, this setting allows you to use a cadence sensor so your bike will work with QZ. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8476,7 +8476,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Use this setting to connect QZ to your cadence sensor. Default is Disabled.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8514,7 +8514,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Wheel ratio is the multiplier used by QZ to calculate your speed based on your cadence. For example, if you enter 1 for your wheel ratio and you are riding at a cadence of 30, QZ will display your speed as 30 km/h. The default of 0.33 is correct for most bikes.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8552,7 +8552,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If your bike doesn’t have Bluetooth, this setting allows you to use a power meter pedal sensor so your bike will work with QZ. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8580,7 +8580,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If your treadmill doesn’t have Bluetooth, this setting allows you to use a Stryde sensor (or similar) so your treadmill will work with QZ. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8608,7 +8608,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Some power sensors send cadence divided by 2. This setting will fix this behavior.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8636,7 +8636,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Divide the cadence sent to Strava by 2.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8663,7 +8663,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you have a bluetooth treadmill and also a Stryd device connected to QZ and you want to use the speed from the stryd instead of the speed of the treadmill, enable this. Default: disabled.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8690,7 +8690,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you have a bluetooth treadmill and also a Stryd device connected to QZ, by default Stryd can't get the inclination from the treadmill. Enabling this and QZ will add a inclination gain to the power read from the Stryd. Default: disabled.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8738,7 +8738,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Leave on Disabled or select from list of found Bluetooth devices.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9517,7 +9517,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Use it to change the gears on QZ!") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9544,7 +9544,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Use it to change the gears on QZ!") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9571,7 +9571,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Debounce the buttons, so you will only see 1 gear step even if you are keep pressing the buttons. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9716,7 +9716,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Leave this setting off unless the Support staff asks you to turn it on during troubleshooting. Can improve the Android Bluetooth connection to Zwift. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9744,7 +9744,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Same as “Relaxed Bluetooth for mad devices”. Leave off unless the Support staff asks you to turn it on. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9772,7 +9772,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Leave this off unless the Support staff asks you to turn it on. Enables a new Bluetooth service, indicating the battery level of your device. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9827,7 +9827,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Forces QZ to communicate ONLY the Heart Rate metric to third-party apps. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9855,7 +9855,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables QZ to communicate with the Echelon app. This setting can only be used with iOS running QZ and iOS running the Echelon app. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9883,7 +9883,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables QZ to send a rower Bluetooth profile instead of a bike profile to third party apps that support rowing (examples: Kinomap and BitGym). This should be off for Zwift. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9911,7 +9911,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables third-party apps to change the resistance of your equipment. Default is on.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9940,7 +9940,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This changes the virtual Bluetooth bridge from the standard FMTS to the Power Sensor interface. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9968,7 +9968,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables a virtual bluetooth bridge to the iFit App. This setting requires that at least one device be Android. For example, this setting does NOT work with QZ on iOS and iFit to iOS, but DOES work with QZ on iOS and iFit to Android. On Android remember to rename your device into I_EL into the android settings and reboot your device.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10004,7 +10004,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables the compatibility of the Wahoo KICKR protocol to Wahoo RGT app. Leave the RGT compatibility disabled in order to use Zwift.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10040,7 +10040,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you have multiple QZ instances, you can change the id of the virtual wahoo device. Default: 0") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10095,7 +10095,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("By default QZ sends the info to Zwift or any other 3rd party apps with a 1000ms interval rate. Enabling the Race Mode setting will cause QZ to send them to 100ms (10hz). Of course the bottleneck will be always your bike/treadmill.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10123,7 +10123,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Forces the virtual Bluetooth bridge to send only the cadence information instead of the full FTMS metrics. Default is off.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10196,7 +10196,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Forces Android devices to remain awake while QZ is running. Default is on.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10224,7 +10224,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This MUST be always ON on an iOS device. Turning it OFF will lead to unexpected crashes of QZ. Default is on.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10252,7 +10252,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Simulates QZ being connected to a bike. When this is turned on QZ will calculate KCal based on your heart rate. Examples of when to use this setting: ○ To capture Peloton class data for classes without connected equipment (e.g., a strength or yoga workout).. ○ To arrange tiles on the QZ dashboard without connecting to your equipment. ○ To use the QZ Apple Watch app without connecting to your equipment.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10280,7 +10280,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Same as Fake Device but instead of simulating a bike it simulates a treadmill.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10308,7 +10308,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Same as Fake Device but instead of simulating a bike it simulates an elliptical.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10335,7 +10335,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Same as Fake Device but instead of simulating a bike it simulates a rower.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10363,7 +10363,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Leave this on unless you have issues connecting your Bluetooth HRM to QZ. If turning this off does not solve the connection issue, open a support ticket on GitHub. Default is on.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10391,7 +10391,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: enable this to force Android to don't kill QZ when it's running on background") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10418,7 +10418,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: force QZ to use the /Documents/QZ folder for debug log and fit files") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10446,7 +10446,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on to save a debug log to your device for use when requesting help with a bug.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10466,7 +10466,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Clears all the QZ logs, QZ .fit files and QZ images (these files are saved by QZ for every session) from your device while maintaining your saved Profiles and Settings.") font.bold: true font.italic: true - font.pixelSize: 9 + font.pixelSize: Qt.application.font.pixelSize textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter From c90849063e3db727264c48aa4f759c42615f76e1 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 27 Aug 2024 15:46:18 +0200 Subject: [PATCH 051/162] Revert " Treadmill stops automatically in Zwift #2539" This reverts commit 4bb4aba1094f7b8d83c8d9ebac96c41a3189b3dd. --- .../trxappgateusbtreadmill/trxappgateusbtreadmill.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp b/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp index 36ae08c45..6f34518e7 100644 --- a/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp +++ b/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp @@ -41,13 +41,10 @@ void trxappgateusbtreadmill::writeCharacteristic(uint8_t *data, uint8_t data_len } writeBuffer = new QByteArray((const char *)data, data_len); -#ifndef Q_OS_IOS if (gattWriteCharacteristic.properties() & QLowEnergyCharacteristic::WriteNoResponse) { gattCommunicationChannelService->writeCharacteristic(gattWriteCharacteristic, *writeBuffer, QLowEnergyService::WriteWithoutResponse); - } else -#endif - { + } else { gattCommunicationChannelService->writeCharacteristic(gattWriteCharacteristic, *writeBuffer); } From f942282b7eb0378904cf204fb84e874cfb62ceef Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 28 Aug 2024 07:54:33 +0200 Subject: [PATCH 052/162] bluetooth connection issue of keep bike #2543 --- src/devices/bluetooth.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 998269a9c..8c2a0cff5 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -2103,7 +2103,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { // connect(ultraSportBike, &solebike::debug, this, &bluetooth::debug); ultraSportBike->deviceDiscovered(b); this->signalBluetoothDeviceConnected(ultraSportBike); - } else if ((b.name().toUpper().startsWith(QStringLiteral("KEEP_BIKE_"))) && !keepBike && filter) { + } else if ((b.name().toUpper().startsWith(QStringLiteral("KEEP_BIKE_")) || + b.name().toUpper().startsWith(QStringLiteral("KEEP_CC_"))) && !keepBike && filter) { this->setLastBluetoothDevice(b); this->stopDiscovery(); keepBike = new keepbike(noWriteResistance, noHeartService, bikeResistanceOffset, bikeResistanceGain); From 328f0992b6bf9b362d45c1bc914bc48969bb04c1 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 28 Aug 2024 08:52:57 +0200 Subject: [PATCH 053/162] Kettler Spin Bike Racer S #2542 --- src/devices/bluetooth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 8c2a0cff5..bf69c390c 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1548,6 +1548,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { this->signalBluetoothDeviceConnected(horizonGr7Bike); } else if ((b.name().toUpper().startsWith(QStringLiteral("STAGES ")) || (b.name().toUpper().startsWith("TACX SATORI")) || + (b.name().toUpper().startsWith("RACER S")) || ((b.name().toUpper().startsWith("KICKR CORE")) && !deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && deviceHasService(b, QBluetoothUuid((quint16)0x1818))) || (b.name().toUpper().startsWith(QStringLiteral("QD")) && b.name().length() == 2) || (b.name().toUpper().startsWith(QStringLiteral("DFC")) && b.name().length() == 3) || From f4b6663c5d7af1b8e7119bc1b0c1f7c035c5ed1c Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 28 Aug 2024 11:14:00 +0200 Subject: [PATCH 054/162] bluetooth connection issue of keep bike #2543 --- src/devices/keepbike/keepbike.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/devices/keepbike/keepbike.cpp b/src/devices/keepbike/keepbike.cpp index 788d6e015..4528d87cc 100644 --- a/src/devices/keepbike/keepbike.cpp +++ b/src/devices/keepbike/keepbike.cpp @@ -355,7 +355,9 @@ void keepbike::stateChanged(QLowEnergyService::ServiceState state) { gattWriteCharacteristic = gattCommunicationChannelService->characteristic(_gattWriteCharacteristicId); gattNotifyCharacteristic = gattCommunicationChannelService->characteristic(_gattNotifyCharacteristicId); - Q_ASSERT(gattWriteCharacteristic.isValid()); + if(!gattWriteCharacteristic.isValid()) { + gattWriteCharacteristic = gattCommunicationChannelService->characteristic(_gattNotifyCharacteristicId); + } Q_ASSERT(gattNotifyCharacteristic.isValid()); // establish hook into notifications From 6b0777233d358003d4d9fa0e36504b4bac19f655 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 28 Aug 2024 13:45:37 +0200 Subject: [PATCH 055/162] removed log of username settings for privacy reasons --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 987aa291e..e35b2a466 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -399,7 +399,7 @@ int main(int argc, char *argv[]) { qInstallMessageHandler(myMessageOutput); qDebug() << QStringLiteral("version ") << app->applicationVersion(); foreach (QString s, settings.allKeys()) { - if (!s.contains(QStringLiteral("password")) && !s.contains("user_email")) { + if (!s.contains(QStringLiteral("password")) && !s.contains("user_email") && !s.contains("username")) { qDebug() << s << settings.value(s); } From 4fe689ac55c6c069c0c2d974f5b469dfaa164c33 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 28 Aug 2024 16:03:03 +0200 Subject: [PATCH 056/162] font in the settings fixed --- src/settings-tiles.qml | 76 +++++----- src/settings.qml | 312 +++++++++++++++++++++-------------------- 2 files changed, 195 insertions(+), 193 deletions(-) diff --git a/src/settings-tiles.qml b/src/settings-tiles.qml index 20b0d8ae8..31d4c80cc 100644 --- a/src/settings-tiles.qml +++ b/src/settings-tiles.qml @@ -238,7 +238,7 @@ ScrollView { text: qsTr("Speed in kilometers per hour. (To set your speed units to miles, go to Settings > General Options > Use Miles unit in UI).") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -304,7 +304,7 @@ ScrollView { text: qsTr("Bike pedal cadence changes color to indicate how your cadence compares to the cadence called out in Peloton classes. The tile displays the following colors: white if there is no target cadence in the program, red if your cadence is lower than the target, green if your cadence matches the target, and orange if your cadence is higher than the target.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -345,7 +345,7 @@ ScrollView { text: qsTr("Bike pedal cadence in rotations per minute (RPM) or Treadmill cadence if a shoe-mounted cadence sensor or Apple Watch QZ app is used.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -422,7 +422,7 @@ ScrollView { text: qsTr("Estimated calories burned during session, calculated on weight, age, and watts.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -467,7 +467,7 @@ ScrollView { text: qsTr("Estimated distance traveled during the session.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -512,7 +512,7 @@ ScrollView { text: qsTr("Current pace per mile or kilometer (Treadmill, Elliptical and Rower)") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -557,7 +557,7 @@ ScrollView { text: qsTr("Displays your bike’s resistance. The +/- buttons can be used to change resistance, if your bike is compatible.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -602,7 +602,7 @@ ScrollView { text: qsTr("Displays the watts generated by your current effort. Watt is also referred to as output (for example, in Peloton). If your equipment does not communicate watts, QZ will calculate watts using resistance and cadence.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -647,7 +647,7 @@ ScrollView { text: qsTr("Estimation of weight loss during the session.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -693,7 +693,7 @@ ScrollView { text: qsTr("Average watts produced for the session.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -771,7 +771,7 @@ ScrollView { text: qsTr("Percentage of current FTP and current FTP zone.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -848,7 +848,7 @@ ScrollView { text: qsTr("Built-in treadmill fan speed (Treadmill only)") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -893,7 +893,7 @@ ScrollView { text: qsTr("Cumulative power produced during the session in kilojoules.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -938,7 +938,7 @@ ScrollView { text: qsTr("Total time from start of the session.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -983,7 +983,7 @@ ScrollView { text: qsTr("Total time moving during the session.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1028,7 +1028,7 @@ ScrollView { text: qsTr("Allows you to sync resistance and cadence target changes with the Peloton coach’s callouts. If the targets are changing in QZ after the coach’s callouts, use the ‘+’ button to add seconds (essentially speeding QZ up). Use the ‘-’ button to slow QZ down. Use this tile in conjunction with the Remaining Time/Row tile (see below).") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1073,7 +1073,7 @@ ScrollView { text: qsTr("Displays time remaining in Peloton class.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1199,7 +1199,7 @@ ScrollView { text: qsTr("Resistance of your bike converted to the Peloton bike scale of 1 to 100.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1244,7 +1244,7 @@ ScrollView { text: qsTr("Displays target resistance in your bike’s resistance scale. For example, during a Peloton class or Zwift session, you want the resistance displayed in this tile to match the Resistance Tile.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1290,7 +1290,7 @@ ScrollView { text: qsTr("Displays target resistance converted to the Peloton bike scale of 1 to 100. For example, during a Peloton class, you want the resistance displayed in this tile to match the Peloton Resistance Tile.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1335,7 +1335,7 @@ ScrollView { text: qsTr("Displays target cadence.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1380,7 +1380,7 @@ ScrollView { text: qsTr("Displays target output (watts) when this information is provided by third-party apps.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1426,7 +1426,7 @@ ScrollView { text: qsTr("Displays the target power zone when this information is provided by third-party apps.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1566,7 +1566,7 @@ ScrollView { text: qsTr("Calculates your output (watts) divided by your weight. This is the primary metric used by Zwift and similar apps to calculate your virtual speed. NOTE: This is a much better metric to use than Output/Watts when comparing your effort to other users. This is why Peloton’s leaderboard, which uses only Output, is flawed.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1611,7 +1611,7 @@ ScrollView { text: qsTr("Allows you to change resistance while in Auto-Follow Mode.This tile allows you override the target resistance sent by third-party apps. For example, you would use the Gears Tile to increase resistance and generate more watts for sprinting in Zwift.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1653,7 +1653,7 @@ ScrollView { text: qsTr("It shows 2 big gear buttons on the UI") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1698,7 +1698,7 @@ ScrollView { text: qsTr("Displays the time remaining until the next cadence and/or resistance interval.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1743,7 +1743,7 @@ ScrollView { text: qsTr("Displays the next Peloton interval with duration and FTP Zone (in Power Zone classes) or Peloton Resistance (non–Power Zone classes).") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1788,7 +1788,7 @@ ScrollView { text: qsTr("Displays metabolic equivalents (METs), a measurement of energy expenditure and amount of oxygen used by the body compared to the body at rest. (e.g., 4 METS requires the body to use 4 times as much oxygen than when at rest, which means it requires more energy and burns more calories).") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1865,7 +1865,7 @@ ScrollView { text: qsTr("Displays the current time.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1910,7 +1910,7 @@ ScrollView { text: qsTr("(Rower only) Displays the number of strokes rowed.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1955,7 +1955,7 @@ ScrollView { text: qsTr("(Rower only) Displays the stroke length.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2000,7 +2000,7 @@ ScrollView { text: qsTr("(Elite Rizer only) Displays steering angle.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2045,7 +2045,7 @@ ScrollView { text: qsTr("Use this tile to display the target heart rate zone in which you’ve chosen to work out in Settings > Training Program Options.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2090,7 +2090,7 @@ ScrollView { text: qsTr("(Elite Rizer only) Allows control of the incline of external inclination equipment.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2135,7 +2135,7 @@ ScrollView { text: qsTr("(requires a compatible footpod with accelerometer; treadmill only) Displays stride while walking or running.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2180,7 +2180,7 @@ ScrollView { text: qsTr("(requires a compatible footpod with accelerometer; treadmill only) Displays time foot is on contact with ground while walking or running.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2225,7 +2225,7 @@ ScrollView { text: qsTr("(requires a compatible footpod with accelerometer; treadmill only) Displays the up and down movement while walking or running.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter diff --git a/src/settings.qml b/src/settings.qml index a623a777a..e95d60a4e 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -1043,11 +1043,12 @@ import QtQuick.Dialogs 1.0 text: qsTr("This changes the size of the tiles that display your metrics. The default is 100%. To fit more tiles on your screen, choose a smaller percentage. To make them larger, choose a percentage over 100%. Do not enter the percent symbol") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter Layout.alignment: Qt.AlignLeft | Qt.AlignTop + width: column1.width * 0.8 Layout.fillWidth: true color: Material.color(Material.Lime) } @@ -1080,7 +1081,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter your weight in kilograms so QZ can more accurately calculate calories burned. NOTE: If you choose to use miles as the unit for distance traveled, you will be asked to enter your weight in pounds (lbs).") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1118,7 +1119,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter your age so that calories burned can be more accurately calculated.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1158,7 +1159,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Select your gender so that calories burned can be more accurately calculated.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1197,7 +1198,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you train to specific output (or watts) levels, for example in Peloton Power Zone classes,and have taken an FTP test (Functional Threshold Power), enter your FTP here. This number is used to calculate your Power Zones (Zones 1 to 7 for Peloton and 1 to 6 for Zwift).") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1233,7 +1234,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you train to specific output (or watts) levels, for example with Stryd,and have taken an CP test (Critical Power Test), enter your CP here. This number is used to calculate your RSS.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1270,7 +1271,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("No need to enter data here. It is for a possible future QZ feature.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1307,7 +1308,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter your email address to receive an automated email with stats and charts when you hit STOP at the end of each workout. Make sure there are no spaces before or after the email address; this is the most common reason the automated email is not sent. Privacy Note: Email addresses are not collected by the developer and are only saved locally on your device.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1335,7 +1336,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn on if you want QZ to display distance traveled in miles. Default is off and set to kilometers.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1363,7 +1364,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn on to set QZ to always open in PAUSE mode. This is important for Peloton classes so that you can sync the start of your QZ workout with the start of the Peloton class. Turn off to have QZ start tracking and timing your workout as soon as it opens.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1391,7 +1392,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on for: - Peloton Bootcamp classes or other workouts that are on and off the bike or treadmill. QZ will continue to track your workout even when you step away from your equipment. - Capturing non-equipment-based workouts, such as yoga or strength training. NOTE: All such workouts are labeled as “Rides” in Strava, but you can edit the label in Strava.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1407,7 +1408,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Zwift users: keep this setting off") font.bold: yes font.italic: yes - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1421,7 +1422,7 @@ import QtQuick.Dialogs 1.0 textColor: Material.color(Material.Grey) color: Material.backgroundColor accordionContent: ColumnLayout { - spacing: 10 + spacing: 0 SwitchDelegate { id: switchDelegate text: qsTr("Heart Rate service outside FTMS") @@ -1441,7 +1442,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("(For Android Version 10 and above, this setting cannot be changed. This setting can be changed for Android Version 9 and below and for iOS.) When this setting is turned off, QZ sends heart rate data in a format designed to improve compatibility with third-party apps, such as Zwift and Peloton. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1469,7 +1470,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on to prevent a built-in heart rate monitor (HRM) on your exercise equipment from sending that data to QZ. This allows QZ to connect to your external HRM, such as a chest band or Apple Watch.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1497,7 +1498,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This prevents your bike or treadmill from sending its calories-burned calculation to QZ and defaults to QZ’s more accurate calculation.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1539,10 +1540,11 @@ import QtQuick.Dialogs 1.0 text: qsTr("Apple Watch users: leave it disabled! Just open the app on your watch") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter + Layout.fillWidth: true color: Material.color(Material.Red) } @@ -1715,7 +1717,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("QZ uses a standard age-based calculation for maximum heart rate and then sets the heart rate zones based on that max heart rate. If you know your actual max heart rate (the highest your heart rate is known to reach), turn this option on and enter your actual max heart rate. Then click OK.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1730,7 +1732,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Choose the percentages for where you want your zones 1-4 to end and click OK.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1852,7 +1854,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Expand the bars to the right to display the options under this setting. These settings are used to calculate power (watts) for bikes that do not have power meters. Instead QZ estimates power from your cadence and heart rate. You can calibrate how QZ calculates your power from heart rate as follows: If you know that at a stable pace you produce 100W of power at a heart rate of 150 BPM and 150W at 170 BPM, you can add these values under Sessions 1 and 2 Watt and HR and QZ will calculate your power based on that trend line.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1892,7 +1894,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("QZ calculates speed based on your pedal cadence (RPMs). Enable this setting if you want your speed to be calculated based on your power output (watts), as Zwift and some other apps do. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1918,7 +1920,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("QZ will remember the last Gears value and it will restore on startup") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -1955,7 +1957,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("0.005 = Clinchers\n0.004 = Tubulars\n0.012 = MTB") font.italic: true Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 color: "steelblue" } RowLayout { @@ -1987,7 +1989,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables QZ to include the weight of your bike when calculating speed. For example, if you are competing against yourself on VZfit, adding bike weight will “level the playing field” against your virtual self. If you have set QZ to calculate distance in miles, enter the bike weight in pounds (lbs). Default unit is kilograms (kgs).") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2063,7 +2065,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enable this setting ONLY when using Zwift in ERG (workout) Mode. QZ will communicate the target resistance (or automatically adjust your resistance if your bike has this capability) to match the target watts based on your cadence (RPM). In ERG Mode, the changes in road slope will not affect target resistance, as is the case in Simulation Mode. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2101,7 +2103,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This setting sets your “flat road” in Zwift. All communicated resistance changes will be based on this setting. The value entered is personal preference and will be dependent on your level of fitness. The suggested value for Echelon bikes is between 18 and 20. Default is 4.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2139,7 +2141,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("(for bikes and treadmills when using “treadmill as a bike” setting). This setting scales the resistance from your bike or the speed from your treadmill before sending it to Zwift. Default is 1.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2177,7 +2179,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("In ERG Mode or during a Power Zone workout on Peloton, the app sends a “target output” request. If the output requested doesn’t match your current output (calculated using cadence and resistance level), your target resistance will change to help you get closer to the target output. If the filter is set to higher values, you will get less adjustment of the target resistance and you will have to increase your cadence to match the target output. The Up and Down Watt Filter settings are the upper and lower margin before the adjustment of resistance is communicated. Example: if the up and down filters are set to 10 and the target output is 100 watts, a change of your resistance will only be communicated if your bike produces less than 90 Watts or more than 110 Watts. Default is 10.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2215,7 +2217,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("See above. Default is 10.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2253,7 +2255,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Use this setting to set a minimum target resistance. For example, if you do not want to ride at a resistance below 25, enter a value of 25 and QZ will not set a target resistance below 25. Default is 0.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2291,7 +2293,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Similar to the above, but sets a maximum target resistance. Default is 999.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2329,7 +2331,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("(only for bikes with electronically-controlled resistance): Enter the resistance level you want QZ to set at startup. Default is 1.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2365,7 +2367,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Applies a multiplier to the gears tile. Default is 1.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2404,7 +2406,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you have a generic FTMS bike and the tiles doesn't appear on the main QZ screen, select here the bluetooth name of your bike.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2418,7 +2420,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Expand the bars to the right to display the options under this setting. Select your specific model (if it is listed) and leave all other settings on default. If you encounter problems or have a question about the QZ settings for your equipment, open a support ticket on GitHub or ask the QZ community on the QZ Facebook Group.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -2504,7 +2506,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Since this bike doesn't send resistance over bluetooth, QZ is calculating it using cadence and wattage. The result could be a little 'jumpy' and so, with this setting, you can filter the resistance tile value. The unit is a pure resistance level, so putting 5 means that you will see a resistance changes only when the resistance is changing by 5 levels.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3486,7 +3488,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Set 100mm as wheel circumference in settings of ant+ speed sensor") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3512,7 +3514,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on if you need to use ANT+ along with Bluetooth. Power is also sent.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3548,7 +3550,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your speed sent over ANT+. The number you enter as an Offset adds that amount to your speed.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3585,7 +3587,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your speed output sent over ANT+. For example, to use a rower to cycle in Zwift, you could double your speed output to better match your cycling speed. The number you enter is a multiplier applied to your actual speed.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3613,7 +3615,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This setting enables receiving the heart rate from an external HRM over ANT+ instead of from QZ.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3678,7 +3680,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Allows continuous display of the Start/Pause and Stop buttons across the top of the screen during your workouts. Default is on.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3715,7 +3717,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: width of the floating window.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3752,7 +3754,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: height of the floating window.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3789,7 +3791,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: transparency percentage of the floating window.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -3817,7 +3819,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: if enabled the floating window will start as soon as the fitness devices is connected.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4066,7 +4068,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter the email address you use to login to Peloton (NOT your leaderboard name). Ensure there are no spaces before or after your email. Click OK.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4105,7 +4107,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter the password you use to login to Peloton. Click OK. If you have entered the correct login credentials and the QZ is able to access your account, you will see a when you reopen QZ. This is a secure login, not accessible by anyone but you.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4145,7 +4147,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Typically, Peloton coaches call out a range for target incline, resistance and/or speed. Use this setting to choose the difficulty of the target QZ communicates. Difficulty level can be set to lower, upper or average. Click OK.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4183,7 +4185,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Difficulty level for peloton treadmill classes. 1 is easy 10 is hard.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4221,7 +4223,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Difficulty level for peloton rower classes. 1 is easy 10 is hard.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4258,7 +4260,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("As of 4/1/2022, this feature is broken due to a Power Zone Pack (PZP) website change. Leave (or change back to) the default of “username” (without quotation marks, all lowercase and all one word) until further notice.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4297,7 +4299,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("As of 4/1/2022, this feature is broken due to a Power Zone Pack (PZP) website change. Leave this setting blank until further notice.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4335,7 +4337,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Conversion gain is a multiplier. Use this setting to align the Peloton resistance calculated by QZ with the relative effort required by your bike. In most cases the default values will be correct.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4373,7 +4375,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Increases the resistance that QZ displays in the Peloton Resistance tile. If QZ’s calculated conversion from your bike’s resistance scale to Peloton’s seems too low, the number you enter here will be added to the calculated resistance without increasing your effort or actual resistance. (Example: If QZ displays Peloton Resistance of 30 and you enter 5, QZ will display 35.)") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4401,7 +4403,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on to send cadence to Peloton over Bluetooth. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4469,7 +4471,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("By default, QZ communicates heart rate to Peloton. Use this setting to change the metric that appears on the Peloton screen.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4509,7 +4511,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Allows you to choose whether you would like the Peloton class air date to display before or after the class title on Strava.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4537,7 +4539,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on if you want QZ to capture a link to the Peloton class and display it in Strava.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4564,7 +4566,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("By default, QZ treats Spin-UPS in Power Zone rides as an increasing ramp to warm you up. You can disable this, to leave the resistance up to you.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4592,7 +4594,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Only for Android where QZ is running on the same Peloton device. This setting enables the AI (Artificial Intelligence) on QZ that will read the peloton workout screen and will adjust the peloton offset in order to stay in sync in realtime with your Peloton workout. A popup about screen recording will appear in order to notify this.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4619,7 +4621,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This setting enables the AI (Artificial Intelligence) on the QZ Companion AI app that will read the peloton workout screen and will adjust the peloton offset in order to stay in sync in realtime with your Peloton workout.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4647,7 +4649,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Only if you are on a real Peloton Bike/Bike+! This will allow QZ to collect metrics from your Bike/Bike+ and send it to Zwift. Peloton Free ride must running.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4694,7 +4696,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter the email address you use to login to Zwift. Ensure there are no spaces before or after your email. Click OK.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4734,7 +4736,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter the password you use to login to Zwift. Click OK.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4770,7 +4772,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Define the number of delay seconds between each inclination change from Zwift. This value can't be less than 5. Default: 5") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4797,7 +4799,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Only for Android and iOS: QZ will read the inclination in real time from the Zwift app and will adjust the inclination on your treadmill. It doesn't work on workout") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4824,7 +4826,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Only for PC where QZ is running on the same Zwift device. This setting enables the AI (Artificial Intelligence) on QZ that will read the Zwift inclination from the Zwift app and will adjust the inclination on your treadmill. A popup about screen recording will appear in order to notify this.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4865,7 +4867,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Only for PC where QZ is running on the same Zwift device. This setting enables the AI (Artificial Intelligence) on QZ that will read the Zwift inclination and speed from the Zwift app during a workout and will adjust the inclination and the speed on your treadmill. A popup about screen recording will appear in order to notify this.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4902,7 +4904,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you want to send metrics to your Garmin device from your Mac, enable this. Otherwise leave it disabled.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4929,7 +4931,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You have to install the QZ Companion App on your Garmin Watch/Computer first.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4956,7 +4958,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Use your garmin watch to get the ANT+ metrics from a bike") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -4996,7 +4998,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Treadmill only: enabling this if you want that QZ will stop the tape at the end of the current train program.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5039,7 +5041,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("QZ controls your treadmill or bike to keep you within a chosen Heart Rate Zone. Turn on, set a target heart rate (HR) zone in which to train and click OK. For example, enter 2 to train in HR zone 2 and the treadmill will auto adjust the speed (or resistance on a bike) to maintain your heart rate in zone 2. QZ gradually increases or decreases your speed (or bike resistance) in small increments every 40 seconds to reach and maintain your target HR zone. During a workout, you can display and use the ‘+’ and ‘-’ button on the PID HR Zone tile to change the target HR zone.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5096,7 +5098,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Alternatively to 'PID on Heart Zone' setting you can use this couple of settings in order to specify a HR range.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5133,7 +5135,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enter your 1 mile time goal, click OK. This setting will be used when you’re following a training program with the speed control. These settings should also match the Zwift app settings. More info: https://github.com/cagnulein/qdomyos-zwift/issues/609.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5170,7 +5172,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("See 1 Mile Pace above; same except 5 km instead of 1 mile.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5207,7 +5209,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("See 1 Mile Pace above; same except 10 km instead of 1 mile.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5244,7 +5246,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("See 1 Mile Pace above; same except half marathon distance instead of 1 mile.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5281,7 +5283,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("See 1 Mile Pace above; same except marathon distance instead of 1 mile.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5321,7 +5323,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Select the default Pace to be used when the ZWO file does not indicate a precise pace.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5543,7 +5545,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn on and enter your choices for workout time (in minutes and seconds) and the maximum and minimum speed, incline (treadmill), and resistance (bike) and QZ will randomly change your speed and resistance or incline accordingly for the period of time you have selected.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5582,7 +5584,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn on to convert your treadmill output to bike output when riding on Zwift. QZ sends your treadmill metrics to Zwift over Bluetooth so that you can participate as a bike rider. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5610,7 +5612,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on to have QZ control the speed of your treadmill during, for example, Peloton classes based on the coach’s speed callouts. Your speed will be in the low, upper or average range based on your Peloton Options > Difficulty setting. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5638,7 +5640,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on to have QZ go into Pause mode upon opening when using a treadmill. This is for treadmills only. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5666,7 +5668,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Target Speed and Target Incline tile offer a way to increase/decrease the current difficulty with the plus/minus buttons. By default, with this setting disabled, the speed and the inclination change with a 3% gain for every pressure. Switching this ON, QZ will add a 0.1 speed offset or a 0.5 incline offset instead.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5704,7 +5706,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("(Speed Tile) This controls the amount of the increase or decrease in the speed (in kph/mph) when you press the plus or minus button in the Speed Tile. Default is 0.5 kph.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5742,7 +5744,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("(Incline Tile) This controls the amount of the increase or decrease in the inclination when you press the plus or minus button in the Incline Tile. Default is 0.5.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5778,7 +5780,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This overrides the minimum inclination value of your treadmill (in order to reduce the inclination movement). Default is -100") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5814,7 +5816,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This overrides the maximum inclination value of your treadmill (in order to reduce the inclination movement). Default is -100") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5835,7 +5837,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Overrides the default inclination values sent from the treadmill") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5862,7 +5864,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("For treadmills without inclination: turning this on and QZ will transform inclination requests into speed changes.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5901,7 +5903,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you have a generic FTMS bike and the tiles doesn't appear on the main QZ screen, select here the bluetooth name of your bike.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -5914,7 +5916,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Expand the bars to the right to display the options under this setting. Select your specific model (if it is listed) and leave all other settings on default. If you encounter problems or have a question about settings for your specific equipment with QZ, click here to open a support ticket on GitHub or ask the QZ community on the QZ Facebook Group.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -6527,7 +6529,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Default: 200. Change this only if you have random issues with speed or inclination (try to put 300)") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7392,7 +7394,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Allows you to force QZ to connect to your FTMS Rower. If you are in doubt, leave this Disabled and send an email to the QZ support. Default is “Disabled.”") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7673,7 +7675,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Allows you to force QZ to connect to your equipment (see “Bluetooth Troubleshooting” below). Default is “Disabled.”") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7711,7 +7713,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your watt output for moving your avatar faster/slower in Zwift or other similar apps as a way of calibrating your equipment. The number you enter as an Offset adds that amount to your watts.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7749,7 +7751,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your watt output for moving your avatar faster/slower in Zwift or other similar apps as a way of calibrating your equipment. For example, to use a rower to cycle in Zwift, you could double your watt output to better match your cycling speed by entering 2. The number you enter is a multiplier applied to your actual watts.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7787,7 +7789,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your speed for moving your avatar faster/slower in Zwift if your equipment outputs speed but not watts. The number you enter as an Offset adds that amount to your speed.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7826,7 +7828,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your speed output for moving your avatar faster/slower in Zwift or other apps as a way of calibrating your equipment if your equipment outputs speed but not watts. For example, to use a rower to cycle in Zwift, you could double your speed output to better match your cycling speed. The number you enter is a multiplier applied to your actual speed.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7864,7 +7866,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your cadence output. The number you enter as an Offset adds that amount to your cadence.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7902,7 +7904,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can increase/decrease your cadence output as a way of calibrating your equipment if your equipment outputs cadence but not watts. The number you enter is a multiplier applied to your actual cadence.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7972,7 +7974,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Default is “QZ.” Please leave this set to default so that other Strava users will see the QZ; a tiny bit of advertising that helps promote the app and support its development. If you choose to remove it, please consider contributing to the developer’s Patreon or Buy Me a Coffee accounts or just subscribe to the Swag bag in the left side bar to allow me to continue developing and supporting the app.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -7999,7 +8001,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("QZ can open a external browser in order to auth strava to QZ. Default: disabled.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8027,7 +8029,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Append the Virtual Tag to the Strava Activity") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8054,7 +8056,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Append the Date to the Strava Activity as a prefix only for non-peloton workout") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8082,7 +8084,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Allows you to change resistance during auto-follow mode using the volume buttons of the device running QZ, Bluetooth headphones or a Bluetooth remote. Changes made using these external controls will be visible in the Gears tile. This is a VERY USEFUL feature! Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8109,7 +8111,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Debounce the volume buttons, so you will only see 1 gear step if there are 2 or more volume near steps. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8137,7 +8139,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If the power output/watts your equipment sends to QZ is quite variable, this setting will result in smoother Power Zone graphs. This is also helpful for use with Power Meter Pedals. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8165,7 +8167,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables the calculation of watts, even while in Pause mode. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8193,7 +8195,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on if you have a bike with inclination capabilities to fix Zwift’s bug that sends half-negative downhill inclination") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8231,7 +8233,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Inclination Offset and Gain are used to adjust the incline set by Zwift instead of, or in addition to, using the QZ Zwift Gain setting. For example, when Zwift changes the incline to 1%, you can have your treadmill change to 2%. The number you enter as an offset adds to the inclination sent from Zwift or any other 3rd party app. Default is 0.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8269,7 +8271,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("The number you enter as a Gain is a multiplier applied to the inclination sent from Zwift or any other 3rd party app. Default is 1.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8296,7 +8298,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This prevents your fitness device from sending its wattage calculation to QZ and defaults to QZ’s more accurate calculation.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8332,7 +8334,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("You can trigger auto laps in the FIT file based on distance. Unit: "+ (settings.miles_unit?"Mi":"KM") +" Default: 0 (disabled).") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8368,7 +8370,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This slow down the inclination changes adding a delay between each change. This is not applied to all the model of treadmill/bike. Default is 0.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8402,7 +8404,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Don't touch these settings if your bike works properly!") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8428,7 +8430,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If your bike doesn’t have Bluetooth, this setting allows you to use a cadence sensor so your bike will work with QZ. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8476,7 +8478,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Use this setting to connect QZ to your cadence sensor. Default is Disabled.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8514,7 +8516,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Wheel ratio is the multiplier used by QZ to calculate your speed based on your cadence. For example, if you enter 1 for your wheel ratio and you are riding at a cadence of 30, QZ will display your speed as 30 km/h. The default of 0.33 is correct for most bikes.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8552,7 +8554,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If your bike doesn’t have Bluetooth, this setting allows you to use a power meter pedal sensor so your bike will work with QZ. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8580,7 +8582,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If your treadmill doesn’t have Bluetooth, this setting allows you to use a Stryde sensor (or similar) so your treadmill will work with QZ. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8608,7 +8610,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Some power sensors send cadence divided by 2. This setting will fix this behavior.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8636,7 +8638,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Divide the cadence sent to Strava by 2.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8663,7 +8665,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you have a bluetooth treadmill and also a Stryd device connected to QZ and you want to use the speed from the stryd instead of the speed of the treadmill, enable this. Default: disabled.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8690,7 +8692,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you have a bluetooth treadmill and also a Stryd device connected to QZ, by default Stryd can't get the inclination from the treadmill. Enabling this and QZ will add a inclination gain to the power read from the Stryd. Default: disabled.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -8738,7 +8740,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Leave on Disabled or select from list of found Bluetooth devices.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9517,7 +9519,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Use it to change the gears on QZ!") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9544,7 +9546,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Use it to change the gears on QZ!") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9571,7 +9573,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Debounce the buttons, so you will only see 1 gear step even if you are keep pressing the buttons. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9716,7 +9718,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Leave this setting off unless the Support staff asks you to turn it on during troubleshooting. Can improve the Android Bluetooth connection to Zwift. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9744,7 +9746,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Same as “Relaxed Bluetooth for mad devices”. Leave off unless the Support staff asks you to turn it on. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9772,7 +9774,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Leave this off unless the Support staff asks you to turn it on. Enables a new Bluetooth service, indicating the battery level of your device. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9827,7 +9829,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Forces QZ to communicate ONLY the Heart Rate metric to third-party apps. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9855,7 +9857,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables QZ to communicate with the Echelon app. This setting can only be used with iOS running QZ and iOS running the Echelon app. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9883,7 +9885,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables QZ to send a rower Bluetooth profile instead of a bike profile to third party apps that support rowing (examples: Kinomap and BitGym). This should be off for Zwift. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9911,7 +9913,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables third-party apps to change the resistance of your equipment. Default is on.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9940,7 +9942,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This changes the virtual Bluetooth bridge from the standard FMTS to the Power Sensor interface. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -9968,7 +9970,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables a virtual bluetooth bridge to the iFit App. This setting requires that at least one device be Android. For example, this setting does NOT work with QZ on iOS and iFit to iOS, but DOES work with QZ on iOS and iFit to Android. On Android remember to rename your device into I_EL into the android settings and reboot your device.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10004,7 +10006,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Enables the compatibility of the Wahoo KICKR protocol to Wahoo RGT app. Leave the RGT compatibility disabled in order to use Zwift.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10040,7 +10042,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("If you have multiple QZ instances, you can change the id of the virtual wahoo device. Default: 0") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10095,7 +10097,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("By default QZ sends the info to Zwift or any other 3rd party apps with a 1000ms interval rate. Enabling the Race Mode setting will cause QZ to send them to 100ms (10hz). Of course the bottleneck will be always your bike/treadmill.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10123,7 +10125,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Forces the virtual Bluetooth bridge to send only the cadence information instead of the full FTMS metrics. Default is off.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10196,7 +10198,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Forces Android devices to remain awake while QZ is running. Default is on.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10224,7 +10226,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("This MUST be always ON on an iOS device. Turning it OFF will lead to unexpected crashes of QZ. Default is on.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10252,7 +10254,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Simulates QZ being connected to a bike. When this is turned on QZ will calculate KCal based on your heart rate. Examples of when to use this setting: ○ To capture Peloton class data for classes without connected equipment (e.g., a strength or yoga workout).. ○ To arrange tiles on the QZ dashboard without connecting to your equipment. ○ To use the QZ Apple Watch app without connecting to your equipment.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10280,7 +10282,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Same as Fake Device but instead of simulating a bike it simulates a treadmill.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10308,7 +10310,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Same as Fake Device but instead of simulating a bike it simulates an elliptical.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10335,7 +10337,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Same as Fake Device but instead of simulating a bike it simulates a rower.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10363,7 +10365,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Leave this on unless you have issues connecting your Bluetooth HRM to QZ. If turning this off does not solve the connection issue, open a support ticket on GitHub. Default is on.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10391,7 +10393,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: enable this to force Android to don't kill QZ when it's running on background") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10418,7 +10420,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Android Only: force QZ to use the /Documents/QZ folder for debug log and fit files") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10446,7 +10448,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Turn this on to save a debug log to your device for use when requesting help with a bug.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter @@ -10466,7 +10468,7 @@ import QtQuick.Dialogs 1.0 text: qsTr("Clears all the QZ logs, QZ .fit files and QZ images (these files are saved by QZ for every session) from your device while maintaining your saved Profiles and Settings.") font.bold: true font.italic: true - font.pixelSize: Qt.application.font.pixelSize + font.pixelSize: Qt.application.font.pixelSize - 2 textFormat: Text.PlainText wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter From aba3ff502ca9ccdef3dcfde853b5c7a3314c37e3 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 28 Aug 2024 16:30:59 +0200 Subject: [PATCH 057/162] Zu250s from ziYou bike #2548 --- src/devices/bluetooth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index bf69c390c..dbfe5d81b 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1497,6 +1497,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { (b.name().toUpper().startsWith("FLX") && b.name().length() == 10) || (b.name().toUpper().startsWith("CSRB") && b.name().length() == 11) || (b.name().toUpper().startsWith("DU30-")) || // BodyTone du30 + (b.name().toUpper().startsWith("BIKZU_")) || (b.name().toUpper().startsWith("HARISON-X15")) || (b.name().toUpper().startsWith("GLT") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || (b.name().toUpper().startsWith("SPORT01-") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // Labgrey Magnetic Exercise Bike https://www.amazon.co.uk/dp/B0CXMF1NPY?_encoding=UTF8&psc=1&ref=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&ref_=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&social_share=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&skipTwisterOG=1 From ff16880faeb90978b20314f0ed4aa0269cfcc311 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 29 Aug 2024 14:43:46 +0200 Subject: [PATCH 058/162] Kettler Ergometer #2551 --- src/devices/bluetooth.cpp | 1 + src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index dbfe5d81b..451b00e2d 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1488,6 +1488,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { (b.name().toUpper().startsWith("WATTBIKE")) || (b.name().toUpper().startsWith("ZYCLEZBIKE")) || (b.name().toUpper().startsWith("WAVEFIT-")) || + (b.name().toUpper().startsWith("KETTLERBLE")) || (b.name().toUpper().startsWith("JAS_C3")) || (b.name().toUpper().startsWith("RAVE WHITE")) || (b.name().toUpper().startsWith("DOMYOS-BIKING-")) || diff --git a/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp b/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp index 6f34518e7..f3f1c280a 100644 --- a/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp +++ b/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp @@ -654,7 +654,7 @@ void trxappgateusbtreadmill::characteristicWritten(const QLowEnergyCharacteristi } void trxappgateusbtreadmill::serviceScanDone(void) { - emit debug(QStringLiteral("serviceScanDone")); + qDebug() << QStringLiteral("serviceScanDone") << treadmill_type; QString uuid = QStringLiteral("0000fff0-0000-1000-8000-00805f9b34fb"); if (treadmill_type == TYPE::IRUNNING || treadmill_type == TYPE::REEBOK || treadmill_type == TYPE::DKN_2) { From a720717d5cca8190344a312179234fe76d769644 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 29 Aug 2024 15:19:26 +0200 Subject: [PATCH 059/162] Qz sets inclination to -15 on sole f85 treadmill, whenever zwift sends negative inclination #2552 --- src/devices/horizontreadmill/horizontreadmill.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/devices/horizontreadmill/horizontreadmill.cpp b/src/devices/horizontreadmill/horizontreadmill.cpp index aa3bbde39..c1ee4cdba 100644 --- a/src/devices/horizontreadmill/horizontreadmill.cpp +++ b/src/devices/horizontreadmill/horizontreadmill.cpp @@ -2087,6 +2087,7 @@ void horizontreadmill::stateChanged(QLowEnergyService::ServiceState state) { QBluetoothUuid _gattWriteCharControlPointId((quint16)0x2AD9); QBluetoothUuid _gattTreadmillDataId((quint16)0x2ACD); QBluetoothUuid _gattCrossTrainerDataId((quint16)0x2ACE); + QBluetoothUuid _gattInclinationSupported((quint16)0x2AD5); emit debug(QStringLiteral("BTLE stateChanged ") + QString::fromLocal8Bit(metaEnum.valueToKey(state))); for (QLowEnergyService *s : qAsConst(gattCommunicationChannelService)) { @@ -2130,6 +2131,9 @@ void horizontreadmill::stateChanged(QLowEnergyService::ServiceState state) { // some treadmills doesn't have the control point and also are Cross Trainer devices so i need // anyway to get the FTMS Service at least gattFTMSService = s; + } else if (c.uuid() == _gattInclinationSupported) { + s->readCharacteristic(c); + qDebug() << s->serviceUuid() << c.uuid() << "reading!"; } if (c.properties() & QLowEnergyCharacteristic::Write && c.uuid() == _gattWriteCharCustomService && @@ -2245,6 +2249,17 @@ void horizontreadmill::characteristicWritten(const QLowEnergyCharacteristic &cha void horizontreadmill::characteristicRead(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) { qDebug() << QStringLiteral("characteristicRead ") << characteristic.uuid() << newValue.toHex(' '); + QBluetoothUuid _gattInclinationSupported((quint16)0x2AD5); + if(characteristic.uuid() == _gattInclinationSupported && newValue.length() > 2) { + minInclination = ((double)( + (int16_t)( + ((int16_t)(int8_t)newValue.at(1) << 8) | + (uint8_t)newValue.at(0) + ) + ) / + 10.0); + qDebug() << "new minInclination is " << minInclination; + } } void horizontreadmill::serviceScanDone(void) { From 7e3eab5b8c88f94cd695c01ef66132d255fa4703 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 29 Aug 2024 21:24:21 +0200 Subject: [PATCH 060/162] New echelon stride treadmill #2555 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/bluetooth.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 4614f2011..a8957d829 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 852; + CURRENT_PROJECT_VERSION = 855; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 852; + CURRENT_PROJECT_VERSION = 855; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 852; + CURRENT_PROJECT_VERSION = 855; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 852; + CURRENT_PROJECT_VERSION = 855; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 852; + CURRENT_PROJECT_VERSION = 855; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 852; + CURRENT_PROJECT_VERSION = 855; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 451b00e2d..2be8a0ff8 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1628,7 +1628,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { } else if ((b.name().toUpper().startsWith(QLatin1String("ECH-STRIDE")) || b.name().toUpper().startsWith(QLatin1String("ECH-UK-")) || b.name().toUpper().startsWith(QLatin1String("ECH-FR-")) || - b.name().toUpper().startsWith(QLatin1String("STRIDE-")) || + b.name().toUpper().startsWith(QLatin1String("STRIDE")) || b.name().toUpper().startsWith(QLatin1String("STRIDE6S-")) || b.name().toUpper().startsWith(QLatin1String("ECH-SD-SPT"))) && !echelonStride && filter) { From f07e7f9c1f1e0f27532ab9bce6271d426bd3b3b5 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 30 Aug 2024 08:23:55 +0200 Subject: [PATCH 061/162] ASCEND S2 Spin bike #2556 --- src/devices/bluetooth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 2be8a0ff8..caba87c70 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1499,6 +1499,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { (b.name().toUpper().startsWith("CSRB") && b.name().length() == 11) || (b.name().toUpper().startsWith("DU30-")) || // BodyTone du30 (b.name().toUpper().startsWith("BIKZU_")) || + (b.name().toUpper().startsWith("WLT8828")) || (b.name().toUpper().startsWith("HARISON-X15")) || (b.name().toUpper().startsWith("GLT") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || (b.name().toUpper().startsWith("SPORT01-") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // Labgrey Magnetic Exercise Bike https://www.amazon.co.uk/dp/B0CXMF1NPY?_encoding=UTF8&psc=1&ref=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&ref_=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&social_share=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&skipTwisterOG=1 From a6cc8b5e87f63409a4c1ec69ee673c260f8611f9 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 30 Aug 2024 09:34:27 +0200 Subject: [PATCH 062/162] added inclination to the 3d maps for bikes --- src/templateinfosenderbuilder.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/templateinfosenderbuilder.cpp b/src/templateinfosenderbuilder.cpp index d9a169439..68ec79315 100644 --- a/src/templateinfosenderbuilder.cpp +++ b/src/templateinfosenderbuilder.cpp @@ -1090,6 +1090,9 @@ void TemplateInfoSenderBuilder::buildContext(bool forceReinit) { obj.setProperty(QStringLiteral("req_cadence"), (dep = ((bike *)device)->lastRequestedCadence()).value()); obj.setProperty(QStringLiteral("req_resistance"), (dep = ((bike *)device)->lastRequestedResistance()).value()); + obj.setProperty(QStringLiteral("inclination"), + (dep = ((bike *)device)->currentInclination()).value()); + obj.setProperty(QStringLiteral("inclination_avg"), dep.average()); } else if (tp == bluetoothdevice::ROWING) { obj.setProperty(QStringLiteral("gears"), ((rower *)device)->gears()); el = ((rower *)device)->lastRequestedPace(); From 5981e7cd001f48cd488c0157ee8a94c150f1902b Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sun, 1 Sep 2024 07:02:22 +0200 Subject: [PATCH 063/162] BH i-Nexor Bike support? #2441 --- src/virtualdevices/virtualtreadmill.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/virtualdevices/virtualtreadmill.cpp b/src/virtualdevices/virtualtreadmill.cpp index 49c4939da..b51bf0d0f 100644 --- a/src/virtualdevices/virtualtreadmill.cpp +++ b/src/virtualdevices/virtualtreadmill.cpp @@ -281,7 +281,7 @@ virtualtreadmill::virtualtreadmill(bluetoothdevice *t, bool noHeartService) { void virtualtreadmill::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) { qDebug() << QStringLiteral("characteristicChanged ") + QString::number(characteristic.uuid().toUInt16()) + - QStringLiteral(" ") + newValue; + QStringLiteral(" ") << newValue.toHex(' '); QByteArray reply; switch (characteristic.uuid().toUInt16()) { From 892d949e72c91a06f2610453d0e21714276ad1da Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sun, 1 Sep 2024 07:04:29 +0200 Subject: [PATCH 064/162] NPE Runn sensor fantasy values #2558 --- src/devices/bluetooth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index caba87c70..e7e1a0170 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1298,6 +1298,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { b.name().toUpper().startsWith(QStringLiteral("XT285")) || b.name().toUpper().startsWith(QStringLiteral("XTERRA TR")) || b.name().toUpper().startsWith(QStringLiteral("T118_")) || + b.name().toUpper().startsWith(QStringLiteral("RUNN ")) || b.name().toUpper().startsWith(QStringLiteral("EW-EP-")) || // Miweba MC700 ellipital Trainer #2419 b.name().toUpper().startsWith(QStringLiteral("TF04-")) || // Sport Synology Z5 Treadmill #2415 b.name().toUpper().startsWith(QStringLiteral("FIT-")) || // FIT-1596 From 496ea9f2be2ad61217a4ecbeea60263061aa94d0 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sun, 1 Sep 2024 08:37:55 +0200 Subject: [PATCH 065/162] stopping homeform session when the trainprogram ends and the ends setting is enabled --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/homeform.cpp | 5 +++++ src/homeform.h | 1 + 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index a8957d829..6c7014e44 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 855; + CURRENT_PROJECT_VERSION = 856; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 855; + CURRENT_PROJECT_VERSION = 856; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 855; + CURRENT_PROJECT_VERSION = 856; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 855; + CURRENT_PROJECT_VERSION = 856; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 855; + CURRENT_PROJECT_VERSION = 856; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 855; + CURRENT_PROJECT_VERSION = 856; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/homeform.cpp b/src/homeform.cpp index b00f478ba..967bf9f3c 100644 --- a/src/homeform.cpp +++ b/src/homeform.cpp @@ -1055,6 +1055,7 @@ void homeform::trainProgramSignals() { connect(trainProgram, &trainprogram::start, bluetoothManager->device(), &bluetoothdevice::start); connect(trainProgram, &trainprogram::stop, bluetoothManager->device(), &bluetoothdevice::stop); + connect(trainProgram, &trainprogram::stop, this, &homeform::StopFromTrainProgram); connect(trainProgram, &trainprogram::lap, this, &homeform::Lap); connect(trainProgram, &trainprogram::toastRequest, this, &homeform::onToastRequested); if (bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) { @@ -3735,6 +3736,10 @@ void homeform::StopRequested() { emit stopRequestedChanged(m_stopRequested); } +void homeform::StopFromTrainProgram(bool paused) { + Stop(); +} + void homeform::Stop() { QSettings settings; diff --git a/src/homeform.h b/src/homeform.h index b54f6443b..54728be0e 100644 --- a/src/homeform.h +++ b/src/homeform.h @@ -803,6 +803,7 @@ class homeform : public QObject { private slots: void Start(); void Stop(); + void StopFromTrainProgram(bool paused); void StartRequested(); void StopRequested(); void Lap(); From c8555e543a2f404597eb33c30f4bdf3e080c6dd8 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sun, 1 Sep 2024 08:55:38 +0200 Subject: [PATCH 066/162] Update homeform.cpp --- src/homeform.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/homeform.cpp b/src/homeform.cpp index 967bf9f3c..06b1750cd 100644 --- a/src/homeform.cpp +++ b/src/homeform.cpp @@ -1006,6 +1006,7 @@ void homeform::trainProgramSignals() { if (bluetoothManager->device()) { disconnect(trainProgram, &trainprogram::start, bluetoothManager->device(), &bluetoothdevice::start); disconnect(trainProgram, &trainprogram::stop, bluetoothManager->device(), &bluetoothdevice::stop); + disconnect(trainProgram, &trainprogram::stop, this, &homeform::StopFromTrainProgram); disconnect(trainProgram, &trainprogram::lap, this, &homeform::Lap); disconnect(trainProgram, &trainprogram::changeSpeed, ((treadmill *)bluetoothManager->device()), &treadmill::changeSpeed); From f1636f7915d73514ff616fae007726eabe02032b Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sun, 1 Sep 2024 14:22:53 +0200 Subject: [PATCH 067/162] adding popup to power, cadence and hr sensor --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/bluetooth.cpp | 6 +++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 6c7014e44..62a0c52ce 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 856; + CURRENT_PROJECT_VERSION = 857; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 856; + CURRENT_PROJECT_VERSION = 857; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 856; + CURRENT_PROJECT_VERSION = 857; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 856; + CURRENT_PROJECT_VERSION = 857; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 856; + CURRENT_PROJECT_VERSION = 857; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 856; + CURRENT_PROJECT_VERSION = 857; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index e7e1a0170..8b2d87bed 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -2375,7 +2375,7 @@ void bluetooth::connectedAndDiscovered() { connect(heartRateBelt, &heartratebelt::debug, this, &bluetooth::debug); connect(heartRateBelt, &heartratebelt::heartRate, this->device(), &bluetoothdevice::heartRate); heartRateBelt->deviceDiscovered(b); - + homeform::singleton()->setToastRequested(b.name() + " (HR sensor) connected!"); break; } } @@ -2462,6 +2462,7 @@ void bluetooth::connectedAndDiscovered() { connect(cadenceSensor, &bluetoothdevice::cadenceChanged, this->device(), &bluetoothdevice::cadenceSensor); cadenceSensor->deviceDiscovered(b); + homeform::singleton()->setToastRequested(b.name() + " (cadence sensor) connected!"); break; } } @@ -2507,6 +2508,9 @@ void bluetooth::connectedAndDiscovered() { &bluetoothdevice::verticalOscillationSensor); powerSensorRun->deviceDiscovered(b); } + + homeform::singleton()->setToastRequested(b.name() + " (power sensor) connected!"); + break; } } From 5e9e82e3f59d368de49778b8b3a09cec1e86d432 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 3 Sep 2024 11:23:02 +0200 Subject: [PATCH 068/162] trying to fix layout on settings --- src/settings.qml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/settings.qml b/src/settings.qml index e95d60a4e..4dda04b25 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -3493,6 +3493,7 @@ import QtQuick.Dialogs 1.0 wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter color: Material.color(Material.Red) + Layout.fillWidth: true } SwitchDelegate { @@ -3841,7 +3842,7 @@ import QtQuick.Dialogs 1.0 textColor: Material.color(Material.Yellow) color: Material.backgroundColor accordionContent: ColumnLayout { - spacing: 10 + spacing: 0 SwitchDelegate { id: tilesIconsDelegate text: qsTr("Tiles Icons") @@ -8388,7 +8389,7 @@ import QtQuick.Dialogs 1.0 textColor: Material.color(Material.Grey) color: Material.backgroundColor accordionContent: ColumnLayout { - spacing: 10 + spacing: 0 AccordionElement { id: cadenceSensorOptionsAccordion @@ -8397,7 +8398,7 @@ import QtQuick.Dialogs 1.0 textColor: Material.color(Material.Yellow) color: Material.backgroundColor accordionContent: ColumnLayout { - spacing: 10 + spacing: 0 Label { id: cadenceSensorLabel @@ -8409,6 +8410,7 @@ import QtQuick.Dialogs 1.0 wrapMode: Text.WordWrap verticalAlignment: Text.AlignVCenter color: Material.color(Material.Red) + Layout.fillWidth: true } SwitchDelegate { @@ -8534,7 +8536,7 @@ import QtQuick.Dialogs 1.0 textColor: Material.color(Material.Yellow) color: Material.backgroundColor accordionContent: ColumnLayout { - spacing: 10 + spacing: 0 SwitchDelegate { id: powerSensorAsBikeDelegate text: qsTr("Power Sensor as a Bike") @@ -8758,7 +8760,7 @@ import QtQuick.Dialogs 1.0 textColor: Material.color(Material.Yellow) color: Material.backgroundColor accordionContent: ColumnLayout { - spacing: 10 + spacing: 0 AccordionElement { id: eliteRizerOptionsAccordion title: qsTr("Elite Rizer Options") @@ -8766,7 +8768,7 @@ import QtQuick.Dialogs 1.0 textColor: Material.color(Material.Blue) color: Material.backgroundColor accordionContent: ColumnLayout { - spacing: 10 + spacing: 0 Label { id: labelEliteRizerName text: qsTr("Elite Rizer:") @@ -8834,7 +8836,7 @@ import QtQuick.Dialogs 1.0 textColor: Material.color(Material.Blue) color: Material.backgroundColor accordionContent: ColumnLayout { - spacing: 10 + spacing: 0 Label { id: labelEliteSterzoSmartName text: qsTr("Elite Sterzo Smart:") @@ -8881,7 +8883,7 @@ import QtQuick.Dialogs 1.0 textColor: Material.color(Material.Yellow) color: Material.backgroundColor accordionContent: ColumnLayout { - spacing: 10 + spacing: 0 Label { id: labelFTMSAccessoryName text: qsTr("SmartSpin2k device:") From ee3f6a1d1f056035ef5d137ead08b8b7e01c132a Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 3 Sep 2024 11:30:26 +0200 Subject: [PATCH 069/162] build 858 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 62a0c52ce..f6d338890 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 857; + CURRENT_PROJECT_VERSION = 858; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 857; + CURRENT_PROJECT_VERSION = 858; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 857; + CURRENT_PROJECT_VERSION = 858; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 857; + CURRENT_PROJECT_VERSION = 858; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 857; + CURRENT_PROJECT_VERSION = 858; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 857; + CURRENT_PROJECT_VERSION = 858; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 0812f419c67722df2b0979e3be0f907727cfef10 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 4 Sep 2024 08:14:07 +0200 Subject: [PATCH 070/162] Skandika Morpheus Support (Issue #2566) --- src/devices/bluetooth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 8b2d87bed..acd158a1a 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -2132,7 +2132,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { soleBike->deviceDiscovered(b); this->signalBluetoothDeviceConnected(soleBike); } else if ((b.name().toUpper().startsWith(QStringLiteral("BFCP")) || - (b.name().toUpper().startsWith(QStringLiteral("HT")) && b.name().length() == 11)) && + (b.name().toUpper().startsWith(QStringLiteral("HT")) && (b.name().length() == 11 || b.name().length() == 12))) && !skandikaWiriBike && filter) { this->setLastBluetoothDevice(b); this->stopDiscovery(); From 36cf326fa4d1db89962fedf2569208c03d0fd321 Mon Sep 17 00:00:00 2001 From: dadude2607 <102355223+dadude2607@users.noreply.github.com> Date: Thu, 5 Sep 2024 05:19:00 +0200 Subject: [PATCH 071/162] Added HR for Skandika Morpheus issue #2566 (#2567) * Added HR for Skandika Morpheus issue #2566 Because the morpheus behaves like a mixture of the x-2000 and the wiry, I have introduced a new variable. Speed, watts and rpm are read out like the wiry, but the heart rate is read out like the x-2000. With this code the morpheus works for me. I have attached a screenshot in the issue #2566. to distinguish an x-2000 from a Morpheus it seems to be enough to pay attention to the number of characters of the bluetooth name * Update skandikawiribike.cpp --------- Co-authored-by: Roberto Viola --- src/devices/skandikawiribike/skandikawiribike.cpp | 14 ++++++++++---- src/devices/skandikawiribike/skandikawiribike.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/devices/skandikawiribike/skandikawiribike.cpp b/src/devices/skandikawiribike/skandikawiribike.cpp index 01022e743..c6df83771 100644 --- a/src/devices/skandikawiribike/skandikawiribike.cpp +++ b/src/devices/skandikawiribike/skandikawiribike.cpp @@ -247,8 +247,8 @@ void skandikawiribike::characteristicChanged(const QLowEnergyCharacteristic &cha #endif { if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) { - if (X2000) { - Heart = newValue.at(8); + if (X2000 || delightechBike) { + Heart = newValue.at(8); // X-2000 or delightech app/protocol compatible bike (e.g. Skandika Morpheus) } else { Heart = 0; } @@ -427,8 +427,14 @@ void skandikawiribike::deviceDiscovered(const QBluetoothDeviceInfo &device) { bluetoothDevice = device; if (device.name().toUpper().startsWith(QLatin1String("HT"))) { - X2000 = true; - qDebug() << "X-2000 WORKAROUND!"; + if (device.name().length() == 11) { // Bikes like the Skandika X-2000 Foldaway Bike + X2000 = true; + qDebug() << "X-2000 WORKAROUND!"; + } else if (device.name().length() == 12) // Bikes compatible with delightech app/protocol, for example Skandika Morpheus + { + qDebug() << "deligthechbike WORKAROUND!"; + delightechBike = true; + } } m_control = QLowEnergyController::createCentral(bluetoothDevice, this); diff --git a/src/devices/skandikawiribike/skandikawiribike.h b/src/devices/skandikawiribike/skandikawiribike.h index caf910d05..e68bbb988 100644 --- a/src/devices/skandikawiribike/skandikawiribike.h +++ b/src/devices/skandikawiribike/skandikawiribike.h @@ -75,6 +75,7 @@ class skandikawiribike : public bike { bool noHeartService = false; bool X2000 = false; + bool delightechBike = false; #ifdef Q_OS_IOS lockscreen *h = 0; From 1ade0788275e1ae50215998e36000502d73090ec Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 5 Sep 2024 17:39:28 +0200 Subject: [PATCH 072/162] The zwift play controllers don't connect and the app crashes (Issue #2531) --- src/devices/bluetooth.cpp | 28 ++++++++++++++++++++++++++-- src/devices/bluetooth.h | 1 + 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index acd158a1a..f85889fda 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -167,10 +167,14 @@ void bluetooth::finished() { bool fitmetriaFanfitFound = !settings.value(QZSettings::fitmetria_fanfit_enable, QZSettings::default_fitmetria_fanfit_enable).toBool(); + bool zwiftDeviceFound = + !settings.value(QZSettings::zwift_click, QZSettings::default_zwift_click).toBool() && !settings.value(QZSettings::zwift_play, QZSettings::default_zwift_play).toBool(); + if ((!heartRateBeltFound && !heartRateBeltAvaiable()) || (!ftmsAccessoryFound && !ftmsAccessoryAvaiable()) || (!cscFound && !cscSensorAvaiable()) || (!powerSensorFound && !powerSensorAvaiable()) || (!eliteRizerFound && !eliteRizerAvaiable()) || (!eliteSterzoSmartFound && !eliteSterzoSmartAvaiable()) || - (!fitmetriaFanfitFound && !fitmetriaFanfitAvaiable())) { + (!fitmetriaFanfitFound && !fitmetriaFanfitAvaiable()) || + (!zwiftDeviceFound && !zwiftDeviceAvaiable())) { // force heartRateBelt off forceHeartBeltOffForTimeout = true; @@ -277,6 +281,20 @@ bool bluetooth::fitmetriaFanfitAvaiable() { return false; } +bool bluetooth::zwiftDeviceAvaiable() { + + uint8_t count = 0; + Q_FOREACH (QBluetoothDeviceInfo b, devices) { + if (b.name().toUpper().startsWith("ZWIFT ")) { + count++; + if(count >= 2) + return true; + } + } + return false; +} + + bool bluetooth::powerSensorAvaiable() { QSettings settings; @@ -374,6 +392,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { settings.value(QZSettings::ftms_accessory_name, QZSettings::default_ftms_accessory_name).toString(); bool heartRateBeltFound = heartRateBeltName.startsWith(QStringLiteral("Disabled")); bool ftmsAccessoryFound = ftmsAccessoryName.startsWith(QStringLiteral("Disabled")); + bool zwiftDeviceFound = + !settings.value(QZSettings::zwift_click, QZSettings::default_zwift_click).toBool() && !settings.value(QZSettings::zwift_play, QZSettings::default_zwift_play).toBool(); bool fitmetriaFanfitFound = !settings.value(QZSettings::fitmetria_fanfit_enable, QZSettings::default_fitmetria_fanfit_enable).toBool(); bool toorx_ftms = settings.value(QZSettings::toorx_ftms, QZSettings::default_toorx_ftms).toBool(); @@ -464,6 +484,10 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { fitmetriaFanfitFound = fitmetriaFanfitAvaiable(); } + if (!zwiftDeviceFound) { + + zwiftDeviceFound = zwiftDeviceAvaiable(); + } if (!ftmsAccessoryFound) { ftmsAccessoryFound = ftmsAccessoryAvaiable(); @@ -595,7 +619,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { #endif bool searchDevices = (heartRateBeltFound && ftmsAccessoryFound && cscFound && powerSensorFound && eliteRizerFound && - eliteSterzoSmartFound && fitmetriaFanfitFound) || + eliteSterzoSmartFound && fitmetriaFanfitFound && zwiftDeviceFound) || forceHeartBeltOffForTimeout; if (searchDevices) { diff --git a/src/devices/bluetooth.h b/src/devices/bluetooth.h index d8f0b86fc..08196008e 100644 --- a/src/devices/bluetooth.h +++ b/src/devices/bluetooth.h @@ -303,6 +303,7 @@ class bluetooth : public QObject, public SignalHandler { bool eliteRizerAvaiable(); bool eliteSterzoSmartAvaiable(); bool fitmetriaFanfitAvaiable(); + bool zwiftDeviceAvaiable(); bool fitmetria_fanfit_isconnected(QString name); #ifdef Q_OS_WIN From fe801547dcd7bf351cb0005fce264002c1776ec4 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 5 Sep 2024 17:53:33 +0200 Subject: [PATCH 073/162] =?UTF-8?q?Domyos=20TC=20540=20Dirk=20P=C3=BCschma?= =?UTF-8?q?nn=20(Issue=20#2568)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/devices/bluetooth.cpp | 6 ++++-- src/devices/horizontreadmill/horizontreadmill.cpp | 13 ++++++++++++- src/devices/horizontreadmill/horizontreadmill.h | 1 + src/qzsettings.cpp | 4 +++- src/qzsettings.h | 2 ++ src/settings.qml | 1 + 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index f85889fda..c989ae49d 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1102,7 +1102,9 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { } else if (b.name().startsWith(QStringLiteral("Domyos")) && !b.name().startsWith(QStringLiteral("DomyosBr")) && !b.name().toUpper().startsWith(QStringLiteral("DOMYOS-BIKING-")) && !domyos && !domyosElliptical && b.name().compare(ftms_treadmill, Qt::CaseInsensitive) && - !domyosBike && !domyosRower && !ftmsBike && !horizonTreadmill && !deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && filter) { + !domyosBike && !domyosRower && !ftmsBike && !horizonTreadmill && + (!deviceHasService(b, QBluetoothUuid((quint16)0x1826)) || settings.value(QZSettings::domyostreadmill_notfmts, QZSettings::default_domyostreadmill_notfmts).toBool()) && + filter) { this->setLastBluetoothDevice(b); this->stopDiscovery(); domyos = new domyostreadmill(this->pollDeviceTime, noConsole, noHeartService); @@ -1317,7 +1319,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { (b.name().toUpper().startsWith(QStringLiteral("I-CONSOLE+")))) && !toorx_ftms && toorx_ftms_treadmill) || !b.name().compare(ftms_treadmill, Qt::CaseInsensitive) || - (b.name().toUpper().startsWith(QStringLiteral("DOMYOS-TC")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || + (b.name().toUpper().startsWith(QStringLiteral("DOMYOS-TC")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && !settings.value(QZSettings::domyostreadmill_notfmts, QZSettings::default_domyostreadmill_notfmts).toBool()) || b.name().toUpper().startsWith(QStringLiteral("XT685")) || b.name().toUpper().startsWith(QStringLiteral("XT285")) || b.name().toUpper().startsWith(QStringLiteral("XTERRA TR")) || diff --git a/src/devices/horizontreadmill/horizontreadmill.cpp b/src/devices/horizontreadmill/horizontreadmill.cpp index c1ee4cdba..b8e639b70 100644 --- a/src/devices/horizontreadmill/horizontreadmill.cpp +++ b/src/devices/horizontreadmill/horizontreadmill.cpp @@ -1,5 +1,5 @@ #include "horizontreadmill.h" - +#include "homeform.h" #include "devices/ftmsbike/ftmsbike.h" #include "virtualdevices/virtualbike.h" #include "virtualdevices/virtualtreadmill.h" @@ -2088,10 +2088,18 @@ void horizontreadmill::stateChanged(QLowEnergyService::ServiceState state) { QBluetoothUuid _gattTreadmillDataId((quint16)0x2ACD); QBluetoothUuid _gattCrossTrainerDataId((quint16)0x2ACE); QBluetoothUuid _gattInclinationSupported((quint16)0x2AD5); + QBluetoothUuid _DomyosServiceId(QStringLiteral("49535343-fe7d-4ae5-8fa9-9fafd205e455")); emit debug(QStringLiteral("BTLE stateChanged ") + QString::fromLocal8Bit(metaEnum.valueToKey(state))); for (QLowEnergyService *s : qAsConst(gattCommunicationChannelService)) { qDebug() << QStringLiteral("stateChanged") << s->serviceUuid() << s->state(); + + if(s->serviceUuid() == _DomyosServiceId && DOMYOS) { + settings.setValue(QZSettings::domyostreadmill_notfmts, true); + homeform::singleton()->setToastRequested("Domyos Treadmill presents itself like a FTMS but it's not. Restart QZ to apply the fix, thanks."); + return; + } + if (s->state() != QLowEnergyService::ServiceDiscovered && s->state() != QLowEnergyService::InvalidService) { qDebug() << QStringLiteral("not all services discovered"); return; @@ -2343,6 +2351,9 @@ void horizontreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device) { } else if(device.name().toUpper().startsWith("T01_")) { ICONCEPT_FTMS_treadmill = true; qDebug() << QStringLiteral("ICONCEPT_FTMS_treadmill workaround ON!"); + } else if ((device.name().toUpper().startsWith("DOMYOS"))) { + qDebug() << QStringLiteral("DOMYOS found"); + DOMYOS = true; } if (device.name().toUpper().startsWith(QStringLiteral("TRX3500"))) { diff --git a/src/devices/horizontreadmill/horizontreadmill.h b/src/devices/horizontreadmill/horizontreadmill.h index 983d15344..d216971a0 100644 --- a/src/devices/horizontreadmill/horizontreadmill.h +++ b/src/devices/horizontreadmill/horizontreadmill.h @@ -98,6 +98,7 @@ class horizontreadmill : public treadmill { bool disableAutoPause = false; bool HORIZON_78AT_treadmill = false; bool ICONCEPT_FTMS_treadmill = false; + bool DOMYOS = false; void testProfileCRC(); void updateProfileCRC(); diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index 84aba38b7..7ce50d4bb 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -757,8 +757,9 @@ const QString QZSettings::domyosbike_notfmts = QStringLiteral("domyosbike_notfmt const QString QZSettings::gears_volume_debouncing = QStringLiteral("gears_volume_debouncing"); const QString QZSettings::tile_biggears_enabled = QStringLiteral("tile_biggears_enabled"); const QString QZSettings::tile_biggears_order = QStringLiteral("tile_biggears_order"); +const QString QZSettings::domyostreadmill_notfmts = QStringLiteral("domyostreadmill_notfmts"); -const uint32_t allSettingsCount = 640; +const uint32_t allSettingsCount = 641; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1405,6 +1406,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::gears_volume_debouncing, QZSettings::default_gears_volume_debouncing}, {QZSettings::tile_biggears_enabled, QZSettings::default_tile_biggears_enabled}, {QZSettings::tile_biggears_order, QZSettings::default_tile_biggears_order}, + {QZSettings::domyostreadmill_notfmts, QZSettings::default_domyostreadmill_notfmts}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index b32cb26ff..8447d863b 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2120,6 +2120,8 @@ class QZSettings { static const QString tile_biggears_order; static constexpr int default_tile_biggears_order = 54; + static const QString domyostreadmill_notfmts; + static constexpr bool default_domyostreadmill_notfmts = false; /** * @brief Write the QSettings values using the constants from this namespace. diff --git a/src/settings.qml b/src/settings.qml index 4dda04b25..f2af40697 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -972,6 +972,7 @@ import QtQuick.Dialogs 1.0 property bool gears_volume_debouncing: false property bool tile_biggears_enabled: false property int tile_biggears_order: 54 + property bool domyostreadmill_notfmts: false } function paddingZeros(text, limit) { From 83185e0e95dcf307a0574e0060bcd3e81c09eff8 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 5 Sep 2024 17:58:35 +0200 Subject: [PATCH 074/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index f6d338890..d7bb759ed 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 858; + CURRENT_PROJECT_VERSION = 859; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 858; + CURRENT_PROJECT_VERSION = 859; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 858; + CURRENT_PROJECT_VERSION = 859; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 858; + CURRENT_PROJECT_VERSION = 859; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 858; + CURRENT_PROJECT_VERSION = 859; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 858; + CURRENT_PROJECT_VERSION = 859; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From b9d5e6141f6b24448d89196233d0984f830bbf53 Mon Sep 17 00:00:00 2001 From: dadude2607 <102355223+dadude2607@users.noreply.github.com> Date: Fri, 6 Sep 2024 07:15:58 +0200 Subject: [PATCH 075/162] Skandika Morpheus: calc speed based on watts fixed (#2572) The speed could not be calculated based on watt, because the code was in an unsolvable if query. I have changed the if query to "cadence", like on the Schwinn bike. Now the speed is calculated correctly as soon as you pedal. Before this fix the option "calculate speed based on watt" had be turned off --- src/devices/skandikawiribike/skandikawiribike.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/skandikawiribike/skandikawiribike.cpp b/src/devices/skandikawiribike/skandikawiribike.cpp index c6df83771..9aca3a16a 100644 --- a/src/devices/skandikawiribike/skandikawiribike.cpp +++ b/src/devices/skandikawiribike/skandikawiribike.cpp @@ -484,7 +484,7 @@ uint16_t skandikawiribike::watts() { // ref // https://translate.google.com/translate?hl=it&sl=en&u=https://support.wattbike.com/hc/en-us/articles/115001881825-Power-Resistance-and-Cadence-Tables&prev=search&pto=aue - if (currentSpeed().value() <= 0) { + if (currentCadence().value() == 0) { // only update watts if pedaling return 0; } From e8fb563b774903f1c2f97d8cc47a6cc0af85b899 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 6 Sep 2024 08:58:59 +0200 Subject: [PATCH 076/162] =?UTF-8?q?Domyos=20TC=20540=20Dirk=20P=C3=BCschma?= =?UTF-8?q?nn=20(Issue=20#2568)=20fe801547d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/horizontreadmill/horizontreadmill.cpp | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index d7bb759ed..38ea5bf41 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 859; + CURRENT_PROJECT_VERSION = 860; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 859; + CURRENT_PROJECT_VERSION = 860; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 859; + CURRENT_PROJECT_VERSION = 860; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 859; + CURRENT_PROJECT_VERSION = 860; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 859; + CURRENT_PROJECT_VERSION = 860; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 859; + CURRENT_PROJECT_VERSION = 860; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/horizontreadmill/horizontreadmill.cpp b/src/devices/horizontreadmill/horizontreadmill.cpp index b8e639b70..b13149118 100644 --- a/src/devices/horizontreadmill/horizontreadmill.cpp +++ b/src/devices/horizontreadmill/horizontreadmill.cpp @@ -2096,6 +2096,7 @@ void horizontreadmill::stateChanged(QLowEnergyService::ServiceState state) { if(s->serviceUuid() == _DomyosServiceId && DOMYOS) { settings.setValue(QZSettings::domyostreadmill_notfmts, true); + settings.sync(); homeform::singleton()->setToastRequested("Domyos Treadmill presents itself like a FTMS but it's not. Restart QZ to apply the fix, thanks."); return; } From 02fbff3f84be861253197d8f99cadc3f7d50a63c Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 6 Sep 2024 09:00:39 +0200 Subject: [PATCH 077/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers (Issue #2541) --- src/qzsettings.cpp | 4 +- src/qzsettings.h | 3 + src/settings.qml | 28 ++++++++++ src/zwift_play/abstractZapDevice.h | 89 ++++++++++++++++++++++-------- 4 files changed, 101 insertions(+), 23 deletions(-) diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index 7ce50d4bb..d3518b986 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -758,8 +758,9 @@ const QString QZSettings::gears_volume_debouncing = QStringLiteral("gears_volume const QString QZSettings::tile_biggears_enabled = QStringLiteral("tile_biggears_enabled"); const QString QZSettings::tile_biggears_order = QStringLiteral("tile_biggears_order"); const QString QZSettings::domyostreadmill_notfmts = QStringLiteral("domyostreadmill_notfmts"); +const QString QZSettings::zwiftplay_swap = QStringLiteral("zwiftplay_swap"); -const uint32_t allSettingsCount = 641; +const uint32_t allSettingsCount = 642; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1407,6 +1408,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::tile_biggears_enabled, QZSettings::default_tile_biggears_enabled}, {QZSettings::tile_biggears_order, QZSettings::default_tile_biggears_order}, {QZSettings::domyostreadmill_notfmts, QZSettings::default_domyostreadmill_notfmts}, + {QZSettings::zwiftplay_swap, QZSettings::default_zwiftplay_swap}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index 8447d863b..9299afe64 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2123,6 +2123,9 @@ class QZSettings { static const QString domyostreadmill_notfmts; static constexpr bool default_domyostreadmill_notfmts = false; + static const QString zwiftplay_swap; + static constexpr bool default_zwiftplay_swap = 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. diff --git a/src/settings.qml b/src/settings.qml index f2af40697..9d82abb90 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -973,6 +973,7 @@ import QtQuick.Dialogs 1.0 property bool tile_biggears_enabled: false property int tile_biggears_order: 54 property bool domyostreadmill_notfmts: false + property bool zwiftplay_swap: false } function paddingZeros(text, limit) { @@ -9584,6 +9585,33 @@ import QtQuick.Dialogs 1.0 Layout.fillWidth: true color: Material.color(Material.Lime) } + + SwitchDelegate { + text: qsTr("Swap sides") + spacing: 0 + bottomPadding: 0 + topPadding: 0 + rightPadding: 0 + leftPadding: 0 + clip: false + checked: settings.zwiftplay_swap + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + onClicked: { settings.zwiftplay_swap = checked; } + } + + Label { + text: qsTr("You can swap the left to the right controller and viceversa. Default is off.") + 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) + } } } diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index 385154f88..6e8af645f 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -39,6 +39,7 @@ class AbstractZapDevice: public QObject { QSettings settings; bool gears_volume_debouncing = settings.value(QZSettings::gears_volume_debouncing, QZSettings::default_gears_volume_debouncing).toBool(); + bool zwiftplay_swap = settings.value(QZSettings::zwiftplay_swap, QZSettings::default_zwiftplay_swap).toBool(); qDebug() << zapType << characteristicName << bytes.toHex() << gears_volume_debouncing << risingEdge; @@ -65,12 +66,20 @@ class AbstractZapDevice: public QObject { case 0x37: if(bytes.length() == 5) { if(bytes[2] == 0) { - if(DEBOUNCE) - emit plus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit plus(); + else + emit minus(); + } risingEdge = true; } else if(bytes[4] == 0) { - if(DEBOUNCE) - emit minus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit minus(); + else + emit plus(); + } risingEdge = true; } else { risingEdge = false; @@ -83,22 +92,38 @@ class AbstractZapDevice: public QObject { (((uint8_t)bytes[bytes.length() - 4]) == 0xc8 && zapType == LEFT) ) && bytes[bytes.length() - 3] == 0x01) { if(zapType == LEFT) { - if(DEBOUNCE) - emit plus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit plus(); + else + emit minus(); + } risingEdge = true; } else { - if(DEBOUNCE) - emit minus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit minus(); + else + emit plus(); + } risingEdge = true; } } else if(bytes.length() > 14 && bytes[11] == 0x30 && bytes[12] == 0x00) { if(zapType == LEFT) { - if(DEBOUNCE) - emit plus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit plus(); + else + emit minus(); + } risingEdge = true; } else { - if(DEBOUNCE) - emit minus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit minus(); + else + emit plus(); + } risingEdge = true; } } else { @@ -111,29 +136,49 @@ class AbstractZapDevice: public QObject { (((uint8_t)bytes[12]) == 0xc8 && zapType == LEFT)) ) { if(zapType == LEFT) { - if(DEBOUNCE) - emit plus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit plus(); + else + emit minus(); + } risingEdge = true; } else { - if(DEBOUNCE) - emit minus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit minus(); + else + emit plus(); + } risingEdge = true; } } else if(bytes.length() > 19 && ((uint8_t)bytes[18]) == 0xc8) { - if(DEBOUNCE) - emit plus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit plus(); + else + emit minus(); + } risingEdge = true; } else if(bytes.length() > 3 && ((((uint8_t)bytes[3]) == 0xdf) || // right top button (((uint8_t)bytes[3]) == 0xbf))) { // right bottom button - if(DEBOUNCE) - emit plus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit plus(); + else + emit minus(); + } risingEdge = true; } else if(bytes.length() > 3 && ((((uint8_t)bytes[3]) == 0xfd) || // left top button (((uint8_t)bytes[3]) == 0xfb))) { // left bottom button - if(DEBOUNCE) - emit minus(); + if(DEBOUNCE) { + if(!zwiftplay_swap) + emit minus(); + else + emit plus(); + } risingEdge = true; } else { risingEdge = false; From 930cc4e0165df0baa0efe0945dfad927879d8240 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 6 Sep 2024 09:35:45 +0200 Subject: [PATCH 078/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++-- src/devices/bike.cpp | 57 +++++++++++++++++++ src/devices/bike.h | 1 + src/devices/ftmsbike/ftmsbike.cpp | 16 ++++-- src/devices/renphobike/renphobike.cpp | 6 +- src/devices/tacxneo2/tacxneo2.cpp | 10 +++- .../wahookickrsnapbike/wahookickrsnapbike.cpp | 9 ++- src/qzsettings.cpp | 4 +- src/qzsettings.h | 4 ++ src/settings.qml | 28 +++++++++ 10 files changed, 129 insertions(+), 18 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 38ea5bf41..2cd1627f5 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 860; + CURRENT_PROJECT_VERSION = 861; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 860; + CURRENT_PROJECT_VERSION = 861; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 860; + CURRENT_PROJECT_VERSION = 861; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 860; + CURRENT_PROJECT_VERSION = 861; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 860; + CURRENT_PROJECT_VERSION = 861; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 860; + CURRENT_PROJECT_VERSION = 861; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index c815f6f7a..e46249169 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -308,3 +308,60 @@ uint16_t bike::wattFromHR(bool useSpeedAndCadence) { } return watt; } + +double bike::gearsZwiftRatio() { + if(m_gears <= 0) + return 0.65; + else if(m_gears > 24) + return 6; + switch((int)m_gears) { + case 1: + return 0.75; + case 2: + return 0.87; + case 3: + return 0.99; + case 4: + return 1.11; + case 5: + return 1.23; + case 6: + return 1.38; + case 7: + return 1.53; + case 8: + return 1.68; + case 9: + return 1.86; + case 10: + return 2.04; + case 11: + return 2.22; + case 12: + return 2.40; + case 13: + return 2.61; + case 14: + return 2.82; + case 15: + return 3.03; + case 16: + return 3.24; + case 17: + return 3.49; + case 18: + return 3.74; + case 19: + return 3.99; + case 20: + return 4.24; + case 21: + return 4.54; + case 22: + return 4.84; + case 23: + return 5.14; + case 24: + return 5.49; + } +} diff --git a/src/devices/bike.h b/src/devices/bike.h index 247cde8c9..9a68ea843 100644 --- a/src/devices/bike.h +++ b/src/devices/bike.h @@ -36,6 +36,7 @@ class bike : public bluetoothdevice { uint8_t metrics_override_heartrate() override; void setGears(double d); double gears(); + double gearsZwiftRatio(); void setSpeedLimit(double speed) { m_speedLimit = speed; } double speedLimit() { return m_speedLimit; } virtual bool ifitCompatible() {return false;} diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index d40d82478..530352647 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -861,13 +861,19 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact for(int i=0; i> 8; + QSettings settings; + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + if(!gears_zwift_ratio) { + if (gears() != 0) { + slope += (gears() * 50); + } + } else { + slope *= gearsZwiftRatio(); } + b[3] = slope & 0xFF; + b[4] = slope >> 8; } if (writeBuffer) { diff --git a/src/devices/renphobike/renphobike.cpp b/src/devices/renphobike/renphobike.cpp index b84e10f29..6d0ff8e5c 100644 --- a/src/devices/renphobike/renphobike.cpp +++ b/src/devices/renphobike/renphobike.cpp @@ -575,10 +575,10 @@ void renphobike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &chara qDebug() << QStringLiteral("sending") << lastFTMSPacketReceived.toHex(' '); // handling gears } else if (lastFTMSPacketReceived.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS) { - qDebug() << "applying gears mod" << m_gears; + qDebug() << "applying gears mod" << gears(); int16_t slope = (((uint8_t)lastFTMSPacketReceived.at(3)) + (lastFTMSPacketReceived.at(4) << 8)); - if (m_gears != 0) { - slope += (m_gears * 50); + if (gears() != 0) { + slope += (gears() * 50); lastFTMSPacketReceived[3] = slope & 0xFF; lastFTMSPacketReceived[4] = slope >> 8; } diff --git a/src/devices/tacxneo2/tacxneo2.cpp b/src/devices/tacxneo2/tacxneo2.cpp index 4189ed1d2..614841994 100644 --- a/src/devices/tacxneo2/tacxneo2.cpp +++ b/src/devices/tacxneo2/tacxneo2.cpp @@ -140,8 +140,14 @@ void tacxneo2::update() { requestInclination = -100; } else if((virtualBike && virtualBike->ftmsDeviceConnected()) && lastGearValue != gears() && lastRawRequestedInclinationValue != -100) { // in order to send the new gear value ASAP - forceInclination(lastRawRequestedInclinationValue + gears()); // since this bike doesn't have the concept of resistance, - // i'm using the gears in the inclination + QSettings settings; + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + if(!gears_zwift_ratio) { + forceInclination(lastRawRequestedInclinationValue + gears()); // since this bike doesn't have the concept of resistance, + // i'm using the gears in the inclination + } else { + forceInclination(lastRawRequestedInclinationValue * gearsZwiftRatio()); + } } lastGearValue = gears(); diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index a783ae594..bebe5fb9d 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -816,7 +816,14 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) { Q_UNUSED(percentage); lastGrade = grade; emit debug(QStringLiteral("writing inclination ") + QString::number(grade)); - QByteArray a = setSimGrade(grade + gears()); + QSettings settings; + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + double g = grade; + if(!gears_zwift_ratio) + g += gears(); + else + g *= gearsZwiftRatio(); + QByteArray a = setSimGrade(g); uint8_t b[20]; memcpy(b, a.constData(), a.length()); writeCharacteristic(b, a.length(), "setSimGrade", false, true); diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index d3518b986..ee3df2f92 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -759,8 +759,9 @@ const QString QZSettings::tile_biggears_enabled = QStringLiteral("tile_biggears_ const QString QZSettings::tile_biggears_order = QStringLiteral("tile_biggears_order"); const QString QZSettings::domyostreadmill_notfmts = QStringLiteral("domyostreadmill_notfmts"); const QString QZSettings::zwiftplay_swap = QStringLiteral("zwiftplay_swap"); +const QString QZSettings::gears_zwift_ratio = QStringLiteral("gears_zwift_ratio"); -const uint32_t allSettingsCount = 642; +const uint32_t allSettingsCount = 643; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1409,6 +1410,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::tile_biggears_order, QZSettings::default_tile_biggears_order}, {QZSettings::domyostreadmill_notfmts, QZSettings::default_domyostreadmill_notfmts}, {QZSettings::zwiftplay_swap, QZSettings::default_zwiftplay_swap}, + {QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index 9299afe64..35d53895e 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2126,6 +2126,10 @@ class QZSettings { static const QString zwiftplay_swap; static constexpr bool default_zwiftplay_swap = false; + static const QString gears_zwift_ratio; + static constexpr bool default_gears_zwift_ratio = 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. diff --git a/src/settings.qml b/src/settings.qml index 9d82abb90..4204f33c0 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -974,6 +974,7 @@ import QtQuick.Dialogs 1.0 property int tile_biggears_order: 54 property bool domyostreadmill_notfmts: false property bool zwiftplay_swap: false + property bool gears_zwift_ratio: false } function paddingZeros(text, limit) { @@ -9612,6 +9613,33 @@ import QtQuick.Dialogs 1.0 Layout.fillWidth: true color: Material.color(Material.Lime) } + + SwitchDelegate { + text: qsTr("Use Zwift app ratio for gears") + spacing: 0 + bottomPadding: 0 + topPadding: 0 + rightPadding: 0 + leftPadding: 0 + clip: false + checked: settings.gears_zwift_ratio + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + onClicked: { settings.gears_zwift_ratio = checked; } + } + + Label { + text: qsTr("Use the zwift gears table instead of the QZ classic gears algorithm. Default is off.") + 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) + } } } From 2955ac9751a7027f1a543a8a69a62944a2b2aef2 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 6 Sep 2024 12:02:50 +0200 Subject: [PATCH 079/162] Power profile Domyos bike 500 (Issue #2573) --- src/devices/domyosbike/domyosbike.cpp | 36 ++++++++++++++++++++++++++- src/qzsettings.cpp | 4 ++- src/qzsettings.h | 2 ++ src/settings.qml | 18 +++++++++++--- 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/devices/domyosbike/domyosbike.cpp b/src/devices/domyosbike/domyosbike.cpp index 40c97c8ce..297349ef9 100644 --- a/src/devices/domyosbike/domyosbike.cpp +++ b/src/devices/domyosbike/domyosbike.cpp @@ -685,7 +685,41 @@ resistance_t domyosbike::resistanceFromPowerRequest(uint16_t power) { uint16_t domyosbike::wattsFromResistance(double resistance) { QSettings settings; - if (!settings.value(QZSettings::domyos_bike_500_profile_v1, QZSettings::default_domyos_bike_500_profile_v1) + if (settings.value(QZSettings::domyos_bike_500_profile_v2, QZSettings::default_domyos_bike_500_profile_v2).toBool()) { + switch ((int)resistance) { + case 1: + return (5.0 * Cadence.value()) / 9.5488; + case 2: + return (5.7 * Cadence.value()) / 9.5488; + case 3: + return (6.5 * Cadence.value()) / 9.5488; + case 4: + return (7.5 * Cadence.value()) / 9.5488; + case 5: + return (8.6 * Cadence.value()) / 9.5488; + case 6: + return (9.9 * Cadence.value()) / 9.5488; + case 7: + return (11.4 * Cadence.value()) / 9.5488; + case 8: + return (13.6 * Cadence.value()) / 9.5488; + case 9: + return (15.3 * Cadence.value()) / 9.5488; + case 10: + return (17.3 * Cadence.value()) / 9.5488; + case 11: + return (19.8 * Cadence.value()) / 9.5488; + case 12: + return (22.5 * Cadence.value()) / 9.5488; + case 13: + return (25.6 * Cadence.value()) / 9.5488; + case 14: + return (28.4 * Cadence.value()) / 9.5488; + case 15: + return (35.9 * Cadence.value()) / 9.5488; + } + return 0; + } else if (!settings.value(QZSettings::domyos_bike_500_profile_v1, QZSettings::default_domyos_bike_500_profile_v1) .toBool() || resistance < 8) return ((10.39 + 1.45 * (resistance - 1.0)) * (exp(0.028 * (currentCadence().value())))); diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index ee3df2f92..d48405d86 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -760,8 +760,9 @@ const QString QZSettings::tile_biggears_order = QStringLiteral("tile_biggears_or const QString QZSettings::domyostreadmill_notfmts = QStringLiteral("domyostreadmill_notfmts"); const QString QZSettings::zwiftplay_swap = QStringLiteral("zwiftplay_swap"); const QString QZSettings::gears_zwift_ratio = QStringLiteral("gears_zwift_ratio"); +const QString QZSettings::domyos_bike_500_profile_v2 = QStringLiteral("domyos_bike_500_profile_v2"); -const uint32_t allSettingsCount = 643; +const uint32_t allSettingsCount = 644; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1411,6 +1412,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::domyostreadmill_notfmts, QZSettings::default_domyostreadmill_notfmts}, {QZSettings::zwiftplay_swap, QZSettings::default_zwiftplay_swap}, {QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio}, + {QZSettings::domyos_bike_500_profile_v2, QZSettings::default_domyos_bike_500_profile_v2}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index 35d53895e..a242e8fe2 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2129,6 +2129,8 @@ class QZSettings { static const QString gears_zwift_ratio; static constexpr bool default_gears_zwift_ratio = false; + static const QString domyos_bike_500_profile_v2; + static constexpr bool default_domyos_bike_500_profile_v2 = false; /** * @brief Write the QSettings values using the constants from this namespace. diff --git a/src/settings.qml b/src/settings.qml index 4204f33c0..41ff4f3c9 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -975,6 +975,7 @@ import QtQuick.Dialogs 1.0 property bool domyostreadmill_notfmts: false property bool zwiftplay_swap: false property bool gears_zwift_ratio: false + property bool domyos_bike_500_profile_v2: false } function paddingZeros(text, limit) { @@ -2964,7 +2965,6 @@ import QtQuick.Dialogs 1.0 } } SwitchDelegate { - id: domyosBikeCaloriesDisplayDelegate text: qsTr("Fix Calories/Km to Console") spacing: 0 bottomPadding: 0 @@ -2978,7 +2978,6 @@ import QtQuick.Dialogs 1.0 onClicked: settings.domyos_bike_display_calories = checked } SwitchDelegate { - id: domyosBike500ProfileV1Delegate text: qsTr("Bike 500 wattage profile") spacing: 0 bottomPadding: 0 @@ -2989,8 +2988,21 @@ import QtQuick.Dialogs 1.0 checked: settings.domyos_bike_500_profile_v1 Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.fillWidth: true - onClicked: settings.domyos_bike_500_profile_v1 = checked + onClicked: { settings.domyos_bike_500_profile_v1 = checked; settings.domyos_bike_500_profile_v2 = false; } } + SwitchDelegate { + text: qsTr("Bike 500 wattage profile v2") + spacing: 0 + bottomPadding: 0 + topPadding: 0 + rightPadding: 0 + leftPadding: 0 + clip: false + checked: settings.domyos_bike_500_profile_v2 + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + onClicked: { settings.domyos_bike_500_profile_v2 = checked; settings.domyos_bike_500_profile_v1 = false; } + } } AccordionElement { title: qsTr("Tacx Neo Options") From ca830a988b5758f434f98dfb3f5b04ea785a5112 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 6 Sep 2024 16:57:34 +0200 Subject: [PATCH 080/162] Zwift Click connection issue #2576 --- src/zwift_play/zwiftclickremote.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zwift_play/zwiftclickremote.cpp b/src/zwift_play/zwiftclickremote.cpp index 226836c95..53c2121bf 100755 --- a/src/zwift_play/zwiftclickremote.cpp +++ b/src/zwift_play/zwiftclickremote.cpp @@ -35,7 +35,7 @@ void zwiftclickremote::update() { writeCharacteristic(gattWrite1Service, &gattWrite1Characteristic, (uint8_t *) s.data(), s.length(), "handshakeStart"); } else if(initDone) { countRxTimeout++; - if(countRxTimeout == 5) { + if(countRxTimeout == 10) { homeform::singleton()->setToastRequested("Zwift device: UPGRADE THE FIRMWARE!"); } } From 52d91de7e48b614251f07051705294e8d9147bde Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 6 Sep 2024 21:49:25 +0200 Subject: [PATCH 081/162] Can't connect QZ to Zwift (Issue #2579) --- src/devices/tacxneo2/tacxneo2.cpp | 167 ++++++++++++++++++++++++++++++ src/devices/tacxneo2/tacxneo2.h | 2 + 2 files changed, 169 insertions(+) diff --git a/src/devices/tacxneo2/tacxneo2.cpp b/src/devices/tacxneo2/tacxneo2.cpp index 614841994..5c4088d55 100644 --- a/src/devices/tacxneo2/tacxneo2.cpp +++ b/src/devices/tacxneo2/tacxneo2.cpp @@ -321,11 +321,174 @@ void tacxneo2::characteristicChanged(const QLowEnergyCharacteristic &characteris emit debug(QStringLiteral("Current heart: ") + QString::number(Heart.value())); } else if (characteristic.uuid() == QBluetoothUuid::CyclingPowerMeasurement) { + uint16_t flags = (((uint16_t)((uint8_t)newValue.at(1)) << 8) | (uint16_t)((uint8_t)newValue.at(0))); + bool cadence_present = false; + bool wheel_revs = false; + bool crank_rev_present = false; + uint16_t time_division = 1024; + uint8_t index = 4; + if (newValue.length() > 3) { m_watt = (((uint16_t)((uint8_t)newValue.at(3)) << 8) | (uint16_t)((uint8_t)newValue.at(2))); } + emit powerChanged(m_watt.value()); emit debug(QStringLiteral("Current watt: ") + QString::number(m_watt.value())); + + if(THINK_X) { + + if ((flags & 0x1) == 0x01) // Pedal Power Balance Present + { + index += 1; + } + if ((flags & 0x2) == 0x02) // Pedal Power Balance Reference + { + } + if ((flags & 0x4) == 0x04) // Accumulated Torque Present + { + index += 2; + } + if ((flags & 0x8) == 0x08) // Accumulated Torque Source + { + } + + if ((flags & 0x10) == 0x10) // Wheel Revolution Data Present + { + cadence_present = true; + wheel_revs = true; + } + + if ((flags & 0x20) == 0x20) // Crank Revolution Data Present + { + cadence_present = true; + crank_rev_present = true; + } + + if (cadence_present) { + if (wheel_revs && !crank_rev_present) { + time_division = 2048; + CrankRevs = + (((uint32_t)((uint8_t)newValue.at(index + 3)) << 24) | + ((uint32_t)((uint8_t)newValue.at(index + 2)) << 16) | + ((uint32_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint32_t)((uint8_t)newValue.at(index))); + index += 4; + + LastCrankEventTime = + (((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))); + + index += 2; // wheel event time + + } else if (wheel_revs && crank_rev_present) { + index += 4; // wheel revs + index += 2; // wheel event time + } + + if (crank_rev_present) { + CrankRevs = + (((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))); + index += 2; + + LastCrankEventTime = + (((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))); + index += 2; + } + + int16_t deltaT = LastCrankEventTime - oldLastCrankEventTime; + if (deltaT < 0) { + deltaT = LastCrankEventTime + time_division - oldLastCrankEventTime; + } + + if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name) + .toString() + .startsWith(QStringLiteral("Disabled"))) { + if (CrankRevs != oldCrankRevs && deltaT) { + double cadence = ((CrankRevs - oldCrankRevs) / deltaT) * time_division * 60; + if (!crank_rev_present) + cadence = + cadence / + 2; // I really don't like this, there is no relationship between wheel rev and crank rev + if (cadence >= 0) { + Cadence = cadence; + } + lastGoodCadence = now; + } else if (lastGoodCadence.msecsTo(now) > 2000) { + Cadence = 0; + } + } + + qDebug() << QStringLiteral("Current Cadence: ") << Cadence.value() << CrankRevs << oldCrankRevs << deltaT + << time_division << LastCrankEventTime << oldLastCrankEventTime; + + oldLastCrankEventTime = LastCrankEventTime; + oldCrankRevs = CrankRevs; + + if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) { + Speed = Cadence.value() * settings + .value(QZSettings::cadence_sensor_speed_ratio, + QZSettings::default_cadence_sensor_speed_ratio) + .toDouble(); + } else { + Speed = metric::calculateSpeedFromPower( + watts(), Inclination.value(), Speed.value(), + fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit()); + } + emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value())); + + Distance += ((Speed.value() / 3600000.0) * + ((double)lastRefreshCharacteristicChanged.msecsTo(now))); + emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value())); + + // if we change this, also change the wattsFromResistance function. We can create a standard function in + // order to have all the costants in one place (I WANT MORE TIME!!!) + double ac = 0.01243107769; + double bc = 1.145964912; + double cc = -23.50977444; + + double ar = 0.1469553975; + double br = -5.841344538; + double cr = 97.62165482; + + double res = + (((sqrt(pow(br, 2.0) - 4.0 * ar * + (cr - (m_watt.value() * 132.0 / + (ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) - + br) / + (2.0 * ar)) * + settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) + + settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); + + if (isnan(res)) { + if (Cadence.value() > 0) { + // let's keep the last good value + } else { + m_pelotonResistance = 0; + } + } else { + m_pelotonResistance = res; + } + + qDebug() << QStringLiteral("Current Peloton Resistance: ") + QString::number(m_pelotonResistance.value()); + + if (settings.value(QZSettings::schwinn_bike_resistance, QZSettings::default_schwinn_bike_resistance) + .toBool()) + Resistance = pelotonToBikeResistance(m_pelotonResistance.value()); + else + Resistance = m_pelotonResistance; + emit resistanceRead(Resistance.value()); + qDebug() << QStringLiteral("Current Resistance Calculated: ") + QString::number(Resistance.value()); + + if (watts()) + KCal += + ((((0.048 * ((double)watts()) + 1.19) * + settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) / + 200.0) / + (60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo( + now)))); //(( (0.048* Output in watts +1.19) * body weight + // in kg * 3.5) / 200 ) / 60 + emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value())); + + } + } } else if (characteristic.uuid() == QBluetoothUuid((quint16)0x2AD2)) { union flags { @@ -731,6 +894,10 @@ void tacxneo2::deviceDiscovered(const QBluetoothDeviceInfo &device) { device.address().toString() + ')'); { bluetoothDevice = device; + if(device.name().toUpper().startsWith(QStringLiteral("THINK X"))) { + THINK_X = true; + qDebug() << "THINK X workaround enabled!"; + } m_control = QLowEnergyController::createCentral(bluetoothDevice, this); connect(m_control, &QLowEnergyController::serviceDiscovered, this, &tacxneo2::serviceDiscovered); diff --git a/src/devices/tacxneo2/tacxneo2.h b/src/devices/tacxneo2/tacxneo2.h index 35fb2c062..5afa967dc 100644 --- a/src/devices/tacxneo2/tacxneo2.h +++ b/src/devices/tacxneo2/tacxneo2.h @@ -78,6 +78,8 @@ class tacxneo2 : public bike { double lastGearValue = -1; bool resistance_received = false; + bool THINK_X = false; + #ifdef Q_OS_IOS lockscreen *h = 0; #endif From 3b943784c0dabf4f72e71b7c90903d2e96e41409 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 6 Sep 2024 22:27:51 +0200 Subject: [PATCH 082/162] fixing crash on echelon in case of missing main service --- src/devices/echelonconnectsport/echelonconnectsport.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/devices/echelonconnectsport/echelonconnectsport.cpp b/src/devices/echelonconnectsport/echelonconnectsport.cpp index 6ad1515f1..0cf5d10a8 100644 --- a/src/devices/echelonconnectsport/echelonconnectsport.cpp +++ b/src/devices/echelonconnectsport/echelonconnectsport.cpp @@ -1,4 +1,5 @@ #include "echelonconnectsport.h" +#include "homeform.h" #ifdef Q_OS_ANDROID #include "keepawakehelper.h" #endif @@ -469,7 +470,12 @@ void echelonconnectsport::serviceScanDone(void) { gattCommunicationChannelService = m_control->createServiceObject(_gattCommunicationChannelServiceId); connect(gattCommunicationChannelService, &QLowEnergyService::stateChanged, this, &echelonconnectsport::stateChanged); - gattCommunicationChannelService->discoverDetails(); + if(gattCommunicationChannelService != nullptr) { + gattCommunicationChannelService->discoverDetails(); + } else { + homeform::singleton()->setToastRequested("Bluetooth Service Error! Restart the bike!"); + m_control->disconnectFromDevice(); + } } void echelonconnectsport::errorService(QLowEnergyService::ServiceError err) { From bce2d2605c6d35731c389d7bc1020e6288c5a79c Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sat, 7 Sep 2024 07:23:13 +0200 Subject: [PATCH 083/162] WalkingPad MC21 treadmill #2580 --- src/devices/bluetooth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index c989ae49d..33fec0b99 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1331,6 +1331,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { b.name().toUpper().startsWith(QStringLiteral("LJJ-")) || // LJJ-02351A 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("KS-HD-Z1D"))) || // Kingsmith WalkingPad Z1 (b.name().toUpper().startsWith(QStringLiteral("FIT-")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // sports tech f37s treadmill #2412 (b.name().toUpper().startsWith(QStringLiteral("NOBLEPRO CONNECT")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // FTMS From 573394366b78b68c4d7c4c52fc281f5bce3e119d Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 9 Sep 2024 10:54:18 +0200 Subject: [PATCH 084/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/devices/bike.cpp | 1 + src/devices/ftmsbike/ftmsbike.cpp | 17 ++++++++++------- src/devices/tacxneo2/tacxneo2.cpp | 12 +++++++++++- .../wahookickrsnapbike/wahookickrsnapbike.cpp | 15 ++++++++++++--- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index e46249169..998a8f2d3 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -364,4 +364,5 @@ double bike::gearsZwiftRatio() { case 24: return 5.49; } + return 1; } diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 530352647..28afb2957 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -870,18 +870,21 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact slope += (gears() * 50); } } else { - slope *= gearsZwiftRatio(); + if(slope == 0) { + slope = 10 * gearsZwiftRatio(); + } else if(slope < 0) { + int16_t absslope = abs(slope); + absslope *= gearsZwiftRatio(); + slope += absslope - slope; + } else { + slope *= gearsZwiftRatio(); + } } b[3] = slope & 0xFF; b[4] = slope >> 8; } - if (writeBuffer) { - delete writeBuffer; - } - writeBuffer = new QByteArray(b); - - gattFTMSService->writeCharacteristic(gattWriteCharControlPointId, *writeBuffer); + writeCharacteristic((uint8_t*)b.data(), b.length(), "injectWrite", false, true); } } diff --git a/src/devices/tacxneo2/tacxneo2.cpp b/src/devices/tacxneo2/tacxneo2.cpp index 5c4088d55..e28fcc3df 100644 --- a/src/devices/tacxneo2/tacxneo2.cpp +++ b/src/devices/tacxneo2/tacxneo2.cpp @@ -146,7 +146,17 @@ void tacxneo2::update() { forceInclination(lastRawRequestedInclinationValue + gears()); // since this bike doesn't have the concept of resistance, // i'm using the gears in the inclination } else { - forceInclination(lastRawRequestedInclinationValue * gearsZwiftRatio()); + double slope = lastRawRequestedInclinationValue; + if(slope == 0) { + slope = 0.1 * gearsZwiftRatio(); + } else if(slope < 0) { + double absslope = fabs(slope); + absslope *= gearsZwiftRatio(); + slope += absslope - slope; + } else { + slope *= gearsZwiftRatio(); + } + forceInclination(slope); } } diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index bebe5fb9d..1c66e01e1 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -821,8 +821,17 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) { double g = grade; if(!gears_zwift_ratio) g += gears(); - else - g *= gearsZwiftRatio(); + else { + if(g == 0) { + g = 0.1 * gearsZwiftRatio(); + } else if(g < 0) { + int16_t absslope = abs(g); + absslope *= gearsZwiftRatio(); + g += absslope - g; + } else { + g *= gearsZwiftRatio(); + } + } QByteArray a = setSimGrade(g); uint8_t b[20]; memcpy(b, a.constData(), a.length()); @@ -831,4 +840,4 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) { bool wahookickrsnapbike::inclinationAvailableByHardware() { return KICKR_BIKE; -} \ No newline at end of file +} From b4a81243b8cf7aefdd2c06f87de5e1f3a7129f12 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 9 Sep 2024 11:02:16 +0200 Subject: [PATCH 085/162] Xterra 4500 Incline Issue #2582 --- src/devices/bluetooth.cpp | 3 ++- src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 33fec0b99..0f51b1aaf 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1308,7 +1308,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { b.name().toUpper().startsWith(QStringLiteral("MX-TM ")) || // FTMS b.name().toUpper().startsWith(QStringLiteral("JFTM")) || // FTMS b.name().toUpper().startsWith(QStringLiteral("CT800")) || // FTMS - b.name().toUpper().startsWith(QStringLiteral("TRX4500")) || // FTMS + (b.name().toUpper().startsWith(QStringLiteral("TRX4500")) && toorx_ftms_treadmill) || // FTMS b.name().toUpper().startsWith(QStringLiteral("MATRIXTF50")) || // FTMS b.name().toUpper().startsWith(QStringLiteral("T01_")) || // FTMS (b.name().startsWith(QStringLiteral("SW")) && b.name().length() == 14 && @@ -2077,6 +2077,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { this->signalBluetoothDeviceConnected(activioTreadmill); } else if (((b.name().startsWith(QStringLiteral("TOORX"))) || (b.name().startsWith(QStringLiteral("V-RUN"))) || + (b.name().toUpper().startsWith(QStringLiteral("TRX4500")) && !toorx_ftms_treadmill) || (b.name().toUpper().startsWith(QStringLiteral("K80_"))) || (b.name().toUpper().startsWith(QStringLiteral("I-CONSOLE+"))) || (b.name().toUpper().startsWith(QStringLiteral("ICONSOLE+"))) || diff --git a/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp b/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp index f3f1c280a..062aed5da 100644 --- a/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp +++ b/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp @@ -738,6 +738,7 @@ void trxappgateusbtreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device device.name().toUpper().startsWith(QStringLiteral("ICONSOLE+")) || device.name().toUpper().startsWith(QStringLiteral("DKN RUN")) || device.name().toUpper().startsWith(QStringLiteral("K80_")) || + device.name().toUpper().startsWith(QStringLiteral("TRX4500")) || device.name().toUpper().startsWith(QStringLiteral("XT900")) || device.name().toUpper().startsWith(QStringLiteral("ADIDAS ")) || device.name().toUpper().startsWith(QStringLiteral("XT485"))) { @@ -749,6 +750,7 @@ void trxappgateusbtreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device device.name().toUpper().startsWith(QStringLiteral("ICONSOLE+")) || device.name().toUpper().startsWith(QStringLiteral("I-CONSOLE+")) || device.name().startsWith(QStringLiteral("F63")) || + device.name().toUpper().startsWith(QStringLiteral("TRX4500")) || device.name().toUpper().startsWith(QStringLiteral("DKN RUN")) || device.name().toUpper().startsWith(QStringLiteral("XT900")) || device.name().toUpper().startsWith(QStringLiteral("XT485"))) { From 79a898d32bae57818aa883e9026c1deaf7a269ab Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 9 Sep 2024 11:51:10 +0200 Subject: [PATCH 086/162] Wahoo Kickr not changing resistance when QZ acting as bridge for MYWHOOSH #2574 --- src/devices/bluetooth.cpp | 17 +++++++++++------ .../echelonconnectsport/echelonconnectsport.cpp | 3 ++- .../fitshowtreadmill/fitshowtreadmill.cpp | 3 ++- src/devices/ftmsbike/ftmsbike.cpp | 6 ++++-- .../horizontreadmill/horizontreadmill.cpp | 3 ++- src/devices/stagesbike/stagesbike.cpp | 3 ++- .../wahookickrsnapbike/wahookickrsnapbike.cpp | 7 ++++++- src/zwift_play/zwiftclickremote.cpp | 3 ++- 8 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 0f51b1aaf..491b58891 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1551,7 +1551,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { b.name().toUpper().startsWith("KICKR ROLLR") || (b.name().toUpper().startsWith("HAMMER ") && saris_trainer) || (b.name().toUpper().startsWith("WAHOO KICKR"))) && - !wahooKickrSnapBike && filter) { + !wahooKickrSnapBike && !ftmsBike && filter) { this->setLastBluetoothDevice(b); this->stopDiscovery(); wahooKickrSnapBike = @@ -2403,7 +2403,8 @@ void bluetooth::connectedAndDiscovered() { connect(heartRateBelt, &heartratebelt::debug, this, &bluetooth::debug); connect(heartRateBelt, &heartratebelt::heartRate, this->device(), &bluetoothdevice::heartRate); heartRateBelt->deviceDiscovered(b); - homeform::singleton()->setToastRequested(b.name() + " (HR sensor) connected!"); + if(homeform::singleton()) + homeform::singleton()->setToastRequested(b.name() + " (HR sensor) connected!"); break; } } @@ -2490,7 +2491,8 @@ void bluetooth::connectedAndDiscovered() { connect(cadenceSensor, &bluetoothdevice::cadenceChanged, this->device(), &bluetoothdevice::cadenceSensor); cadenceSensor->deviceDiscovered(b); - homeform::singleton()->setToastRequested(b.name() + " (cadence sensor) connected!"); + if(homeform::singleton()) + homeform::singleton()->setToastRequested(b.name() + " (cadence sensor) connected!"); break; } } @@ -2537,7 +2539,8 @@ void bluetooth::connectedAndDiscovered() { powerSensorRun->deviceDiscovered(b); } - homeform::singleton()->setToastRequested(b.name() + " (power sensor) connected!"); + if(homeform::singleton()) + homeform::singleton()->setToastRequested(b.name() + " (power sensor) connected!"); break; } @@ -2606,7 +2609,8 @@ void bluetooth::connectedAndDiscovered() { connect(zwiftClickRemote->playDevice, &ZwiftPlayDevice::plus, (bike*)this->device(), &bike::gearUp); connect(zwiftClickRemote->playDevice, &ZwiftPlayDevice::minus, (bike*)this->device(), &bike::gearDown); zwiftClickRemote->deviceDiscovered(b); - homeform::singleton()->setToastRequested("Zwift Click Connected!"); + if(homeform::singleton()) + homeform::singleton()->setToastRequested("Zwift Click Connected!"); break; } } @@ -2633,7 +2637,8 @@ void bluetooth::connectedAndDiscovered() { connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::plus, (bike*)this->device(), &bike::gearUp); connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::minus, (bike*)this->device(), &bike::gearDown); zwiftPlayDevice.last()->deviceDiscovered(b); - homeform::singleton()->setToastRequested("Zwift Play/Ride Connected!"); + if(homeform::singleton()) + homeform::singleton()->setToastRequested("Zwift Play/Ride Connected!"); } } } diff --git a/src/devices/echelonconnectsport/echelonconnectsport.cpp b/src/devices/echelonconnectsport/echelonconnectsport.cpp index 0cf5d10a8..fe60bb503 100644 --- a/src/devices/echelonconnectsport/echelonconnectsport.cpp +++ b/src/devices/echelonconnectsport/echelonconnectsport.cpp @@ -473,7 +473,8 @@ void echelonconnectsport::serviceScanDone(void) { if(gattCommunicationChannelService != nullptr) { gattCommunicationChannelService->discoverDetails(); } else { - homeform::singleton()->setToastRequested("Bluetooth Service Error! Restart the bike!"); + if(homeform::singleton()) + homeform::singleton()->setToastRequested("Bluetooth Service Error! Restart the bike!"); m_control->disconnectFromDevice(); } } diff --git a/src/devices/fitshowtreadmill/fitshowtreadmill.cpp b/src/devices/fitshowtreadmill/fitshowtreadmill.cpp index 12424bf3e..2604fc28f 100644 --- a/src/devices/fitshowtreadmill/fitshowtreadmill.cpp +++ b/src/devices/fitshowtreadmill/fitshowtreadmill.cpp @@ -303,7 +303,8 @@ void fitshowtreadmill::serviceDiscovered(const QBluetoothUuid &gatt) { QSettings settings; settings.setValue(QZSettings::ftms_treadmill, bluetoothDevice.name()); qDebug() << "forcing FTMS treadmill since it has FTMS"; - homeform::singleton()->setToastRequested("FTMS treadmill found, restart the app to apply the change"); + if(homeform::singleton()) + homeform::singleton()->setToastRequested("FTMS treadmill found, restart the app to apply the change"); } } diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 28afb2957..be679b7d9 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -268,7 +268,8 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris if(newValue.length() > 0) { uint8_t b = (uint8_t)newValue.at(0); if(b != battery_level) - homeform::singleton()->setToastRequested(QStringLiteral("Battery Level ") + QString::number(b) + " %"); + if(homeform::singleton()) + homeform::singleton()->setToastRequested(QStringLiteral("Battery Level ") + QString::number(b) + " %"); battery_level = b; } return; @@ -797,7 +798,8 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) { if(gattFTMSService == nullptr && DOMYOS) { settings.setValue(QZSettings::domyosbike_notfmts, true); - homeform::singleton()->setToastRequested("Domyos bike presents itself like a FTMS but it's not. Restart QZ to apply the fix, thanks."); + if(homeform::singleton()) + homeform::singleton()->setToastRequested("Domyos bike presents itself like a FTMS but it's not. Restart QZ to apply the fix, thanks."); } if (gattFTMSService && gattWriteCharControlPointId.isValid() && diff --git a/src/devices/horizontreadmill/horizontreadmill.cpp b/src/devices/horizontreadmill/horizontreadmill.cpp index b13149118..f97fb83de 100644 --- a/src/devices/horizontreadmill/horizontreadmill.cpp +++ b/src/devices/horizontreadmill/horizontreadmill.cpp @@ -2097,7 +2097,8 @@ void horizontreadmill::stateChanged(QLowEnergyService::ServiceState state) { if(s->serviceUuid() == _DomyosServiceId && DOMYOS) { settings.setValue(QZSettings::domyostreadmill_notfmts, true); settings.sync(); - homeform::singleton()->setToastRequested("Domyos Treadmill presents itself like a FTMS but it's not. Restart QZ to apply the fix, thanks."); + if(homeform::singleton()) + homeform::singleton()->setToastRequested("Domyos Treadmill presents itself like a FTMS but it's not. Restart QZ to apply the fix, thanks."); return; } diff --git a/src/devices/stagesbike/stagesbike.cpp b/src/devices/stagesbike/stagesbike.cpp index 5fcc5eb8c..d7de9aff4 100644 --- a/src/devices/stagesbike/stagesbike.cpp +++ b/src/devices/stagesbike/stagesbike.cpp @@ -120,7 +120,8 @@ void stagesbike::serviceDiscovered(const QBluetoothUuid &gatt) { QSettings settings; settings.setValue(QZSettings::ftms_bike, bluetoothDevice.name()); qDebug() << "forcing FTMS bike since it has FTMS"; - homeform::singleton()->setToastRequested("FTMS bike found, restart the app to apply the change!"); + if(homeform::singleton()) + homeform::singleton()->setToastRequested("FTMS bike found, restart the app to apply the change!"); } } diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index 1c66e01e1..d6934a456 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -1,5 +1,5 @@ #include "wahookickrsnapbike.h" - +#include "homeform.h" #include "virtualdevices/virtualbike.h" #include #include @@ -721,6 +721,11 @@ void wahookickrsnapbike::serviceScanDone(void) { connect(gattCommunicationChannelService.constLast(), &QLowEnergyService::stateChanged, this, &wahookickrsnapbike::stateChanged); gattCommunicationChannelService.constLast()->discoverDetails(); + if(s == QBluetoothUuid((quint16)0x1826)) { + qDebug() << "if it doesn't change the inclination, set the bike in the FTMS bike setting under the Bike settings."; + if(homeform::singleton()) + homeform::singleton()->setToastRequested("if it doesn't change the inclination, set the bike in the FTMS bike setting under the Bike settings."); + } } } diff --git a/src/zwift_play/zwiftclickremote.cpp b/src/zwift_play/zwiftclickremote.cpp index 53c2121bf..c3af478fa 100755 --- a/src/zwift_play/zwiftclickremote.cpp +++ b/src/zwift_play/zwiftclickremote.cpp @@ -36,7 +36,8 @@ void zwiftclickremote::update() { } else if(initDone) { countRxTimeout++; if(countRxTimeout == 10) { - homeform::singleton()->setToastRequested("Zwift device: UPGRADE THE FIRMWARE!"); + if(homeform::singleton()) + homeform::singleton()->setToastRequested("Zwift device: UPGRADE THE FIRMWARE!"); } } } From 9ba5bdbb1b97e148eeb1d726709afc54d54a8c6c Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 9 Sep 2024 15:58:06 +0200 Subject: [PATCH 087/162] Update horizontreadmilltestdata.h --- tst/Devices/HorizonTreadmill/horizontreadmilltestdata.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tst/Devices/HorizonTreadmill/horizontreadmilltestdata.h b/tst/Devices/HorizonTreadmill/horizontreadmilltestdata.h index d35cfee56..3c835741c 100644 --- a/tst/Devices/HorizonTreadmill/horizontreadmilltestdata.h +++ b/tst/Devices/HorizonTreadmill/horizontreadmilltestdata.h @@ -22,7 +22,6 @@ class HorizonTreadmillTestData : public TreadmillTestData { this->addDeviceName("PARAGON X", comparison::StartsWithIgnoreCase); this->addDeviceName("JFTM", comparison::StartsWithIgnoreCase); this->addDeviceName("CT800", comparison::StartsWithIgnoreCase); - this->addDeviceName("TRX4500", comparison::StartsWithIgnoreCase); this->addDeviceName("MOBVOI TM", comparison::StartsWithIgnoreCase); this->addDeviceName("ESANGLINKER", comparison::StartsWithIgnoreCase); this->addDeviceName("DK202000725", comparison::StartsWithIgnoreCase); From 47fea6ee8e76f539d746fc591d05f17f3894376b Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 9 Sep 2024 16:14:22 +0200 Subject: [PATCH 088/162] Revert "Xterra 4500 Incline Issue #2582" This reverts commit b4a81243b8cf7aefdd2c06f87de5e1f3a7129f12. --- src/devices/bluetooth.cpp | 3 +-- src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 491b58891..e90a3f97f 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1308,7 +1308,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { b.name().toUpper().startsWith(QStringLiteral("MX-TM ")) || // FTMS b.name().toUpper().startsWith(QStringLiteral("JFTM")) || // FTMS b.name().toUpper().startsWith(QStringLiteral("CT800")) || // FTMS - (b.name().toUpper().startsWith(QStringLiteral("TRX4500")) && toorx_ftms_treadmill) || // FTMS + b.name().toUpper().startsWith(QStringLiteral("TRX4500")) || // FTMS b.name().toUpper().startsWith(QStringLiteral("MATRIXTF50")) || // FTMS b.name().toUpper().startsWith(QStringLiteral("T01_")) || // FTMS (b.name().startsWith(QStringLiteral("SW")) && b.name().length() == 14 && @@ -2077,7 +2077,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { this->signalBluetoothDeviceConnected(activioTreadmill); } else if (((b.name().startsWith(QStringLiteral("TOORX"))) || (b.name().startsWith(QStringLiteral("V-RUN"))) || - (b.name().toUpper().startsWith(QStringLiteral("TRX4500")) && !toorx_ftms_treadmill) || (b.name().toUpper().startsWith(QStringLiteral("K80_"))) || (b.name().toUpper().startsWith(QStringLiteral("I-CONSOLE+"))) || (b.name().toUpper().startsWith(QStringLiteral("ICONSOLE+"))) || diff --git a/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp b/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp index 062aed5da..f3f1c280a 100644 --- a/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp +++ b/src/devices/trxappgateusbtreadmill/trxappgateusbtreadmill.cpp @@ -738,7 +738,6 @@ void trxappgateusbtreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device device.name().toUpper().startsWith(QStringLiteral("ICONSOLE+")) || device.name().toUpper().startsWith(QStringLiteral("DKN RUN")) || device.name().toUpper().startsWith(QStringLiteral("K80_")) || - device.name().toUpper().startsWith(QStringLiteral("TRX4500")) || device.name().toUpper().startsWith(QStringLiteral("XT900")) || device.name().toUpper().startsWith(QStringLiteral("ADIDAS ")) || device.name().toUpper().startsWith(QStringLiteral("XT485"))) { @@ -750,7 +749,6 @@ void trxappgateusbtreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device device.name().toUpper().startsWith(QStringLiteral("ICONSOLE+")) || device.name().toUpper().startsWith(QStringLiteral("I-CONSOLE+")) || device.name().startsWith(QStringLiteral("F63")) || - device.name().toUpper().startsWith(QStringLiteral("TRX4500")) || device.name().toUpper().startsWith(QStringLiteral("DKN RUN")) || device.name().toUpper().startsWith(QStringLiteral("XT900")) || device.name().toUpper().startsWith(QStringLiteral("XT485"))) { From 73ef8b4f0391d7a1384dd41af42993dd6265a0f0 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 10 Sep 2024 08:56:48 +0200 Subject: [PATCH 089/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/devices/ftmsbike/ftmsbike.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index be679b7d9..d847b3faa 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -189,14 +189,14 @@ void ftmsbike::update() { requestResistance = 1; } - if (requestResistance != currentResistance().value()) { + if (requestResistance != currentResistance().value() || lastGearValue != gears()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); // if the FTMS is connected, the ftmsCharacteristicChanged event will do all the stuff because it's a // FTMS bike. This condition handles the peloton requests if (((virtualBike && !virtualBike->ftmsDeviceConnected()) || !virtualBike) && (requestPower == 0 || requestPower == -1)) { init(); - forceResistance(requestResistance); + forceResistance(requestResistance + (gears() * 5)); } } requestResistance = -1; @@ -862,8 +862,7 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact lastPacketFromFTMS.clear(); for(int i=0; i> 8; + + qDebug() << "applying gears mod" << gears() << gearsZwiftRatio() << slope; } - writeCharacteristic((uint8_t*)b.data(), b.length(), "injectWrite", false, true); + writeCharacteristic((uint8_t*)b.data(), b.length(), "injectWrite ", false, true); } } From f8a1a331448b10da4808257bee672d7c2763a6d7 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 10 Sep 2024 08:57:44 +0200 Subject: [PATCH 090/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 2cd1627f5..746cd1bbb 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 861; + CURRENT_PROJECT_VERSION = 862; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 861; + CURRENT_PROJECT_VERSION = 862; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 861; + CURRENT_PROJECT_VERSION = 862; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 861; + CURRENT_PROJECT_VERSION = 862; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 861; + CURRENT_PROJECT_VERSION = 862; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 861; + CURRENT_PROJECT_VERSION = 862; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 99bb36b7f5cbd245d7cc824ee31f71850c1f7352 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 10 Sep 2024 08:58:56 +0200 Subject: [PATCH 091/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 746cd1bbb..a5eac9b5e 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 862; + CURRENT_PROJECT_VERSION = 863; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 862; + CURRENT_PROJECT_VERSION = 863; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 862; + CURRENT_PROJECT_VERSION = 863; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 862; + CURRENT_PROJECT_VERSION = 863; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 862; + CURRENT_PROJECT_VERSION = 863; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 862; + CURRENT_PROJECT_VERSION = 863; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 1a2c5683ad27d3ae8233dd74b90e9939c5cd2e2d Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 10 Sep 2024 12:25:32 +0200 Subject: [PATCH 092/162] Update main.yml (#2585) --- .github/workflows/main.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 15d48c6a4..934055586 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -195,14 +195,14 @@ jobs: if: ${{ ! matrix.config.python }} - name: Archive windows binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: windows-binary path: windows-binary.zip if: matrix.config.python - name: Archive windows binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: windows-binary-no-python path: windows-binary-no-python.zip @@ -433,7 +433,7 @@ jobs: run: qmake; make -j8 - name: Archive linux-desktop binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: linux-desktop-binary path: src/qdomyos-zwift @@ -442,7 +442,7 @@ jobs: run: cd tst; GTEST_OUTPUT=xml:test-results/ GTEST_COLOR=1 ./qdomyos-zwift-tests; cd .. - name: Upload test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: failure() with: name: test_results_xml @@ -630,7 +630,7 @@ jobs: run: cd src; androiddeployqt --input android-qdomyos-zwift-deployment-settings.json --output ${{ github.workspace }}/output/android/ --android-platform android-31 --gradle --aab - name: Archive apk binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: fdroid-android-trial path: ${{ github.workspace }}/output/android/build/outputs/apk/debug/ @@ -904,14 +904,14 @@ jobs: if: ${{ ! matrix.config.python }} - name: Archive windows binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: windows-msvc2019-binary path: windows-msvc2019-binary.zip if: matrix.config.python - name: Archive windows binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: windows-msvc2019-binary-no-python path: windows-msvc2019-binary-no-python.zip @@ -1047,7 +1047,7 @@ jobs: run: Compress-Archive src/debug/output windows-msvc2019-ai-server-binary.zip - name: Archive windows binary - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: windows-msvc2019-ai-server-binary path: windows-msvc2019-ai-server-binary.zip From 7cdf9782af990280260c39e53b5dff4ab35da241 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 11 Sep 2024 09:55:47 +0200 Subject: [PATCH 093/162] trying to fix artifacts --- .github/workflows/main.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 934055586..afa8b31e1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1055,11 +1055,12 @@ jobs: upload_to_release: permissions: write-all runs-on: ubuntu-20.04 - if: github.event_name == 'schedule' + #if: github.event_name == 'schedule' + if: github.ref == 'refs/heads/master' needs: [linux-x86-build, window-msvc2019-build, ios-build, window-build, android-build] # Specify the job dependencies steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Update nightly release uses: andelf/nightly-release@main env: From a675451f5e6e0bc78ac320764e928d7d6339fba1 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 11 Sep 2024 10:36:33 +0200 Subject: [PATCH 094/162] Update main.yml --- .github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index afa8b31e1..704b46484 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1055,8 +1055,7 @@ jobs: upload_to_release: permissions: write-all runs-on: ubuntu-20.04 - #if: github.event_name == 'schedule' - if: github.ref == 'refs/heads/master' + if: github.event_name == 'schedule' needs: [linux-x86-build, window-msvc2019-build, ios-build, window-build, android-build] # Specify the job dependencies steps: - name: Download artifacts From 114ee5317a7e0723009524919b1f873c664bd02a Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 13 Sep 2024 11:32:45 +0200 Subject: [PATCH 095/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/devices/bike.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index 998a8f2d3..41ca1a365 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -86,7 +86,12 @@ void bike::changePower(int32_t power) { double bike::gears() { return m_gears; } void bike::setGears(double gears) { QSettings settings; + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); qDebug() << "setGears" << gears; + if(gears_zwift_ratio && (gears > 24 || gears < 1)) { + qDebug() << "new gear value ignored because of gears_zwift_ratio setting!"; + return; + } m_gears = gears; settings.setValue(QZSettings::gears_current_value, m_gears); if (lastRawRequestedResistanceValue != -1) { From 8801f1d6cf44c44b393f984bdea747d812158431 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 13 Sep 2024 11:35:48 +0200 Subject: [PATCH 096/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/devices/bike.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index 41ca1a365..bfb584dd5 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -83,7 +83,17 @@ void bike::changePower(int32_t power) { } } -double bike::gears() { return m_gears; } +double bike::gears() { + QSettings settings; + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + if(gears_zwift_ratio) { + if(m_gears < 1) + return 1.0; + else if(m_gears > 24) + return 24.0; + } + return m_gears; +} void bike::setGears(double gears) { QSettings settings; bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); From d27335410bab6fd1ed14cf86492efb95033a50ac Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 13 Sep 2024 12:06:35 +0200 Subject: [PATCH 097/162] Bluetooth Remote on Linux CLI (#2553) * let's see if build * fixing linker error? * Update EventHandler.h * fixing build * Update EventHandler.h * Update EventHandler.h * Update EventHandler.h * Update main.cpp * Update EventHandler.h * Update EventHandler.h * Update EventHandler.h * Update EventHandler.h * Update EventHandler.h * -bluetooth-event-gear-device /dev/input/event2 * Update main.cpp --- src/EventHandler.h | 115 ++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 13 +++++ src/qdomyos-zwift.pri | 1 + 3 files changed, 129 insertions(+) create mode 100644 src/EventHandler.h diff --git a/src/EventHandler.h b/src/EventHandler.h new file mode 100644 index 000000000..4fe2859aa --- /dev/null +++ b/src/EventHandler.h @@ -0,0 +1,115 @@ +#ifndef EVENTHANDLER_H +#define EVENTHANDLER_H + +#include +#include +#include + +#ifdef Q_OS_LINUX +#ifndef Q_OS_ANDROID +#include +#include "bluetooth.h" + +class EventHandler : public QObject +{ + Q_OBJECT + + public: + EventHandler(const QString& devicePath, QObject* parent = nullptr) + : QObject(parent), m_devicePath(devicePath), m_notifier(nullptr), m_fd(-1) {} + + ~EventHandler() { + if (m_fd != -1) { + ::close(m_fd); + } + } + + bool initialize() { + m_fd = ::open(m_devicePath.toStdString().c_str(), O_RDONLY | O_NONBLOCK); + if (m_fd == -1) { + qDebug() << "Failed to open device:" << m_devicePath; + emit error(QString("Failed to open device: %1").arg(m_devicePath)); + return false; + } + m_notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); + connect(m_notifier, &QSocketNotifier::activated, this, &EventHandler::handleEvent); + qDebug() << "Device opened successfully:" << m_devicePath; + return true; + } + + signals: + void keyPressed(int keyCode); + void error(const QString& errorMessage); + + private slots: + void handleEvent() { + input_event ev; + ssize_t bytesRead = ::read(m_fd, &ev, sizeof(ev)); + + if (bytesRead == sizeof(ev)) { + if (ev.type == EV_KEY && ev.value == 1) { // Key press event + emit keyPressed(ev.code); + } + } else if (bytesRead == 0) { + qDebug() << "End of file reached."; + m_notifier->setEnabled(false); + } else if (bytesRead == -1) { + qDebug() << "Read error:" << strerror(errno); + emit error(QString("Failed to read from device: %1").arg(strerror(errno))); + } + } + + private: + QString m_devicePath; + int m_fd; + QSocketNotifier* m_notifier; +}; + +class BluetoothHandler : public QObject +{ + Q_OBJECT + + public: + BluetoothHandler(bluetooth* bl, QString eventDevice, QObject* parent = nullptr) + : QObject(parent), m_bluetooth(bl) + { + m_handler = new EventHandler(eventDevice); // Adjust this path as needed + + if (!m_handler->initialize()) { + qDebug() << "Failed to initialize EventHandler."; + return; + } + + connect(m_handler, &EventHandler::keyPressed, this, &BluetoothHandler::onKeyPressed); + connect(m_handler, &EventHandler::error, this, &BluetoothHandler::onError); + } + + ~BluetoothHandler() { + delete m_handler; + } + + private slots: + void onKeyPressed(int keyCode) + { + qDebug() << "Key pressed:" << keyCode; + if (m_bluetooth && m_bluetooth->device() && m_bluetooth->device()->deviceType() == bluetoothdevice::BIKE) { + if (keyCode == 115) // up + ((bike*)m_bluetooth->device())->setGears(((bike*)m_bluetooth->device())->gears() + 1); + else if (keyCode == 114) // down + ((bike*)m_bluetooth->device())->setGears(((bike*)m_bluetooth->device())->gears() - 1); + } + } + + void onError(const QString& errorMessage) + { + qDebug() << "Error:" << errorMessage; + } + + private: + EventHandler* m_handler; + bluetooth* m_bluetooth; +}; + +#endif // EVENTHANDLER_H +#endif // EVENTHANDLER_H +#endif // EVENTHANDLER_H diff --git a/src/main.cpp b/src/main.cpp index e35b2a466..ce25af309 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #ifdef Q_OS_LINUX #ifndef Q_OS_ANDROID #include // getuid +#include "EventHandler.h" #endif #endif #include @@ -67,6 +68,7 @@ bool bike_wheel_revs = false; bool run_cadence_sensor = false; bool nordictrack_10_treadmill = false; bool reebok_fr30_treadmill = false; +QString eventGearDevice = QStringLiteral(""); QString trainProgram; QString deviceName = QLatin1String(""); uint32_t pollDeviceTime = 200; @@ -148,6 +150,10 @@ QCoreApplication *createApplication(int &argc, char *argv[]) { deviceName = argv[++i]; } + if (!qstrcmp(argv[i], "-bluetooth-event-gear-device")) { + + eventGearDevice = argv[++i]; + } if (!qstrcmp(argv[i], "-peloton-username")) { peloton_username = argv[++i]; @@ -642,6 +648,13 @@ int main(int argc, char *argv[]) { } else { // start non-GUI version... } + +#ifdef Q_OS_LINUX +#ifndef Q_OS_ANDROID + if(eventGearDevice.length()) + new BluetoothHandler(&bl, eventGearDevice); +#endif +#endif return app->exec(); #endif } diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index 6db9feb9d..a3fbbf88e 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -299,6 +299,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin INCLUDEPATH += fit-sdk/ devices/ HEADERS += \ + $$PWD/EventHandler.h \ $$PWD/devices/antbike/antbike.h \ $$PWD/devices/crossrope/crossrope.h \ $$PWD/devices/focustreadmill/focustreadmill.h \ From 5b6012ebbcb699585d5b26b1a9c0ea108b47fca2 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 13 Sep 2024 12:41:38 +0200 Subject: [PATCH 098/162] SS2K + Peloton Bike (Low Impact Rides) #2527 --- src/devices/ftmsbike/ftmsbike.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index d847b3faa..2df0d24bd 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -181,7 +181,7 @@ void ftmsbike::update() { auto virtualBike = this->VirtualBike(); - if (requestResistance != -1) { + if (requestResistance != -1 || lastGearValue != gears()) { if (requestResistance > 100) { requestResistance = 100; } // TODO, use the bluetooth value From 3b3d89344793444c1b24b6c03312c889ca2f8987 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 13 Sep 2024 15:05:54 +0200 Subject: [PATCH 099/162] New echelon stride treadmill #2555 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++--- src/devices/echelonstride/echelonstride.cpp | 54 ++++++++++++++++++- src/devices/echelonstride/echelonstride.h | 2 + 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index a5eac9b5e..8d48c4e25 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 863; + CURRENT_PROJECT_VERSION = 864; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 863; + CURRENT_PROJECT_VERSION = 864; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 863; + CURRENT_PROJECT_VERSION = 864; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 863; + CURRENT_PROJECT_VERSION = 864; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 863; + CURRENT_PROJECT_VERSION = 864; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 863; + CURRENT_PROJECT_VERSION = 864; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/echelonstride/echelonstride.cpp b/src/devices/echelonstride/echelonstride.cpp index 356aeaf0e..6b0068cfe 100644 --- a/src/devices/echelonstride/echelonstride.cpp +++ b/src/devices/echelonstride/echelonstride.cpp @@ -196,12 +196,22 @@ void echelonstride::update() { uint8_t initData3[] = {0xf0, 0xb0, 0x01, 0x01, 0xa2}; writeCharacteristic(initData3, sizeof(initData3), QStringLiteral("start"), false, true); + if(stride4) { + uint8_t initData0[] = {0xf0, 0xa5, 0x00, 0x95}; + writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("start"), false, false); + } + uint8_t initData4[] = {0xf0, 0xd0, 0x01, 0x00, 0xc1}; writeCharacteristic(initData4, sizeof(initData4), QStringLiteral("start"), false, false); uint8_t initData5[] = {0xf0, 0xd0, 0x01, 0x11, 0xd2}; writeCharacteristic(initData5, sizeof(initData5), QStringLiteral("start"), false, false); + if(stride4) { + uint8_t initData0[] = {0xf0, 0xd3, 0x02, 0x01, 0xf4, 0xba}; + writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("start"), false, false); + } + lastStart = QDateTime::currentMSecsSinceEpoch(); requestStart = -1; emit tapeStarted(); @@ -285,6 +295,32 @@ void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &charac } else if (((unsigned char)newValue.at(0)) == 0xf0 && ((unsigned char)newValue.at(1)) == 0xd0) { writeCharacteristic((uint8_t *)newValue.constData(), newValue.length(), "reply to d0", false, false); return; + } else if (((unsigned char)newValue.at(0)) == 0xf0 && ((unsigned char)newValue.at(1)) == 0xd1 && stride4) { + + double miles = 1; + if (settings.value(QZSettings::sole_treadmill_miles, QZSettings::default_sole_treadmill_miles).toBool()) + miles = 1.60934; + + // this line on iOS sometimes gives strange overflow values + // uint16_t convertedData = (((uint16_t)newValue.at(3)) << 8) | (uint16_t)newValue.at(4); + qDebug() << "speed1" << newValue.at(7); + uint16_t convertedData = (uint8_t)newValue.at(7); + qDebug() << "speed2" << convertedData; + convertedData = convertedData << 8; + qDebug() << "speed3" << convertedData; + convertedData = convertedData & 0xFF00; + qDebug() << "speed4" << convertedData; + convertedData = convertedData + (uint8_t)newValue.at(8); + qDebug() << "speed5" << convertedData; + Speed = (((double)convertedData) / 100.0) * miles; + + if (Speed.value() > 0) + lastStart = 0; + else + lastStop = 0; + + qDebug() << QStringLiteral("Current Speed: ") + QString::number(Speed.value()); + return; } /*if (newValue.length() != 21) @@ -344,15 +380,25 @@ void echelonstride::btinit() { uint8_t initData1[] = {0xf0, 0xa1, 0x00, 0x91}; uint8_t initData2[] = {0xf0, 0xa3, 0x00, 0x93}; + // stride4 + uint8_t initDataStride4_0[] = {0xf0, 0xe0, 0xfd, 0x3e, 0x65, 0x48, 0xd5, 0x8d}; + writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("init"), false, true); + if(stride4) { + writeCharacteristic(initDataStride4_0, sizeof(initDataStride4_0), QStringLiteral("init"), false, true); + writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("init"), false, true); + } + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true); writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true); writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true); writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true); writeCharacteristic(initData2, sizeof(initData2), QStringLiteral("init"), false, true); - writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true); + + if(!stride4) + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true); initDone = true; } @@ -432,6 +478,12 @@ void echelonstride::error(QLowEnergyController::Error err) { void echelonstride::deviceDiscovered(const QBluetoothDeviceInfo &device) { { bluetoothDevice = device; + + if(bluetoothDevice.name().toUpper().startsWith("STRIDE4")) { + stride4 = true; + qDebug() << "STRIDE4 workaround enabled!"; + } + m_control = QLowEnergyController::createCentral(bluetoothDevice, this); connect(m_control, &QLowEnergyController::serviceDiscovered, this, &echelonstride::serviceDiscovered); connect(m_control, &QLowEnergyController::discoveryFinished, this, &echelonstride::serviceScanDone); diff --git a/src/devices/echelonstride/echelonstride.h b/src/devices/echelonstride/echelonstride.h index ea2c4c6f4..c7906450a 100644 --- a/src/devices/echelonstride/echelonstride.h +++ b/src/devices/echelonstride/echelonstride.h @@ -78,6 +78,8 @@ class echelonstride : public treadmill { bool initDone = false; bool initRequest = false; + bool stride4 = false; + #ifdef Q_OS_IOS lockscreen *h = 0; #endif From 7305e4fab669161cd1fcd97f8098a48c9433fb1e Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sat, 14 Sep 2024 20:40:29 +0200 Subject: [PATCH 100/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers (Issue #2541) --- src/devices/ftmsbike/ftmsbike.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 2df0d24bd..723cc6639 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -872,16 +872,16 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact } } else { if(slope == 0) { - slope = 100 * gearsZwiftRatio(); + slope = 30 * gearsZwiftRatio(); } else if(slope < 0) { int16_t absslope = abs(slope); - if(absslope < 100) - absslope = 100; + if(absslope < 30) + absslope = 30; absslope *= gearsZwiftRatio(); slope += absslope - slope; } else { - if(slope < 100) - slope = 100; + if(slope < 30) + slope = 30; slope *= gearsZwiftRatio(); } } From bc9e33aeadee54edf970a650668b66a321f71274 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sat, 14 Sep 2024 20:49:00 +0200 Subject: [PATCH 101/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 8d48c4e25..a85afacfc 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4046,7 +4046,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 864; + CURRENT_PROJECT_VERSION = 865; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4237,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 864; + CURRENT_PROJECT_VERSION = 865; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4464,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 864; + CURRENT_PROJECT_VERSION = 865; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4560,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 864; + CURRENT_PROJECT_VERSION = 865; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4652,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 864; + CURRENT_PROJECT_VERSION = 865; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4766,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 864; + CURRENT_PROJECT_VERSION = 865; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 77a361905bb1b521c238db8cee76f85026efa6ac Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 16 Sep 2024 09:47:22 +0200 Subject: [PATCH 102/162] iConsole + Torneo C-720BL won't connect #2442 --- src/devices/bike.h | 2 - src/devices/bluetooth.cpp | 26 +- src/devices/bluetooth.h | 2 + src/devices/bluetoothdevice.h | 3 + src/devices/elliptical.cpp | 34 ++ src/devices/elliptical.h | 2 + src/devices/rower.h | 1 - .../sportstechelliptical.cpp | 454 ++++++++++++++++++ .../sportstechelliptical.h | 100 ++++ src/devices/treadmill.h | 2 - src/qdomyos-zwift.pri | 2 + 11 files changed, 621 insertions(+), 7 deletions(-) create mode 100644 src/devices/sportstechelliptical/sportstechelliptical.cpp create mode 100644 src/devices/sportstechelliptical/sportstechelliptical.h diff --git a/src/devices/bike.h b/src/devices/bike.h index 9a68ea843..c9a711675 100644 --- a/src/devices/bike.h +++ b/src/devices/bike.h @@ -75,11 +75,9 @@ class bike : public bluetoothdevice { metric RequestedResistance; metric RequestedPelotonResistance; metric RequestedCadence; - metric RequestedPower; resistance_t requestResistance = -1; double requestInclination = -100; - int16_t requestPower = -1; bool ergModeSupported = false; // if a bike has this mode supported, when from the virtual bike there is a power // request there is no need to translate in resistance levels diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index e90a3f97f..7dec9fa02 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1324,8 +1324,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { b.name().toUpper().startsWith(QStringLiteral("XT285")) || b.name().toUpper().startsWith(QStringLiteral("XTERRA TR")) || b.name().toUpper().startsWith(QStringLiteral("T118_")) || - b.name().toUpper().startsWith(QStringLiteral("RUNN ")) || - b.name().toUpper().startsWith(QStringLiteral("EW-EP-")) || // Miweba MC700 ellipital Trainer #2419 + b.name().toUpper().startsWith(QStringLiteral("RUNN ")) || b.name().toUpper().startsWith(QStringLiteral("TF04-")) || // Sport Synology Z5 Treadmill #2415 b.name().toUpper().startsWith(QStringLiteral("FIT-")) || // FIT-1596 b.name().toUpper().startsWith(QStringLiteral("LJJ-")) || // LJJ-02351A @@ -1834,6 +1833,22 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { // SLOT(inclinationChanged(double))); sportsTechBike->deviceDiscovered(b); this->signalBluetoothDeviceConnected(sportsTechBike); + } else if (b.name().toUpper().startsWith(QStringLiteral("EW-EP-")) && !sportsTechElliptical && !horizonTreadmill && filter) { + this->setLastBluetoothDevice(b); + this->stopDiscovery(); + sportsTechElliptical = new sportstechelliptical(noWriteResistance, noHeartService, bikeResistanceOffset, + bikeResistanceGain); + // stateFileRead(); + emit deviceConnected(b); + connect(sportsTechElliptical, &bluetoothdevice::connectedAndDiscovered, this, + &bluetooth::connectedAndDiscovered); + // connect(echelonConnectSport, SIGNAL(disconnected()), this, SLOT(restart())); + connect(sportsTechElliptical, &sportstechelliptical::debug, this, &bluetooth::debug); + // connect(echelonConnectSport, SIGNAL(speedChanged(double)), this, SLOT(speedChanged(double))); + // connect(echelonConnectSport, SIGNAL(inclinationChanged(double)), this, + // SLOT(inclinationChanged(double))); + sportsTechElliptical->deviceDiscovered(b); + this->signalBluetoothDeviceConnected(sportsTechElliptical); } else if ((b.name().toUpper().startsWith(QStringLiteral("CARDIOFIT")) || (b.name().toUpper().contains(QStringLiteral("CARE")) && b.name().length() == 11)) // CARE9040177 - Carefitness CV-351 @@ -3127,6 +3142,11 @@ void bluetooth::restart() { delete sportsTechBike; sportsTechBike = nullptr; } + if (sportsTechElliptical) { + + delete sportstechElliptical; + sportstechElliptical = nullptr; + } if (sportsPlusBike) { delete sportsPlusBike; @@ -3428,6 +3448,8 @@ bluetoothdevice *bluetooth::device() { return schwinn170Bike; } else if (sportsTechBike) { return sportsTechBike; + } else if (sportsTechElliptical) { + return sportsTechElliptical; } else if (sportsPlusBike) { return sportsPlusBike; } else if (inspireBike) { diff --git a/src/devices/bluetooth.h b/src/devices/bluetooth.h index 08196008e..90d58f7b3 100644 --- a/src/devices/bluetooth.h +++ b/src/devices/bluetooth.h @@ -110,6 +110,7 @@ #include "devices/spirittreadmill/spirittreadmill.h" #include "devices/sportsplusbike/sportsplusbike.h" #include "devices/sportstechbike/sportstechbike.h" +#include "devices/sportstechelliptical/sportstechelliptical.h" #include "devices/stagesbike/stagesbike.h" #include "devices/renphobike/renphobike.h" @@ -217,6 +218,7 @@ class bluetooth : public QObject, public SignalHandler { horizongr7bike *horizonGr7Bike = nullptr; schwinnic4bike *schwinnIC4Bike = nullptr; sportstechbike *sportsTechBike = nullptr; + sportstechelliptical *sportsTechElliptical = nullptr; sportsplusbike *sportsPlusBike = nullptr; inspirebike *inspireBike = nullptr; snodebike *snodeBike = nullptr; diff --git a/src/devices/bluetoothdevice.h b/src/devices/bluetoothdevice.h index ab4fd40cf..afba22a76 100644 --- a/src/devices/bluetoothdevice.h +++ b/src/devices/bluetoothdevice.h @@ -534,6 +534,9 @@ class bluetoothdevice : public QObject { int64_t lastStart = 0; int64_t lastStop = 0; + metric RequestedPower; + int16_t requestPower = -1; + /** * @brief m_difficult The current difficulty gain. Units: device dependent */ diff --git a/src/devices/elliptical.cpp b/src/devices/elliptical.cpp index 05299df7c..32aaff779 100644 --- a/src/devices/elliptical.cpp +++ b/src/devices/elliptical.cpp @@ -38,6 +38,40 @@ void elliptical::update_metrics(bool watt_calc, const double watts) { _firstUpdate = false; } +resistance_t elliptical::resistanceFromPowerRequest(uint16_t power) { return power / 10; } // in order to have something + +void elliptical::changePower(int32_t power) { + + RequestedPower = power; // in order to paint in any case the request power on the charts + + if (!autoResistanceEnable) { + qDebug() << QStringLiteral("changePower ignored because auto resistance is disabled"); + return; + } + + requestPower = power; // used by some bikes that have ERG mode builtin + QSettings settings; + bool force_resistance = + settings.value(QZSettings::virtualbike_forceresistance, QZSettings::default_virtualbike_forceresistance) + .toBool(); + // bool erg_mode = settings.value(QZSettings::zwift_erg, QZSettings::default_zwift_erg).toBool(); //Not used + // anywhere in code + double erg_filter_upper = + settings.value(QZSettings::zwift_erg_filter, QZSettings::default_zwift_erg_filter).toDouble(); + double erg_filter_lower = + settings.value(QZSettings::zwift_erg_filter_down, QZSettings::default_zwift_erg_filter_down).toDouble(); + double deltaDown = wattsMetric().value() - ((double)power); + double deltaUp = ((double)power) - wattsMetric().value(); + qDebug() << QStringLiteral("filter ") + QString::number(deltaUp) + " " + QString::number(deltaDown) + " " + + QString::number(erg_filter_upper) + " " + QString::number(erg_filter_lower); + if (/*!ergModeSupported &&*/ force_resistance /*&& erg_mode*/ && + (deltaUp > erg_filter_upper || deltaDown > erg_filter_lower)) { + resistance_t r = (resistance_t)resistanceFromPowerRequest(power); + changeResistance(r); // resistance start from 1 + } +} + + uint16_t elliptical::watts() { QSettings settings; diff --git a/src/devices/elliptical.h b/src/devices/elliptical.h index e65dd5723..a90f5bdd0 100644 --- a/src/devices/elliptical.h +++ b/src/devices/elliptical.h @@ -33,12 +33,14 @@ class elliptical : public bluetoothdevice { void setGears(double d); double gears(); virtual double minStepInclination() { return 0.5; } + virtual resistance_t resistanceFromPowerRequest(uint16_t power); public Q_SLOTS: virtual void changeSpeed(double speed); void changeResistance(resistance_t res) override; void changeInclination(double grade, double inclination) override; virtual void changeCadence(int16_t cad); + void changePower(int32_t power) override; virtual void changeRequestedPelotonResistance(int8_t resistance); signals: diff --git a/src/devices/rower.h b/src/devices/rower.h index 048bee07e..e65655b4c 100644 --- a/src/devices/rower.h +++ b/src/devices/rower.h @@ -59,7 +59,6 @@ class rower : public bluetoothdevice { metric RequestedPelotonResistance; double requestInclination = -100; metric RequestedCadence; - metric RequestedPower; metric RequestedSpeed; volatile double requestSpeed = -1; metric StrokesLength; diff --git a/src/devices/sportstechelliptical/sportstechelliptical.cpp b/src/devices/sportstechelliptical/sportstechelliptical.cpp new file mode 100644 index 000000000..a0c37ff1f --- /dev/null +++ b/src/devices/sportstechelliptical/sportstechelliptical.cpp @@ -0,0 +1,454 @@ +#include "sportstechelliptical.h" +#ifdef Q_OS_ANDROID +#include "keepawakehelper.h" +#endif +#include "virtualdevices/virtualtreadmill.h".h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::chrono_literals; + +sportstechelliptical::sportstechelliptical(bool noWriteResistance, bool noHeartService, int8_t ellipticalResistanceOffset, + double ellipticalResistanceGain) { + m_watt.setType(metric::METRIC_WATT); + Speed.setType(metric::METRIC_SPEED); + refresh = new QTimer(this); + this->noWriteResistance = noWriteResistance; + this->noHeartService = noHeartService; + this->ellipticalResistanceGain = ellipticalResistanceGain; + this->ellipticalResistanceOffset = ellipticalResistanceOffset; + initDone = false; + connect(refresh, &QTimer::timeout, this, &sportstechelliptical::update); + refresh->start(200ms); +} + +void sportstechelliptical::writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log, + bool wait_for_response) { + QEventLoop loop; + QTimer timeout; + + if (wait_for_response) { + connect(this, &sportstechelliptical::packetReceived, &loop, &QEventLoop::quit); + timeout.singleShot(300ms, &loop, &QEventLoop::quit); + } else { + connect(gattCommunicationChannelService, &QLowEnergyService::characteristicWritten, &loop, &QEventLoop::quit); + timeout.singleShot(300ms, &loop, &QEventLoop::quit); + } + + if (writeBuffer) { + delete writeBuffer; + } + writeBuffer = new QByteArray((const char *)data, data_len); + + gattCommunicationChannelService->writeCharacteristic(gattWriteCharacteristic, *writeBuffer); + + if (!disable_log) { + emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') + " // " + info); + } + + loop.exec(); + + if (timeout.isActive() == false) { + emit debug(QStringLiteral(" exit for timeout")); + } +} + +void sportstechelliptical::forceResistance(resistance_t requestResistance) { + Q_UNUSED(requestResistance) + /* + uint8_t resistance[] = { 0xf0, 0xa6, 0x01, 0x01, 0x00, 0x00 }; + resistance[4] = requestResistance + 1; + for(uint8_t i=0; istate() << gattCommunicationChannelService << + // gattWriteCharacteristic.isValid() << gattNotifyCharacteristic.isValid() << initDone; + + if (!m_control) { + return; + } + + if (m_control->state() == QLowEnergyController::UnconnectedState) { + emit disconnected(); + return; + } + + if (initRequest) { + initRequest = false; + btinit(false); + } else if (bluetoothDevice.isValid() && m_control->state() == QLowEnergyController::DiscoveredState && + gattCommunicationChannelService && gattWriteCharacteristic.isValid() && + gattNotify1Characteristic.isValid() && initDone) { + update_metrics(false, 0); + + // updating the elliptical console every second + if (sec1update++ == (1000 / refresh->interval())) { + sec1update = 0; + // updateDisplay(elapsed); + } + + QSettings settings; + uint8_t noOpData[] = {0xf2, 0xc3, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbe}; + if (requestResistance < 0) { + requestResistance = 0; + } + if (requestResistance > 23) { + requestResistance = 23; + } + noOpData[4] = requestResistance; + noOpData[10] += requestResistance; + writeCharacteristic((uint8_t *)noOpData, sizeof(noOpData), QStringLiteral("noOp"), false, true); + } +} + +void sportstechelliptical::serviceDiscovered(const QBluetoothUuid &gatt) { + emit debug(QStringLiteral("serviceDiscovered ") + gatt.toString()); +} + +void sportstechelliptical::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) { + QDateTime now = QDateTime::currentDateTime(); + // qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length(); + Q_UNUSED(characteristic); + QSettings settings; + QString heartRateBeltName = + settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString(); + emit packetReceived(); + + emit debug(QStringLiteral(" << ") + newValue.toHex(' ')); + + lastPacket = newValue; + if (newValue.length() != 20) { + return; + } + + double speed = GetSpeedFromPacket(newValue); + double cadence = GetCadenceFromPacket(newValue); + double resistance = GetResistanceFromPacket(newValue); + double kcal = GetKcalFromPacket(newValue); + double watt = GetWattFromPacket(newValue); + bool disable_hr_frommachinery = + settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool(); + +#ifdef Q_OS_ANDROID + if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) + Heart = (uint8_t)KeepAwakeHelper::heart(); + else +#endif + { + if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) { + + uint8_t heart = ((uint8_t)newValue.at(11)); + if (heart == 0 || disable_hr_frommachinery) { + update_hr_from_external(); + } else { + Heart = heart; + } + } + } + + if (!firstCharChanged) { + Distance += ((speed / 3600.0) / (1000.0 / (lastTimeCharChanged.msecsTo(QTime::currentTime())))); + } + + emit debug(QStringLiteral("Current speed: ") + QString::number(speed)); + emit debug(QStringLiteral("Current cadence: ") + QString::number(cadence)); + emit debug(QStringLiteral("Current resistance: ") + QString::number(resistance)); + emit debug(QStringLiteral("Current heart: ") + QString::number(Heart.value())); + emit debug(QStringLiteral("Current KCal: ") + QString::number(kcal)); + emit debug(QStringLiteral("Current watt: ") + QString::number(watt)); + emit debug(QStringLiteral("Current Elapsed from the elliptical (not used): ") + + QString::number(GetElapsedFromPacket(newValue))); + emit debug(QStringLiteral("Current Distance Calculated: ") + QString::number(Distance.value())); + + if (m_control->error() != QLowEnergyController::NoError) { + qDebug() << QStringLiteral("QLowEnergyController ERROR!!") << m_control->errorString(); + } + + Speed = speed; + Resistance = requestResistance; + KCal = kcal; + if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name) + .toString() + .startsWith(QStringLiteral("Disabled"))) { + Cadence = cadence; + } + if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name) + .toString() + .startsWith(QStringLiteral("Disabled"))) + m_watt = watt; + + lastTimeCharChanged = QTime::currentTime(); + firstCharChanged = false; +} + +uint16_t sportstechelliptical::GetElapsedFromPacket(const QByteArray &packet) { + uint16_t convertedDataSec = (packet.at(4)); + uint16_t convertedDataMin = (packet.at(3)); + uint16_t convertedData = convertedDataMin * 60.f + convertedDataSec; + return convertedData; +} + +double sportstechelliptical::GetSpeedFromPacket(const QByteArray &packet) { + uint16_t convertedData = (packet.at(12) << 8) | ((uint8_t)packet.at(13)); + double data = (double)(convertedData) / 10.0f; + return data; +} + +double sportstechelliptical::GetKcalFromPacket(const QByteArray &packet) { + uint16_t convertedData = (packet.at(7) << 8) | ((uint8_t)packet.at(8)); + return (double)(convertedData); +} + +double sportstechelliptical::GetWattFromPacket(const QByteArray &packet) { + uint16_t convertedData = (packet.at(9) << 8) | ((uint8_t)packet.at(10)); + double data = ((double)(convertedData)); + return data; +} + +double sportstechelliptical::GetCadenceFromPacket(const QByteArray &packet) { + uint16_t convertedData = packet.at(17); + double data = (convertedData); + if (data < 0) { + return 0; + } + return data; +} + +double sportstechelliptical::GetResistanceFromPacket(const QByteArray &packet) { + uint16_t convertedData = packet.at(15); + double data = (convertedData); + if (data < 0) { + return 0; + } + return data; +} + +void sportstechelliptical::btinit(bool startTape) { + Q_UNUSED(startTape); + QSettings settings; + + const uint8_t initData1[] = {0xf2, 0xc0, 0x00, 0xb2}; + const uint8_t initData2[] = {0xf2, 0xc1, 0x05, 0x01, 0xff, 0xff, 0xff, 0xff, 0xb5}; + const uint8_t initData3[] = {0xf2, 0xc4, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0}; + const uint8_t initData4[] = {0xf2, 0xc3, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbb}; + + writeCharacteristic((uint8_t *)initData1, sizeof(initData1), QStringLiteral("init"), false, true); + writeCharacteristic((uint8_t *)initData2, sizeof(initData2), QStringLiteral("init"), false, true); + writeCharacteristic((uint8_t *)initData3, sizeof(initData3), QStringLiteral("init"), false, true); + writeCharacteristic((uint8_t *)initData4, sizeof(initData4), QStringLiteral("init"), false, true); + + initDone = true; +} + +void sportstechelliptical::stateChanged(QLowEnergyService::ServiceState state) { + QMetaEnum metaEnum = QMetaEnum::fromType(); + emit debug(QStringLiteral("BTLE stateChanged ") + QString::fromLocal8Bit(metaEnum.valueToKey(state))); + + if (state == QLowEnergyService::ServiceDiscovered) { + auto characteristics_list = gattCommunicationChannelService->characteristics(); + for (const QLowEnergyCharacteristic &c : qAsConst(characteristics_list)) { + emit debug(QStringLiteral("characteristic ") + c.uuid().toString()); + } + + // QString uuidWrite = "0000fff2-0000-1000-8000-00805f9b34fb"; + // QString uuidNotify1 = "0000fff1-0000-1000-8000-00805f9b34fb"; + + QBluetoothUuid _gattWriteCharacteristicId(QStringLiteral("0000fff2-0000-1000-8000-00805f9b34fb")); + QBluetoothUuid _gattNotify1CharacteristicId(QStringLiteral("0000fff1-0000-1000-8000-00805f9b34fb")); + + gattWriteCharacteristic = gattCommunicationChannelService->characteristic(_gattWriteCharacteristicId); + gattNotify1Characteristic = gattCommunicationChannelService->characteristic(_gattNotify1CharacteristicId); + Q_ASSERT(gattWriteCharacteristic.isValid()); + Q_ASSERT(gattNotify1Characteristic.isValid()); + + // establish hook into notifications + connect(gattCommunicationChannelService, &QLowEnergyService::characteristicChanged, this, + &sportstechelliptical::characteristicChanged); + connect(gattCommunicationChannelService, &QLowEnergyService::characteristicWritten, this, + &sportstechelliptical::characteristicWritten); + connect(gattCommunicationChannelService, + static_cast(&QLowEnergyService::error), + this, &sportstechelliptical::errorService); + connect(gattCommunicationChannelService, &QLowEnergyService::descriptorWritten, this, + &sportstechelliptical::descriptorWritten); + + // ******************************************* virtual elliptical init ************************************* + if (!firstVirtualelliptical && !this->hasVirtualDevice()) { + QSettings settings; + bool virtual_device_enabled = + settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool(); + if (virtual_device_enabled) { + emit debug(QStringLiteral("creating virtual elliptical interface...")); + auto virtualTreadmill = new virtualtreadmill(this, noHeartService); + // connect(virtualelliptical,&virtualelliptical::debug ,this,&sportstechelliptical::debug); + connect(virtualTreadmill, &virtualtreadmill::changeInclination, this, &sportstechelliptical::changeInclination); + this->setVirtualDevice(virtualTreadmill, VIRTUAL_DEVICE_MODE::PRIMARY); + } + } + firstVirtualelliptical = 1; + // ******************************************************************************************************** + + QByteArray descriptor; + descriptor.append((char)0x01); + descriptor.append((char)0x00); + gattCommunicationChannelService->writeDescriptor( + gattNotify1Characteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), descriptor); + } +} + +void sportstechelliptical::descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue) { + emit debug(QStringLiteral("descriptorWritten ") + descriptor.name() + QStringLiteral(" ") + newValue.toHex(' ')); + + initRequest = true; + emit connectedAndDiscovered(); +} + +void sportstechelliptical::characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) { + Q_UNUSED(characteristic); + emit debug(QStringLiteral("characteristicWritten ") + newValue.toHex(' ')); +} + +void sportstechelliptical::serviceScanDone(void) { + emit debug(QStringLiteral("serviceScanDone")); + + // QString uuid = "0000fff0-0000-1000-8000-00805f9b34fb"; + + QBluetoothUuid _gattCommunicationChannelServiceId(QStringLiteral("0000fff0-0000-1000-8000-00805f9b34fb")); + gattCommunicationChannelService = m_control->createServiceObject(_gattCommunicationChannelServiceId); + + if (gattCommunicationChannelService == nullptr) { + qDebug() << QStringLiteral("invalid service") << _gattCommunicationChannelServiceId.toString(); + return; + } + + connect(gattCommunicationChannelService, &QLowEnergyService::stateChanged, this, &sportstechelliptical::stateChanged); + gattCommunicationChannelService->discoverDetails(); +} + +void sportstechelliptical::errorService(QLowEnergyService::ServiceError err) { + QMetaEnum metaEnum = QMetaEnum::fromType(); + emit debug(QStringLiteral("sportstechelliptical::errorService") + QString::fromLocal8Bit(metaEnum.valueToKey(err)) + + m_control->errorString()); +} + +void sportstechelliptical::error(QLowEnergyController::Error err) { + QMetaEnum metaEnum = QMetaEnum::fromType(); + emit debug(QStringLiteral("sportstechelliptical::error") + QString::fromLocal8Bit(metaEnum.valueToKey(err)) + + m_control->errorString()); +} + +void sportstechelliptical::deviceDiscovered(const QBluetoothDeviceInfo &device) { + emit debug(QStringLiteral("Found new device: ") + device.name() + QStringLiteral(" (") + + device.address().toString() + ')'); + { + bluetoothDevice = device; + m_control = QLowEnergyController::createCentral(bluetoothDevice, this); + connect(m_control, &QLowEnergyController::serviceDiscovered, this, &sportstechelliptical::serviceDiscovered); + connect(m_control, &QLowEnergyController::discoveryFinished, this, &sportstechelliptical::serviceScanDone); + connect(m_control, + static_cast(&QLowEnergyController::error), + this, &sportstechelliptical::error); + connect(m_control, &QLowEnergyController::stateChanged, this, &sportstechelliptical::controllerStateChanged); + + connect(m_control, + static_cast(&QLowEnergyController::error), + this, [this](QLowEnergyController::Error error) { + Q_UNUSED(error); + Q_UNUSED(this); + emit debug(QStringLiteral("Cannot connect to remote device.")); + emit disconnected(); + }); + connect(m_control, &QLowEnergyController::connected, this, [this]() { + Q_UNUSED(this); + emit debug(QStringLiteral("Controller connected. Search services...")); + m_control->discoverServices(); + }); + connect(m_control, &QLowEnergyController::disconnected, this, [this]() { + Q_UNUSED(this); + emit debug(QStringLiteral("LowEnergy controller disconnected")); + emit disconnected(); + }); + + // Connect + m_control->connectToDevice(); + return; + } +} + +uint16_t sportstechelliptical::watts() { + if (currentCadence().value() == 0) { + return 0; + } + + return m_watt.value(); +} + +bool sportstechelliptical::connected() { + if (!m_control) { + return false; + } + return m_control->state() == QLowEnergyController::DiscoveredState; +} + +void sportstechelliptical::controllerStateChanged(QLowEnergyController::ControllerState state) { + qDebug() << QStringLiteral("controllerStateChanged") << state; + if (state == QLowEnergyController::UnconnectedState && m_control) { + qDebug() << QStringLiteral("trying to connect back again..."); + initDone = false; + m_control->connectToDevice(); + } +} + +uint16_t sportstechelliptical::wattsFromResistance(double resistance) { + // Coefficients from the polynomial regression + double intercept = 14.4968; + double b1 = -4.1878; + double b2 = -0.5051; + double b3 = 0.00387; + double b4 = 0.2392; + double b5 = 0.01108; + double cadence = Cadence.value(); + + // Calculate power using the polynomial equation + double power = intercept + + (b1 * resistance) + + (b2 * cadence) + + (b3 * resistance * resistance) + + (b4 * resistance * cadence) + + (b5 * cadence * cadence); + + return power; +} + +resistance_t sportstechelliptical::resistanceFromPowerRequest(uint16_t power) { + qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); + + if (Cadence.value() == 0) + return 1; + + for (resistance_t i = 1; i < maxResistance(); i++) { + if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { + qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) + << wattsFromResistance(i + 1) << power; + return i; + } + } + if (power < wattsFromResistance(1)) + return 1; + else + return maxResistance(); +} diff --git a/src/devices/sportstechelliptical/sportstechelliptical.h b/src/devices/sportstechelliptical/sportstechelliptical.h new file mode 100644 index 000000000..1c6e4128e --- /dev/null +++ b/src/devices/sportstechelliptical/sportstechelliptical.h @@ -0,0 +1,100 @@ +#ifndef SPORTSTECHelliptical_H +#define SPORTSTECHelliptical_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef Q_OS_ANDROID +#include +#else +#include +#endif +#include +#include +#include +#include + +#include +#include + +#include "devices/elliptical.h" + +class sportstechelliptical : public elliptical { + Q_OBJECT + public: + sportstechelliptical(bool noWriteResistance, bool noHeartService, int8_t ellipticalResistanceOffset, + double ellipticalResistanceGain); + bool connected() override; + resistance_t maxResistance() override { return 24; } + resistance_t resistanceFromPowerRequest(uint16_t power) override; + + private: + double GetSpeedFromPacket(const QByteArray &packet); + double GetResistanceFromPacket(const QByteArray &packet); + double GetKcalFromPacket(const QByteArray &packet); + double GetDistanceFromPacket(QByteArray packet); + uint16_t GetElapsedFromPacket(const QByteArray &packet); + uint16_t wattsFromResistance(double resistance); + void forceResistance(resistance_t requestResistance); + void updateDisplay(uint16_t elapsed); + void btinit(bool startTape); + void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log, + bool wait_for_response); + void startDiscover(); + uint16_t watts() override; + double GetWattFromPacket(const QByteArray &packet); + double GetCadenceFromPacket(const QByteArray &packet); + + QTimer *refresh; + + bool noWriteResistance = false; + bool noHeartService = false; + int8_t ellipticalResistanceOffset = 4; + double ellipticalResistanceGain = 1.0; + + uint8_t firstVirtualelliptical = 0; + bool firstCharChanged = true; + QTime lastTimeCharChanged; + uint8_t sec1update = 0; + QByteArray lastPacket; + + QLowEnergyService *gattCommunicationChannelService = nullptr; + QLowEnergyCharacteristic gattWriteCharacteristic; + QLowEnergyCharacteristic gattNotify1Characteristic; + + bool initDone = false; + bool initRequest = false; + bool readyToStart = false; + + signals: + void disconnected(); + void debug(QString string); + void packetReceived(); + + public slots: + void deviceDiscovered(const QBluetoothDeviceInfo &device); + + private slots: + + void characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue); + void characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue); + void descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue); + void stateChanged(QLowEnergyService::ServiceState state); + void controllerStateChanged(QLowEnergyController::ControllerState state); + + void serviceDiscovered(const QBluetoothUuid &gatt); + void serviceScanDone(void); + void update(); + void error(QLowEnergyController::Error err); + void errorService(QLowEnergyService::ServiceError); +}; + +#endif // SPORTSTECHelliptical_H diff --git a/src/devices/treadmill.h b/src/devices/treadmill.h index 29aa39cd2..d5dd17af5 100644 --- a/src/devices/treadmill.h +++ b/src/devices/treadmill.h @@ -80,8 +80,6 @@ class treadmill : public bluetoothdevice { double m_lastRawSpeedRequested = -1; double m_lastRawInclinationRequested = -100; bool instantaneousStrideLengthCMAvailableFromDevice = false; - metric RequestedPower; - int16_t requestPower = -1; treadmillErgTable _ergTable; void parseSpeed(double speed); diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index a3fbbf88e..73d604ece 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -80,6 +80,7 @@ SOURCES += \ $$PWD/devices/focustreadmill/focustreadmill.cpp \ $$PWD/devices/jumprope.cpp \ $$PWD/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.cpp \ + $$PWD/devices/sportstechelliptical/sportstechelliptical.cpp \ $$PWD/devices/trxappgateusbelliptical/trxappgateusbelliptical.cpp \ QTelnet.cpp \ devices/bkoolbike/bkoolbike.cpp \ @@ -305,6 +306,7 @@ HEADERS += \ $$PWD/devices/focustreadmill/focustreadmill.h \ $$PWD/devices/jumprope.h \ $$PWD/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.h \ + $$PWD/devices/sportstechelliptical/sportstechelliptical.h \ $$PWD/devices/trxappgateusbelliptical/trxappgateusbelliptical.h \ $$PWD/ergtable.h \ $$PWD/treadmillErgTable.h \ From e1748022f270de852e3c68f6df7779b9abaabf2d Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 16 Sep 2024 10:08:33 +0200 Subject: [PATCH 103/162] Update bluetooth.cpp --- src/devices/bluetooth.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 7dec9fa02..4a7b114d4 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -3144,8 +3144,8 @@ void bluetooth::restart() { } if (sportsTechElliptical) { - delete sportstechElliptical; - sportstechElliptical = nullptr; + delete sportsTechElliptical; + sportsTechElliptical = nullptr; } if (sportsPlusBike) { From 1bf4c33a7a622ef6bd3e87c383abde21c4f58a26 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 16 Sep 2024 14:46:39 +0200 Subject: [PATCH 104/162] adding gear offset --- src/devices/bike.cpp | 5 ++++- src/qzsettings.cpp | 4 +++- src/qzsettings.h | 3 +++ src/settings.qml | 41 +++++++++++++++++++++++++++++++++++++++-- 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index bfb584dd5..d4a0e58f9 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -86,17 +86,20 @@ void bike::changePower(int32_t power) { double bike::gears() { QSettings settings; bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + double gears_offset = settings.value(QZSettings::gears_offset, QZSettings::default_gears_offset).toDouble(); if(gears_zwift_ratio) { if(m_gears < 1) return 1.0; else if(m_gears > 24) return 24.0; } - return m_gears; + return m_gears + gears_offset; } void bike::setGears(double gears) { QSettings settings; bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + double gears_offset = settings.value(QZSettings::gears_offset, QZSettings::default_gears_offset).toDouble(); + gears -= gears_offset; qDebug() << "setGears" << gears; if(gears_zwift_ratio && (gears > 24 || gears < 1)) { qDebug() << "new gear value ignored because of gears_zwift_ratio setting!"; diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index d48405d86..e9ca46a4a 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -761,8 +761,9 @@ const QString QZSettings::domyostreadmill_notfmts = QStringLiteral("domyostreadm const QString QZSettings::zwiftplay_swap = QStringLiteral("zwiftplay_swap"); const QString QZSettings::gears_zwift_ratio = QStringLiteral("gears_zwift_ratio"); const QString QZSettings::domyos_bike_500_profile_v2 = QStringLiteral("domyos_bike_500_profile_v2"); +const QString QZSettings::gears_offset = QStringLiteral("gears_offset"); -const uint32_t allSettingsCount = 644; +const uint32_t allSettingsCount = 645; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1413,6 +1414,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::zwiftplay_swap, QZSettings::default_zwiftplay_swap}, {QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio}, {QZSettings::domyos_bike_500_profile_v2, QZSettings::default_domyos_bike_500_profile_v2}, + {QZSettings::gears_offset, QZSettings::default_gears_offset}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index a242e8fe2..e5e098c3d 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2132,6 +2132,9 @@ class QZSettings { static const QString domyos_bike_500_profile_v2; static constexpr bool default_domyos_bike_500_profile_v2 = false; + static const QString gears_offset; + static constexpr double default_gears_offset = 0.0; + /** * @brief Write the QSettings values using the constants from this namespace. * @param showDefaults Optionally indicates if the default should be shown with the key. diff --git a/src/settings.qml b/src/settings.qml index 41ff4f3c9..d09724e59 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -976,6 +976,7 @@ import QtQuick.Dialogs 1.0 property bool zwiftplay_swap: false property bool gears_zwift_ratio: false property bool domyos_bike_500_profile_v2: false + property double gears_offset: 0.0 } function paddingZeros(text, limit) { @@ -2368,7 +2369,43 @@ import QtQuick.Dialogs 1.0 } Label { - text: qsTr("Applies a multiplier to the gears tile. Default is 1.") + text: qsTr("Applies a multiplier to the gears. Default is 1.") + 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 { + text: qsTr("Gears Offset:") + Layout.fillWidth: true + } + TextField { + id: gearsOffsetTextField + text: settings.gears_offset + horizontalAlignment: Text.AlignRight + Layout.fillHeight: false + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + //inputMethodHints: Qt.ImhFormattedNumbersOnly + onAccepted: settings.gears_offset = text + onActiveFocusChanged: if(this.focus) this.cursorPosition = this.text.length + } + Button { + text: "OK" + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + onClicked: { settings.gears_offset = gearsOffsetTextField.text; toast.show("Setting saved!"); } + } + } + + Label { + text: qsTr("Applies an offset to the gears. Default is 0.") font.bold: true font.italic: true font.pixelSize: Qt.application.font.pixelSize - 2 @@ -9627,7 +9664,7 @@ import QtQuick.Dialogs 1.0 } SwitchDelegate { - text: qsTr("Use Zwift app ratio for gears") + text: qsTr("Use Zwift app ratio for gears (Experimental)") spacing: 0 bottomPadding: 0 topPadding: 0 From a3252bd47da107d13778d04243a760c37bc4b647 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 16 Sep 2024 14:57:14 +0200 Subject: [PATCH 105/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index a85afacfc..2df647516 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -358,6 +358,8 @@ 8772A0E825E43AE70080718C /* moc_trxappgateusbbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8772A0E725E43AE70080718C /* moc_trxappgateusbbike.cpp */; }; 8775008329E876F8008E48B7 /* iconceptelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8775008129E876F7008E48B7 /* iconceptelliptical.cpp */; }; 8775008529E87713008E48B7 /* moc_iconceptelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8775008429E87712008E48B7 /* moc_iconceptelliptical.cpp */; }; + 877758B32C98627300BB1697 /* moc_sportstechelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 877758B22C98627300BB1697 /* moc_sportstechelliptical.cpp */; }; + 877758B62C98629B00BB1697 /* sportstechelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 877758B52C98629B00BB1697 /* sportstechelliptical.cpp */; }; 877A080D2893DC4300C0F0AB /* CoreVideo.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 879F74122893D705009A64C8 /* CoreVideo.framework */; }; 877A7609269D8E9F0024DD2C /* WebKit.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 877A7608269D8E9F0024DD2C /* WebKit.framework */; }; 877FBA29276E684500F6C0C9 /* bowflextreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 877FBA27276E684400F6C0C9 /* bowflextreadmill.cpp */; }; @@ -1235,6 +1237,9 @@ 8775008129E876F7008E48B7 /* iconceptelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = iconceptelliptical.cpp; path = ../src/devices/iconceptelliptical/iconceptelliptical.cpp; sourceTree = ""; }; 8775008229E876F7008E48B7 /* iconceptelliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iconceptelliptical.h; path = ../src/devices/iconceptelliptical/iconceptelliptical.h; sourceTree = ""; }; 8775008429E87712008E48B7 /* moc_iconceptelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_iconceptelliptical.cpp; sourceTree = ""; }; + 877758B22C98627300BB1697 /* moc_sportstechelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_sportstechelliptical.cpp; sourceTree = ""; }; + 877758B42C98629B00BB1697 /* sportstechelliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sportstechelliptical.h; path = ../src/devices/sportstechelliptical/sportstechelliptical.h; sourceTree = ""; }; + 877758B52C98629B00BB1697 /* sportstechelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sportstechelliptical.cpp; path = ../src/devices/sportstechelliptical/sportstechelliptical.cpp; sourceTree = ""; }; 877A7606269D8E0F0024DD2C /* libqtwebview_darwin_debug.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libqtwebview_darwin_debug.a; path = ../../Qt/5.15.2/ios/plugins/webview/libqtwebview_darwin_debug.a; sourceTree = ""; }; 877A7608269D8E9F0024DD2C /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 877FBA27276E684400F6C0C9 /* bowflextreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bowflextreadmill.cpp; path = ../src/devices/bowflextreadmill/bowflextreadmill.cpp; sourceTree = ""; }; @@ -2068,6 +2073,9 @@ 2EB56BE3C2D93CDAB0C52E67 /* Sources */ = { isa = PBXGroup; children = ( + 877758B52C98629B00BB1697 /* sportstechelliptical.cpp */, + 877758B42C98629B00BB1697 /* sportstechelliptical.h */, + 877758B22C98627300BB1697 /* moc_sportstechelliptical.cpp */, 8715A3E82C75E6DB009BAC05 /* antbike.cpp */, 8715A3E92C75E6DB009BAC05 /* antbike.h */, 8715A3E62C75E6C9009BAC05 /* moc_antbike.cpp */, @@ -3513,6 +3521,7 @@ 87C5F0C026285E5F0067A1B5 /* mimepart.cpp in Compile Sources */, 47E45EE0BB22C1E4332F1D1D /* trxappgateusbtreadmill.cpp in Compile Sources */, 873824BB27E64707004F1B46 /* moc_prober_p.cpp in Compile Sources */, + 877758B32C98627300BB1697 /* moc_sportstechelliptical.cpp in Compile Sources */, 8742C2B227C92C30007D3FA0 /* wahookickrsnapbike.cpp in Compile Sources */, 87EB918327EE5FE7002535E1 /* moc_inappstore.cpp in Compile Sources */, 87CF516B293C87B000A7CABC /* moc_characteristicwriteprocessore005.cpp in Compile Sources */, @@ -3623,6 +3632,7 @@ 87DA8467284933DE00B550E9 /* moc_fakeelliptical.cpp in Compile Sources */, 87C5F0D726285E7E0067A1B5 /* moc_mimefile.cpp in Compile Sources */, 877FBA29276E684500F6C0C9 /* bowflextreadmill.cpp in Compile Sources */, + 877758B62C98629B00BB1697 /* sportstechelliptical.cpp in Compile Sources */, 8762D5102601F7EA00F6F049 /* M3iNSQT.cpp in Compile Sources */, 872261EE289EA873006A6F75 /* nordictrackelliptical.cpp in Compile Sources */, 8718CBA3263063BD004BF4EE /* templateinfosender.cpp in Compile Sources */, @@ -4046,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 865; + CURRENT_PROJECT_VERSION = 866; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4237,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 865; + CURRENT_PROJECT_VERSION = 866; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4464,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 865; + CURRENT_PROJECT_VERSION = 866; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4560,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 865; + CURRENT_PROJECT_VERSION = 866; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4652,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 865; + CURRENT_PROJECT_VERSION = 866; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4766,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 865; + CURRENT_PROJECT_VERSION = 866; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 5b3e089b40b61f1d44a45777c6367ade5b028b93 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 16 Sep 2024 16:29:20 +0200 Subject: [PATCH 106/162] trying to implement zwift gear changes directly --- src/devices/ftmsbike/ftmsbike.cpp | 179 +++++++++++++++++++++++++++++- src/devices/ftmsbike/ftmsbike.h | 5 + 2 files changed, 181 insertions(+), 3 deletions(-) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 723cc6639..44a645f43 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -36,6 +36,43 @@ ftmsbike::ftmsbike(bool noWriteResistance, bool noHeartService, int8_t bikeResis refresh->start(200ms); } +void ftmsbike::writeCharacteristicZwiftPlay(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log, + bool wait_for_response) { + QEventLoop loop; + QTimer timeout; + + if(!zwiftPlayService) { + qDebug() << QStringLiteral("zwiftPlayService is null!"); + return; + } + + if (wait_for_response) { + connect(zwiftPlayService, &QLowEnergyService::characteristicChanged, &loop, &QEventLoop::quit); + timeout.singleShot(300ms, &loop, &QEventLoop::quit); + } else { + connect(zwiftPlayService, &QLowEnergyService::characteristicWritten, &loop, &QEventLoop::quit); + timeout.singleShot(300ms, &loop, &QEventLoop::quit); + } + + if (writeBuffer) { + delete writeBuffer; + } + writeBuffer = new QByteArray((const char *)data, data_len); + + if (zwiftPlayWriteChar.properties() & QLowEnergyCharacteristic::WriteNoResponse) { + zwiftPlayService->writeCharacteristic(zwiftPlayWriteChar, *writeBuffer, + QLowEnergyService::WriteWithoutResponse); + } else { + zwiftPlayService->writeCharacteristic(zwiftPlayWriteChar, *writeBuffer); + } + + if (!disable_log) { + emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') + QStringLiteral(" // ") + info); + } + + loop.exec(); +} + void ftmsbike::writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log, bool wait_for_response) { QEventLoop loop; @@ -82,6 +119,46 @@ void ftmsbike::init() { write[0] = {FTMS_START_RESUME}; writeCharacteristic(write, sizeof(write), "start simulation", false, true); + QSettings settings; + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + + if(zwiftPlayService && gears_zwift_ratio) { + uint8_t rideOn[] = {0x52, 0x69, 0x64, 0x65, 0x4f, 0x6e, 0x02, 0x01}; + writeCharacteristicZwiftPlay(rideOn, sizeof(rideOn), "rideOn", false, true); + + uint8_t init1[] = {0x41, 0x08, 0x05}; + writeCharacteristicZwiftPlay(init1, sizeof(init1), "init1", false, true); + + uint8_t init2[] = {0x04, 0x2a, 0x04, 0x10, 0xc0, 0xbb, 0x01}; + writeCharacteristicZwiftPlay(init2, sizeof(init2), "init2", false, true); + + uint8_t init3[] = {0x00, 0x08, 0x00}; + writeCharacteristicZwiftPlay(init3, sizeof(init3), "init3", false, true); + + writeCharacteristicZwiftPlay(init1, sizeof(init1), "init1", false, true); + + uint8_t init4[] = {0x00, 0x08, 0x88, 0x04}; + writeCharacteristicZwiftPlay(init4, sizeof(init4), "init4", false, true); + + uint8_t init5[] = {0x04, 0x2a, 0x0a, 0x10, 0xc0, 0xbb, 0x01, 0x20, 0xbf, 0x06, 0x28, 0xb4, 0x42}; + writeCharacteristicZwiftPlay(init5, sizeof(init5), "init5", false, true); + + uint8_t init6[] = {0x04, 0x22, 0x0b, 0x08, 0x00, 0x10, 0xda, 0x02, 0x18, 0xec, 0x27, 0x20, 0x90, 0x03}; + writeCharacteristicZwiftPlay(init6, sizeof(init6), "init6", false, true); + + writeCharacteristicZwiftPlay(init2, sizeof(init2), "init2", false, true); + writeCharacteristicZwiftPlay(init4, sizeof(init4), "init4", false, true); + + uint8_t init7[] = {0x04, 0x22, 0x03, 0x10, 0xa9, 0x01}; + writeCharacteristicZwiftPlay(init7, sizeof(init7), "init7", false, true); + + writeCharacteristicZwiftPlay(init2, sizeof(init2), "init2", false, true); + writeCharacteristicZwiftPlay(init4, sizeof(init4), "init4", false, true); + + uint8_t init8[] = {0x04, 0x22, 0x02, 0x10, 0x01}; + writeCharacteristicZwiftPlay(init8, sizeof(init8), "init8", false, true); + } + initDone = true; initRequest = false; } @@ -206,6 +283,94 @@ void ftmsbike::update() { ftmsCharacteristicChanged(QLowEnergyCharacteristic(), lastPacketFromFTMS); } + QSettings settings; + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + if(zwiftPlayService && gears_zwift_ratio && lastGearValue != gears()) { + uint8_t gear[] = {0x04, 0x2a, 0x04, 0x10, 0xdc, 0xec, 0x01}; + switch((int)gears()) { + case 1: + gear[4] = 0xf3; gear[5] = 0xac; + break; + case 2: + gear[4] = 0xc8; gear[5] = 0x91; + break; + case 3: + gear[4] = 0x90; gear[5] = 0xfa; + break; + case 4: + gear[4] = 0xd8; gear[5] = 0xe2; + break; + case 5: + gear[4] = 0x9f; gear[5] = 0xcb; + break; + case 6: + gear[4] = 0xdc; gear[5] = 0xb7; + break; + case 7: + gear[4] = 0x98; gear[5] = 0xa4; + break; + case 8: + gear[4] = 0xd4; gear[5] = 0x90; + break; + case 9: + gear[4] = 0x90; gear[5] = 0xfd; + break; + case 10: + gear[4] = 0xdc; gear[5] = 0xec; + break; + case 11: + gear[4] = 0xa8; gear[5] = 0xdc; + break; + case 12: + gear[4] = 0xf3; gear[5] = 0xcb; + break; + case 13: + gear[4] = 0xc0; gear[5] = 0xbb; + break; + case 14: + gear[4] = 0xb8; gear[5] = 0xad; + break; + case 15: + gear[4] = 0xb0; gear[5] = 0x9f; + break; + case 16: + gear[4] = 0xa8; gear[5] = 0x91; + break; + case 17: + gear[4] = 0xa0; gear[5] = 0x83; + break; + case 18: + gear[4] = 0xc0; gear[5] = 0xbb; + break; + case 19: + gear[4] = 0xa2; gear[5] = 0x8b; + break; + case 20: + gear[4] = 0xa4; gear[5] = 0x93; + break; + case 21: + gear[4] = 0xa6; gear[5] = 0x9b; + break; + case 22: + gear[4] = 0xa8; gear[5] = 0xa3; + break; + case 23: + gear[4] = 0xaa; gear[5] = 0xab; + break; + case 24: + gear[4] = 0xac; gear[5] = 0xb3; + break; + default: + // Gestione del caso di default + break; + } + + writeCharacteristicZwiftPlay(gear, sizeof(gear), "gear", false, true); + + uint8_t gearApply[] = {0x00, 0x08, 0x88, 0x04}; + writeCharacteristicZwiftPlay(gearApply, sizeof(gearApply), "gearApply", false, true); + } + lastGearValue = gears(); if (requestPower != -1) { @@ -792,6 +957,13 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) { gattWriteCharControlPointId = c; gattFTMSService = s; } + + QBluetoothUuid _zwiftPlayWriteCharControlPointId(QStringLiteral("00000003-19ca-4651-86e5-fa29dcdd09d1")); + if (c.properties() & QLowEnergyCharacteristic::Write && c.uuid() == _zwiftPlayWriteCharControlPointId) { + qDebug() << QStringLiteral("Zwift Play service and Control Point found"); + zwiftPlayWriteChar = c; + zwiftPlayService = s; + } } } } @@ -854,18 +1026,19 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact } QByteArray b = newValue; + QSettings settings; + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + if (gattWriteCharControlPointId.isValid()) { qDebug() << "routing FTMS packet to the bike from virtualbike" << characteristic.uuid() << newValue.toHex(' '); // handling gears - if (b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS) { + if (b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS && (zwiftPlayService == nullptr && gears_zwift_ratio)) { lastPacketFromFTMS.clear(); for(int i=0; i Date: Mon, 16 Sep 2024 16:32:03 +0200 Subject: [PATCH 107/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 2df647516..727ab2a74 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 866; + CURRENT_PROJECT_VERSION = 867; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 866; + CURRENT_PROJECT_VERSION = 867; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 866; + CURRENT_PROJECT_VERSION = 867; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 866; + CURRENT_PROJECT_VERSION = 867; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 866; + CURRENT_PROJECT_VERSION = 867; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 866; + CURRENT_PROJECT_VERSION = 867; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 20473f1b31fb443d115aa425d5e4f793fc943bfa Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 16 Sep 2024 17:38:49 +0200 Subject: [PATCH 108/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/devices/ftmsbike/ftmsbike.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 44a645f43..4a9d66833 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -911,7 +911,7 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) { auto characteristics_list = s->characteristics(); for (const QLowEnergyCharacteristic &c : qAsConst(characteristics_list)) { - qDebug() << QStringLiteral("char uuid") << c.uuid() << QStringLiteral("handle") << c.handle(); + qDebug() << QStringLiteral("char uuid") << c.uuid() << QStringLiteral("handle") << c.handle() << c.properties(); auto descriptors_list = c.descriptors(); for (const QLowEnergyDescriptor &d : qAsConst(descriptors_list)) { qDebug() << QStringLiteral("descriptor uuid") << d.uuid() << QStringLiteral("handle") << d.handle(); @@ -959,7 +959,7 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) { } QBluetoothUuid _zwiftPlayWriteCharControlPointId(QStringLiteral("00000003-19ca-4651-86e5-fa29dcdd09d1")); - if (c.properties() & QLowEnergyCharacteristic::Write && c.uuid() == _zwiftPlayWriteCharControlPointId) { + if (c.uuid() == _zwiftPlayWriteCharControlPointId) { qDebug() << QStringLiteral("Zwift Play service and Control Point found"); zwiftPlayWriteChar = c; zwiftPlayService = s; From 7f987c110a328eeac282dbda3978bc4cbf45c62f Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 17 Sep 2024 08:40:40 +0200 Subject: [PATCH 109/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/devices/ftmsbike/ftmsbike.cpp | 9 ++++++--- src/devices/ftmsbike/ftmsbike.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 4a9d66833..701265d45 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -119,6 +119,11 @@ void ftmsbike::init() { write[0] = {FTMS_START_RESUME}; writeCharacteristic(write, sizeof(write), "start simulation", false, true); + initDone = true; + initRequest = false; +} + +void ftmsbike::zwiftPlayInit() { QSettings settings; bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); @@ -158,9 +163,6 @@ void ftmsbike::init() { uint8_t init8[] = {0x04, 0x22, 0x02, 0x10, 0x01}; writeCharacteristicZwiftPlay(init8, sizeof(init8), "init8", false, true); } - - initDone = true; - initRequest = false; } void ftmsbike::forcePower(int16_t requestPower) { @@ -233,6 +235,7 @@ void ftmsbike::update() { } if (initRequest) { + zwiftPlayInit(); initRequest = false; } else if (bluetoothDevice.isValid() && m_control->state() == QLowEnergyController::DiscoveredState //&& diff --git a/src/devices/ftmsbike/ftmsbike.h b/src/devices/ftmsbike/ftmsbike.h index a53120c39..481719388 100644 --- a/src/devices/ftmsbike/ftmsbike.h +++ b/src/devices/ftmsbike/ftmsbike.h @@ -79,6 +79,7 @@ class ftmsbike : public bike { bool wait_for_response = false); void writeCharacteristicZwiftPlay(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, bool wait_for_response = false); + void zwiftPlayInit(); void startDiscover(); uint16_t watts() override; void init(); From b96cc70d514ca5c1f9a4ac5f57933b00bdc0a9f0 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 17 Sep 2024 09:39:59 +0200 Subject: [PATCH 110/162] Elite Aleno Turbo Trainer #2601 --- src/devices/bluetooth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 4a7b114d4..96e98cb11 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1579,6 +1579,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { } else if ((b.name().toUpper().startsWith(QStringLiteral("STAGES ")) || (b.name().toUpper().startsWith("TACX SATORI")) || (b.name().toUpper().startsWith("RACER S")) || + (b.name().toUpper().startsWith("ELITETRAINER")) || ((b.name().toUpper().startsWith("KICKR CORE")) && !deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && deviceHasService(b, QBluetoothUuid((quint16)0x1818))) || (b.name().toUpper().startsWith(QStringLiteral("QD")) && b.name().length() == 2) || (b.name().toUpper().startsWith(QStringLiteral("DFC")) && b.name().length() == 3) || From c96ab6b86a32470487d630826155b52deb243253 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 17 Sep 2024 10:13:47 +0200 Subject: [PATCH 111/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 727ab2a74..d06affc4b 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 867; + CURRENT_PROJECT_VERSION = 869; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 867; + CURRENT_PROJECT_VERSION = 869; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 867; + CURRENT_PROJECT_VERSION = 869; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 867; + CURRENT_PROJECT_VERSION = 869; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 867; + CURRENT_PROJECT_VERSION = 869; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 867; + CURRENT_PROJECT_VERSION = 869; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 5d66c6c513e56c60db54781f3593021b01103fa0 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 17 Sep 2024 13:51:38 +0200 Subject: [PATCH 112/162] Update proformtreadmill.cpp (#2596) --- .../proformtreadmill/proformtreadmill.cpp | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/devices/proformtreadmill/proformtreadmill.cpp b/src/devices/proformtreadmill/proformtreadmill.cpp index f569aaf99..60c57ad79 100644 --- a/src/devices/proformtreadmill/proformtreadmill.cpp +++ b/src/devices/proformtreadmill/proformtreadmill.cpp @@ -1490,22 +1490,6 @@ void proformtreadmill::update() { switch (counterPoll) { case 0: - writeCharacteristic(noOpData1, sizeof(noOpData1), QStringLiteral("noOp")); - break; - case 1: - writeCharacteristic(noOpData2, sizeof(noOpData2), QStringLiteral("noOp")); - break; - case 2: - writeCharacteristic(noOpData3, sizeof(noOpData3), QStringLiteral("noOp")); - break; - case 3: - writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("noOp"), false, true); - break; - case 4: - writeCharacteristic(noOpData5, sizeof(noOpData5), QStringLiteral("noOp")); - break; - case 5: - writeCharacteristic(noOpData6, sizeof(noOpData6), QStringLiteral("noOp"), false, true); if (requestInclination != -100) { if (requestInclination < 0) requestInclination = 0; @@ -1536,6 +1520,22 @@ void proformtreadmill::update() { // writeCharacteristic(initDataF0C800B8, sizeof(initDataF0C800B8), "stop tape"); requestStop = -1; } + writeCharacteristic(noOpData1, sizeof(noOpData1), QStringLiteral("noOp")); + break; + case 1: + writeCharacteristic(noOpData2, sizeof(noOpData2), QStringLiteral("noOp")); + break; + case 2: + writeCharacteristic(noOpData3, sizeof(noOpData3), QStringLiteral("noOp")); + break; + case 3: + writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("noOp"), false, true); + break; + case 4: + writeCharacteristic(noOpData5, sizeof(noOpData5), QStringLiteral("noOp")); + break; + case 5: + writeCharacteristic(noOpData6, sizeof(noOpData6), QStringLiteral("noOp"), false, true); break; } counterPoll++; From 30562f0ed4fc492e5209fb08d78ca16c11d7c786 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 17 Sep 2024 15:33:38 +0200 Subject: [PATCH 113/162] removing ergtable log --- src/ergtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ergtable.h b/src/ergtable.h index c4ebd25d0..b47e0aa78 100644 --- a/src/ergtable.h +++ b/src/ergtable.h @@ -160,7 +160,7 @@ class ergTable : public QObject { uint16_t wattage = fields[1].toUInt(); uint16_t resistance = fields[2].toUInt(); - qDebug() << "inputs.append(ergDataPoint(" << cadence << ", " << wattage << ", "<< resistance << "));"; + //qDebug() << "inputs.append(ergDataPoint(" << cadence << ", " << wattage << ", "<< resistance << "));"; dataTable.append(ergDataPoint(cadence, wattage, resistance)); } From e6b70c03a450161354cda23a49e07c27773bf992 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 17 Sep 2024 15:43:23 +0200 Subject: [PATCH 114/162] Vany Rysel D100 smart trainer #2603 --- src/devices/bluetooth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 96e98cb11..532623100 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1527,6 +1527,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { (b.name().toUpper().startsWith("DU30-")) || // BodyTone du30 (b.name().toUpper().startsWith("BIKZU_")) || (b.name().toUpper().startsWith("WLT8828")) || + (b.name().toUpper().startsWith("VANRYSEL-HT")) || (b.name().toUpper().startsWith("HARISON-X15")) || (b.name().toUpper().startsWith("GLT") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || (b.name().toUpper().startsWith("SPORT01-") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // Labgrey Magnetic Exercise Bike https://www.amazon.co.uk/dp/B0CXMF1NPY?_encoding=UTF8&psc=1&ref=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&ref_=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&social_share=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&skipTwisterOG=1 From f18cd53c80ab07a241c88a01d384fa3528dafcb8 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 17 Sep 2024 17:14:57 +0200 Subject: [PATCH 115/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers (Issue #2541) --- src/devices/ftmsbike/ftmsbike.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 701265d45..77fb5f5ec 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -556,7 +556,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris br) / (2.0 * ar)) * settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) + - settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); + settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); if (!resistance_received && !DU30_bike) { Resistance = m_pelotonResistance; emit resistanceRead(Resistance.value()); @@ -1036,7 +1036,7 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact qDebug() << "routing FTMS packet to the bike from virtualbike" << characteristic.uuid() << newValue.toHex(' '); // handling gears - if (b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS && (zwiftPlayService == nullptr && gears_zwift_ratio)) { + if (b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS && ((zwiftPlayService == nullptr && gears_zwift_ratio) || !gears_zwift_ratio)) { lastPacketFromFTMS.clear(); for(int i=0; i Date: Tue, 17 Sep 2024 19:53:23 +0200 Subject: [PATCH 116/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index d06affc4b..5a015b81d 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 869; + CURRENT_PROJECT_VERSION = 870; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 869; + CURRENT_PROJECT_VERSION = 870; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 869; + CURRENT_PROJECT_VERSION = 870; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 869; + CURRENT_PROJECT_VERSION = 870; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 869; + CURRENT_PROJECT_VERSION = 870; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 869; + CURRENT_PROJECT_VERSION = 870; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 9846dc65a4685251792d950c3bf22f5910a245d2 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 18 Sep 2024 20:03:38 +0200 Subject: [PATCH 117/162] Revert "Update proformtreadmill.cpp (#2596)" This reverts commit 5d66c6c513e56c60db54781f3593021b01103fa0. --- .../proformtreadmill/proformtreadmill.cpp | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/devices/proformtreadmill/proformtreadmill.cpp b/src/devices/proformtreadmill/proformtreadmill.cpp index 60c57ad79..f569aaf99 100644 --- a/src/devices/proformtreadmill/proformtreadmill.cpp +++ b/src/devices/proformtreadmill/proformtreadmill.cpp @@ -1490,6 +1490,22 @@ void proformtreadmill::update() { switch (counterPoll) { case 0: + writeCharacteristic(noOpData1, sizeof(noOpData1), QStringLiteral("noOp")); + break; + case 1: + writeCharacteristic(noOpData2, sizeof(noOpData2), QStringLiteral("noOp")); + break; + case 2: + writeCharacteristic(noOpData3, sizeof(noOpData3), QStringLiteral("noOp")); + break; + case 3: + writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("noOp"), false, true); + break; + case 4: + writeCharacteristic(noOpData5, sizeof(noOpData5), QStringLiteral("noOp")); + break; + case 5: + writeCharacteristic(noOpData6, sizeof(noOpData6), QStringLiteral("noOp"), false, true); if (requestInclination != -100) { if (requestInclination < 0) requestInclination = 0; @@ -1520,22 +1536,6 @@ void proformtreadmill::update() { // writeCharacteristic(initDataF0C800B8, sizeof(initDataF0C800B8), "stop tape"); requestStop = -1; } - writeCharacteristic(noOpData1, sizeof(noOpData1), QStringLiteral("noOp")); - break; - case 1: - writeCharacteristic(noOpData2, sizeof(noOpData2), QStringLiteral("noOp")); - break; - case 2: - writeCharacteristic(noOpData3, sizeof(noOpData3), QStringLiteral("noOp")); - break; - case 3: - writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("noOp"), false, true); - break; - case 4: - writeCharacteristic(noOpData5, sizeof(noOpData5), QStringLiteral("noOp")); - break; - case 5: - writeCharacteristic(noOpData6, sizeof(noOpData6), QStringLiteral("noOp"), false, true); break; } counterPoll++; From a27686172910d7008877d90b2e77a9bacd4c28b7 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 19 Sep 2024 11:08:46 +0200 Subject: [PATCH 118/162] older power zone class does not grab homefitnessbuddy erg #2606 --- src/peloton.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/peloton.cpp b/src/peloton.cpp index 10a505c85..253e5ae4c 100644 --- a/src/peloton.cpp +++ b/src/peloton.cpp @@ -1013,6 +1013,73 @@ void peloton::ride_onfinish(QNetworkReply *reply) { } } + QJsonObject target_metrics_data_list = ride[QStringLiteral("target_metrics_data")].toObject(); + if (trainrows.empty() && !target_metrics_data_list.isEmpty() && + bluetoothManager->device()->deviceType() != bluetoothdevice::ROWING && + bluetoothManager->device()->deviceType() != bluetoothdevice::TREADMILL) { + QJsonArray target_metrics = target_metrics_data_list["target_metrics"].toArray(); + for (const QJsonValue& segment : target_metrics) { + QJsonObject segmentObj = segment.toObject(); + QJsonObject offsets = segmentObj["offsets"].toObject(); + QJsonArray metrics = segmentObj["metrics"].toArray(); + + trainrow r; + int start = offsets["start"].toInt(); + int end = offsets["end"].toInt(); + r.duration = QTime(0, 0, 0).addSecs(end - start); + if (!metrics.isEmpty()) { + QJsonObject metric = metrics[0].toObject(); + int lower = metric["lower"].toInt(); + int upper = metric["upper"].toInt(); + int avg = (upper - lower) / 2; + + int p = lower; + + if (difficulty == QStringLiteral("average")) { + p = avg; + } else if (difficulty == QStringLiteral("upper")) { + p = upper; + } else { // lower + p = lower; + } + + switch(p) { + case 1: + r.power = settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble() * 0.50; + break; + case 2: + r.power = settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble() * 0.66; + break; + case 3: + r.power = settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble() * 0.83; + break; + case 4: + r.power = settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble() * 0.98; + break; + case 5: + r.power = settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble() * 1.13; + break; + case 6: + r.power = settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble() * 1.35; + break; + case 7: + r.power = settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble() * 1.5; + break; + default: + qDebug() << "ERROR not handled!" << p; + break; + } + atLeastOnePower = true; + trainrows.append(r); + qDebug() << r.duration << "power" << r.power; + } + } + // this list doesn't have nothing useful for this session + if (!atLeastOnePower) { + trainrows.clear(); + } + } + if (log_request) { qDebug() << "peloton::ride_onfinish" << trainrows.length() << ride; } else { From 70c0bd9120a0b0b65114bd4b99929d1687cef87a Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 19 Sep 2024 13:24:12 +0200 Subject: [PATCH 119/162] fixing distance on tacx flux s --- src/devices/tacxneo2/tacxneo2.cpp | 17 ++++++++++------- src/devices/tacxneo2/tacxneo2.h | 4 +++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/devices/tacxneo2/tacxneo2.cpp b/src/devices/tacxneo2/tacxneo2.cpp index e28fcc3df..87027a9e7 100644 --- a/src/devices/tacxneo2/tacxneo2.cpp +++ b/src/devices/tacxneo2/tacxneo2.cpp @@ -278,7 +278,7 @@ void tacxneo2::characteristicChanged(const QLowEnergyCharacteristic &characteris .toDouble(); Distance += ((Speed.value() / 3600000.0) * - ((double)lastRefreshCharacteristicChanged.msecsTo(now))); + ((double)lastRefreshCharacteristicChanged2A5B.msecsTo(now))); // Resistance = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | // (uint16_t)((uint8_t)newValue.at(index)))); debug("Current Resistance: " + @@ -312,10 +312,10 @@ void tacxneo2::characteristicChanged(const QLowEnergyCharacteristic &characteris ((((0.048 * ((double)watts()) + 1.19) * settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) / 200.0) / - (60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo( + (60000.0 / ((double)lastRefreshCharacteristicChanged2A5B.msecsTo( now)))); //(( (0.048* Output in watts +1.19) * body weight in // kg * 3.5) / 200 ) / 60 - lastRefreshCharacteristicChanged = now; + lastRefreshCharacteristicChanged2A5B = now; emit debug(QStringLiteral("Current CrankRevsRead: ") + QString::number(CrankRevsRead)); emit debug(QStringLiteral("Last CrankEventTime: ") + QString::number(LastCrankEventTime)); @@ -445,7 +445,7 @@ void tacxneo2::characteristicChanged(const QLowEnergyCharacteristic &characteris emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value())); Distance += ((Speed.value() / 3600000.0) * - ((double)lastRefreshCharacteristicChanged.msecsTo(now))); + ((double)lastRefreshCharacteristicChangedPower.msecsTo(now))); emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value())); // if we change this, also change the wattsFromResistance function. We can create a standard function in @@ -492,11 +492,12 @@ void tacxneo2::characteristicChanged(const QLowEnergyCharacteristic &characteris ((((0.048 * ((double)watts()) + 1.19) * settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) / 200.0) / - (60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo( + (60000.0 / ((double)lastRefreshCharacteristicChangedPower.msecsTo( now)))); //(( (0.048* Output in watts +1.19) * body weight // in kg * 3.5) / 200 ) / 60 emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value())); + lastRefreshCharacteristicChangedPower = now; } } } else if (characteristic.uuid() == QBluetoothUuid((quint16)0x2AD2)) { @@ -584,7 +585,7 @@ void tacxneo2::characteristicChanged(const QLowEnergyCharacteristic &characteris } Distance += ((Speed.value() / 3600000.0) * - ((double)lastRefreshCharacteristicChanged.msecsTo(now))); + ((double)lastRefreshCharacteristicChanged2AD2.msecsTo(now))); emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value())); @@ -656,7 +657,7 @@ void tacxneo2::characteristicChanged(const QLowEnergyCharacteristic &characteris settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) / 200.0) / (60000.0 / - ((double)lastRefreshCharacteristicChanged.msecsTo( + ((double)lastRefreshCharacteristicChanged2AD2.msecsTo( now)))); //(( (0.048* Output in watts +1.19) * body weight in // kg * 3.5) / 200 ) / 60 } @@ -690,6 +691,8 @@ void tacxneo2::characteristicChanged(const QLowEnergyCharacteristic &characteris if (Flags.remainingTime) { // todo } + + lastRefreshCharacteristicChanged2AD2 = now; } #ifdef Q_OS_ANDROID diff --git a/src/devices/tacxneo2/tacxneo2.h b/src/devices/tacxneo2/tacxneo2.h index 5afa967dc..02d56077a 100644 --- a/src/devices/tacxneo2/tacxneo2.h +++ b/src/devices/tacxneo2/tacxneo2.h @@ -61,7 +61,9 @@ class tacxneo2 : public bike { uint8_t sec1Update = 0; QByteArray lastPacket; - QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime(); + QDateTime lastRefreshCharacteristicChanged2A5B = QDateTime::currentDateTime(); + QDateTime lastRefreshCharacteristicChanged2AD2 = QDateTime::currentDateTime(); + QDateTime lastRefreshCharacteristicChangedPower = QDateTime::currentDateTime(); QDateTime lastGoodCadence = QDateTime::currentDateTime(); uint8_t firstStateChanged = 0; From f132a00d30a0ad56a5adc2e6d1fda2ead143b9dc Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 19 Sep 2024 14:07:57 +0200 Subject: [PATCH 120/162] gears on erg mode for ftmsbike --- src/devices/ftmsbike/ftmsbike.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 77fb5f5ec..60c19ad48 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -1065,6 +1065,18 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact b[4] = slope >> 8; qDebug() << "applying gears mod" << gears() << gearsZwiftRatio() << slope; + } else if(b.at(0) == FTMS_SET_TARGET_POWER && b.length() > 2) { + lastPacketFromFTMS.clear(); + for(int i=0; i> 8; + qDebug() << "applying gears mod" << gears() << gearsZwiftRatio() << power; } writeCharacteristic((uint8_t*)b.data(), b.length(), "injectWrite ", false, true); From 7ea23b0ddce6a504f215dc9eb324231a7465b3a3 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 19 Sep 2024 15:11:01 +0200 Subject: [PATCH 121/162] Update echelonstride.cpp --- src/devices/echelonstride/echelonstride.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/devices/echelonstride/echelonstride.cpp b/src/devices/echelonstride/echelonstride.cpp index 6b0068cfe..7a5002bc1 100644 --- a/src/devices/echelonstride/echelonstride.cpp +++ b/src/devices/echelonstride/echelonstride.cpp @@ -383,10 +383,13 @@ void echelonstride::btinit() { // stride4 uint8_t initDataStride4_0[] = {0xf0, 0xe0, 0xfd, 0x3e, 0x65, 0x48, 0xd5, 0x8d}; - writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("init"), false, true); + if(stride4) { - writeCharacteristic(initDataStride4_0, sizeof(initDataStride4_0), QStringLiteral("init"), false, true); + writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("init"), false, false); + writeCharacteristic(initDataStride4_0, sizeof(initDataStride4_0), QStringLiteral("init"), false, false); + writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("init"), false, false); + } else { writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("init"), false, true); } From 15f013071c50f0119fa07336aca6a9b8382247b2 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 19 Sep 2024 15:47:43 +0200 Subject: [PATCH 122/162] Update bluetooth.cpp --- src/devices/bluetooth.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 532623100..3e8ef6aed 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -653,6 +653,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { emit deviceConnected(b); connect(fakeBike, &bluetoothdevice::connectedAndDiscovered, this, &bluetooth::connectedAndDiscovered); connect(fakeBike, &fakebike::inclinationChanged, this, &bluetooth::inclinationChanged); + connect(fakeBike, &fakebike::debug, this, &bluetooth::debug); // connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart())); // connect(this, SIGNAL(searchingStop()), fakeBike, SLOT(searchingStop())); //NOTE: Commented due to // #358 @@ -667,6 +668,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { connect(fakeElliptical, &bluetoothdevice::connectedAndDiscovered, this, &bluetooth::connectedAndDiscovered); connect(fakeElliptical, &fakeelliptical::inclinationChanged, this, &bluetooth::inclinationChanged); + connect(fakeElliptical, &fakeelliptical::debug, this, &bluetooth::debug); // connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart())); // connect(this, SIGNAL(searchingStop()), fakeBike, SLOT(searchingStop())); //NOTE: Commented due to // #358 @@ -680,6 +682,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { emit deviceConnected(b); connect(fakeRower, &bluetoothdevice::connectedAndDiscovered, this, &bluetooth::connectedAndDiscovered); connect(fakeRower, &fakerower::inclinationChanged, this, &bluetooth::inclinationChanged); + connect(fakeRower, &fakerower::debug, this, &bluetooth::debug); // connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart())); // connect(this, SIGNAL(searchingStop()), fakeBike, SLOT(searchingStop())); //NOTE: Commented due to // #358 @@ -694,6 +697,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { connect(fakeTreadmill, &bluetoothdevice::connectedAndDiscovered, this, &bluetooth::connectedAndDiscovered); connect(fakeTreadmill, &faketreadmill::inclinationChanged, this, &bluetooth::inclinationChanged); + connect(fakeTreadmill, &faketreadmill::debug, this, &bluetooth::debug); // connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart())); // connect(this, SIGNAL(searchingStop()), fakeBike, SLOT(searchingStop())); //NOTE: Commented due to // #358 From bbe0a4091cfcb92078b00f99da3c36fbefd381ba Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 19 Sep 2024 16:17:29 +0200 Subject: [PATCH 123/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 5a015b81d..146257ac7 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 870; + CURRENT_PROJECT_VERSION = 871; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 870; + CURRENT_PROJECT_VERSION = 871; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 870; + CURRENT_PROJECT_VERSION = 871; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 870; + CURRENT_PROJECT_VERSION = 871; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 870; + CURRENT_PROJECT_VERSION = 871; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 870; + CURRENT_PROJECT_VERSION = 871; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From eb4e320679df7fdadd5c18eb7c6c6916c8132ff4 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 20 Sep 2024 11:30:53 +0200 Subject: [PATCH 124/162] Proform Carbon TL Connects But Peloton Cannot Force Speed and Incline #2571 --- .../proformtreadmill/proformtreadmill.cpp | 142 +++++++++++++++++- .../proformtreadmill/proformtreadmill.h | 1 + src/qzsettings.cpp | 4 +- src/qzsettings.h | 3 + src/settings.qml | 8 +- 5 files changed, 152 insertions(+), 6 deletions(-) diff --git a/src/devices/proformtreadmill/proformtreadmill.cpp b/src/devices/proformtreadmill/proformtreadmill.cpp index f569aaf99..0c43eed88 100644 --- a/src/devices/proformtreadmill/proformtreadmill.cpp +++ b/src/devices/proformtreadmill/proformtreadmill.cpp @@ -75,7 +75,7 @@ void proformtreadmill::forceIncline(double incline) { } else if (proform_treadmill_8_0 || proform_treadmill_705_cst || proform_treadmill_705_cst_V78_239 || proform_treadmill_9_0 || proform_treadmill_se || proform_treadmill_z1300i || proform_treadmill_l6_0s || norditrack_s25_treadmill || proform_8_5_treadmill || nordictrack_treadmill_exp_5i || proform_2000_treadmill || proform_treadmill_sport_8_5 || proform_treadmill_505_cst || proform_carbon_tl || proform_proshox2 || nordictrack_s20i_treadmill || proform_595i_proshox2 || - proform_treadmill_8_7) { + proform_treadmill_8_7 || proform_carbon_tl_PFTL59720) { write[14] = write[11] + write[12] + 0x12; } else if (!nordictrack_t65s_treadmill && !nordictrack_s30_treadmill && !nordictrack_s20_treadmill && !nordictrack_t65s_83_treadmill) { for (uint8_t i = 0; i < 7; i++) { @@ -102,7 +102,7 @@ void proformtreadmill::forceSpeed(double speed) { } else if (proform_treadmill_8_0 || proform_treadmill_9_0 || proform_treadmill_se || proform_cadence_lt || proform_treadmill_z1300i || proform_treadmill_l6_0s || norditrack_s25_treadmill || proform_8_5_treadmill || nordictrack_treadmill_exp_5i || proform_2000_treadmill || proform_treadmill_sport_8_5 || proform_treadmill_505_cst || proform_treadmill_705_cst || proform_treadmill_705_cst_V78_239 || proform_carbon_tl || proform_proshox2 || nordictrack_s20i_treadmill || proform_595i_proshox2 || - proform_treadmill_8_7) { + proform_treadmill_8_7 || proform_carbon_tl_PFTL59720) { write[14] = write[11] + write[12] + 0x11; } else if (!nordictrack_t65s_treadmill && !nordictrack_s30_treadmill && !nordictrack_s20_treadmill && !nordictrack_t65s_83_treadmill) { for (uint8_t i = 0; i < 7; i++) { @@ -1542,6 +1542,68 @@ void proformtreadmill::update() { if (counterPoll > 5) { counterPoll = 0; } + } else if (proform_carbon_tl_PFTL59720) { + uint8_t noOpData1[] = {0xfe, 0x02, 0x19, 0x03}; + uint8_t noOpData2[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x04, 0x15, 0x02, 0x00, 0x0f, 0x80, 0x0a, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t noOpData3[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x81, 0x00, 0x10, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t noOpData4[] = {0xfe, 0x02, 0x14, 0x03}; + uint8_t noOpData5[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x10, 0x04, 0x10, 0x02, 0x00, 0x0a, 0x1b, 0x94, 0x30, 0x00, 0x00, 0x40, 0x50, 0x00, 0x80}; + uint8_t noOpData6[] = {0xff, 0x02, 0x18, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + switch (counterPoll) { + case 0: + writeCharacteristic(noOpData1, sizeof(noOpData1), QStringLiteral("noOp")); + break; + case 1: + writeCharacteristic(noOpData2, sizeof(noOpData2), QStringLiteral("noOp")); + break; + case 2: + writeCharacteristic(noOpData3, sizeof(noOpData3), QStringLiteral("noOp")); + break; + case 3: + writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("noOp"), false, true); + break; + case 4: + writeCharacteristic(noOpData5, sizeof(noOpData5), QStringLiteral("noOp")); + break; + case 5: + writeCharacteristic(noOpData6, sizeof(noOpData6), QStringLiteral("noOp"), false, true); + if (requestInclination != -100) { + if (requestInclination < 0) + requestInclination = 0; + if (requestInclination != currentInclination().value() && requestInclination >= 0 && + requestInclination <= 15) { + emit debug(QStringLiteral("writing incline ") + QString::number(requestInclination)); + forceIncline(requestInclination); + } + requestInclination = -100; + } + if (requestSpeed != -1) { + if (requestSpeed != currentSpeed().value() && requestSpeed >= 0 && requestSpeed <= 22) { + emit debug(QStringLiteral("writing speed ") + QString::number(requestSpeed)); + forceSpeed(requestSpeed); + } + requestSpeed = -1; + } + if (requestStart != -1) { + emit debug(QStringLiteral("starting...")); + + // btinit(); + + requestStart = -1; + emit tapeStarted(); + } + if (requestStop != -1) { + emit debug(QStringLiteral("stopping...")); + // writeCharacteristic(initDataF0C800B8, sizeof(initDataF0C800B8), "stop tape"); + requestStop = -1; + } + break; + } + counterPoll++; + if (counterPoll > 5) { + counterPoll = 0; + } } else if (proform_treadmill_8_7) { uint8_t noOpData1[] = {0xfe, 0x02, 0x17, 0x03}; uint8_t noOpData2[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x04, 0x13, 0x02, 0x00, 0x0d, 0x13, 0x96, 0x31, 0x00, 0x00, 0x40, 0x10, 0x00, 0x80}; @@ -1887,7 +1949,8 @@ void proformtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha ((norditrack_s25i_treadmill) && (newValue.at(4) != 0x02 || (newValue.at(5) != 0x2f))) || ((nordictrack_t65s_treadmill || proform_pro_1000_treadmill || nordictrack_t65s_83_treadmill || nordictrack_s30_treadmill || - nordictrack_s20_treadmill || proform_treadmill_se || proform_cadence_lt || proform_8_5_treadmill || nordictrack_treadmill_exp_5i || proform_carbon_tl || nordictrack_s20i_treadmill || proform_treadmill_8_7) && + nordictrack_s20_treadmill || proform_treadmill_se || proform_cadence_lt || proform_8_5_treadmill || nordictrack_treadmill_exp_5i || proform_carbon_tl || + nordictrack_s20i_treadmill || proform_treadmill_8_7 || proform_carbon_tl_PFTL59720) && (newValue.at(4) != 0x02 || newValue.at(5) != 0x2e)) || (((uint8_t)newValue.at(12)) == 0xFF && ((uint8_t)newValue.at(13)) == 0xFF && @@ -2006,6 +2069,7 @@ void proformtreadmill::btinit() { proform_proshox2 = settings.value(QZSettings::proform_proshox2, QZSettings::default_proform_proshox2).toBool(); proform_595i_proshox2 = settings.value(QZSettings::proform_595i_proshox2, QZSettings::default_proform_595i_proshox2).toBool(); proform_treadmill_8_7 = settings.value(QZSettings::proform_treadmill_8_7, QZSettings::default_proform_treadmill_8_7).toBool(); + proform_carbon_tl_PFTL59720 = settings.value(QZSettings::proform_carbon_tl_PFTL59720, QZSettings::default_proform_carbon_tl_PFTL59720).toBool(); // bool proform_treadmill_995i = settings.value(QZSettings::proform_treadmill_995i, @@ -2237,6 +2301,78 @@ void proformtreadmill::btinit() { QThread::msleep(sleepms); writeCharacteristic(noOpData6, sizeof(noOpData6), QStringLiteral("init"), false, false); QThread::msleep(sleepms); +} else if (proform_carbon_tl_PFTL59720) { + uint8_t initData1[] = {0xfe, 0x02, 0x08, 0x02}; + uint8_t initData2[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x81, 0x87, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData3[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x04, 0x04, 0x80, 0x88, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData4[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x04, 0x04, 0x88, 0x90, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData5[] = {0xfe, 0x02, 0x0a, 0x02}; + uint8_t initData6[] = {0xff, 0x0a, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x82, 0x00, + 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData7[] = {0xff, 0x0a, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x84, 0x00, + 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData8[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x95, 0x9b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t initData9[] = {0xfe, 0x02, 0x2c, 0x04}; + uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x04, 0x28, 0x90, 0x07, 0x01, 0xdd, 0x28, 0x79, 0xc8, 0x25, 0x70, 0xd9, 0x20, 0x8d}; + uint8_t initData11[] = {0x01, 0x12, 0xe8, 0x49, 0xa8, 0x05, 0x60, 0xc9, 0x50, 0xbd, 0x08, 0x99, 0xe8, 0x65, 0xf0, 0x79, 0xc0, 0x4d, 0xc8, 0x49}; + uint8_t initData12[] = {0xff, 0x08, 0xc8, 0x45, 0xc0, 0x98, 0x02, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t noOpData1[] = {0xfe, 0x02, 0x19, 0x03}; + uint8_t noOpData2[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x04, 0x15, 0x02, 0x00, 0x0f, 0x00, 0x10, 0x00, 0xd8, 0x1c, 0x48, 0x00, 0x00, 0xe0}; + uint8_t noOpData3[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t noOpData4[] = {0xfe, 0x02, 0x19, 0x03}; + uint8_t noOpData5[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x04, 0x15, 0x02, 0x0e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t noOpData6[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x3a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData2, sizeof(initData2), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData3, sizeof(initData3), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData4, sizeof(initData4), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData5, sizeof(initData5), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData6, sizeof(initData6), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData5, sizeof(initData5), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData7, sizeof(initData7), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData8, sizeof(initData8), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData9, sizeof(initData9), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData10, sizeof(initData10), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData11, sizeof(initData11), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData1, sizeof(noOpData1), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData2, sizeof(noOpData2), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData3, sizeof(noOpData3), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData5, sizeof(noOpData5), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); + writeCharacteristic(noOpData6, sizeof(noOpData6), QStringLiteral("init"), false, false); + QThread::msleep(sleepms); } else if (proform_treadmill_8_7) { uint8_t initData1[] = {0xfe, 0x02, 0x08, 0x02}; writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, false); diff --git a/src/devices/proformtreadmill/proformtreadmill.h b/src/devices/proformtreadmill/proformtreadmill.h index d34ac10af..f94d4bf38 100644 --- a/src/devices/proformtreadmill/proformtreadmill.h +++ b/src/devices/proformtreadmill/proformtreadmill.h @@ -97,6 +97,7 @@ class proformtreadmill : public treadmill { bool proform_treadmill_8_7 = false; bool proform_treadmill_705_cst_V78_239 = false; bool nordictrack_treadmill_exp_5i = false; + bool proform_carbon_tl_PFTL59720 = false; #ifdef Q_OS_IOS lockscreen *h = 0; diff --git a/src/qzsettings.cpp b/src/qzsettings.cpp index e9ca46a4a..34ec895e0 100644 --- a/src/qzsettings.cpp +++ b/src/qzsettings.cpp @@ -762,8 +762,9 @@ const QString QZSettings::zwiftplay_swap = QStringLiteral("zwiftplay_swap"); const QString QZSettings::gears_zwift_ratio = QStringLiteral("gears_zwift_ratio"); const QString QZSettings::domyos_bike_500_profile_v2 = QStringLiteral("domyos_bike_500_profile_v2"); const QString QZSettings::gears_offset = QStringLiteral("gears_offset"); +const QString QZSettings::proform_carbon_tl_PFTL59720 = QStringLiteral("proform_carbon_tl_PFTL59720"); -const uint32_t allSettingsCount = 645; +const uint32_t allSettingsCount = 646; QVariant allSettings[allSettingsCount][2] = { {QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles}, @@ -1415,6 +1416,7 @@ QVariant allSettings[allSettingsCount][2] = { {QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio}, {QZSettings::domyos_bike_500_profile_v2, QZSettings::default_domyos_bike_500_profile_v2}, {QZSettings::gears_offset, QZSettings::default_gears_offset}, + {QZSettings::proform_carbon_tl_PFTL59720, QZSettings::default_proform_carbon_tl_PFTL59720}, }; void QZSettings::qDebugAllSettings(bool showDefaults) { diff --git a/src/qzsettings.h b/src/qzsettings.h index e5e098c3d..d420f6503 100644 --- a/src/qzsettings.h +++ b/src/qzsettings.h @@ -2135,6 +2135,9 @@ class QZSettings { static const QString gears_offset; static constexpr double default_gears_offset = 0.0; + static const QString proform_carbon_tl_PFTL59720; + static constexpr bool default_proform_carbon_tl_PFTL59720 = 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. diff --git a/src/settings.qml b/src/settings.qml index d09724e59..f67ca1899 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -977,6 +977,7 @@ import QtQuick.Dialogs 1.0 property bool gears_zwift_ratio: false property bool domyos_bike_500_profile_v2: false property double gears_offset: 0.0 + property bool proform_carbon_tl_PFTL59720: false } function paddingZeros(text, limit) { @@ -6004,7 +6005,7 @@ import QtQuick.Dialogs 1.0 "Proform 8.0", "Proform 9.0", "Proform 705 CST", "Nordictrack x14i", "Proform Carbon TL", "Proform Proshox 2", "Nordictrack S20i", "Proform 595i", "Proform 8.7", "Proform 705 CST V78.239", "Proform Carbon T7", - "Nordictrack EXP 5i" + "Nordictrack EXP 5i", "Proform Carbon TL PFTL59720" ] onCurrentIndexChanged: { @@ -6044,6 +6045,7 @@ import QtQuick.Dialogs 1.0 settings.proform_treadmill_705_cst_V78_239 = false; settings.proform_treadmill_carbon_t7 = false; settings.nordictrack_treadmill_exp_5i = false; + settings.proform_carbon_tl_PFTL59720 = false; // Imposta il setting corrispondente al modello selezionato switch (currentIndex) { @@ -6080,6 +6082,7 @@ import QtQuick.Dialogs 1.0 case 30: settings.proform_treadmill_705_cst_V78_239 = true; break; case 31: settings.proform_treadmill_carbon_t7 = true; break; case 32: settings.nordictrack_treadmill_exp_5i = true; break; + case 33: settings.proform_carbon_tl_PFTL59720 = true; break; } } @@ -6117,7 +6120,8 @@ import QtQuick.Dialogs 1.0 settings.proform_treadmill_8_7 ? 29 : settings.proform_treadmill_705_cst_V78_239 ? 30 : settings.proform_treadmill_carbon_t7 ? 31 : - settings.nordictrack_treadmill_exp_5i ? 32 : -1; + settings.nordictrack_treadmill_exp_5i ? 32 + settings.proform_carbon_tl_PFTL59720 ? 33 : -1; console.log("treadmillModelComboBox " + "Component.onCompleted " + selectedModel); From e54a9e59619bef99988a9cd52aff166959b8ca24 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 20 Sep 2024 13:35:52 +0200 Subject: [PATCH 125/162] New echelon stride treadmill (Issue #2555) --- src/devices/echelonstride/echelonstride.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/devices/echelonstride/echelonstride.cpp b/src/devices/echelonstride/echelonstride.cpp index 7a5002bc1..05978c66a 100644 --- a/src/devices/echelonstride/echelonstride.cpp +++ b/src/devices/echelonstride/echelonstride.cpp @@ -383,9 +383,8 @@ void echelonstride::btinit() { // stride4 uint8_t initDataStride4_0[] = {0xf0, 0xe0, 0xfd, 0x3e, 0x65, 0x48, 0xd5, 0x8d}; - - if(stride4) { + writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("init"), false, true); // send a frame to wait the Value: f0e0728518586198 writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("init"), false, false); writeCharacteristic(initDataStride4_0, sizeof(initDataStride4_0), QStringLiteral("init"), false, false); writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("init"), false, false); From eff72fddc1e91d85cae137c8a800053608d3bf89 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 20 Sep 2024 15:38:24 +0200 Subject: [PATCH 126/162] Update settings.qml --- src/settings.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings.qml b/src/settings.qml index f67ca1899..8f1055e34 100644 --- a/src/settings.qml +++ b/src/settings.qml @@ -6120,7 +6120,7 @@ import QtQuick.Dialogs 1.0 settings.proform_treadmill_8_7 ? 29 : settings.proform_treadmill_705_cst_V78_239 ? 30 : settings.proform_treadmill_carbon_t7 ? 31 : - settings.nordictrack_treadmill_exp_5i ? 32 + settings.nordictrack_treadmill_exp_5i ? 32 : settings.proform_carbon_tl_PFTL59720 ? 33 : -1; console.log("treadmillModelComboBox " + "Component.onCompleted " + selectedModel); From 44410906870e81b20fba71ca231032d85b219312 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 20 Sep 2024 15:43:05 +0200 Subject: [PATCH 127/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 146257ac7..2b07354e5 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 871; + CURRENT_PROJECT_VERSION = 874; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 871; + CURRENT_PROJECT_VERSION = 874; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 871; + CURRENT_PROJECT_VERSION = 874; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 871; + CURRENT_PROJECT_VERSION = 874; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 871; + CURRENT_PROJECT_VERSION = 874; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 871; + CURRENT_PROJECT_VERSION = 874; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 8bf9feacf14acabce3d6bea8d7ab8abaa450bcce Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sat, 21 Sep 2024 08:37:37 +0200 Subject: [PATCH 128/162] Bluetooth Name Android (#2611) * Bluetooth Name Android * Update homeform.h * Update homeform.cpp * New echelon stride treadmill #2555 --- src/homeform.cpp | 29 +++++++++++++++++++++++++++++ src/homeform.h | 1 + 2 files changed, 30 insertions(+) diff --git a/src/homeform.cpp b/src/homeform.cpp index 06b1750cd..533963252 100644 --- a/src/homeform.cpp +++ b/src/homeform.cpp @@ -564,6 +564,14 @@ homeform::homeform(QQmlApplicationEngine *engine, bluetooth *bl) { } } #ifdef Q_OS_ANDROID + + QString bluetoothName = getBluetoothName(); + qDebug() << "getBluetoothName()" << bluetoothName; + + if(bluetoothName.length() > 4) { + setToastRequested("Bluetooth name too long, change it to a 4 letters one in the android settings"); + } + // Android 14 restrics access to /Android/data folder bool android_documents_folder = settings.value(QZSettings::android_documents_folder, QZSettings::default_android_documents_folder).toBool(); if (android_documents_folder || QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Android, 14)) { @@ -6961,6 +6969,27 @@ void homeform::sendMail() { } #if defined(Q_OS_ANDROID) + +QString homeform::getBluetoothName() +{ + QAndroidJniObject bluetoothAdapter = QAndroidJniObject::callStaticObjectMethod( + "android/bluetooth/BluetoothAdapter", + "getDefaultAdapter", + "()Landroid/bluetooth/BluetoothAdapter;"); + + if (bluetoothAdapter.isValid()) { + QAndroidJniObject name = bluetoothAdapter.callObjectMethod( + "getName", + "()Ljava/lang/String;"); + + if (name.isValid()) { + return name.toString(); + } + } + + return QString(); +} + QString homeform::getAndroidDataAppDir() { static QString path = ""; diff --git a/src/homeform.h b/src/homeform.h index 54728be0e..bbf50fa67 100644 --- a/src/homeform.h +++ b/src/homeform.h @@ -498,6 +498,7 @@ class homeform : public QObject { int preview_workout_points(); #if defined(Q_OS_ANDROID) + QString getBluetoothName(); static QString getAndroidDataAppDir(); #endif Q_INVOKABLE static QString getWritableAppDir(); From 93a4ef17713afdc7adabcd8a51b4da2493c89dfa Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 24 Sep 2024 08:51:08 +0200 Subject: [PATCH 129/162] 2.16.70 --- src/android/AndroidManifest.xml | 2 +- src/main.qml | 2 +- src/qdomyos-zwift.pri | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/android/AndroidManifest.xml b/src/android/AndroidManifest.xml index f278e01fd..9760300b4 100644 --- a/src/android/AndroidManifest.xml +++ b/src/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + diff --git a/src/main.qml b/src/main.qml index 172fc36fc..6ff1302ea 100644 --- a/src/main.qml +++ b/src/main.qml @@ -777,7 +777,7 @@ ApplicationWindow { } ItemDelegate { - text: "version 2.16.69" + text: "version 2.16.70" width: parent.width } diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index 73d604ece..ab238924c 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -864,4 +864,4 @@ INCLUDEPATH += purchasing/inapp WINRT_MANIFEST = AppxManifest.xml -VERSION = 2.16.69 +VERSION = 2.16.70 From 716e99c9435d0cacf464437999a85eeb091f4841 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 25 Sep 2024 20:55:02 +0200 Subject: [PATCH 130/162] fixing debouncing issue on zwift ride --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++----- src/zwift_play/abstractZapDevice.h | 25 +++++++++++-------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 2b07354e5..5bc4dad69 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 874; + CURRENT_PROJECT_VERSION = 877; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 874; + CURRENT_PROJECT_VERSION = 877; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 874; + CURRENT_PROJECT_VERSION = 877; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 874; + CURRENT_PROJECT_VERSION = 877; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 874; + CURRENT_PROJECT_VERSION = 877; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 874; + CURRENT_PROJECT_VERSION = 877; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index 6e8af645f..f2b8e3108 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -67,20 +67,20 @@ class AbstractZapDevice: public QObject { if(bytes.length() == 5) { if(bytes[2] == 0) { if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit plus(); else emit minus(); } - risingEdge = true; } else if(bytes[4] == 0) { if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit minus(); else emit plus(); } - risingEdge = true; } else { risingEdge = false; } @@ -93,43 +93,46 @@ class AbstractZapDevice: public QObject { ) && bytes[bytes.length() - 3] == 0x01) { if(zapType == LEFT) { if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit plus(); else emit minus(); } - risingEdge = true; } else { if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit minus(); else emit plus(); } - risingEdge = true; } } else if(bytes.length() > 14 && bytes[11] == 0x30 && bytes[12] == 0x00) { if(zapType == LEFT) { if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit plus(); else emit minus(); } - risingEdge = true; } else { if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit minus(); else emit plus(); } - risingEdge = true; } } else { risingEdge = false; } break; + case 0x15: // empty data + qDebug() << "ignoring this frame"; + return 1; case 0x23: // zwift ride if(bytes.length() > 12 && ((((uint8_t)bytes[12]) == 0xc7 && zapType == RIGHT) || @@ -137,49 +140,49 @@ class AbstractZapDevice: public QObject { ) { if(zapType == LEFT) { if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit plus(); else emit minus(); } - risingEdge = true; } else { if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit minus(); else emit plus(); } - risingEdge = true; } } else if(bytes.length() > 19 && ((uint8_t)bytes[18]) == 0xc8) { if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit plus(); else emit minus(); } - risingEdge = true; } else if(bytes.length() > 3 && ((((uint8_t)bytes[3]) == 0xdf) || // right top button (((uint8_t)bytes[3]) == 0xbf))) { // right bottom button if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit plus(); else emit minus(); } - risingEdge = true; } else if(bytes.length() > 3 && ((((uint8_t)bytes[3]) == 0xfd) || // left top button (((uint8_t)bytes[3]) == 0xfb))) { // left bottom button if(DEBOUNCE) { + risingEdge = true; if(!zwiftplay_swap) emit minus(); else emit plus(); } - risingEdge = true; } else { risingEdge = false; } From d37939ee370d0ff8179bc18cf43f7e05bea52fe8 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 26 Sep 2024 08:22:39 +0200 Subject: [PATCH 131/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/devices/ftmsbike/ftmsbike.cpp | 56 +++++++++++++++++-------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 60c19ad48..5f7b278a2 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -289,86 +289,90 @@ void ftmsbike::update() { QSettings settings; bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); if(zwiftPlayService && gears_zwift_ratio && lastGearValue != gears()) { - uint8_t gear[] = {0x04, 0x2a, 0x04, 0x10, 0xdc, 0xec, 0x01}; + uint8_t gear1[] = {0x04, 0x2a, 0x03, 0x10, 0xdc, 0xec}; + uint8_t gear2[] = {0x04, 0x2a, 0x04, 0x10, 0xdc, 0xec, 0x01}; switch((int)gears()) { case 1: - gear[4] = 0xf3; gear[5] = 0xac; + gear1[4] = 0xcc; gear1[5] = 0x3a; break; case 2: - gear[4] = 0xc8; gear[5] = 0x91; + gear1[4] = 0xfc; gear1[5] = 0x43; break; case 3: - gear[4] = 0x90; gear[5] = 0xfa; + gear1[4] = 0xac; gear1[5] = 0x4d; break; case 4: - gear[4] = 0xd8; gear[5] = 0xe2; + gear1[4] = 0xd5; gear1[5] = 0x56; break; case 5: - gear[4] = 0x9f; gear[5] = 0xcb; + gear1[4] = 0x8c; gear1[5] = 0x60; break; case 6: - gear[4] = 0xdc; gear[5] = 0xb7; + gear1[4] = 0xe8; gear1[5] = 0x6b; break; case 7: - gear[4] = 0x98; gear[5] = 0xa4; + gear1[4] = 0xc4; gear1[5] = 0x77; break; case 8: - gear[4] = 0xd4; gear[5] = 0x90; + gear2[4] = 0xa0; gear2[5] = 0x83; break; case 9: - gear[4] = 0x90; gear[5] = 0xfd; + gear2[4] = 0xa8; gear2[5] = 0x91; break; case 10: - gear[4] = 0xdc; gear[5] = 0xec; + gear2[4] = 0xb0; gear2[5] = 0x9f; break; case 11: - gear[4] = 0xa8; gear[5] = 0xdc; + gear2[4] = 0xb8; gear2[5] = 0xad; break; case 12: - gear[4] = 0xf3; gear[5] = 0xcb; + gear2[4] = 0xc0; gear2[5] = 0xbb; break; case 13: - gear[4] = 0xc0; gear[5] = 0xbb; + gear2[4] = 0xf3; gear2[5] = 0xcb; break; case 14: - gear[4] = 0xb8; gear[5] = 0xad; + gear2[4] = 0xa8; gear2[5] = 0xdc; break; case 15: - gear[4] = 0xb0; gear[5] = 0x9f; + gear2[4] = 0xdc; gear2[5] = 0xec; break; case 16: - gear[4] = 0xa8; gear[5] = 0x91; + gear2[4] = 0x90; gear2[5] = 0xfd; break; case 17: - gear[4] = 0xa0; gear[5] = 0x83; + gear2[4] = 0xd4; gear2[5] = 0x90; gear2[6] = 0x02; break; case 18: - gear[4] = 0xc0; gear[5] = 0xbb; + gear2[4] = 0x98; gear2[5] = 0xa4; gear2[6] = 0x02; break; case 19: - gear[4] = 0xa2; gear[5] = 0x8b; + gear2[4] = 0xdc; gear2[5] = 0xb7; gear2[6] = 0x02; break; case 20: - gear[4] = 0xa4; gear[5] = 0x93; + gear2[4] = 0x9f; gear2[5] = 0xcb; gear2[6] = 0x02; break; case 21: - gear[4] = 0xa6; gear[5] = 0x9b; + gear2[4] = 0xd8; gear2[5] = 0xe2; gear2[6] = 0x02; break; case 22: - gear[4] = 0xa8; gear[5] = 0xa3; + gear2[4] = 0x90; gear2[5] = 0xfa; gear2[6] = 0x02; break; case 23: - gear[4] = 0xaa; gear[5] = 0xab; + gear2[4] = 0xc8; gear2[5] = 0x91; gear2[6] = 0x03; break; case 24: - gear[4] = 0xac; gear[5] = 0xb3; + gear2[4] = 0xf3; gear2[5] = 0xac; gear2[6] = 0x03; break; default: // Gestione del caso di default break; } - writeCharacteristicZwiftPlay(gear, sizeof(gear), "gear", false, true); + if((int)gears() < 8) + writeCharacteristicZwiftPlay(gear1, sizeof(gear1), "gear", false, true); + else + writeCharacteristicZwiftPlay(gear2, sizeof(gear2), "gear", false, true); uint8_t gearApply[] = {0x00, 0x08, 0x88, 0x04}; writeCharacteristicZwiftPlay(gearApply, sizeof(gearApply), "gearApply", false, true); From bacc84a25b1ed28f31c122494401667dc2e62822 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 26 Sep 2024 09:18:13 +0200 Subject: [PATCH 132/162] new zwift play gear down event --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/zwift_play/abstractZapDevice.h | 12 +++++++++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 5bc4dad69..5894c9c28 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 877; + CURRENT_PROJECT_VERSION = 878; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 877; + CURRENT_PROJECT_VERSION = 878; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 877; + CURRENT_PROJECT_VERSION = 878; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 877; + CURRENT_PROJECT_VERSION = 878; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 877; + CURRENT_PROJECT_VERSION = 878; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 877; + CURRENT_PROJECT_VERSION = 878; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index f2b8e3108..c559fe8cf 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -41,7 +41,7 @@ class AbstractZapDevice: public QObject { bool gears_volume_debouncing = settings.value(QZSettings::gears_volume_debouncing, QZSettings::default_gears_volume_debouncing).toBool(); bool zwiftplay_swap = settings.value(QZSettings::zwiftplay_swap, QZSettings::default_zwiftplay_swap).toBool(); - qDebug() << zapType << characteristicName << bytes.toHex() << gears_volume_debouncing << risingEdge; + qDebug() << zapType << characteristicName << bytes.toHex() << zwiftplay_swap << gears_volume_debouncing << risingEdge; #define DEBOUNCE (!gears_volume_debouncing || !risingEdge) @@ -183,6 +183,16 @@ class AbstractZapDevice: public QObject { else emit plus(); } + } else if(bytes.length() > 5 && + ((((uint8_t)bytes[4]) == 0xfd) || // left top button + (((uint8_t)bytes[4]) == 0xfb))) { // left bottom button + if(DEBOUNCE) { + risingEdge = true; + if(!zwiftplay_swap) + emit minus(); + else + emit plus(); + } } else { risingEdge = false; } From b11db80e1c294c11e9da99b1c456cd6f28a4de31 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 26 Sep 2024 10:14:11 +0200 Subject: [PATCH 133/162] fixing debouncing for the zwift ride --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/bluetooth.cpp | 9 +++++++-- src/zwift_play/abstractZapDevice.h | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 5894c9c28..e9cc77b72 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 878; + CURRENT_PROJECT_VERSION = 879; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 878; + CURRENT_PROJECT_VERSION = 879; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 878; + CURRENT_PROJECT_VERSION = 879; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 878; + CURRENT_PROJECT_VERSION = 879; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 878; + CURRENT_PROJECT_VERSION = 879; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 878; + CURRENT_PROJECT_VERSION = 879; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 3e8ef6aed..f777304fb 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -2654,8 +2654,13 @@ void bluetooth::connectedAndDiscovered() { // connect(heartRateBelt, SIGNAL(disconnected()), this, SLOT(restart())); connect(zwiftPlayDevice.last(), &zwiftclickremote::debug, this, &bluetooth::debug); - connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::plus, (bike*)this->device(), &bike::gearUp); - connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::minus, (bike*)this->device(), &bike::gearDown); + if(!b.name().toUpper().startsWith("ZWIFT RIDE") || (b.name().toUpper().startsWith("ZWIFT RIDE") && zwiftPlayDevice.size() == 1)) { + connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::plus, (bike*)this->device(), &bike::gearUp); + connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::minus, (bike*)this->device(), &bike::gearDown); + qDebug() << "listeing to events from" << b.name(); + } else { + qDebug() << "ignoring gears event because the ZWIFT RIDE sends the same events from both side, so I just need to listen 1 source"; + } zwiftPlayDevice.last()->deviceDiscovered(b); if(homeform::singleton()) homeform::singleton()->setToastRequested("Zwift Play/Ride Connected!"); diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index c559fe8cf..7f385d57d 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -241,7 +241,7 @@ class AbstractZapDevice: public QObject { private: QByteArray devicePublicKeyBytes; - bool risingEdge = false; + volatile bool risingEdge = false; signals: void plus(); From 533328dabcbb2903275d34f34ac67e321b811e52 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 27 Sep 2024 12:12:07 +0200 Subject: [PATCH 134/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/devices/bluetooth.cpp | 9 ++------- src/zwift_play/abstractZapDevice.h | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index f777304fb..3e8ef6aed 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -2654,13 +2654,8 @@ void bluetooth::connectedAndDiscovered() { // connect(heartRateBelt, SIGNAL(disconnected()), this, SLOT(restart())); connect(zwiftPlayDevice.last(), &zwiftclickremote::debug, this, &bluetooth::debug); - if(!b.name().toUpper().startsWith("ZWIFT RIDE") || (b.name().toUpper().startsWith("ZWIFT RIDE") && zwiftPlayDevice.size() == 1)) { - connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::plus, (bike*)this->device(), &bike::gearUp); - connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::minus, (bike*)this->device(), &bike::gearDown); - qDebug() << "listeing to events from" << b.name(); - } else { - qDebug() << "ignoring gears event because the ZWIFT RIDE sends the same events from both side, so I just need to listen 1 source"; - } + connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::plus, (bike*)this->device(), &bike::gearUp); + connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::minus, (bike*)this->device(), &bike::gearDown); zwiftPlayDevice.last()->deviceDiscovered(b); if(homeform::singleton()) homeform::singleton()->setToastRequested("Zwift Play/Ride Connected!"); diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index 7f385d57d..2076492ec 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -241,7 +241,7 @@ class AbstractZapDevice: public QObject { private: QByteArray devicePublicKeyBytes; - volatile bool risingEdge = false; + static volatile bool risingEdge = false; signals: void plus(); From 968c7244803004e7e330f7476b7eaeaf177da162 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 27 Sep 2024 12:12:45 +0200 Subject: [PATCH 135/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/zwift_play/abstractZapDevice.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index 2076492ec..be64f4065 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -32,6 +32,7 @@ class AbstractZapDevice: public QObject { RIDE_ON = QByteArray::fromRawData("\x52\x69\x64\x65\x4F\x6E", 6); // "RideOn" REQUEST_START = QByteArray::fromRawData("\x00\x09", 2); // {0, 9} RESPONSE_START = QByteArray::fromRawData("\x01\x03", 2); // {1, 3} + risingEdge = false; } int processCharacteristic(const QString& characteristicName, const QByteArray& bytes, ZWIFT_PLAY_TYPE zapType) { @@ -241,7 +242,7 @@ class AbstractZapDevice: public QObject { private: QByteArray devicePublicKeyBytes; - static volatile bool risingEdge = false; + static volatile bool risingEdge; signals: void plus(); From 17f4bd4d632567040ac72b882301b02ed682ffca Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 27 Sep 2024 12:14:27 +0200 Subject: [PATCH 136/162] 2.17.0 --- src/main.qml | 2 +- src/qdomyos-zwift.pri | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.qml b/src/main.qml index 6ff1302ea..bfa7ee5be 100644 --- a/src/main.qml +++ b/src/main.qml @@ -777,7 +777,7 @@ ApplicationWindow { } ItemDelegate { - text: "version 2.16.70" + text: "version 2.17.0" width: parent.width } diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index ab238924c..18a16dcd9 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -864,4 +864,4 @@ INCLUDEPATH += purchasing/inapp WINRT_MANIFEST = AppxManifest.xml -VERSION = 2.16.70 +VERSION = 2.17.0 From f0828fb66a64c40a5fd465aee43c16c349e3f62e Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 27 Sep 2024 12:29:08 +0200 Subject: [PATCH 137/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/zwift_play/abstractZapDevice.h | 1 - src/zwift_play/zwiftclickremote.cpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index be64f4065..a92b0cf65 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -32,7 +32,6 @@ class AbstractZapDevice: public QObject { RIDE_ON = QByteArray::fromRawData("\x52\x69\x64\x65\x4F\x6E", 6); // "RideOn" REQUEST_START = QByteArray::fromRawData("\x00\x09", 2); // {0, 9} RESPONSE_START = QByteArray::fromRawData("\x01\x03", 2); // {1, 3} - risingEdge = false; } int processCharacteristic(const QString& characteristicName, const QByteArray& bytes, ZWIFT_PLAY_TYPE zapType) { diff --git a/src/zwift_play/zwiftclickremote.cpp b/src/zwift_play/zwiftclickremote.cpp index c3af478fa..cd64125bf 100755 --- a/src/zwift_play/zwiftclickremote.cpp +++ b/src/zwift_play/zwiftclickremote.cpp @@ -14,6 +14,8 @@ using namespace std::chrono_literals; extern quint8 QZ_EnableDiscoveryCharsAndDescripttors; #endif +volatile bool AbstractZapDevice::risingEdge = false; + zwiftclickremote::zwiftclickremote(bluetoothdevice *parentDevice, AbstractZapDevice::ZWIFT_PLAY_TYPE typeZap) { #ifdef Q_OS_IOS QZ_EnableDiscoveryCharsAndDescripttors = true; From ad19afcb8f3d86ea0884921b8becb347440b20b6 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 27 Sep 2024 12:31:30 +0200 Subject: [PATCH 138/162] 2.17.0 - build 880 --- .../qdomyoszwift.xcodeproj/project.pbxproj | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index e9cc77b72..acde9ff3d 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 879; + CURRENT_PROJECT_VERSION = 880; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4135,7 +4135,7 @@ /Users/cagnulein/Qt/5.15.2/ios/plugins/audio, "/Users/cagnulein/qdomyos-zwift/src/ios/adb", ); - MARKETING_VERSION = 2.16; + MARKETING_VERSION = 2.17; OTHER_CFLAGS = ( "-pipe", "-g", @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 879; + CURRENT_PROJECT_VERSION = 880; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4328,7 +4328,7 @@ /Users/cagnulein/Qt/5.15.2/ios/plugins/audio, "/Users/cagnulein/qdomyos-zwift/src/ios/adb", ); - MARKETING_VERSION = 2.16; + MARKETING_VERSION = 2.17; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ( "-pipe", @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 879; + CURRENT_PROJECT_VERSION = 880; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4499,7 +4499,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MARKETING_VERSION = 2.16; + MARKETING_VERSION = 2.17; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der"; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 879; + CURRENT_PROJECT_VERSION = 880; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4591,7 +4591,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MARKETING_VERSION = 2.16; + MARKETING_VERSION = 2.17; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der"; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 879; + CURRENT_PROJECT_VERSION = 880; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4707,7 +4707,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.16; + MARKETING_VERSION = 2.17; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der"; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 879; + CURRENT_PROJECT_VERSION = 880; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; @@ -4817,7 +4817,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.16; + MARKETING_VERSION = 2.17; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der"; From 36ab693ae69326b31ffe8b46523e246dbefeb6c5 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 27 Sep 2024 14:49:50 +0200 Subject: [PATCH 139/162] Bluetooth volume controls on Android not working to change gears (Issue #2614) (#2616) * let's try * Update MediaButtonReceiver.java * Update MediaButtonReceiver.java * fixing crash * Update MediaButtonReceiver.java * Update AndroidManifest.xml * Update homeform.cpp * Update MediaButtonReceiver.java * Update homeform.cpp * Update homeform.h * Update MediaButtonReceiver.java * Update homeform.cpp * Update homeform.cpp --- src/android/AndroidManifest.xml | 8 +++++ src/android/src/MediaButtonReceiver.java | 45 ++++++++++++++++++++++++ src/homeform.cpp | 35 ++++++++++++++++++ src/homeform.h | 4 +-- src/qdomyos-zwift.pri | 1 + 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 src/android/src/MediaButtonReceiver.java diff --git a/src/android/AndroidManifest.xml b/src/android/AndroidManifest.xml index 9760300b4..d7bca6606 100644 --- a/src/android/AndroidManifest.xml +++ b/src/android/AndroidManifest.xml @@ -111,6 +111,12 @@ android:value="ocr" /> + + + + + + @@ -119,6 +125,7 @@ + @@ -129,6 +136,7 @@ + diff --git a/src/android/src/MediaButtonReceiver.java b/src/android/src/MediaButtonReceiver.java new file mode 100644 index 000000000..60d9a0f02 --- /dev/null +++ b/src/android/src/MediaButtonReceiver.java @@ -0,0 +1,45 @@ +package org.cagnulen.qdomyoszwift; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.AudioManager; +import android.util.Log; + +public class MediaButtonReceiver extends BroadcastReceiver { + private static MediaButtonReceiver instance; + + @Override + public void onReceive(Context context, Intent intent) { + Log.d("MediaButtonReceiver", "Received intent: " + intent.toString()); + String intentAction = intent.getAction(); + if ("android.media.VOLUME_CHANGED_ACTION".equals(intentAction)) { + AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); + int currentVolume = intent.getIntExtra("android.media.EXTRA_VOLUME_STREAM_VALUE", -1); + int previousVolume = intent.getIntExtra("android.media.EXTRA_PREV_VOLUME_STREAM_VALUE", -1); + + Log.d("MediaButtonReceiver", "Volume changed. Current: " + currentVolume + ", Max: " + maxVolume); + nativeOnMediaButtonEvent(previousVolume, currentVolume, maxVolume); + } + } + + private native void nativeOnMediaButtonEvent(int prev, int current, int max); + + public static void registerReceiver(Context context) { + if (instance == null) { + instance = new MediaButtonReceiver(); + } + IntentFilter filter = new IntentFilter("android.media.VOLUME_CHANGED_ACTION"); + context.registerReceiver(instance, filter, Context.RECEIVER_EXPORTED); + Log.d("MediaButtonReceiver", "registerReceiver"); + } + + public static void unregisterReceiver(Context context) { + if (instance != null) { + context.unregisterReceiver(instance); + instance = null; + } + } +} diff --git a/src/homeform.cpp b/src/homeform.cpp index 533963252..1e24742c6 100644 --- a/src/homeform.cpp +++ b/src/homeform.cpp @@ -5,6 +5,7 @@ #include "localipaddress.h" #ifdef Q_OS_ANDROID #include "keepawakehelper.h" +#include #include #endif #include "material.h" @@ -693,11 +694,45 @@ homeform::homeform(QQmlApplicationEngine *engine, bluetooth *bl) { QAndroidJniObject javaPath = QAndroidJniObject::fromString(getWritableAppDir()); QAndroidJniObject::callStaticMethod("org/cagnulen/qdomyoszwift/Shortcuts", "createShortcutsForFiles", "(Ljava/lang/String;Landroid/content/Context;)V", javaPath.object(), QtAndroid::androidContext().object()); + + QAndroidJniObject::callStaticMethod("org/cagnulen/qdomyoszwift/MediaButtonReceiver", + "registerReceiver", + "(Landroid/content/Context;)V", + QtAndroid::androidContext().object()); #endif bluetoothManager->homeformLoaded = true; } +#ifdef Q_OS_ANDROID +extern "C" { +JNIEXPORT void JNICALL + Java_org_cagnulen_qdomyoszwift_MediaButtonReceiver_nativeOnMediaButtonEvent(JNIEnv *env, jobject obj, jint prev, jint current, jint max) { + qDebug() << "Media button event: current =" << current << "max =" << max << "prev =" << prev; + static QDateTime volumeLastChange = QDateTime::currentDateTime(); + QSettings settings; + bool gears_volume_debouncing = settings.value(QZSettings::gears_volume_debouncing, QZSettings::default_gears_volume_debouncing).toBool(); + + if (!settings.value(QZSettings::volume_change_gears, QZSettings::default_volume_change_gears).toBool()) { + qDebug() << "volume_change_gears disabled!"; + return; + } + + if(gears_volume_debouncing && volumeLastChange.msecsTo(QDateTime::currentDateTime()) < 500) { + qDebug() << "volume debouncing"; + return; + } + + if(prev > current) + homeform::singleton()->Minus(QStringLiteral("gears")); + else + homeform::singleton()->Plus(QStringLiteral("gears")); + + volumeLastChange = QDateTime::currentDateTime(); + } +} +#endif + void homeform::setActivityDescription(QString desc) { activityDescription = desc; } void homeform::chartSaved(QString fileName) { diff --git a/src/homeform.h b/src/homeform.h index bbf50fa67..ca1c572fa 100644 --- a/src/homeform.h +++ b/src/homeform.h @@ -800,6 +800,8 @@ class homeform : public QObject { void saveProfile(QString profilename); void restart(); bool pelotonAskStart() { return m_pelotonAskStart; } + void Minus(const QString &); + void Plus(const QString &); private slots: void Start(); @@ -808,8 +810,6 @@ class homeform : public QObject { void StartRequested(); void StopRequested(); void Lap(); - void Minus(const QString &); - void Plus(const QString &); void LargeButton(const QString &); void volumeDown(); void volumeUp(); diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index 18a16dcd9..f0babb5a1 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -761,6 +761,7 @@ DISTFILES += \ $$PWD/android/src/HidBridge.java \ $$PWD/android/src/IQMessageReceiverWrapper.java \ $$PWD/android/src/LocationHelper.java \ + $$PWD/android/src/MediaButtonReceiver.java \ $$PWD/android/src/MediaProjection.java \ $$PWD/android/src/NotificationUtils.java \ $$PWD/android/src/ScreenCaptureService.java \ From 04141fbb9fd9c7710cb5d28616529b74391746f9 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sat, 28 Sep 2024 20:02:45 +0200 Subject: [PATCH 140/162] Can not auto adjust downhill inclination in Kinomap (Issue #2625) --- src/characteristics/characteristicwriteprocessor2ad9.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/characteristics/characteristicwriteprocessor2ad9.cpp b/src/characteristics/characteristicwriteprocessor2ad9.cpp index 71459f032..cc9d1e772 100644 --- a/src/characteristics/characteristicwriteprocessor2ad9.cpp +++ b/src/characteristics/characteristicwriteprocessor2ad9.cpp @@ -96,8 +96,6 @@ int CharacteristicWriteProcessor2AD9::writeProcess(quint16 uuid, const QByteArra int16_t sincline = a + (((int16_t)b) << 8); double requestIncline = (double)sincline / 10.0; - if (requestIncline < 0) - requestIncline = 0; if (dt == bluetoothdevice::TREADMILL) ((treadmill *)Bike)->changeInclination(requestIncline, requestIncline); From fb374d966d14e6a4c3fb569f71b0b8b544d5290b Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Sun, 29 Sep 2024 08:02:13 +0200 Subject: [PATCH 141/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers (Issue #2541) --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/ftmsbike/ftmsbike.cpp | 18 ++++++++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index acde9ff3d..96e6dd131 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 880; + CURRENT_PROJECT_VERSION = 882; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 880; + CURRENT_PROJECT_VERSION = 882; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 880; + CURRENT_PROJECT_VERSION = 882; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 880; + CURRENT_PROJECT_VERSION = 882; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 880; + CURRENT_PROJECT_VERSION = 882; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 880; + CURRENT_PROJECT_VERSION = 882; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 5f7b278a2..2912e1ea0 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -24,6 +24,7 @@ using namespace std::chrono_literals; ftmsbike::ftmsbike(bool noWriteResistance, bool noHeartService, int8_t bikeResistanceOffset, double bikeResistanceGain) { + QSettings settings; m_watt.setType(metric::METRIC_WATT); Speed.setType(metric::METRIC_SPEED); refresh = new QTimer(this); @@ -33,7 +34,7 @@ ftmsbike::ftmsbike(bool noWriteResistance, bool noHeartService, int8_t bikeResis this->bikeResistanceOffset = bikeResistanceOffset; initDone = false; connect(refresh, &QTimer::timeout, this, &ftmsbike::update); - refresh->start(200ms); + refresh->start(settings.value(QZSettings::poll_device_time, QZSettings::default_poll_device_time).toInt()); } void ftmsbike::writeCharacteristicZwiftPlay(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log, @@ -160,7 +161,7 @@ void ftmsbike::zwiftPlayInit() { writeCharacteristicZwiftPlay(init2, sizeof(init2), "init2", false, true); writeCharacteristicZwiftPlay(init4, sizeof(init4), "init4", false, true); - uint8_t init8[] = {0x04, 0x22, 0x02, 0x10, 0x01}; + uint8_t init8[] = {0x04, 0x22, 0x02, 0x10, 0x00}; writeCharacteristicZwiftPlay(init8, sizeof(init8), "init8", false, true); } } @@ -1044,7 +1045,7 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact lastPacketFromFTMS.clear(); for(int i=0; i> 8; - + qDebug() << "applying gears mod" << gears() << gearsZwiftRatio() << slope; + } else if(b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS && zwiftPlayService != nullptr && gears_zwift_ratio) { + int16_t slope = (((uint8_t)b.at(3)) + (b.at(4) << 8)); + uint8_t gear2[] = {0x04, 0x22, 0x02, 0x10, 0x00}; + int g = (int)(((double)slope / 100.0) + settings.value(QZSettings::gears_offset, QZSettings::default_gears_offset).toDouble()); + if(g < 0) { + g = 0; + } + gear2[4] = g; + writeCharacteristicZwiftPlay(gear2, sizeof(gear2), "gearInclination", false, false); } else if(b.at(0) == FTMS_SET_TARGET_POWER && b.length() > 2) { lastPacketFromFTMS.clear(); for(int i=0; i Date: Sun, 29 Sep 2024 16:04:17 +0200 Subject: [PATCH 142/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers (Issue #2541) --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 +- src/devices/ftmsbike/ftmsbike.cpp | 172 +++++++++--------- 2 files changed, 97 insertions(+), 87 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 96e6dd131..ba78d2dfe 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 883; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 883; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 883; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 883; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 883; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 882; + CURRENT_PROJECT_VERSION = 883; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 2912e1ea0..e1ca36235 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -292,88 +292,98 @@ void ftmsbike::update() { if(zwiftPlayService && gears_zwift_ratio && lastGearValue != gears()) { uint8_t gear1[] = {0x04, 0x2a, 0x03, 0x10, 0xdc, 0xec}; uint8_t gear2[] = {0x04, 0x2a, 0x04, 0x10, 0xdc, 0xec, 0x01}; + uint32_t gear_value = 0; + switch((int)gears()) { - case 1: - gear1[4] = 0xcc; gear1[5] = 0x3a; - break; - case 2: - gear1[4] = 0xfc; gear1[5] = 0x43; - break; - case 3: - gear1[4] = 0xac; gear1[5] = 0x4d; - break; - case 4: - gear1[4] = 0xd5; gear1[5] = 0x56; - break; - case 5: - gear1[4] = 0x8c; gear1[5] = 0x60; - break; - case 6: - gear1[4] = 0xe8; gear1[5] = 0x6b; - break; - case 7: - gear1[4] = 0xc4; gear1[5] = 0x77; - break; - case 8: - gear2[4] = 0xa0; gear2[5] = 0x83; - break; - case 9: - gear2[4] = 0xa8; gear2[5] = 0x91; - break; - case 10: - gear2[4] = 0xb0; gear2[5] = 0x9f; - break; - case 11: - gear2[4] = 0xb8; gear2[5] = 0xad; - break; - case 12: - gear2[4] = 0xc0; gear2[5] = 0xbb; - break; - case 13: - gear2[4] = 0xf3; gear2[5] = 0xcb; - break; - case 14: - gear2[4] = 0xa8; gear2[5] = 0xdc; - break; - case 15: - gear2[4] = 0xdc; gear2[5] = 0xec; - break; - case 16: - gear2[4] = 0x90; gear2[5] = 0xfd; - break; - case 17: - gear2[4] = 0xd4; gear2[5] = 0x90; gear2[6] = 0x02; - break; - case 18: - gear2[4] = 0x98; gear2[5] = 0xa4; gear2[6] = 0x02; - break; - case 19: - gear2[4] = 0xdc; gear2[5] = 0xb7; gear2[6] = 0x02; - break; - case 20: - gear2[4] = 0x9f; gear2[5] = 0xcb; gear2[6] = 0x02; - break; - case 21: - gear2[4] = 0xd8; gear2[5] = 0xe2; gear2[6] = 0x02; - break; - case 22: - gear2[4] = 0x90; gear2[5] = 0xfa; gear2[6] = 0x02; - break; - case 23: - gear2[4] = 0xc8; gear2[5] = 0x91; gear2[6] = 0x03; - break; - case 24: - gear2[4] = 0xf3; gear2[5] = 0xac; gear2[6] = 0x03; - break; - default: - // Gestione del caso di default - break; + case 1: + gear_value = 0x3acc; + break; + case 2: + gear_value = 0x43fc; + break; + case 3: + gear_value = 0x4dac; + break; + case 4: + gear_value = 0x56d5; + break; + case 5: + gear_value = 0x608c; + break; + case 6: + gear_value = 0x6be8; + break; + case 7: + gear_value = 0x77c4; + break; + case 8: + gear_value = 0x183a0; + break; + case 9: + gear_value = 0x191a8; + break; + case 10: + gear_value = 0x19fb0; + break; + case 11: + gear_value = 0x1adb8; + break; + case 12: + gear_value = 0x1bbc0; + break; + case 13: + gear_value = 0x1cbf3; + break; + case 14: + gear_value = 0x1dca8; + break; + case 15: + gear_value = 0x1ecdc; + break; + case 16: + gear_value = 0x1fd90; + break; + case 17: + gear_value = 0x290d4; + break; + case 18: + gear_value = 0x2a498; + break; + case 19: + gear_value = 0x2b7dc; + break; + case 20: + gear_value = 0x2cb9f; + break; + case 21: + gear_value = 0x2e2d8; + break; + case 22: + gear_value = 0x2fa90; + break; + case 23: + gear_value = 0x391c8; + break; + case 24: + gear_value = 0x3acf3; + break; + default: + // Gestione del caso di default + break; } - if((int)gears() < 8) - writeCharacteristicZwiftPlay(gear1, sizeof(gear1), "gear", false, true); - else - writeCharacteristicZwiftPlay(gear2, sizeof(gear2), "gear", false, true); + gear_value = gear_value * settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble(); + + if(gear_value < 0x10000) { + gear1[4] = gear_value & 0xFF; + gear1[5] = ((gear_value & 0xFF00) >> 8) & 0xFF; + writeCharacteristicZwiftPlay(gear1, sizeof(gear1), "gear", false, true); + } else { + gear2[4] = gear_value & 0xFF; + gear2[5] = ((gear_value & 0xFF00) >> 8) & 0xFF; + gear2[6] = ((gear_value & 0xFF0000) >> 16) & 0xFF; + writeCharacteristicZwiftPlay(gear2, sizeof(gear2), "gear", false, true); + } uint8_t gearApply[] = {0x00, 0x08, 0x88, 0x04}; writeCharacteristicZwiftPlay(gearApply, sizeof(gearApply), "gearApply", false, true); @@ -1070,7 +1080,7 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact b[4] = slope >> 8; qDebug() << "applying gears mod" << gears() << gearsZwiftRatio() << slope; - } else if(b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS && zwiftPlayService != nullptr && gears_zwift_ratio) { + /*} else if(b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS && zwiftPlayService != nullptr && gears_zwift_ratio) { int16_t slope = (((uint8_t)b.at(3)) + (b.at(4) << 8)); uint8_t gear2[] = {0x04, 0x22, 0x02, 0x10, 0x00}; int g = (int)(((double)slope / 100.0) + settings.value(QZSettings::gears_offset, QZSettings::default_gears_offset).toDouble()); @@ -1078,7 +1088,7 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact g = 0; } gear2[4] = g; - writeCharacteristicZwiftPlay(gear2, sizeof(gear2), "gearInclination", false, false); + writeCharacteristicZwiftPlay(gear2, sizeof(gear2), "gearInclination", false, false);*/ } else if(b.at(0) == FTMS_SET_TARGET_POWER && b.length() > 2) { lastPacketFromFTMS.clear(); for(int i=0; i Date: Mon, 30 Sep 2024 14:29:48 +0200 Subject: [PATCH 143/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 https://github.com/cagnulein/qdomyos-zwift/issues/2541#issuecomment-2383003316 --- src/zwift_play/abstractZapDevice.h | 236 ++++++++++++++--------------- 1 file changed, 118 insertions(+), 118 deletions(-) diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index a92b0cf65..5806200c8 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -16,7 +16,7 @@ class AbstractZapDevice: public QObject { Q_OBJECT -public: + public: enum ZWIFT_PLAY_TYPE { NONE, LEFT, @@ -27,7 +27,7 @@ class AbstractZapDevice: public QObject { QByteArray REQUEST_START; QByteArray RESPONSE_START; - //ZapCrypto zapEncryption; + //ZapCrypto zapEncryption; AbstractZapDevice() /*: localKeyProvider(), zapEncryption(localKeyProvider)*/ { RIDE_ON = QByteArray::fromRawData("\x52\x69\x64\x65\x4F\x6E", 6); // "RideOn" REQUEST_START = QByteArray::fromRawData("\x00\x09", 2); // {0, 9} @@ -43,7 +43,7 @@ class AbstractZapDevice: public QObject { qDebug() << zapType << characteristicName << bytes.toHex() << zwiftplay_swap << gears_volume_debouncing << risingEdge; -#define DEBOUNCE (!gears_volume_debouncing || !risingEdge) +#define DEBOUNCE (!gears_volume_debouncing || risingEdge <= 0) #ifdef Q_OS_ANDROID_ENCRYPTION QAndroidJniEnvironment env; @@ -63,140 +63,140 @@ class AbstractZapDevice: public QObject { return button; #else switch(bytes[0]) { - case 0x37: - if(bytes.length() == 5) { - if(bytes[2] == 0) { - if(DEBOUNCE) { - risingEdge = true; - if(!zwiftplay_swap) - emit plus(); - else - emit minus(); - } - } else if(bytes[4] == 0) { - if(DEBOUNCE) { - risingEdge = true; - if(!zwiftplay_swap) - emit minus(); - else - emit plus(); - } - } else { - risingEdge = false; - } - } - break; - case 0x07: // zwift play - if(bytes.length() > 5 && bytes[bytes.length() - 5] == 0x40 && ( - (((uint8_t)bytes[bytes.length() - 4]) == 0xc7 && zapType == RIGHT) || - (((uint8_t)bytes[bytes.length() - 4]) == 0xc8 && zapType == LEFT) - ) && bytes[bytes.length() - 3] == 0x01) { - if(zapType == LEFT) { - if(DEBOUNCE) { - risingEdge = true; - if(!zwiftplay_swap) - emit plus(); - else - emit minus(); - } - } else { - if(DEBOUNCE) { - risingEdge = true; - if(!zwiftplay_swap) - emit minus(); - else - emit plus(); - } + case 0x37: + if(bytes.length() == 5) { + if(bytes[2] == 0) { + if(DEBOUNCE) { + risingEdge = 2; + if(!zwiftplay_swap) + emit plus(); + else + emit minus(); } - } else if(bytes.length() > 14 && bytes[11] == 0x30 && bytes[12] == 0x00) { - if(zapType == LEFT) { - if(DEBOUNCE) { - risingEdge = true; - if(!zwiftplay_swap) - emit plus(); - else - emit minus(); - } - } else { - if(DEBOUNCE) { - risingEdge = true; - if(!zwiftplay_swap) - emit minus(); - else - emit plus(); - } + } else if(bytes[4] == 0) { + if(DEBOUNCE) { + risingEdge = 2; + if(!zwiftplay_swap) + emit minus(); + else + emit plus(); } } else { - risingEdge = false; + risingEdge--; } - break; - case 0x15: // empty data - qDebug() << "ignoring this frame"; - return 1; - case 0x23: // zwift ride - if(bytes.length() > 12 && - ((((uint8_t)bytes[12]) == 0xc7 && zapType == RIGHT) || - (((uint8_t)bytes[12]) == 0xc8 && zapType == LEFT)) - ) { - if(zapType == LEFT) { - if(DEBOUNCE) { - risingEdge = true; - if(!zwiftplay_swap) - emit plus(); - else - emit minus(); - } - } else { - if(DEBOUNCE) { - risingEdge = true; - if(!zwiftplay_swap) - emit minus(); - else - emit plus(); - } - } - } else if(bytes.length() > 19 && ((uint8_t)bytes[18]) == 0xc8) { + } + break; + case 0x07: // zwift play + if(bytes.length() > 5 && bytes[bytes.length() - 5] == 0x40 && ( + (((uint8_t)bytes[bytes.length() - 4]) == 0xc7 && zapType == RIGHT) || + (((uint8_t)bytes[bytes.length() - 4]) == 0xc8 && zapType == LEFT) + ) && bytes[bytes.length() - 3] == 0x01) { + if(zapType == LEFT) { if(DEBOUNCE) { - risingEdge = true; + risingEdge = 2; if(!zwiftplay_swap) emit plus(); else emit minus(); } - } else if(bytes.length() > 3 && - ((((uint8_t)bytes[3]) == 0xdf) || // right top button - (((uint8_t)bytes[3]) == 0xbf))) { // right bottom button + } else { + if(DEBOUNCE) { + risingEdge = 2; + if(!zwiftplay_swap) + emit minus(); + else + emit plus(); + } + } + } else if(bytes.length() > 14 && bytes[11] == 0x30 && bytes[12] == 0x00) { + if(zapType == LEFT) { if(DEBOUNCE) { - risingEdge = true; + risingEdge = 2; if(!zwiftplay_swap) emit plus(); else emit minus(); } - } else if(bytes.length() > 3 && - ((((uint8_t)bytes[3]) == 0xfd) || // left top button - (((uint8_t)bytes[3]) == 0xfb))) { // left bottom button + } else { if(DEBOUNCE) { - risingEdge = true; + risingEdge = 2; if(!zwiftplay_swap) emit minus(); else emit plus(); } - } else if(bytes.length() > 5 && - ((((uint8_t)bytes[4]) == 0xfd) || // left top button - (((uint8_t)bytes[4]) == 0xfb))) { // left bottom button + } + } else { + risingEdge--; + } + break; + case 0x15: // empty data + qDebug() << "ignoring this frame"; + return 1; + case 0x23: // zwift ride + if(bytes.length() > 12 && + ((((uint8_t)bytes[12]) == 0xc7 && zapType == RIGHT) || + (((uint8_t)bytes[12]) == 0xc8 && zapType == LEFT)) + ) { + if(zapType == LEFT) { + if(DEBOUNCE) { + risingEdge = 2; + if(!zwiftplay_swap) + emit plus(); + else + emit minus(); + } + } else { if(DEBOUNCE) { - risingEdge = true; + risingEdge = 2; if(!zwiftplay_swap) emit minus(); else emit plus(); - } - } else { - risingEdge = false; + } + } + } else if(bytes.length() > 19 && ((uint8_t)bytes[18]) == 0xc8) { + if(DEBOUNCE) { + risingEdge = 2; + if(!zwiftplay_swap) + emit plus(); + else + emit minus(); + } + } else if(bytes.length() > 3 && + ((((uint8_t)bytes[3]) == 0xdf) || // right top button + (((uint8_t)bytes[3]) == 0xbf))) { // right bottom button + if(DEBOUNCE) { + risingEdge = 2; + if(!zwiftplay_swap) + emit plus(); + else + emit minus(); + } + } else if(bytes.length() > 3 && + ((((uint8_t)bytes[3]) == 0xfd) || // left top button + (((uint8_t)bytes[3]) == 0xfb))) { // left bottom button + if(DEBOUNCE) { + risingEdge = 2; + if(!zwiftplay_swap) + emit minus(); + else + emit plus(); + } + } else if(bytes.length() > 5 && + ((((uint8_t)bytes[4]) == 0xfd) || // left top button + (((uint8_t)bytes[4]) == 0xfb))) { // left bottom button + if(DEBOUNCE) { + risingEdge = 2; + if(!zwiftplay_swap) + emit minus(); + else + emit plus(); } - break; + } else { + risingEdge--; + } + break; } return 1; @@ -212,20 +212,20 @@ class AbstractZapDevice: public QObject { // Ottiene la lunghezza dell'array di byte jsize length = QAndroidJniEnvironment()->GetArrayLength(result.object()); - // Allocare memoria per i byte nativi + // Allocare memoria per i byte nativi jbyte* bytes = QAndroidJniEnvironment()->GetByteArrayElements(result.object(), nullptr); - // Costruire un QByteArray dal buffer di byte nativi + // Costruire un QByteArray dal buffer di byte nativi QByteArray byteArray(reinterpret_cast(bytes), length); - // Rilasciare la memoria dell'array di byte JNI + // Rilasciare la memoria dell'array di byte JNI QAndroidJniEnvironment()->ReleaseByteArrayElements(result.object(), bytes, JNI_ABORT); - // Ora puoi usare byteArray come necessario + // Ora puoi usare byteArray come necessario return byteArray; } #endif - //return RIDE_ON + REQUEST_START + localKeyProvider.getPublicKeyBytes(); + //return RIDE_ON + REQUEST_START + localKeyProvider.getPublicKeyBytes(); QByteArray a; a.append(0x52); a.append(0x69); @@ -236,14 +236,14 @@ class AbstractZapDevice: public QObject { return a; } -protected: + protected: virtual void processEncryptedData(const QByteArray& bytes) = 0; -private: + private: QByteArray devicePublicKeyBytes; - static volatile bool risingEdge; + static volatile int8_t risingEdge; -signals: + signals: void plus(); void minus(); }; From 23c803add19685678e6e69fa172a2b1c7d402d33 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 30 Sep 2024 14:31:51 +0200 Subject: [PATCH 144/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index ba78d2dfe..aa5d373df 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 883; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 883; + CURRENT_PROJECT_VERSION = 884; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 883; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 883; + CURRENT_PROJECT_VERSION = 884; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 883; + CURRENT_PROJECT_VERSION = 884; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 883; + CURRENT_PROJECT_VERSION = 884; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From a220efa9a455d86322223230d6030e103d442514 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 30 Sep 2024 14:32:45 +0200 Subject: [PATCH 145/162] Update zwiftclickremote.cpp --- src/zwift_play/zwiftclickremote.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zwift_play/zwiftclickremote.cpp b/src/zwift_play/zwiftclickremote.cpp index cd64125bf..7ae9aa489 100755 --- a/src/zwift_play/zwiftclickremote.cpp +++ b/src/zwift_play/zwiftclickremote.cpp @@ -14,7 +14,7 @@ using namespace std::chrono_literals; extern quint8 QZ_EnableDiscoveryCharsAndDescripttors; #endif -volatile bool AbstractZapDevice::risingEdge = false; +volatile int8_t AbstractZapDevice::risingEdge = 0; zwiftclickremote::zwiftclickremote(bluetoothdevice *parentDevice, AbstractZapDevice::ZWIFT_PLAY_TYPE typeZap) { #ifdef Q_OS_IOS From c39f80bdebeea4972f6b7d4baca5051ace5e7db5 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 30 Sep 2024 15:50:56 +0200 Subject: [PATCH 146/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers (Issue #2541) --- src/devices/bike.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/devices/bike.h b/src/devices/bike.h index c9a711675..c296a9138 100644 --- a/src/devices/bike.h +++ b/src/devices/bike.h @@ -60,10 +60,18 @@ class bike : public bluetoothdevice { void changeInclination(double grade, double percentage) override; virtual void changeSteeringAngle(double angle) { m_steeringAngle = angle; } virtual void resistanceFromFTMSAccessory(resistance_t res) { Q_UNUSED(res); } - void gearUp() {QSettings settings; setGears(gears() + - settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble());} - void gearDown() {QSettings settings; setGears(gears() - - settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble());} + void gearUp() { + QSettings settings; + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + setGears(gears() + (gears_zwift_ratio ? 1 : + settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble())); + } + void gearDown() { + QSettings settings; + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + setGears(gears() - (gears_zwift_ratio ? 1 : + settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble())); + } Q_SIGNALS: void bikeStarted(); From 5d4b2a1fe1c557cd86e35265cedc12f86773ffce Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 30 Sep 2024 16:12:47 +0200 Subject: [PATCH 147/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index aa5d373df..8a69252a0 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 884; + CURRENT_PROJECT_VERSION = 885; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 884; + CURRENT_PROJECT_VERSION = 885; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 884; + CURRENT_PROJECT_VERSION = 885; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 884; + CURRENT_PROJECT_VERSION = 885; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 884; + CURRENT_PROJECT_VERSION = 885; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 884; + CURRENT_PROJECT_VERSION = 885; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 1b597c16ddac2f6cf5bdd6eb9f95661fe91ddddf Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 30 Sep 2024 16:13:13 +0200 Subject: [PATCH 148/162] Can not auto adjust downhill inclination in Kinomap- Sole TT8 treadmill #2625 --- src/virtualdevices/virtualtreadmill.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/virtualdevices/virtualtreadmill.cpp b/src/virtualdevices/virtualtreadmill.cpp index b51bf0d0f..00f031b46 100644 --- a/src/virtualdevices/virtualtreadmill.cpp +++ b/src/virtualdevices/virtualtreadmill.cpp @@ -156,8 +156,8 @@ virtualtreadmill::virtualtreadmill(bluetoothdevice *t, bool noHeartService) { (QBluetoothUuid::CharacteristicType)0x2AD6); // supported_resistance_level_rangeCharacteristicUuid charDataFIT2.setProperties(QLowEnergyCharacteristic::Read); QByteArray valueFIT2; - valueFIT2.append((char)0x0A); // min resistance value - valueFIT2.append((char)0x00); // min resistance value + valueFIT2.append((char)0x6A); // min resistance value + valueFIT2.append((char)0xFF); // min resistance value (-15 for kinomap) valueFIT2.append((char)0x96); // max resistance value valueFIT2.append((char)0x00); // max resistance value valueFIT2.append((char)0x0A); // step resistance From 60068dea5b528fa5c50cc011d4d62759b51f8a2e Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 30 Sep 2024 17:34:21 +0200 Subject: [PATCH 149/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers #2541 --- src/zwift_play/abstractZapDevice.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/zwift_play/abstractZapDevice.h b/src/zwift_play/abstractZapDevice.h index 5806200c8..ba429e67e 100755 --- a/src/zwift_play/abstractZapDevice.h +++ b/src/zwift_play/abstractZapDevice.h @@ -83,6 +83,8 @@ class AbstractZapDevice: public QObject { } } else { risingEdge--; + if(risingEdge < 0) + risingEdge = 0; } } break; @@ -128,6 +130,8 @@ class AbstractZapDevice: public QObject { } } else { risingEdge--; + if(risingEdge < 0) + risingEdge = 0; } break; case 0x15: // empty data @@ -195,6 +199,8 @@ class AbstractZapDevice: public QObject { } } else { risingEdge--; + if(risingEdge < 0) + risingEdge = 0; } break; From 533fba4c6e2e31b87bf5b67c85feee8df2e38a29 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 30 Sep 2024 18:13:25 +0200 Subject: [PATCH 150/162] Revert "Can not auto adjust downhill inclination in Kinomap- Sole TT8 treadmill #2625" This reverts commit 1b597c16ddac2f6cf5bdd6eb9f95661fe91ddddf. --- src/virtualdevices/virtualtreadmill.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/virtualdevices/virtualtreadmill.cpp b/src/virtualdevices/virtualtreadmill.cpp index 00f031b46..b51bf0d0f 100644 --- a/src/virtualdevices/virtualtreadmill.cpp +++ b/src/virtualdevices/virtualtreadmill.cpp @@ -156,8 +156,8 @@ virtualtreadmill::virtualtreadmill(bluetoothdevice *t, bool noHeartService) { (QBluetoothUuid::CharacteristicType)0x2AD6); // supported_resistance_level_rangeCharacteristicUuid charDataFIT2.setProperties(QLowEnergyCharacteristic::Read); QByteArray valueFIT2; - valueFIT2.append((char)0x6A); // min resistance value - valueFIT2.append((char)0xFF); // min resistance value (-15 for kinomap) + valueFIT2.append((char)0x0A); // min resistance value + valueFIT2.append((char)0x00); // min resistance value valueFIT2.append((char)0x96); // max resistance value valueFIT2.append((char)0x00); // max resistance value valueFIT2.append((char)0x0A); // step resistance From cf6b1953e0426449dd7f7cdcd42ed09030d7fcda Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Mon, 30 Sep 2024 18:14:36 +0200 Subject: [PATCH 151/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 8a69252a0..22772c0fd 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 885; + CURRENT_PROJECT_VERSION = 886; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 885; + CURRENT_PROJECT_VERSION = 886; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 885; + CURRENT_PROJECT_VERSION = 886; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 885; + CURRENT_PROJECT_VERSION = 886; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 885; + CURRENT_PROJECT_VERSION = 886; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 885; + CURRENT_PROJECT_VERSION = 886; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 77b2ec46d1ba9aa54315101f04142a30ec6bdad1 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Tue, 1 Oct 2024 14:36:33 +0200 Subject: [PATCH 152/162] Several Issues Using QZ with Rouvy and Zwift Play Controllers (Issue #2541) --- src/homeform.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/homeform.cpp b/src/homeform.cpp index 1e24742c6..7bcf5ab7e 100644 --- a/src/homeform.cpp +++ b/src/homeform.cpp @@ -4392,7 +4392,8 @@ void homeform::update() { this->target_power->setValue( QString::number(((bike *)bluetoothManager->device())->lastRequestedPower().value(), 'f', 0)); this->resistance->setValue(QString::number(resistance, 'f', 0)); - if (settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble() == 1.0) + bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); + if (settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble() == 1.0 || gears_zwift_ratio) this->gears->setValue(QString::number(((bike *)bluetoothManager->device())->gears())); else this->gears->setValue(QString::number(((bike *)bluetoothManager->device())->gears(), 'f', 1)); From 01cd02ef94c2e87174c85634e5a9617377590db8 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 2 Oct 2024 16:00:25 +0200 Subject: [PATCH 153/162] Felvon v2 #2627 --- src/devices/bluetooth.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 3e8ef6aed..5e57ca4e3 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1533,6 +1533,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { (b.name().toUpper().startsWith("WLT8828")) || (b.name().toUpper().startsWith("VANRYSEL-HT")) || (b.name().toUpper().startsWith("HARISON-X15")) || + (b.name().toUpper().startsWith("FEIVON V2")) || + (b.name().toUpper().startsWith("FELVON V2")) || (b.name().toUpper().startsWith("GLT") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || (b.name().toUpper().startsWith("SPORT01-") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // Labgrey Magnetic Exercise Bike https://www.amazon.co.uk/dp/B0CXMF1NPY?_encoding=UTF8&psc=1&ref=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&ref_=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&social_share=cm_sw_r_cp_ud_dp_PE420HA7RD7WJBZPN075&skipTwisterOG=1 (b.name().toUpper().startsWith("ZUMO")) || (b.name().toUpper().startsWith("XS08-")) || From eb540dc579a63f87231d2cce96942779788c6638 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Wed, 2 Oct 2024 21:07:17 +0200 Subject: [PATCH 154/162] removing gears_zwift_ratio for device that are not supporting it #2608 --- src/devices/ftmsbike/ftmsbike.cpp | 22 +++---------------- src/devices/tacxneo2/tacxneo2.cpp | 20 ++--------------- .../wahookickrsnapbike/wahookickrsnapbike.cpp | 15 +------------ 3 files changed, 6 insertions(+), 51 deletions(-) diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index e1ca36235..5d22ff74e 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -1057,29 +1057,13 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact lastPacketFromFTMS.append(b.at(i)); qDebug() << "lastPacketFromFTMS" << lastPacketFromFTMS.toHex(' '); int16_t slope = (((uint8_t)b.at(3)) + (b.at(4) << 8)); - if(!gears_zwift_ratio) { - if (gears() != 0) { - slope += (gears() * 50); - } - } else { - if(slope == 0) { - slope = 30 * gearsZwiftRatio(); - } else if(slope < 0) { - int16_t absslope = abs(slope); - if(absslope < 30) - absslope = 30; - absslope *= gearsZwiftRatio(); - slope += absslope - slope; - } else { - if(slope < 30) - slope = 30; - slope *= gearsZwiftRatio(); - } + if (gears() != 0) { + slope += (gears() * 50); } b[3] = slope & 0xFF; b[4] = slope >> 8; - qDebug() << "applying gears mod" << gears() << gearsZwiftRatio() << slope; + qDebug() << "applying gears mod" << gears() << slope; /*} else if(b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS && zwiftPlayService != nullptr && gears_zwift_ratio) { int16_t slope = (((uint8_t)b.at(3)) + (b.at(4) << 8)); uint8_t gear2[] = {0x04, 0x22, 0x02, 0x10, 0x00}; diff --git a/src/devices/tacxneo2/tacxneo2.cpp b/src/devices/tacxneo2/tacxneo2.cpp index 87027a9e7..c180aa3d0 100644 --- a/src/devices/tacxneo2/tacxneo2.cpp +++ b/src/devices/tacxneo2/tacxneo2.cpp @@ -140,24 +140,8 @@ void tacxneo2::update() { requestInclination = -100; } else if((virtualBike && virtualBike->ftmsDeviceConnected()) && lastGearValue != gears() && lastRawRequestedInclinationValue != -100) { // in order to send the new gear value ASAP - QSettings settings; - bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); - if(!gears_zwift_ratio) { - forceInclination(lastRawRequestedInclinationValue + gears()); // since this bike doesn't have the concept of resistance, - // i'm using the gears in the inclination - } else { - double slope = lastRawRequestedInclinationValue; - if(slope == 0) { - slope = 0.1 * gearsZwiftRatio(); - } else if(slope < 0) { - double absslope = fabs(slope); - absslope *= gearsZwiftRatio(); - slope += absslope - slope; - } else { - slope *= gearsZwiftRatio(); - } - forceInclination(slope); - } + forceInclination(lastRawRequestedInclinationValue + gears()); // since this bike doesn't have the concept of resistance, + // i'm using the gears in the inclination } lastGearValue = gears(); diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index d6934a456..caa489acc 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -822,21 +822,8 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) { lastGrade = grade; emit debug(QStringLiteral("writing inclination ") + QString::number(grade)); QSettings settings; - bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool(); double g = grade; - if(!gears_zwift_ratio) - g += gears(); - else { - if(g == 0) { - g = 0.1 * gearsZwiftRatio(); - } else if(g < 0) { - int16_t absslope = abs(g); - absslope *= gearsZwiftRatio(); - g += absslope - g; - } else { - g *= gearsZwiftRatio(); - } - } + g += gears(); QByteArray a = setSimGrade(g); uint8_t b[20]; memcpy(b, a.constData(), a.length()); From e767e964abf6a0999e786c224e4ce01bcf8a6028 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 3 Oct 2024 11:43:35 +0200 Subject: [PATCH 155/162] ]DeerRun Treadmill integration #2621 i need to add it to the bluetooth.cpp --- src/devices/bluetooth.h | 2 + .../deeruntreadmill/deerruntreadmill.cpp | 495 ++++++++++++++++++ .../deeruntreadmill/deerruntreadmill.h | 103 ++++ src/qdomyos-zwift.pri | 2 + 4 files changed, 602 insertions(+) create mode 100644 src/devices/deeruntreadmill/deerruntreadmill.cpp create mode 100644 src/devices/deeruntreadmill/deerruntreadmill.h diff --git a/src/devices/bluetooth.h b/src/devices/bluetooth.h index 90d58f7b3..f5df33c07 100644 --- a/src/devices/bluetooth.h +++ b/src/devices/bluetooth.h @@ -36,6 +36,7 @@ #include "devices/concept2skierg/concept2skierg.h" #include "devices/crossrope/crossrope.h" #include "devices/cscbike/cscbike.h" +#include "devices/deeruntreadmill/deerruntreadmill.h" #include "devices/domyosbike/domyosbike.h" #include "devices/domyoselliptical/domyoselliptical.h" #include "devices/domyosrower/domyosrower.h" @@ -176,6 +177,7 @@ class bluetooth : public QObject, public SignalHandler { csaferower *csafeRower = nullptr; #endif concept2skierg *concept2Skierg = nullptr; + deerruntreadmill *deerrunTreadmill = nullptr; domyostreadmill *domyos = nullptr; domyosbike *domyosBike = nullptr; domyosrower *domyosRower = nullptr; diff --git a/src/devices/deeruntreadmill/deerruntreadmill.cpp b/src/devices/deeruntreadmill/deerruntreadmill.cpp new file mode 100644 index 000000000..3ca9af850 --- /dev/null +++ b/src/devices/deeruntreadmill/deerruntreadmill.cpp @@ -0,0 +1,495 @@ +#include "deerruntreadmill.h" +#include "virtualdevices/virtualbike.h" + +#ifdef Q_OS_ANDROID +#include "keepawakehelper.h" +#endif +#include "virtualdevices/virtualtreadmill.h" +#include +#include +#include +#include +#include +#include + +using namespace std::chrono_literals; + +deerruntreadmill::deerruntreadmill(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 (forceInitSpeed > 0) { + lastSpeed = forceInitSpeed; + } + + if (forceInitInclination > 0) { + lastInclination = forceInitInclination; + } + + refresh = new QTimer(this); + initDone = false; + connect(refresh, &QTimer::timeout, this, &deerruntreadmill::update); + refresh->start(pollDeviceTime); +} + +void deerruntreadmill::writeCharacteristic(const QLowEnergyCharacteristic characteristic, uint8_t *data, + uint8_t data_len, const QString &info, bool disable_log, + bool wait_for_response) { + QEventLoop loop; + QTimer timeout; + + if (wait_for_response) { + connect(this, &deerruntreadmill::packetReceived, &loop, &QEventLoop::quit); + timeout.singleShot(300ms, &loop, &QEventLoop::quit); + } else { + connect(gattCommunicationChannelService, &QLowEnergyService::characteristicWritten, &loop, &QEventLoop::quit); + timeout.singleShot(300ms, &loop, &QEventLoop::quit); + } + + if (gattCommunicationChannelService->state() != QLowEnergyService::ServiceState::ServiceDiscovered || + m_control->state() == QLowEnergyController::UnconnectedState) { + emit debug(QStringLiteral("writeCharacteristic error because the connection is closed")); + + return; + } + + if (writeBuffer) { + delete writeBuffer; + } + writeBuffer = new QByteArray((const char *)data, data_len); + + gattCommunicationChannelService->writeCharacteristic(characteristic, *writeBuffer); + + if (!disable_log) { + emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') + + QStringLiteral(" // ") + info); + } + + loop.exec(); + + if (timeout.isActive() == false) { + emit debug(QStringLiteral(" exit for timeout")); + } +} + +uint8_t deerruntreadmill::calculateXOR(uint8_t arr[], size_t size) { + uint8_t result = 0; + + if (size < 7) { + qDebug() << QStringLiteral("array too small"); + return 0; + } + + for (size_t i = 5; i <= size - 3; i++) { + result ^= arr[i]; + } + + return result; +} + + +void deerruntreadmill::forceSpeed(double requestSpeed) { + QSettings settings; + uint8_t writeSpeed[] = {0x4d, 0x00, 0xc9, 0x17, 0x6a, 0x17, 0x02, 0x00, 0x06, 0x40, 0x04, 0x4c, 0x01, 0x00, 0x50, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x85, 0x11, 0xd8, 0x43}; + + writeSpeed[2] = pollCounter; + writeSpeed[10] = ((int)((requestSpeed * 100)) >> 8) & 0xFF; + writeSpeed[11] = ((int)((requestSpeed * 100))) & 0xFF; + writeSpeed[25] = calculateXOR(writeSpeed, sizeof(writeSpeed)); + + writeCharacteristic(gattWriteCharacteristic, writeSpeed, sizeof(writeSpeed), + QStringLiteral("forceSpeed speed=") + QString::number(requestSpeed), false, false); +} + +void deerruntreadmill::forceIncline(double requestIncline) { + +} + +void deerruntreadmill::changeInclinationRequested(double grade, double percentage) { + if (percentage < 0) + percentage = 0; + changeInclination(grade, percentage); +} + +void deerruntreadmill::update() { + if (m_control->state() == QLowEnergyController::UnconnectedState) { + emit disconnected(); + return; + } + + if (initRequest) { + + initRequest = false; + btinit((lastSpeed > 0 ? true : false)); + } else if (/*bluetoothDevice.isValid() &&*/ + m_control->state() == QLowEnergyController::DiscoveredState && gattCommunicationChannelService && + gattWriteCharacteristic.isValid() && gattNotifyCharacteristic.isValid() && initDone) { + + QSettings settings; + // ******************************************* virtual treadmill init ************************************* + if (!firstInit && !this->hasVirtualDevice()) { + bool virtual_device_enabled = + settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool(); + bool virtual_device_force_bike = + settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike) + .toBool(); + if (virtual_device_enabled) { + if (!virtual_device_force_bike) { + debug("creating virtual treadmill interface..."); + auto virtualTreadMill = new virtualtreadmill(this, noHeartService); + connect(virtualTreadMill, &virtualtreadmill::debug, this, &deerruntreadmill::debug); + connect(virtualTreadMill, &virtualtreadmill::changeInclination, this, + &deerruntreadmill::changeInclinationRequested); + this->setVirtualDevice(virtualTreadMill, VIRTUAL_DEVICE_MODE::PRIMARY); + } else { + debug("creating virtual bike interface..."); + auto virtualBike = new virtualbike(this); + connect(virtualBike, &virtualbike::changeInclination, this, + &deerruntreadmill::changeInclinationRequested); + this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::ALTERNATIVE); + } + firstInit = 1; + } + } + // ******************************************************************************************************** + + // debug("Domyos Treadmill RSSI " + QString::number(bluetoothDevice.rssi())); + + update_metrics(true, watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())); + + { + if (requestSpeed != -1) { + if (requestSpeed != currentSpeed().value() && requestSpeed >= 0 && requestSpeed <= 22) { + emit debug(QStringLiteral("writing speed ") + QString::number(requestSpeed)); + forceSpeed(requestSpeed); + } + requestSpeed = -1; + } else if (requestInclination != -100) { + if (requestInclination < 0) + requestInclination = 0; + if (requestInclination != currentInclination().value() && requestInclination >= 0 && + requestInclination <= 15) { + emit debug(QStringLiteral("writing incline ") + QString::number(requestInclination)); + forceIncline(requestInclination); + } + requestInclination = -100; + } else if (requestStart != -1) { + emit debug(QStringLiteral("starting...")); + if (lastSpeed == 0.0) { + + lastSpeed = 0.5; + } + + // should be: + // 0x49 = inited + // 0x8a = tape stopped after a pause + /*if (lastState == 0x49)*/ { + uint8_t initData2[] = {0x4d, 0x00, 0x0c, 0x17, 0x6a, 0x17, 0x02, 0x00, 0x06, 0x40, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x85, 0x11, 0x2a, 0x43}; + initData2[2] = pollCounter; + + writeCharacteristic(gattWriteCharacteristic, initData2, sizeof(initData2), QStringLiteral("start"), + false, true); + } /*else { + uint8_t pause[] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x07}; + + writeCharacteristic(gattWriteCharacteristic, pause, sizeof(pause), QStringLiteral("pause"), false, + true); + }*/ + + requestStart = -1; + emit tapeStarted(); + } else if (requestStop != -1) { + emit debug(QStringLiteral("stopping... ") + paused); + /*if (lastState == PAUSED) { + uint8_t pause[] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x07}; + + writeCharacteristic(gattWriteCharacteristic, pause, sizeof(pause), QStringLiteral("pause"), false, + true); + + } else*/ { + uint8_t stop[] = {0x4d, 0x00, 0x48, 0x17, 0x6a, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x50, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x85, 0x11, 0xd6, 0x43}; + stop[2] = pollCounter; + + writeCharacteristic(gattWriteCharacteristic, stop, sizeof(stop), QStringLiteral("stop"), false, + true); + } + + requestStop = -1; + } else { + uint8_t poll[] = {0x4d, 0x00, 0x00, 0x05, 0x6a, 0x05, 0xfd, 0xf8, 0x43}; + poll[2] = pollCounter; + + writeCharacteristic(gattWriteCharacteristic, poll, sizeof(poll), QStringLiteral("poll"), false, + true); + } + + pollCounter++; + /*if (requestFanSpeed != -1) { + emit debug(QStringLiteral("changing fan speed...")); + + sendChangeFanSpeed(requestFanSpeed); + requestFanSpeed = -1; + } + if (requestIncreaseFan != -1) { + emit debug(QStringLiteral("increasing fan speed...")); + + sendChangeFanSpeed(FanSpeed + 1); + requestIncreaseFan = -1; + } else if (requestDecreaseFan != -1) { + emit debug(QStringLiteral("decreasing fan speed...")); + + sendChangeFanSpeed(FanSpeed - 1); + requestDecreaseFan = -1; + }*/ + } + } +} + +void deerruntreadmill::serviceDiscovered(const QBluetoothUuid &gatt) { + emit debug(QStringLiteral("serviceDiscovered ") + gatt.toString()); +} + +void deerruntreadmill::characteristicChanged(const QLowEnergyCharacteristic &characteristic, + const QByteArray &newValue) { + // qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length(); + QSettings settings; + QString heartRateBeltName = + settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString(); + Q_UNUSED(characteristic); + QByteArray value = newValue; + QDateTime now = QDateTime::currentDateTime(); + + emit debug(QStringLiteral(" << ") + QString::number(value.length()) + QStringLiteral(" ") + value.toHex(' ')); + emit packetReceived(); + + if (newValue.length() < 51) + return; + + lastPacket = value; + // lastState = value.at(0); + + double speed = ((double)(((value[9] << 8) & 0xff) + value[10]) / 100.0); + double incline = 0.0; + +#ifdef Q_OS_ANDROID + if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) + Heart = (uint8_t)KeepAwakeHelper::heart(); + else +#endif + { + if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) { + + uint8_t heart = 0; + if (heart == 0) { + update_hr_from_external(); + } else + + Heart = heart; + } + } + + if (!firstCharacteristicChanged) { + if (watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) + KCal += + ((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) + + 1.19) * + settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) / + 200.0) / + (60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo( + now)))); //(( (0.048* Output in watts +1.19) * body weight in + // kg * 3.5) / 200 ) / 60 + + Distance += ((speed / (double)3600.0) / + ((double)1000.0 / (double)(lastTimeCharacteristicChanged.msecsTo(now)))); + lastTimeCharacteristicChanged = now; + } + + emit debug(QStringLiteral("Current speed: ") + QString::number(speed)); + emit debug(QStringLiteral("Current incline: ") + QString::number(incline)); + emit debug(QStringLiteral("Current heart: ") + QString::number(Heart.value())); + // emit debug(QStringLiteral("Current KCal: ") + QString::number(kcal)); + // emit debug(QStringLiteral("Current Distance: ") + QString::number(distance)); + emit debug(QStringLiteral("Current Distance Calculated: ") + QString::number(Distance.value())); + + if (m_control->error() != QLowEnergyController::NoError) { + qDebug() << QStringLiteral("QLowEnergyController ERROR!!") << m_control->errorString(); + } + + if (Speed.value() != speed) { + + emit speedChanged(speed); + } + Speed = speed; + if (Inclination.value() != incline) { + + emit inclinationChanged(0, incline); + } + Inclination = incline; + + emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value())); + + emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value())); + + if (speed > 0) { + + lastSpeed = speed; + lastInclination = incline; + } + + firstCharacteristicChanged = false; +} + +void deerruntreadmill::btinit(bool startTape) { + initDone = true; +} + +double deerruntreadmill::minStepInclination() { return 1.0; } + +void deerruntreadmill::stateChanged(QLowEnergyService::ServiceState state) { + + QBluetoothUuid _gattWriteCharacteristicId((quint16)0xfff1); + QBluetoothUuid _gattNotifyCharacteristicId((quint16)0xfff2); + + QMetaEnum metaEnum = QMetaEnum::fromType(); + emit debug(QStringLiteral("BTLE stateChanged ") + QString::fromLocal8Bit(metaEnum.valueToKey(state))); + if (state == QLowEnergyService::ServiceDiscovered) { + + // qDebug() << gattCommunicationChannelService->characteristics(); + auto characteristics_list = gattCommunicationChannelService->characteristics(); + for (const QLowEnergyCharacteristic &c : qAsConst(characteristics_list)) { + qDebug() << QStringLiteral("char uuid") << c.uuid() << QStringLiteral("handle") << c.handle() + << c.properties(); + } + + gattWriteCharacteristic = gattCommunicationChannelService->characteristic(_gattWriteCharacteristicId); + gattNotifyCharacteristic = gattCommunicationChannelService->characteristic(_gattNotifyCharacteristicId); + Q_ASSERT(gattWriteCharacteristic.isValid()); + Q_ASSERT(gattNotifyCharacteristic.isValid()); + + // establish hook into notifications + connect(gattCommunicationChannelService, &QLowEnergyService::characteristicChanged, this, + &deerruntreadmill::characteristicChanged); + connect(gattCommunicationChannelService, &QLowEnergyService::characteristicWritten, this, + &deerruntreadmill::characteristicWritten); + connect(gattCommunicationChannelService, + static_cast(&QLowEnergyService::error), + this, &deerruntreadmill::errorService); + connect(gattCommunicationChannelService, &QLowEnergyService::descriptorWritten, this, + &deerruntreadmill::descriptorWritten); + + QByteArray descriptor; + descriptor.append((char)0x01); + descriptor.append((char)0x00); + gattCommunicationChannelService->writeDescriptor( + gattNotifyCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), descriptor); + } +} + +void deerruntreadmill::descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue) { + emit debug(QStringLiteral("descriptorWritten ") + descriptor.name() + QStringLiteral(" ") + newValue.toHex(' ')); + + initRequest = true; + emit connectedAndDiscovered(); +} + +void deerruntreadmill::characteristicWritten(const QLowEnergyCharacteristic &characteristic, + const QByteArray &newValue) { + Q_UNUSED(characteristic); + emit debug(QStringLiteral("characteristicWritten ") + newValue.toHex(' ')); +} + +void deerruntreadmill::serviceScanDone(void) { + QBluetoothUuid _gattCommunicationChannelServiceId((quint16)0xfff0); + emit debug(QStringLiteral("serviceScanDone")); + + auto services_list = m_control->services(); + emit debug("Services found:"); + for (const QBluetoothUuid &s : qAsConst(services_list)) { + emit debug(s.toString()); + } + + gattCommunicationChannelService = m_control->createServiceObject(_gattCommunicationChannelServiceId); + if (gattCommunicationChannelService) { + connect(gattCommunicationChannelService, &QLowEnergyService::stateChanged, this, + &deerruntreadmill::stateChanged); + gattCommunicationChannelService->discoverDetails(); + } else { + emit debug(QStringLiteral("error on find Service")); + } +} + +void deerruntreadmill::errorService(QLowEnergyService::ServiceError err) { + + QMetaEnum metaEnum = QMetaEnum::fromType(); + emit debug(QStringLiteral("deerruntreadmill::errorService ") + QString::fromLocal8Bit(metaEnum.valueToKey(err)) + + m_control->errorString()); +} + +void deerruntreadmill::error(QLowEnergyController::Error err) { + + QMetaEnum metaEnum = QMetaEnum::fromType(); + emit debug(QStringLiteral("deerruntreadmill::error ") + QString::fromLocal8Bit(metaEnum.valueToKey(err)) + + m_control->errorString()); +} + +void deerruntreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device) { + { + + bluetoothDevice = device; + m_control = QLowEnergyController::createCentral(bluetoothDevice, this); + connect(m_control, &QLowEnergyController::serviceDiscovered, this, &deerruntreadmill::serviceDiscovered); + connect(m_control, &QLowEnergyController::discoveryFinished, this, &deerruntreadmill::serviceScanDone); + connect(m_control, + static_cast(&QLowEnergyController::error), + this, &deerruntreadmill::error); + connect(m_control, &QLowEnergyController::stateChanged, this, &deerruntreadmill::controllerStateChanged); + + connect(m_control, + static_cast(&QLowEnergyController::error), + this, [this](QLowEnergyController::Error error) { + Q_UNUSED(error); + Q_UNUSED(this); + emit debug(QStringLiteral("Cannot connect to remote device.")); + searchStopped = false; + emit disconnected(); + }); + connect(m_control, &QLowEnergyController::connected, this, [this]() { + Q_UNUSED(this); + emit debug(QStringLiteral("Controller connected. Search services...")); + m_control->discoverServices(); + }); + connect(m_control, &QLowEnergyController::disconnected, this, [this]() { + Q_UNUSED(this); + emit debug(QStringLiteral("LowEnergy controller disconnected")); + searchStopped = false; + emit disconnected(); + }); + + // Connect + m_control->connectToDevice(); + return; + } +} + +void deerruntreadmill::controllerStateChanged(QLowEnergyController::ControllerState state) { + qDebug() << QStringLiteral("controllerStateChanged") << state; + if (state == QLowEnergyController::UnconnectedState && m_control) { + qDebug() << QStringLiteral("trying to connect back again..."); + + initDone = false; + m_control->connectToDevice(); + } +} + +bool deerruntreadmill::connected() { + if (!m_control) { + + return false; + } + return m_control->state() == QLowEnergyController::DiscoveredState; +} + +void deerruntreadmill::searchingStop() { searchStopped = true; } diff --git a/src/devices/deeruntreadmill/deerruntreadmill.h b/src/devices/deeruntreadmill/deerruntreadmill.h new file mode 100644 index 000000000..6789b7383 --- /dev/null +++ b/src/devices/deeruntreadmill/deerruntreadmill.h @@ -0,0 +1,103 @@ +#ifndef DEERRUNTREADMILL_H +#define DEERRUNTREADMILL_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#ifndef Q_OS_ANDROID +#include +#else +#include +#endif +#include +#include +#include +#include + +#include +#include + +#include "devices/treadmill.h" + +#ifdef Q_OS_IOS +#include "ios/lockscreen.h" +#endif + +class deerruntreadmill : public treadmill { + + Q_OBJECT + public: + deerruntreadmill(uint32_t poolDeviceTime = 200, bool noConsole = false, bool noHeartService = false, + double forceInitSpeed = 0.0, double forceInitInclination = 0.0); + bool connected() override; + double minStepInclination() override; + + private: + void forceSpeed(double requestSpeed); + void forceIncline(double requestIncline); + void btinit(bool startTape); + void writeCharacteristic(const QLowEnergyCharacteristic characteristic, uint8_t *data, uint8_t data_len, + const QString &info, bool disable_log = false, bool wait_for_response = false); + void startDiscover(); + uint8_t calculateXOR(uint8_t arr[], size_t size); + bool noConsole = false; + bool noHeartService = false; + uint32_t pollDeviceTime = 200; + uint8_t pollCounter = 0; + bool searchStopped = false; + uint8_t sec1Update = 0; + uint8_t firstInit = 0; + QByteArray lastPacket; + QDateTime lastTimeCharacteristicChanged; + bool firstCharacteristicChanged = true; + + QTimer *refresh; + + QLowEnergyService *gattCommunicationChannelService = nullptr; + QLowEnergyCharacteristic gattWriteCharacteristic; + QLowEnergyCharacteristic gattNotifyCharacteristic; + + bool initDone = false; + bool initRequest = false; + +#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 deviceDiscovered(const QBluetoothDeviceInfo &device); + void searchingStop(); + + private slots: + + void characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue); + void characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue); + void descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue); + void stateChanged(QLowEnergyService::ServiceState state); + void controllerStateChanged(QLowEnergyController::ControllerState state); + void changeInclinationRequested(double grade, double percentage); + + void serviceDiscovered(const QBluetoothUuid &gatt); + void serviceScanDone(void); + void update(); + void error(QLowEnergyController::Error err); + void errorService(QLowEnergyService::ServiceError); +}; + +#endif // DEERRUNTREADMILL_H diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index f0babb5a1..6af02ff4e 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -77,6 +77,7 @@ DEFINES += QT_DEPRECATED_WARNINGS IO_UNDER_QT SMTP_BUILD NOMINMAX SOURCES += \ $$PWD/devices/antbike/antbike.cpp \ $$PWD/devices/crossrope/crossrope.cpp \ + $$PWD/devices/deeruntreadmill/deerruntreadmill.cpp \ $$PWD/devices/focustreadmill/focustreadmill.cpp \ $$PWD/devices/jumprope.cpp \ $$PWD/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.cpp \ @@ -303,6 +304,7 @@ HEADERS += \ $$PWD/EventHandler.h \ $$PWD/devices/antbike/antbike.h \ $$PWD/devices/crossrope/crossrope.h \ + $$PWD/devices/deeruntreadmill/deerruntreadmill.h \ $$PWD/devices/focustreadmill/focustreadmill.h \ $$PWD/devices/jumprope.h \ $$PWD/devices/nordictrackifitadbelliptical/nordictrackifitadbelliptical.h \ From deb5eab79e173849886b8998a982ebcf27a5a3dd Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 3 Oct 2024 13:13:51 +0200 Subject: [PATCH 156/162] Speed Adjustment Issue on FS 465D50 Walking Pad (Issue #2630) (#2631) * Speed Adjustment Issue on FS 465D50 Walking Pad (Issue #2630) * Revert "Speed Adjustment Issue on FS 465D50 Walking Pad (Issue #2630)" This reverts commit 4b0a36bb8af7f46bf4363729610a63af9679d68a. * Update fitshowtreadmill.cpp * Update project.pbxproj * Revert "Update fitshowtreadmill.cpp" This reverts commit 10d859fa7084b5d2ad92a4d4a15dfcfcdbab75d2. * better fix --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ src/devices/fitshowtreadmill/fitshowtreadmill.cpp | 10 +++++----- src/devices/fitshowtreadmill/fitshowtreadmill.h | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index 22772c0fd..b93864515 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 886; + CURRENT_PROJECT_VERSION = 888; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 886; + CURRENT_PROJECT_VERSION = 888; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 886; + CURRENT_PROJECT_VERSION = 888; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 886; + CURRENT_PROJECT_VERSION = 888; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 886; + CURRENT_PROJECT_VERSION = 888; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 886; + CURRENT_PROJECT_VERSION = 888; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; diff --git a/src/devices/fitshowtreadmill/fitshowtreadmill.cpp b/src/devices/fitshowtreadmill/fitshowtreadmill.cpp index 2604fc28f..bbc534f21 100644 --- a/src/devices/fitshowtreadmill/fitshowtreadmill.cpp +++ b/src/devices/fitshowtreadmill/fitshowtreadmill.cpp @@ -299,7 +299,7 @@ void fitshowtreadmill::serviceDiscovered(const QBluetoothUuid &gatt) { qDebug() << "adding" << gatt.toString() << "as the default service"; serviceId = gatt; // NOTE: clazy-rule-of-tow } - if(gatt == QBluetoothUuid((quint16)0x1826)) { + if(gatt == QBluetoothUuid((quint16)0x1826) && !fs_connected) { QSettings settings; settings.setValue(QZSettings::ftms_treadmill, bluetoothDevice.name()); qDebug() << "forcing FTMS treadmill since it has FTMS"; @@ -838,10 +838,10 @@ void fitshowtreadmill::error(QLowEnergyController::Error err) { void fitshowtreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device) { emit debug(QStringLiteral("Found new device: ") + device.name() + QStringLiteral(" (") + device.address().toString() + ')'); - /*if (device.name().startsWith(QStringLiteral("FS-")) || - (device.name().startsWith(QStringLiteral("SW")) && device.name().length() == 14))*/ - - if (device.name().toUpper().startsWith(QStringLiteral("NOBLEPRO CONNECT"))) { + if (device.name().toUpper().startsWith(QStringLiteral("FS-"))) { + qDebug() << "FS FIX!"; + fs_connected = true; + } else if (device.name().toUpper().startsWith(QStringLiteral("NOBLEPRO CONNECT"))) { qDebug() << "NOBLEPRO FIX!"; minStepInclinationValue = 0.5; noblepro_connected = true; diff --git a/src/devices/fitshowtreadmill/fitshowtreadmill.h b/src/devices/fitshowtreadmill/fitshowtreadmill.h index cba98b7b6..6aa341e3b 100644 --- a/src/devices/fitshowtreadmill/fitshowtreadmill.h +++ b/src/devices/fitshowtreadmill/fitshowtreadmill.h @@ -152,6 +152,7 @@ class fitshowtreadmill : public treadmill { double minStepInclinationValue = 1.0; bool noblepro_connected = false; + bool fs_connected = false; metric rawInclination; From 1d5d29bf1d0e3a4e0362056bfed1a455685c1bf9 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 3 Oct 2024 16:32:37 +0200 Subject: [PATCH 157/162] Cannot connect to ESLinker treadmill #2628 --- src/devices/bluetooth.cpp | 7 +- .../eslinkertreadmill/eslinkertreadmill.cpp | 86 +++++++++++++++++-- .../eslinkertreadmill/eslinkertreadmill.h | 1 + 3 files changed, 85 insertions(+), 9 deletions(-) diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 5e57ca4e3..60989834c 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -1351,8 +1351,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { (b.name().toUpper().startsWith(QStringLiteral("F85")) && !sole_inclination) || // FMTS (b.name().toUpper().startsWith(QStringLiteral("F89")) && !sole_inclination) || // FMTS (b.name().toUpper().startsWith(QStringLiteral("F80")) && !sole_inclination) || // FMTS - (b.name().toUpper().startsWith(QStringLiteral("ANPLUS-"))) || // FTMS - b.name().toUpper().startsWith(QStringLiteral("ESANGLINKER"))) && + (b.name().toUpper().startsWith(QStringLiteral("ANPLUS-"))) // FTMS + ) && !horizonTreadmill && filter) { this->setLastBluetoothDevice(b); this->stopDiscovery(); @@ -1924,7 +1924,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) { // SLOT(inclinationChanged(double))); proformTreadmill->deviceDiscovered(b); this->signalBluetoothDeviceConnected(proformTreadmill); - } else if (b.name().toUpper().startsWith(QStringLiteral("ESLINKER")) && !eslinkerTreadmill && filter) { + } else if ((b.name().toUpper().startsWith(QStringLiteral("ESANGLINKER")) || + b.name().toUpper().startsWith(QStringLiteral("ESLINKER"))) && !eslinkerTreadmill && filter) { this->setLastBluetoothDevice(b); this->stopDiscovery(); eslinkerTreadmill = new eslinkertreadmill(this->pollDeviceTime, noConsole, noHeartService); diff --git a/src/devices/eslinkertreadmill/eslinkertreadmill.cpp b/src/devices/eslinkertreadmill/eslinkertreadmill.cpp index 82ac13fe3..019981c21 100644 --- a/src/devices/eslinkertreadmill/eslinkertreadmill.cpp +++ b/src/devices/eslinkertreadmill/eslinkertreadmill.cpp @@ -1,4 +1,5 @@ #include "eslinkertreadmill.h" +#include "homeform.h" #include "keepawakehelper.h" #include "virtualdevices/virtualtreadmill.h" #include @@ -71,7 +72,8 @@ void eslinkertreadmill::updateDisplay(uint16_t elapsed) { writeCharacteristic(display, sizeof(display), QStringLiteral("updateDisplay elapsed=") + QString::number(elapsed), false, false); - } else { + } else if (treadmill_type == ESANGLINKER){ + } } @@ -116,6 +118,16 @@ void eslinkertreadmill::forceSpeed(double requestSpeed) { writeCharacteristic(display, sizeof(display), QStringLiteral("forceSpeed speed=") + QString::number(requestSpeed), false, true); + } else if(treadmill_type == ESANGLINKER) { + uint8_t display[] = {0xa9, 0x01, 0x01, 0x0b, 0xa2}; + display[3] = (int)(requestSpeed * 10 * 0.621371); + for (int i = 0; i < 4; i++) { + display[4] = display[4] ^ display[i]; + } + + writeCharacteristic(display, sizeof(display), + QStringLiteral("forceSpeed speed=") + QString::number(requestSpeed), false, true); + } } @@ -159,7 +171,7 @@ void eslinkertreadmill::update() { } if (treadmill_type == TYPE::RHYTHM_FUN || treadmill_type == TYPE::YPOO_MINI_CHANGE || - treadmill_type == TYPE::COSTAWAY) { + treadmill_type == TYPE::COSTAWAY || treadmill_type == TYPE::ESANGLINKER) { if (requestSpeed != -1) { if (requestSpeed != currentSpeed().value() && requestSpeed >= 0 && requestSpeed <= 22) { @@ -255,6 +267,14 @@ void eslinkertreadmill::update() { void eslinkertreadmill::serviceDiscovered(const QBluetoothUuid &gatt) { emit debug(QStringLiteral("serviceDiscovered ") + gatt.toString()); + + if(gatt == QBluetoothUuid((quint16)0x1826)) { + QSettings settings; + settings.setValue(QZSettings::ftms_treadmill, bluetoothDevice.name()); + qDebug() << "forcing FTMS treadmill since it has FTMS"; + if(homeform::singleton()) + homeform::singleton()->setToastRequested("FTMS treadmill found, restart the app to apply the change"); + } } void eslinkertreadmill::characteristicChanged(const QLowEnergyCharacteristic &characteristic, @@ -349,7 +369,7 @@ void eslinkertreadmill::characteristicChanged(const QLowEnergyCharacteristic &ch if ((newValue.length() != 17 && (treadmill_type == RHYTHM_FUN || treadmill_type == YPOO_MINI_CHANGE))) return; - else if (newValue.length() != 5 && treadmill_type == COSTAWAY) + else if (newValue.length() != 5 && (treadmill_type == COSTAWAY || treadmill_type == TYPE::ESANGLINKER)) return; if (treadmill_type == RHYTHM_FUN || treadmill_type == YPOO_MINI_CHANGE) { @@ -388,7 +408,7 @@ void eslinkertreadmill::characteristicChanged(const QLowEnergyCharacteristic &ch lastSpeed = speed; lastInclination = incline; } - } else if (treadmill_type == COSTAWAY) { + } else if (treadmill_type == COSTAWAY || treadmill_type == TYPE::ESANGLINKER) { const double miles = 1.60934; if(((uint8_t)newValue.at(3)) == 0xFF) Speed = 0; @@ -465,7 +485,58 @@ double eslinkertreadmill::GetInclinationFromPacket(const QByteArray &packet) { void eslinkertreadmill::btinit(bool startTape) { Q_UNUSED(startTape) - if (treadmill_type == COSTAWAY) { + if (treadmill_type == ESANGLINKER) { + uint8_t initData1[] = {0xa9, 0xf2, 0x01, 0x2f, 0x75}; + writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true); + + uint8_t initData2[] = {0xa9, 0x0a, 0x01, 0xc6, 0x64}; + writeCharacteristic(initData2, sizeof(initData2), QStringLiteral("init"), false, true); + + uint8_t initData3[] = {0xa9, 0xae, 0x01, 0xfe, 0xf8}; + writeCharacteristic(initData3, sizeof(initData3), QStringLiteral("init"), false, true); + + uint8_t initData4[] = {0xa9, 0xa0, 0x03, 0x00, 0x00, 0x00, 0x0a}; + writeCharacteristic(initData4, sizeof(initData4), QStringLiteral("init"), false, true); + + uint8_t initData5[] = {0xa9, 0x08, 0x01, 0xad, 0x0d}; + writeCharacteristic(initData5, sizeof(initData5), QStringLiteral("init"), false, true); + + uint8_t initData6[] = {0xa9, 0x08, 0x04, 0x0c, 0x06, 0x48, 0x12, 0xf5}; + writeCharacteristic(initData6, sizeof(initData6), QStringLiteral("init"), false, true); + + uint8_t initData7[] = {0xa9, 0x1e, 0x01, 0xfe, 0x48}; + writeCharacteristic(initData7, sizeof(initData7), QStringLiteral("init"), false, true); + + uint8_t initData8[] = {0xa9, 0xae, 0x01, 0xfe, 0xf8}; + writeCharacteristic(initData8, sizeof(initData8), QStringLiteral("init"), false, true); + + uint8_t initData9[] = {0xa9, 0xa3, 0x01, 0x01, 0x0a}; + writeCharacteristic(initData9, sizeof(initData9), QStringLiteral("init"), false, true); + + uint8_t initData10[] = {0xa9, 0x8e, 0x01, 0x09, 0x2f}; + writeCharacteristic(initData10, sizeof(initData10), QStringLiteral("init"), false, true); + + uint8_t initData11[] = {0xa9, 0xb2, 0x01, 0xfe, 0xe4}; + writeCharacteristic(initData11, sizeof(initData11), QStringLiteral("init"), false, true); + + uint8_t initData12[] = {0xa9, 0x8e, 0x01, 0x09, 0x2f}; + writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, true); + + uint8_t initData13[] = {0xa9, 0xae, 0x01, 0xfe, 0xf8}; + writeCharacteristic(initData13, sizeof(initData13), QStringLiteral("init"), false, true); + + uint8_t initData14[] = {0xa9, 0x08, 0x01, 0x76, 0xd6}; + writeCharacteristic(initData14, sizeof(initData14), QStringLiteral("init"), false, true); + + uint8_t initData15[] = {0xa9, 0x08, 0x04, 0x0a, 0x04, 0x28, 0x0e, 0x8d}; + writeCharacteristic(initData15, sizeof(initData15), QStringLiteral("init"), false, true); + + uint8_t initData16[] = {0xa9, 0x08, 0x01, 0x72, 0xd2}; + writeCharacteristic(initData16, sizeof(initData16), QStringLiteral("init"), false, true); + + uint8_t initData17[] = {0xa9, 0x08, 0x04, 0x70, 0x16, 0x0e, 0x08, 0xc5}; + writeCharacteristic(initData17, sizeof(initData17), QStringLiteral("init"), false, true); + } else if (treadmill_type == COSTAWAY) { uint8_t initData1[] = {0xa9, 0xf2, 0x01, 0x2f, 0x75}; writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true); @@ -633,7 +704,10 @@ void eslinkertreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device) { bool eslinker_ypoo = settings.value(QZSettings::eslinker_ypoo, QZSettings::default_eslinker_ypoo).toBool(); bool eslinker_costaway = settings.value(QZSettings::eslinker_costaway, QZSettings::default_eslinker_costaway).toBool(); - if (eslinker_cadenza) { + if(device.name().toUpper().startsWith(QStringLiteral("ESANGLINKER"))) { + treadmill_type = ESANGLINKER; + qDebug() << "ESANGLINKER workaround ENABLED!"; + } else if (eslinker_cadenza) { treadmill_type = CADENZA_FITNESS_T45; } else if (eslinker_ypoo) { treadmill_type = YPOO_MINI_CHANGE; diff --git a/src/devices/eslinkertreadmill/eslinkertreadmill.h b/src/devices/eslinkertreadmill/eslinkertreadmill.h index dfcd7f235..edf1b4b06 100644 --- a/src/devices/eslinkertreadmill/eslinkertreadmill.h +++ b/src/devices/eslinkertreadmill/eslinkertreadmill.h @@ -66,6 +66,7 @@ class eslinkertreadmill : public treadmill { CADENZA_FITNESS_T45 = 1, // it has the same protocol of RHYTHM_FUN but without the header and the footer YPOO_MINI_CHANGE = 2, // Similar to RHYTHM_FUN but has no ascension COSTAWAY = 3, + ESANGLINKER = 4, } TYPE; volatile TYPE treadmill_type = RHYTHM_FUN; From c36afc31738990e2028aebea4bf0ba77f1d1c337 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Thu, 3 Oct 2024 18:33:30 +0200 Subject: [PATCH 158/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index b93864515..aea23f13e 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 888; + CURRENT_PROJECT_VERSION = 889; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 888; + CURRENT_PROJECT_VERSION = 889; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 888; + CURRENT_PROJECT_VERSION = 889; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 888; + CURRENT_PROJECT_VERSION = 889; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 888; + CURRENT_PROJECT_VERSION = 889; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 888; + CURRENT_PROJECT_VERSION = 889; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; From 1e2af212ca8124725fe796e461a0b2117442a85b Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 4 Oct 2024 10:37:46 +0200 Subject: [PATCH 159/162] Cannot connect to ESLinker treadmill (Issue #2628) --- src/devices/eslinkertreadmill/eslinkertreadmill.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/devices/eslinkertreadmill/eslinkertreadmill.cpp b/src/devices/eslinkertreadmill/eslinkertreadmill.cpp index 019981c21..1ac75fb44 100644 --- a/src/devices/eslinkertreadmill/eslinkertreadmill.cpp +++ b/src/devices/eslinkertreadmill/eslinkertreadmill.cpp @@ -409,8 +409,11 @@ void eslinkertreadmill::characteristicChanged(const QLowEnergyCharacteristic &ch lastInclination = incline; } } else if (treadmill_type == COSTAWAY || treadmill_type == TYPE::ESANGLINKER) { + if(newValue.at(1) != 0x09 && treadmill_type == TYPE::ESANGLINKER) + return; + const double miles = 1.60934; - if(((uint8_t)newValue.at(3)) == 0xFF) + if(((uint8_t)newValue.at(3)) == 0xFF && treadmill_type == COSTAWAY) Speed = 0; else Speed = (double)((uint8_t)newValue.at(3)) / 10.0 * miles; From b07a75df9068e15b545c76f88f1ea03b58b0957b Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 4 Oct 2024 10:38:33 +0200 Subject: [PATCH 160/162] Cannot connect to ESLinker treadmill (Issue #2628) --- tst/Devices/HorizonTreadmill/horizontreadmilltestdata.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tst/Devices/HorizonTreadmill/horizontreadmilltestdata.h b/tst/Devices/HorizonTreadmill/horizontreadmilltestdata.h index 3c835741c..7e0b95e28 100644 --- a/tst/Devices/HorizonTreadmill/horizontreadmilltestdata.h +++ b/tst/Devices/HorizonTreadmill/horizontreadmilltestdata.h @@ -23,7 +23,6 @@ class HorizonTreadmillTestData : public TreadmillTestData { this->addDeviceName("JFTM", comparison::StartsWithIgnoreCase); this->addDeviceName("CT800", comparison::StartsWithIgnoreCase); this->addDeviceName("MOBVOI TM", comparison::StartsWithIgnoreCase); - this->addDeviceName("ESANGLINKER", comparison::StartsWithIgnoreCase); this->addDeviceName("DK202000725", comparison::StartsWithIgnoreCase); this->addDeviceName("CTM780102C6BB32D62", comparison::StartsWithIgnoreCase); this->addDeviceName("MX-TM ", comparison::StartsWithIgnoreCase); From f69aee817c0dcc2f06d9c3bead4734c1b070a502 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 4 Oct 2024 11:13:35 +0200 Subject: [PATCH 161/162] fixing timeout for proformwifibike --- src/devices/proformwifibike/proformwifibike.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/proformwifibike/proformwifibike.cpp b/src/devices/proformwifibike/proformwifibike.cpp index 56f722823..4cee24713 100644 --- a/src/devices/proformwifibike/proformwifibike.cpp +++ b/src/devices/proformwifibike/proformwifibike.cpp @@ -34,6 +34,7 @@ proformwifibike::proformwifibike(bool noWriteResistance, bool noHeartService, in ok = connect(&websocket, &QWebSocket::connected, [&]() { qDebug() << "connected!"; }); ok = connect(&websocket, &QWebSocket::disconnected, [&]() { qDebug() << "disconnected!"; + lastRefreshCharacteristicChanged = QDateTime::currentDateTime(); connectToDevice(); }); From 9d808b28a42645658459d2af1b3c8ec56550ae29 Mon Sep 17 00:00:00 2001 From: Roberto Viola Date: Fri, 4 Oct 2024 12:08:57 +0200 Subject: [PATCH 162/162] Update project.pbxproj --- .../qdomyoszwift.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj index aea23f13e..c4d12b515 100644 --- a/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj +++ b/build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj @@ -4056,7 +4056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 889; + CURRENT_PROJECT_VERSION = 890; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1"; @@ -4247,7 +4247,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 889; + CURRENT_PROJECT_VERSION = 890; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = NO; @@ -4474,7 +4474,7 @@ CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 889; + CURRENT_PROJECT_VERSION = 890; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -4570,7 +4570,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 889; + CURRENT_PROJECT_VERSION = 890; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 6335M7T29D; ENABLE_BITCODE = YES; @@ -4662,7 +4662,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 889; + CURRENT_PROJECT_VERSION = 890; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES; ENABLE_PREVIEWS = YES; @@ -4776,7 +4776,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 889; + CURRENT_PROJECT_VERSION = 890; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\""; ENABLE_BITCODE = YES;