zigbee-herdsman-converters 25.28.0 → 25.30.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.
Files changed (74) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/converters/toZigbee.d.ts.map +1 -1
  3. package/dist/converters/toZigbee.js +16 -16
  4. package/dist/converters/toZigbee.js.map +1 -1
  5. package/dist/devices/adeo.d.ts.map +1 -1
  6. package/dist/devices/adeo.js +7 -0
  7. package/dist/devices/adeo.js.map +1 -1
  8. package/dist/devices/bacchus.d.ts.map +1 -1
  9. package/dist/devices/bacchus.js +7 -9
  10. package/dist/devices/bacchus.js.map +1 -1
  11. package/dist/devices/bosch.d.ts.map +1 -1
  12. package/dist/devices/bosch.js +71 -140
  13. package/dist/devices/bosch.js.map +1 -1
  14. package/dist/devices/eurotronic.d.ts.map +1 -1
  15. package/dist/devices/eurotronic.js +1 -0
  16. package/dist/devices/eurotronic.js.map +1 -1
  17. package/dist/devices/index.d.ts.map +1 -1
  18. package/dist/devices/index.js +2 -0
  19. package/dist/devices/index.js.map +1 -1
  20. package/dist/devices/innr.d.ts.map +1 -1
  21. package/dist/devices/innr.js +1 -0
  22. package/dist/devices/innr.js.map +1 -1
  23. package/dist/devices/lumi.d.ts.map +1 -1
  24. package/dist/devices/lumi.js +200 -0
  25. package/dist/devices/lumi.js.map +1 -1
  26. package/dist/devices/multir.d.ts +3 -0
  27. package/dist/devices/multir.d.ts.map +1 -0
  28. package/dist/devices/multir.js +129 -0
  29. package/dist/devices/multir.js.map +1 -0
  30. package/dist/devices/philips.d.ts.map +1 -1
  31. package/dist/devices/philips.js +7 -0
  32. package/dist/devices/philips.js.map +1 -1
  33. package/dist/devices/sber.js +6 -6
  34. package/dist/devices/sber.js.map +1 -1
  35. package/dist/devices/schneider_electric.d.ts.map +1 -1
  36. package/dist/devices/schneider_electric.js +47 -12
  37. package/dist/devices/schneider_electric.js.map +1 -1
  38. package/dist/devices/sonoff.d.ts +2 -0
  39. package/dist/devices/sonoff.d.ts.map +1 -1
  40. package/dist/devices/sonoff.js +34 -0
  41. package/dist/devices/sonoff.js.map +1 -1
  42. package/dist/devices/third_reality.js +2 -2
  43. package/dist/devices/third_reality.js.map +1 -1
  44. package/dist/devices/tuya.d.ts.map +1 -1
  45. package/dist/devices/tuya.js +42 -18
  46. package/dist/devices/tuya.js.map +1 -1
  47. package/dist/devices/yandex.d.ts.map +1 -1
  48. package/dist/devices/yandex.js +6 -18
  49. package/dist/devices/yandex.js.map +1 -1
  50. package/dist/devices/ysrsai.d.ts.map +1 -1
  51. package/dist/devices/ysrsai.js +4 -1
  52. package/dist/devices/ysrsai.js.map +1 -1
  53. package/dist/devices/zemismart.js +1 -1
  54. package/dist/devices/zemismart.js.map +1 -1
  55. package/dist/lib/bosch.d.ts +38 -5
  56. package/dist/lib/bosch.d.ts.map +1 -1
  57. package/dist/lib/bosch.js +651 -167
  58. package/dist/lib/bosch.js.map +1 -1
  59. package/dist/lib/lumi.js +3 -3
  60. package/dist/lib/lumi.js.map +1 -1
  61. package/dist/lib/modernExtend.d.ts +54 -1
  62. package/dist/lib/modernExtend.d.ts.map +1 -1
  63. package/dist/lib/modernExtend.js +97 -21
  64. package/dist/lib/modernExtend.js.map +1 -1
  65. package/dist/lib/philips.js +1 -1
  66. package/dist/lib/philips.js.map +1 -1
  67. package/dist/lib/tuya.js +8 -8
  68. package/dist/lib/tuya.js.map +1 -1
  69. package/dist/lib/utils.d.ts +1 -0
  70. package/dist/lib/utils.d.ts.map +1 -1
  71. package/dist/lib/utils.js +10 -0
  72. package/dist/lib/utils.js.map +1 -1
  73. package/dist/models-index.json +1 -1
  74. package/package.json +3 -3
package/dist/lib/bosch.js CHANGED
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.boschBsenExtend = exports.boschBsirExtend = exports.boschBmctExtend = exports.manufacturerOptions = void 0;
36
+ exports.boschSmartPlugExtend = exports.boschBsenExtend = exports.boschDoorWindowContactExtend = exports.boschBsirExtend = exports.boschBmctExtend = exports.boschGeneralExtend = exports.manufacturerOptions = void 0;
37
37
  const zigbee_herdsman_1 = require("zigbee-herdsman");
38
38
  const fz = __importStar(require("../converters/fromZigbee"));
39
39
  const tz = __importStar(require("../converters/toZigbee"));
@@ -48,88 +48,62 @@ const e = exposes.presets;
48
48
  const ea = exposes.access;
49
49
  const NS = "zhc:bosch";
50
50
  exports.manufacturerOptions = { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.ROBERT_BOSCH_GMBH };
