Can't call cec-client script with keymap

I’m trying to map a key to toggle the TV power. I firstly created an xml file in ~/.kodi/userdata/keymaps, confirming that it works.

<keymap><global><keyboard>
	<key id="61952">pagedown</key>
</keyboard></global></keymap>

And after rebooting, this key indeed does send a pagedown signal. I created this script to toggle power on the TV. This script works perfectly from the command line.

However, when I try to call the script from the keymap file with System.Exec(/usr/local/bin/toggle-tv-power auto), it fails. I turned on debug, and can see it getting triggered in ~/.kodi/temp/kodi.log, but nothing happens. I get some cryptic output that may or may not be related:

2021-02-27 10:58:32.534 T:1915720624   DEBUG: Keyboard: scancode: 0xf0, sym: 0x0000, unicode: 0x0000, modifier: 0x0
2021-02-27 10:58:32.534 T:1915720624   DEBUG: GetActionCode: Trying Hardy keycode for 0xf200
2021-02-27 10:58:32.534 T:1915720624   DEBUG: Previous line repeats 1 times.
2021-02-27 10:58:32.534 T:1915720624   DEBUG: HandleKey: 0 (0xf200, obc-61697) pressed, action is System.Exec(/usr/local/bin/toggle-tv-power auto)
2021-02-27 10:58:32.534 T:1915720624   DEBUG: Keyboard: scancode: 0xf0, sym: 0x0000, unicode: 0x0000, modifier: 0x0
2021-02-27 10:58:32.717 T:1875894496   DEBUG: CAESinkPi:Drain delay:99ms now:0ms
2021-02-27 10:58:32.717 T:1875894496   DEBUG: CAESinkPi:Deinitialize
2021-02-27 10:58:32.718 T:1875894496   DEBUG: CAESinkPi:SetAudioProps hdmi_stream_channels 0 hdmi_channel_map 00000000
2021-02-27 10:58:32.722 T:1875894496   DEBUG: COMXCoreComponent::Deinitialize : OMX.broadcom.audio_render handle 0x6e902e70
2021-02-27 10:58:32.734 T:1884287200    INFO: CAESinkALSA::EnumerateDevice - device default description
2021-02-27 10:58:32.738 T:1884287200    INFO: CAESinkALSA::EnumerateDevice - device @ description
2021-02-27 10:58:32.740 T:1884287200    INFO: CAESinkALSA - Unable to open device "surround71" for playback
2021-02-27 10:58:32.743 T:1884287200    INFO: CAESinkALSA - Unable to open device "surround51" for playback
2021-02-27 10:58:32.744 T:1884287200    INFO: CAESinkALSA - Unable to open device "surround71" for playback
2021-02-27 10:58:32.746 T:1884287200    INFO: CAESinkALSA - Unable to open device "surround40" for playback
2021-02-27 10:58:32.747 T:1884287200    INFO: CAESinkALSA - Unable to open device "surround51" for playback
2021-02-27 10:58:32.747 T:1884287200    INFO: CAESinkALSA - Unable to open device "surround71" for playback
2021-02-27 10:58:32.794 T:1884287200    INFO: CAESinkALSA::EnumerateDevice - device sysdefault:CARD=ALSA description bcm2835 ALSA, bcm2835 ALSA
                                            Default Audio Device
