Skip to content
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

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

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

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

@Lenart12
Copy link
Contributor Author

So I have been testing overnight with constant requests to the car and so far I'm happy to report it has been super stable 🤞🥳 we can maybe consider this PR ready to merge.

(Obligatory xkcd)

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.

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
4 participants