Files
onvif-go/QUICKSTART.md
T

7.9 KiB

Quick Start Guide

Get up and running with go-onvif in 5 minutes!

Installation

go get github.com/0x524a/onvif-go

Step 1: Discover Cameras

Find ONVIF cameras on your network:

package main

import (
    "context"
    "fmt"
    "time"
    
    "github.com/0x524a/onvif-go/discovery"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    
    devices, err := discovery.Discover(ctx, 5*time.Second)
    if err != nil {
        panic(err)
    }
    
    for _, device := range devices {
        fmt.Printf("Found: %s at %s\n", 
            device.GetName(), 
            device.GetDeviceEndpoint())
    }
}

Step 2: Connect to Camera

Create a client and get basic information. The endpoint can be specified in multiple formats:

package main

import (
    "context"
    "fmt"
    "time"
    
    "github.com/0x524a/onvif-go"
)

func main() {
    // Create client - endpoint accepts multiple formats:
    //   - Simple IP: "192.168.1.100"
    //   - IP with port: "192.168.1.100:8080"  
    //   - Full URL: "http://192.168.1.100/onvif/device_service"
    client, err := onvif.NewClient(
        "192.168.1.100",  // Simple IP address works!
        onvif.WithCredentials("admin", "password"),
        onvif.WithTimeout(30*time.Second),
    )
    if err != nil {
        panic(err)
    }
    
    ctx := context.Background()
    
    // Get device info
    info, err := client.GetDeviceInformation(ctx)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("Camera: %s %s (Firmware: %s)\n",
        info.Manufacturer,
        info.Model,
        info.FirmwareVersion)
}

Step 3: Get Stream URL

Retrieve RTSP stream URLs:

// Initialize client (discovers service endpoints)
if err := client.Initialize(ctx); err != nil {
    panic(err)
}

// Get profiles
profiles, err := client.GetProfiles(ctx)
if err != nil {
    panic(err)
}

// Get stream URI for first profile
if len(profiles) > 0 {
    streamURI, err := client.GetStreamURI(ctx, profiles[0].Token)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("Stream URL: %s\n", streamURI.URI)
    // Example: rtsp://192.168.1.100/stream1
}

Step 4: Control PTZ

Move the camera:

profileToken := profiles[0].Token

// Move right for 2 seconds
velocity := &onvif.PTZSpeed{
    PanTilt: &onvif.Vector2D{X: 0.5, Y: 0.0},
}
timeout := "PT2S"
client.ContinuousMove(ctx, profileToken, velocity, &timeout)

time.Sleep(2 * time.Second)

// Stop movement
client.Stop(ctx, profileToken, true, false)

// Go to home position
homePosition := &onvif.PTZVector{
    PanTilt: &onvif.Vector2D{X: 0.0, Y: 0.0},
}
client.AbsoluteMove(ctx, profileToken, homePosition, nil)

Step 5: Adjust Image Settings

Modify camera imaging settings:

// Get video source token
videoSourceToken := profiles[0].VideoSourceConfiguration.SourceToken

// Get current settings
settings, err := client.GetImagingSettings(ctx, videoSourceToken)
if err != nil {
    panic(err)
}

// Modify brightness and contrast
brightness := 60.0
settings.Brightness = &brightness

contrast := 55.0
settings.Contrast = &contrast

// Apply settings
err = client.SetImagingSettings(ctx, videoSourceToken, settings, true)
if err != nil {
    panic(err)
}

fmt.Println("Imaging settings updated!")

Complete Example

Here's a complete program that does everything:

package main

import (
    "context"
    "fmt"
    "log"
    "time"
    
    "github.com/0x524a/onvif-go"
)

func main() {
    // Configuration
    endpoint := "http://192.168.1.100/onvif/device_service"
    username := "admin"
    password := "password"
    
    // Create client
    client, err := onvif.NewClient(
        endpoint,
        onvif.WithCredentials(username, password),
        onvif.WithTimeout(30*time.Second),
    )
    if err != nil {
        log.Fatal(err)
    }
    
    ctx := context.Background()
    
    // Get device information
    fmt.Println("Getting device information...")
    info, err := client.GetDeviceInformation(ctx)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Camera: %s %s\n", info.Manufacturer, info.Model)
    
    // Initialize client
    fmt.Println("\nInitializing client...")
    if err := client.Initialize(ctx); err != nil {
        log.Fatal(err)
    }
    
    // Get profiles
    fmt.Println("Getting media profiles...")
    profiles, err := client.GetProfiles(ctx)
    if err != nil {
        log.Fatal(err)
    }
    
    if len(profiles) == 0 {
        log.Fatal("No profiles found")
    }
    
    profile := profiles[0]
    fmt.Printf("Using profile: %s\n", profile.Name)
    
    // Get stream URI
    streamURI, err := client.GetStreamURI(ctx, profile.Token)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Stream URI: %s\n", streamURI.URI)
    
    // Get snapshot URI
    snapshotURI, err := client.GetSnapshotURI(ctx, profile.Token)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Snapshot URI: %s\n", snapshotURI.URI)
    
    // PTZ control (if supported)
    fmt.Println("\nTesting PTZ control...")
    status, err := client.GetStatus(ctx, profile.Token)
    if err != nil {
        fmt.Printf("PTZ not supported or error: %v\n", err)
    } else {
        fmt.Println("PTZ is supported!")
        if status.Position != nil && status.Position.PanTilt != nil {
            fmt.Printf("Current position: X=%.2f, Y=%.2f\n",
                status.Position.PanTilt.X,
                status.Position.PanTilt.Y)
        }
    }
    
    fmt.Println("\nSetup complete!")
}

Next Steps

  1. Explore Examples: Check out the examples/ directory for more detailed use cases
  2. Read Documentation: Visit pkg.go.dev
  3. Review Architecture: See ARCHITECTURE.md for design details
  4. Check Issues: Look at GitHub Issues for known issues

Common Patterns

Error Handling

info, err := client.GetDeviceInformation(ctx)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) {
        // Handle timeout
    } else if onvif.IsONVIFError(err) {
        // Handle SOAP fault
    } else {
        // Handle other errors
    }
    return err
}

Context with Timeout

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

result, err := client.SomeOperation(ctx)

Checking Service Support

status, err := client.GetStatus(ctx, profileToken)
if errors.Is(err, onvif.ErrServiceNotSupported) {
    fmt.Println("PTZ not supported on this camera")
} else if err != nil {
    return err
}

Tips & Tricks

  1. Always Initialize: Call client.Initialize(ctx) before using service-specific methods
  2. Use Timeouts: Always use contexts with timeouts for network operations
  3. Reuse Clients: Create one client per camera and reuse it
  4. Check Capabilities: Use GetCapabilities() to check what the camera supports
  5. Handle Errors: Check for ErrServiceNotSupported when using optional services

Troubleshooting

Camera Not Found During Discovery

  • Check network connectivity
  • Ensure camera is on the same subnet
  • Verify ONVIF is enabled on the camera
  • Check firewall settings (UDP port 3702)

Authentication Failed

  • Verify username and password
  • Check if camera requires admin privileges
  • Some cameras need authentication enabled

Connection Timeout

  • Increase timeout duration
  • Check network latency
  • Verify endpoint URL is correct
  • Test with ping/curl first

Service Not Supported

  • Check camera capabilities with GetCapabilities()
  • Update camera firmware if needed
  • Some features require specific ONVIF profiles

Additional Resources

Happy coding! 🎥📹