ptx2 / gymnasticon

Make obsolete and/or proprietary exercise bikes work with popular cycling training apps like Zwift, TrainerRoad, Rouvy and more.
https://ptx2.net/posts/unbricking-a-bike-with-a-raspberry-pi
MIT License
299 stars 39 forks source link

Garmin & Schwinn IC8 Support | SOLVED, but not integrated #102

Open smarthomescripting opened 5 months ago

smarthomescripting commented 5 months ago

Dear all,

i just bought an Schwinn IC8 spinning bike and really struggled to connect it properly with my Garmin MARQ.

Thanks to this repository and some (hacking &) coding efforts I managed to:

I am not allowed to create pull request, but maybe anyone can make use of this for personal use or even integrate back into the repository.

All the best Michael

gymnasticon-schwinn-ic8.tar.gz

nealjane commented 5 months ago

Great work Michael! Unfortunately ptx2 hasn’t been around in a very long time now (so it won’t get actioned as a pull request) - he disappeared in the covid pandemic, Ive tried to contact him through his website and had no response there either...☹️☹️

smarthomescripting commented 5 months ago

Thanks a lot for your feedback. Glad to see I am not alone with this ;-)

doudar commented 5 months ago

If you wanted to attempt to implement this for SmartSpin2k, which has all the same features of this project, including (optional) stepper motor control, it would be cool to integrate it. Http://www.github.com/doudar/smartspin2k

cagnulein commented 5 months ago

also check the QZ project https://github.com/cagnulein/qdomyos-zwift/

Ant to garmin and ic8 is already working out of the box with an android phone :)

smarthomescripting commented 5 months ago

also check the QZ project https://github.com/cagnulein/qdomyos-zwift/

Ant to garmin and ic8 is already working out of the box with an android phone :)

Very nice - unfortunately I did not find it on the web!

cagnulein commented 5 months ago

At least you found it now :)

hoges25 commented 5 months ago

Of course I find this the day after spending hours teaching myself basic nodejs and bluetooth packet capture with nRF 😂

In case there are regional differences, mine is marketed as an Schwinn 800IC from 2019 and if it helps anyone this is what I've found:

Service ID is still 1826, characteristic ID is still 2ad2

Packet captured is way longer than the IC4 and starts with 0x74 as @smarthomescripting found: subscription <Buffer 74 03 d8 04 1c 00 1c 01 00 11 00 09 00 04 00 00 00 00 00>

Working through the packet here's what I found each to be through trial and error comparing a few:

Buffer | Features? | InstSpeedB | InstSpeedA | InstCadenceB | InstCadenceA (Offset 4) | DistanceB | DistanceA | Spare? | ResistanceB? | ResistanceA | InstPowerB? | InstPowerA (Offset 11) | TotEnergyB? | TotEnergyA | Spare? | Spare? | Spare? | Spare?

All up and running now by just editing the ic4 file for the new buffer and offsets and I'll add Ant+ when it comes in the mail during the week. I'm getting weird bluetooth disconnects every ~42 seconds which seems to be due to supervision timeout. I've edited /sys/kernel/debug/bluetooth/hci0/supervision_timeout to see if that changes anything but I'll post back here if I figure out something more permanent.

Nice work on calculating the power yourself, do you find it more accurate than the power readout from the bike with the Gymnasticon offset? I'm planning to eventually get power meter pedals for my endurance bike so I'll calibrate it against them at some point.

I tried qz but had trouble getting it up an running (think I'd messed up the bluetooth drivers trying different tools for packet capture) but didn't bother going too far with it as I saw a few comments saying that ANT+ was only on Android not the Pi. Might be different now though as I think the posts were from a while back, eventually I'll probably do Smartspin2k for the variable resistance.

cagnulein commented 5 months ago

Yes Qz has ant+ only on android

smarthomescripting commented 5 months ago

Hi @hoges25!

I had a similar feeling last time ;) At least the problem seems to be with several people.

Thanks for the great documentation - very helpful! Calculating the power myself was simple a quick fix before I was going even deeper into the package analysis.

I did a quick check to compare both values - the two values seem to be close by with a difference of 5-10%: POWER Calc=11 Read=43 POWER Calc=107 Read=104 POWER Calc=185 Read=163 POWER Calc=261 Read=234 POWER Calc=446 Read=406

The weakest point are actually low values, i.e. very low resistance values. So I took your idea and changed few lines:

const IBD_VALUE_IDX_SPEED = 2; // 16-bit speed const IBD_VALUE_IDX_POWER = 11; // 16-bit power (watts) data offset within packet

const speed = Math.round (data.readUInt16LE(IBD_VALUE_IDX_SPEED) / 90); const power = Math.round (data.readUInt16LE(IBD_VALUE_IDX_POWER));

Should be a simple fix.

It would be great to see if you can bring this to work.