Skip to content

Replace go-ble/ble with tinygo-org/bluetooth#373

Closed
Lenart12 wants to merge 20 commits intoteslamotors:mainfrom
Lenart12:tinygo-bluetooth
Closed

Replace go-ble/ble with tinygo-org/bluetooth#373
Lenart12 wants to merge 20 commits intoteslamotors:mainfrom
Lenart12:tinygo-bluetooth

Conversation

@Lenart12
Copy link
Contributor

Description

As per title... works great with my setup (RPi 3B+, Debian 12).
New stuff:

  • Use bluez as a backend on Linux
    • Can now specify which BT adapter to use
    • Will not break other BT clients using the same adapter
  • Write blocks with length depending on supported MTU, not fixed to 20 anymore
  • Also adds suport for windows (though that is untested).

Small example:

lenart@etera:~$ ./tesla-control -ble state closures # Default adapter
{
  "closuresState":  {
    "doorOpenDriverFront":  false,
    ...
    "timestamp":  "2025-02-11T22:40:37.534Z"
  }
}
lenart@etera:~$ ./tesla-control -ble -btAdapter=hci0 state closures # Can specify adapter
{
  "closuresState":  {
    "doorOpenDriverFront":  false,
    ...
    "timestamp":  "2025-02-11T22:41:09.072Z"
  }
}
lenart@etera:~$ ./tesla-control -ble -btAdapter=hci1 state closures # No adapter
Error: ble: failed to enable device: bluetooth: adapter /org/bluez/hci1 does not exist

Closes #372

Please select all options that apply to this change:

  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Bug fix (non-breaking change which fixes an issue)
  • Documentation update

Checklist:

Confirm you have completed the following steps:

  • My code follows the style of this project.
  • I have performed a self-review of my code.
  • I have made corresponding updates to the documentation.
  • I have added/updated unit tests to cover my changes.

This was causing issues if multiple scans were being requested one
after another quickly.
@skrul
Copy link

skrul commented Feb 12, 2025

Tested this on macOS 14.6.1 using a variety of vehicle-command commands (status, charging-set-amps, list-keys, charging-schedule-add, etc.) and it worked great. Thanks @Lenart12!

@Lenart12
Copy link
Contributor Author

Plesantly suprised it worked without changes, I was unable to test on mac so It only worked "in theory". Great :^)

@Lenart12
Copy link
Contributor Author

Lenart12 commented Feb 13, 2025

Ah... scan is still getting stuck 🤬 was testing overnight and it locked up. Not much logs to investigate it unfortunately.

Edit:
Caught it with more debugging statements (code here):

2025/02/13 15:59:39 DEBU received handler=ProxyCommand method=GET url=/api/proxy/1/vehicles/LRWYPC/connection_status from=[::1]:41852
2025/02/13 15:59:39 INFO received command=connection_status
2025/02/13 15:59:39 DEBU command pushed command=connection_status body=map[] stack size=0
2025/02/13 15:59:39 DEBU command popped command=connection_status body=map[] stack size=0
2025/02/13 15:59:39 DEBU processing connection_status command vin=LRWYGCFSXPC882647 operated=false
2025/02/13 15:59:39 DEBU tbhp scan for vehicle (connection_status) ... scanIndex=30
2025-02-13T15:59:39+01:00 [debug] Reusing existing BLE device
2025-02-13T15:59:39+01:00 [debug] [30] Scan for Safa48095868b70f9C
2025-02-13T15:59:39+01:00 [debug] [30] Start scanning
2025-02-13T15:59:40+01:00 [debug] [30] Scan cancelled
2025-02-13T15:59:40+01:00 [debug] [30] Stop scanning
2025/02/13 16:00:09 DEBU received handler=ProxyCommand method=GET url=/api/proxy/1/vehicles/LRWYPC/connection_status from=[::1]:34276
2025/02/13 16:00:09 INFO received command=connection_status
2025/02/13 16:00:09 DEBU command pushed command=connection_status body=map[] stack size=1
2025/02/13 16:00:39 DEBU received handler=ProxyCommand method=GET url=/api/proxy/1/vehicles/LRWYPC/connection_status from=[::1]:51804
2025/02/13 16:00:39 INFO received command=connection_status
2025/02/13 16:00:39 DEBU command pushed command=connection_status body=map[] stack size=2

Here we can see scan is stopped but code from library never finishes, and connection status commands start stacking up.

It should show

[30] Scan gorutine finished
[30] Exiting scanVehicleBeacon

