# Onkyo RI transmit test rig
#
# Bench validation for `remote_transmitter.transmit_onkyori`. Standalone: there
# is no `api:` block and nothing here talks to Home Assistant. Every command is
# fired by hand from the device's own web page.
#
# esphome run ri-transmit-test.yaml
#
# The thirteen codes below are the verified Onkyo A-9050 set. RI codes are
# model-specific. See http://fredboboss.free.fr/articles/onkyo_ri.php
#
# Wiring: RI is 0V/5V and the ESP32 is 3.3V, so the transmit pin goes through a
# level shifter (BSS138-type) to the tip of a 3.5mm mono plug. Sleeve to ground,
# shared with the amp. Without the shifter the amp will not see a valid high.
substitutions:
device_name: onkyo-ri-transmit-test
ri_pin: GPIO17
esphome:
name: ${device_name}
friendly_name: "Onkyo RI Test"
comment: "Bench test rig for the Onkyo RI transmit protocol."
esp32:
board: esp32dev
framework:
type: esp-idf
logger:
# There is no API, so logs come over USB serial or the web page's log panel.
level: DEBUG
ota:
- platform: esphome
password: !secret ota_password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
web_server:
port: 80
version: 3
# Serve the UI from flash, so the rig works on an isolated bench network.
local: true
external_components:
# Onkyo RI is not in any ESPHome release yet. Remove this once #18595 merges.
- source: github://pr#18595
components: [remote_base]
remote_transmitter:
pin: ${ri_pin}
non_blocking: true
# RI is baseband: the protocol sets a carrier frequency of 0, so this value
# never comes into play. 100% is the convention for non-IR protocols.
carrier_duty_percent: 100%
# Fires when the RMT peripheral has finished clocking the frame out. If a code
# logs below but this never appears, the fault is the transmitter or the
# wiring, not the code.
on_complete:
- logger.log:
level: DEBUG
tag: "ri"
format: " frame complete"
# Every button goes through this script rather than calling the transmitter
# directly, so the log line and the code that actually goes out cannot drift
# apart. `mode: queued` so two quick presses both transmit, in order, instead
# of the second being dropped.
script:
- id: ri_send
mode: queued
parameters:
code: int
label: string
then:
- logger.log:
level: INFO
tag: "ri"
format: "TX %s -> 0x%03X"
args:
- "label.c_str()"
- "(unsigned) code"
- remote_transmitter.transmit_onkyori:
data: !lambda "return (uint16_t) code;"
button:
- platform: template
name: "Onkyo RI: Power On"
icon: "mdi:power-on"
on_press:
- script.execute: { id: ri_send, code: 0xD9, label: "Power On" }
- platform: template
name: "Onkyo RI: Power Off"
icon: "mdi:power-off"
on_press:
- script.execute: { id: ri_send, code: 0xDA, label: "Power Off" }
# Discrete On and Off are above. This one flips whatever the current state is,
# so nothing can predict the result. It is here to be tested, not used.
- platform: template
name: "Onkyo RI: Power Toggle"
icon: "mdi:power"
on_press:
- script.execute: { id: ri_send, code: 0x4, label: "Power Toggle" }
- platform: template
name: "Onkyo RI: Volume Up"
icon: "mdi:volume-plus"
on_press:
- script.execute: { id: ri_send, code: 0x2, label: "Volume Up" }
- platform: template
name: "Onkyo RI: Volume Down"
icon: "mdi:volume-minus"
on_press:
- script.execute: { id: ri_send, code: 0x3, label: "Volume Down" }
- platform: template
name: "Onkyo RI: Mute"
icon: "mdi:volume-low"
on_press:
- script.execute: { id: ri_send, code: 0xD7, label: "Mute" }
- platform: template
name: "Onkyo RI: Unmute"
icon: "mdi:volume-high"
on_press:
- script.execute: { id: ri_send, code: 0xD8, label: "Unmute" }
- platform: template
name: "Onkyo RI: Toggle Mute"
icon: "mdi:volume-mute"
on_press:
- script.execute: { id: ri_send, code: 0x5, label: "Toggle Mute" }
- platform: template
name: "Onkyo RI: Next Input"
icon: "mdi:chevron-right-box"
on_press:
- script.execute: { id: ri_send, code: 0xD5, label: "Next Input" }
- platform: template
name: "Onkyo RI: Previous Input"
icon: "mdi:chevron-left-box"
on_press:
- script.execute: { id: ri_send, code: 0xD6, label: "Previous Input" }
- platform: template
name: "Onkyo RI: Input D1"
icon: "mdi:numeric-1-box-outline"
on_press:
- script.execute: { id: ri_send, code: 0x20, label: "Input D1" }
- platform: template
name: "Onkyo RI: Input D2"
icon: "mdi:numeric-2-box-outline"
on_press:
- script.execute: { id: ri_send, code: 0xE0, label: "Input D2" }
# 0x170 is 9 bits wide. RI frames are 12-bit, so this is a valid code and not
# a typo. It is the one entry that proves codes above 0xFF survive encoding.
- platform: template
name: "Onkyo RI: Input D3"
icon: "mdi:numeric-3-box-outline"
on_press:
- script.execute: { id: ri_send, code: 0x170, label: "Input D3" }
# Set a value in the number below, press this, and the code goes out verbatim.
# This is the only control that exercises the templatable form of the action,
# which is a separate code path from the literal `data:` used above.
- platform: template
name: "Onkyo RI: Send Arbitrary Code"
icon: "mdi:send"
on_press:
- script.execute:
id: ri_send
code: !lambda "return (int) id(ri_arbitrary_code).state;"
label: "Arbitrary"
number:
- platform: template
id: ri_arbitrary_code
name: "Onkyo RI: Arbitrary Code"
icon: "mdi:pound"
optimistic: true
min_value: 0
max_value: 4095 # RI frames are 12-bit
step: 1
initial_value: 0xD9
mode: box