Implémentation CLI PowerShell Enocean Eclypse
This commit is contained in:
214
EnoceanCLI.ps1
Normal file
214
EnoceanCLI.ps1
Normal file
@@ -0,0 +1,214 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user