2021-02-27 10:58:32.798 T:1884287200  NOTICE: Found 2 Lists of Devices
2021-02-27 10:58:32.798 T:1884287200  NOTICE: Enumerated ALSA devices:
2021-02-27 10:58:32.799 T:1884287200  NOTICE:     Device 1
2021-02-27 10:58:32.799 T:1884287200  NOTICE:         m_deviceName      : @
2021-02-27 10:58:32.799 T:1884287200  NOTICE:         m_displayName     : Default (bcm2835 ALSA bcm2835 ALSA)
2021-02-27 10:58:32.799 T:1884287200  NOTICE:         m_displayNameExtra:
2021-02-27 10:58:32.799 T:1884287200  NOTICE:         m_deviceType      : AE_DEVTYPE_PCM
2021-02-27 10:58:32.800 T:1884287200  NOTICE:         m_channels        : FL, FR
2021-02-27 10:58:32.800 T:1884287200  NOTICE:         m_sampleRates     : 8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,176400,192000
2021-02-27 10:58:32.800 T:1884287200  NOTICE:         m_dataFormats     : AE_FMT_S16NE,AE_FMT_S16LE,AE_FMT_U8
2021-02-27 10:58:32.800 T:1884287200  NOTICE:         m_streamTypes     : No passthrough capabilities
2021-02-27 10:58:32.801 T:1884287200  NOTICE:     Device 2
2021-02-27 10:58:32.802 T:1884287200  NOTICE:         m_deviceName      : sysdefault:CARD=ALSA
2021-02-27 10:58:32.802 T:1884287200  NOTICE:         m_displayName     : bcm2835 ALSA
2021-02-27 10:58:32.802 T:1884287200  NOTICE:         m_displayNameExtra: bcm2835 ALSA
2021-02-27 10:58:32.802 T:1884287200  NOTICE:         m_deviceType      : AE_DEVTYPE_PCM
2021-02-27 10:58:32.802 T:1884287200  NOTICE:         m_channels        : FL, FR
2021-02-27 10:58:32.802 T:1884287200  NOTICE:         m_sampleRates     : 8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,176400,192000
2021-02-27 10:58:32.802 T:1884287200  NOTICE:         m_dataFormats     : AE_FMT_S16NE,AE_FMT_S16LE,AE_FMT_U8
2021-02-27 10:58:32.802 T:1884287200  NOTICE:         m_streamTypes     : No passthrough capabilities
2021-02-27 10:58:32.802 T:1884287200  NOTICE: Enumerated PI devices:
2021-02-27 10:58:32.802 T:1884287200  NOTICE:     Device 1
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_deviceName      : HDMI
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_displayName     : HDMI
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_displayNameExtra:
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_deviceType      : AE_DEVTYPE_HDMI
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_channels        : FL, FR
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_sampleRates     : 8000,11025,16000,22050,24000,32000,44100,48000,88200,96000,176400,192000
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_dataFormats     : AE_FMT_FLOAT,AE_FMT_S32NE,AE_FMT_S16NE,AE_FMT_S32LE,AE_FMT_S16LE,AE_FMT_FLOATP,AE_FMT_S32NEP,AE_FMT_S16NEP,AE_FMT_RAW
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_streamTypes     : STREAM_TYPE_AC3,STREAM_TYPE_EAC3,STREAM_TYPE_DTSHD_CORE,STREAM_TYPE_DTS_2048,STREAM_TYPE_DTS_1024,STREAM_TYPE_DTS_512
2021-02-27 10:58:32.803 T:1884287200  NOTICE:     Device 2
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_deviceName      : Analogue
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_displayName     : Analogue
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_displayNameExtra:
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_deviceType      : AE_DEVTYPE_PCM
2021-02-27 10:58:32.803 T:1884287200  NOTICE:         m_channels        : FL, FR
2021-02-27 10:58:32.804 T:1884287200  NOTICE:         m_sampleRates     : 48000
2021-02-27 10:58:32.804 T:1884287200  NOTICE:         m_dataFormats     : AE_FMT_FLOAT,AE_FMT_S32LE,AE_FMT_S16LE,AE_FMT_FLOATP,AE_FMT_S32NEP,AE_FMT_S16NEP
2021-02-27 10:58:32.804 T:1884287200  NOTICE:         m_streamTypes     : No passthrough capabilities
2021-02-27 10:58:32.804 T:1884287200  NOTICE:     Device 3
2021-02-27 10:58:32.804 T:1884287200  NOTICE:         m_deviceName      : Both
2021-02-27 10:58:32.805 T:1884287200  NOTICE:         m_displayName     : HDMI and Analogue
2021-02-27 10:58:32.805 T:1884287200  NOTICE:         m_displayNameExtra:
2021-02-27 10:58:32.805 T:1884287200  NOTICE:         m_deviceType      : AE_DEVTYPE_PCM
2021-02-27 10:58:32.805 T:1884287200  NOTICE:         m_channels        : FL, FR
2021-02-27 10:58:32.805 T:1884287200  NOTICE:         m_sampleRates     : 48000
2021-02-27 10:58:32.805 T:1884287200  NOTICE:         m_dataFormats     : AE_FMT_FLOAT,AE_FMT_S32LE,AE_FMT_S16LE,AE_FMT_FLOATP,AE_FMT_S32NEP,AE_FMT_S16NEP
2021-02-27 10:58:32.806 T:1884287200  NOTICE:         m_streamTypes     : No passthrough capabilities
2021-02-27 10:58:32.808 T:1875894496    INFO: CActiveAESink::OpenSink - initialize sink
2021-02-27 10:58:32.809 T:1875894496   DEBUG: CActiveAESink::OpenSink - trying to open device PI:HDMI
2021-02-27 10:58:32.810 T:1875894496   DEBUG: CAESinkPi:Initialize Format:15 Channels:2 Samplerate:44100 framesize:8 bufsize:17640 bytes/s=352800.00 dest=PI:HDMI
2021-02-27 10:58:32.810 T:1875894496   DEBUG: CAESinkPi:SetAudioProps hdmi_stream_channels 0 hdmi_channel_map 00000008
2021-02-27 10:58:32.812 T:1875894496   DEBUG: COMXCoreComponent::Initialize OMX.broadcom.audio_render input port 100 output port 100 m_handle 0x6e94eae0
2021-02-27 10:58:32.815 T:1875894496   DEBUG: COMXCoreComponent::AllocInputBuffers component(OMX.broadcom.audio_render) - port(100), nBufferCountMin(1), nBufferCountActual(2), nBufferSize(17648), nBufferAlignment(16)
2021-02-27 10:58:32.816 T:1875894496   DEBUG: CActiveAESink::OpenSink - SinkPi Initialized:
2021-02-27 10:58:32.816 T:1875894496   DEBUG:   Output Device : HDMI
2021-02-27 10:58:32.816 T:1875894496   DEBUG:   Sample Rate   : 44100
2021-02-27 10:58:32.816 T:1875894496   DEBUG:   Sample Format : AE_FMT_FLOAT
2021-02-27 10:58:32.816 T:1875894496   DEBUG:   Channel Count : 2
2021-02-27 10:58:32.816 T:1875894496   DEBUG:   Channel Layout: FL, FR
2021-02-27 10:58:32.816 T:1875894496   DEBUG:   Frames        : 2205
2021-02-27 10:58:32.816 T:1875894496   DEBUG:   Frame Size    : 8
2021-02-27 10:58:32.821 T:1884287200   DEBUG: CActiveAE::ClearDiscardedBuffers - buffer pool deleted
2021-02-27 10:58:37.620 T:1915720624   ERROR: ActiveAE::Resume - failed to init
2021-02-27 10:58:37.621 T:1915720624   FATAL: OnApplicationMessage: Failed to restart AudioEngine after return from external player
2021-02-27 10:58:42.363 T:1763700960   DEBUG: Thread JobWorker 1763700960 terminating (autodelete)
2021-02-27 10:58:42.363 T:1536676064   DEBUG: Thread JobWorker 1536676064 terminating (autodelete)
2021-02-27 10:58:42.364 T:1755308256   DEBUG: Thread JobWorker 1755308256 terminating (autodelete)
2021-02-27 10:58:42.440 T:1787318496   DEBUG: Thread JobWorker 1787318496 terminating (autodelete)

