1 """Legacy device tracker classes."""
3 from __future__
import annotations
6 from collections.abc
import Callable, Coroutine, Sequence
7 from datetime
import datetime, timedelta
9 from types
import ModuleType
10 from typing
import Any, Final, Protocol, final
13 from propcache
import cached_property
14 import voluptuous
as vol
16 from homeassistant
import util
20 async_log_schema_error,
22 load_yaml_config_file,
35 EVENT_HOMEASSISTANT_STOP,
42 config_validation
as cv,
44 entity_registry
as er,
47 async_track_time_interval,
48 async_track_utc_time_change,
54 async_notify_setup_error,
55 async_prepare_setup_platform,
73 CONF_NEW_DEVICE_DEFAULTS,
76 DEFAULT_CONSIDER_HOME,
85 SERVICE_SEE: Final =
"see"
87 SOURCE_TYPES = [cls.value
for cls
in SourceType]
89 NEW_DEVICE_DEFAULTS_SCHEMA = vol.Any(
91 vol.Schema({vol.Optional(CONF_TRACK_NEW, default=DEFAULT_TRACK_NEW): cv.boolean}),
93 PLATFORM_SCHEMA: Final = cv.PLATFORM_SCHEMA.extend(
95 vol.Optional(CONF_SCAN_INTERVAL): cv.time_period,
96 vol.Optional(CONF_TRACK_NEW): cv.boolean,
97 vol.Optional(CONF_CONSIDER_HOME, default=DEFAULT_CONSIDER_HOME): vol.All(
98 cv.time_period, cv.positive_timedelta
100 vol.Optional(CONF_NEW_DEVICE_DEFAULTS, default={}): NEW_DEVICE_DEFAULTS_SCHEMA,
103 PLATFORM_SCHEMA_BASE: Final[vol.Schema] = cv.PLATFORM_SCHEMA_BASE.extend(
104 PLATFORM_SCHEMA.schema
107 SERVICE_SEE_PAYLOAD_SCHEMA: Final[vol.Schema] = vol.Schema(
109 cv.has_at_least_one_key(ATTR_MAC, ATTR_DEV_ID),
112 ATTR_DEV_ID: cv.string,
113 ATTR_HOST_NAME: cv.string,
114 ATTR_LOCATION_NAME: cv.string,
116 ATTR_GPS_ACCURACY: cv.positive_int,
117 ATTR_BATTERY: cv.positive_int,
118 ATTR_ATTRIBUTES: dict,
119 ATTR_SOURCE_TYPE: vol.Coerce(SourceType),
120 ATTR_CONSIDER_HOME: cv.time_period,
122 vol.Optional(
"battery_status"): str,
123 vol.Optional(
"hostname"): str,
128 YAML_DEVICES: Final =
"known_devices.yaml"
129 EVENT_NEW_DEVICE: Final =
"device_tracker_new_device"
133 """Protocol type for DeviceTracker.see callback."""
137 mac: str |
None =
None,
138 dev_id: str |
None =
None,
139 host_name: str |
None =
None,
140 location_name: str |
None =
None,
141 gps: GPSType |
None =
None,
142 gps_accuracy: int |
None =
None,
143 battery: int |
None =
None,
144 attributes: dict[str, Any] |
None =
None,
145 source_type: SourceType | str = SourceType.GPS,
146 picture: str |
None =
None,
147 icon: str |
None =
None,
148 consider_home: timedelta |
None =
None,
150 """Define see type."""
154 """Protocol type for DeviceTracker.async_see callback."""
158 mac: str |
None =
None,
159 dev_id: str |
None =
None,
160 host_name: str |
None =
None,
161 location_name: str |
None =
None,
162 gps: GPSType |
None =
None,
163 gps_accuracy: int |
None =
None,
164 battery: int |
None =
None,
165 attributes: dict[str, Any] |
None =
None,
166 source_type: SourceType | str = SourceType.GPS,
167 picture: str |
None =
None,
168 icon: str |
None =
None,
169 consider_home: timedelta |
None =
None,
171 """Define async_see type."""
176 mac: str |
None =
None,
177 dev_id: str |
None =
None,
178 host_name: str |
None =
None,
179 location_name: str |
None =
None,
180 gps: GPSType |
None =
None,
181 gps_accuracy: int |
None =
None,
182 battery: int |
None =
None,
183 attributes: dict[str, Any] |
None =
None,
185 """Call service to notify you see device."""
186 data: dict[str, Any] = {
190 (ATTR_DEV_ID, dev_id),
191 (ATTR_HOST_NAME, host_name),
192 (ATTR_LOCATION_NAME, location_name),
194 (ATTR_GPS_ACCURACY, gps_accuracy),
195 (ATTR_BATTERY, battery),
199 if attributes
is not None:
200 data[ATTR_ATTRIBUTES] = attributes
201 hass.services.call(DOMAIN, SERVICE_SEE, data)
206 """Set up the legacy integration."""
211 tracker_future: asyncio.Future[DeviceTracker] = hass.loop.create_future()
213 async
def async_platform_discovered(
214 p_type: str, info: dict[str, Any] |
None
216 """Load a platform."""
219 if platform
is None or platform.type != PLATFORM_TYPE_LEGACY:
222 tracker = await tracker_future
223 await platform.async_setup_legacy(hass, tracker, info)
225 discovery.async_listen_platform(hass, DOMAIN, async_platform_discovered)
232 hass.async_create_task(
240 tracker_future: asyncio.Future[DeviceTracker],
242 """Set up the legacy integration."""
244 tracker_future.set_result(tracker)
246 async
def async_see_service(call: ServiceCall) ->
None:
247 """Service to see a device."""
249 data =
dict(call.data)
250 data.pop(
"hostname",
None)
251 data.pop(
"battery_status",
None)
252 await tracker.async_see(**data)
254 hass.services.async_register(
255 DOMAIN, SERVICE_SEE, async_see_service, SERVICE_SEE_PAYLOAD_SCHEMA
261 create_eager_task(legacy_platform.async_setup_legacy(hass, tracker))
262 for legacy_platform
in legacy_platforms
266 await asyncio.wait(setup_tasks)
270 hass, tracker.async_update_stale, second=range(0, 60, 5)
274 await tracker.async_setup_tracked_device()
277 def _on_hass_stop(_: Event) ->
None:
278 """Cleanup when Home Assistant stops.
280 Cancel the async_update_stale schedule.
282 cancel_update_stale()
284 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _on_hass_stop)
289 """Class to hold platform information."""
291 LEGACY_SETUP: Final[tuple[str, ...]] = (
294 "async_setup_scanner",
298 name: str = attr.ib()
299 platform: ModuleType = attr.ib()
300 config: dict = attr.ib()
304 """Return platform type."""
305 methods, platform_type = self.LEGACY_SETUP, PLATFORM_TYPE_LEGACY
306 for method
in methods:
307 if hasattr(self.platform, method):
314 tracker: DeviceTracker,
315 discovery_info: dict[str, Any] |
None =
None,
317 """Set up a legacy platform."""
319 full_name = f
"{self.name}.{DOMAIN}"
320 LOGGER.info(
"Setting up %s", full_name)
323 integration=self.name,
324 group=
str(id(self.config)),
325 phase=SetupPhases.PLATFORM_SETUP,
329 setup: bool |
None =
None
330 if hasattr(self.platform,
"async_get_scanner"):
332 hass, {DOMAIN: self.config}
334 elif hasattr(self.platform,
"get_scanner"):
335 scanner = await hass.async_add_executor_job(
336 self.platform.get_scanner,
338 {DOMAIN: self.config},
340 elif hasattr(self.platform,
"async_setup_scanner"):
342 hass, self.config, tracker.async_see, discovery_info
344 elif hasattr(self.platform,
"setup_scanner"):
345 setup = await hass.async_add_executor_job(
346 self.platform.setup_scanner,
355 if scanner
is not None:
357 hass, self.config, scanner, tracker.async_see, self.
typetypetype
360 if not setup
and scanner
is None:
362 "Error setting up platform %s %s", self.
typetypetype, self.name
366 hass.config.components.add(full_name)
370 "Error setting up platform %s %s", self.
typetypetype, self.name
375 hass: HomeAssistant, config: ConfigType
376 ) -> list[DeviceTrackerPlatform]:
377 """Extract device tracker config and split between legacy and modern."""
378 legacy: list[DeviceTrackerPlatform] = []
380 for platform
in await asyncio.gather(
384 if p_type
is not None
390 if platform.type == PLATFORM_TYPE_LEGACY:
391 legacy.append(platform)
394 f
"Unable to determine type for {platform.name}: {platform.type}"
401 hass: HomeAssistant, config: ConfigType, p_type: str, p_config: dict
402 ) -> DeviceTrackerPlatform |
None:
403 """Determine type of platform."""
413 scanner: DeviceScanner,
414 device_name_uses_executor: bool,
415 extra_attributes_uses_executor: bool,
417 found_devices: list[str],
418 ) -> tuple[dict[str, str |
None], dict[str, dict[str, Any]]]:
419 """Load device names and attributes in a single executor job."""
420 host_name_by_mac: dict[str, str |
None] = {}
421 extra_attributes_by_mac: dict[str, dict[str, Any]] = {}
422 for mac
in found_devices:
423 if device_name_uses_executor
and mac
not in seen:
424 host_name_by_mac[mac] = scanner.get_device_name(mac)
425 if extra_attributes_uses_executor:
427 extra_attributes_by_mac[mac] = scanner.get_extra_attributes(mac)
428 except NotImplementedError:
429 extra_attributes_by_mac[mac] = {}
430 return host_name_by_mac, extra_attributes_by_mac
437 scanner: DeviceScanner,
438 async_see_device: Callable[..., Coroutine[
None,
None,
None]],
441 """Set up the connect scanner-based platform to device tracker.
443 This method must be run in the event loop.
445 interval = config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL)
446 update_lock = asyncio.Lock()
450 seen: set[str] = set()
452 async
def async_device_tracker_scan(now: datetime |
None) ->
None:
453 """Handle interval matches."""
454 if update_lock.locked():
457 "Updating device list from %s took longer than the scheduled "
465 async
with update_lock:
466 found_devices = await scanner.async_scan_devices()
468 device_name_uses_executor = (
469 scanner.async_get_device_name.__func__
470 is DeviceScanner.async_get_device_name
472 extra_attributes_uses_executor = (
473 scanner.async_get_extra_attributes.__func__
474 is DeviceScanner.async_get_extra_attributes
476 host_name_by_mac: dict[str, str |
None] = {}
477 extra_attributes_by_mac: dict[str, dict[str, Any]] = {}
478 if device_name_uses_executor
or extra_attributes_uses_executor:
481 extra_attributes_by_mac,
482 ) = await hass.async_add_executor_job(
483 _load_device_names_and_attributes,
485 device_name_uses_executor,
486 extra_attributes_uses_executor,
491 for mac
in found_devices:
495 host_name = host_name_by_mac.get(
496 mac, await scanner.async_get_device_name(mac)
501 extra_attributes = extra_attributes_by_mac.get(
502 mac, await scanner.async_get_extra_attributes(mac)
504 except NotImplementedError:
505 extra_attributes = {}
507 kwargs: dict[str, Any] = {
509 "host_name": host_name,
510 "source_type": SourceType.ROUTER,
512 "scanner": scanner.__class__.__name__,
517 zone_home = hass.states.get(ENTITY_ID_HOME)
518 if zone_home
is not None:
520 zone_home.attributes[ATTR_LATITUDE],
521 zone_home.attributes[ATTR_LONGITUDE],
523 kwargs[
"gps_accuracy"] = 0
525 hass.async_create_task(async_see_device(**kwargs), eager_start=
True)
529 async_device_tracker_scan,
531 name=f
"device_tracker {platform} legacy scan",
533 hass.async_create_task(async_device_tracker_scan(
None), eager_start=
True)
536 def _on_hass_stop(_: Event) ->
None:
537 """Cleanup when Home Assistant stops.
539 Cancel the legacy scan.
543 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _on_hass_stop)
546 async
def get_tracker(hass: HomeAssistant, config: ConfigType) -> DeviceTracker:
547 """Create a tracker."""
548 yaml_path = hass.config.path(YAML_DEVICES)
550 conf = config.get(DOMAIN, [])
551 conf = conf[0]
if conf
else {}
552 consider_home = conf.get(CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME)
554 defaults = conf.get(CONF_NEW_DEVICE_DEFAULTS, {})
555 if (track_new := conf.get(CONF_TRACK_NEW))
is None:
556 track_new = defaults.get(CONF_TRACK_NEW, DEFAULT_TRACK_NEW)
559 return DeviceTracker(hass, consider_home, track_new, defaults, devices)
563 """Representation of a device tracker."""
568 consider_home: timedelta,
570 defaults: dict[str, Any],
571 devices: Sequence[Device],
573 """Initialize a device tracker."""
575 self.devices: dict[str, Device] = {dev.dev_id: dev
for dev
in devices}
576 self.
mac_to_devmac_to_dev = {dev.mac: dev
for dev
in devices
if dev.mac}
580 if track_new
is not None
581 else defaults.get(CONF_TRACK_NEW, DEFAULT_TRACK_NEW)
587 if self.devices[dev.dev_id]
is not dev:
588 LOGGER.warning(
"Duplicate device IDs detected %s", dev.dev_id)
589 if dev.mac
and self.
mac_to_devmac_to_dev[dev.mac]
is not dev:
590 LOGGER.warning(
"Duplicate device MAC addresses detected %s", dev.mac)
594 mac: str |
None =
None,
595 dev_id: str |
None =
None,
596 host_name: str |
None =
None,
597 location_name: str |
None =
None,
598 gps: GPSType |
None =
None,
599 gps_accuracy: int |
None =
None,
600 battery: int |
None =
None,
601 attributes: dict[str, Any] |
None =
None,
602 source_type: SourceType | str = SourceType.GPS,
603 picture: str |
None =
None,
604 icon: str |
None =
None,
605 consider_home: timedelta |
None =
None,
607 """Notify the device tracker that you see a device."""
608 self.
hasshass.create_task(
627 mac: str |
None =
None,
628 dev_id: str |
None =
None,
629 host_name: str |
None =
None,
630 location_name: str |
None =
None,
631 gps: GPSType |
None =
None,
632 gps_accuracy: int |
None =
None,
633 battery: int |
None =
None,
634 attributes: dict[str, Any] |
None =
None,
635 source_type: SourceType | str = SourceType.GPS,
636 picture: str |
None =
None,
637 icon: str |
None =
None,
638 consider_home: timedelta |
None =
None,
640 """Notify the device tracker that you see a device.
642 This method is a coroutine.
644 registry = er.async_get(self.
hasshass)
645 if mac
is None and dev_id
is None:
648 mac =
str(mac).upper()
650 dev_id = util.slugify(host_name
or "")
or util.slugify(mac)
652 dev_id = cv.slug(
str(dev_id).lower())
653 device = self.devices.
get(dev_id)
655 if device
is not None:
656 await device.async_seen(
667 device.async_write_ha_state()
671 assert dev_id
is not None
674 entity_id = f
"{DOMAIN}.{dev_id}"
675 if registry.async_is_registered(entity_id):
677 "The see service is not supported for this entity %s", entity_id
682 dev_id = util.ensure_unique_string(dev_id, self.devices.keys())
692 self.devices[dev_id] = device
696 await device.async_seen(
707 device.async_write_ha_state()
709 self.
hasshass.bus.async_fire(
712 ATTR_ENTITY_ID: device.entity_id,
713 ATTR_HOST_NAME: device.host_name,
714 ATTR_MAC: device.mac,
719 self.
hasshass.async_create_task(
721 self.
hasshass.config.path(YAML_DEVICES), dev_id, device
727 """Add device to YAML configuration file.
729 This method is a coroutine.
732 await self.
hasshass.async_add_executor_job(
733 update_config, self.
hasshass.config.path(YAML_DEVICES), dev_id, device
738 """Update stale devices.
740 This method must be run in the event loop.
742 for device
in self.devices.values():
743 if (device.track
and device.last_update_home)
and device.stale(now):
744 self.
hasshass.async_create_task(
745 device.async_update_ha_state(
True), eager_start=
True
749 """Set up all not exists tracked devices.
751 This method is a coroutine.
753 for device
in self.devices.values():
754 if device.track
and not device.last_seen:
762 await device.async_added_to_hass()
763 device.async_write_ha_state()
767 """Base class for a tracked device."""
771 _no_platform_reported =
True
773 host_name: str |
None =
None
774 location_name: str |
None =
None
775 gps: GPSType |
None =
None
776 gps_accuracy: int = 0
777 last_seen: datetime |
None =
None
778 battery: int |
None =
None
779 attributes: dict |
None =
None
782 last_update_home: bool =
False
783 _state: str = STATE_NOT_HOME
788 consider_home: timedelta,
792 name: str |
None =
None,
793 picture: str |
None =
None,
794 gravatar: str |
None =
None,
795 icon: str |
None =
None,
797 """Initialize a device."""
817 if gravatar
is not None:
824 self.
source_typesource_type: SourceType | str |
None =
None
826 self._attributes: dict[str, Any] = {}
830 """Return the name of the entity."""
835 """Return the state of the device."""
840 """Return the picture of the device."""
846 """Return the device state attributes."""
847 attributes: dict[str, StateType] = {ATTR_SOURCE_TYPE: self.
source_typesource_type}
849 if self.
gpsgps
is not None:
850 attributes[ATTR_LATITUDE] = self.
gpsgps[0]
851 attributes[ATTR_LONGITUDE] = self.
gpsgps[1]
852 attributes[ATTR_GPS_ACCURACY] = self.
gps_accuracygps_accuracy
854 if self.
batterybattery
is not None:
855 attributes[ATTR_BATTERY] = self.
batterybattery
861 """Return device state attributes."""
862 return self._attributes
866 """Return device icon."""
867 return self.
_icon_icon
871 host_name: str |
None =
None,
872 location_name: str |
None =
None,
873 gps: GPSType |
None =
None,
874 gps_accuracy: int |
None =
None,
875 battery: int |
None =
None,
876 attributes: dict[str, Any] |
None =
None,
877 source_type: SourceType | str = SourceType.GPS,
878 consider_home: timedelta |
None =
None,
880 """Mark the device as seen."""
887 if battery
is not None:
889 if attributes
is not None:
890 self._attributes.
update(attributes)
898 except (ValueError, TypeError, IndexError):
901 LOGGER.warning(
"Could not parse gps value for %s: %s", self.
dev_iddev_id, gps)
905 def stale(self, now: datetime |
None =
None) -> bool:
906 """Return if device state is stale.
916 """Mark the device state as stale."""
922 """Update state of entity.
924 This method is a coroutine.
930 elif self.
gpsgps
is not None and self.
source_typesource_type == SourceType.GPS:
931 zone_state = zone.async_active_zone(
934 if zone_state
is None:
935 self.
_state_state = STATE_NOT_HOME
936 elif zone_state.entity_id == zone.ENTITY_ID_HOME:
937 self.
_state_state = STATE_HOME
939 self.
_state_state = zone_state.name
940 elif self.
stalestale():
943 self.
_state_state = STATE_HOME
951 self.
_state_state = state.state
953 self.
last_seenlast_seen = dt_util.utcnow()
955 for attribute, var
in (
956 (ATTR_SOURCE_TYPE,
"source_type"),
957 (ATTR_GPS_ACCURACY,
"gps_accuracy"),
958 (ATTR_BATTERY,
"battery"),
960 if attribute
in state.attributes:
961 setattr(self, var, state.attributes[attribute])
963 if ATTR_LONGITUDE
in state.attributes:
965 state.attributes[ATTR_LATITUDE],
966 state.attributes[ATTR_LONGITUDE],
971 """Device scanner object."""
973 hass: HomeAssistant |
None =
None
976 """Scan for devices."""
977 raise NotImplementedError
980 """Scan for devices."""
982 self.hass
is not None
983 ),
"hass should be set by async_setup_scanner_platform"
984 return await self.hass.async_add_executor_job(self.
scan_devicesscan_devices)
987 """Get the name of a device."""
988 raise NotImplementedError
991 """Get the name of a device."""
993 self.hass
is not None
994 ),
"hass should be set by async_setup_scanner_platform"
995 return await self.hass.async_add_executor_job(self.
get_device_nameget_device_name, device)
998 """Get the extra attributes of a device."""
999 raise NotImplementedError
1002 """Get the extra attributes of a device."""
1004 self.hass
is not None
1005 ),
"hass should be set by async_setup_scanner_platform"
1006 return await self.hass.async_add_executor_job(self.
get_extra_attributesget_extra_attributes, device)
1010 path: str, hass: HomeAssistant, consider_home: timedelta
1012 """Load devices from YAML configuration file.
1014 This method is a coroutine.
1016 dev_schema = vol.Schema(
1018 vol.Required(CONF_NAME): cv.string,
1019 vol.Optional(CONF_ICON, default=
None): vol.Any(
None, cv.icon),
1020 vol.Optional(
"track", default=
False): cv.boolean,
1021 vol.Optional(CONF_MAC, default=
None): vol.Any(
1022 None, vol.All(cv.string, vol.Upper)
1024 vol.Optional(
"gravatar", default=
None): vol.Any(
None, cv.string),
1025 vol.Optional(
"picture", default=
None): vol.Any(
None, cv.string),
1026 vol.Optional(CONF_CONSIDER_HOME, default=consider_home): vol.All(
1027 cv.time_period, cv.positive_timedelta
1031 result: list[Device] = []
1033 devices = await hass.async_add_executor_job(load_yaml_config_file, path)
1034 except HomeAssistantError
as err:
1035 LOGGER.error(
"Unable to load %s: %s", path,
str(err))
1037 except FileNotFoundError:
1040 for dev_id, device
in devices.items():
1042 device.pop(
"vendor",
None)
1043 device.pop(
"hide_if_away",
None)
1045 device = dev_schema(device)
1046 device[
"dev_id"] = cv.slugify(dev_id)
1047 except vol.Invalid
as exp:
1051 result.append(
Device(hass, **device))
1056 """Add device to YAML configuration file."""
1057 with open(path,
"a", encoding=
"utf8")
as out:
1060 ATTR_NAME: device.name,
1061 ATTR_MAC: device.mac,
1062 ATTR_ICON: device.icon,
1063 "picture": device.config_picture,
1064 "track": device.track,
1068 out.write(
dump(device_config))
1072 """Remove device from YAML configuration file."""
1073 path = hass.config.path(YAML_DEVICES)
1075 devices.pop(device_id)
1076 dumped =
dump(devices)
1078 with open(path,
"r+", encoding=
"utf8")
as out:
1085 """Return an 80px Gravatar for the given email address.
1091 "https://www.gravatar.com/avatar/"
1092 f
"{hashlib.md5(email.encode('utf-8').lower()).hexdigest()}.jpg?s=80&d=wavatar"
None __call__(self, str|None mac=None, str|None dev_id=None, str|None host_name=None, str|None location_name=None, GPSType|None gps=None, int|None gps_accuracy=None, int|None battery=None, dict[str, Any]|None attributes=None, SourceType|str source_type=SourceType.GPS, str|None picture=None, str|None icon=None, timedelta|None consider_home=None)
str|None get_device_name(self, str device)
dict async_get_extra_attributes(self, str device)
dict get_extra_attributes(self, str device)
list[str] async_scan_devices(self)
list[str] scan_devices(self)
str|None async_get_device_name(self, str device)
None async_update_stale(self, datetime now)
None async_update_config(self, str path, str dev_id, Device device)
None async_setup_tracked_device(self)
None async_see(self, str|None mac=None, str|None dev_id=None, str|None host_name=None, str|None location_name=None, GPSType|None gps=None, int|None gps_accuracy=None, int|None battery=None, dict[str, Any]|None attributes=None, SourceType|str source_type=SourceType.GPS, str|None picture=None, str|None icon=None, timedelta|None consider_home=None)
None see(self, str|None mac=None, str|None dev_id=None, str|None host_name=None, str|None location_name=None, GPSType|None gps=None, int|None gps_accuracy=None, int|None battery=None, dict[str, Any]|None attributes=None, SourceType|str source_type=SourceType.GPS, str|None picture=None, str|None icon=None, timedelta|None consider_home=None)
None __init__(self, HomeAssistant hass, timedelta consider_home, bool track_new, dict[str, Any] defaults, Sequence[Device] devices)
dict[str, Any] extra_state_attributes(self)
None __init__(self, HomeAssistant hass, timedelta consider_home, bool track, str dev_id, str|None mac, str|None name=None, str|None picture=None, str|None gravatar=None, str|None icon=None)
None async_added_to_hass(self)
bool stale(self, datetime|None now=None)
str|None entity_picture(self)
None async_seen(self, str|None host_name=None, str|None location_name=None, GPSType|None gps=None, int|None gps_accuracy=None, int|None battery=None, dict[str, Any]|None attributes=None, SourceType|str source_type=SourceType.GPS, timedelta|None consider_home=None)
dict[str, StateType] state_attributes(self)
None __call__(self, str|None mac=None, str|None dev_id=None, str|None host_name=None, str|None location_name=None, GPSType|None gps=None, int|None gps_accuracy=None, int|None battery=None, dict[str, Any]|None attributes=None, SourceType|str source_type=SourceType.GPS, str|None picture=None, str|None icon=None, timedelta|None consider_home=None)
State|None async_get_last_state(self)
ArrisDeviceScanner|None async_get_scanner(HomeAssistant hass, ConfigType config)
bool async_setup_scanner(HomeAssistant hass, ConfigType config, AsyncSeeCallback async_see, DiscoveryInfoType|None discovery_info=None)
web.Response get(self, web.Request request, str config_key)
None remove_device_from_config(HomeAssistant hass, str device_id)
None see(HomeAssistant hass, str|None mac=None, str|None dev_id=None, str|None host_name=None, str|None location_name=None, GPSType|None gps=None, int|None gps_accuracy=None, int|None battery=None, dict[str, Any]|None attributes=None)
DeviceTrackerPlatform|None async_create_platform_type(HomeAssistant hass, ConfigType config, str p_type, dict p_config)
tuple[dict[str, str|None], dict[str, dict[str, Any]]] _load_device_names_and_attributes(DeviceScanner scanner, bool device_name_uses_executor, bool extra_attributes_uses_executor, set[str] seen, list[str] found_devices)
DeviceTracker get_tracker(HomeAssistant hass, ConfigType config)
list[DeviceTrackerPlatform] async_extract_config(HomeAssistant hass, ConfigType config)
str get_gravatar_for_email(str email)
None _async_setup_integration(HomeAssistant hass, ConfigType config, asyncio.Future[DeviceTracker] tracker_future)
None async_setup_integration(HomeAssistant hass, ConfigType config)
None update_config(str path, str dev_id, Device device)
None async_setup_scanner_platform(HomeAssistant hass, ConfigType config, DeviceScanner scanner, Callable[..., Coroutine[None, None, None]] async_see_device, str platform)
list[Device] async_load_config(str path, HomeAssistant hass, timedelta consider_home)
IssData update(pyiss.ISS iss)
None open(self, **Any kwargs)
Iterable[tuple[str|None, ConfigType]] config_per_platform(ConfigType config, str domain)
None async_log_schema_error(vol.Invalid exc, str domain, dict config, HomeAssistant hass, str|None link=None)
dict[Any, Any] load_yaml_config_file(str config_path, Secrets|None secrets=None)
CALLBACK_TYPE async_track_utc_time_change(HomeAssistant hass, Callable[[datetime], Coroutine[Any, Any, None]|None] action, Any|None hour=None, Any|None minute=None, Any|None second=None, bool local=False)
CALLBACK_TYPE async_track_time_interval(HomeAssistant hass, Callable[[datetime], Coroutine[Any, Any, None]|None] action, timedelta interval, *str|None name=None, bool|None cancel_on_shutdown=None)
ModuleType|None async_prepare_setup_platform(core.HomeAssistant hass, ConfigType hass_config, str domain, str platform_name)
None async_notify_setup_error(HomeAssistant hass, str component, str|None display_link=None)
Generator[None] async_start_setup(core.HomeAssistant hass, str integration, SetupPhases phase, str|None group=None)
str dump(dict|list _dict)