Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Device Support Request] Tuya Thermostatic Radiator Valve (_TZE204_qyr2m29i) #3603

Open
BugSniper3000 opened this issue Dec 10, 2024 · 2 comments

Comments

@BugSniper3000
Copy link

Problem description

Tuya Thermostatic Radiator Valve (_TZE204_qyr2m29i) is not working correctly in Home Assistant through ZHA. Despite creating a custom quirk (rookie), the device does not update attributes like current_temperature, target_temperature, or battery_level reliably or show entities. Logs show issues with duplicate TSNs, incomplete or unexpected data formats, and unhandled commands, leading to inconsistent behavior and updates in Home Assistant.

Solution description

Update Home Assistant attributes correctly and reliably:

  • Display accurate current_temperature.
  • Allow setting and showing target_temperature.
  • Reflect the current battery_level.

Handle device-specific commands properly:

  • Interpret and process set_data_response commands to update attributes.
  • Handle set_time_request commands

Goal:
A working quirk or ZHA integration that enables a Tuya Thermostatic Radiator Valve to:

Fully integrate with Home Assistant.
Provide accurate and responsive controls and feedback for thermostat functions.

Screenshots/Video

Screenshots/Video

[Paste/upload your media here]

Device signature

Device signature
[{
  "node_descriptor": {
    "logical_type": 2,
    "complex_descriptor_available": 0,
    "user_descriptor_available": 0,
    "reserved": 0,
    "aps_flags": 0,
    "frequency_band": 8,
    "mac_capability_flags": 128,
    "manufacturer_code": 4417,
    "maximum_buffer_size": 66,
    "maximum_incoming_transfer_size": 66,
    "server_mask": 10752,
    "maximum_outgoing_transfer_size": 66,
    "descriptor_capability_field": 0
  },
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0x0301",
      "input_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "output_clusters": [
        "0x000a",
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZE204_qyr2m29i",
  "model": "TS0601",
  "class": "ts0601_trv.TuyaThermostaticRadiatorValve"
}]

Diagnostic information

