nebucaz / kracerble

Cycling Power BLE on Raspberry Pi using Swift
4 stars 0 forks source link

Support to other Kettler devices #1

Open Sturmenstrudel opened 3 years ago

Sturmenstrudel commented 3 years ago

Hello, I have an old Ergoracer GT by Kettler and when I try your code it looks like I cannot get the bike connected (while it is recognized by Kettler2Ble by 360manu). Any plan to open up to other models than the Racer 9? The Ergoracer GT has a serial interface and I use a Serial-to-usb converter.

Thanks Guido

nebucaz commented 3 years ago

Hi Gudio. I only have a Racer 9 and will not be able to test any other model. I assume, that older models have lower serial speeds (my Track 5 treadmill communicates at a symbol rate of 9600). Maybe you want to test the serial connection manually using a serial terminal. I used a python script to test the connectoin/speed of the serial line. Then you will have to hack the code to adapt to your speed (the speed is hardcoded for racer 9 at 57600 on line 26 of KettlerRacer.swift and line 38 where the rate is set according to the machine type.) You could edit the code to accommodate your model and make a pull request, when it's working ;-). Below I provide the python script I've used to test the connection with my Track 5 treadmill. Let me know, how things proceed!

`

!/usr/bin/python

import serial import time

def idWithRate(rate): print("try ", rate) ser = serial.Serial('/dev/ttyUSB0', rate, timeout=2) ser.write(b"ID\r\n\r\n") # write a string line = ser.readline() # read a '\n' terminated line print("line %s rate= %s"%(line, rate))

def sendCMD(cmd):

com.write(bytes(cmd, 'utf-8'))

com.write(b"ST\r\n") line=com.readline() print("%s=%s"%(cmd,line))

print ("start")

com = serial.Serial('/dev/ttyUSB0', 9600, timeout=2) print(com.name)

idWithRate(4800) idWithRate(9600) idWithRate(14400) idWithRate(19200) idWithRate(38400) idWithRate(57600) idWithRate(115200)

`

Sturmenstrudel commented 3 years ago

Thanks. The baud rate is 9600 for the Ergoracer, I have already modified the file as per your instructions. Just a question, as I am not so much into Linux and compiling stuff: should I recompile after the changes on KettlerRacer.swift? I thought so... so I just "rm -r .build" directory and recompiled again with "swift run". Is it correct? At the startup, "sudo kracerble/.build/debug/kracerble 2>&1", in the log appearing on screen I read "disconnecting /dev/ttyUSB0" which does not sound good. And indeed the trainer does not show the serial port icon on the display, like it should instead happen. That makes me think that I did something wrong?

2021-01-14 13:57:31.210 kracerble[4158:b3454010] Peripheral type is Cycling Power 2021-01-14 13:57:31.216 kracerble[4158:b3454010] Peripheral Log: Started GATT Server 2021-01-14 13:57:31.220 kracerble[4158:b3454010] Kettler Peripheral started 2021-01-14 13:57:31.237 kracerble[4158:b3454010] advertizing services 0x180A 0x1818 2021-01-14 13:57:31.240 kracerble[4158:b3454010] start bluetooth server 2021-01-14 13:57:31.243 kracerble[4158:b3454010] Start polling 2021-01-14 13:57:32.249 kracerble[4158:b22fe410] Disconnecting /dev/ttyUSB0 2021-01-14 13:57:32.257 kracerble[4158:b22fe410] Serial port /dev/ttyUSB0 opened successfully.

nebucaz commented 3 years ago

Recompile: yes, this is necessary after every change in the source code Disconnecting: This is a normal behaviour: Line 263 of KettlerRacer.swift there is simply a disconnect(). It then starts the process of connecting to the device by cycling through available serial ports. As you can see in your log, just after the disconnection there is a successful reconnection of /dev/ttyUSB0. The USB icon is not shown on the display of my Racer 9 either while values are polled successfully. I did not investigate this any deeper - maybe there is another command to be sent to light this up.