I also created a python wrapper so I could instead call RunScript(/usr/local/bin/toggle-tv-power.py), but that also failed.

2021-02-27 11:11:16.216 T:1915646896   DEBUG: Keyboard: scancode: 0xf0, sym: 0x0000, unicode: 0x0000, modifier: 0x0
2021-02-27 11:11:16.216 T:1565516000    INFO: initializing python engine.
2021-02-27 11:11:16.217 T:1565516000   DEBUG: CPythonInvoker(13, /usr/local/bin/toggle-tv-power.py): start processing
2021-02-27 11:11:16.517 T:1565516000   DEBUG: -->Python Interpreter Initialized<--
2021-02-27 11:11:16.518 T:1565516000   DEBUG: CPythonInvoker(13, /usr/local/bin/toggle-tv-power.py): the source file to load is "/usr/local/bin/toggle-tv-power.py"
2021-02-27 11:11:16.518 T:1565516000 WARNING: CPythonInvoker(13): Script invoked without an addon. Adding all addon modules installed to python path as fallback. This behaviour will be removed in future version.
2021-02-27 11:11:16.535 T:1565516000   DEBUG: CPythonInvoker(13, /usr/local/bin/toggle-tv-power.py): setting the Python path to /usr/local/bin:<redacted>
2021-02-27 11:11:16.535 T:1565516000   DEBUG: CPythonInvoker(13, /usr/local/bin/toggle-tv-power.py): entering source directory /usr/local/bin
2021-02-27 11:11:16.807 T:1565516000    INFO: CPythonInvoker(13, /usr/local/bin/toggle-tv-power.py): script successfully run
2021-02-27 11:11:16.807 T:1565516000   DEBUG: onExecutionDone(13, /usr/local/bin/toggle-tv-power.py)
2021-02-27 11:11:16.816 T:1565516000    INFO: Python interpreter stopped
2021-02-27 11:11:16.817 T:1565516000   DEBUG: Thread LanguageInvoker 1565516000 terminating

I also tried mapping CECToggleState, but this failed too.

2021-02-27 11:32:40.206 T:1916404656   DEBUG: Keyboard: scancode: 0xf0, sym: 0x0000, unicode: 0x0000, modifier: 0x0
2021-02-27 11:32:40.206 T:1916404656   DEBUG: GetActionCode: Trying Hardy keycode for 0xf200
2021-02-27 11:32:40.207 T:1916404656   DEBUG: HandleKey: action CECToggleState [122], toggling state of playing device
2021-02-27 11:32:40.207 T:1916404656   DEBUG: Keyboard: scancode: 0xf0, sym: 0x0000, unicode: 0x0000, modifier: 0x0

How can I call this script from the keymap?

EDIT: I also tried assigning a test script date >> /tmp/test to the same key, and this works fine.

I don’t think your going to get away with making a call to cec-client unless your not planning on using any CEC features in Kodi as I’m pretty sure that will break it in Kodi until restart. The CECToggleState does not seem to be universally supported. I had previously tried it on several of the TV’s in my house and it didn’t work with any of them. You would probably be best to use CECActivateSource and CECStandby to perform this function instead. For these to actually do anything you have to go into Kodi’s CEC settings and set the ‘devices to power on/off during startup/shutdown’ and maybe the “switch sources to this device on startup”. If you wanted to use this with a script then you can use the kodi-send app (ie kodi-send -a "CECActivateSource").

1 Like

On Raspberry Pi, the CEC bus is shared; so multiple access is theoretically possible. But the next kernel and version of Kodi will use libCEC with CEC implemented via the upstream CEC kernel framework. I do not know if this access is shared.

I don’t like the idea of two applications using CEC if they are not in sync. So as @darwindesign suggests – things should go through Kodi which will definitely have a handle of CEC when it is running.

So OP might get away with it, but this might be broken again soon…

1 Like

Thanks all. I’m not 100% sure if I understand, but are you both basically saying that I shouldn’t attempt to call a third-party CEC script via Kodi? (FWIW I don’t intend on using any other CEC features apart from toggling my TV’s power.) Instead, should I use the integrated CEC support, i.e. CECStandby, CECActivateSource, and CECToggleState?

In any case, I tested using the CLI. kodi-send -a 'CECActivateSource' worked fine, but CECStandby failed, and CECToggleState failed for both on and off. (For the record, echo 'on 0' | cec-client -s and echo 'standby 0' | cec-client -s work fine.)

I looked at Kodi’s settings, and I enabled “Switch sources to this device on startup”, “Devices to power on/off during startup/shutdown”. Now both CECActivateSource and CECStandby work! CECToggleState also works, but only for turning the TV off, not on.

Since CECToggleState doesn’t work, then would I need to assign two buttons to on and off? There’s no other real solution?

Not that I found when I was looking into it, at least not using Kodi’s keymaps. This is of course assuming you don’t have a remote that has long-press support in which case you could assign the two functions to long/short press of the same button. Maybe you could figure out a way to script it otherwise to alternate which command gets sent. That kind of thing is outside of my wheelhouse.

Another option may be to keymap to just the home Window instead of global. You would still need two keys but they are only taken up in that one window leaving them available for other function in other windows. This is what I did on the OSMC remote. The home button on the remote in most windows acts as a go to the home screen button, but when on the home screen it is a CECactivatesource on the short press, and CECstandby on the longpress. You can see that keymap [here]

I don’t think the issue with the toggle is on the mediaplayer side. AFAIKT the command gets sent out of the CEC bus. The thing about CEC is that devices get to choose what they do with any given command they receive, including nothing.

1 Like

Thanks again @darwindesign. They all sound like reasonable workarounds.

Another option I just thought of might be to map the physical button to CECActivateSource, and create an item on the Kodi home screen (perhaps power menu?) to CECStandby. A bit fiddly, but at least I don’t “waste” a second button.

If you don’t mind modding your skin I don’t see why that wouldn’t work. The idea of mapping to the home window instead of global is to not “waste” a button as you normally would have some buttons that don’t serve a good purpose on that screen and are suitable for double duty. I suppose the details would depend on the remote that your using. What remote are you using and how it is connected?

I have a Minix NEO A2 Lite remote, which is wireless. I just tested it, and unfortunately longpress doesn’t appear to work.

I do like your idea of mapping to the home window, but thinking about it more, I’ve re-assessed and decided to map the unused G and the almost-unused N to power off/on. Since those keys aren’t really used anyway, I’ll just keep them as global shortcuts. Thanks again for all your input!

For the record, I tested another way to use a single key to “toggle” the power state. Because I couldn’t find a way to access the current state without using cec-client, which breaks kodi’s built-in CEC commands, I just blindly alternate between commands. Not really ideal, but perhaps useful to some.

#!/usr/bin/env bash

if [ -f /tmp/tv_is_on ]; then
  kodi-send -a 'CECStandby'
  rm /tmp/tv_is_on
else
  kodi-send -a 'CECActivateSource'
  touch /tmp/tv_is_on
fi
1 Like

Hello,
I tried to achieve exactly the same, and after a while this is the solution I chose: I mapped a key to activate the screensaver, which is configured to turn off the tv via CEC. Screensaver is also set to trigger after a few minutes, turning off the TV.

To turn on, any action that wakes up Kodi deactivates the screen saver and sends a CEC « on » signal to the TV.

With this config I use only one key (for « off ») and any other key will turn the TV on when needed.

I’ve been running with this for a few years now and I’m quite happy with it as I have no other use of the screensaver functionnality…

2 Likes

I’m not sure how I overlooked this before but the button you were playing with isn’t getting picked up correctly by Kodi so that may factor in. Basically any key that Kodi doesn’t have an internal mapping for gets mapped to a single (I don’t know what it would be called) and I don’t think that is able to do the longpress thing. I don’t claim to actually understand this but I think it is something like anything with a key id over 256 or something and it affects high F-keys, dead keys (an issue when set to non-English kb layouts), etc. Any key that gets picked up this way will share the same keymapping so you might get away with this for one button, but any more than that you would need to fix it proper by remapping the key in the OS using udev to something Kodi understands.

To check for long-press support hold down the OK/select button with debug on and see if it recorded the long-press on that key.

Sorry for the delay in replying… apparently my account wasn’t sending email notifications :confounded:

@Obilolo this is great! I also don’t use the screensaver for anything useful, so this is ideal. Thank you! My Kodi was actually already set to wake the TV up when the screensaver wakes, but this combination is perfect.

@darwindesign Thank you again. Yes, you are totally correct. OK/select works with a long press.

HandleKey: return (0xf00d) pressed, action is Select
HandleKey: long-return (0x100f00d) pressed, action is ContextMenu

With this functionality, it would have been perfect to turn off the TV (aka ActivateScreensaver) with a long-press of one of the front buttons of the remote, but most did not have this functionality unfortunately. All of the following buttons just sent repeating keystrokes.

HandleKey: browser_home (0xf0b6) pressed, action is ActivateWindow(Home)
HandleKey: escape (0xf01b) pressed, action is back
HandleKey: f1 (0xf090) pressed, action is stop
HandleKey: volume_mute (0xf0b7) pressed, action is Mute
1 Like

That is a very interesting finding. In my reading on this subject I don’t recall a situation where there was only partial long-press support to this extent. I’m rather clueless on why this would be the case.

Thanks for reporting back.

1 Like

I’ve been using the solution proposed above by @Obilolo, which works very well. When the TV is off, any action wakes up Kodi, deactivates the screensaver, and the TV turns on.

However, I just realised that my nightly backups are causing the TV to turn on. This involves running xbmc-send -a "UpdateLibrary(video)", which wakes the TV. I like the solution above otherwise, so is there a way to temporarily prevent Kodi from sending CEC « on » when the screensaver stops? If there’s a CLI way I could just pop it in the script. Any other suggestions are welcome!