zigbee2mqtt icon indicating copy to clipboard operation
zigbee2mqtt copied to clipboard

[New device support]: Moes Thermostat - _TZE204_lpedvtvr

Open TesterTurner opened this issue 1 year ago • 43 comments

Link

https://www.aliexpress.com/item/1005008017004760.html?src=google&pdp_npi=4%40dis%21GBP%2170.30%2130.29%21%21%21%21%21%40%2112000043377898982%21ppc%21%21%21&src=google&albch=shopping&acnt=494-037-6276&isdl=y&slnk=&plac=&mtctp=&albbt=Google_7_shopping&aff_platform=google&aff_short_key=UneMJZVf&gclsrc=aw.ds&&albagn=888888&&ds_e_adid=&ds_e_matchtype=&ds_e_device=c&ds_e_network=x&ds_e_product_group_id=&ds_e_product_id=en1005008017004760&ds_e_product_merchant_id=680478118&ds_e_product_country=GB&ds_e_product_language=en&ds_e_product_channel=online&ds_e_product_store_id=&ds_url_v=2&albcp=17859500389&albag=&isSmbAutoCall=false&needSmbHouyi=false&gad_source=1&gclid=CjwKCAiA9bq6BhAKEiwAH6bqoMyzGa27lfVQmlZ0p5iPXlytCHGEa1BQZJNKFUxZJDIftZi1K48KrBoCDSAQAvD_BwE

Database entry

{"id":41,"type":"Router","ieeeAddr":"0xa4c1383ebb899b92","nwkAddr":57155,"manufId":4417,"manufName":"_TZE204_lpedvtvr","powerSource":"Mains (single phase)","modelId":"TS0601","epList":[1,242],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[4,5,61184,0],"outClusterList":[25,10],"clusters":{"genBasic":{"attributes":{"65503":"\u0007\u000b�.i\u0007\u000b�.i","65506":56,"65508":0,"stackVersion":0,"dateCode":"","appVersion":74}}},"binds":[],"configuredReportings":[],"meta":{}},"242":{"profId":41440,"epId":242,"devId":97,"inClusterList":[],"outClusterList":[33],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}}},"appVersion":74,"stackVersion":0,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"meta":{},"lastSeen":1733251203681}

Zigbee2MQTT version

1.42.0-2

Comments

Good Evening, I am struggling to get a working converter for this new thermostat released by Moes. Am unable to locate anything similar to attempt to clone or Frankenstein to get basic functionality. I apologise, I don't seem to have the required skill set to get it running, it has provided no information under the 'Expose' Tab, Could you please assist.

External definition

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

module.exports = definition;

What does/doesn't work with the external definition?

the external definition only provides link quality, No further functionality.

TesterTurner avatar Dec 03 '24 18:12 TesterTurner

I have still not had any luck so far trying to use an alternate configuration to get basic functionality from the thermostat.

TesterTurner avatar Dec 06 '24 17:12 TesterTurner

You are not alone!

Racermouse avatar Dec 06 '24 23:12 Racermouse

My coding skills are very weak, and could not get this to work either. Here's all I could find out from the z2m debug log:

Temp set point: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,205],"type":"Buffer"},"datatype":2,"dp":50}],"seq":4352}' from endpoint 1 with groupID 0

Internal temp sensor reading: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,180],"type":"Buffer"},"datatype":2,"dp":16}],"seq":15616}' from endpoint 1 with groupID 0

External temp sensor reading: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,195],"type":"Buffer"},"datatype":2,"dp":109}],"seq":9984}' from endpoint 1 with groupID 0

Heating on: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":4,"dp":47}],"seq":26112}' from endpoint 1 with groupID

Heating off: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":4,"dp":47}],"seq":29184}' from endpoint 1 with groupID 0

ON/OFF

On: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":1,"dp":1}],"seq":23040}' from endpoint 1 with groupID 0

Off: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":1,"dp":1}],"seq":34048}' from endpoint 1 with groupID 0

WORK MODE

Manual: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":4,"dp":2}],"seq":60672}' from endpoint 1 with groupID 0

Temporary manual: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":4,"dp":2}],"seq":51968}' from endpoint 1 with groupID 0

Programming 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[2],"type":"Buffer"},"datatype":4,"dp":2}],"seq":46336}' from endpoint 1 with groupID 0

Eco: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[3],"type":"Buffer"},"datatype":4,"dp":2}],"seq":42240}' from endpoint 1 with groupID 0

SCREEN BRIGHTNESS

Standby brightness adjustment: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,66],"type":"Buffer"},"datatype":2,"dp":48}],"seq":4608}' from endpoint 1 with groupID 0

CHILD LOCK

Child lock on: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":1,"dp":39}],"seq":13312}' from endpoint 1 with groupID 0

Child lock off: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":1,"dp":39}],"seq":16128}' from endpoint 1 with groupID 0

SENSOR TYPE

In: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":4,"dp":32}],"seq":30208}' from endpoint 1 with groupID 0

AL: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":4,"dp":32}],"seq":35328}' from endpoint 1 with groupID 0

Ou: 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[2],"type":"Buffer"},"datatype":4,"dp":32}],"seq":37376}' from endpoint 1 with groupID 0

What the hell is this: 'Kitchen_Floor_Therm', type 'attributeReport', cluster 'genBasic', data '{"65503":"8\u000f .iF\u000f .iG\u000f .iL\u000f .i[\u000f .if\u000f .ig\u000f .ip\u000f .iv\u000f .iw\u000f .i"}' from endpoint 1 with groupID 0

This Is from startup:

'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,1,194],"type":"Buffer"},"datatype":2,"dp":34}],"seq":256}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,50],"type":"Buffer"},"datatype":2,"dp":18}],"seq":768}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'attributeReport', cluster 'genBasic', data '{"65506":56,"65508":1,"appVersion":74}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":1,"dp":115}],"seq":1024}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":4,"dp":47}],"seq":1280}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,250],"type":"Buffer"},"datatype":2,"dp":50}],"seq":1536}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandMcuVersionResponse', cluster 'manuSpecificTuya', data '{"seq":2048,"version":65}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,185],"type":"Buffer"},"datatype":2,"dp":16}],"seq":1792}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":1,"dp":1}],"seq":2048}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":4,"dp":2}],"seq":2304}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,250],"type":"Buffer"},"datatype":2,"dp":50}],"seq":2560}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":4,"dp":47}],"seq":2816}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[2],"type":"Buffer"},"datatype":4,"dp":32}],"seq":3072}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0],"type":"Buffer"},"datatype":1,"dp":39}],"seq":3328}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,68],"type":"Buffer"},"datatype":2,"dp":48}],"seq":3584}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[255,255,255,250],"type":"Buffer"},"datatype":2,"dp":101}],"seq":3840}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,5],"type":"Buffer"},"datatype":2,"dp":110}],"seq":4096}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,1,194],"type":"Buffer"},"datatype":2,"dp":111}],"seq":4352}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,0],"type":"Buffer"},"datatype":2,"dp":112}],"seq":4608}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,1,44],"type":"Buffer"},"datatype":2,"dp":113}],"seq":4864}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandMcuSyncTime', cluster 'manuSpecificTuya', data '{"payloadSize":20}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,185],"type":"Buffer"},"datatype":2,"dp":16}],"seq":5376}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[0,0,0,185],"type":"Buffer"},"datatype":2,"dp":109}],"seq":5632}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1],"type":"Buffer"},"datatype":4,"dp":114}],"seq":5888}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'read', cluster 'genTime', data '["localTime"]' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[1,6,0,0,200,11,30,0,200,13,30,0,200,17,30,0,200],"type":"Buffer"},"datatype":0,"dp":102}],"seq":6144}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[2,6,0,0,200,11,30,0,200,13,30,0,200,17,30,0,200],"type":"Buffer"},"datatype":0,"dp":103}],"seq":6400}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[3,6,0,0,200,11,30,0,200,13,30,0,200,17,30,0,200],"type":"Buffer"},"datatype":0,"dp":104}],"seq":6656}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[4,6,0,0,200,11,30,0,200,13,30,0,200,17,30,0,200],"type":"Buffer"},"datatype":0,"dp":105}],"seq":6912}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[5,6,0,0,200,11,30,0,200,13,30,0,200,17,30,0,200],"type":"Buffer"},"datatype":0,"dp":106}],"seq":7168}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[6,6,0,0,200,11,30,0,200,13,30,0,200,17,30,0,200],"type":"Buffer"},"datatype":0,"dp":107}],"seq":7424}' from endpoint 1 with groupID 0 'Kitchen_Floor_Therm', type 'commandDataReport', cluster 'manuSpecificTuya', data '{"dpValues":[{"data":{"data":[7,6,0,0,200,11,30,0,200,13,30,0,200,17,30,0,200],"type":"Buffer"},"datatype":0,"dp":108}],"seq":7680}' from endpoint 1 with groupID 0

Racermouse avatar Dec 07 '24 12:12 Racermouse

Hello! Im also very interested in support for this device!

magic1447 avatar Dec 07 '24 15:12 magic1447

I got it working enough to do the stuff I need to do in Node-Red. I'll post the converter file later tonight. Be warned that It is very untidy and contains stuff that does not work.

Racermouse avatar Dec 07 '24 17:12 Racermouse

This converter is a wreck, but it will get basic functionality up and running. Use at own risk. moes_zht_sr.zip

Cheers!

Racermouse avatar Dec 07 '24 20:12 Racermouse

That zip file you have dropped in flags as containing a virus/malware, so I shall play it safe by not opening it, I'm sure its probably just my system playing it safe however to play on the safe side, could you paste your converter directly in?

TesterTurner avatar Dec 08 '24 08:12 TesterTurner

Sure! I have no idea what the "eco temperature" does. It doesn't seem to have any effect on the relay. It's just always on if in "eco" mode Dataponts that are not configured with a proper number ends with "NOT SET". Time is shown correctly for me, but not the day of the week, it's off by two days backwards?!?

const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
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 modernExtend = require('zigbee-herdsman-converters/lib/modernExtend');
const e = exposes.presets;
const ea = exposes.access;
const tuya = require('zigbee-herdsman-converters/lib/tuya');

const definition = {
        fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE204_lpedvtvr'}],
        model: 'ZHT_SR',
        vendor: 'Moes',
        description: 'Thermostat for electric floor',
        fromZigbee: [tuya.fz.datapoints],
        toZigbee: [tuya.tz.datapoints],
        onEvent: tuya.onEventSetTime,
        configure: tuya.configureMagicPacket,
        exposes: [
            e.binary('child_lock', ea.STATE_SET, 'ON', 'OFF').withLabel('Child lock'),
            e.binary('eco_mode', ea.STATE_SET, 'OFF', 'ON').withLabel('ECO mode NOT SET').withDescription('Default: Off'),
            e
                .numeric('eco_temperature', ea.STATE_SET)
                .withValueMin(5)
                .withValueMax(30)
                .withValueStep(1)
                .withUnit('°C')
		.withLabel('Eco temperature')
                .withDescription('Max temperature in ECO mode. Default: 20'),
            e.binary('valve_state', ea.STATE, false, true).withLabel('Heating in process'),
            e
                .climate()
                .withSystemMode(['off', 'heat'], ea.STATE_SET)
                .withPreset(['manual', 'temp_manual', 'programming', 'eco'])
                .withSetpoint('current_heating_setpoint', 5, 35, 0.5, ea.STATE_SET)
                .withLocalTemperature(ea.STATE)
                .withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET)
                .withDescription('Default: -3'),
            e
                .numeric('deadzone_temperature', ea.STATE_SET)
                .withValueMin(1)
                .withValueMax(5)
                .withValueStep(1)
                .withUnit('°C')
		.withLabel('Deadzone temperature NOT SET')
                .withDescription('Hysteresis. Default: 1'),

            e.numeric('min_temperature', ea.STATE_SET)
		.withValueMin(5)
		.withValueMax(15)
		.withValueStep(1)
		.withUnit('°C')
		.withLabel('Minimum temperature NOT SET')
		.withDescription('Default: 5'),
            e
                .numeric('max_temperature', ea.STATE_SET)
                .withValueMin(15)
                .withValueMax(45)
                .withValueStep(1)
                .withUnit('°C')
		.withLabel('Maximum temperature NOT SET')
                .withDescription('Default: 35'),
            e
                .numeric('min_temperature_limit', ea.STATE_SET)
                .withValueMin(0)
                .withValueMax(10)
                .withValueStep(1)
                .withUnit('°C')
                .withLabel('Low temperature protection NOT SET')
                .withDescription('Default: 0'),
            e
                .numeric('max_temperature_limit', ea.STATE_SET)
                .withValueMin(25)
                .withValueMax(70)
                .withValueStep(1)
                .withUnit('°C')
                .withLabel('High temperature protection NOT SET')
                .withDescription('Default: 45'),
            e.temperature_sensor_select(['IN', 'OU', 'AL']).withLabel('Sensor').withDescription('Choose which sensor to use. Default: AL'),
            e
                .numeric('external_temperature_input', ea.STATE)
                .withLabel('Floor temperature')
                .withUnit('°C')
                .withDescription('Temperature from floor sensor'),
            e
                .numeric('brightness', ea.STATE_SET)
                .withValueMin(0)
                .withValueMax(8)
                .withValueStep(1)
                .withLabel('Screen brightness NOT SET')
                .withDescription('0 - on for 10 seconds. Default: 6'),
            e
                .numeric('display_brightness', ea.STATE_SET)
                .withValueMin(0)
                .withValueMax(100)
                .withValueStep(1)
                .withLabel('Stanby screen brightness')
                .withDescription('0-100%'),
            e
                .text('schedule_monday', ea.STATE_SET)
                .withLabel('Schedule for monday TIMETABLES NOT TESTED')
                .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
            e
                .text('schedule_tuesday', ea.STATE_SET)
                .withLabel('Schedule for tuesday')
                .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
            e
                .text('schedule_wednesday', ea.STATE_SET)
                .withLabel('Schedule for wednesday')
                .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
            e
                .text('schedule_thursday', ea.STATE_SET)
                .withLabel('Schedule for thursday')
                .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
            e
                .text('schedule_friday', ea.STATE_SET)
                .withLabel('Schedule for friday')
                .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
            e
                .text('schedule_saturday', ea.STATE_SET)
                .withLabel('Schedule for saturday')
                .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
            e
                .text('schedule_sunday', ea.STATE_SET)
                .withLabel('Schedule for sunday')
                .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
            e.enum('factory_reset', ea.STATE_SET, ['factory reset']).withLabel('Factory reset NOT SET').withDescription('Reset all settings to factory ones'),
        ],
        meta: {
            tuyaDatapoints: [
                [1, 'system_mode', tuya.valueConverterBasic.lookup({off: false, heat: true})],
                [2, 'preset', tuya.valueConverterBasic.lookup({manual: tuya.enum(0), temp_manual: tuya.enum(1), programming: tuya.enum(2), eco: tuya.enum(3)})],
                [50, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
                [19, 'max_temperature', tuya.valueConverter.divideBy10],
                [16, 'local_temperature', tuya.valueConverter.divideBy10],
                [26, 'min_temperature', tuya.valueConverter.divideBy10],
                [27, 'local_temperature_calibration', tuya.valueConverter.raw],
                [28, 'factory_reset', tuya.valueConverterBasic.lookup({factory_reset: true})],
                [47, 'valve_state', tuya.valueConverter.trueFalseInvert],
                [39, 'child_lock', tuya.valueConverterBasic.lookup({ON: true, OFF: false})],
                [40, 'eco_mode', tuya.valueConverterBasic.lookup({ON: true, OFF: false})],
                [32, 'sensor', tuya.valueConverterBasic.lookup({IN: tuya.enum(0), OU: tuya.enum(2), AL: tuya.enum(1)})],
                [109, 'external_temperature_input', tuya.valueConverter.divideBy10],
                [110, 'deadzone_temperature', tuya.valueConverter.raw],
                [104, 'max_temperature_limit', tuya.valueConverter.divideBy10],
                [102, 'schedule_monday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
                [103, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
                [104, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
                [105, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
                [106, 'schedule_friday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
                [107, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
                [108, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
                [114, 'min_temperature_limit', tuya.valueConverter.divideBy10],
                [113, 'eco_temperature', tuya.valueConverter.divideBy10],
                [115, 'brightness', tuya.valueConverter.raw],
                [48, 'display_brightness', tuya.valueConverter.raw],
            ],
        },
};

module.exports = definition;

Racermouse avatar Dec 08 '24 16:12 Racermouse

Hi there!

Here are datapoints that I've got from Tuya hub:

{
  "1": "Switch",
  "2": "Work Mode",
  "16": "Current temperature",
  "18": "The lower limit of temperature",
  "28": "Factory data reset",
  "32": "Sensor selection",
  "34": "Set temperature ceiling",
  "39": "Child lock",
  "47": "State of the valve",
  "48": "Backlight brightness",
  "50": "Set temperature",
  "101": "Temp Calibration",
  "102": "Week Program 13 1",
  "103": "Week Program 13 2",
  "104": "Week Program 13 3",
  "105": "Week Program 13 4",
  "106": "Week Program 13 5",
  "107": "Week Program 13 6",
  "108": "Week Program 13 7",
  "109": "Floor temp.",
  "110": "Dead zone temp.",
  "111": "High protect temp.",
  "112": "Low protection temp.",
  "113": "Eco cool temp.",
  "114": "Screen Time Set",
  "115": "Rgblight"
}

szheliab avatar Dec 08 '24 17:12 szheliab

...And here's mine version of external converter for this thermostat 😃

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

const definition = {
    zigbeeModel: ['TS0601'],
    model: 'ZHT-SR-GB',
    vendor: 'Moes',
    description: 'Smart knob thermostat',
    fromZigbee: [tuya.fz.datapoints],
    toZigbee: [tuya.tz.datapoints],
    exposes: [
        e.binary('child_lock', ea.STATE_SET, 'ON', 'OFF').withLabel('Child lock'),
        e.binary('rgb_backlight', ea.STATE_SET, 'OFF', 'ON').withLabel('RGB backlight').withDescription('Default: Off'),
        e.numeric('eco_temperature', ea.STATE_SET)
            .withValueMin(5)
            .withValueMax(30)
            .withValueStep(1)
            .withUnit('°C')
            .withDescription('Max temperature in ECO mode. Default: 20'),
        e.binary('valve_state', ea.STATE, false, true).withLabel('Heating in process'),
        e.climate()
            .withSystemMode(['off', 'heat'], ea.STATE_SET)
            .withPreset(['manual', 'temporary manual', 'schedule', 'eco'])
            .withSetpoint('current_heating_setpoint', 5, 35, 0.5, ea.STATE_SET)
            .withLocalTemperature(ea.STATE)
            .withLocalTemperatureCalibration(-9, 9, 0.1, ea.STATE_SET)
            .withDescription('Default: -3'),
        e.numeric('deadzone_temperature', ea.STATE_SET)
            .withValueMin(1)
            .withValueMax(5)
            .withValueStep(1)
            .withUnit('°C')
            .withDescription('Hysteresis. Default: 1'),
        e.numeric('min_temperature', ea.STATE_SET)
            .withValueMin(5)
            .withValueMax(15)
            .withValueStep(1)
            .withUnit('°C')
            .withDescription('Default: 5'),
        e.numeric('max_temperature', ea.STATE_SET)
            .withValueMin(15)
            .withValueMax(45)
            .withValueStep(1)
            .withUnit('°C')
            .withDescription('Default: 35'),
        e.numeric('min_temperature_limit', ea.STATE_SET)
            .withValueMin(0)
            .withValueMax(10)
            .withValueStep(1)
            .withUnit('°C')
            .withLabel('Low temperature protection')
            .withDescription('Default: 0'),
        e.numeric('lower_limit_of_temperature', ea.STATE_SET)
            .withValueMin(5)
            .withValueMax(15)
            .withValueStep(1)
            .withUnit('°C')
            .withLabel('The lower limit of temperature')
            .withDescription('Default: 5'),
        e.enum('sensor', ea.STATE_SET, ['IN', 'OU', 'AL']).withLabel('Sensor')
            .withDescription('Choose which sensor to use. Default: AL'),
        e.numeric('external_temperature_input', ea.STATE)
            .withLabel('Floor temperature')
            .withUnit('°C')
            .withDescription('Temperature from floor sensor'),
        e.numeric('brightness', ea.STATE_SET)
            .withValueMin(0)
            .withValueMax(100)
            .withValueStep(1)
            .withLabel('Backlight brightness')
            .withDescription('Backlight brightness in %'),
        e.text('schedule_monday', ea.STATE_SET)
            .withLabel('Schedule for monday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_tuesday', ea.STATE_SET)
            .withLabel('Schedule for tuesday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_wednesday', ea.STATE_SET)
            .withLabel('Schedule for wednesday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_thursday', ea.STATE_SET)
            .withLabel('Schedule for thursday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_friday', ea.STATE_SET)
            .withLabel('Schedule for friday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_saturday', ea.STATE_SET)
            .withLabel('Schedule for saturday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_sunday', ea.STATE_SET)
            .withLabel('Schedule for sunday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.enum('factory_reset', ea.STATE_SET, ['factory_reset'])
            .withLabel('Factory reset')
            .withDescription('Reset all settings to factory ones'),
            
        e.enum('screen_time_set', ea.STATE_SET, ['off', '10s', '30s', '60s'])
            .withLabel('Screen Timeout')
            .withDescription('Set screen timeout duration. Default: off'),
    ],
    meta: {
        tuyaDatapoints: [
            [1, 'system_mode', tuya.valueConverterBasic.lookup({off: false, heat: true})],
            [2, 'preset', tuya.valueConverterBasic.lookup({manual: tuya.enum(0), 'temporary manual': tuya.enum(1), schedule: tuya.enum(2), eco: tuya.enum(3)})],
            [16, 'local_temperature', tuya.valueConverter.divideBy10],
            [18, 'lower_limit_of_temperature', tuya.valueConverter.divideBy10],
            [28, 'factory_reset', tuya.valueConverterBasic.lookup({factory_reset: true})],
            [32, 'sensor', tuya.valueConverterBasic.lookup({IN: tuya.enum(0), OU: tuya.enum(2), AL: tuya.enum(1)})],
            [34, 'max_temperature', tuya.valueConverter.divideBy10],
            [39, 'child_lock', tuya.valueConverterBasic.lookup({ON: true, OFF: false})],
            [47, 'valve_state', tuya.valueConverter.trueFalseInvert],
            [48, 'brightness', tuya.valueConverter.raw],
            [50, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
            [101, 'local_temperature_calibration', tuya.valueConverter.divideBy10],
            [102, 'schedule_monday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
            [103, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
            [104, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
            [105, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
            [106, 'schedule_friday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
            [107, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
            [108, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
            [109, 'external_temperature_input', tuya.valueConverter.divideBy10],
            [110, 'deadzone_temperature', tuya.valueConverter.raw],
            [111, 'max_temperature_limit', tuya.valueConverter.divideBy10],
            [112, 'min_temperature_limit', tuya.valueConverter.divideBy10],
            [113, 'eco_temperature', tuya.valueConverter.divideBy10],
            [114, 'screen_time_set', tuya.valueConverterBasic.lookup({
                off: tuya.enum(0), 
                '10s': tuya.enum(1), 
                '30s': tuya.enum(2), 
                '60s': tuya.enum(3)
            })],
            [115, 'rgb_backlight', tuya.valueConverterBasic.lookup({ON: true, OFF: false})],
        ],
    },
    onEvent: tuya.onEventSetLocalTime,
};

module.exports = definition;

szheliab avatar Dec 08 '24 20:12 szheliab

Nice. I have no Tuya bridge, so thanks for the help! ...and I think most of the temp tings are .withValueStep(0.5)

Racermouse avatar Dec 08 '24 20:12 Racermouse

Screen timeouts are 10, 20, 30, 40 s.

Racermouse avatar Dec 08 '24 21:12 Racermouse

Can't seem to get the "deadzone_temperature" and "local_temperature_calibration" to work properly. Might have something to do with factors?

Racermouse avatar Dec 08 '24 22:12 Racermouse

Not sure, but seems that calibration works now :)

Here is updated converter (fixed default values, min/max values, etc.), can you please try it?

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

const definition = {
    zigbeeModel: ['TS0601'],
    model: 'ZHT-SR-GB',
    vendor: 'Moes',
    description: 'Smart knob thermostat',
    fromZigbee: [tuya.fz.datapoints],
    toZigbee: [tuya.tz.datapoints],
    exposes: [
        e.binary('child_lock', ea.STATE_SET, 'ON', 'OFF').withLabel('Child lock'),
        e.binary('rgb_backlight', ea.STATE_SET, 'ON', 'OFF').withLabel('RGB backlight').withDescription('Default: On'),
        e.numeric('eco_temperature', ea.STATE_SET)
            .withValueMin(10)
            .withValueMax(30)
            .withValueStep(1)
            .withUnit('°C')
            .withDescription('Max temperature in ECO mode. Default: 30'),
        e.binary('valve_state', ea.STATE, false, true).withLabel('Heating in process'),
        e.climate()
            .withSystemMode(['off', 'heat'], ea.STATE_SET)
            .withPreset(['manual', 'temporary manual', 'schedule', 'eco'])
            .withSetpoint('current_heating_setpoint', 5, 45, 0.5, ea.STATE_SET)
            .withLocalTemperature(ea.STATE)
            .withLocalTemperatureCalibration(-10, 10, 1, ea.STATE_SET)
            .withDescription('Default: 22'),
        e.numeric('deadzone_temperature', ea.STATE_SET)
            .withValueMin(0.5)
            .withValueMax(5)
            .withValueStep(0.5)
            .withLabel('Dead zone temperature')
            .withUnit('°C')
            .withDescription('Default: 0.5'),
        e.numeric('max_temperature', ea.STATE_SET)
            .withValueMin(35)
            .withValueMax(45)
            .withValueStep(1)
            .withLabel('Set temperature ceiling')
            .withUnit('°C')
            .withDescription('Default: 45'),
        e.numeric('min_temperature_limit', ea.STATE_SET)
            .withValueMin(0)
            .withValueMax(10)
            .withValueStep(1)
            .withUnit('°C')
            .withLabel('Low temperature protection')
            .withDescription('Default: 0'),
        e.numeric('max_temperature_limit', ea.STATE_SET)
            .withValueMin(10)
            .withValueMax(70)
            .withValueStep(1)
            .withLabel('High temperature protection')
            .withUnit('°C')
            .withDescription('Default: 45'),
        e.numeric('lower_limit_of_temperature', ea.STATE_SET)
            .withValueMin(5)
            .withValueMax(15)
            .withValueStep(1)
            .withUnit('°C')
            .withLabel('The lower limit of temperature')
            .withDescription('Default: 5'),
        e.enum('sensor', ea.STATE_SET, ['IN', 'OU', 'AL']).withLabel('Sensor')
            .withDescription('Choose which sensor to use. Default: AL'),
        e.numeric('external_temperature_input', ea.STATE)
            .withLabel('Floor temperature')
            .withUnit('°C')
            .withDescription('Temperature from floor sensor'),
        e.numeric('brightness', ea.STATE_SET)
            .withValueMin(0)
            .withValueMax(100)
            .withValueStep(1)
            .withLabel('Backlight brightness')
            .withUnit('%')
            .withDescription('Backlight brightness in %. Default: 5%'),
        e.text('schedule_monday', ea.STATE_SET)
            .withLabel('Schedule for monday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_tuesday', ea.STATE_SET)
            .withLabel('Schedule for tuesday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_wednesday', ea.STATE_SET)
            .withLabel('Schedule for wednesday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_thursday', ea.STATE_SET)
            .withLabel('Schedule for thursday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_friday', ea.STATE_SET)
            .withLabel('Schedule for friday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_saturday', ea.STATE_SET)
            .withLabel('Schedule for saturday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.text('schedule_sunday', ea.STATE_SET)
            .withLabel('Schedule for sunday')
            .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
        e.enum('factory_reset', ea.STATE_SET, ['factory_reset'])
            .withLabel('Factory reset')
            .withDescription('Reset all settings to factory ones'),
        e.enum('screen_time_set', ea.STATE_SET, ['10s', '20s', '30s', '40s', '50s', '60s'])
            .withLabel('Screen Timeout')
            .withDescription('Set screen timeout duration. Default: 20s'),
    ],
    meta: {
        tuyaDatapoints: [
            [1, 'system_mode', tuya.valueConverterBasic.lookup({off: false, heat: true})],
            [2, 'preset', tuya.valueConverterBasic.lookup({manual: tuya.enum(0), 'temporary manual': tuya.enum(1), schedule: tuya.enum(2), eco: tuya.enum(3)})],
            [16, 'local_temperature', tuya.valueConverter.divideBy10],
            [18, 'lower_limit_of_temperature', tuya.valueConverter.divideBy10],
            [28, 'factory_reset', tuya.valueConverterBasic.lookup({factory_reset: true})],
            [32, 'sensor', tuya.valueConverterBasic.lookup({IN: tuya.enum(0), OU: tuya.enum(2), AL: tuya.enum(1)})],
            [34, 'max_temperature', tuya.valueConverter.divideBy10],
            [39, 'child_lock', tuya.valueConverterBasic.lookup({ON: true, OFF: false})],
            [47, 'valve_state', tuya.valueConverter.trueFalseInvert],
            [48, 'brightness', tuya.valueConverter.raw],
            [50, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
            [101, 'local_temperature_calibration', tuya.valueConverter.localTemperatureCalibration],
            [102, 'schedule_monday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
            [103, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
            [104, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
            [105, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
            [106, 'schedule_friday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
            [107, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
            [108, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
            [109, 'external_temperature_input', tuya.valueConverter.divideBy10],
            [110, 'deadzone_temperature', tuya.valueConverter.raw],
            [111, 'max_temperature_limit', tuya.valueConverter.divideBy10],
            [112, 'min_temperature_limit', tuya.valueConverter.divideBy10],
            [113, 'eco_temperature', tuya.valueConverter.divideBy10],
            [114, 'screen_time_set', tuya.valueConverterBasic.lookup({
                '10s': tuya.enum(0),
                '20s': tuya.enum(1),
                '30s': tuya.enum(2),
                '40s': tuya.enum(3),
                '50s': tuya.enum(4),
                '60s': tuya.enum(5)
            })],
            [115, 'rgb_backlight', tuya.valueConverterBasic.lookup({ON: true, OFF: false})],
        ],
    },
    onEvent: tuya.onEventSetLocalTime,
};

module.exports = definition;

szheliab avatar Dec 09 '24 09:12 szheliab

I tried the code and it worked for me anyway.

Some things I changed to my way of using a floor thermostat. Limits have been change. Don't know what the real device limits are, but the ones in the code below works. Dead zone (hysteresis) needs to be multiplied by 10 to work. I have no idea how to do it. Can't find a tuya.valueConverter to do this.

...and I don't know why the code does not show up here properly. Sorry.

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

const definition = { zigbeeModel: ['TS0601'], model: 'ZHT-SR-GB', vendor: 'Moes', description: 'Smart knob thermostat', fromZigbee: [tuya.fz.datapoints], toZigbee: [tuya.tz.datapoints], exposes: [ e.binary('child_lock', ea.STATE_SET, 'ON', 'OFF').withLabel('Child lock'),

    e.binary('rgb_backlight', ea.STATE_SET, 'ON', 'OFF').withLabel('Knob light').withDescription('Default: On'),

    e.numeric('eco_temperature', ea.STATE_SET)
        .withValueMin(10)
        .withValueMax(30)
        .withValueStep(0.5)
        .withUnit('°C')
        .withDescription('Max temperature in ECO mode. Default: 30'),

    e.binary('valve_state', ea.STATE, false, true).withLabel('Heating in progress'),

    e.climate()
        .withSystemMode(['off', 'heat'], ea.STATE_SET)
        .withPreset(['manual', 'temporary manual', 'schedule', 'eco'])
        .withSetpoint('current_heating_setpoint', 5, 45, 0.5, ea.STATE_SET)
        .withLocalTemperature(ea.STATE)
        .withLocalTemperatureCalibration(-10, 10, 1, ea.STATE_SET)
        .withDescription('Default: 22'),

    e.numeric('deadzone_temperature', ea.STATE_SET)
        .withValueMin(5)
        .withValueMax(50)
        .withValueStep(5)
        .withLabel('Dead zone temperature')
        .withUnit('°C')
        .withDescription('Default: 0.5'),

    e.numeric('max_temperature', ea.STATE_SET)
        .withValueMin(20)
        .withValueMax(45)
        .withValueStep(0.5)
        .withLabel('Maximum temperature setpont on device')
        .withUnit('°C')
        .withDescription('Default: 45'),

    e.numeric('lower_limit_of_temperature', ea.STATE_SET)
        .withValueMin(5)
        .withValueMax(20)
        .withValueStep(0.5)
        .withUnit('°C')
        .withLabel('Minimum temperature setpont on device')
        .withDescription('Default: 5'),

    e.numeric('external_temperature_input', ea.STATE)
        .withLabel('Floor temperature')
        .withUnit('°C')
        .withDescription('Current temperature measured from floor sensor'),

    e.numeric('max_temperature_limit', ea.STATE_SET)
        .withValueMin(25)
        .withValueMax(45)
        .withValueStep(0.5)
        .withLabel('Maximum floor temperature')
        .withUnit('°C')
        .withDescription('Default: 45'),

    e.numeric('min_temperature_limit', ea.STATE_SET)
        .withValueMin(0)
        .withValueMax(25)
        .withValueStep(0.5)
        .withUnit('°C')
        .withLabel('Minimum floor temperature')
        .withDescription('Default: 0'),

    e.enum('sensor', ea.STATE_SET, ['IN', 'OU', 'AL']).withLabel('Sensor')
        .withDescription('Choose which sensor to use. Default: AL'),

    e.numeric('brightness', ea.STATE_SET)
        .withValueMin(0)
        .withValueMax(100)
        .withValueStep(1)
        .withLabel('Display stanby brightness')
        .withUnit('%')
        .withDescription('Display brightness in %. Default: 5%'),

    e.text('schedule_monday', ea.STATE_SET)
        .withLabel('Schedule for monday')
        .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
    e.text('schedule_tuesday', ea.STATE_SET)
        .withLabel('Schedule for tuesday')
        .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
    e.text('schedule_wednesday', ea.STATE_SET)
        .withLabel('Schedule for wednesday')
        .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
    e.text('schedule_thursday', ea.STATE_SET)
        .withLabel('Schedule for thursday')
        .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
    e.text('schedule_friday', ea.STATE_SET)
        .withLabel('Schedule for friday')
        .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
    e.text('schedule_saturday', ea.STATE_SET)
        .withLabel('Schedule for saturday')
        .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),
    e.text('schedule_sunday', ea.STATE_SET)
        .withLabel('Schedule for sunday')
        .withDescription('Default: 06:00/20.0 11:30/20.0 13:30/20.0 17:30/20.0'),

    e.enum('factory_reset', ea.STATE_SET, ['factory_reset'])
        .withLabel('Factory reset')
        .withDescription('Reset all settings to factory ones'),

    e.enum('screen_time_set', ea.STATE_SET, ['10s', '20s', '30s', '40s', '50s', '60s'])
        .withLabel('Screen Timeout')
        .withDescription('Set screen timeout duration. Default: 20s'),
],
meta: {
    tuyaDatapoints: [
        [1, 'system_mode', tuya.valueConverterBasic.lookup({off: false, heat: true})],
        [2, 'preset', tuya.valueConverterBasic.lookup({manual: tuya.enum(0), 'temporary manual': tuya.enum(1), schedule: tuya.enum(2), eco: tuya.enum(3)})],
        [16, 'local_temperature', tuya.valueConverter.divideBy10],
        [18, 'lower_limit_of_temperature', tuya.valueConverter.divideBy10],
        [28, 'factory_reset', tuya.valueConverterBasic.lookup({factory_reset: true})],
        [32, 'sensor', tuya.valueConverterBasic.lookup({IN: tuya.enum(0), OU: tuya.enum(2), AL: tuya.enum(1)})],
        [34, 'max_temperature', tuya.valueConverter.divideBy10],
        [39, 'child_lock', tuya.valueConverterBasic.lookup({ON: true, OFF: false})],
        [47, 'valve_state', tuya.valueConverter.trueFalseInvert],
        [48, 'brightness', tuya.valueConverter.raw],
        [50, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
        [101, 'local_temperature_calibration', tuya.valueConverter.localTemperatureCalibration],
        [102, 'schedule_monday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
        [103, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
        [104, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
        [105, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
        [106, 'schedule_friday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
        [107, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
        [108, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],
        [109, 'external_temperature_input', tuya.valueConverter.divideBy10],
        [110, 'deadzone_temperature', tuya.valueConverter.raw],
        [111, 'max_temperature_limit', tuya.valueConverter.divideBy10],
        [112, 'min_temperature_limit', tuya.valueConverter.divideBy10],
        [113, 'eco_temperature', tuya.valueConverter.divideBy10],
        [114, 'screen_time_set', tuya.valueConverterBasic.lookup({
            '10s': tuya.enum(0),
            '20s': tuya.enum(1),
            '30s': tuya.enum(2),
            '40s': tuya.enum(3),
            '50s': tuya.enum(4),
            '60s': tuya.enum(5)
        })],
        [115, 'rgb_backlight', tuya.valueConverterBasic.lookup({ON: true, OFF: false})],
    ],
},
onEvent: tuya.onEventSetLocalTime,

};

module.exports = definition;

Racermouse avatar Dec 10 '24 17:12 Racermouse

Why is it doing this? Is there a way to set it to Celsius?

So a little more information, set the device up and it works well the problem is when I try to change the temperature on a thermostat card in home assistant it does this or goes extreme negative. The problem seems to come from home assistant converting to °F. If I change the temperature on Z2M it works fine because it’s in °C. Any and all help would be appreciated!

image

cwtufts avatar Jan 15 '25 20:01 cwtufts

@szheliab So seems like the code work right? Can this be added to Zigbee2MQTT so we don't have to use it as "External" converter?

Regards

ETE-Design avatar Jan 17 '25 20:01 ETE-Design

why don't you try it?

adamkorski avatar Jan 18 '25 08:01 adamkorski

@ETE-Design

@szheliab So seems like the code work right? Can this be added to Zigbee2MQTT so we don't have to use it as "External" converter?

Regards

Hi Unfortunately, I don't have this device installed :(

If you can confirm that my converter works correctly then I can prepare PR to add this device to supported list

szheliab avatar Jan 20 '25 12:01 szheliab

Image Image Image

everything works

adamkorski avatar Jan 20 '25 12:01 adamkorski

Image Image Image

everything works

Everything works as long as the global system is set to °C but if you use global settings as °F the temp will not change and will be a very erratic number. Anyway to fix this?

cwtufts avatar Jan 20 '25 16:01 cwtufts

@ETE-Design

@szheliab So seems like the code work right? Can this be added to Zigbee2MQTT so we don't have to use it as "External" converter? Regards

Hi Unfortunately, I don't have this device installed :(

If you can confirm that my converter works correctly then I can prepare PR to add this device to supported list

Same problem - Have ordered it but not received it yet... So can't test it for now :-(

ETE-Design avatar Jan 20 '25 17:01 ETE-Design

deadzone temperature seems not to work

raudraido avatar Feb 02 '25 12:02 raudraido

Where do I paste this code to make it work? How long does it normally take for zigbee2mqtt to add these as standard? I'm wondering if it's worth me just waiting for the update that carries the support for the thermostat? Thanks.

Johnwhutchinson avatar Feb 07 '25 08:02 Johnwhutchinson

Think @Koenkk is the one who can answer you on that :-D

ETE-Design avatar Feb 09 '25 00:02 ETE-Design

device is not supported on version 2.1.1-1

Image

vpaulos avatar Feb 11 '25 13:02 vpaulos

Where do I paste this code to make it work?

@Johnwhutchinson Assuming you're running z2m with Home Assistant, just paste the code into a new file (e.g. floorheating.js) and drop it in /homeassistant/zigbee2mqtt/. You may need to pair the device again.

sarangnemo avatar Feb 11 '25 13:02 sarangnemo

If you can confirm that my converter works correctly then I can prepare PR to add this device to supported list

@szheliab I can also confirm that all the obvious features are working correctly. I've only tried with the default units in Celsius though, so I can't rule out this potential issue with Fahrenheit: https://github.com/Koenkk/zigbee2mqtt/issues/25038#issuecomment-2602324026

sarangnemo avatar Feb 11 '25 13:02 sarangnemo

Hi, ZigBee rookie here! I have home assistant with ZHA integration. Is this converter usable in zone way with ZHA?

Thanks and sorry if the question is silly!

nicmela avatar Feb 23 '25 20:02 nicmela

Hi, ZigBee rookie here! I have home assistant with ZHA integration. Is this converter usable in zone way with ZHA?

Thanks and sorry if the question is silly!

Sorry @nicmela, zigbee2mqtt code can't plug in to ZHA. Though someone with experience writing ZHA device 'quirks', or a lot of time to learn the ... quirks ... of writing quirks could likely make something for ZHA based on the information contained within this code.

sarangnemo avatar Feb 24 '25 09:02 sarangnemo