zigbee-herdsman-converters icon indicating copy to clipboard operation
zigbee-herdsman-converters copied to clipboard

Issue adding new Thaleos radiator valve TS0601 vendor: '_TZE200_rv6iuyxb'

Open kostya-fr opened this issue 1 year ago • 1 comments

Hello, I got same French valves by Thaleos-Connect, I have following definition :

const definition = {
    zigbeeModel: ['TS0601'],
    model: 'TS0601',
    vendor: '_TZE200_rv6iuyxb',
    description: 'Automatically generated definition',
    extend: [],
    meta: {},
};
I added following code (from #7998) into /config/zigbee2mqtt/TS0601.js :

zigbeeModel: ['TS0601'],
const legacy = require('zigbee-herdsman-converters/lib/legacy');
const fz = {...require('zigbee-herdsman-converters/converters/fromZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').fromZigbee};
const tz = {...require('zigbee-herdsman-converters/converters/toZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').toZigbee};
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const ota = require('zigbee-herdsman-converters/lib/ota');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
  	zigbeeModel: ['TS0601'],
    fingerprint: [
            {modelID: 'TS0601', manufacturerName: '_TZE200_rv6iuyxb'}, //Thaleos Connect
        ],
    model: 'TS0601_thermostat',
    vendor: 'Tuya',
    description: 'Radiator valve with thermostat', 
    meta: {tuyaThermostatPreset: legacy.thermostatPresets, tuyaThermostatSystemMode: legacy.thermostatSystemModes3},
    ota: ota.zigbeeOTA,
    onEvent: tuya.onEventSetLocalTime,
    fromZigbee: [legacy.fromZigbee.tuya_thermostat, fz.ignore_basic_report, fz.ignore_tuya_set_time],
    toZigbee: [
            legacy.toZigbee.tuya_thermostat_child_lock,
            legacy.toZigbee.tuya_thermostat_window_detection,
            legacy.toZigbee.tuya_thermostat_valve_detection,
            legacy.toZigbee.tuya_thermostat_current_heating_setpoint,
            legacy.toZigbee.tuya_thermostat_auto_lock,
            legacy.toZigbee.tuya_thermostat_calibration,
            legacy.toZigbee.tuya_thermostat_min_temp,
            legacy.toZigbee.tuya_thermostat_max_temp,
            legacy.toZigbee.tuya_thermostat_boost_time,
            legacy.toZigbee.tuya_thermostat_comfort_temp,
            legacy.toZigbee.tuya_thermostat_eco_temp,
            legacy.toZigbee.tuya_thermostat_force_to_mode,
            legacy.toZigbee.tuya_thermostat_force,
            legacy.toZigbee.tuya_thermostat_preset,
            legacy.toZigbee.tuya_thermostat_window_detect,
            legacy.toZigbee.tuya_thermostat_schedule,
            legacy.toZigbee.tuya_thermostat_week,
            legacy.toZigbee.tuya_thermostat_schedule_programming_mode,
            legacy.toZigbee.tuya_thermostat_away_mode,
            legacy.toZigbee.tuya_thermostat_away_preset,
        ],
        exposes: [
            e.child_lock(),
            e.window_detection(),
            e.binary('window_open', ea.STATE, true, false).withDescription('Window open?'),
            e.battery_low(),
            e.valve_detection(),
            e.position(),
            e
                .climate()
                .withSetpoint('current_heating_setpoint', 5, 35, 0.5, ea.STATE_SET)
                .withLocalTemperature(ea.STATE)
                .withSystemMode(
                    ['heat', 'auto', 'off'],
                    ea.STATE_SET,
                    'Mode of this device, in the `heat` mode the TS0601 will remain continuously heating, i.e. it does not regulate ' +
                        'to the desired temperature. If you want TRV to properly regulate the temperature you need to use mode `auto` ' +
                        'instead setting the desired temperature.',
                )
                .withLocalTemperatureCalibration(-9, 9, 0.5, ea.STATE_SET)
                .withPreset(['schedule', 'manual', 'boost', 'complex', 'comfort', 'eco', 'away'])
                .withRunningState(['idle', 'heat'], ea.STATE),
            e.auto_lock(),
            e.away_mode(),
            e.away_preset_days(),
            e.boost_time(),
            e.comfort_temperature(),
            e.eco_temperature(),
            e.force(),
            e.max_temperature().withValueMin(16).withValueMax(70),
            e.min_temperature(),
            e.away_preset_temperature(),
            e.week(),
            e
                .text('workdays_schedule', ea.STATE_SET)
                .withDescription('Workdays schedule, 6 entries max, example: "00:20/5°C 01:20/5°C 6:59/15°C 18:00/5°C 20:00/5°C 23:30/5°C"'),
            e
                .text('holidays_schedule', ea.STATE_SET)
                .withDescription('Holidays schedule, 6 entries max, example: "00:20/5°C 01:20/5°C 6:59/15°C 18:00/5°C 20:00/5°C 23:30/5°C"'),
        ],
};

module.exports = definition;
            
But it doesn't work for me. I added to zigbee2mqtt config :
external_converters:
  - /config/zigbee2mqtt/TS0601.js

after restarting zigbee2mqtt and adding device I keep message :


info 2024-10-02 08:16:06z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/0xa4cxxxxxxxxxxxxxxx/availability', payload '{"state":"online"}'
info 2024-10-02 08:16:06zh:controller: Interview for '0xa4cxxxxxxxxxxxxxxx' started
info 2024-10-02 08:16:06z2m: Device '0xa4cxxxxxxxxxxxxxxx' joined
info 2024-10-02 08:16:06z2m: Starting interview of '0xa4cxxxxxxxxxxxxxxx'
info 2024-10-02 08:16:07z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/bridge/event', payload '{"data":{"friendly_name":"0xa4cxxxxxxxxxxxxxxx","ieee_address":"0xa4cxxxxxxxxxxxxxxx"},"type":"device_joined"}'
info 2024-10-02 08:16:07z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/bridge/event', payload '{"data":{"friendly_name":"0xa4cxxxxxxxxxxxxxxx","ieee_address":"0xa4cxxxxxxxxxxxxxxx","status":"started"},"type":"device_interview"}'
info 2024-10-02 08:16:07zh:controller:device: Device '0xa4cxxxxxxxxxxxxxxx' is only compliant to revision '21' of the ZigBee specification (current revision: 23).
info 2024-10-02 08:16:10zh:controller: Succesfully interviewed '0xa4cxxxxxxxxxxxxxxx'
info 2024-10-02 08:16:10z2m: Successfully interviewed '0xa4cxxxxxxxxxxxxxxx', device has successfully been paired
warning 2024-10-02 08:16:10z2m: Device '0xa4cxxxxxxxxxxxxxxx' with Zigbee model 'TS0601' and manufacturer name '_TZE200_rv6iuyxb' is NOT supported, please follow https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html
info 2024-10-02 08:16:10z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/bridge/event', payload '{"data":{"friendly_name":"0xa4cxxxxxxxxxxxxxxx","ieee_address":"0xa4cxxxxxxxxxxxxxxx","status":"successful","supported":false},"type":"device_interview"}'

Originally posted by @kostya-fr in https://github.com/Koenkk/zigbee-herdsman-converters/issues/7998#issuecomment-2387298683

kostya-fr avatar Oct 02 '24 08:10 kostya-fr

I checked my model is TRV06 from this doc https://thaleos.com/wp-content/uploads/2024/06/Catalogue-Thaleos-Thermostat-Connecte-20.pdf.

