Skip to content

IR/RF Proxy

IMPORTANT

This component is EXPERIMENTAL. The API may change at any time without following the normal breaking changes policy. Use at your own risk. Once the API is considered stable, this warning will be removed.

ESPHome’s IR/RF proxy component works with Home Assistant to expand its remote control capabilities. This component provides a unified API-accessible interface for transmitting and receiving infrared and RF signals, acting as a bridge between Home Assistant (or other API clients) and ESPHome’s existing remote_receiver and remote_transmitter components. Note that at least one of these components is required in your device’s configuration if you wish to use the IR/RF proxy component.

The IR/RF proxy enables runtime signal transmission without recompiling and/or reinstalling (flashing) firmware, making it ideal for learning and replaying IR/RF commands, creating universal remote controls, and integrating with Home Assistant’s remote control features.

The IR/RF proxy provides two platform implementations:

# Example configuration entry
remote_receiver:
id: ir_rx
pin: GPIOXX
remote_transmitter:
- id: ir_tx
pin: GPIOXX
carrier_duty_percent: 50%
- id: rf_tx
pin: GPIOXX
carrier_duty_percent: 100%
# Infrared platform — creates infrared entities
infrared:
- platform: ir_rf_proxy
name: IR Transmitter
remote_transmitter_id: ir_tx
- platform: ir_rf_proxy
name: IR Receiver
receiver_frequency: 38kHz
remote_receiver_id: ir_rx
# Radio Frequency platform — creates radio_frequency entities
radio_frequency:
- platform: ir_rf_proxy
name: 433MHz RF Transmitter
frequency: 433.92MHz
remote_transmitter_id: rf_tx

The infrared platform creates an infrared entity backed by a remote_transmitter or remote_receiver. Each instance must be configured as either a transmitter or receiver — not both.

infrared:
- platform: ir_rf_proxy
name: IR Proxy Transmitter
remote_transmitter_id: ir_tx
- platform: ir_rf_proxy
name: IR Proxy Receiver
receiver_frequency: 38kHz
remote_receiver_id: ir_rx
  • remote_transmitter_id (Optional, ID): The ID of the remote_transmitter component to use for sending signals. Exactly one of remote_transmitter_id or remote_receiver_id must be specified.

  • remote_receiver_id (Optional, ID): The ID of the remote_receiver component to use for receiving signals. Exactly one of remote_transmitter_id or remote_receiver_id must be specified.

  • frequency (Optional, frequency): The operating frequency (for example, 433 MHz, 315 MHz, 900 MHz). Set to a non-zero value for RF hardware. Defaults to 0 (infrared). This value is used to distinguish between IR and RF hardware types and is passed to Home Assistant, allowing it to identify integrations this IR/RF proxy instance can potentially support.

  • receiver_frequency (Optional, frequency): The demodulation frequency of the IR receiver hardware (for example, 38kHz for a TSOP38238). This value has no effect on hardware — it is metadata reported to API clients (such as Home Assistant) so they can determine which IR protocols are compatible with the receiver. Only valid with remote_receiver_id; a validation error will occur if used with remote_transmitter_id. Omit if the demodulation frequency is unknown or not relevant.

    All other configuration variables from infrared.

NOTE

When configuring a transmitter for infrared (frequency: 0 or not set), ensure the linked remote_transmitter has carrier_duty_percent set to an appropriate value, typically 30-50%. This is required for proper infrared transmission. If carrier_duty_percent is set to 0% or 100% and frequency is not set or is set to zero, a validation error will occur.

The radio frequency platform creates a radio_frequency entity backed by a remote_transmitter or remote_receiver. Each instance must be configured as either a transmitter or receiver — create separate instances if you need both.

radio_frequency:
- platform: ir_rf_proxy
name: 433MHz RF Transmitter
frequency: 433.92MHz
remote_transmitter_id: rf_tx
- platform: ir_rf_proxy
name: 433MHz RF Receiver
frequency: 433.92MHz
remote_receiver_id: rf_rx
  • remote_transmitter_id (Optional, ID): The ID of the remote_transmitter component to use for sending signals. Exactly one of remote_transmitter_id or remote_receiver_id must be specified.

  • remote_receiver_id (Optional, ID): The ID of the remote_receiver component to use for receiving signals. Exactly one of remote_transmitter_id or remote_receiver_id must be specified.

  • frequency (Optional, frequency): The carrier frequency of the RF hardware (for example, 433.92MHz, 315MHz, 868MHz). This is metadata reported to API clients — it does not tune the hardware. If the hardware operates at a fixed frequency, set this to declare it. When set, both frequency_min and frequency_max traits are populated with this value.

    All other configuration variables from radio_frequency.

NOTE

