This little script will allow you to control your Raspberry Pi using the buttons in your regular TV remote.

Usage

You can press the following buttons on the remote.

OK – launch kodi

up – launch browser

down – change wallpaper (this is a custom script of mine)

left – suspend your desktop computer

back – halt Raspberry Pi

stop – enter “mouse mode”, to move the mouse with the arrows. OK to double click

play – exit “mouse mode”

These bindings are set as an example. Each person should change them to suit their own needs.

Instalation

First, follow the instructions to compile and install libcec. More details below.

Then, get the code from my gist, and create an executable script

wget https://gist.githubusercontent.com/nachoparker/96fa8036d93603b3eee01ee69d3c1606/raw/74ae036ae3e50e7153231e0694c2ca7dd8f43c8a/picec.sh chmod +x picec.sh

You can run picec.sh from whatever “startup programs” configuration your desktop provides. In my case, I just add the following line at the end of /etc/rc.local

/home/pi/picec.sh

Optionally, you can install xdotool for moving the mouse, and osd_cat for showing information in a TV OSD fashion. More details below.

sudo apt-get install xosd-bin xdotool

Details

As a means to control our RPi, we will use the CEC (Consumer Electronics Control) feature of HDMI, which is a standard protocol to send commands back and forth through HDMI.

CEC allows consumer devices to control each other with or without user intervention. The GPU of the Raspberry Pi already supports the CEC protocol, as most modern TVs do. There is a compatibility list here.

An often missed requirement is that your HDMI cable must support CEC as well. Most cables do, but some of the cheapest ones cannot talk CEC, so be careful with this.

In order to speak to our TV using the CEC standard, we make use of the libcec library by Pulse Eight. This library is already included in Kodi out of the box, and it is the reason we can readily control our media center with our remote.

From their website, we can follow the instructions to compile and install libcec on the Raspberry Pi.

sudo apt-get update sudo apt-get install cmake libudev-dev libxrandr-dev python-dev swig cd git clone https://github.com/Pulse-Eight/platform.git mkdir platform/build cd platform/build cmake .. make sudo make install cd git clone https://github.com/Pulse-Eight/libcec.git mkdir libcec/build cd libcec/build cmake -DRPI_INCLUDE_DIR=/opt/vc/include -DRPI_LIB_DIR=/opt/vc/lib .. make -j4 sudo make install sudo ldconfig

After this, we obtain the library, some python bindings and a wrapper utility in C called cec-client .

We can now list connected devices,

tv# cec-client -l libCEC version: 3.1.0, git revision: libcec-3.1.0+5-6d68d21, compiled on Fri 8 Apr 15:44:58 UTC 2016 by nacho@tv on Linux 4.1.19-v7+ (armv7l), features: P8_USB, DRM, P8_detect, randr, RPi Found devices: 1 device: 1 com port: RPI vendor id: 2708 product id: 1001 firmware version: 1 type: Raspberry Pi

, turn the TV on and off from SSH,

echo "on 0" | cec-client -s # turn on the television echo "standby 0" | cec-client -s # turn it off

, and even configure the TV. To see all available commands:

tv# echo h | cec-client -s -d 1 opening a connection to the CEC adapter... ================================================================================ Available commands: [tx] {bytes} transfer bytes over the CEC line. [txn] {bytes} transfer bytes but don't wait for transmission ACK. [on] {address} power on the device with the given logical address. [standby] {address} put the device with the given address in standby mode. [la] {logical address} change the logical address of the CEC adapter. [p] {device} {port} change the HDMI port number of the CEC adapter. [pa] {physical address} change the physical address of the CEC adapter. [as] make the CEC adapter the active source. [is] mark the CEC adapter as inactive source. [osd] {addr} {string} set OSD message on the specified device. [ver] {addr} get the CEC version of the specified device. [ven] {addr} get the vendor ID of the specified device. [lang] {addr} get the menu language of the specified device. [pow] {addr} get the power status of the specified device. [name] {addr} get the OSD name of the specified device. [poll] {addr} poll the specified device. [lad] lists active devices on the bus [ad] {addr} checks whether the specified device is active. [at] {type} checks whether the specified device type is active. [sp] {addr} makes the specified physical address active. [spl] {addr} makes the specified logical address active. [volup] send a volume up command to the amp if present [voldown] send a volume down command to the amp if present [mute] send a mute/unmute command to the amp if present [self] show the list of addresses controlled by libCEC [scan] scan the CEC bus and display device info [mon] {1|0} enable or disable CEC bus monitoring. [log] {1 - 31} change the log level. see cectypes.h for values. [ping] send a ping command to the CEC adapter. [bl] to let the adapter enter the bootloader, to upgrade the flash rom. [r] reconnect to the CEC adapter. [h] or [help] show this help. [q] or [quit] to quit the CEC test client and switch off all connected CEC devices. ================================================================================

