projects:hdmi_switch_homeassistant

HDMI switch on Homeassistant via ESPHome

Hacking the cheap HDMI switch from the lab's kitchen so I don't have to move my lazy ass to press the button or grab the remote on device, via HomeAssistant.

hdmi_switch_homeassistant.jpg

Status du project
Date de début14/12/2023
Statusfinished
Initiateur(s)Maxime Borges

We are using a 4×2 HDMI switch (4 inputs/2 output) in the lab's kitchen, to choose from different sources (2023-12-15: RaspberryPi for MPD/ROC, ChromeCast, HDMI cable for laptop) to the videoprojector (currently the only used output), and to the sound system via the analog output of the switch (which is of a much better quality than the 3.5mm jack output from the RaspberryPi).

There is a remote to switch which input to set to which output, but it is usually close to the switch, so there is not much point using it. Since we recently deployed a HomeAssistant instance, with a tablet available for anyone to access it, I decided to install an ESP32 using ESPHome to be able to change the sources of the switch remotely.

hdmi_switch_home_assistant.jpg

I first had a look at the PCB: it is basically using an unknown chip to control the LEDs, get info from the buttons and the IR receiver for the remote, and send that to the HDMI switch chip that is taking care of the hard work. Not much more interesting circuitry there.

hdmi_switch_scope.jpg

I first wanted to hook the ESP on the buttons and LEDs, but then decided to have a look at the signal on the IR receiver. It seems to be the classic NEC IR remote protocol, which I confirmed with a logic analyzer:

hdmi_switch_logic.jpg

The address is set to 0x00, and the command start from 0x0000 for Output A Input 1 and increases by one for each button going forward (0x01 for Output A Input 2 and so on, and starts at 0x09 for Output B Input 1 somehow). I didn't record the “previous” and “next” input from the remote, but I'd say that they are pretty easy to guess (see plot below).

I recorded the pulse values using the `remote_receiver` component in ESPHome:

remote_receiver:
  pin:
    number: 32
    inverted: true
    mode:
      input: true
  dump:
    - raw
  tolerance: 55%

I then copied the values from the logs after pressing each buttons of the remote, and formated them nicely. Sometimes there are on two lines of values, so just concatenate them to make a single list, and if you press a button for a while you will also get a repeat code that you can skip.

I then added a `remote_transmitter` and switches using those values like so:

remote_transmitter:
  pin:
    number: 32
    inverted: true
    mode: OUTPUT_OPEN_DRAIN
  carrier_duty_percent: 50%

