From 061b1abd1ba0c2f2a5572fc006d2edff571d0cab Mon Sep 17 00:00:00 2001
From: "J. Nick Koston" <nick@koston.org>
Date: Fri, 29 Oct 2021 19:57:01 -0500
Subject: [PATCH] Improve handling of invalid serial numbers in HomeKit
 Controller (#58723)

Fixes #58719
---
 .../components/homekit_controller/__init__.py        |  6 +++---
 .../components/homekit_controller/connection.py      | 12 +++++++++++-
 .../specific_devices/test_ryse_smart_bridge.py       |  2 +-
 3 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/homeassistant/components/homekit_controller/__init__.py b/homeassistant/components/homekit_controller/__init__.py
index bab989ba9bc..f91355906dc 100644
--- a/homeassistant/components/homekit_controller/__init__.py
+++ b/homeassistant/components/homekit_controller/__init__.py
@@ -19,7 +19,7 @@ from homeassistant.exceptions import ConfigEntryNotReady
 from homeassistant.helpers.entity import DeviceInfo, Entity
 
 from .config_flow import normalize_hkid
-from .connection import HKDevice
+from .connection import HKDevice, valid_serial_number
 from .const import (
     CONTROLLER,
     DOMAIN,
@@ -141,7 +141,7 @@ class HomeKitEntity(Entity):
         """Return the ID of this device."""
         info = self.accessory_info
         serial = info.value(CharacteristicsTypes.SERIAL_NUMBER)
-        if serial:
+        if valid_serial_number(serial):
             return f"homekit-{serial}-{self._iid}"
         # Some accessories do not have a serial number
         return f"homekit-{self._accessory.unique_id}-{self._aid}-{self._iid}"
@@ -161,7 +161,7 @@ class HomeKitEntity(Entity):
         """Return the device info."""
         info = self.accessory_info
         accessory_serial = info.value(CharacteristicsTypes.SERIAL_NUMBER)
-        if accessory_serial:
+        if valid_serial_number(accessory_serial):
             # Some accessories do not have a serial number
             identifier = (DOMAIN, IDENTIFIER_SERIAL_NUMBER, accessory_serial)
         else:
diff --git a/homeassistant/components/homekit_controller/connection.py b/homeassistant/components/homekit_controller/connection.py
index cf8381a9a28..8523fec7b8f 100644
--- a/homeassistant/components/homekit_controller/connection.py
+++ b/homeassistant/components/homekit_controller/connection.py
@@ -36,6 +36,16 @@ MAX_POLL_FAILURES_TO_DECLARE_UNAVAILABLE = 3
 _LOGGER = logging.getLogger(__name__)
 
 
+def valid_serial_number(serial):
+    """Return if the serial number appears to be valid."""
+    if not serial:
+        return False
+    try:
+        return float("".join(serial.rsplit(".", 1))) > 1
+    except ValueError:
+        return True
+
+
 def get_accessory_information(accessory):
     """Obtain the accessory information service of a HomeKit device."""
     result = {}
@@ -211,7 +221,7 @@ class HKDevice:
 
             serial_number = info.value(CharacteristicsTypes.SERIAL_NUMBER)
 
-            if serial_number:
+            if valid_serial_number(serial_number):
                 identifiers = {(DOMAIN, IDENTIFIER_SERIAL_NUMBER, serial_number)}
             else:
                 # Some accessories do not have a serial number
diff --git a/tests/components/homekit_controller/specific_devices/test_ryse_smart_bridge.py b/tests/components/homekit_controller/specific_devices/test_ryse_smart_bridge.py
index 8430919297c..ad5180658ad 100644
--- a/tests/components/homekit_controller/specific_devices/test_ryse_smart_bridge.py
+++ b/tests/components/homekit_controller/specific_devices/test_ryse_smart_bridge.py
@@ -19,7 +19,7 @@ async def test_ryse_smart_bridge_setup(hass):
     # Check that the cover.master_bath_south is correctly found and set up
     cover_id = "cover.master_bath_south"
     cover = entity_registry.async_get(cover_id)
-    assert cover.unique_id == "homekit-1.0.0-48"
+    assert cover.unique_id == "homekit-00:00:00:00:00:00-2-48"
 
     cover_helper = Helper(
         hass,
-- 
GitLab