Giter VIP home page Giter VIP logo

esphome-native-hdmi-cec's Introduction

ESPHome Native HDMI-CEC Component

Make your ESPHome devices speak the (machine) language of your living room with this native HDMI-CEC (Consumer Electronics Control) component!

Features

  • Native CEC 1.3a implementation
    • Implemented from scratch specifically for this component. No third-party CEC library used.
    • Meant to be as simple, lightweight and easy-to-understand as possible
    • Interrupts-based receiver (no polling at all). Handles low-level byte acknowledgements
  • Receive CEC commands
    • Handle incoming messages with on_message triggers
      • Each trigger specified in on_message supports filtering based on source, destination, opcode and/or message contents
    • Built-in handlers for some of the system commands defined in the spec :
      • "Get CEC Version"
      • "Give Device Power Status"
      • "Give OSD Name"
  • Send CEC commands
    • Built-in hdmi_cec.send action

To-do list

  • Automatic Physical Address Discovery through E-DDC

Installation

  1. Wire your ESPhome device to an HDMI connector (e.g. an HDMI breakout that can be found on Amazon) as follows :

    • GPIO pin of your choice -> HDMI pin 13 (CEC)
    • GND -> HDMI pin 17 (DDC/CEC ground)
    • Optional: wire your board's 5V supply to HDMI pin 18. This is how your TV/switch on the other end knows something is connected.

    The CEC bus uses 3.3V logic, so it's perfectly safe for ESP32/ESP8266 devices (or any other microcontroller with 3.3V logic).

  2. In your ESPhome configuration file, add this Git repository as an external component

external_components:
  - source: github://Palakis/esphome-hdmi-cec
  1. Setup the HDMI-CEC component
hdmi_cec:
  # Pick a GPIO pin that can do both input AND output
  pin: GPIO26 # Required
  # The address can be anything you want. Use 0xF if you only want to listen to the bus and not act like a standard device
  address: 0xE # Required
  # Physical address of the device. In this case: 4.0.0.0 (HDMI4 on the TV)
  # DDC support is not yet implemented, so you'll have to set this manually.
  physical_address: 0x4000 # Required
  # The name that will we displayed in the list of devices on your TV/receiver
  osd_name: "my device" # Optional. Defaults to "esphome"
  # By default, promiscuous mode is disabled, so the component only handles directly-address messages (matching
  # the address configured above) and broadcast messages. Enabling promiscuous mode will make the component
  # listen for all messages (both in logs and the on_message triggers)
  promiscuous_mode: false # Optional. Defaults to false
  # By default, monitor mode is disabled, so the component can send messages and acknowledge incoming messages.
  # Enabling monitor mode lets the component act as a passive listener, disabling active manipulation of the CEC bus.
  monitor_mode: false # Optional. Defaults to false
  # List of triggers to handle specific commands. Each trigger has the following optional filter parameters:
  # - "source": match messages coming from the specified address
  # - "destination": match messages meant for the specified address
  # - "opcode": match messages bearing the specified opcode
  # - "data": exact-match on message content
  # Actions called from these triggers is called with "source", "destination" and "data" as parameters
  on_message:
    - opcode: 0x36 # opcode for "Standby"
      then:
        logger.log: "Got Standby command"
    
    # Respond to "Menu Request" (not required, example purposes only)
    - opcode: 0x8D
      then:
        hdmi_cec.send:
          # both "destination" and "data" are templatable
          destination: !lambda return source;
          data: [0x8E, 0x01] # 0x01 => "Menu Deactivated"
  1. (optional) Use the hdmi_cec.send action in your ESPHome configuration
button:
  - platform: template
    name: "Turn everything off"
    on_press:
      hdmi_cec.send:
        # "source" can optionally be set, like if you want to spoof another device's address
        destination: 0xF # Broadcast
        data: [0x36] # "Standby" opcode
  1. (optional) Add Services for HomeAssistant
api
  ...
  services:
    - service: hdmi_cec_send
      variables:
        cec_destination: int
        cec_data: int[]
      then:
        - hdmi_cec.send:
            destination: !lambda "return static_cast<unsigned char>(cec_destination);"
            data: !lambda "std::vector<unsigned char> charVector; for (int i : cec_data) { charVector.push_back(static_cast<unsigned char>(i)); } return charVector;"

Compatibility

  • ESP32: ✅ tested, works
  • ESP8266: ✅ tested, works
  • RP2040: ✅ tested, works
  • LibreTiny: ❌ not supported
    • I don't have any LibreTiny device at hand. Feel free to run your own tests and report back your findings.

