Use update coordinator for Xioami Miio subdevices (#46251)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
starkillerOG 2021-02-16 15:28:25 +01:00 committed by GitHub
parent add0d9d3eb
commit 9d8ba6af96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 39 deletions

View file

@ -1,7 +1,13 @@
"""Support for Xiaomi Miio."""
from datetime import timedelta
import logging
from miio.gateway import GatewayException
from homeassistant import config_entries, core
from homeassistant.const import CONF_HOST, CONF_TOKEN
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import (
CONF_DEVICE,
@ -9,10 +15,13 @@ from .const import (
CONF_GATEWAY,
CONF_MODEL,
DOMAIN,
KEY_COORDINATOR,
MODELS_SWITCH,
)
from .gateway import ConnectXiaomiGateway
_LOGGER = logging.getLogger(__name__)
GATEWAY_PLATFORMS = ["alarm_control_panel", "sensor", "light"]
SWITCH_PLATFORMS = ["switch"]
@ -56,8 +65,6 @@ async def async_setup_gateway_entry(
return False
gateway_info = gateway.gateway_info
hass.data[DOMAIN][entry.entry_id] = gateway.gateway_device
gateway_model = f"{gateway_info.model}-{gateway_info.hardware_version}"
device_registry = await dr.async_get_registry(hass)
@ -71,6 +78,30 @@ async def async_setup_gateway_entry(
sw_version=gateway_info.firmware_version,
)
async def async_update_data():
"""Fetch data from the subdevice."""
try:
for sub_device in gateway.gateway_device.devices.values():
await hass.async_add_executor_job(sub_device.update)
except GatewayException as ex:
raise UpdateFailed("Got exception while fetching the state") from ex
# Create update coordinator
coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
# Name of the data. For logging purposes.
name=name,
update_method=async_update_data,
# Polling interval. Will only be polled if there are subscribers.
update_interval=timedelta(seconds=10),
)
hass.data[DOMAIN][entry.entry_id] = {
CONF_GATEWAY: gateway.gateway_device,
KEY_COORDINATOR: coordinator,
}
for component in GATEWAY_PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, component)

View file

@ -15,7 +15,7 @@ from homeassistant.const import (
STATE_ALARM_DISARMED,
)
from .const import DOMAIN
from .const import CONF_GATEWAY, DOMAIN
_LOGGER = logging.getLogger(__name__)
@ -27,7 +27,7 @@ XIAOMI_STATE_ARMING_VALUE = "oning"
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Xiaomi Gateway Alarm from a config entry."""
entities = []
gateway = hass.data[DOMAIN][config_entry.entry_id]
gateway = hass.data[DOMAIN][config_entry.entry_id][CONF_GATEWAY]
entity = XiaomiGatewayAlarm(
gateway,
f"{config_entry.title} Alarm",

View file

@ -7,6 +7,8 @@ CONF_DEVICE = "device"
CONF_MODEL = "model"
CONF_MAC = "mac"
KEY_COORDINATOR = "coordinator"
MODELS_GATEWAY = ["lumi.gateway", "lumi.acpartner"]
MODELS_SWITCH = [
"chuangmi.plug.v1",

View file

@ -4,6 +4,7 @@ import logging
from miio import DeviceException, gateway
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
@ -56,16 +57,16 @@ class ConnectXiaomiGateway:
return True
class XiaomiGatewayDevice(Entity):
class XiaomiGatewayDevice(CoordinatorEntity, Entity):
"""Representation of a base Xiaomi Gateway Device."""
def __init__(self, sub_device, entry):
def __init__(self, coordinator, sub_device, entry):
"""Initialize the Xiaomi Gateway Device."""
super().__init__(coordinator)
self._sub_device = sub_device
self._entry = entry
self._unique_id = sub_device.sid
self._name = f"{sub_device.name} ({sub_device.sid})"
self._available = False
@property
def unique_id(self):
@ -88,18 +89,3 @@ class XiaomiGatewayDevice(Entity):
"model": self._sub_device.model,
"sw_version": self._sub_device.firmware_version,
}
@property
def available(self):
"""Return true when state is known."""
return self._available
async def async_update(self):
"""Fetch state from the sub device."""
try:
await self.hass.async_add_executor_job(self._sub_device.update)
self._available = True
except gateway.GatewayException as ex:
if self._available:
self._available = False
_LOGGER.error("Got exception while fetching the state: %s", ex)

View file

@ -130,7 +130,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
entities = []
if config_entry.data[CONF_FLOW_TYPE] == CONF_GATEWAY:
gateway = hass.data[DOMAIN][config_entry.entry_id]
gateway = hass.data[DOMAIN][config_entry.entry_id][CONF_GATEWAY]
# Gateway light
if gateway.model not in [
GATEWAY_MODEL_AC_V1,

View file

@ -2,13 +2,13 @@
from dataclasses import dataclass
import logging
from miio import AirQualityMonitor, DeviceException # pylint: disable=import-error
from miio import AirQualityMonitor # pylint: disable=import-error
from miio import DeviceException
from miio.gateway import (
GATEWAY_MODEL_AC_V1,
GATEWAY_MODEL_AC_V2,
GATEWAY_MODEL_AC_V3,
GATEWAY_MODEL_EU,
DeviceType,
GatewayException,
)
import voluptuous as vol
@ -31,7 +31,7 @@ from homeassistant.exceptions import PlatformNotReady
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from .const import CONF_FLOW_TYPE, CONF_GATEWAY, DOMAIN
from .const import CONF_FLOW_TYPE, CONF_GATEWAY, DOMAIN, KEY_COORDINATOR
from .gateway import XiaomiGatewayDevice
_LOGGER = logging.getLogger(__name__)
@ -87,7 +87,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
entities = []
if config_entry.data[CONF_FLOW_TYPE] == CONF_GATEWAY:
gateway = hass.data[DOMAIN][config_entry.entry_id]
gateway = hass.data[DOMAIN][config_entry.entry_id][CONF_GATEWAY]
# Gateway illuminance sensor
if gateway.model not in [
GATEWAY_MODEL_AC_V1,
@ -102,16 +102,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
)
# Gateway sub devices
sub_devices = gateway.devices
coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR]
for sub_device in sub_devices.values():
sensor_variables = None
if sub_device.type == DeviceType.SensorHT:
sensor_variables = ["temperature", "humidity"]
if sub_device.type == DeviceType.AqaraHT:
sensor_variables = ["temperature", "humidity", "pressure"]
if sensor_variables is not None:
sensor_variables = set(sub_device.status) & set(GATEWAY_SENSOR_TYPES)
if sensor_variables:
entities.extend(
[
XiaomiGatewaySensor(sub_device, config_entry, variable)
XiaomiGatewaySensor(
coordinator, sub_device, config_entry, variable
)
for variable in sensor_variables
]
)
@ -240,9 +239,9 @@ class XiaomiAirQualityMonitor(Entity):
class XiaomiGatewaySensor(XiaomiGatewayDevice):
"""Representation of a XiaomiGatewaySensor."""
def __init__(self, sub_device, entry, data_key):
def __init__(self, coordinator, sub_device, entry, data_key):
"""Initialize the XiaomiSensor."""
super().__init__(sub_device, entry)
super().__init__(coordinator, sub_device, entry)
self._data_key = data_key
self._unique_id = f"{sub_device.sid}-{data_key}"
self._name = f"{data_key} ({sub_device.sid})".capitalize()
@ -288,9 +287,7 @@ class XiaomiGatewayIlluminanceSensor(Entity):
@property
def device_info(self):
"""Return the device info of the gateway."""
return {
"identifiers": {(DOMAIN, self._gateway_device_id)},
}
return {"identifiers": {(DOMAIN, self._gateway_device_id)}}
@property
def name(self):