Add strict typing to abode (#57673)

This commit is contained in:
Robert Hillis 2022-01-10 09:54:09 -05:00 committed by GitHub
parent bc2f4e82e3
commit 7c51d2f159
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 304 additions and 221 deletions

View File

@ -4,6 +4,7 @@
homeassistant.core
homeassistant.components
homeassistant.components.abode.*
homeassistant.components.acer_projector.*
homeassistant.components.accuweather.*
homeassistant.components.actiontec.*

View File

@ -1,7 +1,10 @@
"""Support for the Abode Security System."""
from __future__ import annotations
from functools import partial
from abodepy import Abode
from abodepy import Abode, AbodeAutomation as AbodeAuto
from abodepy.devices import AbodeDevice as AbodeDev
from abodepy.exceptions import AbodeAuthenticationException, AbodeException
import abodepy.helpers.timeline as TIMELINE
from requests.exceptions import ConnectTimeout, HTTPError
@ -18,15 +21,12 @@ from homeassistant.const import (
EVENT_HOMEASSISTANT_STOP,
Platform,
)
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.core import Event, HomeAssistant, ServiceCall
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers import config_validation as cv, entity
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.entity import DeviceInfo, Entity
from .const import ATTRIBUTION, DEFAULT_CACHEDB, DOMAIN, LOGGER
CONF_POLLING = "polling"
from .const import ATTRIBUTION, CONF_POLLING, DEFAULT_CACHEDB, DOMAIN, LOGGER
SERVICE_SETTINGS = "change_setting"
SERVICE_CAPTURE_IMAGE = "capture_image"
@ -69,25 +69,25 @@ PLATFORMS = [
class AbodeSystem:
"""Abode System class."""
def __init__(self, abode, polling):
def __init__(self, abode: Abode, polling: bool) -> None:
"""Initialize the system."""
self.abode = abode
self.polling = polling
self.entity_ids = set()
self.entity_ids: set[str | None] = set()
self.logout_listener = None
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Abode integration from a config entry."""
username = config_entry.data.get(CONF_USERNAME)
password = config_entry.data.get(CONF_PASSWORD)
polling = config_entry.data.get(CONF_POLLING)
username = entry.data[CONF_USERNAME]
password = entry.data[CONF_PASSWORD]
polling = entry.data[CONF_POLLING]
cache = hass.config.path(DEFAULT_CACHEDB)
# For previous config entries where unique_id is None
if config_entry.unique_id is None:
if entry.unique_id is None:
hass.config_entries.async_update_entry(
config_entry, unique_id=config_entry.data[CONF_USERNAME]
entry, unique_id=entry.data[CONF_USERNAME]
)
try:
@ -103,7 +103,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
hass.data[DOMAIN] = AbodeSystem(abode, polling)
hass.config_entries.async_setup_platforms(config_entry, PLATFORMS)
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
await setup_hass_events(hass)
await hass.async_add_executor_job(setup_hass_services, hass)
@ -112,15 +112,13 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
return True
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
hass.services.async_remove(DOMAIN, SERVICE_SETTINGS)
hass.services.async_remove(DOMAIN, SERVICE_CAPTURE_IMAGE)
hass.services.async_remove(DOMAIN, SERVICE_TRIGGER_AUTOMATION)
unload_ok = await hass.config_entries.async_unload_platforms(
config_entry, PLATFORMS
)
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
await hass.async_add_executor_job(hass.data[DOMAIN].abode.events.stop)
await hass.async_add_executor_job(hass.data[DOMAIN].abode.logout)
@ -188,7 +186,7 @@ def setup_hass_services(hass: HomeAssistant) -> None:
async def setup_hass_events(hass: HomeAssistant) -> None:
"""Home Assistant start and stop callbacks."""
def logout(event):
def logout(event: Event) -> None:
"""Logout of Abode."""
if not hass.data[DOMAIN].polling:
hass.data[DOMAIN].abode.events.stop()
@ -207,7 +205,7 @@ async def setup_hass_events(hass: HomeAssistant) -> None:
def setup_abode_events(hass: HomeAssistant) -> None:
"""Event callbacks."""
def event_callback(event, event_json):
def event_callback(event: str, event_json: dict[str, str]) -> None:
"""Handle an event callback from Abode."""
data = {
ATTR_DEVICE_ID: event_json.get(ATTR_DEVICE_ID, ""),
@ -246,17 +244,17 @@ def setup_abode_events(hass: HomeAssistant) -> None:
)
class AbodeEntity(Entity):
class AbodeEntity(entity.Entity):
"""Representation of an Abode entity."""
_attr_attribution = ATTRIBUTION
def __init__(self, data):
def __init__(self, data: AbodeSystem) -> None:
"""Initialize Abode entity."""
self._data = data
self._attr_should_poll = data.polling
async def async_added_to_hass(self):
async def async_added_to_hass(self) -> None:
"""Subscribe to Abode connection status updates."""
await self.hass.async_add_executor_job(
self._data.abode.events.add_connection_status_callback,
@ -266,13 +264,13 @@ class AbodeEntity(Entity):
self.hass.data[DOMAIN].entity_ids.add(self.entity_id)
async def async_will_remove_from_hass(self):
async def async_will_remove_from_hass(self) -> None:
"""Unsubscribe from Abode connection status updates."""
await self.hass.async_add_executor_job(
self._data.abode.events.remove_connection_status_callback, self.unique_id
)
def _update_connection_status(self):
def _update_connection_status(self) -> None:
"""Update the entity available property."""
self._attr_available = self._data.abode.events.connected
self.schedule_update_ha_state()
@ -281,14 +279,14 @@ class AbodeEntity(Entity):
class AbodeDevice(AbodeEntity):
"""Representation of an Abode device."""
def __init__(self, data, device):
def __init__(self, data: AbodeSystem, device: AbodeDev) -> None:
"""Initialize Abode device."""
super().__init__(data)
self._device = device
self._attr_name = device.name
self._attr_unique_id = device.device_uuid
async def async_added_to_hass(self):
async def async_added_to_hass(self) -> None:
"""Subscribe to device events."""
await super().async_added_to_hass()
await self.hass.async_add_executor_job(
@ -297,19 +295,19 @@ class AbodeDevice(AbodeEntity):
self._update_callback,
)
async def async_will_remove_from_hass(self):
async def async_will_remove_from_hass(self) -> None:
"""Unsubscribe from device events."""
await super().async_will_remove_from_hass()
await self.hass.async_add_executor_job(
self._data.abode.events.remove_all_device_callbacks, self._device.device_id
)
def update(self):
def update(self) -> None:
"""Update device state."""
self._device.refresh()
@property
def extra_state_attributes(self):
def extra_state_attributes(self) -> dict[str, str]:
"""Return the state attributes."""
return {
"device_id": self._device.device_id,
@ -319,16 +317,16 @@ class AbodeDevice(AbodeEntity):
}
@property
def device_info(self) -> DeviceInfo:
def device_info(self) -> entity.DeviceInfo:
"""Return device registry information for this entity."""
return DeviceInfo(
return entity.DeviceInfo(
identifiers={(DOMAIN, self._device.device_id)},
manufacturer="Abode",
model=self._device.type,
name=self._device.name,
)
def _update_callback(self, device):
def _update_callback(self, device: AbodeDev) -> None:
"""Update the device state."""
self.schedule_update_ha_state()
@ -336,7 +334,7 @@ class AbodeDevice(AbodeEntity):
class AbodeAutomation(AbodeEntity):
"""Representation of an Abode automation."""
def __init__(self, data, automation):
def __init__(self, data: AbodeSystem, automation: AbodeAuto) -> None:
"""Initialize for Abode automation."""
super().__init__(data)
self._automation = automation
@ -346,6 +344,6 @@ class AbodeAutomation(AbodeEntity):
"type": "CUE automation",
}
def update(self):
def update(self) -> None:
"""Update automation state."""
self._automation.refresh()

View File

@ -1,4 +1,8 @@
"""Support for Abode Security System alarm control panels."""
from __future__ import annotations
from abodepy.devices.alarm import AbodeAlarm as AbodeAl
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_AWAY,
@ -13,19 +17,17 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AbodeDevice
from . import AbodeDevice, AbodeSystem
from .const import DOMAIN
ICON = "mdi:security"
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Abode alarm control panel device."""
data = hass.data[DOMAIN]
data: AbodeSystem = hass.data[DOMAIN]
async_add_entities(
[AbodeAlarm(data, await hass.async_add_executor_job(data.abode.get_alarm))]
)
@ -37,34 +39,33 @@ class AbodeAlarm(AbodeDevice, alarm.AlarmControlPanelEntity):
_attr_icon = ICON
_attr_code_arm_required = False
_attr_supported_features = SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
_device: AbodeAl
@property
def state(self):
def state(self) -> str | None:
"""Return the state of the device."""
if self._device.is_standby:
state = STATE_ALARM_DISARMED
elif self._device.is_away:
state = STATE_ALARM_ARMED_AWAY
elif self._device.is_home:
state = STATE_ALARM_ARMED_HOME
else:
state = None
return state
return STATE_ALARM_DISARMED
if self._device.is_away:
return STATE_ALARM_ARMED_AWAY
if self._device.is_home:
return STATE_ALARM_ARMED_HOME
return None
def alarm_disarm(self, code=None):
def alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
self._device.set_standby()
def alarm_arm_home(self, code=None):
def alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
self._device.set_home()
def alarm_arm_away(self, code=None):
def alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
self._device.set_away()
@property
def extra_state_attributes(self):
def extra_state_attributes(self) -> dict[str, str]:
"""Return the state attributes."""
return {
"device_id": self._device.device_id,

View File

@ -1,4 +1,7 @@
"""Support for Abode Security System binary sensors."""
from typing import cast
from abodepy.devices.binary_sensor import AbodeBinarySensor as ABBinarySensor
import abodepy.helpers.constants as CONST
from homeassistant.components.binary_sensor import (
@ -9,17 +12,15 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AbodeDevice
from . import AbodeDevice, AbodeSystem
from .const import DOMAIN
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Abode binary sensor devices."""
data = hass.data[DOMAIN]
data: AbodeSystem = hass.data[DOMAIN]
device_types = [
CONST.TYPE_CONNECTIVITY,
@ -40,14 +41,16 @@ async def async_setup_entry(
class AbodeBinarySensor(AbodeDevice, BinarySensorEntity):
"""A binary sensor implementation for Abode device."""
@property
def is_on(self):
"""Return True if the binary sensor is on."""
return self._device.is_on
_device: ABBinarySensor
@property
def device_class(self):
def is_on(self) -> bool:
"""Return True if the binary sensor is on."""
return cast(bool, self._device.is_on)
@property
def device_class(self) -> str:
"""Return the class of the binary sensor."""
if self._device.get_value("is_window") == "1":
return BinarySensorDeviceClass.WINDOW
return self._device.generic_type
return cast(str, self._device.generic_type)

View File

@ -2,32 +2,32 @@
from __future__ import annotations
from datetime import timedelta
from typing import Any, cast
import abodepy.helpers.constants as CONST
from abodepy.devices import CONST, AbodeDevice as AbodeDev
from abodepy.devices.camera import AbodeCamera as AbodeCam
import abodepy.helpers.timeline as TIMELINE
import requests
from requests.models import Response
from homeassistant.components.camera import Camera
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.core import Event, HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util import Throttle
from . import AbodeDevice
from . import AbodeDevice, AbodeSystem
from .const import DOMAIN, LOGGER
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Abode camera devices."""
data = hass.data[DOMAIN]
data: AbodeSystem = hass.data[DOMAIN]
entities = []
for device in data.abode.get_devices(generic_type=CONST.TYPE_CAMERA):
@ -39,14 +39,16 @@ async def async_setup_entry(
class AbodeCamera(AbodeDevice, Camera):
"""Representation of an Abode camera."""
def __init__(self, data, device, event):
_device: AbodeCam
def __init__(self, data: AbodeSystem, device: AbodeDev, event: Event) -> None:
"""Initialize the Abode device."""
AbodeDevice.__init__(self, data, device)
Camera.__init__(self)
self._event = event
self._response = None
self._response: Response | None = None
async def async_added_to_hass(self):
async def async_added_to_hass(self) -> None:
"""Subscribe Abode events."""
await super().async_added_to_hass()
@ -59,17 +61,17 @@ class AbodeCamera(AbodeDevice, Camera):
signal = f"abode_camera_capture_{self.entity_id}"
self.async_on_remove(async_dispatcher_connect(self.hass, signal, self.capture))
def capture(self):
def capture(self) -> bool:
"""Request a new image capture."""
return self._device.capture()
return cast(bool, self._device.capture())
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def refresh_image(self):
def refresh_image(self) -> None:
"""Find a new image on the timeline."""
if self._device.refresh_image():
self.get_image()
def get_image(self):
def get_image(self) -> None:
"""Attempt to download the most recent capture."""
if self._device.image_url:
try:
@ -93,21 +95,21 @@ class AbodeCamera(AbodeDevice, Camera):
return None
def turn_on(self):
def turn_on(self) -> None:
"""Turn on camera."""
self._device.privacy_mode(False)
def turn_off(self):
def turn_off(self) -> None:
"""Turn off camera."""
self._device.privacy_mode(True)
def _capture_callback(self, capture):
def _capture_callback(self, capture: Any) -> None:
"""Update the image with the device then refresh device."""
self._device.update_image_location(capture)
self.get_image()
self.schedule_update_ha_state()
@property
def is_on(self):
def is_on(self) -> bool:
"""Return true if on."""
return self._device.is_on
return cast(bool, self._device.is_on)

View File

@ -1,5 +1,8 @@
"""Config flow for the Abode Security System component."""
from __future__ import annotations
from http import HTTPStatus
from typing import Any, cast
from abodepy import Abode
from abodepy.exceptions import AbodeAuthenticationException, AbodeException
@ -9,11 +12,11 @@ import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.data_entry_flow import FlowResult
from .const import DEFAULT_CACHEDB, DOMAIN, LOGGER
from .const import CONF_POLLING, DEFAULT_CACHEDB, DOMAIN, LOGGER
CONF_MFA = "mfa_code"
CONF_POLLING = "polling"
class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
@ -21,7 +24,7 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
VERSION = 1
def __init__(self):
def __init__(self) -> None:
"""Initialize."""
self.data_schema = {
vol.Required(CONF_USERNAME): str,
@ -31,13 +34,13 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
vol.Required(CONF_MFA): str,
}
self._cache = None
self._mfa_code = None
self._password = None
self._polling = False
self._username = None
self._cache: str | None = None
self._mfa_code: str | None = None
self._password: str | None = None
self._polling: bool = False
self._username: str | None = None
async def _async_abode_login(self, step_id):
async def _async_abode_login(self, step_id: str) -> FlowResult:
"""Handle login with Abode."""
self._cache = self.hass.config.path(DEFAULT_CACHEDB)
errors = {}
@ -47,7 +50,7 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
Abode, self._username, self._password, True, False, False, self._cache
)
except (AbodeException, ConnectTimeout, HTTPError) as ex:
except AbodeException as ex:
if ex.errcode == MFA_CODE_REQUIRED[0]:
return await self.async_step_mfa()
@ -59,6 +62,9 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
else:
errors = {"base": "cannot_connect"}
except (ConnectTimeout, HTTPError):
errors = {"base": "cannot_connect"}
if errors:
return self.async_show_form(
step_id=step_id, data_schema=vol.Schema(self.data_schema), errors=errors
@ -66,7 +72,7 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return await self._async_create_entry()
async def _async_abode_mfa_login(self):
async def _async_abode_mfa_login(self) -> FlowResult:
"""Handle multi-factor authentication (MFA) login with Abode."""
try:
# Create instance to access login method for passing MFA code
@ -89,7 +95,7 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return await self._async_create_entry()
async def _async_create_entry(self):
async def _async_create_entry(self) -> FlowResult:
"""Create the config entry."""
config_data = {
CONF_USERNAME: self._username,
@ -109,9 +115,13 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_abort(reason="reauth_successful")
return self.async_create_entry(title=self._username, data=config_data)
return self.async_create_entry(
title=cast(str, self._username), data=config_data
)
async def async_step_user(self, user_input=None):
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle a flow initialized by the user."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
@ -126,7 +136,9 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return await self._async_abode_login(step_id="user")
async def async_step_mfa(self, user_input=None):
async def async_step_mfa(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle a multi-factor authentication (MFA) flow."""
if user_input is None:
return self.async_show_form(
@ -137,13 +149,15 @@ class AbodeFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return await self._async_abode_mfa_login()
async def async_step_reauth(self, config):
async def async_step_reauth(self, config: dict[str, Any]) -> FlowResult:
"""Handle reauthorization request from Abode."""
self._username = config[CONF_USERNAME]
return await self.async_step_reauth_confirm()
async def async_step_reauth_confirm(self, user_input=None):
async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle reauthorization flow."""
if user_input is None:
return self.async_show_form(

View File

@ -7,3 +7,4 @@ DOMAIN = "abode"
ATTRIBUTION = "Data provided by goabode.com"
DEFAULT_CACHEDB = "abodepy_cache.pickle"
CONF_POLLING = "polling"

View File

@ -1,4 +1,7 @@
"""Support for Abode Security System covers."""
from typing import Any
from abodepy.devices.cover import AbodeCover as AbodeCV
import abodepy.helpers.constants as CONST
from homeassistant.components.cover import CoverEntity
@ -6,17 +9,15 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AbodeDevice
from . import AbodeDevice, AbodeSystem
from .const import DOMAIN
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Abode cover devices."""
data = hass.data[DOMAIN]
data: AbodeSystem = hass.data[DOMAIN]
entities = []
@ -29,15 +30,17 @@ async def async_setup_entry(
class AbodeCover(AbodeDevice, CoverEntity):
"""Representation of an Abode cover."""
_device: AbodeCV
@property
def is_closed(self):
def is_closed(self) -> bool:
"""Return true if cover is closed, else False."""
return not self._device.is_open
def close_cover(self, **kwargs):
def close_cover(self, **kwargs: Any) -> None:
"""Issue close command to cover."""
self._device.close_cover()
def open_cover(self, **kwargs):
def open_cover(self, **kwargs: Any) -> None:
"""Issue open command to cover."""
self._device.open_cover()

View File

@ -1,6 +1,10 @@
"""Support for Abode Security System lights."""
from math import ceil
from __future__ import annotations
from math import ceil
from typing import Any
from abodepy.devices.light import AbodeLight as AbodeLT
import abodepy.helpers.constants as CONST
from homeassistant.components.light import (
@ -20,17 +24,15 @@ from homeassistant.util.color import (
color_temperature_mired_to_kelvin,
)
from . import AbodeDevice
from . import AbodeDevice, AbodeSystem
from .const import DOMAIN
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Abode light devices."""
data = hass.data[DOMAIN]
data: AbodeSystem = hass.data[DOMAIN]
entities = []
@ -43,7 +45,9 @@ async def async_setup_entry(
class AbodeLight(AbodeDevice, LightEntity):
"""Representation of an Abode light."""
def turn_on(self, **kwargs):
_device: AbodeLT
def turn_on(self, **kwargs: Any) -> None:
"""Turn on the light."""
if ATTR_COLOR_TEMP in kwargs and self._device.is_color_capable:
self._device.set_color_temp(
@ -63,40 +67,42 @@ class AbodeLight(AbodeDevice, LightEntity):
self._device.switch_on()
def turn_off(self, **kwargs):
def turn_off(self, **kwargs: Any) -> None:
"""Turn off the light."""
self._device.switch_off()
@property
def is_on(self):
def is_on(self) -> bool:
"""Return true if device is on."""
return self._device.is_on
return bool(self._device.is_on)
@property
def brightness(self):
def brightness(self) -> int | None:
"""Return the brightness of the light."""
if self._device.is_dimmable and self._device.has_brightness:
brightness = int(self._device.brightness)
# Abode returns 100 during device initialization and device refresh
if brightness == 100:
return 255
# Convert Abode brightness (0-99) to Home Assistant brightness (0-255)
return ceil(brightness * 255 / 99.0)
return 255 if brightness == 100 else ceil(brightness * 255 / 99.0)
return None
@property
def color_temp(self):
def color_temp(self) -> int | None:
"""Return the color temp of the light."""
if self._device.has_color:
return color_temperature_kelvin_to_mired(self._device.color_temp)
return None
@property
def hs_color(self):
def hs_color(self) -> tuple[float, float] | None:
"""Return the color of the light."""
_hs = None
if self._device.has_color:
return self._device.color
_hs = self._device.color
return _hs
@property
def supported_features(self):
def supported_features(self) -> int:
"""Flag supported features."""
if self._device.is_dimmable and self._device.is_color_capable:
return SUPPORT_BRIGHTNESS | SUPPORT_COLOR | SUPPORT_COLOR_TEMP

View File

@ -1,4 +1,7 @@
"""Support for the Abode Security System locks."""
from typing import Any
from abodepy.devices.lock import AbodeLock as AbodeLK
import abodepy.helpers.constants as CONST
from homeassistant.components.lock import LockEntity
@ -6,17 +9,15 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AbodeDevice
from . import AbodeDevice, AbodeSystem
from .const import DOMAIN
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Abode lock devices."""
data = hass.data[DOMAIN]
data: AbodeSystem = hass.data[DOMAIN]
entities = []
@ -29,15 +30,17 @@ async def async_setup_entry(
class AbodeLock(AbodeDevice, LockEntity):
"""Representation of an Abode lock."""
def lock(self, **kwargs):
_device: AbodeLK
def lock(self, **kwargs: Any) -> None:
"""Lock the device."""
self._device.lock()
def unlock(self, **kwargs):
def unlock(self, **kwargs: Any) -> None:
"""Unlock the device."""
self._device.unlock()
@property
def is_locked(self):
def is_locked(self) -> bool:
"""Return true if device is on."""
return self._device.is_locked
return bool(self._device.is_locked)

View File

@ -1,7 +1,9 @@
"""Support for Abode Security System sensors."""
from __future__ import annotations
import abodepy.helpers.constants as CONST
from typing import cast
from abodepy.devices.sensor import CONST, AbodeSensor as AbodeSense
from homeassistant.components.sensor import (
SensorDeviceClass,
@ -12,7 +14,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AbodeDevice
from . import AbodeDevice, AbodeSystem
from .const import DOMAIN
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
@ -35,12 +37,10 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Abode sensor devices."""
data = hass.data[DOMAIN]
data: AbodeSystem = hass.data[DOMAIN]
entities = []
@ -60,7 +60,14 @@ async def async_setup_entry(
class AbodeSensor(AbodeDevice, SensorEntity):
"""A sensor implementation for Abode devices."""
def __init__(self, data, device, description: SensorEntityDescription):
_device: AbodeSense
def __init__(
self,
data: AbodeSystem,
device: AbodeSense,
description: SensorEntityDescription,
) -> None:
"""Initialize a sensor for an Abode device."""
super().__init__(data, device)
self.entity_description = description
@ -74,11 +81,12 @@ class AbodeSensor(AbodeDevice, SensorEntity):
self._attr_native_unit_of_measurement = device.lux_unit
@property
def native_value(self):
def native_value(self) -> float | None:
"""Return the state of the sensor."""
if self.entity_description.key == CONST.TEMP_STATUS_KEY:
return self._device.temp
return cast(float, self._device.temp)
if self.entity_description.key == CONST.HUMI_STATUS_KEY:
return self._device.humidity
return cast(float, self._device.humidity)
if self.entity_description.key == CONST.LUX_STATUS_KEY:
return self._device.lux
return cast(float, self._device.lux)
return None

View File

@ -1,7 +1,9 @@
"""Support for Abode Security System switches."""
from __future__ import annotations
import abodepy.helpers.constants as CONST
from typing import Any, cast
from abodepy.devices.switch import CONST, AbodeSwitch as AbodeSW
from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
@ -9,7 +11,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import AbodeAutomation, AbodeDevice
from . import AbodeAutomation, AbodeDevice, AbodeSystem
from .const import DOMAIN
DEVICE_TYPES = [CONST.TYPE_SWITCH, CONST.TYPE_VALVE]
@ -18,12 +20,10 @@ ICON = "mdi:robot"
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up Abode switch devices."""
data = hass.data[DOMAIN]
data: AbodeSystem = hass.data[DOMAIN]
entities: list[SwitchEntity] = []
@ -40,18 +40,20 @@ async def async_setup_entry(
class AbodeSwitch(AbodeDevice, SwitchEntity):
"""Representation of an Abode switch."""
def turn_on(self, **kwargs):
_device: AbodeSW
def turn_on(self, **kwargs: Any) -> None:
"""Turn on the device."""
self._device.switch_on()
def turn_off(self, **kwargs):
def turn_off(self, **kwargs: Any) -> None:
"""Turn off the device."""
self._device.switch_off()
@property
def is_on(self):
def is_on(self) -> bool:
"""Return true if device is on."""
return self._device.is_on
return cast(bool, self._device.is_on)
class AbodeAutomationSwitch(AbodeAutomation, SwitchEntity):
@ -59,28 +61,28 @@ class AbodeAutomationSwitch(AbodeAutomation, SwitchEntity):
_attr_icon = ICON
async def async_added_to_hass(self):
async def async_added_to_hass(self) -> None:
"""Set up trigger automation service."""
await super().async_added_to_hass()
signal = f"abode_trigger_automation_{self.entity_id}"
self.async_on_remove(async_dispatcher_connect(self.hass, signal, self.trigger))
def turn_on(self, **kwargs):
def turn_on(self, **kwargs: Any) -> None:
"""Enable the automation."""
if self._automation.enable(True):
self.schedule_update_ha_state()
def turn_off(self, **kwargs):
def turn_off(self, **kwargs: Any) -> None:
"""Disable the automation."""
if self._automation.enable(False):
self.schedule_update_ha_state()
def trigger(self):
def trigger(self) -> None:
"""Trigger the automation."""
self._automation.trigger()
@property
def is_on(self):
def is_on(self) -> bool:
"""Return True if the automation is enabled."""
return self._automation.is_enabled
return bool(self._automation.is_enabled)

View File

@ -47,6 +47,17 @@ no_implicit_optional = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.abode.*]
check_untyped_defs = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
no_implicit_optional = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.acer_projector.*]
check_untyped_defs = true
disallow_incomplete_defs = true

View File

@ -2,17 +2,23 @@
from unittest.mock import patch
from homeassistant.components.abode import DOMAIN as ABODE_DOMAIN
from homeassistant.components.abode.const import CONF_POLLING
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
async def setup_platform(hass, platform):
async def setup_platform(hass: HomeAssistant, platform: str) -> MockConfigEntry:
"""Set up the Abode platform."""
mock_entry = MockConfigEntry(
domain=ABODE_DOMAIN,
data={CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"},
data={
CONF_USERNAME: "user@email.com",
CONF_PASSWORD: "password",
CONF_POLLING: False,
},
)
mock_entry.add_to_hass(hass)

View File

@ -7,7 +7,7 @@ from tests.components.light.conftest import mock_light_profiles # noqa: F401
@pytest.fixture(autouse=True)
def requests_mock_fixture(requests_mock):
def requests_mock_fixture(requests_mock) -> None:
"""Fixture to provide a requests mocker."""
# Mocks the login response for abodepy.
requests_mock.post(CONST.LOGIN_URL, text=load_fixture("login.json", "abode"))

View File

@ -16,6 +16,7 @@ from homeassistant.const import (
STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import setup_platform
@ -23,7 +24,7 @@ from .common import setup_platform
DEVICE_ID = "alarm_control_panel.abode_alarm"
async def test_entity_registry(hass):
async def test_entity_registry(hass: HomeAssistant) -> None:
"""Tests that the devices are registered in the entity registry."""
await setup_platform(hass, ALARM_DOMAIN)
entity_registry = er.async_get(hass)
@ -33,7 +34,7 @@ async def test_entity_registry(hass):
assert entry.unique_id == "001122334455"
async def test_attributes(hass):
async def test_attributes(hass: HomeAssistant) -> None:
"""Test the alarm control panel attributes are correct."""
await setup_platform(hass, ALARM_DOMAIN)
@ -46,7 +47,7 @@ async def test_attributes(hass):
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 3
async def test_set_alarm_away(hass):
async def test_set_alarm_away(hass: HomeAssistant) -> None:
"""Test the alarm control panel can be set to away."""
with patch("abodepy.AbodeEventController.add_device_callback") as mock_callback:
with patch("abodepy.ALARM.AbodeAlarm.set_away") as mock_set_away:
@ -75,7 +76,7 @@ async def test_set_alarm_away(hass):
assert state.state == STATE_ALARM_ARMED_AWAY
async def test_set_alarm_home(hass):
async def test_set_alarm_home(hass: HomeAssistant) -> None:
"""Test the alarm control panel can be set to home."""
with patch("abodepy.AbodeEventController.add_device_callback") as mock_callback:
with patch("abodepy.ALARM.AbodeAlarm.set_home") as mock_set_home:
@ -103,7 +104,7 @@ async def test_set_alarm_home(hass):
assert state.state == STATE_ALARM_ARMED_HOME
async def test_set_alarm_standby(hass):
async def test_set_alarm_standby(hass: HomeAssistant) -> None:
"""Test the alarm control panel can be set to standby."""
with patch("abodepy.AbodeEventController.add_device_callback") as mock_callback:
with patch("abodepy.ALARM.AbodeAlarm.set_standby") as mock_set_standby:
@ -130,7 +131,7 @@ async def test_set_alarm_standby(hass):
assert state.state == STATE_ALARM_DISARMED
async def test_state_unknown(hass):
async def test_state_unknown(hass: HomeAssistant) -> None:
"""Test an unknown alarm control panel state."""
with patch("abodepy.ALARM.AbodeAlarm.mode", new_callable=PropertyMock) as mock_mode:
await setup_platform(hass, ALARM_DOMAIN)

View File

@ -11,12 +11,13 @@ from homeassistant.const import (
ATTR_FRIENDLY_NAME,
STATE_OFF,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import setup_platform
async def test_entity_registry(hass):
async def test_entity_registry(hass: HomeAssistant) -> None:
"""Tests that the devices are registered in the entity registry."""
await setup_platform(hass, BINARY_SENSOR_DOMAIN)
entity_registry = er.async_get(hass)
@ -25,7 +26,7 @@ async def test_entity_registry(hass):
assert entry.unique_id == "2834013428b6035fba7d4054aa7b25a3"
async def test_attributes(hass):
async def test_attributes(hass: HomeAssistant) -> None:
"""Test the binary sensor attributes are correct."""
await setup_platform(hass, BINARY_SENSOR_DOMAIN)

View File

@ -4,12 +4,13 @@ from unittest.mock import patch
from homeassistant.components.abode.const import DOMAIN as ABODE_DOMAIN
from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
from homeassistant.const import ATTR_ENTITY_ID, STATE_IDLE
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import setup_platform
async def test_entity_registry(hass):
async def test_entity_registry(hass: HomeAssistant) -> None:
"""Tests that the devices are registered in the entity registry."""
await setup_platform(hass, CAMERA_DOMAIN)
entity_registry = er.async_get(hass)
@ -18,7 +19,7 @@ async def test_entity_registry(hass):
assert entry.unique_id == "d0a3a1c316891ceb00c20118aae2a133"
async def test_attributes(hass):
async def test_attributes(hass: HomeAssistant) -> None:
"""Test the camera attributes are correct."""
await setup_platform(hass, CAMERA_DOMAIN)
@ -26,7 +27,7 @@ async def test_attributes(hass):
assert state.state == STATE_IDLE
async def test_capture_image(hass):
async def test_capture_image(hass: HomeAssistant) -> None:
"""Test the camera capture image service."""
await setup_platform(hass, CAMERA_DOMAIN)
@ -41,7 +42,7 @@ async def test_capture_image(hass):
mock_capture.assert_called_once()
async def test_camera_on(hass):
async def test_camera_on(hass: HomeAssistant) -> None:
"""Test the camera turn on service."""
await setup_platform(hass, CAMERA_DOMAIN)
@ -56,7 +57,7 @@ async def test_camera_on(hass):
mock_capture.assert_called_once_with(False)
async def test_camera_off(hass):
async def test_camera_off(hass: HomeAssistant) -> None:
"""Test the camera turn off service."""
await setup_platform(hass, CAMERA_DOMAIN)

View File

@ -4,19 +4,19 @@ from unittest.mock import patch
from abodepy.exceptions import AbodeAuthenticationException
from abodepy.helpers.errors import MFA_CODE_REQUIRED
from requests.exceptions import ConnectTimeout
from homeassistant import data_entry_flow
from homeassistant.components.abode import config_flow
from homeassistant.components.abode.const import DOMAIN
from homeassistant.components.abode.const import CONF_POLLING, DOMAIN
from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
CONF_POLLING = "polling"
async def test_show_form(hass):
async def test_show_form(hass: HomeAssistant) -> None:
"""Test that the form is served with no input."""
flow = config_flow.AbodeFlowHandler()
flow.hass = hass
@ -27,7 +27,7 @@ async def test_show_form(hass):
assert result["step_id"] == "user"
async def test_one_config_allowed(hass):
async def test_one_config_allowed(hass: HomeAssistant) -> None:
"""Test that only one Abode configuration is allowed."""
flow = config_flow.AbodeFlowHandler()
flow.hass = hass
@ -43,7 +43,7 @@ async def test_one_config_allowed(hass):
assert step_user_result["reason"] == "single_instance_allowed"
async def test_invalid_credentials(hass):
async def test_invalid_credentials(hass: HomeAssistant) -> None:
"""Test that invalid credentials throws an error."""
conf = {CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"}
@ -60,7 +60,7 @@ async def test_invalid_credentials(hass):
assert result["errors"] == {"base": "invalid_auth"}
async def test_connection_error(hass):
async def test_connection_auth_error(hass: HomeAssistant) -> None:
"""Test other than invalid credentials throws an error."""
conf = {CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"}
@ -77,7 +77,22 @@ async def test_connection_error(hass):
assert result["errors"] == {"base": "cannot_connect"}
async def test_step_user(hass):
async def test_connection_error(hass: HomeAssistant) -> None:
"""Test login throws an error if connection times out."""
conf = {CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"}
flow = config_flow.AbodeFlowHandler()
flow.hass = hass
with patch(
"homeassistant.components.abode.config_flow.Abode",
side_effect=ConnectTimeout,
):
result = await flow.async_step_user(user_input=conf)
assert result["errors"] == {"base": "cannot_connect"}
async def test_step_user(hass: HomeAssistant) -> None:
"""Test that the user step works."""
conf = {CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"}
@ -98,7 +113,7 @@ async def test_step_user(hass):
}
async def test_step_mfa(hass):
async def test_step_mfa(hass: HomeAssistant) -> None:
"""Test that the MFA step works."""
conf = {CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"}
@ -141,7 +156,7 @@ async def test_step_mfa(hass):
}
async def test_step_reauth(hass):
async def test_step_reauth(hass: HomeAssistant) -> None:
"""Test the reauth flow."""
conf = {CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"}

View File

@ -10,6 +10,7 @@ from homeassistant.const import (
SERVICE_OPEN_COVER,
STATE_CLOSED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import setup_platform
@ -17,7 +18,7 @@ from .common import setup_platform
DEVICE_ID = "cover.garage_door"
async def test_entity_registry(hass):
async def test_entity_registry(hass: HomeAssistant) -> None:
"""Tests that the devices are registered in the entity registry."""
await setup_platform(hass, COVER_DOMAIN)
entity_registry = er.async_get(hass)
@ -26,7 +27,7 @@ async def test_entity_registry(hass):
assert entry.unique_id == "61cbz3b542d2o33ed2fz02721bda3324"
async def test_attributes(hass):
async def test_attributes(hass: HomeAssistant) -> None:
"""Test the cover attributes are correct."""
await setup_platform(hass, COVER_DOMAIN)
@ -39,7 +40,7 @@ async def test_attributes(hass):
assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Garage Door"
async def test_open(hass):
async def test_open(hass: HomeAssistant) -> None:
"""Test the cover can be opened."""
await setup_platform(hass, COVER_DOMAIN)
@ -51,7 +52,7 @@ async def test_open(hass):
mock_open.assert_called_once()
async def test_close(hass):
async def test_close(hass: HomeAssistant) -> None:
"""Test the cover can be closed."""
await setup_platform(hass, COVER_DOMAIN)

View File

@ -14,11 +14,12 @@ from homeassistant.components.abode import (
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_USERNAME
from homeassistant.core import HomeAssistant
from .common import setup_platform
async def test_change_settings(hass):
async def test_change_settings(hass: HomeAssistant) -> None:
"""Test change_setting service."""
await setup_platform(hass, ALARM_DOMAIN)
@ -33,7 +34,7 @@ async def test_change_settings(hass):
mock_set_setting.assert_called_once()
async def test_add_unique_id(hass):
async def test_add_unique_id(hass: HomeAssistant) -> None:
"""Test unique_id is set to Abode username."""
mock_entry = await setup_platform(hass, ALARM_DOMAIN)
# Set unique_id to None to match previous config entries
@ -49,7 +50,7 @@ async def test_add_unique_id(hass):
assert mock_entry.unique_id == mock_entry.data[CONF_USERNAME]
async def test_unload_entry(hass):
async def test_unload_entry(hass: HomeAssistant) -> None:
"""Test unloading the Abode entry."""
mock_entry = await setup_platform(hass, ALARM_DOMAIN)
@ -65,7 +66,7 @@ async def test_unload_entry(hass):
assert not hass.services.has_service(ABODE_DOMAIN, SERVICE_TRIGGER_AUTOMATION)
async def test_invalid_credentials(hass):
async def test_invalid_credentials(hass: HomeAssistant) -> None:
"""Test Abode credentials changing."""
with patch(
"homeassistant.components.abode.Abode",
@ -81,7 +82,7 @@ async def test_invalid_credentials(hass):
mock_async_step_reauth.assert_called_once()
async def test_raise_config_entry_not_ready_when_offline(hass):
async def test_raise_config_entry_not_ready_when_offline(hass: HomeAssistant) -> None:
"""Config entry state is SETUP_RETRY when abode is offline."""
with patch(
"homeassistant.components.abode.Abode",

View File

@ -16,6 +16,7 @@ from homeassistant.const import (
SERVICE_TURN_ON,
STATE_ON,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import setup_platform
@ -23,7 +24,7 @@ from .common import setup_platform
DEVICE_ID = "light.living_room_lamp"
async def test_entity_registry(hass):
async def test_entity_registry(hass: HomeAssistant) -> None:
"""Tests that the devices are registered in the entity registry."""
await setup_platform(hass, LIGHT_DOMAIN)
entity_registry = er.async_get(hass)
@ -32,7 +33,7 @@ async def test_entity_registry(hass):
assert entry.unique_id == "741385f4388b2637df4c6b398fe50581"
async def test_attributes(hass):
async def test_attributes(hass: HomeAssistant) -> None:
"""Test the light attributes are correct."""
await setup_platform(hass, LIGHT_DOMAIN)
@ -49,7 +50,7 @@ async def test_attributes(hass):
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 19
async def test_switch_off(hass):
async def test_switch_off(hass: HomeAssistant) -> None:
"""Test the light can be turned off."""
await setup_platform(hass, LIGHT_DOMAIN)
@ -61,7 +62,7 @@ async def test_switch_off(hass):
mock_switch_off.assert_called_once()
async def test_switch_on(hass):
async def test_switch_on(hass: HomeAssistant) -> None:
"""Test the light can be turned on."""
await setup_platform(hass, LIGHT_DOMAIN)
@ -73,7 +74,7 @@ async def test_switch_on(hass):
mock_switch_on.assert_called_once()
async def test_set_brightness(hass):
async def test_set_brightness(hass: HomeAssistant) -> None:
"""Test the brightness can be set."""
await setup_platform(hass, LIGHT_DOMAIN)
@ -89,7 +90,7 @@ async def test_set_brightness(hass):
mock_set_level.assert_called_once_with(39)
async def test_set_color(hass):
async def test_set_color(hass: HomeAssistant) -> None:
"""Test the color can be set."""
await setup_platform(hass, LIGHT_DOMAIN)
@ -104,7 +105,7 @@ async def test_set_color(hass):
mock_set_color.assert_called_once_with((240.0, 100.0))
async def test_set_color_temp(hass):
async def test_set_color_temp(hass: HomeAssistant) -> None:
"""Test the color temp can be set."""
await setup_platform(hass, LIGHT_DOMAIN)

View File

@ -10,6 +10,7 @@ from homeassistant.const import (
SERVICE_UNLOCK,
STATE_LOCKED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import setup_platform
@ -17,7 +18,7 @@ from .common import setup_platform
DEVICE_ID = "lock.test_lock"
async def test_entity_registry(hass):
async def test_entity_registry(hass: HomeAssistant) -> None:
"""Tests that the devices are registered in the entity registry."""
await setup_platform(hass, LOCK_DOMAIN)
entity_registry = er.async_get(hass)
@ -26,7 +27,7 @@ async def test_entity_registry(hass):
assert entry.unique_id == "51cab3b545d2o34ed7fz02731bda5324"
async def test_attributes(hass):
async def test_attributes(hass: HomeAssistant) -> None:
"""Test the lock attributes are correct."""
await setup_platform(hass, LOCK_DOMAIN)
@ -39,7 +40,7 @@ async def test_attributes(hass):
assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Test Lock"
async def test_lock(hass):
async def test_lock(hass: HomeAssistant) -> None:
"""Test the lock can be locked."""
await setup_platform(hass, LOCK_DOMAIN)
@ -51,7 +52,7 @@ async def test_lock(hass):
mock_lock.assert_called_once()
async def test_unlock(hass):
async def test_unlock(hass: HomeAssistant) -> None:
"""Test the lock can be unlocked."""
await setup_platform(hass, LOCK_DOMAIN)

View File

@ -8,12 +8,13 @@ from homeassistant.const import (
PERCENTAGE,
TEMP_CELSIUS,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import setup_platform
async def test_entity_registry(hass):
async def test_entity_registry(hass: HomeAssistant) -> None:
"""Tests that the devices are registered in the entity registry."""
await setup_platform(hass, SENSOR_DOMAIN)
entity_registry = er.async_get(hass)
@ -22,7 +23,7 @@ async def test_entity_registry(hass):
assert entry.unique_id == "13545b21f4bdcd33d9abd461f8443e65-humidity"
async def test_attributes(hass):
async def test_attributes(hass: HomeAssistant) -> None:
"""Test the sensor attributes are correct."""
await setup_platform(hass, SENSOR_DOMAIN)

View File

@ -13,6 +13,7 @@ from homeassistant.const import (
STATE_OFF,
STATE_ON,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import setup_platform
@ -23,7 +24,7 @@ DEVICE_ID = "switch.test_switch"
DEVICE_UID = "0012a4d3614cb7e2b8c9abea31d2fb2a"
async def test_entity_registry(hass):
async def test_entity_registry(hass: HomeAssistant) -> None:
"""Tests that the devices are registered in the entity registry."""
await setup_platform(hass, SWITCH_DOMAIN)
entity_registry = er.async_get(hass)
@ -35,7 +36,7 @@ async def test_entity_registry(hass):
assert entry.unique_id == DEVICE_UID
async def test_attributes(hass):
async def test_attributes(hass: HomeAssistant) -> None:
"""Test the switch attributes are correct."""
await setup_platform(hass, SWITCH_DOMAIN)
@ -43,7 +44,7 @@ async def test_attributes(hass):
assert state.state == STATE_OFF
async def test_switch_on(hass):
async def test_switch_on(hass: HomeAssistant) -> None:
"""Test the switch can be turned on."""
await setup_platform(hass, SWITCH_DOMAIN)
@ -56,7 +57,7 @@ async def test_switch_on(hass):
mock_switch_on.assert_called_once()
async def test_switch_off(hass):
async def test_switch_off(hass: HomeAssistant) -> None:
"""Test the switch can be turned off."""
await setup_platform(hass, SWITCH_DOMAIN)
@ -69,7 +70,7 @@ async def test_switch_off(hass):
mock_switch_off.assert_called_once()
async def test_automation_attributes(hass):
async def test_automation_attributes(hass: HomeAssistant) -> None:
"""Test the automation attributes are correct."""
await setup_platform(hass, SWITCH_DOMAIN)
@ -78,7 +79,7 @@ async def test_automation_attributes(hass):
assert state.state == STATE_ON
async def test_turn_automation_off(hass):
async def test_turn_automation_off(hass: HomeAssistant) -> None:
"""Test the automation can be turned off."""
with patch("abodepy.AbodeAutomation.enable") as mock_trigger:
await setup_platform(hass, SWITCH_DOMAIN)
@ -94,7 +95,7 @@ async def test_turn_automation_off(hass):
mock_trigger.assert_called_once_with(False)
async def test_turn_automation_on(hass):
async def test_turn_automation_on(hass: HomeAssistant) -> None:
"""Test the automation can be turned on."""
with patch("abodepy.AbodeAutomation.enable") as mock_trigger:
await setup_platform(hass, SWITCH_DOMAIN)
@ -110,7 +111,7 @@ async def test_turn_automation_on(hass):
mock_trigger.assert_called_once_with(True)
async def test_trigger_automation(hass, requests_mock):
async def test_trigger_automation(hass: HomeAssistant) -> None:
"""Test the trigger automation service."""
await setup_platform(hass, SWITCH_DOMAIN)