[RELEASE] LG webOS TV Driver (Oct 2024)

Sorry for the delay, so I've tested using an phone app (LG Remote IOS) and the TV was picked up immediately. Tried again with this driver and still no go but the log messages have changed. My Version of the TV software is 4.50.90 and on webOS TV Version 5.5.0-19

Only thing that changed was that I changed the language of the menus on the TV from french to english just to see if that had anything to do with it (shouldn't but now I'm thinking it might)

From these log messages, looks like the connection is being made but it's not receiving what it's expecting (TV or HE). I don't really know much about websockets in HE and don't really have time to learn it and see if I can have more detailed messages in the Logs with this issue.

just curious... what kind of router do you use. do you have any fancy network settings? is MDNS turned on or off? are you running any VPNs? These are all things I would consider. it looks like it is trying to connect (like you said) but then something is bouncing it off. have you checked also if your TV has a solid uninterrupted connection to your home network? some routers have a minimum signal or usage and will boot a tv off a network if there not being used or have a weak wireless signal (i.e. you use an Apple TV or google tv and have your tv connected to the internet just for the remote Hubitat control features)

final thought. have you tried ethernet?

can I ask what your use case is for current state status updating with remote control?

My LG TVs only ever get turned on and off by AppleTV4K remote and therefore by CEC control over HDMI.

The major use case for Hubitat knowing the TV power state for me is to control my living room lighting, if im up late watching TV, I dont want the lights to go off at 11pm as usual. Right now I use a power-reporting zigbee outlet to detect the TV power state, which works ok, but it feels kind of primitive when I should be able to get the state from an API.

Would be awesome if you could make your driver keep real-time power state.

I’ll work on it and keep you posted :slight_smile:

1 Like

I have the same experience as you. Same WebOS version, works with mobile, no fancy router or settings, etc. Internet works fine on the TV and with everything else in the house. Same "unexpected end of stream" message repeated over and over.

No nothing special, regular home TPLink router, no VPNs, everything is working normally, solid WiFi signal, everything we do with this TV is by WiFi, no cable, no cable box, everything we watch is over the internet and local PLEX server.

I did try connecting with ethernet cable and using wired MAC and IP and still same results.

I'm on v 4.50.90 of LG webOS firmware, in case that helps.

I'm using ethernet to a Unifi Dream Machine via Unifi switch. Pretty vanilla really. I also have one LGTV via wifi and that behaves the same. We don't have cable / cable box either. We are strictly streaming services (hate cable companies!) so have to keep the internet connection open to the TVs.

So wish we could get this to work. @mrferreira89 if there's any testing we can do to help get to the bottom of it, I'm happy to roll up my sleeves and dig in!

1 Like

Just need to get through this week at work. It’s busy season. And next week I promise to take a look.

Send over a bunch of logs if you haven’t already!

2 Likes

Hello,

To everyone having issues, I’d like to share some (potential) insight.

  • on your router, port 3,000 must be open.
  • It’s possible your paring key failed. Delete the virtual device and start over
  • power cycle your tv to restart the websocket services
  • make sure you’re not confusing 0 for O when entering MAC address (sorry I know this might be annoying to read haha)
  • try adjusting websocket connection for ssl:

def connect() {
if (debugLogging) log.debug "Connecting to TV at ${tvIp}"
try {
interfaces.webSocket.close()
} catch (e) {
if (debugLogging) log.debug "No existing WebSocket to close."
}
interfaces.webSocket.connect("wss://${tvIp}:3001/",
pingInterval: 30,
headers: ["Content-Type": "application/json"],
ignoreSSLIssues: true // Add this if necessary
)
}

  • finally, some LG TVs especially older models, might not support the websocket protocol on port 3000 and might require ssl/TLS encryption

Solution: verify your tv supports this. If not, use an adjusted url in your code:

interfaces.webSocket.connect("wss://${tvIp}:3001/", ...)

And reference above code adjustment

I’m not sure what level each of you are at. I hope this proves useful for some. My hope is that we can work together to come to a solution and release two versions.

  1. For webos TVs that support socket 3000, and …
  2. models that do not

I’ll post the code for models that don’t support socket 3000 and require ssl so those less technical can simply copy and paste

Looking forward to feedback!

1 Like

Code for older models:

/**

  • LG webOS TV Driver for Hubitat (Adjusted for Older Models)
  • Author: Echistas
  • Date: 2023-10-21
  • This driver allows Hubitat to control an LG webOS TV.
  • Adjusted to support older LG TV models using secure WebSocket connections.
    */

import groovy.json.JsonSlurper
import groovy.json.JsonBuilder

metadata {
definition(name: "LG webOS TV (Older Models)", namespace: "Echistas", author: "Echistas") {
capability "Switch"
capability "AudioVolume"
capability "Refresh"
capability "Actuator"
capability "Media Input Source"
capability "Initialize"

    attribute "channel", "string"
    attribute "mediaInputSource", "string"
    attribute "mute", "string"
    attribute "volume", "number"

    // Explicitly declare the initialize command
    command "initialize"
    command "launchApp", [[name: "App Id*", type: "STRING", description: "App ID to launch"]]
    command "sendButton", [[name: "Button Name*", type: "STRING", description: "Button name to send"]]
    command "channelUp"
    command "channelDown"
    command "mute"
    command "unmute"
    command "volumeUp"
    command "volumeDown"
}

preferences {
    input name: "tvIp", type: "text", title: "TV IP Address", description: "Enter your TV's IP address", defaultValue: "192.168.1.1", required: true
    input name: "tvMac", type: "text", title: "TV MAC Address", description: "Enter your TV's MAC address", defaultValue: "00:00:00:00:00:00", required: true
    input name: "pairingKey", type: "text", title: "Pairing Key", description: "Leave blank initially", required: false
    input name: "debugLogging", type: "bool", title: "Enable Debug Logging", defaultValue: true
}

}

def installed() {
log.info "LG webOS TV driver installed."
initialize()
}

def updated() {
log.info "LG webOS TV driver updated."
initialize()
}

def initialize() {
if (debugLogging) {
log.debug "Debug logging is enabled."
runIn(1800, logsOff) // Disable debug logging after 30 minutes
}
connect()
}

def logsOff() {
log.warn "Debug logging disabled."
device.updateSetting("debugLogging", [value: "false", type: "bool"])
}

def connect() {
if (debugLogging) log.debug "Connecting to TV at ${tvIp}"
try {
interfaces.webSocket.close()
} catch (e) {
if (debugLogging) log.debug "No existing WebSocket to close."
}
interfaces.webSocket.connect("wss://${tvIp}:3001/", pingInterval: 30, headers: ["Content-Type": "application/json"], ignoreSSLIssues: true)
}

def webSocketStatus(String status) {
if (debugLogging) log.debug "WebSocket status: ${status}"
if (status.startsWith("failure:")) {
log.error "WebSocket failure: ${status}"
reconnectWebSocket()
} else if (status == "status: open") {
if (debugLogging) log.debug "WebSocket is open."
startPairing()
} else if (status == "status: closing") {
if (debugLogging) log.debug "WebSocket is closing."
} else {
log.warn "Unknown WebSocket status: ${status}"
}
}

def reconnectWebSocket() {
if (debugLogging) log.debug "Attempting to reconnect WebSocket..."
runIn(5, connect) // Try to reconnect after 5 seconds
}

def parse(String message) {
if (debugLogging) log.debug "Received message: ${message}"
def jsonSlurper = new JsonSlurper()
def msg = jsonSlurper.parseText(message)
if (msg.type == "registered") {
pairingKey = msg.payload["client-key"]
device.updateSetting("pairingKey", [value: pairingKey, type: "text"])
log.info "Pairing successful. Client Key saved."
} else if (msg.type == "response") {
// Handle responses to commands
} else if (msg.type == "error") {
log.error "Error from TV: ${msg.error}"
} else {
if (debugLogging) log.debug "Unhandled message type: ${msg.type}"
}
}

def startPairing() {
if (debugLogging) log.debug "Starting pairing process..."
def payload = [
type : "register",
id : "register_0",
payload: [
"client-key": pairingKey ?: "",
"manifest" : [
"manifestVersion": 1,
"appVersion" : "1.1",
"signed" : [
"created" : "20140509",
"appId" : "com.lge.test",
"vendorId" : "com.lge",
"localizedAppNames": [
"" : "LG Remote App",
"ko-KR" : "리모컨 앱",
"zxx-XX" : "ЛГ Rэмotэ AПП"
],
"localizedVendorNames": [
"" : "LG Electronics"
],
"permissions": [
"TEST_SECURE",
"CONTROL_INPUT_TEXT",
"CONTROL_MOUSE_AND_KEYBOARD",
"READ_INSTALLED_APPS",
"READ_LGE_SDX",
"READ_NOTIFICATIONS",
"SEARCH",
"WRITE_SETTINGS",
"WRITE_NOTIFICATION_ALERT",
"CONTROL_POWER",
"READ_CURRENT_CHANNEL",
"READ_RUNNING_APPS",
"READ_UPDATE_INFO",
"UPDATE_FROM_REMOTE_APP",
"READ_LGE_TV_INPUT_EVENTS",
"READ_TV_CURRENT_TIME"
],
"serial": "2f930e2d2cfe083771f68e4fe7bb07"
],
"permissions": [
"LAUNCH",
"LAUNCH_WEBAPP",
"APP_TO_APP",
"CLOSE",
"TEST_OPEN",
"TEST_PROTECTED",
"CONTROL_AUDIO",
"CONTROL_DISPLAY",
"CONTROL_INPUT_JOYSTICK",
"CONTROL_INPUT_MEDIA_RECORDING",
"CONTROL_INPUT_MEDIA_PLAYBACK",
"CONTROL_INPUT_TV",
"CONTROL_POWER",
"READ_APP_STATUS",
"READ_CURRENT_CHANNEL",
"READ_INPUT_DEVICE_LIST",
"READ_NETWORK_STATE",
"READ_RUNNING_APPS",
"READ_TV_CHANNEL_LIST",
"WRITE_NOTIFICATION_TOAST",
"READ_POWER_STATE",
"READ_COUNTRY_INFO"
]
]
]
]
sendWebSocketMessage(payload)
}

def on() {
if (debugLogging) log.debug "Turning on TV."
sendWakeOnLan()
runIn(5, connect) // Attempt to connect after 5 seconds
sendEvent(name: "switch", value: "on")
}

def off() {
if (debugLogging) log.debug "Turning off TV."
sendCommand("ssap://system/turnOff")
sendEvent(name: "switch", value: "off")
}

def sendCommand(uri, payload = null) {
def message = [
type : "request",
uri : uri,
id : "req_${now()}",
payload: payload ?: [:]
]
sendWebSocketMessage(message)
}

def sendWebSocketMessage(message) {
def jsonMessage = new JsonBuilder(message).toString()
if (debugLogging) log.debug "Sending message: ${jsonMessage}"
interfaces.webSocket.sendMessage(jsonMessage)
}

def setVolume(volume) {
if (debugLogging) log.debug "Setting volume to ${volume}"
sendCommand("ssap://audio/setVolume", [volume: volume.toString()])
sendEvent(name: "volume", value: volume)
}

def volumeUp() {
if (debugLogging) log.debug "Increasing volume."
sendCommand("ssap://audio/volumeUp")
}

def volumeDown() {
if (debugLogging) log.debug "Decreasing volume."
sendCommand("ssap://audio/volumeDown")
}

def mute() {
if (debugLogging) log.debug "Muting audio."
sendCommand("ssap://audio/setMute", [mute: true])
sendEvent(name: "mute", value: "muted")
}

def unmute() {
if (debugLogging) log.debug "Unmuting audio."
sendCommand("ssap://audio/setMute", [mute: false])
sendEvent(name: "mute", value: "unmuted")
}

def setInputSource(source) {
if (debugLogging) log.debug "Setting input source to ${source}"
sendCommand("ssap://tv/switchInput", [inputId: source])
sendEvent(name: "mediaInputSource", value: source)
}

def launchApp(appId) {
if (debugLogging) log.debug "Launching app with ID ${appId}"
sendCommand("ssap://system.launcher/launch", [id: appId])
}

def channelUp() {
if (debugLogging) log.debug "Channel up."
sendCommand("ssap://tv/channelUp")
}

def channelDown() {
if (debugLogging) log.debug "Channel down."
sendCommand("ssap://tv/channelDown")
}

def refresh() {
if (debugLogging) log.debug "Refreshing TV status."
// Implement status refresh logic here if needed
}

def sendButton(buttonName) {
if (debugLogging) log.debug "Sending button command: ${buttonName}"
sendCommand("ssap://input/generateKey", [name: buttonName])
}

def sendWakeOnLan() {
if (debugLogging) log.debug "Sending Wake-on-LAN packet to MAC: ${tvMac}"
def macFormatted = tvMac.replaceAll(":", "").toUpperCase()
def result = new hubitat.device.HubAction(
"wake on lan ${macFormatted}",
hubitat.device.Protocol.LAN,
null
)
sendHubCommand(result)
}

Thanks @mrferreira89, the SSL code worked perfectly on my 2021 TV. Might want to update the code with a SSL switch in the preferences. Or even better, when connection has "failure : unexpected end of stream..." error, try again with SSL and if success, auto update the settings to SSL?

Thanks again!

I have an older LG Tv (Circa 2020) and have updated my driver with the code above. In my logs I'm getting the following when I try to Power On the TV:

dev:722024-11-10 12:38:31.206 PMdebugNo route to host (Host unreachable)

dev:722024-11-10 12:38:31.191 PMdebugAttempting to reconnect WebSocket...

dev:722024-11-10 12:38:31.189 PMerrorWebSocket failure: failure: No route to host (Host unreachable)

dev:722024-11-10 12:38:31.187 PMdebugWebSocket status: failure: No route to host (Host unreachable)

dev:722024-11-10 12:38:28.124 PMdebugConnecting to TV at 192.168.1.107

dev:722024-11-10 12:38:23.112 PMdebugSending Wake-on-LAN packet to MAC: 00:51:ED:C1:EB:D7

dev:722024-11-10 12:38:23.111 PMdebugTurning on TV.

Any suggestions to get this working?

Many thanks

Major thanks @mrferreira89 … this seems to mostly work for me. Few things I’m still trying to sort out — wonder if anybody has ideas:

  1. I can’t get this driver to turn on my TV — even though if I use a Wake-On-LAN alone, even from HE, it works fine. Log shows WS failures.
  2. The device states (esp. switch/power and external input) don’t seem to update when the events are triggered physically. Is this just me? If not, @mrferreira89, can I beg for a fix?
  3. How does the driver take an “Input Source”? I’ve tried things like AV, HDMI1, HDMI 1, TV, etc., but everything produces log errors. Also wondered if it’s a friendly name alternative to app ID, but nothing like that worked either.

Speaking of app IDs…at first I struggled to find LGTV’s app IDs since prior versions of the LGTV community driver allowed you to refresh the input list and then use friendly names to select an input. But hey, beggars can’t be choosers. I hacked together this list—hope it’s helpful to other folks:

Netflix=netflix, LG Content Store=com.webos.app.discovery, Amazon Prime Video=amazon, Paramount+=com.cbs-all-access.webapp.prod, Apple TV=com.apple.appletv, YouTube=youtube.leanback.v4, HBO Max=com.hbo.hbomax, Peacock=com.peacock.tv, Hulu=hulu, YouTube TV=youtube.leanback.ytv.v1, Web Browser=com.webos.app.browser, HDMI [n]=com.webos.app.hdmi[n], AV=com.webos.app.externalinput.av1

Again - thank you @mrferreira89!

1 Like

Hey,

“HDMI_1”, etc.. should work.

It’s a bit tough to sort out these issues without having every version of the TV to test on. But some of the things you asked for should be do-able

Im traveling at the moment but will take a look once im back on the 11th

Some of the features you asked for are features I want as well.

The one strange thing is that WOL doesn’t work for you. It does indeed work for me straight from the app.

But I’ll take a look to see if there is anything that could be causing it to not work

1 Like

Yup that did the trick. The underscore was the key I was missing!

Awesome thx

The "Older Models" code was required for a LG OLED released in 2023. Thanks for posting it, as the other drivers were not working!

The TV turns on/off fine, but I'm also having the same issue as mluck with the device state not changing to match the TV state.

hey thanks so much. here is what is on my to do list for when I'm back on Dec 11th:

(I would really appreciate any help with testing)

  • consolidate the code so that it detects which model should be used vs. having new model & old model code
  • fix device state reporting
  • determine why & fix TV Wake issues (for those who have it)

@mluck - you mentioned your TV won't wake correct? what model do you have?

