Enable strict type checks for onewire (#50422)

This commit is contained in:
epenet 2021-05-11 17:28:17 +02:00 committed by GitHub
parent efa5c59559
commit d6c99a3db9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 202 additions and 84 deletions

View file

@ -31,6 +31,7 @@ homeassistant.components.media_player.*
homeassistant.components.nam.* homeassistant.components.nam.*
homeassistant.components.notify.* homeassistant.components.notify.*
homeassistant.components.number.* homeassistant.components.number.*
homeassistant.components.onewire.*
homeassistant.components.persistent_notification.* homeassistant.components.persistent_notification.*
homeassistant.components.proximity.* homeassistant.components.proximity.*
homeassistant.components.recorder.purge homeassistant.components.recorder.purge

View file

@ -13,7 +13,7 @@ from .onewirehub import CannotConnect, OneWireHub
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry): async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Set up a 1-Wire proxy for a config entry.""" """Set up a 1-Wire proxy for a config entry."""
hass.data.setdefault(DOMAIN, {}) hass.data.setdefault(DOMAIN, {})
@ -65,7 +65,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry):
return True return True
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry): async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Unload a config entry.""" """Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms( unload_ok = await hass.config_entries.async_unload_platforms(
config_entry, PLATFORMS config_entry, PLATFORMS

View file

@ -1,14 +1,21 @@
"""Support for 1-Wire binary sensors.""" """Support for 1-Wire binary sensors."""
from __future__ import annotations
import os import os
from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import BinarySensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_TYPE from homeassistant.const import CONF_TYPE
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import CONF_TYPE_OWSERVER, DOMAIN, SENSOR_TYPE_SENSED from .const import CONF_TYPE_OWSERVER, DOMAIN, SENSOR_TYPE_SENSED
from .onewire_entities import OneWireProxyEntity from .model import DeviceComponentDescription
from .onewire_entities import OneWireBaseEntity, OneWireProxyEntity
from .onewirehub import OneWireHub from .onewirehub import OneWireHub
DEVICE_BINARY_SENSORS = { DEVICE_BINARY_SENSORS: dict[str, list[DeviceComponentDescription]] = {
# Family : { path, sensor_type } # Family : { path, sensor_type }
"12": [ "12": [
{ {
@ -77,7 +84,11 @@ DEVICE_BINARY_SENSORS = {
} }
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up 1-Wire platform.""" """Set up 1-Wire platform."""
# Only OWServer implementation works with binary sensors # Only OWServer implementation works with binary sensors
if config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER: if config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER:
@ -87,9 +98,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities(entities, True) async_add_entities(entities, True)
def get_entities(onewirehub: OneWireHub): def get_entities(onewirehub: OneWireHub) -> list[OneWireBaseEntity]:
"""Get a list of entities.""" """Get a list of entities."""
entities = [] if not onewirehub.devices:
return []
entities: list[OneWireBaseEntity] = []
for device in onewirehub.devices: for device in onewirehub.devices:
family = device["family"] family = device["family"]
@ -98,7 +112,7 @@ def get_entities(onewirehub: OneWireHub):
if family not in DEVICE_BINARY_SENSORS: if family not in DEVICE_BINARY_SENSORS:
continue continue
device_info = { device_info: DeviceInfo = {
"identifiers": {(DOMAIN, device_id)}, "identifiers": {(DOMAIN, device_id)},
"manufacturer": "Maxim Integrated", "manufacturer": "Maxim Integrated",
"model": device_type, "model": device_type,
@ -126,6 +140,6 @@ class OneWireProxyBinarySensor(OneWireProxyEntity, BinarySensorEntity):
"""Implementation of a 1-Wire binary sensor.""" """Implementation of a 1-Wire binary sensor."""
@property @property
def is_on(self): def is_on(self) -> bool:
"""Return true if sensor is on.""" """Return true if sensor is on."""
return self._state return bool(self._state)

View file

@ -1,9 +1,14 @@
"""Config flow for 1-Wire component.""" """Config flow for 1-Wire component."""
from __future__ import annotations
from typing import Any
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import ConfigFlow from homeassistant.config_entries import ConfigFlow
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResult
from .const import ( from .const import (
CONF_MOUNT_DIR, CONF_MOUNT_DIR,
@ -32,7 +37,9 @@ DATA_SCHEMA_MOUNTDIR = vol.Schema(
) )
async def validate_input_owserver(hass: HomeAssistant, data): async def validate_input_owserver(
hass: HomeAssistant, data: dict[str, Any]
) -> dict[str, str]:
"""Validate the user input allows us to connect. """Validate the user input allows us to connect.
Data has the keys from DATA_SCHEMA_OWSERVER with values provided by the user. Data has the keys from DATA_SCHEMA_OWSERVER with values provided by the user.
@ -49,7 +56,9 @@ async def validate_input_owserver(hass: HomeAssistant, data):
return {"title": host} return {"title": host}
def is_duplicate_owserver_entry(hass: HomeAssistant, user_input): def is_duplicate_owserver_entry(
hass: HomeAssistant, user_input: dict[str, Any]
) -> bool:
"""Check existing entries for matching host and port.""" """Check existing entries for matching host and port."""
for config_entry in hass.config_entries.async_entries(DOMAIN): for config_entry in hass.config_entries.async_entries(DOMAIN):
if ( if (
@ -61,7 +70,9 @@ def is_duplicate_owserver_entry(hass: HomeAssistant, user_input):
return False return False
async def validate_input_mount_dir(hass: HomeAssistant, data): async def validate_input_mount_dir(
hass: HomeAssistant, data: dict[str, Any]
) -> dict[str, str]:
"""Validate the user input allows us to connect. """Validate the user input allows us to connect.
Data has the keys from DATA_SCHEMA_MOUNTDIR with values provided by the user. Data has the keys from DATA_SCHEMA_MOUNTDIR with values provided by the user.
@ -82,16 +93,18 @@ class OneWireFlowHandler(ConfigFlow, domain=DOMAIN):
VERSION = 1 VERSION = 1
def __init__(self): def __init__(self) -> None:
"""Initialize 1-Wire config flow.""" """Initialize 1-Wire config flow."""
self.onewire_config = {} self.onewire_config: dict[str, Any] = {}
async def async_step_user(self, user_input=None): async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle 1-Wire config flow start. """Handle 1-Wire config flow start.
Let user manually input configuration. Let user manually input configuration.
""" """
errors = {} errors: dict[str, str] = {}
if user_input is not None: if user_input is not None:
self.onewire_config.update(user_input) self.onewire_config.update(user_input)
if CONF_TYPE_OWSERVER == user_input[CONF_TYPE]: if CONF_TYPE_OWSERVER == user_input[CONF_TYPE]:
@ -105,7 +118,9 @@ class OneWireFlowHandler(ConfigFlow, domain=DOMAIN):
errors=errors, errors=errors,
) )
async def async_step_owserver(self, user_input=None): async def async_step_owserver(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle OWServer configuration.""" """Handle OWServer configuration."""
errors = {} errors = {}
if user_input: if user_input:
@ -130,7 +145,9 @@ class OneWireFlowHandler(ConfigFlow, domain=DOMAIN):
errors=errors, errors=errors,
) )
async def async_step_mount_dir(self, user_input=None): async def async_step_mount_dir(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle SysBus configuration.""" """Handle SysBus configuration."""
errors = {} errors = {}
if user_input: if user_input:
@ -157,7 +174,7 @@ class OneWireFlowHandler(ConfigFlow, domain=DOMAIN):
errors=errors, errors=errors,
) )
async def async_step_import(self, platform_config): async def async_step_import(self, platform_config: dict[str, Any]) -> FlowResult:
"""Handle import configuration from YAML.""" """Handle import configuration from YAML."""
# OWServer # OWServer
if platform_config[CONF_TYPE] == CONF_TYPE_OWSERVER: if platform_config[CONF_TYPE] == CONF_TYPE_OWSERVER:

View file

@ -1,4 +1,6 @@
"""Constants for 1-Wire component.""" """Constants for 1-Wire component."""
from __future__ import annotations
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
@ -44,7 +46,7 @@ SENSOR_TYPE_WETNESS = "wetness"
SWITCH_TYPE_LATCH = "latch" SWITCH_TYPE_LATCH = "latch"
SWITCH_TYPE_PIO = "pio" SWITCH_TYPE_PIO = "pio"
SENSOR_TYPES = { SENSOR_TYPES: dict[str, list[str | None]] = {
# SensorType: [ Unit, DeviceClass ] # SensorType: [ Unit, DeviceClass ]
SENSOR_TYPE_TEMPERATURE: [TEMP_CELSIUS, DEVICE_CLASS_TEMPERATURE], SENSOR_TYPE_TEMPERATURE: [TEMP_CELSIUS, DEVICE_CLASS_TEMPERATURE],
SENSOR_TYPE_HUMIDITY: [PERCENTAGE, DEVICE_CLASS_HUMIDITY], SENSOR_TYPE_HUMIDITY: [PERCENTAGE, DEVICE_CLASS_HUMIDITY],

View file

@ -0,0 +1,21 @@
"""Type definitions for 1-Wire integration."""
from __future__ import annotations
from typing import TypedDict
class DeviceComponentDescription(TypedDict, total=False):
"""Device component description class."""
path: str
name: str
type: str
default_disabled: bool
class OWServerDeviceDescription(TypedDict):
"""OWServer device description class."""
path: str
family: str
type: str

View file

@ -7,6 +7,7 @@ from typing import Any
from pyownet import protocol from pyownet import protocol
from homeassistant.helpers.entity import DeviceInfo, Entity from homeassistant.helpers.entity import DeviceInfo, Entity
from homeassistant.helpers.typing import StateType
from .const import ( from .const import (
SENSOR_TYPE_COUNT, SENSOR_TYPE_COUNT,
@ -15,6 +16,7 @@ from .const import (
SWITCH_TYPE_LATCH, SWITCH_TYPE_LATCH,
SWITCH_TYPE_PIO, SWITCH_TYPE_PIO,
) )
from .model import DeviceComponentDescription
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -24,13 +26,13 @@ class OneWireBaseEntity(Entity):
def __init__( def __init__(
self, self,
name, name: str,
device_file, device_file: str,
entity_type: str, entity_type: str,
entity_name: str = None, entity_name: str,
device_info: DeviceInfo | None = None, device_info: DeviceInfo,
default_disabled: bool = False, default_disabled: bool,
unique_id: str = None, unique_id: str,
): ):
"""Initialize the entity.""" """Initialize the entity."""
self._name = f"{name} {entity_name or entity_type.capitalize()}" self._name = f"{name} {entity_name or entity_type.capitalize()}"
@ -39,10 +41,10 @@ class OneWireBaseEntity(Entity):
self._device_class = SENSOR_TYPES[entity_type][1] self._device_class = SENSOR_TYPES[entity_type][1]
self._unit_of_measurement = SENSOR_TYPES[entity_type][0] self._unit_of_measurement = SENSOR_TYPES[entity_type][0]
self._device_info = device_info self._device_info = device_info
self._state = None self._state: StateType = None
self._value_raw = None self._value_raw: float | None = None
self._default_disabled = default_disabled self._default_disabled = default_disabled
self._unique_id = unique_id or device_file self._unique_id = unique_id
@property @property
def name(self) -> str | None: def name(self) -> str | None:
@ -84,7 +86,7 @@ class OneWireProxyEntity(OneWireBaseEntity):
device_name: str, device_name: str,
device_info: DeviceInfo, device_info: DeviceInfo,
entity_path: str, entity_path: str,
entity_specs: dict[str, Any], entity_specs: DeviceComponentDescription,
owproxy: protocol._Proxy, owproxy: protocol._Proxy,
): ):
"""Initialize the sensor.""" """Initialize the sensor."""
@ -99,31 +101,30 @@ class OneWireProxyEntity(OneWireBaseEntity):
) )
self._owproxy = owproxy self._owproxy = owproxy
def _read_value_ownet(self): def _read_value_ownet(self) -> str:
"""Read a value from the owserver.""" """Read a value from the owserver."""
return self._owproxy.read(self._device_file).decode().lstrip() read_bytes: bytes = self._owproxy.read(self._device_file)
return read_bytes.decode().lstrip()
def _write_value_ownet(self, value: bytes): def _write_value_ownet(self, value: bytes) -> None:
"""Write a value to the owserver.""" """Write a value to the owserver."""
return self._owproxy.write(self._device_file, value) self._owproxy.write(self._device_file, value)
def update(self): def update(self) -> None:
"""Get the latest data from the device.""" """Get the latest data from the device."""
value = None
try: try:
self._value_raw = float(self._read_value_ownet()) self._value_raw = float(self._read_value_ownet())
except protocol.Error as exc: except protocol.Error as exc:
_LOGGER.error("Owserver failure in read(), got: %s", exc) _LOGGER.error("Owserver failure in read(), got: %s", exc)
self._state = None
else: else:
if self._entity_type == SENSOR_TYPE_COUNT: if self._entity_type == SENSOR_TYPE_COUNT:
value = int(self._value_raw) self._state = int(self._value_raw)
elif self._entity_type in [ elif self._entity_type in [
SENSOR_TYPE_SENSED, SENSOR_TYPE_SENSED,
SWITCH_TYPE_LATCH, SWITCH_TYPE_LATCH,
SWITCH_TYPE_PIO, SWITCH_TYPE_PIO,
]: ]:
value = int(self._value_raw) == 1 self._state = int(self._value_raw) == 1
else: else:
value = round(self._value_raw, 1) self._state = round(self._value_raw, 1)
self._state = value

View file

@ -1,4 +1,6 @@
"""Hub for communication with 1-Wire server or mount_dir.""" """Hub for communication with 1-Wire server or mount_dir."""
from __future__ import annotations
import os import os
from pi1wire import Pi1Wire from pi1wire import Pi1Wire
@ -10,6 +12,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from .const import CONF_MOUNT_DIR, CONF_TYPE_OWSERVER, CONF_TYPE_SYSBUS from .const import CONF_MOUNT_DIR, CONF_TYPE_OWSERVER, CONF_TYPE_SYSBUS
from .model import OWServerDeviceDescription
DEVICE_COUPLERS = { DEVICE_COUPLERS = {
# Family : [branches] # Family : [branches]
@ -23,10 +26,10 @@ class OneWireHub:
def __init__(self, hass: HomeAssistant): def __init__(self, hass: HomeAssistant):
"""Initialize.""" """Initialize."""
self.hass = hass self.hass = hass
self.type: str = None self.type: str | None = None
self.pi1proxy: Pi1Wire = None self.pi1proxy: Pi1Wire | None = None
self.owproxy: protocol._Proxy = None self.owproxy: protocol._Proxy | None = None
self.devices = None self.devices: list | None = None
async def connect(self, host: str, port: int) -> None: async def connect(self, host: str, port: int) -> None:
"""Connect to the owserver host.""" """Connect to the owserver host."""
@ -54,10 +57,11 @@ class OneWireHub:
await self.connect(host, port) await self.connect(host, port)
await self.discover_devices() await self.discover_devices()
async def discover_devices(self): async def discover_devices(self) -> None:
"""Discover all devices.""" """Discover all devices."""
if self.devices is None: if self.devices is None:
if self.type == CONF_TYPE_SYSBUS: if self.type == CONF_TYPE_SYSBUS:
assert self.pi1proxy
self.devices = await self.hass.async_add_executor_job( self.devices = await self.hass.async_add_executor_job(
self.pi1proxy.find_all_sensors self.pi1proxy.find_all_sensors
) )
@ -65,11 +69,13 @@ class OneWireHub:
self.devices = await self.hass.async_add_executor_job( self.devices = await self.hass.async_add_executor_job(
self._discover_devices_owserver self._discover_devices_owserver
) )
return self.devices
def _discover_devices_owserver(self, path="/"): def _discover_devices_owserver(
self, path: str = "/"
) -> list[OWServerDeviceDescription]:
"""Discover all owserver devices.""" """Discover all owserver devices."""
devices = [] devices = []
assert self.owproxy
for device_path in self.owproxy.dir(path): for device_path in self.owproxy.dir(path):
device_family = self.owproxy.read(f"{device_path}family").decode() device_family = self.owproxy.read(f"{device_path}family").decode()
device_type = self.owproxy.read(f"{device_path}type").decode() device_type = self.owproxy.read(f"{device_path}type").decode()

View file

@ -4,15 +4,20 @@ from __future__ import annotations
import asyncio import asyncio
import logging import logging
import os import os
from types import MappingProxyType
from typing import Any
from pi1wire import InvalidCRCException, UnsupportResponseException from pi1wire import InvalidCRCException, OneWireInterface, UnsupportResponseException
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import StateType from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import DiscoveryInfoType, StateType
from .const import ( from .const import (
CONF_MOUNT_DIR, CONF_MOUNT_DIR,
@ -32,12 +37,13 @@ from .const import (
SENSOR_TYPE_VOLTAGE, SENSOR_TYPE_VOLTAGE,
SENSOR_TYPE_WETNESS, SENSOR_TYPE_WETNESS,
) )
from .model import DeviceComponentDescription
from .onewire_entities import OneWireBaseEntity, OneWireProxyEntity from .onewire_entities import OneWireBaseEntity, OneWireProxyEntity
from .onewirehub import OneWireHub from .onewirehub import OneWireHub
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEVICE_SENSORS = { DEVICE_SENSORS: dict[str, list[DeviceComponentDescription]] = {
# Family : { SensorType: owfs path } # Family : { SensorType: owfs path }
"10": [ "10": [
{"path": "temperature", "name": "Temperature", "type": SENSOR_TYPE_TEMPERATURE} {"path": "temperature", "name": "Temperature", "type": SENSOR_TYPE_TEMPERATURE}
@ -145,7 +151,7 @@ DEVICE_SUPPORT_SYSBUS = ["10", "22", "28", "3B", "42"]
# These can only be read by OWFS. Currently this driver only supports them # These can only be read by OWFS. Currently this driver only supports them
# via owserver (network protocol) # via owserver (network protocol)
HOBBYBOARD_EF = { HOBBYBOARD_EF: dict[str, list[DeviceComponentDescription]] = {
"HobbyBoards_EF": [ "HobbyBoards_EF": [
{ {
"path": "humidity/humidity_corrected", "path": "humidity/humidity_corrected",
@ -189,7 +195,7 @@ HOBBYBOARD_EF = {
# 7E sensors are special sensors by Embedded Data Systems # 7E sensors are special sensors by Embedded Data Systems
EDS_SENSORS = { EDS_SENSORS: dict[str, list[DeviceComponentDescription]] = {
"EDS0068": [ "EDS0068": [
{ {
"path": "EDS0068/temperature", "path": "EDS0068/temperature",
@ -225,7 +231,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
) )
def get_sensor_types(device_sub_type): def get_sensor_types(device_sub_type: str) -> dict[str, Any]:
"""Return the proper info array for the device type.""" """Return the proper info array for the device type."""
if "HobbyBoard" in device_sub_type: if "HobbyBoard" in device_sub_type:
return HOBBYBOARD_EF return HOBBYBOARD_EF
@ -234,7 +240,12 @@ def get_sensor_types(device_sub_type):
return DEVICE_SENSORS return DEVICE_SENSORS
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): async def async_setup_platform(
hass: HomeAssistant,
config: dict[str, Any],
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Old way of setting up 1-Wire platform.""" """Old way of setting up 1-Wire platform."""
_LOGGER.warning( _LOGGER.warning(
"Loading 1-Wire via platform setup is deprecated. " "Loading 1-Wire via platform setup is deprecated. "
@ -253,7 +264,11 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
) )
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up 1-Wire platform.""" """Set up 1-Wire platform."""
onewirehub = hass.data[DOMAIN][config_entry.entry_id] onewirehub = hass.data[DOMAIN][config_entry.entry_id]
entities = await hass.async_add_executor_job( entities = await hass.async_add_executor_job(
@ -262,9 +277,14 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities(entities, True) async_add_entities(entities, True)
def get_entities(onewirehub: OneWireHub, config): def get_entities(
onewirehub: OneWireHub, config: MappingProxyType[str, Any]
) -> list[OneWireBaseEntity]:
"""Get a list of entities.""" """Get a list of entities."""
entities = [] if not onewirehub.devices:
return []
entities: list[OneWireBaseEntity] = []
device_names = {} device_names = {}
if CONF_NAMES in config and isinstance(config[CONF_NAMES], dict): if CONF_NAMES in config and isinstance(config[CONF_NAMES], dict):
device_names = config[CONF_NAMES] device_names = config[CONF_NAMES]
@ -272,6 +292,7 @@ def get_entities(onewirehub: OneWireHub, config):
conf_type = config[CONF_TYPE] conf_type = config[CONF_TYPE]
# We have an owserver on a remote(or local) host/port # We have an owserver on a remote(or local) host/port
if conf_type == CONF_TYPE_OWSERVER: if conf_type == CONF_TYPE_OWSERVER:
assert onewirehub.owproxy
for device in onewirehub.devices: for device in onewirehub.devices:
family = device["family"] family = device["family"]
device_type = device["type"] device_type = device["type"]
@ -292,7 +313,7 @@ def get_entities(onewirehub: OneWireHub, config):
device_id, device_id,
) )
continue continue
device_info = { device_info: DeviceInfo = {
"identifiers": {(DOMAIN, device_id)}, "identifiers": {(DOMAIN, device_id)},
"manufacturer": "Maxim Integrated", "manufacturer": "Maxim Integrated",
"model": device_type, "model": device_type,
@ -384,9 +405,23 @@ class OneWireProxySensor(OneWireProxyEntity, OneWireSensor):
class OneWireDirectSensor(OneWireSensor): class OneWireDirectSensor(OneWireSensor):
"""Implementation of a 1-Wire sensor directly connected to RPI GPIO.""" """Implementation of a 1-Wire sensor directly connected to RPI GPIO."""
def __init__(self, name, device_file, device_info, owsensor): def __init__(
self,
name: str,
device_file: str,
device_info: DeviceInfo,
owsensor: OneWireInterface,
) -> None:
"""Initialize the sensor.""" """Initialize the sensor."""
super().__init__(name, device_file, "temperature", "Temperature", device_info) super().__init__(
name,
device_file,
"temperature",
"Temperature",
device_info,
False,
device_file,
)
self._owsensor = owsensor self._owsensor = owsensor
@property @property
@ -394,7 +429,7 @@ class OneWireDirectSensor(OneWireSensor):
"""Return the state of the entity.""" """Return the state of the entity."""
return self._state return self._state
async def get_temperature(self): async def get_temperature(self) -> float:
"""Get the latest data from the device.""" """Get the latest data from the device."""
attempts = 1 attempts = 1
while True: while True:
@ -414,16 +449,15 @@ class OneWireDirectSensor(OneWireSensor):
if attempts > 10: if attempts > 10:
raise raise
async def async_update(self): async def async_update(self) -> None:
"""Get the latest data from the device.""" """Get the latest data from the device."""
value = None
try: try:
self._value_raw = await self.get_temperature() self._value_raw = await self.get_temperature()
value = round(float(self._value_raw), 1) self._state = round(self._value_raw, 1)
except ( except (
FileNotFoundError, FileNotFoundError,
InvalidCRCException, InvalidCRCException,
UnsupportResponseException, UnsupportResponseException,
) as ex: ) as ex:
_LOGGER.warning("Cannot read from sensor %s: %s", self._device_file, ex) _LOGGER.warning("Cannot read from sensor %s: %s", self._device_file, ex)
self._state = value self._state = None

View file

@ -1,15 +1,23 @@
"""Support for 1-Wire environment switches.""" """Support for 1-Wire environment switches."""
from __future__ import annotations
import logging import logging
import os import os
from typing import Any
from homeassistant.components.switch import SwitchEntity from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_TYPE from homeassistant.const import CONF_TYPE
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import CONF_TYPE_OWSERVER, DOMAIN, SWITCH_TYPE_LATCH, SWITCH_TYPE_PIO from .const import CONF_TYPE_OWSERVER, DOMAIN, SWITCH_TYPE_LATCH, SWITCH_TYPE_PIO
from .onewire_entities import OneWireProxyEntity from .model import DeviceComponentDescription
from .onewire_entities import OneWireBaseEntity, OneWireProxyEntity
from .onewirehub import OneWireHub from .onewirehub import OneWireHub
DEVICE_SWITCHES = { DEVICE_SWITCHES: dict[str, list[DeviceComponentDescription]] = {
# Family : { owfs path } # Family : { owfs path }
"12": [ "12": [
{ {
@ -140,7 +148,11 @@ DEVICE_SWITCHES = {
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up 1-Wire platform.""" """Set up 1-Wire platform."""
# Only OWServer implementation works with switches # Only OWServer implementation works with switches
if config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER: if config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER:
@ -150,9 +162,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities(entities, True) async_add_entities(entities, True)
def get_entities(onewirehub: OneWireHub): def get_entities(onewirehub: OneWireHub) -> list[OneWireBaseEntity]:
"""Get a list of entities.""" """Get a list of entities."""
entities = [] if not onewirehub.devices:
return []
entities: list[OneWireBaseEntity] = []
for device in onewirehub.devices: for device in onewirehub.devices:
family = device["family"] family = device["family"]
@ -162,7 +177,7 @@ def get_entities(onewirehub: OneWireHub):
if family not in DEVICE_SWITCHES: if family not in DEVICE_SWITCHES:
continue continue
device_info = { device_info: DeviceInfo = {
"identifiers": {(DOMAIN, device_id)}, "identifiers": {(DOMAIN, device_id)},
"manufacturer": "Maxim Integrated", "manufacturer": "Maxim Integrated",
"model": device_type, "model": device_type,
@ -190,14 +205,14 @@ class OneWireProxySwitch(OneWireProxyEntity, SwitchEntity):
"""Implementation of a 1-Wire switch.""" """Implementation of a 1-Wire switch."""
@property @property
def is_on(self): def is_on(self) -> bool:
"""Return true if sensor is on.""" """Return true if sensor is on."""
return self._state return bool(self._state)
def turn_on(self, **kwargs) -> None: def turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on.""" """Turn the entity on."""
self._write_value_ownet(b"1") self._write_value_ownet(b"1")
def turn_off(self, **kwargs) -> None: def turn_off(self, **kwargs: Any) -> None:
"""Turn the entity off.""" """Turn the entity off."""
self._write_value_ownet(b"0") self._write_value_ownet(b"0")

View file

@ -352,6 +352,17 @@ no_implicit_optional = true
warn_return_any = true warn_return_any = true
warn_unreachable = true warn_unreachable = true
[mypy-homeassistant.components.onewire.*]
check_untyped_defs = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
no_implicit_optional = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.persistent_notification.*] [mypy-homeassistant.components.persistent_notification.*]
check_untyped_defs = true check_untyped_defs = true
disallow_incomplete_defs = true disallow_incomplete_defs = true
@ -1008,9 +1019,6 @@ ignore_errors = true
[mypy-homeassistant.components.ondilo_ico.*] [mypy-homeassistant.components.ondilo_ico.*]
ignore_errors = true ignore_errors = true
[mypy-homeassistant.components.onewire.*]
ignore_errors = true
[mypy-homeassistant.components.onvif.*] [mypy-homeassistant.components.onvif.*]
ignore_errors = true ignore_errors = true

View file

@ -152,7 +152,6 @@ IGNORED_MODULES: Final[list[str]] = [
"homeassistant.components.omnilogic.*", "homeassistant.components.omnilogic.*",
"homeassistant.components.onboarding.*", "homeassistant.components.onboarding.*",
"homeassistant.components.ondilo_ico.*", "homeassistant.components.ondilo_ico.*",
"homeassistant.components.onewire.*",
"homeassistant.components.onvif.*", "homeassistant.components.onvif.*",
"homeassistant.components.ovo_energy.*", "homeassistant.components.ovo_energy.*",
"homeassistant.components.ozw.*", "homeassistant.components.ozw.*",

View file

@ -884,7 +884,7 @@ MOCK_SYSBUS_DEVICES = {
{ {
"entity_id": "sensor.42_111111111112_temperature", "entity_id": "sensor.42_111111111112_temperature",
"unique_id": "/sys/bus/w1/devices/42-111111111112/w1_slave", "unique_id": "/sys/bus/w1/devices/42-111111111112/w1_slave",
"injected_value": [UnsupportResponseException] * 9 + ["27.993"], "injected_value": [UnsupportResponseException] * 9 + [27.993],
"result": "28.0", "result": "28.0",
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,
@ -902,7 +902,7 @@ MOCK_SYSBUS_DEVICES = {
{ {
"entity_id": "sensor.42_111111111113_temperature", "entity_id": "sensor.42_111111111113_temperature",
"unique_id": "/sys/bus/w1/devices/42-111111111113/w1_slave", "unique_id": "/sys/bus/w1/devices/42-111111111113/w1_slave",
"injected_value": [UnsupportResponseException] * 10 + ["27.993"], "injected_value": [UnsupportResponseException] * 10 + [27.993],
"result": "unknown", "result": "unknown",
"unit": TEMP_CELSIUS, "unit": TEMP_CELSIUS,
"class": DEVICE_CLASS_TEMPERATURE, "class": DEVICE_CLASS_TEMPERATURE,