securityspy

package module
v2.0.2+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 17, 2019 License: MIT Imports: 19 Imported by: 5

README

go-securityspy

reportcard

OVERVIEW

Full Featured Go Library for SecuritySpy's web API. Read about the API here.

Everything is reasonably tested and working. Feedback is welcomed!

ffmpeg is used if you want video snippets, but not required for most functions.

A command line interface app that uses this library exists. Most of the testing is done with this app. Find it here: https://github.com/davidnewhall/SecSpyCLI It's full of great examples on how to use this library, and can be easily installed with homebrew.

  • Works with SecuritySpy 4 and 5.
  • There's a lot more to learn about this package in GODOC.

FEATURES

Server
  • All server and system Info is exposed with one API web request.
  • Schedule Presets can be retrieved and invoked.
Cameras
  • Stream live H264 or MJPEG video from an io.ReadCloser.
  • Stream live G711 audio from an io.ReadCloser.
  • Submit G711 audio (files or microphone) to a camera from an io.ReadCloser.
  • Save live video snippets locally (requires FFMPEG).
  • Get live JPEG images in image format, or save files locally.
  • Arm and Disarm actions, motion capture and continuous capture.
  • Trigger Motion.
  • Set schedules and schedule overrides.
  • Inspect PTZ capabilities.
  • Control all PTZ actions including invoking and saving presets.
Events

SecuritySpy has a handy event stream; you can bind functions and/or channels to all or specific events. When a bound event fires the callback method it's bound to is run. In the case of a channel binding, the event is sent to the channel for consumption by a worker (pool).

  • Exposes all SecuritySpy events.
  • Exposes 6 custom events.
  • Method to inject custom events into the event stream.
Files

SecuritySpy saves video and image files based on motion and continuous capture settings. These files can be listed and downloaded with this library.

  • List and retrieve captured images.
  • List and retrieve continuous captured videos.
  • List and retrieve motion captured videos.
  • Save files locally or stream from io.ReadCloser.

EXAMPLE

This example shows some of the data that is provided by the API. None of the actions methods are invoked here. See the SecSpyCLI app for examples of other methods.

package main

import (
	"fmt"
	"golift.io/securityspy"
)

func main() {
  server, err := securityspy.GetServer(&securityspy.Config{
		Username:  "admin",
		Password:  "password",
		URL:       "http://127.0.0.1:8000",
		VerifySSL: false})
	if err != nil {
		panic(err)
	}
	scripts, _ := server.GetScripts()
	sounds, _ := server.GetSounds()

	// Print server info.
	fmt.Printf("%v %v @ %v (http://%v:%v/) %d cameras, %d scripts, %d sounds, %d schedules, %d schedule presets\n",
		server.Info.Name, server.Info.Version, server.Info.CurrentTime,
		server.Info.IP1, server.Info.HTTPPort, len(server.Cameras.Names),
		len(scripts), len(sounds), len(server.Info.ServerSchedules), len(server.Info.SchedulePresets))

	// Print info for each camera.
	for _, camera := range server.Cameras.All() {
		fmt.Printf("%2v: %-14v (%-4vx%-4v %5v/%-7v %v) connected: %3v, down %v, modes: C:%-8v M:%-8v A:%-8v "+
			"%2vFPS, Audio:%3v, MD: %3v/pre:%v/post:%3v idle %-10v Script: %v (reset %v)\n",
			camera.Number, camera.Name, camera.Width, camera.Height, camera.DeviceName, camera.DeviceType, camera.Address,
			camera.Connected.Val, camera.TimeSinceLastFrame.String(), camera.ModeC.Txt, camera.ModeM.Txt,
			camera.ModeA.Txt+",", int(camera.CurrentFPS), camera.HasAudio.Txt, camera.MDenabled.Txt,
			camera.MDpreCapture.String(), camera.MDpostCapture.String(),
			camera.TimeSinceLastMotion.String(), camera.ActionScriptName, camera.ActionResetTime.String())
	}
}

The output looks like this:

