mirror of
https://github.com/home-assistant/core
synced 2024-07-20 18:14:52 +00:00
Improve type annotations for the Brother integration (#49771)
This commit is contained in:
parent
f7cf82be6d
commit
3210c086ef
|
@ -6,6 +6,7 @@ homeassistant.components
|
|||
homeassistant.components.automation.*
|
||||
homeassistant.components.binary_sensor.*
|
||||
homeassistant.components.bond.*
|
||||
homeassistant.components.brother.*
|
||||
homeassistant.components.calendar.*
|
||||
homeassistant.components.cover.*
|
||||
homeassistant.components.device_automation.*
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
"""The Brother component."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from brother import Brother, SnmpError, UnsupportedModel
|
||||
from brother import Brother, DictToObj, SnmpError, UnsupportedModel
|
||||
import pysnmp.hlapi.asyncio as SnmpEngine
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_TYPE
|
||||
|
@ -19,7 +22,7 @@ SCAN_INTERVAL = timedelta(seconds=30)
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Brother from a config entry."""
|
||||
host = entry.data[CONF_HOST]
|
||||
kind = entry.data[CONF_TYPE]
|
||||
|
@ -41,7 +44,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
|
||||
|
@ -57,7 +60,9 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
class BrotherDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
"""Class to manage fetching Brother data from the printer."""
|
||||
|
||||
def __init__(self, hass, host, kind, snmp_engine):
|
||||
def __init__(
|
||||
self, hass: HomeAssistant, host: str, kind: str, snmp_engine: SnmpEngine
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
self.brother = Brother(host, kind=kind, snmp_engine=snmp_engine)
|
||||
|
||||
|
@ -68,7 +73,7 @@ class BrotherDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
update_interval=SCAN_INTERVAL,
|
||||
)
|
||||
|
||||
async def _async_update_data(self):
|
||||
async def _async_update_data(self) -> DictToObj:
|
||||
"""Update data via library."""
|
||||
try:
|
||||
data = await self.brother.async_update()
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
"""Adds config flow for Brother Printer."""
|
||||
from __future__ import annotations
|
||||
|
||||
import ipaddress
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from brother import Brother, SnmpError, UnsupportedModel
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, exceptions
|
||||
from homeassistant.const import CONF_HOST, CONF_TYPE
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.typing import DiscoveryInfoType
|
||||
|
||||
from .const import DOMAIN, PRINTER_TYPES
|
||||
from .utils import get_snmp_engine
|
||||
|
@ -19,14 +24,15 @@ DATA_SCHEMA = vol.Schema(
|
|||
)
|
||||
|
||||
|
||||
def host_valid(host):
|
||||
def host_valid(host: str) -> bool:
|
||||
"""Return True if hostname or IP address is valid."""
|
||||
try:
|
||||
if ipaddress.ip_address(host).version == (4 or 6):
|
||||
if ipaddress.ip_address(host).version in [4, 6]:
|
||||
return True
|
||||
except ValueError:
|
||||
disallowed = re.compile(r"[^a-zA-Z\d\-]")
|
||||
return all(x and not disallowed.search(x) for x in host.split("."))
|
||||
return False
|
||||
|
||||
|
||||
class BrotherConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
@ -35,12 +41,14 @@ class BrotherConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
VERSION = 1
|
||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""Initialize."""
|
||||
self.brother = None
|
||||
self.host = None
|
||||
self.brother: Brother = None
|
||||
self.host: str | None = None
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle the initial step."""
|
||||
errors = {}
|
||||
|
||||
|
@ -72,11 +80,10 @@ class BrotherConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
step_id="user", data_schema=DATA_SCHEMA, errors=errors
|
||||
)
|
||||
|
||||
async def async_step_zeroconf(self, discovery_info):
|
||||
async def async_step_zeroconf(
|
||||
self, discovery_info: DiscoveryInfoType
|
||||
) -> FlowResult:
|
||||
"""Handle zeroconf discovery."""
|
||||
if discovery_info is None:
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
|
||||
if not discovery_info.get("name") or not discovery_info["name"].startswith(
|
||||
"Brother"
|
||||
):
|
||||
|
@ -107,7 +114,9 @@ class BrotherConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
)
|
||||
return await self.async_step_zeroconf_confirm()
|
||||
|
||||
async def async_step_zeroconf_confirm(self, user_input=None):
|
||||
async def async_step_zeroconf_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle a flow initiated by zeroconf."""
|
||||
if user_input is not None:
|
||||
title = f"{self.brother.model} {self.brother.serial}"
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
"""Constants for Brother integration."""
|
||||
from homeassistant.const import ATTR_ICON, PERCENTAGE
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TypedDict
|
||||
|
||||
from homeassistant.const import PERCENTAGE
|
||||
|
||||
ATTR_BELT_UNIT_REMAINING_LIFE = "belt_unit_remaining_life"
|
||||
ATTR_BLACK_DRUM_COUNTER = "black_drum_counter"
|
||||
|
@ -18,9 +22,7 @@ ATTR_DRUM_COUNTER = "drum_counter"
|
|||
ATTR_DRUM_REMAINING_LIFE = "drum_remaining_life"
|
||||
ATTR_DRUM_REMAINING_PAGES = "drum_remaining_pages"
|
||||
ATTR_DUPLEX_COUNTER = "duplex_unit_pages_counter"
|
||||
ATTR_ENABLED = "enabled"
|
||||
ATTR_FUSER_REMAINING_LIFE = "fuser_remaining_life"
|
||||
ATTR_LABEL = "label"
|
||||
ATTR_LASER_REMAINING_LIFE = "laser_remaining_life"
|
||||
ATTR_MAGENTA_DRUM_COUNTER = "magenta_drum_counter"
|
||||
ATTR_MAGENTA_DRUM_REMAINING_LIFE = "magenta_drum_remaining_life"
|
||||
|
@ -32,7 +34,6 @@ ATTR_PAGE_COUNTER = "page_counter"
|
|||
ATTR_PF_KIT_1_REMAINING_LIFE = "pf_kit_1_remaining_life"
|
||||
ATTR_PF_KIT_MP_REMAINING_LIFE = "pf_kit_mp_remaining_life"
|
||||
ATTR_STATUS = "status"
|
||||
ATTR_UNIT = "unit"
|
||||
ATTR_UPTIME = "uptime"
|
||||
ATTR_YELLOW_DRUM_COUNTER = "yellow_drum_counter"
|
||||
ATTR_YELLOW_DRUM_REMAINING_LIFE = "yellow_drum_remaining_life"
|
||||
|
@ -50,7 +51,7 @@ PRINTER_TYPES = ["laser", "ink"]
|
|||
|
||||
SNMP = "snmp"
|
||||
|
||||
ATTRS_MAP = {
|
||||
ATTRS_MAP: dict[str, tuple[str, str]] = {
|
||||
ATTR_DRUM_REMAINING_LIFE: (ATTR_DRUM_REMAINING_PAGES, ATTR_DRUM_COUNTER),
|
||||
ATTR_BLACK_DRUM_REMAINING_LIFE: (
|
||||
ATTR_BLACK_DRUM_REMAINING_PAGES,
|
||||
|
@ -70,149 +71,158 @@ ATTRS_MAP = {
|
|||
),
|
||||
}
|
||||
|
||||
SENSOR_TYPES = {
|
||||
SENSOR_TYPES: dict[str, SensorDescription] = {
|
||||
ATTR_STATUS: {
|
||||
ATTR_ICON: "mdi:printer",
|
||||
ATTR_LABEL: ATTR_STATUS.title(),
|
||||
ATTR_UNIT: None,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer",
|
||||
"label": ATTR_STATUS.title(),
|
||||
"unit": None,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_PAGE_COUNTER: {
|
||||
ATTR_ICON: "mdi:file-document-outline",
|
||||
ATTR_LABEL: ATTR_PAGE_COUNTER.replace("_", " ").title(),
|
||||
ATTR_UNIT: UNIT_PAGES,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:file-document-outline",
|
||||
"label": ATTR_PAGE_COUNTER.replace("_", " ").title(),
|
||||
"unit": UNIT_PAGES,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_BW_COUNTER: {
|
||||
ATTR_ICON: "mdi:file-document-outline",
|
||||
ATTR_LABEL: ATTR_BW_COUNTER.replace("_", " ").title(),
|
||||
ATTR_UNIT: UNIT_PAGES,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:file-document-outline",
|
||||
"label": ATTR_BW_COUNTER.replace("_", " ").title(),
|
||||
"unit": UNIT_PAGES,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_COLOR_COUNTER: {
|
||||
ATTR_ICON: "mdi:file-document-outline",
|
||||
ATTR_LABEL: ATTR_COLOR_COUNTER.replace("_", " ").title(),
|
||||
ATTR_UNIT: UNIT_PAGES,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:file-document-outline",
|
||||
"label": ATTR_COLOR_COUNTER.replace("_", " ").title(),
|
||||
"unit": UNIT_PAGES,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_DUPLEX_COUNTER: {
|
||||
ATTR_ICON: "mdi:file-document-outline",
|
||||
ATTR_LABEL: ATTR_DUPLEX_COUNTER.replace("_", " ").title(),
|
||||
ATTR_UNIT: UNIT_PAGES,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:file-document-outline",
|
||||
"label": ATTR_DUPLEX_COUNTER.replace("_", " ").title(),
|
||||
"unit": UNIT_PAGES,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_DRUM_REMAINING_LIFE: {
|
||||
ATTR_ICON: "mdi:chart-donut",
|
||||
ATTR_LABEL: ATTR_DRUM_REMAINING_LIFE.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:chart-donut",
|
||||
"label": ATTR_DRUM_REMAINING_LIFE.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_BLACK_DRUM_REMAINING_LIFE: {
|
||||
ATTR_ICON: "mdi:chart-donut",
|
||||
ATTR_LABEL: ATTR_BLACK_DRUM_REMAINING_LIFE.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:chart-donut",
|
||||
"label": ATTR_BLACK_DRUM_REMAINING_LIFE.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_CYAN_DRUM_REMAINING_LIFE: {
|
||||
ATTR_ICON: "mdi:chart-donut",
|
||||
ATTR_LABEL: ATTR_CYAN_DRUM_REMAINING_LIFE.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:chart-donut",
|
||||
"label": ATTR_CYAN_DRUM_REMAINING_LIFE.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_MAGENTA_DRUM_REMAINING_LIFE: {
|
||||
ATTR_ICON: "mdi:chart-donut",
|
||||
ATTR_LABEL: ATTR_MAGENTA_DRUM_REMAINING_LIFE.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:chart-donut",
|
||||
"label": ATTR_MAGENTA_DRUM_REMAINING_LIFE.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_YELLOW_DRUM_REMAINING_LIFE: {
|
||||
ATTR_ICON: "mdi:chart-donut",
|
||||
ATTR_LABEL: ATTR_YELLOW_DRUM_REMAINING_LIFE.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:chart-donut",
|
||||
"label": ATTR_YELLOW_DRUM_REMAINING_LIFE.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_BELT_UNIT_REMAINING_LIFE: {
|
||||
ATTR_ICON: "mdi:current-ac",
|
||||
ATTR_LABEL: ATTR_BELT_UNIT_REMAINING_LIFE.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:current-ac",
|
||||
"label": ATTR_BELT_UNIT_REMAINING_LIFE.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_FUSER_REMAINING_LIFE: {
|
||||
ATTR_ICON: "mdi:water-outline",
|
||||
ATTR_LABEL: ATTR_FUSER_REMAINING_LIFE.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:water-outline",
|
||||
"label": ATTR_FUSER_REMAINING_LIFE.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_LASER_REMAINING_LIFE: {
|
||||
ATTR_ICON: "mdi:spotlight-beam",
|
||||
ATTR_LABEL: ATTR_LASER_REMAINING_LIFE.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:spotlight-beam",
|
||||
"label": ATTR_LASER_REMAINING_LIFE.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_PF_KIT_1_REMAINING_LIFE: {
|
||||
ATTR_ICON: "mdi:printer-3d",
|
||||
ATTR_LABEL: ATTR_PF_KIT_1_REMAINING_LIFE.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer-3d",
|
||||
"label": ATTR_PF_KIT_1_REMAINING_LIFE.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_PF_KIT_MP_REMAINING_LIFE: {
|
||||
ATTR_ICON: "mdi:printer-3d",
|
||||
ATTR_LABEL: ATTR_PF_KIT_MP_REMAINING_LIFE.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer-3d",
|
||||
"label": ATTR_PF_KIT_MP_REMAINING_LIFE.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_BLACK_TONER_REMAINING: {
|
||||
ATTR_ICON: "mdi:printer-3d-nozzle",
|
||||
ATTR_LABEL: ATTR_BLACK_TONER_REMAINING.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer-3d-nozzle",
|
||||
"label": ATTR_BLACK_TONER_REMAINING.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_CYAN_TONER_REMAINING: {
|
||||
ATTR_ICON: "mdi:printer-3d-nozzle",
|
||||
ATTR_LABEL: ATTR_CYAN_TONER_REMAINING.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer-3d-nozzle",
|
||||
"label": ATTR_CYAN_TONER_REMAINING.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_MAGENTA_TONER_REMAINING: {
|
||||
ATTR_ICON: "mdi:printer-3d-nozzle",
|
||||
ATTR_LABEL: ATTR_MAGENTA_TONER_REMAINING.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer-3d-nozzle",
|
||||
"label": ATTR_MAGENTA_TONER_REMAINING.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_YELLOW_TONER_REMAINING: {
|
||||
ATTR_ICON: "mdi:printer-3d-nozzle",
|
||||
ATTR_LABEL: ATTR_YELLOW_TONER_REMAINING.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer-3d-nozzle",
|
||||
"label": ATTR_YELLOW_TONER_REMAINING.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_BLACK_INK_REMAINING: {
|
||||
ATTR_ICON: "mdi:printer-3d-nozzle",
|
||||
ATTR_LABEL: ATTR_BLACK_INK_REMAINING.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer-3d-nozzle",
|
||||
"label": ATTR_BLACK_INK_REMAINING.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_CYAN_INK_REMAINING: {
|
||||
ATTR_ICON: "mdi:printer-3d-nozzle",
|
||||
ATTR_LABEL: ATTR_CYAN_INK_REMAINING.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer-3d-nozzle",
|
||||
"label": ATTR_CYAN_INK_REMAINING.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_MAGENTA_INK_REMAINING: {
|
||||
ATTR_ICON: "mdi:printer-3d-nozzle",
|
||||
ATTR_LABEL: ATTR_MAGENTA_INK_REMAINING.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer-3d-nozzle",
|
||||
"label": ATTR_MAGENTA_INK_REMAINING.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_YELLOW_INK_REMAINING: {
|
||||
ATTR_ICON: "mdi:printer-3d-nozzle",
|
||||
ATTR_LABEL: ATTR_YELLOW_INK_REMAINING.replace("_", " ").title(),
|
||||
ATTR_UNIT: PERCENTAGE,
|
||||
ATTR_ENABLED: True,
|
||||
"icon": "mdi:printer-3d-nozzle",
|
||||
"label": ATTR_YELLOW_INK_REMAINING.replace("_", " ").title(),
|
||||
"unit": PERCENTAGE,
|
||||
"enabled": True,
|
||||
},
|
||||
ATTR_UPTIME: {
|
||||
ATTR_ICON: None,
|
||||
ATTR_LABEL: ATTR_UPTIME.title(),
|
||||
ATTR_UNIT: None,
|
||||
ATTR_ENABLED: False,
|
||||
"icon": None,
|
||||
"label": ATTR_UPTIME.title(),
|
||||
"unit": None,
|
||||
"enabled": False,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class SensorDescription(TypedDict):
|
||||
"""Sensor description class."""
|
||||
|
||||
icon: str | None
|
||||
label: str
|
||||
unit: str | None
|
||||
enabled: bool
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
"""Support for the Brother service."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import DEVICE_CLASS_TIMESTAMP
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import BrotherDataUpdateCoordinator
|
||||
from .const import (
|
||||
ATTR_ENABLED,
|
||||
ATTR_ICON,
|
||||
ATTR_LABEL,
|
||||
ATTR_MANUFACTURER,
|
||||
ATTR_UNIT,
|
||||
ATTR_UPTIME,
|
||||
ATTRS_MAP,
|
||||
DATA_CONFIG_ENTRY,
|
||||
|
@ -20,9 +24,11 @@ ATTR_COUNTER = "counter"
|
|||
ATTR_REMAINING_PAGES = "remaining_pages"
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Add Brother entities from a config_entry."""
|
||||
coordinator = hass.data[DOMAIN][DATA_CONFIG_ENTRY][config_entry.entry_id]
|
||||
coordinator = hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry.entry_id]
|
||||
|
||||
sensors = []
|
||||
|
||||
|
@ -43,36 +49,42 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
class BrotherPrinterSensor(CoordinatorEntity, SensorEntity):
|
||||
"""Define an Brother Printer sensor."""
|
||||
|
||||
def __init__(self, coordinator, kind, device_info):
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: BrotherDataUpdateCoordinator,
|
||||
kind: str,
|
||||
device_info: dict[str, Any],
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(coordinator)
|
||||
self._name = f"{coordinator.data.model} {SENSOR_TYPES[kind][ATTR_LABEL]}"
|
||||
self._description = SENSOR_TYPES[kind]
|
||||
self._name = f"{coordinator.data.model} {self._description['label']}"
|
||||
self._unique_id = f"{coordinator.data.serial.lower()}_{kind}"
|
||||
self._device_info = device_info
|
||||
self.kind = kind
|
||||
self._attrs = {}
|
||||
self._attrs: dict[str, Any] = {}
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
def name(self) -> str:
|
||||
"""Return the name."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
def state(self) -> Any:
|
||||
"""Return the state."""
|
||||
if self.kind == ATTR_UPTIME:
|
||||
return getattr(self.coordinator.data, self.kind).isoformat()
|
||||
return getattr(self.coordinator.data, self.kind)
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
def device_class(self) -> str | None:
|
||||
"""Return the class of this sensor."""
|
||||
if self.kind == ATTR_UPTIME:
|
||||
return DEVICE_CLASS_TIMESTAMP
|
||||
return None
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes."""
|
||||
remaining_pages, drum_counter = ATTRS_MAP.get(self.kind, (None, None))
|
||||
if remaining_pages and drum_counter:
|
||||
|
@ -83,26 +95,26 @@ class BrotherPrinterSensor(CoordinatorEntity, SensorEntity):
|
|||
return self._attrs
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
def icon(self) -> str | None:
|
||||
"""Return the icon."""
|
||||
return SENSOR_TYPES[self.kind][ATTR_ICON]
|
||||
return self._description["icon"]
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
def unique_id(self) -> str:
|
||||
"""Return a unique_id for this entity."""
|
||||
return self._unique_id
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
def unit_of_measurement(self) -> str | None:
|
||||
"""Return the unit the value is expressed in."""
|
||||
return SENSOR_TYPES[self.kind][ATTR_UNIT]
|
||||
return self._description["unit"]
|
||||
|
||||
@property
|
||||
def device_info(self):
|
||||
def device_info(self) -> dict[str, Any]:
|
||||
"""Return the device info."""
|
||||
return self._device_info
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self):
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||
return SENSOR_TYPES[self.kind][ATTR_ENABLED]
|
||||
return self._description["enabled"]
|
||||
|
|
|
@ -5,7 +5,7 @@ import pysnmp.hlapi.asyncio as hlapi
|
|||
from pysnmp.hlapi.asyncio.cmdgen import lcd
|
||||
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.core import Event, HomeAssistant, callback
|
||||
from homeassistant.helpers import singleton
|
||||
|
||||
from .const import DOMAIN, SNMP
|
||||
|
@ -14,13 +14,13 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
|
||||
@singleton.singleton("snmp_engine")
|
||||
def get_snmp_engine(hass):
|
||||
def get_snmp_engine(hass: HomeAssistant) -> hlapi.SnmpEngine:
|
||||
"""Get SNMP engine."""
|
||||
_LOGGER.debug("Creating SNMP engine")
|
||||
snmp_engine = hlapi.SnmpEngine()
|
||||
|
||||
@callback
|
||||
def shutdown_listener(ev):
|
||||
def shutdown_listener(ev: Event) -> None:
|
||||
if hass.data.get(DOMAIN):
|
||||
_LOGGER.debug("Unconfiguring SNMP engine")
|
||||
lcd.unconfigure(hass.data[DOMAIN][SNMP], None)
|
||||
|
|
2
mypy.ini
2
mypy.ini
|
@ -35,7 +35,7 @@ warn_return_any = false
|
|||
warn_unreachable = false
|
||||
warn_unused_ignores = false
|
||||
|
||||
[mypy-homeassistant.components,homeassistant.components.automation.*,homeassistant.components.binary_sensor.*,homeassistant.components.bond.*,homeassistant.components.calendar.*,homeassistant.components.cover.*,homeassistant.components.device_automation.*,homeassistant.components.frontend.*,homeassistant.components.geo_location.*,homeassistant.components.group.*,homeassistant.components.history.*,homeassistant.components.http.*,homeassistant.components.huawei_lte.*,homeassistant.components.hyperion.*,homeassistant.components.image_processing.*,homeassistant.components.integration.*,homeassistant.components.knx.*,homeassistant.components.light.*,homeassistant.components.lock.*,homeassistant.components.mailbox.*,homeassistant.components.media_player.*,homeassistant.components.notify.*,homeassistant.components.number.*,homeassistant.components.persistent_notification.*,homeassistant.components.proximity.*,homeassistant.components.recorder.purge,homeassistant.components.recorder.repack,homeassistant.components.remote.*,homeassistant.components.scene.*,homeassistant.components.sensor.*,homeassistant.components.slack.*,homeassistant.components.sonos.media_player,homeassistant.components.sun.*,homeassistant.components.switch.*,homeassistant.components.systemmonitor.*,homeassistant.components.tts.*,homeassistant.components.vacuum.*,homeassistant.components.water_heater.*,homeassistant.components.weather.*,homeassistant.components.websocket_api.*,homeassistant.components.zeroconf.*,homeassistant.components.zone.*,homeassistant.components.zwave_js.*]
|
||||
[mypy-homeassistant.components,homeassistant.components.automation.*,homeassistant.components.binary_sensor.*,homeassistant.components.bond.*,homeassistant.components.brother.*,homeassistant.components.calendar.*,homeassistant.components.cover.*,homeassistant.components.device_automation.*,homeassistant.components.frontend.*,homeassistant.components.geo_location.*,homeassistant.components.group.*,homeassistant.components.history.*,homeassistant.components.http.*,homeassistant.components.huawei_lte.*,homeassistant.components.hyperion.*,homeassistant.components.image_processing.*,homeassistant.components.integration.*,homeassistant.components.knx.*,homeassistant.components.light.*,homeassistant.components.lock.*,homeassistant.components.mailbox.*,homeassistant.components.media_player.*,homeassistant.components.notify.*,homeassistant.components.number.*,homeassistant.components.persistent_notification.*,homeassistant.components.proximity.*,homeassistant.components.recorder.purge,homeassistant.components.recorder.repack,homeassistant.components.remote.*,homeassistant.components.scene.*,homeassistant.components.sensor.*,homeassistant.components.slack.*,homeassistant.components.sonos.media_player,homeassistant.components.sun.*,homeassistant.components.switch.*,homeassistant.components.systemmonitor.*,homeassistant.components.tts.*,homeassistant.components.vacuum.*,homeassistant.components.water_heater.*,homeassistant.components.weather.*,homeassistant.components.websocket_api.*,homeassistant.components.zeroconf.*,homeassistant.components.zone.*,homeassistant.components.zwave_js.*]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
disallow_subclassing_any = true
|
||||
|
|
|
@ -40,8 +40,8 @@ async def test_create_entry_with_hostname(hass):
|
|||
assert result["data"][CONF_TYPE] == CONFIG[CONF_TYPE]
|
||||
|
||||
|
||||
async def test_create_entry_with_ip_address(hass):
|
||||
"""Test that the user step works with printer IP address."""
|
||||
async def test_create_entry_with_ipv4_address(hass):
|
||||
"""Test that the user step works with printer IPv4 address."""
|
||||
with patch(
|
||||
"brother.Brother._get_data",
|
||||
return_value=json.loads(load_fixture("brother_printer_data.json")),
|
||||
|
@ -58,6 +58,24 @@ async def test_create_entry_with_ip_address(hass):
|
|||
assert result["data"][CONF_TYPE] == "laser"
|
||||
|
||||
|
||||
async def test_create_entry_with_ipv6_address(hass):
|
||||
"""Test that the user step works with printer IPv6 address."""
|
||||
with patch(
|
||||
"brother.Brother._get_data",
|
||||
return_value=json.loads(load_fixture("brother_printer_data.json")),
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_USER},
|
||||
data={CONF_HOST: "2001:db8::1428:57ab", CONF_TYPE: "laser"},
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "HL-L2340DW 0123456789"
|
||||
assert result["data"][CONF_HOST] == "2001:db8::1428:57ab"
|
||||
assert result["data"][CONF_TYPE] == "laser"
|
||||
|
||||
|
||||
async def test_invalid_hostname(hass):
|
||||
"""Test invalid hostname in user_input."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -118,16 +136,6 @@ async def test_device_exists_abort(hass):
|
|||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_zeroconf_no_data(hass):
|
||||
"""Test we abort if zeroconf provides no data."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_ZEROCONF}
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "cannot_connect"
|
||||
|
||||
|
||||
async def test_zeroconf_not_brother_printer_error(hass):
|
||||
"""Test we abort zeroconf flow if printer isn't Brother."""
|
||||
with patch(
|
||||
|
|
Loading…
Reference in a new issue