Update typing 14 (#48078)

pull/48088/head
Marc Mueller 2021-03-18 15:08:35 +01:00 committed by GitHub
parent 7d196abc4a
commit dcca29ef68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 614 additions and 521 deletions

View File

@ -1,5 +1,5 @@
"""Provides device automations for Water Heater."""
from typing import List, Optional
from __future__ import annotations
import voluptuous as vol
@ -28,7 +28,7 @@ ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
)
async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]:
async def async_get_actions(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device actions for Water Heater devices."""
registry = await entity_registry.async_get_registry(hass)
actions = []
@ -58,7 +58,7 @@ async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]:
async def async_call_action_from_config(
hass: HomeAssistant, config: dict, variables: dict, context: Optional[Context]
hass: HomeAssistant, config: dict, variables: dict, context: Context | None
) -> None:
"""Execute a device action."""
config = ACTION_SCHEMA(config)

View File

@ -1,7 +1,9 @@
"""Reproduce an Water heater state."""
from __future__ import annotations
import asyncio
import logging
from typing import Any, Dict, Iterable, Optional
from typing import Any, Iterable
from homeassistant.const import (
ATTR_ENTITY_ID,
@ -47,8 +49,8 @@ async def _async_reproduce_state(
hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
context: Context | None = None,
reproduce_options: dict[str, Any] | None = None,
) -> None:
"""Reproduce a single state."""
cur_state = hass.states.get(state.entity_id)
@ -124,8 +126,8 @@ async def async_reproduce_states(
hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
context: Context | None = None,
reproduce_options: dict[str, Any] | None = None,
) -> None:
"""Reproduce Water heater states."""
await asyncio.gather(

View File

@ -1,5 +1,7 @@
"""WebSocket based API for Home Assistant."""
from typing import Optional, Union, cast
from __future__ import annotations
from typing import cast
import voluptuous as vol
@ -43,9 +45,9 @@ DEPENDENCIES = ("http",)
@callback
def async_register_command(
hass: HomeAssistant,
command_or_handler: Union[str, const.WebSocketCommandHandler],
handler: Optional[const.WebSocketCommandHandler] = None,
schema: Optional[vol.Schema] = None,
command_or_handler: str | const.WebSocketCommandHandler,
handler: const.WebSocketCommandHandler | None = None,
schema: vol.Schema | None = None,
) -> None:
"""Register a websocket command."""
# pylint: disable=protected-access

View File

@ -1,6 +1,8 @@
"""Connection session."""
from __future__ import annotations
import asyncio
from typing import Any, Callable, Dict, Hashable, Optional
from typing import Any, Callable, Hashable
import voluptuous as vol
@ -26,7 +28,7 @@ class ActiveConnection:
else:
self.refresh_token_id = None
self.subscriptions: Dict[Hashable, Callable[[], Any]] = {}
self.subscriptions: dict[Hashable, Callable[[], Any]] = {}
self.last_id = 0
def context(self, msg):
@ -37,7 +39,7 @@ class ActiveConnection:
return Context(user_id=user.id)
@callback
def send_result(self, msg_id: int, result: Optional[Any] = None) -> None:
def send_result(self, msg_id: int, result: Any | None = None) -> None:
"""Send a result message."""
self.send_message(messages.result_message(msg_id, result))

View File

@ -1,8 +1,9 @@
"""View to accept incoming websocket connection."""
from __future__ import annotations
import asyncio
from contextlib import suppress
import logging
from typing import Optional
from aiohttp import WSMsgType, web
import async_timeout
@ -57,7 +58,7 @@ class WebSocketHandler:
"""Initialize an active connection."""
self.hass = hass
self.request = request
self.wsock: Optional[web.WebSocketResponse] = None
self.wsock: web.WebSocketResponse | None = None
self._to_write: asyncio.Queue = asyncio.Queue(maxsize=MAX_PENDING_MSG)
self._handle_task = None
self._writer_task = None

View File

@ -1,8 +1,9 @@
"""Message templates for websocket commands."""
from __future__ import annotations
from functools import lru_cache
import logging
from typing import Any, Dict
from typing import Any
import voluptuous as vol
@ -32,12 +33,12 @@ IDEN_TEMPLATE = "__IDEN__"
IDEN_JSON_TEMPLATE = '"__IDEN__"'
def result_message(iden: int, result: Any = None) -> Dict:
def result_message(iden: int, result: Any = None) -> dict:
"""Return a success result message."""
return {"id": iden, "type": const.TYPE_RESULT, "success": True, "result": result}
def error_message(iden: int, code: str, message: str) -> Dict:
def error_message(iden: int, code: str, message: str) -> dict:
"""Return an error result message."""
return {
"id": iden,
@ -47,7 +48,7 @@ def error_message(iden: int, code: str, message: str) -> Dict:
}
def event_message(iden: JSON_TYPE, event: Any) -> Dict:
def event_message(iden: JSON_TYPE, event: Any) -> dict:
"""Return an event message."""
return {"id": iden, "type": "event", "event": event}

View File

@ -1,8 +1,10 @@
"""Classes shared among Wemo entities."""
from __future__ import annotations
import asyncio
import contextlib
import logging
from typing import Any, Dict, Generator, Optional
from typing import Any, Generator
import async_timeout
from pywemo import WeMoDevice
@ -19,7 +21,7 @@ class ExceptionHandlerStatus:
"""Exit status from the _wemo_exception_handler context manager."""
# An exception if one was raised in the _wemo_exception_handler.
exception: Optional[Exception] = None
exception: Exception | None = None
@property
def success(self) -> bool:
@ -68,7 +70,7 @@ class WemoEntity(Entity):
_LOGGER.info("Reconnected to %s", self.name)
self._available = True
def _update(self, force_update: Optional[bool] = True):
def _update(self, force_update: bool | None = True):
"""Update the device state."""
raise NotImplementedError()
@ -99,7 +101,7 @@ class WemoEntity(Entity):
self._available = False
async def _async_locked_update(
self, force_update: bool, timeout: Optional[async_timeout.timeout] = None
self, force_update: bool, timeout: async_timeout.timeout | None = None
) -> None:
"""Try updating within an async lock."""
async with self._update_lock:
@ -124,7 +126,7 @@ class WemoSubscriptionEntity(WemoEntity):
return self.wemo.serialnumber
@property
def device_info(self) -> Dict[str, Any]:
def device_info(self) -> dict[str, Any]:
"""Return the device info."""
return {
"name": self.name,

View File

@ -1,6 +1,5 @@
"""Support for WiLight Fan."""
from typing import Optional
from __future__ import annotations
from pywilight.const import (
FAN_V1,
@ -79,7 +78,7 @@ class WiLightFan(WiLightDevice, FanEntity):
return self._status.get("direction", WL_DIRECTION_OFF) != WL_DIRECTION_OFF
@property
def percentage(self) -> Optional[int]:
def percentage(self) -> int | None:
"""Return the current speed percentage."""
if "direction" in self._status:
if self._status["direction"] == WL_DIRECTION_OFF:

View File

@ -3,8 +3,9 @@ Support for the Withings API.
For more details about this platform, please refer to the documentation at
"""
from __future__ import annotations
import asyncio
from typing import Optional
from aiohttp.web import Request, Response
import voluptuous as vol
@ -175,7 +176,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_webhook_handler(
hass: HomeAssistant, webhook_id: str, request: Request
) -> Optional[Response]:
) -> Response | None:
"""Handle webhooks calls."""
# Handle http head calls to the path.
# When creating a notify subscription, Withings will check that the endpoint is running by sending a HEAD request.

View File

@ -1,5 +1,7 @@
"""Sensors flow for Withings."""
from typing import Callable, List
from __future__ import annotations
from typing import Callable
from homeassistant.components.binary_sensor import (
DEVICE_CLASS_OCCUPANCY,
@ -16,7 +18,7 @@ from .common import BaseWithingsSensor, async_create_entities
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: Callable[[List[Entity], bool], None],
async_add_entities: Callable[[list[Entity], bool], None],
) -> None:
"""Set up the sensor config entry."""
entities = await async_create_entities(

View File

@ -1,4 +1,6 @@
"""Common code for Withings."""
from __future__ import annotations
import asyncio
from dataclasses import dataclass
import datetime
@ -6,7 +8,7 @@ from datetime import timedelta
from enum import Enum, IntEnum
import logging
import re
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
from typing import Any, Callable, Dict
from aiohttp.web import Response
import requests
@ -86,7 +88,7 @@ class WithingsAttribute:
measute_type: Enum
friendly_name: str
unit_of_measurement: str
icon: Optional[str]
icon: str | None
platform: str
enabled_by_default: bool
update_type: UpdateType
@ -461,12 +463,12 @@ WITHINGS_ATTRIBUTES = [
),
]
WITHINGS_MEASUREMENTS_MAP: Dict[Measurement, WithingsAttribute] = {
WITHINGS_MEASUREMENTS_MAP: dict[Measurement, WithingsAttribute] = {
attr.measurement: attr for attr in WITHINGS_ATTRIBUTES
}
WITHINGS_MEASURE_TYPE_MAP: Dict[
Union[NotifyAppli, GetSleepSummaryField, MeasureType], WithingsAttribute
WITHINGS_MEASURE_TYPE_MAP: dict[
NotifyAppli | GetSleepSummaryField | MeasureType, WithingsAttribute
] = {attr.measute_type: attr for attr in WITHINGS_ATTRIBUTES}
@ -486,8 +488,8 @@ class ConfigEntryWithingsApi(AbstractWithingsApi):
self.session = OAuth2Session(hass, config_entry, implementation)
def _request(
self, path: str, params: Dict[str, Any], method: str = "GET"
) -> Dict[str, Any]:
self, path: str, params: dict[str, Any], method: str = "GET"
) -> dict[str, Any]:
"""Perform an async request."""
asyncio.run_coroutine_threadsafe(
self.session.async_ensure_token_valid(), self._hass.loop
@ -524,7 +526,7 @@ class WebhookUpdateCoordinator:
"""Initialize the object."""
self._hass = hass
self._user_id = user_id
self._listeners: List[CALLBACK_TYPE] = []
self._listeners: list[CALLBACK_TYPE] = []
self.data: MeasurementData = {}
def async_add_listener(self, listener: CALLBACK_TYPE) -> Callable[[], None]:
@ -573,10 +575,8 @@ class DataManager:
self._notify_unsubscribe_delay = datetime.timedelta(seconds=1)
self._is_available = True
self._cancel_interval_update_interval: Optional[CALLBACK_TYPE] = None
self._cancel_configure_webhook_subscribe_interval: Optional[
CALLBACK_TYPE
] = None
self._cancel_interval_update_interval: CALLBACK_TYPE | None = None
self._cancel_configure_webhook_subscribe_interval: CALLBACK_TYPE | None = None
self._api_notification_id = f"withings_{self._user_id}"
self.subscription_update_coordinator = DataUpdateCoordinator(
@ -600,7 +600,7 @@ class DataManager:
self.webhook_update_coordinator = WebhookUpdateCoordinator(
self._hass, self._user_id
)
self._cancel_subscription_update: Optional[Callable[[], None]] = None
self._cancel_subscription_update: Callable[[], None] | None = None
self._subscribe_webhook_run_count = 0
@property
@ -728,7 +728,7 @@ class DataManager:
self._api.notify_revoke, profile.callbackurl, profile.appli
)
async def async_get_all_data(self) -> Optional[Dict[MeasureType, Any]]:
async def async_get_all_data(self) -> dict[MeasureType, Any] | None:
"""Update all withings data."""
try:
return await self._do_retry(self._async_get_all_data)
@ -764,14 +764,14 @@ class DataManager:
raise exception
async def _async_get_all_data(self) -> Optional[Dict[MeasureType, Any]]:
async def _async_get_all_data(self) -> dict[MeasureType, Any] | None:
_LOGGER.info("Updating all withings data")
return {
**await self.async_get_measures(),
**await self.async_get_sleep_summary(),
}
async def async_get_measures(self) -> Dict[MeasureType, Any]:
async def async_get_measures(self) -> dict[MeasureType, Any]:
"""Get the measures data."""
_LOGGER.debug("Updating withings measures")
@ -794,7 +794,7 @@ class DataManager:
for measure in group.measures
}
async def async_get_sleep_summary(self) -> Dict[MeasureType, Any]:
async def async_get_sleep_summary(self) -> dict[MeasureType, Any]:
"""Get the sleep summary data."""
_LOGGER.debug("Updating withing sleep summary")
now = dt.utcnow()
@ -837,7 +837,7 @@ class DataManager:
response = await self._hass.async_add_executor_job(get_sleep_summary)
# Set the default to empty lists.
raw_values: Dict[GetSleepSummaryField, List[int]] = {
raw_values: dict[GetSleepSummaryField, list[int]] = {
field: [] for field in GetSleepSummaryField
}
@ -848,9 +848,9 @@ class DataManager:
for field in GetSleepSummaryField:
raw_values[field].append(dict(data)[field.value])
values: Dict[GetSleepSummaryField, float] = {}
values: dict[GetSleepSummaryField, float] = {}
def average(data: List[int]) -> float:
def average(data: list[int]) -> float:
return sum(data) / len(data)
def set_value(field: GetSleepSummaryField, func: Callable) -> None:
@ -907,7 +907,7 @@ def get_attribute_unique_id(attribute: WithingsAttribute, user_id: int) -> str:
async def async_get_entity_id(
hass: HomeAssistant, attribute: WithingsAttribute, user_id: int
) -> Optional[str]:
) -> str | None:
"""Get an entity id for a user's attribute."""
entity_registry: EntityRegistry = (
await hass.helpers.entity_registry.async_get_registry()
@ -936,7 +936,7 @@ class BaseWithingsSensor(Entity):
self._user_id = self._data_manager.user_id
self._name = f"Withings {self._attribute.measurement.value} {self._profile}"
self._unique_id = get_attribute_unique_id(self._attribute, self._user_id)
self._state_data: Optional[Any] = None
self._state_data: Any | None = None
@property
def should_poll(self) -> bool:
@ -1053,7 +1053,7 @@ async def async_get_data_manager(
def get_data_manager_by_webhook_id(
hass: HomeAssistant, webhook_id: str
) -> Optional[DataManager]:
) -> DataManager | None:
"""Get a data manager by it's webhook id."""
return next(
iter(
@ -1067,7 +1067,7 @@ def get_data_manager_by_webhook_id(
)
def get_all_data_managers(hass: HomeAssistant) -> Tuple[DataManager, ...]:
def get_all_data_managers(hass: HomeAssistant) -> tuple[DataManager, ...]:
"""Get all configured data managers."""
return tuple(
config_entry_data[const.DATA_MANAGER]
@ -1086,7 +1086,7 @@ async def async_create_entities(
entry: ConfigEntry,
create_func: Callable[[DataManager, WithingsAttribute], Entity],
platform: str,
) -> List[Entity]:
) -> list[Entity]:
"""Create withings entities from config entry."""
data_manager = await async_get_data_manager(hass, entry)
@ -1096,7 +1096,7 @@ async def async_create_entities(
]
def get_platform_attributes(platform: str) -> Tuple[WithingsAttribute, ...]:
def get_platform_attributes(platform: str) -> tuple[WithingsAttribute, ...]:
"""Get withings attributes used for a specific platform."""
return tuple(
attribute for attribute in WITHINGS_ATTRIBUTES if attribute.platform == platform

View File

@ -1,6 +1,7 @@
"""Config flow for Withings."""
from __future__ import annotations
import logging
from typing import Dict, Union
import voluptuous as vol
from withings_api.common import AuthScope
@ -19,7 +20,7 @@ class WithingsFlowHandler(
DOMAIN = const.DOMAIN
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
# Temporarily holds authorization data during the profile step.
_current_data: Dict[str, Union[None, str, int]] = {}
_current_data: dict[str, None | str | int] = {}
@property
def logger(self) -> logging.Logger:

View File

@ -1,5 +1,7 @@
"""Sensors flow for Withings."""
from typing import Callable, List, Union
from __future__ import annotations
from typing import Callable
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.config_entries import ConfigEntry
@ -12,7 +14,7 @@ from .common import BaseWithingsSensor, async_create_entities
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: Callable[[List[Entity], bool], None],
async_add_entities: Callable[[list[Entity], bool], None],
) -> None:
"""Set up the sensor config entry."""
@ -30,6 +32,6 @@ class WithingsHealthSensor(BaseWithingsSensor):
"""Implementation of a Withings sensor."""
@property
def state(self) -> Union[None, str, int, float]:
def state(self) -> None | str | int | float:
"""Return the state of the entity."""
return self._state_data

View File

@ -1,8 +1,10 @@
"""Support for WLED."""
from __future__ import annotations
import asyncio
from datetime import timedelta
import logging
from typing import Any, Dict
from typing import Any
from wled import WLED, Device as WLEDDevice, WLEDConnectionError, WLEDError
@ -185,7 +187,7 @@ class WLEDDeviceEntity(WLEDEntity):
"""Defines a WLED device entity."""
@property
def device_info(self) -> Dict[str, Any]:
def device_info(self) -> dict[str, Any]:
"""Return device information about this WLED device."""
return {
ATTR_IDENTIFIERS: {(DOMAIN, self.coordinator.data.info.mac_address)},

View File

@ -1,5 +1,7 @@
"""Config flow to configure the WLED integration."""
from typing import Any, Dict, Optional
from __future__ import annotations
from typing import Any
import voluptuous as vol
from wled import WLED, WLEDConnectionError
@ -23,14 +25,14 @@ class WLEDFlowHandler(ConfigFlow, domain=DOMAIN):
CONNECTION_CLASS = CONN_CLASS_LOCAL_POLL
async def async_step_user(
self, user_input: Optional[ConfigType] = None
) -> Dict[str, Any]:
self, user_input: ConfigType | None = None
) -> dict[str, Any]:
"""Handle a flow initiated by the user."""
return await self._handle_config_flow(user_input)
async def async_step_zeroconf(
self, user_input: Optional[ConfigType] = None
) -> Dict[str, Any]:
self, user_input: ConfigType | None = None
) -> dict[str, Any]:
"""Handle zeroconf discovery."""
if user_input is None:
return self.async_abort(reason="cannot_connect")
@ -53,13 +55,13 @@ class WLEDFlowHandler(ConfigFlow, domain=DOMAIN):
async def async_step_zeroconf_confirm(
self, user_input: ConfigType = None
) -> Dict[str, Any]:
) -> dict[str, Any]:
"""Handle a flow initiated by zeroconf."""
return await self._handle_config_flow(user_input)
async def _handle_config_flow(
self, user_input: Optional[ConfigType] = None, prepare: bool = False
) -> Dict[str, Any]:
self, user_input: ConfigType | None = None, prepare: bool = False
) -> dict[str, Any]:
"""Config flow handler for WLED."""
source = self.context.get("source")
@ -100,7 +102,7 @@ class WLEDFlowHandler(ConfigFlow, domain=DOMAIN):
data={CONF_HOST: user_input[CONF_HOST], CONF_MAC: user_input[CONF_MAC]},
)
def _show_setup_form(self, errors: Optional[Dict] = None) -> Dict[str, Any]:
def _show_setup_form(self, errors: dict | None = None) -> dict[str, Any]:
"""Show the setup form to the user."""
return self.async_show_form(
step_id="user",
@ -108,7 +110,7 @@ class WLEDFlowHandler(ConfigFlow, domain=DOMAIN):
errors=errors or {},
)
def _show_confirm_dialog(self, errors: Optional[Dict] = None) -> Dict[str, Any]:
def _show_confirm_dialog(self, errors: dict | None = None) -> dict[str, Any]:
"""Show the confirm dialog to the user."""
name = self.context.get(CONF_NAME)
return self.async_show_form(

View File

@ -1,6 +1,8 @@
"""Support for LED lights."""
from __future__ import annotations
from functools import partial
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
from typing import Any, Callable
import voluptuous as vol
@ -51,7 +53,7 @@ PARALLEL_UPDATES = 1
async def async_setup_entry(
hass: HomeAssistantType,
entry: ConfigEntry,
async_add_entities: Callable[[List[Entity], bool], None],
async_add_entities: Callable[[list[Entity], bool], None],
) -> None:
"""Set up WLED light based on a config entry."""
coordinator: WLEDDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
@ -115,7 +117,7 @@ class WLEDMasterLight(LightEntity, WLEDDeviceEntity):
return SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION
@property
def brightness(self) -> Optional[int]:
def brightness(self) -> int | None:
"""Return the brightness of this light between 1..255."""
return self.coordinator.data.state.brightness
@ -188,7 +190,7 @@ class WLEDSegmentLight(LightEntity, WLEDDeviceEntity):
return super().available
@property
def extra_state_attributes(self) -> Optional[Dict[str, Any]]:
def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return the state attributes of the entity."""
playlist = self.coordinator.data.state.playlist
if playlist == -1:
@ -209,18 +211,18 @@ class WLEDSegmentLight(LightEntity, WLEDDeviceEntity):
}
@property
def hs_color(self) -> Optional[Tuple[float, float]]:
def hs_color(self) -> tuple[float, float] | None:
"""Return the hue and saturation color value [float, float]."""
color = self.coordinator.data.state.segments[self._segment].color_primary
return color_util.color_RGB_to_hs(*color[:3])
@property
def effect(self) -> Optional[str]:
def effect(self) -> str | None:
"""Return the current effect of the light."""
return self.coordinator.data.state.segments[self._segment].effect.name
@property
def brightness(self) -> Optional[int]:
def brightness(self) -> int | None:
"""Return the brightness of this light between 1..255."""
state = self.coordinator.data.state
@ -234,7 +236,7 @@ class WLEDSegmentLight(LightEntity, WLEDDeviceEntity):
return state.segments[self._segment].brightness
@property
def white_value(self) -> Optional[int]:
def white_value(self) -> int | None:
"""Return the white value of this light between 0..255."""
color = self.coordinator.data.state.segments[self._segment].color_primary
return color[-1] if self._rgbw else None
@ -256,7 +258,7 @@ class WLEDSegmentLight(LightEntity, WLEDDeviceEntity):
return flags
@property
def effect_list(self) -> List[str]:
def effect_list(self) -> list[str]:
"""Return the list of supported effects."""
return [effect.name for effect in self.coordinator.data.effects]
@ -357,11 +359,11 @@ class WLEDSegmentLight(LightEntity, WLEDDeviceEntity):
@wled_exception_handler
async def async_effect(
self,
effect: Optional[Union[int, str]] = None,
intensity: Optional[int] = None,
palette: Optional[Union[int, str]] = None,
reverse: Optional[bool] = None,
speed: Optional[int] = None,
effect: int | str | None = None,
intensity: int | None = None,
palette: int | str | None = None,
reverse: bool | None = None,
speed: int | None = None,
) -> None:
"""Set the effect of a WLED light."""
data = {ATTR_SEGMENT_ID: self._segment}
@ -398,7 +400,7 @@ class WLEDSegmentLight(LightEntity, WLEDDeviceEntity):
def async_update_segments(
entry: ConfigEntry,
coordinator: WLEDDataUpdateCoordinator,
current: Dict[int, WLEDSegmentLight],
current: dict[int, WLEDSegmentLight],
async_add_entities,
) -> None:
"""Update segments."""
@ -438,7 +440,7 @@ def async_update_segments(
async def async_remove_entity(
index: int,
coordinator: WLEDDataUpdateCoordinator,
current: Dict[int, WLEDSegmentLight],
current: dict[int, WLEDSegmentLight],
) -> None:
"""Remove WLED segment light from Home Assistant."""
entity = current[index]

View File

@ -1,6 +1,8 @@
"""Support for WLED sensors."""
from __future__ import annotations
from datetime import timedelta
from typing import Any, Callable, Dict, List, Optional
from typing import Any, Callable
from homeassistant.components.sensor import DEVICE_CLASS_CURRENT
from homeassistant.config_entries import ConfigEntry
@ -22,7 +24,7 @@ from .const import ATTR_LED_COUNT, ATTR_MAX_POWER, CURRENT_MA, DOMAIN
async def async_setup_entry(
hass: HomeAssistantType,
entry: ConfigEntry,
async_add_entities: Callable[[List[Entity], bool], None],
async_add_entities: Callable[[list[Entity], bool], None],
) -> None:
"""Set up WLED sensor based on a config entry."""
coordinator: WLEDDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
@ -52,7 +54,7 @@ class WLEDSensor(WLEDDeviceEntity):
icon: str,
key: str,
name: str,
unit_of_measurement: Optional[str] = None,
unit_of_measurement: str | None = None,
) -> None:
"""Initialize WLED sensor."""
self._unit_of_measurement = unit_of_measurement
@ -92,7 +94,7 @@ class WLEDEstimatedCurrentSensor(WLEDSensor):
)
@property
def extra_state_attributes(self) -> Optional[Dict[str, Any]]:
def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return the state attributes of the entity."""
return {
ATTR_LED_COUNT: self.coordinator.data.info.leds.count,
@ -105,7 +107,7 @@ class WLEDEstimatedCurrentSensor(WLEDSensor):
return self.coordinator.data.info.leds.power
@property
def device_class(self) -> Optional[str]:
def device_class(self) -> str | None:
"""Return the class of this sensor."""
return DEVICE_CLASS_CURRENT
@ -131,7 +133,7 @@ class WLEDUptimeSensor(WLEDSensor):
return uptime.replace(microsecond=0).isoformat()
@property
def device_class(self) -> Optional[str]:
def device_class(self) -> str | None:
"""Return the class of this sensor."""
return DEVICE_CLASS_TIMESTAMP
@ -199,7 +201,7 @@ class WLEDWifiRSSISensor(WLEDSensor):
return self.coordinator.data.info.wifi.rssi
@property
def device_class(self) -> Optional[str]:
def device_class(self) -> str | None:
"""Return the class of this sensor."""
return DEVICE_CLASS_SIGNAL_STRENGTH

View File

@ -1,5 +1,7 @@
"""Support for WLED switches."""
from typing import Any, Callable, Dict, List, Optional
from __future__ import annotations
from typing import Any, Callable
from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
@ -21,7 +23,7 @@ PARALLEL_UPDATES = 1
async def async_setup_entry(
hass: HomeAssistantType,
entry: ConfigEntry,
async_add_entities: Callable[[List[Entity], bool], None],
async_add_entities: Callable[[list[Entity], bool], None],
) -> None:
"""Set up WLED switch based on a config entry."""
coordinator: WLEDDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
@ -72,7 +74,7 @@ class WLEDNightlightSwitch(WLEDSwitch):
)
@property
def extra_state_attributes(self) -> Optional[Dict[str, Any]]:
def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return the state attributes of the entity."""
return {
ATTR_DURATION: self.coordinator.data.state.nightlight.duration,
@ -110,7 +112,7 @@ class WLEDSyncSendSwitch(WLEDSwitch):
)
@property
def extra_state_attributes(self) -> Optional[Dict[str, Any]]:
def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return the state attributes of the entity."""
return {ATTR_UDP_PORT: self.coordinator.data.info.udp_port}
@ -144,7 +146,7 @@ class WLEDSyncReceiveSwitch(WLEDSwitch):
)
@property
def extra_state_attributes(self) -> Optional[Dict[str, Any]]:
def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return the state attributes of the entity."""
return {ATTR_UDP_PORT: self.coordinator.data.info.udp_port}

View File

@ -1,9 +1,11 @@
"""Support for WUnderground weather service."""
from __future__ import annotations
import asyncio
from datetime import timedelta
import logging
import re
from typing import Any, Callable, Optional, Union
from typing import Any, Callable
import aiohttp
import async_timeout
@ -64,10 +66,10 @@ class WUSensorConfig:
def __init__(
self,
friendly_name: Union[str, Callable],
friendly_name: str | Callable,
feature: str,
value: Callable[["WUndergroundData"], Any],
unit_of_measurement: Optional[str] = None,
unit_of_measurement: str | None = None,
entity_picture=None,
icon: str = "mdi:gauge",
extra_state_attributes=None,
@ -99,10 +101,10 @@ class WUCurrentConditionsSensorConfig(WUSensorConfig):
def __init__(
self,
friendly_name: Union[str, Callable],
friendly_name: str | Callable,
field: str,
icon: Optional[str] = "mdi:gauge",
unit_of_measurement: Optional[str] = None,
icon: str | None = "mdi:gauge",
unit_of_measurement: str | None = None,
device_class=None,
):
"""Initialize current conditions sensor configuration.
@ -131,9 +133,7 @@ class WUCurrentConditionsSensorConfig(WUSensorConfig):
class WUDailyTextForecastSensorConfig(WUSensorConfig):
"""Helper for defining sensor configurations for daily text forecasts."""
def __init__(
self, period: int, field: str, unit_of_measurement: Optional[str] = None
):
def __init__(self, period: int, field: str, unit_of_measurement: str | None = None):
"""Initialize daily text forecast sensor configuration.
:param period: forecast period number
@ -166,8 +166,8 @@ class WUDailySimpleForecastSensorConfig(WUSensorConfig):
friendly_name: str,
period: int,
field: str,
wu_unit: Optional[str] = None,
ha_unit: Optional[str] = None,
wu_unit: str | None = None,
ha_unit: str | None = None,
icon=None,
device_class=None,
):
@ -273,7 +273,7 @@ class WUAlmanacSensorConfig(WUSensorConfig):
def __init__(
self,
friendly_name: Union[str, Callable],
friendly_name: str | Callable,
field: str,
value_type: str,
wu_unit: str,
@ -303,7 +303,7 @@ class WUAlmanacSensorConfig(WUSensorConfig):
class WUAlertsSensorConfig(WUSensorConfig):
"""Helper for defining field configuration for alerts."""
def __init__(self, friendly_name: Union[str, Callable]):
def __init__(self, friendly_name: str | Callable):
"""Initialiize alerts sensor configuration.
:param friendly_name: Friendly name

View File

@ -1,9 +1,10 @@
"""The xbox integration."""
from __future__ import annotations
import asyncio
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import Dict, Optional
import voluptuous as vol
from xbox.webapi.api.client import XboxLiveClient
@ -133,7 +134,7 @@ class ConsoleData:
"""Xbox console status data."""
status: SmartglassConsoleStatus
app_details: Optional[Product]
app_details: Product | None
@dataclass
@ -149,7 +150,7 @@ class PresenceData:
in_game: bool
in_multiplayer: bool
gamer_score: str
gold_tenure: Optional[str]
gold_tenure: str | None
account_tier: str
@ -157,8 +158,8 @@ class PresenceData:
class XboxData:
"""Xbox dataclass for update coordinator."""
consoles: Dict[str, ConsoleData]
presence: Dict[str, PresenceData]
consoles: dict[str, ConsoleData]
presence: dict[str, PresenceData]
class XboxUpdateCoordinator(DataUpdateCoordinator):
@ -184,9 +185,9 @@ class XboxUpdateCoordinator(DataUpdateCoordinator):
async def _async_update_data(self) -> XboxData:
"""Fetch the latest console status."""
# Update Console Status
new_console_data: Dict[str, ConsoleData] = {}
new_console_data: dict[str, ConsoleData] = {}
for console in self.consoles.result:
current_state: Optional[ConsoleData] = self.data.consoles.get(console.id)
current_state: ConsoleData | None = self.data.consoles.get(console.id)
status: SmartglassConsoleStatus = (
await self.client.smartglass.get_console_status(console.id)
)
@ -198,7 +199,7 @@ class XboxUpdateCoordinator(DataUpdateCoordinator):
)
# Setup focus app
app_details: Optional[Product] = None
app_details: Product | None = None
if current_state is not None:
app_details = current_state.app_details
@ -246,7 +247,7 @@ class XboxUpdateCoordinator(DataUpdateCoordinator):
def _build_presence_data(person: Person) -> PresenceData:
"""Build presence data from a person."""
active_app: Optional[PresenceDetail] = None
active_app: PresenceDetail | None = None
try:
active_app = next(
presence for presence in person.presence_details if presence.is_primary

View File

@ -1,5 +1,5 @@
"""Base Sensor for the Xbox Integration."""
from typing import Optional
from __future__ import annotations
from yarl import URL
@ -24,7 +24,7 @@ class XboxBaseSensorEntity(CoordinatorEntity):
return f"{self.xuid}_{self.attribute}"
@property
def data(self) -> Optional[PresenceData]:
def data(self) -> PresenceData | None:
"""Return coordinator data for this console."""
return self.coordinator.data.presence.get(self.xuid)

View File

@ -1,6 +1,7 @@
"""Xbox friends binary sensors."""
from __future__ import annotations
from functools import partial
from typing import Dict, List
from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.core import callback
@ -44,7 +45,7 @@ class XboxBinarySensorEntity(XboxBaseSensorEntity, BinarySensorEntity):
@callback
def async_update_friends(
coordinator: XboxUpdateCoordinator,
current: Dict[str, List[XboxBinarySensorEntity]],
current: dict[str, list[XboxBinarySensorEntity]],
async_add_entities,
) -> None:
"""Update friends."""
@ -73,7 +74,7 @@ def async_update_friends(
async def async_remove_entities(
xuid: str,
coordinator: XboxUpdateCoordinator,
current: Dict[str, XboxBinarySensorEntity],
current: dict[str, XboxBinarySensorEntity],
) -> None:
"""Remove friend sensors from Home Assistant."""
registry = await async_get_entity_registry(coordinator.hass)

View File

@ -1,5 +1,5 @@
"""Support for media browsing."""
from typing import Dict, List, Optional
from __future__ import annotations
from xbox.webapi.api.client import XboxLiveClient
from xbox.webapi.api.provider.catalog.const import HOME_APP_IDS, SYSTEM_PFN_ID_MAP
@ -41,7 +41,7 @@ async def build_item_response(
tv_configured: bool,
media_content_type: str,
media_content_id: str,
) -> Optional[BrowseMedia]:
) -> BrowseMedia | None:
"""Create response payload for the provided media query."""
apps: InstalledPackagesList = await client.smartglass.get_installed_apps(device_id)
@ -149,7 +149,7 @@ async def build_item_response(
)
def item_payload(item: InstalledPackage, images: Dict[str, List[Image]]):
def item_payload(item: InstalledPackage, images: dict[str, list[Image]]):
"""Create response payload for a single media item."""
thumbnail = None
image = _find_media_image(images.get(item.one_store_product_id, []))
@ -169,7 +169,7 @@ def item_payload(item: InstalledPackage, images: Dict[str, List[Image]]):
)
def _find_media_image(images: List[Image]) -> Optional[Image]:
def _find_media_image(images: list[Image]) -> Image | None:
purpose_order = ["Poster", "Tile", "Logo", "BoxArt"]
for purpose in purpose_order:
for image in images:

