Repository: zigpy/zha-device-handlers

Issue:
[Device Support Request] TS0601 by _TZE200_3ejwxpmu (QOXEZY Zigbee CO2 NDIR Sensor)
**Is your feature request related to a problem? Please describe.**
This is a NDIR CO2 sensor which measures carbon dioxide (additionally humidity and temperature). While I can connect it to ZHA, it generates no entities. Is it possible to integrate?

**Describe the solution you'd like**
I would like to be able to see all available entities.

<details>
<!-- Device signature can be acquired by clicking on the "Zigbee Device Signature" button in the device settings view -->
<summary>Device signature</summary>
{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *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": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZE200_3ejwxpmu",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

</details>

**Additional context**
Add any other context or screenshots about the feature request here.
![image](https://user-images.githubusercontent.com/34242593/228160040-d74ddf56-3017-4ea0-80f9-15f067a74cc9.png)




Discussion:
@Orthodux 

To to find the fitting Sensor here:
https://github.com/zigpy/zha-device-handlers/tree/1fed017136e64274e8665a22ed7bd3556c1e0729/zhaquirks/tuya
maybe this?
https://github.com/zigpy/zha-device-handlers/blob/9babf3e8516a982d6fb85a3e64f4ad37fa650979/zhaquirks/tuya/air/ts0601_air_quality.py

add your _TZE200_3ejwxpmu to it.

Some more input here:
https://github.com/zigpy/zha-device-handlers/issues/1944#issuecomment-1486634014

Add custom quirk like that:

Create a custom quirk dir in HA, e.g., /config/custom_zha_quirks
In configuration.yaml, point to this directory:

```
zha:
  custom_quirks_path: /config/custom_zha_quirks/
```
  
In this directory, but the .py file and edit it.

Restart HA.

More:
https://github.com/zigpy/zha-device-handlers/discussions/693#discussioncomment-857274
Brilliant, I got the CO2 working now. However, no temperature and humidity yet. How would I be able to add this? Is it as simple as copy-pasting?
> 

Cool. I have no idea. Let's find out or hopefully someone helps us.

There are 3 classes:
class TuyaCO2Sensor(CustomDevice):
class TuyaCO2SensorGPP(CustomDevice):
class TuyaNDIRCO2SensorGPP(CustomDevice):

Have you tested your device with all 3, one by one?
I put them all in, then I read what quirk was read by ZHA which was ts0601_co2.TuyaNDIRCO2SensorGPP. The other two I removed to clean up the code.
> I put them all in, then I read what quirk was read by ZHA which was ts0601_co2.TuyaNDIRCO2SensorGPP. The other two I removed to clean up the code.

Is there a way to scan TUYA devices, so we can find the Humidity and Temperature and Battery?
Alright, I found a solution for the temperature and humidity. Give me a few minutes to upload it.
> Alright, I found a solution for the temperature and humidity. Give me a few minutes to upload it.

Cool, then please help me here:
https://github.com/zigpy/zha-device-handlers/issues/2304
So I found out by looking at the **from zhaquirks.tuya.air import** section, that the temperature and humidity were written down. However, when looking further down in the code, I noticed that I couldn't see any reference of the parameters there, only CO2.

```
    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaCO2ManufCluster,
                    TuyaAirQualityCO2,
```

So by adding the parameters found in the **from zhaquirks.tuya.air import** section, the entities were added to HA.

```
    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaCO2ManufCluster,
                    TuyaAirQualityCO2,
                    TuyaAirQualityTemperature,
                    TuyaAirQualityHumidity,
```


<details>

```
"""Tuya Air Quality sensor."""

from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import Basic, GreenPowerProxy, Groups, Ota, Scenes, Time

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.tuya.air import (
    TuyaAirQualityCO2,
    TuyaAirQualityFormaldehyde,
    TuyaAirQualityHumidity,
    TuyaAirQualityTemperature,
    TuyaAirQualityVOC,
    TuyaCO2ManufCluster,
)

class TuyaNDIRCO2SensorGPP(CustomDevice):
    """Tuya NIDR CO2 sensor with GPP."""

    signature = {
        # NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *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)
        # device_version=1
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=81, device_version=1,
        # input_clusters=[0, 4, 5, 61184],
        # output_clusters=[25, 10])
        MODELS_INFO: [
            ("_TZE200_ogkdpgy2", "TS0601"),
            ("_TZE200_3ejwxpmu", "TS0601"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaCO2ManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
                # input_clusters=[]
                # output_clusters=[33]
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaCO2ManufCluster,
                    TuyaAirQualityCO2,
                    TuyaAirQualityTemperature,
                    TuyaAirQualityHumidity,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }

```
</details>
> 

Nice, Pull Request?
And then help here? https://github.com/zigpy/zha-device-handlers/issues/2304
I would suggest to enable the debug logs to see if there are some other information (other DPs) there.
Also the vendor or manufacturer site would tell us which capabilities have the device.
There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.
> There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

shut up, bot. 
Hi, I'd like to pick this up and open a PR. I only skimmed the README with the Contribution Guidelines.
However, I did not find documentation to enabling the debug log, like @javicalle suggested. Could you let me know where I can find it?

Resolving patch:
diff --git a/zhaquirks/tuya/air/ts0601_air_quality.py b/zhaquirks/tuya/air/ts0601_air_quality.py
--- a/zhaquirks/tuya/air/ts0601_air_quality.py
+++ b/zhaquirks/tuya/air/ts0601_air_quality.py
@@ -196,3 +196,64 @@ class TuyaNDIRCO2SensorGPP(CustomDevice):
             },
         }
     }
+
+
+class TuyaNDIRCO2SensorGPP2(CustomDevice):
+    """Tuya NIDR CO2 sensor."""
+
+    signature = {
+        # NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *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)
+        # device_version=1
+        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=81, device_version=1,
+        # input_clusters=[0, 4, 5, 61184],
+        # output_clusters=[10, 25])
+        MODELS_INFO: [
+            ("_TZE200_3ejwxpmu", "TS0601"),
+        ],
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaCO2ManufCluster.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            },
+            242: {
+                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
+                # input_clusters=[]
+                # output_clusters=[33]
+                PROFILE_ID: zgp.PROFILE_ID,
+                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
+                INPUT_CLUSTERS: [],
+                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
+            },
+        },
+    }
+
+    replacement = {
+        ENDPOINTS: {
+            1: {
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaCO2ManufCluster,
+                    TuyaAirQualityCO2,
+                    TuyaAirQualityHumidity,
+                    TuyaAirQualityTemperature,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            },
+            242: {
+                PROFILE_ID: zgp.PROFILE_ID,
+                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
+                INPUT_CLUSTERS: [],
+                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
+            },
+        }
+    }


Test patch: