[Guide] Wake and Shutdown CoreELEC (Kodi) with a Bluetooth Remote

Hey Guys!

If you’re having the same issue as me (the box is hidden) and you’re having trouble waking it up with the help of an IR remote and would prefer to do so with Bluetooth, here is a short guide and script that I’ve made. I’m using a Ugoos UR02 remote with a Ugoos AM8 Pro.

Note: You will need to adjust the values for the event number and buttons, as these vary depending on your setup and box.

  1. Enable SSH access and log in to your box.
  2. Create the file /storage/.config/hwdb.d/remote_remap.hwdb In my case, it looks like this:
evdev:input:b0005v0508p1980*
 KEYBOARD_KEY_c0030=f7

c0030 - In my case it’s power on/off button
f7 - I remap power on/off to unsused F7 button

Your remote you can find here CoreELEC/packages/sysutils/systemd/hwdb.d/70-local-keyboard.hwdb at 72dd552d7c6bbbf49de8f461827db5ddffe0bac8 · CoreELEC/CoreELEC · GitHub

  1. Create a file called gen.xml in the /storage/.kodi/userdata/keymaps folder. Here we’re attaching a script to be executed when a button is pressed.
<keymap>
  <global>
    <keyboard>
      <f7>System.Exec(/storage/.config/kodi_remote_monitor.sh)</f7>
    </keyboard>
  </global>
</keymap>

/storage/.config/kodi_remote_monitor.sh - is a path to script
f7 - button to which we’ve remapped in (2)

  1. Create /storage/.config/kodi_remote_monitor.sh (it stop/start kodi process depending on it’s state. Also if you configure CEC in CoreELEC settings, it can turn of/on your TV, AVR and so on):
#!/bin/sh

# Path to event device
EVENT_DEVICE="/dev/input/event6"

# Specific MSC_SCAN value to monitor
TARGET_SCAN_CODE="c0030"

# PID file for evtest process
EVTEST_PID_FILE="/tmp/evtest_event.pid"

#EVTEST FILE LOCATION
EVTEST="/storage/.kodi/addons/virtual.system-tools/bin/evtest"

# Debounce time in seconds to avoid multiple triggers
DEBOUNCE_TIME=2
LAST_TRIGGER_FILE="/tmp/kodi_last_trigger"

# Function to check if Kodi is running
is_kodi_running() {
    pgrep kodi.bin > /dev/null 2>&1
}

# Function to stop Kodi
stop_kodi() {
    if is_kodi_running; then
        echo "[INFO] Stopping Kodi..."
        systemctl stop kodi
    else
        echo "[INFO] Kodi is already stopped."
    fi
}

# Function to start Kodi
start_kodi() {
    if ! is_kodi_running; then
        echo "[INFO] Starting Kodi..."
        systemctl start kodi
    else
        echo "[INFO] Kodi is already running."
    fi
}

# Function to kill evtest if running
kill_evtest() {
    if [ -f "$EVTEST_PID_FILE" ]; then
        EVTEST_PID=$(cat "$EVTEST_PID_FILE")
        if kill -0 "$EVTEST_PID" 2>/dev/null; then
            echo "[INFO] Killing evtest (PID: $EVTEST_PID)"
            kill "$EVTEST_PID"
        fi
        rm -f "$EVTEST_PID_FILE"
    fi
}

# Function to check if trigger is allowed (debounce)
can_trigger() {
    if [ -f "$LAST_TRIGGER_FILE" ]; then
        LAST_TIME=$(cat "$LAST_TRIGGER_FILE")
        CURRENT_TIME=$(date +%s)
        if [ $((CURRENT_TIME - LAST_TIME)) -lt $DEBOUNCE_TIME ]; then
            return 1  # Too soon, debounce
        fi
    fi
    echo $(date +%s) > "$LAST_TRIGGER_FILE"
    return 0  # OK to trigger
}

