- C++ 88.4%
- Python 11.6%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| home_assistant_configs | ||
| README.md | ||
esphome
ESPHome configs for Home Assistant. Everything in home_assistant_configs/ belongs in Home Assistant's /config/esphome/ folder.
| Config | Device |
|---|---|
bluetooth_proxy.yaml |
bt2tcp (Lolin C3 mini): Bluetooth proxy |
meshtastic_bridge.yaml |
meshtastic-bridge (Lolin C3 mini v2.1.0): Meshtastic Bluetooth → TCP bridge |
schuurlamp.yaml |
schuurlamp (BK72xx, WB3S) |
Meshtastic Bluetooth → TCP bridge
meshtastic_bridge.yaml keeps a Bluetooth connection to a Meshtastic node and serves the node's client API on TCP port 4403, like a Wi-Fi Meshtastic node does. The Home Assistant Meshtastic integration can then connect over TCP to a node that only has Bluetooth. The bridge itself is the custom component in home_assistant_configs/components/meshtastic_ble_bridge/.
Setup
- On the Meshtastic node, set the Bluetooth pairing mode to No PIN or Fixed PIN (Random PIN can't work, since the bridge has no screen; Fixed PIN needs the passkey feature, see Passkey pairing below), and disconnect the phone app: the node takes one Bluetooth connection at a time.
- Copy
meshtastic_bridge.yamland the wholecomponents/folder to/config/esphome/in Home Assistant, or let ESPHome fetch the component from git (see Optional: load the component from git below). The config uses the secretswifi_ssid,wifi_password,wifi_ap_passwordandapi_encryption_key, plusbluetooth_pin_meshtastic(the node's Fixed PIN) as long as thepasskey:block is in the YAML. With No PIN that secret can hold any 6 digits, or you can leave the block out. - If the node changes, update
radio_macat the top of the YAML. - Install it from the ESPHome Device Builder (the first time over USB).
- In Home Assistant, add the Meshtastic integration with connection type TCP, host
meshtastic-bridge.lan, port 4403. Remove any Meshtastic gateway that connects over Bluetooth, since it would compete for the node's single Bluetooth connection.
To check the bridge without Home Assistant, use the Meshtastic Python CLI: meshtastic --host meshtastic-bridge.lan --info.
Passkey pairing (optional)
Pairing with a node on Fixed PIN is optional. meshtastic_bridge.yaml ships with it available but switched off, and you can also leave it out.
Passkey off, feature left out (node on No PIN): no esp32_ble: block, no passkey: block, no PIN secret and no switch in Home Assistant. Everything else stays the same:
esp32_ble_tracker:
ble_client:
- mac_address: ${radio_mac}
id: meshtastic_radio
meshtastic_ble_bridge:
ble_client_id: meshtastic_radio
port: 4403
radio_connected:
id: radio_connected
name: Radio connected
on_state:
- script.execute: update_status_led
client_connected:
id: tcp_client_connected
name: TCP client connected
on_state:
- script.execute: update_status_led
client_address:
name: TCP client
Passkey available (as shipped): add the esp32_ble: block, which lets the bridge enter the PIN, and the passkey: block. Home Assistant then gets a Passkey pairing switch that starts off. Leave it off for a node on No PIN, turn it on for a node on Fixed PIN. No reflashing needed.
esp32_ble:
io_capability: keyboard_only
meshtastic_ble_bridge:
ble_client_id: meshtastic_radio
port: 4403
passkey:
name: Passkey pairing
pin: !secret bluetooth_pin_meshtastic
# radio_connected, client_connected and client_address as above
The config check refuses a passkey: block when io_capability: keyboard_only is missing.
Optional: load the component from git
Instead of copying the components/ folder, ESPHome can fetch the component from a git repository when it compiles. Replace the external_components: block in meshtastic_bridge.yaml (as shipped it reads the local components/ folder) with this one. Then only the YAML file has to be in /config/esphome/.
external_components:
- source:
type: git
url: https://git.lan/watskebart/esphome.git
ref: main
path: home_assistant_configs/components
# Private repository: account name and access token
# username: watskebart
# password: !secret git_password
refresh: 1d
components: [meshtastic_ble_bridge]
pathis the folder in the repository that holds the component folders. It has to exist in the commit thatrefpoints at, so commit and push the component first.refis a branch or a tag. Use a tag to keep installs on a known version.refreshis how often ESPHome checks for updates (default1d).alwayschecks on every compile, handy while developing;neverkeeps the first clone.- Use an
https://URL that the ESPHome Device Builder add-on can reach and whose certificate it trusts. Anssh://URL would need an SSH key inside the add-on. - The access token ends up in
secrets.yaml, so give it read-only access to this one repository.
git.lan can't be used for this yet: on 2026-11-14 it served a self-signed HTTPS certificate and didn't answer on plain HTTP, so a clone from the add-on is expected to fail certificate verification. It works once git.lan has a certificate that Home Assistant trusts, or when the repository is mirrored to a host that has one, such as GitHub. Until then, copy the components/ folder as described in Setup.
Behaviour
- One TCP client at a time. A new connection replaces the old one, as with Meshtastic firmware.
- TCP connections are refused while the Bluetooth link to the node is down. A connected client is disconnected when the link drops, and reconnects once it is back.
- While no client is connected, the bridge leaves packets on the node, which keeps a limited queue for its client and delivers it after the next connect.
- The Radio link switch releases the node, for example to use the phone app over Bluetooth.
- The Passkey pairing switch (when the
passkey:block is in the YAML): off connects without pairing (node on No PIN); on pairs with the PIN once and reuses that bond afterwards (node on Fixed PIN). Flipping it reconnects to the node. After two failed pairings in a row (wrong PIN?) the bridge waits 60 s between attempts. The switch keeps its state across reboots and starts off. - Status LED: blue pulse means no Wi-Fi, red pulse no Bluetooth link to the node, orange pulse waiting for a TCP client; green, then off, means working.
- Built against ESPHome 2026.10.2. Older releases may lack the socket API the component uses.