Top-level supervisor for an Espex server instance.
Starts children in :rest_for_one order:
Registry(duplicate keys) — fan-out point forEspex.push_state/2.- A cross-connection state server (internal) — holds the device config and adapter modules.
ThousandIsland— TCP acceptor pool that spawns a per-client connection handler process (internal).- An mDNS advertiser GenServer (internal) — optional, started
only when
:mdnsis configured.
If the server child crashes, the listener and advertiser restart too, so live connections drop rather than hold stale references.
Configuration is passed as keyword options:
Espex.Supervisor.start_link(
device_config: [name: "my-device"], # or a %DeviceConfig{}
port: 6053, # overrides device_config.port
name: :my_espex, # supervisor registered name
server_name: MyApp.EspexServer, # Espex.Server registered name
num_acceptors: 10,
serial_proxy: MyApp.MySerialAdapter,
zwave_proxy: MyApp.MyZWaveAdapter,
infrared_proxy: MyApp.MyIRAdapter,
bluetooth_scanner: MyApp.MyBLEScanner,
bluetooth_proxy: MyApp.MyBLEProxy,
entity_provider: MyApp.MyEntities,
mdns: Espex.Mdns.MdnsLite,
keepalive_idle_ms: 60_000, # inbound silence before we ping
keepalive_grace_ms: 60_000, # further silence before we close
read_timeout: 180_000 # hard transport-level backstop
)Any adapter key omitted disables that feature. Pass :mdns with an
Espex.Mdns adapter module (e.g. Espex.Mdns.MdnsLite) to advertise
the server over mDNS; omit to skip.
Keepalive
The server pings idle clients the way real ESPHome firmware does:
after keepalive_idle_ms without inbound bytes it sends a
PingRequest, and closes only after keepalive_grace_ms more of
silence. This matters because aioesphomeapi (Home Assistant) skips its
own client→device pings whenever it is receiving data — a device that
streams (e.g. BLE advertisements) therefore sees a permanently silent
inbound side on a healthy connection, and any naive read timeout will
cycle it. read_timeout (passed through to ThousandIsland) is a hard
backstop that reaps connections wedged at the transport level. Keep it
above keepalive_idle_ms + keepalive_grace_ms so a healthy-but-idle
client always gets its full ping-and-grace window before ThousandIsland
times out — the 180 s default clears the 60 s + 60 s keepalive defaults;
if you shorten read_timeout or lengthen the keepalive intervals, raise
it to match.
Summary
Functions
Return the port the listener is currently bound to. Useful when
starting the server with port: 0 (ephemeral) — typically in tests.
Returns a specification to start this module under a supervisor.
Return the conventional Registry name for a given server name.
Functions
@spec bound_port(Supervisor.supervisor()) :: {:ok, :inet.port_number()} | {:error, term()}
Return the port the listener is currently bound to. Useful when
starting the server with port: 0 (ephemeral) — typically in tests.
Returns a specification to start this module under a supervisor.
See Supervisor.
Return the conventional Registry name for a given server name.
@spec start_link(keyword()) :: Supervisor.on_start()