So I updated script to similaire data from tuya.js, but still not working :
const legacy = require('zigbee-herdsman-converters/lib/legacy');
const fz = {...require('zigbee-herdsman-converters/converters/fromZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').fromZigbee};
const tz = {...require('zigbee-herdsman-converters/converters/toZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').toZigbee};
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const ota = require('zigbee-herdsman-converters/lib/ota');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    zigbeeModel: ['TS0601'],
    fingerprint: [
        {modelID: 'TS0601', manufacturerName: '_TZE200_rv6iuyxb'}, //Thaleos Connect
    ],
    model: 'TS0601_thermostat_3',
    vendor: 'Tuya',
    description: 'Thermostatic radiator valve',
    fromZigbee: [tuya.fz.datapoints],
    toZigbee: [tuya.tz.datapoints],
    whiteLabel: [
        tuya.whitelabel('AVATTO', 'ME167', 'Thermostatic radiator valve', ['_TZE200_bvu2wnxz', '_TZE200_6rdj8dzm']),
        tuya.whitelabel('AVATTO', 'ME168', 'Thermostatic radiator valve', ['_TZE200_p3dbf6qs', '_TZE200_rxntag7i']),
        tuya.whitelabel('EARU', 'TRV06', 'Smart thermostat module', ['_TZE200_yqgbrdyo', '_TZE200_rxq4iti9']),
        tuya.whitelabel('AVATTO', 'TRV06', 'Smart thermostat module', ['_TZE200_rv6iuyxb']),
    ],
    onEvent: tuya.onEventSetTime,
    configure: tuya.configureMagicPacket,
    exposes: [
        e.child_lock(),
        e.battery_low(),
        e
            .climate()
            .withSetpoint('current_heating_setpoint', 5, 35, 1, ea.STATE_SET)
            .withLocalTemperature(ea.STATE)
            .withSystemMode(['auto', 'heat', 'off'], ea.STATE_SET)
            .withRunningState(['idle', 'heat'], ea.STATE)
            .withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET),
        ...tuya.exposes.scheduleAllDays(ea.STATE_SET, 'HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C'),
        e
            .binary('scale_protection', ea.STATE_SET, 'ON', 'OFF')
            .withDescription(
                'If the heat sink is not fully opened within ' +
                    'two weeks or is not used for a long time, the valve will be blocked due to silting up and the heat sink will not be ' +
                    'able to be used. To ensure normal use of the heat sink, the controller will automatically open the valve fully every ' +
                    'two weeks. It will run for 30 seconds per time with the screen displaying "Ad", then return to its normal working state ' +
                    'again.',
            ),
        e
            .binary('frost_protection', ea.STATE_SET, 'ON', 'OFF')
            .withDescription(
                'When the room temperature is lower than 5 °C, the valve opens; when the temperature rises to 8 °C, the valve closes.',
            ),
        e.numeric('error', ea.STATE).withDescription('If NTC is damaged, "Er" will be on the TRV display.'),
    ],
    meta: {
        tuyaDatapoints: [
            [2, 'system_mode', tuya.valueConverterBasic.lookup({auto: tuya.enum(0), heat: tuya.enum(1), off: tuya.enum(2)})],
            [3, 'running_state', tuya.valueConverterBasic.lookup({heat: tuya.enum(0), idle: tuya.enum(1)})],
            [4, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
            [5, 'local_temperature', tuya.valueConverter.divideBy10],
            [7, 'child_lock', tuya.valueConverter.lockUnlock],
            [28, 'schedule_monday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
            [29, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
            [30, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
            [31, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
            [32, 'schedule_friday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
            [33, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
            [34, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
            [35, null, tuya.valueConverter.errorOrBatteryLow],
            [36, 'frost_protection', tuya.valueConverter.onOff],
            [39, 'scale_protection', tuya.valueConverter.onOff],
            [47, 'local_temperature_calibration', tuya.valueConverter.localTempCalibration2],
        ],
    },
};

module.exports = definition;

kostya-fr avatar Oct 02 '24 11:10 kostya-fr

OK, I got a external_converters path issues, IDK why it doesn't work I specified directly in /config/zigbee2mqtt/configuration.yaml and it worked perfectly for me. Here is the code :


const legacy = require('zigbee-herdsman-converters/lib/legacy');
const fz = {...require('zigbee-herdsman-converters/converters/fromZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').fromZigbee};
const tz = {...require('zigbee-herdsman-converters/converters/toZigbee'), legacy: require('zigbee-herdsman-converters/lib/legacy').toZigbee};
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const ota = require('zigbee-herdsman-converters/lib/ota');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    zigbeeModel: ['v6iuyxb'],
    fingerprint: [
        {modelID: 'TS0601', manufacturerName: '_TZE200_rv6iuyxb'}, //Thaleos Connect
    ],
    model: 'TS0601_thermostat_3',
    vendor: 'Tuya',
    description: 'Thermostatic radiator valve',
    fromZigbee: [tuya.fz.datapoints],
    toZigbee: [tuya.tz.datapoints],
    whiteLabel: [        
        tuya.whitelabel('AVATTO', 'TRV06', 'Smart thermostat module', ['_TZE200_rv6iuyxb']),
    ],
    onEvent: tuya.onEventSetTime,
    configure: tuya.configureMagicPacket,
    exposes: [
        e.child_lock(),
        e.battery_low(),
        e
            .climate()
            .withSetpoint('current_heating_setpoint', 5, 35, 1, ea.STATE_SET)
            .withLocalTemperature(ea.STATE)
            .withSystemMode(['auto', 'heat', 'off'], ea.STATE_SET)
            .withRunningState(['idle', 'heat'], ea.STATE)
            .withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET),
        ...tuya.exposes.scheduleAllDays(ea.STATE_SET, 'HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C'),
        e
            .binary('scale_protection', ea.STATE_SET, 'ON', 'OFF')
            .withDescription(
                'If the heat sink is not fully opened within ' +
                    'two weeks or is not used for a long time, the valve will be blocked due to silting up and the heat sink will not be ' +
                    'able to be used. To ensure normal use of the heat sink, the controller will automatically open the valve fully every ' +
                    'two weeks. It will run for 30 seconds per time with the screen displaying "Ad", then return to its normal working state ' +
                    'again.',
            ),
        e
            .binary('frost_protection', ea.STATE_SET, 'ON', 'OFF')
            .withDescription(
                'When the room temperature is lower than 5 °C, the valve opens; when the temperature rises to 8 °C, the valve closes.',
            ),
        e.numeric('error', ea.STATE).withDescription('If NTC is damaged, "Er" will be on the TRV display.'),
    ],
    meta: {
        tuyaDatapoints: [
            [2, 'system_mode', tuya.valueConverterBasic.lookup({auto: tuya.enum(0), heat: tuya.enum(1), off: tuya.enum(2)})],
            [3, 'running_state', tuya.valueConverterBasic.lookup({heat: tuya.enum(0), idle: tuya.enum(1)})],
            [4, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
            [5, 'local_temperature', tuya.valueConverter.divideBy10],
            [7, 'child_lock', tuya.valueConverter.lockUnlock],
            [28, 'schedule_monday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
            [29, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
            [30, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
            [31, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
            [32, 'schedule_friday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
            [33, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
            [34, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
            [35, null, tuya.valueConverter.errorOrBatteryLow],
            [36, 'frost_protection', tuya.valueConverter.onOff],
            [39, 'scale_protection', tuya.valueConverter.onOff],
            [47, 'local_temperature_calibration', tuya.valueConverter.localTempCalibration2],
        ],
    },
};

module.exports = definition;

image

State :

{
    "battery_low": false,
    "child_lock": "UNLOCK",
    "current_heating_setpoint": 19,
    "frost_protection": "ON",
    "linkquality": 180,
    "local_temperature": 21,
    "local_temperature_calibration": 3,
    "running_state": "idle",
    "scale_protection": "OFF",
    "schedule_friday": "06:00/21.0 08:00/16.0 12:00/21.0 14:00/16.0",
    "schedule_monday": "06:00/21.0 08:00/16.0 12:00/21.0 14:00/16.0",
    "schedule_saturday": "06:00/21.0 08:00/16.0 12:00/21.0 14:00/16.0",
    "schedule_sunday": "06:00/21.0 08:00/16.0 12:00/21.0 14:00/16.0",
    "schedule_thursday": "06:00/21.0 08:00/16.0 12:00/21.0 14:00/16.0",
    "schedule_tuesday": "06:00/21.0 08:00/16.0 12:00/21.0 14:00/16.0",
    "schedule_wednesday": "06:00/21.0 08:00/16.0 12:00/21.0 14:00/16.0",
    "system_mode": "auto"
}

But documentation says it also could detect windows open/close state. I think it would be nice to add too, so I will work on later this week.

Can somebody help me to understand : tuyaDatapoints and tuya.valueConverters ... ?

kostya-fr avatar Oct 03 '24 08:10 kostya-fr

Hi @kostya-fr , thanks for the configuration you provided, i can confirm that's working well on my instance too. However, i needed to adapt the zigbeeModel & fingerprint for Zigbee2Mqtt to see my device as supported. My définition from auto_generated_definition :

    zigbeeModel: ['TS0601'],
    model: 'TS0601',
    vendor: '_TZE200_ow09xlxm',

Probably the vendor suffix is kinda random. Idk if it's possible to support _TZE200_*

Anyway, thanks :)

martinbonneau avatar Oct 13 '24 08:10 martinbonneau

I just got AVATTO TRV06 radiator valves, they reported as "unsupported" in my z2m (1.40.2) and managed to get them working thanks to @kostya-fr external converter.

Zigbee Model
    TS0601
Zigbee Manufacturer
    _TZE200_hvaxb2tc

The only change I made was the manufacturerName in the fingerprint and whiteLabel keys.

@martinbonneau it looks like the vendor suffix is somewhat random.

wrauner avatar Oct 16 '24 14:10 wrauner

I received an ATTO ME167 that looks like the Thaleos TRV06-AT from above. z2m 1.41.0 is sadly not successfully detecting it and thinks it's a TS0601.

external definition:

const definition = {
    zigbeeModel: ['TS0601'],
    model: 'TS0601',
    vendor: '_TZE200_9xfjixap',
    description: 'Automatically generated definition',
    extend: [],
    meta: {},
};

module.exports = definition;

Optical representation of the actual device: https://www.zigbee2mqtt.io/devices/ME167.html

grafik

rmoriz avatar Nov 27 '24 21:11 rmoriz

            [2, 'system_mode', tuya.valueConverterBasic.lookup({auto: tuya.enum(0), heat: tuya.enum(1), off: tuya.enum(2)})],
            [3, 'running_state', tuya.valueConverterBasic.lookup({heat: tuya.enum(0), idle: tuya.enum(1)})],
            [4, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
            [5, 'local_temperature', tuya.valueConverter.divideBy10],
            [7, 'child_lock', tuya.valueConverter.lockUnlock],
            [28, 'schedule_monday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
            [29, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
            [30, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
            [31, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
            [32, 'schedule_friday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
            [33, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
            [34, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
            [35, null, tuya.valueConverter.errorOrBatteryLow],
            [36, 'frost_protection', tuya.valueConverter.onOff],
            [39, 'scale_protection', tuya.valueConverter.onOff],
            [47, 'local_temperature_calibration', tuya.valueConverter.localTempCalibration2],

It's also working for "TZE204_ogx8u5z6"! Thanks!

skywluke avatar Dec 07 '24 09:12 skywluke

Hello, this was working fine, since the zigbee2mqtt daily update.

Since the restart the devices was "not supportes", any ideas ??

Thx by advance

J3a90r avatar Jan 04 '25 15:01 J3a90r

Hello, I'm experiencing the same issue. Since Z2M was upgraded to v2.0.1, external converters are no longer loaded or active, even though they are located in the data/external-converters folder. Thanks for your help!

davylaroche avatar Jan 04 '25 22:01 davylaroche

Hello, I'm experiencing the same issue. Since Z2M was upgraded to v2.0.1, external converters are no longer loaded or active, even though they are located in the data/external-converters folder. Thanks for your help!

Hello, issue solved by (1) removing external_converters lines in config.yaml and (2) moving *.js file into folder "external_converters" into the zigbee2mqtt folder. As mentioned here https://www.zigbee2mqtt.io/advanced/more/external_converters.html

davylaroche avatar Jan 06 '25 14:01 davylaroche

That is working also for me,

thx a lot

J3a90r avatar Jan 06 '25 15:01 J3a90r

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days

github-actions[bot] avatar Mar 08 '25 01:03 github-actions[bot]