Integrating a 4×4 HDMI Matrix into Home Assistant via RS-232
A system based on a 4×4 HDMI matrix allows you to switch signal sources—cable TV, media players, gaming consoles—between four televisions. Integration with Home Assistant uses RS-232 for commands and a Coordinator for thread-safe operation with the serial port. The Qwen neural network accelerated the reverse engineering of the protocol and code development.
Hardware Requirements and Prerequisites
You need a 4×4 matrix supporting 4K@60 Hz and RS-232, plus a USB-to-RS232 converter for the Raspberry Pi. The control protocol was reverse-engineered based on an article on Habr: commands are in text format, baud rate 115200.
The HDMISwitchCoordinator manages the connection in separate threads, avoiding blocking the Home Assistant event loop. It supports port initialization, sending commands with threading.Lock, and background reading of responses.
Communication Protocol
Switching commands: cir + hex value calculated as 8 × (zone-1) + (input-1).
Examples:
- Zone 1, input 1:
cir 00 - Zone 2, input 3:
cir 11(0x0A as0a)
The command ends with \r\n. The device sends statuses like s{zone}{input}, e.g., s13 means zone 1 is on input 3. The coordinator parses these and updates entities via callbacks.
media_player Entities
Each zone gets its own media_player entity:
- Displays the current source
- Allows selecting an input from a list
- Supports media_player.select_source services
- Custom source names
Features:
- Turn on: selects the first source
- Turn off: selects a dummy second source
- Icons: entity_picture from /config/www/hdmi_switch/img_{n}.png
Installation Structure
Folder custom_components/hdmi_switch/:
config/
├── custom_components/
│ └── hdmi_switch/
│ ├── __init__.py
│ ├── manifest.json
│ ├── const.py
│ ├── media_player.py
│ └── images/ # img_1.png etc.
├── www/
│ └── hdmi_switch/
└── configuration.yaml
Installation via Samba:
- Set up Samba share in HA
- Connect:
\\homeassistant\config - Create the structure, upload files
- Reboot HA
Code: manifest.json
{
"domain": "hdmi_switch",
"name": "HDMI Switch",
"version": "1.1.0",
"requirements": ["pyserial>=3.5"],
"iot_class": "local_push",
"config_flow": false
}
Code: const.py
DOMAIN = "hdmi_switch"
DEFAULT_NAME = "HDMI Switch"
DEFAULT_PORT = "/dev/ttyACM0"
DEFAULT_COMMAND_BAUDRATE = 115200
DEFAULT_TIMEOUT = 5.0
DEFAULT_SOURCES = ["Input 1", "Input 2", "Input 3", "Input 4"]
Code: __init__.py (Coordinator)
Class HDMISwitchCoordinator:
_open_serial(): serial.Serial(port, baudrate=115200, timeout=0.5, 8N1)start(): threading for _initialize_and_listen_listen_loop(): background readingregister_listener(zone_id, callback)
The full code ensures thread safety and asynchronicity.
Configuration in configuration.yaml
hdmi_switch:
port: /dev/ttyACM0 # optional
command_baudrate: 115200
timeout: 5.0
After rebooting, entities are available in the interface. Icons are automatically copied to www/hdmi_switch.
Key Points
- Thread Safety: threading.Lock and separate threads for serial
- Entities: 4 media_player entities with select_source and entity_picture
- Protocol: cir{hex} for switching, s{zone}{input} for status
- Dependencies: pyserial>=3.5
- Installation: custom_components without HACS
— Editorial Team
No comments yet.