From 1aa4fd4cc909a5a8258a871d0210b44095650e9a Mon Sep 17 00:00:00 2001
From: starkillerOG <starkiller.og@gmail.com>
Date: Mon, 15 Mar 2021 12:25:11 +0100
Subject: [PATCH] Make Xiaomi Miio unavailable device independent (#47795)

* make unavailable independent

* fix data is None

* process review comments
---
 .../components/xiaomi_miio/__init__.py        | 24 +++++++++++++------
 homeassistant/components/xiaomi_miio/const.py |  2 ++
 .../components/xiaomi_miio/gateway.py         | 10 +++++++-
 3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/homeassistant/components/xiaomi_miio/__init__.py b/homeassistant/components/xiaomi_miio/__init__.py
index e194225409a..ccecc835b43 100644
--- a/homeassistant/components/xiaomi_miio/__init__.py
+++ b/homeassistant/components/xiaomi_miio/__init__.py
@@ -7,9 +7,10 @@ from miio.gateway.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 homeassistant.helpers.update_coordinator import DataUpdateCoordinator
 
 from .const import (
+    ATTR_AVAILABLE,
     CONF_DEVICE,
     CONF_FLOW_TYPE,
     CONF_GATEWAY,
@@ -86,13 +87,22 @@ async def async_setup_gateway_entry(
         sw_version=gateway_info.firmware_version,
     )
 
-    async def async_update_data():
+    def 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
+        data = {}
+        for sub_device in gateway.gateway_device.devices.values():
+            try:
+                sub_device.update()
+            except GatewayException as ex:
+                _LOGGER.error("Got exception while fetching the state: %s", ex)
+                data[sub_device.sid] = {ATTR_AVAILABLE: False}
+            else:
+                data[sub_device.sid] = {ATTR_AVAILABLE: True}
+        return data
+
+    async def async_update_data():
+        """Fetch data from the subdevice using async_add_executor_job."""
+        return await hass.async_add_executor_job(update_data)
 
     # Create update coordinator
     coordinator = DataUpdateCoordinator(
diff --git a/homeassistant/components/xiaomi_miio/const.py b/homeassistant/components/xiaomi_miio/const.py
index 977e390f26b..ddde0c77229 100644
--- a/homeassistant/components/xiaomi_miio/const.py
+++ b/homeassistant/components/xiaomi_miio/const.py
@@ -9,6 +9,8 @@ CONF_MAC = "mac"
 
 KEY_COORDINATOR = "coordinator"
 
+ATTR_AVAILABLE = "available"
+
 # Fan Models
 MODEL_AIRPURIFIER_V1 = "zhimi.airpurifier.v1"
 MODEL_AIRPURIFIER_V2 = "zhimi.airpurifier.v2"
diff --git a/homeassistant/components/xiaomi_miio/gateway.py b/homeassistant/components/xiaomi_miio/gateway.py
index 356b19dc89a..be96f77240a 100644
--- a/homeassistant/components/xiaomi_miio/gateway.py
+++ b/homeassistant/components/xiaomi_miio/gateway.py
@@ -6,7 +6,7 @@ from miio import DeviceException, gateway
 from homeassistant.helpers.entity import Entity
 from homeassistant.helpers.update_coordinator import CoordinatorEntity
 
-from .const import DOMAIN
+from .const import ATTR_AVAILABLE, DOMAIN
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -89,3 +89,11 @@ class XiaomiGatewayDevice(CoordinatorEntity, Entity):
             "model": self._sub_device.model,
             "sw_version": self._sub_device.firmware_version,
         }
+
+    @property
+    def available(self):
+        """Return if entity is available."""
+        if self.coordinator.data is None:
+            return False
+
+        return self.coordinator.data[self._sub_device.sid][ATTR_AVAILABLE]