mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 08:47:57 +00:00
New scanner device tracker and ZHA device tracker support (#24584)
* initial implementation for zha device trackers * constant * review comments * Revert "review comments" This reverts commit 2130823566820dfc114dbeda08fcdf76ed47a4e7. * rename device tracker entity * update trackers * raise when not implemented * Update homeassistant/components/device_tracker/config_entry.py Review comment Co-Authored-By: Martin Hjelmare <marhje52@kth.se> * move source type to base state attrs * review comments * review comments * review comments * fix super call * fix battery and use last seen from device * add test * cleanup and add more to test * cleanup post zha entity removal PR * add tests for base entities * rework entity tests
This commit is contained in:
parent
e824c553ca
commit
3c487928d4
@ -37,7 +37,7 @@ async def async_unload_entry(hass, entry):
|
||||
return await hass.data[DOMAIN].async_unload_entry(entry)
|
||||
|
||||
|
||||
class DeviceTrackerEntity(Entity):
|
||||
class BaseTrackerEntity(Entity):
|
||||
"""Represent a tracked device."""
|
||||
|
||||
@property
|
||||
@ -48,6 +48,27 @@ class DeviceTrackerEntity(Entity):
|
||||
"""
|
||||
return None
|
||||
|
||||
@property
|
||||
def source_type(self):
|
||||
"""Return the source type, eg gps or router, of the device."""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def state_attributes(self):
|
||||
"""Return the device state attributes."""
|
||||
attr = {
|
||||
ATTR_SOURCE_TYPE: self.source_type
|
||||
}
|
||||
|
||||
if self.battery_level:
|
||||
attr[ATTR_BATTERY_LEVEL] = self.battery_level
|
||||
|
||||
return attr
|
||||
|
||||
|
||||
class TrackerEntity(BaseTrackerEntity):
|
||||
"""Represent a tracked device."""
|
||||
|
||||
@property
|
||||
def location_accuracy(self):
|
||||
"""Return the location accuracy of the device.
|
||||
@ -71,11 +92,6 @@ class DeviceTrackerEntity(Entity):
|
||||
"""Return longitude value of the device."""
|
||||
return NotImplementedError
|
||||
|
||||
@property
|
||||
def source_type(self):
|
||||
"""Return the source type, eg gps or router, of the device."""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the device."""
|
||||
@ -99,16 +115,27 @@ class DeviceTrackerEntity(Entity):
|
||||
@property
|
||||
def state_attributes(self):
|
||||
"""Return the device state attributes."""
|
||||
attr = {
|
||||
ATTR_SOURCE_TYPE: self.source_type
|
||||
}
|
||||
|
||||
attr = {}
|
||||
attr.update(super().state_attributes)
|
||||
if self.latitude is not None:
|
||||
attr[ATTR_LATITUDE] = self.latitude
|
||||
attr[ATTR_LONGITUDE] = self.longitude
|
||||
attr[ATTR_GPS_ACCURACY] = self.location_accuracy
|
||||
|
||||
if self.battery_level:
|
||||
attr[ATTR_BATTERY_LEVEL] = self.battery_level
|
||||
|
||||
return attr
|
||||
|
||||
|
||||
class ScannerEntity(BaseTrackerEntity):
|
||||
"""Represent a tracked device that is on a scanned network."""
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the device."""
|
||||
if self.is_connected:
|
||||
return STATE_HOME
|
||||
return STATE_NOT_HOME
|
||||
|
||||
@property
|
||||
def is_connected(self):
|
||||
"""Return true if the device is connected to the network."""
|
||||
raise NotImplementedError
|
||||
|
@ -8,7 +8,7 @@ from homeassistant.const import (
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.components.device_tracker import SOURCE_TYPE_GPS
|
||||
from homeassistant.components.device_tracker.config_entry import (
|
||||
DeviceTrackerEntity
|
||||
TrackerEntity
|
||||
)
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
@ -52,7 +52,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
return True
|
||||
|
||||
|
||||
class GeofencyEntity(DeviceTrackerEntity, RestoreEntity):
|
||||
class GeofencyEntity(TrackerEntity, RestoreEntity):
|
||||
"""Represent a tracked device."""
|
||||
|
||||
def __init__(self, device, gps=None, location_name=None, attributes=None):
|
||||
|
@ -10,7 +10,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.components.device_tracker import SOURCE_TYPE_GPS
|
||||
from homeassistant.components.device_tracker.config_entry import (
|
||||
DeviceTrackerEntity
|
||||
TrackerEntity
|
||||
)
|
||||
from homeassistant.helpers import device_registry
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
@ -67,7 +67,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry,
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class GPSLoggerEntity(DeviceTrackerEntity, RestoreEntity):
|
||||
class GPSLoggerEntity(TrackerEntity, RestoreEntity):
|
||||
"""Represent a tracked device."""
|
||||
|
||||
def __init__(
|
||||
|
@ -4,7 +4,7 @@ import logging
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.components.device_tracker import SOURCE_TYPE_GPS
|
||||
from homeassistant.components.device_tracker.config_entry import (
|
||||
DeviceTrackerEntity
|
||||
TrackerEntity
|
||||
)
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
@ -33,7 +33,7 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
return True
|
||||
|
||||
|
||||
class LocativeEntity(DeviceTrackerEntity):
|
||||
class LocativeEntity(TrackerEntity):
|
||||
"""Represent a tracked device."""
|
||||
|
||||
def __init__(self, device, location, location_name):
|
||||
|
@ -9,7 +9,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.components.device_tracker.const import SOURCE_TYPE_GPS
|
||||
from homeassistant.components.device_tracker.config_entry import (
|
||||
DeviceTrackerEntity
|
||||
TrackerEntity
|
||||
)
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
from .const import (
|
||||
@ -44,7 +44,7 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
return True
|
||||
|
||||
|
||||
class MobileAppEntity(DeviceTrackerEntity, RestoreEntity):
|
||||
class MobileAppEntity(TrackerEntity, RestoreEntity):
|
||||
"""Represent a tracked device."""
|
||||
|
||||
def __init__(self, entry, data=None):
|
||||
|
@ -11,7 +11,7 @@ from homeassistant.const import (
|
||||
from homeassistant.components.device_tracker.const import (
|
||||
ENTITY_ID_FORMAT, ATTR_SOURCE_TYPE, SOURCE_TYPE_GPS)
|
||||
from homeassistant.components.device_tracker.config_entry import (
|
||||
DeviceTrackerEntity
|
||||
TrackerEntity
|
||||
)
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
from homeassistant.helpers import device_registry
|
||||
@ -62,7 +62,7 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
||||
return True
|
||||
|
||||
|
||||
class OwnTracksEntity(DeviceTrackerEntity, RestoreEntity):
|
||||
class OwnTracksEntity(TrackerEntity, RestoreEntity):
|
||||
"""Represent a tracked device."""
|
||||
|
||||
def __init__(self, dev_id, data=None):
|
||||
|
@ -3,6 +3,7 @@ import enum
|
||||
import logging
|
||||
|
||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR
|
||||
from homeassistant.components.device_tracker import DOMAIN as DEVICE_TRACKER
|
||||
from homeassistant.components.fan import DOMAIN as FAN
|
||||
from homeassistant.components.light import DOMAIN as LIGHT
|
||||
from homeassistant.components.lock import DOMAIN as LOCK
|
||||
@ -25,6 +26,7 @@ ZHA_DISCOVERY_NEW = 'zha_discovery_new_{}'
|
||||
|
||||
COMPONENTS = (
|
||||
BINARY_SENSOR,
|
||||
DEVICE_TRACKER,
|
||||
FAN,
|
||||
LIGHT,
|
||||
LOCK,
|
||||
|
@ -6,6 +6,7 @@ https://home-assistant.io/components/zha/
|
||||
"""
|
||||
|
||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR
|
||||
from homeassistant.components.device_tracker import DOMAIN as DEVICE_TRACKER
|
||||
from homeassistant.components.fan import DOMAIN as FAN
|
||||
from homeassistant.components.light import DOMAIN as LIGHT
|
||||
from homeassistant.components.lock import DOMAIN as LOCK
|
||||
@ -21,8 +22,9 @@ from .const import (
|
||||
CONTROLLER, BATTERY
|
||||
)
|
||||
|
||||
SMARTTHINGS_HUMIDITY_CLUSTER = 64581
|
||||
SMARTTHINGS_ACCELERATION_CLUSTER = 64514
|
||||
SMARTTHINGS_HUMIDITY_CLUSTER = 0xFC45
|
||||
SMARTTHINGS_ACCELERATION_CLUSTER = 0xFC02
|
||||
SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE = 0x8000
|
||||
|
||||
DEVICE_CLASS = {}
|
||||
SINGLE_INPUT_CLUSTER_DEVICE_CLASS = {}
|
||||
@ -39,12 +41,14 @@ OUTPUT_CHANNEL_ONLY_CLUSTERS = []
|
||||
BINDABLE_CLUSTERS = []
|
||||
INPUT_BIND_ONLY_CLUSTERS = []
|
||||
BINARY_SENSOR_CLUSTERS = set()
|
||||
DEVICE_TRACKER_CLUSTERS = set()
|
||||
LIGHT_CLUSTERS = set()
|
||||
SWITCH_CLUSTERS = set()
|
||||
COMPONENT_CLUSTERS = {
|
||||
BINARY_SENSOR: BINARY_SENSOR_CLUSTERS,
|
||||
LIGHT: LIGHT_CLUSTERS,
|
||||
SWITCH: SWITCH_CLUSTERS
|
||||
SWITCH: SWITCH_CLUSTERS,
|
||||
DEVICE_TRACKER: DEVICE_TRACKER_CLUSTERS
|
||||
}
|
||||
|
||||
|
||||
@ -134,7 +138,8 @@ def establish_device_mappings():
|
||||
zha.DeviceType.ON_OFF_PLUG_IN_UNIT: SWITCH,
|
||||
zha.DeviceType.DIMMABLE_PLUG_IN_UNIT: LIGHT,
|
||||
zha.DeviceType.COLOR_TEMPERATURE_LIGHT: LIGHT,
|
||||
zha.DeviceType.EXTENDED_COLOR_LIGHT: LIGHT
|
||||
zha.DeviceType.EXTENDED_COLOR_LIGHT: LIGHT,
|
||||
SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE: DEVICE_TRACKER
|
||||
})
|
||||
|
||||
DEVICE_CLASS[zll.PROFILE_ID].update({
|
||||
@ -323,6 +328,9 @@ def establish_device_mappings():
|
||||
zcl.clusters.measurement.OccupancySensing.cluster_id)
|
||||
BINARY_SENSOR_CLUSTERS.add(SMARTTHINGS_ACCELERATION_CLUSTER)
|
||||
|
||||
DEVICE_TRACKER_CLUSTERS.add(
|
||||
zcl.clusters.general.PowerConfiguration.cluster_id)
|
||||
|
||||
LIGHT_CLUSTERS.add(zcl.clusters.general.OnOff.cluster_id)
|
||||
LIGHT_CLUSTERS.add(zcl.clusters.general.LevelControl.cluster_id)
|
||||
LIGHT_CLUSTERS.add(zcl.clusters.lighting.Color.cluster_id)
|
||||
|
105
homeassistant/components/zha/device_tracker.py
Normal file
105
homeassistant/components/zha/device_tracker.py
Normal file
@ -0,0 +1,105 @@
|
||||
"""Support for the ZHA platform."""
|
||||
import logging
|
||||
import time
|
||||
from homeassistant.components.device_tracker import (
|
||||
SOURCE_TYPE_ROUTER, DOMAIN
|
||||
)
|
||||
from homeassistant.components.device_tracker.config_entry import (
|
||||
ScannerEntity
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from .core.const import (
|
||||
DATA_ZHA, DATA_ZHA_DISPATCHERS, ZHA_DISCOVERY_NEW,
|
||||
POWER_CONFIGURATION_CHANNEL, SIGNAL_ATTR_UPDATED
|
||||
)
|
||||
from .entity import ZhaEntity
|
||||
from .sensor import battery_percentage_remaining_formatter
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up the Zigbee Home Automation device tracker from config entry."""
|
||||
async def async_discover(discovery_info):
|
||||
await _async_setup_entities(hass, config_entry, async_add_entities,
|
||||
[discovery_info])
|
||||
|
||||
unsub = async_dispatcher_connect(
|
||||
hass, ZHA_DISCOVERY_NEW.format(DOMAIN), async_discover)
|
||||
hass.data[DATA_ZHA][DATA_ZHA_DISPATCHERS].append(unsub)
|
||||
|
||||
device_trackers = hass.data.get(DATA_ZHA, {}).get(DOMAIN)
|
||||
if device_trackers is not None:
|
||||
await _async_setup_entities(hass, config_entry, async_add_entities,
|
||||
device_trackers.values())
|
||||
del hass.data[DATA_ZHA][DOMAIN]
|
||||
|
||||
|
||||
async def _async_setup_entities(hass, config_entry, async_add_entities,
|
||||
discovery_infos):
|
||||
"""Set up the ZHA device trackers."""
|
||||
entities = []
|
||||
for discovery_info in discovery_infos:
|
||||
entities.append(ZHADeviceScannerEntity(**discovery_info))
|
||||
|
||||
async_add_entities(entities, update_before_add=True)
|
||||
|
||||
|
||||
class ZHADeviceScannerEntity(ScannerEntity, ZhaEntity):
|
||||
"""Represent a tracked device."""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Initialize the ZHA device tracker."""
|
||||
super().__init__(**kwargs)
|
||||
self._battery_channel = self.cluster_channels.get(
|
||||
POWER_CONFIGURATION_CHANNEL)
|
||||
self._connected = False
|
||||
self._keepalive_interval = 60
|
||||
self._should_poll = True
|
||||
self._battery_level = None
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Run when about to be added to hass."""
|
||||
await super().async_added_to_hass()
|
||||
if self._battery_channel:
|
||||
await self.async_accept_signal(
|
||||
self._battery_channel, SIGNAL_ATTR_UPDATED,
|
||||
self.async_battery_percentage_remaining_updated)
|
||||
|
||||
async def async_update(self):
|
||||
"""Handle polling."""
|
||||
if self.zha_device.last_seen is None:
|
||||
self._connected = False
|
||||
else:
|
||||
difference = time.time() - self.zha_device.last_seen
|
||||
if difference > self._keepalive_interval:
|
||||
self._connected = False
|
||||
else:
|
||||
self._connected = True
|
||||
|
||||
@property
|
||||
def is_connected(self):
|
||||
"""Return true if the device is connected to the network."""
|
||||
return self._connected
|
||||
|
||||
@property
|
||||
def source_type(self):
|
||||
"""Return the source type, eg gps or router, of the device."""
|
||||
return SOURCE_TYPE_ROUTER
|
||||
|
||||
@callback
|
||||
def async_battery_percentage_remaining_updated(self, value):
|
||||
"""Handle tracking."""
|
||||
_LOGGER.debug('battery_percentage_remaining updated: %s', value)
|
||||
self._connected = True
|
||||
self._battery_level = battery_percentage_remaining_formatter(value)
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def battery_level(self):
|
||||
"""Return the battery level of the device.
|
||||
|
||||
Percentage from 0-100.
|
||||
"""
|
||||
return self._battery_level
|
62
tests/components/device_tracker/test_entities.py
Normal file
62
tests/components/device_tracker/test_entities.py
Normal file
@ -0,0 +1,62 @@
|
||||
"""Tests for device tracker entities."""
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.device_tracker.config_entry import (
|
||||
BaseTrackerEntity, ScannerEntity
|
||||
)
|
||||
from homeassistant.components.device_tracker.const import (
|
||||
SOURCE_TYPE_ROUTER, ATTR_SOURCE_TYPE, DOMAIN
|
||||
)
|
||||
from homeassistant.const import (
|
||||
STATE_HOME,
|
||||
STATE_NOT_HOME,
|
||||
ATTR_BATTERY_LEVEL
|
||||
)
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_scanner_entity_device_tracker(hass):
|
||||
"""Test ScannerEntity based device tracker."""
|
||||
config_entry = MockConfigEntry(domain='test')
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_forward_entry_setup(
|
||||
config_entry, DOMAIN)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = 'device_tracker.unnamed_device'
|
||||
entity_state = hass.states.get(entity_id)
|
||||
assert entity_state.attributes == {
|
||||
ATTR_SOURCE_TYPE: SOURCE_TYPE_ROUTER,
|
||||
ATTR_BATTERY_LEVEL: 100
|
||||
}
|
||||
assert entity_state.state == STATE_NOT_HOME
|
||||
|
||||
entity = hass.data[DOMAIN].get_entity(entity_id)
|
||||
entity.set_connected()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_state = hass.states.get(entity_id)
|
||||
assert entity_state.state == STATE_HOME
|
||||
|
||||
|
||||
def test_scanner_entity():
|
||||
"""Test coverage for base ScannerEntity entity class."""
|
||||
entity = ScannerEntity()
|
||||
with pytest.raises(NotImplementedError):
|
||||
assert entity.source_type is None
|
||||
with pytest.raises(NotImplementedError):
|
||||
assert entity.is_connected is None
|
||||
with pytest.raises(NotImplementedError):
|
||||
assert entity.state == STATE_NOT_HOME
|
||||
assert entity.battery_level is None
|
||||
|
||||
|
||||
def test_base_tracker_entity():
|
||||
"""Test coverage for base BaseTrackerEntity entity class."""
|
||||
entity = BaseTrackerEntity()
|
||||
with pytest.raises(NotImplementedError):
|
||||
assert entity.source_type is None
|
||||
assert entity.battery_level is None
|
||||
with pytest.raises(NotImplementedError):
|
||||
assert entity.state_attributes is None
|
89
tests/components/zha/test_device_tracker.py
Normal file
89
tests/components/zha/test_device_tracker.py
Normal file
@ -0,0 +1,89 @@
|
||||
"""Test ZHA Device Tracker."""
|
||||
from datetime import timedelta
|
||||
import time
|
||||
from homeassistant.components.device_tracker import DOMAIN, SOURCE_TYPE_ROUTER
|
||||
from homeassistant.const import (
|
||||
STATE_HOME,
|
||||
STATE_NOT_HOME,
|
||||
STATE_UNAVAILABLE
|
||||
)
|
||||
from homeassistant.components.zha.core.registries import \
|
||||
SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE
|
||||
import homeassistant.util.dt as dt_util
|
||||
from .common import (
|
||||
async_init_zigpy_device, make_attribute, make_entity_id,
|
||||
async_test_device_join, async_enable_traffic
|
||||
)
|
||||
from tests.common import async_fire_time_changed
|
||||
|
||||
|
||||
async def test_device_tracker(hass, config_entry, zha_gateway):
|
||||
"""Test zha device tracker platform."""
|
||||
from zigpy.zcl.clusters.general import (
|
||||
Basic, PowerConfiguration, BinaryInput, Identify, Ota, PollControl)
|
||||
|
||||
# create zigpy device
|
||||
zigpy_device = await async_init_zigpy_device(
|
||||
hass,
|
||||
[
|
||||
Basic.cluster_id,
|
||||
PowerConfiguration.cluster_id,
|
||||
Identify.cluster_id,
|
||||
PollControl.cluster_id,
|
||||
BinaryInput.cluster_id
|
||||
],
|
||||
[
|
||||
Identify.cluster_id,
|
||||
Ota.cluster_id
|
||||
],
|
||||
SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE,
|
||||
zha_gateway
|
||||
)
|
||||
|
||||
# load up device tracker domain
|
||||
await hass.config_entries.async_forward_entry_setup(
|
||||
config_entry, DOMAIN)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
cluster = zigpy_device.endpoints.get(1).power
|
||||
entity_id = make_entity_id(DOMAIN, zigpy_device, cluster, use_suffix=False)
|
||||
zha_device = zha_gateway.get_device(zigpy_device.ieee)
|
||||
|
||||
# test that the device tracker was created and that it is unavailable
|
||||
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
||||
|
||||
zigpy_device.last_seen = time.time() - 120
|
||||
next_update = dt_util.utcnow() + timedelta(seconds=30)
|
||||
async_fire_time_changed(hass, next_update)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# allow traffic to flow through the gateway and device
|
||||
await async_enable_traffic(hass, zha_gateway, [zha_device])
|
||||
|
||||
# test that the state has changed from unavailable to not home
|
||||
assert hass.states.get(entity_id).state == STATE_NOT_HOME
|
||||
|
||||
# turn state flip
|
||||
attr = make_attribute(0x0020, 23)
|
||||
cluster.handle_message(False, 1, 0x0a, [[attr]])
|
||||
|
||||
attr = make_attribute(0x0021, 200)
|
||||
cluster.handle_message(False, 1, 0x0a, [[attr]])
|
||||
|
||||
zigpy_device.last_seen = time.time() + 10
|
||||
next_update = dt_util.utcnow() + timedelta(seconds=30)
|
||||
async_fire_time_changed(hass, next_update)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get(entity_id).state == STATE_HOME
|
||||
|
||||
entity = hass.data[DOMAIN].get_entity(entity_id)
|
||||
|
||||
assert entity.is_connected is True
|
||||
assert entity.source_type == SOURCE_TYPE_ROUTER
|
||||
assert entity.battery_level == 100
|
||||
|
||||
# test adding device tracker to the network and HA
|
||||
await async_test_device_join(
|
||||
hass, zha_gateway, PowerConfiguration.cluster_id, DOMAIN,
|
||||
SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE)
|
@ -1,6 +1,8 @@
|
||||
"""Provide a mock device scanner."""
|
||||
|
||||
from homeassistant.components.device_tracker import DeviceScanner
|
||||
from homeassistant.components.device_tracker.config_entry import ScannerEntity
|
||||
from homeassistant.components.device_tracker.const import SOURCE_TYPE_ROUTER
|
||||
|
||||
|
||||
def get_scanner(hass, config):
|
||||
@ -8,6 +10,43 @@ def get_scanner(hass, config):
|
||||
return SCANNER
|
||||
|
||||
|
||||
class MockScannerEntity(ScannerEntity):
|
||||
"""Test implementation of a ScannerEntity."""
|
||||
|
||||
def __init__(self):
|
||||
"""Init."""
|
||||
self.connected = False
|
||||
|
||||
@property
|
||||
def source_type(self):
|
||||
"""Return the source type, eg gps or router, of the device."""
|
||||
return SOURCE_TYPE_ROUTER
|
||||
|
||||
@property
|
||||
def battery_level(self):
|
||||
"""Return the battery level of the device.
|
||||
|
||||
Percentage from 0-100.
|
||||
"""
|
||||
return 100
|
||||
|
||||
@property
|
||||
def is_connected(self):
|
||||
"""Return true if the device is connected to the network."""
|
||||
return self.connected
|
||||
|
||||
def set_connected(self):
|
||||
"""Set connected to True."""
|
||||
self.connected = True
|
||||
self.async_schedule_update_ha_state()
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up the config entry."""
|
||||
entity = MockScannerEntity()
|
||||
async_add_entities([entity])
|
||||
|
||||
|
||||
class MockScanner(DeviceScanner):
|
||||
"""Mock device scanner."""
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user