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

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

Open
kostya-fr opened this issue Oct 2, 2024 · 4 comments
Open

Comments

@kostya-fr
Copy link

kostya-fr commented Oct 2, 2024

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 #7998 (comment)

@kostya-fr
Copy link
Author

kostya-fr commented Oct 2, 2024

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
Copy link
Author

kostya-fr commented Oct 3, 2024

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 ... ?

@martinbonneau
Copy link

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 :)

@wrauner
Copy link

wrauner commented Oct 16, 2024

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.

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

3 participants