Files
Home-AssistantConfig/tools/holiday_lighting_coverage.ps1
T
2026-06-29 17:09:37 -04:00

162 lines
4.8 KiB
PowerShell

param(
[int]$Months = 24,
[datetime]$StartDate = (Get-Date).Date
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$repoRoot = Split-Path -Parent $PSScriptRoot
$holidayPath = Join-Path $repoRoot 'config/www/json_data/holidays.json'
$flagPath = Join-Path $repoRoot 'config/www/json_data/flag_days.json'
$scenePath = Join-Path $repoRoot 'config/scene/monthly_colors.yaml'
$endDate = $StartDate.Date.AddMonths($Months)
$errors = @()
function Read-JsonFile {
param(
[Parameter(Mandatory = $true)]
[string]$Path
)
if (-not (Test-Path -LiteralPath $Path)) {
throw "Missing JSON file: $Path"
}
try {
return Get-Content -Raw -LiteralPath $Path | ConvertFrom-Json -AsHashtable
} catch {
throw "Invalid JSON in $Path`: $($_.Exception.Message)"
}
}
function Parse-DateKey {
param(
[Parameter(Mandatory = $true)]
[string]$DateText
)
return [datetime]::Parse(
$DateText,
[Globalization.CultureInfo]::InvariantCulture
).Date
}
function Get-DynamicEvents {
param(
[Parameter(Mandatory = $true)]
[object]$DynamicMap,
[Parameter(Mandatory = $true)]
[string[]]$Names
)
$events = @()
foreach ($dateText in $DynamicMap.Keys) {
$eventDate = Parse-DateKey -DateText ([string]$dateText)
$eventName = [string]$DynamicMap[$dateText]
if ($eventDate -ge $StartDate.Date -and $eventDate -lt $endDate -and $Names -contains $eventName) {
$events += [pscustomobject]@{
Name = $eventName
Date = $eventDate
}
}
}
return $events | Sort-Object Date, Name
}
$holidayJson = Read-JsonFile -Path $holidayPath
$flagJson = Read-JsonFile -Path $flagPath
$holidayData = $holidayJson['MAJOR_US']
$flagData = $flagJson['Flag_Days_US']
$holidayStatic = $holidayData['static']
$holidayDynamic = $holidayData['dynamic']
$flagDynamic = $flagData['dynamic']
$sceneText = Get-Content -Raw -LiteralPath $scenePath
$sceneNames = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::Ordinal)
foreach ($match in [regex]::Matches($sceneText, '(?m)^\s*-\s+name:\s+(month_[A-Za-z0-9_]+_colors)\s*$')) {
[void]$sceneNames.Add($match.Groups[1].Value)
}
$lightingModes = @(
'standard',
'RWB',
'new_years_day',
'valentine',
'mardi_gras',
'pi',
'st_patty',
'easter',
'starwars',
'cinco_de_mayo',
'mothers_day',
'fathers_day',
'halloween',
'veterans',
'thanksgiving',
'hanukkah',
'christmas'
)
foreach ($mode in $lightingModes) {
$sceneName = "month_${mode}_colors"
if (-not $sceneNames.Contains($sceneName)) {
$errors += "Missing scene for lighting mode '$mode': expected $sceneName in $scenePath"
}
}
$staticRequirements = @(
@{ Key = '1/1'; Name = 'New Years Day' },
@{ Key = '2/14'; Name = 'Valentines Day' },
@{ Key = '3/14'; Name = 'Pi Day' },
@{ Key = '3/17'; Name = 'St. Patricks Day' },
@{ Key = '5/4'; Name = 'Star Wars Day' },
@{ Key = '5/5'; Name = 'Cinco de Mayo' },
@{ Key = '7/4'; Name = 'Independence Day' },
@{ Key = '10/31'; Name = 'Halloween' },
@{ Key = '11/11'; Name = 'Veterans Day' },
@{ Key = '12/25'; Name = 'Christmas Day' },
@{ Key = '12/31'; Name = 'New Years Eve' }
)
foreach ($requirement in $staticRequirements) {
if (-not $holidayStatic.ContainsKey($requirement.Key)) {
$errors += "Missing static holiday key $($requirement.Key) for $($requirement.Name)"
}
}
$dynamicRequirements = @(
@{ Name = 'Easter Sunday'; Source = 'holidays'; Map = $holidayDynamic },
@{ Name = 'Mothers Day'; Source = 'holidays'; Map = $holidayDynamic },
@{ Name = 'Fathers Day'; Source = 'holidays'; Map = $holidayDynamic },
@{ Name = 'Thanksgiving Day'; Source = 'holidays'; Map = $holidayDynamic },
@{ Name = 'Memorial Day'; Source = 'flag_days'; Map = $flagDynamic },
@{ Name = 'Labor Day'; Source = 'flag_days'; Map = $flagDynamic }
)
foreach ($requirement in $dynamicRequirements) {
$events = @(Get-DynamicEvents -DynamicMap $requirement.Map -Names @($requirement.Name))
if ($events.Count -eq 0) {
$errors += "No $($requirement.Source) calendar coverage for '$($requirement.Name)' between $($StartDate.ToString('yyyy-MM-dd')) and $($endDate.ToString('yyyy-MM-dd'))"
}
}
Write-Host "Holiday lighting coverage window: $($StartDate.ToString('yyyy-MM-dd')) to $($endDate.ToString('yyyy-MM-dd'))"
Write-Host "JSON: OK - parsed holidays.json and flag_days.json"
Write-Host "Scenes: $($sceneNames.Count) monthly scenes found"
if ($errors.Count -gt 0) {
foreach ($err in $errors) {
Write-Host "ERROR: $err"
}
exit 1
}
foreach ($requirement in $dynamicRequirements) {
$events = @(Get-DynamicEvents -DynamicMap $requirement.Map -Names @($requirement.Name))
$dates = ($events | ForEach-Object { $_.Date.ToString('yyyy-MM-dd') }) -join ', '
Write-Host "$($requirement.Name): $dates"
}
Write-Host "Coverage OK: required lighting scenes and dynamic holiday dates are present for the requested window."