{"id":24877,"date":"2026-08-22T17:49:44","date_gmt":"2026-08-22T21:49:44","guid":{"rendered":"https:\/\/nuxx.net\/blog\/?p=24877"},"modified":"2026-08-22T18:05:53","modified_gmt":"2026-08-22T22:05:53","slug":"updating-the-hdmi-cec-and-onkyo-ri-to-home-assistant-bridge","status":"publish","type":"post","link":"https:\/\/nuxx.net\/blog\/2026\/08\/22\/updating-the-hdmi-cec-and-onkyo-ri-to-home-assistant-bridge\/","title":{"rendered":"Updating the HDMI-CEC and Onkyo RI to Home Assistant Bridge"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20251225_032325799.MP_-scaled.jpeg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"771\" src=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20251225_032325799.MP_-1024x771.jpeg\" alt=\"\" class=\"wp-image-24884\" srcset=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20251225_032325799.MP_-1024x771.jpeg 1024w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20251225_032325799.MP_-300x226.jpeg 300w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20251225_032325799.MP_-768x578.jpeg 768w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20251225_032325799.MP_-1536x1157.jpeg 1536w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20251225_032325799.MP_-2048x1542.jpeg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Chip, laying on Kristen&#8217;s lap, in the living room.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A couple years after putting together the <a href=\"https:\/\/nuxx.net\/blog\/2024\/09\/02\/hdmi-cec-to-onkyo-ri-bridge\/\" data-type=\"post\" data-id=\"19805\">HDMI-CEC to Onkyo RI Bridge<\/a> I decided to give it a bit of an update and subtle name change. There were a couple problems that I wanted to fix:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The <a href=\"https:\/\/github.com\/esphome\/esphome\/pull\/7117\">PR for adding Onkyo RI support to ESPHome (#7117)<\/a> worked, but it didn&#8217;t get much attention, fell behind, and it&#8217;d been rejected when it aged out. So, a new <a href=\"https:\/\/esphome.io\/\">ESPHome<\/a> build couldn&#8217;t use it.<\/li>\n\n\n\n<li>Occasionally, usually in the middle of the night, the <a href=\"https:\/\/www.home-assistant.io\/\">Home Assistant<\/a> automation keying off of the Apple TV waking up would turn on the lights in the living room. The Apple TV seemed to wake a little bit for a firmware check, and a false positive in my <a href=\"https:\/\/en.wikipedia.org\/wiki\/Consumer_Electronics_Control\">HDMI-CEC<\/a> watcher would trigger on this, turning on the lights and receiver.<\/li>\n\n\n\n<li>Onkyo receivers also send data out the RI port, but I hadn&#8217;t tested receiving data from a device.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The name was also changed from &#8220;HDMI-CEC <em>to<\/em> Onkyo RI&#8221; to &#8220;HDMI-CEC <em>and<\/em> Onkyo RI&#8221; to better reflect that this bridges these two separate things into Home Assistant (HA). Originally I had the device itself turning the receiver on (via RI) after hearing a certain CEC command (no HA needed), but for flexibility I moved this logic into HA. The name change reflects that it doesn&#8217;t do the bridging itself and is really two separate functions that just happen to run on the same ESPHome device.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To handle this I broke it down into a few pieces:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Fix\/update\/resubmit the Onkyo RI support in ESPHome.<\/li>\n\n\n\n<li>Refine what HDMI-CEC commands are considered to be the Apple TV waking up.<\/li>\n\n\n\n<li>Rewrite\/improve the ESPHome YAML.<\/li>\n\n\n\n<li>Update Home Assistant (HA) to use these new features.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Again, leaning hard on an AI coding assistant\u2020 I started with building an HDMI-CEC sniffer in ESPHome, collecting a few days of traffic on the CEC bus, and built a good understanding of what the communication actually looks like.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The HDMI-CEC sniffer is here: <a href=\"https:\/\/nuxx.net\/files\/esphome\/sniffer.yaml?viewer\">sniffer.yaml<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next I worked with the agent to modernize my previous ESPHome Onkyo RI code for the current version of the platform, tested it in send and receive configurations, and submitted <a href=\"https:\/\/github.com\/esphome\/esphome\/pull\/18595\/\">a new PR (#18585)<\/a>. This PR is much more robust than the last one, even including a hand-drawn schematic showing my hardware test setup. I intentionally did this using AI as a programming partner, leaning on it for code logic and consistency and testing, but doing the architecting and validation and and <code>git<\/code> stuff by hand.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-medium\"><a href=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20260821_144111618-scaled.jpeg\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"149\" src=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20260821_144111618-300x149.jpeg\" alt=\"\" class=\"wp-image-24883\" srcset=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20260821_144111618-300x149.jpeg 300w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20260821_144111618-1024x510.jpeg 1024w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20260821_144111618-768x382.jpeg 768w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20260821_144111618-1536x765.jpeg 1536w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/PXL_20260821_144111618-2048x1020.jpeg 2048w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><figcaption class=\"wp-element-caption\">Test Transmit and Receive hardware for Onkyo RI integration in ESPHome.<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Along the way I took a detour to inspect all commands that came out of the RI port when pressing the buttons on the RC-830S remote that came with the A-9050 receiver. Unfortunately, what I realized is that RI is more complicated than <em>just<\/em> a remote control command, especially as the receiver sends it. Depending on the RI mode switches in the back, current state of the device, etc, different remote buttons result in different things being sent, or perhaps nothing at all. Having set out to only update my current hardware to work better, I opted to not add any read-RI-into-HA stuff for now. There&#8217;d be a lot of complexity to unwind before it&#8217;d be usable, and I don&#8217;t have good use for it, so I dropped the idea. But at least the software support is there and tested.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can download the Onkyo RI transmit and receive tests for ESPHome here: <a href=\"https:\/\/nuxx.net\/files\/esphome\/ri-transmit-test.yaml?viewer\">ri-transmit-test.yaml<\/a> \/ <a href=\"https:\/\/nuxx.net\/files\/esphome\/ri-receive-test.yaml?viewer\">ri-receive-test.yaml<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With these two pieces &#8212; new understanding of HDMI-CEC and a freshened-up Onkyo RI component &#8212; I was then able to build a new config for the <a href=\"https:\/\/wiki.seeedstudio.com\/xiao_esp32s3_getting_started\/\">Seeed Studio XIAO ESP32S3<\/a>-based hardware I already have in place. And along the way a previous bug I&#8217;d encountered with Over-The-Air (OTA) updates to ESPHome failing on this module got fixed, which is a nice side effect. Now it&#8217;ll be <em>much<\/em> easier to try out changes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I&#8217;m pretty happy with this. The result is an expanded\/modernized device that nicely communicates with modern (HDMI-CEC) and old (Onkyo RI serial port) home entertainment stuff, logically coupled together with ESPHome and Home Assistant. There&#8217;s modern code for RI in HA, and while the PR is still waiting to be merged, I&#8217;m hopeful. Going off the test results and AI feedback on the code quality I&#8217;m much more hopeful this time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The updated ESPHome code is here: <a href=\"https:\/\/nuxx.net\/files\/esphome\/seeed-xiao-esp32s3_onkyo-a-9050_v2.1.0.yaml?viewer\">seeed-xiao-esp32s3_onkyo-a-9050_v2.1.0.yaml<\/a><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-medium\"><a href=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/Screenshot-2026-08-22-at-17-26-51-Automations-\u2013-Home-Assistant.png\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"227\" src=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/Screenshot-2026-08-22-at-17-26-51-Automations-\u2013-Home-Assistant-300x227.png\" alt=\"\" class=\"wp-image-24885\" srcset=\"https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/Screenshot-2026-08-22-at-17-26-51-Automations-\u2013-Home-Assistant-300x227.png 300w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/Screenshot-2026-08-22-at-17-26-51-Automations-\u2013-Home-Assistant-1024x775.png 1024w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/Screenshot-2026-08-22-at-17-26-51-Automations-\u2013-Home-Assistant-768x581.png 768w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/Screenshot-2026-08-22-at-17-26-51-Automations-\u2013-Home-Assistant-1536x1163.png 1536w, https:\/\/nuxx.net\/blog\/wp-content\/uploads\/2026\/08\/Screenshot-2026-08-22-at-17-26-51-Automations-\u2013-Home-Assistant.png 1754w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><figcaption class=\"wp-element-caption\">Home Assistant turning on the Onkyo RI receiver and living room light grouping after receiving an HDMI-CEC event.<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Currently the typical usage flow is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Push button on Apple TV to wake it.<\/li>\n\n\n\n<li>Apple TV wakes Vizio TV.<\/li>\n\n\n\n<li>ESPHome sees this happen via HDMI-CEC and informs Home Assistant.<\/li>\n\n\n\n<li>Home Assistant turns on the receiver via Onkyo RI and some lights.<\/li>\n\n\n\n<li>Then later, when the Apple TV goes to sleep (automatic or manual), ESPHome sees this, notifies HA, and an inverse flow happens.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">In the future I might begin looking at waking or sleeping the system remotely by sending HDMI-CEC commands. This eluded me before, but with some automated analysis of traffic on the CEC bus, I might be able to make it happen. Maybe it&#8217;d be nice to have the system wake up remotely, perhaps as part of a lets-watch-TV automation? Even if I don&#8217;t do this in the end, it would at least be nice to know how&#8230;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I might also look at ingesting commands sent out by RI, but this goes beyond the receive-only test and will both require new hardware on the ESP32 side (to handle send and receive on the same pair of wires) and digging into the RI complexity, so&#8230; probably less likely.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Using This in Home Assistant<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With the HDMI-CEC triggers for the logic being in Home Assistant, and as part of handling the random wakes (receiver\/lights turning on), I needed tighter triggers in Home Assistant. Here&#8217;s what&#8217;s now used used, specific CEC frames:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>triggers:\n  - trigger: event\n    event_type: esphome.hdmi_cec_frame\n    event_data:\n      source: '4'\n      opcode: '82'\n      payload: '50:00'\n    id: system_on\n  - trigger: event\n    event_type: esphome.hdmi_cec_frame\n    event_data:\n      source: '4'\n      opcode: '90'\n      payload: '01'\n    id: system_off<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Specifically, this looks for CEC frames that are from source <em>4<\/em> (the Apple TV, a playback device).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>system_on<\/code> event is the <em>Active Source<\/em> opcode (<code>82<\/code>), from physical address <em>5.0.0.0<\/em> (<code>50:00<\/code>) or the Apple TV&#8217;s HDMI port. Or, otherwise stated, a playback device set itself as the active source of content, and is connected to port 5.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>system_off<\/code> event is the <em>Report Power Status<\/em> opcode (<code>90<\/code>), with <em>Standby<\/em> power status (<code>01<\/code>): the same playback device went into standby.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This works for my setup, but be aware that it might not work for you.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With things plugged in differently, or possibly with different devices, different addresses are likely needed. For example, if I added another playback device and added it the source could change. If plugged into a different port, the physical address (payload) of the Apple TV would change from 5.0.0.0.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To use this yourself you&#8217;ll want to inspect the HDMI-CEC frames (look at turning logger <code>level:<\/code> to <code>DEBUG<\/code>) and using <code>esphome logs<\/code>) to see what&#8217;s on your bus before writing the automation. LLMs (AI) are <em>really<\/em> good at helping with this kind of protocol analysis.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">\u2020 Claude Opus 5. Even though it&#8217;s the results that matter, part of me still feels compelled to mention every time I use AI tools to develop something. Yet I don&#8217;t mention using search engines, IDEs, compilers, etc&#8230; And yes, this entire blog post, most of the comments in the code (RI component, HA and ESPHome YAMLs), and and the PR was written by hand, just by me.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A couple years after putting together the HDMI-CEC to Onkyo RI Bridge I decided to give it a bit of an update and subtle name change. There were a couple problems that I wanted to fix: The name was also changed from &#8220;HDMI-CEC to Onkyo RI&#8221; to &#8220;HDMI-CEC and Onkyo RI&#8221; to better reflect that\u2026<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16,13,6,11],"tags":[],"class_list":["post-24877","post","type-post","status-publish","format-standard","hentry","category-around-the-house","category-computers","category-electronics","category-making-things"],"_links":{"self":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts\/24877","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/comments?post=24877"}],"version-history":[{"count":10,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts\/24877\/revisions"}],"predecessor-version":[{"id":24890,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/posts\/24877\/revisions\/24890"}],"wp:attachment":[{"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/media?parent=24877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/categories?post=24877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nuxx.net\/blog\/wp-json\/wp\/v2\/tags?post=24877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}