Cross-platform Bluetooth API for Go and TinyGo.

Go Bluetooth

Go Bluetooth

PkgGoDev CircleCI

Go Bluetooth is a cross-platform package for using Bluetooth Low Energy hardware from the Go programming language.

It works on typical operating systems such as Linux, macOS, and Windows.

It can also be used running "bare metal" on microcontrollers produced by Nordic Semiconductor by using TinyGo.

The Go Bluetooth package can be used to create both Bluetooth Low Energy Centrals as well as to create Bluetooth Low Energy Peripherals.

Bluetooth Low Energy Central

A typical Bluetooth Low Energy Central would be your laptop computer or mobile phone.

This example shows a central that scans for peripheral devices and then displays information about them as they are discovered:

package main

import (
	"tinygo.org/x/bluetooth"
)

var adapter = bluetooth.DefaultAdapter

func main() {
	// Enable BLE interface.
	must("enable BLE stack", adapter.Enable())

	// Start scanning.
	println("scanning...")
	err := adapter.Scan(func(adapter *bluetooth.Adapter, device bluetooth.ScanResult) {
		println("found device:", device.Address.String(), device.RSSI, device.LocalName())
	})
	must("start scan", err)
}

func must(action string, err error) {
	if err != nil {
		panic("failed to " + action + ": " + err.Error())
	}
}

Bluetooth Low Energy Peripheral

A typical Bluetooth Low Energy Peripheral would be a temperature sensor or heart rate sensor.

This example shows a peripheral that advertises itself as being available for connection:

package main

import (
	"time"

	"tinygo.org/x/bluetooth"
)

var adapter = bluetooth.DefaultAdapter

func main() {
  	// Enable BLE interface.
	must("enable BLE stack", adapter.Enable())

  	// Define the peripheral device info.
	adv := adapter.DefaultAdvertisement()
	must("config adv", adv.Configure(bluetooth.AdvertisementOptions{
		LocalName: "Go Bluetooth",
  	}))
  
  	// Start advertising
	must("start adv", adv.Start())

	println("advertising...")
	for {
		// Sleep forever.
		time.Sleep(time.Hour)
	}
}

func must(action string, err error) {
	if err != nil {
		panic("failed to " + action + ": " + err.Error())
	}
}

Current support

Linux macOS Windows Nordic Semi
API used BlueZ CoreBluetooth WinRT SoftDevice
Scanning ✔️ ✔️ ✔️ ✔️
Connect to peripheral ✔️ ✔️ ✔️
Write peripheral characteristics ✔️ ✔️ ✔️
Receive notifications ✔️ ✔️ ✔️
Advertisement ✔️ ✔️
Local services ✔️ ✔️
Local characteristics ✔️ ✔️
Send notifications ✔️ ✔️

Linux

Go Bluetooth support for Linux uses BlueZ via the D-Bus interface thanks to the https://github.com/muka/go-bluetooth package. This should work with most distros that support BlueZ such as Ubuntu, Debian, Fedora, and Arch Linux, among others.

Linux can be used both as a BLE Central or as a BLE Peripheral.

Installation

You need to have a fairly recent version of BlueZ, for example v5.48 is the latest released version for Ubuntu/Debian.

sudo apt update
sudo apt install bluez

Once you have done this, you can obtain the Go Bluetooth package using Git:

git clone https://github.com/tinygo-org/bluetooth.git

Compiling

After you have followed the installation, you should be able to compile/run the "scanner" test program:

cd bluetooth
go run ./examples/scanner

macOS

Go Bluetooth support for macOS uses the CoreBluetooth libraries thanks to the https://github.com/JuulLabs-OSS/cbgo package.

As a result, it should work with most versions of macOS, although it will require compiling using whatever specific version of XCode is required by your version of the operating system.

The macOS support only can only act as a BLE Central at this time, with some additional development work needed for full functionality.

Installation

In order to compile Go Bluetooth code targeting macOS, you must do so on macOS itself. In other words, we do not currently have cross compiler support. You must also have XCode tools installed:

xcode-select --install

Once you have done this, you can obtain the Go Bluetooth package using Git:

git clone https://github.com/tinygo-org/bluetooth.git

Compiling

After you have followed the installation, you should be able to compile/run the "scanner" test program:

