mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +00:00
Update greeclimate to 2.0.0 (#121030)
Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
parent
e9e357b12e
commit
1163cc7cab
@ -18,3 +18,5 @@ FAN_MEDIUM_HIGH = "medium high"
|
|||||||
MAX_ERRORS = 2
|
MAX_ERRORS = 2
|
||||||
|
|
||||||
TARGET_TEMPERATURE_STEP = 1
|
TARGET_TEMPERATURE_STEP = 1
|
||||||
|
|
||||||
|
UPDATE_INTERVAL = 60
|
||||||
|
@ -2,16 +2,20 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from greeclimate.device import Device, DeviceInfo
|
from greeclimate.device import Device, DeviceInfo
|
||||||
from greeclimate.discovery import Discovery, Listener
|
from greeclimate.discovery import Discovery, Listener
|
||||||
from greeclimate.exceptions import DeviceNotBoundError, DeviceTimeoutError
|
from greeclimate.exceptions import DeviceNotBoundError, DeviceTimeoutError
|
||||||
|
from greeclimate.network import Response
|
||||||
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
from homeassistant.helpers.json import json_dumps
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
COORDINATORS,
|
COORDINATORS,
|
||||||
@ -19,12 +23,13 @@ from .const import (
|
|||||||
DISPATCH_DEVICE_DISCOVERED,
|
DISPATCH_DEVICE_DISCOVERED,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
MAX_ERRORS,
|
MAX_ERRORS,
|
||||||
|
UPDATE_INTERVAL,
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DeviceDataUpdateCoordinator(DataUpdateCoordinator):
|
class DeviceDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||||
"""Manages polling for state changes from the device."""
|
"""Manages polling for state changes from the device."""
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant, device: Device) -> None:
|
def __init__(self, hass: HomeAssistant, device: Device) -> None:
|
||||||
@ -34,28 +39,68 @@ class DeviceDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
hass,
|
hass,
|
||||||
_LOGGER,
|
_LOGGER,
|
||||||
name=f"{DOMAIN}-{device.device_info.name}",
|
name=f"{DOMAIN}-{device.device_info.name}",
|
||||||
update_interval=timedelta(seconds=60),
|
update_interval=timedelta(seconds=UPDATE_INTERVAL),
|
||||||
|
always_update=False,
|
||||||
)
|
)
|
||||||
self.device = device
|
self.device = device
|
||||||
self._error_count = 0
|
self.device.add_handler(Response.DATA, self.device_state_updated)
|
||||||
|
self.device.add_handler(Response.RESULT, self.device_state_updated)
|
||||||
|
|
||||||
async def _async_update_data(self):
|
self._error_count: int = 0
|
||||||
|
self._last_response_time: datetime = utcnow()
|
||||||
|
self._last_error_time: datetime | None = None
|
||||||
|
|
||||||
|
def device_state_updated(self, *args: Any) -> None:
|
||||||
|
"""Handle device state updates."""
|
||||||
|
_LOGGER.debug("Device state updated: %s", json_dumps(args))
|
||||||
|
self._error_count = 0
|
||||||
|
self._last_response_time = utcnow()
|
||||||
|
self.async_set_updated_data(self.device.raw_properties)
|
||||||
|
|
||||||
|
async def _async_update_data(self) -> dict[str, Any]:
|
||||||
"""Update the state of the device."""
|
"""Update the state of the device."""
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Updating device state: %s, error count: %d", self.name, self._error_count
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
await self.device.update_state()
|
await self.device.update_state()
|
||||||
except DeviceNotBoundError as error:
|
except DeviceNotBoundError as error:
|
||||||
raise UpdateFailed(f"Device {self.name} is unavailable") from error
|
raise UpdateFailed(
|
||||||
|
f"Device {self.name} is unavailable, device is not bound."
|
||||||
|
) from error
|
||||||
except DeviceTimeoutError as error:
|
except DeviceTimeoutError as error:
|
||||||
self._error_count += 1
|
self._error_count += 1
|
||||||
|
|
||||||
# Under normal conditions GREE units timeout every once in a while
|
# Under normal conditions GREE units timeout every once in a while
|
||||||
if self.last_update_success and self._error_count >= MAX_ERRORS:
|
if self.last_update_success and self._error_count >= MAX_ERRORS:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Device is unavailable: %s (%s)",
|
"Device %s is unavailable: %s", self.name, self.device.device_info
|
||||||
self.name,
|
|
||||||
self.device.device_info,
|
|
||||||
)
|
)
|
||||||
raise UpdateFailed(f"Device {self.name} is unavailable") from error
|
raise UpdateFailed(
|
||||||
|
f"Device {self.name} is unavailable, could not send update request"
|
||||||
|
) from error
|
||||||
|
else:
|
||||||
|
# raise update failed if time for more than MAX_ERRORS has passed since last update
|
||||||
|
now = utcnow()
|
||||||
|
elapsed_success = now - self._last_response_time
|
||||||
|
if self.update_interval and elapsed_success >= self.update_interval:
|
||||||
|
if not self._last_error_time or (
|
||||||
|
(now - self.update_interval) >= self._last_error_time
|
||||||
|
):
|
||||||
|
self._last_error_time = now
|
||||||
|
self._error_count += 1
|
||||||
|
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Device %s is unresponsive for %s seconds",
|
||||||
|
self.name,
|
||||||
|
elapsed_success,
|
||||||
|
)
|
||||||
|
if self.last_update_success and self._error_count >= MAX_ERRORS:
|
||||||
|
raise UpdateFailed(
|
||||||
|
f"Device {self.name} is unresponsive for too long and now unavailable"
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.device.raw_properties
|
||||||
|
|
||||||
async def push_state_update(self):
|
async def push_state_update(self):
|
||||||
"""Send state updates to the physical device."""
|
"""Send state updates to the physical device."""
|
||||||
|
@ -7,5 +7,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/gree",
|
"documentation": "https://www.home-assistant.io/integrations/gree",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"loggers": ["greeclimate"],
|
"loggers": ["greeclimate"],
|
||||||
"requirements": ["greeclimate==1.4.6"]
|
"requirements": ["greeclimate==2.0.0"]
|
||||||
}
|
}
|
||||||
|
@ -1010,7 +1010,7 @@ gpiozero==1.6.2
|
|||||||
gps3==0.33.3
|
gps3==0.33.3
|
||||||
|
|
||||||
# homeassistant.components.gree
|
# homeassistant.components.gree
|
||||||
greeclimate==1.4.6
|
greeclimate==2.0.0
|
||||||
|
|
||||||
# homeassistant.components.greeneye_monitor
|
# homeassistant.components.greeneye_monitor
|
||||||
greeneye_monitor==3.0.3
|
greeneye_monitor==3.0.3
|
||||||
|
@ -854,7 +854,7 @@ govee-local-api==1.5.1
|
|||||||
gps3==0.33.3
|
gps3==0.33.3
|
||||||
|
|
||||||
# homeassistant.components.gree
|
# homeassistant.components.gree
|
||||||
greeclimate==1.4.6
|
greeclimate==2.0.0
|
||||||
|
|
||||||
# homeassistant.components.greeneye_monitor
|
# homeassistant.components.greeneye_monitor
|
||||||
greeneye_monitor==3.0.3
|
greeneye_monitor==3.0.3
|
||||||
|
@ -5,8 +5,12 @@ from datetime import timedelta
|
|||||||
from freezegun.api import FrozenDateTimeFactory
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.climate import DOMAIN
|
from homeassistant.components.climate import DOMAIN, HVACMode
|
||||||
from homeassistant.components.gree.const import COORDINATORS, DOMAIN as GREE
|
from homeassistant.components.gree.const import (
|
||||||
|
COORDINATORS,
|
||||||
|
DOMAIN as GREE,
|
||||||
|
UPDATE_INTERVAL,
|
||||||
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
@ -69,3 +73,30 @@ async def test_discovery_after_setup(
|
|||||||
device_infos = [x.device.device_info for x in hass.data[GREE][COORDINATORS]]
|
device_infos = [x.device.device_info for x in hass.data[GREE][COORDINATORS]]
|
||||||
assert device_infos[0].ip == "1.1.1.2"
|
assert device_infos[0].ip == "1.1.1.2"
|
||||||
assert device_infos[1].ip == "2.2.2.1"
|
assert device_infos[1].ip == "2.2.2.1"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_coordinator_updates(
|
||||||
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device
|
||||||
|
) -> None:
|
||||||
|
"""Test gree devices update their state."""
|
||||||
|
await async_setup_gree(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(hass.states.async_all(DOMAIN)) == 1
|
||||||
|
|
||||||
|
callback = device().add_handler.call_args_list[0][0][1]
|
||||||
|
|
||||||
|
async def fake_update_state(*args) -> None:
|
||||||
|
"""Fake update state."""
|
||||||
|
device().power = True
|
||||||
|
callback()
|
||||||
|
|
||||||
|
device().update_state.side_effect = fake_update_state
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get(ENTITY_ID_1)
|
||||||
|
assert state is not None
|
||||||
|
assert state.state != HVACMode.OFF
|
||||||
|
@ -48,7 +48,12 @@ from homeassistant.components.gree.climate import (
|
|||||||
HVAC_MODES_REVERSE,
|
HVAC_MODES_REVERSE,
|
||||||
GreeClimateEntity,
|
GreeClimateEntity,
|
||||||
)
|
)
|
||||||
from homeassistant.components.gree.const import FAN_MEDIUM_HIGH, FAN_MEDIUM_LOW
|
from homeassistant.components.gree.const import (
|
||||||
|
DISCOVERY_SCAN_INTERVAL,
|
||||||
|
FAN_MEDIUM_HIGH,
|
||||||
|
FAN_MEDIUM_LOW,
|
||||||
|
UPDATE_INTERVAL,
|
||||||
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
ATTR_TEMPERATURE,
|
ATTR_TEMPERATURE,
|
||||||
@ -61,7 +66,6 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ServiceValidationError
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
import homeassistant.util.dt as dt_util
|
|
||||||
|
|
||||||
from .common import async_setup_gree, build_device_mock
|
from .common import async_setup_gree, build_device_mock
|
||||||
|
|
||||||
@ -70,12 +74,6 @@ from tests.common import async_fire_time_changed
|
|||||||
ENTITY_ID = f"{DOMAIN}.fake_device_1"
|
ENTITY_ID = f"{DOMAIN}.fake_device_1"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_now():
|
|
||||||
"""Fixture for dtutil.now."""
|
|
||||||
return dt_util.utcnow()
|
|
||||||
|
|
||||||
|
|
||||||
async def test_discovery_called_once(hass: HomeAssistant, discovery, device) -> None:
|
async def test_discovery_called_once(hass: HomeAssistant, discovery, device) -> None:
|
||||||
"""Test discovery is only ever called once."""
|
"""Test discovery is only ever called once."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
@ -104,7 +102,7 @@ async def test_discovery_setup(hass: HomeAssistant, discovery, device) -> None:
|
|||||||
|
|
||||||
|
|
||||||
async def test_discovery_setup_connection_error(
|
async def test_discovery_setup_connection_error(
|
||||||
hass: HomeAssistant, discovery, device, mock_now
|
hass: HomeAssistant, discovery, device
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test gree integration is setup."""
|
"""Test gree integration is setup."""
|
||||||
MockDevice1 = build_device_mock(
|
MockDevice1 = build_device_mock(
|
||||||
@ -126,7 +124,7 @@ async def test_discovery_setup_connection_error(
|
|||||||
|
|
||||||
|
|
||||||
async def test_discovery_after_setup(
|
async def test_discovery_after_setup(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device, mock_now
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test gree devices don't change after multiple discoveries."""
|
"""Test gree devices don't change after multiple discoveries."""
|
||||||
MockDevice1 = build_device_mock(
|
MockDevice1 = build_device_mock(
|
||||||
@ -142,8 +140,7 @@ async def test_discovery_after_setup(
|
|||||||
discovery.return_value.mock_devices = [MockDevice1, MockDevice2]
|
discovery.return_value.mock_devices = [MockDevice1, MockDevice2]
|
||||||
device.side_effect = [MockDevice1, MockDevice2]
|
device.side_effect = [MockDevice1, MockDevice2]
|
||||||
|
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass) # Update 1
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert discovery.return_value.scan_count == 1
|
assert discovery.return_value.scan_count == 1
|
||||||
assert len(hass.states.async_all(DOMAIN)) == 2
|
assert len(hass.states.async_all(DOMAIN)) == 2
|
||||||
@ -152,9 +149,8 @@ async def test_discovery_after_setup(
|
|||||||
discovery.return_value.mock_devices = [MockDevice1, MockDevice2]
|
discovery.return_value.mock_devices = [MockDevice1, MockDevice2]
|
||||||
device.side_effect = [MockDevice1, MockDevice2]
|
device.side_effect = [MockDevice1, MockDevice2]
|
||||||
|
|
||||||
next_update = mock_now + timedelta(minutes=6)
|
freezer.tick(timedelta(seconds=DISCOVERY_SCAN_INTERVAL))
|
||||||
freezer.move_to(next_update)
|
async_fire_time_changed(hass)
|
||||||
async_fire_time_changed(hass, next_update)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert discovery.return_value.scan_count == 2
|
assert discovery.return_value.scan_count == 2
|
||||||
@ -162,7 +158,7 @@ async def test_discovery_after_setup(
|
|||||||
|
|
||||||
|
|
||||||
async def test_discovery_add_device_after_setup(
|
async def test_discovery_add_device_after_setup(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device, mock_now
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test gree devices can be added after initial setup."""
|
"""Test gree devices can be added after initial setup."""
|
||||||
MockDevice1 = build_device_mock(
|
MockDevice1 = build_device_mock(
|
||||||
@ -178,6 +174,8 @@ async def test_discovery_add_device_after_setup(
|
|||||||
discovery.return_value.mock_devices = [MockDevice1]
|
discovery.return_value.mock_devices = [MockDevice1]
|
||||||
device.side_effect = [MockDevice1]
|
device.side_effect = [MockDevice1]
|
||||||
|
|
||||||
|
await async_setup_gree(hass) # Update 1
|
||||||
|
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -188,9 +186,8 @@ async def test_discovery_add_device_after_setup(
|
|||||||
discovery.return_value.mock_devices = [MockDevice2]
|
discovery.return_value.mock_devices = [MockDevice2]
|
||||||
device.side_effect = [MockDevice2]
|
device.side_effect = [MockDevice2]
|
||||||
|
|
||||||
next_update = mock_now + timedelta(minutes=6)
|
freezer.tick(timedelta(seconds=DISCOVERY_SCAN_INTERVAL))
|
||||||
freezer.move_to(next_update)
|
async_fire_time_changed(hass)
|
||||||
async_fire_time_changed(hass, next_update)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert discovery.return_value.scan_count == 2
|
assert discovery.return_value.scan_count == 2
|
||||||
@ -198,7 +195,7 @@ async def test_discovery_add_device_after_setup(
|
|||||||
|
|
||||||
|
|
||||||
async def test_discovery_device_bind_after_setup(
|
async def test_discovery_device_bind_after_setup(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device, mock_now
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test gree devices can be added after a late device bind."""
|
"""Test gree devices can be added after a late device bind."""
|
||||||
MockDevice1 = build_device_mock(
|
MockDevice1 = build_device_mock(
|
||||||
@ -210,8 +207,7 @@ async def test_discovery_device_bind_after_setup(
|
|||||||
discovery.return_value.mock_devices = [MockDevice1]
|
discovery.return_value.mock_devices = [MockDevice1]
|
||||||
device.return_value = MockDevice1
|
device.return_value = MockDevice1
|
||||||
|
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass) # Update 1
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert len(hass.states.async_all(DOMAIN)) == 1
|
assert len(hass.states.async_all(DOMAIN)) == 1
|
||||||
state = hass.states.get(ENTITY_ID)
|
state = hass.states.get(ENTITY_ID)
|
||||||
@ -222,9 +218,8 @@ async def test_discovery_device_bind_after_setup(
|
|||||||
MockDevice1.bind.side_effect = None
|
MockDevice1.bind.side_effect = None
|
||||||
MockDevice1.update_state.side_effect = None
|
MockDevice1.update_state.side_effect = None
|
||||||
|
|
||||||
next_update = mock_now + timedelta(minutes=5)
|
freezer.tick(timedelta(seconds=DISCOVERY_SCAN_INTERVAL))
|
||||||
freezer.move_to(next_update)
|
async_fire_time_changed(hass)
|
||||||
async_fire_time_changed(hass, next_update)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_ID)
|
state = hass.states.get(ENTITY_ID)
|
||||||
@ -232,7 +227,7 @@ async def test_discovery_device_bind_after_setup(
|
|||||||
|
|
||||||
|
|
||||||
async def test_update_connection_failure(
|
async def test_update_connection_failure(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, device, mock_now
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Testing update hvac connection failure exception."""
|
"""Testing update hvac connection failure exception."""
|
||||||
device().update_state.side_effect = [
|
device().update_state.side_effect = [
|
||||||
@ -241,36 +236,32 @@ async def test_update_connection_failure(
|
|||||||
DeviceTimeoutError,
|
DeviceTimeoutError,
|
||||||
]
|
]
|
||||||
|
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass) # Update 1
|
||||||
|
|
||||||
|
async def run_update():
|
||||||
|
freezer.tick(timedelta(seconds=UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
|
||||||
next_update = mock_now + timedelta(minutes=5)
|
|
||||||
freezer.move_to(next_update)
|
|
||||||
async_fire_time_changed(hass, next_update)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# First update to make the device available
|
# Update 2
|
||||||
|
await run_update()
|
||||||
state = hass.states.get(ENTITY_ID)
|
state = hass.states.get(ENTITY_ID)
|
||||||
assert state.name == "fake-device-1"
|
assert state.name == "fake-device-1"
|
||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
next_update = mock_now + timedelta(minutes=10)
|
# Update 3
|
||||||
freezer.move_to(next_update)
|
await run_update()
|
||||||
async_fire_time_changed(hass, next_update)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
next_update = mock_now + timedelta(minutes=15)
|
# Update 4
|
||||||
freezer.move_to(next_update)
|
await run_update()
|
||||||
async_fire_time_changed(hass, next_update)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
# Then two more update failures to make the device unavailable
|
|
||||||
state = hass.states.get(ENTITY_ID)
|
state = hass.states.get(ENTITY_ID)
|
||||||
assert state.name == "fake-device-1"
|
assert state.name == "fake-device-1"
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
async def test_update_connection_failure_recovery(
|
async def test_update_connection_send_failure_recovery(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device, mock_now
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Testing update hvac connection failure recovery."""
|
"""Testing update hvac connection failure recovery."""
|
||||||
device().update_state.side_effect = [
|
device().update_state.side_effect = [
|
||||||
@ -279,31 +270,27 @@ async def test_update_connection_failure_recovery(
|
|||||||
DEFAULT_MOCK,
|
DEFAULT_MOCK,
|
||||||
]
|
]
|
||||||
|
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass) # Update 1
|
||||||
|
|
||||||
|
async def run_update():
|
||||||
|
freezer.tick(timedelta(seconds=UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
|
||||||
# First update becomes unavailable
|
|
||||||
next_update = mock_now + timedelta(minutes=5)
|
|
||||||
freezer.move_to(next_update)
|
|
||||||
async_fire_time_changed(hass, next_update)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
await run_update() # Update 2
|
||||||
state = hass.states.get(ENTITY_ID)
|
state = hass.states.get(ENTITY_ID)
|
||||||
assert state.name == "fake-device-1"
|
assert state.name == "fake-device-1"
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
# Second update restores the connection
|
await run_update() # Update 3
|
||||||
next_update = mock_now + timedelta(minutes=10)
|
|
||||||
freezer.move_to(next_update)
|
|
||||||
async_fire_time_changed(hass, next_update)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_ID)
|
state = hass.states.get(ENTITY_ID)
|
||||||
assert state.name == "fake-device-1"
|
assert state.name == "fake-device-1"
|
||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
async def test_update_unhandled_exception(
|
async def test_update_unhandled_exception(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device, mock_now
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Testing update hvac connection unhandled response exception."""
|
"""Testing update hvac connection unhandled response exception."""
|
||||||
device().update_state.side_effect = [DEFAULT_MOCK, Exception]
|
device().update_state.side_effect = [DEFAULT_MOCK, Exception]
|
||||||
@ -314,9 +301,8 @@ async def test_update_unhandled_exception(
|
|||||||
assert state.name == "fake-device-1"
|
assert state.name == "fake-device-1"
|
||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
next_update = mock_now + timedelta(minutes=10)
|
freezer.tick(timedelta(seconds=UPDATE_INTERVAL))
|
||||||
freezer.move_to(next_update)
|
async_fire_time_changed(hass)
|
||||||
async_fire_time_changed(hass, next_update)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_ID)
|
state = hass.states.get(ENTITY_ID)
|
||||||
@ -325,15 +311,13 @@ async def test_update_unhandled_exception(
|
|||||||
|
|
||||||
|
|
||||||
async def test_send_command_device_timeout(
|
async def test_send_command_device_timeout(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device, mock_now
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for sending power on command to the device with a device timeout."""
|
"""Test for sending power on command to the device with a device timeout."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
# First update to make the device available
|
freezer.tick(timedelta(seconds=UPDATE_INTERVAL))
|
||||||
next_update = mock_now + timedelta(minutes=5)
|
async_fire_time_changed(hass)
|
||||||
freezer.move_to(next_update)
|
|
||||||
async_fire_time_changed(hass, next_update)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_ID)
|
state = hass.states.get(ENTITY_ID)
|
||||||
@ -355,7 +339,40 @@ async def test_send_command_device_timeout(
|
|||||||
assert state.state != STATE_UNAVAILABLE
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
async def test_send_power_on(hass: HomeAssistant, discovery, device, mock_now) -> None:
|
async def test_unresponsive_device(
|
||||||
|
hass: HomeAssistant, freezer: FrozenDateTimeFactory, discovery, device
|
||||||
|
) -> None:
|
||||||
|
"""Test for unresponsive device."""
|
||||||
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
|
async def run_update():
|
||||||
|
freezer.tick(timedelta(seconds=UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Update 2
|
||||||
|
await run_update()
|
||||||
|
state = hass.states.get(ENTITY_ID)
|
||||||
|
assert state.name == "fake-device-1"
|
||||||
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
# Update 3, 4, 5
|
||||||
|
await run_update()
|
||||||
|
await run_update()
|
||||||
|
await run_update()
|
||||||
|
state = hass.states.get(ENTITY_ID)
|
||||||
|
assert state.name == "fake-device-1"
|
||||||
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
# Receiving update from device will reset the state to available again
|
||||||
|
device().device_state_updated("test")
|
||||||
|
await run_update()
|
||||||
|
state = hass.states.get(ENTITY_ID)
|
||||||
|
assert state.name == "fake-device-1"
|
||||||
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
async def test_send_power_on(hass: HomeAssistant, discovery, device) -> None:
|
||||||
"""Test for sending power on command to the device."""
|
"""Test for sending power on command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
@ -372,7 +389,7 @@ async def test_send_power_on(hass: HomeAssistant, discovery, device, mock_now) -
|
|||||||
|
|
||||||
|
|
||||||
async def test_send_power_off_device_timeout(
|
async def test_send_power_off_device_timeout(
|
||||||
hass: HomeAssistant, discovery, device, mock_now
|
hass: HomeAssistant, discovery, device
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for sending power off command to the device with a device timeout."""
|
"""Test for sending power off command to the device with a device timeout."""
|
||||||
device().push_state_update.side_effect = DeviceTimeoutError
|
device().push_state_update.side_effect = DeviceTimeoutError
|
||||||
@ -543,9 +560,7 @@ async def test_update_target_temperature(
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"preset", [PRESET_AWAY, PRESET_ECO, PRESET_SLEEP, PRESET_BOOST, PRESET_NONE]
|
"preset", [PRESET_AWAY, PRESET_ECO, PRESET_SLEEP, PRESET_BOOST, PRESET_NONE]
|
||||||
)
|
)
|
||||||
async def test_send_preset_mode(
|
async def test_send_preset_mode(hass: HomeAssistant, discovery, device, preset) -> None:
|
||||||
hass: HomeAssistant, discovery, device, mock_now, preset
|
|
||||||
) -> None:
|
|
||||||
"""Test for sending preset mode command to the device."""
|
"""Test for sending preset mode command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
@ -561,9 +576,7 @@ async def test_send_preset_mode(
|
|||||||
assert state.attributes.get(ATTR_PRESET_MODE) == preset
|
assert state.attributes.get(ATTR_PRESET_MODE) == preset
|
||||||
|
|
||||||
|
|
||||||
async def test_send_invalid_preset_mode(
|
async def test_send_invalid_preset_mode(hass: HomeAssistant, discovery, device) -> None:
|
||||||
hass: HomeAssistant, discovery, device, mock_now
|
|
||||||
) -> None:
|
|
||||||
"""Test for sending preset mode command to the device."""
|
"""Test for sending preset mode command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
@ -584,7 +597,7 @@ async def test_send_invalid_preset_mode(
|
|||||||
"preset", [PRESET_AWAY, PRESET_ECO, PRESET_SLEEP, PRESET_BOOST, PRESET_NONE]
|
"preset", [PRESET_AWAY, PRESET_ECO, PRESET_SLEEP, PRESET_BOOST, PRESET_NONE]
|
||||||
)
|
)
|
||||||
async def test_send_preset_mode_device_timeout(
|
async def test_send_preset_mode_device_timeout(
|
||||||
hass: HomeAssistant, discovery, device, mock_now, preset
|
hass: HomeAssistant, discovery, device, preset
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for sending preset mode command to the device with a device timeout."""
|
"""Test for sending preset mode command to the device with a device timeout."""
|
||||||
device().push_state_update.side_effect = DeviceTimeoutError
|
device().push_state_update.side_effect = DeviceTimeoutError
|
||||||
@ -607,7 +620,7 @@ async def test_send_preset_mode_device_timeout(
|
|||||||
"preset", [PRESET_AWAY, PRESET_ECO, PRESET_SLEEP, PRESET_BOOST, PRESET_NONE]
|
"preset", [PRESET_AWAY, PRESET_ECO, PRESET_SLEEP, PRESET_BOOST, PRESET_NONE]
|
||||||
)
|
)
|
||||||
async def test_update_preset_mode(
|
async def test_update_preset_mode(
|
||||||
hass: HomeAssistant, discovery, device, mock_now, preset
|
hass: HomeAssistant, discovery, device, preset
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for updating preset mode from the device."""
|
"""Test for updating preset mode from the device."""
|
||||||
device().steady_heat = preset == PRESET_AWAY
|
device().steady_heat = preset == PRESET_AWAY
|
||||||
@ -634,7 +647,7 @@ async def test_update_preset_mode(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_send_hvac_mode(
|
async def test_send_hvac_mode(
|
||||||
hass: HomeAssistant, discovery, device, mock_now, hvac_mode
|
hass: HomeAssistant, discovery, device, hvac_mode
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for sending hvac mode command to the device."""
|
"""Test for sending hvac mode command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
@ -656,7 +669,7 @@ async def test_send_hvac_mode(
|
|||||||
[HVACMode.AUTO, HVACMode.COOL, HVACMode.DRY, HVACMode.FAN_ONLY, HVACMode.HEAT],
|
[HVACMode.AUTO, HVACMode.COOL, HVACMode.DRY, HVACMode.FAN_ONLY, HVACMode.HEAT],
|
||||||
)
|
)
|
||||||
async def test_send_hvac_mode_device_timeout(
|
async def test_send_hvac_mode_device_timeout(
|
||||||
hass: HomeAssistant, discovery, device, mock_now, hvac_mode
|
hass: HomeAssistant, discovery, device, hvac_mode
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for sending hvac mode command to the device with a device timeout."""
|
"""Test for sending hvac mode command to the device with a device timeout."""
|
||||||
device().push_state_update.side_effect = DeviceTimeoutError
|
device().push_state_update.side_effect = DeviceTimeoutError
|
||||||
@ -687,7 +700,7 @@ async def test_send_hvac_mode_device_timeout(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_update_hvac_mode(
|
async def test_update_hvac_mode(
|
||||||
hass: HomeAssistant, discovery, device, mock_now, hvac_mode
|
hass: HomeAssistant, discovery, device, hvac_mode
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for updating hvac mode from the device."""
|
"""Test for updating hvac mode from the device."""
|
||||||
device().power = hvac_mode != HVACMode.OFF
|
device().power = hvac_mode != HVACMode.OFF
|
||||||
@ -704,9 +717,7 @@ async def test_update_hvac_mode(
|
|||||||
"fan_mode",
|
"fan_mode",
|
||||||
[FAN_AUTO, FAN_LOW, FAN_MEDIUM_LOW, FAN_MEDIUM, FAN_MEDIUM_HIGH, FAN_HIGH],
|
[FAN_AUTO, FAN_LOW, FAN_MEDIUM_LOW, FAN_MEDIUM, FAN_MEDIUM_HIGH, FAN_HIGH],
|
||||||
)
|
)
|
||||||
async def test_send_fan_mode(
|
async def test_send_fan_mode(hass: HomeAssistant, discovery, device, fan_mode) -> None:
|
||||||
hass: HomeAssistant, discovery, device, mock_now, fan_mode
|
|
||||||
) -> None:
|
|
||||||
"""Test for sending fan mode command to the device."""
|
"""Test for sending fan mode command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
@ -722,9 +733,7 @@ async def test_send_fan_mode(
|
|||||||
assert state.attributes.get(ATTR_FAN_MODE) == fan_mode
|
assert state.attributes.get(ATTR_FAN_MODE) == fan_mode
|
||||||
|
|
||||||
|
|
||||||
async def test_send_invalid_fan_mode(
|
async def test_send_invalid_fan_mode(hass: HomeAssistant, discovery, device) -> None:
|
||||||
hass: HomeAssistant, discovery, device, mock_now
|
|
||||||
) -> None:
|
|
||||||
"""Test for sending fan mode command to the device."""
|
"""Test for sending fan mode command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
@ -746,7 +755,7 @@ async def test_send_invalid_fan_mode(
|
|||||||
[FAN_AUTO, FAN_LOW, FAN_MEDIUM_LOW, FAN_MEDIUM, FAN_MEDIUM_HIGH, FAN_HIGH],
|
[FAN_AUTO, FAN_LOW, FAN_MEDIUM_LOW, FAN_MEDIUM, FAN_MEDIUM_HIGH, FAN_HIGH],
|
||||||
)
|
)
|
||||||
async def test_send_fan_mode_device_timeout(
|
async def test_send_fan_mode_device_timeout(
|
||||||
hass: HomeAssistant, discovery, device, mock_now, fan_mode
|
hass: HomeAssistant, discovery, device, fan_mode
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for sending fan mode command to the device with a device timeout."""
|
"""Test for sending fan mode command to the device with a device timeout."""
|
||||||
device().push_state_update.side_effect = DeviceTimeoutError
|
device().push_state_update.side_effect = DeviceTimeoutError
|
||||||
@ -770,7 +779,7 @@ async def test_send_fan_mode_device_timeout(
|
|||||||
[FAN_AUTO, FAN_LOW, FAN_MEDIUM_LOW, FAN_MEDIUM, FAN_MEDIUM_HIGH, FAN_HIGH],
|
[FAN_AUTO, FAN_LOW, FAN_MEDIUM_LOW, FAN_MEDIUM, FAN_MEDIUM_HIGH, FAN_HIGH],
|
||||||
)
|
)
|
||||||
async def test_update_fan_mode(
|
async def test_update_fan_mode(
|
||||||
hass: HomeAssistant, discovery, device, mock_now, fan_mode
|
hass: HomeAssistant, discovery, device, fan_mode
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for updating fan mode from the device."""
|
"""Test for updating fan mode from the device."""
|
||||||
device().fan_speed = FAN_MODES_REVERSE.get(fan_mode)
|
device().fan_speed = FAN_MODES_REVERSE.get(fan_mode)
|
||||||
@ -786,7 +795,7 @@ async def test_update_fan_mode(
|
|||||||
"swing_mode", [SWING_OFF, SWING_BOTH, SWING_VERTICAL, SWING_HORIZONTAL]
|
"swing_mode", [SWING_OFF, SWING_BOTH, SWING_VERTICAL, SWING_HORIZONTAL]
|
||||||
)
|
)
|
||||||
async def test_send_swing_mode(
|
async def test_send_swing_mode(
|
||||||
hass: HomeAssistant, discovery, device, mock_now, swing_mode
|
hass: HomeAssistant, discovery, device, swing_mode
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for sending swing mode command to the device."""
|
"""Test for sending swing mode command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
@ -803,9 +812,7 @@ async def test_send_swing_mode(
|
|||||||
assert state.attributes.get(ATTR_SWING_MODE) == swing_mode
|
assert state.attributes.get(ATTR_SWING_MODE) == swing_mode
|
||||||
|
|
||||||
|
|
||||||
async def test_send_invalid_swing_mode(
|
async def test_send_invalid_swing_mode(hass: HomeAssistant, discovery, device) -> None:
|
||||||
hass: HomeAssistant, discovery, device, mock_now
|
|
||||||
) -> None:
|
|
||||||
"""Test for sending swing mode command to the device."""
|
"""Test for sending swing mode command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
@ -826,7 +833,7 @@ async def test_send_invalid_swing_mode(
|
|||||||
"swing_mode", [SWING_OFF, SWING_BOTH, SWING_VERTICAL, SWING_HORIZONTAL]
|
"swing_mode", [SWING_OFF, SWING_BOTH, SWING_VERTICAL, SWING_HORIZONTAL]
|
||||||
)
|
)
|
||||||
async def test_send_swing_mode_device_timeout(
|
async def test_send_swing_mode_device_timeout(
|
||||||
hass: HomeAssistant, discovery, device, mock_now, swing_mode
|
hass: HomeAssistant, discovery, device, swing_mode
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for sending swing mode command to the device with a device timeout."""
|
"""Test for sending swing mode command to the device with a device timeout."""
|
||||||
device().push_state_update.side_effect = DeviceTimeoutError
|
device().push_state_update.side_effect = DeviceTimeoutError
|
||||||
@ -849,7 +856,7 @@ async def test_send_swing_mode_device_timeout(
|
|||||||
"swing_mode", [SWING_OFF, SWING_BOTH, SWING_VERTICAL, SWING_HORIZONTAL]
|
"swing_mode", [SWING_OFF, SWING_BOTH, SWING_VERTICAL, SWING_HORIZONTAL]
|
||||||
)
|
)
|
||||||
async def test_update_swing_mode(
|
async def test_update_swing_mode(
|
||||||
hass: HomeAssistant, discovery, device, mock_now, swing_mode
|
hass: HomeAssistant, discovery, device, swing_mode
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test for updating swing mode from the device."""
|
"""Test for updating swing mode from the device."""
|
||||||
device().horizontal_swing = (
|
device().horizontal_swing = (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user