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.
Files changed (233) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/converters/fromZigbee.d.ts.map +1 -1
  3. package/dist/converters/fromZigbee.js +53 -11
  4. package/dist/converters/fromZigbee.js.map +1 -1
  5. package/dist/converters/toZigbee.d.ts.map +1 -1
  6. package/dist/converters/toZigbee.js +82 -8
  7. package/dist/converters/toZigbee.js.map +1 -1
  8. package/dist/devices/ITCommander.d.ts.map +1 -1
  9. package/dist/devices/ITCommander.js +1 -0
  10. package/dist/devices/ITCommander.js.map +1 -1
  11. package/dist/devices/adeo.d.ts.map +1 -1
  12. package/dist/devices/adeo.js +1 -0
  13. package/dist/devices/adeo.js.map +1 -1
  14. package/dist/devices/atlantic.d.ts.map +1 -1
  15. package/dist/devices/atlantic.js +2 -0
  16. package/dist/devices/atlantic.js.map +1 -1
  17. package/dist/devices/avatto.js +6 -6
  18. package/dist/devices/avatto.js.map +1 -1
  19. package/dist/devices/bosch.d.ts.map +1 -1
  20. package/dist/devices/bosch.js +2 -0
  21. package/dist/devices/bosch.js.map +1 -1
  22. package/dist/devices/brun_holding.d.ts +3 -0
  23. package/dist/devices/brun_holding.d.ts.map +1 -0
  24. package/dist/devices/brun_holding.js +59 -0
  25. package/dist/devices/brun_holding.js.map +1 -0
  26. package/dist/devices/busch_jaeger.js +1 -1
  27. package/dist/devices/busch_jaeger.js.map +1 -1
  28. package/dist/devices/custom_devices_diy.d.ts.map +1 -1
  29. package/dist/devices/custom_devices_diy.js +18 -13
  30. package/dist/devices/custom_devices_diy.js.map +1 -1
  31. package/dist/devices/develco.js +1 -1
  32. package/dist/devices/develco.js.map +1 -1
  33. package/dist/devices/diyruz.d.ts.map +1 -1
  34. package/dist/devices/diyruz.js +2 -0
  35. package/dist/devices/diyruz.js.map +1 -1
  36. package/dist/devices/dresden_elektronik.js +1 -1
  37. package/dist/devices/dresden_elektronik.js.map +1 -1
  38. package/dist/devices/essentials.js +3 -3
  39. package/dist/devices/essentials.js.map +1 -1
  40. package/dist/devices/eurotronic.d.ts.map +1 -1
  41. package/dist/devices/eurotronic.js +4 -1
  42. package/dist/devices/eurotronic.js.map +1 -1
  43. package/dist/devices/ewelink.d.ts.map +1 -1
  44. package/dist/devices/ewelink.js +15 -37
  45. package/dist/devices/ewelink.js.map +1 -1
  46. package/dist/devices/gledopto.d.ts.map +1 -1
  47. package/dist/devices/gledopto.js +2 -1
  48. package/dist/devices/gledopto.js.map +1 -1
  49. package/dist/devices/gmmts.d.ts.map +1 -1
  50. package/dist/devices/gmmts.js +7 -0
  51. package/dist/devices/gmmts.js.map +1 -1
  52. package/dist/devices/hive.js +1 -1
  53. package/dist/devices/hive.js.map +1 -1
  54. package/dist/devices/ikea.js +1 -1
  55. package/dist/devices/ikea.js.map +1 -1
  56. package/dist/devices/index.d.ts.map +1 -1
  57. package/dist/devices/index.js +4 -0
  58. package/dist/devices/index.js.map +1 -1
  59. package/dist/devices/inovelli.d.ts.map +1 -1
  60. package/dist/devices/inovelli.js +70 -36
  61. package/dist/devices/inovelli.js.map +1 -1
  62. package/dist/devices/insta.js +1 -1
  63. package/dist/devices/insta.js.map +1 -1
  64. package/dist/devices/keen_home.d.ts.map +1 -1
  65. package/dist/devices/keen_home.js +2 -4
  66. package/dist/devices/keen_home.js.map +1 -1
  67. package/dist/devices/lidl.d.ts.map +1 -1
  68. package/dist/devices/lidl.js +5 -2
  69. package/dist/devices/lidl.js.map +1 -1
  70. package/dist/devices/lifecontrol.js +1 -1
  71. package/dist/devices/lifecontrol.js.map +1 -1
  72. package/dist/devices/linptech.d.ts.map +1 -1
  73. package/dist/devices/linptech.js +1 -0
  74. package/dist/devices/linptech.js.map +1 -1
  75. package/dist/devices/lixee.d.ts.map +1 -1
  76. package/dist/devices/lixee.js +69 -49
  77. package/dist/devices/lixee.js.map +1 -1
  78. package/dist/devices/lumi.d.ts.map +1 -1
  79. package/dist/devices/lumi.js +23 -102
  80. package/dist/devices/lumi.js.map +1 -1
  81. package/dist/devices/moes.js +3 -3
  82. package/dist/devices/moes.js.map +1 -1
  83. package/dist/devices/muller_licht.d.ts.map +1 -1
  84. package/dist/devices/muller_licht.js +1 -5
  85. package/dist/devices/muller_licht.js.map +1 -1
  86. package/dist/devices/multiterm.d.ts.map +1 -1
  87. package/dist/devices/multiterm.js +1 -0
  88. package/dist/devices/multiterm.js.map +1 -1
  89. package/dist/devices/namron.js +2 -2
  90. package/dist/devices/namron.js.map +1 -1
  91. package/dist/devices/nue_3a.d.ts.map +1 -1
  92. package/dist/devices/nue_3a.js +2 -0
  93. package/dist/devices/nue_3a.js.map +1 -1
  94. package/dist/devices/orvibo.d.ts.map +1 -1
  95. package/dist/devices/orvibo.js +3 -0
  96. package/dist/devices/orvibo.js.map +1 -1
  97. package/dist/devices/osram.js +2 -2
  98. package/dist/devices/osram.js.map +1 -1
  99. package/dist/devices/owon.d.ts.map +1 -1
  100. package/dist/devices/owon.js +2 -0
  101. package/dist/devices/owon.js.map +1 -1
  102. package/dist/devices/paulmann.d.ts.map +1 -1
  103. package/dist/devices/paulmann.js +7 -0
  104. package/dist/devices/paulmann.js.map +1 -1
  105. package/dist/devices/philips.d.ts.map +1 -1
  106. package/dist/devices/philips.js +7 -0
  107. package/dist/devices/philips.js.map +1 -1
  108. package/dist/devices/rgb_genie.d.ts.map +1 -1
  109. package/dist/devices/rgb_genie.js +2 -0
  110. package/dist/devices/rgb_genie.js.map +1 -1
  111. package/dist/devices/samotech.d.ts.map +1 -1
  112. package/dist/devices/samotech.js +2 -1
  113. package/dist/devices/samotech.js.map +1 -1
  114. package/dist/devices/schneider_electric.d.ts.map +1 -1
  115. package/dist/devices/schneider_electric.js +8 -4
  116. package/dist/devices/schneider_electric.js.map +1 -1
  117. package/dist/devices/shinasystem.d.ts.map +1 -1
  118. package/dist/devices/shinasystem.js +3 -0
  119. package/dist/devices/shinasystem.js.map +1 -1
  120. package/dist/devices/sinope.d.ts.map +1 -1
  121. package/dist/devices/sinope.js +3 -0
  122. package/dist/devices/sinope.js.map +1 -1
  123. package/dist/devices/somfy.d.ts.map +1 -1
  124. package/dist/devices/somfy.js +13 -1
  125. package/dist/devices/somfy.js.map +1 -1
  126. package/dist/devices/sonoff.d.ts.map +1 -1
  127. package/dist/devices/sonoff.js +21 -4
  128. package/dist/devices/sonoff.js.map +1 -1
  129. package/dist/devices/sunricher.d.ts.map +1 -1
  130. package/dist/devices/sunricher.js +17 -743
  131. package/dist/devices/sunricher.js.map +1 -1
  132. package/dist/devices/third_reality.d.ts.map +1 -1
  133. package/dist/devices/third_reality.js +1 -4
  134. package/dist/devices/third_reality.js.map +1 -1
  135. package/dist/devices/tuya.d.ts.map +1 -1
  136. package/dist/devices/tuya.js +45 -22
  137. package/dist/devices/tuya.js.map +1 -1
  138. package/dist/devices/ubisys.d.ts.map +1 -1
  139. package/dist/devices/ubisys.js +6 -1
  140. package/dist/devices/ubisys.js.map +1 -1
  141. package/dist/devices/wmun.d.ts +3 -0
  142. package/dist/devices/wmun.d.ts.map +1 -0
  143. package/dist/devices/wmun.js +61 -0
  144. package/dist/devices/wmun.js.map +1 -0
  145. package/dist/devices/xyzroe.d.ts.map +1 -1
  146. package/dist/devices/xyzroe.js +10 -0
  147. package/dist/devices/xyzroe.js.map +1 -1
  148. package/dist/devices/yale.js +1 -1
  149. package/dist/devices/yale.js.map +1 -1
  150. package/dist/devices/yandex.js +1 -1
  151. package/dist/devices/yandex.js.map +1 -1
  152. package/dist/devices/yokis.d.ts.map +1 -1
  153. package/dist/devices/yokis.js +74 -37
  154. package/dist/devices/yokis.js.map +1 -1
  155. package/dist/devices/ysrsai.js +1 -1
  156. package/dist/devices/ysrsai.js.map +1 -1
  157. package/dist/index.d.ts +1 -0
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.js +8 -1
  160. package/dist/index.js.map +1 -1
  161. package/dist/indexer.d.ts.map +1 -1
  162. package/dist/indexer.js +1 -0
  163. package/dist/indexer.js.map +1 -1
  164. package/dist/lib/color.d.ts.map +1 -1
  165. package/dist/lib/color.js +9 -1
  166. package/dist/lib/color.js.map +1 -1
  167. package/dist/lib/configureKey.js +9 -0
  168. package/dist/lib/configureKey.js.map +1 -1
  169. package/dist/lib/constants.d.ts +3 -1
  170. package/dist/lib/constants.d.ts.map +1 -1
  171. package/dist/lib/develco.d.ts.map +1 -1
  172. package/dist/lib/develco.js +1 -0
  173. package/dist/lib/develco.js.map +1 -1
  174. package/dist/lib/ewelink.d.ts.map +1 -1
  175. package/dist/lib/ewelink.js +10 -7
  176. package/dist/lib/ewelink.js.map +1 -1
  177. package/dist/lib/exposes.d.ts +17 -17
  178. package/dist/lib/exposes.d.ts.map +1 -1
  179. package/dist/lib/exposes.js +50 -30
  180. package/dist/lib/exposes.js.map +1 -1
  181. package/dist/lib/generateDefinition.d.ts.map +1 -1
  182. package/dist/lib/generateDefinition.js +2 -1
  183. package/dist/lib/generateDefinition.js.map +1 -1
  184. package/dist/lib/ikea.d.ts.map +1 -1
  185. package/dist/lib/ikea.js +8 -0
  186. package/dist/lib/ikea.js.map +1 -1
  187. package/dist/lib/ledvance.d.ts.map +1 -1
  188. package/dist/lib/ledvance.js +2 -0
  189. package/dist/lib/ledvance.js.map +1 -1
  190. package/dist/lib/legacy.d.ts +4 -4
  191. package/dist/lib/legacy.d.ts.map +1 -1
  192. package/dist/lib/legacy.js +180 -4
  193. package/dist/lib/legacy.js.map +1 -1
  194. package/dist/lib/light.d.ts.map +1 -1
  195. package/dist/lib/light.js +2 -0
  196. package/dist/lib/light.js.map +1 -1
  197. package/dist/lib/lumi.d.ts +43 -3
  198. package/dist/lib/lumi.d.ts.map +1 -1
  199. package/dist/lib/lumi.js +56 -4
  200. package/dist/lib/lumi.js.map +1 -1
  201. package/dist/lib/modernExtend.d.ts +7 -6
  202. package/dist/lib/modernExtend.d.ts.map +1 -1
  203. package/dist/lib/modernExtend.js +78 -3
  204. package/dist/lib/modernExtend.js.map +1 -1
  205. package/dist/lib/nodon.d.ts.map +1 -1
  206. package/dist/lib/ota.d.ts.map +1 -1
  207. package/dist/lib/ota.js +10 -1
  208. package/dist/lib/ota.js.map +1 -1
  209. package/dist/lib/philips.d.ts +1 -1
  210. package/dist/lib/philips.d.ts.map +1 -1
  211. package/dist/lib/philips.js +20 -1
  212. package/dist/lib/philips.js.map +1 -1
  213. package/dist/lib/reporting.d.ts.map +1 -1
  214. package/dist/lib/reporting.js +0 -1
  215. package/dist/lib/reporting.js.map +1 -1
  216. package/dist/lib/sunricher.d.ts +17 -3
  217. package/dist/lib/sunricher.d.ts.map +1 -1
  218. package/dist/lib/sunricher.js +771 -1
  219. package/dist/lib/sunricher.js.map +1 -1
  220. package/dist/lib/tuya.d.ts +5 -5
  221. package/dist/lib/tuya.d.ts.map +1 -1
  222. package/dist/lib/tuya.js +21 -6
  223. package/dist/lib/tuya.js.map +1 -1
  224. package/dist/lib/types.d.ts +3 -3
  225. package/dist/lib/types.d.ts.map +1 -1
  226. package/dist/lib/types.js +0 -1
  227. package/dist/lib/types.js.map +1 -1
  228. package/dist/lib/utils.d.ts +1 -1
  229. package/dist/lib/utils.d.ts.map +1 -1
  230. package/dist/lib/utils.js +17 -5
  231. package/dist/lib/utils.js.map +1 -1
  232. package/dist/models-index.json +1 -1
  233. package/package.json +6 -6
