-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Echelon Support #27
Comments
Hi @vcipriani it's very interesting! I'm running a similar project, if you're interested you can follow these steps and we will add the compatility https://github.com/cagnulein/qdomyos-zwift#your-machine-is-not-compatible |
@vcipriani Maybe this is a starting point? https://github.com/UCF-SDTeam13/echelon-bike |
I might have a great starting point using a cheap ESP 32. My project takes any spin bike with an old style knob resistance control and converts it to a Smart Bike. It's getting pretty full featured and has a web configuration interface. Hardware design is included. |
Unfortunately, I haven't had time to do anything with this yet. However, another project has deserialized the Echelon messages so adding support here just got easier. |
I already implemented on my app https://github.com/cagnulein/qdomyos-zwift |
Hey @ptx2! Thanks for this awesome repository! I really love the idea and love put into this tool! I've been trying now for several days and many hours getting Echelon support going with the info others provided here and with the debugging JS tool that you outlined in your blog post to this great tool, unfortunately, I wasn't able to get it to work and was hoping you might have some input. It seems to me that noble isn't quite doing what it should since it seems to only ever show the very first Service UUID of any BLE device no matter if that isn't the right service, it won't discover the device or connect to it. Checking with Bluetility, the Echelon Connect Sport Bike provides 2 services, the first one doesn't seem to do anything and the second seems to be structured as a UART similarly to your Flywheel bike with one TX and one RX stream. Yet, noble doesn't want to connect to the second service which is the actual UART service since noble doesn't even discover the service through discover (only the first) and I can only connect to the bike when identifying the bike through it's mac address. Initially I though it was an issue with my hardware, but I've verified it on a rpi4 with arch linux as well as raspbian and then with an rpi0w with your image and the node and npm in the bin directory. Do you have any insight if there's a way around this or this fix this behavior? Thanks! |
Hey, thanks for the kind words @EfficientSetting! Excited to hear you are working on Echelon support. Can you share the noble code that's not working? |
I think it's easiest if I paste the full terminal output and write my observations underneath:
Note: The gymnasticon host is a rpi0w with the image from this repo. The node binary is the node binary in the gymnasticon folder, just added to the path of the root user for convenience. If you look at the advertisement data, noble seems to think that the Echelon bike only advertises the first service and nothing else. This seems to go along with what I found here: abandonware/noble#99 or at least I think so. The newer hci binaries seem to be incompatible, but I don't know for sure. Due to this error, connecting to this peripheral with the service UUID of my target service doesn't work. The only way to connect to the bike with noble seems to be through it's mac address, which won't work for anyone but me (or only through the macaddress option). Interestingly services and characteristics are only shown on connect through the async Would be interesting to hear if you faced similar issues or have any insight @ptx2. Thanks |
Looking at the reference link that ptx2 already posted above, the relevant data that you are looking for seems to be in ServiceUUID 1801 /AttributeUUID 0bf669f4-45f2-11e7-9598-0800200c9a66. That UUID has the capability of "notify", not "read". Therefore you might want to look at the work done in #41, which subscribes to such a notify UUID. But in the case of the Echelon bike, the values are then differently encoded within the Notify message. One challenge that I see, is that the Echelon bike doesn't seem to transmit the power, but only the resistance level. |
@chriselsen Thanks for the reply. The problem is not finding the right GATT UUID, I figured that out after subscribing to the all UUIDs that offered to notify subscribers and seeing that this was the only one that actually gave any response. I haven't had any problems going that route with Swift on an iOS app that I put together, but that's also what I do for a living hence I'm more comfortable with that which is why I was wondering if there's something I'm missing with noble ... |
I'm not sure I understand your problem: It seem like the run of your It's true that the peripheral-explorer.js example that comes with the noble library tries to identify the services and characteristics in a crude way and often fails doing so. But you don't have to use that at all. As you said: You know the desired service and characteristic UUID. Try to subscribe to it and see what data you get back:
If this works, great! Than we can look at mapping the returned data to cadence / resistance / power levels. In that case, start with this pull request, change these two lines to your identified UUID above and replace these lines of code with:
While this doesn't yet map the raw data from the Echelon bike, it should at least spit it out on the console when you paddle. |
@chriselsen Thanks for your reply, unfortunately, your code outputs exactly nothing, which is the whole issue I've been trying to explain. Discovery/Scan on noble is simply not returning those UUIDs on any of the test devices I mentioned before. I'm well aware how Bluetooth works and that this should be working with any other bluetooth library, but as it stands, it seems that noble isn't working correctly with the underlying software dependencies and therefore doesn't work with certain btle devices. Not a problem with this tool itself, I'm aware, but since this also happens with the rpi image provided here both on an rpi 4 and rpi0w, I was hoping that's an issue that the author might seen before and found a more elegant workaround than I currently have in mind. If you look at the advertisement discovery output:
Noble only finds the very first service, not the second one or any the manufacturer data or anything else. This first service that noble finds, is of no use to use since it doesn't give us the data we want. We want service Now if we want to connect to this service, since we know the service exists (either from the Bluetility tool or using bluez or anything like it) then we should be able to connect to it using either the
Both commands didn't work as they returned nothing - since noble doesn't see these advertised services as established earlier. Only if we connect to the mac address of the bike directly, we'll be getting the service discovery you've been mentioning works successfully:
Although note: The synchronous discovery doesn't work as it returned nothing, only the async one did. I think this has to do with abandonware/noble#99 that others mentioned too. I've been able to work around the issue by simply making the connect to the unusable service |
Hey @EfficientSetting sorry for the slow reply here! I have not actually run into that issue before. It seems the service is not advertised but becomes available after connecting? To dig deeper I would capture a trace while running Bluetility and another while running noble and compare the advertising, connection and service discovery packets between the two to see if anything jumps out. You could use PacketLogger to capture a trace on macOS and btmon on Linux. It sounds like you managed to work around though? |
@ptx2 , We've got it working over at https://github.com/doudar/SmartSpin2k/tree/Echelon . Feel free to take a look and use it here if you need. If that link goes dead, it's because we've merged the echelon tree into master. The advertised UUID is #define ECHELON_DEVICE_UUID BLEUUID("0bf669f0-45f2-11e7-9598-0800200c9a66") Then once you connect, the service you need is #define ECHELON_SERVICE_UUID BLEUUID("0bf669f1-45f2-11e7-9598-0800200c9a66") Then you need to write byte message[] = {0xF0, 0xB0, 0x01, 0x01, 0xA2}; to characteristic #define ECHELON_WRITE_UUID BLEUUID("0bf669f2-45f2-11e7-9598-0800200c9a66") to tell the Echelon to broadcast the data. Then you read the data on characteristic #define ECHELON_DATA_UUID BLEUUID("0bf669f4-45f2-11e7-9598-0800200c9a66") The next trick is that it alternates between two different data broadcasts, one for resistance and the other with cadence. Only after you've seen both broadcasts can you calculate power. We do it with this: void EchelonData::decode(uint8_t *data, size_t length) |
Thanks @doudar! |
Just pushed up experimental support for Echelon if anyone with the bike wants to try: #76 |
Not sure the best way to track this, but I wanted to start a thread so that any interested parties can share info. Echelon's $500 connect sport bike seems to be extremely popular and I just purchased one. I'm hoping to start trying to reverse engineer it over the holiday but this is a bit out of my wheelhouse. It would be awesome to have Zwift support for it.
If anyone else makes progress on this front, please share info here (or let me know if there is a more appropriate place to discuss).
The text was updated successfully, but these errors were encountered: