PixooPS.psm1


function Find-Pixoo {
    <#
    .SYNOPSIS
    Finds the IP address of any Pixoo64 device on the local network
 
    .DESCRIPTION
    Finds the IP address of any Pixoo64 device on the local network
 
    .PARAMETER IPAddress
    Specify only if you already know what the IP address is
    Can also be used to verify that the specified IP address is a Pixoo64 device
 
    .EXAMPLE
    Find-Pixoo
 
    .NOTES
    General notes
    #>

    param(
        $IPAddress
    )
    begin {
        function Get-PixooIP {
            if ($env:PixooIP -and (Test-Connection -TargetName $env:PixooIP -Ping -IPv4 -Count 1 -TimeoutSeconds 1 -Quiet -ErrorAction SilentlyContinue)) {
                return $env:PixooIP
            }
            $network = (
                (
                    Get-NetIPInterface -ConnectionState Connected -AddressFamily IPv4 -Dhcp Enabled |
                    Get-NetIPAddress
                ).IPAddress -split '\.'
            )[0..2] -join '.'
            $IPList = 1..254 | ForEach-Object { "$(($network -split '\.')[0..2] -join '.').$_" }
            $PassFailList = Test-Connection -ComputerName $IPList -TcpPort 80 -IPv4 -TimeoutSeconds 1 -ErrorAction SilentlyContinue
            for ($i = 0; $i -lt $PassFailList.Count; $i++) {
                if ($PassFailList[$i]){
                    $IPList[$i]
                }
            }
        }
    }
    process {
        if ($IPAddress) {
            $get = Invoke-RestMethod -Uri "http://$IPAddress/get"
            if ($get -like "*Hello World divoom!*") {
                $env:PixooIP = $IPAddress
                $IPAddress
            }
        } else {
            $IPs = Get-PixooIP
            if ($IPs.Count -eq 0) {
                throw "Pixoo64 not found on network"
            }
            foreach ($Ip in $IPs) {
                try {
                    $get = Invoke-RestMethod -Uri "http://$Ip/get"
                    if ($get -like "*Hello World divoom!*") {
                        $env:PixooIP = $Ip
                        $Ip
                        Write-Information "Pixoo64 found on network at $Ip"
                    }
                    break
                } catch {
                    Write-Information "Pixoo64 not found on network at $Ip"
                }
            }
        }
    }
}
function Get-Channel {
    <#
    .SYNOPSIS
    Returns what channel a Pixoo64 device is currently on
 
    .DESCRIPTION
    Returns what channel a Pixoo64 device is currently on
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Get-Channel
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param (
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command = "Channel/GetIndex"
        } | ConvertTo-Json -Compress

        $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
        if (($res.error_code -eq 0) -or $res.SelectIndex) {
            Write-Verbose "Success"
            $ret = switch ($res.SelectIndex) {
                0 { "Faces" }
                1 { "Cloud Channel" }
                2 { "Visualizer" }
                3 { "Custom" }
                Default { "Error" }
            }
            return $ret
        } else {
            Write-Error "Failed to get channel, Error: $($res.error_code)"
            return $null
        }
    }
}
function Get-Face {
    <#
    .SYNOPSIS
    Gets the current face of a Pixoo64 device
 
    .DESCRIPTION
    Gets the current face of a Pixoo64 device
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Get-Face
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param (
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command = "Channel/GetClockInfo"
        } | ConvertTo-Json -Compress

        $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
        if ($res) {
            Write-Verbose "Success"
            return $ret
        } else {
            Write-Error "Failed to set Face, Error: $($res.error_code)"
            return $null
        }
    }
}
function Get-FaceList {
    <#
    .SYNOPSIS
    Get a list of faces from Divoom
 
    .DESCRIPTION
    Get a list of faces from Divoom
 
    .PARAMETER Type
    The type of face to get from Divoom. Defaults to normal
 
    .PARAMETER Page
    The page number. Defaults to 1.
 
    .EXAMPLE
    Get-FaceList
 
    .EXAMPLE
    Get-FaceList -Type Social
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param (
        [Parameter()]
        [ValidateSet("Social", "normal", "financial", "Game", "HOLIDAYS", "TOOLS")]
        $Type = "normal",
        [Parameter()]
        [ValidateRange(1, 30)]
        $Page = 1
    )
    process {
        $Url = "https://app.divoom-gz.com/Channel/GetDialList"
        $Body = [PSCustomObject]@{
            DialType = $Type
            Page     = $Page
        } | ConvertTo-Json -Compress
        $ret = Invoke-RestMethod -Method Post -Uri $Url -Body $Body
        if ($ret.ReturnCode -eq 0) {
            return $ret.DialList
        }
    }
}
function Get-FaceType {
    <#
    .SYNOPSIS
    Get a list of face(DialType) from Divoom
 
    .DESCRIPTION
    Get a list of face(DialType) from Divoom
 
    .EXAMPLE
    Get-FaceType
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param ()
    process {
        $Url = "https://app.divoom-gz.com/Channel/GetDialType"
        $ret = Invoke-RestMethod -Method Post -Uri $Url
        if ($ret.ReturnCode -eq 0) {
            return $ret.DialTypeList
        }
    }
}
function Get-PixooSetting {
    <#
    .SYNOPSIS
    Gets the settings of a Pixoo64 device
 
    .DESCRIPTION
    Gets the settings of a Pixoo64 device
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Get-PixooSetting
 
    .NOTES
    General notes
    #>

    [OutputType([PSObject])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command = "Channel/GetAllConf"
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Get settings from device")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $res
            } else {
                throw "Failed to get settings, Error: $($res.error_code)"

            }
        }
    }
}
function Invoke-PlayGif {
    <#
    .SYNOPSIS
    Sends a link to a gif, from an http site, to a Pixoo64 device.
 
    .DESCRIPTION
    Sends a link to a gif, from an http site, to a Pixoo64 device.
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .PARAMETER UrlGif
    An http url that points to a gif
 
    .EXAMPLE
    Invoke-PlayGif -Url "http://example.com/MyAnimation.gif"
 
    .NOTES
    General notes
    #>

    [OutputType([Boolean])]
    [CmdletBinding()]
    param(
        [Parameter()]
        [string]
        $DeviceIP,
        [Parameter(Mandatory = $true)]
        [string]
        $UrlGif
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }
        if ($UrlGif -like "http://*") {
            $get = Invoke-RestMethod -Uri "http://$DeviceIP/get"
            if ($get -like "*Hello World divoom!*") {
                $Body = [PSCustomObject]@{
                    Command  = "Device/PlayTFGif"
                    FileType = 2
                    FileName = $UrlGif
                } | ConvertTo-Json -Compress

                $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
                if ($res.error_code -and $res.error_code -eq 0) {
                    Write-Verbose "Success"
                    $Body = [PSCustomObject]@{
                        Command = "Draw/GetHttpGifId"
                    } | ConvertTo-Json -Compress

                    $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
                    if ($res.error_code -and $res.error_code -eq 0) {
                        $res.PicId

                        Write-Verbose "Success"
                        return $true
                        # Don't know if this is needed
                        # Set-Channel -DeviceIP "192.168.1.199" -Channel Cloud
                    }
                } else {
                    Write-Error "Failed to send gif to $DeviceIP."
                    return $false
                }
            } else {
                Write-Error "Device not found. Please check the IP address."
                return $false
            }
        } else {
            Write-Error "Invalid url: https isn't supported."
            return $false
        }
    }
}
function Reset-CountDown {
    <#
    .SYNOPSIS
    Reset the current count down timer on a Pixoo64 device
 
    .DESCRIPTION
    Reset the current count down timer on a Pixoo64 device
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Reset-CountDown
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command = "Tools/SetStopWatch"
            Status  = 2
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Stops the countdown timer")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to stop countdown, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Set-Brightness {
    <#
    .SYNOPSIS
    Sets the Brightness of a Pixoo64 device
 
    .DESCRIPTION
    Sets the Brightness of a Pixoo64 device.
 
    .PARAMETER Brightness
    The Brightness that you wish a Pixoo64 device to be set to, rangine from 0 to 100
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Set-Brightness -Brightness 0
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateRange(0, 100)]
        [int]
        $Brightness,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command    = "Channel/SetBrightness"
            Brightness = $Brightness
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set Brightness to $Brightness")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set Brightness, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Set-Channel {
    <#
    .SYNOPSIS
    Sets the Channel of a Pixoo64 device
 
    .DESCRIPTION
    Sets the Channel of a Pixoo64 device
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .PARAMETER Channel
    The channel that you want
 
    .EXAMPLE
    Set-Channel -Channel Faces
 
    .EXAMPLE
    Set-Channel -Channel Visualizer
 
    .NOTES
    General notes
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([boolean])]
    param(
        [Parameter()]
        [string]
        $DeviceIP,
        [Parameter(Mandatory = $true)]
        [ValidateSet("Faces", "Cloud", "Visualizer", "Custom")]
        [String]
        $Channel
    )
    begin {
        $Index = if ($Channel -eq "Faces") {
            0
        } elseif ($Channel -eq "Cloud") {
            1
        } elseif ($Channel -eq "Visualizer") {
            2
        } elseif ($Channel -eq "Custom") {
            3
        } else {
            Write-Error "Invalid channel"
        }
    }
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }
        $Body = [PSCustomObject]@{
            Command     = "Channel/SetIndex"
            SelectIndex = $Index
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set Channel to $Index")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -and $res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set channel"
                return $false
            }
        }
        return $false
    }
}
function Set-CloudChannel {
    <#
    .SYNOPSIS
    Sets the Cloud Channel of a Pixoo64 device
 
    .DESCRIPTION
    Sets the Cloud Channel of a Pixoo64 device, similar to Set-Face.
 
    .PARAMETER Channel
    The Eq Position that you wish a Pixoo64 device to be set to, 0 or greater.
    0: Recommended Gallery, 1: Favourite, 2: Subscribed Artists
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Set-CloudChannel -EqPosition 0
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateRange(0, 2)]
        [int]
        $Channel,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command    = "Channel/CloudIndex"
            Index   = $Channel
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set Cloud Channel to $Channel")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set Cloud Channel, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Set-CustomPage {
    <#
    .SYNOPSIS
    Sets the custom page of a Pixoo64 device
 
    .DESCRIPTION
    Sets the custom page of a Pixoo64 device, similar to Set-Face.
 
    .PARAMETER Page
    The custom index that you wish a Pixoo64 device to be set to, ranging from 0 to 2
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Set-CustomPage -Page 0
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateRange(0, 2)]
        [int]
        $Page,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command         = "Channel/SetCustomPageIndex"
            CustomPageIndex = $Page
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set custom page to $Page")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set custom page, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Set-Face {
    <#
    .SYNOPSIS
    Sets the face of a Pixoo64 device
 
    .DESCRIPTION
    Sets the face of a Pixoo64 device
 
    .PARAMETER FaceId
    The face id that you wish a Pixoo64 device to be set to
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    $Face = Get-FaceList | Where-Object { $_.Name -like "Big Time" }
    Set-Face -FaceId $Face.ClockId -DeviceIP (Find-Pixoo | Select-Object -First 1)
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory = $true)]
        [int]
        $FaceId,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command = "Channel/SetClockSelectId"
            ClockId = $FaceId
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set Face to $FaceId")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set Face, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Set-Noise {
    <#
    .SYNOPSIS
    Set the NoiseStatus on a Pixoo64 device
 
    .DESCRIPTION
    Set the NoiseStatus on a Pixoo64 device
 
    .PARAMETER On
    Set the NoiseStatus to 1, ie On
 
    .PARAMETER Off
    Set the NoiseStatus to 0, ie Off
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Set-Noise -On
 
    .EXAMPLE
    Set-Noise -Off
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter()]
        [switch]
        $On,
        [Parameter()]
        [switch]
        $Off,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $NoiseStatus = if($On) {
            1
        }elseif($Off){
            0
        }
        $Body = [PSCustomObject]@{
            Command = "Tools/SetNoiseStatus"
            NoiseStatus = $NoiseStatus
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set NoiseStatus to $NoiseStatus")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set NoiseStatus, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Set-PixooLocation {
    <#
    .SYNOPSIS
    Sets the Latitude and Longitude Location of a Pixoo64 device for it to get weather information
 
    .DESCRIPTION
    Sets the Latitude and Longitude Location of a Pixoo64 device for it to get weather information
 
    .PARAMETER Latitude
    The Latitude of a Pixoo64 device
 
    .PARAMETER Longitude
    The Longitude of a Pixoo64 device
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Set-PixooLocation -Latitude 0 -Longitude 0
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateRange(-90, 90)]
        [Alias("lat", "lt")]
        [Single]
        $Latitude,
        [Parameter(Mandatory = $true)]
        [ValidateRange(-180, 180)]
        [Alias("long", "lng", "lon", "ln")]
        [Single]
        $Longitude,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command   = "Sys/LogAndLat"
            Latitude  = $Latitude
            Longitude = $Longitude
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set LogAndLat to $Latitude,$Longitude")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set LogAndLat, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Set-PixooTimeZone {
    <#
    .SYNOPSIS
    Sets the Date and Time of a Pixoo64 device
 
    .DESCRIPTION
    Sets the Date and Time of a Pixoo64 device.
 
    .PARAMETER Date
    The Date and Time that you wish a Pixoo64 device to be set to. Accepts a DateTime object.
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Set-PixooTimeZone
 
    .EXAMPLE
    Set-PixooTimeZone -Date (Get-Date)
 
    .EXAMPLE
    Get-Date | Set-PixooTimeZone
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(ValueFromPipeline)]
        [DateTime]
        $Date,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }
        if (-not $Date) {
            $Date = Get-Date
        }

        $Body = [PSCustomObject]@{
            Command = "Device/SetUTC"
            Utc     = ([DateTimeOffset]$Date).ToUnixTimeSeconds()
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set Date to $Date")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set Date, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Set-PixooTimeZone {
    <#
    .SYNOPSIS
    Sets the TimeZone of a Pixoo64 device
 
    .DESCRIPTION
    Sets the TimeZone of a Pixoo64 device.
 
    .PARAMETER TimeZone
    The TimeZone that you wish a Pixoo64 device to be set to. Must be in the GMT format, like GMT-5/GMT+1
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Set-PixooTimeZone -TimeZone "GMT-5"
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateRange(0, 100)]
        [string]
        $TimeZone,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command    = "Sys/TimeZone"
            TimeZoneValue = $TimeZone
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set TimeZone to $TimeZone")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set TimeZone, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Set-ScoreBoard {
    <#
    .SYNOPSIS
    Controls the scoreboard on a Pixoo64 device
 
    .DESCRIPTION
    Controls the scoreboard on a Pixoo64 device
 
    .PARAMETER BlueScore
    Sets the blue score
 
    .PARAMETER RedScore
    Sets the red score
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Set-ScoreBoard
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter()]
        [ValidateRange(0, 999)]
        [Alias("Blue", "b")]
        [int]
        $BlueScore = 0,
        [Parameter()]
        [ValidateRange(0, 999)]
        [Alias("Red", "r")]
        [int]
        $RedScore = 0,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command   = "Tools/SetScoreBoard"
            BlueScore = $BlueScore
            RedScore  = $RedScore
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set Blue to $BlueScore and Red to $RedScore")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set countdown, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Set-Screen {
    <#
    .SYNOPSIS
    Turns off and on the screen of a Pixoo64 device
 
    .DESCRIPTION
    Turns off and on the screen of a Pixoo64 device
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .PARAMETER On
    Used to turn on the screen
 
    .PARAMETER Off
    Used to turn off the screen
 
    .EXAMPLE
    Set-Screen -On
 
    .EXAMPLE
    Set-Screen -Off
 
    .NOTES
    General notes
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter()]
        [string]
        $DeviceIP,
        [Parameter(Mandatory, ParameterSetName = "On")]
        [switch]
        $On,
        [Parameter(Mandatory, ParameterSetName = "Off")]
        [switch]
        $Off
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }
        $Body = [PSCustomObject]@{
            Command = "Channel/OnOffScreen"
            OnOff   = if ($On) { 1 }elseif ($Off) { 0 }else { throw "On and Off not specified?!" }
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Turn screen $(if ($On) { "On" }elseif ($Off) { "Off" }else{"Error"})")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 1) {
                throw "Pixoo64 returned error_code of $($res.error_code)"
            }
        }

    }
}
function Set-Visualizer {
    <#
    .SYNOPSIS
    Sets the Visualizer of a Pixoo64 device
 
    .DESCRIPTION
    Sets the Visualizer of a Pixoo64 device, similar to Set-Face.
 
    .PARAMETER EqPosition
    The Eq Position that you wish a Pixoo64 device to be set to, 0 or greater
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Set-Visualizer -EqPosition 0
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNull()]
        [int]
        $EqPosition,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command    = "Channel/SetEqPosition"
            EqPosition = $EqPosition
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set EqPosition to $EqPosition")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set EqPosition, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Start-CountDown {
    <#
    .SYNOPSIS
    Start a count down timer on a Pixoo64 device
 
    .DESCRIPTION
    Start a count down timer on a Pixoo64 device
 
    .PARAMETER Hours
    How many hours the count down should last
 
    .PARAMETER Minutes
    How many minutes the count down should last
 
    .PARAMETER Seconds
    How many seconds the count down should last
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Start-CountDown
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter()]
        [int]
        $Hours = 0,
        [Parameter()]
        [int]
        $Minutes = 1,
        [Parameter()]
        [int]
        $Seconds = 0,
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Minutes = if ($Hours -gt 1) {
            ($Hours * 60) + $Minutes
        } else {
            $Minutes
        }

        $Body = [PSCustomObject]@{
            Command = "Tools/SetTimer"
            Minute  = $Minutes
            Second  = $Seconds
            Status  = 1
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Set Minutes to $Minutes and Seconds to $Seconds")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to set countdown, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}
function Stop-CountDown {
    <#
    .SYNOPSIS
    Stop a count down timer on a Pixoo64 device
 
    .DESCRIPTION
    Stop a count down timer on a Pixoo64 device
 
    .PARAMETER DeviceIP
    The device's IP address, not needed if a Pixoo64 device is already in your ARP cache
 
    .EXAMPLE
    Stop-CountDown
 
    .NOTES
    General notes
    #>

    [OutputType([boolean])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [string]
        $DeviceIP
    )
    process {
        if (-not $DeviceIP) {
            $DeviceIP = Find-Pixoo | Select-Object -First 1
        }

        $Body = [PSCustomObject]@{
            Command = "Tools/SetStopWatch"
            Status  = 0
        } | ConvertTo-Json -Compress
        if ($PSCmdlet.ShouldProcess("$DeviceIP", "Stops the countdown timer")) {
            $res = Invoke-RestMethod -Method Post -Uri "http://$DeviceIP/post" -Body $Body
            if ($res.error_code -eq 0) {
                Write-Verbose "Success"
                return $true
            } else {
                Write-Error "Failed to stop countdown, Error: $($res.error_code)"
                return $false
            }
        }
        return $false
    }
}