# Function to monitor event6 for specific scan code press (background mode)
monitor_event_device() {
    echo "[INFO] Waiting for event device $EVENT_DEVICE to become available..."

    # Wait for event device to be available
    while [ ! -e "$EVENT_DEVICE" ]; do
        echo "[INFO] Event device $EVENT_DEVICE not found, waiting..."
        sleep 3
    done

    echo "[INFO] Monitoring $EVENT_DEVICE for scan code $TARGET_SCAN_CODE press..."

    # Start evtest in background and save PID
    "$EVTEST" "$EVENT_DEVICE" | while read -r line; do
        # Look for the specific MSC_SCAN event
        if echo "$line" | grep -q "MSC_SCAN.*value $TARGET_SCAN_CODE"; then
            # Read the next line to check for key press
            if read -r key_line && echo "$key_line" | grep -q "EV_KEY.*value 1"; then
                KEY_CODE=$(echo "$key_line" | sed -n 's/.*code \([0-9]*\) (.*/\1/p')
                echo "[INFO] Target scan code $TARGET_SCAN_CODE pressed, triggering KEY_$KEY_CODE"

                # Check if we can trigger (debounce protection)
                if can_trigger; then
                    echo "[INFO] Starting Kodi via remote button press."
                    start_kodi
                else
                    echo "[INFO] Ignoring button press (debounce protection)."
                fi
            fi
        fi
    done &

    # Save background process PID
    echo $! > "$EVTEST_PID_FILE"
}

# Function to handle keymap execution (stop Kodi when called from keymap)
handle_keymap_execution() {
    echo "[INFO] Script called from keymap - stopping Kodi"
    stop_kodi
    exit 0
}

# Main function - determine mode of operation
main() {
    # Check if script was called with arguments (from keymap)
    if [ $# -eq 0 ]; then
        # Called from keymap - stop Kodi
        handle_keymap_execution
    else
        # Background monitoring mode
        echo "[INFO] Kodi remote monitor started in background mode."
        echo "[INFO] Monitoring for scan code $TARGET_SCAN_CODE only."

        while true; do
            if is_kodi_running; then
                # Ensure evtest is not running
                kill_evtest
            else
                # Start monitoring if not already
                if [ ! -f "$EVTEST_PID_FILE" ]; then
                    monitor_event_device
                fi
            fi

            sleep 2
        done
    fi
}

# Handle script termination
trap 'kill_evtest; exit' INT TERM

# Run main function
main "$@"

EVENT_DEVICE - Adjust, it might be different one to you, in my case event6 is my UR02 remote. You can find your remote by executing cat /proc/bus/input/devices, it will output all your connected devices to the CoreELEC. In H: Handlers=..... event* will be your event number
TARGET_SCAN_CODE - Button which we’ve remapped in (2)
EVTEST - Path to evtest file

  1. Create /storage/.config/system.d/kodi-remote-monitor.service:
[Unit]
Description=Kodi Remote Monitor
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/storage/.config/kodi_remote_monitor.sh 1
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

1 - There is a flag here which is necessary for the script to work correctly.

  1. Run the command: systemctl enable kodi-remote-monitor
  2. Run the command: chmod +x /storage/.config/kodi_remote_monitor.sh
  3. Run the command: systemd-hwdb update
  4. Run the command: udevadm trigger -s input
  5. In CoreELEC, install system tools to make the evtest tool available
  6. Reboot your CoreELEC
  7. You can monitor the script output using the command journalctl -u kodi-remote-monitor.service -f
2 Likes

Forgive me if I’m wrong as I’m no Linux expert…

But doesn’t that just stop and restart the Kodi service.

CoreELEC base OS and the physical hardware is still powered on and running.

You’re right, it’s all about kodi. Yes, the box physically will be on, but they are designed to be on 24/7 and i wouldn’t say that it will consume a lot of power, as the main service will be off.

P.S I might need to adjust title tho, to make it clear.

My testing here on an odroid c5 show 1.6-2 watts whether Kodi was running or not. Plus there still was the CE splash so the display doesn’t go off. Of course this can depend on the addons you run and not Kodi itself.

Yep, that’s what confused me, your title mentions shutdown CoreELEC.

As emveepee says, if the box is still powered on then really what’s the point of stopping and restarting Kodi :confused:

You will be able to turn off/on your devices :), anyway if you leave it in such state, it will not eat much, it just gives you possibility to mange devices if your box is somewhere hidden and you do not have option to use IR like me. I just shared script and wrote a guide, it might will be need for somebody as there are quite a lot of users which were asking for such :smiley:

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.