Bump aioautomower to 2024.10.3 (#128788)
parent
bd55fe868d
commit
1c5193aa4d
homeassistant/components/husqvarna_automower
|
@ -14,6 +14,7 @@ from homeassistant.helpers import (
|
|||
config_entry_oauth2_flow,
|
||||
device_registry as dr,
|
||||
)
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import api
|
||||
from .const import DOMAIN
|
||||
|
@ -48,7 +49,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: AutomowerConfigEntry) ->
|
|||
aiohttp_client.async_get_clientsession(hass),
|
||||
session,
|
||||
)
|
||||
automower_api = AutomowerSession(api_api)
|
||||
time_zone_str = str(dt_util.DEFAULT_TIME_ZONE)
|
||||
automower_api = AutomowerSession(
|
||||
api_api,
|
||||
await dt_util.async_get_time_zone(time_zone_str),
|
||||
)
|
||||
try:
|
||||
await api_api.async_get_access_token()
|
||||
except ClientResponseError as err:
|
||||
|
|
|
@ -11,7 +11,6 @@ from aioautomower.session import AutomowerSession
|
|||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import AutomowerConfigEntry
|
||||
from .coordinator import AutomowerDataUpdateCoordinator
|
||||
|
@ -24,19 +23,6 @@ from .entity import (
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def _async_set_time(
|
||||
session: AutomowerSession,
|
||||
mower_id: str,
|
||||
) -> None:
|
||||
"""Set datetime for the mower."""
|
||||
# dt_util returns the current (aware) local datetime, set in the frontend.
|
||||
# We assume it's the timezone in which the mower is.
|
||||
await session.commands.set_datetime(
|
||||
mower_id,
|
||||
dt_util.now(),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class AutomowerButtonEntityDescription(ButtonEntityDescription):
|
||||
"""Describes Automower button entities."""
|
||||
|
@ -58,7 +44,7 @@ MOWER_BUTTON_TYPES: tuple[AutomowerButtonEntityDescription, ...] = (
|
|||
key="sync_clock",
|
||||
translation_key="sync_clock",
|
||||
available_fn=_check_error_free,
|
||||
press_fn=_async_set_time,
|
||||
press_fn=lambda session, mower_id: session.commands.set_datetime(mower_id),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -60,8 +60,8 @@ class AutomowerCalendarEntity(AutomowerBaseEntity, CalendarEntity):
|
|||
]
|
||||
return CalendarEvent(
|
||||
summary=make_name_string(work_area_name, program_event.schedule_no),
|
||||
start=program_event.start.replace(tzinfo=dt_util.DEFAULT_TIME_ZONE),
|
||||
end=program_event.end.replace(tzinfo=dt_util.DEFAULT_TIME_ZONE),
|
||||
start=program_event.start,
|
||||
end=program_event.end,
|
||||
rrule=program_event.rrule_str,
|
||||
)
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
"documentation": "https://www.home-assistant.io/integrations/husqvarna_automower",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["aioautomower"],
|
||||
"requirements": ["aioautomower==2024.10.0"]
|
||||
"requirements": ["aioautomower==2024.10.3"]
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ from collections.abc import Callable, Mapping
|
|||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
import logging
|
||||
from operator import attrgetter
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from aioautomower.model import (
|
||||
MowerAttributes,
|
||||
|
@ -14,7 +14,6 @@ from aioautomower.model import (
|
|||
RestrictedReasons,
|
||||
WorkArea,
|
||||
)
|
||||
from aioautomower.utils import naive_to_aware
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
|
@ -26,7 +25,6 @@ from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfLength, UnitOf
|
|||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import AutomowerConfigEntry
|
||||
from .coordinator import AutomowerDataUpdateCoordinator
|
||||
|
@ -196,16 +194,16 @@ ERROR_STATES = {
|
|||
}
|
||||
|
||||
RESTRICTED_REASONS: list = [
|
||||
RestrictedReasons.ALL_WORK_AREAS_COMPLETED.lower(),
|
||||
RestrictedReasons.DAILY_LIMIT.lower(),
|
||||
RestrictedReasons.EXTERNAL.lower(),
|
||||
RestrictedReasons.FOTA.lower(),
|
||||
RestrictedReasons.FROST.lower(),
|
||||
RestrictedReasons.NONE.lower(),
|
||||
RestrictedReasons.NOT_APPLICABLE.lower(),
|
||||
RestrictedReasons.PARK_OVERRIDE.lower(),
|
||||
RestrictedReasons.SENSOR.lower(),
|
||||
RestrictedReasons.WEEK_SCHEDULE.lower(),
|
||||
RestrictedReasons.ALL_WORK_AREAS_COMPLETED,
|
||||
RestrictedReasons.DAILY_LIMIT,
|
||||
RestrictedReasons.EXTERNAL,
|
||||
RestrictedReasons.FOTA,
|
||||
RestrictedReasons.FROST,
|
||||
RestrictedReasons.NONE,
|
||||
RestrictedReasons.NOT_APPLICABLE,
|
||||
RestrictedReasons.PARK_OVERRIDE,
|
||||
RestrictedReasons.SENSOR,
|
||||
RestrictedReasons.WEEK_SCHEDULE,
|
||||
]
|
||||
|
||||
STATE_NO_WORK_AREA_ACTIVE = "no_work_area_active"
|
||||
|
@ -272,15 +270,15 @@ MOWER_SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
|
|||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
value_fn=lambda data: data.battery.battery_percent,
|
||||
value_fn=attrgetter("battery.battery_percent"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="mode",
|
||||
translation_key="mode",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
option_fn=lambda data: [option.lower() for option in list(MowerModes)],
|
||||
option_fn=lambda data: list(MowerModes),
|
||||
value_fn=(
|
||||
lambda data: data.mower.mode.lower()
|
||||
lambda data: data.mower.mode
|
||||
if data.mower.mode != MowerModes.UNKNOWN
|
||||
else None
|
||||
),
|
||||
|
@ -293,7 +291,7 @@ MOWER_SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
|
|||
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
exists_fn=lambda data: data.statistics.cutting_blade_usage_time is not None,
|
||||
value_fn=lambda data: data.statistics.cutting_blade_usage_time,
|
||||
value_fn=attrgetter("statistics.cutting_blade_usage_time"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="total_charging_time",
|
||||
|
@ -304,7 +302,7 @@ MOWER_SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
|
|||
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
exists_fn=lambda data: data.statistics.total_charging_time is not None,
|
||||
value_fn=lambda data: data.statistics.total_charging_time,
|
||||
value_fn=attrgetter("statistics.total_charging_time"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="total_cutting_time",
|
||||
|
@ -315,7 +313,7 @@ MOWER_SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
|
|||
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
exists_fn=lambda data: data.statistics.total_cutting_time is not None,
|
||||
value_fn=lambda data: data.statistics.total_cutting_time,
|
||||
value_fn=attrgetter("statistics.total_cutting_time"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="total_running_time",
|
||||
|
@ -326,7 +324,7 @@ MOWER_SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
|
|||
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
exists_fn=lambda data: data.statistics.total_running_time is not None,
|
||||
value_fn=lambda data: data.statistics.total_running_time,
|
||||
value_fn=attrgetter("statistics.total_running_time"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="total_searching_time",
|
||||
|
@ -337,7 +335,7 @@ MOWER_SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
|
|||
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||
suggested_unit_of_measurement=UnitOfTime.HOURS,
|
||||
exists_fn=lambda data: data.statistics.total_searching_time is not None,
|
||||
value_fn=lambda data: data.statistics.total_searching_time,
|
||||
value_fn=attrgetter("statistics.total_searching_time"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="number_of_charging_cycles",
|
||||
|
@ -345,7 +343,7 @@ MOWER_SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
|
|||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.TOTAL,
|
||||
exists_fn=lambda data: data.statistics.number_of_charging_cycles is not None,
|
||||
value_fn=lambda data: data.statistics.number_of_charging_cycles,
|
||||
value_fn=attrgetter("statistics.number_of_charging_cycles"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="number_of_collisions",
|
||||
|
@ -353,7 +351,7 @@ MOWER_SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
|
|||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.TOTAL,
|
||||
exists_fn=lambda data: data.statistics.number_of_collisions is not None,
|
||||
value_fn=lambda data: data.statistics.number_of_collisions,
|
||||
value_fn=attrgetter("statistics.number_of_collisions"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="total_drive_distance",
|
||||
|
@ -364,16 +362,13 @@ MOWER_SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
|
|||
native_unit_of_measurement=UnitOfLength.METERS,
|
||||
suggested_unit_of_measurement=UnitOfLength.KILOMETERS,
|
||||
exists_fn=lambda data: data.statistics.total_drive_distance is not None,
|
||||
value_fn=lambda data: data.statistics.total_drive_distance,
|
||||
value_fn=attrgetter("statistics.total_drive_distance"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="next_start_timestamp",
|
||||
translation_key="next_start_timestamp",
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
value_fn=lambda data: naive_to_aware(
|
||||
data.planner.next_start_datetime_naive,
|
||||
ZoneInfo(str(dt_util.DEFAULT_TIME_ZONE)),
|
||||
),
|
||||
value_fn=attrgetter("planner.next_start_datetime"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="error",
|
||||
|
@ -387,7 +382,7 @@ MOWER_SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
|
|||
translation_key="restricted_reason",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
option_fn=lambda data: RESTRICTED_REASONS,
|
||||
value_fn=lambda data: data.planner.restricted_reason.lower(),
|
||||
value_fn=attrgetter("planner.restricted_reason"),
|
||||
),
|
||||
AutomowerSensorEntityDescription(
|
||||
key="work_area",
|
||||
|
@ -417,17 +412,14 @@ WORK_AREA_SENSOR_TYPES: tuple[WorkAreaSensorEntityDescription, ...] = (
|
|||
exists_fn=lambda data: data.progress is not None,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
value_fn=lambda data: data.progress,
|
||||
value_fn=attrgetter("progress"),
|
||||
),
|
||||
WorkAreaSensorEntityDescription(
|
||||
key="last_time_completed",
|
||||
translation_key_fn=_work_area_translation_key,
|
||||
exists_fn=lambda data: data.last_time_completed_naive is not None,
|
||||
exists_fn=lambda data: data.last_time_completed is not None,
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
value_fn=lambda data: naive_to_aware(
|
||||
data.last_time_completed_naive,
|
||||
ZoneInfo(str(dt_util.DEFAULT_TIME_ZONE)),
|
||||
),
|
||||
value_fn=attrgetter("last_time_completed"),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ aioaseko==1.0.0
|
|||
aioasuswrt==1.4.0
|
||||
|
||||
# homeassistant.components.husqvarna_automower
|
||||
aioautomower==2024.10.0
|
||||
aioautomower==2024.10.3
|
||||
|
||||
# homeassistant.components.azure_devops
|
||||
aioazuredevops==2.2.1
|
||||
|
|
|
@ -186,7 +186,7 @@ aioaseko==1.0.0
|
|||
aioasuswrt==1.4.0
|
||||
|
||||
# homeassistant.components.husqvarna_automower
|
||||
aioautomower==2024.10.0
|
||||
aioautomower==2024.10.3
|
||||
|
||||
# homeassistant.components.azure_devops
|
||||
aioazuredevops==2.2.1
|
||||
|
|
|
@ -4,6 +4,7 @@ from collections.abc import Generator
|
|||
import time
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aioautomower.model import MowerAttributes
|
||||
from aioautomower.session import AutomowerSession, _MowerCommands
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from aiohttp import ClientWebSocketResponse
|
||||
|
@ -16,6 +17,7 @@ from homeassistant.components.application_credentials import (
|
|||
from homeassistant.components.husqvarna_automower.const import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import CLIENT_ID, CLIENT_SECRET, USER_ID
|
||||
|
||||
|
@ -40,6 +42,21 @@ def mock_scope() -> str:
|
|||
return "iam:read amc:api"
|
||||
|
||||
|
||||
@pytest.fixture(name="mower_time_zone")
|
||||
async def mock_time_zone(hass: HomeAssistant) -> dict[str, MowerAttributes]:
|
||||
"""Fixture to set correct scope for the token."""
|
||||
return await dt_util.async_get_time_zone("Europe/Berlin")
|
||||
|
||||
|
||||
@pytest.fixture(name="values")
|
||||
def mock_values(mower_time_zone) -> dict[str, MowerAttributes]:
|
||||
"""Fixture to set correct scope for the token."""
|
||||
return mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN),
|
||||
mower_time_zone,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_config_entry(jwt: str, expires_at: int, scope: str) -> MockConfigEntry:
|
||||
"""Return the default mocked config entry."""
|
||||
|
@ -81,17 +98,13 @@ async def setup_credentials(hass: HomeAssistant) -> None:
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_automower_client() -> Generator[AsyncMock]:
|
||||
def mock_automower_client(values) -> Generator[AsyncMock]:
|
||||
"""Mock a Husqvarna Automower client."""
|
||||
|
||||
mower_dict = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
|
||||
mock = AsyncMock(spec=AutomowerSession)
|
||||
mock.auth = AsyncMock(side_effect=ClientWebSocketResponse)
|
||||
mock.commands = AsyncMock(spec_set=_MowerCommands)
|
||||
mock.get_status.return_value = mower_dict
|
||||
mock.get_status.return_value = values
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.husqvarna_automower.AutomowerSession",
|
||||
|
|
|
@ -68,6 +68,11 @@
|
|||
'start': '2023-06-10T01:00:00+02:00',
|
||||
'summary': 'Back lawn schedule 2',
|
||||
}),
|
||||
dict({
|
||||
'end': '2023-06-12T09:00:00+02:00',
|
||||
'start': '2023-06-12T01:00:00+02:00',
|
||||
'summary': 'Back lawn schedule 2',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
'calendar.test_mower_2': dict({
|
||||
|
|
|
@ -68,31 +68,33 @@
|
|||
'status_dateteime': '2023-06-05T00:00:00+00:00',
|
||||
}),
|
||||
'mower': dict({
|
||||
'activity': 'PARKED_IN_CS',
|
||||
'activity': 'parked_in_cs',
|
||||
'error_code': 0,
|
||||
'error_datetime': None,
|
||||
'error_datetime_naive': None,
|
||||
'error_key': None,
|
||||
'error_timestamp': 0,
|
||||
'inactive_reason': 'NONE',
|
||||
'inactive_reason': 'none',
|
||||
'is_error_confirmable': False,
|
||||
'mode': 'MAIN_AREA',
|
||||
'state': 'RESTRICTED',
|
||||
'mode': 'main_area',
|
||||
'state': 'restricted',
|
||||
'work_area_id': 123456,
|
||||
'work_area_name': 'Front lawn',
|
||||
}),
|
||||
'planner': dict({
|
||||
'next_start': 1685991600000,
|
||||
'next_start_datetime': '2023-06-05T19:00:00+02:00',
|
||||
'next_start_datetime_naive': '2023-06-05T19:00:00',
|
||||
'override': dict({
|
||||
'action': 'NOT_ACTIVE',
|
||||
'action': 'not_active',
|
||||
}),
|
||||
'restricted_reason': 'WEEK_SCHEDULE',
|
||||
'restricted_reason': 'week_schedule',
|
||||
}),
|
||||
'positions': '**REDACTED**',
|
||||
'settings': dict({
|
||||
'cutting_height': 4,
|
||||
'headlight': dict({
|
||||
'mode': 'EVENING_ONLY',
|
||||
'mode': 'evening_only',
|
||||
}),
|
||||
}),
|
||||
'statistics': dict({
|
||||
|
@ -138,6 +140,7 @@
|
|||
'0': dict({
|
||||
'cutting_height': 50,
|
||||
'enabled': False,
|
||||
'last_time_completed': '2024-08-12T05:07:49+02:00',
|
||||
'last_time_completed_naive': '2024-08-12T05:07:49',
|
||||
'name': 'my_lawn',
|
||||
'progress': 20,
|
||||
|
@ -145,6 +148,7 @@
|
|||
'123456': dict({
|
||||
'cutting_height': 50,
|
||||
'enabled': True,
|
||||
'last_time_completed': '2024-08-12T07:54:29+02:00',
|
||||
'last_time_completed_naive': '2024-08-12T07:54:29',
|
||||
'name': 'Front lawn',
|
||||
'progress': 40,
|
||||
|
@ -152,6 +156,7 @@
|
|||
'654321': dict({
|
||||
'cutting_height': 25,
|
||||
'enabled': True,
|
||||
'last_time_completed': None,
|
||||
'last_time_completed_naive': None,
|
||||
'name': 'Back lawn',
|
||||
'progress': None,
|
||||
|
@ -165,7 +170,7 @@
|
|||
'auth_implementation': 'husqvarna_automower',
|
||||
'token': dict({
|
||||
'access_token': '**REDACTED**',
|
||||
'expires_at': 1685926800.0,
|
||||
'expires_at': 1685919600.0,
|
||||
'expires_in': 86399,
|
||||
'provider': 'husqvarna',
|
||||
'refresh_token': '**REDACTED**',
|
||||
|
|
|
@ -552,11 +552,11 @@
|
|||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'main_area',
|
||||
'demo',
|
||||
'secondary_area',
|
||||
'home',
|
||||
'unknown',
|
||||
<MowerModes.MAIN_AREA: 'main_area'>,
|
||||
<MowerModes.DEMO: 'demo'>,
|
||||
<MowerModes.SECONDARY_AREA: 'secondary_area'>,
|
||||
<MowerModes.HOME: 'home'>,
|
||||
<MowerModes.UNKNOWN: 'unknown'>,
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
|
@ -592,11 +592,11 @@
|
|||
'device_class': 'enum',
|
||||
'friendly_name': 'Test Mower 1 Mode',
|
||||
'options': list([
|
||||
'main_area',
|
||||
'demo',
|
||||
'secondary_area',
|
||||
'home',
|
||||
'unknown',
|
||||
<MowerModes.MAIN_AREA: 'main_area'>,
|
||||
<MowerModes.DEMO: 'demo'>,
|
||||
<MowerModes.SECONDARY_AREA: 'secondary_area'>,
|
||||
<MowerModes.HOME: 'home'>,
|
||||
<MowerModes.UNKNOWN: 'unknown'>,
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
|
@ -856,16 +856,16 @@
|
|||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'all_work_areas_completed',
|
||||
'daily_limit',
|
||||
'external',
|
||||
'fota',
|
||||
'frost',
|
||||
'none',
|
||||
'not_applicable',
|
||||
'park_override',
|
||||
'sensor',
|
||||
'week_schedule',
|
||||
<RestrictedReasons.ALL_WORK_AREAS_COMPLETED: 'all_work_areas_completed'>,
|
||||
<RestrictedReasons.DAILY_LIMIT: 'daily_limit'>,
|
||||
<RestrictedReasons.EXTERNAL: 'external'>,
|
||||
<RestrictedReasons.FOTA: 'fota'>,
|
||||
<RestrictedReasons.FROST: 'frost'>,
|
||||
<RestrictedReasons.NONE: 'none'>,
|
||||
<RestrictedReasons.NOT_APPLICABLE: 'not_applicable'>,
|
||||
<RestrictedReasons.PARK_OVERRIDE: 'park_override'>,
|
||||
<RestrictedReasons.SENSOR: 'sensor'>,
|
||||
<RestrictedReasons.WEEK_SCHEDULE: 'week_schedule'>,
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
|
@ -901,16 +901,16 @@
|
|||
'device_class': 'enum',
|
||||
'friendly_name': 'Test Mower 1 Restricted reason',
|
||||
'options': list([
|
||||
'all_work_areas_completed',
|
||||
'daily_limit',
|
||||
'external',
|
||||
'fota',
|
||||
'frost',
|
||||
'none',
|
||||
'not_applicable',
|
||||
'park_override',
|
||||
'sensor',
|
||||
'week_schedule',
|
||||
<RestrictedReasons.ALL_WORK_AREAS_COMPLETED: 'all_work_areas_completed'>,
|
||||
<RestrictedReasons.DAILY_LIMIT: 'daily_limit'>,
|
||||
<RestrictedReasons.EXTERNAL: 'external'>,
|
||||
<RestrictedReasons.FOTA: 'fota'>,
|
||||
<RestrictedReasons.FROST: 'frost'>,
|
||||
<RestrictedReasons.NONE: 'none'>,
|
||||
<RestrictedReasons.NOT_APPLICABLE: 'not_applicable'>,
|
||||
<RestrictedReasons.PARK_OVERRIDE: 'park_override'>,
|
||||
<RestrictedReasons.SENSOR: 'sensor'>,
|
||||
<RestrictedReasons.WEEK_SCHEDULE: 'week_schedule'>,
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
|
@ -1658,11 +1658,11 @@
|
|||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'main_area',
|
||||
'demo',
|
||||
'secondary_area',
|
||||
'home',
|
||||
'unknown',
|
||||
<MowerModes.MAIN_AREA: 'main_area'>,
|
||||
<MowerModes.DEMO: 'demo'>,
|
||||
<MowerModes.SECONDARY_AREA: 'secondary_area'>,
|
||||
<MowerModes.HOME: 'home'>,
|
||||
<MowerModes.UNKNOWN: 'unknown'>,
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
|
@ -1698,11 +1698,11 @@
|
|||
'device_class': 'enum',
|
||||
'friendly_name': 'Test Mower 2 Mode',
|
||||
'options': list([
|
||||
'main_area',
|
||||
'demo',
|
||||
'secondary_area',
|
||||
'home',
|
||||
'unknown',
|
||||
<MowerModes.MAIN_AREA: 'main_area'>,
|
||||
<MowerModes.DEMO: 'demo'>,
|
||||
<MowerModes.SECONDARY_AREA: 'secondary_area'>,
|
||||
<MowerModes.HOME: 'home'>,
|
||||
<MowerModes.UNKNOWN: 'unknown'>,
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
|
@ -1767,16 +1767,16 @@
|
|||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'all_work_areas_completed',
|
||||
'daily_limit',
|
||||
'external',
|
||||
'fota',
|
||||
'frost',
|
||||
'none',
|
||||
'not_applicable',
|
||||
'park_override',
|
||||
'sensor',
|
||||
'week_schedule',
|
||||
<RestrictedReasons.ALL_WORK_AREAS_COMPLETED: 'all_work_areas_completed'>,
|
||||
<RestrictedReasons.DAILY_LIMIT: 'daily_limit'>,
|
||||
<RestrictedReasons.EXTERNAL: 'external'>,
|
||||
<RestrictedReasons.FOTA: 'fota'>,
|
||||
<RestrictedReasons.FROST: 'frost'>,
|
||||
<RestrictedReasons.NONE: 'none'>,
|
||||
<RestrictedReasons.NOT_APPLICABLE: 'not_applicable'>,
|
||||
<RestrictedReasons.PARK_OVERRIDE: 'park_override'>,
|
||||
<RestrictedReasons.SENSOR: 'sensor'>,
|
||||
<RestrictedReasons.WEEK_SCHEDULE: 'week_schedule'>,
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
|
@ -1812,16 +1812,16 @@
|
|||
'device_class': 'enum',
|
||||
'friendly_name': 'Test Mower 2 Restricted reason',
|
||||
'options': list([
|
||||
'all_work_areas_completed',
|
||||
'daily_limit',
|
||||
'external',
|
||||
'fota',
|
||||
'frost',
|
||||
'none',
|
||||
'not_applicable',
|
||||
'park_override',
|
||||
'sensor',
|
||||
'week_schedule',
|
||||
<RestrictedReasons.ALL_WORK_AREAS_COMPLETED: 'all_work_areas_completed'>,
|
||||
<RestrictedReasons.DAILY_LIMIT: 'daily_limit'>,
|
||||
<RestrictedReasons.EXTERNAL: 'external'>,
|
||||
<RestrictedReasons.FOTA: 'fota'>,
|
||||
<RestrictedReasons.FROST: 'frost'>,
|
||||
<RestrictedReasons.NONE: 'none'>,
|
||||
<RestrictedReasons.NOT_APPLICABLE: 'not_applicable'>,
|
||||
<RestrictedReasons.PARK_OVERRIDE: 'park_override'>,
|
||||
<RestrictedReasons.SENSOR: 'sensor'>,
|
||||
<RestrictedReasons.WEEK_SCHEDULE: 'week_schedule'>,
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
|
|
|
@ -2,12 +2,10 @@
|
|||
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aioautomower.model import MowerActivities
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from aioautomower.model import MowerActivities, MowerAttributes
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from syrupy import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.husqvarna_automower.const import DOMAIN
|
||||
from homeassistant.components.husqvarna_automower.coordinator import SCAN_INTERVAL
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
@ -16,12 +14,7 @@ from homeassistant.helpers import entity_registry as er
|
|||
from . import setup_integration
|
||||
from .const import TEST_MOWER_ID
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
load_json_value_fixture,
|
||||
snapshot_platform,
|
||||
)
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
|
||||
|
||||
|
||||
async def test_binary_sensor_states(
|
||||
|
@ -29,11 +22,9 @@ async def test_binary_sensor_states(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test binary sensor states."""
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
state = hass.states.get("binary_sensor.test_mower_1_charging")
|
||||
assert state is not None
|
||||
|
|
|
@ -2,16 +2,14 @@
|
|||
|
||||
import datetime
|
||||
from unittest.mock import AsyncMock, patch
|
||||
import zoneinfo
|
||||
|
||||
from aioautomower.exceptions import ApiException
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from aioautomower.model import MowerAttributes
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
|
||||
from homeassistant.components.husqvarna_automower.const import DOMAIN
|
||||
from homeassistant.components.husqvarna_automower.coordinator import SCAN_INTERVAL
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
|
@ -26,12 +24,7 @@ from homeassistant.helpers import entity_registry as er
|
|||
from . import setup_integration
|
||||
from .const import TEST_MOWER_ID
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
load_json_value_fixture,
|
||||
snapshot_platform,
|
||||
)
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
|
||||
|
||||
|
||||
@pytest.mark.freeze_time(datetime.datetime(2023, 6, 5, tzinfo=datetime.UTC))
|
||||
|
@ -40,6 +33,7 @@ async def test_button_states_and_commands(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test error confirm button command."""
|
||||
entity_id = "button.test_mower_1_confirm_error"
|
||||
|
@ -48,9 +42,6 @@ async def test_button_states_and_commands(
|
|||
assert state.name == "Test Mower 1 Confirm error"
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
values[TEST_MOWER_ID].mower.is_error_confirmable = None
|
||||
mock_automower_client.get_status.return_value = values
|
||||
freezer.tick(SCAN_INTERVAL)
|
||||
|
@ -99,6 +90,7 @@ async def test_sync_clock(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test sync clock button command."""
|
||||
entity_id = "button.test_mower_1_sync_clock"
|
||||
|
@ -106,9 +98,6 @@ async def test_sync_clock(
|
|||
state = hass.states.get(entity_id)
|
||||
assert state.name == "Test Mower 1 Sync clock"
|
||||
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
mock_automower_client.get_status.return_value = values
|
||||
|
||||
await hass.services.async_call(
|
||||
|
@ -118,12 +107,7 @@ async def test_sync_clock(
|
|||
blocking=True,
|
||||
)
|
||||
mocked_method = mock_automower_client.commands.set_datetime
|
||||
# datetime(2024, 2, 29, 11, tzinfo=datetime.UTC) is in local time of the tests
|
||||
# datetime(2024, 2, 29, 12, tzinfo=zoneinfo.ZoneInfo(key='Europe/Berlin'))
|
||||
mocked_method.assert_called_once_with(
|
||||
TEST_MOWER_ID,
|
||||
datetime.datetime(2024, 2, 29, 12, tzinfo=zoneinfo.ZoneInfo("Europe/Berlin")),
|
||||
)
|
||||
mocked_method.assert_called_once_with(TEST_MOWER_ID)
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == "2024-02-29T11:00:00+00:00"
|
||||
|
|
|
@ -6,6 +6,7 @@ from http import HTTPStatus
|
|||
from typing import Any
|
||||
from unittest.mock import AsyncMock
|
||||
import urllib
|
||||
import zoneinfo
|
||||
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
|
@ -93,12 +94,16 @@ async def test_empty_calendar(
|
|||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
get_events: GetEventsFn,
|
||||
mower_time_zone: zoneinfo.ZoneInfo,
|
||||
) -> None:
|
||||
"""State if there is no schedule set."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
json_values = load_json_value_fixture("mower.json", DOMAIN)
|
||||
json_values["data"][0]["attributes"]["calendar"]["tasks"] = []
|
||||
values = mower_list_to_dictionary_dataclass(json_values)
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
json_values,
|
||||
mower_time_zone,
|
||||
)
|
||||
mock_automower_client.get_status.return_value = values
|
||||
freezer.tick(SCAN_INTERVAL)
|
||||
async_fire_time_changed(hass)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import datetime
|
||||
from unittest.mock import AsyncMock
|
||||
import zoneinfo
|
||||
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
@ -21,7 +22,9 @@ from tests.components.diagnostics import (
|
|||
from tests.typing import ClientSessionGenerator
|
||||
|
||||
|
||||
@pytest.mark.freeze_time(datetime.datetime(2023, 6, 5, tzinfo=datetime.UTC))
|
||||
@pytest.mark.freeze_time(
|
||||
datetime.datetime(2023, 6, 5, tzinfo=zoneinfo.ZoneInfo("Europe/Berlin"))
|
||||
)
|
||||
async def test_entry_diagnostics(
|
||||
hass: HomeAssistant,
|
||||
hass_client: ClientSessionGenerator,
|
||||
|
@ -40,7 +43,9 @@ async def test_entry_diagnostics(
|
|||
assert result == snapshot(exclude=props("created_at", "modified_at"))
|
||||
|
||||
|
||||
@pytest.mark.freeze_time(datetime.datetime(2023, 6, 5, tzinfo=datetime.UTC))
|
||||
@pytest.mark.freeze_time(
|
||||
datetime.datetime(2023, 6, 5, tzinfo=zoneinfo.ZoneInfo("Europe/Berlin"))
|
||||
)
|
||||
async def test_device_diagnostics(
|
||||
hass: HomeAssistant,
|
||||
hass_client: ClientSessionGenerator,
|
||||
|
|
|
@ -10,7 +10,7 @@ from aioautomower.exceptions import (
|
|||
AuthException,
|
||||
HusqvarnaWSServerHandshakeError,
|
||||
)
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from aioautomower.model import MowerAttributes
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
@ -23,11 +23,7 @@ from homeassistant.helpers import device_registry as dr, entity_registry as er
|
|||
from . import setup_integration
|
||||
from .const import TEST_MOWER_ID
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
load_json_value_fixture,
|
||||
)
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
|
||||
|
@ -172,12 +168,10 @@ async def test_workarea_deleted(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test if work area is deleted after removed."""
|
||||
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
current_entries = len(
|
||||
er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)
|
||||
|
@ -198,6 +192,7 @@ async def test_coordinator_automatic_registry_cleanup(
|
|||
mock_config_entry: MockConfigEntry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test automatic registry cleanup."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
@ -211,9 +206,6 @@ async def test_coordinator_automatic_registry_cleanup(
|
|||
dr.async_entries_for_config_entry(device_registry, entry.entry_id)
|
||||
)
|
||||
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
values.pop(TEST_MOWER_ID)
|
||||
mock_automower_client.get_status.return_value = values
|
||||
await hass.config_entries.async_reload(mock_config_entry.entry_id)
|
||||
|
|
|
@ -4,7 +4,7 @@ from datetime import timedelta
|
|||
from unittest.mock import AsyncMock
|
||||
|
||||
from aioautomower.exceptions import ApiException
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from aioautomower.model import MowerActivities, MowerAttributes, MowerStates
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from voluptuous.error import MultipleInvalid
|
||||
|
@ -18,11 +18,7 @@ from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
|||
from . import setup_integration
|
||||
from .const import TEST_MOWER_ID
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
load_json_value_fixture,
|
||||
)
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
|
||||
|
||||
async def test_lawn_mower_states(
|
||||
|
@ -30,21 +26,23 @@ async def test_lawn_mower_states(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test lawn_mower state."""
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
state = hass.states.get("lawn_mower.test_mower_1")
|
||||
assert state is not None
|
||||
assert state.state == LawnMowerActivity.DOCKED
|
||||
|
||||
for activity, state, expected_state in (
|
||||
("UNKNOWN", "PAUSED", LawnMowerActivity.PAUSED),
|
||||
("MOWING", "NOT_APPLICABLE", LawnMowerActivity.MOWING),
|
||||
("NOT_APPLICABLE", "ERROR", LawnMowerActivity.ERROR),
|
||||
("GOING_HOME", "IN_OPERATION", LawnMowerActivity.RETURNING),
|
||||
(MowerActivities.UNKNOWN, MowerStates.PAUSED, LawnMowerActivity.PAUSED),
|
||||
(MowerActivities.MOWING, MowerStates.NOT_APPLICABLE, LawnMowerActivity.MOWING),
|
||||
(MowerActivities.NOT_APPLICABLE, MowerStates.ERROR, LawnMowerActivity.ERROR),
|
||||
(
|
||||
MowerActivities.GOING_HOME,
|
||||
MowerStates.IN_OPERATION,
|
||||
LawnMowerActivity.RETURNING,
|
||||
),
|
||||
):
|
||||
values[TEST_MOWER_ID].mower.activity = activity
|
||||
values[TEST_MOWER_ID].mower.state = state
|
||||
|
@ -253,12 +251,10 @@ async def test_lawn_mower_wrong_service_commands(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test lawn_mower commands."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
values[TEST_MOWER_ID].capabilities.work_areas = mower_support_wa
|
||||
mock_automower_client.get_status.return_value = values
|
||||
freezer.tick(SCAN_INTERVAL)
|
||||
|
|
|
@ -4,15 +4,12 @@ from datetime import timedelta
|
|||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aioautomower.exceptions import ApiException
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from aioautomower.model import MowerAttributes
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.husqvarna_automower.const import (
|
||||
DOMAIN,
|
||||
EXECUTION_TIME_DELAY,
|
||||
)
|
||||
from homeassistant.components.husqvarna_automower.const import EXECUTION_TIME_DELAY
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
@ -21,12 +18,7 @@ from homeassistant.helpers import entity_registry as er
|
|||
from . import setup_integration
|
||||
from .const import TEST_MOWER_ID
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
load_json_value_fixture,
|
||||
snapshot_platform,
|
||||
)
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
|
@ -68,13 +60,11 @@ async def test_number_workarea_commands(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test number commands."""
|
||||
entity_id = "number.test_mower_1_front_lawn_cutting_height"
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
values[TEST_MOWER_ID].work_areas[123456].cutting_height = 75
|
||||
mock_automower_client.get_status.return_value = values
|
||||
mocked_method = AsyncMock()
|
||||
|
|
|
@ -3,12 +3,10 @@
|
|||
from unittest.mock import AsyncMock
|
||||
|
||||
from aioautomower.exceptions import ApiException
|
||||
from aioautomower.model import HeadlightModes
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from aioautomower.model import HeadlightModes, MowerAttributes
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.husqvarna_automower.const import DOMAIN
|
||||
from homeassistant.components.husqvarna_automower.coordinator import SCAN_INTERVAL
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
@ -16,11 +14,7 @@ from homeassistant.exceptions import HomeAssistantError
|
|||
from . import setup_integration
|
||||
from .const import TEST_MOWER_ID
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
load_json_value_fixture,
|
||||
)
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
|
||||
|
||||
async def test_select_states(
|
||||
|
@ -28,11 +22,9 @@ async def test_select_states(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test states of headlight mode select."""
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
state = hass.states.get("select.test_mower_1_headlight_mode")
|
||||
assert state is not None
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
"""Tests for sensor platform."""
|
||||
|
||||
import datetime
|
||||
from unittest.mock import AsyncMock, patch
|
||||
import zoneinfo
|
||||
|
||||
from aioautomower.model import MowerModes, MowerStates
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from aioautomower.model import MowerAttributes, MowerModes, MowerStates
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.husqvarna_automower.const import DOMAIN
|
||||
from homeassistant.components.husqvarna_automower.coordinator import SCAN_INTERVAL
|
||||
from homeassistant.const import STATE_UNKNOWN, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
@ -17,12 +17,7 @@ from homeassistant.helpers import entity_registry as er
|
|||
from . import setup_integration
|
||||
from .const import TEST_MOWER_ID
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
load_json_value_fixture,
|
||||
snapshot_platform,
|
||||
)
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
|
||||
|
||||
|
||||
async def test_sensor_unknown_states(
|
||||
|
@ -30,11 +25,9 @@ async def test_sensor_unknown_states(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test a sensor which returns unknown."""
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
state = hass.states.get("sensor.test_mower_1_mode")
|
||||
assert state is not None
|
||||
|
@ -63,11 +56,15 @@ async def test_cutting_blade_usage_time_sensor(
|
|||
assert state.state == "0.034"
|
||||
|
||||
|
||||
@pytest.mark.freeze_time(
|
||||
datetime.datetime(2023, 6, 5, tzinfo=zoneinfo.ZoneInfo("Europe/Berlin"))
|
||||
)
|
||||
async def test_next_start_sensor(
|
||||
hass: HomeAssistant,
|
||||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test if this sensor is only added, if data is available."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
@ -75,10 +72,7 @@ async def test_next_start_sensor(
|
|||
assert state is not None
|
||||
assert state.state == "2023-06-05T17:00:00+00:00"
|
||||
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
values[TEST_MOWER_ID].planner.next_start_datetime_naive = None
|
||||
values[TEST_MOWER_ID].planner.next_start_datetime = None
|
||||
mock_automower_client.get_status.return_value = values
|
||||
freezer.tick(SCAN_INTERVAL)
|
||||
async_fire_time_changed(hass)
|
||||
|
@ -92,6 +86,7 @@ async def test_work_area_sensor(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test the work area sensor."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
@ -99,9 +94,6 @@ async def test_work_area_sensor(
|
|||
assert state is not None
|
||||
assert state.state == "Front lawn"
|
||||
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
values[TEST_MOWER_ID].mower.work_area_id = None
|
||||
mock_automower_client.get_status.return_value = values
|
||||
freezer.tick(SCAN_INTERVAL)
|
||||
|
@ -137,13 +129,10 @@ async def test_statistics_not_available(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
sensor_to_test: str,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test if this sensor is only added, if data is available."""
|
||||
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
|
||||
delattr(values[TEST_MOWER_ID].statistics, sensor_to_test)
|
||||
mock_automower_client.get_status.return_value = values
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
@ -156,11 +145,9 @@ async def test_error_sensor(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test error sensor."""
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
for state, error_key, expected_state in (
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
from datetime import timedelta
|
||||
from unittest.mock import AsyncMock, patch
|
||||
import zoneinfo
|
||||
|
||||
from aioautomower.exceptions import ApiException
|
||||
from aioautomower.model import MowerModes
|
||||
from aioautomower.model import MowerAttributes, MowerModes
|
||||
from aioautomower.utils import mower_list_to_dictionary_dataclass
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
|
@ -46,11 +47,9 @@ async def test_switch_states(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test switch state."""
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
for mode, expected_state in (
|
||||
|
@ -122,12 +121,14 @@ async def test_stay_out_zone_switch_commands(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
mower_time_zone: zoneinfo.ZoneInfo,
|
||||
) -> None:
|
||||
"""Test switch commands."""
|
||||
entity_id = "switch.test_mower_1_avoid_danger_zone"
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
load_json_value_fixture("mower.json", DOMAIN),
|
||||
mower_time_zone,
|
||||
)
|
||||
values[TEST_MOWER_ID].stay_out_zones.zones[TEST_ZONE_ID].enabled = boolean
|
||||
mock_automower_client.get_status.return_value = values
|
||||
|
@ -177,12 +178,14 @@ async def test_work_area_switch_commands(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
mower_time_zone: zoneinfo.ZoneInfo,
|
||||
) -> None:
|
||||
"""Test switch commands."""
|
||||
entity_id = "switch.test_mower_1_my_lawn"
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
load_json_value_fixture("mower.json", DOMAIN),
|
||||
mower_time_zone,
|
||||
)
|
||||
values[TEST_MOWER_ID].work_areas[TEST_AREA_ID].enabled = boolean
|
||||
mock_automower_client.get_status.return_value = values
|
||||
|
@ -221,12 +224,9 @@ async def test_zones_deleted(
|
|||
mock_automower_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
values: dict[str, MowerAttributes],
|
||||
) -> None:
|
||||
"""Test if stay-out-zone is deleted after removed."""
|
||||
|
||||
values = mower_list_to_dictionary_dataclass(
|
||||
load_json_value_fixture("mower.json", DOMAIN)
|
||||
)
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
current_entries = len(
|
||||
er.async_entries_for_config_entry(entity_registry, mock_config_entry.entry_id)
|
||||
|
|
Loading…
Reference in New Issue