Skip to content

Commit

Permalink
fix: add SR-ZG9002KR12-Pro SR-ZG9002KR12-Pro configure and use extend…
Browse files Browse the repository at this point in the history
… instead only fromZigbee
  • Loading branch information
niracler committed Dec 3, 2024
1 parent 7ca2798 commit 972707a
Showing 1 changed file with 155 additions and 113 deletions.
268 changes: 155 additions & 113 deletions src/devices/sunricher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,159 @@ function sunricherMinimumPWM(): ModernExtend {
};
}

function sunricherSRZG9002KR12Pro(): ModernExtend {
const cluster = 0xff03;

const fromZigbee: Fz.Converter[] = [
{
cluster: 0xff03,
type: ['raw'],
convert: (model, msg, publish, options, meta) => {
const bytes = [...msg.data];
const messageType = bytes[3];
let action = 'unknown';

if (messageType === 0x01) {
const pressTypeMask: number = bytes[6];
const pressTypeLookup: {[key: number]: string} = {
0x01: 'short_press',
0x02: 'double_press',
0x03: 'hold',
0x04: 'hold_released',
};
action = pressTypeLookup[pressTypeMask] || 'unknown';

const buttonMask = (bytes[4] << 8) | bytes[5];
const specialButtonMap: {[key: number]: string} = {
9: 'knob',
11: 'k9',
12: 'k10',
15: 'k11',
16: 'k12',
};

const actionButtons: string[] = [];
for (let i = 0; i < 16; i++) {
if ((buttonMask >> i) & 1) {
const button = i + 1;
actionButtons.push(specialButtonMap[button] ?? `k${button}`);
}
}
return {action, action_buttons: actionButtons};
} else if (messageType === 0x03) {
const directionMask = bytes[4];
const actionSpeed = bytes[6];

const directionMap: {[key: number]: string} = {
0x01: 'clockwise',
0x02: 'anti_clockwise',
};
const direction = directionMap[directionMask] || 'unknown';

action = `${direction}_rotation`;
return {action, action_speed: actionSpeed};
}

return {action};
},
},
];

const exposes: Expose[] = [e.action(['short_press', 'double_press', 'hold', 'hold_released', 'clockwise_rotation', 'anti_clockwise_rotation'])];

const configure: [Configure] = [
async (device, coordinatorEndpoint, definition) => {
const endpoint = device.getEndpoint(1);
await endpoint.bind(cluster, coordinatorEndpoint);
},
];

return {
fromZigbee,
exposes,
configure,
isModernExtend: true,
};
}

function sunricherSRZG2836D5Pro(): ModernExtend {
const cluster = 0xff03;

const fromZigbee: Fz.Converter[] = [
{
cluster: 0xff03,
type: ['raw'],
convert: (model, msg, publish, options, meta) => {
const bytes = [...msg.data];
const messageType = bytes[3];
let action = 'unknown';

if (messageType === 0x01) {
const pressTypeMask: number = bytes[6];
const pressTypeLookup: {[key: number]: string} = {
0x01: 'short_press',
0x02: 'double_press',
0x03: 'hold',
0x04: 'hold_released',
};
action = pressTypeLookup[pressTypeMask] || 'unknown';

const buttonMask = bytes[5];
const specialButtonLookup: {[key: number]: string} = {
0x01: 'top_left',
0x02: 'top_right',
0x03: 'bottom_left',
0x04: 'bottom_right',
0x05: 'center',
};

const actionButtons: string[] = [];
for (let i = 0; i < 5; i++) {
if ((buttonMask >> i) & 1) {
const button = i + 1;
actionButtons.push(specialButtonLookup[button] || `unknown_${button}`);
}
}
return {action, action_buttons: actionButtons};
} else if (messageType === 0x03) {
const directionMask = bytes[4];
const actionSpeed = bytes[6];
const isStop = bytes[5] === 0x02;

const directionMap: {[key: number]: string} = {
0x01: 'clockwise',
0x02: 'anti_clockwise',
};
const direction = isStop ? 'stop' : directionMap[directionMask] || 'unknown';

action = `${direction}_rotation`;
return {action, action_speed: actionSpeed};
}

return {action};
},
},
];

const exposes: Expose[] = [
e.action(['short_press', 'double_press', 'hold', 'hold_released', 'clockwise_rotation', 'anti_clockwise_rotation', 'stop_rotation']),
];

const configure: [Configure] = [
async (device, coordinatorEndpoint, definition) => {
const endpoint = device.getEndpoint(1);
await endpoint.bind(cluster, coordinatorEndpoint);
},
];

return {
fromZigbee,
exposes,
configure,
isModernExtend: true,
};
}

