Enable type checks for device_tracker (#50805)
* Enable type checks for device_tracker * Fix MQTT test
This commit is contained in:
parent
4c7fcae536
commit
62386c8676
6 changed files with 84 additions and 73 deletions
|
@ -55,7 +55,7 @@ class ActiontecDeviceScanner(DeviceScanner):
|
||||||
self._update_info()
|
self._update_info()
|
||||||
return [client.mac_address for client in self.last_results]
|
return [client.mac_address for client in self.last_results]
|
||||||
|
|
||||||
def get_device_name(self, device: str) -> str | None: # type: ignore[override]
|
def get_device_name(self, device: str) -> str | None:
|
||||||
"""Return the name of the given device or None if we don't know."""
|
"""Return the name of the given device or None if we don't know."""
|
||||||
for client in self.last_results:
|
for client in self.last_results:
|
||||||
if client.mac_address == device:
|
if client.mac_address == device:
|
||||||
|
|
|
@ -82,19 +82,19 @@ class TrackerEntity(BaseTrackerEntity):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def location_name(self) -> str:
|
def location_name(self) -> str | None:
|
||||||
"""Return a location name for the current location of the device."""
|
"""Return a location name for the current location of the device."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def latitude(self) -> float:
|
def latitude(self) -> float | None:
|
||||||
"""Return latitude value of the device."""
|
"""Return latitude value of the device."""
|
||||||
return NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def longitude(self) -> float:
|
def longitude(self) -> float | None:
|
||||||
"""Return longitude value of the device."""
|
"""Return longitude value of the device."""
|
||||||
return NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
|
@ -102,7 +102,7 @@ class TrackerEntity(BaseTrackerEntity):
|
||||||
if self.location_name:
|
if self.location_name:
|
||||||
return self.location_name
|
return self.location_name
|
||||||
|
|
||||||
if self.latitude is not None:
|
if self.latitude is not None and self.longitude is not None:
|
||||||
zone_state = zone.async_active_zone(
|
zone_state = zone.async_active_zone(
|
||||||
self.hass, self.latitude, self.longitude, self.location_accuracy
|
self.hass, self.latitude, self.longitude, self.location_accuracy
|
||||||
)
|
)
|
||||||
|
|
|
@ -309,7 +309,7 @@ async def async_create_platform_type(
|
||||||
def async_setup_scanner_platform(
|
def async_setup_scanner_platform(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config: ConfigType,
|
config: ConfigType,
|
||||||
scanner: Any,
|
scanner: DeviceScanner,
|
||||||
async_see_device: Callable,
|
async_see_device: Callable,
|
||||||
platform: str,
|
platform: str,
|
||||||
):
|
):
|
||||||
|
@ -324,7 +324,7 @@ def async_setup_scanner_platform(
|
||||||
# Initial scan of each mac we also tell about host name for config
|
# Initial scan of each mac we also tell about host name for config
|
||||||
seen: Any = set()
|
seen: Any = set()
|
||||||
|
|
||||||
async def async_device_tracker_scan(now: dt_util.dt.datetime):
|
async def async_device_tracker_scan(now: dt_util.dt.datetime | None):
|
||||||
"""Handle interval matches."""
|
"""Handle interval matches."""
|
||||||
if update_lock.locked():
|
if update_lock.locked():
|
||||||
LOGGER.warning(
|
LOGGER.warning(
|
||||||
|
@ -424,21 +424,21 @@ class DeviceTracker:
|
||||||
|
|
||||||
def see(
|
def see(
|
||||||
self,
|
self,
|
||||||
mac: str = None,
|
mac: str | None = None,
|
||||||
dev_id: str = None,
|
dev_id: str | None = None,
|
||||||
host_name: str = None,
|
host_name: str | None = None,
|
||||||
location_name: str = None,
|
location_name: str | None = None,
|
||||||
gps: GPSType = None,
|
gps: GPSType | None = None,
|
||||||
gps_accuracy: int = None,
|
gps_accuracy: int | None = None,
|
||||||
battery: int = None,
|
battery: int | None = None,
|
||||||
attributes: dict = None,
|
attributes: dict | None = None,
|
||||||
source_type: str = SOURCE_TYPE_GPS,
|
source_type: str = SOURCE_TYPE_GPS,
|
||||||
picture: str = None,
|
picture: str | None = None,
|
||||||
icon: str = None,
|
icon: str | None = None,
|
||||||
consider_home: timedelta = None,
|
consider_home: timedelta | None = None,
|
||||||
):
|
):
|
||||||
"""Notify the device tracker that you see a device."""
|
"""Notify the device tracker that you see a device."""
|
||||||
self.hass.add_job(
|
self.hass.create_task(
|
||||||
self.async_see(
|
self.async_see(
|
||||||
mac,
|
mac,
|
||||||
dev_id,
|
dev_id,
|
||||||
|
@ -457,19 +457,19 @@ class DeviceTracker:
|
||||||
|
|
||||||
async def async_see(
|
async def async_see(
|
||||||
self,
|
self,
|
||||||
mac: str = None,
|
mac: str | None = None,
|
||||||
dev_id: str = None,
|
dev_id: str | None = None,
|
||||||
host_name: str = None,
|
host_name: str | None = None,
|
||||||
location_name: str = None,
|
location_name: str | None = None,
|
||||||
gps: GPSType = None,
|
gps: GPSType | None = None,
|
||||||
gps_accuracy: int = None,
|
gps_accuracy: int | None = None,
|
||||||
battery: int = None,
|
battery: int | None = None,
|
||||||
attributes: dict = None,
|
attributes: dict | None = None,
|
||||||
source_type: str = SOURCE_TYPE_GPS,
|
source_type: str = SOURCE_TYPE_GPS,
|
||||||
picture: str = None,
|
picture: str | None = None,
|
||||||
icon: str = None,
|
icon: str | None = None,
|
||||||
consider_home: timedelta = None,
|
consider_home: timedelta | None = None,
|
||||||
):
|
) -> None:
|
||||||
"""Notify the device tracker that you see a device.
|
"""Notify the device tracker that you see a device.
|
||||||
|
|
||||||
This method is a coroutine.
|
This method is a coroutine.
|
||||||
|
@ -480,13 +480,13 @@ class DeviceTracker:
|
||||||
if mac is not None:
|
if mac is not None:
|
||||||
mac = str(mac).upper()
|
mac = str(mac).upper()
|
||||||
device = self.mac_to_dev.get(mac)
|
device = self.mac_to_dev.get(mac)
|
||||||
if not device:
|
if device is None:
|
||||||
dev_id = util.slugify(host_name or "") or util.slugify(mac)
|
dev_id = util.slugify(host_name or "") or util.slugify(mac)
|
||||||
else:
|
else:
|
||||||
dev_id = cv.slug(str(dev_id).lower())
|
dev_id = cv.slug(str(dev_id).lower())
|
||||||
device = self.devices.get(dev_id)
|
device = self.devices.get(dev_id)
|
||||||
|
|
||||||
if device:
|
if device is not None:
|
||||||
await device.async_seen(
|
await device.async_seen(
|
||||||
host_name,
|
host_name,
|
||||||
location_name,
|
location_name,
|
||||||
|
@ -501,6 +501,9 @@ class DeviceTracker:
|
||||||
device.async_write_ha_state()
|
device.async_write_ha_state()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# If it's None then device is not None and we can't get here.
|
||||||
|
assert dev_id is not None
|
||||||
|
|
||||||
# Guard from calling see on entity registry entities.
|
# Guard from calling see on entity registry entities.
|
||||||
entity_id = f"{DOMAIN}.{dev_id}"
|
entity_id = f"{DOMAIN}.{dev_id}"
|
||||||
if registry.async_is_registered(entity_id):
|
if registry.async_is_registered(entity_id):
|
||||||
|
@ -598,15 +601,13 @@ class DeviceTracker:
|
||||||
class Device(RestoreEntity):
|
class Device(RestoreEntity):
|
||||||
"""Base class for a tracked device."""
|
"""Base class for a tracked device."""
|
||||||
|
|
||||||
host_name: str = None
|
host_name: str | None = None
|
||||||
location_name: str = None
|
location_name: str | None = None
|
||||||
gps: GPSType = None
|
gps: GPSType | None = None
|
||||||
gps_accuracy: int = 0
|
gps_accuracy: int = 0
|
||||||
last_seen: dt_util.dt.datetime = None
|
last_seen: dt_util.dt.datetime | None = None
|
||||||
consider_home: dt_util.dt.timedelta = None
|
battery: int | None = None
|
||||||
battery: int = None
|
attributes: dict | None = None
|
||||||
attributes: dict = None
|
|
||||||
icon: str = None
|
|
||||||
|
|
||||||
# Track if the last update of this device was HOME.
|
# Track if the last update of this device was HOME.
|
||||||
last_update_home = False
|
last_update_home = False
|
||||||
|
@ -618,11 +619,11 @@ class Device(RestoreEntity):
|
||||||
consider_home: timedelta,
|
consider_home: timedelta,
|
||||||
track: bool,
|
track: bool,
|
||||||
dev_id: str,
|
dev_id: str,
|
||||||
mac: str,
|
mac: str | None,
|
||||||
name: str = None,
|
name: str | None = None,
|
||||||
picture: str = None,
|
picture: str | None = None,
|
||||||
gravatar: str = None,
|
gravatar: str | None = None,
|
||||||
icon: str = None,
|
icon: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a device."""
|
"""Initialize a device."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
|
@ -648,11 +649,11 @@ class Device(RestoreEntity):
|
||||||
else:
|
else:
|
||||||
self.config_picture = picture
|
self.config_picture = picture
|
||||||
|
|
||||||
self.icon = icon
|
self._icon = icon
|
||||||
|
|
||||||
self.source_type = None
|
self.source_type: str | None = None
|
||||||
|
|
||||||
self._attributes = {}
|
self._attributes: dict[str, Any] = {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
@ -686,21 +687,26 @@ class Device(RestoreEntity):
|
||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self):
|
def extra_state_attributes(self) -> dict[str, Any]:
|
||||||
"""Return device state attributes."""
|
"""Return device state attributes."""
|
||||||
return self._attributes
|
return self._attributes
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self) -> str | None:
|
||||||
|
"""Return device icon."""
|
||||||
|
return self._icon
|
||||||
|
|
||||||
async def async_seen(
|
async def async_seen(
|
||||||
self,
|
self,
|
||||||
host_name: str = None,
|
host_name: str | None = None,
|
||||||
location_name: str = None,
|
location_name: str | None = None,
|
||||||
gps: GPSType = None,
|
gps: GPSType | None = None,
|
||||||
gps_accuracy=0,
|
gps_accuracy: int | None = None,
|
||||||
battery: int = None,
|
battery: int | None = None,
|
||||||
attributes: dict = None,
|
attributes: dict[str, Any] | None = None,
|
||||||
source_type: str = SOURCE_TYPE_GPS,
|
source_type: str = SOURCE_TYPE_GPS,
|
||||||
consider_home: timedelta = None,
|
consider_home: timedelta | None = None,
|
||||||
):
|
) -> None:
|
||||||
"""Mark the device as seen."""
|
"""Mark the device as seen."""
|
||||||
self.source_type = source_type
|
self.source_type = source_type
|
||||||
self.last_seen = dt_util.utcnow()
|
self.last_seen = dt_util.utcnow()
|
||||||
|
@ -708,9 +714,9 @@ class Device(RestoreEntity):
|
||||||
self.location_name = location_name
|
self.location_name = location_name
|
||||||
self.consider_home = consider_home or self.consider_home
|
self.consider_home = consider_home or self.consider_home
|
||||||
|
|
||||||
if battery:
|
if battery is not None:
|
||||||
self.battery = battery
|
self.battery = battery
|
||||||
if attributes:
|
if attributes is not None:
|
||||||
self._attributes.update(attributes)
|
self._attributes.update(attributes)
|
||||||
|
|
||||||
self.gps = None
|
self.gps = None
|
||||||
|
@ -726,7 +732,7 @@ class Device(RestoreEntity):
|
||||||
|
|
||||||
await self.async_update()
|
await self.async_update()
|
||||||
|
|
||||||
def stale(self, now: dt_util.dt.datetime = None):
|
def stale(self, now: dt_util.dt.datetime | None = None) -> bool:
|
||||||
"""Return if device state is stale.
|
"""Return if device state is stale.
|
||||||
|
|
||||||
Async friendly.
|
Async friendly.
|
||||||
|
@ -795,7 +801,7 @@ class Device(RestoreEntity):
|
||||||
class DeviceScanner:
|
class DeviceScanner:
|
||||||
"""Device scanner object."""
|
"""Device scanner object."""
|
||||||
|
|
||||||
hass: HomeAssistant = None
|
hass: HomeAssistant | None = None
|
||||||
|
|
||||||
def scan_devices(self) -> list[str]:
|
def scan_devices(self) -> list[str]:
|
||||||
"""Scan for devices."""
|
"""Scan for devices."""
|
||||||
|
@ -803,14 +809,20 @@ class DeviceScanner:
|
||||||
|
|
||||||
async def async_scan_devices(self) -> Any:
|
async def async_scan_devices(self) -> Any:
|
||||||
"""Scan for devices."""
|
"""Scan for devices."""
|
||||||
|
assert (
|
||||||
|
self.hass is not None
|
||||||
|
), "hass should be set by async_setup_scanner_platform"
|
||||||
return await self.hass.async_add_executor_job(self.scan_devices)
|
return await self.hass.async_add_executor_job(self.scan_devices)
|
||||||
|
|
||||||
def get_device_name(self, device: str) -> str:
|
def get_device_name(self, device: str) -> str | None:
|
||||||
"""Get the name of a device."""
|
"""Get the name of a device."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
async def async_get_device_name(self, device: str) -> Any:
|
async def async_get_device_name(self, device: str) -> str | None:
|
||||||
"""Get the name of a device."""
|
"""Get the name of a device."""
|
||||||
|
assert (
|
||||||
|
self.hass is not None
|
||||||
|
), "hass should be set by async_setup_scanner_platform"
|
||||||
return await self.hass.async_add_executor_job(self.get_device_name, device)
|
return await self.hass.async_add_executor_job(self.get_device_name, device)
|
||||||
|
|
||||||
def get_extra_attributes(self, device: str) -> dict:
|
def get_extra_attributes(self, device: str) -> dict:
|
||||||
|
@ -819,6 +831,9 @@ class DeviceScanner:
|
||||||
|
|
||||||
async def async_get_extra_attributes(self, device: str) -> Any:
|
async def async_get_extra_attributes(self, device: str) -> Any:
|
||||||
"""Get the extra attributes of a device."""
|
"""Get the extra attributes of a device."""
|
||||||
|
assert (
|
||||||
|
self.hass is not None
|
||||||
|
), "hass should be set by async_setup_scanner_platform"
|
||||||
return await self.hass.async_add_executor_job(self.get_extra_attributes, device)
|
return await self.hass.async_add_executor_job(self.get_extra_attributes, device)
|
||||||
|
|
||||||
|
|
||||||
|
@ -868,7 +883,7 @@ async def async_load_config(path: str, hass: HomeAssistant, consider_home: timed
|
||||||
def update_config(path: str, dev_id: str, device: Device):
|
def update_config(path: str, dev_id: str, device: Device):
|
||||||
"""Add device to YAML configuration file."""
|
"""Add device to YAML configuration file."""
|
||||||
with open(path, "a") as out:
|
with open(path, "a") as out:
|
||||||
device = {
|
device_config = {
|
||||||
device.dev_id: {
|
device.dev_id: {
|
||||||
ATTR_NAME: device.name,
|
ATTR_NAME: device.name,
|
||||||
ATTR_MAC: device.mac,
|
ATTR_MAC: device.mac,
|
||||||
|
@ -878,7 +893,7 @@ def update_config(path: str, dev_id: str, device: Device):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.write("\n")
|
out.write("\n")
|
||||||
out.write(dump(device))
|
out.write(dump(device_config))
|
||||||
|
|
||||||
|
|
||||||
def get_gravatar_for_email(email: str):
|
def get_gravatar_for_email(email: str):
|
||||||
|
|
3
mypy.ini
3
mypy.ini
|
@ -816,9 +816,6 @@ ignore_errors = true
|
||||||
[mypy-homeassistant.components.denonavr.*]
|
[mypy-homeassistant.components.denonavr.*]
|
||||||
ignore_errors = true
|
ignore_errors = true
|
||||||
|
|
||||||
[mypy-homeassistant.components.device_tracker.*]
|
|
||||||
ignore_errors = true
|
|
||||||
|
|
||||||
[mypy-homeassistant.components.devolo_home_control.*]
|
[mypy-homeassistant.components.devolo_home_control.*]
|
||||||
ignore_errors = true
|
ignore_errors = true
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,6 @@ IGNORED_MODULES: Final[list[str]] = [
|
||||||
"homeassistant.components.deconz.*",
|
"homeassistant.components.deconz.*",
|
||||||
"homeassistant.components.demo.*",
|
"homeassistant.components.demo.*",
|
||||||
"homeassistant.components.denonavr.*",
|
"homeassistant.components.denonavr.*",
|
||||||
"homeassistant.components.device_tracker.*",
|
|
||||||
"homeassistant.components.devolo_home_control.*",
|
"homeassistant.components.devolo_home_control.*",
|
||||||
"homeassistant.components.dhcp.*",
|
"homeassistant.components.dhcp.*",
|
||||||
"homeassistant.components.directv.*",
|
"homeassistant.components.directv.*",
|
||||||
|
|
|
@ -359,4 +359,4 @@ async def test_setting_device_tracker_location_via_lat_lon_message(
|
||||||
async_fire_mqtt_message(hass, "attributes-topic", '{"latitude":32.87336}')
|
async_fire_mqtt_message(hass, "attributes-topic", '{"latitude":32.87336}')
|
||||||
state = hass.states.get("device_tracker.test")
|
state = hass.states.get("device_tracker.test")
|
||||||
assert state.attributes["latitude"] == 32.87336
|
assert state.attributes["latitude"] == 32.87336
|
||||||
assert state.state == STATE_NOT_HOME
|
assert state.state == STATE_UNKNOWN
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue