Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/richard87/esphome-apiclient/llms.txt

Use this file to discover all available pages before exploring further.

Prerequisites

Before you begin, make sure you have:
  • Go 1.21 or later installed
  • An ESPHome device with the Native API component enabled
  • The device’s hostname or IP address and port (default port is 6053)
  • The encryption.key value from your ESPHome YAML (if the device uses encrypted connections)
The encryption key is a base64-encoded 32-byte string found in the api: section of your ESPHome YAML config:
esphome device config
api:
  encryption:
    key: "your-base64-encoded-key-here"
Copy the value of key exactly as it appears.

Steps

1

Install the module

Add the library to your Go project:
go get github.com/richard87/esphome-apiclient
2

Import the packages

Your Go file needs two import paths — the main client package and the generated protobuf types:
import (
    "context"
    "fmt"
    "log"
    "time"

    esphome "github.com/richard87/esphome-apiclient"
    "github.com/richard87/esphome-apiclient/pb"
    "google.golang.org/protobuf/proto"
)
3

Connect with DialWithContext

Use DialWithContext to connect with a parent context. The function signature is:
func DialWithContext(ctx context.Context, address string, timeout time.Duration, opts ...Option) (*Client, error)
Or use Dial if you don’t need context cancellation:
func Dial(address string, timeout time.Duration, opts ...Option) (*Client, error)
Connect to your device:
ctx := context.Background()

client, err := esphome.DialWithContext(ctx, "mydevice.local:6053", 5*time.Second,
    esphome.WithEncryptionKey("base64-noise-psk"),
    esphome.WithClientInfo("my-app"),
    esphome.WithReconnect(10*time.Second),
)
if err != nil {
    log.Fatal(err)
}
defer client.Close()
If your device does not use encryption, omit WithEncryptionKey. The client will connect using a plain (unencrypted) TCP connection instead.
4

Get device info

Fetch basic information about the connected device:
info, err := client.DeviceInfo()
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Connected to %s (ESPHome %s)\n", info.Name, info.EsphomeVersion)
5

List entities and subscribe to states

Discover the device’s entities, then subscribe to live state updates:
// Discover entities and populate the entity registry
client.ListEntities()
for _, s := range client.Entities().Sensors() {
    fmt.Printf("  sensor: %s (%s)\n", s.Name, s.UnitOfMeasurement)
}

// Subscribe to state updates
client.SubscribeStates(func(msg proto.Message) {
    switch m := msg.(type) {
    case *pb.SensorStateResponse:
        entity := client.Entities().ByKey(m.Key)
        fmt.Printf("sensor %s = %.4g\n", entity.GetName(), m.State)
    case *pb.SwitchStateResponse:
        fmt.Printf("switch 0x%08X = %v\n", m.Key, m.State)
    }
})
6

Send a command

Control a switch by its key:
client.SetSwitch(0x12345678, true)
The switch key is a uint32 that identifies the entity on the device. You can find keys by listing entities and inspecting the Key field of each entity response.

Complete example

Here is a full working program that puts all the steps together:
main.go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    esphome "github.com/richard87/esphome-apiclient"
    "github.com/richard87/esphome-apiclient/pb"
    "google.golang.org/protobuf/proto"
)

func main() {
    ctx := context.Background()

    client, err := esphome.DialWithContext(ctx, "mydevice.local:6053", 5*time.Second,
        esphome.WithEncryptionKey("base64-noise-psk"),
        esphome.WithClientInfo("my-app"),
        esphome.WithReconnect(10*time.Second),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    // Get device info
    info, _ := client.DeviceInfo()
    fmt.Printf("Connected to %s (ESPHome %s)\n", info.Name, info.EsphomeVersion)

    // Discover entities
    client.ListEntities()
    for _, s := range client.Entities().Sensors() {
        fmt.Printf("  sensor: %s (%s)\n", s.Name, s.UnitOfMeasurement)
    }

    // Stream state updates
    client.SubscribeStates(func(msg proto.Message) {
        switch m := msg.(type) {
        case *pb.SensorStateResponse:
            entity := client.Entities().ByKey(m.Key)
            fmt.Printf("sensor %s = %.4g\n", entity.GetName(), m.State)
        case *pb.SwitchStateResponse:
            fmt.Printf("switch 0x%08X = %v\n", m.Key, m.State)
        }
    })

    // Send a command
    client.SetSwitch(0x12345678, true)

    <-ctx.Done()
}

Next steps

Library guide

Learn more about connecting, entity discovery, and subscriptions.

API reference

Full reference for all public types and methods.

CLI tool

Use the bundled CLI to inspect devices from the terminal.

Bluetooth proxy

Use ESPHome devices as BLE proxies for advertisement scanning and GATT.

Build docs developers (and LLMs) love