Koenkk / zigbee2mqtt

Zigbee 🐝 to MQTT bridge 🌉, get rid of your proprietary Zigbee bridges 🔨
https://www.zigbee2mqtt.io
GNU General Public License v3.0
12.22k stars 1.69k forks source link

[New device support]: ZigBee Smart Thermostat Avatto - brother of EARU TRV06 #24376

Open barc343 opened 1 month ago

barc343 commented 1 month ago

Link

https://pl.aliexpress.com/item/1005006306054040.html?spm=a2g0o.order_list.order_list_main.47.195e1c24WRU4my&gatewayAdapt=glo2pol

Database entry

{"id":15,"type":"EndDevice","ieeeAddr":"0xa4c138e82a55865a","nwkAddr":24047,"manufId":4417,"manufName":"_TZE200_hvaxb2tc","powerSource":"Battery","modelId":"TS0601","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[4,5,61184,0],"outClusterList":[25,10],"clusters":{"genBasic":{"attributes":{"65534":0,"modelId":"TS0601","manufacturerName":"_TZE200_hvaxb2tc","powerSource":3,"zclVersion":3,"appVersion":67,"stackVersion":0,"hwVersion":1,"dateCode":""}}},"binds":[],"configuredReportings":[],"meta":{}}},"appVersion":67,"stackVersion":0,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"meta":{"configured":217189513},"lastSeen":1729165072293}

Zigbee2MQTT version

1.40.2

Comments

This is a copy of https://www.zigbee2mqtt.io/devices/TRV06.html, but distributed by other vendor with name Avatto

External definition

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

const fixedValueConverter = {
    thermostatScheduleDayMultiDP: {
        from: (v) => {
            const schedule = [];
            for (let index = 1; index < 24; index = index + 4) {
                schedule.push(
                    String(parseInt(v[index+0])).padStart(2, '0') + ':' +
                    String(parseInt(v[index+1])).padStart(2, '0') + '/' +
                    // @ts-ignore
                    (parseFloat((v[index+2] << 8) + v[index+3]) / 10.0).toFixed(1),
                );
            }
            return schedule.join(' ');
        },
        to: (v) => {
            const payload = [0];
            const transitions = v.split(' ');
            if (transitions.length != 6) {
                throw new Error('Invalid schedule: there should be 6 transitions');
            }
            for (const transition of transitions) {
                const timeTemp = transition.split('/');
                if (timeTemp.length != 2) {
                    throw new Error('Invalid schedule: wrong transition format: ' + transition);
                }
                const hourMin = timeTemp[0].split(':');
                const hour = parseInt(hourMin[0]);
                const min = parseInt(hourMin[1]);
                const temperature = Math.floor(parseFloat(timeTemp[1]) * 10);
                if (hour < 0 || hour > 24 || min < 0 || min > 60 || temperature < 50 || temperature > 300) {
                    throw new Error('Invalid hour, minute or temperature of: ' + transition);
                }
                payload.push(
                    hour,
                    min,
                    (temperature & 0xff00) >> 8,
                    temperature & 0xff,
                );
            }
            return payload;
        },
    },
    thermostatScheduleDayMultiDPWithDayNumber: (dayNum) => {
        return {
            from: (v) => fixedValueConverter.thermostatScheduleDayMultiDP.from(v),
            to: (v) => {
                const data = fixedValueConverter.thermostatScheduleDayMultiDP.to(v);
                data[0] = dayNum;
                return data;
            },
        };
    }
};

const definition = {
    fingerprint: [
        {
            modelID: 'TS0601',
            manufacturerName: '_TZE200_hvaxb2tc',
        },
    ],
    model: 'TRV06',
    vendor: 'Avatto',
        description: 'Thermostatic radiator valve',
        fromZigbee: [tuya.fz.datapoints],
        toZigbee: [tuya.tz.datapoints],
        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_wednesday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
                [29, 'schedule_thursday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
                [30, 'schedule_friday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
                [31, 'schedule_saturday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
                [32, 'schedule_sunday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
                [33, 'schedule_monday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
                [34, 'schedule_tuesday', fixedValueConverter.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;

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

All works fine

dszymczuk commented 1 month ago

@barc343 Big thank you for support this device!

~~I've tried to change the schedule, but the schedule doesn't work. I've changed values from 06:00/21.0 08:00/16.0 12:00/21.0 14:00/16.0 to 06:00/21.0 08:00/16.0 12:00/21.0 22:42/18.0.s Initial Current heating setpoint is 23*C. But at 22:42 TRV doesn't change value.~~

☝️ I didn't change TRV to Programmable mode

And one importing thing. Example.

Current time is 11:42. So You have schedule like this06:00/21.0 11:35/26.0 16:00/18.0 23:05/22.0 So, current temperature is 26*C (2nd value matching).

If you change schedule to 06:00/21.0 12:35/26.0 16:00/18.0 23:05/22.0 (2nd value changed), the TRV set up temperature to previous value from schedule (21*C).

Also, another question.

In description, you have Schedule for saturday, format: "HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C HH:MM/C". When I tried to add 5th or 6th value, I've got: z2m: Publish 'set' 'schedule_wednesday' to '0xa4c138b78b8bdcaa' failed: 'Error: Invalid schedule: there should be 4 transitions' where 0xa4c138b78b8bdcaa is my device name.

dszymczuk commented 1 month ago

Next issue or missing setup.

I also found issue in automatization.

My name of device is Termostat.Salon

When I set Termostat.Salon Temperatura it takes entity number.termostat_salon_local_temperature_calibration instead of number.termostat_salon_current_heating_setpoint.

When I've changes entity Temperatura to take termostat_salon_current_heating_setpoint instead of termostat_salon_local_temperature_calibration I've got validation error Error: Value 26.0 for number.termostat_salon_current_heating_setpoint is outside valid range -9.0 - 9.0

So temporary changed to .withLocalTemperatureCalibration(5, 35, 1, ea.STATE_SET),

And... It changes calibration :D Currently, I have 47*C :D

So I can't change from automation perspective current_heating_setpoint.

Zigbee2MQQT version: 1.40.2
Core: 2024.10.2
Supervisor: 2024.10.2
Operating System: 13.2
Barley194 commented 1 month ago

Will this device be available in the next release?

vrflyer commented 1 month ago

regarding the auto or programmed mode issue with temperature jumping to 156 degrees celsius when switching from heating to auto mode I modified my external converter script according to a calculation fix which I found here: https://github.com/sychu/avatto_me167_TZE200_p3dbf6qs/blob/main/avatto_me167.js I adopted the modification to my script so that the calculation for the schedule entries (datapoint 28 to 34) use the fixed routine in 'fixedValueConverter'. This really did the trick for me :-)

vrflyer commented 1 month ago

... and you have to provide 6 entries per day schedule !

dszymczuk commented 1 month ago

@Barley194

Will this device be available in the next release?

If you want to test it, you can extend your configuration using this manual https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html#_2-1-extending-the-external-definition

dszymczuk commented 1 month ago

@vrflyer do you have any idea why automation takes termostat_salon_local_temperature_calibration instead of termostat_salon_current_heating_setpoint ?

vrflyer commented 1 month ago

No idea... I didn't see this problem yet. Maybe it is also related to the calculation issue. Did you apply the fix and test again?

⁣Gesendet mit Blue ​

Am 19. Okt. 2024, 22:16, um 22:16, Damian Szymczuk @.***> schrieb:

@vrflyer do you have any idea why automation takes termostat_salon_local_temperature_calibration instead of termostat_salon_current_heating_setpoint ?

-- Reply to this email directly or view it on GitHub: https://github.com/Koenkk/zigbee2mqtt/issues/24376#issuecomment-2424190596 You are receiving this because you were mentioned.

Message ID: @.***>

dszymczuk commented 1 month ago

No idea... I didn't see this problem yet. Maybe it is also related to the calculation issue. Did you apply the fix and test again? ⁣Gesendet mit Blue ​Am 19. Okt. 2024, 22:16, um 22:16, Damian Szymczuk @.> schrieb: @vrflyer do you have any idea why automation takes termostat_salon_local_temperature_calibration instead of termostat_salon_current_heating_setpoint ? -- Reply to this email directly or view it on GitHub: #24376 (comment) You are receiving this because you were mentioned. Message ID: @.>

It's not related with calculation fixes. It looks like the wrong entity.

dszymczuk commented 4 weeks ago

I found another bug. I've set up a scheduler for Tuesday, but the scheduler was applied on Sunday. So days from the scheduler do not match with real days.

amadeo-alex commented 4 weeks ago

Looks like those devices come in all sorts of flavours - https://github.com/Koenkk/zigbee2mqtt/issues/20732 I also received the "_TZE200_hvaxb2tc" model ("by avatto") and stumbled upon this threads and others. This implementation appears to be functioning and contain ?more logic? that could potentially fix issues reported by @dszymczuk - https://github.com/sychu/avatto_me167_TZE200_p3dbf6qs The only adjustment that needs to be done is replacing "_TZE200_p3dbf6qs" with "_TZE200_hvaxb2tc" although I'm yet to test everything.

dszymczuk commented 4 weeks ago

@amadeo-alex thank you for the different definition of device. I've updated only the part related to the schedule.

amadeo-alex commented 3 weeks ago

Looks like the "_TZE200_hvaxb2tc" has been included in one of the merged PRs - https://github.com/Koenkk/zigbee-herdsman-converters/pull/8151

I'll update the Zigbee2MQTT as two days ago there was a new release with that PR included (zigbee-herdsman-converters update that includes that PR) and report back :)

amadeo-alex commented 3 weeks ago

Looks like the "_TZE200_hvaxb2tc" has been included in one of the merged PRs - Koenkk/zigbee-herdsman-converters#8151

I'll update the Zigbee2MQTT as two days ago there was a new release with that PR included (zigbee-herdsman-converters update that includes that PR) and report back :)

Works, I removed the external converter and updated the container. vEDjQA

tykovec commented 2 weeks ago

Issue with temperature 156 is still present i just use fix from https://github.com/sychu/avatto_me167_TZE200_p3dbf6qs (thanks for it), if weekdays are correct in schedule i cannot confirm.

dszymczuk commented 2 weeks ago

I can see that in this script we have 6 scheduleAllDays. In official, they are 4 days.

How many days are they supported?

copernic-us commented 1 week ago

Issue with temperature 156 is still present i just use fix from https://github.com/sychu/avatto_me167_TZE200_p3dbf6qs (thanks for it), if weekdays are correct in schedule i cannot confirm.

Have You had any problems with this fix? Does weekdays work as they should?

tykovec commented 1 week ago

Honestly I didn't checked it, I have every day same settings. It should be easy to check one day after and compare with json. I think that temperature sensor is also not working well. It is measuring lower temperature that realy is.

dszymczuk commented 1 week ago

I think that this part:

[28, 'schedule_wednesday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
[29, 'schedule_thursday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
[30, 'schedule_friday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
[31, 'schedule_saturday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
[32, 'schedule_sunday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
[33, 'schedule_monday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
[34, 'schedule_tuesday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(7)],  

Works correctly.

dszymczuk commented 1 week ago

The six-schedule option is much better than 4 for me.

copernic-us commented 1 week ago

Maybe but i've switched it to 4 days and managed to fix schedule days. Need to test it.

barc343 commented 1 week ago

Link

https://pl.aliexpress.com/item/1005006306054040.html?spm=a2g0o.order_list.order_list_main.47.195e1c24WRU4my&gatewayAdapt=glo2pol

Database entry

{"id":15,"type":"EndDevice","ieeeAddr":"0xa4c138e82a55865a","nwkAddr":24047,"manufId":4417,"manufName":"_TZE200_hvaxb2tc","powerSource":"Battery","modelId":"TS0601","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":81,"inClusterList":[4,5,61184,0],"outClusterList":[25,10],"clusters":{"genBasic":{"attributes":{"65534":0,"modelId":"TS0601","manufacturerName":"_TZE200_hvaxb2tc","powerSource":3,"zclVersion":3,"appVersion":67,"stackVersion":0,"hwVersion":1,"dateCode":""}}},"binds":[],"configuredReportings":[],"meta":{}}},"appVersion":67,"stackVersion":0,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"meta":{"configured":217189513},"lastSeen":1729165072293}

Zigbee2MQTT version

1.40.2

Comments

This is a copy of https://www.zigbee2mqtt.io/devices/TRV06.html, but distributed by other vendor with name Avatto

External definition

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

const fixedValueConverter = {
    thermostatScheduleDayMultiDP: {
        from: (v) => {
            const schedule = [];
            for (let index = 1; index < 24; index = index + 4) {
                schedule.push(
                    String(parseInt(v[index+0])).padStart(2, '0') + ':' +
                    String(parseInt(v[index+1])).padStart(2, '0') + '/' +
                    // @ts-ignore
                    (parseFloat((v[index+2] << 8) + v[index+3]) / 10.0).toFixed(1),
                );
            }
            return schedule.join(' ');
        },
        to: (v) => {
            const payload = [0];
            const transitions = v.split(' ');
            if (transitions.length != 6) {
                throw new Error('Invalid schedule: there should be 6 transitions');
            }
            for (const transition of transitions) {
                const timeTemp = transition.split('/');
                if (timeTemp.length != 2) {
                    throw new Error('Invalid schedule: wrong transition format: ' + transition);
                }
                const hourMin = timeTemp[0].split(':');
                const hour = parseInt(hourMin[0]);
                const min = parseInt(hourMin[1]);
                const temperature = Math.floor(parseFloat(timeTemp[1]) * 10);
                if (hour < 0 || hour > 24 || min < 0 || min > 60 || temperature < 50 || temperature > 300) {
                    throw new Error('Invalid hour, minute or temperature of: ' + transition);
                }
                payload.push(
                    hour,
                    min,
                    (temperature & 0xff00) >> 8,
                    temperature & 0xff,
                );
            }
            return payload;
        },
    },
    thermostatScheduleDayMultiDPWithDayNumber: (dayNum) => {
        return {
            from: (v) => fixedValueConverter.thermostatScheduleDayMultiDP.from(v),
            to: (v) => {
                const data = fixedValueConverter.thermostatScheduleDayMultiDP.to(v);
                data[0] = dayNum;
                return data;
            },
        };
    }
};

const definition = {
    fingerprint: [
        {
            modelID: 'TS0601',
            manufacturerName: '_TZE200_hvaxb2tc',
        },
    ],
    model: 'TRV06',
    vendor: 'Avatto',
        description: 'Thermostatic radiator valve',
        fromZigbee: [tuya.fz.datapoints],
        toZigbee: [tuya.tz.datapoints],
        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_wednesday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(1)],
                [29, 'schedule_thursday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(2)],
                [30, 'schedule_friday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(3)],
                [31, 'schedule_saturday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(4)],
                [32, 'schedule_sunday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(5)],
                [33, 'schedule_monday', fixedValueConverter.thermostatScheduleDayMultiDPWithDayNumber(6)],
                [34, 'schedule_tuesday', fixedValueConverter.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;

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

All works fine

i updated script by fix from - https://github.com/sychu/avatto_me167_TZE200_p3dbf6qs , now temperature is correct and schedule works (for 6 sets)

dszymczuk commented 1 week ago

@barc343 so 4 or 6 sets are available? Code says that for 6 sets, but you said now temperature is correct and schedule works (for 4 sets) I'm confused 🤔

copernic-us commented 6 days ago

@barc343 so 4 or 6 sets are available? Code says that for 6 sets, but you said now temperature is correct and schedule works (for 4 sets) I'm confused 🤔

I've tried to change schedule to 4 instances but it gives me an error. But managed to fix corresponding days.

barc343 commented 3 days ago

@barc343 so 4 or 6 sets are available? Code says that for 6 sets, but you said now temperature is correct and schedule works (for 4 sets) I'm confused 🤔

I've tried to change schedule to 4 instances but it gives me an error. But managed to fix corresponding days.

Sorry, description changed, on this config, all works in auto mode image

copernic-us commented 3 days ago

@barc343 so 4 or 6 sets are available? Code says that for 6 sets, but you said now temperature is correct and schedule works (for 4 sets) I'm confused 🤔

I've tried to change schedule to 4 instances but it gives me an error. But managed to fix corresponding days.

Sorry, description changed, on this config, all works in auto mode

If i recall You have _TZE200_hvaxb2tc. What about problems with temperature spining to 156° on auto mode?

approde commented 2 days ago

Can anyone help me with this? I don't understand the instructions and would like to integrate mine.

dszymczuk commented 2 days ago

@approde Check this https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html#_2-1-extending-the-external-definition 2.1. Extending the external definition