Get-HAZWaveNode.ps1
|
function Get-HAZWaveNode { <# .SYNOPSIS Inventory of every Z-Wave node known to Home Assistant, with the metadata available from the device registry. .DESCRIPTION Walks every entity owned by the `zwave_js` integration, dedupes to one record per device, and resolves Z-Wave node_id from the device's identifiers. Returns a PwrHass.ZWaveNode per device with: NodeId Z-Wave node_id (1 = controller, others are nodes) Manufacturer device.manufacturer Model device.model SoftwareVersion device.sw_version (firmware) HardwareVersion device.hw_version Name device.name_by_user (or device.name) DeviceId HA device UUID (handy for further lookups) EntryId HA config-entry UUID (for Restart-HAIntegration) Resolved in a single template-engine round trip rather than per device. Note: HA's device registry does NOT expose Z-Wave security class (None / S0 / S2-Authenticated). That information lives in Z-Wave-JS over its WebSocket, not REST. Use the Z-Wave-JS UI add-on to confirm security classification per node. .PARAMETER IncludeController Include the controller (typically node 1). Hidden by default since most reports want endpoints, not the stick itself. .EXAMPLE Get-HAZWaveNode | Sort-Object NodeId .EXAMPLE # Group by model to spot legacy hardware Get-HAZWaveNode | Group-Object Model | Sort-Object Count -Descending | Format-Table Count, Name -AutoSize .EXAMPLE # Filter to mains-powered candidates by inferring from model name Get-HAZWaveNode | Where Model -match 'ZW(10|30|40)\d{2}|WD500Z' #> [CmdletBinding()] [OutputType('PwrHass.ZWaveNode')] param( [switch]$IncludeController ) $cfg = Get-HAConfig $headers = @{ Authorization = "Bearer $($cfg.Token)"; 'Content-Type' = 'application/json' } $tpl = @' {%- set ents = integration_entities('zwave_js') -%} {%- set ns = namespace(devices=[]) -%} {%- for e in ents -%} {%- set d = device_id(e) -%} {%- if d and d not in ns.devices -%}{%- set ns.devices = ns.devices + [d] -%}{%- endif -%} {%- endfor -%} {%- for d in ns.devices -%} {%- set inner = namespace(node_id='?') -%} {%- for id in device_attr(d, 'identifiers') | list if id[0] == 'zwave_js' and ':' not in id[1] -%} {%- set inner.node_id = id[1].split('-')[1] -%} {%- endfor -%} {%- set entries = device_attr(d, 'config_entries') -%} {%- set entry_id = (entries | first) if entries else '' -%} {{ inner.node_id }}|{{ device_attr(d, 'manufacturer') | default('', true) }}|{{ device_attr(d, 'model') | default('', true) }}|{{ device_attr(d, 'sw_version') | default('', true) }}|{{ device_attr(d, 'hw_version') | default('', true) }}|{{ device_attr(d, 'name_by_user') or device_attr(d, 'name') or '' }}|{{ d }}|{{ entry_id }} {% endfor -%} '@ Write-Verbose "Posting Z-Wave inventory template to HA." $body = @{ template = $tpl } | ConvertTo-Json -Compress $params = @{ Method = 'Post' Uri = "$($cfg.BaseUrl)/api/template" Headers = $headers Body = $body TimeoutSec = 90 } if ($cfg.SkipCertificateCheck) { $params.SkipCertificateCheck = $true } $resp = Invoke-RestMethod @params foreach ($line in ($resp -split "`n")) { $line = $line.Trim() if (-not $line) { continue } $parts = $line -split '\|', 8 if ($parts.Count -lt 8) { continue } $nodeId = if ($parts[0] -match '^\d+$') { [int]$parts[0] } else { $null } if (-not $IncludeController -and $nodeId -eq 1) { continue } $rec = [PSCustomObject]@{ PSTypeName = 'PwrHass.ZWaveNode' NodeId = $nodeId Manufacturer = $parts[1] Model = $parts[2] SoftwareVersion = $parts[3] HardwareVersion = $parts[4] Name = $parts[5] DeviceId = $parts[6] EntryId = $parts[7] } $rec } } |