Skip to content

Commit 7310253

Browse files
authored
feat: Add two private attributes for SR-ZG9040A/ZG9041A-D. (#8210)
* Add two private attributes for SR-ZG9040A/ZG9041A-D. 1. External Switch Type 2. Minimum PWM * Add two private attributes for SR-ZG9040A/ZG9041A-D. 1. External Switch Type 2. Minimum PWM
1 parent a3cde02 commit 7310253

File tree

1 file changed

+141
-2
lines changed

1 file changed

+141
-2
lines changed

src/devices/sunricher.ts

+141-2
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,152 @@ import {
2525
} from '../lib/modernExtend';
2626
import * as reporting from '../lib/reporting';
2727
import * as globalStore from '../lib/store';
28-
import {DefinitionWithExtend, Fz, Zh} from '../lib/types';
28+
import {Configure, DefinitionWithExtend, Expose, Fz, ModernExtend, Tz, Zh} from '../lib/types';
2929
import * as utils from '../lib/utils';
3030

3131
const NS = 'zhc:sunricher';
3232
const e = exposes.presets;
3333
const ea = exposes.access;
3434

35+
const sunricherManufacturerCode = 0x1224;
36+
37+
function sunricherExternalSwitchType(): ModernExtend {
38+
const attribute = 0x8803;
39+
const data_type = 0x20;
40+
const value_map: {[key: number]: string} = {
41+
0: 'push_button',
42+
1: 'normal_on_off',
43+
2: 'three_way',
44+
};
45+
const value_lookup: {[key: string]: number} = {
46+
push_button: 0,
47+
normal_on_off: 1,
48+
three_way: 2,
49+
};
50+
51+
const fromZigbee: Fz.Converter[] = [
52+
{
53+
cluster: 'genBasic',
54+
type: ['attributeReport', 'readResponse'],
55+
convert: (model, msg, publish, options, meta) => {
56+
if (Object.prototype.hasOwnProperty.call(msg.data, attribute)) {
57+
const value = msg.data[attribute];
58+
return {
59+
external_switch_type: value_map[value] || 'unknown',
60+
external_switch_type_numeric: value,
61+
};
62+
}
63+
return undefined;
64+
},
65+
} satisfies Fz.Converter,
66+
];
67+
68+
const toZigbee: Tz.Converter[] = [
69+
{
70+
key: ['external_switch_type'],
71+
convertSet: async (entity, key, value: string, meta) => {
72+
const numericValue = value_lookup[value] ?? parseInt(value, 10);
73+
await entity.write('genBasic', {[attribute]: {value: numericValue, type: data_type}}, {manufacturerCode: sunricherManufacturerCode});
74+
return {state: {external_switch_type: value}};
75+
},
76+
convertGet: async (entity, key, meta) => {
77+
await entity.read('genBasic', [attribute], {manufacturerCode: sunricherManufacturerCode});
78+
},
79+
} satisfies Tz.Converter,
80+
];
81+
82+
const exposes: Expose[] = [
83+
e.enum('external_switch_type', ea.ALL, ['push_button', 'normal_on_off', 'three_way']).withLabel('External switch type'),
84+
];
85+
86+
const configure: [Configure] = [
87+
async (device, coordinatorEndpoint, definition) => {
88+
const endpoint = device.getEndpoint(1);
89+
try {
90+
await endpoint.read('genBasic', [attribute], {manufacturerCode: sunricherManufacturerCode});
91+
} catch (error) {
92+
console.warn(`Failed to read external switch type attribute: ${error}`);
93+
}
94+
},
95+
];
96+
97+
return {
98+
fromZigbee,
99+
toZigbee,
100+
exposes,
101+
configure,
102+
isModernExtend: true,
103+
};
104+
}
105+
106+
function sunricherMinimumPWM(): ModernExtend {
107+
const attribute = 0x7809;
108+
const data_type = 0x20;
109+
110+
const fromZigbee: Fz.Converter[] = [
111+
{
112+
cluster: 'genBasic',
113+
type: ['attributeReport', 'readResponse'],
114+
convert: (model, msg, publish, options, meta) => {
115+
if (Object.prototype.hasOwnProperty.call(msg.data, attribute)) {
116+
console.log(`from `, msg.data[attribute]);
117+
const value = Math.round(msg.data[attribute] / 5.1);
118+
return {
119+
minimum_pwm: value,
120+
};
121+
}
122+
return undefined;
123+
},
124+
},
125+
];
126+
127+
const toZigbee: Tz.Converter[] = [
128+
{
129+
key: ['minimum_pwm'],
130+
convertSet: async (entity: Zh.Endpoint, key: string, value: number | string, meta) => {
131+
console.log(`to `, value);
132+
const numValue = typeof value === 'string' ? parseInt(value) : value;
133+
const zgValue = Math.round(numValue * 5.1);
134+
await entity.write('genBasic', {[attribute]: {value: zgValue, type: data_type}}, {manufacturerCode: sunricherManufacturerCode});
135+
return {state: {minimum_pwm: numValue}};
136+
},
137+
convertGet: async (entity: Zh.Endpoint, key: string, meta) => {
138+
await entity.read('genBasic', [attribute], {manufacturerCode: sunricherManufacturerCode});
139+
},
140+
},
141+
];
142+
143+
const exposes: Expose[] = [
144+
e
145+
.numeric('minimum_pwm', ea.ALL)
146+
.withLabel('Minimum PWM')
147+
.withDescription('Power off the device and wait for 3 seconds before reconnecting to apply the settings.')
148+
.withValueMin(0)
149+
.withValueMax(50)
150+
.withUnit('%')
151+
.withValueStep(1),
152+
];
153+
154+
const configure: [Configure] = [
155+
async (device, coordinatorEndpoint, definition) => {
156+
const endpoint = device.getEndpoint(1);
157+
try {
158+
await endpoint.read('genBasic', [attribute], {manufacturerCode: sunricherManufacturerCode});
159+
} catch (error) {
160+
console.warn(`Failed to read external switch type attribute: ${error}`);
161+
}
162+
},
163+
];
164+
165+
return {
166+
fromZigbee,
167+
toZigbee,
168+
exposes,
169+
configure,
170+
isModernExtend: true,
171+
};
172+
}
173+
35174
const fzLocal = {
36175
sunricher_SRZGP2801K45C: {
37176
cluster: 'greenPower',
@@ -378,7 +517,7 @@ const definitions: DefinitionWithExtend[] = [
378517
model: 'SR-ZG9040A/ZG9041A-D',
379518
vendor: 'Sunricher',
380519
description: 'Zigbee micro smart dimmer',
381-
extend: [light({configureReporting: true}), electricityMeter()],
520+
extend: [light({configureReporting: true}), electricityMeter(), sunricherExternalSwitchType(), sunricherMinimumPWM()],
382521
},
383522
{
384523
zigbeeModel: ['HK-ZD-DIM-A'],

0 commit comments

Comments
 (0)