SecuritySpy 4.2.10b9 @ 2019-02-09 16:20:00 -0700 MST (http://192.168.1.1:8000/) 7 cameras, 18 scripts, 20 sounds, 6 schedules, 1 schedule presets
 0: Porch          (2304x1296 ONVIF/Network 192.168.1.12) connected: true, down 0s, modes: C:armed    M:armed    A:armed,   20FPS, Audio:yes, MD: yes/pre:3s/post:10s idle 3h5m5s     Script: SS_SendiMessages.scpt (reset 1m0s)
 1: Door           (2592x1520 ONVIF/Network 192.168.1.13) connected: true, down 0s, modes: C:armed    M:armed    A:armed,   15FPS, Audio:yes, MD: yes/pre:4s/post: 5s idle 9m24s      Script: SS_SendiMessages.scpt (reset 1m0s)
 2: Road           (2592x1520 ONVIF/Network 192.168.1.11) connected: true, down 0s, modes: C:armed    M:armed    A:disarmed, 20FPS, Audio: no, MD: yes/pre:3s/post: 5s idle 4m35s      Script: SS_SendiMessages.scpt (reset 59s)
 3: Garage         (3072x2048 ONVIF/Network 192.168.1.14) connected: true, down 0s, modes: C:armed    M:armed    A:armed,   20FPS, Audio:yes, MD: yes/pre:3s/post: 5s idle -1ns       Script: SS_SendiMessages.scpt (reset 1m0s)
 4: Gate           (2560x1440 ONVIF/Network 192.168.1.16) connected: true, down 0s, modes: C:armed    M:armed    A:armed,   29FPS, Audio:yes, MD: yes/pre:3s/post: 5s idle -1ns       Script: SS_SendiMessages.scpt (reset 1m0s)
 5: Pool           (3072x2048 ONVIF/Network 192.168.1.17) connected: true, down 0s, modes: C:armed    M:armed    A:armed,   10FPS, Audio:yes, MD: yes/pre:2s/post:20s idle 16m18s     Script: SS_SendiMessages.scpt (reset 1m0s)
 6: Car            (2048x1536 ONVIF/Network 192.168.1.18) connected: true, down 0s, modes: C:armed    M:armed    A:armed,   20FPS, Audio: no, MD: yes/pre:0s/post:15s idle -1ns       Script: SS_SendiMessages.scpt (reset 48s)

LICENSE

MIT License - Copyright (c) 2019 David Newhall II

Documentation

Overview

Package securityspy is a full featured SDK library for interacting with the SecuritySpy API: https://www.bensoftware.com/securityspy/web-server-spec.html

Index

Constants

View Source
const (
	// UnknownEventText should only appear if SecuritySpy adds new event types.
	UnknownEventText = "Unknown Event"
	// UnknownReasonText should only appear if SecuritySpy adds new motion detection reasons.
	UnknownReasonText = "Unknown Reason"
	// EventTimeFormat is the go-time-format returned by SecuritySpy's eventStream
	// The GMT offset from ++systemInfo is appended later for unmarshaling w/ localization.
	EventTimeFormat = "20060102150405"
)
View Source
const (
	TriggerByMotion = TriggerEvent(1) << iota
	TriggerByAudio
	TriggerByScript
	TriggerByCameraEvent
	TriggerByWebServer
	TriggerByOtherCamera
	TriggerByManual
	TriggerByHumanDetection
	TriggerByVehicleDetection
)

These are the trigger reasons SecuritySpy exposes. v5+

Variables

View Source
var (
	// ErrorUnknownEvent never really returns, but will fire if SecuritySpy
	// adds new events this library doesn't know about.
	ErrorUnknownEvent = errors.New("unknown event")

	// ErrorCAMParseFail will return if the camera number in an event stream does not exist.
	// If you see this, run Refresh() more often, or fix your flaky camera connection.
	ErrorCAMParseFail = errors.New("CAM parse failed")

	// ErrorIDParseFail will return if the camera number provided by the event stream is not a number.
	// This should never happen, but future versions of SecuritySpy could trigger this if formats change.
	ErrorIDParseFail = errors.New("ID parse failed")

	// ErrorCAMMissing like the errors above should never return.
	// This is triggered by a corrupted event format.
	ErrorCAMMissing = errors.New("camera number missing")

	// ErrorDateParseFail will only trigger if the time stamp format for events changes.
	ErrorDateParseFail = errors.New("timestamp parse failed")

	// ErrorDisconnect becomes the msg in a custom event when the SecSpy event stream is disconnected.
	ErrorDisconnect = errors.New("server connection closed")
)

This is a list of errors returned by the Events methods.

View Source
var (
	// ErrorPathExists returns when a requested write path already exists.
	ErrorPathExists = errors.New("cannot overwrite existing path")

	// ErrorInvalidName returns when requesting a file download and the filename is invalid.
	ErrorInvalidName = errors.New("invalid file name")
)

Errors returned by the Files type methods.

View Source
var (
	// ErrorPTZNotOK is returned for any command that has a successful web request,
	// but the reply does not end with the word OK.
	ErrorPTZNotOK = errors.New("PTZ command not OK")

	// ErrorPTZRange returns when a PTZ preset outside of 1-8 is provided.
	ErrorPTZRange = errors.New("PTZ preset out of range 1-8")
)
View Source
var DefaultTimeout = 10 * time.Second

DefaultTimeout it used for almost every request to SecuritySpy. Adjust as needed.

View Source
var Encoder = "/usr/local/bin/ffmpeg"

Encoder is the path to ffmpeg.

View Source
var ErrorCmdNotOK = errors.New("command unsuccessful")

ErrorCmdNotOK is returned for any command that has a successful web request, but the reply does not end with the word OK.

View Source
var EventNames = map[EventType]string{
	EventArmContinuous:    "Continuous Capture Armed",
	EventDisarmContinuous: "Continuous Capture Disarmed",
	EventArmMotion:        "Motion Capture Armed",
	EventDisarmMotion:     "Motion Capture Disarmed",
	EventArmActions:       "Actions Armed",
	EventDisarmActions:    "Actions Disarmed",
	EventSecSpyError:      "SecuritySpy Error",
	EventConfigChange:     "Configuration Change",
	EventMotionDetected:   "Motion Detected",
	EventOffline:          "Camera Offline",
	EventOnline:           "Camera Online",
	EventClassify:         "Classification",
	EventTriggerMotion:    "Triggered Motion",
	EventTriggerAction:    "Triggered Action",
	EventFileWritten:      "File Written",
	EventKeepAlive:        "Stream Keep Alive",

	EventStreamDisconnect:   "Event Stream Disconnected",
	EventStreamConnect:      "Event Stream Connected",
	EventUnknownEvent:       UnknownEventText,
	EventAllEvents:          "Any Event",
	EventWatcherRefreshed:   "SystemInfo Refresh Success",
	EventWatcherRefreshFail: "SystemInfo Refresh Failure",
	EventStreamCustom:       "Custom Event",
}

EventNames contains the human readable names for each event.

View Source
var Reasons = map[TriggerEvent]string{
	TriggerByMotion:           "Motion Detected",
	TriggerByAudio:            "Audio Detected",
	TriggerByScript:           "AppleScript",
	TriggerByCameraEvent:      "Camera Event",
	TriggerByWebServer:        "Web Server",
	TriggerByOtherCamera:      "Other Camera",
	TriggerByManual:           "Manual",
	TriggerByHumanDetection:   "Human Detected",
	TriggerByVehicleDetection: "Vehicle Detected",
}

Reasons is the human-readable explanation for a motion detection reason.

Functions

This section is empty.

Types

type Camera

type Camera struct {
	Number              int            `xml:"number"`               // 0, 1, 2, 3, 4, 5, 6
	Connected           YesNoBool      `xml:"connected"`            // yes, yes, yes, yes, yes, ...
	Width               int            `xml:"width"`                // 2560, 2592, 2592, 3072, 2...
	Height              int            `xml:"height"`               // 1440, 1520, 1520, 2048, 1...
	Mode                YesNoBool      `xml:"mode"`                 // active, active, active, a...
	ModeC               YesNoBool      `xml:"mode-c"`               // armed, armed, armed, arme...
	ModeM               YesNoBool      `xml:"mode-m"`               // armed, armed, armed, arme...
	ModeA               YesNoBool      `xml:"mode-a"`               // armed, armed, armed, arme...
	HasAudio            YesNoBool      `xml:"hasaudio"`             // yes, yes, no, yes, yes, y...
	PTZ                 *PTZ           `xml:"ptzcapabilities"`      // 0, 0, 31, 0, 0, 0, 0
	TimeSinceLastFrame  Duration       `xml:"timesincelastframe"`   // 0, 0, 0, 0, 0, 0, 0
	TimeSinceLastMotion Duration       `xml:"timesincelastmotion"`  // 689, 3796, 201, 12477, 15...
	DeviceName          string         `xml:"devicename"`           // ONVIF, ONVIF, ONVIF, ONVI...
	DeviceType          string         `xml:"devicetype"`           // Network, Network, Network...
	Address             string         `xml:"address"`              // 192.168.69.12, 192.168.69...
	Port                int            `xml:"port"`                 // 80, 80, 80, 0=80
	PortRTSP            int            `xml:"port-rtsp"`            // 554, 0=554
	Request             string         `xml:"request"`              // /some/rtsp/math (manual only)
	Name                string         `xml:"name"`                 // Porch, Door, Road, Garage...
	Overlay             YesNoBool      `xml:"overlay"`              // no, no, no, no, no, no, n...
	OverlayText         string         `xml:"overlaytext"`          // +d, +d, +d, +d, +d, +d, +...
	Transformation      int            `xml:"transformation"`       // 0, 1, 2, 3, 4, 5
	AudioNetwork        YesNoBool      `xml:"audio_network"`        // yes, yes, yes, yes, yes, ...
	AudioDeviceName     string         `xml:"audio_devicename"`     // Another Camera
	MDenabled           YesNoBool      `xml:"md_enabled"`           // yes, yes, yes, yes, yes, ...
	MDsensitivity       int            `xml:"md_sensitivity"`       // 51, 50, 47, 50, 50, 50, 5...
	MDtriggerTimeX2     Duration       `xml:"md_triggertime_x2"`    // 2, 2, 1, 2, 2, 2, 2
	MDcapture           YesNoBool      `xml:"md_capture"`           // yes, yes, yes, yes, yes, ...
	MDcaptureFPS        float64        `xml:"md_capturefps"`        // 20, 20, 20, 20, 20, 20, 2...
	MDpreCapture        Duration       `xml:"md_precapture"`        // 3, 4, 3, 3, 3, 2, 0
	MDpostCapture       Duration       `xml:"md_postcapture"`       // 10, 5, 5, 5, 5, 20, 15
	MDcaptureImages     YesNoBool      `xml:"md_captureimages"`     // no, no, no, no, no, no, n...
	MDuploadImages      YesNoBool      `xml:"md_uploadimages"`      // no, no, no, no, no, no, n...
	MDeecordAudio       YesNoBool      `xml:"md_recordaudio"`       // yes, yes, yes, yes, yes, ...
	MDaudioTrigger      YesNoBool      `xml:"md_audiotrigger"`      // no, no, no, no, no, no, n...
	MDaudioThreshold    int            `xml:"md_audiothreshold"`    // 50, 50, 50, 50, 50, 50, 5...
	ActionScriptName    string         `xml:"action_scriptname"`    // SS_SendiMessages.scpt, SS...
	ActionSoundName     string         `xml:"action_soundname"`     // sound_file_name
	ActionResetTime     Duration       `xml:"action_resettime"`     // 60, 60, 60, 60, 60, 60, 4...
	TLcapture           YesNoBool      `xml:"tl_capture"`           // no, no, no, no, no, no, n...
	TLrecordAudio       YesNoBool      `xml:"tl_recordaudio"`       // yes, yes, yes, yes, yes, ...
	CurrentFPS          float64        `xml:"current-fps"`          // 20.000, 20.000, 20.000, 2...
	ScheduleIDCC        CameraSchedule `xml:"schedule-id-cc"`       // 1, 1, 1, 1, 1, 1, 0
	ScheduleIDMC        CameraSchedule `xml:"schedule-id-mc"`       // 1, 1, 1, 1, 1, 1, 1
	ScheduleIDA         CameraSchedule `xml:"schedule-id-a"`        // 1, 1, 1, 1, 1, 1, 1
	ScheduleOverrideCC  CameraSchedule `xml:"schedule-override-cc"` // 0, 0, 0, 0, 0, 0, 0
	ScheduleOverrideMC  CameraSchedule `xml:"schedule-override-mc"` // 0, 0, 0, 0, 0, 0, 0
	ScheduleOverrideA   CameraSchedule `xml:"schedule-override-a"`  // 0, 0, 0, 0, 0, 0, 0
	PresetName1         string         `xml:"preset-name-1"`
	PresetName2         string         `xml:"preset-name-2"`
	PresetName3         string         `xml:"preset-name-3"`
	PresetName4         string         `xml:"preset-name-4"`
	PresetName5         string         `xml:"preset-name-5"`
	PresetName6         string         `xml:"preset-name-6"`
	PresetName7         string         `xml:"preset-name-7"`
	PresetName8         string         `xml:"preset-name-8"`
	Permissions         int64          `xml:"permissions"`  // 63167, 63167, 62975, 6316...
	CapturePath         string         `xml:"capture-path"` // "/Volumes/Cameras/Porch" (v5+)
	// contains filtered or unexported fields
}

Camera defines the data returned from the SecuritySpy API. This data is directly unmarshalled from the XML returned by the ++systemInfo method. Use the attached methods to control a camera in various ways.

func (*Camera) GetJPEG

func (c *Camera) GetJPEG(ops *VidOps) (image.Image, error)

GetJPEG returns an images from a camera. VidOps defines the image size. ops.FPS is ignored.

func (*Camera) PostG711

func (c *Camera) PostG711(audio io.ReadCloser) error

PostG711 makes a POST request to send audio to a camera with a speaker. Accepts an io.ReadCloser that will be closed. Probably an open file. This is untested. Report your success or failure!

func (*Camera) SaveJPEG

func (c *Camera) SaveJPEG(ops *VidOps, path string) error

SaveJPEG gets a picture from a camera and puts it in a file (path). The file will be overwritten if it exists. VidOps defines the image size. ops.FPS is ignored.

func (*Camera) SaveVideo

func (c *Camera) SaveVideo(ops *VidOps, length time.Duration, maxsize int64, outputFile string) error

SaveVideo saves a segment of video from a camera to a file using FFMPEG.

func (*Camera) SetSchedule

func (c *Camera) SetSchedule(mode CameraMode, scheduleID int) error

SetSchedule configures a camera mode's primary schedule. Get a list of schedules IDs you can use here from server.Info.Schedules. CameraModes are constants with names that start with CameraMode*

func (*Camera) SetScheduleOverride

func (c *Camera) SetScheduleOverride(mode CameraMode, overrideID int) error

SetScheduleOverride temporarily overrides a camera mode's current schedule. Get a list of overrides IDs you can use here from server.Info.ScheduleOverrides. CameraModes are constants with names that start with CameraMode*

func (*Camera) StreamG711

func (c *Camera) StreamG711() (io.ReadCloser, error)

StreamG711 makes a web request to retrieve an G711 audio stream. Returns an io.ReadCloser that will (hopefully) never end.

func (*Camera) StreamH264

func (c *Camera) StreamH264(ops *VidOps) (io.ReadCloser, error)

StreamH264 makes a web request to retrieve an H264 stream. Returns an io.ReadCloser that will (hopefully) never end.

func (*Camera) StreamMJPG

func (c *Camera) StreamMJPG(ops *VidOps) (io.ReadCloser, error)

StreamMJPG makes a web request to retrieve a motion JPEG stream. Returns an io.ReadCloser that will (hopefully) never end.

func (*Camera) StreamVideo

func (c *Camera) StreamVideo(ops *VidOps, length time.Duration, maxsize int64) (io.ReadCloser, error)

StreamVideo streams a segment of video from a camera using FFMPEG. VidOps defines the video options for the video stream. Returns an io.ReadCloser with the video stream. Close() it when finished.

func (*Camera) ToggleActions

func (c *Camera) ToggleActions(arm CameraArmMode) error

ToggleActions arms (true) or disarms (false) a camera's actions.

func (*Camera) ToggleContinuous

func (c *Camera) ToggleContinuous(arm CameraArmMode) error

ToggleContinuous arms (true) or disarms (false) a camera's continuous capture mode.

func (*Camera) ToggleMotion

func (c *Camera) ToggleMotion(arm CameraArmMode) error

ToggleMotion arms (true) or disarms (false) a camera's motion capture mode.

func (*Camera) TriggerMotion

func (c *Camera) TriggerMotion() error

TriggerMotion sets a camera as currently seeing motion. Other actions likely occur because of this!

type CameraArmMode

type CameraArmMode rune

CameraArmMode locks arming to an integer of 0 or 1.

const (
	CameraDisarm CameraArmMode = iota
	CameraArm
)

Arming is either 0 or 1. Use these constants as inputs to a camera's schedule methods.

type CameraMode

type CameraMode rune

CameraMode is a set of constants to deal with three specific camera modes.

const (
	CameraModeAll        CameraMode = 'X'
	CameraModeMotion     CameraMode = 'M'
	CameraModeActions    CameraMode = 'A'
	CameraModeContinuous CameraMode = 'C'
)

CameraMode* are used by the Camera scheduling methods. Use these constants as inputs to a Camera's schedule methods.

type CameraSchedule

type CameraSchedule struct {
	Name string
	ID   int
}

CameraSchedule contains schedule info for a camera's properties. This is assigned to Motion Capture, Continuous Capture and Actions.

func (*CameraSchedule) UnmarshalXML

func (bit *CameraSchedule) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML stores a schedule ID into a CameraSchedule type. This isn't a method you should ever call directly; it is only used during data initialization.

type Cameras

type Cameras struct {
	Names   []string
	Numbers []int
	// contains filtered or unexported fields
}

Cameras is an interface into the Camera system. Use the methods bound here to retrieve camera interfaces.

func (*Cameras) All

func (c *Cameras) All() (cams []*Camera)

All returns interfaces for every camera.

func (*Cameras) ByName

func (c *Cameras) ByName(name string) *Camera

ByName returns an interface for a single camera, using the name.

func (*Cameras) ByNum

func (c *Cameras) ByNum(number int) *Camera

ByNum returns an interface for a single camera.

type Config

type Config struct {
	VerifySSL bool
	URL       string
	Password  string
	Username  string
}

Config is the input data for this library. Only set VerifySSL to true if your server has a valid SSL certificate. The password is auto-repalced with a base64 encoded string.

type Duration

type Duration struct {
	time.Duration
	Val string
}

Duration is used to convert the "Seconds" given to us by the SecuritySpy API into a go time.Duration.

func (*Duration) UnmarshalXML

func (bit *Duration) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML method converts seconds from a string to time.Duration. This isn't a method you should ever call directly; it is only used during data initialization.

type Event

type Event struct {
	Time   time.Time // Local time event was recorded.
	When   time.Time // Event time according to server.
	ID     int       // Negative numbers are custom events.
	Camera *Camera   // Each event gets a camera interface.
	Type   EventType // Event identifier
	Msg    string    // Event Text
	Errors []error   // Errors populated by parse errors.
}

Event represents a SecuritySpy event from the Stream Reply. This is the INPUT data for an event that is sent to a bound callback method or channel.

func (*Event) String

func (e *Event) String() string

String provides a description of an event.

type EventType

type EventType string

EventType is a set of constant strings validated by the EventNames map.

const (
	EventArmContinuous    EventType = "ARM_C"
	EventDisarmContinuous EventType = "DISARM_C"
	EventArmMotion        EventType = "ARM_M"
	EventDisarmMotion     EventType = "DISARM_M"
	EventDisarmActions    EventType = "DISARM_A"
	EventArmActions       EventType = "ARM_A"
	EventSecSpyError      EventType = "ERROR"
	EventConfigChange     EventType = "CONFIGCHANGE"
	EventMotionDetected   EventType = "MOTION" // Legacy (v4)
	EventOnline           EventType = "ONLINE"
	EventOffline          EventType = "OFFLINE"
	EventClassify         EventType = "CLASSIFY"
	EventTriggerMotion    EventType = "TRIGGER_M"
	EventTriggerAction    EventType = "TRIGGER_A"
	EventFileWritten      EventType = "FILE"
	EventKeepAlive        EventType = "NULL"
	// The following belong to the library, not securityspy.
	EventStreamDisconnect   EventType = "DISCONNECTED"
	EventStreamConnect      EventType = "CONNECTED"
	EventUnknownEvent       EventType = "UNKNOWN"
	EventAllEvents          EventType = "ALL"
	EventWatcherRefreshed   EventType = "REFRESH"
	EventWatcherRefreshFail EventType = "REFRESHFAIL"
	EventStreamCustom       EventType = "CUSTOM"
)

Events that can be returned by the event stream. These events can have channels or callback functions bound to them. The DISCONNECTED event fires when the event stream is disconnected, so watch that event with a binding to detect stream interruptions.

type Events

type Events struct {
	Running bool
	// contains filtered or unexported fields
}

Events is the main Events interface. Use the methods bound here to bind your own functions, methods and channels to SecuritySpy events. Call Watch() to connect to the event stream. The Running bool is true when the event stream watcher routine is active.

func (*Events) BindChan

func (e *Events) BindChan(event EventType, channel chan Event)

BindChan binds a receiving channel to an Event in SecuritySpy. Use this to receive incoming events over a channel. Avoid using unbuffered channels as they may block further event processing.

func (*Events) BindFunc

func (e *Events) BindFunc(event EventType, callBack func(Event))

BindFunc binds a call-back function to an Event in SecuritySpy. Use this to receive incoming events via a callback method in a go routine.

func (*Events) Custom

func (e *Events) Custom(cameraNum int, msg string)

Custom fires an event into the running event Watcher. Any functions or channels bound to the CUSTOM Event type will also be called.

func (*Events) Stop

func (e *Events) Stop(closeChans bool)

Stop stops Watch() loops and disconnects from the event stream. No further callback messages will fire after this is called. Closes all channels that were passed to BindChan if closeChans=true. Stop writing to the channels with Custom() before calling Stop().

func (*Events) UnbindAll

func (e *Events) UnbindAll()

UnbindAll removes all event bindings and channels.

func (*Events) UnbindChan

func (e *Events) UnbindChan(event EventType)

UnbindChan removes all bound channels for a particular event.

func (*Events) UnbindFunc

func (e *Events) UnbindFunc(event EventType)

UnbindFunc removes all bound callbacks for a particular event. EventType is a set of constants that begin with Event*

func (*Events) UnmarshalEvent

func (e *Events) UnmarshalEvent(text string) Event

UnmarshalEvent turns raw text into an Event that can fire callbacks. You generally shouldn't need to call this method, it's exposed for convenience.

 [TIME] is specified in the order year, month, day, hour, minute, second and is always 14 characters long
 * [EVENT NUMBER] increases by 1 for each subsequent event
 * [CAMERA NUMBER] specifies the camera that this event relates to, for example CAM15 for camera number 15
 * [EVENT] describes the event: ARM_C, DISARM_C, ARM_M, DISARM_M, ARM_A, DISARM_A, ERROR, CONFIGCHANGE, MOTION, OFFLINE, ONLINE
	Example Event Stream Flow:
	(old, v4)
	20190114200911 104519 CAM2 MOTION
	20190114201129 104520 CAM5 DISARM_C
	20190114201129 104521 CAM5 DISARM_M
	20190114201129 104522 CAM5 DISARM_A
	20190114201129 104523 CAM5 OFFLINE
	20190114201139 104524 CAM0 ERROR 10,835 Error communicating with the network device "Porch".
	20190114201155 104525 CAM5 ERROR 70900,800 Error communicating with the network device "Pool".
	20190114201206 104526 CAM5 ONLINE
	20190114201206 104527 CAM5 ARM_C
	20190114201206 104528 CAM5 ARM_M
	20190114201206 104529 CAM5 ARM_A
	(new, v5)
	20190927092026 3 3 CLASSIFY HUMAN 99
	20190927092026 4 3 TRIGGER_M 9
	20190927092036 5 3 CLASSIFY HUMAN 5 VEHICLE 95
	20190927092040 5 X NULL
	20190927092050 6 3 FILE /Volumes/VolName/Cam/2019-07-26/26-07-2019 15-52-00 C Cam.m4v
	20190927092055 7 3 DISARM_M
	20190927092056 8 3 OFFLINE

func (*Events) Watch

func (e *Events) Watch(retryInterval time.Duration, refreshOnConfigChange bool)

Watch kicks off the routines to watch the eventStream and fire callback bindings. If your application relies on event stream messages, call this at least once to connect the stream. If you have no call back functions or channels then do not call this. Call Stop() to close the connection when you're done with it.

type File

type File struct {
	Title string `xml:"title"` // 01-12-2019 M Gate.m4v, 01...
	Link  struct {
		Rel    string `xml:"rel,attr"`    // alternate, alternate, alternate
		Type   string `xml:"type,attr"`   // video/quicktime, video/quicktime
		Length int64  `xml:"length,attr"` // 358472320, 483306152, 900789978,
		HREF   string `xml:"href,attr"`   // ++getfile/4/2018-10-17/10-17-2018+M+Gate.m4v
	} `xml:"link"`
	Updated   time.Time     `xml:"updated"`   // 2019-01-12T08:57:58Z, 201...
	CameraNum int           `xml:"cameraNum"` // 0, 1, 2, 4, 5, 7, 9, 10, 11, 12, 13
	GmtOffset time.Duration // the rest are copied in per-file from fileFeed.
	Camera    *Camera
	// contains filtered or unexported fields
}

File represents a saved media file. This is all the data retreived from the ++download method for a particular file. Contains a camera interface for the camera that created the file. All of the Files type methods return this type.

func (*File) Get

func (f *File) Get(highBandwidth bool) (io.ReadCloser, error)

Get opens a file from a SecuritySpy download href and returns the http.Body io.ReadCloser. Close() the Closer when finished. Pass true (for highBandwidth) will download the full size file. Passing false will download a smaller transcoded file.

func (*File) Save

func (f *File) Save(path string) (int64, error)

Save downloads a saved media File from SecuritySpy and saves it to a local file. Returns an error if path exists.

type Files

type Files struct {
	// contains filtered or unexported fields
}

Files powers the Files interface. Use the bound methods to list and download saved media files.

func (*Files) GetAll

func (f *Files) GetAll(cameraNums []int, from, to time.Time) ([]*File, error)

GetAll returns a list of File interfaces to all captured videos and images. Takes in a list of Camera Numbers, as well as a start and stop time to filter results.

func (*Files) GetCCVideos

func (f *Files) GetCCVideos(cameraNums []int, from, to time.Time) ([]*File, error)

GetCCVideos returns a list of File interfaces to continuous-captured videos. Takes in a list of Camera Numbers, as well as a start and stop time to filter results.

func (*Files) GetFile

func (f *Files) GetFile(name string) (*File, error)

GetFile returns a file based on the name. It makes a lot of assumptions about file paths. Not all methods work with this. Avoid it if possible. This allows Get() and Save() to work for an arbitrary file name.

func (*Files) GetImages

func (f *Files) GetImages(cameraNums []int, from, to time.Time) ([]*File, error)

GetImages returns a list of File interfaces to captured images. Takes in a list of Camera Numbers, as well as a start and stop time to filter results.

func (*Files) GetMCVideos

func (f *Files) GetMCVideos(cameraNums []int, from, to time.Time) ([]*File, error)

GetMCVideos returns a list of File interfaces to motion-captured videos. Takes in a list of Camera Numbers, as well as a start and stop time to filter results.

type PTZ

type PTZ struct {
	HasPanTilt bool // true if a camera can pan and tilt using PTZ controls.
	HasHome    bool // true if the camera supports the home position PTZ command.
	HasZoom    bool // true if the camera supports zooming in and out.
	HasPresets bool // true when the camera allows user-defined preset positions.
	Continuous bool // true if the camera supports continuous movement.
	// contains filtered or unexported fields
}

PTZ are what "things" a camera can do. Use the bound methods to interact with a camera's PTZ controls.

func (*PTZ) Down

func (z *PTZ) Down() error

Down makes a camera look down one click.

func (*PTZ) DownLeft

func (z *PTZ) DownLeft() error

DownLeft sends a camera down and to the left a click.

func (*PTZ) DownRight

func (z *PTZ) DownRight() error

DownRight is sorta like making the camera do a dab.

func (*PTZ) Home

func (z *PTZ) Home() error

Home sends a camera to the home position.

func (*PTZ) Left

func (z *PTZ) Left() error

Left sends a camera to the left one click.

func (*PTZ) Preset

func (z *PTZ) Preset(preset PTZpreset) error

Preset instructs a a camera to move a preset position.

func (*PTZ) PresetSave

func (z *PTZ) PresetSave(preset PTZpreset) error

PresetSave instructs a preset to be permanently saved. good luck!

func (*PTZ) Right

func (z *PTZ) Right() error

Right sends a camera to the right one click.

func (*PTZ) Stop

func (z *PTZ) Stop() error

Stop instructs a camera to stop moving, assuming it supports continuous movement.

func (*PTZ) UnmarshalXML

func (z *PTZ) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML method converts ptzCapbilities bitmask from an XML payload into true/false abilities. This isn't a method you should ever call directly; it is only used during data initialization.

func (*PTZ) Up

func (z *PTZ) Up() error

Up sends a camera to the sky one click.

func (*PTZ) UpLeft

func (z *PTZ) UpLeft() error

UpLeft will send a camera up and to the left a click.

func (*PTZ) UpRight

func (z *PTZ) UpRight() error

UpRight sends a camera up and to the right.

func (*PTZ) Zoom

func (z *PTZ) Zoom(in bool) error

Zoom makes a camera zoom in (true) or out (false).

type PTZpreset

type PTZpreset rune

PTZpreset locks our presets to a max of 8

const (
	PTZpreset1 PTZpreset
	PTZpreset2
	PTZpreset3
	PTZpreset4
	PTZpreset5
	PTZpreset6
	PTZpreset7
	PTZpreset8
)

Presets are 1 through 8. Use these constants as inputs to the PTZ methods.

type Server

type Server struct {
	*Config

	Files   *Files      // Files interface.
	Events  *Events     // Events interface.
	Cameras *Cameras    // Cameras & PTZ interfaces.
	Info    *ServerInfo // ServerInfo struct (no methods).
	// contains filtered or unexported fields
}

Server is the main interface for this library. Contains sub-interfaces for cameras, ptz, files & events This is provided in exchange for a url, username and password.

func GetServer added in v1.0.0

func GetServer(c *Config) (*Server, error)

GetServer returns an iterface to interact with SecuritySpy. This is the only exportred function in the library. All of the other interfaces are accessed through this interface.

func (*Server) GetScripts

func (s *Server) GetScripts() ([]string, error)

GetScripts fetches and returns the list of script files. You can't do much with these.

func (*Server) GetSounds

func (s *Server) GetSounds() ([]string, error)

GetSounds fetches and returns the list of sound files. You can't do much with these.

func (*Server) Refresh

func (s *Server) Refresh() error

Refresh gets fresh camera and serverInfo data from SecuritySpy, run this after every action to keep the data pool up to date.

func (*Server) SetSchedulePreset

func (s *Server) SetSchedulePreset(presetID int) error

SetSchedulePreset invokes a schedule preset. This may/will affect all camera arm modes. Find preset IDs you can pass into this method at server.Info.SchedulePresets

type ServerInfo

type ServerInfo struct {
	Name             string    `xml:"name"`               // SecuritySpy
	Version          string    `xml:"version"`            // 4.2.10
	UUID             string    `xml:"uuid"`               // C03L1333F8J3AkXIZS1O
	EventStreamCount int64     `xml:"eventstreamcount"`   // 99270
	DDNSName         string    `xml:"ddns-name"`          // domain.name.dyn
	WanAddress       string    `xml:"wan-address"`        // domain.name
	ServerName       string    `xml:"server-name"`        // <usually empty>
	BonjourName      string    `xml:"bonjour-name"`       // <usually empty>
	IP1              string    `xml:"ip1"`                // 192.168.3.1
	IP2              string    `xml:"ip2"`                // 192.168.69.3
	HTTPEnabled      YesNoBool `xml:"http-enabled"`       // yes
	HTTPPort         int       `xml:"http-port"`          // 8000
	HTTPPortWan      int       `xml:"http-port-wan"`      // 8000
	HTTPSEnabled     YesNoBool `xml:"https-enabled"`      // no
	HTTPSPort        int       `xml:"https-port"`         // 8001
	HTTPSPortWan     int       `xml:"https-port-wan"`     // 8001
	CurrentTime      time.Time `xml:"current-local-time"` // 2019-02-10T03:08:12-08:00
	GmtOffset        Duration  `xml:"seconds-from-gmt"`   // -28800
	DateFormat       string    `xml:"date-format"`        // MM/DD/YYYY
	TimeFormat       string    `xml:"time-format"`        // 12, 24
	CPUUsage         int       `xml:"cpu-usage"`          // 37 (v5+)
	// These are all copied in/created by Refresh()
	Refreshed         time.Time
	ServerSchedules   map[int]string
	SchedulePresets   map[int]string
	ScheduleOverrides map[int]string
	// If there is a chance of calling Refresh() while reading these maps, lock them.
	sync.RWMutex
}

ServerInfo represents all the SecuritySpy server's information. This becomes available as server.Info.

type TriggerEvent

type TriggerEvent int

TriggerEvent represent the "Reason" a motion or action trigger occurred. v5+

type VidOps

type VidOps struct {
	Width   int
	Height  int
	FPS     int
	Quality int
}

VidOps are the frame options for a video that can be requested from SecuritySpy. This same data struct is used for capturing JPEG files, in that case FPS is discarded. Use this data type in the Camera methods that retrieve live videos/images.

type YesNoBool

type YesNoBool struct {
	Val bool
	Txt string
}

YesNoBool is used to capture strings into boolean format. If the string has a Val of: 1, true, yes, armed, active, or enabled then the boolean is true. Any other string Val and the boolean is false.

func (*YesNoBool) UnmarshalXML

func (bit *YesNoBool) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. Really it converts armed, yes, active, enabled, 1, true to true. Anything else is false. This isn't a method you should ever call directly; it is only used during data initialization.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL