functions/Read-TibberWebSocket.ps1

function Read-TibberWebSocket {
    <#
    .Synopsis
        Read packages on the provided WebSocket connection.
    .Description
        Calling this function will read packages on the provided WebSocket connection.
    .Example
        Read-TibberWebSocket -Connection $connection -Callback { param($Json)
            Write-Host "New Json document recieved: $($Json.payload.data | Out-String)"
        }
    .Example
        function Write-PackageToHost {
            param (
                [Object] $Json
            )
            Write-Host "New Json document recieved: $($Json.payload.data | Out-String)"
        }
        Read-TibberWebSocket -Connection $connection -Callback ${function:Write-PackageToHost}
    .Example
        $result = Read-TibberWebSocket -Connection $connection -Callback ${function:Write-PackageToHost} -TimeoutInSeconds 30
        Write-Host "Read $($result.NumberOfPackages) package(s) in $($result.ElapsedTimeInSeconds) seconds"
    .Example
        Read-TibberWebSocket -Connection $connection -Callback ${function:Write-PackageToHost} -PackageCount 3
        Write-Host "Read $($result.NumberOfPackages) package(s) in $($result.ElapsedTimeInSeconds) seconds"
    .Link
        Register-TibberLiveConsumptionSubscription
    .Link
        https://developer.tibber.com/docs/reference#livemeasurement
    #>

    param (
        # Specifies the connection to use for the communication.
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName)]
        [Object] $Connection,

        # Specifies the script block called for each response.
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName)]
        [ScriptBlock] $Callback,

        # Specifies for how long in seconds we should read packages, or -1 to read indefinitely.
        [Parameter(ValueFromPipelineByPropertyName)]
        [ValidateRange(-1, [int]::MaxValue)]
        [Alias('Timeout')]
        [int] $TimeoutInSeconds = -1,

        # Specifies the number of packages to read, or -1 to read indefinitely.
        [Parameter(ValueFromPipelineByPropertyName)]
        [ValidateRange(-1, [int]::MaxValue)]
        [Alias('Count')]
        [int] $PackageCount = -1
    )

    begin {
        # Setup parameters
        $uri = $Connection.URI
        $webSocket = $Connection.WebSocket
        $cancellationToken = $Connection.CancellationTokenSource.Token
        $recvBuffer = $Connection.RecvBuffer
    }

    process {
        Write-Verbose "Read packages from $URI"

        # Reading packages
        $timer = [Diagnostics.Stopwatch]::StartNew()
        $packageCounter = 0
        while (($TimeoutInSeconds -eq -1 -Or $timer.Elapsed.TotalSeconds -lt $TimeoutInSeconds) `
                -And ($PackageCount -eq -1 -Or $packageCounter -lt $PackageCount) `
                -And ($webSocket.State -eq 'Open')) {
            $response = ""
            do {
                $result = $webSocket.ReceiveAsync($recvBuffer, $cancellationToken)
                while (-Not $result.IsCompleted) {
                    Start-Sleep -Milliseconds 10
                }
                Write-Debug -Message "WebSocket status:"
                Write-Debug -Message ($webSocket | Select-Object * | Out-String)
                Write-Debug -Message "WebSocket operation result:"
                Write-Debug -Message ($result | Select-Object * | Out-String)
                if ($result.Result.CloseStatus) {
                    throw "Receive failed: $($result.Result.CloseStatusDescription) [$($result.Result.CloseStatus)]"
                }
                $response += [Text.Encoding]::ASCII.GetString($recvBuffer.Array, 0, $result.Result.Count)
                $packageCounter++
            } until ($result.Result.EndOfMessage)

            Invoke-Command -ScriptBlock $Callback -ArgumentList $($response | ConvertFrom-Json)
        }

        $timer.Stop()
        Write-Verbose "Read $packageCounter package(s) in $($timer.Elapsed.TotalSeconds) seconds"

        # Output result object
        [PSCustomObject]@{
            NumberOfPackages     = $packageCounter
            ElapsedTimeInSeconds = $timer.Elapsed.TotalSeconds
        }
    }
}