I recently upgraded my primary monitor to an LG C3 42″ TV. Not only is it a stunning OLED display, but it also allows me to automate the manual input switching I’ve been doing to use my VM for latency-sensitive1 tasks such as gaming, Altium Layout, etc.
The VM runs in a KVM container with a physical GPU passed through, meaning I use the actual graphics card’s output when viewing my Windows VMs. Previously, I had to manually switch inputs on my primary monitor, which was functional but tedious.
I’d considered building a project to automate HDMI or DisplayPort switching from a computer, but the addition of a Smart TV to my setup made it possible to implement this entirely in software. Smart TVs don’t recognize standby signals the same way monitors do, so this setup also automates replicating that functionality.
Implementation Overview
Here’s the condensed version of how I implemented the automation using my existing Home Assistant setup:
- Power off the TV
- Power on the TV (via Wake-on-LAN)
- Switch inputs
Since the LG Home Assistant integration doesn’t natively support powering on the TV, I added a wake_on_lan
switch in Home Assistant. This triggers a WoL packet to wake the TV. With the TV connected via Ethernet and assigned a static IP, the setup has been surprisingly reliable. Scripts interacting with the Home Assistant API manage all these functions seamlessly.

Home Assistant configuration.yaml
switch:
- platform: wake_on_lan
name: Desk TV Wake on LAN
mac: f8:01:xx:xx:xx:xx # Fill in your MAC
host: 192.168.x.x # Fill in your IP
monitor_sync.sh
This script is ran in the background via a systemd function to regularly check if the screensaver has been activated by the method I use to invoke i3lock
!/bin/bash
# Configuration
HOME_ASSISTANT_URL="{insert your home assistant URL}"
TOKEN_FILE="$(dirname "$0")/.token"
TV_ENTITY_ID="media_player.desk_tv"
WOL_ENTITY_ID="switch.desk_tv_wake_on_lan"
INPUT_BOOLEAN_ID="input_boolean.desk_monitors_on"
LOG_FILE="monitor_sync.log"
NOTIFY_SERVICE="notify.mobile_app_your_device" # Replace with your actual notify service
# Define your main monitors (excluding TV)
MAIN_MONITORS=("DP-2" "DP-4") # Replace with your actual monitor names
# Function to check if screensaver is active using xssstate
is_screensaver_active() {
SCREEN_STATE=$(xssstate -s)
if [ "$SCREEN_STATE" == "on" ]; then
return 0 # Screensaver is active
else
return 1 # Screensaver is not active
fi
}
# Check if the token file exists
if [ ! -f "$TOKEN_FILE" ]; then
echo "$(date): Error: Access token file '.token' not found in $(dirname "$0"). Please create it with your Home Assistant long-lived access tokeI've recently changed primary monitors to an LG C3 42" in TV, which, while in addition to being an beautiful OLED, also allows me to automate some of the manual switching I've been doing on my primary monitor to enable me to use my VM for latency-sensitiven." >> "$LOG_FILE"
echo "Error: Access token file '.token' not found in $(dirname "$0"). Please create it with your Home Assistant long-lived access token."
exit 1
fi
# Source the token
source "$TOKEN_FILE"
# Initialize previous state
PREV_STATE="unknown"
while true; do
if is_screensaver_active; then
CURRENT_STATE="off"
else
CURRENT_STATE="on"
fi
if [ "$CURRENT_STATE" != "$PREV_STATE" ]; then
echo "$(date): Monitor state changed to $CURRENT_STATE" >> "$LOG_FILE"
if [ "$CURRENT_STATE" == "on" ]; then
# Turn TV on
/home/nick/code/homeassistant_scripts/desk_tv_control/turn_tv_on.sh
echo "$(date): Sent turn_on command to WOL switch." >> "$LOG_FILE"
# Update input_boolean to on
curl -X POST \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "'"$INPUT_BOOLEAN_ID"'"}' \
"$HOME_ASSISTANT_URL/api/services/input_boolean/turn_on"
echo "$(date): Set $INPUT_BOOLEAN_ID to on." >> "$LOG_FILE"
# Send Notification (Optional)
# Uncomment the following lines if you have a notify service configured
# curl -X POST \
# -H "Authorization: Bearer $ACCESS_TOKEN" \
# -H "Content-Type: application/json" \
# -d '{"title": "Monitors On", "message": "Main monitors are on. TV has been turned on."}' \
# "$HOME_ASSISTANT_URL/api/services/$NOTIFY_SERVICE"
# echo "$(date): Sent notification for monitors on." >> "$LOG_FILE"
else
# Turn TV off
/home/nick/code/homeassistant_scripts/desk_tv_control/turn_tv_off.sh
echo "$(date): Sent turn_off command to TV." >> "$LOG_FILE"
# Update input_boolean to off
curl -X POST \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id": "'"$INPUT_BOOLEAN_ID"'"}' \
"$HOME_ASSISTANT_URL/api/services/input_boolean/turn_off"
echo "$(date): Set $INPUT_BOOLEAN_ID to off." >> "$LOG_FILE"
# Send Notification (Optional)
# Uncomment the following lines if you have a notify service configured
# curl -X POST \
# -H "Authorization: Bearer $ACCESS_TOKEN" \
# -H "Content-Type: application/json" \
# -d '{"title": "Monitors Off", "message": "Main monitors are off. TV has been turned off."}' \
# "$HOME_ASSISTANT_URL/api/services/$NOTIFY_SERVICE"
# echo "$(date): Sent notification for monitors off." >> "$LOG_FILE"
fi
PREV_STATE="$CURRENT_STATE"
fi
# Wait before checking again
sleep 5 # Check every 10 seconds
done
Systemd Configuration
Mainly putting this here as a reference.
[Unit]
Description=Monitor Synchronization Service
After=network.target
[Service]
Type=simple
ExecStart=/home/nick/code/homeassistant_scripts/desk_tv_control/monitor_sync.sh
Restart=always
RestartSec=5
User=nick
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/nick/.Xauthority
[Install]
WantedBy=multi-user.target