zigpy / zha-device-handlers

ZHA device handlers bridge the functionality gap created when manufacturers deviate from the ZCL specification, handling deviations and exceptions by parsing custom messages to and from Zigbee devices.
Apache License 2.0
743 stars 679 forks source link

[BUG] Ikea Starkvind air purifier & air purifier table sensors missing #1846

Closed willliamchan closed 1 year ago

willliamchan commented 2 years ago

Describe the bug All sensors are missing, zha pick up the device as fan only.

To Reproduce N/A

Expected behavior Expecting zha to pick up sensor like PM25, status light etc.

Screenshots

Device signature ```yaml { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4476, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)", "endpoints": { "1": { "profile_id": 260, "device_type": "0x0007", "in_clusters": [ "0x0000", "0x0003", "0x0004", "0x0005", "0x0202", "0xfc57", "0xfc7c", "0xfc7d" ], "out_clusters": [ "0x0019", "0x0400", "0x042a" ] }, "242": { "profile_id": 41440, "device_type": "0x0061", "in_clusters": [], "out_clusters": [ "0x0021" ] } }, "manufacturer": "IKEA of Sweden", "model": "STARKVIND Air purifier table", "class": "zigpy.device.Device" } ```
Diagnostic information ```yaml { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2022.10.4", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.10.5", "docker": true, "arch": "aarch64", "timezone": "Europe/London", "os_name": "Linux", "os_version": "5.15.61-v8", "supervisor": "2022.10.0", "host_os": "Home Assistant OS 9.2", "docker_version": "20.10.17", "chassis": "embedded", "run_as_root": true }, "custom_components": { "meross_lan": { "version": "2.6.2", "requirements": [] }, "apple_tv": { "version": "3.0.1", "requirements": [ "pyatv==0.10.0" ] }, "daikin_residential": { "version": "2.2.2", "requirements": [ "oic==1.4.0" ] }, "hacs": { "version": "1.28.2", "requirements": [ "aiogithubapi>=22.2.4" ] }, "hildebrandglow_dcc": { "version": "0.6.0", "requirements": [] }, "kef": { "version": "1.0.0", "requirements": [ "aiokef==0.2.16", "getmac==0.8.2" ] }, "xiaomi_miio_fan": { "version": "2022.8.0.0", "requirements": [ "construct==2.10.56", "python-miio>=0.5.12" ] }, "deebot": { "version": "1.4.1", "requirements": [ "deebot-client==1.5.1", "numpy>=1.21.2" ] }, "smartthinq_sensors": { "version": "0.24.2", "requirements": [ "pycountry>=20.7.3", "xmltodict>=0.12.0", "cchardet>=2.1.7" ] }, "xiaomi_cloud_map_extractor": { "version": "v2.2.0", "requirements": [ "pillow", "pybase64", "python-miio", "requests", "pycryptodome" ] } }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/zha", "requirements": [ "bellows==0.34.2", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.82", "zigpy-deconz==0.19.0", "zigpy==0.51.3", "zigpy-xbee==0.16.2", "zigpy-zigate==0.10.2", "zigpy-znp==0.9.1" ], "usb": [ { "vid": "10C4", "pid": "EA60", "description": "*2652*", "known_devices": [ "slae.sh cc2652rb stick" ] }, { "vid": "1A86", "pid": "55D4", "description": "*sonoff*plus*", "known_devices": [ "sonoff zigbee dongle plus v2" ] }, { "vid": "10C4", "pid": "EA60", "description": "*sonoff*plus*", "known_devices": [ "sonoff zigbee dongle plus" ] }, { "vid": "10C4", "pid": "EA60", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*zigstar*", "known_devices": [ "ZigStar Coordinators" ] }, { "vid": "1CF1", "pid": "0030", "description": "*conbee*", "known_devices": [ "Conbee II" ] }, { "vid": "10C4", "pid": "8A2A", "description": "*zigbee*", "known_devices": [ "Nortek HUSBZB-1" ] }, { "vid": "0403", "pid": "6015", "description": "*zigate*", "known_devices": [ "ZiGate+" ] }, { "vid": "10C4", "pid": "EA60", "description": "*zigate*", "known_devices": [ "ZiGate" ] }, { "vid": "10C4", "pid": "8B34", "description": "*bv 2010/10*", "known_devices": [ "Bitron Video AV2010/10" ] } ], "codeowners": [ "@dmulcahey", "@adminiuga", "@puddly" ], "zeroconf": [ { "type": "_esphomelib._tcp.local.", "name": "tube*" }, { "type": "_zigate-zigbee-gateway._tcp.local.", "name": "*zigate*" }, { "type": "_zigstar_gw._tcp.local.", "name": "*zigstar*" } ], "dependencies": [ "file_upload" ], "after_dependencies": [ "onboarding", "usb", "zeroconf" ], "iot_class": "local_polling", "loggers": [ "aiosqlite", "bellows", "crccheck", "pure_pcapy3", "zhaquirks", "zigpy", "zigpy_deconz", "zigpy_xbee", "zigpy_zigate", "zigpy_znp" ], "is_built_in": true }, "data": { "ieee": "**REDACTED**", "nwk": 9374, "manufacturer": "IKEA of Sweden", "model": "STARKVIND Air purifier table", "name": "IKEA of Sweden STARKVIND Air purifier table", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4476, "power_source": "Mains", "lqi": 21, "rssi": null, "last_seen": "2022-10-20T13:53:32", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4476, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)", "endpoints": { "1": { "profile_id": 260, "device_type": "0x0007", "in_clusters": [ "0x0000", "0x0003", "0x0004", "0x0005", "0x0202", "0xfc57", "0xfc7c", "0xfc7d" ], "out_clusters": [ "0x0019", "0x0400", "0x042a" ] }, "242": { "profile_id": 41440, "device_type": "0x0061", "in_clusters": [], "out_clusters": [ "0x0021" ] } } }, "active_coordinator": false, "entities": [ { "entity_id": "button.study_air_purifier_identifybutton", "name": "IKEA of Sweden STARKVIND Air purifier table" }, { "entity_id": "fan.study_air_purifier_fan", "name": "IKEA of Sweden STARKVIND Air purifier table" } ], "neighbors": [ { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x0977", "permit_joining": "Unknown", "depth": "15", "lqi": "214" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x2670", "permit_joining": "Unknown", "depth": "15", "lqi": "173" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x2E6C", "permit_joining": "Unknown", "depth": "15", "lqi": "243" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x3593", "permit_joining": "Unknown", "depth": "15", "lqi": "207" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x3BAC", "permit_joining": "Unknown", "depth": "15", "lqi": "217" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x424C", "permit_joining": "Unknown", "depth": "15", "lqi": "237" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x42CC", "permit_joining": "Unknown", "depth": "15", "lqi": "191" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x42D1", "permit_joining": "Unknown", "depth": "15", "lqi": "179" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x48C3", "permit_joining": "Unknown", "depth": "15", "lqi": "240" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x4B4A", "permit_joining": "Unknown", "depth": "15", "lqi": "198" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x4C64", "permit_joining": "Unknown", "depth": "15", "lqi": "254" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x762D", "permit_joining": "Unknown", "depth": "15", "lqi": "207" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x8785", "permit_joining": "Unknown", "depth": "15", "lqi": "236" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0xC10F", "permit_joining": "Unknown", "depth": "15", "lqi": "238" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0xDC37", "permit_joining": "Unknown", "depth": "15", "lqi": "215" }, { "device_type": "Router", "rx_on_when_idle": "On", "relationship": "Sibling", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0xE4D7", "permit_joining": "Unknown", "depth": "15", "lqi": "224" }, { "device_type": "EndDevice", "rx_on_when_idle": "Off", "relationship": "Child", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x0E3C", "permit_joining": "NotAccepting", "depth": "2", "lqi": "243" }, { "device_type": "EndDevice", "rx_on_when_idle": "Off", "relationship": "Child", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x401E", "permit_joining": "NotAccepting", "depth": "2", "lqi": "226" }, { "device_type": "EndDevice", "rx_on_when_idle": "Off", "relationship": "Child", "extended_pan_id": "**REDACTED**", "ieee": "**REDACTED**", "nwk": "0x5A4D", "permit_joining": "NotAccepting", "depth": "2", "lqi": "197" } ], "endpoint_names": [ { "name": "COMBINED_INTERFACE" }, { "name": "unknown 97 device_type of 0xa1e0 profile id" } ], "user_given_name": "Study Air purifier", "device_reg_id": "2c32bf338127de3509d04f7bbd867fb1", "area_id": "study", "cluster_details": { "1": { "device_type": { "name": "COMBINED_INTERFACE", "id": 7 }, "profile_id": 260, "in_clusters": { "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0004": { "attribute_name": "manufacturer", "value": "IKEA of Sweden" }, "0x0005": { "attribute_name": "model", "value": "STARKVIND Air purifier table" } }, "unsupported_attributes": {} }, "0x0003": { "endpoint_attribute": "identify", "attributes": {}, "unsupported_attributes": {} }, "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0x0202": { "endpoint_attribute": "fan", "attributes": { "0x0000": { "attribute_name": "fan_mode", "value": 5 }, "0x0001": { "attribute_name": "fan_mode_sequence", "value": 2 } }, "unsupported_attributes": {} }, "0xfc57": { "endpoint_attribute": "manufacturer_specific", "attributes": {}, "unsupported_attributes": {} }, "0xfc7c": { "endpoint_attribute": "manufacturer_specific", "attributes": {}, "unsupported_attributes": {} }, "0xfc7d": { "endpoint_attribute": "manufacturer_specific", "attributes": {}, "unsupported_attributes": {} } }, "out_clusters": { "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} }, "0x0400": { "endpoint_attribute": "illuminance", "attributes": {}, "unsupported_attributes": {} }, "0x042a": { "endpoint_attribute": "pm25", "attributes": {}, "unsupported_attributes": {} } } }, "242": { "device_type": { "name": "unknown", "id": 97 }, "profile_id": 41440, "in_clusters": {}, "out_clusters": { "0x0021": { "endpoint_attribute": "green_power", "attributes": {}, "unsupported_attributes": {} } } } } } } ```
Additional logs ``` Paste any additional debug logs here. Don't remove the extra line breaks outside the ``` marks. ```

Additional context Add any other context about the problem here.

javicalle commented 1 year ago

Seems to be another version of the current quirk.

Enable the local custom quirk:

Copy in your local quirks folder the current quirk:

Add at the end of file this quirk:

class IkeaSTARKVIND_v2(CustomDevice):
    """STARKVIND Air purifier by IKEA of Sweden."""

    def __init__(self, *args, **kwargs):
        """Init."""
        self.pm25_bus = Bus()
        self.change_fan_mode_bus = Bus()
        self.change_fan_mode_ha_bus = Bus()
        super().__init__(*args, **kwargs)

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=7 (0x0007)
        # device_version=0
        # input_clusters=[0, 3, 4, 5, 514, 64599, 64637] output_clusters=[25, 1024, 1066]>
        MODELS_INFO: [
            (IKEA, "STARKVIND Air purifier"),
            (IKEA, "STARKVIND Air purifier table"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,  # 0
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    Fan.cluster_id,  # 514    0x0202
                    WWAH_CLUSTER_ID,  # 64599  0xFC57
                    0xFC7C,
                    IkeaAirpurifier.cluster_id,  # 64637  0xFC7D
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id,  # 25      0x0019
                    IlluminanceMeasurement.cluster_id,  # 1024    0x0400
                    PM25.cluster_id,  # 1066    0x042A PM2.5 Measurement Cluster
                ],
            },
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # device_version=0
            # input_clusters=[33] output_clusters=[33]>
            242: {
                PROFILE_ID: 0xA1E0,  # 41440 (dec)
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id,  # 0x0021 = GreenPowerProxy.cluster_id
                ],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,  # 0
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    WWAH_CLUSTER_ID,  # 64599  0xFC57
                    0xFC7C,
                    IkeaAirpurifier,  # 64637  0xFC7D control air purifier with manufacturer-specific attributes
                    PM25Cluster,  # 1066    0x042A PM2.5 Measurement Cluster
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id,  # 25      0x0019
                    IlluminanceMeasurement.cluster_id,  # 1024    0x0400
                ],
            },
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # device_version=0
            # input_clusters=[33] output_clusters=[33]>
            242: {
                PROFILE_ID: 0xA1E0,  # 41440 (dec)
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id,  # 0x0021 = GreenPowerProxy.cluster_id
                ],
            },
        },
    }

Restart HA, remove and pair you device again. Check that the device is loading the quirk and that the device signature has changed.

willliamchan commented 1 year ago

Seems to be another version of the current quirk.

Enable the local custom quirk:

Copy in your local quirks folder the current quirk:

Add at the end of file this quirk:

class IkeaSTARKVIND_v2(CustomDevice):
    """STARKVIND Air purifier by IKEA of Sweden."""

    def __init__(self, *args, **kwargs):
        """Init."""
        self.pm25_bus = Bus()
        self.change_fan_mode_bus = Bus()
        self.change_fan_mode_ha_bus = Bus()
        super().__init__(*args, **kwargs)

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=7 (0x0007)
        # device_version=0
        # input_clusters=[0, 3, 4, 5, 514, 64599, 64637] output_clusters=[25, 1024, 1066]>
        MODELS_INFO: [
            (IKEA, "STARKVIND Air purifier"),
            (IKEA, "STARKVIND Air purifier table"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,  # 0
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    Fan.cluster_id,  # 514    0x0202
                    WWAH_CLUSTER_ID,  # 64599  0xFC57
                    0xFC7C,
                    IkeaAirpurifier.cluster_id,  # 64637  0xFC7D
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id,  # 25      0x0019
                    IlluminanceMeasurement.cluster_id,  # 1024    0x0400
                    PM25.cluster_id,  # 1066    0x042A PM2.5 Measurement Cluster
                ],
            },
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # device_version=0
            # input_clusters=[33] output_clusters=[33]>
            242: {
                PROFILE_ID: 0xA1E0,  # 41440 (dec)
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id,  # 0x0021 = GreenPowerProxy.cluster_id
                ],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.COMBINED_INTERFACE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,  # 0
                    Identify.cluster_id,  # 3
                    Groups.cluster_id,  # 4
                    Scenes.cluster_id,  # 5
                    WWAH_CLUSTER_ID,  # 64599  0xFC57
                    0xFC7C,
                    IkeaAirpurifier,  # 64637  0xFC7D control air purifier with manufacturer-specific attributes
                    PM25Cluster,  # 1066    0x042A PM2.5 Measurement Cluster
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id,  # 25      0x0019
                    IlluminanceMeasurement.cluster_id,  # 1024    0x0400
                ],
            },
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # device_version=0
            # input_clusters=[33] output_clusters=[33]>
            242: {
                PROFILE_ID: 0xA1E0,  # 41440 (dec)
                DEVICE_TYPE: 0x0061,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [
                    GreenPowerProxy.cluster_id,  # 0x0021 = GreenPowerProxy.cluster_id
                ],
            },
        },
    }

Restart HA, remove and pair you device again. Check that the device is loading the quirk and that the device signature has changed.

Worked like a charm! PM2.5 sensor is still missing however the thread owner said it will reappear in a few days. I'll report if it's not showing up on next Monday.

MattWestb commented 1 year ago

I think this is related to the firmware update in the device:

I dont have one of this then the price was 99€ and now its around 150€ and its out off my tech budget :-((

I was getting one recycled TREDANSEN without all needed things only the battery and after little talking i was paying 13.99€ = - 90% very good and its working. I shall try finding the same person and asking if i can getting one STARKVIND returned that not possible selling and have working Zigbee module and getting one good price.

The Satrkvind shall having more sensors like filter change and runtime left for the filter filter time reset command and more but that need sniffing the IKEA Hub but shall not being any problem if i can getting one working device.

javicalle commented 1 year ago

There are a few configuration entities in ZHA for this device: