Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

Merged
merged 1 commit into from
Jun 9, 2018

Conversation

ejel
Copy link
Contributor

@ejel ejel commented May 22, 2018

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:

  • The code change is tested and works locally.
  • Local tests pass with tox. Your PR cannot be merged unless tests pass

@ejel ejel changed the title Samsung TV can't be turn off after idle period. Samsung TV can't be turn off after idle period May 22, 2018
@@ -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:
Copy link
Member

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 ?

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

@ejel ejel May 29, 2018

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.

Copy link
Member

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, …

Copy link
Member

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 ?

Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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?

Copy link
Contributor Author

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().
@ejel ejel force-pushed the samsungtv-turnoff-fix branch from 11c3f31 to 58a1c38 Compare June 8, 2018 23:25
@ghost ghost added in progress and removed small-pr PRs with less than 30 lines. labels Jun 8, 2018
@balloob balloob merged commit d7b7370 into home-assistant:dev Jun 9, 2018
@ghost ghost removed the in progress label Jun 9, 2018
@ejel ejel deleted the samsungtv-turnoff-fix branch June 10, 2018 05:43
@balloob balloob mentioned this pull request Jun 22, 2018
girlpunk pushed a commit to girlpunk/home-assistant that referenced this pull request Sep 4, 2018
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().
@home-assistant home-assistant locked and limited conversation to collaborators Dec 10, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Samsung TV 2016 No longer working in 0.63
3 participants