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
731 stars 673 forks source link

[Device Support Request] Tuya TS0601 _TZE204_g2ki0ejr TRV Thermostatic Radiator Value #2677

Closed oxcid3 closed 1 month ago

oxcid3 commented 11 months ago

Problem description

https://www.aliexpress.com/item/1005005997839493.html

TRV Thermostatic Radiator Valve

Solution description

Datapoints via Tuya IoT

{"2":"Mode", "4":"Set temperature", "5":"Current temperature", "6":"Battery capacity", "7":"Child lock", "9":"Set temperature ceiling", "10":"The lower limit of temperature", "14":"Window check", "16":"Window temp", "17":"Window time", "18":"Backlight brightness", "19":"Factory data reset", "21":"Holiday temperature", "24":"Home temp", "25":"Leave temp", "28":"Week program", "29":"Week program Tuesday", "30":"Week program Wednesday", "31":"Week program Thursday", "32":"Week program Friday", "33":"Week program Saturday", "34":"Week program Sunday", "35":"Fault alarm", "36":"Frost protection", "37":"Rapid warming", "38":"Rapid heating countdown", "39":"Switch Scale", "47":"Temperature correction", "48":"Valve testing", "49":"State of the valve", "101":"111"}

Screenshots/Video

Screenshots/Video [Paste/upload your media here]

Device signature

Device signature ```json { "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=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)", "endpoints": { "1": { "profile_id": "0x0104", "device_type": "0x0301", "input_clusters": [ "0x0000", "0x0001", "0x0004", "0x0005", "0x0006", "0x0201", "0x0204", "0xef00" ], "output_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "_TZE204_g2ki0ejr", "model": "TS0601", ```

Diagnostic information

Diagnostic information ```json { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2023.10.5", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.11.5", "docker": true, "arch": "aarch64", "timezone": "Europe/London", "os_name": "Linux", "os_version": "6.1.21-v8", "supervisor": "2023.10.0", "host_os": "Home Assistant OS 11.0", "docker_version": "24.0.6", "chassis": "embedded", "run_as_root": true }, "custom_components": { "tplink_deco": { "version": "3.5.3", "requirements": [ "pycryptodome>=3.12.0" ] }, "reolink_discovery": { "version": "1.2.0", "requirements": [] }, "deebot": { "version": "2.1.1", "requirements": [ "deebot-client==3.0.1", "numpy>=1.23.2" ] }, "adaptive_lighting": { "version": "1.19.0", "requirements": [ "ulid-transform" ] }, "localtuya": { "version": "5.2.1", "requirements": [] }, "miio_yeelink": { "version": "0.1.12", "requirements": [ "construct==2.10.56", "python-miio>=0.5.6" ] }, "hacs": { "version": "1.33.0", "requirements": [ "aiogithubapi>=22.10.1" ] }, "samsungtv_tizen": { "version": "1.6.1", "requirements": [ "websocket-client>=0.56.0", "wakeonlan>=2.0.0", "numpy>=1.19.2" ] }, "alarmo": { "version": "v1.9.10", "requirements": [] }, "octopus_energy": { "version": "8.4.4", "requirements": [] } }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "after_dependencies": [ "onboarding", "usb" ], "codeowners": [ "@dmulcahey", "@adminiuga", "@puddly" ], "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", "universal_silabs_flasher" ], "requirements": [ "bellows==0.36.5", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.105", "zigpy-deconz==0.21.1", "zigpy==0.57.2", "zigpy-xbee==0.18.3", "zigpy-zigate==0.11.0", "zigpy-znp==0.11.6", "universal-silabs-flasher==0.0.14", "pyserial-asyncio-fast==0.11" ], "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" ] } ], "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*" } ], "is_built_in": true }, "data": { "ieee": "**REDACTED**", "nwk": 41781, "manufacturer": "_TZE204_g2ki0ejr", "model": "TS0601", "name": "_TZE204_g2ki0ejr TS0601", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4417, "power_source": "Battery or Unknown", "lqi": 255, "rssi": -70, "last_seen": "2023-10-23T14:25:45", "available": true, "device_type": "EndDevice", "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=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)", "endpoints": { "1": { "profile_id": "0x0104", "device_type": "0x0051", "input_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "output_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "_TZE204_g2ki0ejr", "model": "TS0601" }, "active_coordinator": false, "entities": [], "neighbors": [], "routes": [], "endpoint_names": [ { "name": "SMART_PLUG" } ], "user_given_name": null, "device_reg_id": "0531c49971e1bd402533ebfe50f71bcc", "area_id": null, "cluster_details": { "1": { "device_type": { "name": "SMART_PLUG", "id": 81 }, "profile_id": 260, "in_clusters": { "0x0004": { "endpoint_attribute": "groups", "attributes": {}, "unsupported_attributes": {} }, "0x0005": { "endpoint_attribute": "scenes", "attributes": {}, "unsupported_attributes": {} }, "0xef00": { "endpoint_attribute": null, "attributes": {}, "unsupported_attributes": {} }, "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0004": { "attribute_name": "manufacturer", "value": "_TZE204_g2ki0ejr" }, "0x0005": { "attribute_name": "model", "value": "TS0601" } }, "unsupported_attributes": {} } }, "out_clusters": { "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} }, "0x000a": { "endpoint_attribute": "time", "attributes": {}, "unsupported_attributes": {} } } } } } } ```