Working example:

2025-02-13T15:59:28+01:00 [debug] [29] Scan for Safa48095868b70f9C
2025-02-13T15:59:28+01:00 [debug] [29] Start scanning
2025-02-13T15:59:29+01:00 [debug] [29] Scan cancelled
2025-02-13T15:59:29+01:00 [debug] [29] Stop scanning
2025-02-13T15:59:29+01:00 [debug] [29] Scan goroutine finished
2025-02-13T15:59:29+01:00 [debug] [29] Exiting scanVehicleBeacon

This seems to me that it is an issue with the bluetooth library... (and/or by other applications using the same adapter)

EDIT: Another event now with btmon logs... Happened at 17:20:14
scanstuck-btmon.log
scanstuck-tbhp.log

By looking at the logs It seems to me that the issues is that another program restarted the adapter while the scan is active. Probably the library doesn't handle such cases yet.

@Lenart12
Copy link
Contributor Author

Lenart12 commented Feb 13, 2025

Alas it was not library bug. What happened:

  1. scanVehicleBeacon starts Scan
  2. Another application restarts the adapter (This causes the scan to stop)
  3. scanVehicleBeacon ctx is canceled, call StopScan
  4. StopScan requests the termination of Scan() call
  5. Scan calls StopDiscovery, fails and returns an error since no scan is running
  6. It hangs on errorCh <- err because scanVehicleBeacon is no longer reading it

device, err := darwin.NewDevice()
if err != nil {
return nil, err
func IsAdapterError(err error) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function causes make linters to fail:

pkg/connector/ble/device_darwin.go:8:21: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)

I.e., change to IsAdapterError(_ error) bool {

return
}

// For simplcity, allow 30 seconds to wake up the vehicle, connect to it,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well fix "simplicity" typo next time you do a push

}
device, err := adapter.Connect(target.Address, params)
if err != nil && !connectionCancelled {
errorCh <- err
Copy link
Collaborator

@sethterashima sethterashima Feb 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's still a race condition here; if we enter into this if branch, and then the main thread sets connectionCancelled = true, we'll be blocked trying to write to errorCh and no one will ever unblock us by reading from it. Similarly, there's a race with the else if branch. We could solve both of these problems by making the errorCh and deviceCh channels buffered, which will allow the goroutine to write to them even if no one is listening:

	deviceCh := make(chan bluetooth.Device, 1)
	errorCh := make(chan error, 1)

This should also obviate teh need to use connectionCancelled, which is a bit sus anyway since AFAIK reading/writing to non-atomic booleans isn't well-defined behavior.

@sethterashima
Copy link
Collaborator

This is just about ready to merge, but I'm about to head out on a vacation with limited availability. @patrickdemers6, if I'm not around and the responses to the above comments look good, I think we can merge.

@Lenart12
Copy link
Contributor Author

Still want to fix an error before merging inside scanVehicleBeacon. It needs to handle adapter being powered off when trying to start a scan otherwise it gets in to an error loop

@Lenart12
Copy link
Contributor Author

I want to wait on tinygo-org/bluetooth#342 before merging

@Lenart12
Copy link
Contributor Author

Lenart12 commented Feb 26, 2025

Hey @sethterashima I have a questing if this is a regression, or not... If I keep the connection open for longer than 30s the car closes connection and if that happens, when i try to open the connection next time it will fail. If I close the connection before 30s it seems to not fail. I don't know if this is issue with tesla, bluez, or tinygo-org/bluetooth, maybe you will know...

In the attachment I sent bluetooth and dbus capture you can open with wireshark. You can check packet 628 that fails and then 919 retries and succedes. Again 3062, 3265 (failed twice) and 3547

merged.pcapng

EDIT: Actually I think this is unrelated to the "30s timeout"... need to figure out what is causing this

EDIT: I acually think this is an bluez issue (related ukBaz/BLE_GATT#9) as it is happening even in bluetoothctl tool. I think I need to implement the same workaroundin the bluetooth library.

@iainwhyte
Copy link

Hi @Lenart12 I've been watching this with interest because the current main branch 3.0.3 bluetooth library in use will go off with the fairies after 1-2 weeks of otherwise stable use, and only way to bring it back it a cold boot.

I've been testing your PR on a raspberry pi 4 and whenever I try any BLE commands, it hard locks up and tesla-control will not return, can't be killed :( only way to bring it back is a power cycle...

Sometimes, the very first command works, but then second one locks it hard.

@sethterashima
Copy link
Collaborator

@iainwhyte Could you run with -debug and post your logs?

@Lenart12
Copy link
Contributor Author

Lenart12 commented Mar 3, 2025

Also while monitoring with ./examples/ble/monitor.sh please. And share the file here :^)

@iainwhyte
Copy link

Also while monitoring with ./examples/ble/monitor.sh please. And share the file here :^)

Changed to branch tinygo-bluetooth to get the monitor.sh and now it seems to working perfectly (doh!).

Attached the bluetooth capture of me waking and honking horn, in case its still of interest.

I will run this branch for a week and see how it goes. Thanks!

bluetooth_capture_20250310_160735.pcapng.zip

return
}

