Difference between revisions of "HDMI-CEC"

From MythTV Official Wiki
Jump to: navigation, search
(+ control MythTv with TV remote)
Line 1: Line 1:
 
{{wikipedia|HDMI#CEC}}
 
{{wikipedia|HDMI#CEC}}
 +
 +
== Introduction ==
  
 
HDMI-CEC is a device control protocol that runs over HDMI cables.
 
HDMI-CEC is a device control protocol that runs over HDMI cables.
  
 
It allows rudimentary control over HDMI-CEC aware devices - these devices oftern have vendor-specific names for the protocol, such as AnyNet+ for Samsung devices.
 
It allows rudimentary control over HDMI-CEC aware devices - these devices oftern have vendor-specific names for the protocol, such as AnyNet+ for Samsung devices.
 +
 +
Therefore, it is possible to either control an HDMI-CEC-aware device (such as a TV) from another (like a computer), e.g. by having the computer turn the TV on, or vice versa, e.g. by using the TV remote to control MythTV on the computer.
 +
 +
== Background ==
  
 
HDMI-CEC devices have two key public properties - a logical address and a physical address.
 
HDMI-CEC devices have two key public properties - a logical address and a physical address.
Line 10: Line 16:
 
If a device with other HDMI ports (referred to as a switch) is plugged in, any devices plugged into that will get a number in the the next "dot range".
 
If a device with other HDMI ports (referred to as a switch) is plugged in, any devices plugged into that will get a number in the the next "dot range".
  
So if an AV Receiver is plugged into port 1 of the tv, it would have physical address 1.0.0.0
+
So if an AV Receiver is plugged into port 1 of the TV, it would have physical address 1.0.0.0
  
 
if the MythTv HDMI out is plugged into port 3 of the AV receiver above, its physical address should be 1.3.0.0
 
if the MythTv HDMI out is plugged into port 3 of the AV receiver above, its physical address should be 1.3.0.0
Line 22: Line 28:
 
  - kwikwai http://www.kwikwai.com/ (not tested)
 
  - kwikwai http://www.kwikwai.com/ (not tested)
 
  - pulse-eight http://www.pulse-eight.com/store
 
  - pulse-eight http://www.pulse-eight.com/store
 +
 +
== Use a TV remote to control MythTV ==
 +
 +
(Adapted from https://ubuntu-mate.community/t/controlling-raspberry-pi-with-tv-remote-using-hdmi-cec/4250)
 +
 +
I found that whilst xdotool and libcec4 was available from Raspbian stretch, cec-client was not, so I installed the latter from Debian stretch - for my Pi3, the armhf architecture was compatible.
 +
 +
#!/bin/bash
 +
 +
function keychar {
 +
    parin1=$1                        # first param; abc1
 +
    parin2=$2                        # second param; 0=a, 1=b, 2=c, 3=1, 4=a, ...
 +
    parin2=$((parin2))                # convert to numeric
 +
    parin1len=${#parin1}              # length of parin1
 +
    parin2pos=$((parin2 % parin1len)) # position mod
 +
    char=${parin1:parin2pos:1}        # char key to simulate
 +
    if [ "$parin2" -gt 0 ]; then      # if same key pressed multiple times, delete previous char; write a, delete a write b, delete b write c, ...
 +
        xdotool key "BackSpace"
 +
    fi
 +
 +
    # special cases for xdotool ( X Keysyms )
 +
    if [ "$char" = " " ]; then char="space"; fi
 +
    if [ "$char" = "." ]; then char="period"; fi
 +
    if [ "$char" = "-" ]; then char="minus"; fi
 +
    xdotool key $char
 +
}
 +
 +
datlastkey=$(date +%s%N)
 +
strlastkey=""
 +
intkeychar=0
 +
intmsbetweenkeys=2000 #two presses of a key sooner that this makes it delete previous key and write the next one (a->b->c->1->a->...)
 +
intmousestartspeed=10 #mouse starts moving at this speed (pixels per key press)
 +
intmouseacc=10 #added to the mouse speed for each key press (while holding down key, more key presses are sent from the remote)
 +
intmousespeed=10
 +
 +
while read oneline
 +
do
 +
    keyline=$(echo $oneline | grep " key " | grep -v current)
 +
    #echo $keyline --- debugAllLines
 +
    if [ -n "$keyline" ]; then
 +
        datnow=$(date +%s%N)
 +
        datdiff=$((($datnow - $datlastkey) / 1000000))          # bla bla key pressed: previous channel (123)
 +
        strkey=$(grep -oP '(?<=sed: ).*?(?= \()' <<< "$keyline") # bla bla key pres-->sed: >>previous channel<< (<--123)
 +
        strstat=$(grep -oP '(?<=key ).*?(?=:)' <<< "$keyline")  # bla bla -->key >>pressed<<:<-- previous channel (123)
 +
        strpressed=$(echo $strstat | grep "pressed")
 +
        strreleased=$(echo $strstat | grep "released")
 +
        if [ -n "$strpressed" ]; then
 +
            #echo $keyline --- debug
 +
            if [ "$strkey" = "$strlastkey" ] && [ "$datdiff" -lt "$intmsbetweenkeys" ]; then
 +
                intkeychar=$((intkeychar + 1))                  # same key pressed for a different char
 +
            else
 +
                intkeychar=0                                    # different key / too far apart
 +
            fi
 +
            datlastkey=$datnow
 +
            strlastkey=$strkey
 +
            case "$strkey" in
 +
                "1")
 +
                    xdotool key 1
 +
                    ;;
 +
                "2")
 +
                    keychar "abc2" intkeychar
 +
                    ;;
 +
                "3")
 +
                    keychar "def3" intkeychar
 +
                    ;;
 +
                "4")
 +
                    keychar "ghi4" intkeychar
 +
                    ;;
 +
                "5")
 +
                    keychar "jkl5" intkeychar
 +
                    ;;
 +
                "6")
 +
                    keychar "mno6" intkeychar
 +
                    ;;
 +
                "7")
 +
                    keychar "pqrs7" intkeychar
 +
                    ;;
 +
                "8")
 +
                    keychar "tuv8" intkeychar
 +
                    ;;
 +
                "9")
 +
                    keychar "wxyz9" intkeychar
 +
                    ;;
 +
                "0")
 +
                    keychar " 0.-" intkeychar
 +
                    ;;
 +
                "previous channel")
 +
                    xdotool key BackSpace
 +
                    ;;
 +
                "channel up")
 +
                    xdotool key Page_Up
 +
                    ;;
 +
                "channel down")
 +
                    xdotool key Page_Down
 +
                    ;;
 +
                "channels list")
 +
                    xdotool key m
 +
                    ;;
 +
                "up")
 +
                    xdotool key Up
 +
                    ;;
 +
                "down")
 +
                    xdotool key Down
 +
                    ;;
 +
                "left")
 +
                    xdotool key Left
 +
                    ;;
 +
                "right")
 +
                    xdotool key Right
 +
                    ;;
 +
                "select")
 +
                    xdotool key Return
 +
                    ;;
 +
                "return")
 +
                    xdotool key Escape
 +
                    ;;
 +
                "exit")
 +
                    xdotool key Escape
 +
                    ;;
 +
                "F2")
 +
                    chromium-browser "https://www.youtube.com"  # Red
 +
                    ;;
 +
                "F3")
 +
                    chromium-browser "https://www.google.com" &  # Green
 +
                    ;;
 +
                "F4")
 +
                    echo Key Pressed: YELLOW C                  # Yellow
 +
                    ;;
 +
                "F1")
 +
                    chromium-browser --incognito "https://www.google.com" & # Blue
 +
                    ;;
 +
                "rewind")
 +
                    xdotool key less
 +
                    ;;
 +
                "pause")
 +
                    xdotool key p
 +
                    ;;
 +
                "Fast forward")
 +
                    xdotool key greater
 +
                    ;;
 +
                "play")
 +
                    xdotool key p
 +
                    ;;
 +
                "record")
 +
                    echo Key Pressed: record
 +
                    ;;
 +
                "stop")
 +
                    ## with my remote I only got "STOP" as key released (auto-released), not as key pressed; see below
 +
                    echo Key Pressed: STOP
 +
                    ;;
 +
                *)
 +
                    echo Unrecognized Key Pressed: $strkey ; CEC Line: $keyline
 +
                    ;;
 +
            esac
 +
        fi
 +
        if [ -n "$strreleased" ]; then
 +
            #echo $keyline --- debug
 +
            case "$strkey" in
 +
                "stop")
 +
                    echo Key Released: STOP
 +
                    ;;
 +
                "up")
 +
                    intmousespeed=$intmousestartspeed #reset mouse speed
 +
                    ;;
 +
                "down")
 +
                    intmousespeed=$intmousestartspeed #reset mouse speed
 +
                    ;;
 +
                "left")
 +
                    intmousespeed=$intmousestartspeed #reset mouse speed
 +
                    ;;
 +
                "right")
 +
                    intmousespeed=$intmousestartspeed #reset mouse speed
 +
                    ;;
 +
            esac
 +
        fi
 +
    fi
 +