View File

@ -1,6 +1,8 @@
"""Xbox Media Player Support."""
from __future__ import annotations
import re
from typing import List, Optional
from typing import List
from xbox.webapi.api.client import XboxLiveClient
from xbox.webapi.api.provider.catalog.models import Image
@ -231,7 +233,7 @@ class XboxMediaPlayer(CoordinatorEntity, MediaPlayerEntity):
}
def _find_media_image(images=List[Image]) -> Optional[Image]:
def _find_media_image(images=List[Image]) -> Image | None:
purpose_order = ["FeaturePromotionalSquareArt", "Tile", "Logo", "BoxArt"]
for purpose in purpose_order:
for image in images:

View File

@ -1,6 +1,7 @@
"""Xbox Media Source Implementation."""
from __future__ import annotations
from dataclasses import dataclass
from typing import List, Tuple
from pydantic.error_wrappers import ValidationError # pylint: disable=no-name-in-module
from xbox.webapi.api.client import XboxLiveClient
@ -50,7 +51,7 @@ async def async_get_media_source(hass: HomeAssistantType):
@callback
def async_parse_identifier(
item: MediaSourceItem,
) -> Tuple[str, str, str]:
) -> tuple[str, str, str]:
"""Parse identifier."""
identifier = item.identifier or ""
start = ["", "", ""]
@ -87,7 +88,7 @@ class XboxSource(MediaSource):
return PlayMedia(url, MIME_TYPE_MAP[kind])
async def async_browse_media(
self, item: MediaSourceItem, media_types: Tuple[str] = MEDIA_MIME_TYPES
self, item: MediaSourceItem, media_types: tuple[str] = MEDIA_MIME_TYPES
) -> BrowseMediaSource:
"""Return media."""
title, category, _ = async_parse_identifier(item)
@ -136,7 +137,7 @@ class XboxSource(MediaSource):
title_id, _, thumbnail = title.split("#", 2)
owner, kind = category.split("#", 1)
items: List[XboxMediaItem] = []
items: list[XboxMediaItem] = []
try:
if kind == "gameclips":
if owner == "my":
@ -206,7 +207,7 @@ class XboxSource(MediaSource):
)
def _build_game_item(item: InstalledPackage, images: List[Image]):
def _build_game_item(item: InstalledPackage, images: list[Image]):
"""Build individual game."""
thumbnail = ""
image = _find_media_image(images.get(item.one_store_product_id, []))

View File

