mirror of
https://github.com/kerberos-io/onvif.git
synced 2026-08-23 15:08:33 +00:00
feat(examples): add event/stream CLI for live camera verification
Adds a small command at examples/event/stream that opens a real ONVIF event stream against a camera and prints decoded events one per line. Intended for verifying the classifier against actual hardware (AXIS in particular) and as runnable documentation for new consumers of the package — point it at a configured camera, trigger motion, watch the events arrive. Behaviour --------- * Required flags: -xaddr, -username, -password (matches existing examples/event/* commands so anyone running the older subscribe / pullmessage demos already knows the shape). * Optional -filter passes through to Options.TopicFilter; default empty so AXIS works out of the box. * -duration N stops after N (default 0 = run until Ctrl-C). * Prints kind/state/op/topic on each event plus source and data maps when present, so multi-item ONVIF payloads (AXIS AOA active+classType+confidence, DigitalInput InputToken+LogicalState) are visible without re-reading PullMessages SOAP. * Errors channel surfaced to stderr via log; the stream auto-recovers per the reconnect logic in stream.go so transient errors do not terminate the demo. Not part of any CI; not a production tool — this is a verification harness.
This commit is contained in:
107
examples/event/stream/main.go
Normal file
107
examples/event/stream/main.go
Normal file
@@ -0,0 +1,107 @@
|
||||
// Command streamtest opens an event stream against an ONVIF camera and
|
||||
// prints decoded events as they arrive. Useful for verifying the
|
||||
// classifier against real-camera topics; not intended as a production
|
||||
// tool.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// go run ./examples/event/stream \
|
||||
// -xaddr 192.168.1.10 \
|
||||
// -username root -password admin \
|
||||
// -duration 60s
|
||||
//
|
||||
// The xaddr is the camera's host or host:port (the library appends
|
||||
// /onvif/device_service); pass with no protocol prefix.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/kerberos-io/onvif"
|
||||
"github.com/kerberos-io/onvif/event/stream"
|
||||
)
|
||||
|
||||
func main() {
|
||||
xaddr := flag.String("xaddr", "", "camera host or host:port (required)")
|
||||
username := flag.String("username", "", "ONVIF user (required)")
|
||||
password := flag.String("password", "", "ONVIF password (required)")
|
||||
deviceID := flag.String("device-id", "", "logical name printed with each event (default: xaddr)")
|
||||
filter := flag.String("filter", "", "raw ONVIF ConcreteSet topic filter (empty = all topics, works on AXIS)")
|
||||
pullTimeout := flag.Duration("pull-timeout", 5*time.Second, "server-side wait per PullMessages call")
|
||||
duration := flag.Duration("duration", 0, "stop after this long (0 = run until Ctrl-C)")
|
||||
flag.Parse()
|
||||
|
||||
if *xaddr == "" || *username == "" || *password == "" {
|
||||
flag.Usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
if *deviceID == "" {
|
||||
*deviceID = *xaddr
|
||||
}
|
||||
|
||||
dev, err := onvif.NewDevice(onvif.DeviceParams{
|
||||
Xaddr: *xaddr,
|
||||
Username: *username,
|
||||
Password: *password,
|
||||
AuthMode: onvif.UsernameTokenAuth,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("connect: %v", err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
if *duration > 0 {
|
||||
var done context.CancelFunc
|
||||
ctx, done = context.WithTimeout(ctx, *duration)
|
||||
defer done()
|
||||
}
|
||||
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-sigs
|
||||
cancel()
|
||||
}()
|
||||
|
||||
s, err := stream.NewStream(ctx, dev, stream.Options{
|
||||
DeviceID: *deviceID,
|
||||
TopicFilter: *filter,
|
||||
PullTimeout: *pullTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("open stream: %v", err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
log.Printf("streaming from %s (device-id=%s, filter=%q)", *xaddr, *deviceID, *filter)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Printf("done (%v)", ctx.Err())
|
||||
return
|
||||
case ev, ok := <-s.Events():
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
fmt.Printf("%s kind=%-15s state=%-9s op=%-12s topic=%s",
|
||||
ev.Timestamp.Format(time.RFC3339), ev.Kind, ev.State, ev.Operation, ev.Topic)
|
||||
if len(ev.Source) > 0 {
|
||||
fmt.Printf(" source=%v", ev.Source)
|
||||
}
|
||||
if len(ev.Data) > 0 {
|
||||
fmt.Printf(" data=%v", ev.Data)
|
||||
}
|
||||
fmt.Println()
|
||||
case e := <-s.Errors():
|
||||
log.Printf("stream error: %v", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user