functions/public/Wait-KlippyHomed.ps1

function Wait-KlippyHomed {
    <#
    .SYNOPSIS
        Waits for specified axes to be homed on a Klipper printer.

    .DESCRIPTION
        Monitors the toolhead homed_axes state via WebSocket and waits until
        the specified axes are homed.

    .PARAMETER Id
        The unique identifier of the printer.

    .PARAMETER PrinterName
        The friendly name of the printer.

    .PARAMETER InputObject
        A printer object from pipeline input.

    .PARAMETER Axes
        The axes to wait for. Default is all axes (X, Y, Z).

    .PARAMETER Timeout
        Maximum time to wait in seconds. Default is 120.

    .PARAMETER Quiet
        Suppress progress messages.

    .EXAMPLE
        Wait-KlippyHomed -PrinterName "voronv2"
        Waits for all axes to be homed.

    .EXAMPLE
        Wait-KlippyHomed -Axes X, Y -Timeout 60
        Waits up to 60 seconds for X and Y axes to be homed.

    .EXAMPLE
        Invoke-KlippyHome | Wait-KlippyHomed
        Sends home command and waits for completion.

    .OUTPUTS
        PSCustomObject with homing state information.
    #>

    [CmdletBinding(DefaultParameterSetName = 'Default')]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory = $true, ParameterSetName = 'ById')]
        [ValidateNotNullOrEmpty()]
        [string]$Id,

        [Parameter(Mandatory = $true, ParameterSetName = 'ByName', Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string]$PrinterName,

        [Parameter(Mandatory = $true, ParameterSetName = 'ByObject', ValueFromPipeline = $true)]
        [PSCustomObject]$InputObject,

        [Parameter()]
        [ValidateSet('X', 'Y', 'Z')]
        [string[]]$Axes = @('X', 'Y', 'Z'),

        [Parameter()]
        [ValidateRange(1, 600)]
        [int]$Timeout = 120,

        [Parameter()]
        [switch]$Quiet
    )

    process {
        # Resolve printer
        $resolveParams = @{}
        switch ($PSCmdlet.ParameterSetName) {
            'ById' { $resolveParams['Id'] = $Id }
            'ByName' { $resolveParams['PrinterName'] = $PrinterName }
            'ByObject' { $resolveParams['InputObject'] = $InputObject }
        }

        $printer = Resolve-KlippyPrinterTarget @resolveParams

        $requiredAxes = ($Axes | ForEach-Object { $_.ToLower() }) -join ''
        $axesDisplay = $Axes -join ', '

        # Helper to check if all required axes are homed
        $checkHomed = {
            param([string]$homedAxes)
            foreach ($axis in $requiredAxes.ToCharArray()) {
                if ($homedAxes -notmatch $axis) {
                    return $false
                }
            }
            return $true
        }

        # First check current state
        try {
            $toolhead = Get-KlippyObject -PrinterName $printer.PrinterName -ObjectName "toolhead" -Attributes "homed_axes"
            if (& $checkHomed $toolhead.HomedAxes) {
                if (-not $Quiet) {
                    Write-Host "[$($printer.PrinterName)] Axes already homed: $($toolhead.HomedAxes)"
                }
                return [PSCustomObject]@{
                    PSTypeName  = 'KlippyCLI.WaitResult'
                    PrinterId   = $printer.Id
                    PrinterName = $printer.PrinterName
                    HomedAxes   = $toolhead.HomedAxes
                    WaitTime    = [TimeSpan]::Zero
                    Success     = $true
                }
            }
        }
        catch {
            Write-Verbose "Could not get current homed state: $_"
        }

        if (-not $Quiet) {
            Write-Host "[$($printer.PrinterName)] Waiting for axes ($axesDisplay) to be homed..." -NoNewline
        }

        $startTime = [datetime]::UtcNow
        $ws = $null

        try {
            $ws = New-KlippyWebSocketClient -Printer $printer
            $null = $ws.Subscribe(@{ toolhead = @('homed_axes') })

            $deadline = [datetime]::UtcNow.AddSeconds($Timeout)
            $lastHomedAxes = ''

            while ([datetime]::UtcNow -lt $deadline) {
                $message = $ws.Receive(1000)

                if ($null -ne $message -and $message.method -eq 'notify_status_update' -and $message.params) {
                    $status = $message.params[0]
                    if ($status.toolhead.homed_axes) {
                        $lastHomedAxes = $status.toolhead.homed_axes

                        if (& $checkHomed $lastHomedAxes) {
                            if (-not $Quiet) {
                                Write-Host " Done! ($lastHomedAxes)"
                            }

                            return [PSCustomObject]@{
                                PSTypeName  = 'KlippyCLI.WaitResult'
                                PrinterId   = $printer.Id
                                PrinterName = $printer.PrinterName
                                HomedAxes   = $lastHomedAxes
                                WaitTime    = [datetime]::UtcNow - $startTime
                                Success     = $true
                            }
                        }
                    }
                }

                if (-not $Quiet) {
                    Write-Host "." -NoNewline
                }
            }

            # Timeout
            if (-not $Quiet) {
                Write-Host " Timeout!"
            }

            Write-Warning "[$($printer.PrinterName)] Timeout waiting for homing after $Timeout seconds. Current: $lastHomedAxes"

            return [PSCustomObject]@{
                PSTypeName  = 'KlippyCLI.WaitResult'
                PrinterId   = $printer.Id
                PrinterName = $printer.PrinterName
                HomedAxes   = $lastHomedAxes
                WaitTime    = [datetime]::UtcNow - $startTime
                Success     = $false
            }
        }
        catch {
            if (-not $Quiet) {
                Write-Host " Error!"
            }
            Write-Error "[$($printer.PrinterName)] Error waiting for homing: $_"

            return [PSCustomObject]@{
                PSTypeName  = 'KlippyCLI.WaitResult'
                PrinterId   = $printer.Id
                PrinterName = $printer.PrinterName
                HomedAxes   = $null
                WaitTime    = [datetime]::UtcNow - $startTime
                Success     = $false
                Error       = $_.Exception.Message
            }
        }
        finally {
            if ($ws) {
                $ws.Close()
            }
        }
    }
}