Logs

Logs ```python [Paste the logs here] ```

Custom quirk

Custom quirk ```python [Paste your custom quirk here] ```

Additional information

Bought a tuya hub to test functionality. (Connection is sketchy, so could really do with local ZigBee integration.)

Functionality: Target temp Current temp Battery Mode

Attributes: Temperature Ceiling Lower limit of Temp Child lock Open window detection

Screenshot_20231103_091801_Tuya Smart Screenshot_20231103_091831_Tuya Smart

No response

elboletaire commented 11 months ago

I also purchased this same TRV, and I'm really interested in this quirk.

FrankM70 commented 11 months ago

I am also interested in a Solution. I have also one not working properly.

oxcid3 commented 11 months ago

Added screenshots from tuya app.

Jastreb07 commented 11 months ago

any update? I'm interested too in this quirk.

wormvortex commented 10 months ago

Got the same device. Adding it via ZHA in home assistant does not expose any of the value nor does it let me control it

Steefph commented 10 months ago

Here is my first attempt to create an actual working converter :)

Just noticed that this is not the zigbee2mqtt integration

const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const extend = require('zigbee-herdsman-converters/lib/extend');
const e = exposes.presets;
const ea = exposes.access;
const tuya = require('zigbee-herdsman-converters/lib/tuya');

