Adding more services etc
Hi, You motivated me to familiarise myself with JS, node.js, frameworks, and the GATT services specs ;) (I used to program, but in C...) I must say I really respect you for getting this to work. The GATT specs are such an incredible MESS! (I really don't understand how ANYTHING on bluetooth works AT ALL...) I added a heart rate service which displays the HR in Zwift next to the power display. Tried to make the cadence display also, but it turns out the Cycle Speed and Cadence Service has to CALCULATE the instantaneous cadence first, from total revs ("since the start of time"), and elapsed time (which rolls over every 62 second). What a fun definition... For some reason the HR and Cadence which is in the FTMS service is NOT displayed by Zwift (but, for example, Rouvy displays them. But Rouvy does not recognise the Power Control Point from your code...) Anyway - some questions 1 - (I realised that the "physics", meaning how much "resistance", in Watts, to set on the trainer, is in fact calculated ON THE TRAINER from the 4 parameters (wind, crr, cw, incline) - or in your code in the case of your kettlerUSB2BLE, of course - and not in Zwift. Frankly, I think thats crazy (i.e. Zwift, the protocol, whoever came up with this) - no possibility of controlling the quality of the simulation by Zwift, no upgrades of the model etc, every racer potentially racing with a different power model, depending on his trainer model...)
- Where did you get your formula? Do you know if Zwift passes the weight of the rider to the trainer? (needed to calc Watts due to riding uphill!)
- do you know how Zwift "creates" the speed it displays? As far as I can tell, what I see as speed in Z (in SIM mode) is not what my Kettler is showing, so clearly the speed in the FMTS service is not being used (just as the hr and cadence is not used to display). Since they "create" a speed in ERG mode, presumably from the power (as there is NOTHING ELSE to use as input in ERG mode), are they using the same method in SIM? 2 - you wrote before (to my Q in issue re Rouvy and RGT not working) that you had not implemented the whole protocol. Can you point out whats missing (maybe I can do something there...)?
and one more question: 3 - can you tell me why in the indoor-bike-data-characteristic the rpm(slash cadence) needs to be multiplied by 2? (and the speed by 100?) I could see the value of the rpm in RGTCycling, and without the 2 it is only half of the Kettler-displayed value, so it DOES need that multiplier, and since its in RGT, and even though I don't see the rpm displayed in Z I assume you also found that its necessary, but why? The SIG GATT spec says nothing of this "interesting" feature. D you know whats going on, what's this about?
Hello,
Thank you for your feedback and questions. I will try to provide some answers to these sometimes poorly documented topics.
-
Participation: If you want to post code on the different services you have implemented, don't hesitate. I should be able to create a role for you in github.
-
About power: From what I understand, Zwift only believes in "power". It's the only input taken into account in a race. By the way, pro's must have 2 power sensors. All the data is then deduced by calculation. The factors depending on the rider (weight, type of bike (crr)) and external factors (slope, suction) are part of the formula to deduce the speed. I try to find the exact formula for you.
When a home trainer has no power sensor but an adjustable resistance. Zwift uses the concept of "Zpower". it is a function that links resistance to power. it is very approximate, and that is why zpower is not usable in competition.
On our side, Zwift uses well the power calculated by Kettler. I added a calculation layer in the SIM mode to simulate a freewheel. I noticed that it was difficult to produce 200 watts constant, while it is easier to have 200 watts on average with a little amplitude. A bit like riding in the mountains vs. the flat.
I tested a physical formula related to the slope, the wind ... but you quickly realize that a simple function allows you to do as well. see bikestate.js line 106. It's bases on my feeling (170 in front of the formula) and the fact that I am using gears.
Btw, i am working on the same idea for the ERG mode. While it's easy to ride under the FTP, it's horrible to ride 5 min at 120% without any flexibility. I will probably implement some flexibility in ERG mode as well
- Full implementation: as you mentioned, the Gatt specifications are complex and don't seem complete. It is for example difficult to know if a service should be implemented or not. And in this service what are the mandatory elements.
I would also have appreciated an official protocol "tester". Anyway, I think a good part of it is implemented but there are probably some omissions. Maybe your code could fill that.
- RPM * 2 It's what they called "resolution" it's a way to transmit a decimal number (ex: 5,5) using an integer without using complex representation (like float)
for the cadence: it's 0.5 per minute. That means that the system is able to represent 120,5 rotation per minute
1 - happy to. I need to be more proficient with git though, and I have a bit of a mess in my clone and branch, so will clean up a bit before any pull requests. Any workflow you suggest - wellcome. 4 - A yes. I saw the "resolution". But - it's in the description of the Control Point. It logical that all data follow the same rule, nevertheless they "forgot to mention" it in describing the data format in the Indoor Bike Data characteristic... 3 - does your Zwift show the cadence (and heart rate)? The rpms are both in the IndoorBikeData characteristic, and in the Cycle Power Service (though the format here is completely different), but in mine its greyed out, as if the data was not present at all (at least this is consistent with the login process , where it does not connect to a "Cadence sensor". But as I said, for example RGT identifies the presence of this data and shows during its login as a Cadance data source) I am planning to ask my son, who has an Elite Suito trainer, to see what services its advertising, and whatever other info about the data format is detectable. Maybe we'll see how to fix this.
2 - I'm riding in workout for now, because the SIM mode did not feel intuitive for me. When I switch gears (via the web server, of course, which is fine, the lack of physical buttons on the gpio does not worry me), I feel like I'm changing the power instead of changing the speed/cadence. This is probably because there is a sizeable time lag between setting a power on the Kettle and the magnetic resistance actually attaining that resistance. For example, in workout "The Wringer", it jumps from 90W to 370W, and the display shows it (in Z and on K), but the second display in Z (in workout mode) which shows the actual resistance (field 7 in the data structure) reaches 370 after 10-11 seconds. And similarly going 370 to 90. But maybe further fiddling with these calculations and algo can improve that feeling in race mode. Will see after the finishing the (lack of) Cadance element, which is annoying me;) btw - I would insert real gear ratios. the closer the formula/parameters is to a real situation, the less chance an unnatural feel gets in from that source. Maybe. (though I appreciate that a simple formula may in fact be better, what with the time lag the kettler eddy current resistance introduces...)
Hello
RPM works fine for me.
As you can see, Zwift is configured to receive the signal from 3 sources.

The SIM mode is based on the
- current Gear
- RPM (faster,-> more resitant)
- Slope (inputed by zwift)
No RPM = no good feeling It's not perfect, laggy but it's better than a fixed power :)
Here's an embarrassing fact- turns out rpms work for me too. You just have to enable them first... I've no idea how I managed to overlook this. A lesson in humility I guess... Luckily (for me) the HR really does need the additional service, so at least that wasn't a waste;) So now I have them all. I will try to clean up over the next couple of days and create a pull request, so you can incorporate whatever you want. Interesting fact - Elite Suito provides 3 services. FTMS, Cycle Power, and Cycle Speed and Cadence. Presumably software other then Zwift may require SC&C (with its differently formatted speed and cadence information).