Files
DaliACLI/DaliACLI.ps1
Charles 89bf57b665 Création du projet DaliACLI
- CLI PowerShell pour la gestion des sorties DALI adressable (ECxLightDaliA)
  - Action Read : rapport CSV des configurations (une ligne par output)
  - Action Write : modification des propriétés via POST JSON
  - Fallback curl.exe -k pour les automates avec problèmes SSL
2026-04-03 08:42:23 +02:00

236 lines
8.7 KiB
PowerShell

<#
.SYNOPSIS
CLI DALI pour automates Distech Controls Eclypse.
Lecture et ecriture des configurations de sorties DALI adressable (ECxLightDaliA).
.DESCRIPTION
DaliACLI permet de gerer les configurations DALI adressable sur des automates
Distech Controls Eclypse en utilisant leur API REST v2.
Action READ : Lit la configuration des modules ECxLightDaliA de chaque automate
et genere un fichier CSV avec une ligne par sortie (output).
Action WRITE : Modifie les proprietes des sorties DALI a partir du CSV.
Toutes les proprietes de chaque ligne sont reecrites.
.PARAMETER Action
Action a effectuer :
Read - Lire la configuration et generer un CSV de sortie
Write - Ecrire les proprietes depuis le CSV vers les automates
.PARAMETER CsvInput
Chemin vers le fichier CSV d'entree (separateur point-virgule).
Pour Read : colonnes minimales Hostname, Current Ip, HttpPort, HttpsPort.
Pour Write : CSV enrichi genere par l'action Read.
.PARAMETER Username
Nom d'utilisateur pour l'authentification API (defaut: admin).
Peut etre surcharge par la colonne Username du CSV.
.PARAMETER Password
Mot de passe pour l'authentification API (defaut: vide).
Peut etre surcharge par la colonne Password du CSV.
.EXAMPLE
.\DaliACLI.ps1 -Action Read -CsvInput ".\automates.csv"
Lit la configuration DALI de tous les automates listes dans le CSV.
Genere un fichier dali_YYYY-MM-DD_HHhMM.csv dans le repertoire courant.
.EXAMPLE
.\DaliACLI.ps1 -Action Write -CsvInput ".\dali_2026-04-02_14h30.csv" -Password "MonMotDePasse"
Ecrit les proprietes du CSV vers les automates.
.EXAMPLE
Get-Help .\DaliACLI.ps1 -Detailed
Affiche cette aide detaillee.
.NOTES
Prerequis : PowerShell 5.1+ (inclus dans Windows 10/11)
API : Distech Controls Eclypse REST API v2
Securite : TLS 1.2, certificats auto-signes acceptes
#>
param(
[Parameter(Mandatory)]
[ValidateSet("Read", "Write")]
[string]$Action,
[Parameter(Mandatory)]
[string]$CsvInput,
[string]$Username = "admin",
[string]$Password = ""
)
# Performance : desactiver la barre de progression Invoke-WebRequest
$ProgressPreference = 'SilentlyContinue'
# Import des modules
$modulesPath = Join-Path $PSScriptRoot "modules"
Import-Module (Join-Path $modulesPath "Logger.psm1") -Force
Import-Module (Join-Path $modulesPath "CsvHandler.psm1") -Force
Import-Module (Join-Path $modulesPath "ApiClient.psm1") -Force
Import-Module (Join-Path $modulesPath "DaliParser.psm1") -Force
# Initialisation
Initialize-Logger
Initialize-ApiClient
Write-Log -Message "=== DaliACLI demarre - Action: $Action ===" -Level INFO
# Chemin de l'API DALI
$daliApiPath = "/api/rest/v2/services/subnet/devices/light-sunblind/modules"
# Lecture du CSV d'entree
$csvRows = Read-AutomateCsv -CsvPath $CsvInput
# ============================================================
# ACTION READ : Lire la config DALI de chaque automate
# ============================================================
if ($Action -eq "Read") {
$timestamp = Get-Date -Format "yyyy-MM-dd_HH\hmm"
$CsvOutput = Join-Path (Get-Location) "dali_$timestamp.csv"
Write-Log -Message "CSV de sortie : $CsvOutput" -Level INFO
$allOutputRows = @()
# Deduplication des automates par IP (le CSV d'entree a une ligne par automate)
$uniqueAutomates = $csvRows | Sort-Object -Property "Current Ip" -Unique
foreach ($automate in $uniqueAutomates) {
$hostname = $automate.Hostname
$ip = $automate."Current Ip"
Update-Stats -Counter AutomatesTotal
try {
$baseUrl = Get-BaseUrl -Automate $automate
if (-not $baseUrl) {
Write-Log -Message "[$hostname] Aucun port HTTP/HTTPS valide - ignore" -Level WARN
Update-Stats -Counter AutomatesError
continue
}
$creds = Get-Credentials -Automate $automate -DefaultUsername $Username -DefaultPassword $Password
$url = "$baseUrl$daliApiPath/"
Write-Log -Message "[$hostname] $url (user: $($creds.Username))" -Level INFO
# GET modules DALI
$jsonContent = Invoke-ApiGet -Url $url -Username $creds.Username -Password $creds.Password
# Parser et filtrer les modules ECxLightDaliA
$daliOutputs = Get-DaliAModules -JsonContent $jsonContent
if ($daliOutputs.Count -eq 0) {
Write-Log -Message "[$hostname] Aucun module ECxLightDaliA trouve" -Level WARN
continue
}
Write-Log -Message "[$hostname] $($daliOutputs.Count) sortie(s) ECxLightDaliA trouvee(s)" -Level INFO
# Creer une ligne CSV par output
foreach ($output in $daliOutputs) {
# Copier toutes les colonnes source de l'automate
$row = [ordered]@{}
foreach ($prop in $automate.PSObject.Properties) {
$row[$prop.Name] = $prop.Value
}
# Ajouter les colonnes DALI
$row["ModuleKey"] = $output.ModuleKey
$row["ModuleName"] = $output.ModuleName
$row["OutputKey"] = $output.OutputKey
$row["OutputName"] = $output.OutputName
$row["ControlGearKey"] = $output.ControlGearKey
$row["Groups"] = $output.Groups
$row["SystemFailLevel"] = $output.SystemFailLevel
$row["PowerOnLevel"] = $output.PowerOnLevel
$row["MinDimmingLevel"] = $output.MinDimmingLevel
$row["DefaultValue"] = $output.DefaultValue
$row["DimmingTime"] = $output.DimmingTime
$row["MaxDimmingLevel"] = $output.MaxDimmingLevel
$allOutputRows += [PSCustomObject]$row
Update-Stats -Counter OutputsProcessed
Write-Log -Message "[$hostname] M$($output.ModuleKey)_O$($output.OutputKey) ($($output.OutputName)) - Groups: $($output.Groups)" -Level SUCCESS
}
}
catch {
Write-Log -Message "[$hostname] ERREUR : $($_.Exception.Message)" -Level ERROR
Update-Stats -Counter AutomatesError
}
}
# Ecriture du CSV de sortie
if ($allOutputRows.Count -gt 0) {
Write-OutputCsv -OutputRows $allOutputRows -OutputPath $CsvOutput
}
else {
Write-Log -Message "Aucune sortie trouvee - CSV non genere" -Level WARN
}
}
# ============================================================
# ACTION WRITE : Ecrire la config DALI sur chaque automate
# ============================================================
elseif ($Action -eq "Write") {
# Grouper les lignes par automate (Current Ip)
$automateGroups = $csvRows | Group-Object -Property "Current Ip"
foreach ($automateGroup in $automateGroups) {
$ip = $automateGroup.Name
$rows = $automateGroup.Group
$hostname = $rows[0].Hostname
Update-Stats -Counter AutomatesTotal
try {
$baseUrl = Get-BaseUrl -Automate $rows[0]
if (-not $baseUrl) {
Write-Log -Message "[$hostname] Aucun port HTTP/HTTPS valide - ignore" -Level WARN
Update-Stats -Counter AutomatesError
continue
}
$creds = Get-Credentials -Automate $rows[0] -DefaultUsername $Username -DefaultPassword $Password
$url = "$baseUrl$daliApiPath"
Write-Log -Message "[$hostname] $url (user: $($creds.Username))" -Level INFO
# Grouper par ModuleKey pour envoyer un POST par module
$moduleGroups = $rows | Group-Object -Property ModuleKey
foreach ($moduleGroup in $moduleGroups) {
$moduleKey = $moduleGroup.Name
$outputRows = $moduleGroup.Group
Write-Log -Message "[$hostname] Module $moduleKey : $($outputRows.Count) sortie(s) a ecrire" -Level INFO
# Construire le body JSON
$jsonBody = Build-ModuleWriteBody -ModuleKey $moduleKey -OutputRows $outputRows
Write-Log -Message "[$hostname] Module $moduleKey body: $jsonBody" -Level INFO
# POST vers l'API
Invoke-ApiPost -Url $url -JsonBody $jsonBody -Username $creds.Username -Password $creds.Password
Update-Stats -Counter OutputsProcessed -Increment $outputRows.Count
Write-Log -Message "[$hostname] Module $moduleKey : configuration ecrite avec succes" -Level SUCCESS
}
}
catch {
Write-Log -Message "[$hostname] ERREUR : $($_.Exception.Message)" -Level ERROR
Update-Stats -Counter AutomatesError
}
}
}
# Resume final
Write-Summary