const definition = {
    fingerprint: [
        {
            // The model ID from: Device with modelID 'TS0601' is not supported
            // You may need to add \u0000 at the end of the name in some cases
            modelID: 'TS0601',
            // The manufacturer name from: Device with modelID 'TS0601' is not supported.
            manufacturerName: '_TZE204_g2ki0ejr',
        },
    ],
    model: 'BAB-1413 Pro',
    vendor: 'TuYa',
    description: 'Thermostat Radiator Valve',
    fromZigbee: [tuya.fz.datapoints],
    toZigbee: [tuya.tz.datapoints],
    onEvent: tuya.onEventSetTime, // Add this if you are getting no converter for 'commandMcuSyncTime'
    configure: tuya.configureMagicPacket,
    exposes: [
        e.child_lock(), e.open_window_temperature().withValueMin(5).withValueMax(30),
        e.comfort_temperature().withValueMin(5).withValueMax(30), e.eco_temperature().withValueMin(5).withValueMax(30), e.holiday_temperature().withValueMin(5).withValueMax(30),
        e.climate().withPreset(['auto', 'manual', 'holiday', 'comfort']).withLocalTemperatureCalibration(-5, 5, 0.1, ea.STATE_SET)
            .withLocalTemperature(ea.STATE).withSetpoint('current_heating_setpoint', 5, 30, 0.5, ea.STATE_SET)
            .withSystemMode(['off', 'heat', 'auto'], ea.STATE_SET, 'Only for Homeassistant'),
        tuya.exposes.frostProtection('When Anti-Freezing function is activated, the temperature in the house is kept '+
                'at 8 °C, the device display "AF".press the pair button to cancel.'),
        e.numeric('boost_timeset_countdown', ea.STATE_SET).withUnit('s').withDescription('Setting '+
                'minimum 0 - maximum 465 seconds boost time. The boost function is activated. The remaining '+
                'time for the function will be counted down in seconds ( 465 to 0 ).').withValueMin(0).withValueMax(465),
        e.text('holiday_start_stop', ea.STATE_SET).withDescription('The holiday mode will automatically start ' +
            'at the set time starting point and run the holiday temperature. Can be defined in the following format: ' +
            '`startYear/startMonth/startDay startHours:startMinutes | endYear/endMonth/endDay endHours:endMinutes`. ' +
            'For example: `2022/10/01 16:30 | 2022/10/21 18:10`. After the end of holiday mode, it switches to "auto" ' +
            'mode and uses schedule.'),
        e.enum('working_day', ea.STATE_SET, ['mon_sun', 'mon_fri+sat+sun', 'separate']).withDescription('`mon_sun` ' +
            '- schedule for Monday used for each day (define it only for Monday). `mon_fri+sat+sun` - schedule for ' +
            'workdays used from Monday (define it only for Monday), Saturday and Sunday are defined separately. `separate` ' +
            '- schedule for each day is defined separately.'),
        e.composite('schedule', 'schedule', ea.SET).withFeature(e.enum('week_day', ea.SET, ['monday', 'tuesday',
            'wednesday', 'thursday', 'friday', 'saturday', 'sunday'])).withFeature(e.text('schedule', ea.SET))
            .withDescription('Schedule will work with "auto" preset. In this mode, the device executes ' +
            'a preset week programming temperature time and temperature. Before using these properties, check `working_day` ' +
            'property. Each day can contain up to 10 segments. At least 1 segment should be defined. Different count of segments ' +
            'can be defined for each day, e.g., 3 segments for Monday, 5 segments for Thursday, etc. It should be defined in the ' +
            'following format: `hours:minutes/temperature`. Minutes can be only tens, i.e., 00, 10, 20, 30, 40, 50. Segments should ' +
            'be divided by space symbol. Each day should end with the last segment of 24:00. Examples: `04:00/20 08:30/22 10:10/18 ' +
            '18:40/24 22:50/19.5`; `06:00/21.5 17:20/26 24:00/18`. The temperature will be set from the beginning/start of one ' +
            'period and until the next period, e.g., `04:00/20 24:00/22` means that from 00:00 to 04:00 temperature will be 20 ' +
            'degrees and from 04:00 to 00:00 temperature will be 22 degrees.'),
        ...tuya.exposes.scheduleAllDays(ea.STATE, 'HH:MM/C'),
        //e.binary('online', ea.STATE_SET, 'ON', 'OFF').withDescription('The current data request from the device.'),
        e.binary('valve', ea.STATE, 'CLOSED', 'OPEN'),
        e.enum('factory_reset', ea.STATE_SET, ['SET']).withDescription('Remove limits'),
        tuya.exposes.errorStatus(),
    ],

    meta: {
        tuyaDatapoints: [
            [2, 'system_mode', tuya.valueConverterBasic.lookup({'auto': tuya.enum(0), 'heat': tuya.enum(2), 'off': tuya.enum(1)})],
            [2, 'preset', tuya.valueConverterBasic.lookup({'comfort': tuya.enum(3),'auto': tuya.enum(0), 'manual': tuya.enum(2), 'holiday': tuya.enum(1)})],
            [4, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
            [5, 'local_temperature', tuya.valueConverter.divideBy10],
            [6, 'battery', tuya.valueConverter.raw],
            [7, 'child_lock', tuya.valueConverter.lockUnlock],
            [9, 'max_temperature_limit', tuya.valueConverter.divideBy10],
            [10, 'min_temperature_limit', tuya.valueConverter.divideBy10],
            [14, 'open_window', tuya.valueConverter.onOff],
            [16, 'open_window_temperature', tuya.valueConverter.divideBy10],
            [17, 'open_window_time', tuya.valueConverter.raw],
            //[18, 'Backlight brightness', tuya.valueConverter.raw],
            [19, 'factory_reset',  tuya.valueConverter.setLimit],
            [21, 'holiday_temperature', tuya.valueConverter.raw],
            [24, 'comfort_temperature', tuya.valueConverter.divideBy10],
            [25, 'eco_temperature', tuya.valueConverter.divideBy10],
            [28, 'schedule_monday', tuya.valueConverter.thermostatScheduleDaySingleDP],
            [29, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDaySingleDP],
            [30, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDaySingleDP],
            [31, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDaySingleDP],
            [32, 'schedule_friday', tuya.valueConverter.thermostatScheduleDaySingleDP],
            [33, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDaySingleDP],
            [34, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDaySingleDP],
            [35, 'error_status', tuya.valueConverter.raw],
            [36, 'frost_protection', tuya.valueConverter.onOff],
            [37, 'boost_heating', tuya.valueConverter.onOff],
            [38, 'boost_time', tuya.valueConverter.countdown],
            [39, 'Switch Scale', tuya.valueConverter.raw],
            [47, 'local_temperature_calibration', tuya.valueConverter.localTempCalibration1],
            [48, 'valve_testing', tuya.valueConverter.raw],
            [49, 'valve', tuya.valueConverterBasic.lookup({'OPEN': 1, 'CLOSE': 0})],
        ],
    },
};

module.exports = definition;
oxcid3 commented 10 months ago

Amazing, thanks for this. - I'll run some testing on my side. Just to be clear, should this work as a custom quirk, or do I need something else to get this to work. (I've not come across the concept of a converter before)

Is this ZigbeetoMQTT or ZHA?

Steefph commented 10 months ago

I looked for the "_TZE204_g2ki0ejr" thinking I would end up at zigbee2mqtt git. But apparently this is ZHA (never used it). The converter is for Z2M

enricocirignaco commented 10 months ago

I have the same problem too. Any changes someone want to write a quirk for ZHA? Would be really appreciated!

frederick9372 commented 10 months ago

How do you integrate the converter?

mleimbach-beeclever commented 10 months ago

@frederick9372 unforgenatly the converter was a miss-post to the wrong issue/project. (hopefully it might be helpful in a quirk development ?) as @Steefph wrote. the contribution was planned togo into the zigbee2mqtt project but got the wrong issue/project.

For zha we would need a custom quirk or a native integration, but currently there does not seem to be a one for that product in the wild.

I also got a couple of those valves around here an would appriecieatea support (a working quirk) or a starting point for altering an existing quirk to be able to get access to the endpoints.

enricocirignaco commented 10 months ago

Anyone interested in helping writing a quirk for this valve? I'm a programmer but I never wrote quirks for HA. I have a valve so I could also test the code myself

mleimbach-beeclever commented 9 months ago

Okay since nobody had a quirk running, i just tried out using the default trv quirk from tuya. It originally did not sepcify the model we talk about here, but i just added it anyway.

I might need additional testing here, but for now i can give positive feedback using the official tuya trv quirk and just adding the devices id in the models info array. This seems to give me the basic functionality that i need.

What you might want to try to also get it running:

MODELS_INFO: [ ("_TZE204_pcdmj88b", "TS0601"), ("_TZE204_g2ki0ejr", "TS0601"), ] ,

works for me 👍

FrankM70 commented 9 months ago

Okay since nobody had a quirk running, i just tried out using the default trv quirk from tuya. It originally did not sepcify the model we talk about here, but i just added it anyway.

I might need additional testing here, but for now i can give positive feedback using the official tuya trv quirk and just adding the devices id in the models info array. This seems to give me the basic functionality that i need.

What you might want to try to also get it running:

  • create a custom quirks folder as described here
  • get the official tuya ts601 _tze204 trv quirk and save the file in your custom quirks folder.
  • modify the "models_info" to add the devices model name we have here

MODELS_INFO: [ ("_TZE204_pcdmj88b", "TS0601"), ("_TZE204_g2ki0ejr", "TS0601"), ] ,

  • restart HA
  • deleted and reconnected the device

works for me 👍

Thank you, it worked for me too. I am so impressed. I think I learned a lot to solve other problems.

Ppatou commented 9 months ago

Hello I think I have discovered a small bug in the converter file. I am using z2m as an add on in HA. So I think I have not easy access to the converter files. In the climate integration 3 attributes concern the detected ambiance temp.

- local_temperature: 22
- local_temperature_calibration: 0.5
- current_temperature: 22

My understanding is that current_temp = local_temp + local_temp_calibration. But current and local temp are identical. I do not see the local_temp number in the expose file of the device z2m expose file 2023-12-20_22h47_55

Can one of you correct the converter file and update the device data's Thanks in advance Patou

elboletaire commented 8 months ago

This seems to give me the basic functionality that i need.

The thermostat works for me, but I am not sure what the two switches do. Have you tried them out? I thought one of them could be used just to open and close the valve, but I'm not sure it works in conjunction with the thermostat. Also, setting the thermostat to "off" doesn't seem to be doing anything.

So at least I can confirm using that quirk allows you to use it like in the manual setting. Changing the temperature opens and closes the valve, depending on the temperature given by its own temperature sensor.

Edit: well, the thermostat "kinda" works... it takes a lot of time and sometimes it just resets its value, forcing you to send the command again. There aren't any logs of any kind either.

Edit2 (to not disturb others with multiple notifications): I've been doing some tests and I know for sure now the first switch is the "force heat" function, but the second one sets the device into a "dP" mode of which I cannot find any information, and I don't see it doing anything special.

Teka101 commented 8 months ago

Support added in PR: https://github.com/zigpy/zha-device-handlers/pull/2873

agnus777 commented 8 months ago

Okay since nobody had a quirk running, i just tried out using the default trv quirk from tuya. It originally did not sepcify the model we talk about here, but i just added it anyway. I might need additional testing here, but for now i can give positive feedback using the official tuya trv quirk and just adding the devices id in the models info array. This seems to give me the basic functionality that i need. What you might want to try to also get it running:

  • create a custom quirks folder as described here
  • get the official tuya ts601 _tze204 trv quirk and save the file in your custom quirks folder.
  • modify the "models_info" to add the devices model name we have here

MODELS_INFO: [ ("_TZE204_pcdmj88b", "TS0601"), ("_TZE204_g2ki0ejr", "TS0601"), ] ,

  • restart HA
  • deleted and reconnected the device

works for me 👍

Thank you, it worked for me too. I am so impressed. I think I learned a lot to solve other problems.

I tried this and it works for basic function. what I noticed is that switch 1 is the related command of "force heat" while switch 2 is the "window detection".

Someone know how to replace functions?

altopais commented 7 months ago

After the HA update 2024.1.6 i get

"Failed to call service switch/turn_on. Failed to send request: Failed to deliver message: <EmberStatus.DELIVERY_FAILED: 102>"

for every function.

As i am new to HA and ZHA, looking for help to resolve the issue. Thanks.

github-actions[bot] commented 1 month ago

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.