From 1cb92d8d2032309147ddd4eb06e120809279099f Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 17:31:48 +0300 Subject: [PATCH 01/16] Documenting with Readme.md --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f3e0a1..e8cba98 100644 --- a/README.md +++ b/README.md @@ -1 +1,7 @@ -# goonvif +# Goonvif +Библиотека Goonvif создана для упрощения взаимодействия с ONVIF устройствами. На данный момент в библиотеке реализована поддержка NVT(Network Video Transmitter) устройств, а именно следующих ONVIF сервисов: +- Core или DeviceManagement +- Media +- Imaging +- PTZ +- Video Analytics \ No newline at end of file From 1aee7f15e3ed0fc3d4bb8e6465876ea8d2d8eb3d Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 17:49:01 +0300 Subject: [PATCH 02/16] The scopes of device functions are edited --- Device.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Device.go b/Device.go index 118bb27..284b582 100644 --- a/Device.go +++ b/Device.go @@ -80,14 +80,17 @@ type device struct { } -func GetAvailableDevicesAtSpecificEthernetInterface(interfaceName string) { +func GetAvailableDevicesAtSpecificEthernetInterface(interfaceName string) []device { /* 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"}) + //nvtDevices := make([]device, len(devices)) for _, j := range devices { fmt.Println(j) + //nvtDevices[i] = NewDevice() } + return nil } func (dev *device) getSupportedServices() { @@ -172,14 +175,14 @@ func (dev device) CallMethod(method interface{}) (string, error) { //TODO: Get endpoint automatically if dev.login != "" && dev.password != "" { - return dev.CallAuthorizedMethod(endpoint, method) + return dev.сallAuthorizedMethod(endpoint, method) } else { - return dev.CallNonAuthorizedMethod(endpoint, method) + return dev.сallNonAuthorizedMethod(endpoint, method) } } //CallNonAuthorizedMethod functions call an method, defined struct without authentication data -func (dev device) CallNonAuthorizedMethod(endpoint string, method interface{}) (string, error) { +func (dev device) сallNonAuthorizedMethod(endpoint string, method interface{}) (string, error) { //TODO: Get endpoint automatically /* Converting struct to xml string representation @@ -208,7 +211,7 @@ func (dev device) CallNonAuthorizedMethod(endpoint string, method interface{}) ( } //CallMethod functions call an method, defined struct with authentication data -func (dev device) CallAuthorizedMethod(endpoint string, method interface{}) (string, error) { +func (dev device) сallAuthorizedMethod(endpoint string, method interface{}) (string, error) { /* Converting struct to xml string representation */ From 4966762ce017e95026e20deb3b51ce403680fe84 Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 18:22:03 +0300 Subject: [PATCH 03/16] README editted, reutrn error if got 404 and return error in device constructor --- Device.go | 39 +++++++++++++++++++++++++++++++-------- README.md | 23 +++++++++++++++++++++-- networking/networking.go | 7 +++++++ 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/Device.go b/Device.go index 284b582..ff8caea 100644 --- a/Device.go +++ b/Device.go @@ -2,16 +2,16 @@ package goonvif import ( "encoding/xml" - "log" "fmt" "github.com/beevik/etree" "github.com/yakovlevdmv/gosoap" "strconv" "github.com/yakovlevdmv/WS-Discovery" - "github.com/yakovlevdmv/goonvif/Networking" + "github.com/yakovlevdmv/goonvif/networking" "reflect" "strings" "github.com/yakovlevdmv/goonvif/Device" + "errors" ) var xlmns = map[string]string { @@ -96,31 +96,39 @@ func GetAvailableDevicesAtSpecificEthernetInterface(interfaceName string) []devi func (dev *device) getSupportedServices() { resp, err := dev.CallMethod(Device.GetCapabilities{}) if err != nil { - log.Println(err.Error()) + //log.Println(err.Error()) return } else { doc := etree.NewDocument() if err := doc.ReadFromString(resp); err != nil { - log.Println(err.Error()) + //log.Println(err.Error()) return } services := doc.FindElements("./Envelope/Body/GetCapabilitiesResponse/Capabilities/*/XAddr") for _, j := range services{ - fmt.Println(j.Text()) - fmt.Println(j.Parent().Tag) + //fmt.Println(j.Text()) + //fmt.Println(j.Parent().Tag) dev.addEndpoint(j.Parent().Tag, j.Text()) } } } //NewDevice function construct a ONVIF Device entity -func NewDevice(xaddr string) *device { +func NewDevice(xaddr string) (*device, error) { dev := new(device) dev.xaddr = xaddr dev.endpoints = make(map[string]string) dev.addEndpoint("Device", "http://"+xaddr+"/onvif/device_service") + + systemDateTime := Device.GetDeviceInformation{} + _, err := dev.CallMethod(systemDateTime) + if err != nil { + panic(errors.New("camera is not available at " + xaddr + " or it does not support ONVIF services")) + return nil, err + } + dev.getSupportedServices() - return dev + return dev, nil } func (dev *device)addEndpoint(Key, Value string) { @@ -144,6 +152,7 @@ func buildMethodSOAP(msg string) (gosoap.SoapMessage, error) { doc := etree.NewDocument() if err := doc.ReadFromString(msg); err != nil { //log.Println("Got error") + return "", err } element := doc.Root() @@ -175,9 +184,23 @@ func (dev device) CallMethod(method interface{}) (string, error) { //TODO: Get endpoint automatically if dev.login != "" && dev.password != "" { + /*resp, err := dev.сallAuthorizedMethod(endpoint, method) + if err != nil { + panic(err) + return resp, err + } + + return resp, err*/ return dev.сallAuthorizedMethod(endpoint, method) } else { + /*resp, err := dev.сallAuthorizedMethod(endpoint, method) + if err != nil { + panic(err) + return resp, err + } + return resp, err*/ return dev.сallNonAuthorizedMethod(endpoint, method) + } } diff --git a/README.md b/README.md index e8cba98..b2fed44 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,26 @@ # Goonvif -Библиотека Goonvif создана для упрощения взаимодействия с ONVIF устройствами. На данный момент в библиотеке реализована поддержка NVT(Network Video Transmitter) устройств, а именно следующих ONVIF сервисов: +Библиотека **Goonvif** создана для упрощения взаимодействия с ONVIF устройствами. На данный момент в библиотеке реализована поддержка NVT(Network Video Transmitter) устройств, а именно следующих ONVIF сервисов: - Core или DeviceManagement - Media - Imaging - PTZ -- Video Analytics \ No newline at end of file +- Video Analytics +# Dependencies + +# Установка +Для установки библиотеки необходимо воспользоваться утилитой go get: +`go get github.com/yakovlevdmv/goonvif` + +# Начало работы +Чтобы начать работать с камерой, необходимо создать объект `device`. +Для этого необходимо воспользоваться функцией `func NewDevice(xaddr string) (*device, error)`, +которая принимает адрес ONVIF устройства и возвращает указатель на созданный объект. +Если камера не доступна, указан неверный адрес для ONVIF сервиса камеры (возможно находся по другому порту) или же камера вообще не поддерживает ONVIF +функция вызовет ошибку. +### Пример подключения к камере +Пусть камера в сети находится по адресу 192.168.13.42, а ее ONVIF сервисы расположены на 1234 порту. Тогда, +`dev := goonvif.NewDevice("192.168.13.42:1234")` +сработает успешно, а +`dev := goonvif.NewDevice("192.168.13.42:80")` +вызовет ошибку: +> camera is not available or it does not support ONVIF services diff --git a/networking/networking.go b/networking/networking.go index bd1a69d..928a610 100644 --- a/networking/networking.go +++ b/networking/networking.go @@ -4,6 +4,8 @@ import ( "net/http" "bytes" "io/ioutil" + "github.com/pkg/errors" + "strconv" ) func SendSoap(endpoint, message string) (string, error) { @@ -13,10 +15,15 @@ func SendSoap(endpoint, message string) (string, error) { if err != nil { return "", err } + if resp.StatusCode != http.StatusOK { + return "", errors.New("error: got HTTP response status " + strconv.Itoa(resp.StatusCode)) + } b, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } + //log.Println(resp.StatusCode) + return string(b),nil } From 86573fc414fb9a8ea3a3e8fddd7f94875222653d Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 18:54:57 +0300 Subject: [PATCH 04/16] Some improvements added. README edited --- Device.go | 20 ++++++++++---------- README.md | 36 ++++++++++++++++++++++++++++-------- networking/networking.go | 2 +- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/Device.go b/Device.go index ff8caea..9333289 100644 --- a/Device.go +++ b/Device.go @@ -80,6 +80,10 @@ type device struct { } +func (dev *device)GetServices() map[string]string { + return dev.endpoints +} + func GetAvailableDevicesAtSpecificEthernetInterface(interfaceName string) []device { /* Call an WS-Discovery Probe Message to Discover NVT type Devices @@ -123,8 +127,8 @@ func NewDevice(xaddr string) (*device, error) { systemDateTime := Device.GetDeviceInformation{} _, err := dev.CallMethod(systemDateTime) if err != nil { - panic(errors.New("camera is not available at " + xaddr + " or it does not support ONVIF services")) - return nil, err + //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() @@ -135,10 +139,6 @@ func (dev *device)addEndpoint(Key, Value string) { dev.endpoints[Key]=Value } -func newDeviceEntity() *device { - return &device{} -} - //Authenticate function authenticate client in the ONVIF Device. //Function takes and params. //You should use this function to allow authorized requests to the ONVIF Device @@ -191,7 +191,7 @@ func (dev device) CallMethod(method interface{}) (string, error) { } return resp, err*/ - return dev.сallAuthorizedMethod(endpoint, method) + return dev.callAuthorizedMethod(endpoint, method) } else { /*resp, err := dev.сallAuthorizedMethod(endpoint, method) if err != nil { @@ -199,13 +199,13 @@ func (dev device) CallMethod(method interface{}) (string, error) { return resp, err } return resp, err*/ - return dev.сallNonAuthorizedMethod(endpoint, method) + return dev.callNonAuthorizedMethod(endpoint, method) } } //CallNonAuthorizedMethod functions call an method, defined struct without authentication data -func (dev device) сallNonAuthorizedMethod(endpoint string, method interface{}) (string, error) { +func (dev device) callNonAuthorizedMethod(endpoint string, method interface{}) (string, error) { //TODO: Get endpoint automatically /* Converting struct to xml string representation @@ -234,7 +234,7 @@ func (dev device) сallNonAuthorizedMethod(endpoint string, method interface{}) } //CallMethod functions call an method, defined struct with authentication data -func (dev device) сallAuthorizedMethod(endpoint string, method interface{}) (string, error) { +func (dev device) callAuthorizedMethod(endpoint string, method interface{}) (string, error) { /* Converting struct to xml string representation */ diff --git a/README.md b/README.md index b2fed44..df51d4a 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,41 @@ - PTZ - Video Analytics # Dependencies - +[etree](https://github.com/beevik/etree) # Установка Для установки библиотеки необходимо воспользоваться утилитой go get: -`go get github.com/yakovlevdmv/goonvif` +``` +go get github.com/yakovlevdmv/goonvif +``` # Начало работы Чтобы начать работать с камерой, необходимо создать объект `device`. Для этого необходимо воспользоваться функцией `func NewDevice(xaddr string) (*device, error)`, -которая принимает адрес ONVIF устройства и возвращает указатель на созданный объект. +которая принимает адрес ONVIF устройства и возвращает указатель на созданный объект либо ошибку. Если камера не доступна, указан неверный адрес для ONVIF сервиса камеры (возможно находся по другому порту) или же камера вообще не поддерживает ONVIF -функция вызовет ошибку. +функция вернет не `nil` error, а в качестве указателя на объект вернет `nil`. ### Пример подключения к камере Пусть камера в сети находится по адресу 192.168.13.42, а ее ONVIF сервисы расположены на 1234 порту. Тогда, -`dev := goonvif.NewDevice("192.168.13.42:1234")` +```dev, err := goonvif.NewDevice("192.168.13.42:1234")``` сработает успешно, а -`dev := goonvif.NewDevice("192.168.13.42:80")` -вызовет ошибку: -> camera is not available or it does not support ONVIF services +```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 данного сервиса \ No newline at end of file diff --git a/networking/networking.go b/networking/networking.go index 928a610..b4dfd84 100644 --- a/networking/networking.go +++ b/networking/networking.go @@ -4,8 +4,8 @@ import ( "net/http" "bytes" "io/ioutil" - "github.com/pkg/errors" "strconv" + "errors" ) func SendSoap(endpoint, message string) (string, error) { From 7b29927a99e2526425d6a933e277516421b39c60 Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 18:57:05 +0300 Subject: [PATCH 05/16] README bugs fixed --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index df51d4a..c836b2e 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,16 @@ go get github.com/yakovlevdmv/goonvif функция вернет не `nil` error, а в качестве указателя на объект вернет `nil`. ### Пример подключения к камере Пусть камера в сети находится по адресу 192.168.13.42, а ее ONVIF сервисы расположены на 1234 порту. Тогда, -```dev, err := goonvif.NewDevice("192.168.13.42:1234")``` +``` +dev, err := goonvif.NewDevice("192.168.13.42:1234") +``` сработает успешно, а -```dev, err := goonvif.NewDevice("192.168.13.42:80")``` +``` +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") From bb10a669f79328d1fdc317954d4497c02390519f Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 19:31:25 +0300 Subject: [PATCH 06/16] README.md modified --- README.md | 47 ++++++++++++++++++++++++++++------- img/exmp_GetCapabilities.png | Bin 0 -> 19566 bytes 2 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 img/exmp_GetCapabilities.png diff --git a/README.md b/README.md index c836b2e..ce70b44 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ - Media - Imaging - PTZ -- Video Analytics +- Analytics # Dependencies [etree](https://github.com/beevik/etree) # Установка @@ -31,15 +31,14 @@ 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) - } - - ///Работа с камерой +dev, err := goonvif.NewDevice("192.168.13.42:80") +if err != nil { + panic(err) +} +///Работа с камерой ``` ### Поддерживаемые ONVIF сервисы Теперь, когда камера доступна, можно приступать к работе с ней. Однако стандарт ONVIF имеет множество сервисов, точка доступа (endpoint) к которым не закреплена стандартом (кроме DeviceManagment: http://onvif_host/onvif/device_service). @@ -48,4 +47,34 @@ dev, err := goonvif.NewDevice("192.168.13.42:80") Однако данная библиотека автоматизирует данный процесс, поэтому при создании объекта device при помощи `func NewDevice(xaddr string) (*device, error)` библиотека одновременно обрабатывает поддерживаемые камерой сервисы. Таким образом чтобы получить поддерживаемые устройством сервисы, можно воспользоваться двумя путями: 1. Вызвать метод GetCapabilities сервиса DeviceManagement(как это сделать будет рассмотрено дальше) и обработать ответ. -2. Довериться библиотеке и вызвать функцию `func (dev *device)GetServices() map[string]string`, которая вернет map[string]string, ключом которой является название сервиса, а значением - endpoint данного сервиса \ No newline at end of file +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](img/exmp_GetCapabilities.png) +Таким образом, Функция 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) +} +``` \ No newline at end of file diff --git a/img/exmp_GetCapabilities.png b/img/exmp_GetCapabilities.png new file mode 100644 index 0000000000000000000000000000000000000000..60843cfb71502f04ecda8752e4c145dc36505a34 GIT binary patch literal 19566 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 z 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 E0w*ki*#H0l literal 0 HcmV?d00001 From f2ea2548466caff226d54ba559e8ee0fff9594df Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 20:46:17 +0300 Subject: [PATCH 07/16] README edited --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index ce70b44..8068484 100644 --- a/README.md +++ b/README.md @@ -52,10 +52,15 @@ if err != nil { Для работы с различными сервисами камерами необходимо отправить корректный 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** на нескольких примерах. @@ -63,6 +68,7 @@ if err != nil { Все необходимые типы данных определены в пакете [Device](Device/types.go). В файле (https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl) можно увидеть: ![GetCapabilities](img/exmp_GetCapabilities.png) + Таким образом, Функция GetCapabilities принимает в качестве аргумента перечисление: `enum { 'All', 'Analytics', 'Device', 'Events', 'Imaging', 'Media', 'PTZ' }` Чтобы вызвать данный метод создадим объект `Device.GetCapabilities`: From 42867920f2cbc29b5af4ff60348b987042aa4633 Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 20:51:12 +0300 Subject: [PATCH 08/16] README.md --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8068484..c36876c 100644 --- a/README.md +++ b/README.md @@ -53,15 +53,15 @@ if err != nil { **Goonvif** берет на себя работу по созданию корректного SOAP запроса и его отправке. В **Goonvif** определены структуры, для каждой функции каждого (поддерживаемого данной бибилиотекой) сервиса ONVIF: - [DeviceManagement Service](Device/types.go) -- [Media Service] (Media/types.go) +- [Media Service](Media/types.go) -- [Imaging Service] (Imaging/types.go) +- [Imaging Service](Imaging/types.go) -- [PTZ Service] (PTZ/types.go) +- [PTZ Service](PTZ/types.go) -- [Analytics Service] (Analytics/types.go) +- [Analytics Service](Analytics/types.go) -[Список всех сервисов стандарта (и документация к ним)] (https://www.onvif.org/profiles/specifications/) +[Список всех сервисов стандарта (и документация к ним)](https://www.onvif.org/profiles/specifications/) Рассмторим, как организована отправка запросов в **Goonvif** на нескольких примерах. 1. Метод GetCapabilities сервиса DeviceManagement @@ -83,4 +83,5 @@ if err != nil { } else { fmt.Println(resp) } -``` \ No newline at end of file +``` +2. \ No newline at end of file From 33464e6c7aecb31faab69f75d638143481491d86 Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 21:11:39 +0300 Subject: [PATCH 09/16] README.md --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c36876c..0de7b77 100644 --- a/README.md +++ b/README.md @@ -84,4 +84,24 @@ if err != nil { fmt.Println(resp) } ``` -2. \ No newline at end of file +2. Создание пользователя методом CreateUsers сервиса DeviceManagement +Все необходимые типы данных определены в пакете [Device](Device/types.go). +В файле (https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl) можно увидеть структуру запроса: +![GetCapabilities](img/exmp_CreateUsers.png) + +Создадим объект `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 вывести список всех пользователей и сравнить. From 42e62d7f52b758f19511dda77e4e4c8da85c5017 Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 22:16:11 +0300 Subject: [PATCH 10/16] Bugs fixed --- Device.go | 34 +++++++++++++++++++++------------- README.md | 13 +++++++++++-- img/exmp_ContinuousMove.png | Bin 0 -> 30138 bytes img/exmp_CreateUsers.png | Bin 0 -> 41446 bytes networking/networking.go | 25 ++++++++++++------------- 5 files changed, 44 insertions(+), 28 deletions(-) create mode 100644 img/exmp_ContinuousMove.png create mode 100644 img/exmp_CreateUsers.png diff --git a/Device.go b/Device.go index 9333289..3c33521 100644 --- a/Device.go +++ b/Device.go @@ -12,6 +12,8 @@ import ( "strings" "github.com/yakovlevdmv/goonvif/Device" "errors" + "net/http" + "io/ioutil" ) var xlmns = map[string]string { @@ -98,13 +100,16 @@ func GetAvailableDevicesAtSpecificEthernetInterface(interfaceName string) []devi } func (dev *device) getSupportedServices() { - resp, err := dev.CallMethod(Device.GetCapabilities{}) + resp, err := dev.CallMethod(Device.GetCapabilities{Category:"All"}) if err != nil { //log.Println(err.Error()) return } else { doc := etree.NewDocument() - if err := doc.ReadFromString(resp); err != nil { + + data, _ := ioutil.ReadAll(resp.Body) + + if err := doc.ReadFromBytes(data); err != nil { //log.Println(err.Error()) return } @@ -124,9 +129,10 @@ func NewDevice(xaddr string) (*device, error) { dev.endpoints = make(map[string]string) dev.addEndpoint("Device", "http://"+xaddr+"/onvif/device_service") - systemDateTime := Device.GetDeviceInformation{} - _, err := dev.CallMethod(systemDateTime) - if err != nil { + systemDateTime := Device.GetSystemDateAndTime{} + resp, err := dev.CallMethod(systemDateTime) + + 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") } @@ -169,7 +175,7 @@ func buildMethodSOAP(msg string) (gosoap.SoapMessage, error) { //CallMethod functions call an method, defined struct. //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(),"/") pkg := pkgPath[len(pkgPath)-1] @@ -182,6 +188,8 @@ func (dev device) CallMethod(method interface{}) (string, error) { case "PTZ": endpoint = dev.endpoints["PTZ"] } + //fmt.Println("endpoint", endpoint) + //TODO: Get endpoint automatically if dev.login != "" && dev.password != "" { /*resp, err := dev.сallAuthorizedMethod(endpoint, method) @@ -205,7 +213,7 @@ func (dev device) CallMethod(method interface{}) (string, error) { } //CallNonAuthorizedMethod functions call an method, defined 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 /* Converting struct to xml string representation @@ -213,7 +221,7 @@ func (dev device) callNonAuthorizedMethod(endpoint string, method interface{}) ( output, err := xml.MarshalIndent(method, " ", " ") if err != nil { //log.Printf("error: %v\n", err.Error()) - return "", err + return nil, err } /* @@ -222,7 +230,7 @@ func (dev device) callNonAuthorizedMethod(endpoint string, method interface{}) ( soap, err := buildMethodSOAP(string(output)) if err != nil { //log.Printf("error: %v\n", err) - return "", err + return nil, err } soap.AddRootNamespaces(xlmns) @@ -234,14 +242,14 @@ func (dev device) callNonAuthorizedMethod(endpoint string, method interface{}) ( } //CallMethod functions call an method, defined 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 struct to xml string representation */ output, err := xml.MarshalIndent(method, " ", " ") if err != nil { //log.Printf("error: %v\n", err.Error()) - return "", err + return nil, err } /* @@ -250,7 +258,7 @@ func (dev device) callAuthorizedMethod(endpoint string, method interface{}) (str soap, err := buildMethodSOAP(string(output)) if err != nil { //log.Printf("error: %v\n", err.Error()) - return "", err + return nil, err } /* @@ -269,7 +277,7 @@ func (dev device) callAuthorizedMethod(endpoint string, method interface{}) (str soapReq, err := xml.MarshalIndent(auth, "", " ") if err != nil { //log.Printf("error: %v\n", err.Error()) - return "", err + return nil, err } /* diff --git a/README.md b/README.md index 0de7b77..e189216 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ if err != nil { 2. Создание пользователя методом CreateUsers сервиса DeviceManagement Все необходимые типы данных определены в пакете [Device](Device/types.go). В файле (https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl) можно увидеть структуру запроса: -![GetCapabilities](img/exmp_CreateUsers.png) +![CreateUsers](img/exmp_CreateUsers.png) Создадим объект `Device.CreateUsers`: ``` @@ -103,5 +103,14 @@ if err != nil { В данном примере можно наблюдать использования пакета onvif, в котором определено большинство типов, используемых в различных сервисах. Поэтому при создании структур запросов необходимо это учитывать. -#####**ВАЖНО** +##### ВАЖНО Некоторые камеры работают специфично. Это означает, что в зависимости от модели камеры можно не получить ошибки при неправильном запросе. Поэтому советую проверять точно ли выполнилась операция. Например, для метода CreateUsers вывести список всех пользователей и сравнить. + +3. Метод ContinuousMove сервиса PTZ +Все необходимые типы данных определены в пакете [PTZ](PTZ/types.go). +В файле (https://www.onvif.org/ver20/ptz/wsdl/ptz.wsdl) можно увидеть структуру запроса: +![ContinuousMove](img/exmp_ContinuousMove.png) + +Так как данная команда определяется сервисом PTZ, необходимый тип находится в пакете [PTZ](PTZ/types.go). + +Создадим объект `PTZ.ContinuousMove`: diff --git a/img/exmp_ContinuousMove.png b/img/exmp_ContinuousMove.png new file mode 100644 index 0000000000000000000000000000000000000000..6ba4847a7b5854fdde88665b2497668280dc3f79 GIT binary patch literal 30138 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�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 D904)+ literal 0 HcmV?d00001 diff --git a/img/exmp_CreateUsers.png b/img/exmp_CreateUsers.png new file mode 100644 index 0000000000000000000000000000000000000000..790f98a3466e7e0f4890ec989869c9828521c654 GIT binary patch literal 41446 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 literal 0 HcmV?d00001 diff --git a/networking/networking.go b/networking/networking.go index b4dfd84..ae3bbad 100644 --- a/networking/networking.go +++ b/networking/networking.go @@ -3,27 +3,26 @@ package networking import ( "net/http" "bytes" - "io/ioutil" - "strconv" - "errors" ) -func SendSoap(endpoint, message string) (string, error) { +func SendSoap(endpoint, message string) (*http.Response, error) { httpClient := new(http.Client) resp, err := httpClient.Post(endpoint, "application/soap+xml; charset=utf-8", bytes.NewBufferString(message)) if err != nil { - return "", err - } - if resp.StatusCode != http.StatusOK { - return "", errors.New("error: got HTTP response status " + strconv.Itoa(resp.StatusCode)) - } - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "", err + return resp, err } + /*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 string(b),nil + return resp,nil } From dffee5313b543f19d983414867c2a83d95ae2bf5 Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 22:20:26 +0300 Subject: [PATCH 11/16] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e189216..9aa1722 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ if err != nil { Рассмторим, как организована отправка запросов в **Goonvif** на нескольких примерах. 1. Метод GetCapabilities сервиса DeviceManagement + Все необходимые типы данных определены в пакете [Device](Device/types.go). В файле (https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl) можно увидеть: ![GetCapabilities](img/exmp_GetCapabilities.png) @@ -85,6 +86,7 @@ if err != nil { } ``` 2. Создание пользователя методом CreateUsers сервиса DeviceManagement + Все необходимые типы данных определены в пакете [Device](Device/types.go). В файле (https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl) можно увидеть структуру запроса: ![CreateUsers](img/exmp_CreateUsers.png) @@ -107,6 +109,7 @@ if err != nil { Некоторые камеры работают специфично. Это означает, что в зависимости от модели камеры можно не получить ошибки при неправильном запросе. Поэтому советую проверять точно ли выполнилась операция. Например, для метода CreateUsers вывести список всех пользователей и сравнить. 3. Метод ContinuousMove сервиса PTZ + Все необходимые типы данных определены в пакете [PTZ](PTZ/types.go). В файле (https://www.onvif.org/ver20/ptz/wsdl/ptz.wsdl) можно увидеть структуру запроса: ![ContinuousMove](img/exmp_ContinuousMove.png) From c0589c604594ffc4d70fb3d360562ed083901b4a Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 22:44:40 +0300 Subject: [PATCH 12/16] Update README.md --- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/README.md b/README.md index 9aa1722..f97c8b4 100644 --- a/README.md +++ b/README.md @@ -115,5 +115,53 @@ if err != nil { ![ContinuousMove](img/exmp_ContinuousMove.png) Так как данная команда определяется сервисом 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) можно увидеть структуру запроса: +![ContinuousMove](img/exmp_GetProfiles.png) + +Вот пример создания и вызова запроса 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) + From 89e65ee86e4538a75f3cbcdcf6b02fa86933dcc1 Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 22:45:45 +0300 Subject: [PATCH 13/16] README updating merge conflicts --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e189216..9aa1722 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ if err != nil { Рассмторим, как организована отправка запросов в **Goonvif** на нескольких примерах. 1. Метод GetCapabilities сервиса DeviceManagement + Все необходимые типы данных определены в пакете [Device](Device/types.go). В файле (https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl) можно увидеть: ![GetCapabilities](img/exmp_GetCapabilities.png) @@ -85,6 +86,7 @@ if err != nil { } ``` 2. Создание пользователя методом CreateUsers сервиса DeviceManagement + Все необходимые типы данных определены в пакете [Device](Device/types.go). В файле (https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl) можно увидеть структуру запроса: ![CreateUsers](img/exmp_CreateUsers.png) @@ -107,6 +109,7 @@ if err != nil { Некоторые камеры работают специфично. Это означает, что в зависимости от модели камеры можно не получить ошибки при неправильном запросе. Поэтому советую проверять точно ли выполнилась операция. Например, для метода CreateUsers вывести список всех пользователей и сравнить. 3. Метод ContinuousMove сервиса PTZ + Все необходимые типы данных определены в пакете [PTZ](PTZ/types.go). В файле (https://www.onvif.org/ver20/ptz/wsdl/ptz.wsdl) можно увидеть структуру запроса: ![ContinuousMove](img/exmp_ContinuousMove.png) From f76c49b1f80df5febac2c2bd76e280aebf84768f Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 22:46:13 +0300 Subject: [PATCH 14/16] README.md --- img/exmp_GetProfiles.png | Bin 0 -> 14358 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 img/exmp_GetProfiles.png diff --git a/img/exmp_GetProfiles.png b/img/exmp_GetProfiles.png new file mode 100644 index 0000000000000000000000000000000000000000..6e99ceb71a1abe6c68362934cbf681b4e129ff40 GIT binary patch literal 14358 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 V6)1>JcH@Ec2N@OVGRco${tu=z<$VAE literal 0 HcmV?d00001 From b71dc183a27b45d3de372df8bd93b5a8052ac3b8 Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sat, 7 Apr 2018 23:33:43 +0300 Subject: [PATCH 15/16] Update README.md --- README.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f97c8b4..da40c9b 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,11 @@ go get github.com/yakovlevdmv/goonvif # Начало работы Чтобы начать работать с камерой, необходимо создать объект `device`. Для этого необходимо воспользоваться функцией `func NewDevice(xaddr string) (*device, error)`, -которая принимает адрес ONVIF устройства и возвращает указатель на созданный объект либо ошибку. -Если камера не доступна, указан неверный адрес для ONVIF сервиса камеры (возможно находся по другому порту) или же камера вообще не поддерживает ONVIF -функция вернет не `nil` error, а в качестве указателя на объект вернет `nil`. +которая принимает IP адрес ONVIF устройства и возвращает указатель на созданный объект либо ошибку. +Если камера недоступна, указан неверный адрес для ONVIF сервиса камеры (возможно находится по другому порту) или же камера вообще не поддерживает ONVIF +функция вернет error не являющимся `nil`, а в качестве указателя на объект устройства вернет `nil`. ### Пример подключения к камере -Пусть камера в сети находится по адресу 192.168.13.42, а ее ONVIF сервисы расположены на 1234 порту. Тогда, +Пусть камера в сети находится по адресу 192.168.13.42, а ее ONVIF сервисы расположены на порте 1234. Тогда, ``` dev, err := goonvif.NewDevice("192.168.13.42:1234") ``` @@ -41,14 +41,14 @@ if err != nil { ///Работа с камерой ``` ### Поддерживаемые ONVIF сервисы -Теперь, когда камера доступна, можно приступать к работе с ней. Однако стандарт ONVIF имеет множество сервисов, точка доступа (endpoint) к которым не закреплена стандартом (кроме DeviceManagment: http://onvif_host/onvif/device_service). +Теперь, когда камера доступна, можно приступать к работе с ней. Однако стандарт ONVIF имеет множество сервисов, а также точку доступа (endpoint) которая не определена стандартом (кроме DeviceManagment: http://onvif_host/onvif/device_service). Поэтому дальше встает вопрос о поддерживаемых камерой сервисах и определении их endpoint'ов. Для получения поддерживаемых камерой сервисов необходимо вызвать метод GetCapabilities сервиса DeviceManagement. -Однако данная библиотека автоматизирует данный процесс, поэтому при создании объекта device при помощи `func NewDevice(xaddr string) (*device, error)` -библиотека одновременно обрабатывает поддерживаемые камерой сервисы. Таким образом чтобы получить поддерживаемые устройством сервисы, можно воспользоваться двумя путями: +Однако эта библиотека автоматизирует данный процесс, поэтому при создании объекта 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) @@ -102,11 +102,10 @@ if err != nil { } ``` -В данном примере можно наблюдать использования пакета onvif, в котором определено большинство типов, используемых в различных сервисах. -Поэтому при создании структур запросов необходимо это учитывать. +В данном примере можно наблюдать использование пакета onvif, в котором определено большинство типов, используемых в поддерживаемых библиотекой сервисах, поэтому при создании структур запросов необходимо это учитывать. ##### ВАЖНО -Некоторые камеры работают специфично. Это означает, что в зависимости от модели камеры можно не получить ошибки при неправильном запросе. Поэтому советую проверять точно ли выполнилась операция. Например, для метода CreateUsers вывести список всех пользователей и сравнить. +Некоторые камеры работают специфично. Это означает, что в зависимости от модели камеры можно не получить ошибки при неправильном запросе. Поэтому советую проверять, точно ли выполнилась операция. Например, для метода CreateUsers надо вывести список всех пользователей и проверить добавился ли пользователь. 3. Метод ContinuousMove сервиса PTZ @@ -135,7 +134,7 @@ move := PTZ.ContinuousMove{ } ``` -**Заметим**, что объекты Velocity, PanTilt и Zoom определены в пакете onvif. Такая ситуация соответствует всем встроенным типам. +**Заметим**, что объекты Velocity, PanTilt и Zoom определены в пакете onvif. Такое применение свойственно для большинства встроенных в структуру типов. Для вызова данной функции воспользуемся методом `func (dev device) CallMethod(method interface{}) (string, error)`: ``` @@ -163,5 +162,10 @@ if err != nil { } ``` -**Важно** Обработка response'ов пока не реализована, поэтому данная задача ложится на Ваши плечи. Вы можете упростить обработку response при помощи библиотеки [etree](https://github.com/beevik/etree). Либо же воспользоваться сервисом (http://www.webtoolkitonline.com/xml-formatter.html) +**Важно** Обработка 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") +``` From 36090abc65e820e4e284c70a05ede09923020bbd Mon Sep 17 00:00:00 2001 From: yakovlevdmv Date: Sun, 8 Apr 2018 02:04:58 +0300 Subject: [PATCH 16/16] Some improvements --- Device.go | 75 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/Device.go b/Device.go index 3c33521..0681cfe 100644 --- a/Device.go +++ b/Device.go @@ -86,25 +86,66 @@ 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 */ devices := WS_Discovery.SendProbe(interfaceName, nil, []string{"dn:"+NVT.String()}, map[string]string{"dn":"http://www.onvif.org/ver10/network/wsdl"}) - //nvtDevices := make([]device, len(devices)) + nvtDevices := make([]device, 0) + ////fmt.Println(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 nil + return nvtDevices } -func (dev *device) getSupportedServices() { - resp, err := dev.CallMethod(Device.GetCapabilities{Category:"All"}) - if err != nil { - //log.Println(err.Error()) - return - } else { +func (dev *device) getSupportedServices(resp *http.Response) { + //resp, err := dev.CallMethod(Device.GetCapabilities{Category:"All"}) + //if err != nil { + // log.Println(err.Error()) + //return + //} else { doc := etree.NewDocument() data, _ := ioutil.ReadAll(resp.Body) @@ -115,11 +156,11 @@ func (dev *device) getSupportedServices() { } services := doc.FindElements("./Envelope/Body/GetCapabilitiesResponse/Capabilities/*/XAddr") for _, j := range services{ - //fmt.Println(j.Text()) - //fmt.Println(j.Parent().Tag) + ////fmt.Println(j.Text()) + ////fmt.Println(j.Parent().Tag) dev.addEndpoint(j.Parent().Tag, j.Text()) } - } + //} } //NewDevice function construct a ONVIF Device entity @@ -129,15 +170,17 @@ func NewDevice(xaddr string) (*device, error) { dev.endpoints = make(map[string]string) dev.addEndpoint("Device", "http://"+xaddr+"/onvif/device_service") - systemDateTime := Device.GetSystemDateAndTime{} - resp, err := dev.CallMethod(systemDateTime) + 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() + dev.getSupportedServices(resp) return dev, nil } @@ -188,7 +231,7 @@ func (dev device) CallMethod(method interface{}) (*http.Response, error) { case "PTZ": endpoint = dev.endpoints["PTZ"] } - //fmt.Println("endpoint", endpoint) + ////fmt.Println("endpoint", endpoint) //TODO: Get endpoint automatically if dev.login != "" && dev.password != "" {