-
Getting our LG TV's Picture settings onto the HA network
05/03/2024 at 07:10 • 0 commentsOur (LG, WebOS) TV was too bright at night (we keep our lights down, and mostly amber, past dusk..) but the settings were too buried to make it practical to tweak routinely by hand so I took another look at adding that to the network. The only refs I found were for luna style urls, which I gather are normally only accessible by other apps running on the WebOS device itself (though not really sure about that). But people on reddit were saying HomeBridge could do it, so I looked at their source and they were essentially hacking (in the exploit sense) the TV with a gross work-around. But I'm not above doing whatever works, so I ran a couple of experiments and got it working using the same hack. Surprisingly it appears to be 100% reliable so far, so much so that I was subsequently able to set it up so the brightness and contrast are continually adjusted to the time of day (whenever the TV is on; and the only really active period is a couple hours' ramp during dusk).
The way it works is: there's an ssap url (the usual WebOS access, which was already set up and working) for popping up a dialog box, and you can set any url to hit when that dialog box is ok'd, canceled, or (critically) closed. So you just set all three to the luna url, and then automatically close the dialog box (with another ssap call) as soon as its open, and that triggers a hit to the luna url from within the WebOS device itself. (!!!Barf!!!) On my TV you never even see the dialog box, so for all intents and purposes... Well, the picture settings are now just another dynamic variable in the HA hierarchy along side the other TV properties like the volume, so it was very easy to script up the dusk ramp. (Fwiw, I found it best to lower the contrast, which brings down the bright end, and to raise the brightness in order to rescue the darks, which otherwise get too dark to see. That combination has the effect of darkening the picture while keeping everything still clear and visible. I may just wrap that up as a "brightness" variable which you can just set with a real value 0-1 so that any calling code doesn't need to know these nuances. But for the moment just the raw brightness, color, and contrast are directly exposed.)
This is essentially the entire change to the low-level driver, and there's a bit more glue code in the next level up to publish this as an ordinary dynamic value on the HA net (note that these values can be polled via a normal ssap call so were already available read-only):async def set_picture(self, settings={'brightness': 50, 'color': 50, 'contrast': 95}): await self.send_luna_command('luna://com.webos.settingsservice/setSystemSettings', { 'category': "picture", 'settings': settings }) await sleep(0.2) # Give it a moment to exec the command? self.poll('picture') # Poll the picture settings; hopefully they'll be updated by now. This won't track manual changes! async def send_luna_command(self, uri, payload): """This hack issues a luna style command by setting it as the on-close of a dialog which we open and then immediately close. BARF. Borrowing this hack (conceptually) from the HomeBridge webos driver. """ luna_call = { 'uri': uri, 'params': payload, } buttons = [{ 'label': 'Ok', 'focus': True, 'buttonType': 'ok', 'onClick': uri, 'params': payload, }] payload = { "title": 'Picture Settings', "message": 'Updating...', "modal": True, "buttons": buttons, "onclose": luna_call, "onfail": luna_call, "type": 'confirm', "isSysReq": True, } # # Open the pop-up: # rv = await self.do_command("ssap://system.notifications/createAlert", payload) # rv e.g.: # 'payload': {'alertId': 'com.webos.service.apiadapter-1714593888911', # 'returnValue': True}, # # Then close it! # if (alert_id := rv.get('alertId')) is None: self.log("WARNING: reply has no alertId.") return payload = { 'alertId': alert_id } await self.do_command('ssap://system.notifications/closeAlert', payload)
Again the code to actually use this now is simply, from any process anywhere on the network:
picture = find('tvlg/picture') ... await picture.send_value(settings)