switch:
  - platform: template
    name: "IN 1 OUT A"
    turn_on_action:
      remote_transmitter.transmit_raw:
        code: [9070, -4448, 620, -513, 613, -511, 615, -513, 614, -537, 590, -512, 614, -514, 613, -512, 615, -513, 613, -1633, 621, -1632, 620, -1633, 620, -1633, 620, -1633, 620, -1633, 620, -1632, 621, -1633, 620, -537, 590, -513, 614, -511, 615, -514, 612, -511, 616, -511, 616, -516, 611, -510, 616, -1633, 620, -1633, 620, -1633, 621, -1632, 620, -1633, 620, -1633, 620, -1632, 621, -1634, 619]
  - platform: template
    name: "IN 2 OUT A"
    turn_on_action:
      remote_transmitter.transmit_raw:
        code: [9068, -4448, 620, -509, 618, -509, 617, -537, 589, -511, 616, -511, 615, -512, 613, -511, 616, -509, 618, -1633, 619, -1632, 621, -1632, 620, -1631, 622, -1632, 621, -1632, 620, -1633, 620, -1632, 620, -1632, 620, -510, 616, -514, 613, -510, 616, -511, 616, -510, 616, -537, 589, -515, 612, -511, 615, -1633, 619, -1633, 620, -1633, 619, -1634, 616, -1636, 617, -1635, 617, -1635, 618]
  - platform: template
    name: "IN 3 OUT A"
    turn_on_action:
      remote_transmitter.transmit_raw:
        code: [9042, -4475, 593, -536, 590, -564, 563, -534, 591, -539, 584, -538, 590, -536, 591, -537, 608, -518, 588, -1663, 592, -1661, 593, -1660, 591, -1661, 592, -1661, 592, -1660, 592, -1661, 589, -1662, 590, -538, 588, -1663, 593, -536, 591, -563, 563, -564, 563, -563, 562, -565, 563, -538, 587, -1661, 592, -564, 562, -1661, 591, -1662, 590, -1662, 610, -1645, 591, -1661, 590, -1663, 590]
  - platform: template
    name: "IN 4 OUT A"
    turn_on_action:
      remote_transmitter.transmit_raw:
        code: [9041, -4478, 589, -538, 590, -536, 588, -538, 590, -536, 591, -539, 588, -539, 587, -564, 563, -537, 589, -1660, 612, -1641, 590, -1663, 593, -1661, 592, -1661, 593, -1660, 592, -1661, 593, -1660, 593, -1660, 590, -1663, 589, -538, 589, -538, 588, -537, 591, -536, 592, -536, 591, -536, 591, -543, 582, -536, 592, -1660, 592, -1661, 593, -1660, 593, -1659, 590, -1664, 589, -1663, 614]

  - platform: template
    name: "IN 1 OUT B"
    turn_on_action:
      remote_transmitter.transmit_raw:
        code: [9064, -4455, 589, -540, 587, -540, 586, -541, 605, -521, 587, -542, 586, -539, 587, -540, 587, -538, 589, -1663, 590, -1663, 613, -1641, 612, -1639, 616, -1640, 588, -1664, 590, -1663, 590, -1664, 589, -1665, 588, -539, 588, -541, 585, -1665, 613, -513, 614, -514, 611, -515, 613, -514, 613, -512, 590, -1665, 588, -1664, 590, -538, 588, -1665, 588, -1666, 588, -1663, 590, -1662, 616]
  - platform: template
    name: "IN 2 OUT B"
    turn_on_action:
      remote_transmitter.transmit_raw:
        code: [9039, -4480, 612, -515, 615, -513, 611, -517, 610, -512, 590, -541, 607, -518, 587, -540, 586, -542, 585, -1663, 590, -1663, 590, -1662, 590, -1664, 614, -1637, 616, -1639, 613, -1638, 590, -1663, 589, -538, 588, -1663, 590, -542, 605, -1643, 590, -539, 587, -544, 583, -539, 608, -517, 612, -1640, 616, -515, 610, -1638, 616, -515, 586, -1664, 589, -1664, 609, -1643, 610, -1644, 588]
  - platform: template
    name: "IN 3 OUT B"
    turn_on_action:
      remote_transmitter.transmit_raw:
        code: [9041, -4479, 608, -524, 585, -539, 587, -539, 588, -539, 588, -539, 607, -520, 587, -540, 586, -537, 612, -1640, 613, -1641, 613, -1641, 589, -1664, 589, -1663, 589, -1664, 589, -1663, 590, -1664, 589, -1664, 614, -1638, 615, -513, 615, -1637, 610, -523, 584, -540, 586, -540, 587, -539, 588, -538, 589, -542, 585, -1663, 590, -540, 587, -1664, 589, -1663, 616, -1637, 617, -1637, 614]
  - platform: template
    name: "IN 4 OUT B"
    turn_on_action:
      remote_transmitter.transmit_raw:
        code: [9039, -4481, 612, -514, 615, -515, 611, -541, 560, -540, 587, -542, 585, -540, 587, -539, 607, -520, 587, -1665, 607, -1646, 589, -1663, 590, -1664, 612, -1639, 614, -1639, 616, -1639, 590, -1664, 589, -539, 588, -539, 588, -1663, 589, -1664, 590, -540, 586, -539, 609, -520, 608, -516, 616, -1613, 637, -1639, 612, -517, 587, -540, 588, -1664, 608, -1644, 590, -1663, 589, -1663, 589]

Note that I'm using the pin 32 now, and not the pin 12 anymore like in the previous picture, because it is a strapping pin.
Also note that it is set up as an open drain, to allow both the IR receiver and the ESP to drive the signal pin down.

Here is a visualization of the remote commands; the hex values correspond to the address and command in the NEC protocol:

hdmi_switch_remote_signals.jpg

Code for generating this plot

Tidied everything by connecting 3.3V to the `+` pad and GND to the ground pad close to the IR receiver, added a 10kOhm from pin 32 to the signal pin, and added some double sided tape:

hdmi_switch_hacked.jpg

🎉 And done! 🎉

  • NoName 4 in/2 out HDMI switch
  • Lolin32 lite (ESP32 board)
  • 10kOhm resistor
  • projects/hdmi_switch_homeassistant.txt
  • Dernière modification: 2023/12/15 05:41
  • de mborges