done
 +
 +
Save the above to, say remote.sh, and run the script with:
 +
 +
cec-client | remote.sh
 +
 +
The above worked for my Samsung TV and Raspberry Pi3
 +
 +
== Control a device from MythTV ==
  
 
These instructions have been developed using the RainshadowTech device - differences will exist.
 
These instructions have been developed using the RainshadowTech device - differences will exist.
Line 29: Line 220:
 
One very useful site is the www.cec-o-matic.com site, developed by kwikwai (http://www.kwikwai.com/)
 
One very useful site is the www.cec-o-matic.com site, developed by kwikwai (http://www.kwikwai.com/)
  
Useful things that can be done with MythTv and HDMI-CEC:
+
To allowing MythTv to automatically set the AV receiver to the correct input whenever playback begins (via MythTV System Event),
- allowing the TV remote control to send commands to Mythtv (via custom comand-line bridge and Mythfront end remote control socket)
+
the following code (saved to a file and marked executable) will turn on the TV, and set the correct AV input when MythTv starts playback
 
+
 
+
- allowing MythTv to automatically set the AV receiver to the correct input whenever playback begins (via MythTV System Event)
+
The following code (saved to a file and marked executable) will turn on the TV, and set the correct AV input when MythTv starts playback
+
  
 
   #!/bin/sh
 
   #!/bin/sh

Revision as of 20:18, 11 September 2017

Wikipedia-logo-en.png
Wikipedia has an article on:

Introduction

HDMI-CEC is a device control protocol that runs over HDMI cables.

It allows rudimentary control over HDMI-CEC aware devices - these devices oftern have vendor-specific names for the protocol, such as AnyNet+ for Samsung devices.

Therefore, it is possible to either control an HDMI-CEC-aware device (such as a TV) from another (like a computer), e.g. by having the computer turn the TV on, or vice versa, e.g. by using the TV remote to control MythTV on the computer.

Background

HDMI-CEC devices have two key public properties - a logical address and a physical address. The physical address is determined by the ports a device is plugged into. HDMI is effectively a tree structure, with the TV/Display defaulting to physical address 0.0.0.0 (I understand there should only be 1 display in a HDMI setup, but exceptions apparently can be sometimes tolerated depending on the equipment)

If a device with other HDMI ports (referred to as a switch) is plugged in, any devices plugged into that will get a number in the the next "dot range".

So if an AV Receiver is plugged into port 1 of the TV, it would have physical address 1.0.0.0

if the MythTv HDMI out is plugged into port 3 of the AV receiver above, its physical address should be 1.3.0.0

Subsequently, any device directly attached to the switch gets a number based on the port it is plugged into. Typically devices determine their physical address via DDC, but as some CEC bridges are not "inline" with the source device they cannot dynamically determine the physical address. (These devices, such as the RainShadowTech one can have their physical address set to allow them to "impersonate" the non-hdmi-cec device - such as a typical HDMI-capable video card.

Secondly, there is a "Logical Address" which largely determines the type of device - and supports negotiation if multiple instances of the same type are on the HDMI tree (ie two bluray players etc). However, the Logical address is used when addressing devices, not the physical address. The Physical address is used when a "source Device" is in playback mode, and alerts all other devices that it is sending a stream to the display device via the path inherent in its physical address.

There are new devices becoming coming available that support a USB-HDMI bridge - some of these are

- RainShadowTech http://www.rainshadowtech.com (used for the purposes of this page). 
- kwikwai http://www.kwikwai.com/ (not tested)
- pulse-eight http://www.pulse-eight.com/store

Use a TV remote to control MythTV

(Adapted from https://ubuntu-mate.community/t/controlling-raspberry-pi-with-tv-remote-using-hdmi-cec/4250)

I found that whilst xdotool and libcec4 was available from Raspbian stretch, cec-client was not, so I installed the latter from Debian stretch - for my Pi3, the armhf architecture was compatible.

#!/bin/bash

function keychar {
    parin1=$1                         # first param; abc1
    parin2=$2                         # second param; 0=a, 1=b, 2=c, 3=1, 4=a, ...
    parin2=$((parin2))                # convert to numeric
    parin1len=${#parin1}              # length of parin1
    parin2pos=$((parin2 % parin1len)) # position mod
    char=${parin1:parin2pos:1}        # char key to simulate
    if [ "$parin2" -gt 0 ]; then      # if same key pressed multiple times, delete previous char; write a, delete a write b, delete b write c, ...
        xdotool key "BackSpace"
    fi

    # special cases for xdotool ( X Keysyms )
    if [ "$char" = " " ]; then char="space"; fi
    if [ "$char" = "." ]; then char="period"; fi
    if [ "$char" = "-" ]; then char="minus"; fi
    xdotool key $char
}

datlastkey=$(date +%s%N)
strlastkey=""
intkeychar=0
intmsbetweenkeys=2000 #two presses of a key sooner that this makes it delete previous key and write the next one (a->b->c->1->a->...)
intmousestartspeed=10 #mouse starts moving at this speed (pixels per key press)
intmouseacc=10 #added to the mouse speed for each key press (while holding down key, more key presses are sent from the remote)
intmousespeed=10

while read oneline
do
    keyline=$(echo $oneline | grep " key " | grep -v current)
    #echo $keyline --- debugAllLines
    if [ -n "$keyline" ]; then
        datnow=$(date +%s%N)
        datdiff=$((($datnow - $datlastkey) / 1000000))           # bla bla key pressed: previous channel (123)
        strkey=$(grep -oP '(?<=sed: ).*?(?= \()' <<< "$keyline") # bla bla key pres-->sed: >>previous channel<< (<--123)
        strstat=$(grep -oP '(?<=key ).*?(?=:)' <<< "$keyline")   # bla bla -->key >>pressed<<:<-- previous channel (123)
        strpressed=$(echo $strstat | grep "pressed")
        strreleased=$(echo $strstat | grep "released")
        if [ -n "$strpressed" ]; then
            #echo $keyline --- debug
            if [ "$strkey" = "$strlastkey" ] && [ "$datdiff" -lt "$intmsbetweenkeys" ]; then
                intkeychar=$((intkeychar + 1))                   # same key pressed for a different char
            else
                intkeychar=0                                     # different key / too far apart
            fi
            datlastkey=$datnow
            strlastkey=$strkey
            case "$strkey" in
                "1")
                    xdotool key 1
                    ;;
                "2")
                    keychar "abc2" intkeychar
                    ;;
                "3")
                    keychar "def3" intkeychar
                    ;;
                "4")
                    keychar "ghi4" intkeychar
                    ;;
                "5")
                    keychar "jkl5" intkeychar
                    ;;
                "6")
                    keychar "mno6" intkeychar
                    ;;
                "7")
                    keychar "pqrs7" intkeychar
                    ;;
                "8")
                    keychar "tuv8" intkeychar
                    ;;
                "9")
                    keychar "wxyz9" intkeychar
                    ;;
                "0")
                    keychar " 0.-" intkeychar
                    ;;
                "previous channel")
                    xdotool key BackSpace
                    ;;
                "channel up")
                    xdotool key Page_Up
                    ;;
                "channel down")
                    xdotool key Page_Down
                    ;;
                "channels list")
                    xdotool key m
                    ;;
                "up")
                    xdotool key Up
                    ;;
                "down")
                    xdotool key Down
                    ;;
                "left")
                    xdotool key Left
                    ;;
                "right")
                    xdotool key Right
                    ;;
                "select")
                    xdotool key Return
                    ;;
                "return")
                    xdotool key Escape
                    ;;
                "exit")
                    xdotool key Escape
                    ;;
                "F2")
                    chromium-browser "https://www.youtube.com"   # Red
                    ;;
                "F3")
                    chromium-browser "https://www.google.com" &  # Green
                    ;;
                "F4")
                    echo Key Pressed: YELLOW C                   # Yellow
                    ;;
                "F1")
                    chromium-browser --incognito "https://www.google.com" & # Blue
                    ;;
                "rewind")
                    xdotool key less
                    ;;
                "pause")
                    xdotool key p
                    ;;
                "Fast forward")
                    xdotool key greater
                    ;;
                "play")
                    xdotool key p
                    ;;
                "record")
                    echo Key Pressed: record
                    ;;
                "stop")
                    ## with my remote I only got "STOP" as key released (auto-released), not as key pressed; see below
                    echo Key Pressed: STOP
                    ;;
                *)
                    echo Unrecognized Key Pressed: $strkey ; CEC Line: $keyline
                    ;;
            esac
        fi
        if [ -n "$strreleased" ]; then
            #echo $keyline --- debug
            case "$strkey" in
                "stop")
                    echo Key Released: STOP
                    ;;
                "up")
                    intmousespeed=$intmousestartspeed #reset mouse speed
                    ;;
                "down")
                    intmousespeed=$intmousestartspeed #reset mouse speed
                    ;;
                "left")
                    intmousespeed=$intmousestartspeed #reset mouse speed
                    ;;
                "right")
                    intmousespeed=$intmousestartspeed #reset mouse speed
                    ;;
            esac
        fi
    fi
