Add sensor platform for husqvarna_automower (#110410)

* Add sensor platform for husqvarna_automower

* Adress review comments

* Try to fix test

* Improve sensors

* Address review

* Adapt some values

* Add test

* Add test for cutting blade usage time

* Import TEST_MOWER_ID

* Use a parenthesis around the lambda and indent it so it's easier to distinguish the entity description parameters from the lambda
This commit is contained in:
Thomas55555 2024-02-22 09:26:38 +01:00 committed by GitHub
parent e88dfd4f68
commit 6e91776d65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 886 additions and 3 deletions

View File

@ -18,9 +18,7 @@ from .coordinator import AutomowerDataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
PLATFORMS: list[Platform] = [
Platform.LAWN_MOWER,
]
PLATFORMS: list[Platform] = [Platform.LAWN_MOWER, Platform.SENSOR]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

View File

@ -0,0 +1,171 @@
"""Creates a the sensor entities for the mower."""
from collections.abc import Callable
from dataclasses import dataclass
import datetime
import logging
from aioautomower.model import MowerAttributes, MowerModes
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfLength, UnitOfTime
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .coordinator import AutomowerDataUpdateCoordinator
from .entity import AutomowerBaseEntity
_LOGGER = logging.getLogger(__name__)
@dataclass(frozen=True, kw_only=True)
class AutomowerSensorEntityDescription(SensorEntityDescription):
"""Describes Automower sensor entity."""
exists_fn: Callable[[MowerAttributes], bool] = lambda _: True
value_fn: Callable[[MowerAttributes], str]
SENSOR_TYPES: tuple[AutomowerSensorEntityDescription, ...] = (
AutomowerSensorEntityDescription(
key="battery_percent",
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.BATTERY,
native_unit_of_measurement=PERCENTAGE,
value_fn=lambda data: data.battery.battery_percent,
),
AutomowerSensorEntityDescription(
key="mode",
translation_key="mode",
device_class=SensorDeviceClass.ENUM,
options=[option.lower() for option in list(MowerModes)],
value_fn=(
lambda data: data.mower.mode.lower()
if data.mower.mode != MowerModes.UNKNOWN
else None
),
),
AutomowerSensorEntityDescription(
key="cutting_blade_usage_time",
translation_key="cutting_blade_usage_time",
state_class=SensorStateClass.TOTAL,
device_class=SensorDeviceClass.DURATION,
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,
),
AutomowerSensorEntityDescription(
key="total_charging_time",
translation_key="total_charging_time",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL,
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
suggested_unit_of_measurement=UnitOfTime.HOURS,
value_fn=lambda data: data.statistics.total_charging_time,
),
AutomowerSensorEntityDescription(
key="total_cutting_time",
translation_key="total_cutting_time",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL,
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
suggested_unit_of_measurement=UnitOfTime.HOURS,
value_fn=lambda data: data.statistics.total_cutting_time,
),
AutomowerSensorEntityDescription(
key="total_running_time",
translation_key="total_running_time",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL,
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
suggested_unit_of_measurement=UnitOfTime.HOURS,
value_fn=lambda data: data.statistics.total_running_time,
),
AutomowerSensorEntityDescription(
key="total_searching_time",
translation_key="total_searching_time",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL,
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
suggested_unit_of_measurement=UnitOfTime.HOURS,
value_fn=lambda data: data.statistics.total_searching_time,
),
AutomowerSensorEntityDescription(
key="number_of_charging_cycles",
translation_key="number_of_charging_cycles",
icon="mdi:battery-sync-outline",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL,
value_fn=lambda data: data.statistics.number_of_charging_cycles,
),
AutomowerSensorEntityDescription(
key="number_of_collisions",
translation_key="number_of_collisions",
icon="mdi:counter",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL,
value_fn=lambda data: data.statistics.number_of_collisions,
),
AutomowerSensorEntityDescription(
key="total_drive_distance",
translation_key="total_drive_distance",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL,
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=UnitOfLength.METERS,
suggested_unit_of_measurement=UnitOfLength.KILOMETERS,
value_fn=lambda data: data.statistics.total_drive_distance,
),
AutomowerSensorEntityDescription(
key="next_start_timestamp",
translation_key="next_start_timestamp",
device_class=SensorDeviceClass.TIMESTAMP,
value_fn=lambda data: data.planner.next_start_dateteime,
),
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up sensor platform."""
coordinator: AutomowerDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
AutomowerSensorEntity(mower_id, coordinator, description)
for mower_id in coordinator.data
for description in SENSOR_TYPES
if description.exists_fn(coordinator.data[mower_id])
)
class AutomowerSensorEntity(AutomowerBaseEntity, SensorEntity):
"""Defining the Automower Sensors with AutomowerSensorEntityDescription."""
entity_description: AutomowerSensorEntityDescription
def __init__(
self,
mower_id: str,
coordinator: AutomowerDataUpdateCoordinator,
description: AutomowerSensorEntityDescription,
) -> None:
"""Set up AutomowerSensors."""
super().__init__(mower_id, coordinator)
self.entity_description = description
self._attr_unique_id = f"{mower_id}_{description.key}"
@property
def native_value(self) -> str | int | datetime.datetime | None:
"""Return the state of the sensor."""
return self.entity_description.value_fn(self.mower_attributes)

View File

@ -22,5 +22,45 @@
"create_entry": {
"default": "[%key:common::config_flow::create_entry::authenticated%]"
}
},
"entity": {
"sensor": {
"number_of_charging_cycles": {
"name": "Number of charging cycles"
},
"number_of_collisions": {
"name": "Number of collisions"
},
"cutting_blade_usage_time": {
"name": "Cutting blade usage time"
},
"total_charging_time": {
"name": "Total charging time"
},
"total_cutting_time": {
"name": "Total cutting time"
},
"total_running_time": {
"name": "Total running time"
},
"total_searching_time": {
"name": "Total searching time"
},
"total_drive_distance": {
"name": "Total drive distance"
},
"next_start_timestamp": {
"name": "Next start"
},
"mode": {
"name": "Mode",
"state": {
"main_area": "Main area",
"secondary_area": "Secondary area",
"home": "Home",
"demo": "Demo"
}
}
}
}
}

View File

@ -1,4 +1,5 @@
"""Constants for Husqvarna Automower tests."""
CLIENT_ID = "1234"
CLIENT_SECRET = "5678"
TEST_MOWER_ID = "c7233734-b219-4287-a173-08e3643f89f0"
USER_ID = "123"

View File

@ -125,6 +125,7 @@
"mode": "EVENING_ONLY"
},
"statistics": {
"cuttingBladeUsageTime": 123,
"numberOfChargingCycles": 1380,
"numberOfCollisions": 11396,
"totalChargingTime": 4334400,

View File

@ -0,0 +1,574 @@
# serializer version: 1
# name: test_sensor[sensor.test_mower_1_battery-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_mower_1_battery',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.BATTERY: 'battery'>,
'original_icon': None,
'original_name': 'Battery',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_battery_percent',
'unit_of_measurement': '%',
})
# ---
# name: test_sensor[sensor.test_mower_1_battery-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'battery',
'friendly_name': 'Test Mower 1 Battery',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_battery',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': '100',
})
# ---
# name: test_sensor[sensor.test_mower_1_cutting_blade_usage_time-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_mower_1_cutting_blade_usage_time',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
}),
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Cutting blade usage time',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'cutting_blade_usage_time',
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_cutting_blade_usage_time',
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
})
# ---
# name: test_sensor[sensor.test_mower_1_cutting_blade_usage_time-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'Test Mower 1 Cutting blade usage time',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_cutting_blade_usage_time',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': '0.034',
})
# ---
# name: test_sensor[sensor.test_mower_1_mode-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'main_area',
'demo',
'secondary_area',
'home',
'unknown',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_mower_1_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Mode',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'mode',
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_mode',
'unit_of_measurement': None,
})
# ---
# name: test_sensor[sensor.test_mower_1_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Test Mower 1 Mode',
'options': list([
'main_area',
'demo',
'secondary_area',
'home',
'unknown',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_mode',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': 'main_area',
})
# ---
# name: test_sensor[sensor.test_mower_1_next_start-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_mower_1_next_start',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Next start',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'next_start_timestamp',
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_next_start_timestamp',
'unit_of_measurement': None,
})
# ---
# name: test_sensor[sensor.test_mower_1_next_start-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'timestamp',
'friendly_name': 'Test Mower 1 Next start',
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_next_start',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': '2023-06-05T19:00:00+00:00',
})
# ---
# name: test_sensor[sensor.test_mower_1_number_of_charging_cycles-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.test_mower_1_number_of_charging_cycles',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:battery-sync-outline',
'original_name': 'Number of charging cycles',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'number_of_charging_cycles',
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_number_of_charging_cycles',
'unit_of_measurement': None,
})
# ---
# name: test_sensor[sensor.test_mower_1_number_of_charging_cycles-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Test Mower 1 Number of charging cycles',
'icon': 'mdi:battery-sync-outline',
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_number_of_charging_cycles',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': '1380',
})
# ---
# name: test_sensor[sensor.test_mower_1_number_of_collisions-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.test_mower_1_number_of_collisions',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:counter',
'original_name': 'Number of collisions',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'number_of_collisions',
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_number_of_collisions',
'unit_of_measurement': None,
})
# ---
# name: test_sensor[sensor.test_mower_1_number_of_collisions-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Test Mower 1 Number of collisions',
'icon': 'mdi:counter',
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_number_of_collisions',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': '11396',
})
# ---
# name: test_sensor[sensor.test_mower_1_total_charging_time-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.test_mower_1_total_charging_time',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
}),
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Total charging time',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'total_charging_time',
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_total_charging_time',
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
})
# ---
# name: test_sensor[sensor.test_mower_1_total_charging_time-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'Test Mower 1 Total charging time',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_total_charging_time',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': '1204.000',
})
# ---
# name: test_sensor[sensor.test_mower_1_total_cutting_time-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.test_mower_1_total_cutting_time',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
}),
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Total cutting time',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'total_cutting_time',
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_total_cutting_time',
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
})
# ---
# name: test_sensor[sensor.test_mower_1_total_cutting_time-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'Test Mower 1 Total cutting time',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_total_cutting_time',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': '1165.000',
})
# ---
# name: test_sensor[sensor.test_mower_1_total_drive_distance-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.test_mower_1_total_drive_distance',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
}),
}),
'original_device_class': <SensorDeviceClass.DISTANCE: 'distance'>,
'original_icon': None,
'original_name': 'Total drive distance',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'total_drive_distance',
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_total_drive_distance',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
# name: test_sensor[sensor.test_mower_1_total_drive_distance-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'distance',
'friendly_name': 'Test Mower 1 Total drive distance',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_total_drive_distance',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': '1780.272',
})
# ---
# name: test_sensor[sensor.test_mower_1_total_running_time-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.test_mower_1_total_running_time',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
}),
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Total running time',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'total_running_time',
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_total_running_time',
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
})
# ---
# name: test_sensor[sensor.test_mower_1_total_running_time-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'Test Mower 1 Total running time',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_total_running_time',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': '1268.000',
})
# ---
# name: test_sensor[sensor.test_mower_1_total_searching_time-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.test_mower_1_total_searching_time',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor.private': dict({
'suggested_unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
}),
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Total searching time',
'platform': 'husqvarna_automower',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'total_searching_time',
'unique_id': 'c7233734-b219-4287-a173-08e3643f89f0_total_searching_time',
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
})
# ---
# name: test_sensor[sensor.test_mower_1_total_searching_time-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'Test Mower 1 Total searching time',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_mower_1_total_searching_time',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': '103.000',
})
# ---

View File

@ -0,0 +1,98 @@
"""Tests for sensor platform."""
from datetime import timedelta
from unittest.mock import AsyncMock, patch
from aioautomower.model import MowerModes
from aioautomower.utils import mower_list_to_dictionary_dataclass
from freezegun.api import FrozenDateTimeFactory
from syrupy import SnapshotAssertion
from homeassistant.components.husqvarna_automower.const import DOMAIN
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
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,
)
async def test_sensor_unknown_states(
hass: HomeAssistant,
mock_automower_client: AsyncMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> 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
assert state.state == "main_area"
values[TEST_MOWER_ID].mower.mode = MowerModes.UNKNOWN
mock_automower_client.get_status.return_value = values
freezer.tick(timedelta(minutes=5))
async_fire_time_changed(hass)
await hass.async_block_till_done()
state = hass.states.get("sensor.test_mower_1_mode")
assert state.state == "unknown"
async def test_cutting_blade_usage_time_sensor(
hass: HomeAssistant,
mock_automower_client: AsyncMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test if this sensor is only added, if data is available."""
await setup_integration(hass, mock_config_entry)
state = hass.states.get("sensor.test_mower_1_cutting_blade_usage_time")
assert state is not None
assert state.state == "0.034"
entry = hass.config_entries.async_entries(DOMAIN)[0]
await hass.config_entries.async_remove(entry.entry_id)
await hass.async_block_till_done()
values = mower_list_to_dictionary_dataclass(
load_json_value_fixture("mower.json", DOMAIN)
)
delattr(values[TEST_MOWER_ID].statistics, "cutting_blade_usage_time")
mock_automower_client.get_status.return_value = values
await setup_integration(hass, mock_config_entry)
state = hass.states.get("sensor.test_mower_1_cutting_blade_usage_time")
assert state is None
async def test_sensor(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_automower_client: AsyncMock,
mock_config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
) -> None:
"""Test states of the sensors."""
with patch(
"homeassistant.components.husqvarna_automower.PLATFORMS",
[Platform.SENSOR],
):
await setup_integration(hass, mock_config_entry)
entity_entries = er.async_entries_for_config_entry(
entity_registry, mock_config_entry.entry_id
)
assert entity_entries
for entity_entry in entity_entries:
assert hass.states.get(entity_entry.entity_id) == snapshot(
name=f"{entity_entry.entity_id}-state"
)
assert entity_entry == snapshot(name=f"{entity_entry.entity_id}-entry")