As a quick and dirty way of playing with this, I wrote this little script that just parses the output of the cec-client utility. I figured it would be faster to implement than using the C library and end up calling system() or popen() anyway.

There is lots of room for improvement, but I hope this can give you ideas to get started.

#!/bin/bash # Simple script to control your Raspberry Pi with your TV remote using libcec # # Copyleft 2017 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com> # GPL licensed (see end of file) * Use at your own risk! # # You can set this to be run in your desktop "startup programs", or # at the last line of /etc/rc.local, just to say a couple options # # keys: # OK - launch kodi # up - launch browser # down - change wallpaper (this is a custom script of mine) # left - suspend my desktop computer # back - exit desktop session # # You can hit 'stop' to enter "mouse mode", or 'play' to exit it. # In "mouse mode" you can move around the mouse with the remote arrows, hit ok # to double-click. # # This is just an example to provide ideas, so you should change what each button does # USER=pi # user that will be logged in OSDCOLOR=red # color for xosd messages MOUSESPEED=50 # how many pixels a mouse will move on each press #dbg=echo # uncomment to print the command without running it VERBOSE=0 # print echov lines #DRY_RUN="yes" # uncomment to actually ignore button presses type cec-client &>/dev/null || { echo "cec-client is requiered"; exit; } type xdotool &>/dev/null || NOXDOTOOL=# USR_CMD="su - $USER -c" _XAUTH="/home/$USER/.Xauthority" d(){ eval "$NOXDOTOOL $@" ; } echov(){ [[ "$VERBOSE" == "1" ]] && echo $@ ; } filter_key(){ grep -q "key pressed: $1 .* duration" <( echo "$2" ) ; } mouse_move(){ XAUTHORITY="$_XAUTH" DISPLAY=:0 xdotool mousemove_relative -- $@; } mouseclick(){ XAUTHORITY="$_XAUTH" DISPLAY=:0 xdotool click --repeat 2 1 ; } osdecho(){ type osd_cat &>/dev/null && echo "$@" | \ XAUTHORITY="$_XAUTH" DISPLAY=:0 osd_cat -ptop -Acenter -c$OSDCOLOR; } while :; do cec-client | while read l; do echov $l [[ "$DRY_RUN" != "" ]] && continue pgrep kodi && { echov "Ignoring key, because Kodi is running"; continue; } if filter_key "select" "$l"; then [[ "$MOUSEMODE" == "1" ]] && mouseclick || { $dbg $USR_CMD kodi killall cec-client } break fi if filter_key "up" "$l"; then [[ "$MOUSEMODE" == "1" ]] && mouse_move 0 -$MOUSESPEED || \ $dbg $USR_CMD "DISPLAY=\":0\" x-www-browser" & fi if filter_key "left" "$l"; then [[ "$MOUSEMODE" == "1" ]] && mouse_move -$MOUSESPEED 0 || \ $dbg nohup su - nacho -c "ssh nacho@desktop sudo pm-suspend" & fi if filter_key "down" "$l"; then [[ "$MOUSEMODE" == "1" ]] && mouse_move 0 $MOUSESPEED || \ $dbg $USR_CMD "DISPLAY=\":0\" /home/pi/.config/lxsession/LXDE-pi/random_wp.sh" fi if filter_key "right" "$l"; then [[ "$MOUSEMODE" == "1" ]] && mouse_move $MOUSESPEED 0 fi if filter_key "exit" "$l"; then $dbg $USR_CMD "pkill -SIGTERM -f lxsession" fi if filter_key "stop" "$l"; then d echov "mouse mode on" d osdecho "mouse mode on" d MOUSEMODE=1 fi if filter_key "play" "$l"; then echov "mouse mode off" osdecho "mouse mode off" MOUSEMODE=0 fi done done # License # # This script is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This script is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this script; if not, write to the # Free Software Foundation, Inc., 59 Temple Place, Suite 330, # Boston, MA 02111-1307 USA

The script makes use of osd_cat for the visual feedback, and xdotool for the mouse control functionality. It is recommended to install them with apt, but it’s not required because the script will detect wether they are available or not.

As you can see on this list, each manufacturer supports the protocol to a varying degree, so you will have to play a little bit to see what button you can detect, and wether you can get the duration of the button press. For instance, on my Philips remote, I do not have access to the numbers.

Moving the mouse is not really very useful, as the latency is terrible. However, there are other cool things that you might want to associate to your remote using xdtool, for example you can read PDFs or websites binding

xdotool key Page_Down xdotool key Page_Up xdotool key Home xdotool key End

, or even bind to <CTRL><TAB> to navigate through browser tabs.