Acknowledgements

esphome-native-hdmi-cec's People

Contributors

minims avatar niko132 avatar palakis avatar segfly avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

esphome-native-hdmi-cec's Issues

Not working on Seeed Xiao ESP32-C3

Very nice library, I'm glad someone refined the work from existing authors.

However, it's not working for me on seeed_xiao_esp32c3. It reports successfully transmitting frames in the logs, but on my logic analyzer I don't see the pin state change at all. I had the same issue with johnboiles library, and for the longest time, I thought the code just didn't work.

After discovering your library, and seeing that it still did not work for me, I decided to try it on a Waveshare ESP32-S3-Zero with esp32-s3-devkitc-1 and it works fine.

So I am a bit perplexed what is going on, I've double and triple checked my physical connections, verified the pins work by testing other output components the same pin, tried all the pins available on the board, and still no output.

My config is very simple to test:

esphome:
  name: basic

esp32:
  board: seeed_xiao_esp32c3
  framework:
    type: arduino
  # board: esp32-s3-devkitc-1 # Works for Waveshare ESP32-S3-Zero
  # framework:
  #   type: arduino

logger:

binary_sensor:
  - platform: gpio
    name: "CEC Send"
    pin:
      number: GPIO9 # Xiao onboard button    
      # number: GPIO0 # Waveshare ESP32-S3-Zero onboard button
      inverted: true
      mode: INPUT_PULLUP
    on_press:
      hdmi_cec.send:
        destination: 0xF # Broadcast
        data: [0x36] # "Standby" opcode                

external_components:
  - source: github://Palakis/esphome-hdmi-cec

hdmi_cec:
  pin: GPIO4
  address: 0x4
  physical_address: 0x1000

Everything seems to be fine in the logs:

[D][binary_sensor:036]: 'CEC Send': Sending state ON
[D][hdmi_cec:204]: sending frame: 4F:36
[D][hdmi_cec:218]: HDMICEC::send(): frame sent and acknowledged
[W][component:237]: Component gpio.binary_sensor took a long time for an operation (53 ms).
[W][component:238]: Components should block for at most 30 ms.
[D][binary_sensor:036]: 'CEC Send': Sending state OFF

But only my S3 will actually output data, the C3 just sits there and pretends to have done something with the line staying high.

In fact, if I put an external pulldown resistor, it actually does something, just junk on when the CEC send is invoked, but it actually does something. So I'm thinking there must be something off with the way the pin is being configured. I tried manually setting some of the pin configuration, like INPUT_OUTPUT_OPEN_DRAIN, etc. but it has no effect - except 'inverted' which results in the error "[E][hdmi_cec:232]: HDMICEC::send(): send failed after five attempts"

Thanks in advance for any pointers as to what may be going on.

Templating

Hello,

First of all thanks for this work !

I'm trying to get a Service in HomeAssistant. So i define this in esphome:

api:
  services:
    - service: hdmi_cec_send
      variables:
        cec_destination: int
        cec_data: int[]
      then:
        - hdmi_cec.send:
            destination: !lambda 'return cec_destination;'
            data: !lambda 'return cec_data;'

but i have this error :

<unicode string>:54:14: error: could not convert 'cec_data' from 'vector<int>' to 'vector<unsigned char>'

Any Idea how i can fix this ?

Implement ID

Hi,

First off LOVE THIS! after 2 months of screwing around with other options this one worked for me and saved my project!!!

Would it be possible to implement id in esphome. The reason is that I would love to use 3 HDMI CEC outputs.

Let me know hwo to buy you a coffee(tm) for all the hard work.

Unable to get the TV to turn on after power-cycling it

I have this simple code working and using HomeAssistant to send in...

cec_destination = 0
cec_data = [0x04]

...and its working to get the tv to turn on, but only when the tv is in standby mode. I'd really like to be able to turn the tv on from complete power-cycle as well. I only wired up 2 of the 3 (3rd was said to be optional) wires suggested in your readme. Perhaps 3 might work if the TV knows a device is there?

services:
    - service: hdmi_cec_send
      variables:
        cec_destination: int
        cec_data: int[]
      then:
        - hdmi_cec.send:
            destination: !lambda 'return static_cast<unsigned char>(cec_destination);'
            data: !lambda 'std::vector<unsigned char> charVector; for (int i : cec_data) { charVector.push_back(static_cast<unsigned char>(i)); } return charVector;'

I can't believe I've been all over the place and can't seem to find a "programmatic solution to turn the tv on and off that is as guaranteed as the IR/RF remote. I was really hoping CEC would be the answer. 😢

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.