51
- exports.boschBmctExtend = {
52
- switchMode: (args) => {
53
- const { endpoint, deviceModeLookup, switchModeLookup, switchTypeLookup } = args;
54
- const expose = (device, options) => {
55
- if (utils.isDummyDevice(device)) {
56
- return [];
57
- }
58
- const switchTypeKey = device.getEndpoint(1).getClusterAttributeValue("boschSpecific", "switchType") ?? 0x00;
59
- const selectedSwitchType = utils.getFromLookupByValue(switchTypeKey, switchTypeLookup);
60
- if (selectedSwitchType === "none") {
61
- return [];
62
- }
63
- let supportedSwitchModes = Object.keys(switchModeLookup);
64
- if (device.modelID === "RBSH-MMS-ZB-EU") {
65
- const deviceModeKey = device.getEndpoint(1).getClusterAttributeValue("boschSpecific", "deviceMode");
66
- const deviceMode = utils.getFromLookupByValue(deviceModeKey, deviceModeLookup);
67
- if (deviceMode === "light") {
68
- if (selectedSwitchType.includes("rocker_switch")) {
69
- supportedSwitchModes = supportedSwitchModes.filter((switchMode) => switchMode === "coupled" || switchMode === "decoupled");
70
- }
51
+ exports.boschGeneralExtend = {
52
+ handleZclVersionReadRequest: () => {
53
+ const onEvent = [
54
+ (event) => {
55
+ if (event.type !== "deviceAnnounce") {
56
+ return;
71
57
  }
72
- if (deviceMode === "shutter") {
73
- if (selectedSwitchType.includes("button")) {
74
- supportedSwitchModes = supportedSwitchModes.filter((switchMode) => switchMode === "coupled" || switchMode === "only_long_press_decoupled");
75
- }
76
- else if (selectedSwitchType.includes("rocker_switch")) {
77
- supportedSwitchModes = supportedSwitchModes.filter((switchMode) => switchMode === "coupled");
58
+ event.data.device.customReadResponse = (frame, endpoint) => {
59
+ const isZclVersionRequest = frame.isCluster("genBasic") && frame.payload.find((i) => i.attrId === 0);
60
+ if (!isZclVersionRequest) {
61
+ return false;
78
62
  }
79
- }
80
- }
81
- const switchModeExpose = e
82
- .enum("switch_mode", ea.ALL, supportedSwitchModes)
83
- .withDescription("Decouple the switch from the corresponding output to use it for other purposes. Please keep in mind that the available options may depend on the used switch type.")
84
- .withCategory("config");
85
- if (endpoint !== undefined) {
86
- switchModeExpose.withEndpoint(endpoint.toString());
87
- }
88
- return [switchModeExpose];
63
+ const payload = {
64
+ zclVersion: 1,
65
+ };
66
+ endpoint.readResponse(frame.cluster.name, frame.header.transactionSequenceNumber, payload).catch((e) => {
67
+ logger_1.logger.warning(`Custom zclVersion response failed for '${event.data.device.ieeeAddr}': ${e}`, NS);
68
+ });
69
+ return true;
70
+ };
71
+ },
72
+ ];
73
+ return {
74
+ onEvent,
75
+ isModernExtend: true,
89
76
  };
90
- const fromZigbee = [
91
- {
92
- cluster: "boschSpecific",
93
- type: ["attributeReport", "readResponse"],
94
- convert: (model, msg, publish, options, meta) => {
95
- const result = {};
96
- const data = msg.data;
97
- if (data.switchMode !== undefined) {
98
- const property = utils.postfixWithEndpointName("switch_mode", msg, model, meta);
99
- result[property] = utils.getFromLookupByValue(data.switchMode, switchModeLookup);
100
- }
101
- return result;
102
- },
77
+ },
78
+ customSeMeteringCluster: () => m.deviceAddCustomCluster("seMetering", {
79
+ ID: zigbee_herdsman_1.Zcl.Clusters.seMetering.ID,
80
+ attributes: {},
81
+ commands: {
82
+ resetEnergyMeters: {
83
+ ID: 0x80,
84
+ parameters: [],
103
85
  },
86
+ },
87
+ commandsResponse: {},
88
+ }),
89
+ resetEnergyMeters: () => {
90
+ const exposes = [
91
+ e
92
+ .enum("reset_energy_meters", ea.SET, ["reset"])
93
+ .withDescription("Triggers the reset of all energy meters on the device to 0 kWh")
94
+ .withCategory("config"),
104
95
  ];
105
96
  const toZigbee = [
106
97
  {
107
- key: ["switch_mode"],
98
+ key: ["reset_energy_meters"],
108
99
  convertSet: async (entity, key, value, meta) => {
109
- if (key === "switch_mode") {
110
- const index = utils.getFromLookup(value, switchModeLookup);
111
- await entity.write("boschSpecific", { switchMode: index });
112
- return { state: { switch_mode: value } };
113
- }
114
- },
115
- convertGet: async (entity, key, meta) => {
116
- if (key === "switch_mode") {
117
- await entity.read("boschSpecific", ["switchMode"]);
118
- }
100
+ await entity.command("seMetering", "resetEnergyMeters", {}, exports.manufacturerOptions);
119
101
  },
120
102
  },
121
103
  ];
122
- const configure = [
123
- async (device, coordinatorEndpoint, definition) => {
124
- const desiredEndpoint = device.getEndpoint(endpoint ?? 1);
125
- await desiredEndpoint.read("boschSpecific", ["switchMode"]);
126
- },
127
- ];
128
104
  return {
129
- exposes: [expose],
130
- fromZigbee,
105
+ exposes,
131
106
  toZigbee,
132
- configure,
133
107
  isModernExtend: true,
134
108
  };
135
109
  },
@@ -144,7 +118,7 @@ exports.boschBmctExtend = {
144
118
  return [];
145
119
  }
146
120
  if (device.modelID === "RBSH-MMR-ZB-EU") {
147
- const pulsedModeEnabled = device.getEndpoint(1).getClusterAttributeValue("boschSpecific", "pulseLength") !== 0;
121
+ const pulsedModeEnabled = device.getEndpoint(1).getClusterAttributeValue("boschEnergyDevice", "pulseLength") !== 0;
148
122
  if (pulsedModeEnabled) {
149
123
  return [];
150
124
  }
@@ -161,7 +135,7 @@ exports.boschBmctExtend = {
161
135
  .withUnit("min")
162
136
  .withValueMin(0)
163
137
  .withValueMax(720)
164
- .withValueStep(1)
138
+ .withValueStep(0.5)
165
139
  .withCategory("config");
166
140
  if (endpoint !== undefined) {
167
141
  autoOffEnabledExpose.withEndpoint(endpoint.toString());
@@ -171,7 +145,7 @@ exports.boschBmctExtend = {
171
145
  };
172
146
  const fromZigbee = [
173
147
  {
174
- cluster: "boschSpecific",
148
+ cluster: "boschEnergyDevice",
175
149
  type: ["attributeReport", "readResponse"],
176
150
  convert: (model, msg, publish, options, meta) => {
177
151
  const result = {};
@@ -182,7 +156,7 @@ exports.boschBmctExtend = {
182
156
  }
183
157
  if (data.autoOffTime !== undefined) {
184
158
  const property = utils.postfixWithEndpointName("auto_off_time", msg, model, meta);
185
- result[property] = msg.data.autoOffTime / 60;
159
+ result[property] = data.autoOffTime / 60;
186
160
  }
187
161
  return result;
188
162
  },
@@ -194,20 +168,108 @@ exports.boschBmctExtend = {
194
168
  convertSet: async (entity, key, value, meta) => {
195
169
  if (key === "auto_off_enabled") {
196
170
  const selectedState = utils.getFromLookup(value, offOnLookup);
197
- await entity.write("boschSpecific", { autoOffEnabled: selectedState });
171
+ await entity.write("boschEnergyDevice", {
172
+ autoOffEnabled: utils.toNumber(selectedState),
173
+ });
198
174
  return { state: { auto_off_enabled: value } };
199
175
  }
200
176
  if (key === "auto_off_time") {
201
- await entity.write("boschSpecific", { autoOffTime: (0, utils_1.toNumber)(value) * 60 });
177
+ await entity.write("boschEnergyDevice", {
178
+ autoOffTime: (0, utils_1.toNumber)(value) * 60,
179
+ });
202
180
  return { state: { auto_off_time: value } };
203
181
  }
204
182
  },
205
183
  convertGet: async (entity, key, meta) => {
206
184
  if (key === "auto_off_enabled") {
207
- await entity.read("boschSpecific", ["autoOffEnabled"]);
185
+ await entity.read("boschEnergyDevice", ["autoOffEnabled"]);
208
186
  }
209
187
  if (key === "auto_off_time") {
210
- await entity.read("boschSpecific", ["autoOffTime"]);
188
+ await entity.read("boschEnergyDevice", ["autoOffTime"]);
189
+ }
190
+ },
191
+ },
192
+ ];
193
+ const configure = [
194
+ m.setupConfigureForBinding("boschEnergyDevice", "input", endpoint ? [endpoint.toString()] : null),
195
+ m.setupConfigureForReading("boschEnergyDevice", ["autoOffEnabled", "autoOffTime"], endpoint ? [endpoint.toString()] : null),
196
+ ];
197
+ return {
198
+ exposes: [expose],
199
+ fromZigbee,
200
+ toZigbee,
201
+ configure,
202
+ isModernExtend: true,
203
+ };
204
+ },
205
+ };
206
+ exports.boschBmctExtend = {
207
+ switchMode: (args) => {
208
+ const { endpoint, deviceModeLookup, switchModeLookup, switchTypeLookup } = args;
209
+ const expose = (device, options) => {
210
+ if (utils.isDummyDevice(device)) {
211
+ return [];
212
+ }
213
+ const switchTypeKey = device.getEndpoint(1).getClusterAttributeValue("boschEnergyDevice", "switchType") ?? 0x00;
214
+ const selectedSwitchType = utils.getFromLookupByValue(switchTypeKey, switchTypeLookup);
215
+ if (selectedSwitchType === "none") {
216
+ return [];
217
+ }
218
+ let supportedSwitchModes = Object.keys(switchModeLookup);
219
+ if (device.modelID === "RBSH-MMS-ZB-EU") {
220
+ const deviceModeKey = device.getEndpoint(1).getClusterAttributeValue("boschEnergyDevice", "deviceMode");
221
+ const deviceMode = utils.getFromLookupByValue(deviceModeKey, deviceModeLookup);
222
+ if (deviceMode === "light") {
223
+ if (selectedSwitchType.includes("rocker_switch")) {
224
+ supportedSwitchModes = supportedSwitchModes.filter((switchMode) => switchMode === "coupled" || switchMode === "decoupled");
225
+ }
226
+ }
227
+ if (deviceMode === "shutter") {
228
+ if (selectedSwitchType.includes("button")) {
229
+ supportedSwitchModes = supportedSwitchModes.filter((switchMode) => switchMode === "coupled" || switchMode === "only_long_press_decoupled");
230
+ }
231
+ else if (selectedSwitchType.includes("rocker_switch")) {
232
+ supportedSwitchModes = supportedSwitchModes.filter((switchMode) => switchMode === "coupled");
233
+ }
234
+ }
235
+ }
236
+ const switchModeExpose = e
237
+ .enum("switch_mode", ea.ALL, supportedSwitchModes)
238
+ .withDescription("Decouple the switch from the corresponding output to use it for other purposes. Please keep in mind that the available options may depend on the used switch type.")
239
+ .withCategory("config");
240
+ if (endpoint !== undefined) {
241
+ switchModeExpose.withEndpoint(endpoint.toString());
242
+ }
243
+ return [switchModeExpose];
244
+ };
245
+ const fromZigbee = [
246
+ {
247
+ cluster: "boschEnergyDevice",
248
+ type: ["attributeReport", "readResponse"],
249
+ convert: (model, msg, publish, options, meta) => {
250
+ const result = {};
251
+ const data = msg.data;
252
+ if (data.switchMode !== undefined) {
253
+ const property = utils.postfixWithEndpointName("switch_mode", msg, model, meta);
254
+ result[property] = utils.getFromLookupByValue(data.switchMode, switchModeLookup);
255
+ }
256
+ return result;
257
+ },
258
+ },
259
+ ];
260
+ const toZigbee = [
261
+ {
262
+ key: ["switch_mode"],
263
+ convertSet: async (entity, key, value, meta) => {
264
+ if (key === "switch_mode") {
265
+ const index = utils.getFromLookup(value, switchModeLookup);
266
+ await entity.write("boschEnergyDevice", { switchMode: index });
267
+ return { state: { switch_mode: value } };
268
+ }
269
+ },
270
+ convertGet: async (entity, key, meta) => {
271
+ if (key === "switch_mode") {
272
+ await entity.read("boschEnergyDevice", ["switchMode"]);
211
273
  }
212
274
  },
213
275
  },
@@ -215,7 +277,7 @@ exports.boschBmctExtend = {
215
277
  const configure = [
216
278
  async (device, coordinatorEndpoint, definition) => {
217
279
  const desiredEndpoint = device.getEndpoint(endpoint ?? 1);
218
- await desiredEndpoint.read("boschSpecific", ["autoOffEnabled", "autoOffTime"]);
280
+ await desiredEndpoint.read("boschEnergyDevice", ["switchMode"]);
219
281
  },
220
282
  ];
221
283
  return {
@@ -236,7 +298,7 @@ exports.boschBmctExtend = {
236
298
  if (utils.isDummyDevice(device)) {
237
299
  return [];
238
300
  }
239
- const currentSwitchType = device.getEndpoint(1).getClusterAttributeValue("boschSpecific", "switchType") ?? 0x00;
301
+ const currentSwitchType = device.getEndpoint(1).getClusterAttributeValue("boschEnergyDevice", "switchType") ?? 0x00;
240
302
  if (currentSwitchType === 0) {
241
303
  return [];
242
304
  }
@@ -251,7 +313,7 @@ exports.boschBmctExtend = {
251
313
  };
252
314
  const fromZigbee = [
253
315
  {
254
- cluster: "boschSpecific",
316
+ cluster: "boschEnergyDevice",
255
317
  type: ["attributeReport", "readResponse"],
256
318
  convert: (model, msg, publish, options, meta) => {
257
319
  const result = {};
@@ -270,13 +332,13 @@ exports.boschBmctExtend = {
270
332
  convertSet: async (entity, key, value, meta) => {
271
333
  if (key === "child_lock") {
272
334
  const selectedMode = utils.getFromLookup(value, childLockLookup);
273
- await entity.write("boschSpecific", { childLock: selectedMode });
335
+ await entity.write("boschEnergyDevice", { childLock: selectedMode });
274
336
  return { state: { child_lock: value } };
275
337
  }
276
338
  },
277
339
  convertGet: async (entity, key, meta) => {
278
340
  if (key === "child_lock") {
279
- await entity.read("boschSpecific", ["childLock"]);
341
+ await entity.read("boschEnergyDevice", ["childLock"]);
280
342
  }
281
343
  },
282
344
  },
@@ -284,7 +346,7 @@ exports.boschBmctExtend = {
284
346
  const configure = [
285
347
  async (device, coordinatorEndpoint, definition) => {
286
348
  const desiredEndpoint = device.getEndpoint(endpoint ?? 1);
287
- await desiredEndpoint.read("boschSpecific", ["childLock"]);
349
+ await desiredEndpoint.read("boschEnergyDevice", ["childLock"]);
288
350
  },
289
351
  ];
290
352
  return {
@@ -297,7 +359,7 @@ exports.boschBmctExtend = {
297
359
  },
298
360
  actuatorType: () => m.enumLookup({
299
361
  name: "actuator_type",
300
- cluster: "boschSpecific",
362
+ cluster: "boschEnergyDevice",
301
363
  attribute: "actuatorType",
302
364
  description: "Select the appropriate actuator type so that the connected device can be controlled correctly.",
303
365
  lookup: {
@@ -308,7 +370,7 @@ exports.boschBmctExtend = {
308
370
  }),
309
371
  dimmerType: () => m.enumLookup({
310
372
  name: "dimmer_type",
311
- cluster: "boschSpecific",
373
+ cluster: "boschEnergyDevice",
312
374
  attribute: "dimmerType",
313
375
  description: "Select the appropriate dimmer type for your lamps. Make sure that you are only using dimmable lamps.",
314
376
  lookup: {
@@ -340,7 +402,7 @@ exports.boschBmctExtend = {
340
402
  };
341
403
  const fromZigbee = [
342
404
  {
343
- cluster: "boschSpecific",
405
+ cluster: "boschEnergyDevice",
344
406
  type: ["attributeReport", "readResponse"],
345
407
  convert: (model, msg, publish, options, meta) => {
346
408
  const result = {};
@@ -361,29 +423,33 @@ exports.boschBmctExtend = {
361
423
  convertSet: async (entity, key, value, meta) => {
362
424
  if (key === "minimum_brightness") {
363
425
  const newMinimumBrightness = (0, utils_1.toNumber)(value);
364
- const currentState = await entity.read("boschSpecific", ["maximumBrightness"]);
426
+ const currentState = await entity.read("boschEnergyDevice", ["maximumBrightness"]);
365
427
  if (newMinimumBrightness >= currentState.maximumBrightness) {
366
428
  throw new Error("The minimum brightness must be lower than the maximum brightness!");
367
429
  }
368
- await entity.write("boschSpecific", { minimumBrightness: newMinimumBrightness });
430
+ await entity.write("boschEnergyDevice", {
431
+ minimumBrightness: newMinimumBrightness,
432
+ });
369
433
  return { state: { minimum_brightness: value } };
370
434
  }
371
435
  if (key === "maximum_brightness") {
372
436
  const newMaximumBrightness = (0, utils_1.toNumber)(value);
373
- const currentState = await entity.read("boschSpecific", ["minimumBrightness"]);
437
+ const currentState = await entity.read("boschEnergyDevice", ["minimumBrightness"]);
374
438
  if (newMaximumBrightness <= currentState.minimumBrightness) {
375
439
  throw new Error("The maximum brightness must be higher than the minimum brightness!");
376
440
  }
377
- await entity.write("boschSpecific", { maximumBrightness: newMaximumBrightness });
441
+ await entity.write("boschEnergyDevice", {
442
+ maximumBrightness: newMaximumBrightness,
443
+ });
378
444
  return { state: { maximum_brightness: value } };
379
445
  }
380
446
  },
381
447
  convertGet: async (entity, key, meta) => {
382
448
  if (key === "minimum_brightness") {
383
- await entity.read("boschSpecific", ["minimumBrightness"]);
449
+ await entity.read("boschEnergyDevice", ["minimumBrightness"]);
384
450
  }
385
451
  if (key === "maximum_brightness") {
386
- await entity.read("boschSpecific", ["maximumBrightness"]);
452
+ await entity.read("boschEnergyDevice", ["maximumBrightness"]);
387
453
  }
388
454
  },
389
455
  },
@@ -391,7 +457,7 @@ exports.boschBmctExtend = {
391
457
  const configure = [
392
458
  async (device, coordinatorEndpoint, definition) => {
393
459
  const endpoint = device.getEndpoint(1);
394
- await endpoint.read("boschSpecific", ["minimumBrightness", "maximumBrightness"]);
460
+ await endpoint.read("boschEnergyDevice", ["minimumBrightness", "maximumBrightness"]);
395
461
  },
396
462
  ];
397
463
  return {
@@ -425,14 +491,14 @@ exports.boschBmctExtend = {
425
491
  const newPulseLength = value === utils.getFromLookupByValue(0x00, deviceModesLookup) ? 0 : 10;
426
492
  const endpoint = meta.device.getEndpoint(1);
427
493
  if (newPulseLength > 0) {
428
- await endpoint.write("boschSpecific", {
494
+ await endpoint.write("boschEnergyDevice", {
429
495
  switchType: 0x05,
430
496
  switchMode: 0x00,
431
497
  childLock: 0x00,
432
498
  autoOffEnabled: 0x00,
433
499
  autoOffTime: 0,
434
500
  });
435
- await endpoint.read("boschSpecific", [
501
+ await endpoint.read("boschEnergyDevice", [
436
502
  "switchType",
437
503
  "switchMode",
438
504
  "childLock",
@@ -441,15 +507,21 @@ exports.boschBmctExtend = {
441
507
  ]);
442
508
  }
443
509
  else {
444
- await endpoint.write("boschSpecific", {
510
+ await endpoint.write("boschEnergyDevice", {
445
511
  switchType: 0x00,
446
512
  switchMode: 0x00,
447
513
  childLock: 0x00,
448
514
  });
449
- await endpoint.read("boschSpecific", ["switchType", "switchMode", "childLock"]);
515
+ await endpoint.read("boschEnergyDevice", [
516
+ "switchType",
517
+ "switchMode",
518
+ "childLock",
519
+ ]);
450
520
  }
451
- await endpoint.write("boschSpecific", { pulseLength: newPulseLength });
452
- await endpoint.read("boschSpecific", ["pulseLength"]);
521
+ await endpoint.write("boschEnergyDevice", {
522
+ pulseLength: newPulseLength,
523
+ });
524
+ await endpoint.read("boschEnergyDevice", ["pulseLength"]);
453
525
  }
454
526
  return { state: { device_mode: value } };
455
527
  }
@@ -468,7 +540,7 @@ exports.boschBmctExtend = {
468
540
  if (utils.isDummyDevice(device)) {
469
541
  return [];
470
542
  }
471
- if (device.getEndpoint(1).getClusterAttributeValue("boschSpecific", "pulseLength") === 0) {
543
+ if (device.getEndpoint(1).getClusterAttributeValue("boschEnergyDevice", "pulseLength") === 0) {
472
544
  return [];
473
545
  }
474
546
  const pulseLengthExpose = e
@@ -484,7 +556,7 @@ exports.boschBmctExtend = {
484
556
  };
485
557
  const fromZigbee = [
486
558
  {
487
- cluster: "boschSpecific",
559
+ cluster: "boschEnergyDevice",
488
560
  type: ["attributeReport", "readResponse"],
489
561
  convert: (model, msg, publish, options, meta) => {
490
562
  const result = {};
@@ -516,13 +588,15 @@ exports.boschBmctExtend = {
516
588
  convertSet: async (entity, key, value, meta) => {
517
589
  if (key === "pulse_length") {
518
590
  const selectedPulseLength = (0, utils_1.toNumber)(value) * 10;
519
- await entity.write("boschSpecific", { pulseLength: selectedPulseLength });
591
+ await entity.write("boschEnergyDevice", {
592
+ pulseLength: selectedPulseLength,
593
+ });
520
594
  return { state: { pulse_length: value } };
521
595
  }
522
596
  },
523
597
  convertGet: async (entity, key, meta) => {
524
598
  if (key === "pulse_length") {
525
- await entity.read("boschSpecific", ["pulseLength"]);
599
+ await entity.read("boschEnergyDevice", ["pulseLength"]);
526
600
  }
527
601
  },
528
602
  },
@@ -530,7 +604,7 @@ exports.boschBmctExtend = {
530
604
  const configure = [
531
605
  async (device, coordinatorEndpoint, definition) => {
532
606
  const endpoint = device.getEndpoint(1);
533
- await endpoint.read("boschSpecific", ["pulseLength"]);
607
+ await endpoint.read("boschEnergyDevice", ["pulseLength"]);
534
608
  },
535
609
  ];
536
610
  return {
@@ -549,7 +623,7 @@ exports.boschBmctExtend = {
549
623
  }
550
624
  let supportedSwitchTypes = Object.keys(switchTypeLookup);
551
625
  if (device.modelID === "RBSH-MMR-ZB-EU") {
552
- const pulseModeActive = device.getEndpoint(1).getClusterAttributeValue("boschSpecific", "pulseLength") > 0;
626
+ const pulseModeActive = device.getEndpoint(1).getClusterAttributeValue("boschEnergyDevice", "pulseLength") > 0;
553
627
  if (pulseModeActive) {
554
628
  supportedSwitchTypes = Object.keys(switchTypeLookup).filter((switchType) => switchType !== utils.getFromLookup("rocker_switch", switchTypeLookup));
555
629
  }
@@ -563,7 +637,7 @@ exports.boschBmctExtend = {
563
637
  };
564
638
  const fromZigbee = [
565
639
  {
566
- cluster: "boschSpecific",
640
+ cluster: "boschEnergyDevice",
567
641
  type: ["attributeReport", "readResponse"],
568
642
  convert: (model, msg, publish, options, meta) => {
569
643
  const result = {};
@@ -587,23 +661,25 @@ exports.boschBmctExtend = {
587
661
  if (key === "switch_type") {
588
662
  const selectedSwitchType = utils.getFromLookup(value, switchTypeLookup);
589
663
  if (meta.device.meta.switchType !== selectedSwitchType) {
590
- const endpoints = meta.device.endpoints.filter((e) => e.supportsInputCluster("boschSpecific"));
664
+ const endpoints = meta.device.endpoints.filter((e) => e.supportsInputCluster("boschEnergyDevice"));
591
665
  for (const endpoint of endpoints) {
592
- await endpoint.write("boschSpecific", {
666
+ await endpoint.write("boschEnergyDevice", {
593
667
  switchMode: 0x00,
594
668
  childLock: 0x00,
595
669
  });
596
- await endpoint.read("boschSpecific", ["switchMode", "childLock"]);
670
+ await endpoint.read("boschEnergyDevice", ["switchMode", "childLock"]);
597
671
  }
598
672
  }
599
- await entity.write("boschSpecific", { switchType: selectedSwitchType });
600
- await entity.read("boschSpecific", ["switchType"]);
673
+ await entity.write("boschEnergyDevice", {
674
+ switchType: selectedSwitchType,
675
+ });
676
+ await entity.read("boschEnergyDevice", ["switchType"]);
601
677
  return { state: { switch_type: value } };
602
678
  }
603
679
  },
604
680
  convertGet: async (entity, key, meta) => {
605
681
  if (key === "switch_type") {
606
- await entity.read("boschSpecific", ["switchType"]);
682
+ await entity.read("boschEnergyDevice", ["switchType"]);
607
683
  }
608
684
  },
609
685
  },
@@ -611,7 +687,7 @@ exports.boschBmctExtend = {
611
687
  const configure = [
612
688
  async (device, coordinatorEndpoint, definition) => {
613
689
  const endpoint = device.getEndpoint(1);
614
- await endpoint.read("boschSpecific", ["switchType"]);
690
+ await endpoint.read("boschEnergyDevice", ["switchType"]);
615
691
  },
616
692
  ];
617
693
  return {
@@ -622,32 +698,6 @@ exports.boschBmctExtend = {
622
698
  isModernExtend: true,
623
699
  };
624
700
  },
625
- handleZclVersionReadRequest: () => {
626
- const onEvent = [
627
- (event) => {
628
- if (event.type !== "deviceAnnounce") {
629
- return;
630
- }
631
- event.data.device.customReadResponse = (frame, endpoint) => {
632
- const isZclVersionRequest = frame.isCluster("genBasic") && frame.payload.find((i) => i.attrId === 0);
633
- if (!isZclVersionRequest) {
634
- return false;
635
- }
636
- const payload = {
637
- zclVersion: 1,
638
- };
639
- endpoint.readResponse(frame.cluster.name, frame.header.transactionSequenceNumber, payload).catch((e) => {
640
- logger_1.logger.warning(`Custom zclVersion response failed for '${event.data.device.ieeeAddr}': ${e}`, NS);
641
- });
642
- return true;
643
- };
644
- },
645
- ];
646
- return {
647
- onEvent,
648
- isModernExtend: true,
649
- };
650
- },
651
701
  reportSwitchAction: (args) => {
652
702
  const { switchTypeLookup, hasDualSwitchInputs } = args;
653
703
  const expose = (device, options) => {
@@ -655,7 +705,7 @@ exports.boschBmctExtend = {
655
705
  if (utils.isDummyDevice(device)) {
656
706
  return exposeList;
657
707
  }
658
- const switchTypeKey = device.getEndpoint(1).getClusterAttributeValue("boschSpecific", "switchType") ?? 0x00;
708
+ const switchTypeKey = device.getEndpoint(1).getClusterAttributeValue("boschEnergyDevice", "switchType") ?? 0x00;
659
709
  const selectedSwitchType = utils.getFromLookupByValue(switchTypeKey, switchTypeLookup);
660
710
  let supportedActionTypes;
661
711
  if (selectedSwitchType.includes("button")) {
@@ -687,7 +737,7 @@ exports.boschBmctExtend = {
687
737
  };
688
738
  const fromZigbee = [
689
739
  {
690
- cluster: "boschSpecific",
740
+ cluster: "boschEnergyDevice",
691
741
  type: ["raw"],
692
742
  convert: (model, msg, publish, options, meta) => {
693
743
  const command = msg.data[4];
@@ -764,7 +814,7 @@ exports.boschBmctExtend = {
764
814
  fz.power_on_behavior,
765
815
  fz.cover_position_tilt,
766
816
  {
767
- cluster: "boschSpecific",
817
+ cluster: "boschEnergyDevice",
768
818
  type: ["attributeReport", "readResponse"],
769
819
  convert: (model, msg, publish, options, meta) => {
770
820
  const result = {};
@@ -851,23 +901,23 @@ exports.boschBmctExtend = {
851
901
  }
852
902
  if (key === "device_mode") {
853
903
  const index = utils.getFromLookup(value, stateDeviceMode);
854
- await entity.write("boschSpecific", { deviceMode: index });
855
- await entity.read("boschSpecific", ["deviceMode"]);
904
+ await entity.write("boschEnergyDevice", { deviceMode: index });
905
+ await entity.read("boschEnergyDevice", ["deviceMode"]);
856
906
  return { state: { device_mode: value } };
857
907
  }
858
908
  if (key === "switch_type") {
859
909
  const applyDefaultForSwitchModeAndChildLock = async (endpoint) => {
860
910
  const switchModeDefault = utils.getFromLookup("coupled", stateSwitchMode);
861
911
  const childLockDefault = utils.getFromLookup("OFF", stateOffOn);
862
- await endpoint.write("boschSpecific", {
912
+ await endpoint.write("boschEnergyDevice", {
863
913
  switchMode: switchModeDefault,
864
914
  childLock: childLockDefault,
865
915
  });
866
- await endpoint.read("boschSpecific", ["switchMode", "childLock"]);
916
+ await endpoint.read("boschEnergyDevice", ["switchMode", "childLock"]);
867
917
  };
868
918
  const switchType = utils.getFromLookup(value, stateSwitchType);
869
- await entity.write("boschSpecific", { switchType: switchType });
870
- await entity.read("boschSpecific", ["switchType"]);
919
+ await entity.write("boschEnergyDevice", { switchType: switchType });
920
+ await entity.read("boschEnergyDevice", ["switchType"]);
871
921
  await applyDefaultForSwitchModeAndChildLock(entity);
872
922
  const leftEndpoint = meta.device.getEndpoint(2);
873
923
  await applyDefaultForSwitchModeAndChildLock(leftEndpoint);
@@ -877,21 +927,21 @@ exports.boschBmctExtend = {
877
927
  }
878
928
  if (key === "switch_mode") {
879
929
  const index = utils.getFromLookup(value, stateSwitchMode);
880
- await entity.write("boschSpecific", { switchMode: index });
930
+ await entity.write("boschEnergyDevice", { switchMode: index });
881
931
  return { state: { switch_mode: value } };
882
932
  }
883
933
  if (key === "child_lock") {
884
934
  const index = utils.getFromLookup(value, stateOffOn);
885
- await entity.write("boschSpecific", { childLock: index });
935
+ await entity.write("boschEnergyDevice", { childLock: index });
886
936
  return { state: { child_lock: value } };
887
937
  }
888
938
  if (key === "auto_off_enabled") {
889
939
  const index = utils.getFromLookup(value, stateOffOn);
890
- await entity.write("boschSpecific", { autoOffEnabled: index });
940
+ await entity.write("boschEnergyDevice", { autoOffEnabled: index });
891
941
  return { state: { auto_off_enabled: value } };
892
942
  }
893
943
  if (key === "auto_off_time" && typeof value === "number") {
894
- await entity.write("boschSpecific", { autoOffTime: value * 60 });
944
+ await entity.write("boschEnergyDevice", { autoOffTime: value * 60 });
895
945
  return { state: { auto_off_time: value } };
896
946
  }
897
947
  },
@@ -905,22 +955,22 @@ exports.boschBmctExtend = {
905
955
  }
906
956
  break;
907
957
  case "device_mode":
908
- await entity.read("boschSpecific", ["deviceMode"]);
958
+ await entity.read("boschEnergyDevice", ["deviceMode"]);
909
959
  break;
910
960
  case "switch_type":
911
- await entity.read("boschSpecific", ["switchType"]);
961
+ await entity.read("boschEnergyDevice", ["switchType"]);
912
962
  break;
913
963
  case "switch_mode":
914
- await entity.read("boschSpecific", ["switchMode"]);
964
+ await entity.read("boschEnergyDevice", ["switchMode"]);
915
965
  break;
916
966
  case "child_lock":
917
- await entity.read("boschSpecific", ["childLock"]);
967
+ await entity.read("boschEnergyDevice", ["childLock"]);
918
968
  break;
919
969
  case "auto_off_enabled":
920
- await entity.read("boschSpecific", ["autoOffEnabled"]);
970
+ await entity.read("boschEnergyDevice", ["autoOffEnabled"]);
921
971
  break;
922
972
  case "auto_off_time":
923
- await entity.read("boschSpecific", ["autoOffTime"]);
973
+ await entity.read("boschEnergyDevice", ["autoOffTime"]);
924
974
  break;
925
975
  default:
926
976
  throw new Error(`Unhandled key boschExtend.bmct.toZigbee.convertGet ${key}`);
@@ -933,41 +983,45 @@ exports.boschBmctExtend = {
933
983
  if (key === "calibration_opening_time") {
934
984
  const number = utils.toNumber(value, "calibration_opening_time");
935
985
  const index = number * 10;
936
- await entity.write("boschSpecific", { calibrationOpeningTime: index });
986
+ await entity.write("boschEnergyDevice", { calibrationOpeningTime: index });
937
987
  return { state: { calibration_opening_time: number } };
938
988
  }
939
989
  if (key === "calibration_closing_time") {
940
990
  const number = utils.toNumber(value, "calibration_closing_time");
941
991
  const index = number * 10;
942
- await entity.write("boschSpecific", { calibrationClosingTime: index });
992
+ await entity.write("boschEnergyDevice", { calibrationClosingTime: index });
943
993
  return { state: { calibration_closing_time: number } };
944
994
  }
945
995
  if (key === "calibration_button_hold_time") {
946
996
  const number = utils.toNumber(value, "calibration_button_hold_time");
947
997
  const index = number * 10;
948
- await entity.write("boschSpecific", { calibrationButtonHoldTime: index });
998
+ await entity.write("boschEnergyDevice", {
999
+ calibrationButtonHoldTime: index,
1000
+ });
949
1001
  return { state: { calibration_button_hold_time: number } };
950
1002
  }
951
1003
  if (key === "calibration_motor_start_delay") {
952
1004
  const number = utils.toNumber(value, "calibration_motor_start_delay");
953
1005
  const index = number * 10;
954
- await entity.write("boschSpecific", { calibrationMotorStartDelay: index });
1006
+ await entity.write("boschEnergyDevice", {
1007
+ calibrationMotorStartDelay: index,
1008
+ });
955
1009
  return { state: { calibration_motor_start_delay: number } };
956
1010
  }
957
1011
  },
958
1012
  convertGet: async (entity, key, meta) => {
959
1013
  switch (key) {
960
1014
  case "calibration_opening_time":
961
- await entity.read("boschSpecific", ["calibrationOpeningTime"]);
1015
+ await entity.read("boschEnergyDevice", ["calibrationOpeningTime"]);
962
1016
  break;
963
1017
  case "calibration_closing_time":
964
- await entity.read("boschSpecific", ["calibrationClosingTime"]);
1018
+ await entity.read("boschEnergyDevice", ["calibrationClosingTime"]);
965
1019
  break;
966
1020
  case "calibration_button_hold_time":
967
- await entity.read("boschSpecific", ["calibrationButtonHoldTime"]);
1021
+ await entity.read("boschEnergyDevice", ["calibrationButtonHoldTime"]);
968
1022
  break;
969
1023
  case "calibration_motor_start_delay":
970
- await entity.read("boschSpecific", ["calibrationMotorStartDelay"]);
1024
+ await entity.read("boschEnergyDevice", ["calibrationMotorStartDelay"]);
971
1025
  break;
972
1026
  default:
973
1027
  throw new Error(`Unhandled key boschExtend.bmct.toZigbee.convertGet ${key}`);
@@ -1295,6 +1349,298 @@ exports.boschBsirExtend = {
1295
1349
  return { exposes, fromZigbee, configure, isModernExtend: true };
1296
1350
  },
1297
1351
  };
1352
+ exports.boschDoorWindowContactExtend = {
1353
+ doorWindowContactCluster: () => m.deviceAddCustomCluster("boschDoorWindowContactCluster", {
1354
+ ID: 0xfcad,
1355
+ attributes: {
1356
+ breakFunctionEnabled: { ID: 0x0000, type: zigbee_herdsman_1.Zcl.DataType.UINT8, manufacturerCode: exports.manufacturerOptions.manufacturerCode },
1357
+ breakFunctionState: { ID: 0x0001, type: zigbee_herdsman_1.Zcl.DataType.UINT8, manufacturerCode: exports.manufacturerOptions.manufacturerCode },
1358
+ breakFunctionTimeout: { ID: 0x0002, type: zigbee_herdsman_1.Zcl.DataType.UINT8, manufacturerCode: exports.manufacturerOptions.manufacturerCode },
1359
+ vibrationDetectionEnabled: { ID: 0x0004, type: zigbee_herdsman_1.Zcl.DataType.UINT8, manufacturerCode: exports.manufacturerOptions.manufacturerCode },
1360
+ vibrationDetectionSensitivity: { ID: 0x0005, type: zigbee_herdsman_1.Zcl.DataType.UINT8, manufacturerCode: exports.manufacturerOptions.manufacturerCode },
1361
+ unknownOne: { ID: 0x0007, type: zigbee_herdsman_1.Zcl.DataType.UINT8, manufacturerCode: exports.manufacturerOptions.manufacturerCode },
1362
+ unknownTwo: { ID: 0x0008, type: zigbee_herdsman_1.Zcl.DataType.UINT16, manufacturerCode: exports.manufacturerOptions.manufacturerCode },
1363
+ unknownThree: { ID: 0x0009, type: zigbee_herdsman_1.Zcl.DataType.UINT8, manufacturerCode: exports.manufacturerOptions.manufacturerCode },
1364
+ unknownFour: { ID: 0x000a, type: zigbee_herdsman_1.Zcl.DataType.UINT8, manufacturerCode: exports.manufacturerOptions.manufacturerCode },
1365
+ },
1366
+ commands: {},
1367
+ commandsResponse: {},
1368
+ }),
1369
+ battery: () => m.battery({
1370
+ percentage: true,
1371
+ lowStatus: true,
1372
+ lowStatusReportingConfig: { min: "MIN", max: "MAX", change: 0 },
1373
+ }),
1374
+ reportContactState: () => m.iasZoneAlarm({
1375
+ zoneType: "contact",
1376
+ zoneAttributes: ["alarm_1"],
1377
+ description: "Indicates whether the device detected an open or closed door/window",
1378
+ }),
1379
+ reportButtonActions: (args) => {
1380
+ const { doublePressSupported } = args ?? { doublePressSupported: false };
1381
+ let buttonActionsLookup = {
1382
+ long_press: 0x02,
1383
+ single_press: 0x01,
1384
+ none: 0x00,
1385
+ };
1386
+ if (doublePressSupported) {
1387
+ buttonActionsLookup = { ...{ double_press: 0x08 }, ...buttonActionsLookup };
1388
+ }
1389
+ const exposes = [
1390
+ e
1391
+ .enum("action", ea.STATE, Object.keys(buttonActionsLookup))
1392
+ .withDescription("Indicates button presses on the device")
1393
+ .withCategory("diagnostic"),
1394
+ ];
1395
+ const fromZigbee = [
1396
+ {
1397
+ cluster: "ssIasZone",
1398
+ type: ["commandStatusChangeNotification", "attributeReport", "readResponse"],
1399
+ convert: (model, msg, publish, options, meta) => {
1400
+ const zoneStatus = "zonestatus" in msg.data ? msg.data.zonestatus : msg.data.zoneStatus;
1401
+ if (zoneStatus !== undefined) {
1402
+ const buttonPayload = zoneStatus >> 11;
1403
+ const buttonState = utils.getFromLookupByValue(buttonPayload, buttonActionsLookup);
1404
+ const result = {
1405
+ action: buttonState,
1406
+ };
1407
+ return result;
1408
+ }
1409
+ },
1410
+ },
1411
+ ];
1412
+ const configure = [m.setupConfigureForBinding("ssIasZone", "input"), m.setupConfigureForReading("ssIasZone", ["zoneStatus"])];
1413
+ return {
1414
+ exposes,
1415
+ fromZigbee,
1416
+ configure,
1417
+ isModernExtend: true,
1418
+ };
1419
+ },
1420
+ breakFunctionality: () => {
1421
+ const breakFunctionEnabledLookup = {
1422
+ ON: 0x01,
1423
+ OFF: 0x00,
1424
+ };
1425
+ const breakFunctionStatusLookup = {
1426
+ break_active: 0x01,
1427
+ idle: 0x00,
1428
+ };
1429
+ const exposes = [
1430
+ e
1431
+ .binary("break_function_enabled", ea.ALL, utils.getFromLookupByValue(0x01, breakFunctionEnabledLookup), utils.getFromLookupByValue(0x00, breakFunctionEnabledLookup))
1432
+ .withLabel("Break function")
1433
+ .withDescription("Activate the break function by pressing the operating button on the door/window contact twice. This means that the device temporarily stops reading the sensors.")
1434
+ .withCategory("config"),
1435
+ e
1436
+ .numeric("break_function_timeout", ea.ALL)
1437
+ .withLabel("Automatic time limit for breaks")
1438
+ .withDescription("Here you can define how long the break function is activated for the door/window contact. Once the time limit has expired, the break ends automatically. The LED on the device will flash orange as long as the break is activated when this setting is being used.")
1439
+ .withValueMin(1)
1440
+ .withValueMax(15)
1441
+ .withUnit("minutes")
1442
+ .withPreset("disable", null, "Disable automatic time limit")
1443
+ .withCategory("config"),
1444
+ e
1445
+ .enum("break_function_state", ea.STATE_GET, Object.keys(breakFunctionStatusLookup))
1446
+ .withLabel("Break function state")
1447
+ .withDescription("Indicates whether the device is in break mode or not"),
1448
+ ];
1449
+ const fromZigbee = [
1450
+ {
1451
+ cluster: "boschDoorWindowContactCluster",
1452
+ type: ["attributeReport", "readResponse"],
1453
+ convert: (model, msg, publish, options, meta) => {
1454
+ const result = {};
1455
+ const data = msg.data;
1456
+ if (data.breakFunctionEnabled !== undefined) {
1457
+ result.break_function_enabled = utils.getFromLookupByValue(data.breakFunctionEnabled, breakFunctionEnabledLookup);
1458
+ }
1459
+ if (data.breakFunctionTimeout !== undefined) {
1460
+ result.break_function_timeout = data.breakFunctionTimeout === 0xff ? null : data.breakFunctionTimeout;
1461
+ }
1462
+ if (data.breakFunctionState !== undefined) {
1463
+ result.break_function_state = utils.getFromLookupByValue(data.breakFunctionState, breakFunctionStatusLookup);
1464
+ }
1465
+ return result;
1466
+ },
1467
+ },
1468
+ ];
1469
+ const toZigbee = [
1470
+ {
1471
+ key: ["break_function_enabled", "break_function_timeout", "break_function_state"],
1472
+ convertSet: async (entity, key, value, meta) => {
1473
+ if (key === "break_function_enabled") {
1474
+ await entity.write("boschDoorWindowContactCluster", {
1475
+ breakFunctionEnabled: utils.getFromLookup(value, breakFunctionEnabledLookup),
1476
+ });
1477
+ return { state: { break_function_enabled: value } };
1478
+ }
1479
+ if (key === "break_function_timeout") {
1480
+ const index = value === null ? 0xff : utils.toNumber(value);
1481
+ await entity.write("boschDoorWindowContactCluster", {
1482
+ breakFunctionTimeout: index,
1483
+ });
1484
+ return { state: { break_function_timeout: value } };
1485
+ }
1486
+ },
1487
+ convertGet: async (entity, key, meta) => {
1488
+ if (key === "break_function_enabled") {
1489
+ await entity.read("boschDoorWindowContactCluster", [
1490
+ "breakFunctionEnabled",
1491
+ ]);
1492
+ }
1493
+ if (key === "break_function_timeout") {
1494
+ await entity.read("boschDoorWindowContactCluster", [
1495
+ "breakFunctionTimeout",
1496
+ ]);
1497
+ }
1498
+ if (key === "break_function_state") {
1499
+ await entity.read("boschDoorWindowContactCluster", [
1500
+ "breakFunctionState",
1501
+ ]);
1502
+ }
1503
+ },
1504
+ },
1505
+ ];
1506
+ const configure = [
1507
+ m.setupConfigureForReading("boschDoorWindowContactCluster", [
1508
+ "breakFunctionEnabled",
1509
+ "breakFunctionTimeout",
1510
+ "breakFunctionState",
1511
+ ]),
1512
+ ];
1513
+ return {
1514
+ exposes,
1515
+ fromZigbee,
1516
+ toZigbee,
1517
+ configure,
1518
+ isModernExtend: true,
1519
+ };
1520
+ },
1521
+ vibrationDetection: () => {
1522
+ const vibrationDetectionEnabledLookup = {
1523
+ ON: 0x01,
1524
+ OFF: 0x00,
1525
+ };
1526
+ const vibrationDetectionSensitivityLookup = {
1527
+ very_high: 0x05,
1528
+ high: 0x04,
1529
+ medium: 0x03,
1530
+ moderate: 0x02,
1531
+ low: 0x01,
1532
+ };
1533
+ const exposes = [
1534
+ e
1535
+ .binary("vibration_detection_enabled", ea.ALL, utils.getFromLookupByValue(0x01, vibrationDetectionEnabledLookup), utils.getFromLookupByValue(0x00, vibrationDetectionEnabledLookup))
1536
+ .withLabel("Vibration detection")
1537
+ .withDescription("Activate the vibration detection to detect vibrations at the window or door via the integrated sensor as well")
1538
+ .withCategory("config"),
1539
+ e
1540
+ .enum("vibration_detection_sensitivity", ea.ALL, Object.keys(vibrationDetectionSensitivityLookup))
1541
+ .withLabel("Vibration detection sensitivity")
1542
+ .withDescription("Set the sensitivity of the vibration detection sensor")
1543
+ .withCategory("config"),
1544
+ e.binary("vibration", ea.STATE_GET, true, false).withDescription("Indicates whether the device detected vibration"),
1545
+ ];
1546
+ const fromZigbee = [
1547
+ {
1548
+ cluster: "boschDoorWindowContactCluster",
1549
+ type: ["attributeReport", "readResponse"],
1550
+ convert: (model, msg, publish, options, meta) => {
1551
+ const result = {};
1552
+ const data = msg.data;
1553
+ if (data.vibrationDetectionEnabled !== undefined) {
1554
+ result.vibration_detection_enabled = utils.getFromLookupByValue(data.vibrationDetectionEnabled, vibrationDetectionEnabledLookup);
1555
+ }
1556
+ if (data.vibrationDetectionSensitivity !== undefined) {
1557
+ result.vibration_detection_sensitivity = utils.getFromLookupByValue(data.vibrationDetectionSensitivity, vibrationDetectionSensitivityLookup);
1558
+ }
1559
+ return result;
1560
+ },
1561
+ },
1562
+ {
1563
+ cluster: "ssIasZone",
1564
+ type: ["commandStatusChangeNotification", "attributeReport", "readResponse"],
1565
+ convert: (model, msg, publish, options, meta) => {
1566
+ const zoneStatus = "zonestatus" in msg.data ? msg.data.zonestatus : msg.data.zoneStatus;
1567
+ if (zoneStatus !== undefined) {
1568
+ const alarm2Payload = (zoneStatus & (1 << 1)) > 0;
1569
+ return {
1570
+ vibration: alarm2Payload,
1571
+ };
1572
+ }
1573
+ },
1574
+ },
1575
+ ];
1576
+ const toZigbee = [
1577
+ {
1578
+ key: ["vibration_detection_enabled", "vibration_detection_sensitivity", "vibration"],
1579
+ convertSet: async (entity, key, value, meta) => {
1580
+ if (key === "vibration_detection_enabled") {
1581
+ await entity.write("boschDoorWindowContactCluster", {
1582
+ vibrationDetectionEnabled: utils.getFromLookup(value, vibrationDetectionEnabledLookup),
1583
+ });
1584
+ return { state: { vibration_detection_enabled: value } };
1585
+ }
1586
+ if (key === "vibration_detection_sensitivity") {
1587
+ await entity.write("boschDoorWindowContactCluster", {
1588
+ vibrationDetectionSensitivity: utils.getFromLookup(value, vibrationDetectionSensitivityLookup),
1589
+ });
1590
+ return { state: { vibration_detection_sensitivity: value } };
1591
+ }
1592
+ },
1593
+ convertGet: async (entity, key, meta) => {
1594
+ if (key === "vibration_detection_enabled") {
1595
+ await entity.read("boschDoorWindowContactCluster", [
1596
+ "vibrationDetectionEnabled",
1597
+ ]);
1598
+ }
1599
+ if (key === "vibration_detection_sensitivity") {
1600
+ await entity.read("boschDoorWindowContactCluster", [
1601
+ "vibrationDetectionSensitivity",
1602
+ ]);
1603
+ }
1604
+ if (key === "vibration") {
1605
+ await entity.read("ssIasZone", ["zoneStatus"]);
1606
+ }
1607
+ },
1608
+ },
1609
+ ];
1610
+ const configure = [
1611
+ m.setupConfigureForBinding("ssIasZone", "input"),
1612
+ m.setupConfigureForReading("ssIasZone", ["zoneStatus"]),
1613
+ async (device, coordinatorEndpoint, definition) => {
1614
+ const endpoint = device.getEndpoint(1);
1615
+ // The write request is made when using the proprietary
1616
+ // Bosch Smart Home Controller II as of 19-09-2025. Looks like
1617
+ // the default value was too high, and they didn't want to
1618
+ // push a firmware update. We mimic it here to avoid complaints.
1619
+ await endpoint.write("boschDoorWindowContactCluster", {
1620
+ vibrationDetectionSensitivity: vibrationDetectionSensitivityLookup.medium,
1621
+ });
1622
+ // The write request is made when using the proprietary
1623
+ // Bosch Smart Home Controller II as of 19-09-2025. I have
1624
+ // no idea what it does, but we mimic it here in case it
1625
+ // fixes any issues.
1626
+ await endpoint.write("boschDoorWindowContactCluster", {
1627
+ unknownOne: 0x00,
1628
+ });
1629
+ },
1630
+ m.setupConfigureForReading("boschDoorWindowContactCluster", [
1631
+ "vibrationDetectionEnabled",
1632
+ "vibrationDetectionSensitivity",
1633
+ ]),
1634
+ ];
1635
+ return {
1636
+ exposes,
1637
+ fromZigbee,
1638
+ toZigbee,
1639
+ configure,
1640
+ isModernExtend: true,
1641
+ };
1642
+ },
1643
+ };
1298
1644
  exports.boschBsenExtend = {
1299
1645
  customIasZoneCluster: () => m.deviceAddCustomCluster("ssIasZone", {
1300
1646
  ID: zigbee_herdsman_1.Zcl.Clusters.ssIasZone.ID,
@@ -1532,5 +1878,143 @@ exports.boschBsenExtend = {
1532
1878
  };
1533
1879
  },
1534
1880
  };
1881
+ exports.boschSmartPlugExtend = {
1882
+ smartPlugCluster: () => m.deviceAddCustomCluster("boschEnergyDevice", {
1883
+ ID: 0xfca0,
1884
+ manufacturerCode: exports.manufacturerOptions.manufacturerCode,
1885
+ attributes: {
1886
+ autoOffEnabled: { ID: 0x0006, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN },
1887
+ autoOffTime: { ID: 0x0007, type: zigbee_herdsman_1.Zcl.DataType.UINT16 },
1888
+ ledBrightness: { ID: 0x002c, type: zigbee_herdsman_1.Zcl.DataType.UINT8 },
1889
+ energySavingModeEnabled: { ID: 0x002d, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN },
1890
+ energySavingModeThreshold: { ID: 0x002e, type: zigbee_herdsman_1.Zcl.DataType.UINT16 },
1891
+ energySavingModeTimer: { ID: 0x002f, type: zigbee_herdsman_1.Zcl.DataType.UINT32 },
1892
+ },
1893
+ commands: {},
1894
+ commandsResponse: {},
1895
+ }),
1896
+ onOff: () => m.onOff({ powerOnBehavior: true, configureReporting: true }),
1897
+ ledBrightness: () => m.numeric({
1898
+ name: "led_brightness",
1899
+ cluster: "boschEnergyDevice",
1900
+ attribute: "ledBrightness",
1901
+ label: "LED brightness",
1902
+ description: "Here you can adjust the LED brightness",
1903
+ valueMin: 0,
1904
+ valueMax: 100,
1905
+ valueStep: 1,
1906
+ unit: "%",
1907
+ entityCategory: "config",
1908
+ }),
1909
+ energySavingMode: () => {
1910
+ const energySavingModeEnabledLookup = {
1911
+ ON: 0x01,
1912
+ OFF: 0x00,
1913
+ };
1914
+ const exposes = [
1915
+ e
1916
+ .binary("energy_saving_mode_enabled", ea.ALL, utils.getFromLookupByValue(0x01, energySavingModeEnabledLookup), utils.getFromLookupByValue(0x00, energySavingModeEnabledLookup))
1917
+ .withLabel("Enable energy-saving mode")
1918
+ .withDescription("Here you can enable/disable the energy-saving mode")
1919
+ .withCategory("config"),
1920
+ e
1921
+ .numeric("energy_saving_mode_threshold", ea.ALL)
1922
+ .withLabel("Energy-saving threshold")
1923
+ .withDescription("Here you can set the threshold for the energy-saving mode. If the consumption falls below the set value (and the timer has been met), the smart plug will be turned off.")
1924
+ .withUnit("watt")
1925
+ .withValueMin(1)
1926
+ .withValueMax(50)
1927
+ .withValueStep(1)
1928
+ .withCategory("config"),
1929
+ e
1930
+ .numeric("energy_saving_mode_timer", ea.ALL)
1931
+ .withLabel("Energy-saving timer")
1932
+ .withDescription("Here you can set the time the threshold has to be met before the smart plug is turned off")
1933
+ .withUnit("seconds")
1934
+ .withValueMin(1)
1935
+ .withValueMax(1800)
1936
+ .withValueStep(1)
1937
+ .withCategory("config"),
1938
+ ];
1939
+ const fromZigbee = [
1940
+ {
1941
+ cluster: "boschEnergyDevice",
1942
+ type: ["attributeReport", "readResponse"],
1943
+ convert: (model, msg, publish, options, meta) => {
1944
+ const result = {};
1945
+ const data = msg.data;
1946
+ if (data.energySavingModeEnabled !== undefined) {
1947
+ result.energy_saving_mode_enabled = utils.getFromLookupByValue(data.energySavingModeEnabled, energySavingModeEnabledLookup);
1948
+ }
1949
+ if (data.energySavingModeThreshold !== undefined) {
1950
+ result.energy_saving_mode_threshold = utils.toNumber(data.energySavingModeThreshold) / 10;
1951
+ }
1952
+ if (data.energySavingModeTimer !== undefined) {
1953
+ result.energy_saving_mode_timer = utils.toNumber(data.energySavingModeTimer);
1954
+ }
1955
+ return result;
1956
+ },
1957
+ },
1958
+ ];
1959
+ const toZigbee = [
1960
+ {
1961
+ key: ["energy_saving_mode_enabled", "energy_saving_mode_threshold", "energy_saving_mode_timer"],
1962
+ convertSet: async (entity, key, value, meta) => {
1963
+ if (key === "energy_saving_mode_enabled") {
1964
+ await entity.write("boschEnergyDevice", {
1965
+ energySavingModeEnabled: utils.getFromLookup(value, energySavingModeEnabledLookup),
1966
+ });
1967
+ return { state: { energy_saving_mode_enabled: value } };
1968
+ }
1969
+ if (key === "energy_saving_mode_threshold") {
1970
+ await entity.write("boschEnergyDevice", {
1971
+ energySavingModeThreshold: utils.toNumber(value) * 10,
1972
+ });
1973
+ return { state: { energy_saving_mode_threshold: value } };
1974
+ }
1975
+ if (key === "energy_saving_mode_timer") {
1976
+ await entity.write("boschEnergyDevice", {
1977
+ energySavingModeTimer: utils.toNumber(value),
1978
+ });
1979
+ return { state: { energy_saving_mode_timer: value } };
1980
+ }
1981
+ },
1982
+ convertGet: async (entity, key, meta) => {
1983
+ if (key === "energy_saving_mode_enabled") {
1984
+ await entity.read("boschEnergyDevice", ["energySavingModeEnabled"]);
1985
+ }
1986
+ if (key === "energy_saving_mode_threshold") {
1987
+ await entity.read("boschEnergyDevice", ["energySavingModeThreshold"]);
1988
+ }
1989
+ if (key === "energy_saving_mode_timer") {
1990
+ await entity.read("boschEnergyDevice", ["energySavingModeTimer"]);
1991
+ }
1992
+ },
1993
+ },
1994
+ ];
1995
+ const configure = [
1996
+ m.setupConfigureForBinding("boschEnergyDevice", "input"),
1997
+ m.setupConfigureForReading("boschEnergyDevice", [
1998
+ "energySavingModeEnabled",
1999
+ "energySavingModeThreshold",
2000
+ "energySavingModeTimer",
2001
+ ]),
2002
+ ];
2003
+ return {
2004
+ exposes,
2005
+ fromZigbee,
2006
+ toZigbee,
2007
+ configure,
2008
+ isModernExtend: true,
2009
+ };
2010
+ },
2011
+ electricityMeter: (args) => m.electricityMeter({
2012
+ voltage: false,
2013
+ current: false,
2014
+ power: { change: 1 },
2015
+ energy: { change: 1 },
2016
+ ...args,
2017
+ }),
2018
+ };
1535
2019
  //endregion
1536
2020
  //# sourceMappingURL=bosch.js.map