Skip to content

Add radio_frequency platform to Broadlink#169107

Closed
piitaya wants to merge 1 commit intodevfrom
claude/broadlink-radio-frequency-platform-lVyS5
Closed

Add radio_frequency platform to Broadlink#169107
piitaya wants to merge 1 commit intodevfrom
claude/broadlink-radio-frequency-platform-lVyS5

Conversation

@piitaya
Copy link
Copy Markdown
Member

@piitaya piitaya commented Apr 24, 2026

Summary

Adds a radio_frequency platform to the Broadlink integration. RF-capable devices (RM Pro, RM4 Pro) now expose a RadioFrequencyTransmitterEntity alongside the existing remote entity. The new entity accepts a RadioFrequencyCommand, encodes its raw OOK timings into Broadlink's pulse-length wire format, and transmits via the existing device.api.send_data() path — no new transport code, no changes to the existing remote.send_command behavior.

This is enabled by #168447, which introduced the radio_frequency domain, and mirrors the transmitter-side shape set by #168448 (ESPHome).

Scope

  • Only RM Pro and RM4 Pro get the entity (registered through the existing DOMAINS_AND_TYPES device-type table).
  • Transmit-only. No learning via the new domain — the existing remote.learn_command path is unchanged.
  • Supported frequency ranges are the two narrow bands the Broadlink RF front-end actually supports:
    • 433.05–434.79 MHz (EU 433.92 MHz ISM band) → type byte 0xB2
    • 314.95–315.25 MHz → type byte 0xB4
  • Frequencies outside these ranges are rejected with HomeAssistantError("frequency_not_supported") before any bytes hit the wire. Non-OOK modulation is rejected with HomeAssistantError("modulation_not_supported"). symbol_rate and output_power on the command are advisory and ignored — the hardware is fixed-rate OOK-only.

Encoder

encode_rf_packet(type_byte, repeat_count, timings_us) produces the Broadlink RF wire format:

  • byte 0: type (0xB2 / 0xB4)
  • byte 1: repeat count (additional transmissions after the first)
  • bytes 2–3: payload length (little-endian), counted from byte 4
  • bytes 4..N-1: pulses. Each pulse is round(abs(µs) / 32.84) ticks, written as one byte when < 256 and as 0x00 <hi> <lo> (big-endian 16-bit) otherwise.

Pulse timings are taken straight from command.get_raw_timings() and rounded to the nearest tick; abs() handles the signed mark/space convention used by rf_protocols.

Test plan

  • Encoder byte-for-byte round-trip against two real-world learned RF captures (plus/minus buttons), after stripping the 0xB1 0xC0 sweep/learning wrapper
  • Hand-crafted short-and-escape-encoded pulse train encodes to the expected bytes
  • 315 MHz carrier produces a packet with type byte 0xB4
  • Dispatch: async_send_command invokes device.api.send_data exactly once with the expected encoded bytes
  • Frequency outside the two supported bands raises HomeAssistantError and does not call send_data
  • Non-OOK modulation raises HomeAssistantError and does not call send_data
  • BroadlinkException from send_data surfaces as HomeAssistantError
  • Entity availability follows the device coordinator (unavailable when coordinator is unavailable)
  • RF-capable devices (RMPRO, RM4PRO) get the entity; non-RF devices (RMMINI, RMMINIB) don't

Out of scope

  • No learn_command via the new domain.
  • No config flow / UI changes — the entity is auto-created on existing entries.
  • No changes to remote.send_command.
  • No rf-protocols library work.

Generated by Claude Code

Exposes one radio_frequency.RadioFrequencyTransmitterEntity per
RF-capable Broadlink device (RM Pro / RM4 Pro). The entity accepts a
RadioFrequencyCommand, encodes its raw OOK timings into Broadlink's
pulse-length wire format (type byte 0xB2 for the 433 MHz ISM band or
0xB4 for the 315 MHz band), and transmits via the existing Broadlink
client's send_data() method.

Non-OOK modulation and out-of-band frequencies are rejected with a
HomeAssistantError before any bytes are sent. symbol_rate and
output_power on the command are advisory and ignored — the Broadlink
RF front-end is fixed-rate OOK-only hardware.

The existing remote.send_command path is unchanged.
Copilot AI review requested due to automatic review settings April 24, 2026 21:48
@home-assistant home-assistant Bot added has-tests integration: broadlink Top 100 Integration is ranked within the top 100 by usage Top 200 Integration is ranked within the top 200 by usage labels Apr 24, 2026
@home-assistant
Copy link
Copy Markdown
Contributor

