zigbee-herdsman-converters 21.9.0 → 21.9.1

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 (1394) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/converters/fromZigbee.d.ts +2036 -0
  3. package/converters/fromZigbee.d.ts.map +1 -0
  4. package/converters/fromZigbee.js +5343 -0
  5. package/converters/fromZigbee.js.map +1 -0
  6. package/converters/toZigbee.d.ts +1578 -0
  7. package/converters/toZigbee.d.ts.map +1 -0
  8. package/converters/toZigbee.js +4422 -0
  9. package/converters/toZigbee.js.map +1 -0
  10. package/devices/ITCommander.d.ts +4 -0
  11. package/devices/ITCommander.d.ts.map +1 -0
  12. package/devices/ITCommander.js +77 -0
  13. package/devices/ITCommander.js.map +1 -0
  14. package/devices/acova.d.ts +4 -0
  15. package/devices/acova.d.ts.map +1 -0
  16. package/devices/acova.js +127 -0
  17. package/devices/acova.js.map +1 -0
  18. package/devices/acuity_brands_lighting.d.ts +4 -0
  19. package/devices/acuity_brands_lighting.d.ts.map +1 -0
  20. package/devices/acuity_brands_lighting.js +29 -0
  21. package/devices/acuity_brands_lighting.js.map +1 -0
  22. package/devices/adeo.d.ts +4 -0
  23. package/devices/adeo.d.ts.map +1 -0
  24. package/devices/adeo.js +486 -0
  25. package/devices/adeo.js.map +1 -0
  26. package/devices/adurosmart.d.ts +4 -0
  27. package/devices/adurosmart.d.ts.map +1 -0
  28. package/devices/adurosmart.js +183 -0
  29. package/devices/adurosmart.js.map +1 -0
  30. package/devices/aeotec.d.ts +4 -0
  31. package/devices/aeotec.d.ts.map +1 -0
  32. package/devices/aeotec.js +66 -0
  33. package/devices/aeotec.js.map +1 -0
  34. package/devices/airam.d.ts +4 -0
  35. package/devices/airam.d.ts.map +1 -0
  36. package/devices/airam.js +106 -0
  37. package/devices/airam.js.map +1 -0
  38. package/devices/airzone_aidoo.d.ts +4 -0
  39. package/devices/airzone_aidoo.d.ts.map +1 -0
  40. package/devices/airzone_aidoo.js +81 -0
  41. package/devices/airzone_aidoo.js.map +1 -0
  42. package/devices/ajax_online.d.ts +4 -0
  43. package/devices/ajax_online.d.ts.map +1 -0
  44. package/devices/ajax_online.js +84 -0
  45. package/devices/ajax_online.js.map +1 -0
  46. package/devices/akuvox.d.ts +4 -0
  47. package/devices/akuvox.d.ts.map +1 -0
  48. package/devices/akuvox.js +68 -0
  49. package/devices/akuvox.js.map +1 -0
  50. package/devices/alchemy.d.ts +4 -0
  51. package/devices/alchemy.d.ts.map +1 -0
  52. package/devices/alchemy.js +22 -0
  53. package/devices/alchemy.js.map +1 -0
  54. package/devices/aldi.d.ts +4 -0
  55. package/devices/aldi.d.ts.map +1 -0
  56. package/devices/aldi.js +57 -0
  57. package/devices/aldi.js.map +1 -0
  58. package/devices/alecto.d.ts +4 -0
  59. package/devices/alecto.d.ts.map +1 -0
  60. package/devices/alecto.js +101 -0
  61. package/devices/alecto.js.map +1 -0
  62. package/devices/amina.d.ts +4 -0
  63. package/devices/amina.d.ts.map +1 -0
  64. package/devices/amina.js +370 -0
  65. package/devices/amina.js.map +1 -0
  66. package/devices/anchor.d.ts +4 -0
  67. package/devices/anchor.d.ts.map +1 -0
  68. package/devices/anchor.js +15 -0
  69. package/devices/anchor.js.map +1 -0
  70. package/devices/atlantic.d.ts +4 -0
  71. package/devices/atlantic.d.ts.map +1 -0
  72. package/devices/atlantic.js +146 -0
  73. package/devices/atlantic.js.map +1 -0
  74. package/devices/atsmart.d.ts +4 -0
  75. package/devices/atsmart.d.ts.map +1 -0
  76. package/devices/atsmart.js +15 -0
  77. package/devices/atsmart.js.map +1 -0
  78. package/devices/aubess.d.ts +4 -0
  79. package/devices/aubess.d.ts.map +1 -0
  80. package/devices/aubess.js +60 -0
  81. package/devices/aubess.js.map +1 -0
  82. package/devices/aurora_lighting.d.ts +4 -0
  83. package/devices/aurora_lighting.d.ts.map +1 -0
  84. package/devices/aurora_lighting.js +338 -0
  85. package/devices/aurora_lighting.js.map +1 -0
  86. package/devices/automaton.d.ts +4 -0
  87. package/devices/automaton.d.ts.map +1 -0
  88. package/devices/automaton.js +65 -0
  89. package/devices/automaton.js.map +1 -0
  90. package/devices/avatto.d.ts +4 -0
  91. package/devices/avatto.d.ts.map +1 -0
  92. package/devices/avatto.js +67 -0
  93. package/devices/avatto.js.map +1 -0
  94. package/devices/awox.d.ts +4 -0
  95. package/devices/awox.d.ts.map +1 -0
  96. package/devices/awox.js +240 -0
  97. package/devices/awox.js.map +1 -0
  98. package/devices/axis.d.ts +4 -0
  99. package/devices/axis.d.ts.map +1 -0
  100. package/devices/axis.js +63 -0
  101. package/devices/axis.js.map +1 -0
  102. package/devices/bankamp.d.ts +4 -0
  103. package/devices/bankamp.d.ts.map +1 -0
  104. package/devices/bankamp.js +15 -0
  105. package/devices/bankamp.js.map +1 -0
  106. package/devices/bega.d.ts +4 -0
  107. package/devices/bega.d.ts.map +1 -0
  108. package/devices/bega.js +29 -0
  109. package/devices/bega.js.map +1 -0
  110. package/devices/belkin.d.ts +4 -0
  111. package/devices/belkin.d.ts.map +1 -0
  112. package/devices/belkin.js +15 -0
  113. package/devices/belkin.js.map +1 -0
  114. package/devices/bitron.d.ts +4 -0
  115. package/devices/bitron.d.ts.map +1 -0
  116. package/devices/bitron.js +359 -0
  117. package/devices/bitron.js.map +1 -0
  118. package/devices/bituo_technik.d.ts +4 -0
  119. package/devices/bituo_technik.d.ts.map +1 -0
  120. package/devices/bituo_technik.js +121 -0
  121. package/devices/bituo_technik.js.map +1 -0
  122. package/devices/blaupunkt.d.ts +4 -0
  123. package/devices/blaupunkt.d.ts.map +1 -0
  124. package/devices/blaupunkt.js +68 -0
  125. package/devices/blaupunkt.js.map +1 -0
  126. package/devices/blitzwolf.d.ts +4 -0
  127. package/devices/blitzwolf.d.ts.map +1 -0
  128. package/devices/blitzwolf.js +73 -0
  129. package/devices/blitzwolf.js.map +1 -0
  130. package/devices/bosch.d.ts +4 -0
  131. package/devices/bosch.d.ts.map +1 -0
  132. package/devices/bosch.js +2048 -0
  133. package/devices/bosch.js.map +1 -0
  134. package/devices/bouffalo_lab.d.ts +4 -0
  135. package/devices/bouffalo_lab.d.ts.map +1 -0
  136. package/devices/bouffalo_lab.js +15 -0
  137. package/devices/bouffalo_lab.js.map +1 -0
  138. package/devices/brimate.d.ts +4 -0
  139. package/devices/brimate.d.ts.map +1 -0
  140. package/devices/brimate.js +55 -0
  141. package/devices/brimate.js.map +1 -0
  142. package/devices/bseed.d.ts +4 -0
  143. package/devices/bseed.d.ts.map +1 -0
  144. package/devices/bseed.js +57 -0
  145. package/devices/bseed.js.map +1 -0
  146. package/devices/bticino.d.ts +4 -0
  147. package/devices/bticino.d.ts.map +1 -0
  148. package/devices/bticino.js +113 -0
  149. package/devices/bticino.js.map +1 -0
  150. package/devices/busch_jaeger.d.ts +4 -0
  151. package/devices/busch_jaeger.d.ts.map +1 -0
  152. package/devices/busch_jaeger.js +186 -0
  153. package/devices/busch_jaeger.js.map +1 -0
  154. package/devices/byun.d.ts +4 -0
  155. package/devices/byun.d.ts.map +1 -0
  156. package/devices/byun.js +64 -0
  157. package/devices/byun.js.map +1 -0
  158. package/devices/calex.d.ts +4 -0
  159. package/devices/calex.d.ts.map +1 -0
  160. package/devices/calex.js +91 -0
  161. package/devices/calex.js.map +1 -0
  162. package/devices/candeo.d.ts +4 -0
  163. package/devices/candeo.d.ts.map +1 -0
  164. package/devices/candeo.js +185 -0
  165. package/devices/candeo.js.map +1 -0
  166. package/devices/casaia.d.ts +4 -0
  167. package/devices/casaia.d.ts.map +1 -0
  168. package/devices/casaia.js +99 -0
  169. package/devices/casaia.js.map +1 -0
  170. package/devices/cel.d.ts +4 -0
  171. package/devices/cel.d.ts.map +1 -0
  172. package/devices/cel.js +20 -0
  173. package/devices/cel.js.map +1 -0
  174. package/devices/centralite.d.ts +4 -0
  175. package/devices/centralite.d.ts.map +1 -0
  176. package/devices/centralite.js +444 -0
  177. package/devices/centralite.js.map +1 -0
  178. package/devices/chacon.d.ts +4 -0
  179. package/devices/chacon.d.ts.map +1 -0
  180. package/devices/chacon.js +18 -0
  181. package/devices/chacon.js.map +1 -0
  182. package/devices/cleode.d.ts +4 -0
  183. package/devices/cleode.d.ts.map +1 -0
  184. package/devices/cleode.js +15 -0
  185. package/devices/cleode.js.map +1 -0
  186. package/devices/cleverio.d.ts +4 -0
  187. package/devices/cleverio.d.ts.map +1 -0
  188. package/devices/cleverio.js +77 -0
  189. package/devices/cleverio.js.map +1 -0
  190. package/devices/climax.d.ts +4 -0
  191. package/devices/climax.d.ts.map +1 -0
  192. package/devices/climax.js +181 -0
  193. package/devices/climax.js.map +1 -0
  194. package/devices/commercial_electric.d.ts +4 -0
  195. package/devices/commercial_electric.d.ts.map +1 -0
  196. package/devices/commercial_electric.js +15 -0
  197. package/devices/commercial_electric.js.map +1 -0
  198. package/devices/cree.d.ts +4 -0
  199. package/devices/cree.d.ts.map +1 -0
  200. package/devices/cree.js +15 -0
  201. package/devices/cree.js.map +1 -0
  202. package/devices/ctm.d.ts +4 -0
  203. package/devices/ctm.d.ts.map +1 -0
  204. package/devices/ctm.js +1383 -0
  205. package/devices/ctm.js.map +1 -0
  206. package/devices/current_products_corp.d.ts +4 -0
  207. package/devices/current_products_corp.d.ts.map +1 -0
  208. package/devices/current_products_corp.js +64 -0
  209. package/devices/current_products_corp.js.map +1 -0
  210. package/devices/custom_devices_diy.d.ts +4 -0
  211. package/devices/custom_devices_diy.d.ts.map +1 -0
  212. package/devices/custom_devices_diy.js +1206 -0
  213. package/devices/custom_devices_diy.js.map +1 -0
  214. package/devices/cy_lighting.d.ts +4 -0
  215. package/devices/cy_lighting.d.ts.map +1 -0
  216. package/devices/cy_lighting.js +15 -0
  217. package/devices/cy_lighting.js.map +1 -0
  218. package/devices/danalock.d.ts +4 -0
  219. package/devices/danalock.d.ts.map +1 -0
  220. package/devices/danalock.js +65 -0
  221. package/devices/danalock.js.map +1 -0
  222. package/devices/danfoss.d.ts +4 -0
  223. package/devices/danfoss.d.ts.map +1 -0
  224. package/devices/danfoss.js +743 -0
  225. package/devices/danfoss.js.map +1 -0
  226. package/devices/databyte.d.ts +4 -0
  227. package/devices/databyte.d.ts.map +1 -0
  228. package/devices/databyte.js +95 -0
  229. package/devices/databyte.js.map +1 -0
  230. package/devices/datek.d.ts +4 -0
  231. package/devices/datek.d.ts.map +1 -0
  232. package/devices/datek.js +298 -0
  233. package/devices/datek.js.map +1 -0
  234. package/devices/dawon_dns.d.ts +4 -0
  235. package/devices/dawon_dns.d.ts.map +1 -0
  236. package/devices/dawon_dns.js +318 -0
  237. package/devices/dawon_dns.js.map +1 -0
  238. package/devices/develco.d.ts +4 -0
  239. package/devices/develco.d.ts.map +1 -0
  240. package/devices/develco.js +1037 -0
  241. package/devices/develco.js.map +1 -0
  242. package/devices/digi.d.ts +4 -0
  243. package/devices/digi.d.ts.map +1 -0
  244. package/devices/digi.js +25 -0
  245. package/devices/digi.js.map +1 -0
  246. package/devices/diyruz.d.ts +4 -0
  247. package/devices/diyruz.d.ts.map +1 -0
  248. package/devices/diyruz.js +403 -0
  249. package/devices/diyruz.js.map +1 -0
  250. package/devices/dlink.d.ts +4 -0
  251. package/devices/dlink.d.ts.map +1 -0
  252. package/devices/dlink.js +76 -0
  253. package/devices/dlink.js.map +1 -0
  254. package/devices/dnake.d.ts +4 -0
  255. package/devices/dnake.d.ts.map +1 -0
  256. package/devices/dnake.js +15 -0
  257. package/devices/dnake.js.map +1 -0
  258. package/devices/dowsing_reynolds.d.ts +4 -0
  259. package/devices/dowsing_reynolds.d.ts.map +1 -0
  260. package/devices/dowsing_reynolds.js +15 -0
  261. package/devices/dowsing_reynolds.js.map +1 -0
  262. package/devices/dresden_elektronik.d.ts +4 -0
  263. package/devices/dresden_elektronik.d.ts.map +1 -0
  264. package/devices/dresden_elektronik.js +50 -0
  265. package/devices/dresden_elektronik.js.map +1 -0
  266. package/devices/easyaccess.d.ts +4 -0
  267. package/devices/easyaccess.d.ts.map +1 -0
  268. package/devices/easyaccess.js +71 -0
  269. package/devices/easyaccess.js.map +1 -0
  270. package/devices/easyiot.d.ts +4 -0
  271. package/devices/easyiot.d.ts.map +1 -0
  272. package/devices/easyiot.js +358 -0
  273. package/devices/easyiot.js.map +1 -0
  274. package/devices/eatonhalo_led.d.ts +4 -0
  275. package/devices/eatonhalo_led.d.ts.map +1 -0
  276. package/devices/eatonhalo_led.js +15 -0
  277. package/devices/eatonhalo_led.js.map +1 -0
  278. package/devices/echostar.d.ts +4 -0
  279. package/devices/echostar.d.ts.map +1 -0
  280. package/devices/echostar.js +65 -0
  281. package/devices/echostar.js.map +1 -0
  282. package/devices/ecodim.d.ts +4 -0
  283. package/devices/ecodim.d.ts.map +1 -0
  284. package/devices/ecodim.js +270 -0
  285. package/devices/ecodim.js.map +1 -0
  286. package/devices/ecolink.d.ts +4 -0
  287. package/devices/ecolink.d.ts.map +1 -0
  288. package/devices/ecolink.js +61 -0
  289. package/devices/ecolink.js.map +1 -0
  290. package/devices/ecosmart.d.ts +4 -0
  291. package/devices/ecosmart.d.ts.map +1 -0
  292. package/devices/ecosmart.js +83 -0
  293. package/devices/ecosmart.js.map +1 -0
  294. package/devices/ecozy.d.ts +4 -0
  295. package/devices/ecozy.d.ts.map +1 -0
  296. package/devices/ecozy.js +89 -0
  297. package/devices/ecozy.js.map +1 -0
  298. package/devices/edp.d.ts +4 -0
  299. package/devices/edp.d.ts.map +1 -0
  300. package/devices/edp.js +74 -0
  301. package/devices/edp.js.map +1 -0
  302. package/devices/efekta.d.ts +4 -0
  303. package/devices/efekta.d.ts.map +1 -0
  304. package/devices/efekta.js +754 -0
  305. package/devices/efekta.js.map +1 -0
  306. package/devices/eglo.d.ts +4 -0
  307. package/devices/eglo.d.ts.map +1 -0
  308. package/devices/eglo.js +132 -0
  309. package/devices/eglo.js.map +1 -0
  310. package/devices/elko.d.ts +4 -0
  311. package/devices/elko.d.ts.map +1 -0
  312. package/devices/elko.js +240 -0
  313. package/devices/elko.js.map +1 -0
  314. package/devices/enbrighten.d.ts +4 -0
  315. package/devices/enbrighten.d.ts.map +1 -0
  316. package/devices/enbrighten.js +97 -0
  317. package/devices/enbrighten.js.map +1 -0
  318. package/devices/enocean.d.ts +4 -0
  319. package/devices/enocean.d.ts.map +1 -0
  320. package/devices/enocean.js +153 -0
  321. package/devices/enocean.js.map +1 -0
  322. package/devices/envilar.d.ts +4 -0
  323. package/devices/envilar.d.ts.map +1 -0
  324. package/devices/envilar.js +100 -0
  325. package/devices/envilar.js.map +1 -0
  326. package/devices/essentialb.d.ts +4 -0
  327. package/devices/essentialb.d.ts.map +1 -0
  328. package/devices/essentialb.js +137 -0
  329. package/devices/essentialb.js.map +1 -0
  330. package/devices/essentials.d.ts +4 -0
  331. package/devices/essentials.d.ts.map +1 -0
  332. package/devices/essentials.js +151 -0
  333. package/devices/essentials.js.map +1 -0
  334. package/devices/eucontrols.d.ts +4 -0
  335. package/devices/eucontrols.d.ts.map +1 -0
  336. package/devices/eucontrols.js +15 -0
  337. package/devices/eucontrols.js.map +1 -0
  338. package/devices/eurotronic.d.ts +4 -0
  339. package/devices/eurotronic.d.ts.map +1 -0
  340. package/devices/eurotronic.js +128 -0
  341. package/devices/eurotronic.js.map +1 -0
  342. package/devices/evanell.d.ts +4 -0
  343. package/devices/evanell.d.ts.map +1 -0
  344. package/devices/evanell.js +75 -0
  345. package/devices/evanell.js.map +1 -0
  346. package/devices/evn.d.ts +4 -0
  347. package/devices/evn.d.ts.map +1 -0
  348. package/devices/evn.js +94 -0
  349. package/devices/evn.js.map +1 -0
  350. package/devices/evology.d.ts +4 -0
  351. package/devices/evology.d.ts.map +1 -0
  352. package/devices/evology.js +64 -0
  353. package/devices/evology.js.map +1 -0
  354. package/devices/evvr.d.ts +4 -0
  355. package/devices/evvr.d.ts.map +1 -0
  356. package/devices/evvr.js +15 -0
  357. package/devices/evvr.js.map +1 -0
  358. package/devices/ewelink.d.ts +4 -0
  359. package/devices/ewelink.d.ts.map +1 -0
  360. package/devices/ewelink.js +343 -0
  361. package/devices/ewelink.js.map +1 -0
  362. package/devices/ezex.d.ts +4 -0
  363. package/devices/ezex.d.ts.map +1 -0
  364. package/devices/ezex.js +15 -0
  365. package/devices/ezex.js.map +1 -0
  366. package/devices/fantem.d.ts +4 -0
  367. package/devices/fantem.d.ts.map +1 -0
  368. package/devices/fantem.js +118 -0
  369. package/devices/fantem.js.map +1 -0
  370. package/devices/feibit.d.ts +4 -0
  371. package/devices/feibit.d.ts.map +1 -0
  372. package/devices/feibit.js +334 -0
  373. package/devices/feibit.js.map +1 -0
  374. package/devices/fireangel.d.ts +4 -0
  375. package/devices/fireangel.d.ts.map +1 -0
  376. package/devices/fireangel.js +55 -0
  377. package/devices/fireangel.js.map +1 -0
  378. package/devices/frankever.d.ts +4 -0
  379. package/devices/frankever.d.ts.map +1 -0
  380. package/devices/frankever.js +71 -0
  381. package/devices/frankever.js.map +1 -0
  382. package/devices/frient.d.ts +4 -0
  383. package/devices/frient.d.ts.map +1 -0
  384. package/devices/frient.js +42 -0
  385. package/devices/frient.js.map +1 -0
  386. package/devices/futurehome.d.ts +4 -0
  387. package/devices/futurehome.d.ts.map +1 -0
  388. package/devices/futurehome.js +124 -0
  389. package/devices/futurehome.js.map +1 -0
  390. package/devices/ge.d.ts +4 -0
  391. package/devices/ge.d.ts.map +1 -0
  392. package/devices/ge.js +134 -0
  393. package/devices/ge.js.map +1 -0
  394. package/devices/gewiss.d.ts +4 -0
  395. package/devices/gewiss.d.ts.map +1 -0
  396. package/devices/gewiss.js +78 -0
  397. package/devices/gewiss.js.map +1 -0
  398. package/devices/gidealed.d.ts +4 -0
  399. package/devices/gidealed.d.ts.map +1 -0
  400. package/devices/gidealed.js +15 -0
  401. package/devices/gidealed.js.map +1 -0
  402. package/devices/giderwel.d.ts +4 -0
  403. package/devices/giderwel.d.ts.map +1 -0
  404. package/devices/giderwel.js +15 -0
  405. package/devices/giderwel.js.map +1 -0
  406. package/devices/giex.d.ts +4 -0
  407. package/devices/giex.d.ts.map +1 -0
  408. package/devices/giex.js +121 -0
  409. package/devices/giex.js.map +1 -0
  410. package/devices/girier.d.ts +4 -0
  411. package/devices/girier.d.ts.map +1 -0
  412. package/devices/girier.js +56 -0
  413. package/devices/girier.js.map +1 -0
  414. package/devices/gledopto.d.ts +4 -0
  415. package/devices/gledopto.d.ts.map +1 -0
  416. package/devices/gledopto.js +1046 -0
  417. package/devices/gledopto.js.map +1 -0
  418. package/devices/gmmts.d.ts +4 -0
  419. package/devices/gmmts.d.ts.map +1 -0
  420. package/devices/gmmts.js +2287 -0
  421. package/devices/gmmts.js.map +1 -0
  422. package/devices/gmy.d.ts +4 -0
  423. package/devices/gmy.d.ts.map +1 -0
  424. package/devices/gmy.js +15 -0
  425. package/devices/gmy.js.map +1 -0
  426. package/devices/gs.d.ts +4 -0
  427. package/devices/gs.d.ts.map +1 -0
  428. package/devices/gs.js +89 -0
  429. package/devices/gs.js.map +1 -0
  430. package/devices/gumax.d.ts +4 -0
  431. package/devices/gumax.d.ts.map +1 -0
  432. package/devices/gumax.js +15 -0
  433. package/devices/gumax.js.map +1 -0
  434. package/devices/halemeier.d.ts +4 -0
  435. package/devices/halemeier.d.ts.map +1 -0
  436. package/devices/halemeier.js +129 -0
  437. package/devices/halemeier.js.map +1 -0
  438. package/devices/hampton_bay.d.ts +4 -0
  439. package/devices/hampton_bay.d.ts.map +1 -0
  440. package/devices/hampton_bay.js +72 -0
  441. package/devices/hampton_bay.js.map +1 -0
  442. package/devices/heatit.d.ts +4 -0
  443. package/devices/heatit.d.ts.map +1 -0
  444. package/devices/heatit.js +15 -0
  445. package/devices/heatit.js.map +1 -0
  446. package/devices/heiman.d.ts +4 -0
  447. package/devices/heiman.d.ts.map +1 -0
  448. package/devices/heiman.js +807 -0
  449. package/devices/heiman.js.map +1 -0
  450. package/devices/heimgard_technologies.d.ts +4 -0
  451. package/devices/heimgard_technologies.d.ts.map +1 -0
  452. package/devices/heimgard_technologies.js +193 -0
  453. package/devices/heimgard_technologies.js.map +1 -0
  454. package/devices/hej.d.ts +4 -0
  455. package/devices/hej.d.ts.map +1 -0
  456. package/devices/hej.js +73 -0
  457. package/devices/hej.js.map +1 -0
  458. package/devices/hfh.d.ts +4 -0
  459. package/devices/hfh.d.ts.map +1 -0
  460. package/devices/hfh.js +15 -0
  461. package/devices/hfh.js.map +1 -0
  462. package/devices/hilux.d.ts +4 -0
  463. package/devices/hilux.d.ts.map +1 -0
  464. package/devices/hilux.js +22 -0
  465. package/devices/hilux.js.map +1 -0
  466. package/devices/hive.d.ts +4 -0
  467. package/devices/hive.d.ts.map +1 -0
  468. package/devices/hive.js +766 -0
  469. package/devices/hive.js.map +1 -0
  470. package/devices/hommyn.d.ts +4 -0
  471. package/devices/hommyn.d.ts.map +1 -0
  472. package/devices/hommyn.js +64 -0
  473. package/devices/hommyn.js.map +1 -0
  474. package/devices/honyar.d.ts +4 -0
  475. package/devices/honyar.d.ts.map +1 -0
  476. package/devices/honyar.js +171 -0
  477. package/devices/honyar.js.map +1 -0
  478. package/devices/hornbach.d.ts +4 -0
  479. package/devices/hornbach.d.ts.map +1 -0
  480. package/devices/hornbach.js +99 -0
  481. package/devices/hornbach.js.map +1 -0
  482. package/devices/hzc_electric.d.ts +4 -0
  483. package/devices/hzc_electric.d.ts.map +1 -0
  484. package/devices/hzc_electric.js +94 -0
  485. package/devices/hzc_electric.js.map +1 -0
  486. package/devices/icasa.d.ts +4 -0
  487. package/devices/icasa.d.ts.map +1 -0
  488. package/devices/icasa.js +167 -0
  489. package/devices/icasa.js.map +1 -0
  490. package/devices/idinio.d.ts +4 -0
  491. package/devices/idinio.d.ts.map +1 -0
  492. package/devices/idinio.js +15 -0
  493. package/devices/idinio.js.map +1 -0
  494. package/devices/ihorn.d.ts +4 -0
  495. package/devices/ihorn.d.ts.map +1 -0
  496. package/devices/ihorn.js +109 -0
  497. package/devices/ihorn.js.map +1 -0
  498. package/devices/ikea.d.ts +4 -0
  499. package/devices/ikea.d.ts.map +1 -0
  500. package/devices/ikea.js +927 -0
  501. package/devices/ikea.js.map +1 -0
  502. package/devices/ilightsin.d.ts +4 -0
  503. package/devices/ilightsin.d.ts.map +1 -0
  504. package/devices/ilightsin.js +15 -0
  505. package/devices/ilightsin.js.map +1 -0
  506. package/devices/iluminize.d.ts +4 -0
  507. package/devices/iluminize.d.ts.map +1 -0
  508. package/devices/iluminize.js +376 -0
  509. package/devices/iluminize.js.map +1 -0
  510. package/devices/ilux.d.ts +4 -0
  511. package/devices/ilux.d.ts.map +1 -0
  512. package/devices/ilux.js +15 -0
  513. package/devices/ilux.js.map +1 -0
  514. package/devices/imhotepcreation.d.ts +4 -0
  515. package/devices/imhotepcreation.d.ts.map +1 -0
  516. package/devices/imhotepcreation.js +251 -0
  517. package/devices/imhotepcreation.js.map +1 -0
  518. package/devices/immax.d.ts +4 -0
  519. package/devices/immax.d.ts.map +1 -0
  520. package/devices/immax.js +304 -0
  521. package/devices/immax.js.map +1 -0
  522. package/devices/imou.d.ts +4 -0
  523. package/devices/imou.d.ts.map +1 -0
  524. package/devices/imou.js +28 -0
  525. package/devices/imou.js.map +1 -0
  526. package/devices/index.d.ts +13 -0
  527. package/devices/index.d.ts.map +1 -0
  528. package/devices/index.js +642 -0
  529. package/devices/index.js.map +1 -0
  530. package/devices/innr.d.ts +4 -0
  531. package/devices/innr.d.ts.map +1 -0
  532. package/devices/innr.js +878 -0
  533. package/devices/innr.js.map +1 -0
  534. package/devices/inovelli.d.ts +4 -0
  535. package/devices/inovelli.d.ts.map +1 -0
  536. package/devices/inovelli.js +1977 -0
  537. package/devices/inovelli.js.map +1 -0
  538. package/devices/insta.d.ts +4 -0
  539. package/devices/insta.d.ts.map +1 -0
  540. package/devices/insta.js +186 -0
  541. package/devices/insta.js.map +1 -0
  542. package/devices/iolloi.d.ts +4 -0
  543. package/devices/iolloi.d.ts.map +1 -0
  544. package/devices/iolloi.js +16 -0
  545. package/devices/iolloi.js.map +1 -0
  546. package/devices/iotperfect.d.ts +4 -0
  547. package/devices/iotperfect.d.ts.map +1 -0
  548. package/devices/iotperfect.js +62 -0
  549. package/devices/iotperfect.js.map +1 -0
  550. package/devices/iris.d.ts +4 -0
  551. package/devices/iris.d.ts.map +1 -0
  552. package/devices/iris.js +211 -0
  553. package/devices/iris.js.map +1 -0
  554. package/devices/istar.d.ts +4 -0
  555. package/devices/istar.d.ts.map +1 -0
  556. package/devices/istar.js +22 -0
  557. package/devices/istar.js.map +1 -0
  558. package/devices/jasco.d.ts +4 -0
  559. package/devices/jasco.d.ts.map +1 -0
  560. package/devices/jasco.js +34 -0
  561. package/devices/jasco.js.map +1 -0
  562. package/devices/javis.d.ts +4 -0
  563. package/devices/javis.d.ts.map +1 -0
  564. package/devices/javis.js +84 -0
  565. package/devices/javis.js.map +1 -0
  566. package/devices/jethome.d.ts +4 -0
  567. package/devices/jethome.d.ts.map +1 -0
  568. package/devices/jethome.js +124 -0
  569. package/devices/jethome.js.map +1 -0
  570. package/devices/jiawen.d.ts +4 -0
  571. package/devices/jiawen.d.ts.map +1 -0
  572. package/devices/jiawen.js +22 -0
  573. package/devices/jiawen.js.map +1 -0
  574. package/devices/jumitech.d.ts +4 -0
  575. package/devices/jumitech.d.ts.map +1 -0
  576. package/devices/jumitech.js +15 -0
  577. package/devices/jumitech.js.map +1 -0
  578. package/devices/jxuan.d.ts +4 -0
  579. package/devices/jxuan.d.ts.map +1 -0
  580. package/devices/jxuan.js +89 -0
  581. package/devices/jxuan.js.map +1 -0
  582. package/devices/kami.d.ts +4 -0
  583. package/devices/kami.d.ts.map +1 -0
  584. package/devices/kami.js +55 -0
  585. package/devices/kami.js.map +1 -0
  586. package/devices/keen_home.d.ts +4 -0
  587. package/devices/keen_home.d.ts.map +1 -0
  588. package/devices/keen_home.js +160 -0
  589. package/devices/keen_home.js.map +1 -0
  590. package/devices/klikaanklikuit.d.ts +4 -0
  591. package/devices/klikaanklikuit.d.ts.map +1 -0
  592. package/devices/klikaanklikuit.js +22 -0
  593. package/devices/klikaanklikuit.js.map +1 -0
  594. package/devices/kmpcil.d.ts +4 -0
  595. package/devices/kmpcil.d.ts.map +1 -0
  596. package/devices/kmpcil.js +219 -0
  597. package/devices/kmpcil.js.map +1 -0
  598. package/devices/konke.d.ts +4 -0
  599. package/devices/konke.d.ts.map +1 -0
  600. package/devices/konke.js +210 -0
  601. package/devices/konke.js.map +1 -0
  602. package/devices/ksentry.d.ts +4 -0
  603. package/devices/ksentry.d.ts.map +1 -0
  604. package/devices/ksentry.js +15 -0
  605. package/devices/ksentry.js.map +1 -0
  606. package/devices/kurvia.d.ts +4 -0
  607. package/devices/kurvia.d.ts.map +1 -0
  608. package/devices/kurvia.js +20 -0
  609. package/devices/kurvia.js.map +1 -0
  610. package/devices/kwikset.d.ts +4 -0
  611. package/devices/kwikset.d.ts.map +1 -0
  612. package/devices/kwikset.js +157 -0
  613. package/devices/kwikset.js.map +1 -0
  614. package/devices/lanesto.d.ts +4 -0
  615. package/devices/lanesto.d.ts.map +1 -0
  616. package/devices/lanesto.js +15 -0
  617. package/devices/lanesto.js.map +1 -0
  618. package/devices/lds.d.ts +4 -0
  619. package/devices/lds.d.ts.map +1 -0
  620. package/devices/lds.js +15 -0
  621. package/devices/lds.js.map +1 -0
  622. package/devices/led_trading.d.ts +4 -0
  623. package/devices/led_trading.d.ts.map +1 -0
  624. package/devices/led_trading.js +112 -0
  625. package/devices/led_trading.js.map +1 -0
  626. package/devices/ledvance.d.ts +4 -0
  627. package/devices/ledvance.d.ts.map +1 -0
  628. package/devices/ledvance.js +337 -0
  629. package/devices/ledvance.js.map +1 -0
  630. package/devices/leedarson.d.ts +4 -0
  631. package/devices/leedarson.d.ts.map +1 -0
  632. package/devices/leedarson.js +182 -0
  633. package/devices/leedarson.js.map +1 -0
  634. package/devices/legrand.d.ts +4 -0
  635. package/devices/legrand.d.ts.map +1 -0
  636. package/devices/legrand.js +740 -0
  637. package/devices/legrand.js.map +1 -0
  638. package/devices/lellki.d.ts +4 -0
  639. package/devices/lellki.d.ts.map +1 -0
  640. package/devices/lellki.js +169 -0
  641. package/devices/lellki.js.map +1 -0
  642. package/devices/letsled.d.ts +4 -0
  643. package/devices/letsled.d.ts.map +1 -0
  644. package/devices/letsled.js +15 -0
  645. package/devices/letsled.js.map +1 -0
  646. package/devices/letv.d.ts +4 -0
  647. package/devices/letv.d.ts.map +1 -0
  648. package/devices/letv.js +90 -0
  649. package/devices/letv.js.map +1 -0
  650. package/devices/leviton.d.ts +4 -0
  651. package/devices/leviton.d.ts.map +1 -0
  652. package/devices/leviton.js +164 -0
  653. package/devices/leviton.js.map +1 -0
  654. package/devices/lg.d.ts +4 -0
  655. package/devices/lg.d.ts.map +1 -0
  656. package/devices/lg.js +29 -0
  657. package/devices/lg.js.map +1 -0
  658. package/devices/lidl.d.ts +4 -0
  659. package/devices/lidl.d.ts.map +1 -0
  660. package/devices/lidl.js +674 -0
  661. package/devices/lidl.js.map +1 -0
  662. package/devices/lifecontrol.d.ts +4 -0
  663. package/devices/lifecontrol.d.ts.map +1 -0
  664. package/devices/lifecontrol.js +149 -0
  665. package/devices/lifecontrol.js.map +1 -0
  666. package/devices/lightsolutions.d.ts +4 -0
  667. package/devices/lightsolutions.d.ts.map +1 -0
  668. package/devices/lightsolutions.js +36 -0
  669. package/devices/lightsolutions.js.map +1 -0
  670. package/devices/linkind.d.ts +4 -0
  671. package/devices/linkind.d.ts.map +1 -0
  672. package/devices/linkind.js +275 -0
  673. package/devices/linkind.js.map +1 -0
  674. package/devices/linptech.d.ts +4 -0
  675. package/devices/linptech.d.ts.map +1 -0
  676. package/devices/linptech.js +159 -0
  677. package/devices/linptech.js.map +1 -0
  678. package/devices/livingwise.d.ts +4 -0
  679. package/devices/livingwise.d.ts.map +1 -0
  680. package/devices/livingwise.js +119 -0
  681. package/devices/livingwise.js.map +1 -0
  682. package/devices/livolo.d.ts +4 -0
  683. package/devices/livolo.d.ts.map +1 -0
  684. package/devices/livolo.js +422 -0
  685. package/devices/livolo.js.map +1 -0
  686. package/devices/lixee.d.ts +4 -0
  687. package/devices/lixee.d.ts.map +1 -0
  688. package/devices/lixee.js +1926 -0
  689. package/devices/lixee.js.map +1 -0
  690. package/devices/lonsonho.d.ts +4 -0
  691. package/devices/lonsonho.d.ts.map +1 -0
  692. package/devices/lonsonho.js +303 -0
  693. package/devices/lonsonho.js.map +1 -0
  694. package/devices/ls.d.ts +4 -0
  695. package/devices/ls.d.ts.map +1 -0
  696. package/devices/ls.js +68 -0
  697. package/devices/ls.js.map +1 -0
  698. package/devices/lubeez.d.ts +4 -0
  699. package/devices/lubeez.d.ts.map +1 -0
  700. package/devices/lubeez.js +15 -0
  701. package/devices/lubeez.js.map +1 -0
  702. package/devices/lumi.d.ts +4 -0
  703. package/devices/lumi.d.ts.map +1 -0
  704. package/devices/lumi.js +4387 -0
  705. package/devices/lumi.js.map +1 -0
  706. package/devices/lupus.d.ts +4 -0
  707. package/devices/lupus.d.ts.map +1 -0
  708. package/devices/lupus.js +98 -0
  709. package/devices/lupus.js.map +1 -0
  710. package/devices/lutron.d.ts +4 -0
  711. package/devices/lutron.d.ts.map +1 -0
  712. package/devices/lutron.js +71 -0
  713. package/devices/lutron.js.map +1 -0
  714. package/devices/lux.d.ts +4 -0
  715. package/devices/lux.d.ts.map +1 -0
  716. package/devices/lux.js +91 -0
  717. package/devices/lux.js.map +1 -0
  718. package/devices/lytko.d.ts +4 -0
  719. package/devices/lytko.d.ts.map +1 -0
  720. package/devices/lytko.js +788 -0
  721. package/devices/lytko.js.map +1 -0
  722. package/devices/m_elec.d.ts +4 -0
  723. package/devices/m_elec.d.ts.map +1 -0
  724. package/devices/m_elec.js +36 -0
  725. package/devices/m_elec.js.map +1 -0
  726. package/devices/makegood.d.ts +4 -0
  727. package/devices/makegood.d.ts.map +1 -0
  728. package/devices/makegood.js +66 -0
  729. package/devices/makegood.js.map +1 -0
  730. package/devices/matcall_bv.d.ts +4 -0
  731. package/devices/matcall_bv.d.ts.map +1 -0
  732. package/devices/matcall_bv.js +22 -0
  733. package/devices/matcall_bv.js.map +1 -0
  734. package/devices/mazda.d.ts +4 -0
  735. package/devices/mazda.d.ts.map +1 -0
  736. package/devices/mazda.js +174 -0
  737. package/devices/mazda.js.map +1 -0
  738. package/devices/meazon.d.ts +4 -0
  739. package/devices/meazon.d.ts.map +1 -0
  740. package/devices/meazon.js +99 -0
  741. package/devices/meazon.js.map +1 -0
  742. package/devices/mercator.d.ts +4 -0
  743. package/devices/mercator.d.ts.map +1 -0
  744. package/devices/mercator.js +256 -0
  745. package/devices/mercator.js.map +1 -0
  746. package/devices/miboxer.d.ts +4 -0
  747. package/devices/miboxer.d.ts.map +1 -0
  748. package/devices/miboxer.js +93 -0
  749. package/devices/miboxer.js.map +1 -0
  750. package/devices/micromatic.d.ts +4 -0
  751. package/devices/micromatic.d.ts.map +1 -0
  752. package/devices/micromatic.js +15 -0
  753. package/devices/micromatic.js.map +1 -0
  754. package/devices/modular.d.ts +4 -0
  755. package/devices/modular.d.ts.map +1 -0
  756. package/devices/modular.js +15 -0
  757. package/devices/modular.js.map +1 -0
  758. package/devices/moes.d.ts +4 -0
  759. package/devices/moes.d.ts.map +1 -0
  760. package/devices/moes.js +654 -0
  761. package/devices/moes.js.map +1 -0
  762. package/devices/muller_licht.d.ts +4 -0
  763. package/devices/muller_licht.d.ts.map +1 -0
  764. package/devices/muller_licht.js +341 -0
  765. package/devices/muller_licht.js.map +1 -0
  766. package/devices/multiterm.d.ts +4 -0
  767. package/devices/multiterm.d.ts.map +1 -0
  768. package/devices/multiterm.js +123 -0
  769. package/devices/multiterm.js.map +1 -0
  770. package/devices/namron.d.ts +4 -0
  771. package/devices/namron.d.ts.map +1 -0
  772. package/devices/namron.js +1464 -0
  773. package/devices/namron.js.map +1 -0
  774. package/devices/nanoleaf.d.ts +4 -0
  775. package/devices/nanoleaf.d.ts.map +1 -0
  776. package/devices/nanoleaf.js +15 -0
  777. package/devices/nanoleaf.js.map +1 -0
  778. package/devices/nedis.d.ts +4 -0
  779. package/devices/nedis.d.ts.map +1 -0
  780. package/devices/nedis.js +88 -0
  781. package/devices/nedis.js.map +1 -0
  782. package/devices/neo.d.ts +4 -0
  783. package/devices/neo.d.ts.map +1 -0
  784. package/devices/neo.js +558 -0
  785. package/devices/neo.js.map +1 -0
  786. package/devices/net2grid.d.ts +4 -0
  787. package/devices/net2grid.d.ts.map +1 -0
  788. package/devices/net2grid.js +68 -0
  789. package/devices/net2grid.js.map +1 -0
  790. package/devices/netvox.d.ts +4 -0
  791. package/devices/netvox.d.ts.map +1 -0
  792. package/devices/netvox.js +75 -0
  793. package/devices/netvox.js.map +1 -0
  794. package/devices/nexelec.d.ts +4 -0
  795. package/devices/nexelec.d.ts.map +1 -0
  796. package/devices/nexelec.js +15 -0
  797. package/devices/nexelec.js.map +1 -0
  798. package/devices/niko.d.ts +4 -0
  799. package/devices/niko.d.ts.map +1 -0
  800. package/devices/niko.js +495 -0
  801. package/devices/niko.js.map +1 -0
  802. package/devices/ninja_blocks.d.ts +4 -0
  803. package/devices/ninja_blocks.d.ts.map +1 -0
  804. package/devices/ninja_blocks.js +64 -0
  805. package/devices/ninja_blocks.js.map +1 -0
  806. package/devices/niviss.d.ts +4 -0
  807. package/devices/niviss.d.ts.map +1 -0
  808. package/devices/niviss.js +15 -0
  809. package/devices/niviss.js.map +1 -0
  810. package/devices/nodon.d.ts +4 -0
  811. package/devices/nodon.d.ts.map +1 -0
  812. package/devices/nodon.js +386 -0
  813. package/devices/nodon.js.map +1 -0
  814. package/devices/nordtronic.d.ts +4 -0
  815. package/devices/nordtronic.d.ts.map +1 -0
  816. package/devices/nordtronic.js +41 -0
  817. package/devices/nordtronic.js.map +1 -0
  818. package/devices/nous.d.ts +4 -0
  819. package/devices/nous.d.ts.map +1 -0
  820. package/devices/nous.js +151 -0
  821. package/devices/nous.js.map +1 -0
  822. package/devices/novo.d.ts +4 -0
  823. package/devices/novo.d.ts.map +1 -0
  824. package/devices/novo.js +57 -0
  825. package/devices/novo.js.map +1 -0
  826. package/devices/nue_3a.d.ts +4 -0
  827. package/devices/nue_3a.d.ts.map +1 -0
  828. package/devices/nue_3a.js +361 -0
  829. package/devices/nue_3a.js.map +1 -0
  830. package/devices/nyce.d.ts +4 -0
  831. package/devices/nyce.d.ts.map +1 -0
  832. package/devices/nyce.js +134 -0
  833. package/devices/nyce.js.map +1 -0
  834. package/devices/onenuo.d.ts +4 -0
  835. package/devices/onenuo.d.ts.map +1 -0
  836. package/devices/onenuo.js +86 -0
  837. package/devices/onenuo.js.map +1 -0
  838. package/devices/onesti.d.ts +4 -0
  839. package/devices/onesti.d.ts.map +1 -0
  840. package/devices/onesti.js +208 -0
  841. package/devices/onesti.js.map +1 -0
  842. package/devices/openlumi.d.ts +4 -0
  843. package/devices/openlumi.d.ts.map +1 -0
  844. package/devices/openlumi.js +62 -0
  845. package/devices/openlumi.js.map +1 -0
  846. package/devices/orvibo.d.ts +4 -0
  847. package/devices/orvibo.d.ts.map +1 -0
  848. package/devices/orvibo.js +391 -0
  849. package/devices/orvibo.js.map +1 -0
  850. package/devices/osram.d.ts +4 -0
  851. package/devices/osram.d.ts.map +1 -0
  852. package/devices/osram.js +516 -0
  853. package/devices/osram.js.map +1 -0
  854. package/devices/oujiabao.d.ts +4 -0
  855. package/devices/oujiabao.d.ts.map +1 -0
  856. package/devices/oujiabao.js +55 -0
  857. package/devices/oujiabao.js.map +1 -0
  858. package/devices/owon.d.ts +4 -0
  859. package/devices/owon.d.ts.map +1 -0
  860. package/devices/owon.js +478 -0
  861. package/devices/owon.js.map +1 -0
  862. package/devices/ozsmartthings.d.ts +4 -0
  863. package/devices/ozsmartthings.d.ts.map +1 -0
  864. package/devices/ozsmartthings.js +48 -0
  865. package/devices/ozsmartthings.js.map +1 -0
  866. package/devices/paul_neuhaus.d.ts +4 -0
  867. package/devices/paul_neuhaus.d.ts.map +1 -0
  868. package/devices/paul_neuhaus.js +194 -0
  869. package/devices/paul_neuhaus.js.map +1 -0
  870. package/devices/paulmann.d.ts +4 -0
  871. package/devices/paulmann.d.ts.map +1 -0
  872. package/devices/paulmann.js +330 -0
  873. package/devices/paulmann.js.map +1 -0
  874. package/devices/peq.d.ts +4 -0
  875. package/devices/peq.d.ts.map +1 -0
  876. package/devices/peq.js +64 -0
  877. package/devices/peq.js.map +1 -0
  878. package/devices/perenio.d.ts +4 -0
  879. package/devices/perenio.d.ts.map +1 -0
  880. package/devices/perenio.js +468 -0
  881. package/devices/perenio.js.map +1 -0
  882. package/devices/philio.d.ts +4 -0
  883. package/devices/philio.d.ts.map +1 -0
  884. package/devices/philio.js +16 -0
  885. package/devices/philio.js.map +1 -0
  886. package/devices/philips.d.ts +4 -0
  887. package/devices/philips.d.ts.map +1 -0
  888. package/devices/philips.js +4051 -0
  889. package/devices/philips.js.map +1 -0
  890. package/devices/plaid.d.ts +4 -0
  891. package/devices/plaid.d.ts.map +1 -0
  892. package/devices/plaid.js +65 -0
  893. package/devices/plaid.js.map +1 -0
  894. package/devices/plugwise.d.ts +4 -0
  895. package/devices/plugwise.d.ts.map +1 -0
  896. package/devices/plugwise.js +210 -0
  897. package/devices/plugwise.js.map +1 -0
  898. package/devices/profalux.d.ts +4 -0
  899. package/devices/profalux.d.ts.map +1 -0
  900. package/devices/profalux.js +191 -0
  901. package/devices/profalux.js.map +1 -0
  902. package/devices/prolight.d.ts +4 -0
  903. package/devices/prolight.d.ts.map +1 -0
  904. package/devices/prolight.js +115 -0
  905. package/devices/prolight.js.map +1 -0
  906. package/devices/pushok.d.ts +4 -0
  907. package/devices/pushok.d.ts.map +1 -0
  908. package/devices/pushok.js +300 -0
  909. package/devices/pushok.js.map +1 -0
  910. package/devices/qa.d.ts +4 -0
  911. package/devices/qa.d.ts.map +1 -0
  912. package/devices/qa.js +295 -0
  913. package/devices/qa.js.map +1 -0
  914. package/devices/qmotion.d.ts +4 -0
  915. package/devices/qmotion.d.ts.map +1 -0
  916. package/devices/qmotion.js +73 -0
  917. package/devices/qmotion.js.map +1 -0
  918. package/devices/qoto.d.ts +4 -0
  919. package/devices/qoto.d.ts.map +1 -0
  920. package/devices/qoto.js +87 -0
  921. package/devices/qoto.js.map +1 -0
  922. package/devices/quotra.d.ts +4 -0
  923. package/devices/quotra.d.ts.map +1 -0
  924. package/devices/quotra.js +22 -0
  925. package/devices/quotra.js.map +1 -0
  926. package/devices/rademacher.d.ts +4 -0
  927. package/devices/rademacher.d.ts.map +1 -0
  928. package/devices/rademacher.js +29 -0
  929. package/devices/rademacher.js.map +1 -0
  930. package/devices/radium.d.ts +4 -0
  931. package/devices/radium.d.ts.map +1 -0
  932. package/devices/radium.js +15 -0
  933. package/devices/radium.js.map +1 -0
  934. package/devices/raex.d.ts +4 -0
  935. package/devices/raex.d.ts.map +1 -0
  936. package/devices/raex.js +15 -0
  937. package/devices/raex.js.map +1 -0
  938. package/devices/rgb_genie.d.ts +4 -0
  939. package/devices/rgb_genie.d.ts.map +1 -0
  940. package/devices/rgb_genie.js +279 -0
  941. package/devices/rgb_genie.js.map +1 -0
  942. package/devices/robb.d.ts +4 -0
  943. package/devices/robb.d.ts.map +1 -0
  944. package/devices/robb.js +449 -0
  945. package/devices/robb.js.map +1 -0
  946. package/devices/roome.d.ts +4 -0
  947. package/devices/roome.d.ts.map +1 -0
  948. package/devices/roome.js +55 -0
  949. package/devices/roome.js.map +1 -0
  950. package/devices/rtx.d.ts +4 -0
  951. package/devices/rtx.d.ts.map +1 -0
  952. package/devices/rtx.js +151 -0
  953. package/devices/rtx.js.map +1 -0
  954. package/devices/salus_controls.d.ts +4 -0
  955. package/devices/salus_controls.d.ts.map +1 -0
  956. package/devices/salus_controls.js +136 -0
  957. package/devices/salus_controls.js.map +1 -0
  958. package/devices/samotech.d.ts +4 -0
  959. package/devices/samotech.d.ts.map +1 -0
  960. package/devices/samotech.js +75 -0
  961. package/devices/samotech.js.map +1 -0
  962. package/devices/saswell.d.ts +4 -0
  963. package/devices/saswell.d.ts.map +1 -0
  964. package/devices/saswell.js +125 -0
  965. package/devices/saswell.js.map +1 -0
  966. package/devices/sber.d.ts +4 -0
  967. package/devices/sber.d.ts.map +1 -0
  968. package/devices/sber.js +66 -0
  969. package/devices/sber.js.map +1 -0
  970. package/devices/scanproducts.d.ts +4 -0
  971. package/devices/scanproducts.d.ts.map +1 -0
  972. package/devices/scanproducts.js +22 -0
  973. package/devices/scanproducts.js.map +1 -0
  974. package/devices/schlage.d.ts +4 -0
  975. package/devices/schlage.d.ts.map +1 -0
  976. package/devices/schlage.js +64 -0
  977. package/devices/schlage.js.map +1 -0
  978. package/devices/schneider_electric.d.ts +4 -0
  979. package/devices/schneider_electric.d.ts.map +1 -0
  980. package/devices/schneider_electric.js +2187 -0
  981. package/devices/schneider_electric.js.map +1 -0
  982. package/devices/schwaiger.d.ts +4 -0
  983. package/devices/schwaiger.d.ts.map +1 -0
  984. package/devices/schwaiger.js +109 -0
  985. package/devices/schwaiger.js.map +1 -0
  986. package/devices/seastar_intelligence.d.ts +4 -0
  987. package/devices/seastar_intelligence.d.ts.map +1 -0
  988. package/devices/seastar_intelligence.js +20 -0
  989. package/devices/seastar_intelligence.js.map +1 -0
  990. package/devices/securifi.d.ts +4 -0
  991. package/devices/securifi.d.ts.map +1 -0
  992. package/devices/securifi.js +83 -0
  993. package/devices/securifi.js.map +1 -0
  994. package/devices/sengled.d.ts +7 -0
  995. package/devices/sengled.d.ts.map +1 -0
  996. package/devices/sengled.js +358 -0
  997. package/devices/sengled.js.map +1 -0
  998. package/devices/sercomm.d.ts +4 -0
  999. package/devices/sercomm.d.ts.map +1 -0
  1000. package/devices/sercomm.js +189 -0
  1001. package/devices/sercomm.js.map +1 -0
  1002. package/devices/shade_control.d.ts +4 -0
  1003. package/devices/shade_control.d.ts.map +1 -0
  1004. package/devices/shade_control.js +65 -0
  1005. package/devices/shade_control.js.map +1 -0
  1006. package/devices/shenzhen_homa.d.ts +4 -0
  1007. package/devices/shenzhen_homa.d.ts.map +1 -0
  1008. package/devices/shenzhen_homa.js +111 -0
  1009. package/devices/shenzhen_homa.js.map +1 -0
  1010. package/devices/shinasystem.d.ts +4 -0
  1011. package/devices/shinasystem.d.ts.map +1 -0
  1012. package/devices/shinasystem.js +961 -0
  1013. package/devices/shinasystem.js.map +1 -0
  1014. package/devices/shyugj.d.ts +4 -0
  1015. package/devices/shyugj.d.ts.map +1 -0
  1016. package/devices/shyugj.js +21 -0
  1017. package/devices/shyugj.js.map +1 -0
  1018. package/devices/siglis.d.ts +4 -0
  1019. package/devices/siglis.d.ts.map +1 -0
  1020. package/devices/siglis.js +457 -0
  1021. package/devices/siglis.js.map +1 -0
  1022. package/devices/sikom.d.ts +4 -0
  1023. package/devices/sikom.d.ts.map +1 -0
  1024. package/devices/sikom.js +68 -0
  1025. package/devices/sikom.js.map +1 -0
  1026. package/devices/sinope.d.ts +4 -0
  1027. package/devices/sinope.d.ts.map +1 -0
  1028. package/devices/sinope.js +1755 -0
  1029. package/devices/sinope.js.map +1 -0
  1030. package/devices/siterwell.d.ts +4 -0
  1031. package/devices/siterwell.d.ts.map +1 -0
  1032. package/devices/siterwell.js +111 -0
  1033. package/devices/siterwell.js.map +1 -0
  1034. package/devices/skydance.d.ts +4 -0
  1035. package/devices/skydance.d.ts.map +1 -0
  1036. package/devices/skydance.js +156 -0
  1037. package/devices/skydance.js.map +1 -0
  1038. package/devices/slv.d.ts +4 -0
  1039. package/devices/slv.d.ts.map +1 -0
  1040. package/devices/slv.js +38 -0
  1041. package/devices/slv.js.map +1 -0
  1042. package/devices/smart9.d.ts +4 -0
  1043. package/devices/smart9.d.ts.map +1 -0
  1044. package/devices/smart9.js +67 -0
  1045. package/devices/smart9.js.map +1 -0
  1046. package/devices/smart_home_pty.d.ts +4 -0
  1047. package/devices/smart_home_pty.d.ts.map +1 -0
  1048. package/devices/smart_home_pty.js +22 -0
  1049. package/devices/smart_home_pty.js.map +1 -0
  1050. package/devices/smartenit.d.ts +4 -0
  1051. package/devices/smartenit.d.ts.map +1 -0
  1052. package/devices/smartenit.js +81 -0
  1053. package/devices/smartenit.js.map +1 -0
  1054. package/devices/smartthings.d.ts +4 -0
  1055. package/devices/smartthings.d.ts.map +1 -0
  1056. package/devices/smartthings.js +527 -0
  1057. package/devices/smartthings.js.map +1 -0
  1058. package/devices/smartwings.d.ts +4 -0
  1059. package/devices/smartwings.d.ts.map +1 -0
  1060. package/devices/smartwings.js +64 -0
  1061. package/devices/smartwings.js.map +1 -0
  1062. package/devices/smlight.d.ts +4 -0
  1063. package/devices/smlight.d.ts.map +1 -0
  1064. package/devices/smlight.js +22 -0
  1065. package/devices/smlight.js.map +1 -0
  1066. package/devices/sohan_electric.d.ts +4 -0
  1067. package/devices/sohan_electric.d.ts.map +1 -0
  1068. package/devices/sohan_electric.js +20 -0
  1069. package/devices/sohan_electric.js.map +1 -0
  1070. package/devices/solaredge.d.ts +4 -0
  1071. package/devices/solaredge.d.ts.map +1 -0
  1072. package/devices/solaredge.js +15 -0
  1073. package/devices/solaredge.js.map +1 -0
  1074. package/devices/soma.d.ts +4 -0
  1075. package/devices/soma.d.ts.map +1 -0
  1076. package/devices/soma.js +15 -0
  1077. package/devices/soma.js.map +1 -0
  1078. package/devices/somfy.d.ts +4 -0
  1079. package/devices/somfy.d.ts.map +1 -0
  1080. package/devices/somfy.js +88 -0
  1081. package/devices/somfy.js.map +1 -0
  1082. package/devices/somgoms.d.ts +4 -0
  1083. package/devices/somgoms.d.ts.map +1 -0
  1084. package/devices/somgoms.js +84 -0
  1085. package/devices/somgoms.js.map +1 -0
  1086. package/devices/sonoff.d.ts +4 -0
  1087. package/devices/sonoff.d.ts.map +1 -0
  1088. package/devices/sonoff.js +1452 -0
  1089. package/devices/sonoff.js.map +1 -0
  1090. package/devices/sowilo.d.ts +4 -0
  1091. package/devices/sowilo.d.ts.map +1 -0
  1092. package/devices/sowilo.js +15 -0
  1093. package/devices/sowilo.js.map +1 -0
  1094. package/devices/spotmau.d.ts +4 -0
  1095. package/devices/spotmau.d.ts.map +1 -0
  1096. package/devices/spotmau.js +42 -0
  1097. package/devices/spotmau.js.map +1 -0
  1098. package/devices/stelpro.d.ts +4 -0
  1099. package/devices/stelpro.d.ts.map +1 -0
  1100. package/devices/stelpro.js +366 -0
  1101. package/devices/stelpro.js.map +1 -0
  1102. package/devices/sunricher.d.ts +4 -0
  1103. package/devices/sunricher.d.ts.map +1 -0
  1104. package/devices/sunricher.js +1308 -0
  1105. package/devices/sunricher.js.map +1 -0
  1106. package/devices/swann.d.ts +4 -0
  1107. package/devices/swann.d.ts.map +1 -0
  1108. package/devices/swann.js +73 -0
  1109. package/devices/swann.js.map +1 -0
  1110. package/devices/sylvania.d.ts +4 -0
  1111. package/devices/sylvania.d.ts.map +1 -0
  1112. package/devices/sylvania.js +226 -0
  1113. package/devices/sylvania.js.map +1 -0
  1114. package/devices/tapestry.d.ts +4 -0
  1115. package/devices/tapestry.d.ts.map +1 -0
  1116. package/devices/tapestry.js +56 -0
  1117. package/devices/tapestry.js.map +1 -0
  1118. package/devices/tci.d.ts +4 -0
  1119. package/devices/tci.d.ts.map +1 -0
  1120. package/devices/tci.js +29 -0
  1121. package/devices/tci.js.map +1 -0
  1122. package/devices/tech.d.ts +4 -0
  1123. package/devices/tech.d.ts.map +1 -0
  1124. package/devices/tech.js +131 -0
  1125. package/devices/tech.js.map +1 -0
  1126. package/devices/technicolor.d.ts +4 -0
  1127. package/devices/technicolor.d.ts.map +1 -0
  1128. package/devices/technicolor.js +102 -0
  1129. package/devices/technicolor.js.map +1 -0
  1130. package/devices/terncy.d.ts +4 -0
  1131. package/devices/terncy.d.ts.map +1 -0
  1132. package/devices/terncy.js +116 -0
  1133. package/devices/terncy.js.map +1 -0
  1134. package/devices/the_light_group.d.ts +4 -0
  1135. package/devices/the_light_group.d.ts.map +1 -0
  1136. package/devices/the_light_group.js +130 -0
  1137. package/devices/the_light_group.js.map +1 -0
  1138. package/devices/third_reality.d.ts +4 -0
  1139. package/devices/third_reality.d.ts.map +1 -0
  1140. package/devices/third_reality.js +569 -0
  1141. package/devices/third_reality.js.map +1 -0
  1142. package/devices/titan_products.d.ts +4 -0
  1143. package/devices/titan_products.d.ts.map +1 -0
  1144. package/devices/titan_products.js +62 -0
  1145. package/devices/titan_products.js.map +1 -0
  1146. package/devices/tlwglobal.d.ts +4 -0
  1147. package/devices/tlwglobal.d.ts.map +1 -0
  1148. package/devices/tlwglobal.js +32 -0
  1149. package/devices/tlwglobal.js.map +1 -0
  1150. package/devices/tplink.d.ts +4 -0
  1151. package/devices/tplink.d.ts.map +1 -0
  1152. package/devices/tplink.js +82 -0
  1153. package/devices/tplink.js.map +1 -0
  1154. package/devices/trust.d.ts +4 -0
  1155. package/devices/trust.d.ts.map +1 -0
  1156. package/devices/trust.js +183 -0
  1157. package/devices/trust.js.map +1 -0
  1158. package/devices/tubeszb.d.ts +4 -0
  1159. package/devices/tubeszb.d.ts.map +1 -0
  1160. package/devices/tubeszb.js +60 -0
  1161. package/devices/tubeszb.js.map +1 -0
  1162. package/devices/tuya.d.ts +4 -0
  1163. package/devices/tuya.d.ts.map +1 -0
  1164. package/devices/tuya.js +13607 -0
  1165. package/devices/tuya.js.map +1 -0
  1166. package/devices/ubisys.d.ts +4 -0
  1167. package/devices/ubisys.d.ts.map +1 -0
  1168. package/devices/ubisys.js +1300 -0
  1169. package/devices/ubisys.js.map +1 -0
  1170. package/devices/uhome.d.ts +4 -0
  1171. package/devices/uhome.d.ts.map +1 -0
  1172. package/devices/uhome.js +64 -0
  1173. package/devices/uhome.js.map +1 -0
  1174. package/devices/universal_electronics_inc.d.ts +4 -0
  1175. package/devices/universal_electronics_inc.d.ts.map +1 -0
  1176. package/devices/universal_electronics_inc.js +186 -0
  1177. package/devices/universal_electronics_inc.js.map +1 -0
  1178. package/devices/vbled.d.ts +4 -0
  1179. package/devices/vbled.d.ts.map +1 -0
  1180. package/devices/vbled.js +15 -0
  1181. package/devices/vbled.js.map +1 -0
  1182. package/devices/vesternet.d.ts +4 -0
  1183. package/devices/vesternet.d.ts.map +1 -0
  1184. package/devices/vesternet.js +330 -0
  1185. package/devices/vesternet.js.map +1 -0
  1186. package/devices/viessmann.d.ts +4 -0
  1187. package/devices/viessmann.d.ts.map +1 -0
  1188. package/devices/viessmann.js +115 -0
  1189. package/devices/viessmann.js.map +1 -0
  1190. package/devices/villeroy_boch.d.ts +4 -0
  1191. package/devices/villeroy_boch.d.ts.map +1 -0
  1192. package/devices/villeroy_boch.js +22 -0
  1193. package/devices/villeroy_boch.js.map +1 -0
  1194. package/devices/vimar.d.ts +4 -0
  1195. package/devices/vimar.d.ts.map +1 -0
  1196. package/devices/vimar.js +137 -0
  1197. package/devices/vimar.js.map +1 -0
  1198. package/devices/visonic.d.ts +4 -0
  1199. package/devices/visonic.d.ts.map +1 -0
  1200. package/devices/visonic.js +138 -0
  1201. package/devices/visonic.js.map +1 -0
  1202. package/devices/vrey.d.ts +4 -0
  1203. package/devices/vrey.d.ts.map +1 -0
  1204. package/devices/vrey.js +18 -0
  1205. package/devices/vrey.js.map +1 -0
  1206. package/devices/wally.d.ts +4 -0
  1207. package/devices/wally.d.ts.map +1 -0
  1208. package/devices/wally.js +64 -0
  1209. package/devices/wally.js.map +1 -0
  1210. package/devices/waxman.d.ts +4 -0
  1211. package/devices/waxman.d.ts.map +1 -0
  1212. package/devices/waxman.js +85 -0
  1213. package/devices/waxman.js.map +1 -0
  1214. package/devices/weiser.d.ts +4 -0
  1215. package/devices/weiser.d.ts.map +1 -0
  1216. package/devices/weiser.js +103 -0
  1217. package/devices/weiser.js.map +1 -0
  1218. package/devices/weten.d.ts +4 -0
  1219. package/devices/weten.d.ts.map +1 -0
  1220. package/devices/weten.js +89 -0
  1221. package/devices/weten.js.map +1 -0
  1222. package/devices/wirenboard.d.ts +4 -0
  1223. package/devices/wirenboard.d.ts.map +1 -0
  1224. package/devices/wirenboard.js +626 -0
  1225. package/devices/wirenboard.js.map +1 -0
  1226. package/devices/wisdom.d.ts +4 -0
  1227. package/devices/wisdom.d.ts.map +1 -0
  1228. package/devices/wisdom.js +15 -0
  1229. package/devices/wisdom.js.map +1 -0
  1230. package/devices/woolley.d.ts +4 -0
  1231. package/devices/woolley.d.ts.map +1 -0
  1232. package/devices/woolley.js +88 -0
  1233. package/devices/woolley.js.map +1 -0
  1234. package/devices/woox.d.ts +4 -0
  1235. package/devices/woox.d.ts.map +1 -0
  1236. package/devices/woox.js +137 -0
  1237. package/devices/woox.js.map +1 -0
  1238. package/devices/wyze.d.ts +4 -0
  1239. package/devices/wyze.d.ts.map +1 -0
  1240. package/devices/wyze.js +63 -0
  1241. package/devices/wyze.js.map +1 -0
  1242. package/devices/xinghuoyuan.d.ts +4 -0
  1243. package/devices/xinghuoyuan.d.ts.map +1 -0
  1244. package/devices/xinghuoyuan.js +15 -0
  1245. package/devices/xinghuoyuan.js.map +1 -0
  1246. package/devices/xyzroe.d.ts +4 -0
  1247. package/devices/xyzroe.d.ts.map +1 -0
  1248. package/devices/xyzroe.js +519 -0
  1249. package/devices/xyzroe.js.map +1 -0
  1250. package/devices/yale.d.ts +4 -0
  1251. package/devices/yale.d.ts.map +1 -0
  1252. package/devices/yale.js +503 -0
  1253. package/devices/yale.js.map +1 -0
  1254. package/devices/yandex.d.ts +4 -0
  1255. package/devices/yandex.d.ts.map +1 -0
  1256. package/devices/yandex.js +410 -0
  1257. package/devices/yandex.js.map +1 -0
  1258. package/devices/ynoa.d.ts +4 -0
  1259. package/devices/ynoa.d.ts.map +1 -0
  1260. package/devices/ynoa.js +113 -0
  1261. package/devices/ynoa.js.map +1 -0
  1262. package/devices/yookee.d.ts +4 -0
  1263. package/devices/yookee.d.ts.map +1 -0
  1264. package/devices/yookee.js +63 -0
  1265. package/devices/yookee.js.map +1 -0
  1266. package/devices/ysrsai.d.ts +4 -0
  1267. package/devices/ysrsai.d.ts.map +1 -0
  1268. package/devices/ysrsai.js +66 -0
  1269. package/devices/ysrsai.js.map +1 -0
  1270. package/devices/zemismart.d.ts +4 -0
  1271. package/devices/zemismart.d.ts.map +1 -0
  1272. package/devices/zemismart.js +405 -0
  1273. package/devices/zemismart.js.map +1 -0
  1274. package/devices/zen.d.ts +4 -0
  1275. package/devices/zen.d.ts.map +1 -0
  1276. package/devices/zen.js +96 -0
  1277. package/devices/zen.js.map +1 -0
  1278. package/devices/zigbeetlc.d.ts +13 -0
  1279. package/devices/zigbeetlc.d.ts.map +1 -0
  1280. package/devices/zigbeetlc.js +201 -0
  1281. package/devices/zigbeetlc.js.map +1 -0
  1282. package/devices/zipato.d.ts +4 -0
  1283. package/devices/zipato.d.ts.map +1 -0
  1284. package/devices/zipato.js +15 -0
  1285. package/devices/zipato.js.map +1 -0
  1286. package/index.d.ts +21 -0
  1287. package/index.d.ts.map +1 -0
  1288. package/index.js +488 -0
  1289. package/index.js.map +1 -0
  1290. package/lib/color.d.ts +272 -0
  1291. package/lib/color.d.ts.map +1 -0
  1292. package/lib/color.js +765 -0
  1293. package/lib/color.js.map +1 -0
  1294. package/lib/configureKey.d.ts +3 -0
  1295. package/lib/configureKey.d.ts.map +1 -0
  1296. package/lib/configureKey.js +939 -0
  1297. package/lib/configureKey.js.map +1 -0
  1298. package/lib/constants.d.ts +68 -0
  1299. package/lib/constants.d.ts.map +1 -0
  1300. package/lib/constants.js +293 -0
  1301. package/lib/constants.js.map +1 -0
  1302. package/lib/develco.d.ts +15 -0
  1303. package/lib/develco.d.ts.map +1 -0
  1304. package/lib/develco.js +183 -0
  1305. package/lib/develco.js.map +1 -0
  1306. package/lib/ewelink.d.ts +30 -0
  1307. package/lib/ewelink.d.ts.map +1 -0
  1308. package/lib/ewelink.js +718 -0
  1309. package/lib/ewelink.js.map +1 -0
  1310. package/lib/exposes.d.ts +344 -0
  1311. package/lib/exposes.d.ts.map +1 -0
  1312. package/lib/exposes.js +1065 -0
  1313. package/lib/exposes.js.map +1 -0
  1314. package/lib/generateDefinition.d.ts +6 -0
  1315. package/lib/generateDefinition.d.ts.map +1 -0
  1316. package/lib/generateDefinition.js +356 -0
  1317. package/lib/generateDefinition.js.map +1 -0
  1318. package/lib/ikea.d.ts +39 -0
  1319. package/lib/ikea.d.ts.map +1 -0
  1320. package/lib/ikea.js +776 -0
  1321. package/lib/ikea.js.map +1 -0
  1322. package/lib/kelvinToXy.d.ts +8 -0
  1323. package/lib/kelvinToXy.d.ts.map +1 -0
  1324. package/lib/kelvinToXy.js +1914 -0
  1325. package/lib/kelvinToXy.js.map +1 -0
  1326. package/lib/ledvance.d.ts +20 -0
  1327. package/lib/ledvance.d.ts.map +1 -0
  1328. package/lib/ledvance.js +103 -0
  1329. package/lib/ledvance.js.map +1 -0
  1330. package/lib/legacy.d.ts +5128 -0
  1331. package/lib/legacy.d.ts.map +1 -0
  1332. package/lib/legacy.js +6603 -0
  1333. package/lib/legacy.js.map +1 -0
  1334. package/lib/legrand.d.ts +69 -0
  1335. package/lib/legrand.d.ts.map +1 -0
  1336. package/lib/legrand.js +282 -0
  1337. package/lib/legrand.js.map +1 -0
  1338. package/lib/light.d.ts +6 -0
  1339. package/lib/light.d.ts.map +1 -0
  1340. package/lib/light.js +146 -0
  1341. package/lib/light.js.map +1 -0
  1342. package/lib/logger.d.ts +4 -0
  1343. package/lib/logger.d.ts.map +1 -0
  1344. package/lib/logger.js +14 -0
  1345. package/lib/logger.js.map +1 -0
  1346. package/lib/lumi.d.ts +953 -0
  1347. package/lib/lumi.d.ts.map +1 -0
  1348. package/lib/lumi.js +4973 -0
  1349. package/lib/lumi.js.map +1 -0
  1350. package/lib/modernExtend.d.ts +325 -0
  1351. package/lib/modernExtend.d.ts.map +1 -0
  1352. package/lib/modernExtend.js +1995 -0
  1353. package/lib/modernExtend.js.map +1 -0
  1354. package/lib/ota.d.ts +71 -0
  1355. package/lib/ota.d.ts.map +1 -0
  1356. package/lib/ota.js +663 -0
  1357. package/lib/ota.js.map +1 -0
  1358. package/lib/philips.d.ts +84 -0
  1359. package/lib/philips.d.ts.map +1 -0
  1360. package/lib/philips.js +657 -0
  1361. package/lib/philips.js.map +1 -0
  1362. package/lib/reporting.d.ts +58 -0
  1363. package/lib/reporting.d.ts.map +1 -0
  1364. package/lib/reporting.js +336 -0
  1365. package/lib/reporting.js.map +1 -0
  1366. package/lib/store.d.ts +7 -0
  1367. package/lib/store.d.ts.map +1 -0
  1368. package/lib/store.js +56 -0
  1369. package/lib/store.js.map +1 -0
  1370. package/lib/sunricher.d.ts +13 -0
  1371. package/lib/sunricher.d.ts.map +1 -0
  1372. package/lib/sunricher.js +14 -0
  1373. package/lib/sunricher.js.map +1 -0
  1374. package/lib/tuya.d.ts +764 -0
  1375. package/lib/tuya.d.ts.map +1 -0
  1376. package/lib/tuya.js +2425 -0
  1377. package/lib/tuya.js.map +1 -0
  1378. package/lib/types.d.ts +433 -0
  1379. package/lib/types.d.ts.map +1 -0
  1380. package/lib/types.js +4 -0
  1381. package/lib/types.js.map +1 -0
  1382. package/lib/ubisys.d.ts +19 -0
  1383. package/lib/ubisys.d.ts.map +1 -0
  1384. package/lib/ubisys.js +293 -0
  1385. package/lib/ubisys.js.map +1 -0
  1386. package/lib/utils.d.ts +93 -0
  1387. package/lib/utils.d.ts.map +1 -0
  1388. package/lib/utils.js +790 -0
  1389. package/lib/utils.js.map +1 -0
  1390. package/lib/zosung.d.ts +52 -0
  1391. package/lib/zosung.d.ts.map +1 -0
  1392. package/lib/zosung.js +256 -0
  1393. package/lib/zosung.js.map +1 -0
  1394. package/package.json +2 -2
@@ -0,0 +1,4422 @@
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
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const zigbee_herdsman_1 = require("zigbee-herdsman");
37
+ const libColor = __importStar(require("../lib/color"));
38
+ const constants = __importStar(require("../lib/constants"));
39
+ const exposes = __importStar(require("../lib/exposes"));
40
+ const legacy = __importStar(require("../lib/legacy"));
41
+ const light = __importStar(require("../lib/light"));
42
+ const logger_1 = require("../lib/logger");
43
+ const globalStore = __importStar(require("../lib/store"));
44
+ const utils = __importStar(require("../lib/utils"));
45
+ const NS = 'zhc:tz';
46
+ const manufacturerOptions = {
47
+ sunricher: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.SHENZHEN_SUNRICHER_TECHNOLOGY_LTD },
48
+ lumi: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.LUMI_UNITED_TECHOLOGY_LTD_SHENZHEN, disableDefaultResponse: true },
49
+ eurotronic: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.NXP_SEMICONDUCTORS },
50
+ danfoss: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DANFOSS_A_S },
51
+ hue: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.SIGNIFY_NETHERLANDS_B_V },
52
+ ikea: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.IKEA_OF_SWEDEN },
53
+ sinope: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.SINOPE_TECHNOLOGIES },
54
+ tint: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.MUELLER_LICHT_INTERNATIONAL_INC },
55
+ legrand: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.LEGRAND_GROUP, disableDefaultResponse: true },
56
+ viessmann: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.VIESSMANN_ELEKTRONIK_GMBH },
57
+ nodon: { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.NODON },
58
+ };
59
+ const converters1 = {
60
+ on_off: {
61
+ key: ['state', 'on_time', 'off_wait_time'],
62
+ convertSet: async (entity, key, value, meta) => {
63
+ const state = utils.isString(meta.message.state) ? meta.message.state.toLowerCase() : null;
64
+ utils.validateValue(state, ['toggle', 'off', 'on']);
65
+ if (state === 'on' && (meta.message.on_time !== undefined || meta.message.off_wait_time !== undefined)) {
66
+ const onTime = meta.message.on_time !== undefined ? meta.message.on_time : 0;
67
+ const offWaitTime = meta.message.off_wait_time !== undefined ? meta.message.off_wait_time : 0;
68
+ if (typeof onTime !== 'number') {
69
+ throw Error('The on_time value must be a number!');
70
+ }
71
+ if (typeof offWaitTime !== 'number') {
72
+ throw Error('The off_wait_time value must be a number!');
73
+ }
74
+ const payload = { ctrlbits: 0, ontime: Math.round(onTime * 10), offwaittime: Math.round(offWaitTime * 10) };
75
+ await entity.command('genOnOff', 'onWithTimedOff', payload, utils.getOptions(meta.mapped, entity));
76
+ }
77
+ else {
78
+ await entity.command('genOnOff', state, {}, utils.getOptions(meta.mapped, entity));
79
+ if (state === 'toggle') {
80
+ const currentState = meta.state[`state${meta.endpoint_name ? `_${meta.endpoint_name}` : ''}`];
81
+ return currentState ? { state: { state: currentState === 'OFF' ? 'ON' : 'OFF' } } : {};
82
+ }
83
+ else {
84
+ return { state: { state: state.toUpperCase() } };
85
+ }
86
+ }
87
+ },
88
+ convertGet: async (entity, key, meta) => {
89
+ await entity.read('genOnOff', ['onOff']);
90
+ },
91
+ },
92
+ light_color: {
93
+ key: ['color'],
94
+ options: [exposes.options.color_sync(), exposes.options.transition()],
95
+ convertSet: async (entity, key, value, meta) => {
96
+ let command;
97
+ const newColor = libColor.Color.fromConverterArg(value);
98
+ const newState = {};
99
+ const zclData = { transtime: utils.getTransition(entity, key, meta).time };
100
+ const supportsHueAndSaturation = utils.getMetaValue(entity, meta.mapped, 'supportsHueAndSaturation', 'allEqual', true);
101
+ const supportsEnhancedHue = utils.getMetaValue(entity, meta.mapped, 'supportsEnhancedHue', 'allEqual', true);
102
+ if (newColor.isHSV() && !supportsHueAndSaturation) {
103
+ // The color we got is HSV but the bulb does not support Hue/Saturation mode
104
+ throw new Error('This light does not support Hue/Saturation, please use X/Y instead.');
105
+ }
106
+ else if (newColor.isRGB() || newColor.isXY()) {
107
+ // Convert RGB to XY color mode because Zigbee doesn't support RGB (only x/y and hue/saturation)
108
+ const xy = newColor.isRGB() ? newColor.rgb.gammaCorrected().toXY().rounded(4) : newColor.xy;
109
+ // Some bulbs e.g. RB 185 C don't turn to red (they don't respond at all) when x: 0.701 and y: 0.299
110
+ // is send. These values are e.g. send by Home Assistant when clicking red in the color wheel.
111
+ // If we slightly modify these values the bulb will respond.
112
+ // https://github.com/home-assistant/home-assistant/issues/31094
113
+ if (utils.getMetaValue(entity, meta.mapped, 'applyRedFix', 'allEqual', false) && xy.x == 0.701 && xy.y === 0.299) {
114
+ xy.x = 0.7006;
115
+ xy.y = 0.2993;
116
+ }
117
+ newState.color_mode = constants.colorModeLookup[1];
118
+ newState.color = xy.toObject();
119
+ zclData.colorx = utils.mapNumberRange(xy.x, 0, 1, 0, 65535);
120
+ zclData.colory = utils.mapNumberRange(xy.y, 0, 1, 0, 65535);
121
+ command = 'moveToColor';
122
+ }
123
+ else if (newColor.isHSV()) {
124
+ const hsv = newColor.hsv;
125
+ const hsvCorrected = hsv.colorCorrected(meta);
126
+ newState.color_mode = constants.colorModeLookup[0];
127
+ newState.color = hsv.toObject(false);
128
+ if (hsv.hue !== null) {
129
+ if (supportsEnhancedHue) {
130
+ zclData.enhancehue = utils.mapNumberRange(hsvCorrected.hue, 0, 360, 0, 65535);
131
+ }
132
+ else {
133
+ zclData.hue = utils.mapNumberRange(hsvCorrected.hue, 0, 360, 0, 254);
134
+ }
135
+ // @ts-expect-error ignore
136
+ zclData.direction = value.direction || 0;
137
+ }
138
+ if (hsv.saturation != null) {
139
+ zclData.saturation = utils.mapNumberRange(hsvCorrected.saturation, 0, 100, 0, 254);
140
+ }
141
+ if (hsv.value !== null) {
142
+ // fallthrough to genLevelCtrl
143
+ // @ts-expect-error ignore
144
+ value.brightness = utils.mapNumberRange(hsvCorrected.value, 0, 100, 0, 254);
145
+ }
146
+ if (hsv.hue !== null && hsv.saturation !== null) {
147
+ if (supportsEnhancedHue) {
148
+ command = 'enhancedMoveToHueAndSaturation';
149
+ }
150
+ else {
151
+ command = 'moveToHueAndSaturation';
152
+ }
153
+ }
154
+ else if (hsv.hue !== null) {
155
+ if (supportsEnhancedHue) {
156
+ command = 'enhancedMoveToHue';
157
+ }
158
+ else {
159
+ command = 'moveToHue';
160
+ }
161
+ }
162
+ else if (hsv.saturation !== null) {
163
+ command = 'moveToSaturation';
164
+ }
165
+ }
166
+ if (utils.isObject(value) && value.brightness !== undefined) {
167
+ await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', { level: Number(value.brightness), transtime: utils.getTransition(entity, key, meta).time }, utils.getOptions(meta.mapped, entity));
168
+ }
169
+ await entity.command('lightingColorCtrl', command, zclData, utils.getOptions(meta.mapped, entity));
170
+ return { state: libColor.syncColorState(newState, meta.state, entity, meta.options) };
171
+ },
172
+ convertGet: async (entity, key, meta) => {
173
+ await entity.read('lightingColorCtrl', light.readColorAttributes(entity, meta));
174
+ },
175
+ },
176
+ light_colortemp: {
177
+ key: ['color_temp', 'color_temp_percent'],
178
+ options: [exposes.options.color_sync(), exposes.options.transition()],
179
+ convertSet: async (entity, key, value, meta) => {
180
+ const [colorTempMin, colorTempMax] = light.findColorTempRange(entity);
181
+ const preset = { warmest: colorTempMax, warm: 454, neutral: 370, cool: 250, coolest: colorTempMin };
182
+ if (key === 'color_temp_percent') {
183
+ utils.assertNumber(value);
184
+ value = utils
185
+ .mapNumberRange(value, 0, 100, colorTempMin != null ? colorTempMin : 154, colorTempMax != null ? colorTempMax : 500)
186
+ .toString();
187
+ }
188
+ if (utils.isString(value) && value in preset) {
189
+ value = utils.getFromLookup(value, preset);
190
+ }
191
+ value = Number(value);
192
+ // ensure value within range
193
+ utils.assertNumber(value);
194
+ value = light.clampColorTemp(value, colorTempMin, colorTempMax);
195
+ const payload = { colortemp: value, transtime: utils.getTransition(entity, key, meta).time };
196
+ await entity.command('lightingColorCtrl', 'moveToColorTemp', payload, utils.getOptions(meta.mapped, entity));
197
+ return {
198
+ state: libColor.syncColorState({ color_mode: constants.colorModeLookup[2], color_temp: value }, meta.state, entity, meta.options),
199
+ };
200
+ },
201
+ convertGet: async (entity, key, meta) => {
202
+ await entity.read('lightingColorCtrl', ['colorMode', 'colorTemperature']);
203
+ },
204
+ },
205
+ };
206
+ const converters2 = {
207
+ // #region Generic converters
208
+ read: {
209
+ key: ['read'],
210
+ convertSet: async (entity, key, value, meta) => {
211
+ utils.assertObject(value, key);
212
+ const result = await entity.read(value.cluster, value.attributes, value.options !== undefined ? value.options : {});
213
+ logger_1.logger.info(`Read result of '${value.cluster}': ${JSON.stringify(result)}`, NS);
214
+ if (value.state_property !== undefined) {
215
+ return { state: { [value.state_property]: result } };
216
+ }
217
+ },
218
+ },
219
+ write: {
220
+ key: ['write'],
221
+ convertSet: async (entity, key, value, meta) => {
222
+ utils.assertObject(value, key);
223
+ const options = utils.getOptions(meta.mapped, entity);
224
+ if (value.options !== undefined) {
225
+ Object.assign(options, value.options);
226
+ }
227
+ await entity.write(value.cluster, value.payload, options);
228
+ logger_1.logger.info(`Wrote '${JSON.stringify(value.payload)}' to '${value.cluster}'`, NS);
229
+ },
230
+ },
231
+ command: {
232
+ key: ['command'],
233
+ convertSet: async (entity, key, value, meta) => {
234
+ utils.assertObject(value, key);
235
+ const options = utils.getOptions(meta.mapped, entity);
236
+ await entity.command(value.cluster, value.command, value.payload !== undefined ? value.payload : {}, options);
237
+ logger_1.logger.info(`Invoked '${value.cluster}.${value.command}' with payload '${JSON.stringify(value.payload)}'`, NS);
238
+ },
239
+ },
240
+ factory_reset: {
241
+ key: ['reset'],
242
+ convertSet: async (entity, key, value, meta) => {
243
+ await entity.command('genBasic', 'resetFactDefault', {}, utils.getOptions(meta.mapped, entity));
244
+ },
245
+ },
246
+ identify: {
247
+ key: ['identify'],
248
+ options: [exposes.options.identify_timeout()],
249
+ convertSet: async (entity, key, value, meta) => {
250
+ // External value takes priority over options for compatibility
251
+ const identifyTimeout = value ?? meta.options.identify_timeout ?? 3;
252
+ await entity.command('genIdentify', 'identify', { identifytime: identifyTimeout }, utils.getOptions(meta.mapped, entity));
253
+ },
254
+ },
255
+ zcl_command: {
256
+ key: ['zclcommand'],
257
+ convertSet: async (entity, key, value, meta) => {
258
+ utils.assertObject(value, key);
259
+ const payload = value.payload !== undefined ? value.payload : {};
260
+ utils.assertEndpoint(entity);
261
+ await entity.zclCommand(value.cluster, value.command, payload, value.options !== undefined ? value.options : {});
262
+ logger_1.logger.info(`Invoked ZCL command ${value.cluster}.${value.command} with payload '${JSON.stringify(payload)}'`, NS);
263
+ },
264
+ },
265
+ arm_mode: {
266
+ key: ['arm_mode'],
267
+ convertSet: async (entity, key, value, meta) => {
268
+ utils.assertEndpoint(entity);
269
+ utils.assertObject(value, key);
270
+ if (Array.isArray(meta.mapped))
271
+ throw new Error(`Not supported for groups`);
272
+ const isNotification = value.transaction !== undefined;
273
+ const modeSrc = isNotification ? constants.armNotification : constants.armMode;
274
+ const mode = utils.getKey(modeSrc, value.mode, undefined, Number);
275
+ if (mode === undefined) {
276
+ throw new Error(`Unsupported mode: '${value.mode}', should be one of: ${Object.values(modeSrc)}`);
277
+ }
278
+ if (isNotification) {
279
+ await entity.commandResponse('ssIasAce', 'armRsp', { armnotification: mode }, {}, value.transaction);
280
+ // Do not update PanelStatus after confirming transaction.
281
+ // Instead the server should send an arm_mode command with the necessary state.
282
+ // e.g. exit_delay as a result of arm_all_zones
283
+ return;
284
+ }
285
+ let panelStatus = mode;
286
+ if (meta.mapped.model === '3400-D') {
287
+ panelStatus = mode !== 0 && mode !== 4 ? 0x80 : 0x00;
288
+ }
289
+ globalStore.putValue(entity, 'panelStatus', panelStatus);
290
+ const payload = { panelstatus: panelStatus, secondsremain: 0, audiblenotif: 0, alarmstatus: 0 };
291
+ await entity.commandResponse('ssIasAce', 'panelStatusChanged', payload);
292
+ },
293
+ },
294
+ battery_percentage_remaining: {
295
+ key: ['battery'],
296
+ convertGet: async (entity, key, meta) => {
297
+ await entity.read('genPowerCfg', ['batteryPercentageRemaining']);
298
+ },
299
+ },
300
+ battery_voltage: {
301
+ key: ['battery', 'voltage'],
302
+ convertGet: async (entity, key, meta) => {
303
+ await entity.read('genPowerCfg', ['batteryVoltage']);
304
+ },
305
+ },
306
+ power_on_behavior: {
307
+ key: ['power_on_behavior'],
308
+ convertSet: async (entity, key, value, meta) => {
309
+ utils.assertString(value, key);
310
+ value = value.toLowerCase();
311
+ const lookup = { off: 0, on: 1, toggle: 2, previous: 255 };
312
+ try {
313
+ await entity.write('genOnOff', { startUpOnOff: utils.getFromLookup(value, lookup) }, utils.getOptions(meta.mapped, entity));
314
+ }
315
+ catch (e) {
316
+ if (e.message.includes('UNSUPPORTED_ATTRIBUTE')) {
317
+ throw new Error('Got `UNSUPPORTED_ATTRIBUTE` error, device does not support power on behaviour');
318
+ }
319
+ throw e;
320
+ }
321
+ return { state: { power_on_behavior: value } };
322
+ },
323
+ convertGet: async (entity, key, meta) => {
324
+ await entity.read('genOnOff', ['startUpOnOff']);
325
+ },
326
+ },
327
+ light_color_mode: {
328
+ key: ['color_mode'],
329
+ convertGet: async (entity, key, meta) => {
330
+ await entity.read('lightingColorCtrl', ['colorMode']);
331
+ },
332
+ },
333
+ light_color_options: {
334
+ key: ['color_options'],
335
+ convertSet: async (entity, key, value, meta) => {
336
+ utils.assertObject(value, key);
337
+ const options = value.execute_if_off !== undefined && value.execute_if_off ? 1 : 0;
338
+ await entity.write('lightingColorCtrl', { options }, utils.getOptions(meta.mapped, entity));
339
+ return { state: { color_options: value } };
340
+ },
341
+ convertGet: async (entity, key, meta) => {
342
+ await entity.read('lightingColorCtrl', ['options']);
343
+ },
344
+ },
345
+ lock: {
346
+ key: ['state'],
347
+ convertSet: async (entity, key, value, meta) => {
348
+ utils.assertString(value, key);
349
+ await entity.command('closuresDoorLock', `${value.toLowerCase()}Door`, { pincodevalue: '' }, utils.getOptions(meta.mapped, entity));
350
+ },
351
+ convertGet: async (entity, key, meta) => {
352
+ await entity.read('closuresDoorLock', ['lockState']);
353
+ },
354
+ },
355
+ lock_auto_relock_time: {
356
+ key: ['auto_relock_time'],
357
+ convertSet: async (entity, key, value, meta) => {
358
+ await entity.write('closuresDoorLock', { autoRelockTime: value }, utils.getOptions(meta.mapped, entity));
359
+ return { state: { auto_relock_time: value } };
360
+ },
361
+ convertGet: async (entity, key, meta) => {
362
+ await entity.read('closuresDoorLock', ['autoRelockTime']);
363
+ },
364
+ },
365
+ lock_sound_volume: {
366
+ key: ['sound_volume'],
367
+ convertSet: async (entity, key, value, meta) => {
368
+ utils.assertString(value, key);
369
+ utils.validateValue(value, constants.lockSoundVolume);
370
+ await entity.write('closuresDoorLock', { soundVolume: constants.lockSoundVolume.indexOf(value) }, utils.getOptions(meta.mapped, entity));
371
+ return { state: { sound_volume: value } };
372
+ },
373
+ convertGet: async (entity, key, meta) => {
374
+ await entity.read('closuresDoorLock', ['soundVolume']);
375
+ },
376
+ },
377
+ pincode_lock: {
378
+ key: ['pin_code'],
379
+ convertSet: async (entity, key, value, meta) => {
380
+ utils.assertObject(value, key);
381
+ const user = value.user;
382
+ const userType = value.user_type || 'unrestricted';
383
+ const userEnabled = value.user_enabled !== undefined ? value.user_enabled : true;
384
+ const pinCode = value.pin_code;
385
+ if (isNaN(user))
386
+ throw new Error('user must be numbers');
387
+ const pinCodeCount = utils.getMetaValue(entity, meta.mapped, 'pinCodeCount');
388
+ if (!utils.isInRange(0, pinCodeCount - 1, user))
389
+ throw new Error('user must be in range for device');
390
+ if (pinCode == null) {
391
+ await entity.command('closuresDoorLock', 'clearPinCode', { userid: user }, utils.getOptions(meta.mapped, entity));
392
+ }
393
+ else {
394
+ if (isNaN(pinCode))
395
+ throw new Error('pinCode must be a number');
396
+ const typeLookup = { unrestricted: 0, year_day_schedule: 1, week_day_schedule: 2, master: 3, non_access: 4 };
397
+ const payload = {
398
+ userid: user,
399
+ userstatus: userEnabled ? 1 : 3,
400
+ usertype: utils.getFromLookup(userType, typeLookup),
401
+ pincodevalue: pinCode.toString(),
402
+ };
403
+ await entity.command('closuresDoorLock', 'setPinCode', payload, utils.getOptions(meta.mapped, entity));
404
+ }
405
+ },
406
+ convertGet: async (entity, key, meta) => {
407
+ // @ts-expect-error ignore
408
+ const user = meta && meta.message && meta.message.pin_code ? meta.message.pin_code.user : undefined;
409
+ if (user === undefined) {
410
+ const max = utils.getMetaValue(entity, meta.mapped, 'pinCodeCount');
411
+ // Get all
412
+ const options = utils.getOptions(meta.mapped, entity);
413
+ for (let i = 0; i < max; i++) {
414
+ await entity.command('closuresDoorLock', 'getPinCode', { userid: i }, options);
415
+ }
416
+ }
417
+ else {
418
+ if (isNaN(user)) {
419
+ throw new Error('user must be numbers');
420
+ }
421
+ const pinCodeCount = utils.getMetaValue(entity, meta.mapped, 'pinCodeCount');
422
+ if (!utils.isInRange(0, pinCodeCount - 1, user)) {
423
+ throw new Error('userId must be in range for device');
424
+ }
425
+ await entity.command('closuresDoorLock', 'getPinCode', { userid: user }, utils.getOptions(meta.mapped, entity));
426
+ }
427
+ },
428
+ },
429
+ lock_userstatus: {
430
+ key: ['user_status'],
431
+ convertSet: async (entity, key, value, meta) => {
432
+ utils.assertObject(value, key);
433
+ const user = value.user;
434
+ if (isNaN(user)) {
435
+ throw new Error('user must be numbers');
436
+ }
437
+ const pinCodeCount = utils.getMetaValue(entity, meta.mapped, 'pinCodeCount');
438
+ if (!utils.isInRange(0, pinCodeCount - 1, user)) {
439
+ throw new Error('user must be in range for device');
440
+ }
441
+ const status = utils.getKey(constants.lockUserStatus, value.status, undefined, Number);
442
+ if (status === undefined) {
443
+ throw new Error(`Unsupported status: '${value.status}', should be one of: ${Object.values(constants.lockUserStatus)}`);
444
+ }
445
+ await entity.command('closuresDoorLock', 'setUserStatus', {
446
+ userid: user,
447
+ userstatus: status,
448
+ }, utils.getOptions(meta.mapped, entity));
449
+ },
450
+ convertGet: async (entity, key, meta) => {
451
+ // @ts-expect-error ignore
452
+ const user = meta && meta.message && meta.message.user_status ? meta.message.user_status.user : undefined;
453
+ const pinCodeCount = utils.getMetaValue(entity, meta.mapped, 'pinCodeCount');
454
+ if (user === undefined) {
455
+ const max = pinCodeCount;
456
+ // Get all
457
+ const options = utils.getOptions(meta.mapped, entity);
458
+ for (let i = 0; i < max; i++) {
459
+ await entity.command('closuresDoorLock', 'getUserStatus', { userid: i }, options);
460
+ }
461
+ }
462
+ else {
463
+ if (isNaN(user)) {
464
+ throw new Error('user must be numbers');
465
+ }
466
+ if (!utils.isInRange(0, pinCodeCount - 1, user)) {
467
+ throw new Error('userId must be in range for device');
468
+ }
469
+ await entity.command('closuresDoorLock', 'getUserStatus', { userid: user }, utils.getOptions(meta.mapped, entity));
470
+ }
471
+ },
472
+ },
473
+ cover_via_brightness: {
474
+ key: ['position', 'state'],
475
+ options: [exposes.options.invert_cover()],
476
+ convertSet: async (entity, key, value, meta) => {
477
+ if (typeof value !== 'number') {
478
+ utils.assertString(value, key);
479
+ value = value.toLowerCase();
480
+ if (value === 'stop') {
481
+ await entity.command('genLevelCtrl', 'stop', {}, utils.getOptions(meta.mapped, entity));
482
+ return;
483
+ }
484
+ const lookup = { open: 100, close: 0 };
485
+ value = utils.getFromLookup(value, lookup);
486
+ }
487
+ const invert = utils.getMetaValue(entity, meta.mapped, 'coverInverted', 'allEqual', false)
488
+ ? !meta.options.invert_cover
489
+ : meta.options.invert_cover;
490
+ utils.assertNumber(value);
491
+ const position = invert ? 100 - value : value;
492
+ await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', { level: utils.mapNumberRange(Number(position), 0, 100, 0, 255).toString(), transtime: 0 }, utils.getOptions(meta.mapped, entity));
493
+ return { state: { position: value } };
494
+ },
495
+ convertGet: async (entity, key, meta) => {
496
+ await entity.read('genLevelCtrl', ['currentLevel']);
497
+ },
498
+ },
499
+ warning: {
500
+ key: ['warning'],
501
+ convertSet: async (entity, key, value, meta) => {
502
+ const mode = { stop: 0, burglar: 1, fire: 2, emergency: 3, police_panic: 4, fire_panic: 5, emergency_panic: 6 };
503
+ const level = { low: 0, medium: 1, high: 2, very_high: 3 };
504
+ const strobeLevel = { low: 0, medium: 1, high: 2, very_high: 3 };
505
+ const values = {
506
+ // @ts-expect-error ignore
507
+ mode: value.mode || 'emergency',
508
+ // @ts-expect-error ignore
509
+ level: value.level || 'medium',
510
+ // @ts-expect-error ignore
511
+ strobe: value.strobe !== undefined ? value.strobe : true,
512
+ // @ts-expect-error ignore
513
+ duration: value.duration !== undefined ? value.duration : 10,
514
+ // @ts-expect-error ignore
515
+ strobeDutyCycle: value.strobe_duty_cycle !== undefined ? value.strobe_duty_cycle * 10 : 0,
516
+ // @ts-expect-error ignore
517
+ strobeLevel: value.strobe_level !== undefined ? utils.getFromLookup(value.strobe_level, strobeLevel) : 1,
518
+ };
519
+ let info;
520
+ // https://github.com/Koenkk/zigbee2mqtt/issues/8310 some devices require the info to be reversed.
521
+ if (Array.isArray(meta.mapped))
522
+ throw new Error(`Not supported for groups`);
523
+ if (['SIRZB-110', 'SRAC-23B-ZBSR', 'AV2010/29A', 'AV2010/24A'].includes(meta.mapped.model)) {
524
+ info = utils.getFromLookup(values.mode, mode) + ((values.strobe ? 1 : 0) << 4) + (utils.getFromLookup(values.level, level) << 6);
525
+ }
526
+ else {
527
+ info = (utils.getFromLookup(values.mode, mode) << 4) + ((values.strobe ? 1 : 0) << 2) + utils.getFromLookup(values.level, level);
528
+ }
529
+ await entity.command('ssIasWd', 'startWarning', { startwarninginfo: info, warningduration: values.duration, strobedutycycle: values.strobeDutyCycle, strobelevel: values.strobeLevel }, utils.getOptions(meta.mapped, entity));
530
+ },
531
+ },
532
+ ias_max_duration: {
533
+ key: ['max_duration'],
534
+ convertSet: async (entity, key, value, meta) => {
535
+ await entity.write('ssIasWd', { maxDuration: value });
536
+ return { state: { max_duration: value } };
537
+ },
538
+ convertGet: async (entity, key, meta) => {
539
+ await entity.read('ssIasWd', ['maxDuration']);
540
+ },
541
+ },
542
+ warning_simple: {
543
+ key: ['alarm'],
544
+ convertSet: async (entity, key, value, meta) => {
545
+ const alarmState = value === 'alarm' || value === 'OFF' ? 0 : 1;
546
+ let info;
547
+ // For Develco SMSZB-120 and HESZB-120, introduced change in fw 4.0.5, tested backward with 4.0.4
548
+ if (Array.isArray(meta.mapped))
549
+ throw new Error(`Not supported for groups`);
550
+ if (['SMSZB-120', 'HESZB-120'].includes(meta.mapped.model)) {
551
+ info = (alarmState << 7) + (alarmState << 6);
552
+ }
553
+ else {
554
+ info = (3 << 6) + (alarmState << 2);
555
+ }
556
+ await entity.command('ssIasWd', 'startWarning', { startwarninginfo: info, warningduration: 300, strobedutycycle: 0, strobelevel: 0 }, utils.getOptions(meta.mapped, entity));
557
+ },
558
+ },
559
+ squawk: {
560
+ key: ['squawk'],
561
+ convertSet: async (entity, key, value, meta) => {
562
+ utils.assertObject(value, key);
563
+ const state = { system_is_armed: 0, system_is_disarmed: 1 };
564
+ const level = { low: 0, medium: 1, high: 2, very_high: 3 };
565
+ const values = {
566
+ state: value.state,
567
+ level: value.level || 'very_high',
568
+ strobe: value.strobe !== undefined ? value.strobe : false,
569
+ };
570
+ const info = utils.getFromLookup(values.state, state) + ((values.strobe ? 1 : 0) << 4) + (utils.getFromLookup(values.level, level) << 6);
571
+ await entity.command('ssIasWd', 'squawk', { squawkinfo: info }, utils.getOptions(meta.mapped, entity));
572
+ },
573
+ },
574
+ cover_state: {
575
+ key: ['state'],
576
+ convertSet: async (entity, key, value, meta) => {
577
+ const lookup = { open: 'upOpen', close: 'downClose', stop: 'stop', on: 'upOpen', off: 'downClose' };
578
+ utils.assertString(value, key);
579
+ value = value.toLowerCase();
580
+ await entity.command('closuresWindowCovering', utils.getFromLookup(value, lookup), {}, utils.getOptions(meta.mapped, entity));
581
+ },
582
+ },
583
+ cover_position_tilt: {
584
+ key: ['position', 'tilt'],
585
+ options: [exposes.options.invert_cover(), exposes.options.cover_position_tilt_disable_report()],
586
+ convertSet: async (entity, key, value, meta) => {
587
+ utils.assertNumber(value, key);
588
+ const isPosition = key === 'position';
589
+ const invert = !(utils.getMetaValue(entity, meta.mapped, 'coverInverted', 'allEqual', false)
590
+ ? !meta.options.invert_cover
591
+ : meta.options.invert_cover);
592
+ const disableReport = utils.getMetaValue(entity, meta.mapped, 'coverPositionTiltDisableReport', 'allEqual', false)
593
+ ? !meta.options.cover_position_tilt_disable_report
594
+ : meta.options.cover_position_tilt_disable_report;
595
+ const position = invert ? 100 - value : value;
596
+ // Zigbee officially expects 'open' to be 0 and 'closed' to be 100 whereas
597
+ // HomeAssistant etc. work the other way round.
598
+ // For zigbee-herdsman-converters: open = 100, close = 0
599
+ await entity.command('closuresWindowCovering', isPosition ? 'goToLiftPercentage' : 'goToTiltPercentage', isPosition ? { percentageliftvalue: position } : { percentagetiltvalue: position }, utils.getOptions(meta.mapped, entity));
600
+ if (disableReport) {
601
+ return;
602
+ }
603
+ else {
604
+ return { state: { [isPosition ? 'position' : 'tilt']: value } };
605
+ }
606
+ },
607
+ convertGet: async (entity, key, meta) => {
608
+ const isPosition = key === 'position';
609
+ await entity.read('closuresWindowCovering', [isPosition ? 'currentPositionLiftPercentage' : 'currentPositionTiltPercentage']);
610
+ },
611
+ },
612
+ cover_mode: {
613
+ key: ['cover_mode'],
614
+ convertSet: async (entity, key, value, meta) => {
615
+ utils.assertObject(value, key);
616
+ const windowCoveringMode = ((value.reversed ? 1 : 0) << 0) |
617
+ ((value.calibration ? 1 : 0) << 1) |
618
+ ((value.maintenance ? 1 : 0) << 2) |
619
+ ((value.led ? 1 : 0) << 3);
620
+ await entity.write('closuresWindowCovering', { windowCoveringMode }, utils.getOptions(meta.mapped, entity));
621
+ return { state: { cover_mode: value } };
622
+ },
623
+ convertGet: async (entity, key, meta) => {
624
+ await entity.read('closuresWindowCovering', ['windowCoveringMode']);
625
+ },
626
+ },
627
+ occupancy_timeout: {
628
+ // Sets delay after motion detector changes from occupied to unoccupied
629
+ key: ['occupancy_timeout'],
630
+ convertSet: async (entity, key, value, meta) => {
631
+ utils.assertNumber(value);
632
+ value *= 1;
633
+ await entity.write('msOccupancySensing', { pirOToUDelay: value }, utils.getOptions(meta.mapped, entity));
634
+ return { state: { occupancy_timeout: value } };
635
+ },
636
+ convertGet: async (entity, key, meta) => {
637
+ await entity.read('msOccupancySensing', ['pirOToUDelay']);
638
+ },
639
+ },
640
+ level_config: {
641
+ key: ['level_config'],
642
+ convertSet: async (entity, key, value, meta) => {
643
+ const state = {};
644
+ // parse payload to grab the keys
645
+ if (typeof value === 'string') {
646
+ try {
647
+ value = JSON.parse(value);
648
+ }
649
+ catch {
650
+ throw new Error('Payload is not valid JSON');
651
+ }
652
+ }
653
+ utils.assertObject(value, key);
654
+ // onOffTransitionTime - range 0x0000 to 0xffff - optional
655
+ if (value.on_off_transition_time !== undefined) {
656
+ let onOffTransitionTimeValue = Number(value.on_off_transition_time);
657
+ if (onOffTransitionTimeValue > 65535)
658
+ onOffTransitionTimeValue = 65535;
659
+ if (onOffTransitionTimeValue < 0)
660
+ onOffTransitionTimeValue = 0;
661
+ await entity.write('genLevelCtrl', { onOffTransitionTime: onOffTransitionTimeValue }, utils.getOptions(meta.mapped, entity));
662
+ Object.assign(state, { on_off_transition_time: onOffTransitionTimeValue });
663
+ }
664
+ // onTransitionTime - range 0x0000 to 0xffff - optional
665
+ // 0xffff = use onOffTransitionTime
666
+ if (value.on_transition_time !== undefined) {
667
+ let onTransitionTimeValue = value.on_transition_time;
668
+ if (typeof onTransitionTimeValue === 'string' && onTransitionTimeValue.toLowerCase() == 'disabled') {
669
+ onTransitionTimeValue = 65535;
670
+ }
671
+ else {
672
+ onTransitionTimeValue = Number(onTransitionTimeValue);
673
+ }
674
+ if (onTransitionTimeValue > 65535)
675
+ onTransitionTimeValue = 65534;
676
+ if (onTransitionTimeValue < 0)
677
+ onTransitionTimeValue = 0;
678
+ await entity.write('genLevelCtrl', { onTransitionTime: onTransitionTimeValue }, utils.getOptions(meta.mapped, entity));
679
+ // reverse translate number -> preset
680
+ if (onTransitionTimeValue == 65535) {
681
+ onTransitionTimeValue = 'disabled';
682
+ }
683
+ Object.assign(state, { on_transition_time: onTransitionTimeValue });
684
+ }
685
+ // offTransitionTime - range 0x0000 to 0xffff - optional
686
+ // 0xffff = use onOffTransitionTime
687
+ if (value.off_transition_time !== undefined) {
688
+ let offTransitionTimeValue = value.off_transition_time;
689
+ if (typeof offTransitionTimeValue === 'string' && offTransitionTimeValue.toLowerCase() == 'disabled') {
690
+ offTransitionTimeValue = 65535;
691
+ }
692
+ else {
693
+ offTransitionTimeValue = Number(offTransitionTimeValue);
694
+ }
695
+ if (offTransitionTimeValue > 65535)
696
+ offTransitionTimeValue = 65534;
697
+ if (offTransitionTimeValue < 0)
698
+ offTransitionTimeValue = 0;
699
+ await entity.write('genLevelCtrl', { offTransitionTime: offTransitionTimeValue }, utils.getOptions(meta.mapped, entity));
700
+ // reverse translate number -> preset
701
+ if (offTransitionTimeValue == 65535) {
702
+ offTransitionTimeValue = 'disabled';
703
+ }
704
+ Object.assign(state, { off_transition_time: offTransitionTimeValue });
705
+ }
706
+ // startUpCurrentLevel - range 0x00 to 0xff - optional
707
+ // 0x00 = return to minimum supported level
708
+ // 0xff = return to previous previous
709
+ if (value.current_level_startup !== undefined) {
710
+ let startUpCurrentLevelValue = value.current_level_startup;
711
+ if (typeof startUpCurrentLevelValue === 'string' && startUpCurrentLevelValue.toLowerCase() == 'previous') {
712
+ startUpCurrentLevelValue = 255;
713
+ }
714
+ else if (typeof startUpCurrentLevelValue === 'string' && startUpCurrentLevelValue.toLowerCase() == 'minimum') {
715
+ startUpCurrentLevelValue = 0;
716
+ }
717
+ else {
718
+ startUpCurrentLevelValue = Number(startUpCurrentLevelValue);
719
+ }
720
+ if (startUpCurrentLevelValue > 255)
721
+ startUpCurrentLevelValue = 254;
722
+ if (startUpCurrentLevelValue < 0)
723
+ startUpCurrentLevelValue = 1;
724
+ await entity.write('genLevelCtrl', { startUpCurrentLevel: startUpCurrentLevelValue }, utils.getOptions(meta.mapped, entity));
725
+ // reverse translate number -> preset
726
+ if (startUpCurrentLevelValue == 255) {
727
+ startUpCurrentLevelValue = 'previous';
728
+ }
729
+ if (startUpCurrentLevelValue == 0) {
730
+ startUpCurrentLevelValue = 'minimum';
731
+ }
732
+ Object.assign(state, { current_level_startup: startUpCurrentLevelValue });
733
+ }
734
+ // onLevel - range 0x00 to 0xff - optional
735
+ // Any value outside of MinLevel to MaxLevel, including 0xff and 0x00, is interpreted as "previous".
736
+ if (value.on_level !== undefined) {
737
+ let onLevel = value.on_level;
738
+ if (typeof onLevel === 'string' && onLevel.toLowerCase() == 'previous') {
739
+ onLevel = 255;
740
+ }
741
+ else {
742
+ onLevel = Number(onLevel);
743
+ }
744
+ if (onLevel > 255)
745
+ onLevel = 254;
746
+ if (onLevel < 1)
747
+ onLevel = 1;
748
+ await entity.write('genLevelCtrl', { onLevel }, utils.getOptions(meta.mapped, entity));
749
+ Object.assign(state, { on_level: onLevel == 255 ? 'previous' : onLevel });
750
+ }
751
+ // options - 8-bit map
752
+ // bit 0: ExecuteIfOff - when 0, Move commands are ignored if the device is off;
753
+ // when 1, CurrentLevel can be changed while the device is off.
754
+ // bit 1: CoupleColorTempToLevel - when 1, changes to level also change color temperature.
755
+ // (What this means is not defined, but it's most likely to be "dim to warm".)
756
+ if (value.execute_if_off !== undefined) {
757
+ const executeIfOffValue = !!value.execute_if_off;
758
+ await entity.write('genLevelCtrl', { options: executeIfOffValue ? 1 : 0 }, utils.getOptions(meta.mapped, entity));
759
+ Object.assign(state, { execute_if_off: executeIfOffValue });
760
+ }
761
+ if (Object.keys(state).length > 0) {
762
+ return { state: { level_config: state } };
763
+ }
764
+ },
765
+ convertGet: async (entity, key, meta) => {
766
+ for (const attribute of ['onOffTransitionTime', 'onTransitionTime', 'offTransitionTime', 'startUpCurrentLevel', 'onLevel', 'options']) {
767
+ try {
768
+ await entity.read('genLevelCtrl', [attribute]);
769
+ }
770
+ catch {
771
+ // continue regardless of error, all these are optional in ZCL
772
+ }
773
+ }
774
+ },
775
+ },
776
+ ballast_config: {
777
+ key: ['ballast_config', 'ballast_minimum_level', 'ballast_maximum_level', 'ballast_power_on_level'],
778
+ // zcl attribute names are camel case, but we want to use snake case in the outside communication
779
+ convertSet: async (entity, key, value, meta) => {
780
+ if (key === 'ballast_config') {
781
+ value = utils.toCamelCase(value);
782
+ for (const [attrName, attrValue] of Object.entries(value)) {
783
+ const attributes = { [attrName]: attrValue };
784
+ await entity.write('lightingBallastCfg', attributes);
785
+ }
786
+ }
787
+ if (key === 'ballast_minimum_level') {
788
+ await entity.write('lightingBallastCfg', { minLevel: value });
789
+ }
790
+ if (key === 'ballast_maximum_level') {
791
+ await entity.write('lightingBallastCfg', { maxLevel: value });
792
+ }
793
+ if (key === 'ballast_power_on_level') {
794
+ await entity.write('lightingBallastCfg', { powerOnLevel: value });
795
+ }
796
+ return { state: { [key]: value } };
797
+ },
798
+ convertGet: async (entity, key, meta) => {
799
+ let result = {};
800
+ for (const attrName of [
801
+ 'ballast_status',
802
+ 'min_level',
803
+ 'max_level',
804
+ 'power_on_level',
805
+ 'power_on_fade_time',
806
+ 'intrinsic_ballast_factor',
807
+ 'ballast_factor_adjustment',
808
+ 'lamp_quantity',
809
+ 'lamp_type',
810
+ 'lamp_manufacturer',
811
+ 'lamp_rated_hours',
812
+ 'lamp_burn_hours',
813
+ 'lamp_alarm_mode',
814
+ 'lamp_burn_hours_trip_point',
815
+ ]) {
816
+ try {
817
+ // @ts-expect-error ignore
818
+ result = { ...result, ...(await entity.read('lightingBallastCfg', [utils.toCamelCase(attrName)])) };
819
+ }
820
+ catch {
821
+ // continue regardless of error
822
+ }
823
+ }
824
+ if (key === 'ballast_config') {
825
+ logger_1.logger.debug(`ballast_config attribute results received: ${JSON.stringify(utils.toSnakeCase(result))}`, NS);
826
+ }
827
+ },
828
+ },
829
+ light_brightness_step: {
830
+ key: ['brightness_step', 'brightness_step_onoff'],
831
+ options: [exposes.options.transition()],
832
+ convertSet: async (entity, key, value, meta) => {
833
+ const onOff = key.endsWith('_onoff');
834
+ const command = onOff ? 'stepWithOnOff' : 'step';
835
+ value = Number(value);
836
+ utils.assertNumber(value, key);
837
+ const mode = value > 0 ? 0 : 1;
838
+ const transition = utils.getTransition(entity, key, meta).time;
839
+ const payload = { stepmode: mode, stepsize: Math.abs(value), transtime: transition };
840
+ await entity.command('genLevelCtrl', command, payload, utils.getOptions(meta.mapped, entity));
841
+ if (meta.state.brightness !== undefined) {
842
+ utils.assertNumber(meta.state.brightness);
843
+ let brightness = onOff || meta.state.state === 'ON' ? meta.state.brightness + value : meta.state.brightness;
844
+ if (value === 0) {
845
+ const entityToRead = utils.getEntityOrFirstGroupMember(entity);
846
+ if (entityToRead) {
847
+ brightness = (await entityToRead.read('genLevelCtrl', ['currentLevel'])).currentLevel;
848
+ }
849
+ }
850
+ brightness = Math.min(254, brightness);
851
+ brightness = Math.max(onOff || meta.state.state === 'OFF' ? 0 : 1, brightness);
852
+ if (utils.getMetaValue(entity, meta.mapped, 'turnsOffAtBrightness1', 'allEqual', false)) {
853
+ if (onOff && value < 0 && brightness === 1) {
854
+ brightness = 0;
855
+ }
856
+ else if (onOff && value > 0 && meta.state.brightness === 0) {
857
+ brightness++;
858
+ }
859
+ }
860
+ return { state: { brightness, state: brightness === 0 ? 'OFF' : 'ON' } };
861
+ }
862
+ },
863
+ },
864
+ light_brightness_move: {
865
+ key: ['brightness_move', 'brightness_move_onoff'],
866
+ convertSet: async (entity, key, value, meta) => {
867
+ if (value === 'stop' || value === 0) {
868
+ await entity.command('genLevelCtrl', 'stop', {}, utils.getOptions(meta.mapped, entity));
869
+ // As we cannot determine the new brightness state, we read it from the device
870
+ await utils.sleep(500);
871
+ const target = utils.getEntityOrFirstGroupMember(entity);
872
+ const onOff = (await target.read('genOnOff', ['onOff'])).onOff;
873
+ const brightness = (await target.read('genLevelCtrl', ['currentLevel'])).currentLevel;
874
+ return { state: { brightness, state: onOff === 1 ? 'ON' : 'OFF' } };
875
+ }
876
+ else {
877
+ value = Number(value);
878
+ utils.assertNumber(value, key);
879
+ const payload = { movemode: value > 0 ? 0 : 1, rate: Math.abs(value) };
880
+ const command = key.endsWith('onoff') ? 'moveWithOnOff' : 'move';
881
+ await entity.command('genLevelCtrl', command, payload, utils.getOptions(meta.mapped, entity));
882
+ }
883
+ },
884
+ },
885
+ light_colortemp_step: {
886
+ key: ['color_temp_step'],
887
+ options: [exposes.options.transition()],
888
+ convertSet: async (entity, key, value, meta) => {
889
+ value = Number(value);
890
+ utils.assertNumber(value, key);
891
+ const mode = value > 0 ? 1 : 3;
892
+ const transition = utils.getTransition(entity, key, meta).time;
893
+ const payload = { stepmode: mode, stepsize: Math.abs(value), transtime: transition, minimum: 0, maximum: 600 };
894
+ await entity.command('lightingColorCtrl', 'stepColorTemp', payload, utils.getOptions(meta.mapped, entity));
895
+ // We cannot determine the color temperature from the current state so we read it, because
896
+ // - We don't know the max/min values
897
+ // - Color mode could have been switched (x/y or hue/saturation)
898
+ const entityToRead = utils.getEntityOrFirstGroupMember(entity);
899
+ if (entityToRead) {
900
+ await utils.sleep(100 + transition * 100);
901
+ await entityToRead.read('lightingColorCtrl', ['colorTemperature']);
902
+ }
903
+ },
904
+ },
905
+ light_colortemp_move: {
906
+ key: ['colortemp_move', 'color_temp_move'],
907
+ convertSet: async (entity, key, value, meta) => {
908
+ if (key === 'color_temp_move' && (value === 'stop' || utils.isNumber(value))) {
909
+ value = value === 'stop' ? value : Number(value);
910
+ const payload = { minimum: 0, maximum: 600 };
911
+ if (value === 'stop' || value === 0) {
912
+ payload.rate = 1;
913
+ payload.movemode = 0;
914
+ }
915
+ else {
916
+ utils.assertNumber(value, key);
917
+ payload.rate = Math.abs(value);
918
+ payload.movemode = value > 0 ? 1 : 3;
919
+ }
920
+ await entity.command('lightingColorCtrl', 'moveColorTemp', payload, utils.getOptions(meta.mapped, entity));
921
+ // We cannot determine the color temperaturefrom the current state so we read it, because
922
+ // - Color mode could have been switched (x/y or colortemp)
923
+ if (value === 'stop' || value === 0) {
924
+ const entityToRead = utils.getEntityOrFirstGroupMember(entity);
925
+ if (entityToRead) {
926
+ await utils.sleep(100);
927
+ await entityToRead.read('lightingColorCtrl', ['colorTemperature', 'colorMode']);
928
+ }
929
+ }
930
+ }
931
+ else {
932
+ // Deprecated
933
+ const payload = { minimum: 153, maximum: 370, rate: 55 };
934
+ const stop = (val) => ['stop', 'release', '0'].some((el) => val.includes(el));
935
+ const up = (val) => ['1', 'up'].some((el) => val.includes(el));
936
+ const arr = [value.toString()];
937
+ const moverate = meta.message.rate !== undefined ? Number(meta.message.rate) : 55;
938
+ payload.rate = moverate;
939
+ if (arr.filter(stop).length) {
940
+ payload.movemode = 0;
941
+ }
942
+ else {
943
+ payload.movemode = arr.filter(up).length ? 1 : 3;
944
+ }
945
+ await entity.command('lightingColorCtrl', 'moveColorTemp', payload, utils.getOptions(meta.mapped, entity));
946
+ }
947
+ },
948
+ },
949
+ light_color_and_colortemp_via_color: {
950
+ key: ['color', 'color_temp', 'color_temp_percent'],
951
+ options: [exposes.options.color_sync(), exposes.options.transition()],
952
+ convertSet: async (entity, key, value, meta) => {
953
+ if (key == 'color') {
954
+ return await converters1.light_color.convertSet(entity, key, value, meta);
955
+ }
956
+ else if (key == 'color_temp' || key == 'color_temp_percent') {
957
+ utils.assertNumber(value);
958
+ const xy = libColor.ColorXY.fromMireds(value);
959
+ const payload = {
960
+ transtime: utils.getTransition(entity, key, meta).time,
961
+ colorx: utils.mapNumberRange(xy.x, 0, 1, 0, 65535),
962
+ colory: utils.mapNumberRange(xy.y, 0, 1, 0, 65535),
963
+ };
964
+ await entity.command('lightingColorCtrl', 'moveToColor', payload, utils.getOptions(meta.mapped, entity));
965
+ return {
966
+ state: libColor.syncColorState({ color_mode: constants.colorModeLookup[2], color_temp: value }, meta.state, entity, meta.options),
967
+ };
968
+ }
969
+ },
970
+ convertGet: async (entity, key, meta) => {
971
+ await entity.read('lightingColorCtrl', light.readColorAttributes(entity, meta));
972
+ },
973
+ },
974
+ light_hue_saturation_step: {
975
+ key: ['hue_step', 'saturation_step'],
976
+ options: [exposes.options.transition()],
977
+ convertSet: async (entity, key, value, meta) => {
978
+ value = Number(value);
979
+ utils.assertNumber(value, key);
980
+ const command = key === 'hue_step' ? 'stepHue' : 'stepSaturation';
981
+ const attribute = key === 'hue_step' ? 'currentHue' : 'currentSaturation';
982
+ const mode = value > 0 ? 1 : 3;
983
+ const transition = utils.getTransition(entity, key, meta).time;
984
+ const payload = { stepmode: mode, stepsize: Math.abs(value), transtime: transition };
985
+ await entity.command('lightingColorCtrl', command, payload, utils.getOptions(meta.mapped, entity));
986
+ // We cannot determine the hue/saturation from the current state so we read it, because
987
+ // - Color mode could have been switched (x/y or colortemp)
988
+ const entityToRead = utils.getEntityOrFirstGroupMember(entity);
989
+ if (entityToRead) {
990
+ await utils.sleep(100 + transition * 100);
991
+ await entityToRead.read('lightingColorCtrl', [attribute, 'colorMode']);
992
+ }
993
+ },
994
+ },
995
+ light_hue_saturation_move: {
996
+ key: ['hue_move', 'saturation_move'],
997
+ convertSet: async (entity, key, value, meta) => {
998
+ value = value === 'stop' ? value : Number(value);
999
+ const command = key === 'hue_move' ? 'moveHue' : 'moveSaturation';
1000
+ const attribute = key === 'hue_move' ? 'currentHue' : 'currentSaturation';
1001
+ const payload = {};
1002
+ if (value === 'stop' || value === 0) {
1003
+ payload.rate = 1;
1004
+ payload.movemode = 0;
1005
+ }
1006
+ else {
1007
+ utils.assertNumber(value, key);
1008
+ payload.rate = Math.abs(value);
1009
+ payload.movemode = value > 0 ? 1 : 3;
1010
+ }
1011
+ await entity.command('lightingColorCtrl', command, payload, utils.getOptions(meta.mapped, entity));
1012
+ // We cannot determine the hue/saturation from the current state so we read it, because
1013
+ // - Color mode could have been switched (x/y or colortemp)
1014
+ if (value === 'stop' || value === 0) {
1015
+ const entityToRead = utils.getEntityOrFirstGroupMember(entity);
1016
+ if (entityToRead) {
1017
+ await utils.sleep(100);
1018
+ await entityToRead.read('lightingColorCtrl', [attribute, 'colorMode']);
1019
+ }
1020
+ }
1021
+ },
1022
+ },
1023
+ light_onoff_brightness: {
1024
+ key: ['state', 'brightness', 'brightness_percent', 'on_time', 'off_wait_time'],
1025
+ options: [exposes.options.transition()],
1026
+ convertSet: async (entity, key, value, meta) => {
1027
+ const { message } = meta;
1028
+ const transition = utils.getTransition(entity, 'brightness', meta);
1029
+ const turnsOffAtBrightness1 = utils.getMetaValue(entity, meta.mapped, 'turnsOffAtBrightness1', 'allEqual', false);
1030
+ let state = message.state !== undefined ? (typeof message.state === 'string' ? message.state.toLowerCase() : null) : undefined;
1031
+ let brightness = undefined;
1032
+ if (message.brightness !== undefined) {
1033
+ brightness = Number(message.brightness);
1034
+ }
1035
+ else if (message.brightness_percent !== undefined) {
1036
+ brightness = utils.mapNumberRange(Number(message.brightness_percent), 0, 100, 0, 255);
1037
+ }
1038
+ if (brightness === 255) {
1039
+ // Allow 255 for backwards compatibility.
1040
+ brightness = 254;
1041
+ }
1042
+ if (brightness !== undefined && (isNaN(brightness) || brightness < 0 || brightness > 254)) {
1043
+ throw new Error(`Brightness value of message: '${JSON.stringify(message)}' invalid, must be a number >= 0 and =< 254`);
1044
+ }
1045
+ if (state !== undefined && state !== null && ['on', 'off', 'toggle'].includes(state) === false) {
1046
+ throw new Error(`State value of message: '${JSON.stringify(message)}' invalid, must be 'ON', 'OFF' or 'TOGGLE'`);
1047
+ }
1048
+ if ((state === undefined || state === null) && brightness === undefined) {
1049
+ throw new Error(`At least one of "brightness" or "state" must have a value: '${JSON.stringify(message)}'`);
1050
+ }
1051
+ // Infer state from desired brightness if unset. Ideally we'd want to keep it as it is, but this code has always
1052
+ // used 'MoveToLevelWithOnOff' so that'd break backwards compatibility. To keep the state, the user
1053
+ // has to explicitly set it to null.
1054
+ if (state === undefined) {
1055
+ // Also write to `meta.message.state` in case we delegate to the `on_off` converter.
1056
+ state = meta.message.state = brightness === 0 ? 'off' : 'on';
1057
+ }
1058
+ let publishBrightness = brightness !== undefined;
1059
+ const targetState = state === 'toggle' ? (meta.state.state === 'ON' ? 'off' : 'on') : state;
1060
+ if (targetState === 'off') {
1061
+ // Simulate 'Off' with transition via 'MoveToLevelWithOnOff', otherwise just use 'Off'.
1062
+ // TODO: if this is a group where some members don't support Level Control, turning them off
1063
+ // with transition may have no effect. (Some devices, such as Envilar ZG302-BOX-RELAY, handle
1064
+ // 'MoveToLevelWithOnOff' despite not supporting the cluster; others, like the LEDVANCE SMART+
1065
+ // plug, do not.)
1066
+ brightness = transition.specified || brightness === 0 ? 0 : undefined;
1067
+ if (brightness !== undefined &&
1068
+ meta.state.state === 'OFF' &&
1069
+ utils.getMetaValue(entity, meta.mapped, 'noOffTransitionWhenOff', { atLeastOnce: true }, false)) {
1070
+ logger_1.logger.debug(`Supressing OFF transition since entity is OFF and has noOffTransitionWhenOff=true`, NS);
1071
+ brightness = undefined;
1072
+ }
1073
+ if (meta.state.brightness !== undefined && meta.state.state === 'ON') {
1074
+ // The light's current level gets clobbered in two cases:
1075
+ // 1. when 'Off' has a transition, in which case it is really 'MoveToLevelWithOnOff'
1076
+ // https://github.com/Koenkk/zigbee-herdsman-converters/issues/1073
1077
+ // 2. when 'OnLevel' is set: "If OnLevel is not defined, set the CurrentLevel to the stored level."
1078
+ // https://github.com/Koenkk/zigbee2mqtt/issues/2850#issuecomment-580365633
1079
+ // We need to remember current brightness in case the next 'On' does not provide it. `meta` is not reliable
1080
+ // here, as it will get clobbered too if reporting is configured.
1081
+ globalStore.putValue(entity, 'brightness', meta.state.brightness);
1082
+ globalStore.putValue(entity, 'turnedOffWithTransition', brightness !== undefined);
1083
+ }
1084
+ }
1085
+ else if (targetState === 'on' && brightness === undefined) {
1086
+ // Simulate 'On' with transition via 'MoveToLevelWithOnOff', or restore the level from before
1087
+ // it was clobbered by a previous transition to off; otherwise just use 'On'.
1088
+ // TODO: same problem as above.
1089
+ // TODO: if transition is not specified, should use device default (OnTransitionTime), not 0.
1090
+ if (transition.specified || globalStore.getValue(entity, 'turnedOffWithTransition') === true) {
1091
+ const levelConfig = utils.getObjectProperty(meta.state, 'level_config', {});
1092
+ let onLevel = utils.getObjectProperty(levelConfig, 'on_level', 0);
1093
+ if (onLevel === 0 && entity.meta.onLevelSupported !== false) {
1094
+ try {
1095
+ const attributeRead = await entity.read('genLevelCtrl', ['onLevel']);
1096
+ if (attributeRead !== undefined) {
1097
+ // @ts-expect-error ignore
1098
+ onLevel = attributeRead['onLevel'];
1099
+ }
1100
+ }
1101
+ catch {
1102
+ // OnLevel not supported
1103
+ }
1104
+ }
1105
+ if (onLevel === 0) {
1106
+ onLevel = 'previous';
1107
+ entity.meta.onLevelSupported = false;
1108
+ entity.save();
1109
+ }
1110
+ if (onLevel === 255 || onLevel === 'previous') {
1111
+ const current = utils.getObjectProperty(meta.state, 'brightness', 254);
1112
+ brightness = globalStore.getValue(entity, 'brightness', current);
1113
+ }
1114
+ else {
1115
+ brightness = onLevel;
1116
+ }
1117
+ // Published state might have gotten clobbered by reporting.
1118
+ publishBrightness = true;
1119
+ }
1120
+ }
1121
+ if (brightness === undefined) {
1122
+ const result = (await converters1.on_off.convertSet(entity, 'state', state, meta));
1123
+ if (result) {
1124
+ if (result.state && result.state.state === 'ON' && meta.state.brightness === 0) {
1125
+ result.state.brightness = 1;
1126
+ }
1127
+ }
1128
+ return result;
1129
+ }
1130
+ if (brightness === 0 && (targetState === 'on' || state === null)) {
1131
+ brightness = 1;
1132
+ }
1133
+ if (brightness === 1 && turnsOffAtBrightness1) {
1134
+ brightness = 2;
1135
+ }
1136
+ if (targetState !== 'off') {
1137
+ globalStore.putValue(entity, 'brightness', brightness);
1138
+ globalStore.clearValue(entity, 'turnedOffWithTransition');
1139
+ }
1140
+ await entity.command('genLevelCtrl', state === null ? 'moveToLevel' : 'moveToLevelWithOnOff', { level: Number(brightness), transtime: transition.time }, utils.getOptions(meta.mapped, entity));
1141
+ const result = { state: {} };
1142
+ if (publishBrightness) {
1143
+ result.state.brightness = Number(brightness);
1144
+ }
1145
+ if (state !== null) {
1146
+ result.state.state = brightness === 0 ? 'OFF' : 'ON';
1147
+ }
1148
+ return result;
1149
+ },
1150
+ convertGet: async (entity, key, meta) => {
1151
+ if (key === 'brightness') {
1152
+ await entity.read('genLevelCtrl', ['currentLevel']);
1153
+ }
1154
+ else if (key === 'state') {
1155
+ await converters1.on_off.convertGet(entity, key, meta);
1156
+ }
1157
+ },
1158
+ },
1159
+ light_colortemp_startup: {
1160
+ key: ['color_temp_startup'],
1161
+ convertSet: async (entity, key, value, meta) => {
1162
+ const [colorTempMin, colorTempMax] = light.findColorTempRange(entity);
1163
+ const preset = { warmest: colorTempMax, warm: 454, neutral: 370, cool: 250, coolest: colorTempMin, previous: 65535 };
1164
+ if (utils.isString(value) && value in preset) {
1165
+ value = utils.getFromLookup(value, preset);
1166
+ }
1167
+ value = Number(value);
1168
+ utils.assertNumber(value);
1169
+ // ensure value within range
1170
+ // we do allow one exception for 0xffff, which is to restore the previous value
1171
+ if (value != 65535) {
1172
+ value = light.clampColorTemp(value, colorTempMin, colorTempMax);
1173
+ }
1174
+ await entity.write('lightingColorCtrl', { startUpColorTemperature: value }, utils.getOptions(meta.mapped, entity));
1175
+ return { state: { color_temp_startup: value } };
1176
+ },
1177
+ convertGet: async (entity, key, meta) => {
1178
+ await entity.read('lightingColorCtrl', ['startUpColorTemperature']);
1179
+ },
1180
+ },
1181
+ light_color_colortemp: {
1182
+ /**
1183
+ * This converter is a combination of light_color and light_colortemp and
1184
+ * can be used instead of the two individual converters . When used to set,
1185
+ * it actually calls out to light_color or light_colortemp to get the
1186
+ * return value. When used to get, it gets both color and colorTemp in
1187
+ * one call.
1188
+ * The reason for the existence of this somewhat peculiar converter is
1189
+ * that some lights don't report their state when changed. To fix this,
1190
+ * we query the state after we set it. We want to query color and colorTemp
1191
+ * both when setting either, because both change when setting one. This
1192
+ * converter is used to do just that.
1193
+ */
1194
+ key: ['color', 'color_temp', 'color_temp_percent'],
1195
+ options: [exposes.options.color_sync(), exposes.options.transition()],
1196
+ convertSet: async (entity, key, value, meta) => {
1197
+ if (key == 'color') {
1198
+ const result = await converters1.light_color.convertSet(entity, key, value, meta);
1199
+ return result;
1200
+ }
1201
+ else if (key == 'color_temp' || key == 'color_temp_percent') {
1202
+ const result = await converters1.light_colortemp.convertSet(entity, key, value, meta);
1203
+ return result;
1204
+ }
1205
+ },
1206
+ convertGet: async (entity, key, meta) => {
1207
+ await entity.read('lightingColorCtrl', light.readColorAttributes(entity, meta, ['colorTemperature']));
1208
+ },
1209
+ },
1210
+ effect: {
1211
+ key: ['effect', 'alert', 'flash'], // alert and flash are deprecated.
1212
+ convertSet: async (entity, key, value, meta) => {
1213
+ if (key === 'effect') {
1214
+ utils.assertString(value, key);
1215
+ const lookup = { blink: 0, breathe: 1, okay: 2, channel_change: 11, finish_effect: 254, stop_effect: 255 };
1216
+ value = value.toLowerCase();
1217
+ if (value === 'colorloop') {
1218
+ const transition = meta.message.transition ?? 15;
1219
+ utils.assertNumber(transition, 'transition');
1220
+ const speed = Math.min(255, Math.max(1, Math.round(255 / transition)));
1221
+ await converters2.light_hue_saturation_move.convertSet(entity, 'hue_move', speed, meta);
1222
+ }
1223
+ else if (value === 'stop_colorloop') {
1224
+ await converters2.light_hue_saturation_move.convertSet(entity, 'hue_move', 'stop', meta);
1225
+ }
1226
+ else {
1227
+ const payload = { effectid: utils.getFromLookup(value, lookup), effectvariant: 0 };
1228
+ await entity.command('genIdentify', 'triggerEffect', payload, utils.getOptions(meta.mapped, entity));
1229
+ }
1230
+ }
1231
+ else if (key === 'alert' || key === 'flash') {
1232
+ // Deprecated
1233
+ let effectid = 0;
1234
+ const lookup = { select: 0x00, lselect: 0x01, none: 0xff };
1235
+ if (key === 'flash') {
1236
+ if (value === 2) {
1237
+ value = 'select';
1238
+ }
1239
+ else if (value === 10) {
1240
+ value = 'lselect';
1241
+ }
1242
+ }
1243
+ effectid = utils.getFromLookup(value, lookup);
1244
+ const payload = { effectid, effectvariant: 0 };
1245
+ await entity.command('genIdentify', 'triggerEffect', payload, utils.getOptions(meta.mapped, entity));
1246
+ }
1247
+ },
1248
+ },
1249
+ thermostat_remote_sensing: {
1250
+ key: ['remote_sensing'],
1251
+ convertSet: async (entity, key, value, meta) => {
1252
+ await entity.write('hvacThermostat', { remoteSensing: value });
1253
+ },
1254
+ convertGet: async (entity, key, meta) => {
1255
+ await entity.read('hvacThermostat', ['remoteSensing']);
1256
+ },
1257
+ },
1258
+ thermostat_weekly_schedule: {
1259
+ key: ['weekly_schedule'],
1260
+ convertSet: async (entity, key, value, meta) => {
1261
+ /*
1262
+ * We want to support a simple human creatable format to send a schedule:
1263
+ {"weekly_schedule": {
1264
+ "dayofweek": ["monday", "tuesday"],
1265
+ "transitions": [
1266
+ {"heatSetpoint": 16, "transitionTime": "0:00"},
1267
+ {"heatSetpoint": 20, "transitionTime": "18:00"},
1268
+ {"heatSetpoint": 16, "transitionTime": "19:30"}
1269
+ ]}}
1270
+
1271
+ * However exposes is not flexible enough to describe something like this. There is a
1272
+ * much more verbose format we also support so that exposes work.
1273
+ {"weekly_schedule": {
1274
+ "dayofweek": [
1275
+ {"day": "monday"},
1276
+ {"day": "tuesday"}
1277
+ ],
1278
+ "transitions": [
1279
+ {"heatSetpoint": 16, "transitionTime": {"hour": 0, "minute": 0}},
1280
+ {"heatSetpoint": 20, "transitionTime": {"hour": 18, "minute": 0}},
1281
+ {"heatSetpoint": 16, "transitionTime": {"hour": 19, "minute": 30}}
1282
+ ]}}
1283
+ */
1284
+ utils.assertObject(value, key);
1285
+ const payload = {
1286
+ dayofweek: value.dayofweek,
1287
+ transitions: value.transitions,
1288
+ };
1289
+ if (Array.isArray(payload.transitions)) {
1290
+ // calculate numoftrans
1291
+ if (typeof value.numoftrans !== 'undefined') {
1292
+ logger_1.logger.warning(`weekly_schedule: ignoring provided numoftrans value (${JSON.stringify(value.numoftrans)}), ` +
1293
+ 'this is now calculated automatically', NS);
1294
+ }
1295
+ payload.numoftrans = payload.transitions.length;
1296
+ // mode is calculated below
1297
+ if (typeof value.mode !== 'undefined') {
1298
+ logger_1.logger.warning(`weekly_schedule: ignoring provided mode value (${JSON.stringify(value.mode)}), ` + 'this is now calculated automatically', NS);
1299
+ }
1300
+ payload.mode = [];
1301
+ // transform transition payload values if needed
1302
+ for (const elem of payload.transitions) {
1303
+ // update payload.mode if needed
1304
+ if (elem.heatSetpoint !== undefined && !payload.mode.includes('heat')) {
1305
+ payload.mode.push('heat');
1306
+ }
1307
+ if (elem.coolSetpoint !== undefined && !payload.mode.includes('cool')) {
1308
+ payload.mode.push('cool');
1309
+ }
1310
+ // transform setpoint values if numeric
1311
+ if (typeof elem['heatSetpoint'] === 'number') {
1312
+ elem['heatSetpoint'] = Math.round(elem['heatSetpoint'] * 100);
1313
+ }
1314
+ if (typeof elem['coolSetpoint'] === 'number') {
1315
+ elem['coolSetpoint'] = Math.round(elem['coolSetpoint'] * 100);
1316
+ }
1317
+ // accept 24h time notation (e.g. 19:30)
1318
+ if (typeof elem['transitionTime'] === 'string') {
1319
+ const time = elem['transitionTime'].split(':');
1320
+ const timeHour = parseInt(time[0]) * 60;
1321
+ const timeMinute = parseInt(time[1]);
1322
+ if (time.length != 2 || isNaN(timeHour) || isNaN(timeMinute)) {
1323
+ logger_1.logger.warning(`weekly_schedule: expected 24h time notation (e.g. 19:30) but got '${elem['transitionTime']}'!`, NS);
1324
+ }
1325
+ else {
1326
+ elem['transitionTime'] = timeHour + timeMinute;
1327
+ }
1328
+ }
1329
+ else if (typeof elem['transitionTime'] === 'object') {
1330
+ if (elem['transitionTime'].hour === undefined || elem['transitionTime'].minute === undefined) {
1331
+ throw new Error('weekly_schedule: expected 24h time object (e.g. {"hour": 19, "minute": 30}), ' +
1332
+ `but got '${JSON.stringify(elem['transitionTime'])}'!`);
1333
+ }
1334
+ else if (isNaN(elem['transitionTime']['hour'])) {
1335
+ throw new Error('weekly_schedule: expected time.hour to be a number, ' + `but got '${elem['transitionTime']['hour']}'!`);
1336
+ }
1337
+ else if (isNaN(elem['transitionTime']['minute'])) {
1338
+ throw new Error('weekly_schedule: expected time.minute to be a number, ' + `but got '${elem['transitionTime']['minute']}'!`);
1339
+ }
1340
+ else {
1341
+ elem['transitionTime'] = parseInt(elem['transitionTime']['hour']) * 60 + parseInt(elem['transitionTime']['minute']);
1342
+ }
1343
+ }
1344
+ }
1345
+ }
1346
+ else {
1347
+ logger_1.logger.error('weekly_schedule: transitions is not an array!', NS);
1348
+ return;
1349
+ }
1350
+ // map array of desired modes to bitmask
1351
+ let mode = 0;
1352
+ for (let m of payload.mode) {
1353
+ // lookup mode bit
1354
+ m = utils.getKey(constants.thermostatScheduleMode, m.toLowerCase(), m, Number);
1355
+ mode |= 1 << m;
1356
+ }
1357
+ payload.mode = mode;
1358
+ // map array of days to desired dayofweek bitmask
1359
+ if (typeof payload.dayofweek === 'string')
1360
+ payload.dayofweek = [payload.dayofweek];
1361
+ if (Array.isArray(payload.dayofweek)) {
1362
+ let dayofweek = 0;
1363
+ for (let d of payload.dayofweek) {
1364
+ if (typeof d === 'object') {
1365
+ if (d.day === undefined) {
1366
+ throw new Error('weekly_schedule: expected dayofweek to be string or {"day": "str"}, ' + `but got '${JSON.stringify(d)}'!`);
1367
+ }
1368
+ d = d.day;
1369
+ }
1370
+ // lookup dayofweek bit
1371
+ d = utils.getKey(constants.thermostatDayOfWeek, d.toLowerCase(), d, Number);
1372
+ dayofweek |= 1 << d;
1373
+ }
1374
+ payload.dayofweek = dayofweek;
1375
+ }
1376
+ await entity.command('hvacThermostat', 'setWeeklySchedule', payload, utils.getOptions(meta.mapped, entity));
1377
+ },
1378
+ convertGet: async (entity, key, meta) => {
1379
+ const payload = {
1380
+ daystoreturn: 0xff, // Sun-Sat and vacation
1381
+ modetoreturn: 3, // heat + cool
1382
+ };
1383
+ await entity.command('hvacThermostat', 'getWeeklySchedule', payload, utils.getOptions(meta.mapped, entity));
1384
+ },
1385
+ },
1386
+ thermostat_system_mode: {
1387
+ key: ['system_mode'],
1388
+ convertSet: async (entity, key, value, meta) => {
1389
+ let systemMode = utils.getKey(constants.thermostatSystemModes, value, undefined, Number);
1390
+ if (systemMode === undefined) {
1391
+ systemMode = utils.getKey(legacy.thermostatSystemModes, value, value, Number);
1392
+ }
1393
+ await entity.write('hvacThermostat', { systemMode });
1394
+ return { state: { system_mode: value } };
1395
+ },
1396
+ convertGet: async (entity, key, meta) => {
1397
+ await entity.read('hvacThermostat', ['systemMode']);
1398
+ },
1399
+ },
1400
+ acova_thermostat_system_mode: {
1401
+ key: ['system_mode'],
1402
+ convertSet: async (entity, key, value, meta) => {
1403
+ let systemMode = utils.getKey(constants.acovaThermostatSystemModes, value, undefined, Number);
1404
+ if (systemMode === undefined) {
1405
+ systemMode = utils.getKey(legacy.thermostatSystemModes, value, value, Number);
1406
+ }
1407
+ await entity.write('hvacThermostat', { systemMode });
1408
+ return { state: { system_mode: value } };
1409
+ },
1410
+ convertGet: async (entity, key, meta) => {
1411
+ await entity.read('hvacThermostat', ['systemMode']);
1412
+ },
1413
+ },
1414
+ thermostat_control_sequence_of_operation: {
1415
+ key: ['control_sequence_of_operation'],
1416
+ convertSet: async (entity, key, value, meta) => {
1417
+ utils.assertEndpoint(entity);
1418
+ let val = utils.getKey(constants.thermostatControlSequenceOfOperations, value, undefined, Number);
1419
+ if (val === undefined) {
1420
+ val = utils.getKey(constants.thermostatControlSequenceOfOperations, value, value, Number);
1421
+ }
1422
+ const attributes = { ctrlSeqeOfOper: val };
1423
+ await entity.write('hvacThermostat', attributes);
1424
+ // NOTE: update the cluster attribute we store as this is used by
1425
+ // SMaBiT AV2010/32's dynamic expose function.
1426
+ entity.saveClusterAttributeKeyValue('hvacThermostat', attributes);
1427
+ return { state: { control_sequence_of_operation: value } };
1428
+ },
1429
+ convertGet: async (entity, key, meta) => {
1430
+ await entity.read('hvacThermostat', ['ctrlSeqeOfOper']);
1431
+ },
1432
+ },
1433
+ thermostat_programming_operation_mode: {
1434
+ key: ['programming_operation_mode'],
1435
+ convertSet: async (entity, key, value, meta) => {
1436
+ const val = utils.getKey(constants.thermostatProgrammingOperationModes, value, undefined, Number);
1437
+ if (val === undefined) {
1438
+ throw new Error('Programming operation mode invalid, must be one of: ' + Object.values(constants.thermostatProgrammingOperationModes).join(', '));
1439
+ }
1440
+ await entity.write('hvacThermostat', { programingOperMode: val });
1441
+ return { state: { programming_operation_mode: value } };
1442
+ },
1443
+ convertGet: async (entity, key, meta) => {
1444
+ await entity.read('hvacThermostat', ['programingOperMode']);
1445
+ },
1446
+ },
1447
+ thermostat_temperature_display_mode: {
1448
+ key: ['temperature_display_mode'],
1449
+ convertSet: async (entity, key, value, meta) => {
1450
+ const tempDisplayMode = utils.getKey(constants.temperatureDisplayMode, value, value, Number);
1451
+ await entity.write('hvacUserInterfaceCfg', { tempDisplayMode });
1452
+ return { state: { temperature_display_mode: value } };
1453
+ },
1454
+ convertGet: async (entity, key, meta) => {
1455
+ await entity.read('hvacUserInterfaceCfg', ['tempDisplayMode']);
1456
+ },
1457
+ },
1458
+ thermostat_keypad_lockout: {
1459
+ key: ['keypad_lockout'],
1460
+ convertSet: async (entity, key, value, meta) => {
1461
+ const keypadLockout = utils.getKey(constants.keypadLockoutMode, value, value, Number);
1462
+ await entity.write('hvacUserInterfaceCfg', { keypadLockout });
1463
+ return { state: { keypad_lockout: value } };
1464
+ },
1465
+ convertGet: async (entity, key, meta) => {
1466
+ await entity.read('hvacUserInterfaceCfg', ['keypadLockout']);
1467
+ },
1468
+ },
1469
+ thermostat_temperature_setpoint_hold: {
1470
+ key: ['temperature_setpoint_hold'],
1471
+ convertSet: async (entity, key, value, meta) => {
1472
+ const tempSetpointHold = value;
1473
+ await entity.write('hvacThermostat', { tempSetpointHold });
1474
+ },
1475
+ convertGet: async (entity, key, meta) => {
1476
+ await entity.read('hvacThermostat', ['tempSetpointHold']);
1477
+ },
1478
+ },
1479
+ thermostat_temperature_setpoint_hold_duration: {
1480
+ key: ['temperature_setpoint_hold_duration'],
1481
+ convertSet: async (entity, key, value, meta) => {
1482
+ const tempSetpointHoldDuration = value;
1483
+ await entity.write('hvacThermostat', { tempSetpointHoldDuration });
1484
+ },
1485
+ convertGet: async (entity, key, meta) => {
1486
+ await entity.read('hvacThermostat', ['tempSetpointHoldDuration']);
1487
+ },
1488
+ },
1489
+ fan_mode: {
1490
+ key: ['fan_mode', 'fan_state'],
1491
+ convertSet: async (entity, key, value, meta) => {
1492
+ utils.assertString(value, key);
1493
+ const fanMode = utils.getFromLookup(value, constants.fanMode);
1494
+ await entity.write('hvacFanCtrl', { fanMode });
1495
+ return { state: { fan_mode: value.toLowerCase(), fan_state: value.toLowerCase() === 'off' ? 'OFF' : 'ON' } };
1496
+ },
1497
+ convertGet: async (entity, key, meta) => {
1498
+ await entity.read('hvacFanCtrl', ['fanMode']);
1499
+ },
1500
+ },
1501
+ thermostat_local_temperature: {
1502
+ key: ['local_temperature'],
1503
+ convertGet: async (entity, key, meta) => {
1504
+ await entity.read('hvacThermostat', ['localTemp']);
1505
+ },
1506
+ },
1507
+ thermostat_outdoor_temperature: {
1508
+ key: ['outdoor_temperature'],
1509
+ convertGet: async (entity, key, meta) => {
1510
+ await entity.read('hvacThermostat', ['outdoorTemp']);
1511
+ },
1512
+ },
1513
+ thermostat_local_temperature_calibration: {
1514
+ key: ['local_temperature_calibration'],
1515
+ convertSet: async (entity, key, value, meta) => {
1516
+ utils.assertNumber(value);
1517
+ await entity.write('hvacThermostat', { localTemperatureCalibration: Math.round(value * 10) });
1518
+ return { state: { local_temperature_calibration: value } };
1519
+ },
1520
+ convertGet: async (entity, key, meta) => {
1521
+ await entity.read('hvacThermostat', ['localTemperatureCalibration']);
1522
+ },
1523
+ },
1524
+ thermostat_occupancy: {
1525
+ key: ['occupancy'],
1526
+ convertGet: async (entity, key, meta) => {
1527
+ await entity.read('hvacThermostat', ['occupancy']);
1528
+ },
1529
+ },
1530
+ thermostat_clear_weekly_schedule: {
1531
+ key: ['clear_weekly_schedule'],
1532
+ convertSet: async (entity, key, value, meta) => {
1533
+ await entity.command('hvacThermostat', 'clearWeeklySchedule', {}, utils.getOptions(meta.mapped, entity));
1534
+ },
1535
+ },
1536
+ thermostat_pi_heating_demand: {
1537
+ key: ['pi_heating_demand'],
1538
+ convertGet: async (entity, key, meta) => {
1539
+ await entity.read('hvacThermostat', ['pIHeatingDemand']);
1540
+ },
1541
+ },
1542
+ thermostat_running_state: {
1543
+ key: ['running_state'],
1544
+ convertGet: async (entity, key, meta) => {
1545
+ await entity.read('hvacThermostat', ['runningState']);
1546
+ },
1547
+ },
1548
+ thermostat_occupied_heating_setpoint: {
1549
+ key: ['occupied_heating_setpoint'],
1550
+ options: [exposes.options.thermostat_unit()],
1551
+ convertSet: async (entity, key, value, meta) => {
1552
+ utils.assertNumber(value, key);
1553
+ let result;
1554
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1555
+ result = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
1556
+ }
1557
+ else {
1558
+ result = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
1559
+ }
1560
+ const occupiedHeatingSetpoint = result;
1561
+ await entity.write('hvacThermostat', { occupiedHeatingSetpoint });
1562
+ return { state: { occupied_heating_setpoint: value } };
1563
+ },
1564
+ convertGet: async (entity, key, meta) => {
1565
+ await entity.read('hvacThermostat', ['occupiedHeatingSetpoint']);
1566
+ },
1567
+ },
1568
+ thermostat_unoccupied_heating_setpoint: {
1569
+ key: ['unoccupied_heating_setpoint'],
1570
+ options: [exposes.options.thermostat_unit()],
1571
+ convertSet: async (entity, key, value, meta) => {
1572
+ utils.assertNumber(value, key);
1573
+ let result;
1574
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1575
+ result = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
1576
+ }
1577
+ else {
1578
+ result = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
1579
+ }
1580
+ const unoccupiedHeatingSetpoint = result;
1581
+ await entity.write('hvacThermostat', { unoccupiedHeatingSetpoint });
1582
+ return { state: { unoccupied_heating_setpoint: value } };
1583
+ },
1584
+ convertGet: async (entity, key, meta) => {
1585
+ await entity.read('hvacThermostat', ['unoccupiedHeatingSetpoint']);
1586
+ },
1587
+ },
1588
+ thermostat_occupied_cooling_setpoint: {
1589
+ key: ['occupied_cooling_setpoint'],
1590
+ options: [exposes.options.thermostat_unit()],
1591
+ convertSet: async (entity, key, value, meta) => {
1592
+ utils.assertNumber(value, key);
1593
+ let result;
1594
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1595
+ result = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
1596
+ }
1597
+ else {
1598
+ result = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
1599
+ }
1600
+ const occupiedCoolingSetpoint = result;
1601
+ await entity.write('hvacThermostat', { occupiedCoolingSetpoint });
1602
+ return { state: { occupied_cooling_setpoint: value } };
1603
+ },
1604
+ convertGet: async (entity, key, meta) => {
1605
+ await entity.read('hvacThermostat', ['occupiedCoolingSetpoint']);
1606
+ },
1607
+ },
1608
+ thermostat_unoccupied_cooling_setpoint: {
1609
+ key: ['unoccupied_cooling_setpoint'],
1610
+ options: [exposes.options.thermostat_unit()],
1611
+ convertSet: async (entity, key, value, meta) => {
1612
+ utils.assertNumber(value, key);
1613
+ let result;
1614
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1615
+ result = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
1616
+ }
1617
+ else {
1618
+ result = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
1619
+ }
1620
+ const unoccupiedCoolingSetpoint = result;
1621
+ await entity.write('hvacThermostat', { unoccupiedCoolingSetpoint });
1622
+ return { state: { unoccupied_cooling_setpoint: value } };
1623
+ },
1624
+ convertGet: async (entity, key, meta) => {
1625
+ await entity.read('hvacThermostat', ['unoccupiedCoolingSetpoint']);
1626
+ },
1627
+ },
1628
+ thermostat_setpoint_raise_lower: {
1629
+ key: ['setpoint_raise_lower'],
1630
+ convertSet: async (entity, key, value, meta) => {
1631
+ utils.assertObject(value, key);
1632
+ const payload = { mode: value.mode, amount: Math.round(value.amount) * 100 };
1633
+ await entity.command('hvacThermostat', 'setpointRaiseLower', payload, utils.getOptions(meta.mapped, entity));
1634
+ },
1635
+ },
1636
+ thermostat_relay_status_log: {
1637
+ key: ['relay_status_log'],
1638
+ convertGet: async (entity, key, meta) => {
1639
+ await entity.command('hvacThermostat', 'getRelayStatusLog', {}, utils.getOptions(meta.mapped, entity));
1640
+ },
1641
+ },
1642
+ thermostat_running_mode: {
1643
+ key: ['running_mode'],
1644
+ convertGet: async (entity, key, meta) => {
1645
+ await entity.read('hvacThermostat', ['runningMode']);
1646
+ },
1647
+ },
1648
+ thermostat_min_heat_setpoint_limit: {
1649
+ key: ['min_heat_setpoint_limit'],
1650
+ convertSet: async (entity, key, value, meta) => {
1651
+ utils.assertNumber(value);
1652
+ let result;
1653
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1654
+ result = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
1655
+ }
1656
+ else {
1657
+ result = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
1658
+ }
1659
+ const minHeatSetpointLimit = result;
1660
+ await entity.write('hvacThermostat', { minHeatSetpointLimit });
1661
+ return { state: { min_heat_setpoint_limit: value } };
1662
+ },
1663
+ convertGet: async (entity, key, meta) => {
1664
+ await entity.read('hvacThermostat', ['minHeatSetpointLimit']);
1665
+ },
1666
+ },
1667
+ thermostat_max_heat_setpoint_limit: {
1668
+ key: ['max_heat_setpoint_limit'],
1669
+ convertSet: async (entity, key, value, meta) => {
1670
+ utils.assertNumber(value, key);
1671
+ let result;
1672
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1673
+ result = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
1674
+ }
1675
+ else {
1676
+ result = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
1677
+ }
1678
+ const maxHeatSetpointLimit = result;
1679
+ await entity.write('hvacThermostat', { maxHeatSetpointLimit });
1680
+ return { state: { max_heat_setpoint_limit: value } };
1681
+ },
1682
+ convertGet: async (entity, key, meta) => {
1683
+ await entity.read('hvacThermostat', ['maxHeatSetpointLimit']);
1684
+ },
1685
+ },
1686
+ thermostat_min_cool_setpoint_limit: {
1687
+ key: ['min_cool_setpoint_limit'],
1688
+ convertSet: async (entity, key, value, meta) => {
1689
+ utils.assertNumber(value, key);
1690
+ let result;
1691
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1692
+ result = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
1693
+ }
1694
+ else {
1695
+ result = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
1696
+ }
1697
+ const minCoolSetpointLimit = result;
1698
+ await entity.write('hvacThermostat', { minCoolSetpointLimit });
1699
+ return { state: { min_cool_setpoint_limit: value } };
1700
+ },
1701
+ convertGet: async (entity, key, meta) => {
1702
+ await entity.read('hvacThermostat', ['minCoolSetpointLimit']);
1703
+ },
1704
+ },
1705
+ thermostat_max_cool_setpoint_limit: {
1706
+ key: ['max_cool_setpoint_limit'],
1707
+ convertSet: async (entity, key, value, meta) => {
1708
+ utils.assertNumber(value, key);
1709
+ let result;
1710
+ if (meta.options.thermostat_unit === 'fahrenheit') {
1711
+ result = Math.round(utils.normalizeCelsiusVersionOfFahrenheit(value) * 100);
1712
+ }
1713
+ else {
1714
+ result = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
1715
+ }
1716
+ const maxCoolSetpointLimit = result;
1717
+ await entity.write('hvacThermostat', { maxCoolSetpointLimit });
1718
+ return { state: { max_cool_setpoint_limit: value } };
1719
+ },
1720
+ convertGet: async (entity, key, meta) => {
1721
+ await entity.read('hvacThermostat', ['maxCoolSetpointLimit']);
1722
+ },
1723
+ },
1724
+ thermostat_ac_louver_position: {
1725
+ key: ['ac_louver_position'],
1726
+ convertSet: async (entity, key, value, meta) => {
1727
+ let acLouverPosition = utils.getKey(constants.thermostatAcLouverPositions, value, undefined, Number);
1728
+ if (acLouverPosition === undefined) {
1729
+ acLouverPosition = utils.getKey(constants.thermostatAcLouverPositions, value, value, Number);
1730
+ }
1731
+ await entity.write('hvacThermostat', { acLouverPosition });
1732
+ return { state: { ac_louver_position: value } };
1733
+ },
1734
+ convertGet: async (entity, key, meta) => {
1735
+ await entity.read('hvacThermostat', ['acLouverPosition']);
1736
+ },
1737
+ },
1738
+ electrical_measurement_power: {
1739
+ key: ['power'],
1740
+ convertGet: async (entity, key, meta) => {
1741
+ await entity.read('haElectricalMeasurement', ['activePower']);
1742
+ },
1743
+ },
1744
+ electrical_measurement_power_phase_b: {
1745
+ key: ['power_phase_b'],
1746
+ convertGet: async (entity, key, meta) => {
1747
+ await entity.read('haElectricalMeasurement', ['activePowerPhB']);
1748
+ },
1749
+ },
1750
+ electrical_measurement_power_phase_c: {
1751
+ key: ['power_phase_c'],
1752
+ convertGet: async (entity, key, meta) => {
1753
+ await entity.read('haElectricalMeasurement', ['activePowerPhC']);
1754
+ },
1755
+ },
1756
+ metering_power: {
1757
+ key: ['power'],
1758
+ convertGet: async (entity, key, meta) => {
1759
+ utils.assertEndpoint(entity);
1760
+ await utils.enforceEndpoint(entity, key, meta).read('seMetering', ['instantaneousDemand']);
1761
+ },
1762
+ },
1763
+ currentsummdelivered: {
1764
+ key: ['energy'],
1765
+ convertGet: async (entity, key, meta) => {
1766
+ utils.assertEndpoint(entity);
1767
+ await utils.enforceEndpoint(entity, key, meta).read('seMetering', ['currentSummDelivered']);
1768
+ },
1769
+ },
1770
+ currentsummreceived: {
1771
+ key: ['produced_energy'],
1772
+ convertGet: async (entity, key, meta) => {
1773
+ utils.assertEndpoint(entity);
1774
+ await utils.enforceEndpoint(entity, key, meta).read('seMetering', ['currentSummReceived']);
1775
+ },
1776
+ },
1777
+ frequency: {
1778
+ key: ['ac_frequency'],
1779
+ convertGet: async (entity, key, meta) => {
1780
+ await entity.read('haElectricalMeasurement', ['acFrequency']);
1781
+ },
1782
+ },
1783
+ electrical_measurement_power_reactive: {
1784
+ key: ['power_reactive'],
1785
+ convertGet: async (entity, key, meta) => {
1786
+ await entity.read('haElectricalMeasurement', ['reactivePower']);
1787
+ },
1788
+ },
1789
+ powerfactor: {
1790
+ key: ['power_factor'],
1791
+ convertGet: async (entity, key, meta) => {
1792
+ await entity.read('haElectricalMeasurement', ['powerFactor']);
1793
+ },
1794
+ },
1795
+ acvoltage: {
1796
+ key: ['voltage'],
1797
+ convertGet: async (entity, key, meta) => {
1798
+ await entity.read('haElectricalMeasurement', ['rmsVoltage']);
1799
+ },
1800
+ },
1801
+ acvoltage_phase_b: {
1802
+ key: ['voltage_phase_b'],
1803
+ convertGet: async (entity, key, meta) => {
1804
+ await entity.read('haElectricalMeasurement', ['rmsVoltagePhB']);
1805
+ },
1806
+ },
1807
+ acvoltage_phase_c: {
1808
+ key: ['voltage_phase_c'],
1809
+ convertGet: async (entity, key, meta) => {
1810
+ await entity.read('haElectricalMeasurement', ['rmsVoltagePhC']);
1811
+ },
1812
+ },
1813
+ accurrent: {
1814
+ key: ['current'],
1815
+ convertGet: async (entity, key, meta) => {
1816
+ await entity.read('haElectricalMeasurement', ['rmsCurrent']);
1817
+ },
1818
+ },
1819
+ accurrent_phase_b: {
1820
+ key: ['current_phase_b'],
1821
+ convertGet: async (entity, key, meta) => {
1822
+ await entity.read('haElectricalMeasurement', ['rmsCurrentPhB']);
1823
+ },
1824
+ },
1825
+ accurrent_phase_c: {
1826
+ key: ['current_phase_c'],
1827
+ convertGet: async (entity, key, meta) => {
1828
+ await entity.read('haElectricalMeasurement', ['rmsCurrentPhC']);
1829
+ },
1830
+ },
1831
+ temperature: {
1832
+ key: ['temperature'],
1833
+ convertGet: async (entity, key, meta) => {
1834
+ await entity.read('msTemperatureMeasurement', ['measuredValue']);
1835
+ },
1836
+ },
1837
+ humidity: {
1838
+ key: ['humidity'],
1839
+ convertGet: async (entity, key, meta) => {
1840
+ await entity.read('msRelativeHumidity', ['measuredValue']);
1841
+ },
1842
+ },
1843
+ illuminance: {
1844
+ key: ['illuminance'],
1845
+ convertGet: async (entity, key, meta) => {
1846
+ await entity.read('msIlluminanceMeasurement', ['measuredValue']);
1847
+ },
1848
+ },
1849
+ // #endregion
1850
+ // #region Non-generic converters
1851
+ elko_power_status: {
1852
+ key: ['system_mode'],
1853
+ convertSet: async (entity, key, value, meta) => {
1854
+ await entity.write('hvacThermostat', { elkoPowerStatus: value === 'heat' });
1855
+ return { state: { system_mode: value } };
1856
+ },
1857
+ convertGet: async (entity, key, meta) => {
1858
+ await entity.read('hvacThermostat', ['elkoPowerStatus']);
1859
+ },
1860
+ },
1861
+ elko_relay_state: {
1862
+ key: ['running_state'],
1863
+ convertGet: async (entity, key, meta) => {
1864
+ await entity.read('hvacThermostat', ['elkoRelayState']);
1865
+ },
1866
+ },
1867
+ elko_local_temperature_calibration: {
1868
+ key: ['local_temperature_calibration'],
1869
+ convertSet: async (entity, key, value, meta) => {
1870
+ utils.assertNumber(value, key);
1871
+ await entity.write('hvacThermostat', { elkoCalibration: Math.round(value * 10) });
1872
+ return { state: { local_temperature_calibration: value } };
1873
+ },
1874
+ convertGet: async (entity, key, meta) => {
1875
+ await entity.read('hvacThermostat', ['elkoCalibration']);
1876
+ },
1877
+ },
1878
+ livolo_socket_switch_on_off: {
1879
+ key: ['state'],
1880
+ convertSet: async (entity, key, value, meta) => {
1881
+ if (typeof value !== 'string') {
1882
+ return;
1883
+ }
1884
+ const state = value.toLowerCase();
1885
+ let oldstate = 1;
1886
+ if (state === 'on') {
1887
+ oldstate = 108;
1888
+ }
1889
+ let channel = 1.0;
1890
+ const postfix = meta.endpoint_name || 'left';
1891
+ await entity.command('genOnOff', 'toggle', {}, { transactionSequenceNumber: 0 });
1892
+ const payloadOn = { 0x0001: { value: Buffer.from([1, 0, 0, 0, 0, 0, 0, 0]), type: 1 } };
1893
+ const payloadOff = { 0x0001: { value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 1 } };
1894
+ const payloadOnRight = { 0x0001: { value: Buffer.from([2, 0, 0, 0, 0, 0, 0, 0]), type: 2 } };
1895
+ const payloadOffRight = { 0x0001: { value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 2 } };
1896
+ const payloadOnBottomLeft = { 0x0001: { value: Buffer.from([4, 0, 0, 0, 0, 0, 0, 0]), type: 4 } };
1897
+ const payloadOffBottomLeft = { 0x0001: { value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 4 } };
1898
+ const payloadOnBottomRight = { 0x0001: { value: Buffer.from([8, 0, 0, 0, 0, 0, 0, 0]), type: 136 } };
1899
+ const payloadOffBottomRight = { 0x0001: { value: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), type: 136 } };
1900
+ if (postfix === 'left') {
1901
+ await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', { level: oldstate, transtime: channel });
1902
+ await entity.write('genPowerCfg', state === 'on' ? payloadOn : payloadOff, {
1903
+ manufacturerCode: 0x1ad2,
1904
+ disableDefaultResponse: true,
1905
+ disableResponse: true,
1906
+ reservedBits: 3,
1907
+ direction: 1,
1908
+ transactionSequenceNumber: 0xe9,
1909
+ });
1910
+ return { state: { state: value.toUpperCase() } };
1911
+ }
1912
+ else if (postfix === 'right') {
1913
+ channel = 2.0;
1914
+ await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', { level: oldstate, transtime: channel });
1915
+ await entity.write('genPowerCfg', state === 'on' ? payloadOnRight : payloadOffRight, {
1916
+ manufacturerCode: 0x1ad2,
1917
+ disableDefaultResponse: true,
1918
+ disableResponse: true,
1919
+ reservedBits: 3,
1920
+ direction: 1,
1921
+ transactionSequenceNumber: 0xe9,
1922
+ });
1923
+ return { state: { state: value.toUpperCase() } };
1924
+ }
1925
+ else if (postfix === 'bottom_right') {
1926
+ await entity.write('genPowerCfg', state === 'on' ? payloadOnBottomRight : payloadOffBottomRight, {
1927
+ manufacturerCode: 0x1ad2,
1928
+ disableDefaultResponse: true,
1929
+ disableResponse: true,
1930
+ reservedBits: 3,
1931
+ direction: 1,
1932
+ transactionSequenceNumber: 0xe9,
1933
+ });
1934
+ return { state: { state: value.toUpperCase() } };
1935
+ }
1936
+ else if (postfix === 'bottom_left') {
1937
+ await entity.write('genPowerCfg', state === 'on' ? payloadOnBottomLeft : payloadOffBottomLeft, {
1938
+ manufacturerCode: 0x1ad2,
1939
+ disableDefaultResponse: true,
1940
+ disableResponse: true,
1941
+ reservedBits: 3,
1942
+ direction: 1,
1943
+ transactionSequenceNumber: 0xe9,
1944
+ });
1945
+ return { state: { state: value.toUpperCase() } };
1946
+ }
1947
+ return { state: { state: value.toUpperCase() } };
1948
+ },
1949
+ convertGet: async (entity, key, meta) => {
1950
+ await entity.command('genOnOff', 'toggle', {}, { transactionSequenceNumber: 0 });
1951
+ },
1952
+ },
1953
+ livolo_switch_on_off: {
1954
+ key: ['state'],
1955
+ convertSet: async (entity, key, value, meta) => {
1956
+ utils.assertString(value, key);
1957
+ const postfix = meta.endpoint_name || 'left';
1958
+ const state = value.toLowerCase() === 'on' ? 108 : 1;
1959
+ let channel = 1;
1960
+ if (postfix === 'left') {
1961
+ channel = 1.0;
1962
+ }
1963
+ else if (postfix === 'right') {
1964
+ channel = 2.0;
1965
+ }
1966
+ else {
1967
+ return;
1968
+ }
1969
+ await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', { level: state, transtime: channel });
1970
+ return { state: { state: value.toUpperCase() } };
1971
+ },
1972
+ convertGet: async (entity, key, meta) => {
1973
+ await entity.command('genOnOff', 'toggle', {}, { transactionSequenceNumber: 0 });
1974
+ },
1975
+ },
1976
+ livolo_dimmer_level: {
1977
+ key: ['brightness', 'brightness_percent', 'level'],
1978
+ convertSet: async (entity, key, value, meta) => {
1979
+ // upscale to 100
1980
+ value = Number(value);
1981
+ utils.assertNumber(value, key);
1982
+ let newValue;
1983
+ if (key === 'level') {
1984
+ if (value >= 0 && value <= 1000) {
1985
+ newValue = utils.mapNumberRange(value, 0, 1000, 0, 100);
1986
+ }
1987
+ else {
1988
+ throw new Error('Dimmer level is out of range 0..1000');
1989
+ }
1990
+ }
1991
+ else if (key === 'brightness_percent') {
1992
+ if (value >= 0 && value <= 100) {
1993
+ newValue = Math.round(value);
1994
+ }
1995
+ else {
1996
+ throw new Error('Dimmer brightness_percent is out of range 0..100');
1997
+ }
1998
+ }
1999
+ else {
2000
+ if (value >= 0 && value <= 255) {
2001
+ newValue = utils.mapNumberRange(value, 0, 255, 0, 100);
2002
+ }
2003
+ else {
2004
+ throw new Error('Dimmer brightness is out of range 0..255');
2005
+ }
2006
+ }
2007
+ await entity.command('genOnOff', 'toggle', {}, { transactionSequenceNumber: 0 });
2008
+ const payload = { 0x0301: { value: Buffer.from([newValue, 0, 0, 0, 0, 0, 0, 0]), type: 1 } };
2009
+ await entity.write('genPowerCfg', payload, {
2010
+ manufacturerCode: 0x1ad2,
2011
+ disableDefaultResponse: true,
2012
+ disableResponse: true,
2013
+ reservedBits: 3,
2014
+ direction: 1,
2015
+ transactionSequenceNumber: 0xe9,
2016
+ writeUndiv: true,
2017
+ });
2018
+ return {
2019
+ state: { brightness_percent: newValue, brightness: utils.mapNumberRange(newValue, 0, 100, 0, 255), level: newValue * 10 },
2020
+ };
2021
+ },
2022
+ convertGet: async (entity, key, meta) => {
2023
+ await entity.command('genOnOff', 'toggle', {}, { transactionSequenceNumber: 0 });
2024
+ },
2025
+ },
2026
+ livolo_cover_state: {
2027
+ key: ['state'],
2028
+ convertSet: async (entity, key, value, meta) => {
2029
+ utils.assertEndpoint(entity);
2030
+ let payload;
2031
+ const options = {
2032
+ frameType: 0,
2033
+ manufacturerCode: 0x1ad2,
2034
+ disableDefaultResponse: true,
2035
+ disableResponse: true,
2036
+ reservedBits: 3,
2037
+ direction: 1,
2038
+ writeUndiv: true,
2039
+ transactionSequenceNumber: 0xe9,
2040
+ };
2041
+ switch (value) {
2042
+ case 'OPEN':
2043
+ payload = { attrId: 0x0000, selector: null, elementData: [0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] };
2044
+ break;
2045
+ case 'CLOSE':
2046
+ payload = { attrId: 0x0000, selector: null, elementData: [0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] };
2047
+ break;
2048
+ case 'STOP':
2049
+ payload = { attrId: 0x0000, selector: null, elementData: [0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] };
2050
+ break;
2051
+ default:
2052
+ throw new Error(`Value '${value}' is not a valid cover position (must be one of 'OPEN' or 'CLOSE')`);
2053
+ }
2054
+ await entity.writeStructured('genPowerCfg', [payload], options);
2055
+ return {
2056
+ state: {
2057
+ moving: true,
2058
+ },
2059
+ };
2060
+ },
2061
+ },
2062
+ livolo_cover_position: {
2063
+ key: ['position'],
2064
+ convertSet: async (entity, key, value, meta) => {
2065
+ utils.assertNumber(value, key);
2066
+ const position = 100 - value;
2067
+ await entity.command('genOnOff', 'toggle', {}, { transactionSequenceNumber: 0 });
2068
+ const payload = { 0x0401: { value: [position, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], type: 1 } };
2069
+ await entity.write('genPowerCfg', payload, {
2070
+ manufacturerCode: 0x1ad2,
2071
+ disableDefaultResponse: true,
2072
+ disableResponse: true,
2073
+ reservedBits: 3,
2074
+ direction: 1,
2075
+ transactionSequenceNumber: 0xe9,
2076
+ writeUndiv: true,
2077
+ });
2078
+ return {
2079
+ state: {
2080
+ position: value,
2081
+ moving: true,
2082
+ },
2083
+ };
2084
+ },
2085
+ },
2086
+ livolo_cover_options: {
2087
+ key: ['options'],
2088
+ convertSet: async (entity, key, value, meta) => {
2089
+ utils.assertObject(value);
2090
+ const options = {
2091
+ frameType: 0,
2092
+ manufacturerCode: 0x1ad2,
2093
+ disableDefaultResponse: true,
2094
+ disableResponse: true,
2095
+ reservedBits: 3,
2096
+ direction: 1,
2097
+ writeUndiv: true,
2098
+ transactionSequenceNumber: 0xe9,
2099
+ };
2100
+ if (value.motor_direction !== undefined) {
2101
+ let direction;
2102
+ switch (value.motor_direction) {
2103
+ case 'FORWARD':
2104
+ direction = 0x00;
2105
+ break;
2106
+ case 'REVERSE':
2107
+ direction = 0x80;
2108
+ break;
2109
+ default:
2110
+ throw new Error(`livolo_cover_options: ${value.motor_direction} is not a valid motor direction \
2111
+ (must be one of 'FORWARD' or 'REVERSE')`);
2112
+ }
2113
+ const payload = { 0x1301: { value: [direction, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] } };
2114
+ await entity.write('genPowerCfg', payload, options);
2115
+ }
2116
+ if (value.motor_speed !== undefined) {
2117
+ if (value.motor_speed < 20 || value.motor_speed > 40) {
2118
+ throw new Error('livolo_cover_options: Motor speed is out of range (20-40)');
2119
+ }
2120
+ const payload = { 0x1201: { value: [value.motor_speed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] } };
2121
+ await entity.write('genPowerCfg', payload, options);
2122
+ }
2123
+ },
2124
+ },
2125
+ ZigUP_lock: {
2126
+ key: ['led'],
2127
+ convertSet: async (entity, key, value, meta) => {
2128
+ const lookup = { off: 'lockDoor', on: 'unlockDoor', toggle: 'toggleDoor' };
2129
+ await entity.command('closuresDoorLock', utils.getFromLookup(value, lookup), { pincodevalue: '' });
2130
+ },
2131
+ },
2132
+ LS21001_alert_behaviour: {
2133
+ key: ['alert_behaviour'],
2134
+ convertSet: async (entity, key, value, meta) => {
2135
+ const lookup = { siren_led: 3, siren: 2, led: 1, nothing: 0 };
2136
+ await entity.write('genBasic', { 0x400a: { value: utils.getFromLookup(value, lookup), type: 32 } }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.LEEDARSON_LIGHTING_CO_LTD, disableDefaultResponse: true });
2137
+ return { state: { alert_behaviour: value } };
2138
+ },
2139
+ },
2140
+ STS_PRS_251_beep: {
2141
+ key: ['beep'],
2142
+ convertSet: async (entity, key, value, meta) => {
2143
+ await entity.command('genIdentify', 'identify', { identifytime: value }, utils.getOptions(meta.mapped, entity));
2144
+ },
2145
+ },
2146
+ SPZ01_power_outage_memory: {
2147
+ key: ['power_outage_memory'],
2148
+ convertSet: async (entity, key, value, meta) => {
2149
+ await entity.write('genOnOff', { 0x2000: { value: value ? 0x01 : 0x00, type: 0x20 } });
2150
+ return { state: { power_outage_memory: value } };
2151
+ },
2152
+ },
2153
+ tuya_relay_din_led_indicator: {
2154
+ key: ['indicator_mode'],
2155
+ convertSet: async (entity, key, value, meta) => {
2156
+ utils.assertString(value, key);
2157
+ value = value.toLowerCase();
2158
+ const lookup = { off: 0x00, on_off: 0x01, off_on: 0x02 };
2159
+ const payload = utils.getFromLookup(value, lookup);
2160
+ await entity.write('genOnOff', { 0x8001: { value: payload, type: 0x30 } });
2161
+ return { state: { indicator_mode: value } };
2162
+ },
2163
+ },
2164
+ kmpcil_res005_on_off: {
2165
+ key: ['state'],
2166
+ convertSet: async (entity, key, value, meta) => {
2167
+ utils.assertString(value, key);
2168
+ const options = { disableDefaultResponse: true };
2169
+ value = value.toLowerCase();
2170
+ utils.assertString(value, key);
2171
+ utils.validateValue(value, ['toggle', 'off', 'on']);
2172
+ if (value === 'toggle') {
2173
+ if (meta.state.state === undefined) {
2174
+ throw new Error('Cannot toggle, state not known yet');
2175
+ }
2176
+ else {
2177
+ const payload = { 0x0055: { value: meta.state.state === 'OFF' ? 0x01 : 0x00, type: 0x10 } };
2178
+ await entity.write('genBinaryOutput', payload, options);
2179
+ return { state: { state: meta.state.state === 'OFF' ? 'ON' : 'OFF' } };
2180
+ }
2181
+ }
2182
+ else {
2183
+ const payload = { 0x0055: { value: value.toUpperCase() === 'OFF' ? 0x00 : 0x01, type: 0x10 } };
2184
+ await entity.write('genBinaryOutput', payload, options);
2185
+ return { state: { state: value.toUpperCase() } };
2186
+ }
2187
+ },
2188
+ convertGet: async (entity, key, meta) => {
2189
+ await entity.read('genBinaryOutput', ['presentValue']);
2190
+ },
2191
+ },
2192
+ hue_wall_switch_device_mode: {
2193
+ key: ['device_mode'],
2194
+ convertSet: async (entity, key, value, meta) => {
2195
+ utils.assertString(value);
2196
+ const values = ['single_rocker', 'single_push_button', 'dual_rocker', 'dual_push_button'];
2197
+ utils.validateValue(value, values);
2198
+ await entity.write('genBasic', { 0x0034: { value: values.indexOf(value), type: 48 } }, manufacturerOptions.hue);
2199
+ },
2200
+ convertGet: async (entity, key, meta) => {
2201
+ await entity.read('genBasic', [0x0034], manufacturerOptions.hue);
2202
+ },
2203
+ },
2204
+ danfoss_thermostat_occupied_heating_setpoint: {
2205
+ key: ['occupied_heating_setpoint'],
2206
+ convertSet: async (entity, key, value, meta) => {
2207
+ utils.assertNumber(value, key);
2208
+ const payload = {
2209
+ // 1: "User Interaction" Changes occupied heating setpoint and triggers an aggressive reaction
2210
+ // of the actuator as soon as control SW runs, to replicate the behavior of turning the dial on the eTRV.
2211
+ setpointType: 1,
2212
+ setpoint: Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100,
2213
+ };
2214
+ await entity.command('hvacThermostat', 'danfossSetpointCommand', payload, manufacturerOptions.danfoss);
2215
+ },
2216
+ convertGet: async (entity, key, meta) => {
2217
+ await entity.read('hvacThermostat', ['occupiedHeatingSetpoint']);
2218
+ },
2219
+ },
2220
+ danfoss_thermostat_occupied_heating_setpoint_scheduled: {
2221
+ key: ['occupied_heating_setpoint_scheduled'],
2222
+ convertSet: async (entity, key, value, meta) => {
2223
+ utils.assertNumber(value, key);
2224
+ const payload = {
2225
+ // 0: "Schedule Change" Just changes occupied heating setpoint. No special behavior,
2226
+ // the PID control setpoint will be update with the new setpoint.
2227
+ setpointType: 0,
2228
+ setpoint: Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100,
2229
+ };
2230
+ await entity.command('hvacThermostat', 'danfossSetpointCommand', payload, manufacturerOptions.danfoss);
2231
+ },
2232
+ convertGet: async (entity, key, meta) => {
2233
+ await entity.read('hvacThermostat', ['occupiedHeatingSetpoint']);
2234
+ },
2235
+ },
2236
+ danfoss_mounted_mode_active: {
2237
+ key: ['mounted_mode_active'],
2238
+ convertGet: async (entity, key, meta) => {
2239
+ await entity.read('hvacThermostat', ['danfossMountedModeActive'], manufacturerOptions.danfoss);
2240
+ },
2241
+ },
2242
+ danfoss_mounted_mode_control: {
2243
+ key: ['mounted_mode_control'],
2244
+ convertSet: async (entity, key, value, meta) => {
2245
+ await entity.write('hvacThermostat', { danfossMountedModeControl: value }, manufacturerOptions.danfoss);
2246
+ return { state: { mounted_mode_control: value } };
2247
+ },
2248
+ convertGet: async (entity, key, meta) => {
2249
+ await entity.read('hvacThermostat', ['danfossMountedModeControl'], manufacturerOptions.danfoss);
2250
+ },
2251
+ },
2252
+ danfoss_thermostat_vertical_orientation: {
2253
+ key: ['thermostat_vertical_orientation'],
2254
+ convertSet: async (entity, key, value, meta) => {
2255
+ await entity.write('hvacThermostat', { danfossThermostatOrientation: value }, manufacturerOptions.danfoss);
2256
+ return { state: { thermostat_vertical_orientation: value } };
2257
+ },
2258
+ convertGet: async (entity, key, meta) => {
2259
+ await entity.read('hvacThermostat', ['danfossThermostatOrientation'], manufacturerOptions.danfoss);
2260
+ },
2261
+ },
2262
+ danfoss_external_measured_room_sensor: {
2263
+ key: ['external_measured_room_sensor'],
2264
+ convertSet: async (entity, key, value, meta) => {
2265
+ await entity.write('hvacThermostat', { danfossExternalMeasuredRoomSensor: value }, manufacturerOptions.danfoss);
2266
+ return { state: { external_measured_room_sensor: value } };
2267
+ },
2268
+ convertGet: async (entity, key, meta) => {
2269
+ await entity.read('hvacThermostat', ['danfossExternalMeasuredRoomSensor'], manufacturerOptions.danfoss);
2270
+ },
2271
+ },
2272
+ danfoss_radiator_covered: {
2273
+ key: ['radiator_covered'],
2274
+ convertSet: async (entity, key, value, meta) => {
2275
+ await entity.write('hvacThermostat', { danfossRadiatorCovered: value }, manufacturerOptions.danfoss);
2276
+ return { state: { radiator_covered: value } };
2277
+ },
2278
+ convertGet: async (entity, key, meta) => {
2279
+ await entity.read('hvacThermostat', ['danfossRadiatorCovered'], manufacturerOptions.danfoss);
2280
+ },
2281
+ },
2282
+ danfoss_viewing_direction: {
2283
+ key: ['viewing_direction'],
2284
+ convertSet: async (entity, key, value, meta) => {
2285
+ await entity.write('hvacUserInterfaceCfg', { danfossViewingDirection: value }, manufacturerOptions.danfoss);
2286
+ return { state: { viewing_direction: value } };
2287
+ },
2288
+ convertGet: async (entity, key, meta) => {
2289
+ await entity.read('hvacUserInterfaceCfg', ['danfossViewingDirection'], manufacturerOptions.danfoss);
2290
+ },
2291
+ },
2292
+ danfoss_algorithm_scale_factor: {
2293
+ key: ['algorithm_scale_factor'],
2294
+ convertSet: async (entity, key, value, meta) => {
2295
+ await entity.write('hvacThermostat', { danfossAlgorithmScaleFactor: value }, manufacturerOptions.danfoss);
2296
+ return { state: { algorithm_scale_factor: value } };
2297
+ },
2298
+ convertGet: async (entity, key, meta) => {
2299
+ await entity.read('hvacThermostat', ['danfossAlgorithmScaleFactor'], manufacturerOptions.danfoss);
2300
+ },
2301
+ },
2302
+ danfoss_heat_available: {
2303
+ key: ['heat_available'],
2304
+ convertSet: async (entity, key, value, meta) => {
2305
+ await entity.write('hvacThermostat', { danfossHeatAvailable: value }, manufacturerOptions.danfoss);
2306
+ return { state: { heat_available: value } };
2307
+ },
2308
+ convertGet: async (entity, key, meta) => {
2309
+ await entity.read('hvacThermostat', ['danfossHeatAvailable'], manufacturerOptions.danfoss);
2310
+ },
2311
+ },
2312
+ danfoss_heat_required: {
2313
+ key: ['heat_required'],
2314
+ convertGet: async (entity, key, meta) => {
2315
+ await entity.read('hvacThermostat', ['danfossHeatRequired'], manufacturerOptions.danfoss);
2316
+ },
2317
+ },
2318
+ danfoss_day_of_week: {
2319
+ key: ['day_of_week'],
2320
+ convertSet: async (entity, key, value, meta) => {
2321
+ const payload = { danfossDayOfWeek: utils.getKey(constants.thermostatDayOfWeek, value, undefined, Number) };
2322
+ await entity.write('hvacThermostat', payload, manufacturerOptions.danfoss);
2323
+ return { state: { day_of_week: value } };
2324
+ },
2325
+ convertGet: async (entity, key, meta) => {
2326
+ await entity.read('hvacThermostat', ['danfossDayOfWeek'], manufacturerOptions.danfoss);
2327
+ },
2328
+ },
2329
+ danfoss_trigger_time: {
2330
+ key: ['trigger_time'],
2331
+ convertSet: async (entity, key, value, meta) => {
2332
+ await entity.write('hvacThermostat', { danfossTriggerTime: value }, manufacturerOptions.danfoss);
2333
+ return { state: { trigger_time: value } };
2334
+ },
2335
+ convertGet: async (entity, key, meta) => {
2336
+ await entity.read('hvacThermostat', ['danfossTriggerTime'], manufacturerOptions.danfoss);
2337
+ },
2338
+ },
2339
+ danfoss_window_open_feature: {
2340
+ key: ['window_open_feature'],
2341
+ convertSet: async (entity, key, value, meta) => {
2342
+ await entity.write('hvacThermostat', { danfossWindowOpenFeatureEnable: value }, manufacturerOptions.danfoss);
2343
+ return { state: { window_open_feature: value } };
2344
+ },
2345
+ convertGet: async (entity, key, meta) => {
2346
+ await entity.read('hvacThermostat', ['danfossWindowOpenFeatureEnable'], manufacturerOptions.danfoss);
2347
+ },
2348
+ },
2349
+ danfoss_window_open_internal: {
2350
+ key: ['window_open_internal'],
2351
+ convertGet: async (entity, key, meta) => {
2352
+ await entity.read('hvacThermostat', ['danfossWindowOpenInternal'], manufacturerOptions.danfoss);
2353
+ },
2354
+ },
2355
+ danfoss_window_open_external: {
2356
+ key: ['window_open_external'],
2357
+ convertSet: async (entity, key, value, meta) => {
2358
+ await entity.write('hvacThermostat', { danfossWindowOpenExternal: value }, manufacturerOptions.danfoss);
2359
+ return { state: { window_open_external: value } };
2360
+ },
2361
+ convertGet: async (entity, key, meta) => {
2362
+ await entity.read('hvacThermostat', ['danfossWindowOpenExternal'], manufacturerOptions.danfoss);
2363
+ },
2364
+ },
2365
+ danfoss_load_balancing_enable: {
2366
+ key: ['load_balancing_enable'],
2367
+ convertSet: async (entity, key, value, meta) => {
2368
+ await entity.write('hvacThermostat', { danfossLoadBalancingEnable: value }, manufacturerOptions.danfoss);
2369
+ return { state: { load_balancing_enable: value } };
2370
+ },
2371
+ convertGet: async (entity, key, meta) => {
2372
+ await entity.read('hvacThermostat', ['danfossLoadBalancingEnable'], manufacturerOptions.danfoss);
2373
+ },
2374
+ },
2375
+ danfoss_load_room_mean: {
2376
+ key: ['load_room_mean'],
2377
+ convertSet: async (entity, key, value, meta) => {
2378
+ await entity.write('hvacThermostat', { danfossLoadRoomMean: value }, manufacturerOptions.danfoss);
2379
+ return { state: { load_room_mean: value } };
2380
+ },
2381
+ convertGet: async (entity, key, meta) => {
2382
+ await entity.read('hvacThermostat', ['danfossLoadRoomMean'], manufacturerOptions.danfoss);
2383
+ },
2384
+ },
2385
+ danfoss_load_estimate: {
2386
+ key: ['load_estimate'],
2387
+ convertGet: async (entity, key, meta) => {
2388
+ await entity.read('hvacThermostat', ['danfossLoadEstimate'], manufacturerOptions.danfoss);
2389
+ },
2390
+ },
2391
+ danfoss_preheat_status: {
2392
+ key: ['preheat_status'],
2393
+ convertGet: async (entity, key, meta) => {
2394
+ await entity.read('hvacThermostat', ['danfossPreheatStatus'], manufacturerOptions.danfoss);
2395
+ },
2396
+ },
2397
+ danfoss_adaptation_status: {
2398
+ key: ['adaptation_run_status'],
2399
+ convertGet: async (entity, key, meta) => {
2400
+ await entity.read('hvacThermostat', ['danfossAdaptionRunStatus'], manufacturerOptions.danfoss);
2401
+ },
2402
+ },
2403
+ danfoss_adaptation_settings: {
2404
+ key: ['adaptation_run_settings'],
2405
+ convertSet: async (entity, key, value, meta) => {
2406
+ await entity.write('hvacThermostat', { danfossAdaptionRunSettings: value }, manufacturerOptions.danfoss);
2407
+ return { state: { adaptation_run_settings: value } };
2408
+ },
2409
+ convertGet: async (entity, key, meta) => {
2410
+ await entity.read('hvacThermostat', ['danfossAdaptionRunSettings'], manufacturerOptions.danfoss);
2411
+ },
2412
+ },
2413
+ danfoss_adaptation_control: {
2414
+ key: ['adaptation_run_control'],
2415
+ convertSet: async (entity, key, value, meta) => {
2416
+ const payload = { danfossAdaptionRunControl: utils.getKey(constants.danfossAdaptionRunControl, value, value, Number) };
2417
+ await entity.write('hvacThermostat', payload, manufacturerOptions.danfoss);
2418
+ return { state: { adaptation_run_control: value } };
2419
+ },
2420
+ convertGet: async (entity, key, meta) => {
2421
+ await entity.read('hvacThermostat', ['danfossAdaptionRunControl'], manufacturerOptions.danfoss);
2422
+ },
2423
+ },
2424
+ danfoss_regulation_setpoint_offset: {
2425
+ key: ['regulation_setpoint_offset'],
2426
+ convertSet: async (entity, key, value, meta) => {
2427
+ const payload = { danfossRegulationSetpointOffset: value };
2428
+ await entity.write('hvacThermostat', payload, manufacturerOptions.danfoss);
2429
+ return { state: { regulation_setpoint_offset: value } };
2430
+ },
2431
+ convertGet: async (entity, key, meta) => {
2432
+ await entity.read('hvacThermostat', ['danfossRegulationSetpointOffset'], manufacturerOptions.danfoss);
2433
+ },
2434
+ },
2435
+ danfoss_output_status: {
2436
+ key: ['output_status'],
2437
+ convertGet: async (entity, key, meta) => {
2438
+ await entity.read('hvacThermostat', ['danfossOutputStatus'], manufacturerOptions.danfoss);
2439
+ },
2440
+ },
2441
+ danfoss_room_status_code: {
2442
+ key: ['room_status_code'],
2443
+ convertGet: async (entity, key, meta) => {
2444
+ await entity.read('hvacThermostat', ['danfossRoomStatusCode'], manufacturerOptions.danfoss);
2445
+ },
2446
+ },
2447
+ danfoss_floor_sensor_mode: {
2448
+ key: ['room_floor_sensor_mode'],
2449
+ convertGet: async (entity, key, meta) => {
2450
+ await entity.read('hvacThermostat', ['danfossRoomFloorSensorMode'], manufacturerOptions.danfoss);
2451
+ },
2452
+ },
2453
+ danfoss_floor_min_setpoint: {
2454
+ key: ['floor_min_setpoint'],
2455
+ convertSet: async (entity, key, value, meta) => {
2456
+ utils.assertNumber(value, key);
2457
+ const danfossFloorMinSetpoint = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
2458
+ await entity.write('hvacThermostat', { danfossFloorMinSetpoint }, manufacturerOptions.danfoss);
2459
+ return { state: { floor_min_setpoint: value } };
2460
+ },
2461
+ convertGet: async (entity, key, meta) => {
2462
+ await entity.read('hvacThermostat', ['danfossFloorMinSetpoint'], manufacturerOptions.danfoss);
2463
+ },
2464
+ },
2465
+ danfoss_floor_max_setpoint: {
2466
+ key: ['floor_max_setpoint'],
2467
+ convertSet: async (entity, key, value, meta) => {
2468
+ utils.assertNumber(value, key);
2469
+ const danfossFloorMaxSetpoint = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
2470
+ await entity.write('hvacThermostat', { danfossFloorMaxSetpoint }, manufacturerOptions.danfoss);
2471
+ return { state: { floor_max_setpoint: value } };
2472
+ },
2473
+ convertGet: async (entity, key, meta) => {
2474
+ await entity.read('hvacThermostat', ['danfossFloorMaxSetpoint'], manufacturerOptions.danfoss);
2475
+ },
2476
+ },
2477
+ danfoss_system_status_code: {
2478
+ key: ['system_status_code'],
2479
+ convertGet: async (entity, key, meta) => {
2480
+ await entity.read('haDiagnostic', ['danfossSystemStatusCode'], manufacturerOptions.danfoss);
2481
+ },
2482
+ },
2483
+ danfoss_system_status_water: {
2484
+ key: ['system_status_water'],
2485
+ convertGet: async (entity, key, meta) => {
2486
+ await entity.read('haDiagnostic', ['danfossSystemStatusWater'], manufacturerOptions.danfoss);
2487
+ },
2488
+ },
2489
+ danfoss_multimaster_role: {
2490
+ key: ['multimaster_role'],
2491
+ convertGet: async (entity, key, meta) => {
2492
+ await entity.read('haDiagnostic', ['danfossMultimasterRole'], manufacturerOptions.danfoss);
2493
+ },
2494
+ },
2495
+ ZMCSW032D_cover_position: {
2496
+ key: ['position', 'tilt'],
2497
+ convertSet: async (entity, key, value, meta) => {
2498
+ utils.assertNumber(value, key);
2499
+ if (meta.options.time_close !== undefined && meta.options.time_open !== undefined) {
2500
+ const sleepSeconds = async (s) => {
2501
+ return await new Promise((resolve) => setTimeout(resolve, s * 1000));
2502
+ };
2503
+ const oldPosition = meta.state.position;
2504
+ if (value == 100) {
2505
+ await entity.command('closuresWindowCovering', 'upOpen', {}, utils.getOptions(meta.mapped, entity));
2506
+ }
2507
+ else if (value == 0) {
2508
+ await entity.command('closuresWindowCovering', 'downClose', {}, utils.getOptions(meta.mapped, entity));
2509
+ }
2510
+ else {
2511
+ if (utils.isNumber(oldPosition) && oldPosition > value) {
2512
+ const delta = oldPosition - value;
2513
+ utils.assertNumber(meta.options.time_open);
2514
+ const mutiplicateur = meta.options.time_open / 100;
2515
+ const timeBeforeStop = delta * mutiplicateur;
2516
+ await entity.command('closuresWindowCovering', 'downClose', {}, utils.getOptions(meta.mapped, entity));
2517
+ await sleepSeconds(timeBeforeStop);
2518
+ await entity.command('closuresWindowCovering', 'stop', {}, utils.getOptions(meta.mapped, entity));
2519
+ }
2520
+ else if (utils.isNumber(oldPosition) && oldPosition < value) {
2521
+ const delta = value - oldPosition;
2522
+ utils.assertNumber(meta.options.time_close);
2523
+ const mutiplicateur = meta.options.time_close / 100;
2524
+ const timeBeforeStop = delta * mutiplicateur;
2525
+ await entity.command('closuresWindowCovering', 'upOpen', {}, utils.getOptions(meta.mapped, entity));
2526
+ await sleepSeconds(timeBeforeStop);
2527
+ await entity.command('closuresWindowCovering', 'stop', {}, utils.getOptions(meta.mapped, entity));
2528
+ }
2529
+ }
2530
+ return { state: { position: value } };
2531
+ }
2532
+ },
2533
+ convertGet: async (entity, key, meta) => {
2534
+ const isPosition = key === 'position';
2535
+ await entity.read('closuresWindowCovering', [isPosition ? 'currentPositionLiftPercentage' : 'currentPositionTiltPercentage']);
2536
+ },
2537
+ },
2538
+ namron_thermostat: {
2539
+ key: [
2540
+ 'lcd_brightness',
2541
+ 'button_vibration_level',
2542
+ 'floor_sensor_type',
2543
+ 'sensor',
2544
+ 'powerup_status',
2545
+ 'floor_sensor_calibration',
2546
+ 'dry_time',
2547
+ 'mode_after_dry',
2548
+ 'temperature_display',
2549
+ 'window_open_check',
2550
+ 'hysterersis',
2551
+ 'display_auto_off_enabled',
2552
+ 'alarm_airtemp_overvalue',
2553
+ 'away_mode',
2554
+ ],
2555
+ convertSet: async (entity, key, value, meta) => {
2556
+ if (key === 'lcd_brightness') {
2557
+ const lookup = { low: 0, mid: 1, high: 2 };
2558
+ const payload = { 0x1000: { value: utils.getFromLookup(value, lookup), type: zigbee_herdsman_1.Zcl.DataType.ENUM8 } };
2559
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2560
+ }
2561
+ else if (key === 'button_vibration_level') {
2562
+ const lookup = { off: 0, low: 1, high: 2 };
2563
+ const payload = { 0x1001: { value: utils.getFromLookup(value, lookup), type: zigbee_herdsman_1.Zcl.DataType.ENUM8 } };
2564
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2565
+ }
2566
+ else if (key === 'floor_sensor_type') {
2567
+ const lookup = { '10k': 1, '15k': 2, '50k': 3, '100k': 4, '12k': 5 };
2568
+ const payload = { 0x1002: { value: utils.getFromLookup(value, lookup), type: zigbee_herdsman_1.Zcl.DataType.ENUM8 } };
2569
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2570
+ }
2571
+ else if (key === 'sensor') {
2572
+ const lookup = { air: 0, floor: 1, both: 2 };
2573
+ const payload = { 0x1003: { value: utils.getFromLookup(value, lookup), type: zigbee_herdsman_1.Zcl.DataType.ENUM8 } };
2574
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2575
+ }
2576
+ else if (key === 'powerup_status') {
2577
+ const lookup = { default: 0, last_status: 1 };
2578
+ const payload = { 0x1004: { value: utils.getFromLookup(value, lookup), type: zigbee_herdsman_1.Zcl.DataType.ENUM8 } };
2579
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2580
+ }
2581
+ else if (key === 'floor_sensor_calibration') {
2582
+ utils.assertNumber(value);
2583
+ const payload = { 0x1005: { value: Math.round(value * 10), type: 0x28 } }; // INT8S
2584
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2585
+ }
2586
+ else if (key === 'dry_time') {
2587
+ const payload = { 0x1006: { value: value, type: 0x20 } }; // INT8U
2588
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2589
+ }
2590
+ else if (key === 'mode_after_dry') {
2591
+ const lookup = { off: 0, manual: 1, auto: 2, away: 3 };
2592
+ const payload = { 0x1007: { value: utils.getFromLookup(value, lookup), type: zigbee_herdsman_1.Zcl.DataType.ENUM8 } };
2593
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2594
+ }
2595
+ else if (key === 'temperature_display') {
2596
+ const lookup = { room: 0, floor: 1 };
2597
+ const payload = { 0x1008: { value: utils.getFromLookup(value, lookup), type: zigbee_herdsman_1.Zcl.DataType.ENUM8 } };
2598
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2599
+ }
2600
+ else if (key === 'window_open_check') {
2601
+ utils.assertNumber(value);
2602
+ const payload = { 0x1009: { value: value * 2, type: 0x20 } };
2603
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2604
+ }
2605
+ else if (key === 'hysterersis') {
2606
+ utils.assertNumber(value);
2607
+ const payload = { 0x100a: { value: value * 10, type: 0x20 } };
2608
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2609
+ }
2610
+ else if (key === 'display_auto_off_enabled') {
2611
+ const lookup = { disabled: 0, enabled: 1 };
2612
+ const payload = { 0x100b: { value: utils.getFromLookup(value, lookup), type: zigbee_herdsman_1.Zcl.DataType.ENUM8 } };
2613
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2614
+ }
2615
+ else if (key === 'alarm_airtemp_overvalue') {
2616
+ const payload = { 0x2001: { value: value, type: 0x20 } };
2617
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2618
+ }
2619
+ else if (key === 'away_mode') {
2620
+ const payload = { 0x2002: { value: Number(value === 'ON'), type: 0x30 } };
2621
+ await entity.write('hvacThermostat', payload, manufacturerOptions.sunricher);
2622
+ }
2623
+ },
2624
+ convertGet: async (entity, key, meta) => {
2625
+ switch (key) {
2626
+ case 'lcd_brightness':
2627
+ await entity.read('hvacThermostat', [0x1000], manufacturerOptions.sunricher);
2628
+ break;
2629
+ case 'button_vibration_level':
2630
+ await entity.read('hvacThermostat', [0x1001], manufacturerOptions.sunricher);
2631
+ break;
2632
+ case 'floor_sensor_type':
2633
+ await entity.read('hvacThermostat', [0x1002], manufacturerOptions.sunricher);
2634
+ break;
2635
+ case 'sensor':
2636
+ await entity.read('hvacThermostat', [0x1003], manufacturerOptions.sunricher);
2637
+ break;
2638
+ case 'powerup_status':
2639
+ await entity.read('hvacThermostat', [0x1004], manufacturerOptions.sunricher);
2640
+ break;
2641
+ case 'floor_sensor_calibration':
2642
+ await entity.read('hvacThermostat', [0x1005], manufacturerOptions.sunricher);
2643
+ break;
2644
+ case 'dry_time':
2645
+ await entity.read('hvacThermostat', [0x1006], manufacturerOptions.sunricher);
2646
+ break;
2647
+ case 'mode_after_dry':
2648
+ await entity.read('hvacThermostat', [0x1007], manufacturerOptions.sunricher);
2649
+ break;
2650
+ case 'temperature_display':
2651
+ await entity.read('hvacThermostat', [0x1008], manufacturerOptions.sunricher);
2652
+ break;
2653
+ case 'window_open_check':
2654
+ await entity.read('hvacThermostat', [0x1009], manufacturerOptions.sunricher);
2655
+ break;
2656
+ case 'hysterersis':
2657
+ await entity.read('hvacThermostat', [0x100a], manufacturerOptions.sunricher);
2658
+ break;
2659
+ case 'display_auto_off_enabled':
2660
+ await entity.read('hvacThermostat', [0x100b], manufacturerOptions.sunricher);
2661
+ break;
2662
+ case 'alarm_airtemp_overvalue':
2663
+ await entity.read('hvacThermostat', [0x2001], manufacturerOptions.sunricher);
2664
+ break;
2665
+ case 'away_mode':
2666
+ await entity.read('hvacThermostat', [0x2002], manufacturerOptions.sunricher);
2667
+ break;
2668
+ default: // Unknown key
2669
+ throw new Error(`Unhandled key toZigbee.namron_thermostat.convertGet ${key}`);
2670
+ }
2671
+ },
2672
+ },
2673
+ namron_thermostat_child_lock: {
2674
+ key: ['child_lock'],
2675
+ convertSet: async (entity, key, value, meta) => {
2676
+ const keypadLockout = Number(value === 'LOCK');
2677
+ await entity.write('hvacUserInterfaceCfg', { keypadLockout });
2678
+ return { state: { child_lock: value } };
2679
+ },
2680
+ convertGet: async (entity, key, meta) => {
2681
+ await entity.read('hvacUserInterfaceCfg', ['keypadLockout']);
2682
+ },
2683
+ },
2684
+ easycode_auto_relock: {
2685
+ key: ['auto_relock'],
2686
+ convertSet: async (entity, key, value, meta) => {
2687
+ await entity.write('closuresDoorLock', { autoRelockTime: value ? 1 : 0 }, utils.getOptions(meta.mapped, entity));
2688
+ return { state: { auto_relock: value } };
2689
+ },
2690
+ },
2691
+ tuya_led_control: {
2692
+ key: ['brightness', 'color', 'color_temp'],
2693
+ options: [exposes.options.color_sync()],
2694
+ convertSet: async (entity, key, value, meta) => {
2695
+ if (key === 'brightness' &&
2696
+ meta.state.color_mode == constants.colorModeLookup[2] &&
2697
+ meta.message.color === undefined &&
2698
+ meta.message.color_temp === undefined) {
2699
+ const zclData = { level: Number(value), transtime: 0 };
2700
+ await entity.command('genLevelCtrl', 'moveToLevel', zclData, utils.getOptions(meta.mapped, entity));
2701
+ globalStore.putValue(entity, 'brightness', zclData.level);
2702
+ return { state: { brightness: zclData.level } };
2703
+ }
2704
+ if (key === 'brightness' && utils.isNumber(meta.message.color_temp)) {
2705
+ const zclData = { colortemp: utils.mapNumberRange(meta.message.color_temp, 500, 154, 0, 254), transtime: 0 };
2706
+ const zclDataBrightness = { level: Number(value), transtime: 0 };
2707
+ await entity.command('lightingColorCtrl', 'tuyaRgbMode', { enable: 0 });
2708
+ await entity.command('lightingColorCtrl', 'moveToColorTemp', zclData, utils.getOptions(meta.mapped, entity));
2709
+ await entity.command('genLevelCtrl', 'moveToLevel', zclDataBrightness, utils.getOptions(meta.mapped, entity));
2710
+ globalStore.putValue(entity, 'brightness', zclDataBrightness.level);
2711
+ const newState = {
2712
+ brightness: zclDataBrightness.level,
2713
+ color_mode: constants.colorModeLookup[2],
2714
+ color_temp: meta.message.color_temp,
2715
+ };
2716
+ return { state: libColor.syncColorState(newState, meta.state, entity, meta.options) };
2717
+ }
2718
+ if (key === 'color_temp') {
2719
+ utils.assertNumber(value, key);
2720
+ const zclData = { colortemp: utils.mapNumberRange(value, 500, 154, 0, 254), transtime: 0 };
2721
+ const zclDataBrightness = { level: globalStore.getValue(entity, 'brightness') || 100, transtime: 0 };
2722
+ await entity.command('lightingColorCtrl', 'tuyaRgbMode', { enable: 0 });
2723
+ await entity.command('lightingColorCtrl', 'moveToColorTemp', zclData, utils.getOptions(meta.mapped, entity));
2724
+ await entity.command('genLevelCtrl', 'moveToLevel', zclDataBrightness, utils.getOptions(meta.mapped, entity));
2725
+ const newState = {
2726
+ brightness: zclDataBrightness.level,
2727
+ color_mode: constants.colorModeLookup[2],
2728
+ color_temp: value,
2729
+ };
2730
+ return { state: libColor.syncColorState(newState, meta.state, entity, meta.options) };
2731
+ }
2732
+ const zclData = {
2733
+ brightness: globalStore.getValue(entity, 'brightness') || 100,
2734
+ // @ts-expect-error ignore
2735
+ hue: utils.mapNumberRange(meta.state.color.h, 0, 360, 0, 254) || 100,
2736
+ // @ts-expect-error ignore
2737
+ saturation: utils.mapNumberRange(meta.state.color.s, 0, 100, 0, 254) || 100,
2738
+ transtime: 0,
2739
+ };
2740
+ if (utils.isObject(value)) {
2741
+ if (value.h) {
2742
+ zclData.hue = utils.mapNumberRange(value.h, 0, 360, 0, 254);
2743
+ }
2744
+ if (value.hue) {
2745
+ zclData.hue = utils.mapNumberRange(value.hue, 0, 360, 0, 254);
2746
+ }
2747
+ if (value.s) {
2748
+ zclData.saturation = utils.mapNumberRange(value.s, 0, 100, 0, 254);
2749
+ }
2750
+ if (value.saturation) {
2751
+ zclData.saturation = utils.mapNumberRange(value.saturation, 0, 100, 0, 254);
2752
+ }
2753
+ if (value.b) {
2754
+ zclData.brightness = Number(value.b);
2755
+ }
2756
+ if (value.brightness) {
2757
+ zclData.brightness = Number(value.brightness);
2758
+ }
2759
+ if (typeof value === 'number') {
2760
+ zclData.brightness = value;
2761
+ }
2762
+ }
2763
+ if (meta.message.color !== undefined) {
2764
+ if (utils.isObject(meta.message.color)) {
2765
+ if (meta.message.color.h) {
2766
+ zclData.hue = utils.mapNumberRange(meta.message.color.h, 0, 360, 0, 254);
2767
+ }
2768
+ if (meta.message.color.s) {
2769
+ zclData.saturation = utils.mapNumberRange(meta.message.color.s, 0, 100, 0, 254);
2770
+ }
2771
+ if (meta.message.color.b) {
2772
+ zclData.brightness = Number(meta.message.color.b);
2773
+ }
2774
+ if (meta.message.color.brightness) {
2775
+ zclData.brightness = Number(meta.message.color.brightness);
2776
+ }
2777
+ }
2778
+ }
2779
+ await entity.command('lightingColorCtrl', 'tuyaRgbMode', { enable: 1 });
2780
+ await entity.command('lightingColorCtrl', 'tuyaMoveToHueAndSaturationBrightness', zclData, utils.getOptions(meta.mapped, entity));
2781
+ globalStore.putValue(entity, 'brightness', zclData.brightness);
2782
+ const newState = {
2783
+ brightness: zclData.brightness,
2784
+ color: {
2785
+ h: utils.mapNumberRange(zclData.hue, 0, 254, 0, 360),
2786
+ hue: utils.mapNumberRange(zclData.hue, 0, 254, 0, 360),
2787
+ s: utils.mapNumberRange(zclData.saturation, 0, 254, 0, 100),
2788
+ saturation: utils.mapNumberRange(zclData.saturation, 0, 254, 0, 100),
2789
+ },
2790
+ color_mode: constants.colorModeLookup[0],
2791
+ };
2792
+ return { state: libColor.syncColorState(newState, meta.state, entity, meta.options) };
2793
+ },
2794
+ convertGet: async (entity, key, meta) => {
2795
+ await entity.read('lightingColorCtrl', ['currentHue', 'currentSaturation', 'tuyaBrightness', 'tuyaRgbMode', 'colorTemperature']);
2796
+ },
2797
+ },
2798
+ tuya_led_controller: {
2799
+ key: ['state', 'color'],
2800
+ convertSet: async (entity, key, value, meta) => {
2801
+ if (key === 'state') {
2802
+ utils.assertString(value, key);
2803
+ if (value.toLowerCase() === 'off') {
2804
+ await entity.command('genOnOff', 'offWithEffect', { effectid: 0x01, effectvariant: 0x01 }, utils.getOptions(meta.mapped, entity));
2805
+ }
2806
+ else {
2807
+ const payload = { level: 255, transtime: 0 };
2808
+ await entity.command('genLevelCtrl', 'moveToLevelWithOnOff', payload, utils.getOptions(meta.mapped, entity));
2809
+ }
2810
+ return { state: { state: value.toUpperCase() } };
2811
+ }
2812
+ else if (key === 'color') {
2813
+ const hue = {};
2814
+ const saturation = {};
2815
+ utils.assertObject(value);
2816
+ hue.hue = utils.mapNumberRange(value.h, 0, 360, 0, 254);
2817
+ saturation.saturation = utils.mapNumberRange(value.s, 0, 100, 0, 254);
2818
+ hue.transtime = saturation.transtime = 0;
2819
+ hue.direction = 0;
2820
+ await entity.command('lightingColorCtrl', 'moveToHue', hue, utils.getOptions(meta.mapped, entity));
2821
+ await entity.command('lightingColorCtrl', 'moveToSaturation', saturation, utils.getOptions(meta.mapped, entity));
2822
+ }
2823
+ },
2824
+ convertGet: async (entity, key, meta) => {
2825
+ if (key === 'state') {
2826
+ await entity.read('genOnOff', ['onOff']);
2827
+ }
2828
+ else if (key === 'color') {
2829
+ await entity.read('lightingColorCtrl', ['currentHue', 'currentSaturation']);
2830
+ }
2831
+ },
2832
+ },
2833
+ EMIZB_132_mode: {
2834
+ key: ['interface_mode'],
2835
+ convertSet: async (entity, key, value, meta) => {
2836
+ const endpoint = meta.device.getEndpoint(2);
2837
+ const lookup = {
2838
+ norwegian_han: { value: 0x0200, acVoltageDivisor: 10, acCurrentDivisor: 10 },
2839
+ norwegian_han_extra_load: { value: 0x0201, acVoltageDivisor: 10, acCurrentDivisor: 10 },
2840
+ aidon_meter: { value: 0x0202, acVoltageDivisor: 10, acCurrentDivisor: 10 },
2841
+ kaifa_and_kamstrup: { value: 0x0203, acVoltageDivisor: 10, acCurrentDivisor: 1000 },
2842
+ };
2843
+ await endpoint.write('seMetering', { 0x0302: { value: utils.getFromLookup(value, lookup).value, type: 49 } }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DEVELCO });
2844
+ // As the device reports the incorrect divisor, we need to set it here
2845
+ // https://github.com/Koenkk/zigbee-herdsman-converters/issues/974#issuecomment-604347303
2846
+ // Values for norwegian_han and aidon_meter have not been been checked
2847
+ endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {
2848
+ acVoltageMultiplier: 1,
2849
+ acVoltageDivisor: utils.getFromLookup(value, lookup).acVoltageDivisor,
2850
+ acCurrentMultiplier: 1,
2851
+ acCurrentDivisor: utils.getFromLookup(value, lookup).acCurrentDivisor,
2852
+ });
2853
+ return { state: { interface_mode: value } };
2854
+ },
2855
+ },
2856
+ eurotronic_host_flags: {
2857
+ key: ['eurotronic_host_flags', 'system_mode'],
2858
+ convertSet: async (entity, key, value, meta) => {
2859
+ const origValue = value;
2860
+ await entity.read('hvacThermostat', [0x4008], manufacturerOptions.eurotronic);
2861
+ // calculate bit value
2862
+ let bitValue = 0x01; // bit 0 always 1
2863
+ if (meta.state.mirror_display == 'ON') {
2864
+ bitValue |= 0x02;
2865
+ }
2866
+ if (value == constants.thermostatSystemModes[0]) {
2867
+ // off
2868
+ bitValue |= 0x20;
2869
+ }
2870
+ else if (value == constants.thermostatSystemModes[4]) {
2871
+ // "heat"
2872
+ bitValue |= 0x04;
2873
+ }
2874
+ else {
2875
+ // auto
2876
+ bitValue |= 0x10;
2877
+ }
2878
+ if (meta.state.child_lock == 'LOCK') {
2879
+ bitValue |= 0x80;
2880
+ }
2881
+ value = bitValue;
2882
+ const payload = { 0x4008: { value, type: 0x22 } };
2883
+ await entity.write('hvacThermostat', payload, manufacturerOptions.eurotronic);
2884
+ return { state: { [key]: origValue } };
2885
+ },
2886
+ convertGet: async (entity, key, meta) => {
2887
+ await entity.read('hvacThermostat', [0x4008], manufacturerOptions.eurotronic);
2888
+ },
2889
+ },
2890
+ eurotronic_error_status: {
2891
+ key: ['eurotronic_error_status'],
2892
+ convertGet: async (entity, key, meta) => {
2893
+ await entity.read('hvacThermostat', [0x4002], manufacturerOptions.eurotronic);
2894
+ },
2895
+ },
2896
+ eurotronic_current_heating_setpoint: {
2897
+ key: ['current_heating_setpoint'],
2898
+ convertSet: async (entity, key, value, meta) => {
2899
+ utils.assertNumber(value, key);
2900
+ const val = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
2901
+ const payload = { 0x4003: { value: val, type: 0x29 } };
2902
+ await entity.write('hvacThermostat', payload, manufacturerOptions.eurotronic);
2903
+ },
2904
+ convertGet: async (entity, key, meta) => {
2905
+ await entity.read('hvacThermostat', [0x4003], manufacturerOptions.eurotronic);
2906
+ },
2907
+ },
2908
+ eurotronic_valve_position: {
2909
+ key: ['eurotronic_valve_position', 'valve_position'],
2910
+ convertSet: async (entity, key, value, meta) => {
2911
+ const payload = { 0x4001: { value, type: 0x20 } };
2912
+ await entity.write('hvacThermostat', payload, manufacturerOptions.eurotronic);
2913
+ return { state: { [key]: value } };
2914
+ },
2915
+ convertGet: async (entity, key, meta) => {
2916
+ await entity.read('hvacThermostat', [0x4001], manufacturerOptions.eurotronic);
2917
+ },
2918
+ },
2919
+ eurotronic_trv_mode: {
2920
+ key: ['eurotronic_trv_mode', 'trv_mode'],
2921
+ convertSet: async (entity, key, value, meta) => {
2922
+ const payload = { 0x4000: { value, type: 0x30 } };
2923
+ await entity.write('hvacThermostat', payload, manufacturerOptions.eurotronic);
2924
+ return { state: { [key]: value } };
2925
+ },
2926
+ convertGet: async (entity, key, meta) => {
2927
+ await entity.read('hvacThermostat', [0x4000], manufacturerOptions.eurotronic);
2928
+ },
2929
+ },
2930
+ eurotronic_child_lock: {
2931
+ key: ['eurotronic_child_lock', 'child_lock'],
2932
+ convertSet: async (entity, key, value, meta) => {
2933
+ await entity.read('hvacThermostat', [0x4008], manufacturerOptions.eurotronic);
2934
+ // calculate bit value
2935
+ let bitValue = 0x01; // bit 0 always 1
2936
+ if (meta.state.mirror_display == 'ON') {
2937
+ bitValue |= 0x02;
2938
+ }
2939
+ if (meta.state.system_mode == constants.thermostatSystemModes[0]) {
2940
+ // off
2941
+ bitValue |= 0x20;
2942
+ }
2943
+ else if (meta.state.system_mode == constants.thermostatSystemModes[4]) {
2944
+ // "heat"
2945
+ bitValue |= 0x04;
2946
+ }
2947
+ else {
2948
+ // auto
2949
+ bitValue |= 0x10;
2950
+ }
2951
+ if (value == 'LOCK') {
2952
+ bitValue |= 0x80;
2953
+ }
2954
+ const origValue = value;
2955
+ value = bitValue;
2956
+ const payload = { 0x4008: { value, type: 0x22 } };
2957
+ await entity.write('hvacThermostat', payload, manufacturerOptions.eurotronic);
2958
+ return { state: { [key]: origValue } };
2959
+ },
2960
+ },
2961
+ eurotronic_mirror_display: {
2962
+ key: ['eurotronic_mirror_display', 'mirror_display'],
2963
+ convertSet: async (entity, key, value, meta) => {
2964
+ await entity.read('hvacThermostat', [0x4008], manufacturerOptions.eurotronic);
2965
+ // calculate bit value
2966
+ let bitValue = 0x01; // bit 0 always 1
2967
+ if (value == 'ON') {
2968
+ bitValue |= 0x02;
2969
+ }
2970
+ if (meta.state.system_mode == constants.thermostatSystemModes[0]) {
2971
+ // off
2972
+ bitValue |= 0x20;
2973
+ }
2974
+ else if (meta.state.system_mode == constants.thermostatSystemModes[4]) {
2975
+ // "heat"
2976
+ bitValue |= 0x04;
2977
+ }
2978
+ else {
2979
+ // auto
2980
+ bitValue |= 0x10;
2981
+ }
2982
+ if (meta.state.child_lock == 'LOCK') {
2983
+ bitValue |= 0x80;
2984
+ }
2985
+ const origValue = value;
2986
+ value = bitValue;
2987
+ const payload = { 0x4008: { value, type: 0x22 } };
2988
+ await entity.write('hvacThermostat', payload, manufacturerOptions.eurotronic);
2989
+ return { state: { [key]: origValue } };
2990
+ },
2991
+ convertGet: async (entity, key, meta) => {
2992
+ await entity.read('hvacThermostat', [0x4008], manufacturerOptions.eurotronic);
2993
+ },
2994
+ },
2995
+ stelpro_thermostat_outdoor_temperature: {
2996
+ key: ['thermostat_outdoor_temperature'],
2997
+ convertSet: async (entity, key, value, meta) => {
2998
+ utils.assertNumber(value, key);
2999
+ if (value > -100 && value < 100) {
3000
+ await entity.write('hvacThermostat', { StelproOutdoorTemp: value * 100 });
3001
+ }
3002
+ },
3003
+ },
3004
+ DTB190502A1_LED: {
3005
+ key: ['LED'],
3006
+ convertSet: async (entity, key, value, meta) => {
3007
+ if (value === 'default') {
3008
+ value = 1;
3009
+ }
3010
+ const lookup = {
3011
+ OFF: 0,
3012
+ ON: 1,
3013
+ };
3014
+ value = utils.getFromLookup(value, lookup);
3015
+ // Check for valid data
3016
+ utils.assertNumber(value, key);
3017
+ if ((value >= 0 && value < 2) == false)
3018
+ value = 0;
3019
+ const payload = {
3020
+ 0x4010: {
3021
+ value,
3022
+ type: 0x21,
3023
+ },
3024
+ };
3025
+ await entity.write('genBasic', payload);
3026
+ },
3027
+ },
3028
+ ptvo_switch_trigger: {
3029
+ key: ['trigger', 'interval'],
3030
+ convertSet: async (entity, key, value, meta) => {
3031
+ utils.assertNumber(value, key);
3032
+ utils.assertEndpoint(entity);
3033
+ if (key === 'trigger') {
3034
+ await entity.command('genOnOff', 'onWithTimedOff', { ctrlbits: 0, ontime: Math.round(value / 100), offwaittime: 0 });
3035
+ }
3036
+ else if (key === 'interval') {
3037
+ await entity.configureReporting('genOnOff', [
3038
+ {
3039
+ attribute: 'onOff',
3040
+ minimumReportInterval: value,
3041
+ maximumReportInterval: value,
3042
+ reportableChange: 0,
3043
+ },
3044
+ ]);
3045
+ }
3046
+ },
3047
+ },
3048
+ ptvo_switch_uart: {
3049
+ key: ['action'],
3050
+ convertSet: async (entity, key, value, meta) => {
3051
+ if (!value) {
3052
+ return;
3053
+ }
3054
+ const payload = { 14: { value, type: 0x42 } };
3055
+ for (const endpoint of meta.device.endpoints) {
3056
+ const cluster = 'genMultistateValue';
3057
+ if (endpoint.supportsInputCluster(cluster) || endpoint.supportsOutputCluster(cluster)) {
3058
+ await endpoint.write(cluster, payload);
3059
+ return;
3060
+ }
3061
+ }
3062
+ await entity.write('genMultistateValue', payload);
3063
+ },
3064
+ },
3065
+ ptvo_switch_analog_input: {
3066
+ key: ['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12', 'l13', 'l14', 'l15', 'l16'],
3067
+ convertGet: async (entity, key, meta) => {
3068
+ const epId = parseInt(key.substr(1, 2));
3069
+ if (utils.hasEndpoints(meta.device, [epId])) {
3070
+ const endpoint = meta.device.getEndpoint(epId);
3071
+ await endpoint.read('genAnalogInput', ['presentValue', 'description']);
3072
+ }
3073
+ },
3074
+ convertSet: async (entity, key, value, meta) => {
3075
+ const epId = parseInt(key.substr(1, 2));
3076
+ if (utils.hasEndpoints(meta.device, [epId])) {
3077
+ const endpoint = meta.device.getEndpoint(epId);
3078
+ let cluster = 'genLevelCtrl';
3079
+ if (endpoint.supportsInputCluster(cluster) || endpoint.supportsOutputCluster(cluster)) {
3080
+ const value2 = Number(value);
3081
+ if (isNaN(value2)) {
3082
+ return;
3083
+ }
3084
+ const payload = { currentLevel: value2 };
3085
+ await endpoint.write(cluster, payload);
3086
+ return;
3087
+ }
3088
+ cluster = 'genAnalogInput';
3089
+ if (endpoint.supportsInputCluster(cluster) || endpoint.supportsOutputCluster(cluster)) {
3090
+ const value2 = Number(value);
3091
+ if (isNaN(value2)) {
3092
+ return;
3093
+ }
3094
+ const payload = { presentValue: value2 };
3095
+ await endpoint.write(cluster, payload);
3096
+ return;
3097
+ }
3098
+ }
3099
+ return;
3100
+ },
3101
+ },
3102
+ tint_scene: {
3103
+ key: ['tint_scene'],
3104
+ convertSet: async (entity, key, value, meta) => {
3105
+ await entity.write('genBasic', { 0x4005: { value, type: 0x20 } }, manufacturerOptions.tint);
3106
+ },
3107
+ },
3108
+ bticino_4027C_cover_state: {
3109
+ key: ['state'],
3110
+ options: [exposes.options.invert_cover()],
3111
+ convertSet: async (entity, key, value, meta) => {
3112
+ utils.assertString(value);
3113
+ const invert = !(utils.getMetaValue(entity, meta.mapped, 'coverInverted', 'allEqual', false)
3114
+ ? !meta.options.invert_cover
3115
+ : meta.options.invert_cover);
3116
+ const lookup = invert
3117
+ ? { open: 'upOpen', close: 'downClose', stop: 'stop', on: 'upOpen', off: 'downClose' }
3118
+ : { open: 'downClose', close: 'upOpen', stop: 'stop', on: 'downClose', off: 'upOpen' };
3119
+ value = value.toLowerCase();
3120
+ utils.validateValue(value, Object.keys(lookup));
3121
+ let position = 50;
3122
+ if (value === 'open') {
3123
+ position = 100;
3124
+ }
3125
+ else if (value === 'close') {
3126
+ position = 0;
3127
+ }
3128
+ await entity.command('closuresWindowCovering', utils.getFromLookup(value, lookup), {}, utils.getOptions(meta.mapped, entity));
3129
+ return { state: { position } };
3130
+ },
3131
+ },
3132
+ bticino_4027C_cover_position: {
3133
+ key: ['position'],
3134
+ options: [exposes.options.invert_cover(), exposes.options.no_position_support()],
3135
+ convertSet: async (entity, key, value, meta) => {
3136
+ const invert = !(utils.getMetaValue(entity, meta.mapped, 'coverInverted', 'allEqual', false)
3137
+ ? !meta.options.invert_cover
3138
+ : meta.options.invert_cover);
3139
+ utils.assertNumber(value, key);
3140
+ let newPosition = value;
3141
+ if (meta.options.no_position_support) {
3142
+ newPosition = value >= 50 ? 100 : 0;
3143
+ }
3144
+ const position = newPosition;
3145
+ if (invert) {
3146
+ newPosition = 100 - newPosition;
3147
+ }
3148
+ await entity.command('closuresWindowCovering', 'goToLiftPercentage', { percentageliftvalue: newPosition }, utils.getOptions(meta.mapped, entity));
3149
+ return { state: { ['position']: position } };
3150
+ },
3151
+ convertGet: async (entity, key, meta) => {
3152
+ await entity.read('closuresWindowCovering', ['currentPositionLiftPercentage']);
3153
+ },
3154
+ },
3155
+ legrand_device_mode: {
3156
+ key: ['device_mode'],
3157
+ convertSet: async (entity, key, value, meta) => {
3158
+ utils.assertString(value, key);
3159
+ // enable the dimmer, requires a recent firmware on the device
3160
+ const lookup = {
3161
+ // dimmer
3162
+ dimmer_on: 0x0101,
3163
+ dimmer_off: 0x0100,
3164
+ // contactor
3165
+ switch: 0x0003,
3166
+ auto: 0x0004,
3167
+ // pilot wire
3168
+ pilot_on: 0x0002,
3169
+ pilot_off: 0x0001,
3170
+ };
3171
+ value = value.toLowerCase();
3172
+ utils.validateValue(value, Object.keys(lookup));
3173
+ const payload = { 0: { value: utils.getFromLookup(value, lookup), type: 9 } };
3174
+ await entity.write('manuSpecificLegrandDevices', payload, manufacturerOptions.legrand);
3175
+ return { state: { device_mode: value } };
3176
+ },
3177
+ convertGet: async (entity, key, meta) => {
3178
+ await entity.read('manuSpecificLegrandDevices', [0x0000, 0x0001, 0x0002], manufacturerOptions.legrand);
3179
+ },
3180
+ },
3181
+ legrand_pilot_wire_mode: {
3182
+ key: ['pilot_wire_mode'],
3183
+ convertSet: async (entity, key, value, meta) => {
3184
+ const mode = {
3185
+ comfort: 0x00,
3186
+ 'comfort_-1': 0x01,
3187
+ 'comfort_-2': 0x02,
3188
+ eco: 0x03,
3189
+ frost_protection: 0x04,
3190
+ off: 0x05,
3191
+ };
3192
+ const payload = { data: Buffer.from([utils.getFromLookup(value, mode)]) };
3193
+ await entity.command('manuSpecificLegrandDevices2', 'command0', payload);
3194
+ return { state: { pilot_wire_mode: value } };
3195
+ },
3196
+ convertGet: async (entity, key, meta) => {
3197
+ await entity.read('manuSpecificLegrandDevices2', [0x0000], manufacturerOptions.legrand);
3198
+ },
3199
+ },
3200
+ legrand_power_alarm: {
3201
+ key: ['power_alarm'],
3202
+ convertSet: async (entity, key, value, meta) => {
3203
+ const enableAlarm = value === 'DISABLE' || value === false ? false : true;
3204
+ const payloadBolean = { 0xf001: { value: enableAlarm ? 0x01 : 0x00, type: 0x10 } };
3205
+ const payloadValue = { 0xf002: { value: value, type: 0x29 } };
3206
+ await entity.write('haElectricalMeasurement', payloadValue);
3207
+ await entity.write('haElectricalMeasurement', payloadBolean);
3208
+ // To have consistent information in the system.
3209
+ await entity.read('haElectricalMeasurement', [0xf000, 0xf001, 0xf002]);
3210
+ },
3211
+ convertGet: async (entity, key, meta) => {
3212
+ await entity.read('haElectricalMeasurement', [0xf000, 0xf001, 0xf002]);
3213
+ },
3214
+ },
3215
+ diyruz_freepad_on_off_config: {
3216
+ key: ['switch_type', 'switch_actions'],
3217
+ convertGet: async (entity, key, meta) => {
3218
+ await entity.read('genOnOffSwitchCfg', ['switchType', 'switchActions']);
3219
+ },
3220
+ convertSet: async (entity, key, value, meta) => {
3221
+ const switchTypesLookup = {
3222
+ toggle: 0x00,
3223
+ momentary: 0x01,
3224
+ multifunction: 0x02,
3225
+ };
3226
+ const switchActionsLookup = {
3227
+ on: 0x00,
3228
+ off: 0x01,
3229
+ toggle: 0x02,
3230
+ };
3231
+ const intVal = Number(value);
3232
+ const switchType = utils.getFromLookup(value, switchTypesLookup, intVal);
3233
+ const switchActions = utils.getFromLookup(value, switchActionsLookup, intVal);
3234
+ const payloads = {
3235
+ switch_type: { switchType },
3236
+ switch_actions: { switchActions },
3237
+ };
3238
+ await entity.write('genOnOffSwitchCfg', payloads[key]);
3239
+ return { state: { [`${key}`]: value } };
3240
+ },
3241
+ },
3242
+ TYZB01_on_off: {
3243
+ key: ['state', 'time_in_seconds'],
3244
+ convertSet: async (entity, key, value, meta) => {
3245
+ const result = await converters1.on_off.convertSet(entity, key, value, meta);
3246
+ utils.assertString(value, key);
3247
+ const lowerCaseValue = value.toLowerCase();
3248
+ if (!['on', 'off'].includes(lowerCaseValue)) {
3249
+ return result;
3250
+ }
3251
+ const messageKeys = Object.keys(meta.message);
3252
+ const timeInSecondsValue = (function () {
3253
+ if (messageKeys.includes('state')) {
3254
+ return meta.message.time_in_seconds;
3255
+ }
3256
+ if (meta.endpoint_name) {
3257
+ return meta.message[`time_in_seconds_${meta.endpoint_name}`];
3258
+ }
3259
+ return null;
3260
+ })();
3261
+ if (!timeInSecondsValue) {
3262
+ return result;
3263
+ }
3264
+ const timeInSeconds = Number(timeInSecondsValue);
3265
+ if (!Number.isInteger(timeInSeconds) || timeInSeconds < 0 || timeInSeconds > 0xfffe) {
3266
+ throw Error('The time_in_seconds value must be convertible to an integer in the range: <0x0000, 0xFFFE>');
3267
+ }
3268
+ const on = lowerCaseValue === 'on';
3269
+ await entity.command('genOnOff', 'onWithTimedOff', {
3270
+ ctrlbits: 0,
3271
+ ontime: on ? 0 : timeInSeconds.valueOf(),
3272
+ offwaittime: on ? timeInSeconds.valueOf() : 0,
3273
+ }, utils.getOptions(meta.mapped, entity));
3274
+ return result;
3275
+ },
3276
+ convertGet: async (entity, key, meta) => {
3277
+ await entity.read('genOnOff', ['onOff']);
3278
+ },
3279
+ },
3280
+ diyruz_geiger_config: {
3281
+ key: ['sensitivity', 'led_feedback', 'buzzer_feedback', 'sensors_count', 'sensors_type', 'alert_threshold'],
3282
+ convertSet: async (entity, key, rawValue, meta) => {
3283
+ const lookup = {
3284
+ OFF: 0x00,
3285
+ ON: 0x01,
3286
+ };
3287
+ const sensorsTypeLookup = {
3288
+ 'СБМ-20/СТС-5/BOI-33': '0',
3289
+ 'СБМ-19/СТС-6': '1',
3290
+ Others: '2',
3291
+ };
3292
+ let value = utils.getFromLookup(rawValue, lookup, Number(rawValue));
3293
+ if (key == 'sensors_type') {
3294
+ // @ts-expect-error ignore
3295
+ value = utils.getFromLookup(rawValue, sensorsTypeLookup, Number(rawValue));
3296
+ }
3297
+ const payloads = {
3298
+ sensitivity: { 0xf000: { value, type: 0x21 } },
3299
+ led_feedback: { 0xf001: { value, type: 0x10 } },
3300
+ buzzer_feedback: { 0xf002: { value, type: 0x10 } },
3301
+ sensors_count: { 0xf003: { value, type: 0x20 } },
3302
+ sensors_type: { 0xf004: { value, type: 0x30 } },
3303
+ alert_threshold: { 0xf005: { value, type: 0x23 } },
3304
+ };
3305
+ await entity.write('msIlluminanceLevelSensing', payloads[key]);
3306
+ return {
3307
+ state: { [key]: rawValue },
3308
+ };
3309
+ },
3310
+ convertGet: async (entity, key, meta) => {
3311
+ const payloads = {
3312
+ sensitivity: ['msIlluminanceLevelSensing', 0xf000],
3313
+ led_feedback: ['msIlluminanceLevelSensing', 0xf001],
3314
+ buzzer_feedback: ['msIlluminanceLevelSensing', 0xf002],
3315
+ sensors_count: ['msIlluminanceLevelSensing', 0xf003],
3316
+ sensors_type: ['msIlluminanceLevelSensing', 0xf004],
3317
+ alert_threshold: ['msIlluminanceLevelSensing', 0xf005],
3318
+ };
3319
+ await entity.read(payloads[key][0], [payloads[key][1]]);
3320
+ },
3321
+ },
3322
+ diyruz_airsense_config: {
3323
+ key: ['led_feedback', 'enable_abc', 'threshold1', 'threshold2', 'temperature_offset', 'pressure_offset', 'humidity_offset'],
3324
+ convertSet: async (entity, key, rawValue, meta) => {
3325
+ const lookup = { OFF: 0x00, ON: 0x01 };
3326
+ const value = utils.getFromLookup(rawValue, lookup, Number(rawValue));
3327
+ const payloads = {
3328
+ led_feedback: ['msCO2', { 0x0203: { value, type: 0x10 } }],
3329
+ enable_abc: ['msCO2', { 0x0202: { value, type: 0x10 } }],
3330
+ threshold1: ['msCO2', { 0x0204: { value, type: 0x21 } }],
3331
+ threshold2: ['msCO2', { 0x0205: { value, type: 0x21 } }],
3332
+ temperature_offset: ['msTemperatureMeasurement', { 0x0210: { value, type: 0x29 } }],
3333
+ pressure_offset: ['msPressureMeasurement', { 0x0210: { value, type: 0x2b } }],
3334
+ humidity_offset: ['msRelativeHumidity', { 0x0210: { value, type: 0x29 } }],
3335
+ };
3336
+ await entity.write(payloads[key][0], payloads[key][1]);
3337
+ return {
3338
+ state: { [key]: rawValue },
3339
+ };
3340
+ },
3341
+ convertGet: async (entity, key, meta) => {
3342
+ const payloads = {
3343
+ led_feedback: ['msCO2', 0x0203],
3344
+ enable_abc: ['msCO2', 0x0202],
3345
+ threshold1: ['msCO2', 0x0204],
3346
+ threshold2: ['msCO2', 0x0205],
3347
+ temperature_offset: ['msTemperatureMeasurement', 0x0210],
3348
+ pressure_offset: ['msPressureMeasurement', 0x0210],
3349
+ humidity_offset: ['msRelativeHumidity', 0x0210],
3350
+ };
3351
+ await entity.read(payloads[key][0], [payloads[key][1]]);
3352
+ },
3353
+ },
3354
+ diyruz_zintercom_config: {
3355
+ key: ['mode', 'sound', 'time_ring', 'time_talk', 'time_open', 'time_bell', 'time_report'],
3356
+ convertSet: async (entity, key, rawValue, meta) => {
3357
+ const lookup = { OFF: 0x00, ON: 0x01 };
3358
+ const modeOpenLookup = { never: '0', once: '1', always: '2', drop: '3' };
3359
+ let value = utils.getFromLookup(rawValue, lookup, Number(rawValue));
3360
+ if (key == 'mode') {
3361
+ // @ts-expect-error ignore
3362
+ value = utils.getFromLookup(rawValue, modeOpenLookup, Number(rawValue));
3363
+ }
3364
+ const payloads = {
3365
+ mode: { 0x0051: { value, type: 0x30 } },
3366
+ sound: { 0x0052: { value, type: 0x10 } },
3367
+ time_ring: { 0x0053: { value, type: 0x20 } },
3368
+ time_talk: { 0x0054: { value, type: 0x20 } },
3369
+ time_open: { 0x0055: { value, type: 0x20 } },
3370
+ time_bell: { 0x0057: { value, type: 0x20 } },
3371
+ time_report: { 0x0056: { value, type: 0x20 } },
3372
+ };
3373
+ await entity.write('closuresDoorLock', payloads[key]);
3374
+ return {
3375
+ state: { [key]: rawValue },
3376
+ };
3377
+ },
3378
+ convertGet: async (entity, key, meta) => {
3379
+ const payloads = {
3380
+ mode: ['closuresDoorLock', 0x0051],
3381
+ sound: ['closuresDoorLock', 0x0052],
3382
+ time_ring: ['closuresDoorLock', 0x0053],
3383
+ time_talk: ['closuresDoorLock', 0x0054],
3384
+ time_open: ['closuresDoorLock', 0x0055],
3385
+ time_bell: ['closuresDoorLock', 0x0057],
3386
+ time_report: ['closuresDoorLock', 0x0056],
3387
+ };
3388
+ const v = utils.getFromLookup(key, payloads);
3389
+ await entity.read(v[0], [v[1]]);
3390
+ },
3391
+ },
3392
+ power_source: {
3393
+ key: ['power_source', 'charging'],
3394
+ convertGet: async (entity, key, meta) => {
3395
+ await entity.read('genBasic', ['powerSource']);
3396
+ },
3397
+ },
3398
+ ts0201_temperature_humidity_alarm: {
3399
+ key: ['alarm_humidity_max', 'alarm_humidity_min', 'alarm_temperature_max', 'alarm_temperature_min'],
3400
+ convertSet: async (entity, key, value, meta) => {
3401
+ switch (key) {
3402
+ case 'alarm_temperature_max':
3403
+ case 'alarm_temperature_min':
3404
+ case 'alarm_humidity_max':
3405
+ case 'alarm_humidity_min': {
3406
+ // await entity.write('manuSpecificTuya_2', {[key]: value});
3407
+ // instead write as custom attribute to override incorrect herdsman dataType from uint16 to int16
3408
+ // https://github.com/Koenkk/zigbee-herdsman/blob/v0.13.191/src/zcl/definition/cluster.ts#L4235
3409
+ const keyToAttributeLookup = {
3410
+ alarm_temperature_max: 0xd00a,
3411
+ alarm_temperature_min: 0xd00b,
3412
+ alarm_humidity_max: 0xd00d,
3413
+ alarm_humidity_min: 0xd00e,
3414
+ };
3415
+ const payload = { [keyToAttributeLookup[key]]: { value: value, type: zigbee_herdsman_1.Zcl.DataType.INT16 } };
3416
+ await entity.write('manuSpecificTuya_2', payload);
3417
+ break;
3418
+ }
3419
+ default: // Unknown key
3420
+ logger_1.logger.warning(`Unhandled key ${key}`, NS);
3421
+ }
3422
+ },
3423
+ },
3424
+ heiman_ir_remote: {
3425
+ key: ['send_key', 'create', 'learn', 'delete', 'get_list'],
3426
+ convertSet: async (entity, key, value, meta) => {
3427
+ const options = {
3428
+ // Don't send a manufacturerCode (otherwise set in herdsman):
3429
+ // https://github.com/Koenkk/zigbee-herdsman-converters/pull/2827
3430
+ // @ts-expect-error ignore
3431
+ manufacturerCode: null,
3432
+ ...utils.getOptions(meta.mapped, entity),
3433
+ };
3434
+ switch (key) {
3435
+ case 'send_key':
3436
+ utils.assertObject(value);
3437
+ await entity.command('heimanSpecificInfraRedRemote', 'sendKey', { id: value['id'], keyCode: value['key_code'] }, options);
3438
+ break;
3439
+ case 'create':
3440
+ utils.assertObject(value);
3441
+ await entity.command('heimanSpecificInfraRedRemote', 'createId', { modelType: value['model_type'] }, options);
3442
+ break;
3443
+ case 'learn':
3444
+ utils.assertObject(value);
3445
+ await entity.command('heimanSpecificInfraRedRemote', 'studyKey', { id: value['id'], keyCode: value['key_code'] }, options);
3446
+ break;
3447
+ case 'delete':
3448
+ utils.assertObject(value);
3449
+ await entity.command('heimanSpecificInfraRedRemote', 'deleteKey', { id: value['id'], keyCode: value['key_code'] }, options);
3450
+ break;
3451
+ case 'get_list':
3452
+ await entity.command('heimanSpecificInfraRedRemote', 'getIdAndKeyCodeList', {}, options);
3453
+ break;
3454
+ default: // Unknown key
3455
+ throw new Error(`Unhandled key ${key}`);
3456
+ }
3457
+ },
3458
+ },
3459
+ scene_store: {
3460
+ key: ['scene_store'],
3461
+ convertSet: async (entity, key, value, meta) => {
3462
+ const isGroup = utils.isGroup(entity);
3463
+ const groupid = isGroup ? entity.groupID : value.group_id != undefined ? value.group_id : 0;
3464
+ let sceneid = value;
3465
+ let scenename = null;
3466
+ if (typeof value === 'object') {
3467
+ sceneid = value.ID;
3468
+ scenename = value.name;
3469
+ }
3470
+ utils.assertNumber(sceneid, 'ID');
3471
+ if (groupid === 0 && sceneid === 0) {
3472
+ // From Zigbee spec:
3473
+ // "Scene identifier 0x00, along with group identifier 0x0000, is reserved for the global scene used by the OnOff cluster"
3474
+ throw new Error('Scene ID 0 cannot be used with group ID 0 (reserved).');
3475
+ }
3476
+ const response = await entity.command('genScenes', 'store', { groupid, sceneid }, utils.getOptions(meta.mapped, entity));
3477
+ if (isGroup) {
3478
+ if (meta.membersState) {
3479
+ for (const member of entity.members) {
3480
+ utils.saveSceneState(member, sceneid, groupid, meta.membersState[member.getDevice().ieeeAddr], scenename);
3481
+ }
3482
+ }
3483
+ // @ts-expect-error ignore
3484
+ }
3485
+ else if (response.status === 0) {
3486
+ utils.saveSceneState(entity, sceneid, groupid, meta.state, scenename);
3487
+ }
3488
+ else {
3489
+ // @ts-expect-error ignore
3490
+ throw new Error(`Scene add not successful ('${zigbee_herdsman_1.Zcl.Status[response.status]}')`);
3491
+ }
3492
+ logger_1.logger.info('Successfully stored scene', NS);
3493
+ return { state: {} };
3494
+ },
3495
+ },
3496
+ scene_recall: {
3497
+ key: ['scene_recall'],
3498
+ convertSet: async (entity, key, value, meta) => {
3499
+ const groupid = utils.isGroup(entity) ? entity.groupID : 0;
3500
+ utils.assertNumber(value);
3501
+ const sceneid = value;
3502
+ await entity.command('genScenes', 'recall', { groupid, sceneid }, utils.getOptions(meta.mapped, entity));
3503
+ const addColorMode = (newState) => {
3504
+ if (newState.color_temp !== undefined) {
3505
+ newState.color_mode = constants.colorModeLookup[2];
3506
+ }
3507
+ else if (newState.color !== undefined) {
3508
+ if (newState.color.x !== undefined) {
3509
+ newState.color_mode = constants.colorModeLookup[1];
3510
+ }
3511
+ else {
3512
+ newState.color_mode = constants.colorModeLookup[0];
3513
+ }
3514
+ }
3515
+ return newState;
3516
+ };
3517
+ if (utils.isGroup(entity)) {
3518
+ const membersState = {};
3519
+ for (const member of entity.members) {
3520
+ let recalledState = utils.getSceneState(member, sceneid, groupid);
3521
+ if (recalledState) {
3522
+ // add color_mode if saved state does not contain it
3523
+ if (recalledState.color_mode === undefined) {
3524
+ recalledState = addColorMode(recalledState);
3525
+ }
3526
+ Object.assign(recalledState, libColor.syncColorState(recalledState, meta.state, entity, meta.options));
3527
+ membersState[member.getDevice().ieeeAddr] = recalledState;
3528
+ }
3529
+ else {
3530
+ logger_1.logger.warning(`Unknown scene was recalled for ${member.getDevice().ieeeAddr}, can't restore state.`, NS);
3531
+ membersState[member.getDevice().ieeeAddr] = {};
3532
+ }
3533
+ }
3534
+ logger_1.logger.info('Successfully recalled group scene', NS);
3535
+ return { membersState };
3536
+ }
3537
+ else {
3538
+ let recalledState = utils.getSceneState(entity, sceneid, groupid);
3539
+ if (recalledState) {
3540
+ // add color_mode if saved state does not contain it
3541
+ if (recalledState.color_mode === undefined) {
3542
+ recalledState = addColorMode(recalledState);
3543
+ }
3544
+ Object.assign(recalledState, libColor.syncColorState(recalledState, meta.state, entity, meta.options));
3545
+ logger_1.logger.info('Successfully recalled scene', NS);
3546
+ return { state: recalledState };
3547
+ }
3548
+ else {
3549
+ logger_1.logger.warning(`Unknown scene was recalled for ${entity.deviceIeeeAddress}, can't restore state.`, NS);
3550
+ return { state: {} };
3551
+ }
3552
+ }
3553
+ },
3554
+ },
3555
+ scene_add: {
3556
+ key: ['scene_add'],
3557
+ convertSet: async (entity, key, value, meta) => {
3558
+ utils.assertObject(value);
3559
+ utils.assertNumber(value.ID, 'ID');
3560
+ if (value.color_temp != undefined && value.color != undefined) {
3561
+ throw new Error(`Don't specify both 'color_temp' and 'color'`);
3562
+ }
3563
+ const isGroup = utils.isGroup(entity);
3564
+ const groupid = isGroup ? entity.groupID : value.group_id != undefined ? value.group_id : 0;
3565
+ const sceneid = value.ID;
3566
+ const scenename = value.name;
3567
+ const transtime = value.transition != undefined ? value.transition : 0;
3568
+ if (groupid === 0 && sceneid === 0) {
3569
+ // From Zigbee spec:
3570
+ // "Scene identifier 0x00, along with group identifier 0x0000, is reserved for the global scene used by the OnOff cluster"
3571
+ throw new Error('Scene ID 0 cannot be used with group ID 0 (reserved).');
3572
+ }
3573
+ const state = {};
3574
+ const extensionfieldsets = [];
3575
+ for (const attribute of Object.keys(value)) {
3576
+ let val = value[attribute];
3577
+ if (attribute === 'state') {
3578
+ extensionfieldsets.push({ clstId: 6, len: 1, extField: [val.toLowerCase() === 'on' ? 1 : 0] });
3579
+ state['state'] = val.toUpperCase();
3580
+ }
3581
+ else if (attribute === 'brightness') {
3582
+ extensionfieldsets.push({ clstId: 8, len: 1, extField: [val] });
3583
+ state['brightness'] = val;
3584
+ }
3585
+ else if (attribute === 'position') {
3586
+ const invert = utils.getMetaValue(entity, meta.mapped, 'coverInverted', 'allEqual', false)
3587
+ ? !meta.options.invert_cover
3588
+ : meta.options.invert_cover;
3589
+ extensionfieldsets.push({ clstId: 258, len: 1, extField: [invert ? 100 - val : val] });
3590
+ state['position'] = val;
3591
+ }
3592
+ else if (attribute === 'color_temp') {
3593
+ /*
3594
+ * ZCL version 7 added support for ColorTemperatureMireds
3595
+ *
3596
+ * Currently no devices seem to support this, so always fallback to XY conversion. In the future if a device
3597
+ * supports this, or other features get added this the following commit contains an implementation:
3598
+ * https://github.com/Koenkk/zigbee-herdsman-converters/pull/1837/commits/c22175b946b83230ce4e711c2a3796cf2029e78f
3599
+ *
3600
+ * Conversion to XY is allowed according to the ZCL:
3601
+ * `Since there is a direct relation between ColorTemperatureMireds and XY,
3602
+ * color temperature, if supported, is stored as XY in the scenes table.`
3603
+ *
3604
+ * See https://github.com/Koenkk/zigbee2mqtt/issues/4926#issuecomment-735947705
3605
+ */
3606
+ const [colorTempMin, colorTempMax] = light.findColorTempRange(entity);
3607
+ val = light.clampColorTemp(val, colorTempMin, colorTempMax);
3608
+ const xy = libColor.ColorXY.fromMireds(val);
3609
+ const xScaled = utils.mapNumberRange(xy.x, 0, 1, 0, 65535);
3610
+ const yScaled = utils.mapNumberRange(xy.y, 0, 1, 0, 65535);
3611
+ extensionfieldsets.push({ clstId: 768, len: 4, extField: [xScaled, yScaled] });
3612
+ state['color_mode'] = constants.colorModeLookup[2];
3613
+ state['color_temp'] = val;
3614
+ }
3615
+ else if (attribute === 'color') {
3616
+ try {
3617
+ val = JSON.parse(val);
3618
+ }
3619
+ catch {
3620
+ /* empty */
3621
+ }
3622
+ const newColor = libColor.Color.fromConverterArg(val);
3623
+ if (newColor.isXY()) {
3624
+ const xScaled = utils.mapNumberRange(newColor.xy.x, 0, 1, 0, 65535);
3625
+ const yScaled = utils.mapNumberRange(newColor.xy.y, 0, 1, 0, 65535);
3626
+ extensionfieldsets.push({
3627
+ clstId: 768,
3628
+ len: 4,
3629
+ extField: [xScaled, yScaled],
3630
+ });
3631
+ state['color_mode'] = constants.colorModeLookup[1];
3632
+ state['color'] = newColor.xy.toObject();
3633
+ }
3634
+ else if (newColor.isHSV()) {
3635
+ const hsvCorrected = newColor.hsv.colorCorrected(meta);
3636
+ if (utils.getMetaValue(entity, meta.mapped, 'supportsEnhancedHue', 'allEqual', true)) {
3637
+ const hScaled = utils.mapNumberRange(hsvCorrected.hue, 0, 360, 0, 65535);
3638
+ const sScaled = utils.mapNumberRange(hsvCorrected.saturation, 0, 100, 0, 254);
3639
+ extensionfieldsets.push({
3640
+ clstId: 768,
3641
+ len: 13,
3642
+ extField: [0, 0, hScaled, sScaled, 0, 0, 0, 0],
3643
+ });
3644
+ }
3645
+ else {
3646
+ // The extensionFieldSet is always EnhancedCurrentHue according to ZCL
3647
+ // When the bulb or all bulbs in a group do not support enhanchedHue,
3648
+ const colorXY = hsvCorrected.toXY();
3649
+ const xScaled = utils.mapNumberRange(colorXY.x, 0, 1, 0, 65535);
3650
+ const yScaled = utils.mapNumberRange(colorXY.y, 0, 1, 0, 65535);
3651
+ extensionfieldsets.push({
3652
+ clstId: 768,
3653
+ len: 4,
3654
+ extField: [xScaled, yScaled],
3655
+ });
3656
+ }
3657
+ state['color_mode'] = constants.colorModeLookup[0];
3658
+ state['color'] = newColor.hsv.toObject(false, false);
3659
+ }
3660
+ }
3661
+ }
3662
+ /*
3663
+ * Remove scene first
3664
+ *
3665
+ * Multiple add scene calls will result in the current and previous
3666
+ * payloads to be merged. Resulting in unexpected behavior when
3667
+ * trying to replace a scene.
3668
+ *
3669
+ * We accept a SUCCESS or NOT_FOUND as a result of the remove call.
3670
+ */
3671
+ const removeresp = await entity.command('genScenes', 'remove', { groupid, sceneid }, utils.getOptions(meta.mapped, entity));
3672
+ if (isGroup || (utils.isObject(removeresp) && (removeresp.status === 0 || removeresp.status == 133 || removeresp.status == 139))) {
3673
+ const addSceneCommand = Number.isInteger(transtime) ? 'add' : 'enhancedAdd';
3674
+ const commandTransitionTime = addSceneCommand === 'enhancedAdd' ? Math.floor(transtime * 10) : transtime;
3675
+ const response = await entity.command('genScenes', addSceneCommand, { groupid, sceneid, scenename: '', transtime: commandTransitionTime, extensionfieldsets }, utils.getOptions(meta.mapped, entity));
3676
+ if (isGroup) {
3677
+ if (meta.membersState) {
3678
+ for (const member of entity.members) {
3679
+ utils.saveSceneState(member, sceneid, groupid, state, scenename);
3680
+ }
3681
+ }
3682
+ }
3683
+ else {
3684
+ utils.assertObject(response);
3685
+ if (response.status === 0) {
3686
+ utils.saveSceneState(entity, sceneid, groupid, state, scenename);
3687
+ }
3688
+ else {
3689
+ throw new Error(`Scene add not successful ('${zigbee_herdsman_1.Zcl.Status[response.status]}')`);
3690
+ }
3691
+ }
3692
+ }
3693
+ else {
3694
+ const status = utils.isObject(removeresp) ? zigbee_herdsman_1.Zcl.Status[removeresp.status] : 'unknown';
3695
+ throw new Error(`Scene add unable to remove existing scene ('${status}')`);
3696
+ }
3697
+ logger_1.logger.info('Successfully added scene', NS);
3698
+ return { state: {} };
3699
+ },
3700
+ },
3701
+ scene_remove: {
3702
+ key: ['scene_remove'],
3703
+ convertSet: async (entity, key, value, meta) => {
3704
+ const isGroup = utils.isGroup(entity);
3705
+ utils.assertNumber(value);
3706
+ const groupid = isGroup ? entity.groupID : 0;
3707
+ const sceneid = value;
3708
+ const response = await entity.command('genScenes', 'remove', { groupid, sceneid }, utils.getOptions(meta.mapped, entity));
3709
+ if (isGroup) {
3710
+ if (meta.membersState) {
3711
+ for (const member of entity.members) {
3712
+ utils.deleteSceneState(member, sceneid, groupid);
3713
+ }
3714
+ }
3715
+ // @ts-expect-error ignore
3716
+ }
3717
+ else if (response.status === 0) {
3718
+ utils.deleteSceneState(entity, sceneid, groupid);
3719
+ }
3720
+ else {
3721
+ // @ts-expect-error ignore
3722
+ throw new Error(`Scene remove not successful ('${zigbee_herdsman_1.Zcl.Status[response.status]}')`);
3723
+ }
3724
+ logger_1.logger.info('Successfully removed scene', NS);
3725
+ },
3726
+ },
3727
+ scene_remove_all: {
3728
+ key: ['scene_remove_all'],
3729
+ convertSet: async (entity, key, value, meta) => {
3730
+ const groupid = utils.isGroup(entity) ? entity.groupID : 0;
3731
+ const response = await entity.command('genScenes', 'removeAll', { groupid }, utils.getOptions(meta.mapped, entity));
3732
+ utils.assertObject(response);
3733
+ if (utils.isGroup(entity)) {
3734
+ if (meta.membersState) {
3735
+ for (const member of entity.members) {
3736
+ utils.deleteSceneState(member);
3737
+ }
3738
+ }
3739
+ }
3740
+ else if (response.status === 0) {
3741
+ utils.deleteSceneState(entity);
3742
+ }
3743
+ else {
3744
+ throw new Error(`Scene remove all not successful ('${zigbee_herdsman_1.Zcl.Status[response.status]}')`);
3745
+ }
3746
+ logger_1.logger.info('Successfully removed all scenes', NS);
3747
+ },
3748
+ },
3749
+ scene_rename: {
3750
+ key: ['scene_rename'],
3751
+ convertSet: async (entity, key, value, meta) => {
3752
+ utils.assertObject(value);
3753
+ const isGroup = utils.isGroup(entity);
3754
+ const sceneid = value.ID;
3755
+ const scenename = value.name;
3756
+ const groupid = isGroup ? entity.groupID : value.group_id !== undefined ? value.group_id : 0;
3757
+ if (isGroup) {
3758
+ if (meta.membersState) {
3759
+ for (const member of entity.members) {
3760
+ const state = utils.getSceneState(member, sceneid, groupid);
3761
+ if (state) {
3762
+ utils.saveSceneState(member, sceneid, groupid, state, scenename);
3763
+ }
3764
+ }
3765
+ }
3766
+ }
3767
+ else {
3768
+ const state = utils.getSceneState(entity, sceneid, groupid);
3769
+ if (!state) {
3770
+ throw new Error(`No such scene in device meta data`);
3771
+ }
3772
+ utils.saveSceneState(entity, sceneid, groupid, state, scenename);
3773
+ }
3774
+ logger_1.logger.info('Successfully renamed scene', NS);
3775
+ },
3776
+ },
3777
+ TS0003_curtain_switch: {
3778
+ key: ['state'],
3779
+ convertSet: async (entity, key, value, meta) => {
3780
+ utils.assertString(value, key);
3781
+ utils.assertEndpoint(entity);
3782
+ const lookup = { close: 1, stop: 2, open: 1 };
3783
+ value = value.toLowerCase();
3784
+ utils.validateValue(value, Object.keys(lookup));
3785
+ const endpointID = utils.getFromLookup(value, lookup);
3786
+ const endpoint = entity.getDevice().getEndpoint(endpointID);
3787
+ await endpoint.command('genOnOff', 'on', {}, utils.getOptions(meta.mapped, entity));
3788
+ },
3789
+ convertGet: async (entity, key, meta) => {
3790
+ await entity.read('genOnOff', ['onOff']);
3791
+ },
3792
+ },
3793
+ ts0216_duration: {
3794
+ key: ['duration'],
3795
+ convertSet: async (entity, key, value, meta) => {
3796
+ await entity.write('ssIasWd', { maxDuration: value });
3797
+ },
3798
+ convertGet: async (entity, key, meta) => {
3799
+ await entity.read('ssIasWd', ['maxDuration']);
3800
+ },
3801
+ },
3802
+ ts0216_volume: {
3803
+ key: ['volume'],
3804
+ convertSet: async (entity, key, value, meta) => {
3805
+ utils.assertNumber(value);
3806
+ await entity.write('ssIasWd', { 0x0002: { value: utils.mapNumberRange(value, 0, 100, 100, 10), type: 0x20 } });
3807
+ },
3808
+ convertGet: async (entity, key, meta) => {
3809
+ await entity.read('ssIasWd', [0x0002]);
3810
+ },
3811
+ },
3812
+ ts0216_alarm: {
3813
+ key: ['alarm'],
3814
+ convertSet: async (entity, key, value, meta) => {
3815
+ const info = value ? (2 << 4) + (1 << 2) + 0 : 0;
3816
+ await entity.command('ssIasWd', 'startWarning', { startwarninginfo: info, warningduration: 0, strobedutycycle: 0, strobelevel: 3 }, utils.getOptions(meta.mapped, entity));
3817
+ },
3818
+ },
3819
+ tuya_cover_calibration: {
3820
+ key: ['calibration', 'calibration_up', 'calibration_down'],
3821
+ convertSet: async (entity, key, value, meta) => {
3822
+ utils.assertString(value, key);
3823
+ const lookup = { ON: 0, OFF: 1 };
3824
+ value = value.toUpperCase();
3825
+ const calibration = utils.getFromLookup(value, lookup);
3826
+ switch (key) {
3827
+ case 'calibration':
3828
+ case 'calibration_up':
3829
+ await entity.write('closuresWindowCovering', { tuyaCalibration: calibration });
3830
+ break;
3831
+ case 'calibration_down':
3832
+ await meta.device.getEndpoint(2).write('closuresWindowCovering', { tuyaCalibration: calibration });
3833
+ break;
3834
+ }
3835
+ return { state: { [key]: value } };
3836
+ },
3837
+ convertGet: async (entity, key, meta) => {
3838
+ switch (key) {
3839
+ case 'calibration':
3840
+ case 'calibration_up':
3841
+ await entity.read('closuresWindowCovering', ['tuyaCalibration']);
3842
+ break;
3843
+ case 'calibration_down':
3844
+ await meta.device.getEndpoint(2).read('closuresWindowCovering', ['tuyaCalibration']);
3845
+ break;
3846
+ }
3847
+ },
3848
+ },
3849
+ tuya_cover_reversal: {
3850
+ key: ['motor_reversal'],
3851
+ convertSet: async (entity, key, value, meta) => {
3852
+ utils.assertString(value, key);
3853
+ const lookup = { ON: 1, OFF: 0 };
3854
+ value = value.toUpperCase();
3855
+ const reversal = utils.getFromLookup(value, lookup);
3856
+ await entity.write('closuresWindowCovering', { tuyaMotorReversal: reversal });
3857
+ return { state: { motor_reversal: value } };
3858
+ },
3859
+ convertGet: async (entity, key, meta) => {
3860
+ await entity.read('closuresWindowCovering', ['tuyaMotorReversal']);
3861
+ },
3862
+ },
3863
+ moes_cover_calibration: {
3864
+ key: ['calibration_time'],
3865
+ convertSet: async (entity, key, value, meta) => {
3866
+ utils.assertNumber(value);
3867
+ const calibration = value * 10;
3868
+ await entity.write('closuresWindowCovering', { moesCalibrationTime: calibration });
3869
+ return { state: { calibration_time: value } };
3870
+ },
3871
+ convertGet: async (entity, key, meta) => {
3872
+ await entity.read('closuresWindowCovering', ['moesCalibrationTime']);
3873
+ },
3874
+ },
3875
+ ZM35HQ_attr: {
3876
+ key: ['sensitivity', 'keep_time'],
3877
+ convertSet: async (entity, key, value, meta) => {
3878
+ switch (key) {
3879
+ case 'sensitivity':
3880
+ await entity.write('ssIasZone', { currentZoneSensitivityLevel: utils.getFromLookup(value, { low: 0, medium: 1, high: 2 }) });
3881
+ break;
3882
+ case 'keep_time':
3883
+ await entity.write('ssIasZone', { 61441: { value: utils.getFromLookup(value, { 30: 0, 60: 1, 120: 2 }), type: 0x20 } });
3884
+ break;
3885
+ default: // Unknown key
3886
+ throw new Error(`Unhandled key ${key}`);
3887
+ }
3888
+ },
3889
+ convertGet: async (entity, key, meta) => {
3890
+ // Apparently, reading values may interfere with a commandStatusChangeNotification for changed occupancy.
3891
+ // Therefore, read "zoneStatus" as well.
3892
+ await entity.read('ssIasZone', ['currentZoneSensitivityLevel', 61441, 'zoneStatus']);
3893
+ },
3894
+ },
3895
+ TS0210_sensitivity: {
3896
+ key: ['sensitivity'],
3897
+ convertSet: async (entity, key, value, meta) => {
3898
+ value = utils.toNumber(value, 'sensitivity');
3899
+ await entity.write('ssIasZone', { currentZoneSensitivityLevel: value });
3900
+ return { state: { sensitivity: value } };
3901
+ },
3902
+ },
3903
+ viessmann_window_open: {
3904
+ key: ['window_open'],
3905
+ convertGet: async (entity, key, meta) => {
3906
+ await entity.read('hvacThermostat', ['viessmannWindowOpenInternal'], manufacturerOptions.viessmann);
3907
+ },
3908
+ },
3909
+ viessmann_window_open_force: {
3910
+ key: ['window_open_force'],
3911
+ convertSet: async (entity, key, value, meta) => {
3912
+ if (typeof value === 'boolean') {
3913
+ await entity.write('hvacThermostat', { viessmannWindowOpenForce: value }, manufacturerOptions.viessmann);
3914
+ return { state: { window_open_force: value } };
3915
+ }
3916
+ else {
3917
+ logger_1.logger.error('window_open_force must be a boolean!', NS);
3918
+ }
3919
+ },
3920
+ convertGet: async (entity, key, meta) => {
3921
+ await entity.read('hvacThermostat', ['viessmannWindowOpenForce'], manufacturerOptions.viessmann);
3922
+ },
3923
+ },
3924
+ viessmann_assembly_mode: {
3925
+ key: ['assembly_mode'],
3926
+ convertGet: async (entity, key, meta) => {
3927
+ await entity.read('hvacThermostat', ['viessmannAssemblyMode'], manufacturerOptions.viessmann);
3928
+ },
3929
+ },
3930
+ dawondns_only_off: {
3931
+ key: ['state'],
3932
+ convertSet: async (entity, key, value, meta) => {
3933
+ utils.assertString(value, key);
3934
+ value = value.toLowerCase();
3935
+ utils.assertString(value, key);
3936
+ utils.validateValue(value, ['off']);
3937
+ await entity.command('genOnOff', value, {}, utils.getOptions(meta.mapped, entity));
3938
+ },
3939
+ convertGet: async (entity, key, meta) => {
3940
+ await entity.read('genOnOff', ['onOff']);
3941
+ },
3942
+ },
3943
+ idlock_master_pin_mode: {
3944
+ key: ['master_pin_mode'],
3945
+ convertSet: async (entity, key, value, meta) => {
3946
+ await entity.write('closuresDoorLock', { 0x4000: { value: value === true ? 1 : 0, type: 0x10 } }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
3947
+ return { state: { master_pin_mode: value } };
3948
+ },
3949
+ convertGet: async (entity, key, meta) => {
3950
+ await entity.read('closuresDoorLock', [0x4000], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
3951
+ },
3952
+ },
3953
+ idlock_rfid_enable: {
3954
+ key: ['rfid_enable'],
3955
+ convertSet: async (entity, key, value, meta) => {
3956
+ await entity.write('closuresDoorLock', { 0x4001: { value: value === true ? 1 : 0, type: 0x10 } }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
3957
+ return { state: { rfid_enable: value } };
3958
+ },
3959
+ convertGet: async (entity, key, meta) => {
3960
+ await entity.read('closuresDoorLock', [0x4001], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
3961
+ },
3962
+ },
3963
+ idlock_service_mode: {
3964
+ key: ['service_mode'],
3965
+ convertSet: async (entity, key, value, meta) => {
3966
+ const lookup = { deactivated: 0, random_pin_1x_use: 5, random_pin_24_hours: 6 };
3967
+ await entity.write('closuresDoorLock', { 0x4003: { value: utils.getFromLookup(value, lookup), type: 0x20 } }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
3968
+ return { state: { service_mode: value } };
3969
+ },
3970
+ convertGet: async (entity, key, meta) => {
3971
+ await entity.read('closuresDoorLock', [0x4003], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
3972
+ },
3973
+ },
3974
+ idlock_lock_mode: {
3975
+ key: ['lock_mode'],
3976
+ convertSet: async (entity, key, value, meta) => {
3977
+ const lookup = { auto_off_away_off: 0, auto_on_away_off: 1, auto_off_away_on: 2, auto_on_away_on: 3 };
3978
+ await entity.write('closuresDoorLock', { 0x4004: { value: utils.getFromLookup(value, lookup), type: 0x20 } }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
3979
+ return { state: { lock_mode: value } };
3980
+ },
3981
+ convertGet: async (entity, key, meta) => {
3982
+ await entity.read('closuresDoorLock', [0x4004], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
3983
+ },
3984
+ },
3985
+ idlock_relock_enabled: {
3986
+ key: ['relock_enabled'],
3987
+ convertSet: async (entity, key, value, meta) => {
3988
+ await entity.write('closuresDoorLock', { 0x4005: { value: value === true ? 1 : 0, type: 0x10 } }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
3989
+ return { state: { relock_enabled: value } };
3990
+ },
3991
+ convertGet: async (entity, key, meta) => {
3992
+ await entity.read('closuresDoorLock', [0x4005], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
3993
+ },
3994
+ },
3995
+ schneider_pilot_mode: {
3996
+ key: ['schneider_pilot_mode'],
3997
+ convertSet: async (entity, key, value, meta) => {
3998
+ utils.assertString(value, key);
3999
+ const lookup = { contactor: 1, pilot: 3 };
4000
+ value = value.toLowerCase();
4001
+ const mode = utils.getFromLookup(value, lookup);
4002
+ await entity.write('schneiderSpecificPilotMode', { pilotMode: mode }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.SCHNEIDER_ELECTRIC });
4003
+ return { state: { schneider_pilot_mode: value } };
4004
+ },
4005
+ convertGet: async (entity, key, meta) => {
4006
+ await entity.read('schneiderSpecificPilotMode', ['pilotMode'], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.SCHNEIDER_ELECTRIC });
4007
+ },
4008
+ },
4009
+ schneider_dimmer_mode: {
4010
+ key: ['dimmer_mode'],
4011
+ convertSet: async (entity, key, value, meta) => {
4012
+ const lookup = { RC: 1, RL: 2 };
4013
+ const mode = utils.getFromLookup(value, lookup);
4014
+ await entity.write('lightingBallastCfg', { 0xe000: { value: mode, type: 0x30 } }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.SCHNEIDER_ELECTRIC });
4015
+ return { state: { dimmer_mode: value } };
4016
+ },
4017
+ convertGet: async (entity, key, meta) => {
4018
+ await entity.read('lightingBallastCfg', [0xe000], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.SCHNEIDER_ELECTRIC });
4019
+ },
4020
+ },
4021
+ wiser_dimmer_mode: {
4022
+ key: ['dimmer_mode'],
4023
+ convertSet: async (entity, key, value, meta) => {
4024
+ const controlMode = utils.getKey(constants.wiserDimmerControlMode, value, value, Number);
4025
+ await entity.write('lightingBallastCfg', { wiserControlMode: controlMode }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.SCHNEIDER_ELECTRIC });
4026
+ return { state: { dimmer_mode: value } };
4027
+ },
4028
+ convertGet: async (entity, key, meta) => {
4029
+ await entity.read('lightingBallastCfg', ['wiserControlMode'], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.SCHNEIDER_ELECTRIC });
4030
+ },
4031
+ },
4032
+ schneider_temperature_measured_value: {
4033
+ key: ['temperature_measured_value'],
4034
+ convertSet: async (entity, key, value, meta) => {
4035
+ utils.assertNumber(value);
4036
+ utils.assertEndpoint(entity);
4037
+ await entity.report('msTemperatureMeasurement', { measuredValue: Math.round(value * 100) });
4038
+ },
4039
+ },
4040
+ schneider_thermostat_system_mode: {
4041
+ key: ['system_mode'],
4042
+ convertSet: async (entity, key, value, meta) => {
4043
+ utils.assertEndpoint(entity);
4044
+ const systemMode = utils.getKey(constants.thermostatSystemModes, value, undefined, Number);
4045
+ entity.saveClusterAttributeKeyValue('hvacThermostat', { systemMode: systemMode });
4046
+ return { state: { system_mode: value } };
4047
+ },
4048
+ },
4049
+ schneider_thermostat_occupied_heating_setpoint: {
4050
+ key: ['occupied_heating_setpoint'],
4051
+ convertSet: async (entity, key, value, meta) => {
4052
+ utils.assertNumber(value, key);
4053
+ utils.assertEndpoint(entity);
4054
+ const occupiedHeatingSetpoint = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
4055
+ entity.saveClusterAttributeKeyValue('hvacThermostat', { occupiedHeatingSetpoint: occupiedHeatingSetpoint });
4056
+ return { state: { occupied_heating_setpoint: value } };
4057
+ },
4058
+ },
4059
+ schneider_thermostat_control_sequence_of_operation: {
4060
+ key: ['control_sequence_of_operation'],
4061
+ convertSet: async (entity, key, value, meta) => {
4062
+ utils.assertEndpoint(entity);
4063
+ const val = utils.getKey(constants.thermostatControlSequenceOfOperations, value, value, Number);
4064
+ entity.saveClusterAttributeKeyValue('hvacThermostat', { ctrlSeqeOfOper: val });
4065
+ return { state: { control_sequence_of_operation: value } };
4066
+ },
4067
+ },
4068
+ schneider_thermostat_pi_heating_demand: {
4069
+ key: ['pi_heating_demand'],
4070
+ convertSet: async (entity, key, value, meta) => {
4071
+ utils.assertEndpoint(entity);
4072
+ entity.saveClusterAttributeKeyValue('hvacThermostat', { pIHeatingDemand: value });
4073
+ return { state: { pi_heating_demand: value } };
4074
+ },
4075
+ },
4076
+ schneider_thermostat_keypad_lockout: {
4077
+ key: ['keypad_lockout'],
4078
+ convertSet: async (entity, key, value, meta) => {
4079
+ utils.assertEndpoint(entity);
4080
+ const keypadLockout = utils.getKey(constants.keypadLockoutMode, value, value, Number);
4081
+ await entity.write('hvacUserInterfaceCfg', { keypadLockout });
4082
+ entity.saveClusterAttributeKeyValue('hvacUserInterfaceCfg', { keypadLockout });
4083
+ return { state: { keypad_lockout: value } };
4084
+ },
4085
+ },
4086
+ wiser_fip_setting: {
4087
+ key: ['fip_setting'],
4088
+ convertSet: async (entity, key, value, meta) => {
4089
+ utils.assertString(value, key);
4090
+ const zoneLookup = { manual: 1, schedule: 2, energy_saver: 3, holiday: 6 };
4091
+ const zonemodeNum = utils.getFromLookup(meta.state.zone_mode, zoneLookup);
4092
+ const fipLookup = { comfort: 0, 'comfort_-1': 1, 'comfort_-2': 2, energy_saving: 3, frost_protection: 4, off: 5 };
4093
+ value = value.toLowerCase();
4094
+ utils.validateValue(value, Object.keys(fipLookup));
4095
+ const fipmodeNum = utils.getFromLookup(value, fipLookup);
4096
+ const payload = {
4097
+ zonemode: zonemodeNum,
4098
+ fipmode: fipmodeNum,
4099
+ reserved: 0xff,
4100
+ };
4101
+ await entity.command('hvacThermostat', 'wiserSmartSetFipMode', payload, { srcEndpoint: 11, disableDefaultResponse: true });
4102
+ return { state: { fip_setting: value } };
4103
+ },
4104
+ convertGet: async (entity, key, meta) => {
4105
+ await entity.read('hvacThermostat', [0xe020]);
4106
+ },
4107
+ },
4108
+ wiser_hact_config: {
4109
+ key: ['hact_config'],
4110
+ convertSet: async (entity, key, value, meta) => {
4111
+ utils.assertString(value, key);
4112
+ const lookup = { unconfigured: 0x00, setpoint_switch: 0x80, setpoint_fip: 0x82, fip_fip: 0x83 };
4113
+ value = value.toLowerCase();
4114
+ const mode = utils.getFromLookup(value, lookup);
4115
+ await entity.write('hvacThermostat', { 0xe011: { value: mode, type: 0x18 } });
4116
+ return { state: { hact_config: value } };
4117
+ },
4118
+ convertGet: async (entity, key, meta) => {
4119
+ await entity.read('hvacThermostat', [0xe011]);
4120
+ },
4121
+ },
4122
+ wiser_zone_mode: {
4123
+ key: ['zone_mode'],
4124
+ convertSet: async (entity, key, value, meta) => {
4125
+ const lookup = { manual: 1, schedule: 2, energy_saver: 3, holiday: 6 };
4126
+ const zonemodeNum = utils.getFromLookup(value, lookup);
4127
+ await entity.write('hvacThermostat', { 0xe010: { value: zonemodeNum, type: 0x30 } });
4128
+ return { state: { zone_mode: value } };
4129
+ },
4130
+ convertGet: async (entity, key, meta) => {
4131
+ await entity.read('hvacThermostat', [0xe010]);
4132
+ },
4133
+ },
4134
+ wiser_vact_calibrate_valve: {
4135
+ key: ['calibrate_valve'],
4136
+ convertSet: async (entity, key, value, meta) => {
4137
+ await entity.command('hvacThermostat', 'wiserSmartCalibrateValve', {}, { srcEndpoint: 11, disableDefaultResponse: true });
4138
+ return { state: { calibrate_valve: value } };
4139
+ },
4140
+ },
4141
+ wiser_sed_zone_mode: {
4142
+ key: ['zone_mode'],
4143
+ convertSet: async (entity, key, value, meta) => {
4144
+ return { state: { zone_mode: value } };
4145
+ },
4146
+ },
4147
+ wiser_sed_occupied_heating_setpoint: {
4148
+ key: ['occupied_heating_setpoint'],
4149
+ convertSet: async (entity, key, value, meta) => {
4150
+ utils.assertNumber(value, key);
4151
+ utils.assertEndpoint(entity);
4152
+ const occupiedHeatingSetpoint = Number((Math.round(Number((value * 2).toFixed(1))) / 2).toFixed(1)) * 100;
4153
+ entity.saveClusterAttributeKeyValue('hvacThermostat', { occupiedHeatingSetpoint });
4154
+ return { state: { occupied_heating_setpoint: value } };
4155
+ },
4156
+ },
4157
+ wiser_sed_thermostat_local_temperature_calibration: {
4158
+ key: ['local_temperature_calibration'],
4159
+ convertSet: async (entity, key, value, meta) => {
4160
+ utils.assertNumber(value);
4161
+ await entity.write('hvacThermostat', { localTemperatureCalibration: Math.round(value * 10) }, { srcEndpoint: 11, disableDefaultResponse: true });
4162
+ return { state: { local_temperature_calibration: value } };
4163
+ },
4164
+ },
4165
+ wiser_sed_thermostat_keypad_lockout: {
4166
+ key: ['keypad_lockout'],
4167
+ convertSet: async (entity, key, value, meta) => {
4168
+ const keypadLockout = utils.getKey(constants.keypadLockoutMode, value, value, Number);
4169
+ await entity.write('hvacUserInterfaceCfg', { keypadLockout }, { srcEndpoint: 11, disableDefaultResponse: true });
4170
+ return { state: { keypad_lockout: value } };
4171
+ },
4172
+ },
4173
+ sihas_set_people: {
4174
+ key: ['people'],
4175
+ convertSet: async (entity, key, value, meta) => {
4176
+ const payload = { presentValue: value };
4177
+ const endpoint = meta.device.endpoints.find((e) => e.supportsInputCluster('genAnalogInput'));
4178
+ await endpoint.write('genAnalogInput', payload);
4179
+ },
4180
+ convertGet: async (entity, key, meta) => {
4181
+ const endpoint = meta.device.endpoints.find((e) => e.supportsInputCluster('genAnalogInput'));
4182
+ await endpoint.read('genAnalogInput', ['presentValue']);
4183
+ },
4184
+ },
4185
+ tuya_operation_mode: {
4186
+ key: ['operation_mode'],
4187
+ convertSet: async (entity, key, value, meta) => {
4188
+ // modes:
4189
+ // 0 - 'command' mode. keys send commands. useful for group control
4190
+ // 1 - 'event' mode. keys send events. useful for handling
4191
+ utils.assertString(value, key);
4192
+ const endpoint = meta.device.getEndpoint(1);
4193
+ await endpoint.write('genOnOff', { tuyaOperationMode: utils.getFromLookup(value, { command: 0, event: 1 }) });
4194
+ return { state: { operation_mode: value.toLowerCase() } };
4195
+ },
4196
+ convertGet: async (entity, key, meta) => {
4197
+ const endpoint = meta.device.getEndpoint(1);
4198
+ await endpoint.read('genOnOff', ['tuyaOperationMode']);
4199
+ },
4200
+ },
4201
+ led_on_motion: {
4202
+ key: ['led_on_motion'],
4203
+ convertSet: async (entity, key, value, meta) => {
4204
+ await entity.write('ssIasZone', { 0x4000: { value: value === true ? 1 : 0, type: 0x10 } }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
4205
+ return { state: { led_on_motion: value } };
4206
+ },
4207
+ convertGet: async (entity, key, meta) => {
4208
+ await entity.read('ssIasZone', [0x4000], { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.DATEK_WIRELESS_AS });
4209
+ },
4210
+ },
4211
+ nodon_pilot_wire_mode: {
4212
+ key: ['pilot_wire_mode'],
4213
+ convertSet: async (entity, key, value, meta) => {
4214
+ const mode = utils.getFromLookup(value, {
4215
+ off: 0x00,
4216
+ comfort: 0x01,
4217
+ eco: 0x02,
4218
+ frost_protection: 0x03,
4219
+ 'comfort_-1': 0x04,
4220
+ 'comfort_-2': 0x05,
4221
+ });
4222
+ const payload = { mode: mode };
4223
+ await entity.command('manuSpecificNodOnPilotWire', 'setMode', payload);
4224
+ return { state: { pilot_wire_mode: value } };
4225
+ },
4226
+ convertGet: async (entity, key, meta) => {
4227
+ await entity.read('manuSpecificNodOnPilotWire', [0x0000], manufacturerOptions.nodon);
4228
+ },
4229
+ },
4230
+ // #endregion
4231
+ // #region Ignore converters
4232
+ ignore_transition: {
4233
+ key: ['transition'],
4234
+ convertSet: async (entity, key, value, meta) => { },
4235
+ },
4236
+ ignore_rate: {
4237
+ key: ['rate'],
4238
+ convertSet: async (entity, key, value, meta) => { },
4239
+ },
4240
+ // #endregion
4241
+ // Not a converter, can be used by tests to clear the store.
4242
+ __clearStore__: () => {
4243
+ globalStore.clear();
4244
+ },
4245
+ };
4246
+ const converters3 = {
4247
+ light_onoff_restorable_brightness: {
4248
+ /**
4249
+ * Some devices reset brightness to 100% when turned on, even if previous brightness was different
4250
+ * This uses the stored state of the device to restore to the previous brightness level when turning on
4251
+ */
4252
+ key: ['state', 'brightness', 'brightness_percent'],
4253
+ options: [exposes.options.transition()],
4254
+ convertSet: async (entity, key, value, meta) => {
4255
+ const deviceState = meta.state || {};
4256
+ const message = meta.message;
4257
+ const state = utils.isString(message.state) ? message.state.toLowerCase() : null;
4258
+ const hasBrightness = message.brightness !== undefined || message.brightness_percent !== undefined;
4259
+ // Add brightness if command is 'on' and we can restore previous value
4260
+ if (state === 'on' && !hasBrightness && utils.isNumber(deviceState.brightness) && deviceState.brightness > 0) {
4261
+ message.brightness = deviceState.brightness;
4262
+ }
4263
+ return await converters2.light_onoff_brightness.convertSet(entity, key, value, meta);
4264
+ },
4265
+ convertGet: async (entity, key, meta) => {
4266
+ return await converters2.light_onoff_brightness.convertGet(entity, key, meta);
4267
+ },
4268
+ },
4269
+ RM01_light_onoff_brightness: {
4270
+ key: ['state', 'brightness', 'brightness_percent'],
4271
+ options: [exposes.options.transition()],
4272
+ convertSet: async (entity, key, value, meta) => {
4273
+ if (utils.hasEndpoints(meta.device, [0x12])) {
4274
+ const endpoint = meta.device.getEndpoint(0x12);
4275
+ return await converters2.light_onoff_brightness.convertSet(endpoint, key, value, meta);
4276
+ }
4277
+ else {
4278
+ throw new Error('OnOff and LevelControl not supported on this RM01 device.');
4279
+ }
4280
+ },
4281
+ convertGet: async (entity, key, meta) => {
4282
+ if (utils.hasEndpoints(meta.device, [0x12])) {
4283
+ const endpoint = meta.device.getEndpoint(0x12);
4284
+ return await converters2.light_onoff_brightness.convertGet(endpoint, key, meta);
4285
+ }
4286
+ else {
4287
+ throw new Error('OnOff and LevelControl not supported on this RM01 device.');
4288
+ }
4289
+ },
4290
+ },
4291
+ RM01_light_brightness_step: {
4292
+ options: [exposes.options.transition()],
4293
+ key: ['brightness_step', 'brightness_step_onoff'],
4294
+ convertSet: async (entity, key, value, meta) => {
4295
+ if (utils.hasEndpoints(meta.device, [0x12])) {
4296
+ const endpoint = meta.device.getEndpoint(0x12);
4297
+ return await converters2.light_brightness_step.convertSet(endpoint, key, value, meta);
4298
+ }
4299
+ else {
4300
+ throw new Error('LevelControl not supported on this RM01 device.');
4301
+ }
4302
+ },
4303
+ },
4304
+ RM01_light_brightness_move: {
4305
+ key: ['brightness_move', 'brightness_move_onoff'],
4306
+ convertSet: async (entity, key, value, meta) => {
4307
+ if (utils.hasEndpoints(meta.device, [0x12])) {
4308
+ const endpoint = meta.device.getEndpoint(0x12);
4309
+ return await converters2.light_brightness_move.convertSet(endpoint, key, value, meta);
4310
+ }
4311
+ else {
4312
+ throw new Error('LevelControl not supported on this RM01 device.');
4313
+ }
4314
+ },
4315
+ },
4316
+ ptvo_switch_light_brightness: {
4317
+ key: ['brightness', 'brightness_percent', 'transition'],
4318
+ options: [exposes.options.transition()],
4319
+ convertSet: async (entity, key, value, meta) => {
4320
+ if (key === 'transition') {
4321
+ return;
4322
+ }
4323
+ const cluster = 'genLevelCtrl';
4324
+ utils.assertEndpoint(entity);
4325
+ if (entity.supportsInputCluster(cluster) || entity.supportsOutputCluster(cluster)) {
4326
+ const message = meta.message;
4327
+ let brightness = undefined;
4328
+ if (message.brightness !== undefined) {
4329
+ brightness = Number(message.brightness);
4330
+ }
4331
+ else if (message.brightness_percent !== undefined)
4332
+ brightness = Math.round(Number(message.brightness_percent) * 2.55);
4333
+ if (brightness !== undefined && brightness === 0) {
4334
+ message.state = 'off';
4335
+ message.brightness = 1;
4336
+ }
4337
+ return await converters2.light_onoff_brightness.convertSet(entity, key, value, meta);
4338
+ }
4339
+ else {
4340
+ throw new Error('LevelControl not supported on this endpoint.');
4341
+ }
4342
+ },
4343
+ convertGet: async (entity, key, meta) => {
4344
+ const cluster = 'genLevelCtrl';
4345
+ utils.assertEndpoint(entity);
4346
+ if (entity.supportsInputCluster(cluster) || entity.supportsOutputCluster(cluster)) {
4347
+ return await converters2.light_onoff_brightness.convertGet(entity, key, meta);
4348
+ }
4349
+ else {
4350
+ throw new Error('LevelControl not supported on this endpoint.');
4351
+ }
4352
+ },
4353
+ },
4354
+ TS110E_options: {
4355
+ key: ['min_brightness', 'max_brightness', 'light_type', 'switch_type'],
4356
+ convertSet: async (entity, key, value, meta) => {
4357
+ let payload = null;
4358
+ if (key === 'min_brightness' || key == 'max_brightness') {
4359
+ const id = key === 'min_brightness' ? 64515 : 64516;
4360
+ payload = { [id]: { value: utils.mapNumberRange(utils.toNumber(value, key), 1, 255, 0, 1000), type: 0x21 } };
4361
+ }
4362
+ else if (key === 'light_type' || key === 'switch_type') {
4363
+ utils.assertString(value, 'light_type/switch_type');
4364
+ const lookup = key === 'light_type' ? { led: 0, incandescent: 1, halogen: 2 } : { momentary: 0, toggle: 1, state: 2 };
4365
+ payload = { 64514: { value: lookup[value], type: 0x20 } };
4366
+ }
4367
+ await entity.write('genLevelCtrl', payload, utils.getOptions(meta.mapped, entity));
4368
+ return { state: { [key]: value } };
4369
+ },
4370
+ convertGet: async (entity, key, meta) => {
4371
+ let id = null;
4372
+ if (key === 'min_brightness')
4373
+ id = 64515;
4374
+ if (key === 'max_brightness')
4375
+ id = 64516;
4376
+ if (key === 'light_type' || key === 'switch_type')
4377
+ id = 64514;
4378
+ await entity.read('genLevelCtrl', [id]);
4379
+ },
4380
+ },
4381
+ TS110E_onoff_brightness: {
4382
+ key: ['state', 'brightness'],
4383
+ convertSet: async (entity, key, value, meta) => {
4384
+ const { message, state } = meta;
4385
+ if (message.state === 'OFF' || (message.state !== undefined && message.brightness === undefined)) {
4386
+ return await converters1.on_off.convertSet(entity, key, value, meta);
4387
+ }
4388
+ else if (message.brightness !== undefined) {
4389
+ // set brightness
4390
+ if (state.state === 'OFF') {
4391
+ await entity.command('genOnOff', 'on', {}, utils.getOptions(meta.mapped, entity));
4392
+ }
4393
+ const brightness = utils.toNumber(message.brightness, 'brightness');
4394
+ const level = utils.mapNumberRange(brightness, 0, 254, 0, 1000);
4395
+ await entity.command('genLevelCtrl', 'moveToLevelTuya', { level, transtime: 100 }, utils.getOptions(meta.mapped, entity));
4396
+ return { state: { state: 'ON', brightness } };
4397
+ }
4398
+ },
4399
+ convertGet: async (entity, key, meta) => {
4400
+ if (key === 'state')
4401
+ await converters1.on_off.convertGet(entity, key, meta);
4402
+ if (key === 'brightness')
4403
+ await entity.read('genLevelCtrl', [61440]);
4404
+ },
4405
+ },
4406
+ TS110E_light_onoff_brightness: {
4407
+ ...converters2.light_onoff_brightness,
4408
+ convertSet: async (entity, key, value, meta) => {
4409
+ const { message } = meta;
4410
+ if (message.state === 'ON' || (typeof message.brightness === 'number' && message.brightness > 1)) {
4411
+ // Does not turn off with physical press when turned on with just moveToLevelWithOnOff, required on before.
4412
+ // https://github.com/Koenkk/zigbee2mqtt/issues/15902#issuecomment-1382848150
4413
+ await entity.command('genOnOff', 'on', {}, utils.getOptions(meta.mapped, entity));
4414
+ }
4415
+ return await converters2.light_onoff_brightness.convertSet(entity, key, value, meta);
4416
+ },
4417
+ },
4418
+ };
4419
+ const converters = { ...converters1, ...converters2, ...converters3 };
4420
+ exports.default = converters;
4421
+ module.exports = converters;
4422
+ //# sourceMappingURL=toZigbee.js.map