-
-
Notifications
You must be signed in to change notification settings - Fork 34.1k
Samsung TV can't be turn off after idle period #14587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -155,18 +154,17 @@ def send_key(self, key): | |||
_LOGGER.info("TV is powering off, not sending command: %s", key) | |||
return | |||
try: | |||
self.get_remote().control(key) | |||
with self.get_remote() as remote: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating and closing a new connection for every key seems expensive. Why not retry the command with a new connection if we get a ConnectionClosed
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, in my mind the overhead of establishing a TCP new connection should be negligible in this usage scenario. If the control()
function is called in a tight loop then the connection should definitely not be recreated on every iteration. I checked out some other components in HA and I don't see any that maintain persistent connection to the host—which makes sense to me.
Other reasons for switching to short-live connection:
samsungctl
is not thread safe. Since this component can be run from different worker thread it could cause unexpected behavior if the connection is shared.- Not having to maintain another state makes the implementation simpler and reduce testing surface.
- Based on my testing (which is very limited as I only have one TV model), it takes less than one or two minutes for a connection to get closed. This means that in real-life scenario where the component does not get triggered every few second, the connection will need to be re-established every time anyway.
I'm still new to HA and Python so please correct me if I'm wrong on any point and if there is anything that I miss.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the thread safe argument is an argument in favor of reusing the connection. Otherwise we might end up opening a ton of connections at the same time and overwhelm the TV.
Using WebSockets heartbeat feature, it should be pretty quick to detect a closed connection and reconnect right away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thread safety is an issue with reusing the connection. When sending multiple commands consecutively—like pressing volume up multiple times, a common scenario—there could be multiple workers sending/receiving data using the same connection at the same time which could be a problem. I believe the root cause for having this catch for BorkenPipeError is because of this issue.
While it's possible to overwhelm to TV with large number of open connection at a given time, it is less likely to happen in real life as the number is limited by number of worker threads as well as the fact that these short-live connections will finish relatively quickly.
Do you mind sharing why you're particular about having this component using long-live connection, despite this is not the pattern implemented by other components? I might be missing something that you are seeing or know and just want to understand that's all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure where the notion comes from that other components do this. Any component that has a (web)socket connection, will keep it open. Chromecast, Cloud, Tradfri, …
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be fairly simple to have a method sendCommand
:
- if closed or never opened, open connection
- try sending command
- if we get broken pipe error or other exception, set connection to None and call
sendCommand
again ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't that solve the cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is also a case where there is no exception raised from connection but TV won't respond. In this case we won't know whether the command succeeded or not.
I found the issue within samsungctl and working on a way to fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we then close this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I forgot that the fixes for the two issues are independent to each other. I'm updating this PR with the fix for turn_off issue. The fix in samsungctl
for the no response issue can come in later.
When Samsung TV is idle for a period of time after issued a command, subsequent 'turn_off' command won't turn off the TV. The issue is seen in Samsung models with websocket as discussed in home-assistant#12302. == Reproducible Steps 1. Turn on TV (either via HA or directly). 2. Issue some commands e.g. volume ups / downs. 3. Wait for ~1 minute. 4. Issue turn_off command via HA. TV won't turn off. 5. Issue subsequent turn off commands won't turn off TV still. 6. However, issue some other commands e.g. volume ups / downs multiple times in a row and then turn_off will turn off the TV. == Root Cause The underlying websocket connection opened by samsungctl get closed after some idle time. There was no retry mechanism so issued commands would intermittently fail but the subsequent one would succeed when `_remote` get recreated. With `turn_off()`, however, there is an additional call to `self.get_remote().close()` which indirectly caused new connection to be created and then closed immediately. This causes the component to stuck in failure mode when turn_off command is repeatly issued. == The Fix Recreate the connection and retry the command if connection is closed to avoid silent failures due to connection closed. Also set `_remote` to None after calling close() to put it in correct state. This fix eliminates intermittent command failure and failure mode in turn_off().
11c3f31
to
58a1c38
Compare
Description:
When Samsung TV is idle for a period of time after issued a command,
subsequent 'turn_off' command won't turn off the TV. The issue is seen
in Samsung models with websocket as discussed in #12302.
Detailed explanation of the root cause and fix is in the commit message.
Related issue (if applicable): fixes #12302
Checklist:
tox
. Your PR cannot be merged unless tests pass