Files
oleksandr e97475ed17
Build deb packages on release / build-deb (release) Successful in 3m29s
docs: add README and Home Assistant integration guide
2026-05-24 18:53:37 +03:00

4.7 KiB

Home Assistant integration

ezcoo-usb-control publishes an MQTT discovery payload, so the matrix appears in Home Assistant as a single device with two select entities — one per HDMI output — without any YAML.

Prerequisites

  • Home Assistant is connected to the same MQTT broker that the bridge is configured to use.
  • The MQTT integration is enabled and its Discovery prefix matches mqtt.discovery_prefix in the bridge config (default: homeassistant).
  • ezcoo-usb-control is running and reports online on <base_topic>/availability.

Discovery

On startup the bridge publishes a retained device-level discovery payload to:

<discovery_prefix>/device/ezcoo_matrix/config

With defaults that resolves to homeassistant/device/ezcoo_matrix/config. You can inspect it with:

mosquitto_sub -h <broker> -t 'homeassistant/device/ezcoo_matrix/config' -v

Home Assistant picks the payload up automatically and creates the device. Removing the retained message (or stopping the bridge with the broker configured to drop retained messages) makes the entities disappear.

Entities

By default the bridge registers a single device, EZCOO HDMI Matrix, with two entities:

Entity ID Type Options Source topic
select.ezcoo_hdmi_matrix_output_1 select IN1, IN2, IN3, IN4 ezcoo/output1/state
select.ezcoo_hdmi_matrix_output_2 select IN1, IN2, IN3, IN4 ezcoo/output2/state

Setting an option publishes to ezcoo/output<N>/set; the bridge then issues the corresponding EZS OUT<N> VS IN<M> command to the matrix and re-publishes the confirmed state.

Entity IDs can be renamed in the Home Assistant UI. The examples below use the default slugs — adjust if you renamed yours.

Example automations

Route Apple TV to the living-room TV

Switch output 1 to input 2 whenever the Apple TV starts playing:

- alias: "Route Apple TV to living-room TV"
  trigger:
    - platform: state
      entity_id: media_player.apple_tv
      to: "playing"
  action:
    - service: select.select_option
      target:
        entity_id: select.ezcoo_hdmi_matrix_output_1
      data:
        option: "IN2"

Mirror both outputs to the same input

Whenever either output is changed (via Home Assistant, the front panel, or the IR remote), this automation routes the other output to the same input — so both displays always show the same source. The template condition prevents a feedback loop when the second select is already in sync.

alias: EZCOO HDMI Matrix — sync outputs
description: ""
triggers:
  - trigger: state
    entity_id:
      - select.ezcoo_hdmi_matrix_output_1
      - select.ezcoo_hdmi_matrix_output_2
    not_to:
      - unknown
      - unavailable
conditions: []
actions:
  - variables:
      target: |-
        {% if trigger.entity_id == 'select.ezcoo_hdmi_matrix_output_1' %}
          select.ezcoo_hdmi_matrix_output_2
        {% else %}
          select.ezcoo_hdmi_matrix_output_1
        {% endif %}
  - condition: template
    value_template: "{{ states(target) != trigger.to_state.state }}"
  - action: select.select_option
    target:
      entity_id: "{{ target }}"
    data:
      option: "{{ trigger.to_state.state }}"
mode: single
max_exceeded: silent

Lovelace card

A minimal Lovelace entities card:

type: entities
title: HDMI Matrix
entities:
  - entity: select.ezcoo_hdmi_matrix_output_1
    name: Output 1
  - entity: select.ezcoo_hdmi_matrix_output_2
    name: Output 2

Troubleshooting

  • Entities don't appear. Confirm the broker has a retained payload on homeassistant/device/ezcoo_matrix/config, and that Home Assistant's MQTT integration uses the same discovery prefix.
  • Entities are stuck on unavailable. The bridge publishes offline to ezcoo/availability as its Last Will. Check journalctl -u ezcoo-usb-control for connection errors.
  • Changing a select does nothing. Watch ezcoo/output<N>/set with mosquitto_sub — if the message arrives, the failure is on the serial side; run the bridge with --debug to see the command exchange.
  • Automations fire in a loop. When reacting to select state changes, always guard with a template condition that compares current vs target state (see the sync outputs example above).