diff --git a/packages/cc/src/lib/utils.ts b/packages/cc/src/lib/utils.ts index 13bcc2fb8e70..d3c87a3a6f06 100644 --- a/packages/cc/src/lib/utils.ts +++ b/packages/cc/src/lib/utils.ts @@ -130,6 +130,9 @@ export function isAssociationAllowed( // The following checks don't apply to Lifeline associations if (destination.nodeId === applHost.ownNodeId) return true; + // Disallow self-associations + if (destination.nodeId === endpoint.nodeId) return false; + // For Association version 1 and version 2 / MCA version 1-3: // A controlling node MUST NOT associate Node A to a Node B destination // if Node A and Node B’s highest Security Class are not identical. @@ -362,6 +365,15 @@ export async function addAssociations( ); } + // Disallow associating a node with itself. This is technically checked as part of + // isAssociationAllowed, but here we provide a better error message. + if (destinations.some((d) => d.nodeId === endpoint.nodeId)) { + throw new ZWaveError( + `Associating a node with itself is not allowed!`, + ZWaveErrorCodes.AssociationCC_NotAllowed, + ); + } + const assocGroupCount = assocInstance?.getGroupCountCached(applHost, endpoint) ?? 0; const mcGroupCount = mcInstance?.getGroupCountCached(applHost, endpoint) diff --git a/packages/zwave-js/src/lib/controller/Controller.ts b/packages/zwave-js/src/lib/controller/Controller.ts index 975347107da6..c6adbd1aaf8a 100644 --- a/packages/zwave-js/src/lib/controller/Controller.ts +++ b/packages/zwave-js/src/lib/controller/Controller.ts @@ -4446,6 +4446,8 @@ supported CCs: ${ ) // ...except the controller itself, which was handled by step 2 .filter((id) => id !== this._ownNodeId!) + // ...and the node itself + .filter((id) => id !== nodeId) .sort(); } catch { /* ignore */