done

Save the above to, say remote.sh, and run the script with:

cec-client | remote.sh

The above worked for my Samsung TV and Raspberry Pi3

Control a device from MythTV

These instructions have been developed using the RainshadowTech device - differences will exist.

The RainShadowTech device exposes a device under /dev that can be read from or written to, with a simple "language" that slightly abstracts from the raw HDMI codes.

One very useful site is the www.cec-o-matic.com site, developed by kwikwai (http://www.kwikwai.com/)

To allowing MythTv to automatically set the AV receiver to the correct input whenever playback begins (via MythTV System Event), the following code (saved to a file and marked executable) will turn on the TV, and set the correct AV input when MythTv starts playback

 #!/bin/sh
 # Broadcast active path to every device (Destination Device = f [broadcast message], 0x82 = active path, path is 1300 (3rd device, plugged into 1st device in display)
 echo \!xf 821300~ >  /dev/ttyACM0
 # tell active path to AV reciever (Destination Device = 5 [Av receiver], 0x82 = active path, path is 1300 (3rd device, plugged into 1st device in display)
 echo \!x5 821300~ > /dev/ttyACM0
 # Turn on Display (Destination Device = 0 [Display], 0x04 = power on)
 echo \!x0 04~ >  /dev/ttyACM0


Code to send volume up to av receiver (save it to an executable file, and configure irexec to execute the file on appropriate remote key press)

 #!/bin/sh
 # Increase volume (Destination Device = 5 [Av receiver], 0x44 = Send Key, key code is 41 (Vol up)
 echo \!x5 4441~ >  /dev/ttyACM0

example lircrc setting

 begin
   prog = irexec
   button = Vol+
   repeat = 0
   config = /home/mythtv/hdmi-cec/volup
 end


Code to send volume down to AV receiver (save to /home/mythtv/hdmi-cec/voldown, chmod +x) NOTE - there is a security risk associated with irexec and custom bash files, but if this is your home HTPC, take your chances...

 ----
 #!/bin/sh
 # Decrease volume (Destination Device = 5 [Av receiver], 0x44 = Send Key, key code is 42 (Vol down)
 echo \!x5 4442~ >  /dev/ttyACM0
 ----

example lircrc setting

 begin
   prog = irexec
   button = Vol-
   repeat = 0
   config = /home/mythtv/hdmi-cec/voldown
 end


Things that would be nice for MythTv to support in HDMI-CEC:

- setting the hostname for HDMI-CEC device discovery (maybe could be done through System Event?)
- support recording from non-mythtv TV Mheg display

There is also implementation in 0.25 of use of http://libcec.pulse-eight.com/ - I will be trying this soon.


Here are some preliminary observations on libcec and mythtv with a pulse8 device on ubuntu precise:

basically I had to install not only libcec1 but also libcec1-dev. Otherwise mythfrontend shows the error "failed to load libcec" error. (I also made sure both my user and mythtv are member of the "dialout" group although not sure this is necessary.) Apart from that libcec support works kind of out-of-the box on my 2012 phlilips tv, in the sense that I can use the TV remote to control mythtv. Most keys from the TV remote work instantly. But I manually made some configuration to myth tv key maps via the frontend config dialogue. The OK key which triggers select I had to manually map to SELECT in "global" and I also chose to map the red button (F2) to MENU. Another effect is that the name of HDMI 1 in the TV changes to mythtv.


See also: http://themanfrey.blogspot.de/2012/09/enabling-libcec-on-mythbuntu-1204-with.html