@@ -1,6 +1,50 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.tz = void 0;
36
+ exports.extend = exports.tz = void 0;
37
+ const constants = __importStar(require("./constants"));
38
+ const constants_1 = require("./constants");
39
+ const exposes = __importStar(require("./exposes"));
40
+ const reporting = __importStar(require("./reporting"));
41
+ const reporting_1 = require("./reporting");
42
+ const globalStore = __importStar(require("./store"));
43
+ const utils = __importStar(require("./utils"));
44
+ const utils_1 = require("./utils");
45
+ const e = exposes.presets;
46
+ const ea = exposes.access;
47
+ const sunricherManufacturerCode = 0x1224;
4
48
  const tz = {
5
49
  setModel: {
6
50
  key: ["model"],
@@ -11,4 +55,730 @@ const tz = {
11
55
  },
12
56
  };
13
57
  exports.tz = tz;
58
+ const extend = {
59
+ externalSwitchType: () => {
60
+ const attribute = 0x8803;
61
+ const data_type = 0x20;
62
+ const value_map = {
63
+ 0: "push_button",
64
+ 1: "normal_on_off",
65
+ 2: "three_way",
66
+ };
67
+ const value_lookup = {
68
+ push_button: 0,
69
+ normal_on_off: 1,
70
+ three_way: 2,
71
+ };
72
+ const fromZigbee = [
73
+ {
74
+ cluster: "genBasic",
75
+ type: ["attributeReport", "readResponse"],
76
+ convert: (model, msg, publish, options, meta) => {
77
+ if (Object.prototype.hasOwnProperty.call(msg.data, attribute)) {
78
+ const value = msg.data[attribute];
79
+ return {
80
+ external_switch_type: value_map[value] || "unknown",
81
+ external_switch_type_numeric: value,
82
+ };
83
+ }
84
+ return undefined;
85
+ },
86
+ },
87
+ ];
88
+ const toZigbee = [
89
+ {
90
+ key: ["external_switch_type"],
91
+ convertSet: async (entity, key, value, meta) => {
92
+ const numericValue = value_lookup[value] ?? Number.parseInt(value, 10);
93
+ await entity.write("genBasic", { [attribute]: { value: numericValue, type: data_type } }, { manufacturerCode: sunricherManufacturerCode });
94
+ return { state: { external_switch_type: value } };
95
+ },
96
+ convertGet: async (entity, key, meta) => {
97
+ await entity.read("genBasic", [attribute], {
98
+ manufacturerCode: sunricherManufacturerCode,
99
+ });
100
+ },
101
+ },
102
+ ];
103
+ const exposes = [
104
+ e.enum("external_switch_type", ea.ALL, ["push_button", "normal_on_off", "three_way"]).withLabel("External switch type"),
105
+ ];
106
+ const configure = [
107
+ async (device, coordinatorEndpoint, definition) => {
108
+ const endpoint = device.getEndpoint(1);
109
+ try {
110
+ await endpoint.read("genBasic", [attribute], {
111
+ manufacturerCode: sunricherManufacturerCode,
112
+ });
113
+ }
114
+ catch (error) {
115
+ console.warn(`Failed to read external switch type attribute: ${error}`);
116
+ }
117
+ },
118
+ ];
119
+ return {
120
+ fromZigbee,
121
+ toZigbee,
122
+ exposes,
123
+ configure,
124
+ isModernExtend: true,
125
+ };
126
+ },
127
+ minimumPWM: () => {
128
+ const attribute = 0x7809;
129
+ const data_type = 0x20;
130
+ const fromZigbee = [
131
+ {
132
+ cluster: "genBasic",
133
+ type: ["attributeReport", "readResponse"],
134
+ convert: (model, msg, publish, options, meta) => {
135
+ if (Object.prototype.hasOwnProperty.call(msg.data, attribute)) {
136
+ console.log("from ", msg.data[attribute]);
137
+ const value = Math.round(msg.data[attribute] / 5.1);
138
+ return {
139
+ minimum_pwm: value,
140
+ };
141
+ }
142
+ return undefined;
143
+ },
144
+ },
145
+ ];
146
+ const toZigbee = [
147
+ {
148
+ key: ["minimum_pwm"],
149
+ convertSet: async (entity, key, value, meta) => {
150
+ console.log("to ", value);
151
+ const numValue = typeof value === "string" ? Number.parseInt(value) : value;
152
+ const zgValue = Math.round(numValue * 5.1);
153
+ await entity.write("genBasic", { [attribute]: { value: zgValue, type: data_type } }, { manufacturerCode: sunricherManufacturerCode });
154
+ return { state: { minimum_pwm: numValue } };
155
+ },
156
+ convertGet: async (entity, key, meta) => {
157
+ await entity.read("genBasic", [attribute], {
158
+ manufacturerCode: sunricherManufacturerCode,
159
+ });
160
+ },
161
+ },
162
+ ];
163
+ const exposes = [
164
+ e
165
+ .numeric("minimum_pwm", ea.ALL)
166
+ .withLabel("Minimum PWM")
167
+ .withDescription("Power off the device and wait for 3 seconds before reconnecting to apply the settings.")
168
+ .withValueMin(0)
169
+ .withValueMax(50)
170
+ .withUnit("%")
171
+ .withValueStep(1),
172
+ ];
173
+ const configure = [
174
+ async (device, coordinatorEndpoint, definition) => {
175
+ const endpoint = device.getEndpoint(1);
176
+ try {
177
+ await endpoint.read("genBasic", [attribute], {
178
+ manufacturerCode: sunricherManufacturerCode,
179
+ });
180
+ }
181
+ catch (error) {
182
+ console.warn(`Failed to read external switch type attribute: ${error}`);
183
+ }
184
+ },
185
+ ];
186
+ return {
187
+ fromZigbee,
188
+ toZigbee,
189
+ exposes,
190
+ configure,
191
+ isModernExtend: true,
192
+ };
193
+ },
194
+ SRZG9002KR12Pro: () => {
195
+ const cluster = 0xff03;
196
+ const fromZigbee = [
197
+ {
198
+ cluster: 0xff03,
199
+ type: ["raw"],
200
+ convert: (model, msg, publish, options, meta) => {
201
+ const bytes = [...msg.data];
202
+ const messageType = bytes[3];
203
+ let action = "unknown";
204
+ if (messageType === 0x01) {
205
+ const pressTypeMask = bytes[6];
206
+ const pressTypeLookup = {
207
+ 1: "short_press",
208
+ 2: "double_press",
209
+ 3: "hold",
210
+ 4: "hold_released",
211
+ };
212
+ action = pressTypeLookup[pressTypeMask] || "unknown";
213
+ const buttonMask = (bytes[4] << 8) | bytes[5];
214
+ const specialButtonMap = {
215
+ 9: "knob",
216
+ 11: "k9",
217
+ 12: "k10",
218
+ 15: "k11",
219
+ 16: "k12",
220
+ };
221
+ const actionButtons = [];
222
+ for (let i = 0; i < 16; i++) {
223
+ if ((buttonMask >> i) & 1) {
224
+ const button = i + 1;
225
+ actionButtons.push(specialButtonMap[button] ?? `k${button}`);
226
+ }
227
+ }
228
+ return { action, action_buttons: actionButtons };
229
+ }
230
+ if (messageType === 0x03) {
231
+ const directionMask = bytes[4];
232
+ const actionSpeed = bytes[6];
233
+ const directionMap = {
234
+ 1: "clockwise",
235
+ 2: "anti_clockwise",
236
+ };
237
+ const direction = directionMap[directionMask] || "unknown";
238
+ action = `${direction}_rotation`;
239
+ return { action, action_speed: actionSpeed };
240
+ }
241
+ return { action };
242
+ },
243
+ },
244
+ ];
245
+ const exposes = [
246
+ e.action(["short_press", "double_press", "hold", "hold_released", "clockwise_rotation", "anti_clockwise_rotation"]),
247
+ ];
248
+ const configure = [
249
+ async (device, coordinatorEndpoint, definition) => {
250
+ const endpoint = device.getEndpoint(1);
251
+ await endpoint.bind(cluster, coordinatorEndpoint);
252
+ },
253
+ ];
254
+ return {
255
+ fromZigbee,
256
+ exposes,
257
+ configure,
258
+ isModernExtend: true,
259
+ };
260
+ },
261
+ SRZG2836D5Pro: () => {
262
+ const cluster = 0xff03;
263
+ const fromZigbee = [
264
+ {
265
+ cluster: 0xff03,
266
+ type: ["raw"],
267
+ convert: (model, msg, publish, options, meta) => {
268
+ const bytes = [...msg.data];
269
+ const messageType = bytes[3];
270
+ let action = "unknown";
271
+ if (messageType === 0x01) {
272
+ const pressTypeMask = bytes[6];
273
+ const pressTypeLookup = {
274
+ 1: "short_press",
275
+ 2: "double_press",
276
+ 3: "hold",
277
+ 4: "hold_released",
278
+ };
279
+ action = pressTypeLookup[pressTypeMask] || "unknown";
280
+ const buttonMask = bytes[5];
281
+ const specialButtonLookup = {
282
+ 1: "top_left",
283
+ 2: "top_right",
284
+ 3: "bottom_left",
285
+ 4: "bottom_right",
286
+ 5: "center",
287
+ };
288
+ const actionButtons = [];
289
+ for (let i = 0; i < 5; i++) {
290
+ if ((buttonMask >> i) & 1) {
291
+ const button = i + 1;
292
+ actionButtons.push(specialButtonLookup[button] || `unknown_${button}`);
293
+ }
294
+ }
295
+ return { action, action_buttons: actionButtons };
296
+ }
297
+ if (messageType === 0x03) {
298
+ const directionMask = bytes[4];
299
+ const actionSpeed = bytes[6];
300
+ const isStop = bytes[5] === 0x02;
301
+ const directionMap = {
302
+ 1: "clockwise",
303
+ 2: "anti_clockwise",
304
+ };
305
+ const direction = isStop ? "stop" : directionMap[directionMask] || "unknown";
306
+ action = `${direction}_rotation`;
307
+ return { action, action_speed: actionSpeed };
308
+ }
309
+ return { action };
310
+ },
311
+ },
312
+ ];
313
+ const exposes = [
314
+ e.action(["short_press", "double_press", "hold", "hold_released", "clockwise_rotation", "anti_clockwise_rotation", "stop_rotation"]),
315
+ ];
316
+ const configure = [
317
+ async (device, coordinatorEndpoint, definition) => {
318
+ const endpoint = device.getEndpoint(1);
319
+ await endpoint.bind(cluster, coordinatorEndpoint);
320
+ },
321
+ ];
322
+ return {
323
+ fromZigbee,
324
+ exposes,
325
+ configure,
326
+ isModernExtend: true,
327
+ };
328
+ },
329
+ SRZG9002K16Pro: () => {
330
+ const cluster = 0xff03;
331
+ const fromZigbee = [
332
+ {
333
+ cluster,
334
+ type: ["raw"],
335
+ convert: (model, msg, publish, options, meta) => {
336
+ const bytes = [...msg.data];
337
+ const messageType = bytes[3];
338
+ let action = "unknown";
339
+ if (messageType === 0x01) {
340
+ const pressTypeMask = bytes[6];
341
+ const pressTypeLookup = {
342
+ 1: "short_press",
343
+ 2: "double_press",
344
+ 3: "hold",
345
+ 4: "hold_released",
346
+ };
347
+ action = pressTypeLookup[pressTypeMask] || "unknown";
348
+ const buttonMask = (bytes[4] << 8) | bytes[5];
349
+ const getButtonNumber = (input) => {
350
+ const row = Math.floor((input - 1) / 4);
351
+ const col = (input - 1) % 4;
352
+ return col * 4 + row + 1;
353
+ };
354
+ const actionButtons = [];
355
+ for (let i = 0; i < 16; i++) {
356
+ if ((buttonMask >> i) & 1) {
357
+ const button = i + 1;
358
+ actionButtons.push(`k${getButtonNumber(button)}`);
359
+ }
360
+ }
361
+ return { action, action_buttons: actionButtons };
362
+ }
363
+ return { action };
364
+ },
365
+ },
366
+ ];
367
+ const exposes = [e.action(["short_press", "double_press", "hold", "hold_released"])];
368
+ const configure = [
369
+ async (device, coordinatorEndpoint, definition) => {
370
+ const endpoint = device.getEndpoint(1);
371
+ await endpoint.bind(cluster, coordinatorEndpoint);
372
+ },
373
+ ];
374
+ return {
375
+ fromZigbee,
376
+ exposes,
377
+ configure,
378
+ isModernExtend: true,
379
+ };
380
+ },
381
+ indicatorLight() {
382
+ const cluster = 0xfc8b;
383
+ const attribute = 0xf001;
384
+ const data_type = 0x20;
385
+ const manufacturerCode = 0x120b;
386
+ const exposes = [
387
+ e.enum("indicator_light", ea.ALL, ["on", "off"]).withDescription("Enable/disable the LED indicator").withCategory("config"),
388
+ ];
389
+ const fromZigbee = [
390
+ {
391
+ cluster,
392
+ type: ["attributeReport", "readResponse"],
393
+ convert: (model, msg, publish, options, meta) => {
394
+ if (!Object.prototype.hasOwnProperty.call(msg.data, attribute))
395
+ return;
396
+ const indicatorLight = msg.data[attribute];
397
+ const firstBit = indicatorLight & 0x01;
398
+ return { indicator_light: firstBit === 1 ? "on" : "off" };
399
+ },
400
+ },
401
+ ];
402
+ const toZigbee = [
403
+ {
404
+ key: ["indicator_light"],
405
+ convertSet: async (entity, key, value, meta) => {
406
+ const attributeRead = await entity.read(cluster, [attribute]);
407
+ if (attributeRead === undefined)
408
+ return;
409
+ // @ts-expect-error ignore
410
+ const currentValue = attributeRead[attribute];
411
+ const newValue = value === "on" ? currentValue | 0x01 : currentValue & ~0x01;
412
+ await entity.write(cluster, { [attribute]: { value: newValue, type: data_type } }, { manufacturerCode });
413
+ return { state: { indicator_light: value } };
414
+ },
415
+ convertGet: async (entity, key, meta) => {
416
+ await entity.read(cluster, [attribute], { manufacturerCode });
417
+ },
418
+ },
419
+ ];
420
+ const configure = [
421
+ async (device, coordinatorEndpoint, definition) => {
422
+ const endpoint = device.getEndpoint(1);
423
+ await endpoint.bind(cluster, coordinatorEndpoint);
424
+ await endpoint.read(cluster, [attribute], { manufacturerCode });
425
+ },
426
+ ];
427
+ return {
428
+ exposes,
429
+ configure,
430
+ fromZigbee,
431
+ toZigbee,
432
+ isModernExtend: true,
433
+ };
434
+ },
435
+ thermostatWeeklySchedule: () => {
436
+ const exposes = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"].map((day) => e
437
+ .text(`schedule_${day}`, ea.ALL)
438
+ .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"`)
439
+ .withCategory("config"));
440
+ const fromZigbee = [
441
+ {
442
+ cluster: "hvacThermostat",
443
+ type: ["commandGetWeeklyScheduleRsp"],
444
+ convert: (model, msg, publish, options, meta) => {
445
+ const day = Object.entries(constants.thermostatDayOfWeek).find((d) => msg.data.dayofweek & (1 << +d[0]))[1];
446
+ const transitions = msg.data.transitions
447
+ .map((t) => {
448
+ const hours = Math.floor(t.transitionTime / 60);
449
+ const minutes = t.transitionTime % 60;
450
+ return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}/${t.heatSetpoint / 100}`;
451
+ })
452
+ .sort()
453
+ .join(" ");
454
+ return {
455
+ ...meta.state.weekly_schedule,
456
+ [`schedule_${day}`]: transitions,
457
+ };
458
+ },
459
+ },
460
+ ];
461
+ const toZigbee = [
462
+ {
463
+ key: [
464
+ "schedule_sunday",
465
+ "schedule_monday",
466
+ "schedule_tuesday",
467
+ "schedule_wednesday",
468
+ "schedule_thursday",
469
+ "schedule_friday",
470
+ "schedule_saturday",
471
+ ],
472
+ convertSet: async (entity, key, value, meta) => {
473
+ const transitionRegex = /^(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])\/(\d+(\.\d+)?)$/;
474
+ const dayOfWeekName = key.replace("schedule_", "");
475
+ utils.assertString(value, dayOfWeekName);
476
+ const dayKey = utils.getKey(constants.thermostatDayOfWeek, dayOfWeekName.toLowerCase(), null);
477
+ if (!dayKey)
478
+ throw new Error(`Invalid schedule: invalid day name, found: ${dayOfWeekName}`);
479
+ const transitions = value.split(" ").sort();
480
+ if (transitions.length !== 4) {
481
+ throw new Error("Invalid schedule: days must have exactly 4 transitions");
482
+ }
483
+ const payload = {
484
+ dayofweek: 1 << Number(dayKey),
485
+ numoftrans: transitions.length,
486
+ mode: 1 << 0,
487
+ transitions: transitions.map((transition) => {
488
+ const matches = transition.match(transitionRegex);
489
+ if (!matches) {
490
+ throw new Error(`Invalid schedule: transitions must be in format HH:mm/temperature (e.g. 12:00/15.5), found: ${transition}`);
491
+ }
492
+ const [, hours, minutes, temp] = matches;
493
+ const temperature = Number.parseFloat(temp);
494
+ if (temperature < 4 || temperature > 35) {
495
+ throw new Error(`Invalid schedule: temperature value must be between 4-35 (inclusive), found: ${temperature}`);
496
+ }
497
+ return {
498
+ transitionTime: Number.parseInt(hours) * 60 + Number.parseInt(minutes),
499
+ heatSetpoint: Math.round(temperature * 100),
500
+ };
501
+ }),
502
+ };
503
+ await entity.command("hvacThermostat", "setWeeklySchedule", payload, utils.getOptions(meta.mapped, entity));
504
+ },
505
+ convertGet: async (entity, key, meta) => {
506
+ const dayOfWeekName = key.replace("schedule_", "");
507
+ const dayKey = utils.getKey(constants.thermostatDayOfWeek, dayOfWeekName.toLowerCase(), null);
508
+ await entity.command("hvacThermostat", "getWeeklySchedule", {
509
+ daystoreturn: dayKey !== null ? 1 << Number(dayKey) : 0xff,
510
+ modetoreturn: 1,
511
+ }, utils.getOptions(meta.mapped, entity));
512
+ },
513
+ },
514
+ ];
515
+ const configure = [
516
+ async (device, coordinatorEndpoint, definition) => {
517
+ const endpoint = device.getEndpoint(1);
518
+ await endpoint.command("hvacThermostat", "getWeeklySchedule", {
519
+ daystoreturn: 0xff,
520
+ modetoreturn: 1,
521
+ });
522
+ },
523
+ ];
524
+ return { exposes, fromZigbee, toZigbee, configure, isModernExtend: true };
525
+ },
526
+ thermostatChildLock: () => {
527
+ const exposes = [e.binary("child_lock", ea.ALL, "LOCK", "UNLOCK").withDescription("Enables/disables physical input on the device")];
528
+ const fromZigbee = [
529
+ {
530
+ cluster: "hvacUserInterfaceCfg",
531
+ type: ["attributeReport", "readResponse"],
532
+ convert: (model, msg, publish, options, meta) => {
533
+ if (Object.hasOwn(msg.data, "keypadLockout")) {
534
+ return {
535
+ child_lock: msg.data.keypadLockout === 0 ? "UNLOCK" : "LOCK",
536
+ };
537
+ }
538
+ return {};
539
+ },
540
+ },
541
+ ];
542
+ const toZigbee = [
543
+ {
544
+ key: ["child_lock"],
545
+ convertSet: async (entity, key, value, meta) => {
546
+ const keypadLockout = Number(value === "LOCK");
547
+ await entity.write("hvacUserInterfaceCfg", { keypadLockout });
548
+ return { state: { child_lock: value } };
549
+ },
550
+ convertGet: async (entity, key, meta) => {
551
+ await entity.read("hvacUserInterfaceCfg", ["keypadLockout"]);
552
+ },
553
+ },
554
+ ];
555
+ const configure = [
556
+ async (device, coordinatorEndpoint, definition) => {
557
+ const endpoint = device.getEndpoint(1);
558
+ await reporting.bind(endpoint, coordinatorEndpoint, ["hvacUserInterfaceCfg"]);
559
+ await endpoint.read("hvacUserInterfaceCfg", ["keypadLockout"]);
560
+ await reporting.thermostatKeypadLockMode(endpoint);
561
+ },
562
+ ];
563
+ return { exposes, fromZigbee, toZigbee, configure, isModernExtend: true };
564
+ },
565
+ thermostatPreset: () => {
566
+ const systemModeLookup = {
567
+ 0: "off",
568
+ 1: "auto",
569
+ 3: "cool",
570
+ 4: "manual",
571
+ 5: "emergency_heating",
572
+ 6: "precooling",
573
+ 7: "fan_only",
574
+ 8: "dry",
575
+ 9: "sleep",
576
+ };
577
+ const awayOrBoostModeLookup = { 0: "normal", 1: "away", 2: "forced" };
578
+ const fromZigbee = [
579
+ {
580
+ cluster: "hvacThermostat",
581
+ type: ["attributeReport", "readResponse"],
582
+ convert: (model, msg, publish, options, meta) => {
583
+ if (!Object.hasOwn(msg.data, "systemMode") && !Object.hasOwn(msg.data, "awayOrBoostMode"))
584
+ return;
585
+ const systemMode = msg.data.systemMode ?? globalStore.getValue(msg.device, "systemMode");
586
+ const awayOrBoostMode = msg.data.awayOrBoostMode ?? globalStore.getValue(msg.device, "awayOrBoostMode");
587
+ globalStore.putValue(msg.device, "systemMode", systemMode);
588
+ globalStore.putValue(msg.device, "awayOrBoostMode", awayOrBoostMode);
589
+ const result = {};
590
+ if (awayOrBoostMode !== undefined && awayOrBoostMode !== 0) {
591
+ result.preset = utils.getFromLookup(awayOrBoostMode, awayOrBoostModeLookup);
592
+ result.away_or_boost_mode = utils.getFromLookup(awayOrBoostMode, awayOrBoostModeLookup);
593
+ if (systemMode !== undefined) {
594
+ result.system_mode = constants.thermostatSystemModes[systemMode];
595
+ }
596
+ }
597
+ else if (systemMode !== undefined) {
598
+ result.preset = utils.getFromLookup(systemMode, systemModeLookup);
599
+ result.system_mode = constants.thermostatSystemModes[systemMode];
600
+ if (awayOrBoostMode !== undefined) {
601
+ result.away_or_boost_mode = utils.getFromLookup(awayOrBoostMode, awayOrBoostModeLookup);
602
+ }
603
+ }
604
+ return result;
605
+ },
606
+ },
607
+ ];
608
+ const toZigbee = [
609
+ {
610
+ key: ["preset"],
611
+ convertSet: async (entity, key, value, meta) => {
612
+ if (value === "away" || value === "forced") {
613
+ const awayOrBoostMode = value === "away" ? 1 : 2;
614
+ globalStore.putValue(entity, "awayOrBoostMode", awayOrBoostMode);
615
+ if (value === "away") {
616
+ await entity.read("hvacThermostat", ["unoccupiedHeatingSetpoint"]);
617
+ }
618
+ await entity.write("hvacThermostat", { awayOrBoostMode });
619
+ return { state: { preset: value, away_or_boost_mode: value } };
620
+ }
621
+ globalStore.putValue(entity, "awayOrBoostMode", 0);
622
+ const systemMode = utils.getKey(systemModeLookup, value, undefined, Number);
623
+ await entity.write("hvacThermostat", { systemMode });
624
+ if (typeof systemMode === "number") {
625
+ return {
626
+ state: {
627
+ // @ts-expect-error ignore
628
+ preset: systemModeLookup[systemMode],
629
+ system_mode: constants.thermostatSystemModes[systemMode],
630
+ },
631
+ };
632
+ }
633
+ },
634
+ },
635
+ {
636
+ key: ["system_mode"],
637
+ convertSet: async (entity, key, value, meta) => {
638
+ const systemMode = utils.getKey(constants.thermostatSystemModes, value, undefined, Number);
639
+ if (systemMode === undefined || typeof systemMode !== "number") {
640
+ throw new Error(`Invalid system mode: ${value}`);
641
+ }
642
+ await entity.write("hvacThermostat", { systemMode });
643
+ return {
644
+ state: {
645
+ // @ts-expect-error ignore
646
+ preset: systemModeLookup[systemMode],
647
+ system_mode: constants.thermostatSystemModes[systemMode],
648
+ },
649
+ };
650
+ },
651
+ convertGet: async (entity, key, meta) => {
652
+ await entity.read("hvacThermostat", ["systemMode"]);
653
+ },
654
+ },
655
+ ];
656
+ const configure = [
657
+ async (device, coordinatorEndpoint, definition) => {
658
+ const endpoint = device.getEndpoint(1);
659
+ await endpoint.read("hvacThermostat", ["systemMode"]);
660
+ await endpoint.read("hvacThermostat", ["awayOrBoostMode"]);
661
+ await reporting.bind(endpoint, coordinatorEndpoint, ["hvacThermostat"]);
662
+ await reporting.thermostatSystemMode(endpoint);
663
+ await endpoint.configureReporting("hvacThermostat", (0, reporting_1.payload)("awayOrBoostMode", 10, constants_1.repInterval.HOUR, null));
664
+ },
665
+ ];
666
+ return { fromZigbee, toZigbee, configure, isModernExtend: true };
667
+ },
668
+ thermostatCurrentHeatingSetpoint: () => {
669
+ const getAwayOrBoostMode = async (entity) => {
670
+ let result = globalStore.getValue(entity, "awayOrBoostMode");
671
+ if (result === undefined) {
672
+ const attributeRead = await entity.read("hvacThermostat", ["awayOrBoostMode"]);
673
+ // @ts-expect-error ignore
674
+ result = attributeRead.awayOrBoostMode;
675
+ globalStore.putValue(entity, "awayOrBoostMode", result);
676
+ }
677
+ return result;
678
+ };
679
+ const fromZigbee = [
680
+ {
681
+ cluster: "hvacThermostat",
682
+ type: ["attributeReport", "readResponse"],
683
+ convert: async (model, msg, publish, options, meta) => {
684
+ const hasHeatingSetpoints = Object.hasOwn(msg.data, "occupiedHeatingSetpoint") || Object.hasOwn(msg.data, "unoccupiedHeatingSetpoint");
685
+ if (!hasHeatingSetpoints)
686
+ return;
687
+ const processSetpoint = (value) => {
688
+ if (value === undefined)
689
+ return undefined;
690
+ return (0, utils_1.precisionRound)(value, 2) / 100;
691
+ };
692
+ const occupiedSetpoint = processSetpoint(msg.data.occupiedHeatingSetpoint);
693
+ const unoccupiedSetpoint = processSetpoint(msg.data.unoccupiedHeatingSetpoint);
694
+ const awayOrBoostMode = msg.data.awayOrBoostMode ?? (await getAwayOrBoostMode(msg.device.getEndpoint(1)));
695
+ const result = {};
696
+ if (awayOrBoostMode === 1 && unoccupiedSetpoint !== undefined) {
697
+ result.current_heating_setpoint = unoccupiedSetpoint;
698
+ }
699
+ else if (occupiedSetpoint !== undefined) {
700
+ result.current_heating_setpoint = occupiedSetpoint;
701
+ }
702
+ return result;
703
+ },
704
+ },
705
+ ];
706
+ const toZigbee = [
707
+ {
708
+ key: ["current_heating_setpoint"],
709
+ convertSet: async (entity, key, value, meta) => {
710
+ utils.assertNumber(value, key);
711
+ const awayOrBoostMode = await getAwayOrBoostMode(entity);
712
+ let convertedValue;
713
+ if (meta.options.thermostat_unit === "fahrenheit") {
714
+ convertedValue = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
715
+ }
716
+ else {
717
+ convertedValue = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
718
+ }
719
+ const attribute = awayOrBoostMode === 1 ? "unoccupiedHeatingSetpoint" : "occupiedHeatingSetpoint";
720
+ await entity.write("hvacThermostat", { [attribute]: convertedValue });
721
+ return { state: { current_heating_setpoint: value } };
722
+ },
723
+ convertGet: async (entity, key, meta) => {
724
+ await entity.read("hvacThermostat", ["occupiedHeatingSetpoint", "unoccupiedHeatingSetpoint"]);
725
+ },
726
+ },
727
+ ];
728
+ const configure = [
729
+ async (device, coordinatorEndpoint, definition) => {
730
+ const endpoint = device.getEndpoint(1);
731
+ await endpoint.read("hvacThermostat", ["occupiedHeatingSetpoint", "unoccupiedHeatingSetpoint"]);
732
+ await reporting.bind(endpoint, coordinatorEndpoint, ["hvacThermostat"]);
733
+ await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
734
+ await reporting.thermostatUnoccupiedHeatingSetpoint(endpoint);
735
+ },
736
+ ];
737
+ return { fromZigbee, toZigbee, configure, isModernExtend: true };
738
+ },
739
+ SRZG2856Pro: () => {
740
+ const fromZigbee = [
741
+ {
742
+ cluster: "sunricherRemote",
743
+ type: ["commandPress"],
744
+ convert: (model, msg, publish, options, meta) => {
745
+ let action = "unknown";
746
+ if (msg.data.messageType === 0x01) {
747
+ const pressTypeLookup = {
748
+ 1: "short_press",
749
+ 2: "double_press",
750
+ 3: "hold",
751
+ 4: "hold_released",
752
+ };
753
+ action = pressTypeLookup[msg.data.pressType] || "unknown";
754
+ const buttonMask = (msg.data.button2 << 8) | msg.data.button1;
755
+ const actionButtons = [];
756
+ for (let i = 0; i < 16; i++) {
757
+ if ((buttonMask >> i) & 1) {
758
+ const button = i + 1;
759
+ actionButtons.push(`k${button}`);
760
+ }
761
+ }
762
+ return { action, action_buttons: actionButtons };
763
+ }
764
+ return { action };
765
+ },
766
+ },
767
+ ];
768
+ const exposes = [e.action(["short_press", "double_press", "hold", "hold_released"])];
769
+ const configure = [
770
+ async (device, coordinatorEndpoint, definition) => {
771
+ const endpoint = device.getEndpoint(1);
772
+ await endpoint.bind("sunricherRemote", coordinatorEndpoint);
773
+ },
774
+ ];
775
+ return {
776
+ fromZigbee,
777
+ exposes,
778
+ configure,
779
+ isModernExtend: true,
780
+ };
781
+ },
782
+ };
783
+ exports.extend = extend;
14
784
  //# sourceMappingURL=sunricher.js.map