Skip to content

feat(ws_bridge): add WebSocket bridge component to Home Assistant (no…#269

Merged
eigger merged 3 commits into
masterfrom
feat/ws-bridge
Jul 18, 2026
Merged

feat(ws_bridge): add WebSocket bridge component to Home Assistant (no…#269
eigger merged 3 commits into
masterfrom
feat/ws-bridge

Conversation

@eigger

@eigger eigger commented Jul 18, 2026

Copy link
Copy Markdown
Owner

… MQTT)

Connects an ESP32 (ESP-IDF) directly to Home Assistant's /api/websocket and speaks the hass-ws-bridge protocol (github.com/eigger/hass-ws-bridge) to declare entities, push state, and receive commands — removing the need for an MQTT broker. Combined with a secure way to reach HA from outside the LAN (Nabu Casa remote UI, a reverse proxy with a valid cert), it can also remove the need for a VPN for remote devices.

  • ws_bridge.h/.cpp: hub Component. Uses ESP-IDF's esp_websocket_client (pulled in via esp32.add_idf_component, no framing/TLS hand-rolled) for wss://, a small state machine for the HA auth handshake (auth_required -> auth -> auth_ok -> ws_bridge/connect), and a lock-free SPSC queue (EventPool + LockFreeQueue) to hand transport events from the esp_websocket_client task to the main loop safely.
  • ws_protocol.h/.cpp: JSON message build/parse using ESPHome's existing json::build_json/parse_json helpers (ArduinoJson v7 API).
  • ws_bridge_device.h: shared entity mixin; the hub re-declares every registered entity (and its current state) on every (re)connect, per the protocol's reconnection guidance.
  • sensor/binary_sensor/switch/number/select/button: one hub + per-platform subfolder structure mirroring this repo's uartex component. Read-only platforms push via add_on_state_callback; control platforms route incoming HA commands to turn_on/turn_off/make_call().set_value()/ set_option()/press().
  • Exposes keep_last_state_on_disconnect (sent in ws_bridge/connect) so a gateway's entities can keep their last state instead of going unavailable on disconnect, matching the hass-ws-bridge PR adding that option.

Verified compiling for esp32dev (esp-idf) with ESPHome 2026.7, hub + all six platforms, zero errors/warnings.

eigger and others added 3 commits July 18, 2026 12:44
… MQTT)

Connects an ESP32 (ESP-IDF) directly to Home Assistant's /api/websocket and
speaks the hass-ws-bridge protocol (github.com/eigger/hass-ws-bridge) to
declare entities, push state, and receive commands — removing the need for
an MQTT broker. Combined with a secure way to reach HA from outside the LAN
(Nabu Casa remote UI, a reverse proxy with a valid cert), it can also remove
the need for a VPN for remote devices.

- ws_bridge.h/.cpp: hub Component. Uses ESP-IDF's esp_websocket_client
  (pulled in via esp32.add_idf_component, no framing/TLS hand-rolled) for
  wss://, a small state machine for the HA auth handshake
  (auth_required -> auth -> auth_ok -> ws_bridge/connect), and a lock-free
  SPSC queue (EventPool + LockFreeQueue) to hand transport events from the
  esp_websocket_client task to the main loop safely.
- ws_protocol.h/.cpp: JSON message build/parse using ESPHome's existing
  json::build_json/parse_json helpers (ArduinoJson v7 API).
- ws_bridge_device.h: shared entity mixin; the hub re-declares every
  registered entity (and its current state) on every (re)connect, per the
  protocol's reconnection guidance.
- sensor/binary_sensor/switch/number/select/button: one hub + per-platform
  subfolder structure mirroring this repo's uartex component. Read-only
  platforms push via add_on_state_callback; control platforms route
  incoming HA commands to turn_on/turn_off/make_call().set_value()/
  set_option()/press().
- Exposes keep_last_state_on_disconnect (sent in ws_bridge/connect) so a
  gateway's entities can keep their last state instead of going unavailable
  on disconnect, matching the hass-ws-bridge PR adding that option.

Verified compiling for esp32dev (esp-idf) with ESPHome 2026.7, hub + all
six platforms, zero errors/warnings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rx_accum_ (the WS fragment reassembly buffer) was only cleared after a
complete message was dequeued. If the socket dropped mid-fragment (a
message split across TCP segments that never finished), the leftover
partial bytes would still be sitting in rx_accum_ when the connection
came back, and would get silently prepended to the next connection's
first fragmented message, corrupting the JSON.

Clear rx_accum_ on WEBSOCKET_EVENT_CONNECTED/DISCONNECTED/ERROR/CLOSED
(from the producer-task callback itself, preserving the single-writer
invariant) so every connection starts message reassembly from a clean
slate.

Verified compiling for esp32dev (esp-idf) with ESPHome 2026.7.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds tests/components/ws_bridge/test.esp32-idf.yaml exercising the hub and
all six platforms (sensor/binary_sensor/switch/number/select/button),
required by the repo's CI workflow (.github/workflows/esphome.yml) for any
modified component.

Verified with `esphome config` and `esphome compile` run the same way CI
does (relative external_components path, cwd inside tests/components/ws_bridge).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@eigger
eigger merged commit 176305e into master Jul 18, 2026
4 checks passed
@eigger
eigger deleted the feat/ws-bridge branch July 18, 2026 03:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant