@zwave-js/cc 9.3.1-0-pr-4662-79458fb

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 (297) hide show
  1. package/build/cc/AlarmSensorCC.d.ts +54 -0
  2. package/build/cc/AlarmSensorCC.d.ts.map +1 -0
  3. package/build/cc/AlarmSensorCC.js +378 -0
  4. package/build/cc/AlarmSensorCC.js.map +1 -0
  5. package/build/cc/AssociationCC.d.ts +123 -0
  6. package/build/cc/AssociationCC.d.ts.map +1 -0
  7. package/build/cc/AssociationCC.js +615 -0
  8. package/build/cc/AssociationCC.js.map +1 -0
  9. package/build/cc/AssociationGroupInfoCC.d.ts +97 -0
  10. package/build/cc/AssociationGroupInfoCC.d.ts.map +1 -0
  11. package/build/cc/AssociationGroupInfoCC.js +530 -0
  12. package/build/cc/AssociationGroupInfoCC.js.map +1 -0
  13. package/build/cc/BarrierOperatorCC.d.ts +75 -0
  14. package/build/cc/BarrierOperatorCC.d.ts.map +1 -0
  15. package/build/cc/BarrierOperatorCC.js +492 -0
  16. package/build/cc/BarrierOperatorCC.js.map +1 -0
  17. package/build/cc/BasicCC.d.ts +51 -0
  18. package/build/cc/BasicCC.d.ts.map +1 -0
  19. package/build/cc/BasicCC.js +344 -0
  20. package/build/cc/BasicCC.js.map +1 -0
  21. package/build/cc/BatteryCC.d.ts +56 -0
  22. package/build/cc/BatteryCC.d.ts.map +1 -0
  23. package/build/cc/BatteryCC.js +417 -0
  24. package/build/cc/BatteryCC.js.map +1 -0
  25. package/build/cc/BinarySensorCC.d.ts +52 -0
  26. package/build/cc/BinarySensorCC.d.ts.map +1 -0
  27. package/build/cc/BinarySensorCC.js +321 -0
  28. package/build/cc/BinarySensorCC.js.map +1 -0
  29. package/build/cc/BinarySwitchCC.d.ts +55 -0
  30. package/build/cc/BinarySwitchCC.d.ts.map +1 -0
  31. package/build/cc/BinarySwitchCC.js +327 -0
  32. package/build/cc/BinarySwitchCC.js.map +1 -0
  33. package/build/cc/CRC16CC.d.ts +28 -0
  34. package/build/cc/CRC16CC.d.ts.map +1 -0
  35. package/build/cc/CRC16CC.js +109 -0
  36. package/build/cc/CRC16CC.js.map +1 -0
  37. package/build/cc/CentralSceneCC.d.ts +69 -0
  38. package/build/cc/CentralSceneCC.d.ts.map +1 -0
  39. package/build/cc/CentralSceneCC.js +443 -0
  40. package/build/cc/CentralSceneCC.js.map +1 -0
  41. package/build/cc/ClimateControlScheduleCC.d.ts +78 -0
  42. package/build/cc/ClimateControlScheduleCC.d.ts.map +1 -0
  43. package/build/cc/ClimateControlScheduleCC.js +417 -0
  44. package/build/cc/ClimateControlScheduleCC.js.map +1 -0
  45. package/build/cc/ClockCC.d.ts +40 -0
  46. package/build/cc/ClockCC.d.ts.map +1 -0
  47. package/build/cc/ClockCC.js +185 -0
  48. package/build/cc/ClockCC.js.map +1 -0
  49. package/build/cc/ColorSwitchCC.d.ts +98 -0
  50. package/build/cc/ColorSwitchCC.d.ts.map +1 -0
  51. package/build/cc/ColorSwitchCC.js +1045 -0
  52. package/build/cc/ColorSwitchCC.js.map +1 -0
  53. package/build/cc/ConfigurationCC.d.ts +315 -0
  54. package/build/cc/ConfigurationCC.d.ts.map +1 -0
  55. package/build/cc/ConfigurationCC.js +2257 -0
  56. package/build/cc/ConfigurationCC.js.map +1 -0
  57. package/build/cc/DeviceResetLocallyCC.d.ts +9 -0
  58. package/build/cc/DeviceResetLocallyCC.d.ts.map +1 -0
  59. package/build/cc/DeviceResetLocallyCC.js +28 -0
  60. package/build/cc/DeviceResetLocallyCC.js.map +1 -0
  61. package/build/cc/DoorLockCC.d.ts +116 -0
  62. package/build/cc/DoorLockCC.d.ts.map +1 -0
  63. package/build/cc/DoorLockCC.js +1112 -0
  64. package/build/cc/DoorLockCC.js.map +1 -0
  65. package/build/cc/DoorLockLoggingCC.d.ts +41 -0
  66. package/build/cc/DoorLockLoggingCC.d.ts.map +1 -0
  67. package/build/cc/DoorLockLoggingCC.js +288 -0
  68. package/build/cc/DoorLockLoggingCC.js.map +1 -0
  69. package/build/cc/EntryControlCC.d.ts +71 -0
  70. package/build/cc/EntryControlCC.d.ts.map +1 -0
  71. package/build/cc/EntryControlCC.js +492 -0
  72. package/build/cc/EntryControlCC.js.map +1 -0
  73. package/build/cc/FirmwareUpdateMetaDataCC.d.ts +148 -0
  74. package/build/cc/FirmwareUpdateMetaDataCC.d.ts.map +1 -0
  75. package/build/cc/FirmwareUpdateMetaDataCC.js +727 -0
  76. package/build/cc/FirmwareUpdateMetaDataCC.js.map +1 -0
  77. package/build/cc/HailCC.d.ts +6 -0
  78. package/build/cc/HailCC.d.ts.map +1 -0
  79. package/build/cc/HailCC.js +23 -0
  80. package/build/cc/HailCC.js.map +1 -0
  81. package/build/cc/HumidityControlModeCC.d.ts +47 -0
  82. package/build/cc/HumidityControlModeCC.d.ts.map +1 -0
  83. package/build/cc/HumidityControlModeCC.js +288 -0
  84. package/build/cc/HumidityControlModeCC.js.map +1 -0
  85. package/build/cc/HumidityControlOperatingStateCC.d.ts +24 -0
  86. package/build/cc/HumidityControlOperatingStateCC.d.ts.map +1 -0
  87. package/build/cc/HumidityControlOperatingStateCC.js +129 -0
  88. package/build/cc/HumidityControlOperatingStateCC.js.map +1 -0
  89. package/build/cc/HumidityControlSetpointCC.d.ts +103 -0
  90. package/build/cc/HumidityControlSetpointCC.d.ts.map +1 -0
  91. package/build/cc/HumidityControlSetpointCC.js +626 -0
  92. package/build/cc/HumidityControlSetpointCC.js.map +1 -0
  93. package/build/cc/IndicatorCC.d.ts +88 -0
  94. package/build/cc/IndicatorCC.d.ts.map +1 -0
  95. package/build/cc/IndicatorCC.js +758 -0
  96. package/build/cc/IndicatorCC.js.map +1 -0
  97. package/build/cc/IrrigationCC.d.ts +278 -0
  98. package/build/cc/IrrigationCC.d.ts.map +1 -0
  99. package/build/cc/IrrigationCC.js +2062 -0
  100. package/build/cc/IrrigationCC.js.map +1 -0
  101. package/build/cc/LanguageCC.d.ts +41 -0
  102. package/build/cc/LanguageCC.d.ts.map +1 -0
  103. package/build/cc/LanguageCC.js +220 -0
  104. package/build/cc/LanguageCC.js.map +1 -0
  105. package/build/cc/LockCC.d.ts +41 -0
  106. package/build/cc/LockCC.d.ts.map +1 -0
  107. package/build/cc/LockCC.js +185 -0
  108. package/build/cc/LockCC.js.map +1 -0
  109. package/build/cc/ManufacturerProprietaryCC.d.ts +31 -0
  110. package/build/cc/ManufacturerProprietaryCC.d.ts.map +1 -0
  111. package/build/cc/ManufacturerProprietaryCC.js +275 -0
  112. package/build/cc/ManufacturerProprietaryCC.js.map +1 -0
  113. package/build/cc/ManufacturerSpecificCC.d.ts +59 -0
  114. package/build/cc/ManufacturerSpecificCC.d.ts.map +1 -0
  115. package/build/cc/ManufacturerSpecificCC.js +285 -0
  116. package/build/cc/ManufacturerSpecificCC.js.map +1 -0
  117. package/build/cc/MeterCC.d.ts +100 -0
  118. package/build/cc/MeterCC.d.ts.map +1 -0
  119. package/build/cc/MeterCC.js +820 -0
  120. package/build/cc/MeterCC.js.map +1 -0
  121. package/build/cc/MultiChannelAssociationCC.d.ts +127 -0
  122. package/build/cc/MultiChannelAssociationCC.d.ts.map +1 -0
  123. package/build/cc/MultiChannelAssociationCC.js +883 -0
  124. package/build/cc/MultiChannelAssociationCC.js.map +1 -0
  125. package/build/cc/MultiChannelCC.d.ts +164 -0
  126. package/build/cc/MultiChannelCC.d.ts.map +1 -0
  127. package/build/cc/MultiChannelCC.js +1004 -0
  128. package/build/cc/MultiChannelCC.js.map +1 -0
  129. package/build/cc/MultiCommandCC.d.ts +28 -0
  130. package/build/cc/MultiCommandCC.d.ts.map +1 -0
  131. package/build/cc/MultiCommandCC.js +137 -0
  132. package/build/cc/MultiCommandCC.js.map +1 -0
  133. package/build/cc/MultilevelSensorCC.d.ts +83 -0
  134. package/build/cc/MultilevelSensorCC.d.ts.map +1 -0
  135. package/build/cc/MultilevelSensorCC.js +633 -0
  136. package/build/cc/MultilevelSensorCC.js.map +1 -0
  137. package/build/cc/MultilevelSwitchCC.d.ts +86 -0
  138. package/build/cc/MultilevelSwitchCC.d.ts.map +1 -0
  139. package/build/cc/MultilevelSwitchCC.js +774 -0
  140. package/build/cc/MultilevelSwitchCC.js.map +1 -0
  141. package/build/cc/NoOperationCC.d.ts +17 -0
  142. package/build/cc/NoOperationCC.d.ts.map +1 -0
  143. package/build/cc/NoOperationCC.js +50 -0
  144. package/build/cc/NoOperationCC.js.map +1 -0
  145. package/build/cc/NodeNamingCC.d.ts +57 -0
  146. package/build/cc/NodeNamingCC.d.ts.map +1 -0
  147. package/build/cc/NodeNamingCC.js +313 -0
  148. package/build/cc/NodeNamingCC.js.map +1 -0
  149. package/build/cc/NotificationCC.d.ts +127 -0
  150. package/build/cc/NotificationCC.d.ts.map +1 -0
  151. package/build/cc/NotificationCC.js +1193 -0
  152. package/build/cc/NotificationCC.js.map +1 -0
  153. package/build/cc/PowerlevelCC.d.ts +63 -0
  154. package/build/cc/PowerlevelCC.d.ts.map +1 -0
  155. package/build/cc/PowerlevelCC.js +262 -0
  156. package/build/cc/PowerlevelCC.js.map +1 -0
  157. package/build/cc/ProtectionCC.d.ts +94 -0
  158. package/build/cc/ProtectionCC.d.ts.map +1 -0
  159. package/build/cc/ProtectionCC.js +630 -0
  160. package/build/cc/ProtectionCC.js.map +1 -0
  161. package/build/cc/SceneActivationCC.d.ts +34 -0
  162. package/build/cc/SceneActivationCC.d.ts.map +1 -0
  163. package/build/cc/SceneActivationCC.js +170 -0
  164. package/build/cc/SceneActivationCC.js.map +1 -0
  165. package/build/cc/SceneActuatorConfigurationCC.d.ts +52 -0
  166. package/build/cc/SceneActuatorConfigurationCC.d.ts.map +1 -0
  167. package/build/cc/SceneActuatorConfigurationCC.js +368 -0
  168. package/build/cc/SceneActuatorConfigurationCC.js.map +1 -0
  169. package/build/cc/SceneControllerConfigurationCC.d.ts +61 -0
  170. package/build/cc/SceneControllerConfigurationCC.d.ts.map +1 -0
  171. package/build/cc/SceneControllerConfigurationCC.js +444 -0
  172. package/build/cc/SceneControllerConfigurationCC.js.map +1 -0
  173. package/build/cc/Security2CC.d.ts +213 -0
  174. package/build/cc/Security2CC.d.ts.map +1 -0
  175. package/build/cc/Security2CC.js +1124 -0
  176. package/build/cc/Security2CC.js.map +1 -0
  177. package/build/cc/SecurityCC.d.ts +109 -0
  178. package/build/cc/SecurityCC.d.ts.map +1 -0
  179. package/build/cc/SecurityCC.js +609 -0
  180. package/build/cc/SecurityCC.js.map +1 -0
  181. package/build/cc/SoundSwitchCC.d.ts +87 -0
  182. package/build/cc/SoundSwitchCC.d.ts.map +1 -0
  183. package/build/cc/SoundSwitchCC.js +548 -0
  184. package/build/cc/SoundSwitchCC.js.map +1 -0
  185. package/build/cc/SupervisionCC.d.ts +63 -0
  186. package/build/cc/SupervisionCC.d.ts.map +1 -0
  187. package/build/cc/SupervisionCC.js +239 -0
  188. package/build/cc/SupervisionCC.js.map +1 -0
  189. package/build/cc/ThermostatFanModeCC.d.ts +53 -0
  190. package/build/cc/ThermostatFanModeCC.d.ts.map +1 -0
  191. package/build/cc/ThermostatFanModeCC.js +359 -0
  192. package/build/cc/ThermostatFanModeCC.js.map +1 -0
  193. package/build/cc/ThermostatFanStateCC.d.ts +24 -0
  194. package/build/cc/ThermostatFanStateCC.d.ts.map +1 -0
  195. package/build/cc/ThermostatFanStateCC.js +131 -0
  196. package/build/cc/ThermostatFanStateCC.js.map +1 -0
  197. package/build/cc/ThermostatModeCC.d.ts +58 -0
  198. package/build/cc/ThermostatModeCC.d.ts.map +1 -0
  199. package/build/cc/ThermostatModeCC.js +370 -0
  200. package/build/cc/ThermostatModeCC.js.map +1 -0
  201. package/build/cc/ThermostatOperatingStateCC.d.ts +24 -0
  202. package/build/cc/ThermostatOperatingStateCC.d.ts.map +1 -0
  203. package/build/cc/ThermostatOperatingStateCC.js +127 -0
  204. package/build/cc/ThermostatOperatingStateCC.js.map +1 -0
  205. package/build/cc/ThermostatSetbackCC.d.ts +42 -0
  206. package/build/cc/ThermostatSetbackCC.d.ts.map +1 -0
  207. package/build/cc/ThermostatSetbackCC.js +237 -0
  208. package/build/cc/ThermostatSetbackCC.js.map +1 -0
  209. package/build/cc/ThermostatSetpointCC.d.ts +98 -0
  210. package/build/cc/ThermostatSetpointCC.d.ts.map +1 -0
  211. package/build/cc/ThermostatSetpointCC.js +707 -0
  212. package/build/cc/ThermostatSetpointCC.js.map +1 -0
  213. package/build/cc/TimeCC.d.ts +78 -0
  214. package/build/cc/TimeCC.d.ts.map +1 -0
  215. package/build/cc/TimeCC.js +373 -0
  216. package/build/cc/TimeCC.js.map +1 -0
  217. package/build/cc/TimeParametersCC.d.ts +40 -0
  218. package/build/cc/TimeParametersCC.d.ts.map +1 -0
  219. package/build/cc/TimeParametersCC.js +275 -0
  220. package/build/cc/TimeParametersCC.js.map +1 -0
  221. package/build/cc/TransportServiceCC.d.ts +101 -0
  222. package/build/cc/TransportServiceCC.d.ts.map +1 -0
  223. package/build/cc/TransportServiceCC.js +404 -0
  224. package/build/cc/TransportServiceCC.js.map +1 -0
  225. package/build/cc/UserCodeCC.d.ts +219 -0
  226. package/build/cc/UserCodeCC.d.ts.map +1 -0
  227. package/build/cc/UserCodeCC.js +1526 -0
  228. package/build/cc/UserCodeCC.js.map +1 -0
  229. package/build/cc/VersionCC.d.ts +91 -0
  230. package/build/cc/VersionCC.d.ts.map +1 -0
  231. package/build/cc/VersionCC.js +654 -0
  232. package/build/cc/VersionCC.js.map +1 -0
  233. package/build/cc/WakeUpCC.d.ts +67 -0
  234. package/build/cc/WakeUpCC.d.ts.map +1 -0
  235. package/build/cc/WakeUpCC.js +425 -0
  236. package/build/cc/WakeUpCC.js.map +1 -0
  237. package/build/cc/ZWavePlusCC.d.ts +40 -0
  238. package/build/cc/ZWavePlusCC.d.ts.map +1 -0
  239. package/build/cc/ZWavePlusCC.js +269 -0
  240. package/build/cc/ZWavePlusCC.js.map +1 -0
  241. package/build/cc/index.d.ts +64 -0
  242. package/build/cc/index.d.ts.map +1 -0
  243. package/build/cc/index.js +496 -0
  244. package/build/cc/index.js.map +1 -0
  245. package/build/cc/manufacturerProprietary/FibaroCC.d.ts +62 -0
  246. package/build/cc/manufacturerProprietary/FibaroCC.d.ts.map +1 -0
  247. package/build/cc/manufacturerProprietary/FibaroCC.js +247 -0
  248. package/build/cc/manufacturerProprietary/FibaroCC.js.map +1 -0
  249. package/build/index.d.ts +11 -0
  250. package/build/index.d.ts.map +1 -0
  251. package/build/index.js +48 -0
  252. package/build/index.js.map +1 -0
  253. package/build/index_safe.d.ts +4 -0
  254. package/build/index_safe.d.ts.map +1 -0
  255. package/build/index_safe.js +30 -0
  256. package/build/index_safe.js.map +1 -0
  257. package/build/lib/API.d.ts +176 -0
  258. package/build/lib/API.d.ts.map +1 -0
  259. package/build/lib/API.js +325 -0
  260. package/build/lib/API.js.map +1 -0
  261. package/build/lib/CommandClass.d.ts +341 -0
  262. package/build/lib/CommandClass.d.ts.map +1 -0
  263. package/build/lib/CommandClass.js +1088 -0
  264. package/build/lib/CommandClass.js.map +1 -0
  265. package/build/lib/EncapsulatingCommandClass.d.ts +35 -0
  266. package/build/lib/EncapsulatingCommandClass.d.ts.map +1 -0
  267. package/build/lib/EncapsulatingCommandClass.js +53 -0
  268. package/build/lib/EncapsulatingCommandClass.js.map +1 -0
  269. package/build/lib/ICommandClassContainer.d.ts +9 -0
  270. package/build/lib/ICommandClassContainer.d.ts.map +1 -0
  271. package/build/lib/ICommandClassContainer.js +12 -0
  272. package/build/lib/ICommandClassContainer.js.map +1 -0
  273. package/build/lib/NotificationEventPayload.d.ts +11 -0
  274. package/build/lib/NotificationEventPayload.d.ts.map +1 -0
  275. package/build/lib/NotificationEventPayload.js +11 -0
  276. package/build/lib/NotificationEventPayload.js.map +1 -0
  277. package/build/lib/Security2/Extension.d.ts +87 -0
  278. package/build/lib/Security2/Extension.d.ts.map +1 -0
  279. package/build/lib/Security2/Extension.js +235 -0
  280. package/build/lib/Security2/Extension.js.map +1 -0
  281. package/build/lib/Security2/shared.d.ts +31 -0
  282. package/build/lib/Security2/shared.d.ts.map +1 -0
  283. package/build/lib/Security2/shared.js +37 -0
  284. package/build/lib/Security2/shared.js.map +1 -0
  285. package/build/lib/_Types.d.ts +1446 -0
  286. package/build/lib/_Types.d.ts.map +1 -0
  287. package/build/lib/_Types.js +1334 -0
  288. package/build/lib/_Types.js.map +1 -0
  289. package/build/lib/serializers.d.ts +24 -0
  290. package/build/lib/serializers.d.ts.map +1 -0
  291. package/build/lib/serializers.js +66 -0
  292. package/build/lib/serializers.js.map +1 -0
  293. package/build/lib/utils.d.ts +13 -0
  294. package/build/lib/utils.d.ts.map +1 -0
  295. package/build/lib/utils.js +675 -0
  296. package/build/lib/utils.js.map +1 -0
  297. package/package.json +77 -0