When configuring a transmitter for RF, the linked remote_transmitter must have carrier_duty_percent set to 100%. RF hardware handles its own modulation; applying a carrier duty cycle would corrupt the signal. A validation error will occur if carrier_duty_percent is set to any other value.

To use a programmable RF chip like the CC1101 with the radio frequency platform, wire its state-control actions to remote_transmitter’s on_transmit / on_complete triggers. The example below shows the recommended dual-pin configuration (CC1101 GDO0 → remote_transmitter, CC1101 GDO2 → remote_receiver). For single-pin variants or for more detail, see the CC1101 docs (open-drain on ESP32, auto-switching on ESP8266) — the pin configuration changes, but the trigger wiring shown here is the same.

# CC1101 GDO0 wired to one GPIO pin
remote_transmitter:
id: rf_tx
pin: GPIOXX
carrier_duty_percent: 100%
on_transmit:
then:
- cc1101.begin_tx: cc1101_radio
on_complete:
then:
- cc1101.begin_rx: cc1101_radio
# CC1101 GDO2 wired to a second GPIO pin
remote_receiver:
id: rf_rx
pin: GPIOXX
radio_frequency:
- platform: ir_rf_proxy
name: RF Proxy Transmitter
frequency: 433.92MHz
remote_transmitter_id: rf_tx
# Optional: retune the CC1101 when an API request specifies a different
# carrier frequency. `x` is the radio_frequency call object.
on_control:
then:
- if:
condition:
lambda: "return x.get_frequency().has_value() && *x.get_frequency() > 0;"
then:
- cc1101.set_frequency:
id: cc1101_radio
value: !lambda "return *x.get_frequency();"
- platform: ir_rf_proxy
name: RF Proxy Receiver
frequency: 433.92MHz
remote_receiver_id: rf_rx

The triggers used above:

  • on_transmit on remote_transmitter — fires before each transmission. Call cc1101.begin_tx here to put the chip into TX state.
  • on_complete on remote_transmitter — fires after a transmission finishes. Call cc1101.begin_rx here to return the chip to RX state (idle listening).
  • on_control on the radio_frequency entity — fires when a transmit request arrives, before the underlying transmission begins. The call object (x) exposes get_frequency(), get_modulation(), and get_repeat_count() — use this trigger for per-call adjustments such as retuning the chip to the requested carrier frequency.

The same wiring pattern applies to other RF front-ends (SX127x, custom external components) — substitute the chip’s equivalent state-change actions for cc1101.begin_tx / cc1101.begin_rx.

The IR/RF proxy component creates API-accessible entities that can be controlled from Home Assistant or other API clients. Each instance can be configured as either a transmitter or receiver by specifying the appropriate hardware component ID.

Both platforms transmit signals using raw timings, which provides full remote control over the exact waveform sent to the hardware. When configured with a remote_transmitter_id, the component can transmit IR/RF signals by accepting an array of microsecond timing values representing alternating mark (LED on) and space (LED off) periods.

Transmission parameters:

  • Raw timings array: Alternating mark/space durations in microseconds (just as the remote_transmitter.transmit_raw action uses)
  • Carrier frequency (infrared platform): Optional carrier frequency in Hz (0 = no carrier modulation)
  • Repeat count: Number of times to transmit the signal (defaults to 1)

For the radio frequency platform, carrier frequency is always set to 0 (no IR carrier modulation) since dedicated RF hardware handles modulation at the physical layer.

The raw timings format allows for maximum flexibility and can support more or less any protocol, whether implemented in ESPHome or not. Home Assistant integrations can encode protocol-specific commands into raw timings and transmit them through the IR/RF proxy component.

When configured with a remote_receiver_id, the IR/RF proxy captures raw timings and sends them to API clients for decoding or analysis. This enables:

  • Learning IR/RF commands from existing remotes
  • Analyzing unknown protocols
  • Creating universal remote controls

Both platforms share the same receive event stream — received signals include the entity key so API clients can identify which specific entity (infrared or radio frequency) produced the event.

Reception is non-blocking, allowing other listeners to also process signals simultaneously.

The IR/RF proxy can work with both infrared and RF hardware:

  • Infrared (infrared platform): Do not set frequency (or set frequency: 0, which is the default) and use standard IR LEDs/receivers. For receivers, you can set receiver_frequency to declare the demodulation frequency of the hardware (for example, 38kHz for a TSOP38238).
  • RF (radio_frequency platform): Use the radio frequency platform for RF configurations. Set frequency to match your RF hardware (for example, 433.92MHz). The radio frequency platform reports RF-specific metadata (supported modulations, frequency range) to API clients.

You can create separate instances for different purposes:

  • Transmit-only (specify only remote_transmitter_id)
  • Receive-only (specify only remote_receiver_id)
  • Multiple instances of any of the above for different hardware or frequencies. For example, a single ESPHome device could have multiple transmitter LEDs, each in a different room/cabinet.