I have four LG webOS TVs, all of which require WOL separately to turn on:
one 49UM7300PUA, two 70UM7370PUA, and one OLED55C8PUA. I’m a bit embarrassed to admit I have another 3 LGTVs in another home.

I’m happy to help however you want, just say the word!

May I humbling add a request: adding the “device notification” command to the driver. It allows the TV to be used like any other “send message” destination.

By chance have you seen the earlier LGTV device driver by @ekimmagrann which I believe was later picked up by @asj? Later @mo.hesham picked up the driver here. While none of these drivers work for me any more, they do have all or almost all of your to-do’s in the code. Maybe there is inspiration for you in there?

Also, @mrferreira89, what’s the syntax of the button command? Nothing I’ve tried works.

Hi @mrferreira89 - thanks for the driver!
I did some tweaking and added some features. I don't know if you have this in github or in HPM. But here is your code, with some tweaks (buttons, slider, feedback, etc)

/**

  • LG webOS TV Driver for Hubitat
  • Author: Echistas
  • Date: 2023-10-21
  • This driver allows Hubitat to control an LG webOS TV.
  • 2024-12-17 V.1.1 - hhorigian - Added Volume Feedback, Push Buttons for dashboards, Added Volume Slider Control and Feedback. Added HBO, YouTube, Amazon, Netflix buttons. Added Play, Pause, Stop controls.

*/

import groovy.json.JsonSlurper
import groovy.json.JsonBuilder

metadata {
definition(name: "LG wesocketbOS TV", namespace: "Echistas", author: "Echistas") {
capability "Switch"
capability "AudioVolume"
capability "Refresh"
capability "Actuator"
capability "Media Input Source"
capability "MusicPlayer"
capability "Initialize"
capability "PushableButton"
capability "Variable"

    attribute "channel", "string"
    attribute "mediaInputSource", "string"
    attribute "mute", "string"
    attribute "volume", "integer"

    // Explicitly declare the initialize command
    command "initialize"
    command "launchApp", [[name: "App Id*", type: "STRING", description: "App ID to launch"]]
    command "sendButton", [[name: "Button Name*", type: "STRING", description: "Button name to send"]]
    command "channelUp"
    command "channelDown"
    command "mute"
    command "unmute"
    command "volumeUp"
    command "volumeDown"
    command "getstatus"


    
}

preferences {
    input name: "tvIp", type: "text", title: "TV IP Address", description: "Enter your TV's IP address", defaultValue: "192.168.1.1", required: true
    input name: "tvMac", type: "text", title: "TV MAC Address", description: "Enter your TV's MAC address", defaultValue: "d1:b0:ce:02:1c:tc", required: true
    input name: "pairingKey", type: "text", title: "Pairing Key", description: "Leave blank initially", required: false
    input name: "debugLogging", type: "bool", title: "Enable Debug Logging", defaultValue: true
}

}

def installed() {
log.info "LG webOS TV driver installed."
sendEvent(name: "volume", value: 0)
initialize()
}

def updated() {
log.info "LG webOS TV driver updated."
schedule('0/15 * * ? * *', getstatus) //BE CAREFUL this is the check for feedback schedule 15secs
initialize()
}

def initialize() {
if (debugLogging) {
log.debug "Debug logging is enabled."
runIn(1800, logsOff) // Disable debug logging after 30 minutes
}
sendEvent(name: "numberOfButtons", value: "20")
sendEvent(name: "volume", value: 0)
connect()
}

def logsOff() {
log.warn "Debug logging disabled."
device.updateSetting("debugLogging", [value: "false", type: "bool"])
}

def connect() {
if (debugLogging) log.debug "Connecting to TV at ${tvIp}"
try {
interfaces.webSocket.close()
} catch (e) {
if (debugLogging) log.debug "No existing WebSocket to close."
}
interfaces.webSocket.connect("wss://${tvIp}:3001/", pingInterval: 30, headers: ["Content-Type": "application/json"], ignoreSSLIssues: true)
}

def webSocketStatus(String status) {
if (debugLogging) log.debug "WebSocket status: ${status}"
if (status.startsWith("failure:")) {
reconnectWebSocket()
} else if (status == "status: open") {
if (debugLogging) log.debug "WebSocket is open."
startPairing()
} else if (status == "status: closing") {
if (debugLogging) log.debug "WebSocket is closing."
}
}

