| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 | """Library to handle connection with Switchbot."""from __future__ import annotationsfrom collections.abc import Callablefrom typing import TypedDictfrom bleak.backends.device import BLEDevicefrom bleak.backends.scanner import AdvertisementDatafrom .adv_parsers.bot import process_wohandfrom .adv_parsers.bulb import process_color_bulbfrom .adv_parsers.contact import process_wocontactfrom .adv_parsers.curtain import process_wocurtainfrom .adv_parsers.light_strip import process_wostripfrom .adv_parsers.meter import process_wosensorthfrom .adv_parsers.motion import process_wopresencefrom .adv_parsers.plug import process_woplugminifrom .const import SwitchbotModelfrom .models import SwitchBotAdvertisementclass SwitchbotSupportedType(TypedDict):    """Supported type of Switchbot."""    modelName: SwitchbotModel    modelFriendlyName: str    func: Callable[[bytes, bytes | None], dict[str, bool | int]]SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {    "d": {        "modelName": SwitchbotModel.CONTACT_SENSOR,        "modelFriendlyName": "Contact Sensor",        "func": process_wocontact,    },    "H": {        "modelName": SwitchbotModel.BOT,        "modelFriendlyName": "Bot",        "func": process_wohand,    },    "s": {        "modelName": SwitchbotModel.MOTION_SENSOR,        "modelFriendlyName": "Motion Sensor",        "func": process_wopresence,    },    "r": {        "modelName": SwitchbotModel.LIGHT_STRIP,        "modelFriendlyName": "Light Strip",        "func": process_wostrip,    },    "c": {        "modelName": SwitchbotModel.CURTAIN,        "modelFriendlyName": "Curtain",        "func": process_wocurtain,    },    "T": {        "modelName": SwitchbotModel.METER,        "modelFriendlyName": "Meter",        "func": process_wosensorth,    },    "i": {        "modelName": SwitchbotModel.METER,        "modelFriendlyName": "Meter Plus",        "func": process_wosensorth,    },    "g": {        "modelName": SwitchbotModel.PLUG_MINI,        "modelFriendlyName": "Plug Mini",        "func": process_woplugmini,    },    "u": {        "modelName": SwitchbotModel.COLOR_BULB,        "modelFriendlyName": "Color Bulb",        "func": process_color_bulb,    },}def parse_advertisement_data(    device: BLEDevice, advertisement_data: AdvertisementData) -> SwitchBotAdvertisement | None:    """Parse advertisement data."""    _services = list(advertisement_data.service_data.values())    _mgr_datas = list(advertisement_data.manufacturer_data.values())    if not _services:        return None    _service_data = _services[0]    if not _service_data:        return None    _mfr_data = _mgr_datas[0] if _mgr_datas else None    _model = chr(_service_data[0] & 0b01111111)    data = {        "address": device.address,  # MacOS uses UUIDs        "rawAdvData": list(advertisement_data.service_data.values())[0],        "data": {},    }    type_data = SUPPORTED_TYPES.get(_model)    if type_data:        data.update(            {                "isEncrypted": bool(_service_data[0] & 0b10000000),                "model": _model,                "modelFriendlyName": type_data["modelFriendlyName"],                "modelName": type_data["modelName"],                "data": type_data["func"](_service_data, _mfr_data),            }        )    data["data"]["rssi"] = device.rssi    return SwitchBotAdvertisement(device.address, data, device)
 |