Mark oralb devices as sleepy (#93250)

This commit is contained in:
J. Nick Koston 2023-05-18 16:32:24 -05:00 committed by GitHub
parent be08bb5ba6
commit aebded049b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 2 deletions

View file

@ -124,3 +124,20 @@ class OralBBluetoothSensorEntity(
def native_value(self) -> str | int | None:
"""Return the native value."""
return self.processor.entity_data.get(self.entity_key)
@property
def available(self) -> bool:
"""Return True if entity is available.
The sensor is only created when the device is seen.
Since these are sleepy devices which stop broadcasting
when not in use, we can't rely on the last update time
so once we have seen the device we always return True.
"""
return True
@property
def assumed_state(self) -> bool:
"""Return True if the device is no longer broadcasting."""
return not self.processor.available

View file

@ -1,8 +1,17 @@
"""Test the OralB sensors."""
from datetime import timedelta
import time
from unittest.mock import patch
from homeassistant.components.bluetooth import (
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
async_address_present,
)
from homeassistant.components.oralb.const import DOMAIN
from homeassistant.const import ATTR_FRIENDLY_NAME
from homeassistant.const import ATTR_ASSUMED_STATE, ATTR_FRIENDLY_NAME
from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util
from . import (
ORALB_IO_SERIES_4_SERVICE_INFO,
@ -10,10 +19,11 @@ from . import (
ORALB_SERVICE_INFO,
)
from tests.common import MockConfigEntry
from tests.common import MockConfigEntry, async_fire_time_changed
from tests.components.bluetooth import (
inject_bluetooth_service_info,
inject_bluetooth_service_info_bleak,
patch_all_discovered_devices,
)
@ -44,6 +54,7 @@ async def test_sensors(
toothbrush_sensor_attrs[ATTR_FRIENDLY_NAME]
== "Smart Series 7000 48BE Toothbrush State"
)
assert ATTR_ASSUMED_STATE not in toothbrush_sensor_attrs
assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()
@ -53,6 +64,8 @@ async def test_sensors_io_series_4(
hass: HomeAssistant, entity_registry_enabled_by_default: None
) -> None:
"""Test setting up creates the sensors with an io series 4."""
start_monotonic = time.monotonic()
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=ORALB_IO_SERIES_4_SERVICE_INFO.address,
@ -71,6 +84,30 @@ async def test_sensors_io_series_4(
toothbrush_sensor_attrs = toothbrush_sensor.attributes
assert toothbrush_sensor.state == "gum care"
assert toothbrush_sensor_attrs[ATTR_FRIENDLY_NAME] == "IO Series 4 48BE Mode"
assert ATTR_ASSUMED_STATE not in toothbrush_sensor_attrs
# Fast-forward time without BLE advertisements
monotonic_now = start_monotonic + FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS + 1
with patch(
"homeassistant.components.bluetooth.manager.MONOTONIC_TIME",
return_value=monotonic_now,
), patch_all_discovered_devices([]):
async_fire_time_changed(
hass,
dt_util.utcnow()
+ timedelta(seconds=FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS + 1),
)
await hass.async_block_till_done()
assert (
async_address_present(hass, ORALB_IO_SERIES_4_SERVICE_INFO.address) is False
)
toothbrush_sensor = hass.states.get("sensor.io_series_4_48be_mode")
# Sleepy devices should keep their state over time
assert toothbrush_sensor.state == "gum care"
toothbrush_sensor_attrs = toothbrush_sensor.attributes
assert toothbrush_sensor_attrs[ATTR_ASSUMED_STATE] is True
assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()