if result.LocalName() == localName {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code has the same issues described in #373 (comment).

@sethterashima
Copy link
Collaborator

I know this is taking a while to get in, but I want you to know that your work here is appreciated, @Lenart12. I think we're in the homestretch.

@Lenart12
Copy link
Contributor Author

Lenart12 commented Apr 8, 2025

I think this approach wont work. As much as I hoped that BlueZ would solve much of the issues some people are experiencing in reality it seems that it is not stable enough to use reliably atleast on my setup (RPi 4B+). In some cases it blocks up the whole adapter for 30+ seconds.... (by failing to make a connection to the car)

This is an issue with BlueZ not with tinygo-org/bluetooth and as such we can't really fix it here or in the library, (only by changing hardware). I guess the best way to support as many people would be to use both libraries and allow the user to select whichever one they want, but then that seems like a waste and too much complexity.

@sethterashima what do you think should be done as fully switching the project to this library will break things for some people depending on the setup. I have not heard much feedback on which one most people prefer.

@Lenart12 Lenart12 mentioned this pull request Apr 8, 2025
8 tasks
@sethterashima
Copy link
Collaborator

It's discouraging that Golang BLE support is finicky. But thanks for your work here. Hopefully in the not to distant future the upstream issues will be resolved and we can blow the dust off of this PR.

@zlymeda
Copy link
Contributor

zlymeda commented Apr 28, 2025

I have been using the tinygo ble version for some time and it worked well.

I switched to the latest main branch that uses go-ble, and after a while the library wasn't able to "down" the hci, was getting connection timeout - actually I had to restart my raspberry pi in order to make it work again.

reverted again to tinygo, as it seems more stable (at least for me).

I think it'd be worth to be able to pick the implementation by a library user. I could draft a PR if you'd be interested.

@Lenart12
Copy link
Contributor Author

Having some system to choose the BT library would be great for me.

Right now, I have a Homeasistant addon using this library, and I need to include two compiled versions of the program. One with the current implementation, and one with tinygo-org library.

If instead we could select it perhaps during adapter initialization that would be great. Maybe even allowing to pass an implemented interface to allow users of the library to have complete HAL.

@zlymeda
Copy link
Contributor

zlymeda commented Apr 30, 2025

I started on it, but found some issues when trying to use both go-ble and tinygo at the same time.
the issue is caused by this replace replace github.com/JuulLabs-OSS/cbgo => github.com/tinygo-org/cbgo v0.0.4
we want to use it for the go-ble package, but tinygo is also using it and go fails with:

go mod tidy
go: github.com/tinygo-org/cbgo@v0.0.4 used for two different module paths (github.com/JuulLabs-OSS/cbgo and github.com/tinygo-org/cbgo)

removing the replace works, but that means cbgo for go-ble is used from JuulLabs-OSS and not tinygo

The cleanest would be to have different impl packages, one for tinygo and one for go-ble. And this repo would be extracted as a library and the current repo would have runnable commands and the examples (picking one ble impl by default)

What do you think would be the best course of action to support multiple ble impls?

I have experimented with the go.work and multiple modules in this repo, but that also comes with drawbacks..

@zlymeda
Copy link
Contributor

zlymeda commented Apr 30, 2025

another idea is to have this repo as-is, using go-ble as default (for now at least), but still implement interfaces to be able to replace the impl. and tinygo version would be a different repo

and then whoever uses this repo as a library can use the default or use the tinygo one (if they choose to)

@Lenart12
Copy link
Contributor Author

Would it be easier to fork go-ble/ble and change the cbgo dependency there. That repo is unmaintained anyways...

@zlymeda
Copy link
Contributor

zlymeda commented May 3, 2025

created a draft today: #400

still WIP, need to test it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace go-ble/ble with tinygo-org/bluetooth

5 participants