Diagnostic information
[{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2024.11.3",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.12.4",
    "docker": true,
    "arch": "aarch64",
    "timezone": "Europe/London",
    "os_name": "Linux",
    "os_version": "6.6.31-haos-raspi",
    "supervisor": "2024.11.4",
    "host_os": "Home Assistant OS 13.2",
    "docker_version": "27.2.0",
    "chassis": "embedded",
    "run_as_root": true
  },
  "custom_components": {
    "badnest": {
      "documentation": "https://custom-components.github.io/badnest",
      "version": "5.0.1",
      "requirements": [
        "simplejson>=3.17.2"
      ]
    },
    "nodered": {
      "documentation": "https://zachowj.github.io/node-red-contrib-home-assistant-websocket/guide/custom_integration/",
      "version": "4.1.1",
      "requirements": []
    },
    "hacs": {
      "documentation": "https://hacs.xyz/docs/configuration/start",
      "version": "2.0.1",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    },
    "zha_toolkit": {
      "documentation": "https://github.com/mdeweerd/zha-toolkit",
      "version": "v1.1.19",
      "requirements": [
        "aiofiles>=0.4.0",
        "pytz>=2016.10"
      ]
    },
    "waste_collection_schedule": {
      "documentation": "https://github.com/mampfes/hacs_waste_collection_schedule#readme",
      "version": "2.5.0",
      "requirements": [
        "icalendar",
        "recurring_ical_events",
        "icalevents>=0.1.26,!=0.1.28",
        "beautifulsoup4",
        "lxml",
        "pycryptodome"
      ]
    },
    "robovac": {
      "documentation": "https://github.com/codefoodpixels/robovac",
      "version": "1.0.0",
      "requirements": []
    },
    "garmin_connect": {
      "documentation": "https://github.com/cyberjunky/home-assistant-garmin_connect",
      "version": "0.2.22",
      "requirements": [
        "garminconnect>=0.2.23",
        "tzlocal"
      ]
    },
    "dwains_dashboard": {
      "documentation": "https://dwainscheeren.github.io/dwains-lovelace-dashboard/",
      "version": "3.7.1",
      "requirements": []
    },
    "teamtracker": {
      "documentation": "https://github.com/vasqued2/ha-teamtracker",
      "version": "0.1",
      "requirements": [
        "arrow",
        "aiofiles"
      ]
    },
    "hildebrandglow_dcc": {
      "documentation": "https://github.com/HandyHat/ha-hildebrandglow-dcc",
      "version": "1.0.3",
      "requirements": [
        "pyglowmarkt==0.5.5"
      ]
    }
  },
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "after_dependencies": [
      "hassio",
      "onboarding",
      "usb"
    ],
    "codeowners": [
      "dmulcahey",
      "adminiuga",
      "puddly",
      "TheJulianJES"
    ],
    "config_flow": true,
    "dependencies": [
      "file_upload"
    ],
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "iot_class": "local_polling",
    "loggers": [
      "aiosqlite",
      "bellows",
      "crccheck",
      "pure_pcapy3",
      "zhaquirks",
      "zigpy",
      "zigpy_deconz",
      "zigpy_xbee",
      "zigpy_zigate",
      "zigpy_znp",
      "zha",
      "universal_silabs_flasher"
    ],
    "requirements": [
      "universal-silabs-flasher==0.0.25",
      "zha==0.0.39"
    ],
    "usb": [
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*2652*",
        "known_devices": [
          "slae.sh cc2652rb stick"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*slzb-07*",
        "known_devices": [
          "smlight slzb-07"
        ]
      },
      {
        "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": "0403",
        "pid": "6015",
        "description": "*conbee*",
        "known_devices": [
          "Conbee III"
        ]
      },
      {
        "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"
        ]
      }
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      },
      {
        "type": "_zigstar_gw._tcp.local.",
        "name": "*zigstar*"
      },
      {
        "type": "_uzg-01._tcp.local.",
        "name": "uzg-01*"
      },
      {
        "type": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      },
      {
        "type": "_xzg._tcp.local.",
        "name": "xzg*"
      },
      {
        "type": "_czc._tcp.local.",
        "name": "czc*"
      }
    ],
    "is_built_in": true,
    "overwrites_built_in": false
  },
  "setup_times": {
    "null": {
      "setup": 7.248192559927702e-05
    },
    "01JE0QPVDPG8ZYA4PWCP4965AS": {
      "wait_import_platforms": -0.008102908032014966,
      "config_entry_setup": 14.924909924040549
    }
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 25130,
    "manufacturer": "_TZE204_qyr2m29i",
    "model": "TS0601",
    "name": "_TZE204_qyr2m29i TS0601",
    "quirk_applied": true,
    "quirk_class": "ts0601_trv.TuyaThermostaticRadiatorValve",
    "quirk_id": null,
    "manufacturer_code": 4417,
    "power_source": "Battery or Unknown",
    "lqi": 156,
    "rssi": null,
    "last_seen": "2024-12-10T23:25:58",
    "available": true,
    "device_type": "EndDevice",
    "signature": {
      "node_descriptor": {
        "logical_type": 2,
        "complex_descriptor_available": 0,
        "user_descriptor_available": 0,
        "reserved": 0,
        "aps_flags": 0,
        "frequency_band": 8,
        "mac_capability_flags": 128,
        "manufacturer_code": 4417,
        "maximum_buffer_size": 66,
        "maximum_incoming_transfer_size": 66,
        "server_mask": 10752,
        "maximum_outgoing_transfer_size": 66,
        "descriptor_capability_field": 0
      },
      "endpoints": {
        "1": {
          "profile_id": "0x0104",
          "device_type": "0x0301",
          "input_clusters": [
            "0x0000",
            "0x0004",
            "0x0005",
            "0xef00"
          ],
          "output_clusters": [
            "0x000a",
            "0x0019"
          ]
        }
      },
      "manufacturer": "_TZE204_qyr2m29i",
      "model": "TS0601"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "update.tze204_qyr2m29i_ts0601_firmware",
        "name": "_TZE204_qyr2m29i TS0601"
      },
      {
        "entity_id": "update.test_trv_firmware",
        "name": "_TZE204_qyr2m29i TS0601"
      }
    ],
    "neighbors": [],
    "routes": [],
    "endpoint_names": [
      {
        "name": "THERMOSTAT"
      }
    ],
    "user_given_name": "Test TRV",
    "device_reg_id": "8f4020e786c92c56c8ddde243d7961bb",
    "area_id": "living_room",
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "THERMOSTAT",
          "id": 769
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0013": {
                "attribute": "ZCLAttributeDef(id=0x0013, name='alarm_mask', type=<flag 'AlarmMask'>, zcl_type=<DataTypeId.map8: 24>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0001": {
                "attribute": "ZCLAttributeDef(id=0x0001, name='app_version', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": 74
              },
              "0xfffd": {
                "attribute": "ZCLAttributeDef(id=0xFFFD, name='cluster_revision', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0006": {
                "attribute": "ZCLAttributeDef(id=0x0006, name='date_code', type=<class 'zigpy.types.basic.LimitedCharString.<locals>.LimitedCharString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0012": {
                "attribute": "ZCLAttributeDef(id=0x0012, name='device_enabled', type=<enum 'Bool'>, zcl_type=<DataTypeId.bool_: 16>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0014": {
                "attribute": "ZCLAttributeDef(id=0x0014, name='disable_local_config', type=<flag 'DisableLocalConfig'>, zcl_type=<DataTypeId.map8: 24>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0008": {
                "attribute": "ZCLAttributeDef(id=0x0008, name='generic_device_class', type=<enum 'GenericDeviceClass'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0009": {
                "attribute": "ZCLAttributeDef(id=0x0009, name='generic_device_type', type=<enum 'GenericLightingDeviceType'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0003": {
                "attribute": "ZCLAttributeDef(id=0x0003, name='hw_version', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0010": {
                "attribute": "ZCLAttributeDef(id=0x0010, name='location_desc', type=<class 'zigpy.types.basic.LimitedCharString.<locals>.LimitedCharString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0004": {
                "attribute": "ZCLAttributeDef(id=0x0004, name='manufacturer', type=<class 'zigpy.types.basic.LimitedCharString.<locals>.LimitedCharString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000c": {
                "attribute": "ZCLAttributeDef(id=0x000C, name='manufacturer_version_details', type=<class 'zigpy.types.basic.CharacterString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0005": {
                "attribute": "ZCLAttributeDef(id=0x0005, name='model', type=<class 'zigpy.types.basic.LimitedCharString.<locals>.LimitedCharString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0011": {
                "attribute": "ZCLAttributeDef(id=0x0011, name='physical_env', type=<enum 'PhysicalEnvironment'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0007": {
                "attribute": "ZCLAttributeDef(id=0x0007, name='power_source', type=<enum 'PowerSource'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000a": {
                "attribute": "ZCLAttributeDef(id=0x000A, name='product_code', type=<class 'zigpy.types.basic.LVBytes'>, zcl_type=<DataTypeId.octstr: 65>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000e": {
                "attribute": "ZCLAttributeDef(id=0x000E, name='product_label', type=<class 'zigpy.types.basic.CharacterString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000b": {
                "attribute": "ZCLAttributeDef(id=0x000B, name='product_url', type=<class 'zigpy.types.basic.CharacterString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0xfffe": {
                "attribute": "ZCLAttributeDef(id=0xFFFE, name='reporting_status', type=<enum 'AttributeReportingStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000d": {
                "attribute": "ZCLAttributeDef(id=0x000D, name='serial_number', type=<class 'zigpy.types.basic.CharacterString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0002": {
                "attribute": "ZCLAttributeDef(id=0x0002, name='stack_version', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x4000": {
                "attribute": "ZCLAttributeDef(id=0x4000, name='sw_build_id', type=<class 'zigpy.types.basic.CharacterString'>, zcl_type=<DataTypeId.string: 66>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0000": {
                "attribute": "ZCLAttributeDef(id=0x0000, name='zcl_version', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              }
            },
            "unsupported_attributes": []
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {
              "0xfffd": {
                "attribute": "ZCLAttributeDef(id=0xFFFD, name='cluster_revision', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0000": {
                "attribute": "ZCLAttributeDef(id=0x0000, name='name_support', type=<flag 'NameSupport'>, zcl_type=<DataTypeId.map8: 24>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0xfffe": {
                "attribute": "ZCLAttributeDef(id=0xFFFE, name='reporting_status', type=<enum 'AttributeReportingStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              }
            },
            "unsupported_attributes": []
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {
              "0xfffd": {
                "attribute": "ZCLAttributeDef(id=0xFFFD, name='cluster_revision', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0000": {
                "attribute": "ZCLAttributeDef(id=0x0000, name='count', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0002": {
                "attribute": "ZCLAttributeDef(id=0x0002, name='current_group', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0001": {
                "attribute": "ZCLAttributeDef(id=0x0001, name='current_scene', type=<class 'zigpy.types.basic.uint8_t'>, zcl_type=<DataTypeId.uint8: 32>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0005": {
                "attribute": "ZCLAttributeDef(id=0x0005, name='last_configured_by', type=<class 'zigpy.types.named.EUI64'>, zcl_type=<DataTypeId.EUI64: 240>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0004": {
                "attribute": "ZCLAttributeDef(id=0x0004, name='name_support', type=<flag 'NameSupport'>, zcl_type=<DataTypeId.map8: 24>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0xfffe": {
                "attribute": "ZCLAttributeDef(id=0xFFFE, name='reporting_status', type=<enum 'AttributeReportingStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0003": {
                "attribute": "ZCLAttributeDef(id=0x0003, name='scene_valid', type=<enum 'Bool'>, zcl_type=<DataTypeId.bool_: 16>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              }
            },
            "unsupported_attributes": []
          },
          "0xef00": {
            "endpoint_attribute": "tuya_manufacturer",
            "attributes": {},
            "unsupported_attributes": []
          }
        },
        "out_clusters": {
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {
              "0xfffd": {
                "attribute": "ZCLAttributeDef(id=0xFFFD, name='cluster_revision', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0004": {
                "attribute": "ZCLAttributeDef(id=0x0004, name='dst_end', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0005": {
                "attribute": "ZCLAttributeDef(id=0x0005, name='dst_shift', type=<class 'zigpy.types.basic.int32s'>, zcl_type=<DataTypeId.int32: 43>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0003": {
                "attribute": "ZCLAttributeDef(id=0x0003, name='dst_start', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0008": {
                "attribute": "ZCLAttributeDef(id=0x0008, name='last_set_time', type=<class 'zigpy.types.named.UTCTime'>, zcl_type=<DataTypeId.UTC: 226>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0007": {
                "attribute": "ZCLAttributeDef(id=0x0007, name='local_time', type=<class 'zigpy.types.named.LocalTime'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0xfffe": {
                "attribute": "ZCLAttributeDef(id=0xFFFE, name='reporting_status', type=<enum 'AttributeReportingStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0006": {
                "attribute": "ZCLAttributeDef(id=0x0006, name='standard_time', type=<class 'zigpy.types.named.StandardTime'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0000": {
                "attribute": "ZCLAttributeDef(id=0x0000, name='time', type=<class 'zigpy.types.named.UTCTime'>, zcl_type=<DataTypeId.UTC: 226>, access=<ZCLAttributeAccess.Read|Write_Optional: 5>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0001": {
                "attribute": "ZCLAttributeDef(id=0x0001, name='time_status', type=<flag 'TimeStatus'>, zcl_type=<DataTypeId.map8: 24>, access=<ZCLAttributeAccess.Read|Write_Optional: 5>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0002": {
                "attribute": "ZCLAttributeDef(id=0x0002, name='time_zone', type=<class 'zigpy.types.basic.int32s'>, zcl_type=<DataTypeId.int32: 43>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0009": {
                "attribute": "ZCLAttributeDef(id=0x0009, name='valid_until_time', type=<class 'zigpy.types.named.UTCTime'>, zcl_type=<DataTypeId.UTC: 226>, access=<ZCLAttributeAccess.Read|Write: 3>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              }
            },
            "unsupported_attributes": []
          },
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {
              "0xfffd": {
                "attribute": "ZCLAttributeDef(id=0xFFFD, name='cluster_revision', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0002": {
                "attribute": "ZCLAttributeDef(id=0x0002, name='current_file_version', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": 74
              },
              "0x0003": {
                "attribute": "ZCLAttributeDef(id=0x0003, name='current_zigbee_stack_version', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0004": {
                "attribute": "ZCLAttributeDef(id=0x0004, name='downloaded_file_version', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0005": {
                "attribute": "ZCLAttributeDef(id=0x0005, name='downloaded_zigbee_stack_version', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0001": {
                "attribute": "ZCLAttributeDef(id=0x0001, name='file_offset', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000a": {
                "attribute": "ZCLAttributeDef(id=0x000A, name='image_stamp', type=<class 'zigpy.types.basic.uint32_t'>, zcl_type=<DataTypeId.uint32: 35>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0008": {
                "attribute": "ZCLAttributeDef(id=0x0008, name='image_type_id', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0006": {
                "attribute": "ZCLAttributeDef(id=0x0006, name='image_upgrade_status', type=<enum 'ImageUpgradeStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0007": {
                "attribute": "ZCLAttributeDef(id=0x0007, name='manufacturer_id', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0009": {
                "attribute": "ZCLAttributeDef(id=0x0009, name='minimum_block_req_delay', type=<class 'zigpy.types.basic.uint16_t'>, zcl_type=<DataTypeId.uint16: 33>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0xfffe": {
                "attribute": "ZCLAttributeDef(id=0xFFFE, name='reporting_status', type=<enum 'AttributeReportingStatus'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000b": {
                "attribute": "ZCLAttributeDef(id=0x000B, name='upgrade_activation_policy', type=<enum 'UpgradeActivationPolicy'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              },
              "0x0000": {
                "attribute": "ZCLAttributeDef(id=0x0000, name='upgrade_server_id', type=<class 'zigpy.types.named.EUI64'>, zcl_type=<DataTypeId.EUI64: 240>, access=<ZCLAttributeAccess.Read: 1>, mandatory=True, is_manufacturer_specific=False)",
                "value": null
              },
              "0x000c": {
                "attribute": "ZCLAttributeDef(id=0x000C, name='upgrade_timeout_policy', type=<enum 'UpgradeTimeoutPolicy'>, zcl_type=<DataTypeId.enum8: 48>, access=<ZCLAttributeAccess.Read: 1>, mandatory=False, is_manufacturer_specific=False)",
                "value": null
              }
            },
            "unsupported_attributes": []
          }
        }
      }
    }
  }
}]

Logs

Logs
[2024-12-10 23:17:53.937 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 160): set_time_request(param=[193, 0])
2024-12-10 23:18:24.215 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received ZCL frame: b'\t\xa1$\xc2\x00'
2024-12-10 23:18:24.215 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x09>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=161, command_id=36, *direction=<Direction.Server_to_Client: 1>)
2024-12-10 23:18:24.216 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame: TuyaThermostaticCluster:set_time_request(param=[194, 0])
2024-12-10 23:18:24.216 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 161): set_time_request(param=[194, 0])
2024-12-10 23:18:54.513 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received ZCL frame: b'\t\xa2$\xc3\x00'
2024-12-10 23:18:54.513 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x09>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=162, command_id=36, *direction=<Direction.Server_to_Client: 1>)
2024-12-10 23:18:54.514 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame: TuyaThermostaticCluster:set_time_request(param=[195, 0])
2024-12-10 23:18:54.514 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 162): set_time_request(param=[195, 0])
2024-12-10 23:19:24.824 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received ZCL frame: b'\t\xa3$\xc4\x00'
2024-12-10 23:19:24.825 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x09>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=163, command_id=36, *direction=<Direction.Server_to_Client: 1>)
2024-12-10 23:19:24.825 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame: TuyaThermostaticCluster:set_time_request(param=[196, 0])
2024-12-10 23:19:24.825 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 163): set_time_request(param=[196, 0])
2024-12-10 23:19:55.136 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received ZCL frame: b'\t\xa4$\xc5\x00'
2024-12-10 23:19:55.137 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x09>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=164, command_id=36, *direction=<Direction.Server_to_Client: 1>)
2024-12-10 23:19:55.137 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame: TuyaThermostaticCluster:set_time_request(param=[197, 0])
2024-12-10 23:19:55.137 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 164): set_time_request(param=[197, 0])
2024-12-10 23:20:25.422 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received ZCL frame: b'\t\xa5$\xc6\x00'
2024-12-10 23:20:25.422 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x09>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=165, command_id=36, *direction=<Direction.Server_to_Client: 1>)
2024-12-10 23:20:25.423 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame: TuyaThermostaticCluster:set_time_request(param=[198, 0])
2024-12-10 23:20:25.423 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 165): set_time_request(param=[198, 0])
2024-12-10 23:20:55.713 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received ZCL frame: b'\t\xa6$\xc7\x00'
2024-12-10 23:20:55.713 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x09>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=166, command_id=36, *direction=<Direction.Server_to_Client: 1>)
2024-12-10 23:20:55.714 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame: TuyaThermostaticCluster:set_time_request(param=[199, 0])
2024-12-10 23:20:55.714 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 166): set_time_request(param=[199, 0])
2024-12-10 23:21:26.003 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received ZCL frame: b'\t\xa7$\xc8\x00'
2024-12-10 23:21:26.003 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x09>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=167, command_id=36, *direction=<Direction.Server_to_Client: 1>)
2024-12-10 23:21:26.004 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame: TuyaThermostaticCluster:set_time_request(param=[200, 0])
2024-12-10 23:21:26.004 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 167): set_time_request(param=[200, 0])
2024-12-10 23:21:56.304 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received ZCL frame: b'\t\xa8$\xc9\x00'
2024-12-10 23:21:56.304 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x09>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=168, command_id=36, *direction=<Direction.Server_to_Client: 1>)
2024-12-10 23:21:56.304 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame: TuyaThermostaticCluster:set_time_request(param=[201, 0])
2024-12-10 23:21:56.305 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 168): set_time_request(param=[201, 0])
2024-12-10 23:22:26.599 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received ZCL frame: b'\t\xa9$\xca\x00'
2024-12-10 23:22:26.599 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x09>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=169, command_id=36, *direction=<Direction.Server_to_Client: 1>)
2024-12-10 23:22:26.600 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame: TuyaThermostaticCluster:set_time_request(param=[202, 0])
2024-12-10 23:22:26.600 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 169): set_time_request(param=[202, 0])
2024-12-10 23:22:56.895 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received ZCL frame: b'\t\xaa$\xcb\x00'
2024-12-10 23:22:56.895 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl<0x09>(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=0, direction=<Direction.Server_to_Client: 1>, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=170, command_id=36, *direction=<Direction.Server_to_Client: 1>)
2024-12-10 23:22:56.896 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Decoded ZCL frame: TuyaThermostaticCluster:set_time_request(param=[203, 0])
2024-12-10 23:22:56.896 DEBUG (MainThread) [zigpy.zcl] [0x622A:1:0xef00] Received command 0x24 (TSN 170): set_time_request(param=[203, 0])]

Custom quirk

Custom quirk
[from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import Basic, Groups, Scenes, Ota, Time
from zhaquirks.tuya import TuyaManufClusterAttributes

class TuyaThermostaticCluster(TuyaManufClusterAttributes):
    """Custom cluster for Tuya TRV to handle specific attributes."""

    manufacturer_attributes = {
        0x0103: ("current_temperature", "degrees"),
        0x0104: ("target_temperature", "degrees"),
        0x0105: ("battery_level", "%"),
    }

    processed_tsn = set()

    def handle_cluster_request(self, tsn, command_id, args):
        """Handle incoming cluster commands."""
        if tsn in self.processed_tsn:
            self.debug(f"TSN {tsn} already processed, skipping.")
            return
        self.processed_tsn.add(tsn)

        self.debug(f"Handling command_id={command_id}, args={args}")
        if command_id == 0x02:  # set_data_response
            self._handle_set_data_response(args)
        elif command_id == 0x24:  # set_time_request
            self._handle_set_time_request(args)
        else:
            self.debug(f"Unhandled command {command_id}: {args}")

    def _handle_set_data_response(self, args):
        """Process set_data_response to update entities."""
        self.debug(f"Processing set_data_response: {args}")
        if not isinstance(args, dict):
            self.debug("Invalid args format, expected a dictionary.")
            return
        for attribute_id, value in args.items():
            if attribute_id in self.manufacturer_attributes:
                attr_name, unit = self.manufacturer_attributes[attribute_id]
                self.debug(f"Updating {attr_name} to {value}{unit}")
                if hasattr(self.endpoint.device, "update_entity"):
                    self.endpoint.device.update_entity(attr_name, value)
                else:
                    self.debug(f"Device does not support update_entity for {attr_name}")

    def _handle_set_time_request(self, args):
        """Handle set_time_request, if needed."""
        self.debug(f"Set time request: {args}")

class TuyaThermostaticRadiatorValve(CustomDevice):
    """Custom device for Tuya TRV."""

    signature = {
        "models_info": [("_TZE204_qyr2m29i", "TS0601")],
        "endpoints": {
            1: {
                "profile_id": zha.PROFILE_ID,  # 0x0104
                "device_type": 0x0051,  # Thermostat device type
                "input_clusters": [
                    0x0000,  # Basic
                    0x0004,  # Groups
                    0x0005,  # Scenes
                    0xEF00,  # Tuya Manufacturer Specific
                ],
                "output_clusters": [
                    0x000A,  # Time
                    0x0019,  # OTA
                ],
            }
        },
    }

    replacement = {
        "endpoints": {
            1: {
                "profile_id": zha.PROFILE_ID,
                "device_type": zha.DeviceType.THERMOSTAT,
                "input_clusters": [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaThermostaticCluster,  # Use the custom thermostat-specific cluster
                ],
                "output_clusters": [
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }

    def update_entity(self, attr_name, value):
        """Update Home Assistant entity."""
        self.debug(f"Updating entity {attr_name} with value {value}")
        if hasattr(self, attr_name):
            setattr(self, attr_name, value)
            # Signal Home Assistant to refresh the entity
            self.hass.bus.fire("zha_custom_update", {"entity": attr_name, "value": value})]

Additional information

No response

@prairiesnpr
Copy link
Contributor

Looks like z2m has identified the Datapoints: Koenkk/zigbee2mqtt#24958

I'd recommend building a v2 quirk, docs are here https://github.com/zigpy/zha-device-handlers/blob/dev/tuya.md and there is a guide on the wiki now. https://github.com/zigpy/zha-device-handlers/wiki/Tuya-%E2%80%90-v2-Quirk-with-TuyaQuirkBuilder

This should get you started. See the quirk in work here #3565

from zigpy.quirks.v2 import EntityType
import zigpy.types as t

from zhaquirks.tuya.builder import TuyaQuirkBuilder
from zigpy.quirks.v2.homeassistant import UnitOfTemperature,,
from zigpy.quirks.v2.homeassistant.sensor import SensorDeviceClass, SensorStateClass

(
    TuyaQuirkBuilder("_TZE204_qyr2m29i", "TS0601")
   .tuya_number(
        dp_id=4,
        type=t.int16s,
        attribute_name="current_heating_setpoint",
        min_value=5,
        max_value=35,
        step=1,
        unit=UnitOfTemperature.CELSIUS,
        translation_key="heating_setpoint",
        fallback_name="Heating setpoint",
    )
    .tuya_sensor(
        dp_id=5,
        attribute_name="local_temperature",
        type=t.int16s,
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
        unit=UnitOfTemperature.CELSIUS,
        translation_key="local_temperature",
        fallback_name="Local temperature",
    )
    .skip_configuration()
    .add_to_registry()
)

@BugSniper3000
Copy link
Author

Thanks for the help @prairiesnpr , rather than battle on my own I have used Z2M and have got to the same point as the others with it partially working. Hopefully there is come more progress in the future :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants