Repository: postlund/pyatv

Issue:
Since tvOS 14 turn_off SOMETIMES only open the lateral menu, maybe just timing issue...
Since tvOS 14 (I cannot easily know if it was already the case with 14.0.1, or even 14.0.0, but with tvOS 13 this issue never came into light), the turn_off command I send using atvremote sometimes only open the lateral menu, and don't validate the sleep command.

A simple select command works or a second turn_off does the job every time though.

System Setup:
 - OS: Mac OS X Mojave 10.14.6
 - Python: 3.8.3
 - pyatv: 0.7.5 (using atvremote)
- Apple TV: Apple TV 4 tvOS 14.0.2 build 18J411


Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/postlund/pyatv/pull/923?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@df56149`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/postlund/pyatv/pull/923/graphs/tree.svg?width=650&height=150&src=pr&token=wb6azJjRSY)](https://codecov.io/gh/postlund/pyatv/pull/923?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master     #923   +/-   ##
=========================================
  Coverage          ?   95.67%           
=========================================
  Files             ?       38           
  Lines             ?     3287           
  Branches          ?        0           
=========================================
  Hits              ?     3145           
  Misses            ?      142           
  Partials          ?        0           
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `95.67% <0.00%> (?)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags#carryforward-flags-in-the-pull-request-comment) to find out more.


------

[Continue to review full report at Codecov](https://codecov.io/gh/postlund/pyatv/pull/923?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/postlund/pyatv/pull/923?src=pr&el=footer). Last update [df56149...1b988a8](https://codecov.io/gh/postlund/pyatv/pull/923?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/pyatv/mrp/__init__.py b/pyatv/mrp/__init__.py
index e03f8790..26f85ffb 100644
--- a/pyatv/mrp/__init__.py
+++ b/pyatv/mrp/__init__.py
@@ -110,6 +110,8 @@ _FIELD_FEATURES = {
     FeatureName.Position: "elapsedTimeTimestamp",
 }  # type: Dict[FeatureName, str]
 
+DELAY_BETWEEN_COMMANDS = 0.1
+
 
 def _cocoa_to_timestamp(time):
     delta = datetime.datetime(2001, 1, 1) - datetime.datetime(1970, 1, 1)
@@ -527,6 +529,7 @@ class MrpPower(Power):
     async def turn_off(self, await_new_state: bool = False) -> None:
         """Turn device off."""
         await self.remote.home(InputAction.Hold)
+        await asyncio.sleep(DELAY_BETWEEN_COMMANDS)
         await self.remote.select()
 
         if await_new_state and self.power_state != PowerState.Off:


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index c06a3e99..121c427b 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -23,6 +23,8 @@ jobs:
           - 3.9
     steps:
     - uses: actions/checkout@v2
+      with:
+        fetch-depth: 2
     - name: Set up Python ${{ matrix.python-version }}
       uses: actions/setup-python@v2
       with:
@@ -62,7 +64,7 @@ jobs:
       run: tox -q -p auto -e regression
       if: matrix.python-version == '3.8' && runner.os == 'Linux'
     - name: Upload coverage to Codecov
-      uses: codecov/codecov-action@v1.0.13
+      uses: codecov/codecov-action@v1.2.1
       with:
         token: ${{ secrets.CODECOV_TOKEN }}
         file: ./coverage.xml
diff --git a/tests/mrp/test_mrp_functional.py b/tests/mrp/test_mrp_functional.py
index 7cce3130..23f2493b 100644
--- a/tests/mrp/test_mrp_functional.py
+++ b/tests/mrp/test_mrp_functional.py
@@ -1,5 +1,6 @@
 """Functional tests using the API with a fake Apple TV."""
 
+import math
 import logging
 from ipaddress import IPv4Address
 from aiohttp.test_utils import unittest_run_loop
@@ -19,7 +20,7 @@ from pyatv.conf import AirPlayService, MrpService, AppleTV
 from pyatv.mrp.protobuf import CommandInfo_pb2
 
 from tests import common_functional_tests
-from tests.utils import until, faketime
+from tests.utils import until, faketime, stub_sleep
 from tests.fake_device import FakeAppleTV
 from tests.fake_device.mrp import APP_NAME, PLAYER_IDENTIFIER
 from tests.fake_device.airplay import DEVICE_CREDENTIALS
@@ -247,6 +248,7 @@ class MRPFunctionalTest(common_functional_tests.CommonFunctionalTests):
 
         # Check if power state changes after turn_off command
         await self.atv.power.turn_off()
+        assert math.isclose(stub_sleep(), 0.1)
         await until(lambda: self.atv.power.power_state == PowerState.Off)
         await until(lambda: listener.old_state == PowerState.On)
         await until(lambda: listener.new_state == PowerState.Off)