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

feat: support for tuya TRV706 #8581

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/devices/tuya.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5451,6 +5451,91 @@
],
},
},
{
fingerprint: [{ modelID: 'TS0601', manufacturerName: '_TZE284_ltwbm23f' }],
model: 'TRV-705ZB',
vendor: 'Tuya',
// whiteLabel: [
// {vendor: 'Tuya', model: 'TRV-706Z'},
// ],
description: 'Thermostat Radiator Valve', fromZigbee: [tuya.fz.datapoints],
toZigbee: [tuya.tz.datapoints],
onEvent: tuya.onEventSetLocalTime,
configure: tuya.configureMagicPacket,
exposes: [
e.battery(),
e.child_lock(),
e.position(),
e.window_detection(),
e.binary('window', ea.STATE, 'OPEN', 'CLOSE').withDescription('Window status closed or open '),
e.binary('valve_state', ea.STATE, 'OPEN', 'CLOSE').withDescription('Valve status closed or opened '),
e.climate()
.withLocalTemperatureCalibration(-5, 5, 0.1, ea.STATE_SET)
.withLocalTemperature(ea.STATE)
.withSetpoint('current_heating_setpoint', 5, 30, 0.5, ea.STATE_SET)
.withPreset( ['off', 'antifrost', 'eco', 'comfort', 'program', 'valve_open'],
'Off deactivates valve operation, ' +
'the other modes presets when setting on 5º (antifrost), from 15º (eco) and from 20º (comfort). ' +
'It is better to set directly the temperature to deactivate off mode.'),
e.binary('frost_protection', ea.STATE_SET, 'ON', 'OFF').withDescription('Antifreeze function'),
e.enum('valve_status', ea.STATE_SET, ['valve_closed', 'valve_open']).withDescription('Off deactivates valve operation, '
+ 'the other modes presets when setting on 5º (antifrost), from 15º (eco) and from 20º (comfort). ' +
'It is better to set directly the temperature to deactivate off mode.'),
...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.comfort_temperature().withValueMin(15.5).withValueMax(30.0).withValueStep(0.5).withDescription('Comfort mode temperature'),
e.eco_temperature().withValueMin(5.5).withValueMax(20).withValueStep(0.5).withDescription('Eco mode temperature'),
e.holiday_temperature().withValueMin(5).withValueMax(15).withValueStep(0.5).withDescription('Antifreeze mode temperature'),
e.enum('display_brightness', ea.STATE_SET, ['high', 'medium', 'low']).withDescription('Display brightness'),
e.enum('screen_orientation', ea.STATE_SET, ['up', 'down']).withDescription('Screen orientation'),
e.enum('mode', ea.STATE_SET, ['comfort', 'eco']).withDescription(
'Hysteresis - comfort > switches off/on exactly at reached ' +
'temperature with valve smooth from 0 to 100%, eco > 0.5 degrees above or below, valve either 0 or 100%',
),
],
meta: {
tuyaDatapoints: [
[2, 'preset', tuya.valueConverterBasic.lookup({
'off': tuya.enum(0),
'antifrost': tuya.enum(1),
'eco': tuya.enum(2),
'comfort': tuya.enum(3),
'program': tuya.enum(4),
'valve_open': tuya.enum(5),
})],
[2, 'valve_status', tuya.valueConverterBasic.lookup({
'valve_closed': tuya.enum(0),
'auto': tuya.enum(1),
'auto': tuya.enum(2),
'auto': tuya.enum(4),
'auto': tuya.enum(3),

Check failure on line 5510 in src/devices/tuya.ts

View workflow job for this annotation

GitHub Actions / ci

An object literal cannot have multiple properties with the same name.
'valve_open': tuya.enum(5),

Check failure on line 5511 in src/devices/tuya.ts

View workflow job for this annotation

GitHub Actions / ci

An object literal cannot have multiple properties with the same name.
}, 'auto')],

Check failure on line 5512 in src/devices/tuya.ts

View workflow job for this annotation

GitHub Actions / ci

An object literal cannot have multiple properties with the same name.
[3, 'valve_state', tuya.valueConverterBasic.lookup({ CLOSE: tuya.enum(0), OPEN: tuya.enum(1) })],
[4, 'current_heating_setpoint', tuya.valueConverter.divideBy10],
[5, 'local_temperature', tuya.valueConverter.divideBy10],
[6, 'battery', tuya.valueConverter.raw],
[7, 'child_lock', tuya.valueConverter.lockUnlock],
[14, 'window_detection', tuya.valueConverter.onOff],
[15, 'window', tuya.valueConverterBasic.lookup({ CLOSE: tuya.enum(0), OPEN: tuya.enum(1) })],
[47, 'local_temperature_calibration', tuya.valueConverter.localTempCalibration1],
[102, 'schedule_monday', tuya.valueConverter.thermostatScheduleDayMultiDP_TRV705ZB_WithDayNumber(1)],
[103, 'schedule_tuesday', tuya.valueConverter.thermostatScheduleDayMultiDP_TRV705ZB_WithDayNumber(2)],
[104, 'schedule_wednesday', tuya.valueConverter.thermostatScheduleDayMultiDP_TRV705ZB_WithDayNumber(3)],
[105, 'schedule_thursday', tuya.valueConverter.thermostatScheduleDayMultiDP_TRV705ZB_WithDayNumber(4)],
[106, 'schedule_friday', tuya.valueConverter.thermostatScheduleDayMultiDP_TRV705ZB_WithDayNumber(5)],
[107, 'schedule_saturday', tuya.valueConverter.thermostatScheduleDayMultiDP_TRV705ZB_WithDayNumber(6)],
[108, 'schedule_sunday', tuya.valueConverter.thermostatScheduleDayMultiDP_TRV705ZB_WithDayNumber(7)],
[111, 'display_brightness', tuya.valueConverterBasic.lookup({high: tuya.enum(0), medium: tuya.enum(1), low: tuya.enum(2)})],
[113, 'screen_orientation', tuya.valueConverterBasic.lookup({ up: tuya.enum(0), down: tuya.enum(1) })],
[114, 'position', tuya.valueConverter.divideBy10],
[119, 'comfort_temperature', tuya.valueConverter.divideBy10], //--
[120, 'eco_temperature', tuya.valueConverter.divideBy10], //--
[121, 'holiday_temperature', tuya.valueConverter.divideBy10], //--
[122, 'frost_protection', tuya.valueConverter.onOff], //--
[127, 'mode', tuya.valueConverterBasic.lookup({comfort: tuya.enum(0), eco: tuya.enum(1)})],
],
},
},
{
zigbeeModel: ['TS0121'],
model: 'TS0121_plug',
Expand Down
63 changes: 63 additions & 0 deletions src/lib/tuya.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,69 @@ export const valueConverter = {
},
};
},
thermostatScheduleDayMultiDP_TRV705ZB: {
from: (v: string) => {
const schedule = [];
for (let index = 1; index < 24; index = index + 4) {
const firstMinutesByte = (parseInt(v[index]) & 0x0f) << 8;
const secondMinutesByte = parseInt(v[index + 1]);
const minutesSinceMidnight = firstMinutesByte | secondMinutesByte;

const firstTemperatureByte = (parseInt(v[index + 2]) & 0x0f) << 8;
const secondTemperatureByte = parseInt(v[index + 3]);
const temperature = (firstTemperatureByte | secondTemperatureByte) / 10.0;

const hour = Math.floor(minutesSinceMidnight / 60);
const minutes = minutesSinceMidnight % 60;

schedule.push(
String(hour).padStart(2, '0') + ':' + String(minutes).padStart(2, '0') + '/' + temperature.toFixed(1),
);
}
return schedule.join(' ');
},
to: (v: string) => {
const payload = [];
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);
}

const minutesSinceMidnight = hour * 60 + min;

const firstByte = 0xa0 | (minutesSinceMidnight >> 8);
const secondByte = minutesSinceMidnight & 0xff;
const thirdByte = 0x40 | (temperature >> 8);
const fourthByte = temperature & 0xff;

payload.push(firstByte, secondByte, thirdByte, fourthByte);
}
return payload;
},
},
thermostatScheduleDayMultiDP_TRV705ZB_WithDayNumber: (dayNum: number) => {
return {
from: (v: string) => valueConverter.thermostatScheduleDayMultiDP_TRV705ZB.from(v),
to: (v: string) => {
const data = valueConverter.thermostatScheduleDayMultiDP_TRV705ZB.to(v);
data.unshift(dayNum);
return data;
},
};
},

tv02Preset: () => {
return {
from: (v: number) => {
Expand Down
Loading