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 19 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.

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