mirror of
https://github.com/home-assistant/core.git
synced 2025-07-09 14:27:07 +00:00
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:
parent
e88dfd4f68
commit
6e91776d65
@ -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:
|
||||
|
171
homeassistant/components/husqvarna_automower/sensor.py
Normal file
171
homeassistant/components/husqvarna_automower/sensor.py
Normal 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)
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -125,6 +125,7 @@
|
||||
"mode": "EVENING_ONLY"
|
||||
},
|
||||
"statistics": {
|
||||
"cuttingBladeUsageTime": 123,
|
||||
"numberOfChargingCycles": 1380,
|
||||
"numberOfCollisions": 11396,
|
||||
"totalChargingTime": 4334400,
|
||||
|
574
tests/components/husqvarna_automower/snapshots/test_sensor.ambr
Normal file
574
tests/components/husqvarna_automower/snapshots/test_sensor.ambr
Normal 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',
|
||||
})
|
||||
# ---
|
98
tests/components/husqvarna_automower/test_sensor.py
Normal file
98
tests/components/husqvarna_automower/test_sensor.py
Normal 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")
|
Loading…
x
Reference in New Issue
Block a user