cd bluetooth
go run ./examples/scanner

Windows

Go Bluetooth support for Windows uses the WinRT Bluetooth interfaces by way of the https://github.com/tinygo-org/bluetooth/winbt package that is part of this package.

The Windows support is still experimental, and needs additional development to be useful. At this time, it can only be used to perform scanning operations as a BLE Central.

For specifics please see https://github.com/tinygo-org/bluetooth/issues/13

Installation

Once you have done this, you can obtain the Go Bluetooth package using Git:

git clone https://github.com/tinygo-org/bluetooth.git

Compiling

After you have followed the installation, you should be able to compile/run the "scanner" test program:

cd bluetooth
go run .\examples\scanner

Nordic Semiconductor

Go Bluetooth has bare metal support for several chips from Nordic Semiconductor that include a built-in Bluetooth Low Energy radio.

This support requires compiling your programs using TinyGo.

You must also use firmware provided by Nordic Semiconductor known as the "SoftDevice". The SoftDevice is a binary blob that implements the BLE stack. There are other (open source) BLE stacks, but the SoftDevices are pretty solid and have all the qualifications you might need. Other BLE stacks might be added in the future.

The Nordic Semiconductor SoftDevice can be used both as a BLE Central or as a BLE Peripheral, depending on which chip is being used. See the "Supported Chips" section below.

Installation

You must install TinyGo to be able to compile bare metal code using Go Bluetooth. Follow the instructions for your operating system at https://tinygo.org/getting-started/

Once you have installed TinyGo, you can install the Go Bluetooth package by running:

git clone https://github.com/tinygo-org/bluetooth.git

Check your desired target board for any additional installation requirements.

Adafruit "Bluefruit" boards

The line of "Bluefruit" boards created by Adafruit already have the SoftDevice firmware pre-loaded. This means you can use TinyGo and the Go Bluetooth package without any additional steps required. Supported Adafruit boards include:

After you have installed TinyGo and the Go Bluetooth package, you should be able to compile/run code for your device.

For example, this command can be used to compile and flash an Adafruit Circuit Playground Bluefruit board with the example we provide that turns it into a BLE server to control the built-in NeoPixel LEDs:

tinygo flash -target circuitplay-bluefruit ./examples/circuitplay

There are other boards with TinyGo support that also use the same UF2 bootloader with pre-loaded SoftDevice. They include:

BBC micro:bit

Version 1

The BBC micro:bit uses an nRF51 chip with a CMSIS-DAP interface.

You will need to install OpenOCD (http://openocd.org/) to flash the board.

First, flash the SoftDevice firmware by copying the .hex file to the device. For example (on Linux):

cd bluetooth
cp ./s110_nrf51_8.0.0/s110_nrf51_8.0.0_softdevice.hex /media/yourusername/MICROBIT/

Once you have copied the SoftDevice firmware to the BBC micro:bit, you can then flash your TinyGo program:

tinygo flash -target=microbit-s110v8 ./examples/heartrate

Version 2

The BBC micro:bit v2 uses an nRF52833 chip with a CMSIS-DAP interface.

Support for the v2 will be available soon.

Supported Chips

The following Nordic Semiconductor chips are currently supported:

  • nRF51822 with the S110 SoftDevice (version 8). This SoftDevice does not support all features (e.g. scanning).
  • nRF52832 with the S132 SoftDevice (version 6).
  • nRF52840 with the S140 SoftDevice (version 6 and 7).

Flashing the SoftDevice on Other Boards

To use a board that uses one of the above supported chips from Nordic Semiconductor, other then those already listed, you will probably need to install the SoftDevice firmware on the board yourself in order to use it with TinyGo and the Go Bluetooth package.

Flashing the SoftDevice can sometimes be tricky. If you have nrfjprog installed, you can erase the flash and flash the new BLE firmware using the following commands. Replace the path to the hex file with the correct SoftDevice, for example s132_nrf52_6.1.1/s132_nrf52_6.1.1_softdevice.hex for S132 version 6.

nrfjprog -f nrf52 --eraseall
nrfjprog -f nrf52 --program path/to/softdevice.hex

After that, don't reset the board but instead flash a new program to it. For example, you can flash the Heart Rate Sensor example using tinygo (modify the -target flag as needed for your board):

tinygo flash -target=pca10040-s132v6 ./examples/heartrate

Flashing will normally reset the board.

API stability

The API is not stable! Because many features are not yet implemented and some platforms (e.g. Windows and macOS) are not yet fully supported, it's hard to say what a good API will be. Therefore, if you want stability you should pick a particular git commit and use that. Go modules can be useful for this purpose.

Some things that will probably change:

  • Add options to the Scan method, for example to filter on UUID.
  • Extra options to the Enable function, to request particular features (such as the number of peripheral connections supported).

This package will probably remain unstable until the following has been implemented:

  • Scan filters. For example, to filter on service UUID.
  • Bonding and private addresses.
  • Full support for all features at least two desktop operating systems.
  • Maybe some Bluetooth Classic support, such as A2DP.

Contributing

Your contributions are welcome!

Please take a look at our CONTRIBUTING.md document for details.

Frequently Asked Questions

Q. Where can I get an introduction to Bluetooth Low Energy, GAP, GATT, etc.?

A. Please see this excellent article from our friends at Adafruit: https://learn.adafruit.com/introduction-to-bluetooth-low-energy

Q. What is a client and server in BLE?

A. Please see https://devzone.nordicsemi.com/f/nordic-q-a/71/what-is-a-client-and-server-in-ble

Q. Can a device be both a GATT client and GATT server?

A. Yes, but this is not currently supported by Go Bluetooth. Current support is either to act as a central in client mode, or as a peripheral in server mode.

License

This project is licensed under the BSD 3-clause license, see the LICENSE file for details.

The SoftDevices from Nordic are licensed under a different license, check the license file in the SoftDevice source directory.

Owner
TinyGo
Go compiler for small places. Microcontrollers, WebAssembly, and command-line tools. Based on LLVM.
TinyGo
Comments
  • windows: finish adding needed interfaces to act as central

    windows: finish adding needed interfaces to act as central

    To use this module as a BLE central from a machine running Windows there are a few more interfaces that need to be implemented.

    • [ ] Connect to a Device
    • [ ] DiscoverServices on Device
    • [ ] DiscoverCharacteristics on a discovered Services
    • [ ] Write to a characteristic
    • [ ] Receive notifications from a characteristic

    See https://github.com/tinygo-org/bluetooth/blob/dev/gattc_darwin.go for example implementation in macOS.

    The core of the low-level code needed to communicate with Windows Bluetooth interfaces has been written, see https://github.com/tinygo-org/bluetooth/tree/dev/winbt for more info.

  • {darwin,linux,windows,sd}: add get mtu function

    {darwin,linux,windows,sd}: add get mtu function

    This PR adds a function to retrieve the MTU of a characteristic on Darwin, Linux, Windows and SoftDevice.

    Implementation details

    I tried to keep the same signature on both implementations. So I had to adapt the Darwin implementation a little bit to match the requirements of linux:

    • In Linux (bluez) we read the MTU property in the characteristic. So I did the same in other platforms, even though we read the MTU from the device.
    • Since in Linux reading the MTU can fail, I added the same return type ((uint16, error)) on other platforms, even though it cannot fail.

    Regarding Linux implementation, the MTU property is quite recent (bluez 5.62), so it is going to fail to anyone using an older version of bluez. I though about calling AcquireWrite as a fallback. This method returns a file descriptor to write messages and its MTU, and we could just call it and immediately close the file descriptor to get the MTU. But it felt ugly, and hacky, and I'm not sure if it has any other implications.

  • DefaultAdapter not declared by package bluetooth compiler (UndeclaredImportedName)

    DefaultAdapter not declared by package bluetooth compiler (UndeclaredImportedName)

    I wired up a HC-05 to a Raspberry Pi Pico's UART0. I connect the 3.3 to 3.3 and gnd to gnd and tx to GP1 and rx to GP0.

    When working with the stock example:

    package main
    
    import (
    	"time"
    
    	"tinygo.org/x/bluetooth"
    )
    
    var adapter = bluetooth.DefaultAdapter
    
    func main() {
    	// Enable BLE interface.
    	must("enable BLE stack", adapter.Enable())
    
    	// Define the peripheral device info.
    	adv := adapter.DefaultAdvertisement()
    	must("config adv", adv.Configure(bluetooth.AdvertisementOptions{
    		LocalName: "Go Bluetooth",
    	}))
    
    	// Start advertising
    	must("start adv", adv.Start())
    
    	println("advertising...")
    	for {
    		// Sleep forever.
    		time.Sleep(time.Hour)
    	}
    }
    
    func must(action string, err error) {
    	if err != nil {
    		panic("failed to " + action + ": " + err.Error())
    	}
    }
    

    The error:

    DefaultAdapter not declared by package bluetooth compiler (UndeclaredImportedName)
    

    Is there additional setup necessary? There is nothing in the example showing how to handle the DefaultAdapter as the bluetooth mod on line 9 does not recognize it.

    I am simply looking to run this example to connect to a central.

  • sd: unable to run scanner example

    sd: unable to run scanner example

    When I try to run the scanner example with -target circuitplay-bluefruit, the call to adaptor.Scan() results in a crash. The message itself seems to be obscured, nothing comes thru except the character p which I perhaps assume might be due to a panic getting lost?

  • macOS 12+: Accept service UUIDs when scanning for devices

    macOS 12+: Accept service UUIDs when scanning for devices

    Issue

    In macOS 12 Monterey, developers have been reporting issues with CoreBluetooth device discovery. This issue manifests as a BLE scan returning no device results. This currently affects lots of BLE projects that use CoreBluetooth under the hood, such as Python Bleak.

    Fix

    The fix for this issue is to provide a non-empty list of service UUIDs to scanForPeripheralsWithServices:options:.

    More context

    This issue (feature?) has not yet been officially acknowledged by Apple. In the meantime, other projects are working to add user ergonomics around this issue. Bleak warns users who do not provide a list of advertised service UUIDs that MacOS will not return any results for their scan.

    To serve macOS users, I would like to add support for tinygo Bluetooth to take a list of advertised service UUIDs when starting to scan. This is a first attempt at adding support for this to the Darwin adapter.

    I know this breaks the interface and will not compile, but I'd like to start a conversation with this first draft of code. I'm totally OK with maintainers editing this PR however they like. I'm not familiar with this codebase and want to help fit this fix into tinygo – how can I help?

  • windows: add characteristic discovery

    windows: add characteristic discovery

    Adds service characteristic discovery. This change does not include characteristic reading or writing. It only allows obtaining their UUID and their properties (whether the characteristic supports writes, notifications, and so on. Checkout the winRT-go source file to view all properties).

  • windows: add winrt-go dependency and remove manually generated code

    windows: add winrt-go dependency and remove manually generated code

    This change removes the winbt package that included all the manually created WinRT classes and adds a dependency to saltosystems/winrt-go, which contains automatically generated WinRT API projections.

    This will vastly simplify development, as developers won't have to go through the Windows IDL files to generate a Go struct that matches the Windows API they want to call.

  • windows: add device connection and disconnection

    windows: add device connection and disconnection

    ~~All the code under winbt/winrt/<package> has been automatically generated. The change also includes utilities to dynamically generate UUIDs for parameterised classes and a reference counter used in delegates.~~

    ~~As I said in #13, the generated code has been added to the PR because the repository it belongs to is not yet public.~~

    This PR adds the Device struct and the Connect and Disconnect methods.

    When testing this, notice that calling Disconnect may not disconnect from the device. Disconnect only removes the references to it, and Windows will decide when to call disconnect (another program may be connected to it).

  • 16bits UUID byte format on macos is different from other platforms.

    16bits UUID byte format on macos is different from other platforms.

    DIS service discovered UUID on macos: 180a0000-0000-0000-0000-000000000000

    DIS service discovered UUID on others: 0000180a-0000-1000-8000-00805f9b34fb

    specification: 128_bit_value = 16_bit_value * 2^96 + Bluetooth_Base_UUID

  • gattc: return pointers to DeviceService and DeviceCharacteristic types

    gattc: return pointers to DeviceService and DeviceCharacteristic types

    This PR changes the API to always return pointers to DeviceService and DeviceCharacteristic instead of the value types to ensure consistency.

    For example:

    func (s *DeviceService) DiscoverCharacteristics(uuids []UUID) ([]*DeviceCharacteristic, error)
    

    The slice is now []*DeviceCharacteristic instead of []DeviceCharacteristic so that any cached copies still refer to the same characteristic. This will make it a lot easier for the macOS implementation of the Read() function, among other things.

  • Field not found: Roles

    Field not found: Roles

    $ go run ./examples/scanner
    panic: failed to enable BLE stack: MapToStruct: Field not found: Roles
    
    goroutine 1 [running]:
    main.must(...)
    	/dev/shm/bluetooth/examples/scanner/main.go:23
    main.main()
    	/dev/shm/bluetooth/examples/scanner/main.go:11 +0x1df
    

    os: Archlinux kernel: 5.8.10 bluez: 5.55 go: 1.15.2

  • linux: fix io.Reader impl for characteristics

    linux: fix io.Reader impl for characteristics

    The DeviceCharacteristics type implements io.Reader, but previously did not follow the semantics as defined in the docs. Several bugs are present that were fixed by this pull request:

    1. the previous code always returned the full length of the data, regardless of how much data was actually read from the copy
    2. io.EOF was never returned, meaning that we could never tell if the read was complete
    3. the read always filled the buffer, then started over, meaning if the destination buffer was too small you would always get a partial read with no way to tell that the read was incomplete

    This patch fixes this by caching the read internally, then copying from the read slice. The value is not actually read again using the upstream methods until the internal cached value is fully read.


    It may also be beneficial to expose the internal read method in the future

    func (*DeviceCharacteristics) ReadValue() ([]byte, error)
    

    This would always allocate a byte slice, but would also always call the upstream read method, ignoring the internal cache. Effectively this would be the same as:

    io.ReadAll(characteristic)
    
  • Device characteristics returned out of order on Linux

    Device characteristics returned out of order on Linux

    The documentation for DiscoverCharacteristics says:

    If there is no error, the characteristics slice has the same length as the UUID slice with characteristics in the same order in the slice as in the requested UUID list.

    However, at least on Linux, the code appears to just iterate through characteristics appending them to the slice as they are found. The documentation either needs to be changed, or the code updated to reflect the expected behavior.

  • No DefaultAdvertisement found

    No DefaultAdvertisement found

    What is missing?

    go run ./examples/advertisement

    tinygo.org/x/bluetooth/examples/advertisement

    examples/advertisement/main.go:13:17: adapter.DefaultAdvertisement undefined (type *bluetooth.Adapter has no field or method DefaultAdvertisement) examples/advertisement/main.go:20:24: adapter.Address undefined (type *bluetooth.Adapter has no field or method Address)

  • Update uuids and their generation

    Update uuids and their generation

    Hi!

    Upon inspecting the Bluetooth Assigned Numbers, I noticed a lot of them were missing in this library at this moment; the last update seems to be from 2021. I opened this PR to update the uuids and their generation.

    Changes:

    • Removed the data folder and added the Bluetooth Numbers Database as submodule instead. Now the 'uuid data' can be updated by pulling in the changes from that repo and running the generators.
    • Variable names now remove 'illegal' characters based on a regular expression. I think using a regex is fine here, since this code only runs while generating the uuids. It is an easy way to get rid of weird characters like e.g. ® in "LEGO® Wireless Protocol v3 Hub Service".
    • Updated the usage of deprecated strings.Title
    • Added a dedup function to avoid naming collision. "Apple Reserved Service" is defined multiple times, for example. These get called AppleReservedService1, AppleReservedService2, etc.
  • LocalName returning empty on Windows

    LocalName returning empty on Windows

    Hi guys,

    I am having some difficulty fetching the LocalName from an advertisement while running on Windows 10 (1903). I have no problem getting the manufacturer data, device address, and RSSI. I have tried 3 different computers running Windows 10 and had no luck.

    To test, I am using the Central example in README.md and this is an example of what is returned.

    scanning...
    found device: FF:37:4A:A2:AA:60 -63
    found device: 76:F8:55:B0:87:C0 -59
    found device: F0:B3:EC:54:17:E4 -61
    found device: 59:33:42:90:36:A4 -50
    found device: FF:09:C7:01:14:2B -63
    found device: 4B:06:6E:6D:9E:AC -65
    found device: FF:37:4A:A2:AA:60 -66
    

    I have tried v0.6.0 as well as the latest on dev.

    I have had a bit of a look myself but quickly got out of my depth when it moved to WinRT.

    Cheers

  • It cannot find more than one characteristic with the same UUID

    It cannot find more than one characteristic with the same UUID

    I have a temperature sensor peripheral that has an environmental sensing service, and there, two temperatures (same UUID).

    A call to DiscoverCharacteristics, with either empty or the Temperature UUID, returns only one of the two characteristics.

    Is this a bug or something yet to be implemented?

Cross platform locale detection for Golang

go-locale go-locale is a Golang lib for cross platform locale detection. OS Support Support all OS that Golang supported, except android: aix: IBM AIX

Aug 20, 2022
this is an api that execute your deno code and send you the output

this a simple api that execute your deno code and send you the output, has not limit per request example request: in deno: const rawResponse = await f

Dec 23, 2022
An API that provides a small but well-thought service converting Euro to US Dollar and vice-versa

Currency Converter ###Problem An API that provides a small but well-thought service converting Euro to US Dollar and vice-versa. That API should only

Jan 30, 2022
Go API backed by the native Dart Sass Embedded executable.

This is a Go API backed by the native Dart Sass Embedded executable. The primary motivation for this project is to provide SCSS support to Hugo. I wel

Jan 5, 2023
A pluggable backend API that enforces the Event Sourcing Pattern for persisting & broadcasting application state changes
A pluggable backend API that enforces the Event Sourcing Pattern for persisting & broadcasting application state changes

A pluggable "Application State Gateway" that enforces the Event Sourcing Pattern for securely persisting & broadcasting application state ch

Nov 1, 2022
The easiest way to make API documents for GraphQL

Document Generator for GraphQL gqldoc is now alpha gqldoc is command line tool to generate documents from GraphQL schema or your GraphQL endpoint. the

Dec 20, 2022
reflect api without runtime reflect.Value cost

reflect2 reflect api that avoids runtime reflect.Value cost reflect get/set interface{}, with type checking reflect get/set unsafe.Pointer, without ty

Jan 4, 2023
Go scripts for finding an API key / some keywords in repository
Go scripts for finding an API key / some keywords in repository

Git-Secret Go scripts for finding an API key / some keywords in repository Update V1.0 ?? Added some API Key checker Screenshoot ?? How to Install go

Dec 30, 2022
🚀 Use Lanyard API easily in your Go app!

?? Go Lanyard Use Lanyard API easily in your Go app! ?? Installation Initialize your project (go mod init example.com/example) Add package (go get git

Mar 11, 2022
A simple API for computing diffs of your documents over the time built on a scalable technology stack.

Diffme API WIP - this is an API to compute diffs between documents. It serves as a way to easily create audit logs for documents in your system, think

Sep 8, 2021
An Api for Task by Appointy made using go.

AppointyTask API How to Compile Export All the required environment variables. MONGO_URI = Database URI PORT = Port to run the server on DATABA

Oct 10, 2021
Instagram Backend API Using GO
Instagram Backend API Using GO

InstaCloneGo ⚡ Instagram Backend API Using GO Setup ❄️ go run server.go API END POINTS CREATE USERS :http://localhost:8001/users GET A USER USING ID

Oct 10, 2021
An implement of CNI depending on neutron API

An implement of CNI depending on neutron API

Dec 27, 2021
A lib of golang which contains many funny api;

A lib of golang which contains many funny api; I created it cause I could not find these more-effient apis from other repo.

Oct 27, 2021
Rest Api Generator for Golang Programming Language

Rest Api Generator for Golang Programming Language

Nov 29, 2021
Golang code-generators used to implement Kubernetes-style API types.

code-generator Golang code-generators used to implement Kubernetes-style API types. Purpose These code-generators can be used in the context of Custom

Dec 30, 2022
Sentiment Analysis Pipeline + API written in Golang (currently processing Twitter tweets).

Go Sentiment Analysis Components Config: config module based in JSON (enter twitter credentials for use) Controllers: handle the API db call/logic for

Mar 22, 2022
Sentiment Analysis Pipeline + API written in Golang (currently processing Twitter tweets).

Go Sentiment Analysis Components Config: config module based in JSON (enter twitter credentials for use) Controllers: handle the API db call/logic for

Mar 22, 2022
GoApiRandom - Api to get random numbers

GoApiRandom - Api to get random numbers

Jan 18, 2022