Samsung TV can't turn off after idle period

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.

== 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().
This commit is contained in:
ejel 2018-05-31 13:48:00 -07:00
parent 6af995026b
commit 58a1c38393

View file

@ -155,16 +155,25 @@ class SamsungTVDevice(MediaPlayerDevice):
_LOGGER.info("TV is powering off, not sending command: %s", key)
return
try:
self.get_remote().control(key)
# recreate connection if connection was dead
retry_count = 1
for _ in range(retry_count + 1):
try:
self.get_remote().control(key)
break
except (self._exceptions_class.ConnectionClosed,
BrokenPipeError):
# BrokenPipe can occur when the commands is sent to fast
self._remote = None
self._state = STATE_ON
except (self._exceptions_class.UnhandledResponse,
self._exceptions_class.AccessDenied, BrokenPipeError):
self._exceptions_class.AccessDenied):
# We got a response so it's on.
# BrokenPipe can occur when the commands is sent to fast
self._state = STATE_ON
self._remote = None
_LOGGER.debug("Failed sending command %s", key, exc_info=True)
return
except (self._exceptions_class.ConnectionClosed, OSError):
except OSError:
self._state = STATE_OFF
self._remote = None
if self._power_off_in_progress():
@ -207,6 +216,7 @@ class SamsungTVDevice(MediaPlayerDevice):
# Force closing of remote session to provide instant UI feedback
try:
self.get_remote().close()
self._remote = None
except OSError:
_LOGGER.debug("Could not establish connection.")