Files
gfx-enocean/EnoceanCLI.ps1

215 lines
7.9 KiB
PowerShell

# EnoceanCLI.ps1 - CLI Enocean pour automates Distech Controls Eclypse
# Lecture/ecriture des configurations Enocean via REST API
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 "XmlParser.psm1") -Force
Import-Module (Join-Path $modulesPath "ApiClient.psm1") -Force
Import-Module (Join-Path $modulesPath "ZipBuilder.psm1") -Force
# Initialisation
Initialize-Logger
Initialize-ApiClient
Write-Log -Message "=== EnoceanCLI demarre - Action: $Action ===" -Level INFO
# Lecture du CSV d'entree
$automates = Read-AutomateCsv -CsvPath $CsvInput
# ============================================================
# ACTION READ : Lire la config Enocean de chaque automate
# ============================================================
if ($Action -eq "Read") {
# Chemin CSV de sortie automatique dans le repertoire courant
$timestamp = Get-Date -Format "yyyy-MM-dd_HH\hmm"
$CsvOutput = Join-Path (Get-Location) "enocean_$timestamp.csv"
Write-Log -Message "CSV de sortie : $CsvOutput" -Level INFO
# Stockage des devices par IP : @{ "10.60.x.x" = @( @{DeviceId=...; DeviceType=...}, ... ) }
$deviceData = @{}
foreach ($automate in $automates) {
$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
}
$apiBasePath = Get-ApiBasePath -Automate $automate
$creds = Get-Credentials -Automate $automate -DefaultUsername $Username -DefaultPassword $Password
Write-Log -Message "[$hostname] $baseUrl$apiBasePath (user: $($creds.Username))" -Level INFO
# GET liste des devices Enocean
$jsonContent = Invoke-EnoceanGet `
-BaseUrl $baseUrl `
-ApiBasePath $apiBasePath `
-ResourcePath "files/enocean/configuration/devices" `
-Username $creds.Username `
-Password $creds.Password
$deviceFiles = Get-DeviceListFromJson -JsonContent $jsonContent
if ($deviceFiles.Count -eq 0) {
Write-Log -Message "[$hostname] Aucun device Enocean trouve" -Level WARN
$deviceData[$ip] = @()
continue
}
Write-Log -Message "[$hostname] $($deviceFiles.Count) device(s) trouve(s)" -Level INFO
# GET chaque XML device et parser
$devices = @()
foreach ($deviceFile in $deviceFiles) {
try {
$xmlContent = Invoke-EnoceanGet `
-BaseUrl $baseUrl `
-ApiBasePath $apiBasePath `
-ResourcePath "files/enocean/configuration/devices/$($deviceFile.Name)?encode=bin" `
-Username $creds.Username `
-Password $creds.Password
$parsed = Parse-EnoceanDeviceXml -XmlContent $xmlContent
$devices += $parsed
Update-Stats -Counter DevicesProcessed
Write-Log -Message "[$hostname] Device $($deviceFile.Name) : Id=$($parsed.DeviceId), Type=$($parsed.DeviceType)" -Level SUCCESS
}
catch {
Write-Log -Message "[$hostname] Erreur lecture $($deviceFile.Name) : $($_.Exception.Message)" -Level ERROR
}
}
# Trier par ResourceNumber puis stocker
$devices = @($devices | Sort-Object { $_.ResourceNumber })
$deviceData[$ip] = $devices
}
catch {
Write-Log -Message "[$hostname] ERREUR : $($_.Exception.Message)" -Level ERROR
Update-Stats -Counter AutomatesError
$deviceData[$ip] = @()
}
}
# Ecriture du CSV de sortie
Write-OutputCsv -InputRows $automates -DeviceData $deviceData -OutputPath $CsvOutput
}
# ============================================================
# ACTION WRITE : Ecrire la config Enocean sur chaque automate
# ============================================================
elseif ($Action -eq "Write") {
foreach ($automate in $automates) {
$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
}
$apiBasePath = Get-ApiBasePath -Automate $automate
$creds = Get-Credentials -Automate $automate -DefaultUsername $Username -DefaultPassword $Password
Write-Log -Message "[$hostname] $baseUrl$apiBasePath (user: $($creds.Username))" -Level INFO
# Lire les colonnes dynamiques DeviceId_N / DeviceType_N
$xmlFiles = @()
$resourceIndex = 1
while ($true) {
$deviceIdCol = "DeviceId_$resourceIndex"
$deviceTypeCol = "DeviceType_$resourceIndex"
# Verifier si les colonnes existent
$props = $automate.PSObject.Properties.Name
if ($deviceIdCol -notin $props -or $deviceTypeCol -notin $props) {
break
}
$deviceId = $automate.$deviceIdCol
$deviceType = $automate.$deviceTypeCol
# Ignorer si vide
if (-not $deviceId -or $deviceId -eq "" -or -not $deviceType -or $deviceType -eq "") {
$resourceIndex++
continue
}
$xmlContent = New-EnoceanDeviceXml `
-ResourceNumber $resourceIndex `
-DeviceId $deviceId `
-DeviceType $deviceType
$xmlFiles += @{
Name = "enoceandevice$resourceIndex.xml"
Content = $xmlContent
}
Update-Stats -Counter DevicesProcessed
Write-Log -Message "[$hostname] XML genere : device $resourceIndex (Id=$deviceId, Type=$deviceType)" -Level INFO
$resourceIndex++
}
if ($xmlFiles.Count -eq 0) {
Write-Log -Message "[$hostname] Aucun device a ecrire - ignore" -Level WARN
continue
}
# Creer le ZIP et l'envoyer
$zipBytes = New-EnoceanZip -XmlFiles $xmlFiles
$zipFilename = Get-ZipFilename -ZipBytes $zipBytes
Write-Log -Message "[$hostname] Envoi de $($xmlFiles.Count) device(s) ($zipFilename)..." -Level INFO
Send-EnoceanConfig `
-BaseUrl $baseUrl `
-ApiBasePath $apiBasePath `
-ZipBytes $zipBytes `
-ZipFilename $zipFilename `
-Username $creds.Username `
-Password $creds.Password
Write-Log -Message "[$hostname] Configuration envoyee avec succes" -Level SUCCESS
}
catch {
Write-Log -Message "[$hostname] ERREUR : $($_.Exception.Message)" -Level ERROR
Update-Stats -Counter AutomatesError
}
}
}
# Resume final
Write-Summary