MySensors: Fix linter errors

This commit is contained in:
functionpointer 2021-01-17 17:54:06 +01:00
parent af28bc1e1b
commit fbac292ba6
17 changed files with 415 additions and 204 deletions

View file

@ -284,7 +284,7 @@ homeassistant/components/mpd/* @fabaff
homeassistant/components/mqtt/* @home-assistant/core @emontnemery
homeassistant/components/msteams/* @peroyvind
homeassistant/components/myq/* @bdraco
homeassistant/components/mysensors/* @MartinHjelmare
homeassistant/components/mysensors/* @MartinHjelmare @functionpointer
homeassistant/components/mystrom/* @fabaff
homeassistant/components/neato/* @dshokouhi @Santobert
homeassistant/components/nederlandse_spoorwegen/* @YarmoM

View file

@ -1,16 +1,18 @@
"""Connect to a MySensors gateway via pymysensors API."""
import logging
from typing import Optional, Dict, List, Type, Callable, Union, Tuple
from typing import Callable, Dict, List, Optional, Tuple, Type, Union
import voluptuous as vol
from mysensors import BaseAsyncGateway
import voluptuous as vol
from .device import MySensorsEntity, MySensorsDevice
from homeassistant.components.mqtt import valid_publish_topic, valid_subscribe_topic
from homeassistant.const import CONF_OPTIMISTIC
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from ... import config_entries
from ...config_entries import ConfigEntry
from ...helpers.typing import ConfigType, HomeAssistantType
from .const import (
ATTR_DEVICES,
CONF_BAUD_RATE,
@ -25,15 +27,15 @@ from .const import (
CONF_TOPIC_OUT_PREFIX,
CONF_VERSION,
DOMAIN,
MYSENSORS_GATEWAYS, SensorType, PLATFORM_TYPES, SUPPORTED_PLATFORMS_WITH_ENTRY_SUPPORT, GatewayId,
MYSENSORS_GATEWAYS,
MYSENSORS_ON_UNLOAD,
SUPPORTED_PLATFORMS_WITH_ENTRY_SUPPORT,
DevId,
GatewayId,
SensorType,
)
from .device import get_mysensors_devices
from .gateway import finish_setup, get_mysensors_gateway, setup_gateway, gw_stop
from .const import DevId
from ... import config_entries
from ...config_entries import ConfigEntry
from ...helpers.typing import HomeAssistantType, ConfigType
from .device import MySensorsDevice, MySensorsEntity, get_mysensors_devices
from .gateway import finish_setup, get_mysensors_gateway, gw_stop, setup_gateway
_LOGGER = logging.getLogger(__name__)
@ -119,41 +121,53 @@ CONFIG_SCHEMA = vol.Schema(
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass, config: ConfigType) -> bool:
"""Set up the MySensors component."""
if config is None or DOMAIN not in config:
#when configured via ConfigEntry, hass calls async_setup(hass,None) and then calls async_setup_entry(...).
#so in async_setup we have to check if there are any ConfigEntries and then return True. This lets async_setup_entry run.
# when configured via ConfigEntry, hass calls async_setup(hass,None) and then calls async_setup_entry(...).
# so in async_setup we have to check if there are any ConfigEntries and then return True. This lets async_setup_entry run.
return bool(hass.config_entries.async_entries(DOMAIN))
config = config[DOMAIN]
user_inputs = [{
CONF_DEVICE: gw[CONF_DEVICE],
CONF_PERSISTENCE: gw.get(CONF_PERSISTENCE_FILE,None),
CONF_BAUD_RATE: gw.get(CONF_BAUD_RATE, None),
CONF_TCP_PORT: gw.get(CONF_TCP_PORT, None),
CONF_TOPIC_OUT_PREFIX: gw.get(CONF_TOPIC_OUT_PREFIX, None),
CONF_TOPIC_IN_PREFIX: gw.get(CONF_TOPIC_IN_PREFIX, None),
user_inputs = [
{
CONF_DEVICE: gw[CONF_DEVICE],
CONF_PERSISTENCE: gw.get(CONF_PERSISTENCE_FILE, None),
CONF_BAUD_RATE: gw.get(CONF_BAUD_RATE, None),
CONF_TCP_PORT: gw.get(CONF_TCP_PORT, None),
CONF_TOPIC_OUT_PREFIX: gw.get(CONF_TOPIC_OUT_PREFIX, None),
CONF_TOPIC_IN_PREFIX: gw.get(CONF_TOPIC_IN_PREFIX, None),
CONF_OPTIMISTIC: config.get(CONF_OPTIMISTIC, None),
CONF_RETAIN: config.get(CONF_RETAIN, None),
CONF_VERSION: config.get(CONF_VERSION, None),
# nodes config ignored at this time. renaming nodes can now be done from the frontend.
}
for gw in config[CONF_GATEWAYS]
]
user_inputs = [
{k: v for k, v in userinput.items() if v is not None}
for userinput in user_inputs
]
CONF_OPTIMISTIC: config.get(CONF_OPTIMISTIC, None),
CONF_RETAIN: config.get(CONF_RETAIN, None),
CONF_VERSION: config.get(CONF_VERSION, None),
#nodes config ignored at this time. renaming nodes can now be done from the frontend.
} for gw in config[CONF_GATEWAYS]]
user_inputs = [{k: v for k, v in userinput.items() if v is not None} for userinput in user_inputs]
#there is an actual configuration in configuration.yaml, so we have to process it
# there is an actual configuration in configuration.yaml, so we have to process it
for user_input in user_inputs:
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=user_input
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data=user_input,
)
)
return True
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
"""Set up an instance of the MySensors integration.
Every instance has a connection to exactly one Gateway.
"""
_LOGGER.debug("async_setup_entry: %s (id: %s)", entry.title, entry.unique_id)
gateway = await setup_gateway(hass, entry)
@ -169,16 +183,19 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool
for platform in SUPPORTED_PLATFORMS_WITH_ENTRY_SUPPORT:
await hass.config_entries.async_forward_entry_setup(entry, platform)
await finish_setup(hass, entry, gateway)
hass.async_create_task(finish())
return True
async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
"""Remove an instance of the MySensors integration."""
_LOGGER.debug("unload entry: %s (id: %s)", entry.title, entry.unique_id)
gateway = get_mysensors_gateway(hass, entry.unique_id)
if not gateway:
_LOGGER.error("cant unload configentry %s, no gateway found", entry.unique_id)
_LOGGER.error("can't unload configentry %s, no gateway found", entry.unique_id)
return False
for platform in SUPPORTED_PLATFORMS_WITH_ENTRY_SUPPORT:
@ -196,7 +213,13 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> boo
return True
async def on_unload(hass: HomeAssistantType, entry: Union[ConfigEntry,GatewayId], fnct: Callable) -> None:
async def on_unload(
hass: HomeAssistantType, entry: Union[ConfigEntry, GatewayId], fnct: Callable
) -> None:
"""Register a callback to be called when entry is unloaded.
This function is used by platforms to cleanup after themselves
"""
if isinstance(entry, GatewayId):
uniqueid = entry
else:
@ -206,16 +229,19 @@ async def on_unload(hass: HomeAssistantType, entry: Union[ConfigEntry,GatewayId]
hass.data[key] = []
hass.data[key].append(fnct)
@callback
def setup_mysensors_platform(
hass,
domain: str, # hass platform name
discovery_info: Optional[Dict[str, List[DevId]]],
device_class: Union[Type[MySensorsDevice], Dict[SensorType, Type[MySensorsEntity]]],
device_args: Optional[Tuple] = None, # extra arguments that will be given to the entity constructor
device_args: Optional[
Tuple
] = None, # extra arguments that will be given to the entity constructor
async_add_entities: Callable = None,
) -> Optional[List[MySensorsDevice]]:
"""Set up a MySensors platform
"""Set up a MySensors platform.
Sets up a bunch of instances of a single platform that is supported by this integration.
The function is given a list of DevId, each one describing an instance to set up.
@ -234,7 +260,11 @@ def setup_mysensors_platform(
for dev_id in new_dev_ids:
devices: Dict[DevId, MySensorsDevice] = get_mysensors_devices(hass, domain)
if dev_id in devices:
_LOGGER.debug("skipping setup of %s for platform %s as it already exists", dev_id, domain)
_LOGGER.debug(
"skipping setup of %s for platform %s as it already exists",
dev_id,
domain,
)
continue
gateway_id, node_id, child_id, value_type = dev_id
gateway: Optional[BaseAsyncGateway] = get_mysensors_gateway(hass, gateway_id)

View file

@ -31,12 +31,18 @@ SENSORS = {
}
async def async_setup_platform(hass: HomeAssistantType, config, async_add_entities, discovery_info=None):
async def async_setup_platform(
hass: HomeAssistantType, config, async_add_entities, discovery_info=None
):
"""Set up the mysensors platform for binary sensors."""
pass
async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable):
async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable
):
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
async def async_discover(discovery_info):
"""Discover and add a MySensors binary_sensor."""
mysensors.setup_mysensors_platform(
@ -47,9 +53,16 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry,
async_add_entities=async_add_entities,
)
await on_unload(hass, config_entry, async_dispatcher_connect(
hass, MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN), async_discover
))
await on_unload(
hass,
config_entry,
async_dispatcher_connect(
hass,
MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN),
async_discover,
),
)
class MySensorsBinarySensor(mysensors.device.MySensorsEntity, BinarySensorEntity):
"""Representation of a MySensors Binary Sensor child node."""

View file

@ -39,12 +39,18 @@ FAN_LIST = ["Auto", "Min", "Normal", "Max"]
OPERATION_LIST = [HVAC_MODE_OFF, HVAC_MODE_AUTO, HVAC_MODE_COOL, HVAC_MODE_HEAT]
async def async_setup_platform(hass: HomeAssistantType, config, async_add_entities, discovery_info=None):
async def async_setup_platform(
hass: HomeAssistantType, config, async_add_entities, discovery_info=None
):
"""Set up the mysensors climate."""
pass
async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable):
async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable
):
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
async def async_discover(discovery_info):
"""Discover and add a MySensors climate."""
mysensors.setup_mysensors_platform(
@ -55,9 +61,15 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry,
async_add_entities=async_add_entities,
)
await on_unload(hass, config_entry, async_dispatcher_connect(
hass, MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN), async_discover
))
await on_unload(
hass,
config_entry,
async_dispatcher_connect(
hass,
MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN),
async_discover,
),
)
class MySensorsHVAC(mysensors.device.MySensorsEntity, ClimateEntity):

View file

@ -1,35 +1,48 @@
"""Config flow for MySensors."""
import asyncio
import logging
from mysensors import BaseAsyncGateway
from homeassistant.components.mysensors import CONF_DEVICE, NODE_SCHEMA, DEFAULT_BAUD_RATE, DEFAULT_TCP_PORT, \
CONF_NODE_NAME, is_persistence_file
from .const import DOMAIN, CONF_PERSISTENCE_FILE, CONF_BAUD_RATE, CONF_TCP_PORT, CONF_TOPIC_IN_PREFIX, \
CONF_TOPIC_OUT_PREFIX, CONF_NODES
from collections import OrderedDict
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
import hashlib
import async_timeout
import logging
from typing import Optional
from ..mqtt import valid_subscribe_topic, valid_publish_topic
import async_timeout
from mysensors import BaseAsyncGateway
import voluptuous as vol
from homeassistant.components.mysensors import (
CONF_DEVICE,
DEFAULT_BAUD_RATE,
DEFAULT_TCP_PORT,
is_persistence_file,
)
import homeassistant.helpers.config_validation as cv
from . import (
CONF_OPTIMISTIC,
CONF_PERSISTENCE,
CONF_RETAIN,
CONF_VERSION,
DEFAULT_VERSION,
)
from ... import config_entries
from ...config_entries import ConfigEntry
from ...core import callback
from .gateway import _get_gateway, MQTT_COMPONENT, is_serial_port, is_socket_address
from . import CONFIG_SCHEMA, CONF_VERSION, CONF_GATEWAYS, CONF_RETAIN, CONF_PERSISTENCE, CONF_OPTIMISTIC, GATEWAY_SCHEMA, DEFAULT_VERSION
from ...data_entry_flow import RESULT_TYPE_CREATE_ENTRY
from ..mqtt import valid_publish_topic, valid_subscribe_topic
from .const import (
CONF_BAUD_RATE,
CONF_PERSISTENCE_FILE,
CONF_TCP_PORT,
CONF_TOPIC_IN_PREFIX,
CONF_TOPIC_OUT_PREFIX,
DOMAIN,
)
from .gateway import MQTT_COMPONENT, _get_gateway, is_serial_port, is_socket_address
_LOGGER = logging.getLogger(__name__)
async def try_connect(hass, user_input, uniqueid):
if user_input[CONF_DEVICE]==MQTT_COMPONENT:
return True#dont validate mqtt. mqtt gateways dont send ready messages :(
async def try_connect(hass, user_input, uniqueid: str) -> bool:
"""Try to connect to a gateway and report if it worked."""
if user_input[CONF_DEVICE] == MQTT_COMPONENT:
return True # dont validate mqtt. mqtt gateways dont send ready messages :(
else:
u = user_input.copy()
u[CONF_PERSISTENCE] = False
@ -68,8 +81,9 @@ async def try_connect(hass, user_input, uniqueid):
return False
class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow."""
async def async_step_import(self, user_input):
"""Import a config entry.
@ -78,19 +92,23 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""
return await self.async_step_user(user_input=user_input)
async def async_step_user(self, user_input=None):
"""Create a config entry from frontend user input."""
errors = {}
if user_input is not None:
is_mqtt = user_input[CONF_DEVICE] == MQTT_COMPONENT
is_serial = False
try:
if user_input[CONF_DEVICE]!=MQTT_COMPONENT:
if user_input[CONF_DEVICE] != MQTT_COMPONENT:
try:
await self.hass.async_add_executor_job(is_serial_port, user_input[CONF_DEVICE])
await self.hass.async_add_executor_job(
is_serial_port, user_input[CONF_DEVICE]
)
is_serial = True
except vol.Invalid:
await self.hass.async_add_executor_job(is_socket_address, user_input[CONF_DEVICE])
await self.hass.async_add_executor_job(
is_socket_address, user_input[CONF_DEVICE]
)
is_serial = False
except vol.Invalid:
errors[CONF_DEVICE] = "invalid_device"
@ -105,7 +123,10 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
valid_publish_topic(user_input[CONF_TOPIC_OUT_PREFIX])
except vol.Invalid:
errors[CONF_TOPIC_OUT_PREFIX] = "invalid_publish_topic"
if not is_mqtt and (CONF_TCP_PORT in user_input and (user_input[CONF_TCP_PORT] < 1 or user_input[CONF_TCP_PORT] > 65535)):
if not is_mqtt and (
CONF_TCP_PORT in user_input
and (user_input[CONF_TCP_PORT] < 1 or user_input[CONF_TCP_PORT] > 65535)
):
errors[CONF_TCP_PORT] = "invalid_port"
try:
if CONF_PERSISTENCE_FILE in user_input:
@ -115,20 +136,26 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
uniquestr = user_input[CONF_DEVICE]
if is_mqtt:
uniquestr += user_input[CONF_TOPIC_IN_PREFIX] + user_input[CONF_TOPIC_OUT_PREFIX]
uniquestr += (
user_input[CONF_TOPIC_IN_PREFIX] + user_input[CONF_TOPIC_OUT_PREFIX]
)
elif not is_serial:
uniquestr += str(user_input[CONF_TCP_PORT])
gateway_id = hashlib.sha256(uniquestr.encode()).hexdigest()[:8]
await self.async_set_unique_id(gateway_id)
self._abort_if_unique_id_configured()
#if no errors so far, try to connect
if not errors and not await try_connect(self.hass, user_input, uniqueid=gateway_id):
# if no errors so far, try to connect
if not errors and not await try_connect(
self.hass, user_input, uniqueid=gateway_id
):
errors["base"] = "cannot_connect"
if not errors:
_LOGGER.info("config_flow completed for %s", gateway_id)
return self.async_create_entry(title=f"{user_input[CONF_DEVICE]}", data=user_input)
return self.async_create_entry(
title=f"{user_input[CONF_DEVICE]}", data=user_input
)
schema = OrderedDict()
schema[vol.Optional(CONF_OPTIMISTIC, default=False)] = bool
@ -137,16 +164,13 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
schema[vol.Optional(CONF_VERSION, default=DEFAULT_VERSION)] = str
schema[vol.Required(CONF_DEVICE, default="127.0.0.1")] = str
#schema[vol.Optional(CONF_PERSISTENCE_FILE)] = str
schema[vol.Optional(CONF_BAUD_RATE, default=DEFAULT_BAUD_RATE)] = cv.positive_int
# schema[vol.Optional(CONF_PERSISTENCE_FILE)] = str
schema[
vol.Optional(CONF_BAUD_RATE, default=DEFAULT_BAUD_RATE)
] = cv.positive_int
schema[vol.Optional(CONF_TCP_PORT, default=DEFAULT_TCP_PORT)] = int
schema[vol.Optional(CONF_TOPIC_IN_PREFIX)] = str
schema[vol.Optional(CONF_TOPIC_OUT_PREFIX)] = str
schema = vol.Schema(schema)
return self.async_show_form(
step_id="user",
data_schema=schema,
errors=errors
)
return self.async_show_form(step_id="user", data_schema=schema, errors=errors)

View file

@ -1,6 +1,6 @@
"""MySensors constants."""
from collections import defaultdict
from typing import Set, Dict, Tuple, List
from typing import Dict, List, Set, Tuple
ATTR_DEVICES: str = "devices"
@ -62,7 +62,9 @@ BINARY_SENSOR_TYPES: Dict[SensorType, Set[ValueType]] = {
CLIMATE_TYPES: Dict[SensorType, Set[ValueType]] = {"S_HVAC": {"V_HVAC_FLOW_STATE"}}
COVER_TYPES: Dict[SensorType, Set[ValueType]] = {"S_COVER": {"V_DIMMER", "V_PERCENTAGE", "V_LIGHT", "V_STATUS"}}
COVER_TYPES: Dict[SensorType, Set[ValueType]] = {
"S_COVER": {"V_DIMMER", "V_PERCENTAGE", "V_LIGHT", "V_STATUS"}
}
DEVICE_TRACKER_TYPES: Dict[SensorType, Set[ValueType]] = {"S_GPS": {"V_POSITION"}}
@ -138,7 +140,7 @@ FLAT_PLATFORM_TYPES: Dict[Tuple[str, SensorType], Set[ValueType]] = {
}
"""flatter version of PLATFORM_TYPES
dict mapping tuples of hass platform name and mysensors s_type to mysensors v_type
dict mapping tuples of hass platform name and mysensors s_type to mysensors v_type
"""
TYPE_TO_PLATFORMS: Dict[SensorType, List[str]] = defaultdict(list)

View file

@ -14,12 +14,17 @@ from homeassistant.helpers.typing import HomeAssistantType
_LOGGER = logging.getLogger(__name__)
async def async_setup_platform(hass: HomeAssistantType, config, async_add_entities, discovery_info=None):
async def async_setup_platform(
hass: HomeAssistantType, config, async_add_entities, discovery_info=None
):
"""Set up the mysensors platform for covers."""
pass
async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable):
async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable
):
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
async def async_discover(discovery_info):
"""Discover and add a MySensors cover."""
@ -31,9 +36,15 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry,
async_add_entities=async_add_entities,
)
await on_unload(hass, config_entry, async_dispatcher_connect(
hass, MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN), async_discover
))
await on_unload(
hass,
config_entry,
async_dispatcher_connect(
hass,
MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN),
async_discover,
),
)
class MySensorsCover(mysensors.device.MySensorsEntity, CoverEntity):

View file

@ -1,19 +1,24 @@
"""Handle MySensors devices."""
from functools import partial
import logging
from typing import Dict, List, Optional, Any
from typing import Any, Dict, Optional
from mysensors import Sensor, BaseAsyncGateway
from mysensors import BaseAsyncGateway, Sensor
from mysensors.sensor import ChildSensor
from homeassistant.const import ATTR_BATTERY_LEVEL, STATE_OFF, STATE_ON
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
from .const import DevId, PLATFORM_TYPES
from .const import DOMAIN
from .const import CHILD_CALLBACK, NODE_CALLBACK, UPDATE_DELAY
from .const import (
CHILD_CALLBACK,
DOMAIN,
NODE_CALLBACK,
PLATFORM_TYPES,
UPDATE_DELAY,
DevId,
)
_LOGGER = logging.getLogger(__name__)
@ -33,7 +38,7 @@ class MySensorsDevice:
self.gateway: BaseAsyncGateway = gateway
self.node_id: int = node_id
self.child_id: int = child_id
self.value_type: int = value_type # value_type as int. string variant can be looked up in gateway consts
self.value_type: int = value_type # value_type as int. string variant can be looked up in gateway consts
self.child_type = self._mysensors_childsensor.type
self._values = {}
self._update_scheduled = False
@ -41,26 +46,35 @@ class MySensorsDevice:
@property
def dev_id(self) -> DevId:
"""Return the DevId of this device.
It is used to route incoming MySensors messages to the correct device/entity.
"""
return self.gateway_id, self.node_id, self.child_id, self.value_type
@property
def logger(self):
def _logger(self):
return logging.getLogger(f"{__name__}.{self.name}")
async def async_will_remove_from_hass(self):
"""Remove this entity from home assistant."""
for platform in PLATFORM_TYPES:
platform_str = MYSENSORS_PLATFORM_DEVICES.format(platform)
if platform_str in self.hass.data:
platform_dict = self.hass.data[platform_str]
if self.dev_id in platform_dict:
if platform_dict[self.dev_id] is not self:
self.logger.warning("possible duplicate device: %s", self.dev_id)
self._logger.warning(
"possible duplicate device: %s", self.dev_id
)
del platform_dict[self.dev_id]
self.logger.debug("deleted %s from platform %s", self.dev_id, platform)
self._logger.debug(
"deleted %s from platform %s", self.dev_id, platform
)
@property
def gateway_id(self) -> str:
"""Return the id of the gateway that this device belongs to."""
return self.gateway.unique_id
@property
@ -73,28 +87,29 @@ class MySensorsDevice:
@property
def sketch_name(self) -> str:
"""Return the name of the sketch running on the whole node (will be the same for several entities!)."""
return self._mysensors_sensor.sketch_name
@property
def sketch_version(self) -> str:
"""Return the version of the sketch running on the whole node (will be the same for several entities!)."""
return self._mysensors_sensor.sketch_version
@property
def node_name(self) -> str:
"""Name of the whole node (will be the same for several entities!)"""
"""Name of the whole node (will be the same for several entities!)."""
return f"{self.sketch_name} {self.node_id}"
@property
def unique_id(self) -> str:
"""Return a unique ID."""
"""Return a unique ID for use in home assistant."""
return f"mys{self.gateway_id}-{self.node_id}-{self.child_id}-{self.value_type}"
@property
def device_info(self) -> Optional[Dict[str, Any]]:
"""Return a dict that allows home assistant to puzzle all entities belonging to a node together."""
return {
"identifiers": {
(DOMAIN, f"mys{self.gateway_id}-{self.node_id}")
},
"identifiers": {(DOMAIN, f"mys{self.gateway_id}-{self.node_id}")},
"name": self.node_name,
"manufacturer": DOMAIN,
"model": self.node_name,
@ -176,11 +191,12 @@ class MySensorsDevice:
def get_mysensors_devices(hass, domain: str) -> Dict[DevId, MySensorsDevice]:
"""Return MySensors devices for a hass platform name"""
"""Return MySensors devices for a hass platform name."""
if MYSENSORS_PLATFORM_DEVICES.format(domain) not in hass.data:
hass.data[MYSENSORS_PLATFORM_DEVICES.format(domain)] = {}
return hass.data[MYSENSORS_PLATFORM_DEVICES.format(domain)]
class MySensorsEntity(MySensorsDevice, Entity):
"""Representation of a MySensors entity."""
@ -202,7 +218,9 @@ class MySensorsEntity(MySensorsDevice, Entity):
"""Register update callback."""
self.async_on_remove(
async_dispatcher_connect(
self.hass, CHILD_CALLBACK.format(*self.dev_id), self.async_update_callback
self.hass,
CHILD_CALLBACK.format(*self.dev_id),
self.async_update_callback,
)
)
self.async_on_remove(

View file

@ -1,24 +1,16 @@
"""Support for tracking MySensors devices."""
from typing import Callable
from homeassistant.components import mysensors
from homeassistant.components.device_tracker import DOMAIN
from homeassistant.components.mysensors import DevId, on_unload
from homeassistant.components.mysensors.const import GatewayId
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.util import slugify
async def async_setup_platform(hass: HomeAssistantType, config, async_add_entities, discovery_info=None) -> None:
pass
async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable) -> None:
pass
async def async_setup_scanner(hass, config, async_see, discovery_info=None):
async def async_setup_scanner(
hass: HomeAssistantType, config, async_see, discovery_info=None
):
"""Set up the MySensors device scanner."""
new_devices = mysensors.setup_mysensors_platform(
hass,
@ -33,16 +25,24 @@ async def async_setup_scanner(hass, config, async_see, discovery_info=None):
for device in new_devices:
gateway_id: GatewayId = device.gateway.unique_id
dev_id: DevId = (gateway_id, device.node_id, device.child_id, device.value_type)
await on_unload(hass, gateway_id, async_dispatcher_connect(
await on_unload(
hass,
mysensors.const.CHILD_CALLBACK.format(*dev_id),
device.async_update_callback,
))
await on_unload(hass, gateway_id, async_dispatcher_connect(
gateway_id,
async_dispatcher_connect(
hass,
mysensors.const.CHILD_CALLBACK.format(*dev_id),
device.async_update_callback,
),
)
await on_unload(
hass,
mysensors.const.NODE_CALLBACK.format(gateway_id, device.node_id),
device.async_update_callback,
))
gateway_id,
async_dispatcher_connect(
hass,
mysensors.const.NODE_CALLBACK.format(gateway_id, device.node_id),
device.async_update_callback,
),
)
return True
@ -50,7 +50,7 @@ async def async_setup_scanner(hass, config, async_see, discovery_info=None):
class MySensorsDeviceScanner(mysensors.device.MySensorsDevice):
"""Represent a MySensors scanner."""
def __init__(self, hass, async_see, *args):
def __init__(self, hass: HomeAssistantType, async_see, *args):
"""Set up instance."""
super().__init__(*args)
self.async_see = async_see

View file

@ -4,22 +4,21 @@ from collections import defaultdict
import logging
import socket
import sys
from typing import Any, Callable, Coroutine, Dict, Optional, Union
import async_timeout
from mysensors import mysensors, BaseAsyncGateway, Sensor, Message
from typing import Optional, List, Any, Callable, Coroutine, Union, Dict
from mysensors import BaseAsyncGateway, Message, Sensor, mysensors
import voluptuous as vol
from homeassistant.const import CONF_OPTIMISTIC, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from homeassistant.setup import async_setup_component
from ...config_entries import ConfigEntry
from ...helpers.typing import HomeAssistantType
from .const import (
CONF_BAUD_RATE,
CONF_DEVICE,
CONF_GATEWAYS,
CONF_NODES,
CONF_PERSISTENCE,
CONF_PERSISTENCE_FILE,
CONF_RETAIN,
@ -27,15 +26,12 @@ from .const import (
CONF_TOPIC_IN_PREFIX,
CONF_TOPIC_OUT_PREFIX,
CONF_VERSION,
DOMAIN,
MYSENSORS_GATEWAY_READY,
MYSENSORS_GATEWAYS,
GatewayId,
)
from .const import GatewayId
from .handler import HANDLERS
from .helpers import discover_mysensors_platform, validate_child, validate_node
from ...config_entries import ConfigEntry
from ...helpers.typing import HomeAssistantType
_LOGGER = logging.getLogger(__name__)
@ -62,22 +58,30 @@ def is_socket_address(value):
raise vol.Invalid("Device is not a valid domain name or ip address") from err
def get_mysensors_gateway(hass: HomeAssistantType, gateway_id: GatewayId) -> Optional[BaseAsyncGateway]:
"""Returns the Gateway for a given GatewayId."""
def get_mysensors_gateway(
hass: HomeAssistantType, gateway_id: GatewayId
) -> Optional[BaseAsyncGateway]:
"""Return the Gateway for a given GatewayId."""
if MYSENSORS_GATEWAYS not in hass.data:
hass.data[MYSENSORS_GATEWAYS] = {}
gateways = hass.data.get(MYSENSORS_GATEWAYS)
return gateways.get(gateway_id)
async def setup_gateway(hass: HomeAssistantType, entry: ConfigEntry) -> Optional[BaseAsyncGateway]:
async def setup_gateway(
hass: HomeAssistantType, entry: ConfigEntry
) -> Optional[BaseAsyncGateway]:
"""Set up all gateways."""
ready_gateway = await _get_gateway(hass, entry)
return ready_gateway
async def _get_gateway(hass: HomeAssistantType, entry: Union[ConfigEntry,Dict[str, Any]], unique_id: Optional[str]=None) -> Optional[BaseAsyncGateway]:
async def _get_gateway(
hass: HomeAssistantType,
entry: Union[ConfigEntry, Dict[str, Any]],
unique_id: Optional[str] = None,
) -> Optional[BaseAsyncGateway]:
"""Return gateway after setup of the gateway."""
if isinstance(entry, ConfigEntry):
@ -87,8 +91,12 @@ async def _get_gateway(hass: HomeAssistantType, entry: Union[ConfigEntry,Dict[st
data: Dict[str, Any] = entry
if unique_id is None:
raise ValueError("no unique id! either give configEntry for auto-extraction or explicitly give one")
persistence_file = data.get(CONF_PERSISTENCE_FILE, hass.config.path(f"mysensors{unique_id}.pickle"))
raise ValueError(
"no unique id! either give configEntry for auto-extraction or explicitly give one"
)
persistence_file = data.get(
CONF_PERSISTENCE_FILE, hass.config.path(f"mysensors{unique_id}.pickle")
)
persistence = data.get(CONF_PERSISTENCE)
version = data.get(CONF_VERSION)
device = data.get(CONF_DEVICE)
@ -98,8 +106,8 @@ async def _get_gateway(hass: HomeAssistantType, entry: Union[ConfigEntry,Dict[st
out_prefix = data.get(CONF_TOPIC_OUT_PREFIX, "")
if device == MQTT_COMPONENT:
#what is the purpose of this?
#if not await async_setup_component(hass, MQTT_COMPONENT, entry):
# what is the purpose of this?
# if not await async_setup_component(hass, MQTT_COMPONENT, entry):
# return None
mqtt = hass.components.mqtt
retain = data.get(CONF_RETAIN)
@ -170,7 +178,9 @@ async def _get_gateway(hass: HomeAssistantType, entry: Union[ConfigEntry,Dict[st
return gateway
async def finish_setup(hass: HomeAssistantType, hass_config: ConfigEntry, gateway: BaseAsyncGateway):
async def finish_setup(
hass: HomeAssistantType, hass_config: ConfigEntry, gateway: BaseAsyncGateway
):
"""Load any persistent devices and platforms and start gateway."""
discover_tasks = []
start_tasks = []
@ -183,7 +193,9 @@ async def finish_setup(hass: HomeAssistantType, hass_config: ConfigEntry, gatewa
await asyncio.wait(start_tasks)
async def _discover_persistent_devices(hass: HomeAssistantType, hass_config: ConfigEntry, gateway: BaseAsyncGateway):
async def _discover_persistent_devices(
hass: HomeAssistantType, hass_config: ConfigEntry, gateway: BaseAsyncGateway
):
"""Discover platforms for devices loaded via persistence file."""
tasks = []
new_devices = defaultdict(list)
@ -191,7 +203,7 @@ async def _discover_persistent_devices(hass: HomeAssistantType, hass_config: Con
if not validate_node(gateway, node_id):
continue
node: Sensor = gateway.sensors[node_id]
for child in node.children.values():#child is of type ChildSensor
for child in node.children.values(): # child is of type ChildSensor
validated = validate_child(gateway, node_id, child)
for platform, dev_ids in validated.items():
new_devices[platform].extend(dev_ids)
@ -201,9 +213,15 @@ async def _discover_persistent_devices(hass: HomeAssistantType, hass_config: Con
if tasks:
await asyncio.wait(tasks)
async def gw_stop(hass, gateway: BaseAsyncGateway):
"""Stop the gateway."""
_LOGGER.info("stopping gateway %s", gateway.unique_id)
if hasattr(gateway, "connect_task") and gateway.connect_task is not None and not gateway.connect_task.done():
if (
hasattr(gateway, "connect_task")
and gateway.connect_task is not None
and not gateway.connect_task.done()
):
gateway.connect_task.cancel()
await gateway.stop()
@ -213,7 +231,9 @@ async def _gw_start(hass: HomeAssistantType, gateway: BaseAsyncGateway):
# Don't use hass.async_create_task to avoid holding up setup indefinitely.
gateway.connect_task = hass.loop.create_task(gateway.start())
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, lambda event: gw_stop(hass, gateway))
hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP, lambda event: gw_stop(hass, gateway)
)
if gateway.device == "mqtt":
# Gatways connected via mqtt doesn't send gateway ready message.
return
@ -234,18 +254,24 @@ async def _gw_start(hass: HomeAssistantType, gateway: BaseAsyncGateway):
hass.data.pop(gateway_ready_key, None)
def _gw_callback_factory(hass: HomeAssistantType, hass_config: ConfigEntry) -> Callable[[Message], None]:
def _gw_callback_factory(
hass: HomeAssistantType, hass_config: ConfigEntry
) -> Callable[[Message], None]:
"""Return a new callback for the gateway."""
@callback
def mysensors_callback(msg: Message):
"""Handle messages from a MySensors gateway."""
"""Handle messages from a MySensors gateway.
All MySenors messages are received here.
The messages are passed to handler functions depending on their type.
"""
_LOGGER.debug("Node update: node %s child %s", msg.node_id, msg.child_id)
msg_type = msg.gateway.const.MessageType(msg.type)
msg_handler: Callable[[Any, ConfigEntry, Message], Coroutine[None]] = HANDLERS.get(
msg_type.name
)
msg_handler: Callable[
[Any, ConfigEntry, Message], Coroutine[None]
] = HANDLERS.get(msg_type.name)
if msg_handler is None:
return

View file

@ -7,11 +7,10 @@ from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.util import decorator
from .const import CHILD_CALLBACK, MYSENSORS_GATEWAY_READY, NODE_CALLBACK
from .const import DevId
from ...config_entries import ConfigEntry
from .const import CHILD_CALLBACK, MYSENSORS_GATEWAY_READY, NODE_CALLBACK, DevId
from .device import get_mysensors_devices
from .helpers import discover_mysensors_platform, validate_set_msg
from ...config_entries import ConfigEntry
HANDLERS = decorator.Registry()
@ -70,7 +69,9 @@ async def handle_gateway_ready(hass, hass_config: ConfigEntry, msg: Message) ->
@callback
def _handle_child_update(hass, hass_config: ConfigEntry, validated: Dict[str, List[DevId]]):
def _handle_child_update(
hass, hass_config: ConfigEntry, validated: Dict[str, List[DevId]]
):
"""Handle a child update."""
signals: List[str] = []

View file

@ -1,80 +1,104 @@
"""Helper functions for mysensors package."""
from collections import defaultdict
import logging
from enum import IntEnum
import logging
from typing import DefaultDict, Dict, List, Optional, Set
import voluptuous as vol
from mysensors import BaseAsyncGateway, Message
from typing import Dict, Tuple, Optional, List, Set, Any, DefaultDict
from mysensors.sensor import ChildSensor
import voluptuous as vol
from homeassistant.const import CONF_NAME
from homeassistant.core import callback
from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv
from homeassistant.util.decorator import Registry
from .const import ATTR_DEVICES, DOMAIN, FLAT_PLATFORM_TYPES, TYPE_TO_PLATFORMS, ValueType, SensorType, DevId, \
MYSENSORS_DISCOVERY
from ...config_entries import ConfigEntry
from ...helpers.dispatcher import async_dispatcher_send
from .const import (
ATTR_DEVICES,
DOMAIN,
FLAT_PLATFORM_TYPES,
MYSENSORS_DISCOVERY,
TYPE_TO_PLATFORMS,
DevId,
SensorType,
ValueType,
)
_LOGGER = logging.getLogger(__name__)
SCHEMAS = Registry()
@callback
def discover_mysensors_platform(hass, hass_config: ConfigEntry, platform: str, new_devices: List[DevId]) -> None:
def discover_mysensors_platform(
hass, hass_config: ConfigEntry, platform: str, new_devices: List[DevId]
) -> None:
"""Discover a MySensors platform."""
_LOGGER.debug("discovering platform %s with devIds: %s", platform, new_devices)
async_dispatcher_send(
hass, MYSENSORS_DISCOVERY.format(hass_config.unique_id, platform), {ATTR_DEVICES: new_devices, CONF_NAME: DOMAIN}
hass,
MYSENSORS_DISCOVERY.format(hass_config.unique_id, platform),
{ATTR_DEVICES: new_devices, CONF_NAME: DOMAIN},
)
def default_schema(gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType) -> vol.Schema:
def default_schema(
gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
) -> vol.Schema:
"""Return a default validation schema for value types."""
schema = {value_type_name: cv.string}
return get_child_schema(gateway, child, value_type_name, schema)
@SCHEMAS.register(("light", "V_DIMMER"))
def light_dimmer_schema(gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType) -> vol.Schema:
def light_dimmer_schema(
gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
) -> vol.Schema:
"""Return a validation schema for V_DIMMER."""
schema = {"V_DIMMER": cv.string, "V_LIGHT": cv.string}
return get_child_schema(gateway, child, value_type_name, schema)
@SCHEMAS.register(("light", "V_PERCENTAGE"))
def light_percentage_schema(gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType) -> vol.Schema:
def light_percentage_schema(
gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
) -> vol.Schema:
"""Return a validation schema for V_PERCENTAGE."""
schema = {"V_PERCENTAGE": cv.string, "V_STATUS": cv.string}
return get_child_schema(gateway, child, value_type_name, schema)
@SCHEMAS.register(("light", "V_RGB"))
def light_rgb_schema(gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType) -> vol.Schema:
def light_rgb_schema(
gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
) -> vol.Schema:
"""Return a validation schema for V_RGB."""
schema = {"V_RGB": cv.string, "V_STATUS": cv.string}
return get_child_schema(gateway, child, value_type_name, schema)
@SCHEMAS.register(("light", "V_RGBW"))
def light_rgbw_schema(gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType) -> vol.Schema:
def light_rgbw_schema(
gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
) -> vol.Schema:
"""Return a validation schema for V_RGBW."""
schema = {"V_RGBW": cv.string, "V_STATUS": cv.string}
return get_child_schema(gateway, child, value_type_name, schema)
@SCHEMAS.register(("switch", "V_IR_SEND"))
def switch_ir_send_schema(gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType) -> vol.Schema:
def switch_ir_send_schema(
gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
) -> vol.Schema:
"""Return a validation schema for V_IR_SEND."""
schema = {"V_IR_SEND": cv.string, "V_LIGHT": cv.string}
return get_child_schema(gateway, child, value_type_name, schema)
def get_child_schema(gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType, schema) -> vol.Schema:
def get_child_schema(
gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType, schema
) -> vol.Schema:
"""Return a child schema."""
set_req = gateway.const.SetReq
child_schema = child.get_schema(gateway.protocol_version)
@ -90,7 +114,9 @@ def get_child_schema(gateway: BaseAsyncGateway, child: ChildSensor, value_type_n
return schema
def invalid_msg(gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType):
def invalid_msg(
gateway: BaseAsyncGateway, child: ChildSensor, value_type_name: ValueType
):
"""Return a message for an invalid child during schema validation."""
pres = gateway.const.Presentation
set_req = gateway.const.SetReq
@ -115,8 +141,13 @@ def validate_node(gateway: BaseAsyncGateway, node_id: int) -> bool:
return True
def validate_child(gateway: BaseAsyncGateway, node_id: int, child: ChildSensor, value_type: Optional[int] = None) -> DefaultDict[str, List[DevId]]:
"""Validate a child. Returns a dict mapping hass platform names to list of DevId"""
def validate_child(
gateway: BaseAsyncGateway,
node_id: int,
child: ChildSensor,
value_type: Optional[int] = None,
) -> DefaultDict[str, List[DevId]]:
"""Validate a child. Returns a dict mapping hass platform names to list of DevId."""
validated: defaultdict[str, List[DevId]] = defaultdict(list)
pres: IntEnum = gateway.const.Presentation
set_req: IntEnum = gateway.const.SetReq
@ -133,7 +164,9 @@ def validate_child(gateway: BaseAsyncGateway, node_id: int, child: ChildSensor,
return validated
for platform in platforms:
platform_v_names: Set[ValueType] = FLAT_PLATFORM_TYPES[platform, child_type_name]
platform_v_names: Set[ValueType] = FLAT_PLATFORM_TYPES[
platform, child_type_name
]
v_names: Set[ValueType] = platform_v_names & value_type_names
if not v_names:
child_value_names: Set[ValueType] = {
@ -155,7 +188,12 @@ def validate_child(gateway: BaseAsyncGateway, node_id: int, child: ChildSensor,
exc,
)
continue
dev_id: DevId = gateway.unique_id, node_id, child.id, set_req[v_name].value
dev_id: DevId = (
gateway.unique_id,
node_id,
child.id,
set_req[v_name].value,
)
validated[platform].append(dev_id)
return validated

View file

@ -17,25 +17,31 @@ from homeassistant.components.mysensors.const import MYSENSORS_DISCOVERY
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.core import callback
import homeassistant.util.color as color_util
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.typing import HomeAssistantType
import homeassistant.util.color as color_util
from homeassistant.util.color import rgb_hex_to_rgb_list
SUPPORT_MYSENSORS_RGBW = SUPPORT_COLOR | SUPPORT_WHITE_VALUE
async def async_setup_platform(hass: HomeAssistantType, config, async_add_entities, discovery_info=None):
async def async_setup_platform(
hass: HomeAssistantType, config, async_add_entities, discovery_info=None
):
"""Set up the mysensors platform for lights."""
pass
async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable):
async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable
):
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
device_class_map = {
"S_DIMMER": MySensorsLightDimmer,
"S_RGB_LIGHT": MySensorsLightRGB,
"S_RGBW_LIGHT": MySensorsLightRGBW,
}
async def async_discover(discovery_info):
"""Discover and add a MySensors light."""
mysensors.setup_mysensors_platform(
@ -46,9 +52,16 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry,
async_add_entities=async_add_entities,
)
await on_unload(hass, config_entry, async_dispatcher_connect(
hass, MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN), async_discover
))
await on_unload(
hass,
config_entry,
async_dispatcher_connect(
hass,
MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN),
async_discover,
),
)
class MySensorsLight(mysensors.device.MySensorsEntity, LightEntity):
"""Representation of a MySensors Light child node."""

View file

@ -61,12 +61,18 @@ SENSORS = {
}
async def async_setup_platform(hass: HomeAssistantType, config, async_add_entities, discovery_info=None):
async def async_setup_platform(
hass: HomeAssistantType, config, async_add_entities, discovery_info=None
):
"""Set up the MySensors platform for sensors."""
pass
async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable):
async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable
):
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
async def async_discover(discovery_info):
"""Discover and add a MySensors sensor."""
mysensors.setup_mysensors_platform(
@ -77,9 +83,15 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry,
async_add_entities=async_add_entities,
)
await on_unload(hass, config_entry, async_dispatcher_connect(
hass, MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN), async_discover
))
await on_unload(
hass,
config_entry,
async_dispatcher_connect(
hass,
MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN),
async_discover,
),
)
class MySensorsSensor(mysensors.device.MySensorsEntity):

View file

@ -7,12 +7,12 @@ from homeassistant.components import mysensors
from homeassistant.components.switch import DOMAIN, SwitchEntity
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON
import homeassistant.helpers.config_validation as cv
from . import on_unload
from .const import DOMAIN as MYSENSORS_DOMAIN, SERVICE_SEND_IR_CODE, MYSENSORS_DISCOVERY
from . import on_unload
from ...config_entries import ConfigEntry
from ...helpers.dispatcher import async_dispatcher_connect
from ...helpers.typing import HomeAssistantType
from .const import DOMAIN as MYSENSORS_DOMAIN, MYSENSORS_DISCOVERY, SERVICE_SEND_IR_CODE
ATTR_IR_CODE = "V_IR_SEND"
@ -21,12 +21,17 @@ SEND_IR_CODE_SERVICE_SCHEMA = vol.Schema(
)
async def async_setup_platform(hass: HomeAssistantType, config, async_add_entities, discovery_info=None):
async def async_setup_platform(
hass: HomeAssistantType, config, async_add_entities, discovery_info=None
):
"""Set up the mysensors platform for switches."""
pass
async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable):
"""Set up the mysensors platform for switches."""
async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities: Callable
):
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
device_class_map = {
"S_DOOR": MySensorsSwitch,
"S_MOTION": MySensorsSwitch,
@ -64,7 +69,7 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry,
device
for device in devices.values()
if isinstance(device, MySensorsIRSwitch)
and device.entity_id in entity_ids
and device.entity_id in entity_ids
]
else:
_devices = [
@ -84,9 +89,15 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry,
schema=SEND_IR_CODE_SERVICE_SCHEMA,
)
await on_unload(hass, config_entry, async_dispatcher_connect(
hass, MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN), async_discover
))
await on_unload(
hass,
config_entry,
async_dispatcher_connect(
hass,
MYSENSORS_DISCOVERY.format(config_entry.unique_id, DOMAIN),
async_discover,
),
)
class MySensorsSwitch(mysensors.device.MySensorsEntity, SwitchEntity):

View file

@ -1542,7 +1542,7 @@ pymusiccast==0.1.6
pymyq==2.0.14
# homeassistant.components.mysensors
pymysensors==0.18.0
pymysensors==0.20.1
# homeassistant.components.nanoleaf
pynanoleaf==0.0.5

View file

@ -788,7 +788,7 @@ pymonoprice==0.3
pymyq==2.0.14
# homeassistant.components.mysensors
pymysensors==0.18.0
pymysensors==0.20.1
# homeassistant.components.nut
pynut2==2.1.2