zigbee-herdsman-converters 23.2.0 → 23.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/dist/converters/fromZigbee.d.ts.map +1 -1
- package/dist/converters/fromZigbee.js +53 -11
- package/dist/converters/fromZigbee.js.map +1 -1
- package/dist/converters/toZigbee.d.ts.map +1 -1
- package/dist/converters/toZigbee.js +82 -8
- package/dist/converters/toZigbee.js.map +1 -1
- package/dist/devices/ITCommander.d.ts.map +1 -1
- package/dist/devices/ITCommander.js +1 -0
- package/dist/devices/ITCommander.js.map +1 -1
- package/dist/devices/adeo.d.ts.map +1 -1
- package/dist/devices/adeo.js +1 -0
- package/dist/devices/adeo.js.map +1 -1
- package/dist/devices/atlantic.d.ts.map +1 -1
- package/dist/devices/atlantic.js +2 -0
- package/dist/devices/atlantic.js.map +1 -1
- package/dist/devices/avatto.js +6 -6
- package/dist/devices/avatto.js.map +1 -1
- package/dist/devices/bosch.d.ts.map +1 -1
- package/dist/devices/bosch.js +2 -0
- package/dist/devices/bosch.js.map +1 -1
- package/dist/devices/brun_holding.d.ts +3 -0
- package/dist/devices/brun_holding.d.ts.map +1 -0
- package/dist/devices/brun_holding.js +59 -0
- package/dist/devices/brun_holding.js.map +1 -0
- package/dist/devices/busch_jaeger.js +1 -1
- package/dist/devices/busch_jaeger.js.map +1 -1
- package/dist/devices/custom_devices_diy.d.ts.map +1 -1
- package/dist/devices/custom_devices_diy.js +18 -13
- package/dist/devices/custom_devices_diy.js.map +1 -1
- package/dist/devices/develco.js +1 -1
- package/dist/devices/develco.js.map +1 -1
- package/dist/devices/diyruz.d.ts.map +1 -1
- package/dist/devices/diyruz.js +2 -0
- package/dist/devices/diyruz.js.map +1 -1
- package/dist/devices/dresden_elektronik.js +1 -1
- package/dist/devices/dresden_elektronik.js.map +1 -1
- package/dist/devices/essentials.js +3 -3
- package/dist/devices/essentials.js.map +1 -1
- package/dist/devices/eurotronic.d.ts.map +1 -1
- package/dist/devices/eurotronic.js +4 -1
- package/dist/devices/eurotronic.js.map +1 -1
- package/dist/devices/ewelink.d.ts.map +1 -1
- package/dist/devices/ewelink.js +15 -37
- package/dist/devices/ewelink.js.map +1 -1
- package/dist/devices/gledopto.d.ts.map +1 -1
- package/dist/devices/gledopto.js +2 -1
- package/dist/devices/gledopto.js.map +1 -1
- package/dist/devices/gmmts.d.ts.map +1 -1
- package/dist/devices/gmmts.js +7 -0
- package/dist/devices/gmmts.js.map +1 -1
- package/dist/devices/hive.js +1 -1
- package/dist/devices/hive.js.map +1 -1
- package/dist/devices/ikea.js +1 -1
- package/dist/devices/ikea.js.map +1 -1
- package/dist/devices/index.d.ts.map +1 -1
- package/dist/devices/index.js +4 -0
- package/dist/devices/index.js.map +1 -1
- package/dist/devices/inovelli.d.ts.map +1 -1
- package/dist/devices/inovelli.js +70 -36
- package/dist/devices/inovelli.js.map +1 -1
- package/dist/devices/insta.js +1 -1
- package/dist/devices/insta.js.map +1 -1
- package/dist/devices/keen_home.d.ts.map +1 -1
- package/dist/devices/keen_home.js +2 -4
- package/dist/devices/keen_home.js.map +1 -1
- package/dist/devices/lidl.d.ts.map +1 -1
- package/dist/devices/lidl.js +5 -2
- package/dist/devices/lidl.js.map +1 -1
- package/dist/devices/lifecontrol.js +1 -1
- package/dist/devices/lifecontrol.js.map +1 -1
- package/dist/devices/linptech.d.ts.map +1 -1
- package/dist/devices/linptech.js +1 -0
- package/dist/devices/linptech.js.map +1 -1
- package/dist/devices/lixee.d.ts.map +1 -1
- package/dist/devices/lixee.js +69 -49
- package/dist/devices/lixee.js.map +1 -1
- package/dist/devices/lumi.d.ts.map +1 -1
- package/dist/devices/lumi.js +23 -102
- package/dist/devices/lumi.js.map +1 -1
- package/dist/devices/moes.js +3 -3
- package/dist/devices/moes.js.map +1 -1
- package/dist/devices/muller_licht.d.ts.map +1 -1
- package/dist/devices/muller_licht.js +1 -5
- package/dist/devices/muller_licht.js.map +1 -1
- package/dist/devices/multiterm.d.ts.map +1 -1
- package/dist/devices/multiterm.js +1 -0
- package/dist/devices/multiterm.js.map +1 -1
- package/dist/devices/namron.js +2 -2
- package/dist/devices/namron.js.map +1 -1
- package/dist/devices/nue_3a.d.ts.map +1 -1
- package/dist/devices/nue_3a.js +2 -0
- package/dist/devices/nue_3a.js.map +1 -1
- package/dist/devices/orvibo.d.ts.map +1 -1
- package/dist/devices/orvibo.js +3 -0
- package/dist/devices/orvibo.js.map +1 -1
- package/dist/devices/osram.js +2 -2
- package/dist/devices/osram.js.map +1 -1
- package/dist/devices/owon.d.ts.map +1 -1
- package/dist/devices/owon.js +2 -0
- package/dist/devices/owon.js.map +1 -1
- package/dist/devices/paulmann.d.ts.map +1 -1
- package/dist/devices/paulmann.js +7 -0
- package/dist/devices/paulmann.js.map +1 -1
- package/dist/devices/philips.d.ts.map +1 -1
- package/dist/devices/philips.js +7 -0
- package/dist/devices/philips.js.map +1 -1
- package/dist/devices/rgb_genie.d.ts.map +1 -1
- package/dist/devices/rgb_genie.js +2 -0
- package/dist/devices/rgb_genie.js.map +1 -1
- package/dist/devices/samotech.d.ts.map +1 -1
- package/dist/devices/samotech.js +2 -1
- package/dist/devices/samotech.js.map +1 -1
- package/dist/devices/schneider_electric.d.ts.map +1 -1
- package/dist/devices/schneider_electric.js +8 -4
- package/dist/devices/schneider_electric.js.map +1 -1
- package/dist/devices/shinasystem.d.ts.map +1 -1
- package/dist/devices/shinasystem.js +3 -0
- package/dist/devices/shinasystem.js.map +1 -1
- package/dist/devices/sinope.d.ts.map +1 -1
- package/dist/devices/sinope.js +3 -0
- package/dist/devices/sinope.js.map +1 -1
- package/dist/devices/somfy.d.ts.map +1 -1
- package/dist/devices/somfy.js +13 -1
- package/dist/devices/somfy.js.map +1 -1
- package/dist/devices/sonoff.d.ts.map +1 -1
- package/dist/devices/sonoff.js +21 -4
- package/dist/devices/sonoff.js.map +1 -1
- package/dist/devices/sunricher.d.ts.map +1 -1
- package/dist/devices/sunricher.js +17 -743
- package/dist/devices/sunricher.js.map +1 -1
- package/dist/devices/third_reality.d.ts.map +1 -1
- package/dist/devices/third_reality.js +1 -4
- package/dist/devices/third_reality.js.map +1 -1
- package/dist/devices/tuya.d.ts.map +1 -1
- package/dist/devices/tuya.js +45 -22
- package/dist/devices/tuya.js.map +1 -1
- package/dist/devices/ubisys.d.ts.map +1 -1
- package/dist/devices/ubisys.js +6 -1
- package/dist/devices/ubisys.js.map +1 -1
- package/dist/devices/wmun.d.ts +3 -0
- package/dist/devices/wmun.d.ts.map +1 -0
- package/dist/devices/wmun.js +61 -0
- package/dist/devices/wmun.js.map +1 -0
- package/dist/devices/xyzroe.d.ts.map +1 -1
- package/dist/devices/xyzroe.js +10 -0
- package/dist/devices/xyzroe.js.map +1 -1
- package/dist/devices/yale.js +1 -1
- package/dist/devices/yale.js.map +1 -1
- package/dist/devices/yandex.js +1 -1
- package/dist/devices/yandex.js.map +1 -1
- package/dist/devices/yokis.d.ts.map +1 -1
- package/dist/devices/yokis.js +74 -37
- package/dist/devices/yokis.js.map +1 -1
- package/dist/devices/ysrsai.js +1 -1
- package/dist/devices/ysrsai.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/indexer.d.ts.map +1 -1
- package/dist/indexer.js +1 -0
- package/dist/indexer.js.map +1 -1
- package/dist/lib/color.d.ts.map +1 -1
- package/dist/lib/color.js +9 -1
- package/dist/lib/color.js.map +1 -1
- package/dist/lib/configureKey.js +9 -0
- package/dist/lib/configureKey.js.map +1 -1
- package/dist/lib/constants.d.ts +3 -1
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/develco.d.ts.map +1 -1
- package/dist/lib/develco.js +1 -0
- package/dist/lib/develco.js.map +1 -1
- package/dist/lib/ewelink.d.ts.map +1 -1
- package/dist/lib/ewelink.js +10 -7
- package/dist/lib/ewelink.js.map +1 -1
- package/dist/lib/exposes.d.ts +17 -17
- package/dist/lib/exposes.d.ts.map +1 -1
- package/dist/lib/exposes.js +50 -30
- package/dist/lib/exposes.js.map +1 -1
- package/dist/lib/generateDefinition.d.ts.map +1 -1
- package/dist/lib/generateDefinition.js +2 -1
- package/dist/lib/generateDefinition.js.map +1 -1
- package/dist/lib/ikea.d.ts.map +1 -1
- package/dist/lib/ikea.js +8 -0
- package/dist/lib/ikea.js.map +1 -1
- package/dist/lib/ledvance.d.ts.map +1 -1
- package/dist/lib/ledvance.js +2 -0
- package/dist/lib/ledvance.js.map +1 -1
- package/dist/lib/legacy.d.ts +4 -4
- package/dist/lib/legacy.d.ts.map +1 -1
- package/dist/lib/legacy.js +180 -4
- package/dist/lib/legacy.js.map +1 -1
- package/dist/lib/light.d.ts.map +1 -1
- package/dist/lib/light.js +2 -0
- package/dist/lib/light.js.map +1 -1
- package/dist/lib/lumi.d.ts +43 -3
- package/dist/lib/lumi.d.ts.map +1 -1
- package/dist/lib/lumi.js +56 -4
- package/dist/lib/lumi.js.map +1 -1
- package/dist/lib/modernExtend.d.ts +7 -6
- package/dist/lib/modernExtend.d.ts.map +1 -1
- package/dist/lib/modernExtend.js +78 -3
- package/dist/lib/modernExtend.js.map +1 -1
- package/dist/lib/nodon.d.ts.map +1 -1
- package/dist/lib/ota.d.ts.map +1 -1
- package/dist/lib/ota.js +10 -1
- package/dist/lib/ota.js.map +1 -1
- package/dist/lib/philips.d.ts +1 -1
- package/dist/lib/philips.d.ts.map +1 -1
- package/dist/lib/philips.js +20 -1
- package/dist/lib/philips.js.map +1 -1
- package/dist/lib/reporting.d.ts.map +1 -1
- package/dist/lib/reporting.js +0 -1
- package/dist/lib/reporting.js.map +1 -1
- package/dist/lib/sunricher.d.ts +17 -3
- package/dist/lib/sunricher.d.ts.map +1 -1
- package/dist/lib/sunricher.js +771 -1
- package/dist/lib/sunricher.js.map +1 -1
- package/dist/lib/tuya.d.ts +5 -5
- package/dist/lib/tuya.d.ts.map +1 -1
- package/dist/lib/tuya.js +21 -6
- package/dist/lib/tuya.js.map +1 -1
- package/dist/lib/types.d.ts +3 -3
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +0 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/utils.d.ts +1 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +17 -5
- package/dist/lib/utils.js.map +1 -1
- package/dist/models-index.json +1 -1
- package/package.json +6 -6
|
@@ -47,738 +47,12 @@ const reporting_1 = require("../lib/reporting");
|
|
|
47
47
|
const globalStore = __importStar(require("../lib/store"));
|
|
48
48
|
const sunricher = __importStar(require("../lib/sunricher"));
|
|
49
49
|
const utils = __importStar(require("../lib/utils"));
|
|
50
|
-
const utils_1 = require("../lib/utils");
|
|
51
50
|
const NS = "zhc:sunricher";
|
|
52
51
|
const e = exposes.presets;
|
|
53
52
|
const ea = exposes.access;
|
|
54
53
|
const sunricherManufacturerCode = 0x1224;
|
|
55
|
-
const sunricherExtend = {
|
|
56
|
-
externalSwitchType: () => {
|
|
57
|
-
const attribute = 0x8803;
|
|
58
|
-
const data_type = 0x20;
|
|
59
|
-
const value_map = {
|
|
60
|
-
0: "push_button",
|
|
61
|
-
1: "normal_on_off",
|
|
62
|
-
2: "three_way",
|
|
63
|
-
};
|
|
64
|
-
const value_lookup = {
|
|
65
|
-
push_button: 0,
|
|
66
|
-
normal_on_off: 1,
|
|
67
|
-
three_way: 2,
|
|
68
|
-
};
|
|
69
|
-
const fromZigbee = [
|
|
70
|
-
{
|
|
71
|
-
cluster: "genBasic",
|
|
72
|
-
type: ["attributeReport", "readResponse"],
|
|
73
|
-
convert: (model, msg, publish, options, meta) => {
|
|
74
|
-
if (Object.prototype.hasOwnProperty.call(msg.data, attribute)) {
|
|
75
|
-
const value = msg.data[attribute];
|
|
76
|
-
return {
|
|
77
|
-
external_switch_type: value_map[value] || "unknown",
|
|
78
|
-
external_switch_type_numeric: value,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
return undefined;
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
];
|
|
85
|
-
const toZigbee = [
|
|
86
|
-
{
|
|
87
|
-
key: ["external_switch_type"],
|
|
88
|
-
convertSet: async (entity, key, value, meta) => {
|
|
89
|
-
const numericValue = value_lookup[value] ?? Number.parseInt(value, 10);
|
|
90
|
-
await entity.write("genBasic", { [attribute]: { value: numericValue, type: data_type } }, { manufacturerCode: sunricherManufacturerCode });
|
|
91
|
-
return { state: { external_switch_type: value } };
|
|
92
|
-
},
|
|
93
|
-
convertGet: async (entity, key, meta) => {
|
|
94
|
-
await entity.read("genBasic", [attribute], {
|
|
95
|
-
manufacturerCode: sunricherManufacturerCode,
|
|
96
|
-
});
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
];
|
|
100
|
-
const exposes = [
|
|
101
|
-
e.enum("external_switch_type", ea.ALL, ["push_button", "normal_on_off", "three_way"]).withLabel("External switch type"),
|
|
102
|
-
];
|
|
103
|
-
const configure = [
|
|
104
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
105
|
-
const endpoint = device.getEndpoint(1);
|
|
106
|
-
try {
|
|
107
|
-
await endpoint.read("genBasic", [attribute], {
|
|
108
|
-
manufacturerCode: sunricherManufacturerCode,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
console.warn(`Failed to read external switch type attribute: ${error}`);
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
];
|
|
116
|
-
return {
|
|
117
|
-
fromZigbee,
|
|
118
|
-
toZigbee,
|
|
119
|
-
exposes,
|
|
120
|
-
configure,
|
|
121
|
-
isModernExtend: true,
|
|
122
|
-
};
|
|
123
|
-
},
|
|
124
|
-
minimumPWM: () => {
|
|
125
|
-
const attribute = 0x7809;
|
|
126
|
-
const data_type = 0x20;
|
|
127
|
-
const fromZigbee = [
|
|
128
|
-
{
|
|
129
|
-
cluster: "genBasic",
|
|
130
|
-
type: ["attributeReport", "readResponse"],
|
|
131
|
-
convert: (model, msg, publish, options, meta) => {
|
|
132
|
-
if (Object.prototype.hasOwnProperty.call(msg.data, attribute)) {
|
|
133
|
-
console.log("from ", msg.data[attribute]);
|
|
134
|
-
const value = Math.round(msg.data[attribute] / 5.1);
|
|
135
|
-
return {
|
|
136
|
-
minimum_pwm: value,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
return undefined;
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
];
|
|
143
|
-
const toZigbee = [
|
|
144
|
-
{
|
|
145
|
-
key: ["minimum_pwm"],
|
|
146
|
-
convertSet: async (entity, key, value, meta) => {
|
|
147
|
-
console.log("to ", value);
|
|
148
|
-
const numValue = typeof value === "string" ? Number.parseInt(value) : value;
|
|
149
|
-
const zgValue = Math.round(numValue * 5.1);
|
|
150
|
-
await entity.write("genBasic", { [attribute]: { value: zgValue, type: data_type } }, { manufacturerCode: sunricherManufacturerCode });
|
|
151
|
-
return { state: { minimum_pwm: numValue } };
|
|
152
|
-
},
|
|
153
|
-
convertGet: async (entity, key, meta) => {
|
|
154
|
-
await entity.read("genBasic", [attribute], {
|
|
155
|
-
manufacturerCode: sunricherManufacturerCode,
|
|
156
|
-
});
|
|
157
|
-
},
|
|
158
|
-
},
|
|
159
|
-
];
|
|
160
|
-
const exposes = [
|
|
161
|
-
e
|
|
162
|
-
.numeric("minimum_pwm", ea.ALL)
|
|
163
|
-
.withLabel("Minimum PWM")
|
|
164
|
-
.withDescription("Power off the device and wait for 3 seconds before reconnecting to apply the settings.")
|
|
165
|
-
.withValueMin(0)
|
|
166
|
-
.withValueMax(50)
|
|
167
|
-
.withUnit("%")
|
|
168
|
-
.withValueStep(1),
|
|
169
|
-
];
|
|
170
|
-
const configure = [
|
|
171
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
172
|
-
const endpoint = device.getEndpoint(1);
|
|
173
|
-
try {
|
|
174
|
-
await endpoint.read("genBasic", [attribute], {
|
|
175
|
-
manufacturerCode: sunricherManufacturerCode,
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
catch (error) {
|
|
179
|
-
console.warn(`Failed to read external switch type attribute: ${error}`);
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
];
|
|
183
|
-
return {
|
|
184
|
-
fromZigbee,
|
|
185
|
-
toZigbee,
|
|
186
|
-
exposes,
|
|
187
|
-
configure,
|
|
188
|
-
isModernExtend: true,
|
|
189
|
-
};
|
|
190
|
-
},
|
|
191
|
-
SRZG9002KR12Pro: () => {
|
|
192
|
-
const cluster = 0xff03;
|
|
193
|
-
const fromZigbee = [
|
|
194
|
-
{
|
|
195
|
-
cluster: 0xff03,
|
|
196
|
-
type: ["raw"],
|
|
197
|
-
convert: (model, msg, publish, options, meta) => {
|
|
198
|
-
const bytes = [...msg.data];
|
|
199
|
-
const messageType = bytes[3];
|
|
200
|
-
let action = "unknown";
|
|
201
|
-
if (messageType === 0x01) {
|
|
202
|
-
const pressTypeMask = bytes[6];
|
|
203
|
-
const pressTypeLookup = {
|
|
204
|
-
1: "short_press",
|
|
205
|
-
2: "double_press",
|
|
206
|
-
3: "hold",
|
|
207
|
-
4: "hold_released",
|
|
208
|
-
};
|
|
209
|
-
action = pressTypeLookup[pressTypeMask] || "unknown";
|
|
210
|
-
const buttonMask = (bytes[4] << 8) | bytes[5];
|
|
211
|
-
const specialButtonMap = {
|
|
212
|
-
9: "knob",
|
|
213
|
-
11: "k9",
|
|
214
|
-
12: "k10",
|
|
215
|
-
15: "k11",
|
|
216
|
-
16: "k12",
|
|
217
|
-
};
|
|
218
|
-
const actionButtons = [];
|
|
219
|
-
for (let i = 0; i < 16; i++) {
|
|
220
|
-
if ((buttonMask >> i) & 1) {
|
|
221
|
-
const button = i + 1;
|
|
222
|
-
actionButtons.push(specialButtonMap[button] ?? `k${button}`);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
return { action, action_buttons: actionButtons };
|
|
226
|
-
}
|
|
227
|
-
if (messageType === 0x03) {
|
|
228
|
-
const directionMask = bytes[4];
|
|
229
|
-
const actionSpeed = bytes[6];
|
|
230
|
-
const directionMap = {
|
|
231
|
-
1: "clockwise",
|
|
232
|
-
2: "anti_clockwise",
|
|
233
|
-
};
|
|
234
|
-
const direction = directionMap[directionMask] || "unknown";
|
|
235
|
-
action = `${direction}_rotation`;
|
|
236
|
-
return { action, action_speed: actionSpeed };
|
|
237
|
-
}
|
|
238
|
-
return { action };
|
|
239
|
-
},
|
|
240
|
-
},
|
|
241
|
-
];
|
|
242
|
-
const exposes = [
|
|
243
|
-
e.action(["short_press", "double_press", "hold", "hold_released", "clockwise_rotation", "anti_clockwise_rotation"]),
|
|
244
|
-
];
|
|
245
|
-
const configure = [
|
|
246
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
247
|
-
const endpoint = device.getEndpoint(1);
|
|
248
|
-
await endpoint.bind(cluster, coordinatorEndpoint);
|
|
249
|
-
},
|
|
250
|
-
];
|
|
251
|
-
return {
|
|
252
|
-
fromZigbee,
|
|
253
|
-
exposes,
|
|
254
|
-
configure,
|
|
255
|
-
isModernExtend: true,
|
|
256
|
-
};
|
|
257
|
-
},
|
|
258
|
-
SRZG2836D5Pro: () => {
|
|
259
|
-
const cluster = 0xff03;
|
|
260
|
-
const fromZigbee = [
|
|
261
|
-
{
|
|
262
|
-
cluster: 0xff03,
|
|
263
|
-
type: ["raw"],
|
|
264
|
-
convert: (model, msg, publish, options, meta) => {
|
|
265
|
-
const bytes = [...msg.data];
|
|
266
|
-
const messageType = bytes[3];
|
|
267
|
-
let action = "unknown";
|
|
268
|
-
if (messageType === 0x01) {
|
|
269
|
-
const pressTypeMask = bytes[6];
|
|
270
|
-
const pressTypeLookup = {
|
|
271
|
-
1: "short_press",
|
|
272
|
-
2: "double_press",
|
|
273
|
-
3: "hold",
|
|
274
|
-
4: "hold_released",
|
|
275
|
-
};
|
|
276
|
-
action = pressTypeLookup[pressTypeMask] || "unknown";
|
|
277
|
-
const buttonMask = bytes[5];
|
|
278
|
-
const specialButtonLookup = {
|
|
279
|
-
1: "top_left",
|
|
280
|
-
2: "top_right",
|
|
281
|
-
3: "bottom_left",
|
|
282
|
-
4: "bottom_right",
|
|
283
|
-
5: "center",
|
|
284
|
-
};
|
|
285
|
-
const actionButtons = [];
|
|
286
|
-
for (let i = 0; i < 5; i++) {
|
|
287
|
-
if ((buttonMask >> i) & 1) {
|
|
288
|
-
const button = i + 1;
|
|
289
|
-
actionButtons.push(specialButtonLookup[button] || `unknown_${button}`);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
return { action, action_buttons: actionButtons };
|
|
293
|
-
}
|
|
294
|
-
if (messageType === 0x03) {
|
|
295
|
-
const directionMask = bytes[4];
|
|
296
|
-
const actionSpeed = bytes[6];
|
|
297
|
-
const isStop = bytes[5] === 0x02;
|
|
298
|
-
const directionMap = {
|
|
299
|
-
1: "clockwise",
|
|
300
|
-
2: "anti_clockwise",
|
|
301
|
-
};
|
|
302
|
-
const direction = isStop ? "stop" : directionMap[directionMask] || "unknown";
|
|
303
|
-
action = `${direction}_rotation`;
|
|
304
|
-
return { action, action_speed: actionSpeed };
|
|
305
|
-
}
|
|
306
|
-
return { action };
|
|
307
|
-
},
|
|
308
|
-
},
|
|
309
|
-
];
|
|
310
|
-
const exposes = [
|
|
311
|
-
e.action(["short_press", "double_press", "hold", "hold_released", "clockwise_rotation", "anti_clockwise_rotation", "stop_rotation"]),
|
|
312
|
-
];
|
|
313
|
-
const configure = [
|
|
314
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
315
|
-
const endpoint = device.getEndpoint(1);
|
|
316
|
-
await endpoint.bind(cluster, coordinatorEndpoint);
|
|
317
|
-
},
|
|
318
|
-
];
|
|
319
|
-
return {
|
|
320
|
-
fromZigbee,
|
|
321
|
-
exposes,
|
|
322
|
-
configure,
|
|
323
|
-
isModernExtend: true,
|
|
324
|
-
};
|
|
325
|
-
},
|
|
326
|
-
SRZG9002K16Pro: () => {
|
|
327
|
-
const cluster = 0xff03;
|
|
328
|
-
const fromZigbee = [
|
|
329
|
-
{
|
|
330
|
-
cluster,
|
|
331
|
-
type: ["raw"],
|
|
332
|
-
convert: (model, msg, publish, options, meta) => {
|
|
333
|
-
const bytes = [...msg.data];
|
|
334
|
-
const messageType = bytes[3];
|
|
335
|
-
let action = "unknown";
|
|
336
|
-
if (messageType === 0x01) {
|
|
337
|
-
const pressTypeMask = bytes[6];
|
|
338
|
-
const pressTypeLookup = {
|
|
339
|
-
1: "short_press",
|
|
340
|
-
2: "double_press",
|
|
341
|
-
3: "hold",
|
|
342
|
-
4: "hold_released",
|
|
343
|
-
};
|
|
344
|
-
action = pressTypeLookup[pressTypeMask] || "unknown";
|
|
345
|
-
const buttonMask = (bytes[4] << 8) | bytes[5];
|
|
346
|
-
const getButtonNumber = (input) => {
|
|
347
|
-
const row = Math.floor((input - 1) / 4);
|
|
348
|
-
const col = (input - 1) % 4;
|
|
349
|
-
return col * 4 + row + 1;
|
|
350
|
-
};
|
|
351
|
-
const actionButtons = [];
|
|
352
|
-
for (let i = 0; i < 16; i++) {
|
|
353
|
-
if ((buttonMask >> i) & 1) {
|
|
354
|
-
const button = i + 1;
|
|
355
|
-
actionButtons.push(`k${getButtonNumber(button)}`);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
return { action, action_buttons: actionButtons };
|
|
359
|
-
}
|
|
360
|
-
return { action };
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
];
|
|
364
|
-
const exposes = [e.action(["short_press", "double_press", "hold", "hold_released"])];
|
|
365
|
-
const configure = [
|
|
366
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
367
|
-
const endpoint = device.getEndpoint(1);
|
|
368
|
-
await endpoint.bind(cluster, coordinatorEndpoint);
|
|
369
|
-
},
|
|
370
|
-
];
|
|
371
|
-
return {
|
|
372
|
-
fromZigbee,
|
|
373
|
-
exposes,
|
|
374
|
-
configure,
|
|
375
|
-
isModernExtend: true,
|
|
376
|
-
};
|
|
377
|
-
},
|
|
378
|
-
indicatorLight() {
|
|
379
|
-
const cluster = 0xfc8b;
|
|
380
|
-
const attribute = 0xf001;
|
|
381
|
-
const data_type = 0x20;
|
|
382
|
-
const manufacturerCode = 0x120b;
|
|
383
|
-
const exposes = [
|
|
384
|
-
e.enum("indicator_light", ea.ALL, ["on", "off"]).withDescription("Enable/disable the LED indicator").withCategory("config"),
|
|
385
|
-
];
|
|
386
|
-
const fromZigbee = [
|
|
387
|
-
{
|
|
388
|
-
cluster,
|
|
389
|
-
type: ["attributeReport", "readResponse"],
|
|
390
|
-
convert: (model, msg, publish, options, meta) => {
|
|
391
|
-
if (!Object.prototype.hasOwnProperty.call(msg.data, attribute))
|
|
392
|
-
return;
|
|
393
|
-
const indicatorLight = msg.data[attribute];
|
|
394
|
-
const firstBit = indicatorLight & 0x01;
|
|
395
|
-
return { indicator_light: firstBit === 1 ? "on" : "off" };
|
|
396
|
-
},
|
|
397
|
-
},
|
|
398
|
-
];
|
|
399
|
-
const toZigbee = [
|
|
400
|
-
{
|
|
401
|
-
key: ["indicator_light"],
|
|
402
|
-
convertSet: async (entity, key, value, meta) => {
|
|
403
|
-
const attributeRead = await entity.read(cluster, [attribute]);
|
|
404
|
-
if (attributeRead === undefined)
|
|
405
|
-
return;
|
|
406
|
-
// @ts-expect-error ignore
|
|
407
|
-
const currentValue = attributeRead[attribute];
|
|
408
|
-
const newValue = value === "on" ? currentValue | 0x01 : currentValue & ~0x01;
|
|
409
|
-
await entity.write(cluster, { [attribute]: { value: newValue, type: data_type } }, { manufacturerCode });
|
|
410
|
-
return { state: { indicator_light: value } };
|
|
411
|
-
},
|
|
412
|
-
convertGet: async (entity, key, meta) => {
|
|
413
|
-
await entity.read(cluster, [attribute], { manufacturerCode });
|
|
414
|
-
},
|
|
415
|
-
},
|
|
416
|
-
];
|
|
417
|
-
const configure = [
|
|
418
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
419
|
-
const endpoint = device.getEndpoint(1);
|
|
420
|
-
await endpoint.bind(cluster, coordinatorEndpoint);
|
|
421
|
-
await endpoint.read(cluster, [attribute], { manufacturerCode });
|
|
422
|
-
},
|
|
423
|
-
];
|
|
424
|
-
return {
|
|
425
|
-
exposes,
|
|
426
|
-
configure,
|
|
427
|
-
fromZigbee,
|
|
428
|
-
toZigbee,
|
|
429
|
-
isModernExtend: true,
|
|
430
|
-
};
|
|
431
|
-
},
|
|
432
|
-
thermostatWeeklySchedule: () => {
|
|
433
|
-
const exposes = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"].map((day) => e
|
|
434
|
-
.text(`schedule_${day}`, ea.ALL)
|
|
435
|
-
.withDescription(`Schedule for ${day.charAt(0).toUpperCase() + day.slice(1)}, example: "06:00/21.0 12:00/21.0 18:00/21.0 22:00/16.0"`)
|
|
436
|
-
.withCategory("config"));
|
|
437
|
-
const fromZigbee = [
|
|
438
|
-
{
|
|
439
|
-
cluster: "hvacThermostat",
|
|
440
|
-
type: ["commandGetWeeklyScheduleRsp"],
|
|
441
|
-
convert: (model, msg, publish, options, meta) => {
|
|
442
|
-
const day = Object.entries(constants.thermostatDayOfWeek).find((d) => msg.data.dayofweek & (1 << +d[0]))[1];
|
|
443
|
-
const transitions = msg.data.transitions
|
|
444
|
-
.map((t) => {
|
|
445
|
-
const hours = Math.floor(t.transitionTime / 60);
|
|
446
|
-
const minutes = t.transitionTime % 60;
|
|
447
|
-
return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}/${t.heatSetpoint / 100}`;
|
|
448
|
-
})
|
|
449
|
-
.sort()
|
|
450
|
-
.join(" ");
|
|
451
|
-
return {
|
|
452
|
-
...meta.state.weekly_schedule,
|
|
453
|
-
[`schedule_${day}`]: transitions,
|
|
454
|
-
};
|
|
455
|
-
},
|
|
456
|
-
},
|
|
457
|
-
];
|
|
458
|
-
const toZigbee = [
|
|
459
|
-
{
|
|
460
|
-
key: [
|
|
461
|
-
"schedule_sunday",
|
|
462
|
-
"schedule_monday",
|
|
463
|
-
"schedule_tuesday",
|
|
464
|
-
"schedule_wednesday",
|
|
465
|
-
"schedule_thursday",
|
|
466
|
-
"schedule_friday",
|
|
467
|
-
"schedule_saturday",
|
|
468
|
-
],
|
|
469
|
-
convertSet: async (entity, key, value, meta) => {
|
|
470
|
-
const transitionRegex = /^(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])\/(\d+(\.\d+)?)$/;
|
|
471
|
-
const dayOfWeekName = key.replace("schedule_", "");
|
|
472
|
-
utils.assertString(value, dayOfWeekName);
|
|
473
|
-
const dayKey = utils.getKey(constants.thermostatDayOfWeek, dayOfWeekName.toLowerCase(), null);
|
|
474
|
-
if (!dayKey)
|
|
475
|
-
throw new Error(`Invalid schedule: invalid day name, found: ${dayOfWeekName}`);
|
|
476
|
-
const transitions = value.split(" ").sort();
|
|
477
|
-
if (transitions.length !== 4) {
|
|
478
|
-
throw new Error("Invalid schedule: days must have exactly 4 transitions");
|
|
479
|
-
}
|
|
480
|
-
const payload = {
|
|
481
|
-
dayofweek: 1 << Number(dayKey),
|
|
482
|
-
numoftrans: transitions.length,
|
|
483
|
-
mode: 1 << 0,
|
|
484
|
-
transitions: transitions.map((transition) => {
|
|
485
|
-
const matches = transition.match(transitionRegex);
|
|
486
|
-
if (!matches) {
|
|
487
|
-
throw new Error(`Invalid schedule: transitions must be in format HH:mm/temperature (e.g. 12:00/15.5), found: ${transition}`);
|
|
488
|
-
}
|
|
489
|
-
const [, hours, minutes, temp] = matches;
|
|
490
|
-
const temperature = Number.parseFloat(temp);
|
|
491
|
-
if (temperature < 4 || temperature > 35) {
|
|
492
|
-
throw new Error(`Invalid schedule: temperature value must be between 4-35 (inclusive), found: ${temperature}`);
|
|
493
|
-
}
|
|
494
|
-
return {
|
|
495
|
-
transitionTime: Number.parseInt(hours) * 60 + Number.parseInt(minutes),
|
|
496
|
-
heatSetpoint: Math.round(temperature * 100),
|
|
497
|
-
};
|
|
498
|
-
}),
|
|
499
|
-
};
|
|
500
|
-
await entity.command("hvacThermostat", "setWeeklySchedule", payload, utils.getOptions(meta.mapped, entity));
|
|
501
|
-
},
|
|
502
|
-
convertGet: async (entity, key, meta) => {
|
|
503
|
-
const dayOfWeekName = key.replace("schedule_", "");
|
|
504
|
-
const dayKey = utils.getKey(constants.thermostatDayOfWeek, dayOfWeekName.toLowerCase(), null);
|
|
505
|
-
await entity.command("hvacThermostat", "getWeeklySchedule", {
|
|
506
|
-
daystoreturn: dayKey !== null ? 1 << Number(dayKey) : 0xff,
|
|
507
|
-
modetoreturn: 1,
|
|
508
|
-
}, utils.getOptions(meta.mapped, entity));
|
|
509
|
-
},
|
|
510
|
-
},
|
|
511
|
-
];
|
|
512
|
-
const configure = [
|
|
513
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
514
|
-
const endpoint = device.getEndpoint(1);
|
|
515
|
-
await endpoint.command("hvacThermostat", "getWeeklySchedule", {
|
|
516
|
-
daystoreturn: 0xff,
|
|
517
|
-
modetoreturn: 1,
|
|
518
|
-
});
|
|
519
|
-
},
|
|
520
|
-
];
|
|
521
|
-
return { exposes, fromZigbee, toZigbee, configure, isModernExtend: true };
|
|
522
|
-
},
|
|
523
|
-
thermostatChildLock: () => {
|
|
524
|
-
const exposes = [e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device")];
|
|
525
|
-
const fromZigbee = [
|
|
526
|
-
{
|
|
527
|
-
cluster: "hvacUserInterfaceCfg",
|
|
528
|
-
type: ["attributeReport", "readResponse"],
|
|
529
|
-
convert: (model, msg, publish, options, meta) => {
|
|
530
|
-
if (Object.hasOwn(msg.data, "keypadLockout")) {
|
|
531
|
-
return {
|
|
532
|
-
child_lock: msg.data.keypadLockout === 0 ? "UNLOCK" : "LOCK",
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
return {};
|
|
536
|
-
},
|
|
537
|
-
},
|
|
538
|
-
];
|
|
539
|
-
const toZigbee = [
|
|
540
|
-
{
|
|
541
|
-
key: ["child_lock"],
|
|
542
|
-
convertSet: async (entity, key, value, meta) => {
|
|
543
|
-
const keypadLockout = Number(value === "LOCK");
|
|
544
|
-
await entity.write("hvacUserInterfaceCfg", { keypadLockout });
|
|
545
|
-
return { state: { child_lock: value } };
|
|
546
|
-
},
|
|
547
|
-
convertGet: async (entity, key, meta) => {
|
|
548
|
-
await entity.read("hvacUserInterfaceCfg", ["keypadLockout"]);
|
|
549
|
-
},
|
|
550
|
-
},
|
|
551
|
-
];
|
|
552
|
-
const configure = [
|
|
553
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
554
|
-
const endpoint = device.getEndpoint(1);
|
|
555
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ["hvacUserInterfaceCfg"]);
|
|
556
|
-
await endpoint.read("hvacUserInterfaceCfg", ["keypadLockout"]);
|
|
557
|
-
await reporting.thermostatKeypadLockMode(endpoint);
|
|
558
|
-
},
|
|
559
|
-
];
|
|
560
|
-
return { exposes, fromZigbee, toZigbee, configure, isModernExtend: true };
|
|
561
|
-
},
|
|
562
|
-
thermostatPreset: () => {
|
|
563
|
-
const systemModeLookup = {
|
|
564
|
-
0: "off",
|
|
565
|
-
1: "auto",
|
|
566
|
-
3: "cool",
|
|
567
|
-
4: "manual",
|
|
568
|
-
5: "emergency_heating",
|
|
569
|
-
6: "precooling",
|
|
570
|
-
7: "fan_only",
|
|
571
|
-
8: "dry",
|
|
572
|
-
9: "sleep",
|
|
573
|
-
};
|
|
574
|
-
const awayOrBoostModeLookup = { 0: "normal", 1: "away", 2: "forced" };
|
|
575
|
-
const fromZigbee = [
|
|
576
|
-
{
|
|
577
|
-
cluster: "hvacThermostat",
|
|
578
|
-
type: ["attributeReport", "readResponse"],
|
|
579
|
-
convert: (model, msg, publish, options, meta) => {
|
|
580
|
-
if (!Object.hasOwn(msg.data, "systemMode") && !Object.hasOwn(msg.data, "awayOrBoostMode"))
|
|
581
|
-
return;
|
|
582
|
-
const systemMode = msg.data.systemMode ?? globalStore.getValue(msg.device, "systemMode");
|
|
583
|
-
const awayOrBoostMode = msg.data.awayOrBoostMode ?? globalStore.getValue(msg.device, "awayOrBoostMode");
|
|
584
|
-
globalStore.putValue(msg.device, "systemMode", systemMode);
|
|
585
|
-
globalStore.putValue(msg.device, "awayOrBoostMode", awayOrBoostMode);
|
|
586
|
-
const result = {};
|
|
587
|
-
if (awayOrBoostMode !== undefined && awayOrBoostMode !== 0) {
|
|
588
|
-
result.preset = utils.getFromLookup(awayOrBoostMode, awayOrBoostModeLookup);
|
|
589
|
-
result.away_or_boost_mode = utils.getFromLookup(awayOrBoostMode, awayOrBoostModeLookup);
|
|
590
|
-
if (systemMode !== undefined) {
|
|
591
|
-
result.system_mode = constants.thermostatSystemModes[systemMode];
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
else if (systemMode !== undefined) {
|
|
595
|
-
result.preset = utils.getFromLookup(systemMode, systemModeLookup);
|
|
596
|
-
result.system_mode = constants.thermostatSystemModes[systemMode];
|
|
597
|
-
if (awayOrBoostMode !== undefined) {
|
|
598
|
-
result.away_or_boost_mode = utils.getFromLookup(awayOrBoostMode, awayOrBoostModeLookup);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
return result;
|
|
602
|
-
},
|
|
603
|
-
},
|
|
604
|
-
];
|
|
605
|
-
const toZigbee = [
|
|
606
|
-
{
|
|
607
|
-
key: ["preset"],
|
|
608
|
-
convertSet: async (entity, key, value, meta) => {
|
|
609
|
-
if (value === "away" || value === "forced") {
|
|
610
|
-
const awayOrBoostMode = value === "away" ? 1 : 2;
|
|
611
|
-
globalStore.putValue(entity, "awayOrBoostMode", awayOrBoostMode);
|
|
612
|
-
if (value === "away") {
|
|
613
|
-
await entity.read("hvacThermostat", ["unoccupiedHeatingSetpoint"]);
|
|
614
|
-
}
|
|
615
|
-
await entity.write("hvacThermostat", { awayOrBoostMode });
|
|
616
|
-
return { state: { preset: value, away_or_boost_mode: value } };
|
|
617
|
-
}
|
|
618
|
-
globalStore.putValue(entity, "awayOrBoostMode", 0);
|
|
619
|
-
const systemMode = utils.getKey(systemModeLookup, value, undefined, Number);
|
|
620
|
-
await entity.write("hvacThermostat", { systemMode });
|
|
621
|
-
if (typeof systemMode === "number") {
|
|
622
|
-
return {
|
|
623
|
-
state: {
|
|
624
|
-
// @ts-expect-error ignore
|
|
625
|
-
preset: systemModeLookup[systemMode],
|
|
626
|
-
system_mode: constants.thermostatSystemModes[systemMode],
|
|
627
|
-
},
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
},
|
|
631
|
-
},
|
|
632
|
-
{
|
|
633
|
-
key: ["system_mode"],
|
|
634
|
-
convertSet: async (entity, key, value, meta) => {
|
|
635
|
-
const systemMode = utils.getKey(constants.thermostatSystemModes, value, undefined, Number);
|
|
636
|
-
if (systemMode === undefined || typeof systemMode !== "number") {
|
|
637
|
-
throw new Error(`Invalid system mode: ${value}`);
|
|
638
|
-
}
|
|
639
|
-
await entity.write("hvacThermostat", { systemMode });
|
|
640
|
-
return {
|
|
641
|
-
state: {
|
|
642
|
-
// @ts-expect-error ignore
|
|
643
|
-
preset: systemModeLookup[systemMode],
|
|
644
|
-
system_mode: constants.thermostatSystemModes[systemMode],
|
|
645
|
-
},
|
|
646
|
-
};
|
|
647
|
-
},
|
|
648
|
-
convertGet: async (entity, key, meta) => {
|
|
649
|
-
await entity.read("hvacThermostat", ["systemMode"]);
|
|
650
|
-
},
|
|
651
|
-
},
|
|
652
|
-
];
|
|
653
|
-
const configure = [
|
|
654
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
655
|
-
const endpoint = device.getEndpoint(1);
|
|
656
|
-
await endpoint.read("hvacThermostat", ["systemMode"]);
|
|
657
|
-
await endpoint.read("hvacThermostat", ["awayOrBoostMode"]);
|
|
658
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ["hvacThermostat"]);
|
|
659
|
-
await reporting.thermostatSystemMode(endpoint);
|
|
660
|
-
await endpoint.configureReporting("hvacThermostat", (0, reporting_1.payload)("awayOrBoostMode", 10, constants_1.repInterval.HOUR, null));
|
|
661
|
-
},
|
|
662
|
-
];
|
|
663
|
-
return { fromZigbee, toZigbee, configure, isModernExtend: true };
|
|
664
|
-
},
|
|
665
|
-
thermostatCurrentHeatingSetpoint: () => {
|
|
666
|
-
const getAwayOrBoostMode = async (entity) => {
|
|
667
|
-
let result = globalStore.getValue(entity, "awayOrBoostMode");
|
|
668
|
-
if (result === undefined) {
|
|
669
|
-
const attributeRead = await entity.read("hvacThermostat", ["awayOrBoostMode"]);
|
|
670
|
-
// @ts-expect-error ignore
|
|
671
|
-
result = attributeRead.awayOrBoostMode;
|
|
672
|
-
globalStore.putValue(entity, "awayOrBoostMode", result);
|
|
673
|
-
}
|
|
674
|
-
return result;
|
|
675
|
-
};
|
|
676
|
-
const fromZigbee = [
|
|
677
|
-
{
|
|
678
|
-
cluster: "hvacThermostat",
|
|
679
|
-
type: ["attributeReport", "readResponse"],
|
|
680
|
-
convert: async (model, msg, publish, options, meta) => {
|
|
681
|
-
const hasHeatingSetpoints = Object.hasOwn(msg.data, "occupiedHeatingSetpoint") || Object.hasOwn(msg.data, "unoccupiedHeatingSetpoint");
|
|
682
|
-
if (!hasHeatingSetpoints)
|
|
683
|
-
return;
|
|
684
|
-
const processSetpoint = (value) => {
|
|
685
|
-
if (value === undefined)
|
|
686
|
-
return undefined;
|
|
687
|
-
return (0, utils_1.precisionRound)(value, 2) / 100;
|
|
688
|
-
};
|
|
689
|
-
const occupiedSetpoint = processSetpoint(msg.data.occupiedHeatingSetpoint);
|
|
690
|
-
const unoccupiedSetpoint = processSetpoint(msg.data.unoccupiedHeatingSetpoint);
|
|
691
|
-
const awayOrBoostMode = msg.data.awayOrBoostMode ?? (await getAwayOrBoostMode(msg.device.getEndpoint(1)));
|
|
692
|
-
const result = {};
|
|
693
|
-
if (awayOrBoostMode === 1 && unoccupiedSetpoint !== undefined) {
|
|
694
|
-
result.current_heating_setpoint = unoccupiedSetpoint;
|
|
695
|
-
}
|
|
696
|
-
else if (occupiedSetpoint !== undefined) {
|
|
697
|
-
result.current_heating_setpoint = occupiedSetpoint;
|
|
698
|
-
}
|
|
699
|
-
return result;
|
|
700
|
-
},
|
|
701
|
-
},
|
|
702
|
-
];
|
|
703
|
-
const toZigbee = [
|
|
704
|
-
{
|
|
705
|
-
key: ["current_heating_setpoint"],
|
|
706
|
-
convertSet: async (entity, key, value, meta) => {
|
|
707
|
-
utils.assertNumber(value, key);
|
|
708
|
-
const awayOrBoostMode = await getAwayOrBoostMode(entity);
|
|
709
|
-
let convertedValue;
|
|
710
|
-
if (meta.options.thermostat_unit === "fahrenheit") {
|
|
711
|
-
convertedValue = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
|
|
712
|
-
}
|
|
713
|
-
else {
|
|
714
|
-
convertedValue = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
|
|
715
|
-
}
|
|
716
|
-
const attribute = awayOrBoostMode === 1 ? "unoccupiedHeatingSetpoint" : "occupiedHeatingSetpoint";
|
|
717
|
-
await entity.write("hvacThermostat", { [attribute]: convertedValue });
|
|
718
|
-
return { state: { current_heating_setpoint: value } };
|
|
719
|
-
},
|
|
720
|
-
convertGet: async (entity, key, meta) => {
|
|
721
|
-
await entity.read("hvacThermostat", ["occupiedHeatingSetpoint", "unoccupiedHeatingSetpoint"]);
|
|
722
|
-
},
|
|
723
|
-
},
|
|
724
|
-
];
|
|
725
|
-
const configure = [
|
|
726
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
727
|
-
const endpoint = device.getEndpoint(1);
|
|
728
|
-
await endpoint.read("hvacThermostat", ["occupiedHeatingSetpoint", "unoccupiedHeatingSetpoint"]);
|
|
729
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ["hvacThermostat"]);
|
|
730
|
-
await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
|
|
731
|
-
await reporting.thermostatUnoccupiedHeatingSetpoint(endpoint);
|
|
732
|
-
},
|
|
733
|
-
];
|
|
734
|
-
return { fromZigbee, toZigbee, configure, isModernExtend: true };
|
|
735
|
-
},
|
|
736
|
-
SRZG2856Pro: () => {
|
|
737
|
-
const fromZigbee = [
|
|
738
|
-
{
|
|
739
|
-
cluster: "sunricherRemote",
|
|
740
|
-
type: ["commandPress"],
|
|
741
|
-
convert: (model, msg, publish, options, meta) => {
|
|
742
|
-
let action = "unknown";
|
|
743
|
-
if (msg.data.messageType === 0x01) {
|
|
744
|
-
const pressTypeLookup = {
|
|
745
|
-
1: "short_press",
|
|
746
|
-
2: "double_press",
|
|
747
|
-
3: "hold",
|
|
748
|
-
4: "hold_released",
|
|
749
|
-
};
|
|
750
|
-
action = pressTypeLookup[msg.data.pressType] || "unknown";
|
|
751
|
-
const buttonMask = (msg.data.button2 << 8) | msg.data.button1;
|
|
752
|
-
const actionButtons = [];
|
|
753
|
-
for (let i = 0; i < 16; i++) {
|
|
754
|
-
if ((buttonMask >> i) & 1) {
|
|
755
|
-
const button = i + 1;
|
|
756
|
-
actionButtons.push(`k${button}`);
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
return { action, action_buttons: actionButtons };
|
|
760
|
-
}
|
|
761
|
-
return { action };
|
|
762
|
-
},
|
|
763
|
-
},
|
|
764
|
-
];
|
|
765
|
-
const exposes = [e.action(["short_press", "double_press", "hold", "hold_released"])];
|
|
766
|
-
const configure = [
|
|
767
|
-
async (device, coordinatorEndpoint, definition) => {
|
|
768
|
-
const endpoint = device.getEndpoint(1);
|
|
769
|
-
await endpoint.bind("sunricherRemote", coordinatorEndpoint);
|
|
770
|
-
},
|
|
771
|
-
];
|
|
772
|
-
return {
|
|
773
|
-
fromZigbee,
|
|
774
|
-
exposes,
|
|
775
|
-
configure,
|
|
776
|
-
isModernExtend: true,
|
|
777
|
-
};
|
|
778
|
-
},
|
|
779
|
-
};
|
|
780
54
|
const fzLocal = {
|
|
781
|
-
|
|
55
|
+
SRZGP2801K45C: {
|
|
782
56
|
cluster: "greenPower",
|
|
783
57
|
type: ["commandNotification", "commandCommissioningNotification"],
|
|
784
58
|
convert: (model, msg, publish, options, meta) => {
|
|
@@ -850,7 +124,7 @@ exports.definitions = [
|
|
|
850
124
|
},
|
|
851
125
|
commandsResponse: {},
|
|
852
126
|
}),
|
|
853
|
-
|
|
127
|
+
sunricher.extend.SRZG2856Pro(),
|
|
854
128
|
],
|
|
855
129
|
},
|
|
856
130
|
{
|
|
@@ -911,8 +185,8 @@ exports.definitions = [
|
|
|
911
185
|
commands: {},
|
|
912
186
|
commandsResponse: {},
|
|
913
187
|
}),
|
|
914
|
-
|
|
915
|
-
|
|
188
|
+
sunricher.extend.thermostatPreset(),
|
|
189
|
+
sunricher.extend.thermostatCurrentHeatingSetpoint(),
|
|
916
190
|
m.battery(),
|
|
917
191
|
m.identify(),
|
|
918
192
|
m.numeric({
|
|
@@ -1015,8 +289,8 @@ exports.definitions = [
|
|
|
1015
289
|
access: "ALL",
|
|
1016
290
|
entityCategory: "config",
|
|
1017
291
|
}),
|
|
1018
|
-
|
|
1019
|
-
|
|
292
|
+
sunricher.extend.thermostatWeeklySchedule(),
|
|
293
|
+
sunricher.extend.thermostatChildLock(),
|
|
1020
294
|
],
|
|
1021
295
|
fromZigbee: [fz.thermostat],
|
|
1022
296
|
toZigbee: [
|
|
@@ -1131,7 +405,7 @@ exports.definitions = [
|
|
|
1131
405
|
commands: {},
|
|
1132
406
|
commandsResponse: {},
|
|
1133
407
|
}),
|
|
1134
|
-
|
|
408
|
+
sunricher.extend.indicatorLight(),
|
|
1135
409
|
m.numeric({
|
|
1136
410
|
name: "detection_area",
|
|
1137
411
|
cluster: "sunricherSensor",
|
|
@@ -1218,7 +492,7 @@ exports.definitions = [
|
|
|
1218
492
|
model: "SR-ZG2835RAC-UK",
|
|
1219
493
|
vendor: "Sunricher",
|
|
1220
494
|
description: "Push compatible zigBee knob smart dimmer",
|
|
1221
|
-
extend: [m.light(), m.electricityMeter(),
|
|
495
|
+
extend: [m.light(), m.electricityMeter(), sunricher.extend.externalSwitchType()],
|
|
1222
496
|
},
|
|
1223
497
|
{
|
|
1224
498
|
zigbeeModel: ["ZG2837RAC-K4"],
|
|
@@ -1294,7 +568,7 @@ exports.definitions = [
|
|
|
1294
568
|
model: "SR-ZG9002K16-Pro",
|
|
1295
569
|
vendor: "Sunricher",
|
|
1296
570
|
description: "Zigbee smart wall panel remote",
|
|
1297
|
-
extend: [m.battery(),
|
|
571
|
+
extend: [m.battery(), sunricher.extend.SRZG9002K16Pro()],
|
|
1298
572
|
},
|
|
1299
573
|
{
|
|
1300
574
|
zigbeeModel: ["ZG9030A-MW"],
|
|
@@ -1507,14 +781,14 @@ exports.definitions = [
|
|
|
1507
781
|
model: "SR-ZG2836D5-Pro",
|
|
1508
782
|
vendor: "Sunricher",
|
|
1509
783
|
description: "Zigbee smart remote",
|
|
1510
|
-
extend: [m.battery(),
|
|
784
|
+
extend: [m.battery(), sunricher.extend.SRZG2836D5Pro()],
|
|
1511
785
|
},
|
|
1512
786
|
{
|
|
1513
787
|
zigbeeModel: ["HK-ZRC-K12&RS-E"],
|
|
1514
788
|
model: "SR-ZG9002KR12-Pro",
|
|
1515
789
|
vendor: "Sunricher",
|
|
1516
790
|
description: "Zigbee smart wall panel remote",
|
|
1517
|
-
extend: [m.battery(),
|
|
791
|
+
extend: [m.battery(), sunricher.extend.SRZG9002KR12Pro()],
|
|
1518
792
|
},
|
|
1519
793
|
{
|
|
1520
794
|
zigbeeModel: ["ZV9380A", "ZG9380A"],
|
|
@@ -1528,14 +802,14 @@ exports.definitions = [
|
|
|
1528
802
|
model: "SR-ZG2835PAC-AU",
|
|
1529
803
|
vendor: "Sunricher",
|
|
1530
804
|
description: "Zigbee push button smart dimmer",
|
|
1531
|
-
extend: [m.light({ configureReporting: true }),
|
|
805
|
+
extend: [m.light({ configureReporting: true }), sunricher.extend.externalSwitchType(), m.electricityMeter()],
|
|
1532
806
|
},
|
|
1533
807
|
{
|
|
1534
808
|
zigbeeModel: ["HK-SL-DIM-CLN"],
|
|
1535
809
|
model: "SR-ZG9101SAC-HP-CLN",
|
|
1536
810
|
vendor: "Sunricher",
|
|
1537
811
|
description: "Zigbee micro smart dimmer",
|
|
1538
|
-
extend: [m.light({ configureReporting: true }),
|
|
812
|
+
extend: [m.light({ configureReporting: true }), sunricher.extend.externalSwitchType(), sunricher.extend.minimumPWM()],
|
|
1539
813
|
},
|
|
1540
814
|
{
|
|
1541
815
|
zigbeeModel: ["HK-SENSOR-CT-MINI"],
|
|
@@ -1807,7 +1081,7 @@ exports.definitions = [
|
|
|
1807
1081
|
model: "ZG9101SAC-HP-Switch",
|
|
1808
1082
|
vendor: "Sunricher",
|
|
1809
1083
|
description: "Zigbee AC in wall switch",
|
|
1810
|
-
extend: [m.onOff({ powerOnBehavior: false }),
|
|
1084
|
+
extend: [m.onOff({ powerOnBehavior: false }), sunricher.extend.externalSwitchType()],
|
|
1811
1085
|
},
|
|
1812
1086
|
{
|
|
1813
1087
|
zigbeeModel: ["Micro Smart Dimmer", "SM311", "HK-SL-RDIM-A", "HK-SL-DIM-EU-A"],
|
|
@@ -1841,7 +1115,7 @@ exports.definitions = [
|
|
|
1841
1115
|
model: "SR-ZG9040A/ZG9041A-D",
|
|
1842
1116
|
vendor: "Sunricher",
|
|
1843
1117
|
description: "Zigbee micro smart dimmer",
|
|
1844
|
-
extend: [m.light({ configureReporting: true }), m.electricityMeter(),
|
|
1118
|
+
extend: [m.light({ configureReporting: true }), m.electricityMeter(), sunricher.extend.externalSwitchType(), sunricher.extend.minimumPWM()],
|
|
1845
1119
|
},
|
|
1846
1120
|
{
|
|
1847
1121
|
zigbeeModel: ["HK-ZD-DIM-A"],
|
|
@@ -1969,7 +1243,7 @@ exports.definitions = [
|
|
|
1969
1243
|
model: "SR-ZGP2801K-5C",
|
|
1970
1244
|
vendor: "Sunricher",
|
|
1971
1245
|
description: "Pushbutton transmitter module",
|
|
1972
|
-
fromZigbee: [fzLocal.
|
|
1246
|
+
fromZigbee: [fzLocal.SRZGP2801K45C],
|
|
1973
1247
|
toZigbee: [],
|
|
1974
1248
|
exposes: [
|
|
1975
1249
|
e.action([
|
|
@@ -2068,7 +1342,7 @@ exports.definitions = [
|
|
|
2068
1342
|
.withValueMax(60)
|
|
2069
1343
|
.withDescription("Room temperature alarm threshold, between 20 and 60 in °C. 0 means disabled. Default: 45."),
|
|
2070
1344
|
],
|
|
2071
|
-
onEvent:
|
|
1345
|
+
onEvent: (type, data, device, options) => {
|
|
2072
1346
|
if (type === "stop") {
|
|
2073
1347
|
clearInterval(globalStore.getValue(device, "time"));
|
|
2074
1348
|
globalStore.clearValue(device, "time");
|