diff --git a/TODO.md b/TODO.md
index b5f6396..7634ab2 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,15 +1,8 @@
- [X] Camera discovery
-- [ ] OnvifDevice
- - [ ] getInformation
- - [ ] getCurrentProfile
- - [ ] getProfileList
- - [ ] changeProfile
- - [ ] getUdpStreamUrl
- - [ ] fetchSnapshot
- - [ ] ptzMove
- - [ ] ptzStop
- [ ] OnvifServiceDevice
- - [ ] getCapabilities
+ - [X] getDeviceInformation
+ - [X] getSystemDateAndTime
+ - [X] getCapabilities
- [ ] getWsdlUrl
- [ ] getDiscoveryMode
- [ ] getScopes
@@ -25,8 +18,6 @@
- [ ] setNetworkProtocols
- [ ] getNetworkDefaultGateway
- [ ] setNetworkDefaultGateway
- - [ ] getDeviceInformation
- - [X] getSystemDateAndTime
- [ ] reboot
- [ ] getUsers
- [ ] createUsers
diff --git a/device.go b/device.go
index 45a7031..ea43c5c 100644
--- a/device.go
+++ b/device.go
@@ -2,6 +2,7 @@ package onvif
import (
"encoding/json"
+ "strings"
)
var deviceXMLNs = []string{
@@ -11,9 +12,6 @@ var deviceXMLNs = []string{
// GetDeviceInformation fetch information of ONVIF camera
func (device Device) GetDeviceInformation() (DeviceInformation, error) {
- // Create initial result
- result := DeviceInformation{}
-
// Create SOAP
soap := SOAP{
Body: "",
@@ -23,17 +21,18 @@ func (device Device) GetDeviceInformation() (DeviceInformation, error) {
// Send SOAP request
response, err := soap.SendRequest(device.XAddr)
if err != nil {
- return result, err
+ return DeviceInformation{}, err
}
// Parse response to interface
deviceInfo, err := response.ValueForPath("Envelope.Body.GetDeviceInformationResponse")
if err != nil {
- return result, err
+ return DeviceInformation{}, err
}
// Parse interface to struct
- err = device.interfaceToStruct(&deviceInfo, &result)
+ result := DeviceInformation{}
+ err = interfaceToStruct(&deviceInfo, &result)
if err != nil {
return result, err
}
@@ -45,7 +44,7 @@ func (device Device) GetDeviceInformation() (DeviceInformation, error) {
func (device Device) GetSystemDateAndTime() (string, error) {
// Create SOAP
soap := SOAP{
- Body: "",
+ Body: "",
XMLNs: deviceXMLNs,
}
@@ -60,7 +59,93 @@ func (device Device) GetSystemDateAndTime() (string, error) {
return dateTime, nil
}
-func (device Device) interfaceToStruct(src, dst interface{}) error {
+// GetCapabilities fetch info of ONVIF camera's capabilities
+func (device Device) GetCapabilities() (DeviceCapabilities, error) {
+ // Create SOAP
+ soap := SOAP{
+ XMLNs: deviceXMLNs,
+ Body: ``,
+ }
+
+ // Send SOAP request
+ response, err := soap.SendRequest(device.XAddr)
+ if err != nil {
+ return DeviceCapabilities{}, err
+ }
+
+ // Get network capabilities
+ envelopeBodyPath := "Envelope.Body.GetCapabilitiesResponse.Capabilities"
+ ifaceNetCap, err := response.ValueForPath(envelopeBodyPath + ".Device.Network")
+ if err != nil {
+ return DeviceCapabilities{}, err
+ }
+
+ netCap := NetworkCapabilities{}
+ mapNetCap, ok := ifaceNetCap.(map[string]interface{})
+ if ok {
+ netCap.DynDNS = interfaceToBool(mapNetCap["DynDNS"])
+ netCap.IPFilter = interfaceToBool(mapNetCap["IPFilter"])
+ netCap.IPVersion6 = interfaceToBool(mapNetCap["IPVersion6"])
+ netCap.ZeroConfig = interfaceToBool(mapNetCap["ZeroConfiguration"])
+ netCap.Extension = make(map[string]bool)
+
+ if mapNetExtension, ok := mapNetCap["Extension"].(map[string]interface{}); ok {
+ for key, value := range mapNetExtension {
+ netCap.Extension[key] = interfaceToBool(value)
+ }
+ }
+ }
+
+ // Get events capabilities
+ ifaceEventsCap, err := response.ValueForPath(envelopeBodyPath + ".Events")
+ if err != nil {
+ return DeviceCapabilities{}, err
+ }
+
+ eventsCap := make(map[string]bool)
+ if mapEventsCap, ok := ifaceEventsCap.(map[string]interface{}); ok {
+ for key, value := range mapEventsCap {
+ if strings.ToLower(key) == "xaddr" {
+ continue
+ }
+
+ key = strings.Replace(key, "WS", "", 1)
+ eventsCap[key] = interfaceToBool(value)
+ }
+ }
+
+ // Get events capabilities
+ ifaceStreamingCap, err := response.ValueForPath(envelopeBodyPath + ".Media.StreamingCapabilities")
+ if err != nil {
+ return DeviceCapabilities{}, err
+ }
+
+ streamingCap := make(map[string]bool)
+ if mapStreamingCap, ok := ifaceStreamingCap.(map[string]interface{}); ok {
+ for key, value := range mapStreamingCap {
+ key = strings.Replace(key, "_", " ", -1)
+ streamingCap[key] = interfaceToBool(value)
+ }
+ }
+
+ // Get PTZ capabilities
+ ptzCap := true
+ if _, err = response.ValueForPath(envelopeBodyPath + ".PTZ"); err != nil {
+ ptzCap = false
+ }
+
+ // Create final result
+ deviceCapabilities := DeviceCapabilities{
+ Network: netCap,
+ Events: eventsCap,
+ Streaming: streamingCap,
+ PTZ: ptzCap,
+ }
+
+ return deviceCapabilities, nil
+}
+
+func interfaceToStruct(src, dst interface{}) error {
bt, err := json.Marshal(&src)
if err != nil {
return err
@@ -73,3 +158,13 @@ func (device Device) interfaceToStruct(src, dst interface{}) error {
return nil
}
+
+func interfaceToString(src interface{}) string {
+ str, _ := src.(string)
+ return str
+}
+
+func interfaceToBool(src interface{}) bool {
+ strBool := interfaceToString(src)
+ return strings.ToLower(strBool) == "true"
+}
diff --git a/model.go b/model.go
index dc88f0d..fa5b4a1 100644
--- a/model.go
+++ b/model.go
@@ -17,3 +17,20 @@ type DeviceInformation struct {
Model string
SerialNumber string
}
+
+// NetworkCapabilities contains networking capabilities of ONVIF camera
+type NetworkCapabilities struct {
+ DynDNS bool
+ Extension map[string]bool
+ IPFilter bool
+ IPVersion6 bool
+ ZeroConfig bool
+}
+
+// DeviceCapabilities contains capabilities of an ONVIF camera
+type DeviceCapabilities struct {
+ Network NetworkCapabilities
+ Events map[string]bool
+ Streaming map[string]bool
+ PTZ bool
+}