Public/Device/Get-LifxDeviceColor.ps1
|
<#
.SYNOPSIS Get the color of a Lifx device .DESCRIPTION Returns the HSBK values of a device. Hue will be a range between 0-360 degrees and Saturation/Brightness between 0-100 percent. If a device is multi-zoned (as determined from Get-LifxDeviceSetting), this will return all Zones and the HSBK values within each Zone. Zones consist of up to 8 HSBK segments. For example, a LIFX Z Strip will have 1 Zone of 8 HSBK values whereas a Neon Flex would have 8 zones, with 60 HSBK values. In the case of the Neon Flex, this means the last Zone would have its last 4 HSBK segments of 0,0,0,0 since 60 can't fit into 7 zones, but it can fit into 8 leaving the last 4 HSKB segments empty since. This cmdlet will discard irrelevant zones. .EXAMPLE Get-LifxDevice | Initialize-LifxDevice | Get-LifxDeviceColor .EXAMPLE Get-LifxDevice | Get-LifxDeviceSetting | Get-LifxDeviceColor #> function Get-LifxDeviceColor { param( #a discovered Lifx bulb (use Get-LifxDevice) [parameter( Position = 0, Mandatory = $true, ValueFromPipeline = $true)] [PSCustomObject[]]$Device ) #declare the counters [int]$Total = $Input.Count [int]$Count = 0 #process $Input | ForEach-Object { #constants $Port = "56700" $localIP = [System.Net.IPAddress]::Parse([System.Net.IPAddress]::Any) $RemoteIpEndPoint = New-Object System.Net.IPEndpoint($localIP, $Port) $receivingUdpClient = $null $receivingUdpClient = New-Object System.Net.Sockets.UDPClient($RemoteIpEndPoint) $receivingUdpClient.Client.Blocking = $true $receivingUdpClient.DontFragment = $true $receivingUdpClient.Client.SetSocketOption([System.Net.Sockets.SocketOptionLevel]::Socket, [System.Net.Sockets.SocketOptionName]::ReuseAddress, $true) $receivingUdpClient.Client.ReceiveTimeout = 3000 #milliseconds #does the device support multizone as defined by Get-LifxDeviceSetting? if ($_.Product.Multizone -eq $true) { [Byte[]]$getColorZonesPacket = New-LifxPacket -Type "GetColorZones" | Convert-LifxPacketToBuffer #get the color zones $send = $receivingUdpClient.SendAsync($getColorZonesPacket, $getColorZonesPacket.Length, $_.IPAddress.Address, $_.IPAddress.Port) #parse the GetColorZones result, this should many StateMultiZone 506 messages that should be received near simultaneously $zones = @() try { while ($true) { # This call blocks until a message is received $result = $receivingUdpClient.Receive([ref]$RemoteIpEndPoint) $zone = [PSCustomObject]@{ #current index of 8 colors Index = $result[37] #array of 8 HSBK colors Colors = @( [PSCustomObject]@{ Color = 0 Hue = [Math]::Round([BitConverter]::ToUInt16($result, 38) / 0xFFFF * 360) Saturation = [Math]::Round([BitConverter]::ToUInt16($result, 40) / 0xFFFF * 100) Brightness = [Math]::Round([BitConverter]::ToUInt16($result, 42) / 0xFFFF * 100) Kelvin = [BitConverter]::ToUInt16($result, 44) } [PSCustomObject]@{ Color = 1 Hue = [Math]::Round([BitConverter]::ToUInt16($result, 46) / 0xFFFF * 360) Saturation = [Math]::Round([BitConverter]::ToUInt16($result, 48) / 0xFFFF * 100) Brightness = [Math]::Round([BitConverter]::ToUInt16($result, 50) / 0xFFFF * 100) Kelvin = [BitConverter]::ToUInt16($result, 52) } [PSCustomObject]@{ Color = 2 Hue = [Math]::Round([BitConverter]::ToUInt16($result, 54) / 0xFFFF * 360) Saturation = [Math]::Round([BitConverter]::ToUInt16($result, 56) / 0xFFFF * 100) Brightness = [Math]::Round([BitConverter]::ToUInt16($result, 58) / 0xFFFF * 100) Kelvin = [BitConverter]::ToUInt16($result, 60) } [PSCustomObject]@{ Color = 3 Hue = [Math]::Round([BitConverter]::ToUInt16($result, 62) / 0xFFFF * 360) Saturation = [Math]::Round([BitConverter]::ToUInt16($result, 64) / 0xFFFF * 100) Brightness = [Math]::Round([BitConverter]::ToUInt16($result, 66) / 0xFFFF * 100) Kelvin = [BitConverter]::ToUInt16($result, 68) } [PSCustomObject]@{ Color = 4 Hue = [Math]::Round([BitConverter]::ToUInt16($result, 70) / 0xFFFF * 360) Saturation = [Math]::Round([BitConverter]::ToUInt16($result, 72) / 0xFFFF * 100) Brightness = [Math]::Round([BitConverter]::ToUInt16($result, 74) / 0xFFFF * 100) Kelvin = [BitConverter]::ToUInt16($result, 76) } [PSCustomObject]@{ Color = 5 Hue = [Math]::Round([BitConverter]::ToUInt16($result, 78) / 0xFFFF * 360) Saturation = [Math]::Round([BitConverter]::ToUInt16($result, 80) / 0xFFFF * 100) Brightness = [Math]::Round([BitConverter]::ToUInt16($result, 82) / 0xFFFF * 100) Kelvin = [BitConverter]::ToUInt16($result, 84) } [PSCustomObject]@{ Color = 6 Hue = [Math]::Round([BitConverter]::ToUInt16($result, 86) / 0xFFFF * 360) Saturation = [Math]::Round([BitConverter]::ToUInt16($result, 88) / 0xFFFF * 100) Brightness = [Math]::Round([BitConverter]::ToUInt16($result, 90) / 0xFFFF * 100) Kelvin = [BitConverter]::ToUInt16($result, 92) } [PSCustomObject]@{ Color = 7 Hue = [Math]::Round([BitConverter]::ToUInt16($result, 94) / 0xFFFF * 360) Saturation = [Math]::Round([BitConverter]::ToUInt16($result, 96) / 0xFFFF * 100) Brightness = [Math]::Round([BitConverter]::ToUInt16($result, 98) / 0xFFFF * 100) Kelvin = [BitConverter]::ToUInt16($result, 100) } ) } $zones += $zone } } catch { Write-Warning "$($_.Exception.Message). Get-LifxDeviceColor, Line 123. Its likely that the MultiZone LIFX device responded with its zones. This message can be suppressed with -WarningAction Ignore" } #add the Zones (count of items that can be colored in) and MultiZone which contains the 8 colors in each index $_ | Add-Member -Name 'Zones' -Type NoteProperty -Value $result[36] -Force $_ | Add-Member -Name 'MultiZone' -Type NoteProperty -Value $zones -Force #if there is more than 1 index, remove invalid colors from the last one if ($_.MultiZone.Count -gt 1) { $lastZone = $_.MultiZone[$_.MultiZone.count - 1] $arrayCountToKeep = 7 - ($_.MultiZone.Colors.count - $_.Zones) ($_.MultiZone | Where-Object { $_.Index -eq $lastZone.Index }).Colors = $lastZone.Colors[0..$arrayCountToKeep] } #shut the udp client down $receivingUdpClient.Dispose() $receivingUdpClient.Close() $Count++ [int]$percentComplete = ($Count / $Total * 100) Write-Progress -Activity "Retrieving Device Color Zones" -PercentComplete $percentComplete -Status ("$($_.Name) color zone retrieved - " + $percentComplete + "%") return $_ } else { #Device packets [Byte[]]$getColorPacket = New-LifxPacket -Type "GetColor" | Convert-LifxPacketToBuffer #get the color $send = $receivingUdpClient.SendAsync($getColorPacket, $getColorPacket.Length, $_.IPAddress.Address, $_.IPAddress.Port) #wait a second Start-Sleep -Seconds 1 #parse the GetColor result $result = $receivingUdpClient.Receive([ref]$RemoteIpEndPoint) $hue = [Math]::Round(([System.BitConverter]::ToUInt16($result, 36) * 360) / 0x10000) $saturation = (([System.BitConverter]::ToUInt16($result, 38)) % 0xFFFF) * 100 $brightness = (([System.BitConverter]::ToUInt16($result, 40)) / 0xFFFF) * 100 $kelvin = ([System.BitConverter]::ToUInt16($result, 42)) #$powerState = ([System.BitConverter]::ToUInt16($result, 46)) -gt 0 #on/off #$itemName = [System.Text.Encoding]::UTF8.GetString($result, 48, 32) #name #set the GetColor values $_ | Add-Member -Name 'Hue' -Type NoteProperty -Value $hue -Force $_ | Add-Member -Name 'Saturation' -Type NoteProperty -Value $saturation -Force $_ | Add-Member -Name 'Brightness' -Type NoteProperty -Value $brightness -Force $_ | Add-Member -Name 'Kelvin' -Type NoteProperty -Value $kelvin -Force #$_ | Add-Member -Name 'Power' -Type NoteProperty -Value $powerState -Force #$_ | Add-Member -Name 'Name' -Type NoteProperty -Value $itemName -Force #shut the udp client down $receivingUdpClient.Dispose() $receivingUdpClient.Close() $Count++ [int]$percentComplete = ($Count / $Total * 100) Write-Progress -Activity "Retrieving Device Color" -PercentComplete $percentComplete -Status ("$($_.Name) color retrieved - " + $percentComplete + "%") return $_ } } } |