Get-VEValue.ps1

function Get-VEValue {
    <#
        .SYNOPSIS
            Ult
        .DESCRIPTION
            Ult
        .INPUTS
            The raw value can be piped to the function
        .EXAMPLE
            Get-VEValue
            Example of how to Ult
        .NOTES
            Author: Decembry Quentin
    #>

    [CmdletBinding(DefaultParameterSetName='All')]
    [OutputType([PSCustomObject])]
    [Alias()]
    param(
        # The VE site
        [Parameter(Mandatory=$true,ParameterSetName='Object')] [PSTypeName('VictronEnergy.Site')] $Site,
        
        # The VE site id
        [Parameter(Mandatory=$true,ParameterSetName='Property')] [string] $SiteId,
        
        # The value
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $RawValue,
        
        # The attribute code (case sensitive)
        [Parameter(Mandatory=$true)] [string] $Code
    )

    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"
        if (!$SiteId) {
            $SiteId = $Site.IdSite
        }
        
        $ValueFormatting = Get-VEValueFormatting -SiteId $SiteId -Code $Code -ErrorAction Stop
    }
    
    process {
        Write-Debug "[$Private:ThisFunction] Process raw value '$RawValue'"
        $Value = $RawValue
        $NumValue = if ([Int]::TryParse($RawValue, [Ref] 0)) { [Int]$RawValue } elseif ([Double]::TryParse($RawValue, [Ref] 0)) { [Double]$RawValue } else { 0 }
        
        # Weird side effect on [Bool](@{}) -> True or [Bool](@{}.Keys) -> True
        # Solved with [Bool](@{}.Keys -join '') -> False
        if ($ValueFormatting.BitMask) {
            Write-Debug "[$Private:ThisFunction] Get value from enum values and flags"
            if ($NumValue -is [Int]) {
                if ($ValueFormatting.EnumValues.Keys -join '') {
                    $Value = ($ValueFormatting.EnumValues.Keys | ForEach-Object { if ($NumValue -band $_) { $ValueFormatting.EnumValues.$_ } }) -join ', '
                } else {
                    Write-Warning "[$Private:ThisFunction] Bit mask without enum values for code '$($Meta.Code)'"
                }
            } else {
                Write-Warning "[$Private:ThisFunction] Unable to convert raw value '$RawValue' using enumeration values"
                $Value = 'n.a.'
            }
        } elseif ($ValueFormatting.EnumValues.Keys -join '') {
            Write-Debug "[$Private:ThisFunction] Get value from enum values"
            if ($NumValue -is [Int]) {
                if ($NumValue -in $ValueFormatting.EnumValues.Keys) {
                    if ($ValueFormatting.EnumValues.([string]$NumValue)) {
                        $Value = $ValueFormatting.EnumValues.([string]$NumValue)
                    } else {
                        Write-Warning "[$Private:ThisFunction] Unexpected empty or missing value for key '$NumValue' in enum values for code '$($Meta.Code)'"
                    }
                } else {
                    Write-Warning "[$Private:ThisFunction] Value '$NumValue' not in enum keys ($($ValueFormatting.EnumValues.Keys -join ',')) for code '$($Meta.Code)'"
                }
            } else {
                Write-Warning "[$Private:ThisFunction] Unable to convert raw value '$RawValue' using enumeration values"
                $Value = 'n.a.'
            }
        }
        
        Write-Debug "[$Private:ThisFunction] Cast value"
        if ($NumValue -is [Double] -and $ValueFormatting.TargetType -eq [Int]) {
            $Value = [Math]::Round($NumValue)
        }
        $Value = [System.Management.Automation.LanguagePrimitives]::ConvertTo($Value, $ValueFormatting.TargetType)
        
        Write-Debug "[$Private:ThisFunction] Create value object"
        $Object = [PSCustomObject] @{
            PSTypeName = 'VictronEnergy.Value'
            NumValue = $NumValue
            Value = $Value
            Pattern = $ValueFormatting.Pattern
        }
        
        $Object | Add-Member -MemberType ScriptProperty -Name FormattedValue -Value { $this.Pattern -f $this.Value }
        $Object | Add-Member -MemberType ScriptMethod -Name ToString -Value { $this.FormattedValue } -Force
        
        Write-Debug "[$Private:ThisFunction] Return value object"
        Write-Output -NoEnumerate -InputObject $Object
    }
    
    end {
        Write-Debug "[$Private:ThisFunction] End"
    }
}

# SIG # Begin signature block
# MIIIbQYJKoZIhvcNAQcCoIIIXjCCCFoCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUWTooaD/MDeH/h3PGc0eDsYvR
# RSSgggX4MIICYjCCAgigAwIBAgITXwAAAAITcsrrTJecaQAAAAAAAjAKBggqhkjO
# 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
# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUuDVhCTHg
# nxIRJ4i2HJ0PwRoYPJ4wDQYJKoZIhvcNAQEBBQAEggEAaaFmIpIW2ACTlmcNeTyz
# bbtAsFvvkzzmcZ+lGuHfP5IMRewoit/2+BSHmG2rTxHwdqD7mbUwU7gt/3WNWLPq
# Iv7ugxRixJZzZn6ZRVmjrP4F1KvPIkXYIiA+JZsc3F1wr+LdcXI6UaSpXIURF91M
# jC+uClOA1BbS3wzFWvYirTtTGi50LVmfD7BTqnIzS0W/gdztTfqfU6pda0nXrxFA
# yCD9wHPAPkv6GKHy1txXrr5QnVCl7FAUFz6yCnGQgCR6XfvbU9MXpeWKqLBzwJ3q
# zXvvPrNfOwiVi+9YI40p8ng2BZFhW7PvrNRTgujmhW/ekGiXwERIhEtTqxHq+W7p
# fw==
# SIG # End signature block