Skip to content

Fix ESPHome transport by subscribing serial proxy instance#29

Merged
puddly merged 1 commit into
puddly:puddly/esphomefrom
balloob:codex/esphome-instance-subscribe
Mar 6, 2026
Merged

Fix ESPHome transport by subscribing serial proxy instance#29
puddly merged 1 commit into
puddly:puddly/esphomefrom
balloob:codex/esphome-instance-subscribe

Conversation

@balloob
Copy link
Copy Markdown
Contributor

@balloob balloob commented Mar 6, 2026

I was messing around with the ESPHome proxy PR with serialx and ran into an issue.

Below is written by AI:

Summary

Fix esphome:// serial transports so they explicitly subscribe to the selected serial-proxy instance before expecting RX data.

This restores end-to-end behavior for ESPHome serial proxy setups where writes succeed but no inbound bytes are delivered unless serial_proxy_subscribe(instance) is called.

Problem

With recent ESPHome serial proxy behavior, connecting and configuring a serial proxy instance is not enough to receive data events. The client must explicitly subscribe to that instance.

serialx currently:

  • connects API client
  • configures serial proxy port
  • registers subscribe_serial_proxy_data(...) callback

…but never sends serial_proxy_subscribe(instance).

Observed failure mode

On a live setup (connect-proxy-sendspin at 192.168.1.227, Denon AVR-X2700H on RS232):

  • serialx.open_serial_connection("esphome://192.168.1.227/1", baudrate=9600)
  • writer.write(b"PW?\\r")
  • reader.read(...) timed out with empty bytes repeatedly

At the same time, the exact same command path worked immediately when sending api.serial_proxy_subscribe(1) manually first.

Root Cause

subscribe_serial_proxy_data(...) registers a callback for data events, but does not itself request that the server begin streaming a specific serial instance.

The explicit instance request is done via:

  • serial_proxy_subscribe(instance)
  • and should be paired with serial_proxy_unsubscribe(instance) on close.

Changes

serialx/platforms/serial_esphome.py

  • Add instance subscription lifecycle tracking:
    • self._instance_subscribed
    • _subscribe_instance()
    • _unsubscribe_instance()
  • On open/connect:
    • call _subscribe_instance() before setting the data callback
  • On close:
    • call _unsubscribe_instance() before API disconnect
  • Apply this in both:
    • sync ESPHomeSerial path
    • async ESPHomeSerialTransport path

Backward compatibility

Some older aioesphomeapi variants may not expose subscribe/unsubscribe helpers.

To avoid regressions, this patch uses getattr(...) and no-ops when those methods are unavailable.

Tests

Added: tests/test_serial_esphome.py

  1. test_transport_subscribes_instance_and_unsubscribes_on_close
    • verifies serial_proxy_subscribe(instance) is called on connect
    • verifies serial_proxy_unsubscribe(instance) is called on close
  2. test_transport_works_without_instance_subscribe_api
    • verifies behavior remains functional when subscribe APIs do not exist

Verification

Unit

  • pytest -q -o addopts='' tests/test_serial_esphome.py
  • Result: 2 passed

Manual (live hardware)

On the setup above:

Before patch:

  • esphome://.../1 writes sent, but RX stayed empty.

After patch:

  • PW?\r over serialx returns PWON\r
  • higher-level Denon client connection succeeds and power queries return PowerState.ON

This confirms the fix in real-world traffic and not only mocked tests.

@puddly
Copy link
Copy Markdown
Owner

puddly commented Mar 6, 2026

If it runs on a real device then it's good enough for me 😄. We're still iterating on the flush() semantics for ESP8266 and other platforms so once the aioesphomeapi PR is finished we can start merging everything.

@puddly puddly merged commit c33e0f3 into puddly:puddly/esphome Mar 6, 2026
13 of 14 checks passed
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 6, 2026

Codecov Report

❌ Patch coverage is 0% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.51%. Comparing base (615c1b4) to head (b00ddbd).
⚠️ Report is 7 commits behind head on puddly/esphome.

Files with missing lines Patch % Lines
serialx/platforms/serial_esphome.py 0.00% 22 Missing ⚠️
Additional details and impacted files
@@                Coverage Diff                 @@
##           puddly/esphome      #29      +/-   ##
==================================================
- Coverage           63.20%   59.51%   -3.70%     
==================================================
  Files                  11       13       +2     
  Lines                1166     1408     +242     
==================================================
+ Hits                  737      838     +101     
- Misses                429      570     +141     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

2 participants