mirror of
				https://github.com/kerberos-io/onvif.git
				synced 2025-10-31 02:47:44 +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
	 George Palanjyan
					George Palanjyan