mirror of
https://github.com/kerberos-io/onvif.git
synced 2025-10-30 02:31:54 +08:00
merge Device.go
This commit is contained in:
144
Device.go
144
Device.go
@@ -2,16 +2,17 @@ package goonvif
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"log"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/beevik/etree"
|
"github.com/beevik/etree"
|
||||||
"github.com/yakovlevdmv/gosoap"
|
"github.com/yakovlevdmv/gosoap"
|
||||||
"strconv"
|
"strconv"
|
||||||
"reflect"
|
"net/http"
|
||||||
|
"io/ioutil"
|
||||||
|
"github.com/yakovlevdmv/WS-Discovery"
|
||||||
"strings"
|
"strings"
|
||||||
"github.com/yakovlevdmv/goonvif/Device"
|
"github.com/yakovlevdmv/goonvif/Device"
|
||||||
"github.com/yakovlevdmv/WS-Discovery"
|
|
||||||
"errors"
|
"errors"
|
||||||
|
"reflect"
|
||||||
"github.com/yakovlevdmv/goonvif/networking"
|
"github.com/yakovlevdmv/goonvif/networking"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -81,54 +82,112 @@ type device struct {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAvailableDevicesAtSpecificEthernetInterface(interfaceName string) {
|
func (dev *device)GetServices() map[string]string {
|
||||||
|
return dev.endpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
func readResponse(resp *http.Response) string {
|
||||||
|
b, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAvailableDevicesAtSpecificEthernetInterface(interfaceName string) []device {
|
||||||
/*
|
/*
|
||||||
Call an WS-Discovery Probe Message to Discover NVT type Devices
|
Call an WS-Discovery Probe Message to Discover NVT type Devices
|
||||||
*/
|
*/
|
||||||
devices := WS_Discovery.SendProbe(interfaceName, nil, []string{"dn:"+NVT.String()}, map[string]string{"dn":"http://www.onvif.org/ver10/network/wsdl"})
|
devices := WS_Discovery.SendProbe(interfaceName, nil, []string{"dn:"+NVT.String()}, map[string]string{"dn":"http://www.onvif.org/ver10/network/wsdl"})
|
||||||
|
nvtDevices := make([]device, 0)
|
||||||
|
////fmt.Println(devices)
|
||||||
for _, j := range devices {
|
for _, j := range devices {
|
||||||
fmt.Println(j)
|
doc := etree.NewDocument()
|
||||||
|
if err := doc.ReadFromString(j); err != nil {
|
||||||
|
fmt.Errorf("%s", err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
////fmt.Println(j)
|
||||||
|
endpoints := doc.Root().FindElements("./Body/ProbeMatches/ProbeMatch/XAddrs")
|
||||||
|
for _, xaddr := range endpoints {
|
||||||
|
//fmt.Println(xaddr.Tag,strings.Split(strings.Split(xaddr.Text(), " ")[0], "/")[2] )
|
||||||
|
xaddr := strings.Split(strings.Split(xaddr.Text(), " ")[0], "/")[2]
|
||||||
|
fmt.Println(xaddr)
|
||||||
|
c := 0
|
||||||
|
for c = 0; c < len(nvtDevices); c++ {
|
||||||
|
if nvtDevices[c].xaddr == xaddr {
|
||||||
|
fmt.Println(nvtDevices[c].xaddr, "==", xaddr)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c < len(nvtDevices) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dev, err := NewDevice(strings.Split(xaddr, " ")[0])
|
||||||
|
//fmt.Println(dev)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error", xaddr)
|
||||||
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
////fmt.Println(dev)
|
||||||
|
nvtDevices = append(nvtDevices, *dev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////fmt.Println(j)
|
||||||
|
//nvtDevices[i] = NewDevice()
|
||||||
}
|
}
|
||||||
|
return nvtDevices
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dev *device) getSupportedServices() {
|
func (dev *device) getSupportedServices(resp *http.Response) {
|
||||||
resp, err := dev.CallMethod(Device.GetCapabilities{})
|
//resp, err := dev.CallMethod(Device.GetCapabilities{Category:"All"})
|
||||||
if err != nil {
|
//if err != nil {
|
||||||
log.Println(err.Error())
|
// log.Println(err.Error())
|
||||||
return
|
//return
|
||||||
} else {
|
//} else {
|
||||||
doc := etree.NewDocument()
|
doc := etree.NewDocument()
|
||||||
if err := doc.ReadFromString(resp); err != nil {
|
|
||||||
log.Println(err.Error())
|
data, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if err := doc.ReadFromBytes(data); err != nil {
|
||||||
|
//log.Println(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
services := doc.FindElements("./Envelope/Body/GetCapabilitiesResponse/Capabilities/*/XAddr")
|
services := doc.FindElements("./Envelope/Body/GetCapabilitiesResponse/Capabilities/*/XAddr")
|
||||||
for _, j := range services{
|
for _, j := range services{
|
||||||
fmt.Println(j.Text())
|
////fmt.Println(j.Text())
|
||||||
fmt.Println(j.Parent().Tag)
|
////fmt.Println(j.Parent().Tag)
|
||||||
dev.addEndpoint(j.Parent().Tag, j.Text())
|
dev.addEndpoint(j.Parent().Tag, j.Text())
|
||||||
}
|
}
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewDevice function construct a ONVIF Device entity
|
//NewDevice function construct a ONVIF Device entity
|
||||||
func NewDevice(xaddr string) *device {
|
func NewDevice(xaddr string) (*device, error) {
|
||||||
dev := new(device)
|
dev := new(device)
|
||||||
dev.xaddr = xaddr
|
dev.xaddr = xaddr
|
||||||
dev.endpoints = make(map[string]string)
|
dev.endpoints = make(map[string]string)
|
||||||
dev.addEndpoint("Device", "http://"+xaddr+"/onvif/device_service")
|
dev.addEndpoint("Device", "http://"+xaddr+"/onvif/device_service")
|
||||||
dev.getSupportedServices()
|
|
||||||
return dev
|
getCapabilities := Device.GetCapabilities{Category: "All"}
|
||||||
|
|
||||||
|
resp, err := dev.CallMethod(getCapabilities)
|
||||||
|
//fmt.Println(resp.Request.Host)
|
||||||
|
//fmt.Println(readResponse(resp))
|
||||||
|
if err != nil || resp.StatusCode != http.StatusOK {
|
||||||
|
//panic(errors.New("camera is not available at " + xaddr + " or it does not support ONVIF services"))
|
||||||
|
return nil, errors.New("camera is not available at " + xaddr + " or it does not support ONVIF services")
|
||||||
|
}
|
||||||
|
|
||||||
|
dev.getSupportedServices(resp)
|
||||||
|
return dev, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dev *device)addEndpoint(Key, Value string) {
|
func (dev *device)addEndpoint(Key, Value string) {
|
||||||
dev.endpoints[Key]=Value
|
dev.endpoints[Key]=Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDeviceEntity() *device {
|
|
||||||
return &device{}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Authenticate function authenticate client in the ONVIF Device.
|
//Authenticate function authenticate client in the ONVIF Device.
|
||||||
//Function takes <username> and <password> params.
|
//Function takes <username> and <password> params.
|
||||||
//You should use this function to allow authorized requests to the ONVIF Device
|
//You should use this function to allow authorized requests to the ONVIF Device
|
||||||
@@ -146,6 +205,7 @@ func buildMethodSOAP(msg string) (gosoap.SoapMessage, error) {
|
|||||||
doc := etree.NewDocument()
|
doc := etree.NewDocument()
|
||||||
if err := doc.ReadFromString(msg); err != nil {
|
if err := doc.ReadFromString(msg); err != nil {
|
||||||
//log.Println("Got error")
|
//log.Println("Got error")
|
||||||
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
element := doc.Root()
|
element := doc.Root()
|
||||||
@@ -162,7 +222,7 @@ func buildMethodSOAP(msg string) (gosoap.SoapMessage, error) {
|
|||||||
|
|
||||||
//CallMethod functions call an method, defined <method> struct.
|
//CallMethod functions call an method, defined <method> struct.
|
||||||
//You should use Authenticate method to call authorized requests.
|
//You should use Authenticate method to call authorized requests.
|
||||||
func (dev device) CallMethod(method interface{}) (string, error) {
|
func (dev device) CallMethod(method interface{}) (*http.Response, error) {
|
||||||
pkgPath := strings.Split(reflect.TypeOf(method).PkgPath(),"/")
|
pkgPath := strings.Split(reflect.TypeOf(method).PkgPath(),"/")
|
||||||
pkg := pkgPath[len(pkgPath)-1]
|
pkg := pkgPath[len(pkgPath)-1]
|
||||||
|
|
||||||
@@ -175,20 +235,30 @@ func (dev device) CallMethod(method interface{}) (string, error) {
|
|||||||
case "PTZ": endpoint = dev.endpoints["PTZ"]
|
case "PTZ": endpoint = dev.endpoints["PTZ"]
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(endpoint) == 0 {
|
|
||||||
return "", errors.New("requested service is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Get endpoint automatically
|
//TODO: Get endpoint automatically
|
||||||
if dev.login != "" && dev.password != "" {
|
if dev.login != "" && dev.password != "" {
|
||||||
return dev.CallAuthorizedMethod(endpoint, method)
|
/*resp, err := dev.сallAuthorizedMethod(endpoint, method)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, err*/
|
||||||
|
return dev.callAuthorizedMethod(endpoint, method)
|
||||||
} else {
|
} else {
|
||||||
return dev.CallNonAuthorizedMethod(endpoint, method)
|
/*resp, err := dev.сallAuthorizedMethod(endpoint, method)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
return resp, err*/
|
||||||
|
return dev.callNonAuthorizedMethod(endpoint, method)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//CallNonAuthorizedMethod functions call an method, defined <method> struct without authentication data
|
//CallNonAuthorizedMethod functions call an method, defined <method> struct without authentication data
|
||||||
func (dev device) CallNonAuthorizedMethod(endpoint string, method interface{}) (string, error) {
|
func (dev device) callNonAuthorizedMethod(endpoint string, method interface{}) (*http.Response, error) {
|
||||||
//TODO: Get endpoint automatically
|
//TODO: Get endpoint automatically
|
||||||
/*
|
/*
|
||||||
Converting <method> struct to xml string representation
|
Converting <method> struct to xml string representation
|
||||||
@@ -196,7 +266,7 @@ func (dev device) CallNonAuthorizedMethod(endpoint string, method interface{}) (
|
|||||||
output, err := xml.MarshalIndent(method, " ", " ")
|
output, err := xml.MarshalIndent(method, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//log.Printf("error: %v\n", err.Error())
|
//log.Printf("error: %v\n", err.Error())
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -205,7 +275,7 @@ func (dev device) CallNonAuthorizedMethod(endpoint string, method interface{}) (
|
|||||||
soap, err := buildMethodSOAP(string(output))
|
soap, err := buildMethodSOAP(string(output))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//log.Printf("error: %v\n", err)
|
//log.Printf("error: %v\n", err)
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
soap.AddRootNamespaces(Xlmns)
|
soap.AddRootNamespaces(Xlmns)
|
||||||
@@ -217,14 +287,14 @@ func (dev device) CallNonAuthorizedMethod(endpoint string, method interface{}) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
//CallMethod functions call an method, defined <method> struct with authentication data
|
//CallMethod functions call an method, defined <method> struct with authentication data
|
||||||
func (dev device) CallAuthorizedMethod(endpoint string, method interface{}) (string, error) {
|
func (dev device) callAuthorizedMethod(endpoint string, method interface{}) (*http.Response, error) {
|
||||||
/*
|
/*
|
||||||
Converting <method> struct to xml string representation
|
Converting <method> struct to xml string representation
|
||||||
*/
|
*/
|
||||||
output, err := xml.MarshalIndent(method, " ", " ")
|
output, err := xml.MarshalIndent(method, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//log.Printf("error: %v\n", err.Error())
|
//log.Printf("error: %v\n", err.Error())
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -233,7 +303,7 @@ func (dev device) CallAuthorizedMethod(endpoint string, method interface{}) (str
|
|||||||
soap, err := buildMethodSOAP(string(output))
|
soap, err := buildMethodSOAP(string(output))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//log.Printf("error: %v\n", err.Error())
|
//log.Printf("error: %v\n", err.Error())
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -252,7 +322,7 @@ func (dev device) CallAuthorizedMethod(endpoint string, method interface{}) (str
|
|||||||
soapReq, err := xml.MarshalIndent(auth, "", " ")
|
soapReq, err := xml.MarshalIndent(auth, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//log.Printf("error: %v\n", err.Error())
|
//log.Printf("error: %v\n", err.Error())
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
172
README.md
172
README.md
@@ -1 +1,171 @@
|
|||||||
# goonvif
|
# Goonvif
|
||||||
|
Библиотека **Goonvif** создана для упрощения взаимодействия с ONVIF устройствами. На данный момент в библиотеке реализована поддержка NVT(Network Video Transmitter) устройств, а именно следующих ONVIF сервисов:
|
||||||
|
- Core или DeviceManagement
|
||||||
|
- Media
|
||||||
|
- Imaging
|
||||||
|
- PTZ
|
||||||
|
- Analytics
|
||||||
|
# Dependencies
|
||||||
|
[etree](https://github.com/beevik/etree)
|
||||||
|
# Установка
|
||||||
|
Для установки библиотеки необходимо воспользоваться утилитой go get:
|
||||||
|
```
|
||||||
|
go get github.com/yakovlevdmv/goonvif
|
||||||
|
```
|
||||||
|
|
||||||
|
# Начало работы
|
||||||
|
Чтобы начать работать с камерой, необходимо создать объект `device`.
|
||||||
|
Для этого необходимо воспользоваться функцией `func NewDevice(xaddr string) (*device, error)`,
|
||||||
|
которая принимает IP адрес ONVIF устройства и возвращает указатель на созданный объект либо ошибку.
|
||||||
|
Если камера недоступна, указан неверный адрес для ONVIF сервиса камеры (возможно находится по другому порту) или же камера вообще не поддерживает ONVIF
|
||||||
|
функция вернет error не являющимся `nil`, а в качестве указателя на объект устройства вернет `nil`.
|
||||||
|
### Пример подключения к камере
|
||||||
|
Пусть камера в сети находится по адресу 192.168.13.42, а ее ONVIF сервисы расположены на порте 1234. Тогда,
|
||||||
|
```
|
||||||
|
dev, err := goonvif.NewDevice("192.168.13.42:1234")
|
||||||
|
```
|
||||||
|
сработает успешно, а
|
||||||
|
```
|
||||||
|
dev, err := goonvif.NewDevice("192.168.13.42:80")
|
||||||
|
```
|
||||||
|
вернет нулевой объект камеры и ошибку:
|
||||||
|
> camera is not available at 192.168.13.42:80 or it does not support ONVIF services
|
||||||
|
|
||||||
|
Модернизируем код, добавив обработку ошибки, и получим:
|
||||||
|
```
|
||||||
|
dev, err := goonvif.NewDevice("192.168.13.42:80")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
///Работа с камерой
|
||||||
|
```
|
||||||
|
### Поддерживаемые ONVIF сервисы
|
||||||
|
Теперь, когда камера доступна, можно приступать к работе с ней. Однако стандарт ONVIF имеет множество сервисов, а также точку доступа (endpoint) которая не определена стандартом (кроме DeviceManagment: http://onvif_host/onvif/device_service).
|
||||||
|
Поэтому дальше встает вопрос о поддерживаемых камерой сервисах и определении их endpoint'ов.
|
||||||
|
Для получения поддерживаемых камерой сервисов необходимо вызвать метод GetCapabilities сервиса DeviceManagement.
|
||||||
|
Однако эта библиотека автоматизирует данный процесс, поэтому при создании объекта device при помощи `func NewDevice(xaddr string) (*device, error)`
|
||||||
|
библиотека одновременно обрабатывает поддерживаемые камерой сервисы. Таким образом есть два способа получения поддерживаемых устройством сервисов:
|
||||||
|
1. Вызвать метод GetCapabilities сервиса DeviceManagement(как это сделать будет рассмотрено дальше) и обработать ответ.
|
||||||
|
2. Довериться библиотеке и вызвать функцию `func (dev *device)GetServices() map[string]string`, которая вернет map[string]string, ключом которой является название сервиса, а значением - endpoint данного сервиса
|
||||||
|
### Работа с камерой
|
||||||
|
Для работы с различными сервисами камерами необходимо отправить корректный SOAP запрос, в теле которого находится вызываемый метод и принимаемые им функции.
|
||||||
|
**Goonvif** берет на себя работу по созданию корректного SOAP запроса и его отправке. В **Goonvif** определены структуры, для каждой функции каждого (поддерживаемого данной бибилиотекой) сервиса ONVIF:
|
||||||
|
- [DeviceManagement Service](Device/types.go)
|
||||||
|
|
||||||
|
- [Media Service](Media/types.go)
|
||||||
|
|
||||||
|
- [Imaging Service](Imaging/types.go)
|
||||||
|
|
||||||
|
- [PTZ Service](PTZ/types.go)
|
||||||
|
|
||||||
|
- [Analytics Service](Analytics/types.go)
|
||||||
|
|
||||||
|
[Список всех сервисов стандарта (и документация к ним)](https://www.onvif.org/profiles/specifications/)
|
||||||
|
|
||||||
|
Рассмторим, как организована отправка запросов в **Goonvif** на нескольких примерах.
|
||||||
|
1. Метод GetCapabilities сервиса DeviceManagement
|
||||||
|
|
||||||
|
Все необходимые типы данных определены в пакете [Device](Device/types.go).
|
||||||
|
В файле (https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl) можно увидеть:
|
||||||
|

|
||||||
|
|
||||||
|
Таким образом, Функция GetCapabilities принимает в качестве аргумента перечисление:
|
||||||
|
`enum { 'All', 'Analytics', 'Device', 'Events', 'Imaging', 'Media', 'PTZ' }`
|
||||||
|
Чтобы вызвать данный метод создадим объект `Device.GetCapabilities`:
|
||||||
|
```
|
||||||
|
capabilities := Device.GetCapabilities{Category:"All"}
|
||||||
|
```
|
||||||
|
Для вызова данной функции воспользуемся методом `func (dev device) CallMethod(method interface{}) (string, error)`:
|
||||||
|
```
|
||||||
|
resp, err := dev.CallMethod(capab)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
} else {
|
||||||
|
fmt.Println(resp)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
2. Создание пользователя методом CreateUsers сервиса DeviceManagement
|
||||||
|
|
||||||
|
Все необходимые типы данных определены в пакете [Device](Device/types.go).
|
||||||
|
В файле (https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl) можно увидеть структуру запроса:
|
||||||
|

|
||||||
|
|
||||||
|
Создадим объект `Device.CreateUsers`:
|
||||||
|
```
|
||||||
|
createUsers := Device.CreateUsers{User: onvif.User{Username:"korolev", Password:"qwerty", UserLevel:"User"}}
|
||||||
|
resp, err := dev.CallMethod(createUsers)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
} else {
|
||||||
|
fmt.Println(resp)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
В данном примере можно наблюдать использование пакета onvif, в котором определено большинство типов, используемых в поддерживаемых библиотекой сервисах, поэтому при создании структур запросов необходимо это учитывать.
|
||||||
|
|
||||||
|
##### ВАЖНО
|
||||||
|
Некоторые камеры работают специфично. Это означает, что в зависимости от модели камеры можно не получить ошибки при неправильном запросе. Поэтому советую проверять, точно ли выполнилась операция. Например, для метода CreateUsers надо вывести список всех пользователей и проверить добавился ли пользователь.
|
||||||
|
|
||||||
|
3. Метод ContinuousMove сервиса PTZ
|
||||||
|
|
||||||
|
Все необходимые типы данных определены в пакете [PTZ](PTZ/types.go).
|
||||||
|
В файле (https://www.onvif.org/ver20/ptz/wsdl/ptz.wsdl) можно увидеть структуру запроса:
|
||||||
|

|
||||||
|
|
||||||
|
Так как данная команда определяется сервисом PTZ, необходимый тип находится в пакете [PTZ](PTZ/types.go).
|
||||||
|
Из файла [PTZ](PTZ/types.go) можно заметить, что :
|
||||||
|
> ProfileToken [ReferenceToken]
|
||||||
|
> A reference to the **MediaProfile** that indicate what should be stopped.
|
||||||
|
|
||||||
|
Таким образом, для того, чтобы начать работать с PTZ сервисом для начала необходимо получить **ProfileToken** сервиса **Media**. Как это сделать смотрите в примере 4. Сейчас же предположим, что нам известен нужный токен. Пусть ProfileToken = "Profile_1".
|
||||||
|
|
||||||
|
Создадим объект `PTZ.ContinuousMove`:
|
||||||
|
```
|
||||||
|
move := PTZ.ContinuousMove{
|
||||||
|
ProfileToken:"Profile_1",
|
||||||
|
Velocity:onvif.PTZSpeed{
|
||||||
|
PanTilt:onvif.Vector2D{
|
||||||
|
X: 1,
|
||||||
|
Y: 1,
|
||||||
|
},
|
||||||
|
Zoom:onvif.Vector1D{X:0.5},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Заметим**, что объекты Velocity, PanTilt и Zoom определены в пакете onvif. Такое применение свойственно для большинства встроенных в структуру типов.
|
||||||
|
|
||||||
|
Для вызова данной функции воспользуемся методом `func (dev device) CallMethod(method interface{}) (string, error)`:
|
||||||
|
```
|
||||||
|
resp, err := dev.CallMethod(capab)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
} else {
|
||||||
|
fmt.Println(resp)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Получение списков Media профилей
|
||||||
|
|
||||||
|
Все необходимые типы данных определены в пакете [Media](Media/types.go).
|
||||||
|
В файле (https://www.onvif.org/ver10/media/wsdl/media.wsdl) можно увидеть структуру запроса:
|
||||||
|

|
||||||
|
|
||||||
|
Вот пример создания и вызова запроса GetProfiles
|
||||||
|
```
|
||||||
|
resp, err := dev.CallMethod(Media.GetProfiles{})
|
||||||
|
if err != nil {
|
||||||
|
panic (err)
|
||||||
|
} else {
|
||||||
|
fmt.Println(readResponse(resp))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Важно** Обработка response'ов камеры пока не реализована, поэтому данная задача ложится на **Ваши** плечи. Вы можете упростить обработку response'ов при помощи библиотеки [etree](https://github.com/beevik/etree) либо же воспользоваться сервисом (http://www.webtoolkitonline.com/xml-formatter.html)
|
||||||
|
|
||||||
|
**Важно** Многие запросы требуют авторизованного доступа и для того, чтобы добавить аторизацию к конкретной камере, необходимо воспользоваться функцией `func (dev *device) Authenticate(username, password string)`. После применения данной функции все отправляемые камерой запросы будут авторизованными.
|
||||||
|
```
|
||||||
|
device := onvif.NewDevice("192.168.13.42:1234")
|
||||||
|
device.Authenticate("username", "password")
|
||||||
|
```
|
||||||
|
|||||||
BIN
img/exmp_ContinuousMove.png
Normal file
BIN
img/exmp_ContinuousMove.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
img/exmp_CreateUsers.png
Normal file
BIN
img/exmp_CreateUsers.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
BIN
img/exmp_GetCapabilities.png
Normal file
BIN
img/exmp_GetCapabilities.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
img/exmp_GetProfiles.png
Normal file
BIN
img/exmp_GetProfiles.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -3,20 +3,26 @@ package networking
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func SendSoap(endpoint, message string) (string, error) {
|
func SendSoap(endpoint, message string) (*http.Response, error) {
|
||||||
httpClient := new(http.Client)
|
httpClient := new(http.Client)
|
||||||
|
|
||||||
resp, err := httpClient.Post(endpoint, "application/soap+xml; charset=utf-8", bytes.NewBufferString(message))
|
resp, err := httpClient.Post(endpoint, "application/soap+xml; charset=utf-8", bytes.NewBufferString(message))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return resp, err
|
||||||
}
|
|
||||||
b, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return string(b),nil
|
/*if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusBadRequest {
|
||||||
|
return "", errors.New("error: got HTTP response status " + strconv.Itoa(resp.StatusCode))
|
||||||
|
}*/
|
||||||
|
//b, err := ioutil.ReadAll(resp.Body)
|
||||||
|
//if err != nil {
|
||||||
|
// return resp, err
|
||||||
|
//}
|
||||||
|
//fmt.Println(endpoint)
|
||||||
|
//fmt.Println(string(b))
|
||||||
|
//log.Println(resp.StatusCode)
|
||||||
|
|
||||||
|
return resp,nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user