Watch-NanoLeaf.ps1
function Watch-NanoLeaf { <# .Synopsis Watches a NanoLeaf for touch events .Description Watches a NanoLeaf for touch events. A background job is launched to monitor for UDP messages from a given Nanoleaf. These messages are unpacked and translated into PowerShell events: * NanoLeaf.Touch.Hover * NanoLeaf.Touch.Hold * NanoLeaf.Touch.Down * NanoLeaf.Touch.Up * NanoLeaf.Touch.Swipe .Link Get-NanoLeaf .Example Watch-NanoLeaf #> [OutputType([Management.Automation.Job])] param( # The IP Address of the NanoLeaf. [Parameter(ValueFromPipelineByPropertyName)] [IPAddress] $IPAddress = $([IPAddress]::any), # The nanoleaf token [Parameter(ValueFromPipelineByPropertyName)] [string] $NanoLeafToken, # The UDP port used for TouchStreamData [Parameter(ValueFromPipelineByPropertyName)] [string] $TouchEventsPort = $(Get-Random -Minimum 250 -Maximum 5kb) ) begin { #region Declare ScriptBlocks $watchNanoLeafTouchUDP = { param([IPAddress]$ipaddress, [int]$TouchPort) Register-EngineEvent -SourceIdentifier NanoLeaf.Touch.Hover -Forward Register-EngineEvent -SourceIdentifier NanoLeaf.Touch.Hold -Forward Register-EngineEvent -SourceIdentifier NanoLeaf.Touch.Down -Forward Register-EngineEvent -SourceIdentifier NanoLeaf.Touch.Up -Forward Register-EngineEvent -SourceIdentifier NanoLeaf.Touch.Swipe -Forward $udpSvr= [Net.Sockets.UdpClient]::new() $endpoint = [Net.IpEndpoint]::new([ipaddress]::Any, $TouchPort) try { $udpSvr.Client.Bind($endpoint) } catch { Write-Error -Message $_.Message -Exception $_ return } while ($true) { $packet = $udpSvr.Receive([ref]$endpoint) $panelCount = [BitConverter]::ToUInt16($packet[1..0],0) $offset = 2 for ($i =0 ; $i -lt $panelCount; $i++) { $offset = 2 + ($I * 5) $dataByte = [BitConverter]::ToString($packet[$offset + 2]) $eventData = [PSCustomObject]@{ FromPanelID = [BitConverter]::ToUInt16(@($packet[$offset + 1],$packet[$offset]), 0) ToPanelID = [BitConverter]::ToUInt16(@($packet[$offset + 4],$packet[$offset + 3]), 0) TouchStrength = [int]::Parse($dataByte[1], "HexNumber") TouchType = [int]::Parse($dataByte[0], "HexNumber") Packet = $packet } $touchTypes = 'Hover', 'Down', 'Hold', 'Up','Swipe' $touchType = $touchTypes[$eventData.TouchType] New-Event -Sender $IPAddress -EventArguments $eventData -MessageData $eventData -SourceIdentifier "NanoLeaf.Touch.$touchType" | Out-Null } } } $watchNanoLeafJob = { param($IPAddress,$NanoLeafToken, $touchEventPort = 199) $touchEventRequest = [Net.HttpWebRequest]::CreateHttp("http://${IPAddress}:16021/api/v1/$NanoLeafToken/events?id=4") $touchEventRequest.Headers.Add("TouchEventsPort",$touchEventPort) Register-EngineEvent -SourceIdentifier NanoLeaf.Touch.Hover -Forward Register-EngineEvent -SourceIdentifier NanoLeaf.Touch.Hold -Forward Register-EngineEvent -SourceIdentifier NanoLeaf.Touch.Down -Forward Register-EngineEvent -SourceIdentifier NanoLeaf.Touch.Up -Forward Register-EngineEvent -SourceIdentifier NanoLeaf.Touch.Swipe -Forward $touchEventResponse = $touchEventRequest.GetResponse() $responseStream = $touchEventResponse.GetResponseStream() while ($true) { <# $buff = [byte[]]::new(2kb) $bytesRead = $responseStream.Read($buff,0,$buff.Length) if ($bytesRead -gt 0) { [Text.Encoding]::UTF8.GetString($buff -ne 0) } $buff = $null #> Start-Sleep -milliseconds 100 } } #endregion Declare ScriptBlocks } process { #region Handle Broadcast Recursively if ($IPAddress -in [IPAddress]::Any,[IPAddress]::Broadcast) { $splat = @{} + $PsBoundParameters $splat.Remove('IPAddress') $splat.Remove('NanoLeafToken') foreach ($val in $Script:NanoLeafCache.Values) { $splat['IPAddress'] = $val.IPAddress $splat['NanoLeafToken'] = $val.NanoLeafToken Watch-NanoLeaf @splat } return } #endregion Handle Broadcast Recursively Start-Job -ScriptBlock $watchNanoLeafJob -Name "Watch-NanoLeaf-$($IPAddress)" -ArgumentList $IPAddress,$NanoLeafToken, $TouchEventsPort Start-Job -ScriptBlock $watchNanoLeafTouchUDP -Name "Watch-NanoLeaf-$($IPAddress)" -ArgumentList $IPAddress,$TouchEventsPort } } |