If the program is able to communicate with the fitness device, the output will be similar to the following lines (I'm running an older version of the software on this device, so there may be small differences):

pi@raspberrypi:~ $ 2021-01-14 19:06:45.143 kracerble[603:76f3e230] Characteristic 2A29 (Manufacturer Name String) with permissions [Read] and 0 descriptors 2021-01-14 19:06:45.155 kracerble[603:76f3e230] Characteristic 2A63 (Cycling Power Measurement) with permissions [Read] and 2 descriptors 2021-01-14 19:06:45.161 kracerble[603:76f3e230] Characteristic 2A65 (Cycling Power Feature) with permissions [Read] and 1 descriptors 2021-01-14 19:06:45.166 kracerble[603:76f3e230] Characteristic 2A5D (Sensor Location) with permissions [Read] and 1 descriptors 2021-01-14 19:06:45.169 kracerble[603:76f3e230] Peripheral Log: Started GATT Server 2021-01-14 19:06:45.171 kracerble[603:76f3e230] Kettler Peripheral started 2021-01-14 19:06:45.179 kracerble[603:76f3e230] advertizing services 0x180A 0x1818 2021-01-14 19:06:45.180 kracerble[603:76f3e230] start 2021-01-14 19:06:46.182 kracerble[603:722fe410] Disconnecting /dev/ttyUSB0 2021-01-14 19:06:46.187 kracerble[603:722fe410] Serial port /dev/ttyUSB0 opened successfully. 2021-01-14 19:06:48.418 kracerble[603:722fe410] will Start Session 2021-01-14 19:06:48.655 kracerble[603:722fe410] Created fitness session kracer9_2021-01-14_1906.csv 2021-01-14 19:06:48.658 kracerble[603:722fe410] Service 1818 (Cycling Power): characteristic 2A63 (Cycling Power Measurement) did change with new value 34 bytes 2021-01-14 19:06:49.189 kracerble[603:722fe410] Service 1818 (Cycling Power): characteristic 2A63 (Cycling Power Measurement) did change with new value 34 bytes 2021-01-14 19:06:50.189 kracerble[603:722fe410] Service 1818 (Cycling Power): characteristic 2A63 (Cycling Power Measurement) did change with new value 34 bytes

The periodic (every second) output of the highlighted line indicates, that there is a successful pull of values over the serial connection from the fitness device, forwarded to the Bluetooth/GATT server and broadcasted from there. If this does not happen on your device, polling does not work properly.

In this case I recommend using the python script or a serial terminal program first to test communication. Maybe the command set is different? I had to do it to find out the proper sequence of newlines and also had to change the way characters are read (when communicating to Track5 after Racer 9 worked). The termination of strings is important when sending a command (line 317) but also when receiving (to detect the end of the response, see line 323). Try to get an answer to the ID command an/or the ST (more on commands). Latter should send you all the relevant values you need

Sturmenstrudel commented 3 years ago

Hi, interesting update: 1) if I execute the python serial communication test BEFORE starting the kracerble, then the polling works and I can correctly transfer the power reading from the bike to the computer running The Sufferfest. 2) Only the power reading is recognized, while I can't get any info about cadence and I cannot control the power from the application in ERG mode. What do you think? I find very weird point #1, maybe it's a matter of initiation or what else?

nebucaz commented 3 years ago

1: I have no idea, why this is behaving as you describe. Kracerble uses the swift serial lib - I don't know, if there is a difference between python serial and swift serial. Maybe your device needs another "start sequence" - kracerble is sending the ID command once and then starts to request status. Maybe the device expects 2x ID command. (I saw this, when sniffing the USB connection between the official Kettler software and my Track5 device). 2: This is as designed. KracerBLE only is broadcasting the characteristics according to the CyclingPower Service (0x1818). There is no cadence available and no power setting possible. For this, you might want to implement the Fitness Machine service with the corresponding characteristics.