Virtual Serial Proxy — allow components to share UART data with HA #3595
Unanswered
FredM67
asked this question in
Native API
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Context
This idea emerged from a discussion with @bdraco on PR esphome/esphome#9027 (emontx component). The emontx component reads UART data to parse JSON and update sensors, but also needs to forward a copy of that data bidirectionally to Home Assistant for a configuration panel (HACS integration).
bdraco's observations (from PR #9027 review)
After discussion, the fundamental issue was identified:
bdraco suggested a longer-term solution:
Problem Statement
A common pattern exists where an ESPHome component:
This cannot use
serial_proxybecause both components would try to read from the same UART (reads are destructive — bytes consumed by one are gone for the other).This cannot use
HomeassistantActionRequestbecause that's restricted to thehomeassistantcomponent (internal API, not public).Adding component-specific protobuf messages doesn't scale ("we can't start allocating protobuf messages to specific components").
Proposed Solution: Virtual Serial Proxy
Instead of creating new protobuf messages, extend the existing
serial_proxywith aVIRTUALport type that decouples the API communication from the physical UART.A component that owns the UART creates a virtual serial proxy and pushes data into it. Home Assistant subscribes to it using the exact same protocol as a physical serial proxy. Zero new protobuf messages, zero aioesphomeapi changes.
Architecture
Changes Required
1. Proto (
api.proto) — one line additionNo new messages. All existing subscribe/write/data messages work unchanged.
2. C++ — Extract
SerialProxyBasefromSerialProxyMove the API communication code (subscription management,
push_to_client(), instance indexing, pre-allocated message) into a base class. The existingSerialProxyinherits from it +UARTDevice. A newVirtualSerialProxyinherits from it alone.3. C++ —
VirtualSerialProxy(~30 lines)4.
application.h— widen pointer type// Was: StaticVector<serial_proxy::SerialProxy *> StaticVector<serial_proxy::SerialProxyBase *, SERIAL_PROXY_COUNT> serial_proxies_;5.
api_connection.cpp— renamewrite_from_client→on_client_dataSame dispatch logic via
App.get_serial_proxies(), just calls the virtual method.6. Python — add VIRTUAL port type, make
uart_idoptional for virtual7. aioesphomeapi — no changes needed
Virtual proxies appear in
DeviceInfoResponse.serial_proxieswithport_type=VIRTUAL(value 3). Clients subscribe, write, and receive data using the exact same messages as physical proxies.Usage Example
A component that reads UART and wants to share data with HA:
The HA-side integration discovers the virtual proxy and subscribes using the standard serial proxy API — no custom services needed.
Standalone YAML Usage
A virtual serial proxy could also be configured directly in YAML for other use cases:
Other components could then reference
my_virtual_proxyto push/receive data.Benefits
Comparison with Alternatives
Who Benefits
CC @bdraco @kbx81
Beta Was this translation helpful? Give feedback.
All reactions