const fzLocal = {
sunricher_SRZGP2801K45C: {
cluster: 'greenPower',
Expand All @@ -196,111 +349,6 @@ const fzLocal = {
return {action: utils.getFromLookup(commandID, lookup)};
},
} satisfies Fz.Converter,
sunricher_SRZG9002KR12Pro: {
cluster: 0xff03,
type: ['raw'],
convert: (model, msg, publish, options, meta) => {
const bytes = [...msg.data];
const messageType = bytes[3];
let action = 'unknown';

if (messageType === 0x01) {
const pressTypeMask: number = bytes[6];
const pressTypeLookup: {[key: number]: string} = {
0x01: 'short_press',
0x02: 'double_press',
0x03: 'hold',
0x04: 'hold_released',
};
action = pressTypeLookup[pressTypeMask] || 'unknown';

const buttonMask = (bytes[4] << 8) | bytes[5];
const specialButtonMap: {[key: number]: string} = {
9: 'knob',
11: 'k9',
12: 'k10',
15: 'k11',
16: 'k12',
};

const actionButtons: string[] = [];
for (let i = 0; i < 16; i++) {
if ((buttonMask >> i) & 1) {
const button = i + 1;
actionButtons.push(specialButtonMap[button] ?? `k${button}`);
}
}
return {action, action_buttons: actionButtons};
} else if (messageType === 0x03) {
const directionMask = bytes[4];
const actionSpeed = bytes[6];

const directionMap: {[key: number]: string} = {
0x01: 'clockwise',
0x02: 'anti_clockwise',
};
const direction = directionMap[directionMask] || 'unknown';

action = `${direction}_rotation`;
return {action, action_speed: actionSpeed};
}

return {action};
},
} satisfies Fz.Converter,
sunricher_SRZG2836D5Pro: {
cluster: 0xff03,
type: ['raw'],
convert: (model, msg, publish, options, meta) => {
const bytes = [...msg.data];
const messageType = bytes[3];
let action = 'unknown';

if (messageType === 0x01) {
const pressTypeMask: number = bytes[6];
const pressTypeLookup: {[key: number]: string} = {
0x01: 'short_press',
0x02: 'double_press',
0x03: 'hold',
0x04: 'hold_released',
};
action = pressTypeLookup[pressTypeMask] || 'unknown';

const buttonMask = bytes[5];
const specialButtonLookup: {[key: number]: string} = {
0x01: 'top_left',
0x02: 'top_right',
0x03: 'bottom_left',
0x04: 'bottom_right',
0x05: 'center',
};

const actionButtons: string[] = [];
for (let i = 0; i < 5; i++) {
if ((buttonMask >> i) & 1) {
const button = i + 1;
actionButtons.push(specialButtonLookup[button] || `unknown_${button}`);
}
}
return {action, action_buttons: actionButtons};
} else if (messageType === 0x03) {
const directionMask = bytes[4];
const actionSpeed = bytes[6];
const isStop = bytes[5] === 0x02;

const directionMap: {[key: number]: string} = {
0x01: 'clockwise',
0x02: 'anti_clockwise',
};
const direction = isStop ? 'stop' : directionMap[directionMask] || 'unknown';

action = `${direction}_rotation`;
return {action, action_speed: actionSpeed};
}

return {action};
},
} satisfies Fz.Converter,
};

async function syncTime(endpoint: Zh.Endpoint) {
Expand All @@ -319,20 +367,14 @@ const definitions: DefinitionWithExtend[] = [
model: 'SR-ZG2836D5-Pro',
vendor: 'Sunricher',
description: 'Zigbee smart remote',
extend: [battery()],
fromZigbee: [fzLocal.sunricher_SRZG2836D5Pro],
exposes: [
e.action(['short_press', 'double_press', 'hold', 'hold_released', 'clockwise_rotation', 'anti_clockwise_rotation', 'stop_rotation']),
],
extend: [battery(), sunricherSRZG2836D5Pro()],
},
{
zigbeeModel: ['HK-ZRC-K12&RS-E'],
model: 'SR-ZG9002KR12-Pro',
vendor: 'Sunricher',
description: 'Zigbee smart wall panel remote',
extend: [battery()],
fromZigbee: [fzLocal.sunricher_SRZG9002KR12Pro],
exposes: [e.action(['short_press', 'double_press', 'hold', 'hold_released', 'clockwise_rotation', 'anti_clockwise_rotation'])],
extend: [battery(), sunricherSRZG9002KR12Pro()],
},
{
zigbeeModel: ['ZV9380A', 'ZG9380A'],
Expand Down

0 comments on commit 972707a

Please sign in to comment.