examples/Webcam-Timelapse.ps1

<#
.SYNOPSIS
    Webcam and timelapse examples.

.DESCRIPTION
    Demonstrates how to work with webcams, capture snapshots,
    and create timelapses during prints.
#>


Import-Module KlippyCLI

#region List Webcams

# Get all configured webcams
Get-KlippyWebcam | Format-Table Name, Service, StreamUrl, SnapshotUrl

# Get specific webcam details
$webcam = Get-KlippyWebcam -Name "main_camera"
Write-Host "Webcam: $($webcam.Name)"
Write-Host " Stream URL: $($webcam.StreamUrl)"
Write-Host " Snapshot URL: $($webcam.SnapshotUrl)"
Write-Host " Rotation: $($webcam.Rotation)"
Write-Host " FPS: $($webcam.TargetFps)"

#endregion

#region Capture Snapshots

# Save a snapshot (auto-named with timestamp)
Save-KlippyWebcamSnapshot

# Save to specific path
Save-KlippyWebcamSnapshot -Path "C:\PrinterSnapshots\current.jpg"

# Save from specific webcam
Save-KlippyWebcamSnapshot -WebcamName "bed_camera" -Path "C:\PrinterSnapshots\bed.jpg"

# Save snapshots from all webcams
Get-KlippyWebcam | Save-KlippyWebcamSnapshot -Path "C:\PrinterSnapshots"

# Save with force overwrite
Save-KlippyWebcamSnapshot -Path "C:\PrinterSnapshots\latest.jpg" -Force

#endregion

#region Simple Timelapse Capture

function Start-PrintTimelapse {
    <#
    .SYNOPSIS
        Capture timelapse images during a print
    #>

    param(
        [string]$OutputFolder,
        [int]$IntervalSeconds = 30,
        [string]$WebcamName
    )

    # Create output folder
    if (-not (Test-Path $OutputFolder)) {
        New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
    }

    $frameNumber = 0
    $status = Get-KlippyStatus

    while ($status.State -eq "printing") {
        $frameNumber++
        $frameName = "frame_{0:D5}.jpg" -f $frameNumber
        $framePath = Join-Path $OutputFolder $frameName

        $params = @{
            Path = $framePath
            Force = $true
        }
        if ($WebcamName) {
            $params['WebcamName'] = $WebcamName
        }

        Save-KlippyWebcamSnapshot @params | Out-Null

        $job = Get-KlippyPrintJob
        $progress = [math]::Round($job.Progress * 100, 1)
        Write-Host "Frame $frameNumber captured ($progress% complete)"

        Start-Sleep -Seconds $IntervalSeconds
        $status = Get-KlippyStatus
    }

    Write-Host "Timelapse capture complete: $frameNumber frames in $OutputFolder" -ForegroundColor Green
    return $frameNumber
}

# Usage - Start print then capture timelapse
Start-KlippyPrint -FileName "benchy.gcode"
$frames = Start-PrintTimelapse -OutputFolder "C:\Timelapses\benchy_$(Get-Date -Format 'yyyyMMdd')" -IntervalSeconds 15

#endregion

#region Advanced Timelapse with FFmpeg

function New-TimelapseVideo {
    <#
    .SYNOPSIS
        Create video from captured frames using FFmpeg
    #>

    param(
        [string]$FramesFolder,
        [string]$OutputVideo,
        [int]$Fps = 30
    )

    # Check for FFmpeg
    if (-not (Get-Command ffmpeg -ErrorAction SilentlyContinue)) {
        Write-Error "FFmpeg not found. Please install FFmpeg and add to PATH."
        return
    }

    $inputPattern = Join-Path $FramesFolder "frame_%05d.jpg"

    $ffmpegArgs = @(
        "-framerate", $Fps,
        "-i", $inputPattern,
        "-c:v", "libx264",
        "-pix_fmt", "yuv420p",
        "-y",
        $OutputVideo
    )

    Write-Host "Creating timelapse video..."
    & ffmpeg @ffmpegArgs

    if (Test-Path $OutputVideo) {
        $fileSize = (Get-Item $OutputVideo).Length / 1MB
        Write-Host "Timelapse created: $OutputVideo ($([math]::Round($fileSize, 2)) MB)" -ForegroundColor Green
    }
}

# Usage
New-TimelapseVideo -FramesFolder "C:\Timelapses\benchy_20240101" -OutputVideo "C:\Timelapses\benchy_timelapse.mp4" -Fps 30

#endregion

#region Layer-Change Timelapse

function Start-LayerChangeTimelapse {
    <#
    .SYNOPSIS
        Capture images at each layer change (requires G-code macro integration)

        Note: This requires a TIMELAPSE_TAKE_FRAME macro in your Klipper config
        that's called at layer changes in your slicer.
    #>

    param(
        [string]$OutputFolder,
        [int]$CheckIntervalMs = 500
    )

    # Create output folder
    if (-not (Test-Path $OutputFolder)) {
        New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
    }

    $lastLayer = 0
    $frameNumber = 0

    while ((Get-KlippyStatus).State -eq "printing") {
        # Get current layer from print stats
        $job = Get-KlippyPrintJob

        # Check if layer changed (this depends on your slicer/config exposing layer info)
        # Alternative: Monitor for specific G-code or use webhooks

        # For now, capture at regular intervals during printing
        $frameNumber++
        $framePath = Join-Path $OutputFolder ("layer_{0:D4}.jpg" -f $frameNumber)
        Save-KlippyWebcamSnapshot -Path $framePath -Force | Out-Null

        Start-Sleep -Milliseconds $CheckIntervalMs
    }

    return $frameNumber
}

#endregion

#region Snapshot on Event

function Watch-PrinterAndCapture {
    <#
    .SYNOPSIS
        Monitor printer and capture snapshots on state changes
    #>

    param(
        [string]$OutputFolder
    )

    if (-not (Test-Path $OutputFolder)) {
        New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
    }

    $lastState = ""

    while ($true) {
        $status = Get-KlippyStatus
        $currentState = $status.State

        if ($currentState -ne $lastState) {
            $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
            $snapshotPath = Join-Path $OutputFolder "${timestamp}_${currentState}.jpg"

            Save-KlippyWebcamSnapshot -Path $snapshotPath -Force | Out-Null
            Write-Host "State change: $lastState -> $currentState (captured: $snapshotPath)"

            $lastState = $currentState
        }

        # Exit on certain states
        if ($currentState -in @("shutdown", "error")) {
            Write-Host "Monitoring stopped due to state: $currentState" -ForegroundColor Yellow
            break
        }

        Start-Sleep -Seconds 5
    }
}

#endregion