Skip to content

Instantly share code, notes, and snippets.

@greyshi
Forked from cmer/waketv.lua
Last active February 15, 2023 02:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save greyshi/89d06eb52b1ac19a5e09ef6ffafa1cd5 to your computer and use it in GitHub Desktop.
Save greyshi/89d06eb52b1ac19a5e09ef6ffafa1cd5 to your computer and use it in GitHub Desktop.
Wake TV when MacOS wakes from sleep (Hammerspoon)
local tv_input = "HDMI_2" -- Input to which your Mac is connected
local mac_address = "80:5B:65:6D:AF:D4"
local switch_input_on_wake = true -- Switch input to Mac when waking the TV
local prevent_sleep_when_using_other_input = true -- Prevent sleep when using other input (ie: watching TV)
local debug = false -- If you run into issues, set to true to enable debug messages
-- You likely will not need to change anything below this line
local tv_name = "MyTV" -- Name of your TV, set when you run `lgtv auth`
local connected_tv_identifiers = {"LG TV", "LG TV SSCR2"} -- Used to identify the TV when it's connected to this computer
local screen_off_command = "off" -- use "screenOff" to keep the TV on, but turn off the screen.
local lgtv_path = "/opt/lgtv-venv/bin/lgtv" -- Full path to lgtv executable
local lgtv_cmd = lgtv_path.." "..tv_name
local app_id = "com.webos.app."..tv_input:lower():gsub("_", "")
local lgtv_ssl = true -- Required for firmware 03.30.16 and up. Also requires LGWebOSRemote version 2023-01-27 or newer.
function lgtv_current_app_id()
local foreground_app_info = exec_command("getForegroundAppInfo")
foreground_app_info = string.match(foreground_app_info, '^%b{}')
foreground_app_info = hs.json.decode(foreground_app_info)
return foreground_app_info["payload"]["appId"]
end
function tv_is_connected()
for i, v in ipairs(connected_tv_identifiers) do
if hs.screen.find(v) ~= nil then
return true
end
end
return false
end
function dump_table(o)
if type(o) == 'table' then
local s = '{ '
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"'..k..'"' end
s = s .. '['..k..'] = ' .. dump_table(v) .. ','
end
return s .. '} '
else
return tostring(o)
end
end
function exec_command(command)
if lgtv_ssl then
command = command.." ssl"
end
command = lgtv_cmd.." "..command
if debug then
print("Executing command: "..command)
end
return hs.execute(command)
end
if debug then
print ("TV name: "..tv_name)
print ("TV input: "..tv_input)
print ("LGTV path: "..lgtv_path)
print ("LGTV command: "..lgtv_cmd)
print ("SSL: "..tostring(lgtv_ssl))
print ("App ID: "..app_id)
print (exec_command("swInfo"))
print (exec_command("getForegroundAppInfo"))
print("Connected screens: "..dump_table(hs.screen.allScreens()))
print("TV is connected? "..tostring(tv_is_connected()))
end
watcher = hs.caffeinate.watcher.new(function(eventType)
if debug then print("Received event: "..eventType) end
if not tv_is_connected() then
if debug then print("TV is not connected. Skipping.") end
return
end
if (eventType == hs.caffeinate.watcher.screensDidWake or
eventType == hs.caffeinate.watcher.systemDidWake or
eventType == hs.caffeinate.watcher.sessionDidBecomeActive or
eventType == hs.caffeinate.watcher.screensDidUnlock) then
exec_command("on") -- wake on lan
exec_command("screenOn") -- turn on screen
hs.execute("/opt/homebrew/bin/wakeonlan "..mac_address)
if debug then print("TV was turned on") end
if lgtv_current_app_id() ~= app_id and switch_input_on_wake then
exec_command("startApp "..app_id)
if debug then print("TV input switched to "..app_id) end
end
end
if (eventType == hs.caffeinate.watcher.screensDidSleep or
eventType == hs.caffeinate.watcher.systemWillPowerOff) then
if lgtv_current_app_id() ~= app_id and prevent_sleep_when_using_other_input then
if debug then print("TV is currently on another input ("..current_app_id.."). Skipping powering off.") end
return
end
-- This puts the TV in standby mode.
-- For true "power off" use `off` instead of `screenOff`.
exec_command(screen_off_command)
if debug then print("TV screen was turned off with command `"..screen_off_command.."`.") end
end
end)
watcher:start()
@greyshi
Copy link
Author

greyshi commented Jan 19, 2023

This extends the original script by @cmer so that it:

  1. Turns the TV off when the system sleeps or powers off
  2. Switches the TV input to the value you have specified in the script's tv_input variable on wake. This is useful for when the last time you used the TV you were on a different input than the one your computer is connected to

You'll need to install the required dependencies for this to work, and @tonycassara has documented those steps here.

@tonycassara
Copy link

tonycassara commented Jan 19, 2023

Wait you're setting the input before turning on the TV? Does that work? Maybe in "Always Ready" mode but I wonder if it does if it's not in that mode...

Another thought: I don't have time currently to test but I suspect that wakeonlan works regardless of Always Ready and the lgtv MyTV on works solely in Always Ready mode.

@greyshi
Copy link
Author

greyshi commented Jan 19, 2023

Nice catch on that. I had an older version of this saved in the gist from when I was testing things out trying to find the culprit of the screen turning on right after powering off. Just updated it to properly put the wakeonlan as the first command.

I actually don't have Always Ready on, and I'm able to use both wakeonlan as well as lgtv MyTV on to turn the TV on from powered on state. Seems like lots of commands will turn the TV on, including the lgtv MyTV off command surprisingly.

@tonycassara
Copy link

Interesting so the TV is always on in some way, makes sense with the need for the IR receiver to work, there must be other parts also on including the part that lets you connect via CLI!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment