Sony Devices Binding for OH3

Initial tests with running the unchanged Sony binding under OH 4.1.0.M3 show no issues so far.

My understanding of your patch of the Neeo binding is that the introduction of an HttpClient stack is the real fix for the exhaustive thread creation issue. So what is the relevance of the migration to the jetty client?

I’ve also started to introduce the jetty client for the Sony binding. However, I’m now struggling with the registration of servlet filters, which I think need the use of additional services or components. Do you have any hint on how to do this in the context of migrating to the Jetty client?

I’m glad it’s working cleanly. We’re still not 100% sure why some of the bindings leaked. What we believed was that http clients were not being closed properly. When they got discarded, trash collection didn’t dispose of them because they weren’t dead (even though we lost all of our pointers to them). This ultimately lead to memory exhaustion.

In the Neeo binding we did two things. First, we believed that ClientBuilder was causing some of the issues due to an update there in karaf. So moving to the jetty client seemed logical because OH actually maintains a central pool at the core level. I’m more of a fan of aligning with the core than using different libraries. Less chance of something breaking and not being caught. Where we could use the central ones we did. Unfortunately Neeo also has some added complexity where it does a ton of things very fast (specifically when keys were pressed on the remote). That’s where the stack came into play. Instead of allowing the system to spin freely we maintained a stack of clients in a waiting state. If more than the stack ever was needed we would create them on demand (to avoid congestion), but then once we filled up the stack we would force close and discard to avoid the stack growing out of control. This gave a really good balance between speed and memory resources.

As far as the registration, check out [neeo] Fix Servlet exceptions due to non-unique names by wborn · Pull Request #14554 · openhab/openhab-addons · GitHub I believe that’s where that was fixed on neeo.

Hi everybody

I recently found out that my Sony TV ( KD-65A85 ) was using about 30 Watts when the TV is off, I think this is quit a lot and would like to reduce it.
If I disable the binding it will reduce the power consumption to about 0 Watts 5 minutes after the TV is turned off, but when the binding is enabled it continues to use about 30 Watts.
I originally had Remote Start enabled even for apps on the TV and I tried to disable that but that did not change anything. I only use the system#powerstatus channel.
When I turn the TV off the system#powerstatus channel goes OFF so this is fine (The binding remains online).
If I disable both Retry Polling and Refresh Interval the Tv will reduce power, so it must be the polling that keeps the TV awake.
If I enable Retry Polling and Refresh Interval after the TV has gone to sleep it will remain at 0 watts.

So disabling both Retry Polling and Refresh Interval will fix the issue but then on off status is unreliable

So the question is if anybody else is seeing the same ?
and if anybody knows of a solution ?
I guess that if the binding could stop polling for some time after it has detected the TV is off this would fix the issue.

Anyway thanks for a great binding.
/Kennet

Your observation sounds similar to what is described in Sony Bravia TV integration does not permit sleeping/standby - Configuration - Home Assistant Community (home-assistant.io). I will check if the discussed workarounds can be implemented in this binding.

You might also try the Andoird TV binding and check whether it shows the same behavior.

Hi

Thank for your feedback.
I was thinking that a simple solution might be to allow setting a poll interval for when the device is online but off. This could then be set to something above 5 minutes.
Then incase the device wakes up unintended the binding would allow it to fall asleep again.
I tried your suggestion with Android TV and it looks like it works so that the tv goes to sleep. I will keep a watch on it for the next days. Thanks.

I have uploaded a new version of the binding on the marketplace. This version uses the same offline detection implementation as the AndroidTV binding and therefore might solve the issue with preventing the deep sleep mode of the TV. So if you are still interested in using the Sony binding, you might give this version a try.

Hi

Thanks for looking at this.
I have been a bit busy so I only managed to do some monitoring.
I can see that if I unplug the ethernet cable the TV does not wakeup at all, I monitored this for about 24 hours.
But if I have the Android TV binding running the TV sleeps for about 3 hours and then wakes up about 30 minutes. (monitored for some days). However I can not say for sure if it is other things on the network that is causing it to wakeup or maybe the TV is doing something by itself. I will investigate this more.
I did find that the Android TV binding stopped working in detecting that the TV was turned on, this might be som misconfiguration on my part did not have time to check.
But I think I will switch back to your binding to see how that works now.

For the record I originally test with version:
3.2.0.202206161002 x openHAB Add-ons :: Bundles :: Sony Binding

I have tried your binding overnight and the tv stayed awake all night at 30 watts.
Do i need to configure anything to enable the new mode?
My poll values are Refresh Interval 30, Retry Polling 10 and Status Check Interval 30.

The version I tested is:
4.0.0.202405191519 x openHAB Add-ons :: Bundles :: Sony Binding

I’d guess that the Android TV binding with your (default?) settings doesn’t poll the TV, thus the reduced power consumption when your TV is off.
I now believe that any attempt to detect the power state of the Sony TV will prevent the activation of the deep standby mode (see also my link in a previous post). I will think about implementing a workaround based on your suggestion.

Hi.

Yes I used default settings in the android TV binding.
I found that the network binding with allowDHCPlisten is a very fast method to detect when the tv might be turned on. However sometimes the tv is detected as online when it is off. I guess this is because it responds to a ping. So using this method alone does not work.
But maybe the two methods can be combined so that if the tv sends a dhcp request the binding tried to connect and updates the power on status. Maybe a item input to request a connect attempt or use the network binding from code. Then we cloud have very long time between polls. Just in case tv gets turned on without the dhcp being detected.

Anyway this is just an optimization on top of any fix.

I found a solution that works fairly well in regards to lowering the power consumption.
I configured a network thing for the TV like this:

Thing network:pingdevice:sony_tv [ hostname="x.x.x.x", macAddress="xx:xx:xx:xx:xx:xx", retry=1, timeout=1000, refreshInterval=600000 ]

When the network thing goes online I have a rule that enable the Sony binding like this:

rule "Start TV polling when online"
when
	Item stue_tv_online changed to ON
then
    val headers = newHashMap("Authorization" -> "Bearer oh.EnableDisable.xxxxxxxx", "WWW-Authenticate"-> "Basic")
    val url = "http://x.x.x.x:x/rest/things/sony.../enable"
    sendHttpPutRequest(url, "text/plain", "true", headers, 5000)
end

Then I have another rule to disable the binding when the power status goes OFF.
Because the TV might go online on the network without being turned on I also start the timer to stop polling when it goes online.

var Timer StopTVPolling = null
val int NoNOTimeoutMinutes = 5

rule "Stop TV polling when OFF"
when
	Item stue_tv_online changed to ON or
	Item stue_tv_power changed to OFF
then
    if( StopTVPolling !== null )
    {
        StopTVPolling.cancel()
        StopTVPolling = null
    }
    StopTVPolling = createTimer(now.plusSeconds(NoNOTimeoutMinutes*60), [|
        if( stue_tv_power.state !== ON )
        {	
            val headers = newHashMap("Authorization" -> "Bearer oh.EnableDisable.xxxxxxx", "WWW-Authenticate"-> "Basic")
            val url = "http://x.x.x.x:x/rest/things/sony.../enable"
            sendHttpPutRequest(url, "text/plain", "false", headers, 5000)
        }
	])
end

This works to ensure the tv goes to deep standby mode.
The solution does have the side effect that the sony binding is creating warning logs every 10 seconds while the binding is disabled. :frowning:

2024-06-22 19:47:39.707 [WARN ] [.core.thing.binding.BaseThingHandler] - Handler ScalarWebHandler tried updating the thing status although the handler was already disposed.

Also I get exceptions like this when the binding is disabled.

2024-06-22 20:13:34.231 [WARN ] [mmon.WrappedScheduledExecutorService] - Scheduled runnable ended with an exception: 
java.lang.IllegalStateException: client is closed
	at org.apache.cxf.jaxrs.client.spec.ClientImpl.checkClosed(ClientImpl.java:167) ~[?:?]
	at org.apache.cxf.jaxrs.client.spec.ClientImpl.target(ClientImpl.java:108) ~[?:?]
	at org.apache.cxf.jaxrs.client.spec.ClientImpl.target(ClientImpl.java:120) ~[?:?]
	at org.openhab.binding.sony.internal.net.HttpRequest.sendPostCommand(HttpRequest.java:157) ~[?:?]
	at org.openhab.binding.sony.internal.net.HttpRequest.sendPostJsonCommand(HttpRequest.java:138) ~[?:?]
	at org.openhab.binding.sony.internal.transports.SonyHttpTransport.executePostJson(SonyHttpTransport.java:331) ~[?:?]
	at org.openhab.binding.sony.internal.transports.SonyHttpTransport.executePostJson(SonyHttpTransport.java:308) ~[?:?]
	at org.openhab.binding.sony.internal.transports.SonyHttpTransport.execute(SonyHttpTransport.java:129) ~[?:?]
	at org.openhab.binding.sony.internal.transports.SonyTransport.execute(SonyTransport.java:108) ~[?:?]
	at org.openhab.binding.sony.internal.scalarweb.models.ScalarWebService.execute(ScalarWebService.java:311) ~[?:?]
	at org.openhab.binding.sony.internal.scalarweb.models.ScalarWebService.executeSpecific(ScalarWebService.java:295) ~[?:?]
	at org.openhab.binding.sony.internal.scalarweb.protocols.ScalarWebAvContentProtocol.lambda$4(ScalarWebAvContentProtocol.java:1405) ~[?:?]
	at java.util.concurrent.ConcurrentHashMap.compute(ConcurrentHashMap.java:1916) ~[?:?]
	at org.openhab.binding.sony.internal.scalarweb.protocols.ScalarWebAvContentProtocol.getSources(ScalarWebAvContentProtocol.java:1397) ~[?:?]
	at org.openhab.binding.sony.internal.scalarweb.protocols.ScalarWebAvContentProtocol.lambda$3(ScalarWebAvContentProtocol.java:1361) ~[?:?]
	at java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:273) ~[?:?]
	at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1707) ~[?:?]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[?:?]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[?:?]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[?:?]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[?:?]
	at org.openhab.binding.sony.internal.scalarweb.protocols.ScalarWebAvContentProtocol.getSources(ScalarWebAvContentProtocol.java:1362) ~[?:?]
	at org.openhab.binding.sony.internal.scalarweb.protocols.ScalarWebAvContentProtocol.refreshSources(ScalarWebAvContentProtocol.java:2440) ~[?:?]
	at org.openhab.binding.sony.internal.scalarweb.protocols.ScalarWebAvContentProtocol.refreshState(ScalarWebAvContentProtocol.java:2458) ~[?:?]
	at org.openhab.binding.sony.internal.scalarweb.protocols.ScalarWebProtocolFactory.lambda$2(ScalarWebProtocolFactory.java:167) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) [?:?]
	at java.lang.Thread.run(Thread.java:840) [?:?]

I guess handling of enabling and disabling of the binding is not used that often normally :slight_smile: