Add-HueSchedule.ps1
function Add-HueSchedule { <# .Synopsis Adds a schedule to a Hue Bridge .Description Adds a new schedule to a Hue Bridge .Example Add-HueSchedule -Daily -Name "Shift to Sunset" -Description "Shift to warmer and brighter as the day draws to a close" -Command (Set-Light -ColorTemperature 400 -Luminance 1 -TransitionTime '01:30:00' -OutputInput) -LocalTime "3:00 PM" .Link Get-HueSchedule .Link Get-HueBridge #> [OutputType([PSObject])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("Test-ForParameterSetAmbiguity", "", Justification="Ambiguity desired")] param( # The name of the schedule [Parameter(ValueFromPipelineByPropertyName)] [string] $Name, # A description for the schedule [Parameter(ValueFromPipelineByPropertyName)] [string] $Description, # The command that will be run [Parameter(Mandatory,ValueFromPipelineByPropertyName)] [PSObject] $Command, # The time of the command [Parameter(Mandatory,ParameterSetName='LocalTime',Position=0,ValueFromPipelineByPropertyName)] [Alias('At')] [DateTime] $LocalTime, # If set, will run daily [Parameter(ParameterSetName='LocalTime',Position=1,ValueFromPipelineByPropertyName)] [switch] $Daily, # The days of the week the schedule will be executed (1 is Sunday, 7 is Saturday). [Parameter(ParameterSetName='LocalTime',Position=2,ValueFromPipelineByPropertyName)] [ValidateRange(1,7)] [byte[]] $DayOfWeek, # The time the schedule should last [Parameter(ParameterSetName='LocalTime',Position=3,ValueFromPipelineByPropertyName)] [Alias('ForTimeframe','ForTimespan')] [Timespan] $For, # Sets a countdown timer. This timer will occur once, in a given timespan. [Parameter(Mandatory=$true,Position=0,ParameterSetName='InTimespan',ValueFromPipelineByPropertyName)] [Alias('InTime', 'InTimespan')] [Timespan] $In, # If set, will repeat every N timeframe [Parameter(Mandatory=$true,Position=0,ParameterSetName='EveryTimespan',ValueFromPipelineByPropertyName)] [Alias('EveryTime', 'EveryTimespan')] [Timespan] $Every, # If provided, the schedule will execute at a random time within the provided timespan. [Parameter(ParameterSetName='LocalTime',Position=4,ValueFromPipelineByPropertyName)] [Parameter(ParameterSetName='InTimespan',Position=1,ValueFromPipelineByPropertyName)] [Alias('Jitter', 'Around')] [Timespan] $Within, # If provided, the schedule will only run on the bridge with a particular device ID [Parameter(ValueFromPipelineByPropertyName)] [string] $DeviceID, # If provided, the schedule will only run on the bridge found at the provided IP address [Parameter(ValueFromPipelineByPropertyName)] [Alias('IP')] [IPAddress] $IPAddress ) begin { $dayBits = @{ 1 = 1 # Sunday 2 = 64 # Monday 3 = 32 # Tuesday 4 = 16 # Wednesday 5 = 8 # Thursday 6 = 4 # Friday 7 = 2 # Saturday } } process { $restIn = @{} if ($Name) { $restIn.name = $Name } if ($Description) { $restIn.description = $Description } $restIn.command = if ($Command -is [Collections.IDictionary]) { [PSCustomObject]$Command } else { $Command } $timeparts = @( if ($PSCmdlet.ParameterSetName -eq 'LocalTime') { #region Weekly Schedules if ($DayOfWeek) { # If we want a day of week, # We'll have to mask some bits. $dayMask = 0 foreach ($d in $DayOfWeek) { # Just walk thru the days $daymask = $daymask -bxor $dayBits[$d -as [int]] # And XOR the 2^(d-1) } "W$daymask" # Then we take the day mask 'T{0:d2}:{1:d2}:{2:d2}' -f # and append the time. $LocalTime.Hour, $LocalTime.Minute, $LocalTime.Second if ($For) { $until = $LocalTime + $For 'T{0:d2}:{1:d2}:{2:d2}' -f # and append the time. $Until.Hour, $Until.Minute, $Until.Second + $(if ($Within) {"A$($Within)" }) } } #endregion Weekly Schedules #region Daily Schedules elseif ($Daily) { # If we're running every day, 'W127' # the date part goes away, 'T{0:d2}:{1:d2}:{2:d2}' -f # and the time is formatted after. $LocalTime.Hour, $LocalTime.Minute, $LocalTime.Second + $(if ($Within) { "A$($Within)" }) if ($For) { $until = $LocalTime + $For 'T{0:d2}:{1:d2}:{2:d2}' -f # and append the time. $Until.Hour, $Until.Minute, $Until.Second + $(if ($Within) {"A$($Within)" }) } } #endregion Daily Schedules elseif ($for) { 'T{0:d2}:{1:d2}:{2:d2}' -f # and the time is formatted after. $LocalTime.Hour, $LocalTime.Minute, $LocalTime.Second if ($For) { $until = $LocalTime + $For 'T{0:d2}:{1:d2}:{2:d2}' -f # and append the time. $Until.Hour, $Until.Minute, $Until.Second + $(if ($Within) {"A$($Within)" }) } } else { # If they really only want this once, life is easy $LocalTime.ToString('s') + $(if ($Within) { "A$($Within)" }) } } elseif ($PSCmdlet.ParameterSetName -eq 'InTimespan') { "PT$In" + $(if ($Within) { "A$($Within)" }) } elseif ($PSCmdlet.ParameterSetName -eq 'EveryTimespan') { "R/PT$Every" + $(if ($Within) { "A$($Within)" }) } ) # $restin = & $SetLightScheduleInput $restin.localtime = $timeparts -join '/' $restin.recycle = $false $scheduleExists = Get-HueSchedule -Name $Name -ExactMatch $httpVerb = 'POST' $httpCommand = 'schedules' if ($scheduleExists) { $httpVerb = 'PUT' $httpCommand = "schedules/$($scheduleExists.ID)" $restin.Remove('Recycle') } if (-not $restin.status) { $restin.status = 'enabled' } Get-HueBridge | Where-Object { if ($DeviceID -and $_.DeviceID -ne $DeviceID) { return $false } if ($IPAddress -and $_.IPAddress -ne $IPAddress) { return $false } $true } | Send-HueBridge -Command $httpCommand -Method $httpVerb -Data $restIn } } |