Refactor Husqvarna Automower (#117938)
parent
bc72f82776
commit
13385912d1
|
@ -1,6 +1,7 @@
|
|||
"""The constants for the Husqvarna Automower integration."""
|
||||
|
||||
DOMAIN = "husqvarna_automower"
|
||||
EXECUTION_TIME_DELAY = 5
|
||||
NAME = "Husqvarna Automower"
|
||||
OAUTH2_AUTHORIZE = "https://api.authentication.husqvarnagroup.dev/v1/oauth2/authorize"
|
||||
OAUTH2_TOKEN = "https://api.authentication.husqvarnagroup.dev/v1/oauth2/token"
|
||||
|
|
|
@ -12,13 +12,13 @@ from aioautomower.session import AutomowerSession
|
|||
|
||||
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory, Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .const import DOMAIN, EXECUTION_TIME_DELAY
|
||||
from .coordinator import AutomowerDataUpdateCoordinator
|
||||
from .entity import AutomowerControlEntity
|
||||
|
||||
|
@ -52,10 +52,6 @@ async def async_set_work_area_cutting_height(
|
|||
await coordinator.api.commands.set_cutting_height_workarea(
|
||||
mower_id, int(cheight), work_area_id
|
||||
)
|
||||
# As there are no updates from the websocket regarding work area changes,
|
||||
# we need to wait 5s and then poll the API.
|
||||
await asyncio.sleep(5)
|
||||
await coordinator.async_request_refresh()
|
||||
|
||||
|
||||
async def async_set_cutting_height(
|
||||
|
@ -189,6 +185,7 @@ class AutomowerWorkAreaNumberEntity(AutomowerControlEntity, NumberEntity):
|
|||
) -> None:
|
||||
"""Set up AutomowerNumberEntity."""
|
||||
super().__init__(mower_id, coordinator)
|
||||
self.coordinator = coordinator
|
||||
self.entity_description = description
|
||||
self.work_area_id = work_area_id
|
||||
self._attr_unique_id = f"{mower_id}_{work_area_id}_{description.key}"
|
||||
|
@ -221,6 +218,11 @@ class AutomowerWorkAreaNumberEntity(AutomowerControlEntity, NumberEntity):
|
|||
raise HomeAssistantError(
|
||||
f"Command couldn't be sent to the command queue: {exception}"
|
||||
) from exception
|
||||
else:
|
||||
# As there are no updates from the websocket regarding work area changes,
|
||||
# we need to wait 5s and then poll the API.
|
||||
await asyncio.sleep(EXECUTION_TIME_DELAY)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
|
||||
@callback
|
||||
|
@ -241,7 +243,10 @@ def async_remove_entities(
|
|||
for entity_entry in er.async_entries_for_config_entry(
|
||||
entity_reg, config_entry.entry_id
|
||||
):
|
||||
if entity_entry.unique_id.split("_")[0] == mower_id:
|
||||
if entity_entry.unique_id.endswith("cutting_height_work_area"):
|
||||
if entity_entry.unique_id not in active_work_areas:
|
||||
if (
|
||||
entity_entry.domain == Platform.NUMBER
|
||||
and (split := entity_entry.unique_id.split("_"))[0] == mower_id
|
||||
and split[-1] == "area"
|
||||
and entity_entry.unique_id not in active_work_areas
|
||||
):
|
||||
entity_reg.async_remove(entity_entry.entity_id)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""Creates a the sensor entities for the mower."""
|
||||
"""Creates the sensor entities for the mower."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
|
|
|
@ -15,12 +15,13 @@ from aioautomower.model import (
|
|||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .const import DOMAIN, EXECUTION_TIME_DELAY
|
||||
from .coordinator import AutomowerDataUpdateCoordinator
|
||||
from .entity import AutomowerControlEntity
|
||||
|
||||
|
@ -40,7 +41,6 @@ ERROR_STATES = [
|
|||
MowerStates.STOPPED,
|
||||
MowerStates.OFF,
|
||||
]
|
||||
EXECUTION_TIME = 5
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -172,7 +172,7 @@ class AutomowerStayOutZoneSwitchEntity(AutomowerControlEntity, SwitchEntity):
|
|||
else:
|
||||
# As there are no updates from the websocket regarding stay out zone changes,
|
||||
# we need to wait until the command is executed and then poll the API.
|
||||
await asyncio.sleep(EXECUTION_TIME)
|
||||
await asyncio.sleep(EXECUTION_TIME_DELAY)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
|
@ -188,7 +188,7 @@ class AutomowerStayOutZoneSwitchEntity(AutomowerControlEntity, SwitchEntity):
|
|||
else:
|
||||
# As there are no updates from the websocket regarding stay out zone changes,
|
||||
# we need to wait until the command is executed and then poll the API.
|
||||
await asyncio.sleep(EXECUTION_TIME)
|
||||
await asyncio.sleep(EXECUTION_TIME_DELAY)
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
|
||||
|
@ -211,7 +211,8 @@ def async_remove_entities(
|
|||
entity_reg, config_entry.entry_id
|
||||
):
|
||||
if (
|
||||
(split := entity_entry.unique_id.split("_"))[0] == mower_id
|
||||
entity_entry.domain == Platform.SWITCH
|
||||
and (split := entity_entry.unique_id.split("_"))[0] == mower_id
|
||||
and split[-1] == "zones"
|
||||
and entity_entry.unique_id not in active_zones
|
||||
):
|
||||
|
|
|
@ -4,6 +4,7 @@ from collections.abc import Generator
|
|||
import time
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aioautomower.session import AutomowerSession, _MowerCommands
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from aiohttp import ClientWebSocketResponse
|
||||
import pytest
|
||||
|
@ -82,20 +83,18 @@ async def setup_credentials(hass: HomeAssistant) -> None:
|
|||
@pytest.fixture
|
||||
def mock_automower_client() -> Generator[AsyncMock, None, None]:
|
||||
"""Mock a Husqvarna Automower client."""
|
||||
with patch(
|
||||
"homeassistant.components.husqvarna_automower.AutomowerSession",
|
||||
autospec=True,
|
||||
) as mock_client:
|
||||
client = mock_client.return_value
|
||||
client.get_status.return_value = mower_list_to_dictionary_dataclass(
|
||||
|
||||
mower_dict = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
|
||||
async def websocket_connect() -> ClientWebSocketResponse:
|
||||
"""Mock listen."""
|
||||
return ClientWebSocketResponse
|
||||
mock = AsyncMock(spec=AutomowerSession)
|
||||
mock.auth = AsyncMock(side_effect=ClientWebSocketResponse)
|
||||
mock.commands = AsyncMock(spec_set=_MowerCommands)
|
||||
mock.get_status.return_value = mower_dict
|
||||
|
||||
client.auth = AsyncMock(side_effect=websocket_connect)
|
||||
client.commands = AsyncMock()
|
||||
|
||||
yield client
|
||||
with patch(
|
||||
"homeassistant.components.husqvarna_automower.AutomowerSession",
|
||||
return_value=mock,
|
||||
):
|
||||
yield mock
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# serializer version: 1
|
||||
# name: test_sensor[binary_sensor.test_mower_1_charging-entry]
|
||||
# name: test_binary_sensor_snapshot[binary_sensor.test_mower_1_charging-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -32,7 +32,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[binary_sensor.test_mower_1_charging-state]
|
||||
# name: test_binary_sensor_snapshot[binary_sensor.test_mower_1_charging-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'battery_charging',
|
||||
|
@ -41,11 +41,12 @@
|
|||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.test_mower_1_charging',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[binary_sensor.test_mower_1_leaving_dock-entry]
|
||||
# name: test_binary_sensor_snapshot[binary_sensor.test_mower_1_leaving_dock-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -78,7 +79,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[binary_sensor.test_mower_1_leaving_dock-state]
|
||||
# name: test_binary_sensor_snapshot[binary_sensor.test_mower_1_leaving_dock-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Leaving dock',
|
||||
|
@ -86,11 +87,12 @@
|
|||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.test_mower_1_leaving_dock',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[binary_sensor.test_mower_1_returning_to_dock-entry]
|
||||
# name: test_binary_sensor_snapshot[binary_sensor.test_mower_1_returning_to_dock-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -123,145 +125,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[binary_sensor.test_mower_1_returning_to_dock-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Returning to dock',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.test_mower_1_returning_to_dock',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_binary_sensor[binary_sensor.test_mower_1_charging-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.test_mower_1_charging',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.BATTERY_CHARGING: 'battery_charging'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Charging',
|
||||
'platform': 'husqvarna_automower',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_battery_charging',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_binary_sensor[binary_sensor.test_mower_1_charging-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'battery_charging',
|
||||
'friendly_name': 'Test Mower 1 Charging',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.test_mower_1_charging',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_binary_sensor[binary_sensor.test_mower_1_leaving_dock-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.test_mower_1_leaving_dock',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Leaving dock',
|
||||
'platform': 'husqvarna_automower',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'leaving_dock',
|
||||
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_leaving_dock',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_binary_sensor[binary_sensor.test_mower_1_leaving_dock-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Leaving dock',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.test_mower_1_leaving_dock',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_binary_sensor[binary_sensor.test_mower_1_returning_to_dock-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.test_mower_1_returning_to_dock',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Returning to dock',
|
||||
'platform': 'husqvarna_automower',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'returning_to_dock',
|
||||
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_returning_to_dock',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_binary_sensor[binary_sensor.test_mower_1_returning_to_dock-state]
|
||||
# name: test_binary_sensor_snapshot[binary_sensor.test_mower_1_returning_to_dock-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Returning to dock',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# serializer version: 1
|
||||
# name: test_snapshot_number[number.test_mower_1_back_lawn_cutting_height-entry]
|
||||
# name: test_number_snapshot[number.test_mower_1_back_lawn_cutting_height-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -37,7 +37,7 @@
|
|||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_number[number.test_mower_1_back_lawn_cutting_height-state]
|
||||
# name: test_number_snapshot[number.test_mower_1_back_lawn_cutting_height-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Back lawn cutting height',
|
||||
|
@ -55,7 +55,7 @@
|
|||
'state': '25',
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_number[number.test_mower_1_cutting_height-entry]
|
||||
# name: test_number_snapshot[number.test_mower_1_cutting_height-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -93,7 +93,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_number[number.test_mower_1_cutting_height-state]
|
||||
# name: test_number_snapshot[number.test_mower_1_cutting_height-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Cutting height',
|
||||
|
@ -110,7 +110,7 @@
|
|||
'state': '4',
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_number[number.test_mower_1_front_lawn_cutting_height-entry]
|
||||
# name: test_number_snapshot[number.test_mower_1_front_lawn_cutting_height-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -148,7 +148,7 @@
|
|||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_number[number.test_mower_1_front_lawn_cutting_height-state]
|
||||
# name: test_number_snapshot[number.test_mower_1_front_lawn_cutting_height-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Front lawn cutting height',
|
||||
|
@ -166,7 +166,7 @@
|
|||
'state': '50',
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_number[number.test_mower_1_my_lawn_cutting_height-entry]
|
||||
# name: test_number_snapshot[number.test_mower_1_my_lawn_cutting_height-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -204,7 +204,7 @@
|
|||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_snapshot_number[number.test_mower_1_my_lawn_cutting_height-state]
|
||||
# name: test_number_snapshot[number.test_mower_1_my_lawn_cutting_height-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 My lawn cutting height ',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# serializer version: 1
|
||||
# name: test_sensor[sensor.test_mower_1_battery-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_battery-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -34,7 +34,7 @@
|
|||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_battery-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_battery-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'battery',
|
||||
|
@ -50,7 +50,7 @@
|
|||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_cutting_blade_usage_time-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_cutting_blade_usage_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -88,7 +88,7 @@
|
|||
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_cutting_blade_usage_time-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_cutting_blade_usage_time-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
|
@ -104,7 +104,7 @@
|
|||
'state': '0.034',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_error-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_error-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -283,7 +283,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_error-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_error-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'enum',
|
||||
|
@ -442,7 +442,7 @@
|
|||
'state': 'no_error',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_mode-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_mode-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -483,7 +483,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_mode-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_mode-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'enum',
|
||||
|
@ -504,7 +504,7 @@
|
|||
'state': 'main_area',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_next_start-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_next_start-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -537,7 +537,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_next_start-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_next_start-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'timestamp',
|
||||
|
@ -551,7 +551,7 @@
|
|||
'state': '2023-06-05T19:00:00+00:00',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_number_of_charging_cycles-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_number_of_charging_cycles-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -586,7 +586,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_number_of_charging_cycles-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_number_of_charging_cycles-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Number of charging cycles',
|
||||
|
@ -600,7 +600,7 @@
|
|||
'state': '1380',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_number_of_collisions-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_number_of_collisions-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -635,7 +635,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_number_of_collisions-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_number_of_collisions-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Number of collisions',
|
||||
|
@ -649,7 +649,7 @@
|
|||
'state': '11396',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_restricted_reason-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_restricted_reason-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -695,7 +695,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_restricted_reason-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_restricted_reason-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'enum',
|
||||
|
@ -721,7 +721,7 @@
|
|||
'state': 'week_schedule',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_total_charging_time-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_total_charging_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -759,7 +759,7 @@
|
|||
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_total_charging_time-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_total_charging_time-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
|
@ -775,7 +775,7 @@
|
|||
'state': '1204.000',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_total_cutting_time-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_total_cutting_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -813,7 +813,7 @@
|
|||
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_total_cutting_time-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_total_cutting_time-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
|
@ -829,7 +829,7 @@
|
|||
'state': '1165.000',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_total_drive_distance-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_total_drive_distance-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -867,7 +867,7 @@
|
|||
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_total_drive_distance-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_total_drive_distance-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'distance',
|
||||
|
@ -883,7 +883,7 @@
|
|||
'state': '1780.272',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_total_running_time-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_total_running_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -921,7 +921,7 @@
|
|||
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_total_running_time-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_total_running_time-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
|
@ -937,7 +937,7 @@
|
|||
'state': '1268.000',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_total_searching_time-entry]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_total_searching_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -975,7 +975,7 @@
|
|||
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor[sensor.test_mower_1_total_searching_time-state]
|
||||
# name: test_sensor_snapshot[sensor.test_mower_1_total_searching_time-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# serializer version: 1
|
||||
# name: test_switch[switch.test_mower_1_avoid_danger_zone-entry]
|
||||
# name: test_switch_snapshot[switch.test_mower_1_avoid_danger_zone-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -32,7 +32,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_switch[switch.test_mower_1_avoid_danger_zone-state]
|
||||
# name: test_switch_snapshot[switch.test_mower_1_avoid_danger_zone-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Avoid Danger Zone',
|
||||
|
@ -45,7 +45,7 @@
|
|||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_switch[switch.test_mower_1_avoid_springflowers-entry]
|
||||
# name: test_switch_snapshot[switch.test_mower_1_avoid_springflowers-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -78,7 +78,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_switch[switch.test_mower_1_avoid_springflowers-state]
|
||||
# name: test_switch_snapshot[switch.test_mower_1_avoid_springflowers-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Avoid Springflowers',
|
||||
|
@ -91,7 +91,7 @@
|
|||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_switch[switch.test_mower_1_enable_schedule-entry]
|
||||
# name: test_switch_snapshot[switch.test_mower_1_enable_schedule-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
|
@ -124,7 +124,7 @@
|
|||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_switch[switch.test_mower_1_enable_schedule-state]
|
||||
# name: test_switch_snapshot[switch.test_mower_1_enable_schedule-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Mower 1 Enable schedule',
|
||||
|
|
|
@ -59,14 +59,14 @@ async def test_binary_sensor_states(
|
|||
assert state.state == "on"
|
||||
|
||||
|
||||
async def test_snapshot_binary_sensor(
|
||||
async def test_binary_sensor_snapshot(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test states of the binary sensors."""
|
||||
"""Snapshot test states of the binary sensors."""
|
||||
with patch(
|
||||
"homeassistant.components.husqvarna_automower.PLATFORMS",
|
||||
[Platform.BINARY_SENSOR],
|
||||
|
|
|
@ -20,7 +20,7 @@ async def test_device_tracker_snapshot(
|
|||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test device tracker with a snapshot."""
|
||||
"""Snapshot test of the device tracker."""
|
||||
with patch(
|
||||
"homeassistant.components.husqvarna_automower.PLATFORMS",
|
||||
[Platform.DEVICE_TRACKER],
|
||||
|
|
|
@ -70,19 +70,16 @@ async def test_lawn_mower_commands(
|
|||
) -> None:
|
||||
"""Test lawn_mower commands."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
getattr(
|
||||
mock_automower_client.commands, aioautomower_command
|
||||
).side_effect = ApiException("Test error")
|
||||
|
||||
with pytest.raises(HomeAssistantError) as exc_info:
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match="Command couldn't be sent to the command queue: Test error",
|
||||
):
|
||||
await hass.services.async_call(
|
||||
domain="lawn_mower",
|
||||
service=service,
|
||||
service_data={"entity_id": "lawn_mower.test_mower_1"},
|
||||
blocking=True,
|
||||
)
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== "Command couldn't be sent to the command queue: Test error"
|
||||
)
|
||||
|
|
|
@ -36,10 +36,13 @@ async def test_number_commands(
|
|||
blocking=True,
|
||||
)
|
||||
mocked_method = mock_automower_client.commands.set_cutting_height
|
||||
assert len(mocked_method.mock_calls) == 1
|
||||
mocked_method.assert_called_once_with(TEST_MOWER_ID, 3)
|
||||
|
||||
mocked_method.side_effect = ApiException("Test error")
|
||||
with pytest.raises(HomeAssistantError) as exc_info:
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match="Command couldn't be sent to the command queue: Test error",
|
||||
):
|
||||
await hass.services.async_call(
|
||||
domain="number",
|
||||
service="set_value",
|
||||
|
@ -47,10 +50,6 @@ async def test_number_commands(
|
|||
service_data={"value": "3"},
|
||||
blocking=True,
|
||||
)
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== "Command couldn't be sent to the command queue: Test error"
|
||||
)
|
||||
assert len(mocked_method.mock_calls) == 2
|
||||
|
||||
|
||||
|
@ -78,13 +77,16 @@ async def test_number_workarea_commands(
|
|||
service_data={"value": "75"},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(mocked_method.mock_calls) == 1
|
||||
mocked_method.assert_called_once_with(TEST_MOWER_ID, 75, 123456)
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state is not None
|
||||
assert state.state == "75"
|
||||
|
||||
mocked_method.side_effect = ApiException("Test error")
|
||||
with pytest.raises(HomeAssistantError) as exc_info:
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match="Command couldn't be sent to the command queue: Test error",
|
||||
):
|
||||
await hass.services.async_call(
|
||||
domain="number",
|
||||
service="set_value",
|
||||
|
@ -92,10 +94,6 @@ async def test_number_workarea_commands(
|
|||
service_data={"value": "75"},
|
||||
blocking=True,
|
||||
)
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== "Command couldn't be sent to the command queue: Test error"
|
||||
)
|
||||
assert len(mocked_method.mock_calls) == 2
|
||||
|
||||
|
||||
|
@ -125,14 +123,14 @@ async def test_workarea_deleted(
|
|||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_snapshot_number(
|
||||
async def test_number_snapshot(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test states of the number entity."""
|
||||
"""Snapshot tests of the number entities."""
|
||||
with patch(
|
||||
"homeassistant.components.husqvarna_automower.PLATFORMS",
|
||||
[Platform.NUMBER],
|
||||
|
|
|
@ -82,10 +82,14 @@ async def test_select_commands(
|
|||
blocking=True,
|
||||
)
|
||||
mocked_method = mock_automower_client.commands.set_headlight_mode
|
||||
mocked_method.assert_called_once_with(TEST_MOWER_ID, service.upper())
|
||||
assert len(mocked_method.mock_calls) == 1
|
||||
|
||||
mocked_method.side_effect = ApiException("Test error")
|
||||
with pytest.raises(HomeAssistantError) as exc_info:
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match="Command couldn't be sent to the command queue: Test error",
|
||||
):
|
||||
await hass.services.async_call(
|
||||
domain="select",
|
||||
service="select_option",
|
||||
|
@ -95,8 +99,4 @@ async def test_select_commands(
|
|||
},
|
||||
blocking=True,
|
||||
)
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== "Command couldn't be sent to the command queue: Test error"
|
||||
)
|
||||
assert len(mocked_method.mock_calls) == 2
|
||||
|
|
|
@ -144,14 +144,14 @@ async def test_error_sensor(
|
|||
assert state.state == expected_state
|
||||
|
||||
|
||||
async def test_sensor(
|
||||
async def test_sensor_snapshot(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test states of the sensors."""
|
||||
"""Snapshot test of the sensors."""
|
||||
with patch(
|
||||
"homeassistant.components.husqvarna_automower.PLATFORMS",
|
||||
[Platform.SENSOR],
|
||||
|
|
|
@ -79,20 +79,19 @@ async def test_switch_commands(
|
|||
blocking=True,
|
||||
)
|
||||
mocked_method = getattr(mock_automower_client.commands, aioautomower_command)
|
||||
assert len(mocked_method.mock_calls) == 1
|
||||
mocked_method.assert_called_once_with(TEST_MOWER_ID)
|
||||
|
||||
mocked_method.side_effect = ApiException("Test error")
|
||||
with pytest.raises(HomeAssistantError) as exc_info:
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match="Command couldn't be sent to the command queue: Test error",
|
||||
):
|
||||
await hass.services.async_call(
|
||||
domain="switch",
|
||||
service=service,
|
||||
service_data={"entity_id": "switch.test_mower_1_enable_schedule"},
|
||||
blocking=True,
|
||||
)
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== "Command couldn't be sent to the command queue: Test error"
|
||||
)
|
||||
assert len(mocked_method.mock_calls) == 2
|
||||
|
||||
|
||||
|
@ -172,14 +171,14 @@ async def test_zones_deleted(
|
|||
) == (current_entries - 1)
|
||||
|
||||
|
||||
async def test_switch(
|
||||
async def test_switch_snapshot(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test states of the switch."""
|
||||
"""Snapshot tests of the switches."""
|
||||
with patch(
|
||||
"homeassistant.components.husqvarna_automower.PLATFORMS",
|
||||
[Platform.SWITCH],
|
||||
|
|
Loading…
Reference in New Issue