@ -1,6 +1,7 @@
"""Xbox friends binary sensors."""
from __future__ import annotations
from functools import partial
from typing import Dict, List
from homeassistant.core import callback
from homeassistant.helpers.entity_registry import (
@ -43,7 +44,7 @@ class XboxSensorEntity(XboxBaseSensorEntity):
@callback
def async_update_friends(
coordinator: XboxUpdateCoordinator,
current: Dict[str, List[XboxSensorEntity]],
current: dict[str, list[XboxSensorEntity]],
async_add_entities,
) -> None:
"""Update friends."""
@ -72,7 +73,7 @@ def async_update_friends(
async def async_remove_entities(
xuid: str,
coordinator: XboxUpdateCoordinator,
current: Dict[str, XboxSensorEntity],
current: dict[str, XboxSensorEntity],
) -> None:
"""Remove friend sensors from Home Assistant."""
registry = await async_get_entity_registry(coordinator.hass)

View File

@ -1,8 +1,9 @@
"""Support for Xiaomi Yeelight WiFi color bulb."""
from __future__ import annotations
import asyncio
from datetime import timedelta
import logging
from typing import Optional
import voluptuous as vol
from yeelight import Bulb, BulbException, discover_bulbs
@ -181,7 +182,7 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Yeelight from a config entry."""
async def _initialize(host: str, capabilities: Optional[dict] = None) -> None:
async def _initialize(host: str, capabilities: dict | None = None) -> None:
remove_dispatcher = async_dispatcher_connect(
hass,
DEVICE_INITIALIZED.format(host),
@ -593,7 +594,7 @@ async def _async_get_device(
hass: HomeAssistant,
host: str,
entry: ConfigEntry,
capabilities: Optional[dict],
capabilities: dict | None,
) -> YeelightDevice:
# Get model from config and capabilities
model = entry.options.get(CONF_MODEL)

View File

@ -1,7 +1,9 @@
"""Zerproc light platform."""
from __future__ import annotations
from datetime import timedelta
import logging
from typing import Callable, List, Optional
from typing import Callable
import pyzerproc
@ -29,7 +31,7 @@ SUPPORT_ZERPROC = SUPPORT_BRIGHTNESS | SUPPORT_COLOR
DISCOVERY_INTERVAL = timedelta(seconds=60)
async def discover_entities(hass: HomeAssistant) -> List[Entity]:
async def discover_entities(hass: HomeAssistant) -> list[Entity]:
"""Attempt to discover new lights."""
lights = await pyzerproc.discover()
@ -49,7 +51,7 @@ async def discover_entities(hass: HomeAssistant) -> List[Entity]:
async def async_setup_entry(
hass: HomeAssistantType,
config_entry: ConfigEntry,
async_add_entities: Callable[[List[Entity], bool], None],
async_add_entities: Callable[[list[Entity], bool], None],
) -> None:
"""Set up Zerproc light devices."""
warned = False
@ -122,7 +124,7 @@ class ZerprocLight(LightEntity):
}
@property
def icon(self) -> Optional[str]:
def icon(self) -> str | None:
"""Return the icon to use in the frontend."""
return "mdi:string-lights"

View File

@ -4,11 +4,12 @@ Climate on Zigbee Home Automation networks.
For more details on this platform, please refer to the documentation
at https://home-assistant.io/components/zha.climate/
"""
from __future__ import annotations
from datetime import datetime, timedelta
import enum
import functools
from random import randint
from typing import List, Optional, Tuple
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
@ -212,7 +213,7 @@ class Thermostat(ZhaEntity, ClimateEntity):
return data
@property
def fan_mode(self) -> Optional[str]:
def fan_mode(self) -> str | None:
"""Return current FAN mode."""
if self._thrm.running_state is None:
return FAN_AUTO
@ -224,14 +225,14 @@ class Thermostat(ZhaEntity, ClimateEntity):
return FAN_AUTO
@property
def fan_modes(self) -> Optional[List[str]]:
def fan_modes(self) -> list[str] | None:
"""Return supported FAN modes."""
if not self._fan:
return None
return [FAN_AUTO, FAN_ON]
@property
def hvac_action(self) -> Optional[str]:
def hvac_action(self) -> str | None:
"""Return the current HVAC action."""
if (
self._thrm.pi_heating_demand is None
@ -241,7 +242,7 @@ class Thermostat(ZhaEntity, ClimateEntity):
return self._pi_demand_action
@property
def _rm_rs_action(self) -> Optional[str]:
def _rm_rs_action(self) -> str | None:
"""Return the current HVAC action based on running mode and running state."""
running_mode = self._thrm.running_mode
@ -260,7 +261,7 @@ class Thermostat(ZhaEntity, ClimateEntity):
return CURRENT_HVAC_OFF
@property
def _pi_demand_action(self) -> Optional[str]:
def _pi_demand_action(self) -> str | None:
"""Return the current HVAC action based on pi_demands."""
heating_demand = self._thrm.pi_heating_demand
@ -275,12 +276,12 @@ class Thermostat(ZhaEntity, ClimateEntity):
return CURRENT_HVAC_OFF
@property
def hvac_mode(self) -> Optional[str]:
def hvac_mode(self) -> str | None:
"""Return HVAC operation mode."""
return SYSTEM_MODE_2_HVAC.get(self._thrm.system_mode)
@property
def hvac_modes(self) -> Tuple[str, ...]:
def hvac_modes(self) -> tuple[str, ...]:
"""Return the list of available HVAC operation modes."""
return SEQ_OF_OPERATION.get(self._thrm.ctrl_seqe_of_oper, (HVAC_MODE_OFF,))
@ -290,12 +291,12 @@ class Thermostat(ZhaEntity, ClimateEntity):
return PRECISION_TENTHS
@property
def preset_mode(self) -> Optional[str]:
def preset_mode(self) -> str | None:
"""Return current preset mode."""
return self._preset
@property
def preset_modes(self) -> Optional[List[str]]:
def preset_modes(self) -> list[str] | None:
"""Return supported preset modes."""
return self._presets
@ -566,7 +567,7 @@ class ZenWithinThermostat(Thermostat):
"""Zen Within Thermostat implementation."""
@property
def _rm_rs_action(self) -> Optional[str]:
def _rm_rs_action(self) -> str | None:
"""Return the current HVAC action based on running mode and running state."""
running_state = self._thrm.running_state

View File

@ -1,6 +1,8 @@
"""Config flow for ZHA."""
from __future__ import annotations
import os
from typing import Any, Dict, Optional
from typing import Any
import serial.tools.list_ports
import voluptuous as vol
@ -127,7 +129,7 @@ class ZhaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
)
async def detect_radios(dev_path: str) -> Optional[Dict[str, Any]]:
async def detect_radios(dev_path: str) -> dict[str, Any] | None:
"""Probe all radio types on the device port."""
for radio in RadioType:
dev_config = radio.controller.SCHEMA_DEVICE({CONF_DEVICE_PATH: dev_path})

View File

@ -2,7 +2,7 @@
from __future__ import annotations
import asyncio
from typing import Any, Dict, List, Optional, Tuple, Union
from typing import Any, Dict
import zigpy.zcl.clusters.closures
@ -40,7 +40,7 @@ class Channels:
def __init__(self, zha_device: zha_typing.ZhaDeviceType) -> None:
"""Initialize instance."""
self._pools: List[zha_typing.ChannelPoolType] = []
self._pools: list[zha_typing.ChannelPoolType] = []
self._power_config = None
self._identify = None
self._semaphore = asyncio.Semaphore(3)
@ -49,7 +49,7 @@ class Channels:
self._zha_device = zha_device
@property
def pools(self) -> List[ChannelPool]:
def pools(self) -> list[ChannelPool]:
"""Return channel pools list."""
return self._pools
@ -96,7 +96,7 @@ class Channels:
return self._unique_id
@property
def zigbee_signature(self) -> Dict[int, Dict[str, Any]]:
def zigbee_signature(self) -> dict[int, dict[str, Any]]:
"""Get the zigbee signatures for the pools in channels."""
return {
signature[0]: signature[1]
@ -137,7 +137,7 @@ class Channels:
component: str,
entity_class: zha_typing.CALLABLE_T,
unique_id: str,
channels: List[zha_typing.ChannelType],
channels: list[zha_typing.ChannelType],
):
"""Signal new entity addition."""
if self.zha_device.status == zha_core_device.DeviceStatus.INITIALIZED:
@ -153,7 +153,7 @@ class Channels:
async_dispatcher_send(self.zha_device.hass, signal, *args)
@callback
def zha_send_event(self, event_data: Dict[str, Union[str, int]]) -> None:
def zha_send_event(self, event_data: dict[str, str | int]) -> None:
"""Relay events to hass."""
self.zha_device.hass.bus.async_fire(
"zha_event",
@ -175,7 +175,7 @@ class ChannelPool:
self._channels: Channels = channels
self._claimed_channels: ChannelsDict = {}
self._id: int = ep_id
self._client_channels: Dict[str, zha_typing.ClientChannelType] = {}
self._client_channels: dict[str, zha_typing.ClientChannelType] = {}
self._unique_id: str = f"{channels.unique_id}-{ep_id}"
@property
@ -189,7 +189,7 @@ class ChannelPool:
return self._claimed_channels
@property
def client_channels(self) -> Dict[str, zha_typing.ClientChannelType]:
def client_channels(self) -> dict[str, zha_typing.ClientChannelType]:
"""Return a dict of client channels."""
return self._client_channels
@ -214,12 +214,12 @@ class ChannelPool:
return self._channels.zha_device.is_mains_powered
@property
def manufacturer(self) -> Optional[str]:
def manufacturer(self) -> str | None:
"""Return device manufacturer."""
return self._channels.zha_device.manufacturer
@property
def manufacturer_code(self) -> Optional[int]:
def manufacturer_code(self) -> int | None:
"""Return device manufacturer."""
return self._channels.zha_device.manufacturer_code
@ -229,7 +229,7 @@ class ChannelPool:
return self._channels.zha_device.hass
@property
def model(self) -> Optional[str]:
def model(self) -> str | None:
"""Return device model."""
return self._channels.zha_device.model
@ -244,7 +244,7 @@ class ChannelPool:
return self._unique_id
@property
def zigbee_signature(self) -> Tuple[int, Dict[str, Any]]:
def zigbee_signature(self) -> tuple[int, dict[str, Any]]:
"""Get the zigbee signature for the endpoint this pool represents."""
return (
self.endpoint.endpoint_id,
@ -342,7 +342,7 @@ class ChannelPool:
component: str,
entity_class: zha_typing.CALLABLE_T,
unique_id: str,
channels: List[zha_typing.ChannelType],
channels: list[zha_typing.ChannelType],
):
"""Signal new entity addition."""
self._channels.async_new_entity(component, entity_class, unique_id, channels)
@ -353,19 +353,19 @@ class ChannelPool:
self._channels.async_send_signal(signal, *args)
@callback
def claim_channels(self, channels: List[zha_typing.ChannelType]) -> None:
def claim_channels(self, channels: list[zha_typing.ChannelType]) -> None:
"""Claim a channel."""
self.claimed_channels.update({ch.id: ch for ch in channels})
@callback
def unclaimed_channels(self) -> List[zha_typing.ChannelType]:
def unclaimed_channels(self) -> list[zha_typing.ChannelType]:
"""Return a list of available (unclaimed) channels."""
claimed = set(self.claimed_channels)
available = set(self.all_channels)
return [self.all_channels[chan_id] for chan_id in (available - claimed)]
@callback
def zha_send_event(self, event_data: Dict[str, Union[str, int]]) -> None:
def zha_send_event(self, event_data: dict[str, str | int]) -> None:
"""Relay events to hass."""
self._channels.zha_send_event(
{

View File

@ -1,10 +1,11 @@
"""Base classes for channels."""
from __future__ import annotations
import asyncio
from enum import Enum
from functools import wraps
import logging
from typing import Any, Union
from typing import Any
import zigpy.exceptions
@ -238,7 +239,7 @@ class ZigbeeChannel(LogMixin):
"""Handle ZDO commands on this cluster."""
@callback
def zha_send_event(self, command: str, args: Union[int, dict]) -> None:
def zha_send_event(self, command: str, args: int | dict) -> None:
"""Relay events to hass."""
self._ch_pool.zha_send_event(
{

View File

@ -1,6 +1,8 @@
"""General channels module for Zigbee Home Automation."""
from __future__ import annotations
import asyncio
from typing import Any, Coroutine, List, Optional
from typing import Any, Coroutine
import zigpy.exceptions
import zigpy.zcl.clusters.general as general
@ -44,42 +46,42 @@ class AnalogOutput(ZigbeeChannel):
REPORT_CONFIG = [{"attr": "present_value", "config": REPORT_CONFIG_DEFAULT}]
@property
def present_value(self) -> Optional[float]:
def present_value(self) -> float | None:
"""Return cached value of present_value."""
return self.cluster.get("present_value")
@property
def min_present_value(self) -> Optional[float]:
def min_present_value(self) -> float | None:
"""Return cached value of min_present_value."""
return self.cluster.get("min_present_value")
@property
def max_present_value(self) -> Optional[float]:
def max_present_value(self) -> float | None:
"""Return cached value of max_present_value."""
return self.cluster.get("max_present_value")
@property
def resolution(self) -> Optional[float]:
def resolution(self) -> float | None:
"""Return cached value of resolution."""
return self.cluster.get("resolution")
@property
def relinquish_default(self) -> Optional[float]:
def relinquish_default(self) -> float | None:
"""Return cached value of relinquish_default."""
return self.cluster.get("relinquish_default")
@property
def description(self) -> Optional[str]:
def description(self) -> str | None:
"""Return cached value of description."""
return self.cluster.get("description")
@property
def engineering_units(self) -> Optional[int]:
def engineering_units(self) -> int | None:
"""Return cached value of engineering_units."""
return self.cluster.get("engineering_units")
@property
def application_type(self) -> Optional[int]:
def application_type(self) -> int | None:
"""Return cached value of application_type."""
return self.cluster.get("application_type")
@ -215,7 +217,7 @@ class LevelControlChannel(ZigbeeChannel):
REPORT_CONFIG = ({"attr": "current_level", "config": REPORT_CONFIG_ASAP},)
@property
def current_level(self) -> Optional[int]:
def current_level(self) -> int | None:
"""Return cached value of the current_level attribute."""
return self.cluster.get("current_level")
@ -293,7 +295,7 @@ class OnOffChannel(ZigbeeChannel):
self._off_listener = None
@property
def on_off(self) -> Optional[bool]:
def on_off(self) -> bool | None:
"""Return cached value of on/off attribute."""
return self.cluster.get("on_off")
@ -367,7 +369,7 @@ class Ota(ZigbeeChannel):
@callback
def cluster_command(
self, tsn: int, command_id: int, args: Optional[List[Any]]
self, tsn: int, command_id: int, args: list[Any] | None
) -> None:
"""Handle OTA commands."""
cmd_name = self.cluster.server_commands.get(command_id, [command_id])[0]
@ -402,7 +404,7 @@ class PollControl(ZigbeeChannel):
@callback
def cluster_command(
self, tsn: int, command_id: int, args: Optional[List[Any]]
self, tsn: int, command_id: int, args: list[Any] | None
) -> None:
"""Handle commands received to this cluster."""
cmd_name = self.cluster.client_commands.get(command_id, [command_id])[0]

View File

@ -1,5 +1,7 @@
"""Home automation channels module for Zigbee Home Automation."""
from typing import Coroutine, Optional
from __future__ import annotations
from typing import Coroutine
import zigpy.zcl.clusters.homeautomation as homeautomation
@ -76,14 +78,14 @@ class ElectricalMeasurementChannel(ZigbeeChannel):
)
@property
def divisor(self) -> Optional[int]:
def divisor(self) -> int | None:
"""Return active power divisor."""
return self.cluster.get(
"ac_power_divisor", self.cluster.get("power_divisor", 1)
)
@property
def multiplier(self) -> Optional[int]:
def multiplier(self) -> int | None:
"""Return active power divisor."""
return self.cluster.get(
"ac_power_multiplier", self.cluster.get("power_multiplier", 1)

View File

@ -4,9 +4,11 @@ HVAC channels module for Zigbee Home Automation.
For more details about this component, please refer to the documentation at
https://home-assistant.io/integrations/zha/
"""
from __future__ import annotations
import asyncio
from collections import namedtuple
from typing import Any, Dict, List, Optional, Tuple, Union
from typing import Any
from zigpy.exceptions import ZigbeeException
import zigpy.zcl.clusters.hvac as hvac
@ -44,7 +46,7 @@ class FanChannel(ZigbeeChannel):
REPORT_CONFIG = ({"attr": "fan_mode", "config": REPORT_CONFIG_OP},)
@property
def fan_mode(self) -> Optional[int]:
def fan_mode(self) -> int | None:
"""Return current fan mode."""
return self.cluster.get("fan_mode")
@ -198,22 +200,22 @@ class ThermostatChannel(ZigbeeChannel):
return self._min_heat_setpoint_limit
@property
def local_temp(self) -> Optional[int]:
def local_temp(self) -> int | None:
"""Thermostat temperature."""
return self._local_temp
@property
def occupancy(self) -> Optional[int]:
def occupancy(self) -> int | None:
"""Is occupancy detected."""
return self._occupancy
@property
def occupied_cooling_setpoint(self) -> Optional[int]:
def occupied_cooling_setpoint(self) -> int | None:
"""Temperature when room is occupied."""
return self._occupied_cooling_setpoint
@property
def occupied_heating_setpoint(self) -> Optional[int]:
def occupied_heating_setpoint(self) -> int | None:
"""Temperature when room is occupied."""
return self._occupied_heating_setpoint
@ -228,27 +230,27 @@ class ThermostatChannel(ZigbeeChannel):
return self._pi_heating_demand
@property
def running_mode(self) -> Optional[int]:
def running_mode(self) -> int | None:
"""Thermostat running mode."""
return self._running_mode
@property
def running_state(self) -> Optional[int]:
def running_state(self) -> int | None:
"""Thermostat running state, state of heat, cool, fan relays."""
return self._running_state
@property
def system_mode(self) -> Optional[int]:
def system_mode(self) -> int | None:
"""System mode."""
return self._system_mode
@property
def unoccupied_cooling_setpoint(self) -> Optional[int]:
def unoccupied_cooling_setpoint(self) -> int | None:
"""Temperature when room is not occupied."""
return self._unoccupied_cooling_setpoint
@property
def unoccupied_heating_setpoint(self) -> Optional[int]:
def unoccupied_heating_setpoint(self) -> int | None:
"""Temperature when room is not occupied."""
return self._unoccupied_heating_setpoint
@ -309,7 +311,7 @@ class ThermostatChannel(ZigbeeChannel):
chunk, rest = rest[:4], rest[4:]
def _configure_reporting_status(
self, attrs: Dict[Union[int, str], Tuple], res: Union[List, Tuple]
self, attrs: dict[int | str, tuple], res: list | tuple
) -> None:
"""Parse configure reporting result."""
if not isinstance(res, list):
@ -405,7 +407,7 @@ class ThermostatChannel(ZigbeeChannel):
self.debug("set cooling setpoint to %s", temperature)
return True
async def get_occupancy(self) -> Optional[bool]:
async def get_occupancy(self) -> bool | None:
"""Get unreportable occupancy attribute."""
try:
res, fail = await self.cluster.read_attributes(["occupancy"])

View File

@ -1,5 +1,7 @@
"""Lighting channels module for Zigbee Home Automation."""
from typing import Coroutine, Optional
from __future__ import annotations
from typing import Coroutine
import zigpy.zcl.clusters.lighting as lighting
@ -46,22 +48,22 @@ class ColorChannel(ZigbeeChannel):
return self.CAPABILITIES_COLOR_XY
@property
def color_loop_active(self) -> Optional[int]:
def color_loop_active(self) -> int | None:
"""Return cached value of the color_loop_active attribute."""
return self.cluster.get("color_loop_active")
@property
def color_temperature(self) -> Optional[int]:
def color_temperature(self) -> int | None:
"""Return cached value of color temperature."""
return self.cluster.get("color_temperature")
@property
def current_x(self) -> Optional[int]:
def current_x(self) -> int | None:
"""Return cached value of the current_x attribute."""
return self.cluster.get("current_x")
@property
def current_y(self) -> Optional[int]:
def current_y(self) -> int | None:
"""Return cached value of the current_y attribute."""
return self.cluster.get("current_y")

View File

@ -1,5 +1,7 @@
"""Smart energy channels module for Zigbee Home Automation."""
from typing import Coroutine, Union
from __future__ import annotations
from typing import Coroutine
import zigpy.zcl.clusters.smartenergy as smartenergy
@ -139,7 +141,7 @@ class Metering(ZigbeeChannel):
else:
self._format_spec = "{:0" + str(width) + "." + str(r_digits) + "f}"
def formatter_function(self, value: int) -> Union[int, float]:
def formatter_function(self, value: int) -> int | float:
"""Return formatted value for display."""
value = value * self.multiplier / self.divisor
if self.unit_of_measurement == POWER_WATT:

View File

@ -1,7 +1,8 @@
"""All constants related to the ZHA component."""
from __future__ import annotations
import enum
import logging
from typing import List
import bellows.zigbee.application
from zigpy.config import CONF_DEVICE_PATH # noqa: F401 # pylint: disable=unused-import
@ -203,7 +204,7 @@ class RadioType(enum.Enum):
)
@classmethod
def list(cls) -> List[str]:
def list(cls) -> list[str]:
"""Return a list of descriptions."""
return [e.description for e in RadioType]

View File

@ -1,5 +1,7 @@
"""Decorators for ZHA core registries."""
from typing import Callable, TypeVar, Union
from __future__ import annotations
from typing import Callable, TypeVar
CALLABLE_T = TypeVar("CALLABLE_T", bound=Callable) # pylint: disable=invalid-name
@ -8,7 +10,7 @@ class DictRegistry(dict):
"""Dict Registry of items."""
def register(
self, name: Union[int, str], item: Union[str, CALLABLE_T] = None
self, name: int | str, item: str | CALLABLE_T = None
) -> Callable[[CALLABLE_T], CALLABLE_T]:
"""Return decorator to register item with a specific name."""
@ -26,7 +28,7 @@ class DictRegistry(dict):
class SetRegistry(set):
"""Set Registry of items."""
def register(self, name: Union[int, str]) -> Callable[[CALLABLE_T], CALLABLE_T]:
def register(self, name: int | str) -> Callable[[CALLABLE_T], CALLABLE_T]:
"""Return decorator to register item with a specific name."""
def decorator(channel: CALLABLE_T) -> CALLABLE_T:

View File

@ -1,11 +1,13 @@
"""Device for Zigbee Home Automation."""
from __future__ import annotations
import asyncio
from datetime import timedelta
from enum import Enum
import logging
import random
import time
from typing import Any, Dict
from typing import Any
from zigpy import types
import zigpy.exceptions
@ -275,7 +277,7 @@ class ZHADevice(LogMixin):
self._available = new_availability
@property
def zigbee_signature(self) -> Dict[str, Any]:
def zigbee_signature(self) -> dict[str, Any]:
"""Get zigbee signature for this device."""
return {
ATTR_NODE_DESCRIPTOR: str(self._zigpy_device.node_desc),

View File

@ -1,8 +1,9 @@
"""Device discovery functions for Zigbee Home Automation."""
from __future__ import annotations
from collections import Counter
import logging
from typing import Callable, List, Tuple
from typing import Callable
from homeassistant import const as ha_const
from homeassistant.core import callback
@ -34,10 +35,10 @@ _LOGGER = logging.getLogger(__name__)
@callback
async def async_add_entities(
_async_add_entities: Callable,
entities: List[
Tuple[
entities: list[
tuple[
zha_typing.ZhaEntityType,
Tuple[str, zha_typing.ZhaDeviceType, List[zha_typing.ChannelType]],
tuple[str, zha_typing.ZhaDeviceType, list[zha_typing.ChannelType]],
]
],
update_before_add: bool = True,
@ -235,9 +236,9 @@ class GroupProbe:
@staticmethod
def determine_entity_domains(
hass: HomeAssistantType, group: zha_typing.ZhaGroupType
) -> List[str]:
) -> list[str]:
"""Determine the entity domains for this group."""
entity_domains: List[str] = []
entity_domains: list[str] = []
zha_gateway = hass.data[zha_const.DATA_ZHA][zha_const.DATA_ZHA_GATEWAY]
all_domain_occurrences = []
for member in group.members:

View File

@ -1,4 +1,5 @@
"""Virtual gateway for Zigbee Home Automation."""
from __future__ import annotations
import asyncio
import collections
@ -9,7 +10,6 @@ import logging
import os
import time
import traceback
from typing import List, Optional
from serial import SerialException
from zigpy.config import CONF_DEVICE
@ -378,12 +378,12 @@ class ZHAGateway:
"""Return ZHADevice for given ieee."""
return self._devices.get(ieee)
def get_group(self, group_id: str) -> Optional[ZhaGroupType]:
def get_group(self, group_id: str) -> ZhaGroupType | None:
"""Return Group for given group id."""
return self.groups.get(group_id)
@callback
def async_get_group_by_name(self, group_name: str) -> Optional[ZhaGroupType]:
def async_get_group_by_name(self, group_name: str) -> ZhaGroupType | None:
"""Get ZHA group by name."""
for group in self.groups.values():
if group.name == group_name:
@ -620,7 +620,7 @@ class ZHAGateway:
zha_device.update_available(True)
async def async_create_zigpy_group(
self, name: str, members: List[GroupMember]
self, name: str, members: list[GroupMember]
) -> ZhaGroupType:
"""Create a new Zigpy Zigbee group."""
# we start with two to fill any gaps from a user removing existing groups

View File

@ -1,8 +1,10 @@
"""Group for Zigbee Home Automation."""
from __future__ import annotations
import asyncio
import collections
import logging
from typing import Any, Dict, List
from typing import Any
import zigpy.exceptions
@ -58,16 +60,16 @@ class ZHAGroupMember(LogMixin):
return self._zha_device
@property
def member_info(self) -> Dict[str, Any]:
def member_info(self) -> dict[str, Any]:
"""Get ZHA group info."""
member_info: Dict[str, Any] = {}
member_info: dict[str, Any] = {}
member_info["endpoint_id"] = self.endpoint_id
member_info["device"] = self.device.zha_device_info
member_info["entities"] = self.associated_entities
return member_info
@property
def associated_entities(self) -> List[GroupEntityReference]:
def associated_entities(self) -> list[GroupEntityReference]:
"""Return the list of entities that were derived from this endpoint."""
ha_entity_registry = self.device.gateway.ha_entity_registry
zha_device_registry = self.device.gateway.device_registry
@ -136,7 +138,7 @@ class ZHAGroup(LogMixin):
return self._zigpy_group.endpoint
@property
def members(self) -> List[ZHAGroupMember]:
def members(self) -> list[ZHAGroupMember]:
"""Return the ZHA devices that are members of this group."""
return [
ZHAGroupMember(
@ -146,7 +148,7 @@ class ZHAGroup(LogMixin):
if member_ieee in self._zha_gateway.devices
]
async def async_add_members(self, members: List[GroupMember]) -> None:
async def async_add_members(self, members: list[GroupMember]) -> None:
"""Add members to this group."""
if len(members) > 1:
tasks = []
@ -162,7 +164,7 @@ class ZHAGroup(LogMixin):
members[0].ieee
].async_add_endpoint_to_group(members[0].endpoint_id, self.group_id)
async def async_remove_members(self, members: List[GroupMember]) -> None:
async def async_remove_members(self, members: list[GroupMember]) -> None:
"""Remove members from this group."""
if len(members) > 1:
tasks = []
@ -181,18 +183,18 @@ class ZHAGroup(LogMixin):
].async_remove_endpoint_from_group(members[0].endpoint_id, self.group_id)
@property
def member_entity_ids(self) -> List[str]:
def member_entity_ids(self) -> list[str]:
"""Return the ZHA entity ids for all entities for the members of this group."""
all_entity_ids: List[str] = []
all_entity_ids: list[str] = []
for member in self.members:
entity_references = member.associated_entities
for entity_reference in entity_references:
all_entity_ids.append(entity_reference["entity_id"])
return all_entity_ids
def get_domain_entity_ids(self, domain) -> List[str]:
def get_domain_entity_ids(self, domain) -> list[str]:
"""Return entity ids from the entity domain for this group."""
domain_entity_ids: List[str] = []
domain_entity_ids: list[str] = []
for member in self.members:
if member.device.is_coordinator:
continue
@ -207,9 +209,9 @@ class ZHAGroup(LogMixin):
return domain_entity_ids
@property
def group_info(self) -> Dict[str, Any]:
def group_info(self) -> dict[str, Any]:
"""Get ZHA group info."""
group_info: Dict[str, Any] = {}
group_info: dict[str, Any] = {}
group_info["group_id"] = self.group_id
group_info["name"] = self.name
group_info["members"] = [member.member_info for member in self.members]

View File

@ -4,6 +4,7 @@ Helpers for Zigbee Home Automation.
For more details about this component, please refer to the documentation at
https://home-assistant.io/integrations/zha/
"""
from __future__ import annotations
import asyncio
import binascii
@ -13,7 +14,7 @@ import itertools
import logging
from random import uniform
import re
from typing import Any, Callable, Iterator, List, Optional, Tuple
from typing import Any, Callable, Iterator
import voluptuous as vol
import zigpy.exceptions
@ -67,7 +68,7 @@ async def safe_read(
async def get_matched_clusters(
source_zha_device: ZhaDeviceType, target_zha_device: ZhaDeviceType
) -> List[BindingPair]:
) -> list[BindingPair]:
"""Get matched input/output cluster pairs for 2 devices."""
source_clusters = source_zha_device.async_get_std_clusters()
target_clusters = target_zha_device.async_get_std_clusters()
@ -131,7 +132,7 @@ async def async_get_zha_device(hass, device_id):
return zha_gateway.devices[ieee]
def find_state_attributes(states: List[State], key: str) -> Iterator[Any]:
def find_state_attributes(states: list[State], key: str) -> Iterator[Any]:
"""Find attributes with matching key from states."""
for state in states:
value = state.attributes.get(key)
@ -150,9 +151,9 @@ def mean_tuple(*args):
def reduce_attribute(
states: List[State],
states: list[State],
key: str,
default: Optional[Any] = None,
default: Any | None = None,
reduce: Callable[..., Any] = mean_int,
) -> Any:
"""Find the first attribute matching key from states.
@ -280,7 +281,7 @@ QR_CODES = (
)
def qr_to_install_code(qr_code: str) -> Tuple[zigpy.types.EUI64, bytes]:
def qr_to_install_code(qr_code: str) -> tuple[zigpy.types.EUI64, bytes]:
"""Try to parse the QR code.
if successful, return a tuple of a EUI64 address and install code.

View File

@ -1,6 +1,8 @@
"""Mapping registries for Zigbee Home Automation."""
from __future__ import annotations
import collections
from typing import Callable, Dict, List, Set, Tuple, Union
from typing import Callable, Dict
import attr
import zigpy.profiles.zha
@ -134,19 +136,19 @@ def set_or_callable(value):
class MatchRule:
"""Match a ZHA Entity to a channel name or generic id."""
channel_names: Union[Callable, Set[str], str] = attr.ib(
channel_names: Callable | set[str] | str = attr.ib(
factory=frozenset, converter=set_or_callable
)
generic_ids: Union[Callable, Set[str], str] = attr.ib(
generic_ids: Callable | set[str] | str = attr.ib(
factory=frozenset, converter=set_or_callable
)
manufacturers: Union[Callable, Set[str], str] = attr.ib(
manufacturers: Callable | set[str] | str = attr.ib(
factory=frozenset, converter=set_or_callable
)
models: Union[Callable, Set[str], str] = attr.ib(
models: Callable | set[str] | str = attr.ib(
factory=frozenset, converter=set_or_callable
)
aux_channels: Union[Callable, Set[str], str] = attr.ib(
aux_channels: Callable | set[str] | str = attr.ib(
factory=frozenset, converter=set_or_callable
)
@ -176,7 +178,7 @@ class MatchRule:
weight += 1 * len(self.aux_channels)
return weight
def claim_channels(self, channel_pool: List[ChannelType]) -> List[ChannelType]:
def claim_channels(self, channel_pool: list[ChannelType]) -> list[ChannelType]:
"""Return a list of channels this rule matches + aux channels."""
claimed = []
if isinstance(self.channel_names, frozenset):
@ -189,15 +191,15 @@ class MatchRule:
claimed.extend([ch for ch in channel_pool if ch.name in self.aux_channels])
return claimed
def strict_matched(self, manufacturer: str, model: str, channels: List) -> bool:
def strict_matched(self, manufacturer: str, model: str, channels: list) -> bool:
"""Return True if this device matches the criteria."""
return all(self._matched(manufacturer, model, channels))
def loose_matched(self, manufacturer: str, model: str, channels: List) -> bool:
def loose_matched(self, manufacturer: str, model: str, channels: list) -> bool:
"""Return True if this device matches the criteria."""
return any(self._matched(manufacturer, model, channels))
def _matched(self, manufacturer: str, model: str, channels: List) -> list:
def _matched(self, manufacturer: str, model: str, channels: list) -> list:
"""Return a list of field matches."""
if not any(attr.asdict(self).values()):
return [False]
@ -245,9 +247,9 @@ class ZHAEntityRegistry:
component: str,
manufacturer: str,
model: str,
channels: List[ChannelType],
channels: list[ChannelType],
default: CALLABLE_T = None,
) -> Tuple[CALLABLE_T, List[ChannelType]]:
) -> tuple[CALLABLE_T, list[ChannelType]]:
"""Match a ZHA Channels to a ZHA Entity class."""
matches = self._strict_registry[component]
for match in sorted(matches, key=lambda x: x.weight, reverse=True):
@ -264,11 +266,11 @@ class ZHAEntityRegistry:
def strict_match(
self,
component: str,
channel_names: Union[Callable, Set[str], str] = None,
generic_ids: Union[Callable, Set[str], str] = None,
manufacturers: Union[Callable, Set[str], str] = None,
models: Union[Callable, Set[str], str] = None,
aux_channels: Union[Callable, Set[str], str] = None,
channel_names: Callable | set[str] | str = None,
generic_ids: Callable | set[str] | str = None,
manufacturers: Callable | set[str] | str = None,
models: Callable | set[str] | str = None,
aux_channels: Callable | set[str] | str = None,
) -> Callable[[CALLABLE_T], CALLABLE_T]:
"""Decorate a strict match rule."""
@ -289,11 +291,11 @@ class ZHAEntityRegistry:
def loose_match(
self,
component: str,
channel_names: Union[Callable, Set[str], str] = None,
generic_ids: Union[Callable, Set[str], str] = None,
manufacturers: Union[Callable, Set[str], str] = None,
models: Union[Callable, Set[str], str] = None,
aux_channels: Union[Callable, Set[str], str] = None,
channel_names: Callable | set[str] | str = None,
generic_ids: Callable | set[str] | str = None,
manufacturers: Callable | set[str] | str = None,
models: Callable | set[str] | str = None,
aux_channels: Callable | set[str] | str = None,
) -> Callable[[CALLABLE_T], CALLABLE_T]:
"""Decorate a loose match rule."""

View File

@ -1,8 +1,10 @@
"""Data storage helper for ZHA."""
from __future__ import annotations
from collections import OrderedDict
import datetime
import time
from typing import MutableMapping, Optional, cast
from typing import MutableMapping, cast
import attr
@ -24,9 +26,9 @@ TOMBSTONE_LIFETIME = datetime.timedelta(days=60).total_seconds()
class ZhaDeviceEntry:
"""Zha Device storage Entry."""
name: Optional[str] = attr.ib(default=None)
ieee: Optional[str] = attr.ib(default=None)
last_seen: Optional[float] = attr.ib(default=None)
name: str | None = attr.ib(default=None)
ieee: str | None = attr.ib(default=None)
last_seen: float | None = attr.ib(default=None)
class ZhaStorage:

View File

@ -1,8 +1,9 @@
"""Support for ZHA covers."""
from __future__ import annotations
import asyncio
import functools
import logging
from typing import List, Optional
from zigpy.zcl.foundation import Status
@ -180,7 +181,7 @@ class Shade(ZhaEntity, CoverEntity):
self,
unique_id: str,
zha_device: ZhaDeviceType,
channels: List[ChannelType],
channels: list[ChannelType],
**kwargs,
):
"""Initialize the ZHA light."""
@ -199,12 +200,12 @@ class Shade(ZhaEntity, CoverEntity):
return self._position
@property
def device_class(self) -> Optional[str]:
def device_class(self) -> str | None:
"""Return the class of this device, from component DEVICE_CLASSES."""
return DEVICE_CLASS_SHADE
@property
def is_closed(self) -> Optional[bool]:
def is_closed(self) -> bool | None:
"""Return True if shade is closed."""
if self._is_open is None:
return None
@ -289,7 +290,7 @@ class KeenVent(Shade):
"""Keen vent cover."""
@property
def device_class(self) -> Optional[str]:
def device_class(self) -> str | None:
"""Return the class of this device, from component DEVICE_CLASSES."""
return DEVICE_CLASS_DAMPER

View File

@ -1,5 +1,5 @@
"""Provides device actions for ZHA devices."""
from typing import List
from __future__ import annotations
import voluptuous as vol
@ -54,7 +54,7 @@ async def async_call_action_from_config(
)
async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]:
async def async_get_actions(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device actions."""
try:
zha_device = await async_get_zha_device(hass, device_id)

View File

@ -1,9 +1,10 @@
"""Entity for Zigbee Home Automation."""
from __future__ import annotations
import asyncio
import functools
import logging
from typing import Any, Awaitable, Dict, List, Optional
from typing import Any, Awaitable
from homeassistant.const import ATTR_NAME
from homeassistant.core import CALLBACK_TYPE, Event, callback
@ -45,9 +46,9 @@ class BaseZhaEntity(LogMixin, entity.Entity):
self._should_poll: bool = False
self._unique_id: str = unique_id
self._state: Any = None
self._extra_state_attributes: Dict[str, Any] = {}
self._extra_state_attributes: dict[str, Any] = {}
self._zha_device: ZhaDeviceType = zha_device
self._unsubs: List[CALLABLE_T] = []
self._unsubs: list[CALLABLE_T] = []
self.remove_future: Awaitable[None] = None
@property
@ -66,7 +67,7 @@ class BaseZhaEntity(LogMixin, entity.Entity):
return self._zha_device
@property
def extra_state_attributes(self) -> Dict[str, Any]:
def extra_state_attributes(self) -> dict[str, Any]:
"""Return device specific state attributes."""
return self._extra_state_attributes
@ -81,7 +82,7 @@ class BaseZhaEntity(LogMixin, entity.Entity):
return self._should_poll
@property
def device_info(self) -> Dict[str, Any]:
def device_info(self) -> dict[str, Any]:
"""Return a device description for device registry."""
zha_device_info = self._zha_device.device_info
ieee = zha_device_info["ieee"]
@ -143,7 +144,7 @@ class ZhaEntity(BaseZhaEntity, RestoreEntity):
self,
unique_id: str,
zha_device: ZhaDeviceType,
channels: List[ChannelType],
channels: list[ChannelType],
**kwargs,
):
"""Init ZHA entity."""
@ -152,7 +153,7 @@ class ZhaEntity(BaseZhaEntity, RestoreEntity):
ch_names = [ch.cluster.ep_attribute for ch in channels]
ch_names = ", ".join(sorted(ch_names))
self._name: str = f"{zha_device.name} {ieeetail} {ch_names}"
self.cluster_channels: Dict[str, ChannelType] = {}
self.cluster_channels: dict[str, ChannelType] = {}
for channel in channels:
self.cluster_channels[channel.name] = channel
@ -217,7 +218,7 @@ class ZhaGroupEntity(BaseZhaEntity):
"""A base class for ZHA group entities."""
def __init__(
self, entity_ids: List[str], unique_id: str, group_id: int, zha_device, **kwargs
self, entity_ids: list[str], unique_id: str, group_id: int, zha_device, **kwargs
) -> None:
"""Initialize a light group."""
super().__init__(unique_id, zha_device, **kwargs)
@ -225,8 +226,8 @@ class ZhaGroupEntity(BaseZhaEntity):
self._group = zha_device.gateway.groups.get(group_id)
self._name = f"{self._group.name}_zha_group_0x{group_id:04x}"
self._group_id: int = group_id
self._entity_ids: List[str] = entity_ids
self._async_unsub_state_changed: Optional[CALLBACK_TYPE] = None
self._entity_ids: list[str] = entity_ids
self._async_unsub_state_changed: CALLBACK_TYPE | None = None
self._handled_group_membership = False
@property

View File

@ -1,8 +1,9 @@
"""Fans on Zigbee Home Automation networks."""
from __future__ import annotations
from abc import abstractmethod
import functools
import math
from typing import List, Optional
from zigpy.exceptions import ZigbeeException
import zigpy.zcl.clusters.hvac as hvac
@ -77,7 +78,7 @@ class BaseFan(FanEntity):
"""Base representation of a ZHA fan."""
@property
def preset_modes(self) -> List[str]:
def preset_modes(self) -> list[str]:
"""Return the available preset modes."""
return PRESET_MODES
@ -103,7 +104,7 @@ class BaseFan(FanEntity):
"""Turn the entity off."""
await self.async_set_percentage(0)
async def async_set_percentage(self, percentage: Optional[int]) -> None:
async def async_set_percentage(self, percentage: int | None) -> None:
"""Set the speed percenage of the fan."""
fan_mode = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage))
await self._async_set_fan_mode(fan_mode)
@ -142,7 +143,7 @@ class ZhaFan(BaseFan, ZhaEntity):
)
@property
def percentage(self) -> Optional[int]:
def percentage(self) -> int | None:
"""Return the current speed percentage."""
if (
self._fan_channel.fan_mode is None
@ -154,7 +155,7 @@ class ZhaFan(BaseFan, ZhaEntity):
return ranged_value_to_percentage(SPEED_RANGE, self._fan_channel.fan_mode)
@property
def preset_mode(self) -> Optional[str]:
def preset_mode(self) -> str | None:
"""Return the current preset mode."""
return PRESET_MODES_TO_NAME.get(self._fan_channel.fan_mode)
@ -174,7 +175,7 @@ class FanGroup(BaseFan, ZhaGroupEntity):
"""Representation of a fan group."""
def __init__(
self, entity_ids: List[str], unique_id: str, group_id: int, zha_device, **kwargs
self, entity_ids: list[str], unique_id: str, group_id: int, zha_device, **kwargs
) -> None:
"""Initialize a fan group."""
super().__init__(entity_ids, unique_id, group_id, zha_device, **kwargs)
@ -185,12 +186,12 @@ class FanGroup(BaseFan, ZhaGroupEntity):
self._preset_mode = None
@property
def percentage(self) -> Optional[int]:
def percentage(self) -> int | None:
"""Return the current speed percentage."""
return self._percentage
@property
def preset_mode(self) -> Optional[str]:
def preset_mode(self) -> str | None:
"""Return the current preset mode."""
return self._preset_mode
@ -205,11 +206,11 @@ class FanGroup(BaseFan, ZhaGroupEntity):
async def async_update(self):
"""Attempt to retrieve on off state from the fan."""
all_states = [self.hass.states.get(x) for x in self._entity_ids]
states: List[State] = list(filter(None, all_states))
percentage_states: List[State] = [
states: list[State] = list(filter(None, all_states))
percentage_states: list[State] = [
state for state in states if state.attributes.get(ATTR_PERCENTAGE)
]
preset_mode_states: List[State] = [
preset_mode_states: list[State] = [
state for state in states if state.attributes.get(ATTR_PRESET_MODE)
]
self._available = any(state.state != STATE_UNAVAILABLE for state in states)

View File

@ -1,4 +1,6 @@
"""Lights on Zigbee Home Automation networks."""
from __future__ import annotations
from collections import Counter
from datetime import timedelta
import enum
@ -6,7 +8,7 @@ import functools
import itertools
import logging
import random
from typing import Any, Dict, List, Optional, Tuple
from typing import Any
from zigpy.zcl.clusters.general import Identify, LevelControl, OnOff
from zigpy.zcl.clusters.lighting import Color
@ -122,15 +124,15 @@ class BaseLight(LogMixin, light.LightEntity):
"""Initialize the light."""
super().__init__(*args, **kwargs)
self._available: bool = False
self._brightness: Optional[int] = None
self._off_brightness: Optional[int] = None
self._hs_color: Optional[Tuple[float, float]] = None
self._color_temp: Optional[int] = None
self._min_mireds: Optional[int] = 153
self._max_mireds: Optional[int] = 500
self._white_value: Optional[int] = None
self._effect_list: Optional[List[str]] = None
self._effect: Optional[str] = None
self._brightness: int | None = None
self._off_brightness: int | None = None
self._hs_color: tuple[float, float] | None = None
self._color_temp: int | None = None
self._min_mireds: int | None = 153
self._max_mireds: int | None = 500
self._white_value: int | None = None
self._effect_list: list[str] | None = None
self._effect: str | None = None
self._supported_features: int = 0
self._state: bool = False
self._on_off_channel = None
@ -139,7 +141,7 @@ class BaseLight(LogMixin, light.LightEntity):
self._identify_channel = None
@property
def extra_state_attributes(self) -> Dict[str, Any]:
def extra_state_attributes(self) -> dict[str, Any]:
"""Return state attributes."""
attributes = {"off_brightness": self._off_brightness}
return attributes
@ -348,8 +350,8 @@ class Light(BaseLight, ZhaEntity):
self._color_channel = self.cluster_channels.get(CHANNEL_COLOR)
self._identify_channel = self.zha_device.channels.identify_ch
if self._color_channel:
self._min_mireds: Optional[int] = self._color_channel.min_mireds
self._max_mireds: Optional[int] = self._color_channel.max_mireds
self._min_mireds: int | None = self._color_channel.min_mireds
self._max_mireds: int | None = self._color_channel.max_mireds
self._cancel_refresh_handle = None
effect_list = []
@ -532,7 +534,7 @@ class LightGroup(BaseLight, ZhaGroupEntity):
"""Representation of a light group."""
def __init__(
self, entity_ids: List[str], unique_id: str, group_id: int, zha_device, **kwargs
self, entity_ids: list[str], unique_id: str, group_id: int, zha_device, **kwargs
) -> None:
"""Initialize a light group."""
super().__init__(entity_ids, unique_id, group_id, zha_device, **kwargs)
@ -569,7 +571,7 @@ class LightGroup(BaseLight, ZhaGroupEntity):
async def async_update(self) -> None:
"""Query all members and determine the light group state."""
all_states = [self.hass.states.get(x) for x in self._entity_ids]
states: List[State] = list(filter(None, all_states))
states: list[State] = list(filter(None, all_states))
on_states = [state for state in states if state.state == STATE_ON]
self._state = len(on_states) > 0

View File

@ -1,7 +1,9 @@
"""Sensors on Zigbee Home Automation networks."""
from __future__ import annotations
import functools
import numbers
from typing import Any, Callable, Dict, List, Optional, Union
from typing import Any, Callable
from homeassistant.components.sensor import (
DEVICE_CLASS_BATTERY,
@ -90,18 +92,18 @@ async def async_setup_entry(
class Sensor(ZhaEntity):
"""Base ZHA sensor."""
SENSOR_ATTR: Optional[Union[int, str]] = None
SENSOR_ATTR: int | str | None = None
_decimals: int = 1
_device_class: Optional[str] = None
_device_class: str | None = None
_divisor: int = 1
_multiplier: int = 1
_unit: Optional[str] = None
_unit: str | None = None
def __init__(
self,
unique_id: str,
zha_device: ZhaDeviceType,
channels: List[ChannelType],
channels: list[ChannelType],
**kwargs,
):
"""Init this sensor."""
@ -121,7 +123,7 @@ class Sensor(ZhaEntity):
return self._device_class
@property
def unit_of_measurement(self) -> Optional[str]:
def unit_of_measurement(self) -> str | None:
"""Return the unit of measurement of this entity."""
return self._unit
@ -139,7 +141,7 @@ class Sensor(ZhaEntity):
"""Handle state update from channel."""
self.async_write_ha_state()
def formatter(self, value: int) -> Union[int, float]:
def formatter(self, value: int) -> int | float:
"""Numeric pass-through formatter."""
if self._decimals > 0:
return round(
@ -178,7 +180,7 @@ class Battery(Sensor):
return value
@property
def extra_state_attributes(self) -> Dict[str, Any]:
def extra_state_attributes(self) -> dict[str, Any]:
"""Return device state attrs for battery sensors."""
state_attrs = {}
battery_size = self._channel.cluster.get("battery_size")
@ -208,7 +210,7 @@ class ElectricalMeasurement(Sensor):
"""Return True if HA needs to poll for state changes."""
return True
def formatter(self, value: int) -> Union[int, float]:
def formatter(self, value: int) -> int | float:
"""Return 'normalized' value."""
value = value * self._channel.multiplier / self._channel.divisor
if value < 100 and self._channel.divisor > 1:
@ -254,7 +256,7 @@ class SmartEnergyMetering(Sensor):
SENSOR_ATTR = "instantaneous_demand"
_device_class = DEVICE_CLASS_POWER
def formatter(self, value: int) -> Union[int, float]:
def formatter(self, value: int) -> int | float:
"""Pass through channel formatter."""
return self._channel.formatter_function(value)

View File

@ -1,6 +1,8 @@
"""Switches on Zigbee Home Automation networks."""
from __future__ import annotations
import functools
from typing import Any, List
from typing import Any
from zigpy.zcl.clusters.general import OnOff
from zigpy.zcl.foundation import Status
@ -113,7 +115,7 @@ class SwitchGroup(BaseSwitch, ZhaGroupEntity):
"""Representation of a switch group."""
def __init__(
self, entity_ids: List[str], unique_id: str, group_id: int, zha_device, **kwargs
self, entity_ids: list[str], unique_id: str, group_id: int, zha_device, **kwargs
) -> None:
"""Initialize a switch group."""
super().__init__(entity_ids, unique_id, group_id, zha_device, **kwargs)
@ -124,7 +126,7 @@ class SwitchGroup(BaseSwitch, ZhaGroupEntity):
async def async_update(self) -> None:
"""Query all members and determine the light group state."""
all_states = [self.hass.states.get(x) for x in self._entity_ids]
states: List[State] = list(filter(None, all_states))
states: list[State] = list(filter(None, all_states))
on_states = [state for state in states if state.state == STATE_ON]
self._state = len(on_states) > 0

View File

@ -2,7 +2,7 @@
from __future__ import annotations
import logging
from typing import Any, Dict, Optional, cast
from typing import Any, Dict, cast
import voluptuous as vol
@ -92,7 +92,7 @@ STORAGE_VERSION = 1
@bind_hass
def async_active_zone(
hass: HomeAssistant, latitude: float, longitude: float, radius: int = 0
) -> Optional[State]:
) -> State | None:
"""Find the active zone for given latitude, longitude.
This method must be run in the event loop.
@ -161,22 +161,22 @@ class ZoneStorageCollection(collection.StorageCollection):
CREATE_SCHEMA = vol.Schema(CREATE_FIELDS)
UPDATE_SCHEMA = vol.Schema(UPDATE_FIELDS)
async def _process_create_data(self, data: Dict) -> Dict:
async def _process_create_data(self, data: dict) -> dict:
"""Validate the config is valid."""
return cast(Dict, self.CREATE_SCHEMA(data))
@callback
def _get_suggested_id(self, info: Dict) -> str:
def _get_suggested_id(self, info: dict) -> str:
"""Suggest an ID based on the config."""
return cast(str, info[CONF_NAME])
async def _update_data(self, data: dict, update_data: Dict) -> Dict:
async def _update_data(self, data: dict, update_data: dict) -> dict:
"""Return a new updated data object."""
update_data = self.UPDATE_SCHEMA(update_data)
return {**data, **update_data}
async def async_setup(hass: HomeAssistant, config: Dict) -> bool:
async def async_setup(hass: HomeAssistant, config: dict) -> bool:
"""Set up configured zones as well as Home Assistant zone if necessary."""
component = entity_component.EntityComponent(_LOGGER, DOMAIN, hass)
id_manager = collection.IDManager()
@ -240,7 +240,7 @@ async def async_setup(hass: HomeAssistant, config: Dict) -> bool:
@callback
def _home_conf(hass: HomeAssistant) -> Dict:
def _home_conf(hass: HomeAssistant) -> dict:
"""Return the home zone config."""
return {
CONF_NAME: hass.config.location_name,
@ -279,15 +279,15 @@ async def async_unload_entry(
class Zone(entity.Entity):
"""Representation of a Zone."""
def __init__(self, config: Dict):
def __init__(self, config: dict):
"""Initialize the zone."""
self._config = config
self.editable = True
self._attrs: Optional[Dict] = None
self._attrs: dict | None = None
self._generate_attrs()
@classmethod
def from_yaml(cls, config: Dict) -> Zone:
def from_yaml(cls, config: dict) -> Zone:
"""Return entity instance initialized from yaml storage."""
zone = cls(config)
zone.editable = False
@ -305,17 +305,17 @@ class Zone(entity.Entity):
return cast(str, self._config[CONF_NAME])
@property
def unique_id(self) -> Optional[str]:
def unique_id(self) -> str | None:
"""Return unique ID."""
return self._config.get(CONF_ID)
@property
def icon(self) -> Optional[str]:
def icon(self) -> str | None:
"""Return the icon if any."""
return self._config.get(CONF_ICON)
@property
def state_attributes(self) -> Optional[Dict]:
def state_attributes(self) -> dict | None:
"""Return the state attributes of the zone."""
return self._attrs
@ -324,7 +324,7 @@ class Zone(entity.Entity):
"""Zone does not poll."""
return False
async def async_update_config(self, config: Dict) -> None:
async def async_update_config(self, config: dict) -> None:
"""Handle when the config is updated."""
if self._config == config:
return

View File

@ -1,7 +1,8 @@
"""Support for Z-Wave climate devices."""
# Because we do not compile openzwave on CI
from __future__ import annotations
import logging
from typing import Optional, Tuple
from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
@ -191,7 +192,7 @@ class ZWaveClimateBase(ZWaveDeviceEntity, ClimateEntity):
"""Return thermostat mode Z-Wave value."""
raise NotImplementedError()
def _current_mode_setpoints(self) -> Tuple:
def _current_mode_setpoints(self) -> tuple:
"""Return a tuple of current setpoint Z-Wave value(s)."""
raise NotImplementedError()
@ -483,12 +484,12 @@ class ZWaveClimateBase(ZWaveDeviceEntity, ClimateEntity):
return self._target_temperature
@property
def target_temperature_low(self) -> Optional[float]:
def target_temperature_low(self) -> float | None:
"""Return the lowbound target temperature we try to reach."""
return self._target_temperature_range[0]
@property
def target_temperature_high(self) -> Optional[float]:
def target_temperature_high(self) -> float | None:
"""Return the highbound target temperature we try to reach."""
return self._target_temperature_range[1]
@ -590,7 +591,7 @@ class ZWaveClimateSingleSetpoint(ZWaveClimateBase):
"""Return thermostat mode Z-Wave value."""
return self.values.mode
def _current_mode_setpoints(self) -> Tuple:
def _current_mode_setpoints(self) -> tuple:
"""Return a tuple of current setpoint Z-Wave value(s)."""
return (self.values.primary,)
@ -606,7 +607,7 @@ class ZWaveClimateMultipleSetpoint(ZWaveClimateBase):
"""Return thermostat mode Z-Wave value."""
return self.values.primary
def _current_mode_setpoints(self) -> Tuple:
def _current_mode_setpoints(self) -> tuple:
"""Return a tuple of current setpoint Z-Wave value(s)."""
current_mode = str(self.values.primary.data).lower()
setpoints_names = MODE_SETPOINT_MAPPINGS.get(current_mode, ())

View File

@ -1,6 +1,8 @@
"""The Z-Wave JS integration."""
from __future__ import annotations
import asyncio
from typing import Callable, List
from typing import Callable
from async_timeout import timeout
from zwave_js_server.client import Client as ZwaveClient
@ -226,7 +228,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry_hass_data[DATA_CONNECT_FAILED_LOGGED] = False
entry_hass_data[DATA_INVALID_SERVER_VERSION_LOGGED] = False
unsubscribe_callbacks: List[Callable] = []
unsubscribe_callbacks: list[Callable] = []
entry_hass_data[DATA_CLIENT] = client
entry_hass_data[DATA_UNSUBSCRIBE] = unsubscribe_callbacks

View File

@ -3,7 +3,7 @@ from __future__ import annotations
import asyncio
from functools import partial
from typing import Any, Callable, Optional, TypeVar, cast
from typing import Any, Callable, TypeVar, cast
from homeassistant.components.hassio import (
async_create_snapshot,
@ -66,9 +66,9 @@ class AddonManager:
def __init__(self, hass: HomeAssistant) -> None:
"""Set up the add-on manager."""
self._hass = hass
self._install_task: Optional[asyncio.Task] = None
self._start_task: Optional[asyncio.Task] = None
self._update_task: Optional[asyncio.Task] = None
self._install_task: asyncio.Task | None = None
self._start_task: asyncio.Task | None = None
self._update_task: asyncio.Task | None = None
def task_in_progress(self) -> bool:
"""Return True if any of the add-on tasks are in progress."""

View File

@ -1,7 +1,8 @@
"""Websocket API for Z-Wave JS."""
from __future__ import annotations
import dataclasses
import json
from typing import Dict
from aiohttp import hdrs, web, web_exceptions
import voluptuous as vol
@ -399,7 +400,7 @@ def convert_log_level_to_enum(value: str) -> LogLevel:
return LogLevel[value.upper()]
def filename_is_present_if_logging_to_file(obj: Dict) -> Dict:
def filename_is_present_if_logging_to_file(obj: dict) -> dict:
"""Validate that filename is provided if log_to_file is True."""
if obj.get(LOG_TO_FILE, False) and FILENAME not in obj:
raise vol.Invalid("`filename` must be provided if logging to file")

View File

@ -1,7 +1,8 @@
"""Representation of Z-Wave binary sensors."""
from __future__ import annotations
import logging
from typing import Callable, List, Optional, TypedDict
from typing import Callable, TypedDict
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import CommandClass
@ -56,14 +57,14 @@ class NotificationSensorMapping(TypedDict, total=False):
"""Represent a notification sensor mapping dict type."""
type: int # required
states: List[str]
states: list[str]
device_class: str
enabled: bool
# Mappings for Notification sensors
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/config/config/notifications.json
NOTIFICATION_SENSOR_MAPPINGS: List[NotificationSensorMapping] = [
NOTIFICATION_SENSOR_MAPPINGS: list[NotificationSensorMapping] = [
{
# NotificationType 1: Smoke Alarm - State Id's 1 and 2 - Smoke detected
"type": NOTIFICATION_SMOKE_ALARM,
@ -201,13 +202,13 @@ class PropertySensorMapping(TypedDict, total=False):
"""Represent a property sensor mapping dict type."""
property_name: str # required
on_states: List[str] # required
on_states: list[str] # required
device_class: str
enabled: bool
# Mappings for property sensors
PROPERTY_SENSOR_MAPPINGS: List[PropertySensorMapping] = [
PROPERTY_SENSOR_MAPPINGS: list[PropertySensorMapping] = [
{
"property_name": PROPERTY_DOOR_STATUS,
"on_states": ["open"],
@ -226,7 +227,7 @@ async def async_setup_entry(
@callback
def async_add_binary_sensor(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Binary Sensor."""
entities: List[BinarySensorEntity] = []
entities: list[BinarySensorEntity] = []
if info.platform_hint == "notification":
# Get all sensors from Notification CC states
@ -268,14 +269,14 @@ class ZWaveBooleanBinarySensor(ZWaveBaseEntity, BinarySensorEntity):
self._name = self.generate_name(include_value_name=True)
@property
def is_on(self) -> Optional[bool]:
def is_on(self) -> bool | None:
"""Return if the sensor is on or off."""
if self.info.primary_value.value is None:
return None
return bool(self.info.primary_value.value)
@property
def device_class(self) -> Optional[str]:
def device_class(self) -> str | None:
"""Return device class."""
if self.info.primary_value.command_class == CommandClass.BATTERY:
return DEVICE_CLASS_BATTERY
@ -314,14 +315,14 @@ class ZWaveNotificationBinarySensor(ZWaveBaseEntity, BinarySensorEntity):
self._mapping_info = self._get_sensor_mapping()
@property
def is_on(self) -> Optional[bool]:
def is_on(self) -> bool | None:
"""Return if the sensor is on or off."""
if self.info.primary_value.value is None:
return None
return int(self.info.primary_value.value) == int(self.state_key)
@property
def device_class(self) -> Optional[str]:
def device_class(self) -> str | None:
"""Return device class."""
return self._mapping_info.get("device_class")
@ -365,14 +366,14 @@ class ZWavePropertyBinarySensor(ZWaveBaseEntity, BinarySensorEntity):
self._name = self.generate_name(include_value_name=True)
@property
def is_on(self) -> Optional[bool]:
def is_on(self) -> bool | None:
"""Return if the sensor is on or off."""
if self.info.primary_value.value is None:
return None
return self.info.primary_value.value in self._mapping_info["on_states"]
@property
def device_class(self) -> Optional[str]:
def device_class(self) -> str | None:
"""Return device class."""
return self._mapping_info.get("device_class")

View File

@ -1,5 +1,7 @@
"""Representation of Z-Wave thermostats."""
from typing import Any, Callable, Dict, List, Optional, cast
from __future__ import annotations
from typing import Any, Callable, cast
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import (
@ -50,7 +52,7 @@ from .entity import ZWaveBaseEntity
# Map Z-Wave HVAC Mode to Home Assistant value
# Note: We treat "auto" as "heat_cool" as most Z-Wave devices
# report auto_changeover as auto without schedule support.
ZW_HVAC_MODE_MAP: Dict[int, str] = {
ZW_HVAC_MODE_MAP: dict[int, str] = {
ThermostatMode.OFF: HVAC_MODE_OFF,
ThermostatMode.HEAT: HVAC_MODE_HEAT,
ThermostatMode.COOL: HVAC_MODE_COOL,
@ -67,7 +69,7 @@ ZW_HVAC_MODE_MAP: Dict[int, str] = {
ThermostatMode.FULL_POWER: HVAC_MODE_HEAT,
}
HVAC_CURRENT_MAP: Dict[int, str] = {
HVAC_CURRENT_MAP: dict[int, str] = {
ThermostatOperatingState.IDLE: CURRENT_HVAC_IDLE,
ThermostatOperatingState.PENDING_HEAT: CURRENT_HVAC_IDLE,
ThermostatOperatingState.HEATING: CURRENT_HVAC_HEAT,
@ -94,7 +96,7 @@ async def async_setup_entry(
@callback
def async_add_climate(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Climate."""
entities: List[ZWaveBaseEntity] = []
entities: list[ZWaveBaseEntity] = []
entities.append(ZWaveClimate(config_entry, client, info))
async_add_entities(entities)
@ -116,14 +118,14 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
) -> None:
"""Initialize lock."""
super().__init__(config_entry, client, info)
self._hvac_modes: Dict[str, Optional[int]] = {}
self._hvac_presets: Dict[str, Optional[int]] = {}
self._unit_value: Optional[ZwaveValue] = None
self._hvac_modes: dict[str, int | None] = {}
self._hvac_presets: dict[str, int | None] = {}
self._unit_value: ZwaveValue | None = None
self._current_mode = self.get_zwave_value(
THERMOSTAT_MODE_PROPERTY, command_class=CommandClass.THERMOSTAT_MODE
)
self._setpoint_values: Dict[ThermostatSetpointType, ZwaveValue] = {}
self._setpoint_values: dict[ThermostatSetpointType, ZwaveValue] = {}
for enum in ThermostatSetpointType:
self._setpoint_values[enum] = self.get_zwave_value(
THERMOSTAT_SETPOINT_PROPERTY,
@ -184,8 +186,8 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
def _set_modes_and_presets(self) -> None:
"""Convert Z-Wave Thermostat modes into Home Assistant modes and presets."""
all_modes: Dict[str, Optional[int]] = {}
all_presets: Dict[str, Optional[int]] = {PRESET_NONE: None}
all_modes: dict[str, int | None] = {}
all_presets: dict[str, int | None] = {PRESET_NONE: None}
# Z-Wave uses one list for both modes and presets.
# Iterate over all Z-Wave ThermostatModes and extract the hvac modes and presets.
@ -208,7 +210,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
self._hvac_presets = all_presets
@property
def _current_mode_setpoint_enums(self) -> List[Optional[ThermostatSetpointType]]:
def _current_mode_setpoint_enums(self) -> list[ThermostatSetpointType | None]:
"""Return the list of enums that are relevant to the current thermostat mode."""
if self._current_mode is None:
# Thermostat(valve) with no support for setting a mode is considered heating-only
@ -238,12 +240,12 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
return ZW_HVAC_MODE_MAP.get(int(self._current_mode.value), HVAC_MODE_HEAT_COOL)
@property
def hvac_modes(self) -> List[str]:
def hvac_modes(self) -> list[str]:
"""Return the list of available hvac operation modes."""
return list(self._hvac_modes)
@property
def hvac_action(self) -> Optional[str]:
def hvac_action(self) -> str | None:
"""Return the current running hvac operation if supported."""
if not self._operating_state:
return None
@ -253,17 +255,17 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
return HVAC_CURRENT_MAP.get(int(self._operating_state.value))
@property
def current_humidity(self) -> Optional[int]:
def current_humidity(self) -> int | None:
"""Return the current humidity level."""
return self._current_humidity.value if self._current_humidity else None
@property
def current_temperature(self) -> Optional[float]:
def current_temperature(self) -> float | None:
"""Return the current temperature."""
return self._current_temp.value if self._current_temp else None
@property
def target_temperature(self) -> Optional[float]:
def target_temperature(self) -> float | None:
"""Return the temperature we try to reach."""
if self._current_mode and self._current_mode.value is None:
# guard missing value
@ -275,7 +277,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
return temp.value if temp else None
@property
def target_temperature_high(self) -> Optional[float]:
def target_temperature_high(self) -> float | None:
"""Return the highbound target temperature we try to reach."""
if self._current_mode and self._current_mode.value is None:
# guard missing value
@ -287,7 +289,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
return temp.value if temp else None
@property
def target_temperature_low(self) -> Optional[float]:
def target_temperature_low(self) -> float | None:
"""Return the lowbound target temperature we try to reach."""
if self._current_mode and self._current_mode.value is None:
# guard missing value
@ -297,7 +299,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
return None
@property
def preset_mode(self) -> Optional[str]:
def preset_mode(self) -> str | None:
"""Return the current preset mode, e.g., home, away, temp."""
if self._current_mode and self._current_mode.value is None:
# guard missing value
@ -310,12 +312,12 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
return PRESET_NONE
@property
def preset_modes(self) -> Optional[List[str]]:
def preset_modes(self) -> list[str] | None:
"""Return a list of available preset modes."""
return list(self._hvac_presets)
@property
def fan_mode(self) -> Optional[str]:
def fan_mode(self) -> str | None:
"""Return the fan setting."""
if (
self._fan_mode
@ -326,14 +328,14 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
return None
@property
def fan_modes(self) -> Optional[List[str]]:
def fan_modes(self) -> list[str] | None:
"""Return the list of available fan modes."""
if self._fan_mode and self._fan_mode.metadata.states:
return list(self._fan_mode.metadata.states.values())
return None
@property
def extra_state_attributes(self) -> Optional[Dict[str, str]]:
def extra_state_attributes(self) -> dict[str, str] | None:
"""Return the optional state attributes."""
if (
self._fan_state
@ -373,7 +375,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
hvac_mode: Optional[str] = kwargs.get(ATTR_HVAC_MODE)
hvac_mode: str | None = kwargs.get(ATTR_HVAC_MODE)
if hvac_mode is not None:
await self.async_set_hvac_mode(hvac_mode)
@ -381,7 +383,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
setpoint: ZwaveValue = self._setpoint_value(
self._current_mode_setpoint_enums[0]
)
target_temp: Optional[float] = kwargs.get(ATTR_TEMPERATURE)
target_temp: float | None = kwargs.get(ATTR_TEMPERATURE)
if target_temp is not None:
await self.info.node.async_set_value(setpoint, target_temp)
elif len(self._current_mode_setpoint_enums) == 2:
@ -391,8 +393,8 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
setpoint_high: ZwaveValue = self._setpoint_value(
self._current_mode_setpoint_enums[1]
)
target_temp_low: Optional[float] = kwargs.get(ATTR_TARGET_TEMP_LOW)
target_temp_high: Optional[float] = kwargs.get(ATTR_TARGET_TEMP_HIGH)
target_temp_low: float | None = kwargs.get(ATTR_TARGET_TEMP_LOW)
target_temp_high: float | None = kwargs.get(ATTR_TARGET_TEMP_HIGH)
if target_temp_low is not None:
await self.info.node.async_set_value(setpoint_low, target_temp_low)
if target_temp_high is not None:

View File

@ -1,7 +1,9 @@
"""Config flow for Z-Wave JS integration."""
from __future__ import annotations
import asyncio
import logging
from typing import Any, Dict, Optional, cast
from typing import Any, cast
import aiohttp
from async_timeout import timeout
@ -76,18 +78,18 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
def __init__(self) -> None:
"""Set up flow instance."""
self.network_key: Optional[str] = None
self.usb_path: Optional[str] = None
self.network_key: str | None = None
self.usb_path: str | None = None
self.use_addon = False
self.ws_address: Optional[str] = None
self.ws_address: str | None = None
# If we install the add-on we should uninstall it on entry remove.
self.integration_created_addon = False
self.install_task: Optional[asyncio.Task] = None
self.start_task: Optional[asyncio.Task] = None
self.install_task: asyncio.Task | None = None
self.start_task: asyncio.Task | None = None
async def async_step_user(
self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Handle the initial step."""
if is_hassio(self.hass): # type: ignore # no-untyped-call
return await self.async_step_on_supervisor()
@ -95,8 +97,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return await self.async_step_manual()
async def async_step_manual(
self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Handle a manual configuration."""
if user_input is None:
return self.async_show_form(
@ -133,8 +135,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
)
async def async_step_hassio( # type: ignore # override
self, discovery_info: Dict[str, Any]
) -> Dict[str, Any]:
self, discovery_info: dict[str, Any]
) -> dict[str, Any]:
"""Receive configuration from add-on discovery info.
This flow is triggered by the Z-Wave JS add-on.
@ -151,8 +153,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return await self.async_step_hassio_confirm()
async def async_step_hassio_confirm(
self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Confirm the add-on discovery."""
if user_input is not None:
return await self.async_step_on_supervisor(
@ -162,7 +164,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_show_form(step_id="hassio_confirm")
@callback
def _async_create_entry_from_vars(self) -> Dict[str, Any]:
def _async_create_entry_from_vars(self) -> dict[str, Any]:
"""Return a config entry for the flow."""
return self.async_create_entry(
title=TITLE,
@ -176,8 +178,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
)
async def async_step_on_supervisor(
self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Handle logic when on Supervisor host."""
if user_input is None:
return self.async_show_form(
@ -200,8 +202,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return await self.async_step_install_addon()
async def async_step_install_addon(
self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Install Z-Wave JS add-on."""
if not self.install_task:
self.install_task = self.hass.async_create_task(self._async_install_addon())
@ -220,18 +222,18 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_show_progress_done(next_step_id="configure_addon")
async def async_step_install_failed(
self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Add-on installation failed."""
return self.async_abort(reason="addon_install_failed")
async def async_step_configure_addon(
self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Ask for config for Z-Wave JS add-on."""
addon_config = await self._async_get_addon_config()
errors: Dict[str, str] = {}
errors: dict[str, str] = {}
if user_input is not None:
self.network_key = user_input[CONF_NETWORK_KEY]
@ -262,8 +264,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
)
async def async_step_start_addon(
self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Start Z-Wave JS add-on."""
if not self.start_task:
self.start_task = self.hass.async_create_task(self._async_start_addon())
@ -280,8 +282,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_show_progress_done(next_step_id="finish_addon_setup")
async def async_step_start_failed(
self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Add-on start failed."""
return self.async_abort(reason="addon_start_failed")
@ -317,8 +319,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
)
async def async_step_finish_addon_setup(
self, user_input: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
self, user_input: dict[str, Any] | None = None
) -> dict[str, Any]:
"""Prepare info needed to complete the config entry.
Get add-on discovery info and server version info.

View File

@ -1,6 +1,8 @@
"""Support for Z-Wave cover devices."""
from __future__ import annotations
import logging
from typing import Any, Callable, List, Optional
from typing import Any, Callable
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.model.value import Value as ZwaveValue
@ -42,7 +44,7 @@ async def async_setup_entry(
@callback
def async_add_cover(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave cover."""
entities: List[ZWaveBaseEntity] = []
entities: list[ZWaveBaseEntity] = []
if info.platform_hint == "motorized_barrier":
entities.append(ZwaveMotorizedBarrier(config_entry, client, info))
else:
@ -72,7 +74,7 @@ class ZWaveCover(ZWaveBaseEntity, CoverEntity):
"""Representation of a Z-Wave Cover device."""
@property
def is_closed(self) -> Optional[bool]:
def is_closed(self) -> bool | None:
"""Return true if cover is closed."""
if self.info.primary_value.value is None:
# guard missing value
@ -80,7 +82,7 @@ class ZWaveCover(ZWaveBaseEntity, CoverEntity):
return bool(self.info.primary_value.value == 0)
@property
def current_cover_position(self) -> Optional[int]:
def current_cover_position(self) -> int | None:
"""Return the current position of cover where 0 means closed and 100 is fully open."""
if self.info.primary_value.value is None:
# guard missing value
@ -130,31 +132,31 @@ class ZwaveMotorizedBarrier(ZWaveBaseEntity, CoverEntity):
)
@property
def supported_features(self) -> Optional[int]:
def supported_features(self) -> int | None:
"""Flag supported features."""
return SUPPORT_OPEN | SUPPORT_CLOSE
@property
def device_class(self) -> Optional[str]:
def device_class(self) -> str | None:
"""Return the class of this device, from component DEVICE_CLASSES."""
return DEVICE_CLASS_GARAGE
@property
def is_opening(self) -> Optional[bool]:
def is_opening(self) -> bool | None:
"""Return if the cover is opening or not."""
if self.info.primary_value.value is None:
return None
return bool(self.info.primary_value.value == BARRIER_STATE_OPENING)
@property
def is_closing(self) -> Optional[bool]:
def is_closing(self) -> bool | None:
"""Return if the cover is closing or not."""
if self.info.primary_value.value is None:
return None
return bool(self.info.primary_value.value == BARRIER_STATE_CLOSING)
@property
def is_closed(self) -> Optional[bool]:
def is_closed(self) -> bool | None:
"""Return if the cover is closed or not."""
if self.info.primary_value.value is None:
return None

View File

@ -1,7 +1,8 @@
"""Map Z-Wave nodes and values to Home Assistant entities."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Generator, List, Optional, Set, Union
from typing import Generator
from zwave_js_server.const import CommandClass
from zwave_js_server.model.device_class import DeviceClassItem
@ -22,7 +23,7 @@ class ZwaveDiscoveryInfo:
# the home assistant platform for which an entity should be created
platform: str
# hint for the platform about this discovered entity
platform_hint: Optional[str] = ""
platform_hint: str | None = ""
@dataclass
@ -35,13 +36,13 @@ class ZWaveValueDiscoverySchema:
"""
# [optional] the value's command class must match ANY of these values
command_class: Optional[Set[int]] = None
command_class: set[int] | None = None
# [optional] the value's endpoint must match ANY of these values
endpoint: Optional[Set[int]] = None
endpoint: set[int] | None = None
# [optional] the value's property must match ANY of these values
property: Optional[Set[Union[str, int]]] = None
property: set[str | int] | None = None
# [optional] the value's metadata_type must match ANY of these values
type: Optional[Set[str]] = None
type: set[str] | None = None
@dataclass
@ -58,25 +59,25 @@ class ZWaveDiscoverySchema:
# primary value belonging to this discovery scheme
primary_value: ZWaveValueDiscoverySchema
# [optional] hint for platform
hint: Optional[str] = None
hint: str | None = None
# [optional] the node's manufacturer_id must match ANY of these values
manufacturer_id: Optional[Set[int]] = None
manufacturer_id: set[int] | None = None
# [optional] the node's product_id must match ANY of these values
product_id: Optional[Set[int]] = None
product_id: set[int] | None = None
# [optional] the node's product_type must match ANY of these values
product_type: Optional[Set[int]] = None
product_type: set[int] | None = None
# [optional] the node's firmware_version must match ANY of these values
firmware_version: Optional[Set[str]] = None
firmware_version: set[str] | None = None
# [optional] the node's basic device class must match ANY of these values
device_class_basic: Optional[Set[Union[str, int]]] = None
device_class_basic: set[str | int] | None = None
# [optional] the node's generic device class must match ANY of these values
device_class_generic: Optional[Set[Union[str, int]]] = None
device_class_generic: set[str | int] | None = None
# [optional] the node's specific device class must match ANY of these values
device_class_specific: Optional[Set[Union[str, int]]] = None
device_class_specific: set[str | int] | None = None
# [optional] additional values that ALL need to be present on the node for this scheme to pass
required_values: Optional[List[ZWaveValueDiscoverySchema]] = None
required_values: list[ZWaveValueDiscoverySchema] | None = None
# [optional] additional values that MAY NOT be present on the node for this scheme to pass
absent_values: Optional[List[ZWaveValueDiscoverySchema]] = None
absent_values: list[ZWaveValueDiscoverySchema] | None = None
# [optional] bool to specify if this primary value may be discovered by multiple platforms
allow_multi: bool = False
@ -487,7 +488,7 @@ def check_value(value: ZwaveValue, schema: ZWaveValueDiscoverySchema) -> bool:
@callback
def check_device_class(
device_class: DeviceClassItem, required_value: Optional[Set[Union[str, int]]]
device_class: DeviceClassItem, required_value: set[str | int] | None
) -> bool:
"""Check if device class id or label matches."""
if required_value is None:

View File

@ -1,7 +1,7 @@
"""Generic Z-Wave Entity Class."""
from __future__ import annotations
import logging
from typing import List, Optional, Union
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.model.value import Value as ZwaveValue, get_value_id
@ -97,8 +97,8 @@ class ZWaveBaseEntity(Entity):
def generate_name(
self,
include_value_name: bool = False,
alternate_value_name: Optional[str] = None,
additional_info: Optional[List[str]] = None,
alternate_value_name: str | None = None,
additional_info: list[str] | None = None,
) -> str:
"""Generate entity name."""
if additional_info is None:
@ -167,13 +167,13 @@ class ZWaveBaseEntity(Entity):
@callback
def get_zwave_value(
self,
value_property: Union[str, int],
command_class: Optional[int] = None,
endpoint: Optional[int] = None,
value_property_key: Optional[int] = None,
value_property: str | int,
command_class: int | None = None,
endpoint: int | None = None,
value_property_key: int | None = None,
add_to_watched_value_ids: bool = True,
check_all_endpoints: bool = False,
) -> Optional[ZwaveValue]:
) -> ZwaveValue | None:
"""Return specific ZwaveValue on this ZwaveNode."""
# use commandclass and endpoint from primary value if omitted
return_value = None

View File

@ -1,6 +1,8 @@
"""Support for Z-Wave fans."""
from __future__ import annotations
import math
from typing import Any, Callable, List, Optional
from typing import Any, Callable
from zwave_js_server.client import Client as ZwaveClient
@ -36,7 +38,7 @@ async def async_setup_entry(
@callback
def async_add_fan(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave fan."""
entities: List[ZWaveBaseEntity] = []
entities: list[ZWaveBaseEntity] = []
entities.append(ZwaveFan(config_entry, client, info))
async_add_entities(entities)
@ -52,7 +54,7 @@ async def async_setup_entry(
class ZwaveFan(ZWaveBaseEntity, FanEntity):
"""Representation of a Z-Wave fan."""
async def async_set_percentage(self, percentage: Optional[int]) -> None:
async def async_set_percentage(self, percentage: int | None) -> None:
"""Set the speed percentage of the fan."""
target_value = self.get_zwave_value("targetValue")
@ -68,9 +70,9 @@ class ZwaveFan(ZWaveBaseEntity, FanEntity):
async def async_turn_on(
self,
speed: Optional[str] = None,
percentage: Optional[int] = None,
preset_mode: Optional[str] = None,
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs: Any,
) -> None:
"""Turn the device on."""
@ -82,7 +84,7 @@ class ZwaveFan(ZWaveBaseEntity, FanEntity):
await self.info.node.async_set_value(target_value, 0)
@property
def is_on(self) -> Optional[bool]: # type: ignore
def is_on(self) -> bool | None: # type: ignore
"""Return true if device is on (speed above 0)."""
if self.info.primary_value.value is None:
# guard missing value
@ -90,7 +92,7 @@ class ZwaveFan(ZWaveBaseEntity, FanEntity):
return bool(self.info.primary_value.value > 0)
@property
def percentage(self) -> Optional[int]:
def percentage(self) -> int | None:
"""Return the current speed percentage."""
if self.info.primary_value.value is None:
# guard missing value

View File

@ -1,5 +1,7 @@
"""Helper functions for Z-Wave JS integration."""
from typing import List, Tuple, cast
from __future__ import annotations
from typing import cast
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.model.node import Node as ZwaveNode
@ -19,13 +21,13 @@ def get_unique_id(home_id: str, value_id: str) -> str:
@callback
def get_device_id(client: ZwaveClient, node: ZwaveNode) -> Tuple[str, str]:
def get_device_id(client: ZwaveClient, node: ZwaveNode) -> tuple[str, str]:
"""Get device registry identifier for Z-Wave node."""
return (DOMAIN, f"{client.driver.controller.home_id}-{node.node_id}")
@callback
def get_home_and_node_id_from_device_id(device_id: Tuple[str, str]) -> List[str]:
def get_home_and_node_id_from_device_id(device_id: tuple[str, str]) -> list[str]:
"""
Get home ID and node ID for Z-Wave device registry entry.

View File

@ -1,6 +1,8 @@
"""Support for Z-Wave lights."""
from __future__ import annotations
import logging
from typing import Any, Callable, Dict, Optional, Tuple
from typing import Any, Callable
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import ColorComponent, CommandClass
@ -85,9 +87,9 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity):
self._supports_color = False
self._supports_white_value = False
self._supports_color_temp = False
self._hs_color: Optional[Tuple[float, float]] = None
self._white_value: Optional[int] = None
self._color_temp: Optional[int] = None
self._hs_color: tuple[float, float] | None = None
self._white_value: int | None = None
self._color_temp: int | None = None
self._min_mireds = 153 # 6500K as a safe default
self._max_mireds = 370 # 2700K as a safe default
self._supported_features = SUPPORT_BRIGHTNESS
@ -126,17 +128,17 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity):
return self.brightness > 0
@property
def hs_color(self) -> Optional[Tuple[float, float]]:
def hs_color(self) -> tuple[float, float] | None:
"""Return the hs color."""
return self._hs_color
@property
def white_value(self) -> Optional[int]:
def white_value(self) -> int | None:
"""Return the white value of this light between 0..255."""
return self._white_value
@property
def color_temp(self) -> Optional[int]:
def color_temp(self) -> int | None:
"""Return the color temperature."""
return self._color_temp
@ -220,7 +222,7 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity):
"""Turn the light off."""
await self._async_set_brightness(0, kwargs.get(ATTR_TRANSITION))
async def _async_set_colors(self, colors: Dict[ColorComponent, int]) -> None:
async def _async_set_colors(self, colors: dict[ColorComponent, int]) -> None:
"""Set (multiple) defined colors to given value(s)."""
# prefer the (new) combined color property
# https://github.com/zwave-js/node-zwave-js/pull/1782
@ -258,7 +260,7 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity):
await self.info.node.async_set_value(target_zwave_value, new_value)
async def _async_set_brightness(
self, brightness: Optional[int], transition: Optional[int] = None
self, brightness: int | None, transition: int | None = None
) -> None:
"""Set new brightness to light."""
if brightness is None:
@ -273,9 +275,7 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity):
# setting a value requires setting targetValue
await self.info.node.async_set_value(self._target_value, zwave_brightness)
async def _async_set_transition_duration(
self, duration: Optional[int] = None
) -> None:
async def _async_set_transition_duration(self, duration: int | None = None) -> None:
"""Set the transition time for the brightness value."""
if self._dimming_duration is None:
return

View File

@ -1,6 +1,8 @@
"""Representation of Z-Wave locks."""
from __future__ import annotations
import logging
from typing import Any, Callable, Dict, List, Optional, Union
from typing import Any, Callable
import voluptuous as vol
from zwave_js_server.client import Client as ZwaveClient
@ -28,7 +30,7 @@ from .entity import ZWaveBaseEntity
LOGGER = logging.getLogger(__name__)
STATE_TO_ZWAVE_MAP: Dict[int, Dict[str, Union[int, bool]]] = {
STATE_TO_ZWAVE_MAP: dict[int, dict[str, int | bool]] = {
CommandClass.DOOR_LOCK: {
STATE_UNLOCKED: DoorLockMode.UNSECURED,
STATE_LOCKED: DoorLockMode.SECURED,
@ -52,7 +54,7 @@ async def async_setup_entry(
@callback
def async_add_lock(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Lock."""
entities: List[ZWaveBaseEntity] = []
entities: list[ZWaveBaseEntity] = []
entities.append(ZWaveLock(config_entry, client, info))
async_add_entities(entities)
@ -88,7 +90,7 @@ class ZWaveLock(ZWaveBaseEntity, LockEntity):
"""Representation of a Z-Wave lock."""
@property
def is_locked(self) -> Optional[bool]:
def is_locked(self) -> bool | None:
"""Return true if the lock is locked."""
if self.info.primary_value.value is None:
# guard missing value
@ -100,7 +102,7 @@ class ZWaveLock(ZWaveBaseEntity, LockEntity):
) == int(self.info.primary_value.value)
async def _set_lock_state(
self, target_state: str, **kwargs: Dict[str, Any]
self, target_state: str, **kwargs: dict[str, Any]
) -> None:
"""Set the lock state."""
target_value: ZwaveValue = self.get_zwave_value(
@ -112,11 +114,11 @@ class ZWaveLock(ZWaveBaseEntity, LockEntity):
STATE_TO_ZWAVE_MAP[self.info.primary_value.command_class][target_state],
)
async def async_lock(self, **kwargs: Dict[str, Any]) -> None:
async def async_lock(self, **kwargs: dict[str, Any]) -> None:
"""Lock the lock."""
await self._set_lock_state(STATE_LOCKED)
async def async_unlock(self, **kwargs: Dict[str, Any]) -> None:
async def async_unlock(self, **kwargs: dict[str, Any]) -> None:
"""Unlock the lock."""
await self._set_lock_state(STATE_UNLOCKED)

View File

@ -1,6 +1,7 @@
"""Functions used to migrate unique IDs for Z-Wave JS entities."""
from __future__ import annotations
import logging
from typing import List
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.model.value import Value as ZwaveValue
@ -85,7 +86,7 @@ def async_migrate_discovered_value(
@callback
def get_old_value_ids(value: ZwaveValue) -> List[str]:
def get_old_value_ids(value: ZwaveValue) -> list[str]:
"""Get old value IDs so we can migrate entity unique ID."""
value_ids = []

View File

@ -1,5 +1,7 @@
"""Support for Z-Wave controls using the number platform."""
from typing import Callable, List, Optional
from __future__ import annotations
from typing import Callable
from zwave_js_server.client import Client as ZwaveClient
@ -22,7 +24,7 @@ async def async_setup_entry(
@callback
def async_add_number(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave number entity."""
entities: List[ZWaveBaseEntity] = []
entities: list[ZWaveBaseEntity] = []
entities.append(ZwaveNumberEntity(config_entry, client, info))
async_add_entities(entities)
@ -66,14 +68,14 @@ class ZwaveNumberEntity(ZWaveBaseEntity, NumberEntity):
return float(self.info.primary_value.metadata.max)
@property
def value(self) -> Optional[float]: # type: ignore
def value(self) -> float | None: # type: ignore
"""Return the entity value."""
if self.info.primary_value.value is None:
return None
return float(self.info.primary_value.value)
@property
def unit_of_measurement(self) -> Optional[str]:
def unit_of_measurement(self) -> str | None:
"""Return the unit of measurement of this entity, if any."""
if self.info.primary_value.metadata.unit is None:
return None

View File

@ -1,7 +1,8 @@
"""Representation of Z-Wave sensors."""
from __future__ import annotations
import logging
from typing import Callable, Dict, List, Optional
from typing import Callable
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import CommandClass
@ -39,7 +40,7 @@ async def async_setup_entry(
@callback
def async_add_sensor(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Sensor."""
entities: List[ZWaveBaseEntity] = []
entities: list[ZWaveBaseEntity] = []
if info.platform_hint == "string_sensor":
entities.append(ZWaveStringSensor(config_entry, client, info))
@ -80,7 +81,7 @@ class ZwaveSensorBase(ZWaveBaseEntity):
self._name = self.generate_name(include_value_name=True)
@property
def device_class(self) -> Optional[str]:
def device_class(self) -> str | None:
"""Return the device class of the sensor."""
if self.info.primary_value.command_class == CommandClass.BATTERY:
return DEVICE_CLASS_BATTERY
@ -122,14 +123,14 @@ class ZWaveStringSensor(ZwaveSensorBase):
"""Representation of a Z-Wave String sensor."""
@property
def state(self) -> Optional[str]:
def state(self) -> str | None:
"""Return state of the sensor."""
if self.info.primary_value.value is None:
return None
return str(self.info.primary_value.value)
@property
def unit_of_measurement(self) -> Optional[str]:
def unit_of_measurement(self) -> str | None:
"""Return unit of measurement the value is expressed in."""
if self.info.primary_value.metadata.unit is None:
return None
@ -161,7 +162,7 @@ class ZWaveNumericSensor(ZwaveSensorBase):
return round(float(self.info.primary_value.value), 2)
@property
def unit_of_measurement(self) -> Optional[str]:
def unit_of_measurement(self) -> str | None:
"""Return unit of measurement the value is expressed in."""
if self.info.primary_value.metadata.unit is None:
return None
@ -191,7 +192,7 @@ class ZWaveListSensor(ZwaveSensorBase):
)
@property
def state(self) -> Optional[str]:
def state(self) -> str | None:
"""Return state of the sensor."""
if self.info.primary_value.value is None:
return None
@ -205,7 +206,7 @@ class ZWaveListSensor(ZwaveSensorBase):
)
@property
def extra_state_attributes(self) -> Optional[Dict[str, str]]:
def extra_state_attributes(self) -> dict[str, str] | None:
"""Return the device specific state attributes."""
# add the value's int value as property for multi-value (list) items
return {"value": self.info.primary_value.value}

View File

@ -1,7 +1,7 @@
"""Methods and classes related to executing Z-Wave commands and publishing these to hass."""
from __future__ import annotations
import logging
from typing import Dict, Set, Union
import voluptuous as vol
from zwave_js_server.model.node import Node as ZwaveNode
@ -20,8 +20,8 @@ _LOGGER = logging.getLogger(__name__)
def parameter_name_does_not_need_bitmask(
val: Dict[str, Union[int, str]]
) -> Dict[str, Union[int, str]]:
val: dict[str, int | str]
) -> dict[str, int | str]:
"""Validate that if a parameter name is provided, bitmask is not as well."""
if isinstance(val[const.ATTR_CONFIG_PARAMETER], str) and (
val.get(const.ATTR_CONFIG_PARAMETER_BITMASK)
@ -88,7 +88,7 @@ class ZWaveServices:
async def async_set_config_parameter(self, service: ServiceCall) -> None:
"""Set a config value on a node."""
nodes: Set[ZwaveNode] = set()
nodes: set[ZwaveNode] = set()
if ATTR_ENTITY_ID in service.data:
nodes |= {
async_get_node_from_entity_id(self._hass, entity_id)

View File

@ -1,7 +1,8 @@
"""Representation of Z-Wave switches."""
from __future__ import annotations
import logging
from typing import Any, Callable, List, Optional
from typing import Any, Callable
from zwave_js_server.client import Client as ZwaveClient
@ -30,7 +31,7 @@ async def async_setup_entry(
@callback
def async_add_switch(info: ZwaveDiscoveryInfo) -> None:
"""Add Z-Wave Switch."""
entities: List[ZWaveBaseEntity] = []
entities: list[ZWaveBaseEntity] = []
if info.platform_hint == "barrier_event_signaling_state":
entities.append(
ZWaveBarrierEventSignalingSwitch(config_entry, client, info)
@ -53,7 +54,7 @@ class ZWaveSwitch(ZWaveBaseEntity, SwitchEntity):
"""Representation of a Z-Wave switch."""
@property
def is_on(self) -> Optional[bool]: # type: ignore
def is_on(self) -> bool | None: # type: ignore
"""Return a boolean for the state of the switch."""
if self.info.primary_value.value is None:
# guard missing value
@ -85,7 +86,7 @@ class ZWaveBarrierEventSignalingSwitch(ZWaveBaseEntity, SwitchEntity):
"""Initialize a ZWaveBarrierEventSignalingSwitch entity."""
super().__init__(config_entry, client, info)
self._name = self.generate_name(include_value_name=True)
self._state: Optional[bool] = None
self._state: bool | None = None
self._update_state()
@ -100,7 +101,7 @@ class ZWaveBarrierEventSignalingSwitch(ZWaveBaseEntity, SwitchEntity):
return self._name
@property
def is_on(self) -> Optional[bool]: # type: ignore
def is_on(self) -> bool | None: # type: ignore
"""Return a boolean for the state of the switch."""
return self._state