mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Add moisture sensors entities for gardena (#98282)
Add support for soil moisture sensors for gardena
This commit is contained in:
parent
364d872a47
commit
816f834807
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
from gardena_bluetooth.const import Valve
|
from gardena_bluetooth.const import Sensor, Valve
|
||||||
from gardena_bluetooth.parse import CharacteristicBool
|
from gardena_bluetooth.parse import CharacteristicBool
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import (
|
from homeassistant.components.binary_sensor import (
|
||||||
@ -26,6 +26,11 @@ class GardenaBluetoothBinarySensorEntityDescription(BinarySensorEntityDescriptio
|
|||||||
|
|
||||||
char: CharacteristicBool = field(default_factory=lambda: CharacteristicBool(""))
|
char: CharacteristicBool = field(default_factory=lambda: CharacteristicBool(""))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def context(self) -> set[str]:
|
||||||
|
"""Context needed for update coordinator."""
|
||||||
|
return {self.char.uuid}
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTIONS = (
|
DESCRIPTIONS = (
|
||||||
GardenaBluetoothBinarySensorEntityDescription(
|
GardenaBluetoothBinarySensorEntityDescription(
|
||||||
@ -35,6 +40,13 @@ DESCRIPTIONS = (
|
|||||||
entity_category=EntityCategory.DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
char=Valve.connected_state,
|
char=Valve.connected_state,
|
||||||
),
|
),
|
||||||
|
GardenaBluetoothBinarySensorEntityDescription(
|
||||||
|
key=Sensor.connected_state.uuid,
|
||||||
|
translation_key="sensor_connected_state",
|
||||||
|
device_class=BinarySensorDeviceClass.CONNECTIVITY,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
char=Sensor.connected_state,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -44,7 +56,7 @@ async def async_setup_entry(
|
|||||||
"""Set up binary sensor based on a config entry."""
|
"""Set up binary sensor based on a config entry."""
|
||||||
coordinator: Coordinator = hass.data[DOMAIN][entry.entry_id]
|
coordinator: Coordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
entities = [
|
entities = [
|
||||||
GardenaBluetoothBinarySensor(coordinator, description)
|
GardenaBluetoothBinarySensor(coordinator, description, description.context)
|
||||||
for description in DESCRIPTIONS
|
for description in DESCRIPTIONS
|
||||||
if description.key in coordinator.characteristics
|
if description.key in coordinator.characteristics
|
||||||
]
|
]
|
||||||
|
@ -22,6 +22,11 @@ class GardenaBluetoothButtonEntityDescription(ButtonEntityDescription):
|
|||||||
|
|
||||||
char: CharacteristicBool = field(default_factory=lambda: CharacteristicBool(""))
|
char: CharacteristicBool = field(default_factory=lambda: CharacteristicBool(""))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def context(self) -> set[str]:
|
||||||
|
"""Context needed for update coordinator."""
|
||||||
|
return {self.char.uuid}
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTIONS = (
|
DESCRIPTIONS = (
|
||||||
GardenaBluetoothButtonEntityDescription(
|
GardenaBluetoothButtonEntityDescription(
|
||||||
@ -40,7 +45,7 @@ async def async_setup_entry(
|
|||||||
"""Set up button based on a config entry."""
|
"""Set up button based on a config entry."""
|
||||||
coordinator: Coordinator = hass.data[DOMAIN][entry.entry_id]
|
coordinator: Coordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
entities = [
|
entities = [
|
||||||
GardenaBluetoothButton(coordinator, description)
|
GardenaBluetoothButton(coordinator, description, description.context)
|
||||||
for description in DESCRIPTIONS
|
for description in DESCRIPTIONS
|
||||||
if description.key in coordinator.characteristics
|
if description.key in coordinator.characteristics
|
||||||
]
|
]
|
||||||
|
@ -117,18 +117,25 @@ class GardenaBluetoothEntity(CoordinatorEntity[Coordinator]):
|
|||||||
@property
|
@property
|
||||||
def available(self) -> bool:
|
def available(self) -> bool:
|
||||||
"""Return if entity is available."""
|
"""Return if entity is available."""
|
||||||
return super().available and bluetooth.async_address_present(
|
return (
|
||||||
|
self.coordinator.last_update_success
|
||||||
|
and bluetooth.async_address_present(
|
||||||
self.hass, self.coordinator.address, True
|
self.hass, self.coordinator.address, True
|
||||||
)
|
)
|
||||||
|
and self._attr_available
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class GardenaBluetoothDescriptorEntity(GardenaBluetoothEntity):
|
class GardenaBluetoothDescriptorEntity(GardenaBluetoothEntity):
|
||||||
"""Coordinator entity for entities with entity description."""
|
"""Coordinator entity for entities with entity description."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, coordinator: Coordinator, description: EntityDescription
|
self,
|
||||||
|
coordinator: Coordinator,
|
||||||
|
description: EntityDescription,
|
||||||
|
context: set[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize description entity."""
|
"""Initialize description entity."""
|
||||||
super().__init__(coordinator, {description.key})
|
super().__init__(coordinator, context)
|
||||||
self._attr_unique_id = f"{coordinator.address}-{description.key}"
|
self._attr_unique_id = f"{coordinator.address}-{description.key}"
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
|
@ -3,8 +3,9 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
from gardena_bluetooth.const import DeviceConfiguration, Valve
|
from gardena_bluetooth.const import DeviceConfiguration, Sensor, Valve
|
||||||
from gardena_bluetooth.parse import (
|
from gardena_bluetooth.parse import (
|
||||||
|
Characteristic,
|
||||||
CharacteristicInt,
|
CharacteristicInt,
|
||||||
CharacteristicLong,
|
CharacteristicLong,
|
||||||
CharacteristicUInt16,
|
CharacteristicUInt16,
|
||||||
@ -16,7 +17,7 @@ from homeassistant.components.number import (
|
|||||||
NumberMode,
|
NumberMode,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import EntityCategory, UnitOfTime
|
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfTime
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
@ -35,6 +36,15 @@ class GardenaBluetoothNumberEntityDescription(NumberEntityDescription):
|
|||||||
char: CharacteristicInt | CharacteristicUInt16 | CharacteristicLong = field(
|
char: CharacteristicInt | CharacteristicUInt16 | CharacteristicLong = field(
|
||||||
default_factory=lambda: CharacteristicInt("")
|
default_factory=lambda: CharacteristicInt("")
|
||||||
)
|
)
|
||||||
|
connected_state: Characteristic | None = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def context(self) -> set[str]:
|
||||||
|
"""Context needed for update coordinator."""
|
||||||
|
data = {self.char.uuid}
|
||||||
|
if self.connected_state:
|
||||||
|
data.add(self.connected_state.uuid)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTIONS = (
|
DESCRIPTIONS = (
|
||||||
@ -81,6 +91,18 @@ DESCRIPTIONS = (
|
|||||||
entity_category=EntityCategory.CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
char=DeviceConfiguration.seasonal_adjust,
|
char=DeviceConfiguration.seasonal_adjust,
|
||||||
),
|
),
|
||||||
|
GardenaBluetoothNumberEntityDescription(
|
||||||
|
key=Sensor.threshold.uuid,
|
||||||
|
translation_key="sensor_threshold",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
mode=NumberMode.BOX,
|
||||||
|
native_min_value=0.0,
|
||||||
|
native_max_value=100.0,
|
||||||
|
native_step=1.0,
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
char=Sensor.threshold,
|
||||||
|
connected_state=Sensor.connected_state,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -90,7 +112,7 @@ async def async_setup_entry(
|
|||||||
"""Set up entity based on a config entry."""
|
"""Set up entity based on a config entry."""
|
||||||
coordinator: Coordinator = hass.data[DOMAIN][entry.entry_id]
|
coordinator: Coordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
entities: list[NumberEntity] = [
|
entities: list[NumberEntity] = [
|
||||||
GardenaBluetoothNumber(coordinator, description)
|
GardenaBluetoothNumber(coordinator, description, description.context)
|
||||||
for description in DESCRIPTIONS
|
for description in DESCRIPTIONS
|
||||||
if description.key in coordinator.characteristics
|
if description.key in coordinator.characteristics
|
||||||
]
|
]
|
||||||
@ -110,6 +132,12 @@ class GardenaBluetoothNumber(GardenaBluetoothDescriptorEntity, NumberEntity):
|
|||||||
self._attr_native_value = None
|
self._attr_native_value = None
|
||||||
else:
|
else:
|
||||||
self._attr_native_value = float(data)
|
self._attr_native_value = float(data)
|
||||||
|
|
||||||
|
if char := self.entity_description.connected_state:
|
||||||
|
self._attr_available = bool(self.coordinator.get_cached(char))
|
||||||
|
else:
|
||||||
|
self._attr_available = True
|
||||||
|
|
||||||
super()._handle_coordinator_update()
|
super()._handle_coordinator_update()
|
||||||
|
|
||||||
async def async_set_native_value(self, value: float) -> None:
|
async def async_set_native_value(self, value: float) -> None:
|
||||||
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from datetime import UTC, datetime, timedelta
|
from datetime import UTC, datetime, timedelta
|
||||||
|
|
||||||
from gardena_bluetooth.const import Battery, Valve
|
from gardena_bluetooth.const import Battery, Sensor, Valve
|
||||||
from gardena_bluetooth.parse import Characteristic
|
from gardena_bluetooth.parse import Characteristic
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
@ -32,6 +32,15 @@ class GardenaBluetoothSensorEntityDescription(SensorEntityDescription):
|
|||||||
"""Description of entity."""
|
"""Description of entity."""
|
||||||
|
|
||||||
char: Characteristic = field(default_factory=lambda: Characteristic(""))
|
char: Characteristic = field(default_factory=lambda: Characteristic(""))
|
||||||
|
connected_state: Characteristic | None = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def context(self) -> set[str]:
|
||||||
|
"""Context needed for update coordinator."""
|
||||||
|
data = {self.char.uuid}
|
||||||
|
if self.connected_state:
|
||||||
|
data.add(self.connected_state.uuid)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTIONS = (
|
DESCRIPTIONS = (
|
||||||
@ -51,6 +60,40 @@ DESCRIPTIONS = (
|
|||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
char=Battery.battery_level,
|
char=Battery.battery_level,
|
||||||
),
|
),
|
||||||
|
GardenaBluetoothSensorEntityDescription(
|
||||||
|
key=Sensor.battery_level.uuid,
|
||||||
|
translation_key="sensor_battery_level",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
device_class=SensorDeviceClass.BATTERY,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
char=Sensor.battery_level,
|
||||||
|
connected_state=Sensor.connected_state,
|
||||||
|
),
|
||||||
|
GardenaBluetoothSensorEntityDescription(
|
||||||
|
key=Sensor.value.uuid,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
device_class=SensorDeviceClass.MOISTURE,
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
char=Sensor.value,
|
||||||
|
connected_state=Sensor.connected_state,
|
||||||
|
),
|
||||||
|
GardenaBluetoothSensorEntityDescription(
|
||||||
|
key=Sensor.type.uuid,
|
||||||
|
translation_key="sensor_type",
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
char=Sensor.type,
|
||||||
|
connected_state=Sensor.connected_state,
|
||||||
|
),
|
||||||
|
GardenaBluetoothSensorEntityDescription(
|
||||||
|
key=Sensor.measurement_timestamp.uuid,
|
||||||
|
translation_key="sensor_measurement_timestamp",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
device_class=SensorDeviceClass.TIMESTAMP,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
char=Sensor.measurement_timestamp,
|
||||||
|
connected_state=Sensor.connected_state,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -60,7 +103,7 @@ async def async_setup_entry(
|
|||||||
"""Set up Gardena Bluetooth sensor based on a config entry."""
|
"""Set up Gardena Bluetooth sensor based on a config entry."""
|
||||||
coordinator: Coordinator = hass.data[DOMAIN][entry.entry_id]
|
coordinator: Coordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
entities: list[GardenaBluetoothEntity] = [
|
entities: list[GardenaBluetoothEntity] = [
|
||||||
GardenaBluetoothSensor(coordinator, description)
|
GardenaBluetoothSensor(coordinator, description, description.context)
|
||||||
for description in DESCRIPTIONS
|
for description in DESCRIPTIONS
|
||||||
if description.key in coordinator.characteristics
|
if description.key in coordinator.characteristics
|
||||||
]
|
]
|
||||||
@ -81,6 +124,12 @@ class GardenaBluetoothSensor(GardenaBluetoothDescriptorEntity, SensorEntity):
|
|||||||
tzinfo=dt_util.get_time_zone(self.hass.config.time_zone)
|
tzinfo=dt_util.get_time_zone(self.hass.config.time_zone)
|
||||||
)
|
)
|
||||||
self._attr_native_value = value
|
self._attr_native_value = value
|
||||||
|
|
||||||
|
if char := self.entity_description.connected_state:
|
||||||
|
self._attr_available = bool(self.coordinator.get_cached(char))
|
||||||
|
else:
|
||||||
|
self._attr_available = True
|
||||||
|
|
||||||
super()._handle_coordinator_update()
|
super()._handle_coordinator_update()
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
"valve_connected_state": {
|
"valve_connected_state": {
|
||||||
"name": "Valve connection"
|
"name": "Valve connection"
|
||||||
|
},
|
||||||
|
"sensor_connected_state": {
|
||||||
|
"name": "Sensor connection"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"button": {
|
"button": {
|
||||||
@ -45,12 +48,24 @@
|
|||||||
},
|
},
|
||||||
"seasonal_adjust": {
|
"seasonal_adjust": {
|
||||||
"name": "Seasonal adjust"
|
"name": "Seasonal adjust"
|
||||||
|
},
|
||||||
|
"sensor_threshold": {
|
||||||
|
"name": "Sensor threshold"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sensor": {
|
"sensor": {
|
||||||
"activation_reason": {
|
"activation_reason": {
|
||||||
"name": "Activation reason"
|
"name": "Activation reason"
|
||||||
},
|
},
|
||||||
|
"sensor_battery_level": {
|
||||||
|
"name": "Sensor battery"
|
||||||
|
},
|
||||||
|
"sensor_type": {
|
||||||
|
"name": "Sensor type"
|
||||||
|
},
|
||||||
|
"sensor_measurement_timestamp": {
|
||||||
|
"name": "Sensor timestamp"
|
||||||
|
},
|
||||||
"remaining_open_timestamp": {
|
"remaining_open_timestamp": {
|
||||||
"name": "Valve closing"
|
"name": "Valve closing"
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,40 @@
|
|||||||
'state': 'unavailable',
|
'state': 'unavailable',
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
|
# name: test_connected_state
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Mock Title Sensor threshold',
|
||||||
|
'max': 100.0,
|
||||||
|
'min': 0.0,
|
||||||
|
'mode': <NumberMode.BOX: 'box'>,
|
||||||
|
'step': 1.0,
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'number.mock_title_sensor_threshold',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'unavailable',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_connected_state.1
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Mock Title Sensor threshold',
|
||||||
|
'max': 100.0,
|
||||||
|
'min': 0.0,
|
||||||
|
'mode': <NumberMode.BOX: 'box'>,
|
||||||
|
'step': 1.0,
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'number.mock_title_sensor_threshold',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '45.0',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_setup[98bd0f13-0b0e-421a-84e5-ddbf75dc6de4-raw1-number.mock_title_remaining_open_time]
|
# name: test_setup[98bd0f13-0b0e-421a-84e5-ddbf75dc6de4-raw1-number.mock_title_remaining_open_time]
|
||||||
StateSnapshot({
|
StateSnapshot({
|
||||||
'attributes': ReadOnlyDict({
|
'attributes': ReadOnlyDict({
|
||||||
|
@ -1,4 +1,34 @@
|
|||||||
# serializer version: 1
|
# serializer version: 1
|
||||||
|
# name: test_connected_state
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'battery',
|
||||||
|
'friendly_name': 'Mock Title Sensor battery',
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.mock_title_sensor_battery',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'unavailable',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_connected_state.1
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'battery',
|
||||||
|
'friendly_name': 'Mock Title Sensor battery',
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.mock_title_sensor_battery',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '45',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_setup[98bd0f13-0b0e-421a-84e5-ddbf75dc6de4-raw1-sensor.mock_title_valve_closing]
|
# name: test_setup[98bd0f13-0b0e-421a-84e5-ddbf75dc6de4-raw1-sensor.mock_title_valve_closing]
|
||||||
StateSnapshot({
|
StateSnapshot({
|
||||||
'attributes': ReadOnlyDict({
|
'attributes': ReadOnlyDict({
|
||||||
|
@ -5,7 +5,7 @@ from collections.abc import Awaitable, Callable
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import Mock, call
|
from unittest.mock import Mock, call
|
||||||
|
|
||||||
from gardena_bluetooth.const import Valve
|
from gardena_bluetooth.const import Sensor, Valve
|
||||||
from gardena_bluetooth.exceptions import (
|
from gardena_bluetooth.exceptions import (
|
||||||
CharacteristicNoAccess,
|
CharacteristicNoAccess,
|
||||||
GardenaBluetoothException,
|
GardenaBluetoothException,
|
||||||
@ -149,3 +149,28 @@ async def test_bluetooth_error_unavailable(
|
|||||||
await scan_step()
|
await scan_step()
|
||||||
assert hass.states.get("number.mock_title_remaining_open_time") == snapshot
|
assert hass.states.get("number.mock_title_remaining_open_time") == snapshot
|
||||||
assert hass.states.get("number.mock_title_manual_watering_time") == snapshot
|
assert hass.states.get("number.mock_title_manual_watering_time") == snapshot
|
||||||
|
|
||||||
|
|
||||||
|
async def test_connected_state(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
mock_entry: MockConfigEntry,
|
||||||
|
mock_read_char_raw: dict[str, bytes],
|
||||||
|
scan_step: Callable[[], Awaitable[None]],
|
||||||
|
) -> None:
|
||||||
|
"""Verify that a connectivity error makes all entities unavailable."""
|
||||||
|
|
||||||
|
mock_read_char_raw[Sensor.connected_state.uuid] = Sensor.connected_state.encode(
|
||||||
|
False
|
||||||
|
)
|
||||||
|
mock_read_char_raw[Sensor.threshold.uuid] = Sensor.threshold.encode(45)
|
||||||
|
|
||||||
|
await setup_entry(hass, mock_entry, [Platform.NUMBER])
|
||||||
|
assert hass.states.get("number.mock_title_sensor_threshold") == snapshot
|
||||||
|
|
||||||
|
mock_read_char_raw[Sensor.connected_state.uuid] = Sensor.connected_state.encode(
|
||||||
|
True
|
||||||
|
)
|
||||||
|
|
||||||
|
await scan_step()
|
||||||
|
assert hass.states.get("number.mock_title_sensor_threshold") == snapshot
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Test Gardena Bluetooth sensor."""
|
"""Test Gardena Bluetooth sensor."""
|
||||||
from collections.abc import Awaitable, Callable
|
from collections.abc import Awaitable, Callable
|
||||||
|
|
||||||
from gardena_bluetooth.const import Battery, Valve
|
from gardena_bluetooth.const import Battery, Sensor, Valve
|
||||||
import pytest
|
import pytest
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
@ -52,3 +52,28 @@ async def test_setup(
|
|||||||
mock_read_char_raw[uuid] = char_raw
|
mock_read_char_raw[uuid] = char_raw
|
||||||
await scan_step()
|
await scan_step()
|
||||||
assert hass.states.get(entity_id) == snapshot
|
assert hass.states.get(entity_id) == snapshot
|
||||||
|
|
||||||
|
|
||||||
|
async def test_connected_state(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
mock_entry: MockConfigEntry,
|
||||||
|
mock_read_char_raw: dict[str, bytes],
|
||||||
|
scan_step: Callable[[], Awaitable[None]],
|
||||||
|
) -> None:
|
||||||
|
"""Verify that a connectivity error makes all entities unavailable."""
|
||||||
|
|
||||||
|
mock_read_char_raw[Sensor.connected_state.uuid] = Sensor.connected_state.encode(
|
||||||
|
False
|
||||||
|
)
|
||||||
|
mock_read_char_raw[Sensor.battery_level.uuid] = Sensor.battery_level.encode(45)
|
||||||
|
|
||||||
|
await setup_entry(hass, mock_entry, [Platform.SENSOR])
|
||||||
|
assert hass.states.get("sensor.mock_title_sensor_battery") == snapshot
|
||||||
|
|
||||||
|
mock_read_char_raw[Sensor.connected_state.uuid] = Sensor.connected_state.encode(
|
||||||
|
True
|
||||||
|
)
|
||||||
|
|
||||||
|
await scan_step()
|
||||||
|
assert hass.states.get("sensor.mock_title_sensor_battery") == snapshot
|
||||||
|
Loading…
x
Reference in New Issue
Block a user