Set-VEValueFormatter.ps1
|
function Set-VEValueFormatter { <# .SYNOPSIS Ult .DESCRIPTION Ult .INPUTS No object can be piped to the function .EXAMPLE Set-VEValueFormatter Example of how to set value formatting object .NOTES Author: Decembry Quentin #> [CmdletBinding(DefaultParameterSetName='Diagnostic')] [OutputType([PSCustomObject])] [Alias()] param( # The VE session # Default: the default VE session [Parameter(Mandatory=$false)] [PSTypeName('VictronEnergy.Session')] $Session = $Script:VE_Session, # The VE diagnostics [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName='Diagnostic')] [PSTypeName('VictronEnergy.Diagnostic')] $Diagnostic, # The VE meta [Parameter(Mandatory=$true,ParameterSetName='Meta')] [Object] $Meta, # The site id [Parameter(Mandatory=$true,ParameterSetName='Meta')] [string] $SiteId, # Switch to return the value formatter object [Parameter(Mandatory=$false)] [switch] $PassThru ) begin { if ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' } if ($MyInvocation.MyCommand.ModuleName) { $Private:ThisFunction = '{0}::{1}' -f $MyInvocation.MyCommand.ModuleName, $MyInvocation.MyCommand.Name } else { $Private:ThisFunction = '{0}::{1}' -f (Get-PSCallStack)[0].ScriptName, $MyInvocation.MyCommand.Name } Write-Debug "[$Private:ThisFunction] Begin" } process { Write-Debug "[$Private:ThisFunction] Process code $Code" [string] $Code = '' [string] $FormatWithUnit = '' $Hashtable = @{ PSTypeName = 'VictronEnergy.ValueFormatter' Source = $PSCmdlet.ParameterSetName } $Create = $true switch ($PSCmdlet.ParameterSetName) { # # Diagnostic is the best source but not always available # 'Diagnostic' { $SiteId = $Diagnostic.idSite $Code = $Diagnostic.Code if ($Script:VE_ValueFormatter.$SiteId.$Code.Source -eq $_) { # Object already exists from Diagnostic $Create = $false break } $Hashtable.BitMask = [Bool] $Diagnostic.Bitmask $Hashtable.EnumValues = @{} $Diagnostic.dataAttributeEnumValues | ForEach-Object { if ($Key = [string]$_.ValueEnum) { $Hashtable.EnumValues.$Key = $_.NameEnum } } $FormatWithUnit = $Diagnostic.formatWithUnit } # # Meta is not the best source because it laks enum values and bitmask information # 'Meta' { $Code = $Meta.code if (!$Script:VE_ValueFormatter.$SiteId.LastDiagnostic) { Write-Debug "[$Private:ThisFunction] Run diagnostics first" $null = Get-VEDiagnostics -SiteId $SiteId -Session $Session -ErrorAction SilentlyContinue -ErrorVariable ErrVar $ErrVar | ForEach-Object { Write-Debug "[$Private:ThisFunction] Error getting diagnostics: $_" } } if ($Script:VE_ValueFormatter.$SiteId.$Code.Source) { # Object already exists from Meta or Diagnostic $Create = $false break } $Hashtable.BitMask = $false $Hashtable.EnumValues = @{} $FormatWithUnit = $Meta.formatWithUnit } default { throw "Unsupported parameter set name '$_'" } } if ($Create) { if (!$Script:VE_ValueFormatter.$SiteId) { Write-Debug "[$Private:ThisFunction] Create the hastable for site $SiteId" # Use 'New-Object System.Collections.Hashtable' instead of '@{}' to get a hashtable case sensitive $Script:VE_ValueFormatter.$SiteId = New-Object System.Collections.Hashtable } Write-Debug "[$Private:ThisFunction] Fill in the hashtable properties" $Hashtable.SiteId = $SiteId $Hashtable.Code = $Code $FormatValue, $Unit = $FormatWithUnit -split ' ',2 #Bugs from VE switch ($VEObject.Code) { { $_ -in 'AI','Af' } { $FormatValue = '%s' } { $_ -in 'TO' } { $FormatValue = '%d' } } $Hashtable.TargetType, $Hashtable.Pattern = switch -Regex ($FormatValue) { '^%d$' { @([int], '{0:D}') } '^%s$' { @([string], '{0}') } '^%\.[0-9]+F$' { $N = $_ -replace '^%.([0-9]+)F$', '$1' @([double], "{0:F$N}") } default { Write-Warning "[$Private:ThisFunction] Unsupported format '$_' for code '$($VEObject.Code)'" @([string], '{0}') } } if ($Unit) { $Hashtable.Pattern += ' {0}' -f ($Unit -replace '%%','%') } Write-Debug "[$Private:ThisFunction] Create value formatting object" $Object = [PSCustomObject] $Hashtable $Object | Add-Member -MemberType ScriptMethod -Name Format -Value { param( [string] $RawValue ) if ([Int]::TryParse($RawValue, [Ref] 0)) { $Value = $NumValue = [Int]$RawValue } elseif ([Double]::TryParse($RawValue, [Ref] 0)) { $Value = $NumValue = [Double]$RawValue } else { $NumValue = 0 $Value = [string] $RawValue } if ($this.BitMask) { if ($NumValue -is [Int]) { if ($this.EnumValues.Keys.Count) { $Value = ($this.EnumValues.Keys | ForEach-Object { if ($NumValue -band $_) { $this.EnumValues.$_ } }) -join ', ' } else { # Write-Warning "[$Private:ThisFunction] Bit mask without enum values for code '$($Meta.Code)'" $Value = '[{0}]' -f $NumValue } } elseif ($NumValue -is [Double]) { # Unable to convert raw value using enumeration values $Value = 'n.a.' } } elseif ($this.EnumValues.Keys.Count) { if ($NumValue -is [Int]) { if ($NumValue -in $this.EnumValues.Keys) { $Value = $this.EnumValues.([string]$NumValue) } else { # Value not in enum keys $Value = '<{0}>' -f $NumValue } } elseif ($NumValue -is [Double]) { # Unable to convert raw value using enumeration values $Value = 'n.a.' } } if ($NumValue -is [Double] -and $this.TargetType -eq [Int]) { $Value = [Math]::Round($NumValue) } try { $Value = [System.Management.Automation.LanguagePrimitives]::ConvertTo($Value, $this.TargetType) } catch { Write-Warning "Unable to cast value '$Value' to target type '$($this.TargetType)' for attribute code '$($this.Code)'" } # Create and return value object [PSCustomObject] @{ PSTypeName = 'VictronEnergy.Value' NumValue = $NumValue Value = $Value FormattedValue = $this.Pattern -f $Value } | Add-Member -MemberType ScriptMethod -Name ToString -Value { $this.FormattedValue } -Force -PassThru } Write-Debug "[$Private:ThisFunction] Add formatting object for code $Code from site $SiteId" $Script:VE_ValueFormatter.$SiteId.$Code = $Object } if ($PassThru) { Write-Debug "[$Private:ThisFunction] Return the value formatter object" Write-Output -NoEnumerate -InputObject $Script:VE_ValueFormatter.$SiteId.$Code } } end { Write-Debug "[$Private:ThisFunction] End" } } # SIG # Begin signature block # MIIIbQYJKoZIhvcNAQcCoIIIXjCCCFoCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUY9SKHZTyrxl+EjJDZ/fBddww # aeCgggX4MIICYjCCAgigAwIBAgITXwAAAAITcsrrTJecaQAAAAAAAjAKBggqhkjO # PQQDAjAkMQswCQYDVQQGEwJCRTEVMBMGA1UEAxMMSG9tZSBSb290IENBMB4XDTIy # MDUwNTE0MDMxOFoXDTMyMDUwNTE0MTMxOFowJzELMAkGA1UEBhMCQkUxGDAWBgNV # BAMTD0hvbWUgSXNzdWluZyBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDOT # aIIU+QU7LfsmyPqGkCf53SrJuaBPpb5iVILCvG3cQxL6vgIZaGRaKlzYO+lq3CnN # b4rtJW2d7rlTeehXtpWjggEUMIIBEDAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4E # FgQUYf1/nMEp3Df+Nzi+Hvk7FymPsrMwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBD # AEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUfSS6 # P6qin/3ibmvelGJQhV1r1VgwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL3BraS5x # ZWRpbnV4LmJlL0hvbWUlMjBSb290JTIwQ0EuY3JsMEYGCCsGAQUFBwEBBDowODA2 # BggrBgEFBQcwAoYqaHR0cDovL3BraS5xZWRpbnV4LmJlL0hvbWUlMjBSb290JTIw # Q0EuY3J0MAoGCCqGSM49BAMCA0gAMEUCIERRzfMu3vx9vb+Apud4sDkOEKhKrCEl # gSsedbjZRJ+YAiEA8BBaOqhnbnsUBIX2nty77euunwoAHrCuWzab5xJiy0UwggOO # MIIDM6ADAgECAhNRAAAAMJpCm89a8zgYAAAAAAAwMAoGCCqGSM49BAMCMCcxCzAJ # BgNVBAYTAkJFMRgwFgYDVQQDEw9Ib21lIElzc3VpbmcgQ0EwHhcNMjIwNzExMDc0 # NzQ3WhcNMjQwNzExMDc1NzQ3WjAbMRkwFwYDVQQDExBEZWNlbWJyeSBRdWVudGlu # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjALWtmJ1AQG77y9rUBbT # HXR9FZokTP01bBWfNzk4Kenr/Xpm7Jt09PqLoNS8ToWWKRz9EkM+jg7lnLljWKcO # G+fT1TbaEwxOpncugnbrioQQonbdWpyn0P7PxlqjUQdWd5Z7xQ0Z8RO3vvERWtDA # L9QH0VBHNK4WqdWh3ElV6ogJUsy5hYxVTIU0K5VEYkIT4qvqq0RdajKavGWIr57R # EsYv52Jcyh9FNgZKGdu9NwSKZUvkwHxGsI8zmwfP1I6QRkzsqPXlpk7A8NTD3+h+ # 4Y5AprRFyAWrVNYH+UQQe2D/PjjbKtfsU9xzG9EnqJF09pVRchapis+8DbfWnoC8 # iQIDAQABo4IBfTCCAXkwOgYJKwYBBAGCNxUHBC0wKwYjKwYBBAGCNxUIhorlOcPr # DIadiwndkzuHjPAAPqb1CYWVxXgCAWQCAQowEwYDVR0lBAwwCgYIKwYBBQUHAwMw # DgYDVR0PAQH/BAQDAgeAMBsGCSsGAQQBgjcVCgQOMAwwCgYIKwYBBQUHAwMwHQYD # VR0OBBYEFAkUh200U2U2epAoy2ZvT7nwAYGBMB8GA1UdIwQYMBaAFGH9f5zBKdw3 # /jc4vh75Oxcpj7KzMD4GA1UdHwQ3MDUwM6AxoC+GLWh0dHA6Ly9wa2kucWVkaW51 # eC5iZS9Ib21lJTIwSXNzdWluZyUyMENBLmNybDBJBggrBgEFBQcBAQQ9MDswOQYI # KwYBBQUHMAKGLWh0dHA6Ly9wa2kucWVkaW51eC5iZS9Ib21lJTIwSXNzdWluZyUy # MENBLmNydDAuBgNVHREEJzAloCMGCisGAQQBgjcUAgOgFQwTRGVjZW1icnkuUUBo # b21lLmxhbjAKBggqhkjOPQQDAgNJADBGAiEAh39vHCgqIDL4XazyHPiChMbu0by+ # aFP7rdzlJmM0K6ACIQCaP4CXolxlzdfkJsoIoDIJUrunYIlZ0yxs9OSnG1qmCjGC # Ad8wggHbAgEBMD4wJzELMAkGA1UEBhMCQkUxGDAWBgNVBAMTD0hvbWUgSXNzdWlu # ZyBDQQITUQAAADCaQpvPWvM4GAAAAAAAMDAJBgUrDgMCGgUAoHgwGAYKKwYBBAGC # NwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUPlZ+RwbF # A+ZBkE5JAR+unE5hIPYwDQYJKoZIhvcNAQEBBQAEggEAOa+b7TFj/xH1iWfQRIbh # zSPDCMF05gS3g01FDzRjschufu7FyN+BjK/ajgpm2Tli7VPF6ocofbeFKsBnrCRt # ri4CY2WnPPHyhJVRjBCFR91is+6RIAeCyeEX3er1cJ7QjQqLEsL6x3Ieij39PAZg # 2LDLv1byvF6kvsqA6XYWcr1xkAtPShhz/+SWrAhjWWWf8gpW2xKnat4UFsKyZp1M # wpe5oS9DYoNPAB+vH+/0TRlW+6YEIA3i6R0rw/ccY5V4/skWZgerBng3+4aAsNJY # 19dW7FBYJE8tE96iFAOD006DuQNeGN2rVOtQouOjYcVfDcHXEn5sqAPOawjDHbMi # 5g== # SIG # End signature block |