@@ -0,0 +1,675 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configureLifelineAssociations = exports.removeAssociations = exports.addAssociations = exports.getAllAssociationGroups = exports.getAssociationGroups = exports.isAssociationAllowed = exports.getAllAssociations = exports.getAssociations = void 0;
4
+ const safe_1 = require("@zwave-js/core/safe");
5
+ const safe_2 = require("@zwave-js/shared/safe");
6
+ const arrays_1 = require("alcalzone-shared/arrays");
7
+ const AssociationCC_1 = require("../cc/AssociationCC");
8
+ const AssociationGroupInfoCC_1 = require("../cc/AssociationGroupInfoCC");
9
+ const MultiChannelAssociationCC_1 = require("../cc/MultiChannelAssociationCC");
10
+ const API_1 = require("./API");
11
+ function getAssociations(applHost, endpoint) {
12
+ const ret = new Map();
13
+ if (endpoint.supportsCC(safe_1.CommandClasses.Association)) {
14
+ const destinations = AssociationCC_1.AssociationCC.getAllDestinationsCached(applHost, endpoint);
15
+ for (const [groupId, assocs] of destinations) {
16
+ ret.set(groupId, assocs);
17
+ }
18
+ }
19
+ else {
20
+ throw new safe_1.ZWaveError(`Node ${endpoint.nodeId}${endpoint.index > 0 ? `, endpoint ${endpoint.index}` : ""} does not support associations!`, safe_1.ZWaveErrorCodes.CC_NotSupported);
21
+ }
22
+ // Merge the "normal" destinations with multi channel destinations
23
+ if (endpoint.supportsCC(safe_1.CommandClasses["Multi Channel Association"])) {
24
+ const destinations = MultiChannelAssociationCC_1.MultiChannelAssociationCC.getAllDestinationsCached(applHost, endpoint);
25
+ for (const [groupId, assocs] of destinations) {
26
+ if (ret.has(groupId)) {
27
+ const normalAssociations = ret.get(groupId);
28
+ ret.set(groupId, [
29
+ ...normalAssociations,
30
+ // Eliminate potential duplicates
31
+ ...assocs.filter((a1) => normalAssociations.findIndex((a2) => a1.nodeId === a2.nodeId &&
32
+ a1.endpoint === a2.endpoint) === -1),
33
+ ]);
34
+ }
35
+ else {
36
+ ret.set(groupId, assocs);
37
+ }
38
+ }
39
+ }
40
+ return ret;
41
+ }
42
+ exports.getAssociations = getAssociations;
43
+ function getAllAssociations(applHost, node) {
44
+ const ret = new safe_2.ObjectKeyMap();
45
+ for (const endpoint of node.getAllEndpoints()) {
46
+ const address = {
47
+ nodeId: node.id,
48
+ endpoint: endpoint.index,
49
+ };
50
+ if (endpoint.supportsCC(safe_1.CommandClasses.Association)) {
51
+ ret.set(address, getAssociations(applHost, endpoint));
52
+ }
53
+ }
54
+ return ret;
55
+ }
56
+ exports.getAllAssociations = getAllAssociations;
57
+ function isAssociationAllowed(applHost, endpoint, group, destination) {
58
+ var _a;
59
+ // Check that the target endpoint exists except when adding an association to the controller
60
+ const targetNode = applHost.nodes.getOrThrow(destination.nodeId);
61
+ const targetEndpoint = destination.nodeId === applHost.ownNodeId
62
+ ? targetNode
63
+ : targetNode.getEndpointOrThrow((_a = destination.endpoint) !== null && _a !== void 0 ? _a : 0);
64
+ // SDS14223:
65
+ // A controlling node MUST NOT associate Node A to a Node B destination that does not support
66
+ // the Command Class that the Node A will be controlling
67
+ //
68
+ // To determine this, the node must support the AGI CC or we have no way of knowing which
69
+ // CCs the node will control
70
+ if (!endpoint.supportsCC(safe_1.CommandClasses.Association) &&
71
+ !endpoint.supportsCC(safe_1.CommandClasses["Multi Channel Association"])) {
72
+ throw new safe_1.ZWaveError(`Node ${endpoint.nodeId}${endpoint.index > 0 ? `, endpoint ${endpoint.index}` : ""} does not support associations!`, safe_1.ZWaveErrorCodes.CC_NotSupported);
73
+ }
74
+ else if (!endpoint.supportsCC(safe_1.CommandClasses["Association Group Information"])) {
75
+ return true;
76
+ }
77
+ // The following checks don't apply to Lifeline associations
78
+ if (destination.nodeId === applHost.ownNodeId)
79
+ return true;
80
+ const groupCommandList = AssociationGroupInfoCC_1.AssociationGroupInfoCC.getIssuedCommandsCached(applHost, endpoint, group);
81
+ if (!groupCommandList || !groupCommandList.size) {
82
+ // We don't know which CCs this group controls, just allow it
83
+ return true;
84
+ }
85
+ const groupCCs = [...groupCommandList.keys()];
86
+ // A controlling node MAY create an association to a destination supporting an
87
+ // actuator Command Class if the actual association group sends Basic Control Command Class.
88
+ if (groupCCs.includes(safe_1.CommandClasses.Basic) &&
89
+ safe_1.actuatorCCs.some((cc) => targetEndpoint === null || targetEndpoint === void 0 ? void 0 : targetEndpoint.supportsCC(cc))) {
90
+ return true;
91
+ }
92
+ // Enforce that at least one issued CC is supported
93
+ return groupCCs.some((cc) => targetEndpoint === null || targetEndpoint === void 0 ? void 0 : targetEndpoint.supportsCC(cc));
94
+ }
95
+ exports.isAssociationAllowed = isAssociationAllowed;
96
+ function getAssociationGroups(applHost, endpoint) {
97
+ var _a, _b, _c, _d, _e, _f, _g;
98
+ // Check whether we have multi channel support or not
99
+ let assocInstance;
100
+ let mcInstance;
101
+ if (endpoint.supportsCC(safe_1.CommandClasses.Association)) {
102
+ assocInstance = AssociationCC_1.AssociationCC;
103
+ }
104
+ else {
105
+ throw new safe_1.ZWaveError(`Node ${endpoint.nodeId}${endpoint.index > 0 ? `, endpoint ${endpoint.index}` : ""} does not support associations!`, safe_1.ZWaveErrorCodes.CC_NotSupported);
106
+ }
107
+ if (endpoint.supportsCC(safe_1.CommandClasses["Multi Channel Association"])) {
108
+ mcInstance = MultiChannelAssociationCC_1.MultiChannelAssociationCC;
109
+ }
110
+ const assocGroupCount = (_a = assocInstance.getGroupCountCached(applHost, endpoint)) !== null && _a !== void 0 ? _a : 0;
111
+ const mcGroupCount = (_b = mcInstance === null || mcInstance === void 0 ? void 0 : mcInstance.getGroupCountCached(applHost, endpoint)) !== null && _b !== void 0 ? _b : 0;
112
+ const groupCount = Math.max(assocGroupCount, mcGroupCount);
113
+ const deviceConfig = (_c = applHost.getDeviceConfig) === null || _c === void 0 ? void 0 : _c.call(applHost, endpoint.nodeId);
114
+ const ret = new Map();
115
+ if (endpoint.supportsCC(safe_1.CommandClasses["Association Group Information"])) {
116
+ // We can read all information we need from the AGI CC
117
+ const agiInstance = AssociationGroupInfoCC_1.AssociationGroupInfoCC;
118
+ for (let group = 1; group <= groupCount; group++) {
119
+ const assocConfig = deviceConfig === null || deviceConfig === void 0 ? void 0 : deviceConfig.getAssociationConfigForEndpoint(endpoint.index, group);
120
+ const multiChannel = !!mcInstance && group <= mcGroupCount;
121
+ ret.set(group, {
122
+ maxNodes: (multiChannel
123
+ ? mcInstance
124
+ : assocInstance).getMaxNodesCached(applHost, endpoint, group) || 1,
125
+ // AGI implies Z-Wave+ where group 1 is the lifeline
126
+ isLifeline: group === 1,
127
+ label:
128
+ // prefer the configured label if we have one
129
+ (_e = (_d = assocConfig === null || assocConfig === void 0 ? void 0 : assocConfig.label) !== null && _d !== void 0 ? _d :
130
+ // the ones reported by AGI are sometimes pretty bad
131
+ agiInstance.getGroupNameCached(applHost, endpoint, group)) !== null && _e !== void 0 ? _e :
132
+ // but still better than "unnamed"
133
+ `Unnamed group ${group}`,
134
+ multiChannel,
135
+ profile: agiInstance.getGroupProfileCached(applHost, endpoint, group),
136
+ issuedCommands: agiInstance.getIssuedCommandsCached(applHost, endpoint, group),
137
+ });
138
+ }
139
+ }
140
+ else {
141
+ // we need to consult the device config
142
+ for (let group = 1; group <= groupCount; group++) {
143
+ const assocConfig = deviceConfig === null || deviceConfig === void 0 ? void 0 : deviceConfig.getAssociationConfigForEndpoint(endpoint.index, group);
144
+ const multiChannel = !!mcInstance && group <= mcGroupCount;
145
+ ret.set(group, {
146
+ maxNodes: (multiChannel
147
+ ? mcInstance
148
+ : assocInstance).getMaxNodesCached(applHost, endpoint, group) ||
149
+ (assocConfig === null || assocConfig === void 0 ? void 0 : assocConfig.maxNodes) ||
150
+ 1,
151
+ isLifeline: (_f = assocConfig === null || assocConfig === void 0 ? void 0 : assocConfig.isLifeline) !== null && _f !== void 0 ? _f : group === 1,
152
+ label: (_g = assocConfig === null || assocConfig === void 0 ? void 0 : assocConfig.label) !== null && _g !== void 0 ? _g : `Unnamed group ${group}`,
153
+ multiChannel,
154
+ });
155
+ }
156
+ }
157
+ return ret;
158
+ }
159
+ exports.getAssociationGroups = getAssociationGroups;
160
+ function getAllAssociationGroups(applHost, node) {
161
+ const ret = new Map();
162
+ for (const endpoint of node.getAllEndpoints()) {
163
+ if (endpoint.supportsCC(safe_1.CommandClasses.Association)) {
164
+ ret.set(endpoint.index, getAssociationGroups(applHost, endpoint));
165
+ }
166
+ }
167
+ return ret;
168
+ }
169
+ exports.getAllAssociationGroups = getAllAssociationGroups;
170
+ async function addAssociations(applHost, endpoint, group, destinations) {
171
+ var _a, _b, _c, _d, _e;
172
+ const nodeAndEndpointString = `${endpoint.nodeId}${endpoint.index > 0 ? `, endpoint ${endpoint.index}` : ""}`;
173
+ // Check whether we should add any associations the device does not have support for
174
+ let assocInstance;
175
+ let mcInstance;
176
+ // Split associations into conventional and endpoint associations
177
+ const nodeAssociations = (0, arrays_1.distinct)(destinations
178
+ .filter((a) => a.endpoint == undefined)
179
+ .map((a) => a.nodeId));
180
+ const endpointAssociations = destinations.filter((a) => a.endpoint != undefined);
181
+ if (endpoint.supportsCC(safe_1.CommandClasses.Association)) {
182
+ assocInstance = AssociationCC_1.AssociationCC;
183
+ }
184
+ else if (nodeAssociations.length > 0) {
185
+ throw new safe_1.ZWaveError(`Node ${nodeAndEndpointString} does not support associations!`, safe_1.ZWaveErrorCodes.CC_NotSupported);
186
+ }
187
+ if (endpoint.supportsCC(safe_1.CommandClasses["Multi Channel Association"])) {
188
+ mcInstance = MultiChannelAssociationCC_1.MultiChannelAssociationCC;
189
+ }
190
+ else if (endpointAssociations.length > 0) {
191
+ throw new safe_1.ZWaveError(`Node ${nodeAndEndpointString} does not support multi channel associations!`, safe_1.ZWaveErrorCodes.CC_NotSupported);
192
+ }
193
+ const assocGroupCount = (_a = assocInstance === null || assocInstance === void 0 ? void 0 : assocInstance.getGroupCountCached(applHost, endpoint)) !== null && _a !== void 0 ? _a : 0;
194
+ const mcGroupCount = (_b = mcInstance === null || mcInstance === void 0 ? void 0 : mcInstance.getGroupCountCached(applHost, endpoint)) !== null && _b !== void 0 ? _b : 0;
195
+ const groupCount = Math.max(assocGroupCount, mcGroupCount);
196
+ if (group > groupCount) {
197
+ throw new safe_1.ZWaveError(`Group ${group} does not exist on node ${nodeAndEndpointString}`, safe_1.ZWaveErrorCodes.AssociationCC_InvalidGroup);
198
+ }
199
+ const deviceConfig = (_c = applHost.getDeviceConfig) === null || _c === void 0 ? void 0 : _c.call(applHost, endpoint.nodeId);
200
+ const groupIsMultiChannel = !!mcInstance &&
201
+ group <= mcGroupCount &&
202
+ ((_e = (_d = deviceConfig === null || deviceConfig === void 0 ? void 0 : deviceConfig.associations) === null || _d === void 0 ? void 0 : _d.get(group)) === null || _e === void 0 ? void 0 : _e.multiChannel) !== false;
203
+ if (groupIsMultiChannel) {
204
+ // Check that all associations are allowed
205
+ const disallowedAssociations = destinations.filter((a) => !isAssociationAllowed(applHost, endpoint, group, a));
206
+ if (disallowedAssociations.length) {
207
+ let message = `The following associations are not allowed:`;
208
+ message += disallowedAssociations
209
+ .map((a) => `\n· Node ${a.nodeId}${a.endpoint ? `, endpoint ${a.endpoint}` : ""}`)
210
+ .join("");
211
+ throw new safe_1.ZWaveError(message, safe_1.ZWaveErrorCodes.AssociationCC_NotAllowed);
212
+ }
213
+ // And add them
214
+ const api = API_1.CCAPI.create(safe_1.CommandClasses["Multi Channel Association"], applHost, endpoint);
215
+ await api.addDestinations({
216
+ groupId: group,
217
+ nodeIds: nodeAssociations,
218
+ endpoints: endpointAssociations,
219
+ });
220
+ // Refresh the association list
221
+ await api.getGroup(group);
222
+ }
223
+ else {
224
+ // Although the node supports multi channel associations, this group only supports "normal" associations
225
+ if (destinations.some((a) => a.endpoint != undefined)) {
226
+ throw new safe_1.ZWaveError(`Node ${nodeAndEndpointString}, group ${group} does not support multi channel associations!`, safe_1.ZWaveErrorCodes.CC_NotSupported);
227
+ }
228
+ // Check that all associations are allowed
229
+ const disallowedAssociations = destinations.filter((a) => !isAssociationAllowed(applHost, endpoint, group, a));
230
+ if (disallowedAssociations.length) {
231
+ throw new safe_1.ZWaveError(`The associations to the following nodes are not allowed: ${disallowedAssociations
232
+ .map((a) => a.nodeId)
233
+ .join(", ")}`, safe_1.ZWaveErrorCodes.AssociationCC_NotAllowed);
234
+ }
235
+ const api = API_1.CCAPI.create(safe_1.CommandClasses.Association, applHost, endpoint);
236
+ await api.addNodeIds(group, ...destinations.map((a) => a.nodeId));
237
+ // Refresh the association list
238
+ await api.getGroup(group);
239
+ }
240
+ }
241
+ exports.addAssociations = addAssociations;
242
+ async function removeAssociations(applHost, endpoint, group, destinations) {
243
+ const nodeAndEndpointString = `${endpoint.nodeId}${endpoint.index > 0 ? `, endpoint ${endpoint.index}` : ""}`;
244
+ // Split associations into conventional and endpoint associations
245
+ const nodeAssociations = (0, arrays_1.distinct)(destinations
246
+ .filter((a) => a.endpoint == undefined)
247
+ .map((a) => a.nodeId));
248
+ const endpointAssociations = destinations.filter((a) => a.endpoint != undefined);
249
+ // Removing associations is not either/or - we could have a device with duplicated associations between
250
+ // Association CC and Multi Channel Association CC
251
+ // Figure out what we need to use to remove the associations
252
+ let groupExistsAsMultiChannel = false;
253
+ let groupExistsAsNodeAssociation = false;
254
+ let mcInstance;
255
+ let assocInstance;
256
+ // To remove a multi channel association, we need to make sure that the group exists
257
+ // and the node supports multi channel associations
258
+ if (endpoint.supportsCC(safe_1.CommandClasses["Multi Channel Association"])) {
259
+ mcInstance = MultiChannelAssociationCC_1.MultiChannelAssociationCC;
260
+ if (group <= mcInstance.getGroupCountCached(applHost, endpoint)) {
261
+ groupExistsAsMultiChannel = true;
262
+ }
263
+ }
264
+ else if (endpointAssociations.length > 0) {
265
+ throw new safe_1.ZWaveError(`Node ${nodeAndEndpointString} does not support multi channel associations!`, safe_1.ZWaveErrorCodes.CC_NotSupported);
266
+ }
267
+ // To remove a normal association, we need to make sure that the group exists either as a normal association
268
+ // or as a multi channel association
269
+ if (endpoint.supportsCC(safe_1.CommandClasses.Association)) {
270
+ assocInstance = AssociationCC_1.AssociationCC;
271
+ if (group <= assocInstance.getGroupCountCached(applHost, endpoint)) {
272
+ groupExistsAsNodeAssociation = true;
273
+ }
274
+ }
275
+ if (!mcInstance && !assocInstance) {
276
+ throw new safe_1.ZWaveError(`Node ${nodeAndEndpointString} does not support associations!`, safe_1.ZWaveErrorCodes.CC_NotSupported);
277
+ }
278
+ // Ensure the group exists and can be used
279
+ if (!groupExistsAsMultiChannel && !groupExistsAsNodeAssociation) {
280
+ throw new safe_1.ZWaveError(` Association group ${group} does not exist for node ${nodeAndEndpointString}`, safe_1.ZWaveErrorCodes.AssociationCC_InvalidGroup);
281
+ }
282
+ if (endpointAssociations.length > 0 && !groupExistsAsMultiChannel) {
283
+ throw new safe_1.ZWaveError(`Node ${nodeAndEndpointString}, association group ${group} does not support multi channel associations!`, safe_1.ZWaveErrorCodes.AssociationCC_InvalidGroup);
284
+ }
285
+ // Even if we only remove node associations, we use both CCs since it has been found that some
286
+ // devices do not correctly share the node list between the two commands
287
+ if (assocInstance &&
288
+ nodeAssociations.length > 0 &&
289
+ groupExistsAsNodeAssociation) {
290
+ const api = API_1.CCAPI.create(safe_1.CommandClasses.Association, applHost, endpoint);
291
+ await api.removeNodeIds({
292
+ groupId: group,
293
+ nodeIds: nodeAssociations,
294
+ });
295
+ // Refresh the association list
296
+ await api.getGroup(group);
297
+ }
298
+ if (mcInstance && groupExistsAsMultiChannel) {
299
+ const api = API_1.CCAPI.create(safe_1.CommandClasses["Multi Channel Association"], applHost, endpoint);
300
+ await api.removeDestinations({
301
+ groupId: group,
302
+ nodeIds: nodeAssociations,
303
+ endpoints: endpointAssociations,
304
+ });
305
+ // Refresh the multi channel association list
306
+ await api.getGroup(group);
307
+ }
308
+ }
309
+ exports.removeAssociations = removeAssociations;
310
+ async function configureLifelineAssociations(applHost, endpoint) {
311
+ var _a, _b, _c, _d, _e, _f, _g, _h;
312
+ // Assign the controller to all lifeline groups
313
+ const ownNodeId = applHost.ownNodeId;
314
+ const node = endpoint.getNodeUnsafe();
315
+ const valueDB = applHost.getValueDB(node.id);
316
+ const deviceConfig = (_a = applHost.getDeviceConfig) === null || _a === void 0 ? void 0 : _a.call(applHost, node.id);
317
+ // We check if a node supports Multi Channel CC before creating Multi Channel Lifeline Associations (#1109)
318
+ const nodeSupportsMultiChannel = node.supportsCC(safe_1.CommandClasses["Multi Channel"]);
319
+ let assocInstance;
320
+ const assocAPI = API_1.CCAPI.create(safe_1.CommandClasses.Association, applHost, endpoint);
321
+ if (endpoint.supportsCC(safe_1.CommandClasses.Association)) {
322
+ assocInstance = AssociationCC_1.AssociationCC;
323
+ }
324
+ let mcInstance;
325
+ let mcGroupCount = 0;
326
+ const mcAPI = API_1.CCAPI.create(safe_1.CommandClasses["Multi Channel Association"], applHost, endpoint);
327
+ if (endpoint.supportsCC(safe_1.CommandClasses["Multi Channel Association"])) {
328
+ mcInstance = MultiChannelAssociationCC_1.MultiChannelAssociationCC;
329
+ mcGroupCount = (_b = mcInstance.getGroupCountCached(applHost, endpoint)) !== null && _b !== void 0 ? _b : 0;
330
+ }
331
+ const lifelineGroups = (0, AssociationCC_1.getLifelineGroupIds)(applHost, node);
332
+ if (lifelineGroups.length === 0) {
333
+ applHost.controllerLog.logNode(node.id, {
334
+ endpoint: endpoint.index,
335
+ message: "No information about Lifeline associations, cannot assign ourselves!",
336
+ level: "warn",
337
+ });
338
+ // Remember that we have NO lifeline association
339
+ valueDB.setValue((0, AssociationCC_1.getHasLifelineValueId)(endpoint.index), false);
340
+ return;
341
+ }
342
+ applHost.controllerLog.logNode(node.id, {
343
+ endpoint: endpoint.index,
344
+ message: `Checking/assigning lifeline groups: ${lifelineGroups.join(", ")}
345
+ supports classic associations: ${!!assocInstance}
346
+ supports multi channel associations: ${!!mcInstance}`,
347
+ });
348
+ for (const group of lifelineGroups) {
349
+ const groupSupportsMultiChannelAssociation = group <= mcGroupCount;
350
+ const assocConfig = deviceConfig === null || deviceConfig === void 0 ? void 0 : deviceConfig.getAssociationConfigForEndpoint(endpoint.index, group);
351
+ const mustUseNodeAssociation = !groupSupportsMultiChannelAssociation ||
352
+ !nodeSupportsMultiChannel ||
353
+ (assocConfig === null || assocConfig === void 0 ? void 0 : assocConfig.multiChannel) === false;
354
+ let mustUseMultiChannelAssociation = false;
355
+ if (groupSupportsMultiChannelAssociation && nodeSupportsMultiChannel) {
356
+ if ((assocConfig === null || assocConfig === void 0 ? void 0 : assocConfig.multiChannel) === true) {
357
+ mustUseMultiChannelAssociation = true;
358
+ }
359
+ else if (endpoint.index === 0) {
360
+ // If the node has multiple endpoints but none of the extra ones support associations,
361
+ // the root endpoints needs a Multi Channel Association
362
+ const allEndpoints = node.getAllEndpoints();
363
+ if (allEndpoints.length > 1 &&
364
+ allEndpoints
365
+ .filter((e) => e.index !== endpoint.index)
366
+ .every((e) => !e.supportsCC(safe_1.CommandClasses.Association) &&
367
+ !e.supportsCC(safe_1.CommandClasses["Multi Channel Association"]))) {
368
+ mustUseMultiChannelAssociation = true;
369
+ }
370
+ }
371
+ }
372
+ applHost.controllerLog.logNode(node.id, {
373
+ endpoint: endpoint.index,
374
+ message: `Configuring lifeline group #${group}:
375
+ group supports multi channel: ${groupSupportsMultiChannelAssociation}
376
+ configured strategy: ${(_c = assocConfig === null || assocConfig === void 0 ? void 0 : assocConfig.multiChannel) !== null && _c !== void 0 ? _c : "auto"}
377
+ must use node association: ${mustUseNodeAssociation}
378
+ must use endpoint association: ${mustUseMultiChannelAssociation}`,
379
+ });
380
+ // Figure out which associations exist and may need to be removed
381
+ const isAssignedAsNodeAssociation = () => {
382
+ var _a, _b;
383
+ if (groupSupportsMultiChannelAssociation && mcInstance) {
384
+ if (
385
+ // Only consider a group if it doesn't share its associations with the root endpoint
386
+ mcInstance.getMaxNodesCached(applHost, endpoint, group) >
387
+ 0 &&
388
+ !!((_a = mcInstance
389
+ .getAllDestinationsCached(applHost, endpoint)
390
+ .get(group)) === null || _a === void 0 ? void 0 : _a.some((addr) => addr.nodeId === ownNodeId &&
391
+ addr.endpoint == undefined))) {
392
+ return true;
393
+ }
394
+ }
395
+ if (assocInstance) {
396
+ if (
397
+ // Only consider a group if it doesn't share its associations with the root endpoint
398
+ assocInstance.getMaxNodesCached(applHost, endpoint, group) >
399
+ 0 &&
400
+ !!((_b = assocInstance
401
+ .getAllDestinationsCached(applHost, endpoint)
402
+ .get(group)) === null || _b === void 0 ? void 0 : _b.some((addr) => addr.nodeId === ownNodeId))) {
403
+ return true;
404
+ }
405
+ }
406
+ return false;
407
+ };
408
+ const isAssignedAsEndpointAssociation = () => {
409
+ var _a;
410
+ if (mcInstance) {
411
+ if (
412
+ // Only consider a group if it doesn't share its associations with the root endpoint
413
+ mcInstance.getMaxNodesCached(applHost, endpoint, group) >
414
+ 0 &&
415
+ ((_a = mcInstance
416
+ .getAllDestinationsCached(applHost, endpoint)
417
+ .get(group)) === null || _a === void 0 ? void 0 : _a.some((addr) => addr.nodeId === ownNodeId &&
418
+ addr.endpoint === 0))) {
419
+ return true;
420
+ }
421
+ }
422
+ return false;
423
+ };
424
+ // If the node was used with other controller softwares, there might be
425
+ // invalid lifeline associations which cause reporting problems
426
+ const invalidEndpointAssociations = (_e = (_d = mcInstance === null || mcInstance === void 0 ? void 0 : mcInstance.getAllDestinationsCached(applHost, endpoint).get(group)) === null || _d === void 0 ? void 0 : _d.filter((addr) => addr.nodeId === ownNodeId &&
427
+ addr.endpoint != undefined &&
428
+ addr.endpoint !== 0)) !== null && _e !== void 0 ? _e : [];
429
+ // Clean them up first
430
+ if (invalidEndpointAssociations.length > 0 &&
431
+ mcAPI.isSupported() &&
432
+ groupSupportsMultiChannelAssociation) {
433
+ applHost.controllerLog.logNode(node.id, {
434
+ endpoint: endpoint.index,
435
+ message: `Found invalid lifeline associations in group #${group}, removing them...`,
436
+ direction: "outbound",
437
+ });
438
+ await mcAPI.removeDestinations({
439
+ groupId: group,
440
+ endpoints: invalidEndpointAssociations,
441
+ });
442
+ // refresh the associations - don't trust that it worked
443
+ await mcAPI.getGroup(group);
444
+ }
445
+ // Assigning the correct lifelines depends on the association kind, source endpoint and the desired strategy:
446
+ //
447
+ // When `mustUseMultiChannelAssociation` is `true` - Use a multi channel association (if possible), no fallback
448
+ // When `mustUseNodeAssociation` is `true` - Use a node association (if possible), no fallback
449
+ // Otherwise:
450
+ // 1. Try a node association on the current endpoint/root
451
+ // 2. If Association CC is not supported, try assigning a node association with the Multi Channel Association CC
452
+ // 3. If that did not work, fall back to a multi channel association (target endpoint 0)
453
+ // 4. If that did not work either, the endpoint index is >0 and the node is Z-Wave+:
454
+ // Fall back to a multi channel association (target endpoint 0) on the root, if it doesn't have one yet.
455
+ let hasLifeline = false;
456
+ // First try: node association
457
+ if (!mustUseMultiChannelAssociation) {
458
+ if (isAssignedAsNodeAssociation()) {
459
+ // We already have the correct association
460
+ hasLifeline = true;
461
+ applHost.controllerLog.logNode(node.id, {
462
+ endpoint: endpoint.index,
463
+ message: `Lifeline group #${group} is already assigned with a node association`,
464
+ direction: "none",
465
+ });
466
+ }
467
+ else if (assocAPI.isSupported() &&
468
+ // Some endpoint groups don't support having any destinations because they are shared with the root
469
+ assocInstance.getMaxNodesCached(applHost, endpoint, group) > 0) {
470
+ // We can use a node association, but first remove any possible endpoint associations
471
+ applHost.controllerLog.logNode(node.id, {
472
+ endpoint: endpoint.index,
473
+ message: `Assigning lifeline group #${group} with a node association via Association CC...`,
474
+ direction: "outbound",
475
+ });
476
+ if (isAssignedAsEndpointAssociation() && mcAPI.isSupported()) {
477
+ await mcAPI.removeDestinations({
478
+ groupId: group,
479
+ endpoints: [{ nodeId: ownNodeId, endpoint: 0 }],
480
+ });
481
+ // refresh the associations - don't trust that it worked
482
+ await mcAPI.getGroup(group);
483
+ }
484
+ await assocAPI.addNodeIds(group, ownNodeId);
485
+ // refresh the associations - don't trust that it worked
486
+ const groupReport = await assocAPI.getGroup(group);
487
+ hasLifeline = !!(groupReport === null || groupReport === void 0 ? void 0 : groupReport.nodeIds.includes(ownNodeId));
488
+ if (hasLifeline) {
489
+ applHost.controllerLog.logNode(node.id, {
490
+ endpoint: endpoint.index,
491
+ message: `Lifeline group #${group} was assigned with a node association via Association CC`,
492
+ direction: "none",
493
+ });
494
+ }
495
+ else {
496
+ applHost.controllerLog.logNode(node.id, {
497
+ endpoint: endpoint.index,
498
+ message: `Assigning lifeline group #${group} with a node association via Association CC did not work`,
499
+ direction: "none",
500
+ });
501
+ }
502
+ }
503
+ // Second try: Node association using the Multi Channel Association CC
504
+ if (!hasLifeline &&
505
+ mcAPI.isSupported() &&
506
+ mcInstance.getMaxNodesCached(applHost, endpoint, group) > 0) {
507
+ // We can use a node association, but first remove any possible endpoint associations
508
+ applHost.controllerLog.logNode(node.id, {
509
+ endpoint: endpoint.index,
510
+ message: `Assigning lifeline group #${group} with a node association via Multi Channel Association CC...`,
511
+ direction: "outbound",
512
+ });
513
+ if (isAssignedAsEndpointAssociation()) {
514
+ await mcAPI.removeDestinations({
515
+ groupId: group,
516
+ endpoints: [{ nodeId: ownNodeId, endpoint: 0 }],
517
+ });
518
+ }
519
+ await mcAPI.addDestinations({
520
+ groupId: group,
521
+ nodeIds: [ownNodeId],
522
+ });
523
+ // refresh the associations - don't trust that it worked
524
+ const groupReport = await mcAPI.getGroup(group);
525
+ hasLifeline = !!(groupReport === null || groupReport === void 0 ? void 0 : groupReport.nodeIds.includes(ownNodeId));
526
+ if (hasLifeline) {
527
+ applHost.controllerLog.logNode(node.id, {
528
+ endpoint: endpoint.index,
529
+ message: `Lifeline group #${group} was assigned with a node association via Multi Channel Association CC`,
530
+ direction: "none",
531
+ });
532
+ }
533
+ else {
534
+ applHost.controllerLog.logNode(node.id, {
535
+ endpoint: endpoint.index,
536
+ message: `Assigning lifeline group #${group} with a node association via Multi Channel Association CC did not work`,
537
+ direction: "none",
538
+ });
539
+ }
540
+ }
541
+ }
542
+ // Third try: Use an endpoint association (target endpoint 0)
543
+ // This is only supported starting in Multi Channel Association CC V3
544
+ if (!hasLifeline && !mustUseNodeAssociation) {
545
+ if (isAssignedAsEndpointAssociation()) {
546
+ // We already have the correct association
547
+ hasLifeline = true;
548
+ applHost.controllerLog.logNode(node.id, {
549
+ endpoint: endpoint.index,
550
+ message: `Lifeline group #${group} is already assigned with an endpoint association`,
551
+ direction: "none",
552
+ });
553
+ }
554
+ else if (mcAPI.isSupported() &&
555
+ mcAPI.version >= 3 &&
556
+ mcInstance.getMaxNodesCached(applHost, endpoint, group) > 0) {
557
+ // We can use a multi channel association, but first remove any possible node associations
558
+ applHost.controllerLog.logNode(node.id, {
559
+ endpoint: endpoint.index,
560
+ message: `Assigning lifeline group #${group} with a multi channel association...`,
561
+ direction: "outbound",
562
+ });
563
+ if (isAssignedAsNodeAssociation()) {
564
+ // It has been found that some devices don't correctly share the node associations between
565
+ // Association CC and Multi Channel Association CC, so we remove the nodes from both lists
566
+ await mcAPI.removeDestinations({
567
+ groupId: group,
568
+ nodeIds: [ownNodeId],
569
+ });
570
+ if (assocAPI.isSupported()) {
571
+ await assocAPI.removeNodeIds({
572
+ groupId: group,
573
+ nodeIds: [ownNodeId],
574
+ });
575
+ // refresh the associations - don't trust that it worked
576
+ await assocAPI.getGroup(group);
577
+ }
578
+ }
579
+ await mcAPI.addDestinations({
580
+ groupId: group,
581
+ endpoints: [{ nodeId: ownNodeId, endpoint: 0 }],
582
+ });
583
+ // refresh the associations - don't trust that it worked
584
+ const groupReport = await mcAPI.getGroup(group);
585
+ hasLifeline = !!(groupReport === null || groupReport === void 0 ? void 0 : groupReport.endpoints.some((a) => a.nodeId === ownNodeId && a.endpoint === 0));
586
+ if (hasLifeline) {
587
+ applHost.controllerLog.logNode(node.id, {
588
+ endpoint: endpoint.index,
589
+ message: `Lifeline group #${group} was assigned with a multi channel association`,
590
+ direction: "none",
591
+ });
592
+ }
593
+ else {
594
+ applHost.controllerLog.logNode(node.id, {
595
+ endpoint: endpoint.index,
596
+ message: `Assigning lifeline group #${group} with a multi channel association did not work`,
597
+ direction: "none",
598
+ });
599
+ }
600
+ }
601
+ }
602
+ // Last attempt (actual Z-Wave+ Lifelines only): Try a multi channel association on the root.
603
+ // Endpoint interviews happen AFTER the root interview, so this enables us to overwrite what
604
+ // we previously configured on the root.
605
+ if (!hasLifeline &&
606
+ group === 1 &&
607
+ node.supportsCC(safe_1.CommandClasses["Z-Wave Plus Info"]) &&
608
+ endpoint.index > 0) {
609
+ // But first check if the root may have a multi channel association
610
+ const rootAssocConfig = deviceConfig === null || deviceConfig === void 0 ? void 0 : deviceConfig.getAssociationConfigForEndpoint(0, group);
611
+ const rootMustUseNodeAssociation = !nodeSupportsMultiChannel ||
612
+ (rootAssocConfig === null || rootAssocConfig === void 0 ? void 0 : rootAssocConfig.multiChannel) === false;
613
+ applHost.controllerLog.logNode(node.id, {
614
+ endpoint: endpoint.index,
615
+ message: `Checking root device for fallback assignment of lifeline group #${group}:
616
+ root supports multi channel: ${nodeSupportsMultiChannel}
617
+ configured strategy: ${(_f = rootAssocConfig === null || rootAssocConfig === void 0 ? void 0 : rootAssocConfig.multiChannel) !== null && _f !== void 0 ? _f : "auto"}
618
+ must use node association: ${rootMustUseNodeAssociation}`,
619
+ });
620
+ if (!rootMustUseNodeAssociation) {
621
+ const rootNodesValueId = (0, MultiChannelAssociationCC_1.getNodeIdsValueId)(0, group);
622
+ const rootHasNodeAssociation = !!((_g = valueDB
623
+ .getValue(rootNodesValueId)) === null || _g === void 0 ? void 0 : _g.some((a) => a === ownNodeId));
624
+ const rootEndpointsValueId = (0, MultiChannelAssociationCC_1.getEndpointsValueId)(0, group);
625
+ const rootHasEndpointAssociation = !!((_h = valueDB
626
+ .getValue(rootEndpointsValueId)) === null || _h === void 0 ? void 0 : _h.some((a) => a.nodeId === ownNodeId && a.endpoint === 0));
627
+ if (rootHasEndpointAssociation) {
628
+ // We already have the correct association
629
+ hasLifeline = true;
630
+ applHost.controllerLog.logNode(node.id, {
631
+ endpoint: endpoint.index,
632
+ message: `Lifeline group #${group} is already assigned with a multi channel association on the root device`,
633
+ direction: "none",
634
+ });
635
+ }
636
+ else {
637
+ const rootMCAPI = API_1.CCAPI.create(safe_1.CommandClasses["Multi Channel Association"], applHost, node);
638
+ if (rootMCAPI.isSupported()) {
639
+ applHost.controllerLog.logNode(node.id, {
640
+ endpoint: endpoint.index,
641
+ message: `Assigning lifeline group #${group} with a multi channel association on the root device...`,
642
+ direction: "outbound",
643
+ });
644
+ // Clean up node associations because they might prevent us from adding the endpoint association
645
+ if (rootHasNodeAssociation) {
646
+ await rootMCAPI.removeDestinations({
647
+ groupId: group,
648
+ nodeIds: [ownNodeId],
649
+ });
650
+ }
651
+ await rootMCAPI.addDestinations({
652
+ groupId: group,
653
+ endpoints: [{ nodeId: ownNodeId, endpoint: 0 }],
654
+ });
655
+ // refresh the associations - don't trust that it worked
656
+ const groupReport = await rootMCAPI.getGroup(group);
657
+ hasLifeline = !!(groupReport === null || groupReport === void 0 ? void 0 : groupReport.endpoints.some((a) => a.nodeId === ownNodeId && a.endpoint === 0));
658
+ }
659
+ }
660
+ }
661
+ }
662
+ if (!hasLifeline) {
663
+ applHost.controllerLog.logNode(node.id, {
664
+ endpoint: endpoint.index,
665
+ message: `All attempts to assign lifeline group #${group} failed, skipping...`,
666
+ direction: "none",
667
+ level: "warn",
668
+ });
669
+ }
670
+ }
671
+ // Remember that we did the association assignment
672
+ valueDB.setValue((0, AssociationCC_1.getHasLifelineValueId)(endpoint.index), true);
673
+ }
674
+ exports.configureLifelineAssociations = configureLifelineAssociations;
675
+ //# sourceMappingURL=utils.js.map