Hey there @Danielhiversen, @felipediel, @L-I-Am, @eifinger, mind taking a look at this pull request as it has been labeled with an integration (broadlink) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of broadlink can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant mark-draft Mark the pull request as draft.
  • @home-assistant ready-for-review Remove the draft status from the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign broadlink Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant update-branch Update the pull request branch with the base branch.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) on the pull request.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a radio_frequency transmitter entity to the Broadlink integration for RF-capable RM devices, including an encoder that converts raw OOK timings into Broadlink’s RF pulse-length wire format and transmits via device.api.send_data().

Changes:

  • Add radio_frequency platform/entity for Broadlink RM Pro / RM4 Pro devices.
  • Implement Broadlink RF packet encoder and transmit path with translated errors on failure.
  • Add comprehensive tests for entity registration, encoding correctness, dispatch, and error handling.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
homeassistant/components/broadlink/radio_frequency.py New platform entity + encoder and transmit implementation.
homeassistant/components/broadlink/const.py Registers Platform.RADIO_FREQUENCY for RF-capable Broadlink device types.
homeassistant/components/broadlink/strings.json Adds translated exception messages for RF transmit-related failures.
tests/components/broadlink/test_radio_frequency.py New test suite validating setup, encoding, dispatch, and error scenarios.

Comment on lines +68 to +75
for duration in timings_us:
ticks = round(abs(duration) / _TICK_US)
div, mod = divmod(ticks, 256)
if div:
buf.append(0x00)
buf.append(div)
buf.append(mod)
payload_len = len(buf) - 4
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate that each encoded pulse has at least 1 tick (and never 0), since 0 is reserved as the escape marker in the Broadlink pulse format and a rounded-to-zero duration would produce a malformed payload.

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +74
buf = bytearray([type_byte, repeat_count & 0xFF, 0, 0])
for duration in timings_us:
ticks = round(abs(duration) / _TICK_US)
div, mod = divmod(ticks, 256)
if div:
buf.append(0x00)
buf.append(div)
buf.append(mod)
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add explicit bounds checks for repeat_count (0–255) and tick counts (<= 0xFFFF) instead of truncating/overflowing into invalid bytes, and raise a clear error when inputs exceed Broadlink’s wire format limits.

Suggested change
buf = bytearray([type_byte, repeat_count & 0xFF, 0, 0])
for duration in timings_us:
ticks = round(abs(duration) / _TICK_US)
div, mod = divmod(ticks, 256)
if div:
buf.append(0x00)
buf.append(div)
buf.append(mod)
if not 0 <= repeat_count <= 0xFF:
raise HomeAssistantError(
f"Broadlink RF repeat_count must be between 0 and 255, got {repeat_count}"
)
buf = bytearray([type_byte, repeat_count, 0, 0])
for duration in timings_us:
ticks = round(abs(duration) / _TICK_US)
if ticks > 0xFFFF:
raise HomeAssistantError(
"Broadlink RF timing exceeds the maximum encodable duration: "
f"{duration} µs -> {ticks} ticks"
)
if ticks < 256:
buf.append(ticks)
else:
buf.append(0x00)
buf.extend(ticks.to_bytes(2, "big"))

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +57
"frequency_not_supported": {
"message": "Broadlink devices cannot transmit on {frequency} Hz"
},
"modulation_not_supported": {
"message": "Broadlink devices only support OOK modulation, got {modulation}"
},
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove or consolidate these Broadlink-specific unsupported frequency/modulation exception translations, since the radio_frequency domain rejects unsupported frequencies/modulations before dispatching to the entity in normal usage, making these messages unlikely to ever be surfaced.

Suggested change
"frequency_not_supported": {
"message": "Broadlink devices cannot transmit on {frequency} Hz"
},
"modulation_not_supported": {
"message": "Broadlink devices only support OOK modulation, got {modulation}"
},

Copilot uses AI. Check for mistakes.
@piitaya piitaya closed this Apr 24, 2026
@piitaya piitaya deleted the claude/broadlink-radio-frequency-platform-lVyS5 branch April 25, 2026 08:01
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

has-tests integration: broadlink Quality Scale: No score Top 100 Integration is ranked within the top 100 by usage Top 200 Integration is ranked within the top 200 by usage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants