RS485 Frame Button
Each rs485_frame button entity is a shortcut for sending one pre-configured frame onto the
bus. Pressing the button queues that frame, and the hub sends it at the next TX gate
window. The bytes are built at compile time, so nothing is encoded when the button is
pressed. On buses where the target device treats incoming frames as
commands (like pressing a key on a physical panel), a button entity gives you direct
control from Home Assistant. It requires the RS485 Frame hub to
be configured, and supports three construction forms:
value:— encodes one or more values into the on-wire payload, back-to-back, using thecommand_format:block of the button or the hub. Requires one of the two to be set.value_element_bytessets how many bytes each value is written as (1, 2, 3, or 4), and a value that does not fit is rejected. A list is shorthand for protocols whose frame carries more than one value in a single payload, without repeating the preamble/postamble per value.frame_type:+payload:— bypassescommand_format:entirely. The supplied frame type and payload bytes are sent as-is after DLE-framing, byte-stuffing, and CRC. Use this for hubs with nocommand_format:, probe frames, or any custom frame layout. See also the rs485_frame.send_frame action for invoking raw frames from scripts or computed-payload contexts.value:+command_format:— encodes the value(s) using a button-levelcommand_format:block instead of the hub’s. Use this when one button needs a different encoding than the hub default (different preamble, element size, or postamble), or when the hub has nocommand_format:set and you want thevalue:shorthand on a single button without adding a hub-level encoder.
The value: form and the frame_type: + payload: form are mutually exclusive.
command_format: on the button can only be combined with value:, not with
frame_type: / payload:.
How Commands Work
Section titled “How Commands Work”A button press queues a frame on the hub, which transmits it during the next TX gate window. What happens after depends on your bus: the remote device may toggle a state, execute an action, or send back an acknowledgement — the ESP cannot know the outcome until it reads a subsequent response frame. That is why each button entity models a single outbound frame event rather than a stateful on/off switch.
On Hayward AquaLogic pool controllers, for example, this maps directly to pressing a key on the physical panel: the controller receives the frame (typically within its 100 ms keep-alive cycle) and decides whether to change state; the LED status frame that follows reflects the result.
Finding Command Values
Section titled “Finding Command Values”Enable dump_frames: true and sniffer_only: true on the hub, then press a physical
button on your controller and watch the ESP log. Each validated frame is printed in hex
as wire bytes: DLE/STX, the frame type and payload, the CRC (1 or 2 bytes depending on
crc.type), then DLE/ETX, with byte-stuffing still applied. Frames longer than 32 bytes
span several log lines, and the closing DLE/ETX can be split across two of them; join them
first.
To get the bytes a button sends, drop the leading DLE/STX and the trailing DLE/ETX, undo
the byte-stuffing (with escape_byte, DLE followed by the marker byte is one DLE; with
double, two DLEs are one DLE), then drop the CRC bytes from the end. The CRC is stuffed
too, so remove it only after unstuffing. What is left starts with the frame type.
Use it as the raw frame_type: + payload: form, or, if the same layout repeats across
buttons, as command_format: on the hub: put the frame type and the fixed bytes after it
in preamble, and the part that changes between buttons in value:.
Known value: entries for Hayward AquaLogic, confirmed from live bus captures, are in the
rs485_frame-examples repository. AUX outputs are
controller-wiring-dependent — rename and verify against your physical panel.
Configuration Variables
Section titled “Configuration Variables”- rs485_frame_id (Required, ID): The ID of the
rs485_framehub.
Provide exactly one of the following forms:
-
value (Required, hex uint32 or list of up to 8 hex uint32): Value(s) to encode, e.g.
0x00010000or[0x00010000, 0x00020000]. Each value is written asvalue_element_bytesbytes, back-to-back between the preamble and postamble of thecommand_format:in use (the button’s, otherwise the hub’s); a value that does not fit is rejected at config time. Also rejected when neither the button nor the hub has acommand_format:— use the raw form or add one. -
frame_type + payload (Required together when not using
value:):- frame_type (list of hex bytes): Frame type prefix, up to 8 bytes (usually 2). Frame type
and payload together must be at least 2 bytes.
Same convention as
gate.frame_typeandon_frame.frame_typeelsewhere in the component. - payload (list of hex bytes): The payload bytes that follow the frame type. Caller-composed; the hub adds framing and CRC.
Whichever form is used, the button’s resolved on-wire frame (
frame_type:+payload:, orcommand_format:’s preamble + encoded value(s) + postamble) must fit within the referenced hub’smax_frame_length:(see the hub config) — rejected at config time otherwise. - frame_type (list of hex bytes): Frame type prefix, up to 8 bytes (usually 2). Frame type
and payload together must be at least 2 bytes.
Same convention as
-
value_element_bytes (Optional, integer): Overrides only the element byte width for this button, using
1,2,3, or4. Inherits the hub’spreamble,endian, andpostamble. Requires the hub to havecommand_format:set. Cannot be combined with a per-buttoncommand_format:or withframe_type:/payload:. -
command_format (Optional): Overrides the hub’s
command_format:for this button only. Accepts the same sub-keys ascommand_format:on the hub:preamble,value_element_bytes,endian,postamble. When present, thevalue:form is accepted even if the hub has nocommand_format:set. Cannot be combined withframe_type:/payload:.
All other options from Button.
Examples
Section titled “Examples”Value Form (Hub with a command_format:)
Section titled “Value Form (Hub with a command_format:)”button: - platform: rs485_frame rs485_frame_id: pool name: "Pool Lights" # Confirmed from bus capture: the first word is the press, the second the release (a quick press). value: [ 0x00010000, 0x00010000 ]
- platform: rs485_frame rs485_frame_id: pool name: "Filter" value: [ 0x80000000, 0x80000000 ]
- platform: rs485_frame rs485_frame_id: pool name: "Pool/Spa Mode" value: [ 0x40000000, 0x40000000 ]Raw Form (Custom Devices, No command_format:)
Section titled “Raw Form (Custom Devices, No command_format:)”button: - platform: rs485_frame rs485_frame_id: my_device name: "Open Door" frame_type: [0x00, 0xA1] payload: [0x01, 0x00, 0x55]
- platform: rs485_frame rs485_frame_id: my_device name: "Close Door" frame_type: [0x00, 0xA1] payload: [0x01, 0x00, 0xAA]Per-Button command_format: Override
Section titled “Per-Button command_format: Override”Use when a single button needs a different encoding than the hub default, or when the hub
has no command_format: set (for example, a Hayward AquaLogic setup where most buttons
use the wired-remote preamble but one must use the wireless preamble):
button: - platform: rs485_frame rs485_frame_id: pool name: "System Off" value: 0x08000000 command_format: preamble: [0x00, 0x83, 0x01] value_element_bytes: 4 endian: big postamble: [0x00]Read the resulting state from a response frame on the bus — decode the relevant frame type
in on_frame: on the hub and push to template binary sensors. See the
Basic usage example for the general pattern. For a
single status bit decoded from a Hayward AquaLogic LED-mask frame:
rs485_frame: id: pool on_frame: - frame_type: [0x01, 0x02] then: - lambda: |- if (payload.size() < 6) return; uint32_t mask = uint32_t(payload[2]) | (uint32_t(payload[3]) << 8) | (uint32_t(payload[4]) << 16) | (uint32_t(payload[5]) << 24); id(led_filter).publish_state(bool(mask & (1UL << 5)));
binary_sensor: - platform: template id: led_filter name: "Filter"