Skip to content

Commit

Permalink
feat(add): M9-zigbee-SL (#5965)
Browse files Browse the repository at this point in the history
* Update terncy.ts

Added Terncy CL001 support

* Update terncy.ts

Fixed linting issues

* Update tuya.ts

added support for tuya G3 smart 4 gang switch with 2 scene controller

* Update tuya.ts

Changed model name

* Update tuya.ts

fix typo

* Update terncy.ts

* Update tuya.ts

Adds support for tuya 4gang + 2 scene switch with backlight.
Power on behavior is still WIP.
master_switch requires Koenkk/zigbee2mqtt#18157 to work

* Update tuya.ts

fixed linting errors

* Update tuya.ts

Moved _TZE200_wunufsil to an individual device with switch countdown timer, power on behavior, backlight control, and master switch functions.

* Update tuya.ts

Changed model name to reflect 2 gang control

* Update tuya.ts

_TZE200_0j5jma9b :
  fixed description
  fixed master switch
_TZE200_wunufsil:
  removed extra endpoints

* Update tuya.ts

Added TS0601_3gang switch with backlight

* Update tuya.ts

Fixed duplicate _TZE200_vhy3iakz (new code supports countdown, backlight mode, and main switch)  and changed some formatting

* Update tuya.ts

fix duplicates and format

* Update tuya.ts

Changed _TZE200_k6jhsr0q to support additional features

* Update tuya.ts

Update device names per request

* Update tuya.ts

Updated model names

* Update tuya.ts

Changed

* Update tuya.ts

Fixed power on behavior
Fixed backlightModeOffOn get

* Update tuya.ts

* Update tuya.ts

 Add individual mode/power on behavior switch for tuya devices

* Adds support for M9-zigbee-SL

Adds support for M9-zigbee-SL
'light_mode' is needed to control individual indicator lights.

* Fix linting

* refactor code

* Code refactor

* Update tuya.ts

* Update tuya.ts

---------

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
  • Loading branch information
Qianli-Ma and Koenkk authored Jul 17, 2023
1 parent 709590b commit fc33990
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 5 deletions.
78 changes: 74 additions & 4 deletions src/devices/tuya.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5192,7 +5192,7 @@ const definitions: Definition[] = [
[11, 'countdown_l5', tuya.valueConverter.countdown],
[12, 'countdown_l6', tuya.valueConverter.countdown],
[13, 'state', tuya.valueConverter.onOff],
[14, 'power_on_behavior', tuya.valueConverterBasic.lookup({'off': tuya.enum(0), 'on': tuya.enum(1), 'previous': tuya.enum(2)})],
[14, 'power_on_behavior', tuya.valueConverter.powerOnBehaviorEnum],
[16, 'backlight_mode', tuya.valueConverter.onOff],
],
},
Expand Down Expand Up @@ -5226,7 +5226,7 @@ const definitions: Definition[] = [
[7, 'countdown_l1', tuya.valueConverter.countdown],
[8, 'countdown_l2', tuya.valueConverter.countdown],
[13, 'state', tuya.valueConverter.onOff],
[14, 'power_on_behavior', tuya.valueConverterBasic.lookup({'off': tuya.enum(0), 'on': tuya.enum(1), 'previous': tuya.enum(2)})],
[14, 'power_on_behavior', tuya.valueConverter.powerOnBehaviorEnum],
[16, 'backlight_mode', tuya.valueConverter.onOff],
],
},
Expand Down Expand Up @@ -5264,7 +5264,7 @@ const definitions: Definition[] = [
[8, 'countdown_l2', tuya.valueConverter.countdown],
[9, 'countdown_l3', tuya.valueConverter.countdown],
[13, 'state', tuya.valueConverter.onOff],
[14, 'power_on_behavior', tuya.valueConverterBasic.lookup({'off': tuya.enum(0), 'on': tuya.enum(1), 'previous': tuya.enum(2)})],
[14, 'power_on_behavior', tuya.valueConverter.powerOnBehaviorEnum],
[16, 'backlight_mode', tuya.valueConverter.onOff],
],
},
Expand Down Expand Up @@ -5306,11 +5306,81 @@ const definitions: Definition[] = [
[9, 'countdown_l3', tuya.valueConverter.countdown],
[10, 'countdown_l4', tuya.valueConverter.countdown],
[13, 'state', tuya.valueConverter.onOff],
[14, 'power_on_behavior', tuya.valueConverterBasic.lookup({'off': tuya.enum(0), 'on': tuya.enum(1), 'previous': tuya.enum(2)})],
[14, 'power_on_behavior', tuya.valueConverter.powerOnBehaviorEnum],
[16, 'backlight_mode', tuya.valueConverter.onOff],
],
},
},
{
fingerprint: tuya.fingerprint('TS0601', ['_TZE200_nvodulvi']),
model: 'M9-zigbee-SL',
vendor: 'TuYa',
description: 'Smart Switch (4 gang + 4 scene) with neutral wire and motion sensing',
fromZigbee: [tuya.fz.datapoints, fz.ias_occupancy_only_alarm_2, tuya.fz.indicator_mode],
toZigbee: [tuya.tz.datapoints, tuya.tz.power_on_behavior_1, tuya.tz.backlight_indicator_mode_1],
configure: tuya.configureMagicPacket,
exposes: [
...[1, 2, 3, 4, 5, 6, 7, 8].map((i) => tuya.exposes.switch().withEndpoint(`l${i}`)),
...[1, 2, 3, 4, 5, 6, 7, 8].map((i) => e.power_on_behavior().withAccess(ea.STATE_SET).withEndpoint(`l${i}`)),
...[1, 2, 3, 4, 5, 6, 7, 8].map((i) => tuya.exposes.switchMode().withEndpoint(`l${i}`)),
...[1, 2, 3, 4, 5, 6, 7, 8].map((i) => tuya.exposes.lightMode().withEndpoint(`l${i}`)),
tuya.exposes.backlightModeOffOn().withAccess(ea.STATE_SET),
e.action(['scene_1', 'scene_2', 'scene_3', 'scene_4', 'scene_5', 'scene_6', 'scene_7', 'scene_8']),
e.presence(),
new exposes.Numeric('delay', ea.STATE_SET).withUnit('sec').withDescription('light off delay').withValueMin(0).withValueMax(1000),
],
endpoint: (device) => {
return {'l1': 1, 'l2': 1, 'l3': 1, 'l4': 1, 'l5': 1, 'l6': 1, 'state': 1, 'backlight': 1, 'l7': 1, 'l8': 1};
},
meta: {
multiEndpoint: true,
tuyaDatapoints: [
[1, 'state_l1', tuya.valueConverter.onOff],
[2, 'state_l2', tuya.valueConverter.onOff],
[3, 'state_l3', tuya.valueConverter.onOff],
[4, 'state_l4', tuya.valueConverter.onOff],
[5, 'state_l5', tuya.valueConverter.onOff],
[6, 'state_l6', tuya.valueConverter.onOff],
[16, 'backlight_mode', tuya.valueConverter.onOff],
[29, 'power_on_behavior_l1', tuya.valueConverter.powerOnBehaviorEnum],
[30, 'power_on_behavior_l2', tuya.valueConverter.powerOnBehaviorEnum],
[31, 'power_on_behavior_l3', tuya.valueConverter.powerOnBehaviorEnum],
[32, 'power_on_behavior_l4', tuya.valueConverter.powerOnBehaviorEnum],
[33, 'power_on_behavior_l5', tuya.valueConverter.powerOnBehaviorEnum],
[34, 'power_on_behavior_l6', tuya.valueConverter.powerOnBehaviorEnum],
[101, 'action', tuya.valueConverter.static('scene_1')],
[102, 'action', tuya.valueConverter.static('scene_2')],
[103, 'action', tuya.valueConverter.static('scene_3')],
[104, 'action', tuya.valueConverter.static('scene_4')],
[105, 'presence', tuya.valueConverter.raw],
[106, 'delay', tuya.valueConverter.raw],
[108, 'action', tuya.valueConverter.static('scene_5')],
[109, 'action', tuya.valueConverter.static('scene_6')],
[110, 'action', tuya.valueConverter.static('scene_7')],
[111, 'action', tuya.valueConverter.static('scene_8')],
[112, 'state_l7', tuya.valueConverter.onOff],
[113, 'state_l8', tuya.valueConverter.onOff],
[114, 'switch_mode_l1', tuya.valueConverter.switchMode],
[115, 'switch_mode_l2', tuya.valueConverter.switchMode],
[116, 'switch_mode_l3', tuya.valueConverter.switchMode],
[117, 'switch_mode_l4', tuya.valueConverter.switchMode],
[118, 'switch_mode_l5', tuya.valueConverter.switchMode],
[119, 'switch_mode_l6', tuya.valueConverter.switchMode],
[120, 'switch_mode_l7', tuya.valueConverter.switchMode],
[121, 'switch_mode_l8', tuya.valueConverter.switchMode],
[122, 'light_mode_l1', tuya.valueConverter.lightMode],
[123, 'light_mode_l2', tuya.valueConverter.lightMode],
[124, 'light_mode_l3', tuya.valueConverter.lightMode],
[125, 'light_mode_l4', tuya.valueConverter.lightMode],
[126, 'light_mode_l5', tuya.valueConverter.lightMode],
[127, 'light_mode_l6', tuya.valueConverter.lightMode],
[128, 'light_mode_l7', tuya.valueConverter.lightMode],
[129, 'light_mode_l8', tuya.valueConverter.lightMode],
[130, 'power_on_behavior_l7', tuya.valueConverter.powerOnBehaviorEnum],
[131, 'power_on_behavior_l8', tuya.valueConverter.powerOnBehaviorEnum],
],
},
},
];

module.exports = definitions;
13 changes: 12 additions & 1 deletion src/lib/tuya.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,14 @@ const tuyaExposes = {
.withDescription('Do not disturb mode, when enabled this function will keep the light OFF after a power outage'),
colorPowerOnBehavior: () => e.enum('color_power_on_behavior', ea.STATE_SET, ['initial', 'previous', 'cutomized'])
.withDescription('Power on behavior state'),
switchMode: () => e.enum('switch_mode', ea.STATE_SET, ['switch', 'scene'])
.withDescription('Sets the mode of the switch to act as a switch or as a scene'),
lightMode: () => e.enum('light_mode', ea.STATE_SET, ['normal', 'on', 'off', 'flash'])
.withDescription(`'Sets the indicator mode of l1.
Normal: Orange while off and white while on.
On: Always white. Off: Always orange.
Flash: Flashes white when triggered.
Note: Orange light will turn off after light off delay, white light always stays on. Light mode updates on next state change.'`),
};
export {tuyaExposes as exposes};

Expand Down Expand Up @@ -381,6 +389,7 @@ export const valueConverter = {
trueFalseEnum0: valueConverterBasic.trueFalse(new Enum(0)),
onOff: valueConverterBasic.lookup({'ON': true, 'OFF': false}),
powerOnBehavior: valueConverterBasic.lookup({'off': 0, 'on': 1, 'previous': 2}),
powerOnBehaviorEnum: valueConverterBasic.lookup({'off': new Enum(0), 'on': new Enum(1), 'previous': new Enum(2)}),
lightType: valueConverterBasic.lookup({'led': 0, 'incandescent': 1, 'halogen': 2}),
countdown: valueConverterBasic.raw(),
scale0_254to0_1000: valueConverterBasic.scale(0, 254, 0, 1000),
Expand All @@ -390,6 +399,8 @@ export const valueConverter = {
batteryState: valueConverterBasic.lookup({'low': 0, 'medium': 1, 'high': 2}),
divideBy10: valueConverterBasic.divideBy(10),
divideBy1000: valueConverterBasic.divideBy(1000),
switchMode: valueConverterBasic.lookup({'switch': new Enum(0), 'scene': new Enum(1)}),
lightMode: valueConverterBasic.lookup({'normal': new Enum(0), 'on': new Enum(1), 'off': new Enum(2), 'flash': new Enum(3)}),
raw: valueConverterBasic.raw(),
setLimit: {
to: (v: number) => {
Expand Down Expand Up @@ -786,7 +797,7 @@ const tuyaTz = {
'min_temperature', 'max_temperature', 'window_detection', 'boost_heating', 'alarm_ringtone', 'alarm_time', 'fan_speed',
'reverse_direction', 'border', 'click_control', 'motor_direction', 'opening_mode', 'factory_reset', 'set_upper_limit', 'set_bottom_limit',
'motor_speed', 'timer', 'reset_frost_lock', 'schedule_periodic', 'schedule_weekday', 'backlight_mode', 'calibration', 'motor_steering',
'mode', 'lower', 'upper', 'delay', 'reverse', 'touch', 'program',
'mode', 'lower', 'upper', 'delay', 'reverse', 'touch', 'program', 'light_mode', 'switch_mode',
...[1, 2, 3, 4, 5, 6].map((no) => `schedule_slot_${no}`), 'minimum_range', 'maximum_range', 'detection_delay', 'fading_time',
],
convertSet: async (entity, key, value, meta) => {
Expand Down

0 comments on commit fc33990

Please sign in to comment.