def reconnectWebSocket() {
if (debugLogging) log.debug "Attempting to reconnect WebSocket..."
runIn(5, connect) // Try to reconnect after 5 seconds
}

def parse(String message) {
if (debugLogging) log.debug "Received message: ${message}"
def jsonSlurper = new JsonSlurper()
def msg = jsonSlurper.parseText(message)

if (msg.type == "registered") {
    pairingKey = msg.payload["client-key"]
    device.updateSetting("pairingKey", [value: pairingKey, type: "text"])
    log.info "Pairing successful. Client Key saved."
} else if (msg.type == "response") {
    if (msg.payload["scenario"] == "mastervolume_tv_speaker_ext") {    //Was requested a GetVolume
    
        log.info "Volume = " + msg.payload["volume"]
        intvolume = msg.payload["volume"]
        sendEvent(name: "volume", value: intvolume)
                    
        log.info "Mute = " + msg.payload["muted"]
        if (msg.payload["muted"] == false) {
            sendEvent(name: "mute", value: "unmuted")
        } else {
            sendEvent(name: "mute", value: "muted") 
        }
            

            
    }
    // Handle responses to commands
} else if (msg.type == "error") {
    log.error "Error from TV: ${msg.error}"
} else {
    if (debugLogging) log.debug "Unhandled message type: ${msg.type}"
}

}

def startPairing() {
if (debugLogging) log.debug "Starting pairing process..."
def payload = [
type : "register",
id : "register_0",
payload: [
"client-key": pairingKey ?: "",
"manifest" : [
"manifestVersion": 1,
"appVersion" : "1.1",
"signed" : [
"created" : "20140509",
"appId" : "com.lge.test",
"vendorId" : "com.lge",
"localizedAppNames": [
"": "LG Remote App",
"ko-KR": "리모컨 앱",
"zxx-XX": "ЛГ Rэмotэ AПП"
],
"localizedVendorNames": [
"": "LG Electronics"
],
"permissions": [
"TEST_SECURE",
"CONTROL_INPUT_TEXT",
"CONTROL_MOUSE_AND_KEYBOARD",
"READ_INSTALLED_APPS",
"READ_LGE_SDX",
"READ_NOTIFICATIONS",
"SEARCH",
"WRITE_SETTINGS",
"WRITE_NOTIFICATION_ALERT",
"CONTROL_POWER",
"READ_CURRENT_CHANNEL",
"READ_RUNNING_APPS",
"READ_UPDATE_INFO",
"UPDATE_FROM_REMOTE_APP",
"READ_LGE_TV_INPUT_EVENTS",
"READ_TV_CURRENT_TIME"
],
"serial": "2f930e2d2cfe083771f68e4fe7bb07"
],
"permissions": [
"LAUNCH",
"LAUNCH_WEBAPP",
"APP_TO_APP",
"CLOSE",
"TEST_OPEN",
"TEST_PROTECTED",
"CONTROL_AUDIO",
"CONTROL_DISPLAY",
"CONTROL_INPUT_JOYSTICK",
"CONTROL_INPUT_MEDIA_RECORDING",
"CONTROL_INPUT_MEDIA_PLAYBACK",
"CONTROL_INPUT_TV",
"CONTROL_POWER",
"READ_APP_STATUS",
"READ_CURRENT_CHANNEL",
"READ_INPUT_DEVICE_LIST",
"READ_NETWORK_STATE",
"READ_RUNNING_APPS",
"READ_TV_CHANNEL_LIST",
"WRITE_NOTIFICATION_TOAST",
"READ_POWER_STATE",
"READ_COUNTRY_INFO"
]
]
]
]
sendWebSocketMessage(payload)
}

def on() {
if (debugLogging) log.debug "Turning on TV."
sendWakeOnLan()
runIn(5, connect) // Attempt to connect after 5 seconds
sendEvent(name: "switch", value: "on")
}

def off() {
if (debugLogging) log.debug "Turning off TV."
sendCommand("ssap://system/turnOff")
sendEvent(name: "switch", value: "off")
}

def sendCommand(uri, payload = null) {
def message = [
type : "request",
uri : uri,
id : "req_${now()}",
payload: payload ?: [:]
]
sendWebSocketMessage(message)
}

def sendWebSocketMessage(message) {
def jsonMessage = new JsonBuilder(message).toString()
if (debugLogging) log.debug "Sending message: ${jsonMessage}"
interfaces.webSocket.sendMessage(jsonMessage)
}

def setLevel(volume){
if (debugLogging) log.debug "Setting volume to ${volume}"
def intVolumeLevel = (volume >= 0) ? ((volume <=100) ? volume : 100) : 0

     sendCommand("ssap://audio/setVolume", [volume: intVolumeLevel])
     sendEvent(name: "volume", value: intVolumeLevel)

}

def setVolume(volumelevel)
{
log.debug("LG setVolume()")
setLevel(volumelevel)
}

def getstatus() {
if (debugLogging) log.debug "Run: Get status."
sendCommand("ssap://audio/getVolume")
}

def pause() {
if (debugLogging) log.debug "Run: Send pause Key."
sendCommand("ssap://media.controls/pause")
}

def play() {
if (debugLogging) log.debug "Run: Send play Key."
sendCommand("ssap://media.controls/play")
}

def stop() {
if (debugLogging) log.debug "Run: Send stop Key."
sendCommand("ssap://media.controls/stop")
}

def volumeUp() {
if (debugLogging) log.debug "Increasing volume."
sendCommand("ssap://audio/volumeUp")
}

def volumeDown() {
if (debugLogging) log.debug "Decreasing volume."
sendCommand("ssap://audio/volumeDown")
}

def mute() {
if (debugLogging) log.debug "Muting audio."
sendCommand("ssap://audio/setMute", [mute: true])
sendEvent(name: "mute", value: "muted")
}

def unmute() {
if (debugLogging) log.debug "Unmuting audio."
sendCommand("ssap://audio/setMute", [mute: false])
sendEvent(name: "mute", value: "unmuted")
}

def setInputSource(source) {
if (debugLogging) log.debug "Setting input source to ${source}"
sendCommand("ssap://tv/switchInput", [inputId: source])
sendEvent(name: "mediaInputSource", value: source)
}

def launchApp(appId) {
if (debugLogging) log.debug "Launching app with ID ${appId}"
sendCommand("ssap://system.launcher/launch", [id: appId])
}

def channelUp() {
if (debugLogging) log.debug "Channel up."
sendCommand("ssap://tv/channelUp")
}

def channelDown() {
if (debugLogging) log.debug "Channel down."
sendCommand("ssap://tv/channelDown")
}

def refresh() {
if (debugLogging) log.debug "Refreshing TV status."
// Implement status refresh logic here if needed
}

def sendButton(buttonName) {
if (debugLogging) log.debug "Sending button command: ${buttonName}"
sendCommand("ssap://input/generateKey", [name: buttonName])
}

def sendWakeOnLan() {
if (debugLogging) log.debug "Sending Wake-on-LAN packet to MAC: ${tvMac}"
def macFormatted = tvMac.replaceAll(":", "").toUpperCase()
def result = new hubitat.device.HubAction(
"wake on lan ${macFormatted}",
hubitat.device.Protocol.LAN,
null
)
sendHubCommand(result)
}

// ===== BUTTON INTERFACE =====
def push(pushed) {
log.debug("push: button = ${pushed}, trigger = ${state.triggered}")
if (pushed == null) {
log.warn("push: pushed is null. Input ignored")
return
}
pushed = pushed.toInteger()
switch(pushed) {
// ===== Physical Remote Commands =====
case 2 : mute(); break //
case 3 : unmute(); break
case 4 : channelUp(); break //
case 5 : channelDown(); break //
case 6 : volumeUp(); break
case 7 : volumeDown(); break
case 8 : arrowLeft(); break
case 9 : arrowRight(); break
case 20: launchApp("amazon"); break
case 21: launchApp("netflix"); break
case 22: launchApp("youtube.leanback.v4"); break
case 23: launchApp("hbo"); break
case 24: play(); break
case 25: pause(); break
case 26: stop(); break
case 27: setInputSource("HDMI_1"); break
case 28: setInputSource("HDMI_2"); break
//case 29: setInputSource("Live_TV"); break

	default:
		log.debug("push: Invalid Button Number!")
		break
}

}

1 Like