A lightweight TCP service that implements the ESPHome Native API, enabling any Linux device to provide the same functionality as an ESPHome device. Home Assistant will see the device as a native ESPHome device.
This implementation does not currently implement encryption or authentication! Use at your own risk. Since it only provides BLE scanning functionality currently it was not required but an upgrade to use encryption and authentication would be accepted in a PR.
Note: this project is not affiliated with ESPHome in any way. It is its own standalone implementation.
- ESPHome Native API implementation - Full native C protobuf-based protocol compatibility
- Plugin architecture - Easily extend with additional ESPHome API features
- Bluetooth Proxy plugin included - BLE scanning via BlueZ D-Bus (included by default)
- Multi-client support - Handle multiple Home Assistant connections
- Cross-platform - Released for ARM64, AMD64 (x86_64), and Ingenic T31 MIPS; others supported via cross-compilation
- mDNS integration - Works with
mdnsdoravahifor automatic discovery - Extensible - Add MediaPlayer, VoiceAssistant, Climate, and other ESPHome features via plugins
- Embedded IP cameras with Bluetooth (e.g., Thingino firmware)
- Single-board computers (Raspberry Pi, Orange Pi, etc.)
- IoT gateways and edge devices
- Any Linux device wanting to integrate with Home Assistant as an ESPHome device
- Custom hardware needing ESPHome API support beyond traditional ESP devices
- Meson >= 0.55.0 - Build system
- Ninja - Build backend
- pkg-config - Dependency discovery
- GCC or Clang - C11 compiler OR
- Docker - All building can be done with Docker (see scripts/build.sh)
- deps-${arch}.tar.gz - Pre-built dependencies (see Releases) of BlueZ's libbluetooth, Nimble's libnimble, and BLE++ libblepp
- pthread - POSIX threads
- mDNS service -
mdnsdoravahi-daemonrecommended for auto-discovery
# Install dependencies (Debian/Ubuntu)
sudo apt-get install curl wget build-essential meson ninja-build pkg-config
# Build dependencies
scripts/build-deps.sh
# Configure
meson setup build
# Build
meson compile -C build
# Install dependencies (optional)
cp -r nimble/out/* /usr
cp -r bluez/out/* /usr
cp -r libble/out/* /
# Install (optional)
sudo meson install -C buildFor Thingino cameras and other Ingenic T31 devices:
# Single command - uses Docker multi-stage build
./scripts/build.sh --mips
# Or use make
make cross
# Output: ./esphome-linux-mipsThe script automatically:
- Builds dependencies (nimble, bluez, libble) on first run
- Caches them in Docker layers
- Subsequent builds only rebuild your app code
- Uses multi-stage Dockerfile for optimal caching
Fast rebuilds: Change your code and rerun - only the app layer rebuilds!
The project includes a plugin architecture for extensibility:
# Build with all plugins (default)
meson setup build
meson compile -C build
# Build without plugins (core API server only)
meson setup build -Denable_plugins=false
meson compile -C buildSee PLUGIN_ARCHITECTURE.md for details on creating plugins.
For other platforms, create a cross-file or modify cross/mips-linux.txt:
[binaries]
c = 'mipsel-linux-gcc'
ar = 'mipsel-linux-ar'
strip = 'mipsel-linux-strip'
pkg-config = 'pkg-config'
[properties]
sys_root = '/path/to/sysroot'
pkg_config_libdir = '/path/to/sysroot/usr/lib/pkgconfig'
[host_machine]
system = 'linux'
cpu_family = 'mips'
cpu = 'mips32'
endian = 'little'Then build:
meson setup build --cross-file cross/mips-linux.txt
meson compile -C buildIf you prefer traditional CROSS_COMPILE variable:
# Set compiler via environment
export CC=mipsel-linux-gcc
export AR=mipsel-linux-ar
export PKG_CONFIG_PATH=/path/to/sysroot/usr/lib/pkgconfig
meson setup build
meson compile -C build1mDNS for automatic discovery (recommended):
# mdnsd (lightweight, recommended for embedded systems)
# Configuration file:
# type _esphomelib._tcp
# port 6053
mdnsd
# Or use Avahi
avahi-daemon./build/esphome-linuxThe service will:
- Listen on TCP port 6053
- Load plugins (Bluetooth Proxy plugin by default)
- Connect to BlueZ via D-Bus (if Bluetooth Proxy plugin is enabled)
- Wait for Home Assistant to connect and subscribe to services
- The service advertises itself via mDNS as
_esphomelib._tcp(requires mdnsd or avahi) - Home Assistant auto-discovers it as an ESPHome device
- Add it through the ESPHome integration
- Depending on loaded plugins, it will provide different functionality:
- Bluetooth Proxy plugin - BLE device scanning and forwarding
- Future plugins - MediaPlayer, VoiceAssistant, Climate, etc.
Currently configuration is compile-time:
- TCP port: 6053 (standard ESPHome API port, defined in
esphome_api.c) - Device name: Hostname (auto-detected in
main.c) - Plugin-specific settings: See individual plugin documentation in
plugins/*/README.md
┌─────────────────────────────────────────┐
│ Home Assistant │
│ (ESPHome Client) │
└────────────────┬────────────────────────┘
│ TCP 6053 (ESPHome Native API)
│ Protobuf framed messages
│
┌────────────────▼────────────────────────┐
│ esphome-linux │
│ │
│ ┌───────────────────────────────────┐ │
│ │ ESPHome API Server │ │ - Protocol handshake
│ │ (Core) │ │ - Device info
│ └──────────────┬────────────────────┘ │ - Message routing
│ │ │
│ ┌──────────────▼────────────────────┐ │
│ │ Plugin Manager │ │ - Auto-registration
│ │ │ │ - Message dispatch
│ └──┬───────────┬──────────────────┬─┘ │
│ │ │ │ │
│ ┌──▼───────┐ ┌▼────────┐ ┌──────▼──┐ │
│ │Bluetooth │ │MediaPlayer│ │Custom │ │
│ │Proxy │ │(future) │ │Plugins │ │
│ │(BlueZ) │ └─────────┘ └─────────┘ │
│ └──┬───────┘ │
│ │ │
└─────┼───────────────────────────────────┘
│ D-Bus (for Bluetooth plugin)
┌─────▼─────────┐
│ bluetoothd │ - BLE scanning (BlueZ)
│ (Optional) │ - Advertisement parsing
└───────────────┘
esphome-linux/
├── docs/ # Detailed developer docs
├── src/
│ ├── main.c # Entry point
│ ├── esphome_api.c # ESPHome protocol server (core)
│ ├── esphome_proto.c # Protobuf encoder/decoder
│ └── include/
│ ├── esphome_api.h
│ ├── esphome_proto.h
│ ├── esphome_plugin_internal.h
│ └── esphome_plugin.h # Plugin API
├── plugins/
│ ├── bluetooth_proxy/ # Bluetooth LE scanning (included)
│ │ ├── ble_scanner.c
│ │ ├── ble_scanner.h
│ │ ├── bluetooth_proxy_plugin.c
│ │ └── README.md
│ └── README.md # Plugin development guide
├── cross/
│ └── mips-linux.txt # Cross-compilation config
├── meson.build # Build configuration
├── PLUGIN_ARCHITECTURE.md # Architecture overview
├── BUILDROOT_INTEGRATION.md # Buildroot packaging guide
├── README.md
└── LICENSE
-
Check BlueZ is scanning:
bluetoothctl > scan on -
Check D-Bus permissions:
dbus-send --system --print-reply \ --dest=org.bluez \ /org/bluez/hci0 \ org.freedesktop.DBus.Properties.Get \ string:org.bluez.Adapter1 string:Discovering
-
Check service logs for errors
- Verify mDNS/Avahi is running
- Check firewall allows TCP port 6053
- Manually add via ESPHome integration using IP:6053
-
Ensure pkg-config can find dependencies:
pkg-config --modversion dbus-1 glib-2.0
-
For cross-compilation, verify sysroot has required libraries
- Memory usage: ~2-4 MB RSS
- CPU usage: <1% idle, ~2-5% during scanning
- Network: Minimal (batched reports every 10s)
- BLE scan rate: Depends on BlueZ configuration
MIT License - see LICENSE file
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Test on target hardware
- Submit a pull request
Developed for the Thingino Project - open-source firmware for Ingenic SoC cameras.
- ESPHome - Home automation framework
- Home Assistant - Open source home automation
- BlueZ - Official Linux Bluetooth stack
- Thingino - IP camera firmware