Add bare bones homekit module for iot devices (#1566)

Based on the existing smart HomeKit module, this has been tested with a real device that supports this module.


---------

Co-authored-by: Teemu Rytilahti <tpr@iki.fi>
This commit is contained in:
ZeliardM
2025-10-10 10:45:16 -04:00
committed by GitHub
parent 2b881cfd7b
commit 0f6fc9c4d1
13 changed files with 221 additions and 5 deletions

View File

@@ -47,6 +47,7 @@ Devices support different functionality that are exposed via
>>> for module_name in dev.modules:
>>> print(module_name)
homekit
Energy
schedule
usage
@@ -85,6 +86,7 @@ state
rssi
on_since
reboot
...
current_consumption
consumption_today
consumption_this_month

View File

@@ -31,7 +31,7 @@ from ..module import Module
from ..modulemapping import ModuleMapping, ModuleName
from ..protocols import BaseProtocol
from .iotmodule import IotModule, merge
from .modules import Emeter
from .modules import Emeter, HomeKit
_LOGGER = logging.getLogger(__name__)
@@ -330,6 +330,8 @@ class IotDevice(Device):
async def _initialize_modules(self) -> None:
"""Initialize modules not added in init."""
self.add_module(Module.IotHomeKit, HomeKit(self, "smartlife.iot.homekit"))
if self.has_emeter:
_LOGGER.debug(
"The device has emeter, querying its information along sysinfo"

View File

@@ -21,7 +21,17 @@ from .iotdevice import (
)
from .iotmodule import IotModule
from .iotplug import IotPlug
from .modules import Antitheft, Cloud, Countdown, Emeter, Led, Schedule, Time, Usage
from .modules import (
Antitheft,
Cloud,
Countdown,
Emeter,
HomeKit,
Led,
Schedule,
Time,
Usage,
)
_LOGGER = logging.getLogger(__name__)
@@ -109,6 +119,7 @@ class IotStrip(IotDevice):
self.add_module(Module.IotCountdown, Countdown(self, "countdown"))
self.add_module(Module.Led, Led(self, "system"))
self.add_module(Module.IotCloud, Cloud(self, "cnCloud"))
self.add_module(Module.IotHomeKit, HomeKit(self, "smartlife.iot.homekit"))
if self.has_emeter:
_LOGGER.debug(
"The device has emeter, querying its information along sysinfo"

View File

@@ -6,6 +6,7 @@ from .cloud import Cloud
from .countdown import Countdown
from .dimmer import Dimmer
from .emeter import Emeter
from .homekit import HomeKit
from .led import Led
from .light import Light
from .lighteffect import LightEffect
@@ -34,4 +35,5 @@ __all__ = [
"Schedule",
"Time",
"Usage",
"HomeKit",
]

View File

@@ -0,0 +1,53 @@
"""Implementation of HomeKit module for IOT devices that natively support HomeKit."""
from __future__ import annotations
from typing import Any
from ...feature import Feature
from ..iotmodule import IotModule
class HomeKit(IotModule):
"""Implementation of HomeKit module for IOT devices."""
def query(self) -> dict:
"""Request HomeKit setup info."""
return {"smartlife.iot.homekit": {"setup_info_get": {}}}
@property
def info(self) -> dict[str, Any]:
"""Return the HomeKit setup info."""
# Only return info if the module has data
if self._module not in self._device._last_update:
return {}
return self.data.get("setup_info_get", {})
@property
def setup_code(self) -> str:
"""Return the HomeKit setup code."""
return self.info["setup_code"]
@property
def setup_payload(self) -> str:
"""Return the HomeKit setup payload."""
return self.info["setup_payload"]
def _initialize_features(self) -> None:
"""Initialize features after the initial update."""
# Only add features if the device supports the module
data = self._device._last_update.get(self._module, {})
if not data or "setup_info_get" not in data:
return
self._add_feature(
Feature(
self._device,
container=self,
id="homekit_setup_code",
name="HomeKit setup code",
attribute_getter="setup_code",
type=Feature.Type.Sensor,
category=Feature.Category.Debug,
)
)

View File

@@ -116,6 +116,7 @@ class Module(ABC):
IotSchedule: Final[ModuleName[iot.Schedule]] = ModuleName("schedule")
IotUsage: Final[ModuleName[iot.Usage]] = ModuleName("usage")
IotCloud: Final[ModuleName[iot.Cloud]] = ModuleName("cloud")
IotHomeKit: Final[ModuleName[iot.HomeKit]] = ModuleName("homekit")
# SMART only Modules
AutoOff: Final[ModuleName[smart.AutoOff]] = ModuleName("AutoOff")

View File

@@ -4,6 +4,7 @@ from __future__ import annotations
import asyncio
import logging
import re
from collections.abc import Callable
from pprint import pformat as pf
from typing import TYPE_CHECKING, Any
@@ -54,6 +55,8 @@ REDACTORS: dict[str, Callable[[Any], Any] | None] = {
"oemId": lambda x: "REDACTED_" + x[9::],
"username": lambda _: "user@example.com", # cnCloud
"hwId": lambda x: "REDACTED_" + x[9::],
"setup_code": lambda x: re.sub(r"\w", "0", x), # homekit
"setup_payload": lambda x: re.sub(r"\w", "0", x), # homekit
}