Bluetooth
Advice for getting a reliable Bluetooth Low Energy (BLE) connection between the SignalK server and your labels.
Bluetooth can be used in of three ways by a plugin:
- Direct access to dongle (usually
hci0device). Not recommended - Access via
bluezanddbusservices. Better but not ideal - Using the BLE Manager added to SignalK in 2026. Recommended with caveats.
- “Use the SignalK BLE Manager API” setting is enabled, the adapter and its lifecycle are managed by the SignalK server, under its own Bluetooth admin settings, once for every BLE-consuming plugin.
- Under the hood, this uses
bluezanddbushowever manages them so that plugins are controlled in how they can impact each other - It also has a very useful GUI for seeing all scanned devices, and all GATT claims (GATT being the protocol for directly connecting to BLE devices).
- This is still new and settling down, so not yet the default for this plugin
The advice here is general to Bluetooth on Linux, whichever way its being used.
Choosing a Bluetooth Adapter
Section titled “Choosing a Bluetooth Adapter”First step is having a Bluetooth Low Energy (BLE) compatible bluetooth adapter available.
- Bluetooth adapters for Linux can be tricky
- TP-Link UB400 and Asus USB-BT500 are two well-known and available ones, though the ASUS USB-BT500 one can have problems with some Pi type boards (see Adapter stops responding)
- CSR4.0 dongles (CSR8510 chip) have had kernel support for years, and there are well known work arounds for some of them, including in the Linux kernel since v5.17
- Some Raspberry Pi models come with suitable Bluetooth built in
- See advice at Recommended Bluetooth Adapters for Linux
- Bluetooth adapters typically prefer being in USB2.0 ports rather than USB3.0 ports, since often the USB3.0 implementation leaks radio energy on the same 2.4Ghz spectrum as Bluetooth. If no USB2.0 port available, try a shielded USB2.0 extension lead to distance the dongle from the port. Some dongle manufacturees seems to do a better job at shielding for this than others.
- Don’t worry about the very latest Bluetooth versions, 4.0 is minimum for BLE, 5.0 is nice
- Home Assistant is massively more popular than SignalK, and often also run on Raspberry Pi and similar, so good source of advice
SignalK BLE Manager also supports BLE Gateways, which could be an MQTT topic or an ESP-32 device. The espos-ble-gateway can be used with a cheap ESP32 device (see the list of supported hardware), which allows positioning of the gateway closer to devices, or having multiple gateways on a big boat.
BLE Manager Readiness
Section titled “BLE Manager Readiness”v2.31.0 is the minumum version of SignalK possible for BLE Manager. Several fixes went in to v2.33.0 so this is the practical minimum version for using the plugin.
Gicisky labels have been painted successfully using BLE Manager, however Zhsunyco have some different interactions that are waiting other fixes.
- PR#3082 - hung connections locking up device
- PR#3088 - Support plain GATT write requests
- PR#3089 - Pause scanning while GATT operation in progress
There’s a workaround for PR#3088 available in the Advanced Options, and PR#3082 isn’t a problem if operations don’t fail, however PR#3089 is a blocker for using Zhsunyco labels - they’ll fail with a 0x0e error code.
Weak Signal
Section titled “Weak Signal”If the label is too far from the SignalK server’s adapter, try a BLE proxy device - ESP32 is popular for this - or, with the BLE Manager API, a remote BLE gateway.
If your dongle is plugged into a USB3 port (usually blue-highlighted), then there’s a good chance the infamous USB3 interference on the 2.4Ghz spectrum is impacting your adapter. Switch to a USB2 port if you have one, or better, use a USB extension cable to position the dongle far away.
Bluetooth Plugins Impacting Each Other
Section titled “Bluetooth Plugins Impacting Each Other”Bluetooth plugins can kick off scanning, and otherwise interfere with each other. Worst case is when plugins attempt to connect directly to Bluetooth adapters. Better is when they connect using bluez and dbus Linux components, and best of all when they use the SignalK BLE Manager added in 2026.
If you’re having problems with Bluetooth connections, make sure other plugins are well behaved, using BLE Manager where they can, and consider temporarily switching them off if needed to debug label connections.
SignalK in Docker
Section titled “SignalK in Docker”Check for the bluetooth service working at both host level and inside the SignalK container. If there are stability issues, stop and disable the host level service (for example sudo systemctl stop bluetooth on a systemd controlled host).
Stuck Bluetooth Adapters
Section titled “Stuck Bluetooth Adapters”Sometime Bluetooth adapters, and/or the Linux services that use them, can get into a ‘stuck’ state, where the only solution is to reboot the server (although unplugging and plugging the dongle may help). The best way to avoid this is using a known good dongle, and using BLE Manager in SignalK wherever possible.
Zhsunyco Labels and the BLE Manager
Section titled “Zhsunyco Labels and the BLE Manager”With the “Use the SignalK BLE Manager API” setting on, Zhsunyco labels can connect and authenticate, then fail as soon as the image upload starts, with Operation failed with ATT error: 0x0e in the log. SignalK’s BLE Manager (2.33 and earlier) sends every write that waits for an acknowledgement as a Bluetooth “reliable” write, which these labels don’t support.
Either:
- turn on Send image without waiting for each write (Zhsunyco) in the label’s Advanced settings - the image is sent with a small gap between writes instead, and the label still confirms once the whole image has arrived; or
- switch the BLE Manager setting off, if no other plugins need to share Bluetooth with this one.
Gicisky labels aren’t affected, since they don’t use acknowledged writes.
Stuck Labels
Section titled “Stuck Labels”A label can itself get into a stuck state - usually after several connections were cut off part way through a repaint - where it still advertises and accepts connections, but no longer lists its services. Every repaint then connects and fails a couple of seconds later, with Service not available in this plugin’s log, or Characteristic … was not found from other software such as Home Assistant.
You can confirm it’s the label rather than your server: bluetoothctl info <label address> shows no UUID: lines even after a connection, and the same failure happens from a different adapter or computer.
The fix is to power-cycle the label - take the battery out for 10-20 seconds, put it back, then trigger a repaint (for example with Force repaint). If it still fails, the manufacturer’s own app may be needed to reset it.
Tuning Bluetooth Connections
Section titled “Tuning Bluetooth Connections”Labels spend most of their time asleep, so they can be slow to accept a connection, and slow to answer while an image is being sent to them. Linux’s Bluetooth defaults are set with phones, headphones and sensors in mind, so if connections to labels regularly time out, or drop partway through a repaint (for example with GATT or connection-abort errors in the log), some Bluetooth settings on the server may need adjusting:
- The plugin’s own timeouts - the Paint connect timeout and Paint retries, set plugin-wide or per label (see Setting up a Label). Try these first, since they only affect this plugin.
- BlueZ’s connection settings, in the
[LE]section of/etc/bluetooth/main.conf- the connection interval range (MinConnectionInterval/MaxConnectionInterval), how long a quiet connection is kept before it’s dropped (ConnectionSupervisionTimeout), and how long a connection attempt waits (Autoconnecttimeout). The file’s own comments describe each one. Restart the Bluetooth service after changing it. - The kernel’s Bluetooth settings for the adapter, under
/sys/kernel/debug/bluetooth/hci0/- such assupervision_timeout,conn_min_intervalandconn_max_interval. Values written here are lost on reboot, unless something re-applies them at startup.
These apply whenever the server’s Bluetooth goes through BlueZ, including the SignalK BLE Manager with a local adapter. They affect every Bluetooth device the server talks to, not just labels, so change one thing at a time and check that your other Bluetooth equipment still works.
No particular values are recommended here - what works depends on the adapter, the labels and whatever else is using Bluetooth. Get advice before changing them, for example from the SignalK community or Home Assistant’s Bluetooth community, where many of the same adapters and Linux setups are used.
SignalK starts before the Bluetooth daemon
Section titled “SignalK starts before the Bluetooth daemon”This and the next section are about direct BlueZ mode only - if the “Use the SignalK BLE Manager API” setting is enabled, adapter/dongle lifecycle is the SignalK server’s problem to manage once, for every BLE-consuming plugin, not this plugin’s.
The plugin retries BLE adapter initialisation with backoff (starting at 2s, capping at 30s) if bluetoothd/D-Bus isn’t up yet when the plugin starts, so a slow-starting Bluetooth stack on boot will no longer strand it — it keeps retrying until the adapter appears rather than failing once and giving up. You’ll see BLE adapter not ready … — retrying in Ns … in the SignalK logs in the meantime.
That said, it’s cleaner to fix the boot ordering at the systemd level so the plugin finds the adapter ready on its first attempt. If SignalK runs as a systemd service (systemctl status signalk) and its unit file has no [Unit] section (check with systemctl cat signalk), add one:
sudo systemctl edit signalk.serviceThis opens an override file — add:
[Unit]After=bluetooth.targetWants=bluetooth.targetSave and exit, then:
sudo systemctl daemon-reloadsudo systemctl restart signalkThis tells systemd to start bluetoothd first and wait for it before starting SignalK, rather than relying on both racing to start in parallel at boot.
Adapter stops responding: “No gpio to reset”
Section titled “Adapter stops responding: “No gpio to reset””Example log:
Bluetooth: hci0: No gpio to reset Realtek device, ignoringBluetooth: hci0: Unable to disable scanning: -110Bluetooth: hci0: command 0x2042 tx timeoutBluetooth: hci0: Opcode 0x2042 failed: -110Adapters like the popular ASUS USB-500 lack a GPIO to allow reset when suspended and it gets stuck, spamming the logs. See Adapter Goes to Sleep for stopping the auto-suspend happening.
Adapter Goes to Sleep
Section titled “Adapter Goes to Sleep”This happens when USB autosuspend cycles the dongle in and out of low-power suspend while idle. When bluetoothd sends an HCI command while the device is suspended or mid-resume, it never gets answered
Example udev rule fix
Section titled “Example udev rule fix”Following file created at /etc/udev/rules.d/99-bt500-no-autosuspend.rules
# Disable USB autosuspend for the ASUS USB-BT500 (RTL8761BU, 0b05:190e).ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0b05", ATTR{idProduct}=="190e", TEST=="power/control", ATTR{power/control}="on"Example tlp fix
Section titled “Example tlp fix”If tlp running to minimize power, it may have its own rules trying to suspend the Bluetooth dongle.
Following file created at /etc/tlp.d/99-bt500-no-autosuspend.conf
USB_DENYLIST="0b05:190e"Bluetooth Jargon Buster
Section titled “Bluetooth Jargon Buster”Bluetooth comes with a lot of acronyms. Here’s what the ones on this page mean, without needing to be a computer person.
When the plugin paints a label, the request goes down a chain: the plugin asks BlueZ over D-Bus, BlueZ gives orders to the Bluetooth dongle over HCI, and the dongle’s radio talks to the label using BLE, reading and writing the label’s GATT services. A gateway or proxy simply moves the radio end of that chain somewhere else on the boat.
- BLE (Bluetooth Low Energy) - the kind of Bluetooth made for small battery-powered gadgets like labels, sensors and battery monitors.
- It’s different from the “classic” Bluetooth used by headphones and speakers, and doesn’t have the usual pairing process.
- BLE devices talk in short bursts and sleep in between, which is how a label runs for years on a coin cell.
- They regularly broadcast short “advertisements” saying who they are, and the server picks these up by scanning.
- BLE needs an adapter supporting Bluetooth 4.0 or later.
- HCI (Host Controller Interface) - the standard set of commands a computer uses to give orders to a Bluetooth radio chip, such as “start scanning” or “connect to this device”.
- Linux names each Bluetooth adapter after it, so
hci0is the first adapter,hci1the second, and so on. - A plugin using the adapter “directly” is sending HCI commands itself, works fine if there’s only one Bluetooth app on the server.
- Linux names each Bluetooth adapter after it, so
- BlueZ - the standard Bluetooth software on Linux.
- It runs quietly in the background as a service called
bluetoothd, takes charge of the adapter, keeps a list of the devices it has heard, and handles connecting to them. - Its a sane alternative to multiple Linux programs all trying to grab the limited resources of the Bluetooth adapter and stomping over each other. It does at a Linux level what BLE Manager does for SignalK - a single point of ownership and control over a contested resource.
- It runs quietly in the background as a service called
- D-Bus - the messaging system that programs on a Linux computer use to talk to each other.
- It’s how the plugin, or SignalK’s BLE Manager, asks BlueZ to scan or connect.
- If you know NMEA 2000, it’s a similar idea: one shared backbone that everything plugs into and exchanges messages over, rather than a separate cable between every pair of devices.
- GATT (Generic Attribute Profile) - how a BLE device organises what it offers once you’re connected to it.
- The device has services, each a group of related features, and each service has characteristics, individual values you can read, write or be told about when they change.
- Painting a label means connecting, finding its image service, and writing the picture into the right characteristic a piece at a time.
- The “GATT claims” shown in SignalK’s BLE Manager are simply which plugin has booked which device for a connection, so that two plugins don’t try to talk to it at once.
- Gateway - a separate small device, often a cheap ESP32 board, with its own Bluetooth radio, which listens for and talks to BLE devices near it and relays everything to SignalK over the boat’s network.
- It’s effectively fitting a remote antenna closer to where it’s needed: useful when a label is too far from the server, or on a big boat that needs more than one. SignalK’s BLE Manager can use gateways alongside, or instead of, a local adapter.
- Proxy - much the same idea as a gateway: a device that does the Bluetooth radio work on the server’s behalf, somewhere with a better signal.
- Different software uses different names for it. Home Assistant users, for example, will know ESP32 “Bluetooth proxies”.