ruby_onvif_client 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ruby_onvif_client/helper/ptz_common.rb +124 -0
- data/lib/ruby_onvif_client/ptz/absolute_move.rb +85 -0
- data/lib/ruby_onvif_client/ptz/continuous_move.rb +57 -0
- data/lib/ruby_onvif_client/ptz/get_configuration.rb +47 -0
- data/lib/ruby_onvif_client/ptz/get_configuration_options.rb +53 -0
- data/lib/ruby_onvif_client/ptz/get_configurations.rb +46 -0
- data/lib/ruby_onvif_client/ptz/get_node.rb +18 -2
- data/lib/ruby_onvif_client/ptz/get_nodes.rb +21 -4
- data/lib/ruby_onvif_client/ptz/get_presets.rb +37 -0
- data/lib/ruby_onvif_client/ptz/goto_home_position.rb +55 -0
- data/lib/ruby_onvif_client/ptz/goto_preset.rb +57 -0
- data/lib/ruby_onvif_client/ptz/relative_move.rb +85 -0
- data/lib/ruby_onvif_client/ptz/remove_preset.rb +25 -0
- data/lib/ruby_onvif_client/ptz/set_preset.rb +33 -0
- data/ruby-onvif-client.gemspec +2 -2
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff6213cb0545f46781a35cdeb0b2a23410dc6fe1
|
4
|
+
data.tar.gz: 552415292467d299f720d748568b559ac460f480
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00a9acf05dd4d4e9d5a2ae0093eec0a435d6cf4061aa19b6e181b462b1069d6b77e3924c293a231a205595226cf7cb87237049a8719d9659c5a6f5233dc48d0c
|
7
|
+
data.tar.gz: 35bbd68f291dd691f019fe26552d0295051fe5644eb5607b88eac9856bbc1d5f67791ce8defeead8dabe7d89d6201b1af3cecfd7f10f4cafaa74a4a9e63400cd
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module ONVIF
|
2
|
+
module PtzCommon
|
3
|
+
def get_configuration_optional_value xml_doc, configuration
|
4
|
+
configuration = {} if configuration.nil?
|
5
|
+
unless xml_doc.at_xpath("tt:DefaultAbsolutePantTiltPositionSpace").nil?
|
6
|
+
configuration[:daptps] = value(xml_doc, "tt:DefaultAbsolutePantTiltPositionSpace")
|
7
|
+
end
|
8
|
+
unless xml_doc.at_xpath("tt:DefaultAbsoluteZoomPositionSpace").nil?
|
9
|
+
configuration[:dazps] = value(xml_doc, "tt:DefaultAbsoluteZoomPositionSpace")
|
10
|
+
end
|
11
|
+
unless xml_doc.at_xpath("tt:DefaultRelativePanTiltTranslationSpace").nil?
|
12
|
+
configuration[:drptts] = value(xml_doc, "tt:DefaultRelativePanTiltTranslationSpace")
|
13
|
+
end
|
14
|
+
unless xml_doc.at_xpath("tt:DefaultRelativeZoomTranslationSpace").nil?
|
15
|
+
configuration[:drzts] = value(xml_doc, "tt:DefaultRelativeZoomTranslationSpace")
|
16
|
+
end
|
17
|
+
unless xml_doc.at_xpath("tt:DefaultContinuousPanTiltVelocitySpace").nil?
|
18
|
+
configuration[:dcptvs] = value(xml_doc, "tt:DefaultContinuousPanTiltVelocitySpace")
|
19
|
+
end
|
20
|
+
unless xml_doc.at_xpath("tt:DefaultContinuousZoomVelocitySpace").nil?
|
21
|
+
configuration[:dczvs] = value(xml_doc, "tt:DefaultContinuousZoomVelocitySpace")
|
22
|
+
end
|
23
|
+
unless xml_doc.at_xpath("tt:DefaultPTZTimeout").nil?
|
24
|
+
configuration[:d_ptz_timeout] = value(xml_doc, "tt:DefaultPTZTimeout")
|
25
|
+
end
|
26
|
+
return configuration
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_space_muster root_doc, parent_node_name, configuration
|
30
|
+
configuration = {} if configuration.nil?
|
31
|
+
configuration[parent_node_name.underscore] = {}
|
32
|
+
spaces = root_doc.xpath("tt:" + parent_node_name)
|
33
|
+
unless spaces.at_xpath("tt:AbsolutePanTiltPositionSpace").nil?
|
34
|
+
configuration[parent_node_name.underscore][:aptps] = get_spaces spaces, "AbsolutePanTiltPositionSpace"
|
35
|
+
end
|
36
|
+
unless spaces.at_xpath("tt:AbsoluteZoomPositionSpace").nil?
|
37
|
+
configuration[parent_node_name.underscore][:azps] = get_spaces spaces, "AbsoluteZoomPositionSpace"
|
38
|
+
end
|
39
|
+
unless spaces.at_xpath("tt:RelativePanTiltTranslationSpace").nil?
|
40
|
+
configuration[parent_node_name.underscore][:rptts] = get_spaces spaces, "RelativePanTiltTranslationSpace"
|
41
|
+
end
|
42
|
+
unless spaces.at_xpath("tt:RelativeZoomTranslationSpace").nil?
|
43
|
+
configuration[parent_node_name.underscore][:rzts] = get_spaces spaces, "RelativeZoomTranslationSpace"
|
44
|
+
end
|
45
|
+
unless spaces.at_xpath("tt:ContinuousPanTiltVelocitySpace").nil?
|
46
|
+
configuration[parent_node_name.underscore][:cptvs] = get_spaces spaces, "ContinuousPanTiltVelocitySpace"
|
47
|
+
end
|
48
|
+
unless spaces.at_xpath("tt:ContinuousZoomVelocitySpace").nil?
|
49
|
+
configuration[parent_node_name.underscore][:czvs] = get_spaces spaces, "ContinuousZoomVelocitySpace"
|
50
|
+
end
|
51
|
+
unless spaces.at_xpath("tt:PanTiltSpeedSpace").nil?
|
52
|
+
configuration[parent_node_name.underscore][:ptss] = get_spaces spaces, "PanTiltSpeedSpace"
|
53
|
+
end
|
54
|
+
unless spaces.at_xpath("tt:ZoomSpeedSpace").nil?
|
55
|
+
configuration[parent_node_name.underscore][:zss] = get_spaces spaces, "ZoomSpeedSpace"
|
56
|
+
end
|
57
|
+
configuration[parent_node_name.underscore][:extension] = ""
|
58
|
+
return configuration
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_spaces xml_doc, node_name
|
62
|
+
results = []
|
63
|
+
unless xml_doc.at_xpath("tt:" + node_name).nil?
|
64
|
+
xml_doc.xpath("tt:" + node_name).each do |space|
|
65
|
+
if space.at_xpath("tt:YRange").nil?
|
66
|
+
results << get_zoom_limits(space)
|
67
|
+
else
|
68
|
+
results << get_pan_tilt_limits(space)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
return results
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_speed xml_doc, speed_name, configuration
|
76
|
+
configuration = {} if configuration.nil?
|
77
|
+
speed_doc = xml_doc.at_xpath("tt:" + speed_name)
|
78
|
+
unless speed_doc.nil?
|
79
|
+
pan_tilt = speed_doc.at_xpath("tt:PanTilt")
|
80
|
+
zoom = speed_doc.at_xpath("tt:Zoom")
|
81
|
+
configuration[speed_name.underscore] = {}
|
82
|
+
unless pan_tilt.nil?
|
83
|
+
configuration[speed_name.underscore][:pan_tilt] = {
|
84
|
+
x: attribute(pan_tilt, "x"),
|
85
|
+
y: attribute(pan_tilt, "y"),
|
86
|
+
space: attribute(pan_tilt, "space")
|
87
|
+
}
|
88
|
+
end
|
89
|
+
unless zoom.nil?
|
90
|
+
configuration[speed_name.underscore][:pan_tilt] = {
|
91
|
+
x: attribute(zoom, "x"),
|
92
|
+
space: attribute(zoom, "space")
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
return configuration
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_pan_tilt_limits xml_doc
|
100
|
+
configuration = {}
|
101
|
+
configuration = get_zoom_limits xml_doc
|
102
|
+
configuration[:y_range] = get_min_max(xml_doc, "tt:YRange")
|
103
|
+
return configuration
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_zoom_limits xml_doc
|
107
|
+
return {
|
108
|
+
uri: value(xml_doc, "tt:URI"),
|
109
|
+
x_range: get_min_max(xml_doc, "tt:XRange")
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_min_max xml_doc, parent_name
|
114
|
+
this_node = xml_doc
|
115
|
+
unless parent_name.nil?
|
116
|
+
this_node = xml_doc.at_xpath(parent_name)
|
117
|
+
end
|
118
|
+
return {
|
119
|
+
min: value(this_node, "tt:Min"),
|
120
|
+
max: value(this_node, "tt:Max")
|
121
|
+
}
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
|
3
|
+
module ONVIF
|
4
|
+
module PtzAction
|
5
|
+
class AbsoluteMove < Action
|
6
|
+
# options 的结构
|
7
|
+
# {
|
8
|
+
# profile_token: "xxxxxxx",//[ReferenceToken] A reference to the MediaProfile where the operation should take place.
|
9
|
+
# position: {
|
10
|
+
# pan_tilt: { //optional
|
11
|
+
# x: 1, //[float]
|
12
|
+
# y: 2, //[float]
|
13
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace", //[anyURI]
|
14
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace
|
15
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace
|
16
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace
|
17
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace
|
18
|
+
# },
|
19
|
+
# zoom: { //optional
|
20
|
+
# x: 1,//[float]
|
21
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace",//[anyURI]
|
22
|
+
# }
|
23
|
+
# }
|
24
|
+
# speed: { //optional
|
25
|
+
# pan_tilt: { //optional
|
26
|
+
# x: 1, //[float]
|
27
|
+
# y: 2, //[float]
|
28
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace", //[anyURI]
|
29
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace
|
30
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace
|
31
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace
|
32
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace
|
33
|
+
# },
|
34
|
+
# zoom: { //optional
|
35
|
+
# x: 1,//[float]
|
36
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace",//[anyURI]
|
37
|
+
# }
|
38
|
+
# }
|
39
|
+
# }
|
40
|
+
def run options, cb
|
41
|
+
message = create_ptz_onvif_message
|
42
|
+
message.body = ->(xml) do
|
43
|
+
xml.wsdl(:AbsoluteMove) do
|
44
|
+
xml.wsdl :ProfileToken, options[:profile_token]
|
45
|
+
xml.wsdl(:Position) do
|
46
|
+
unless options[:position][:pan_tilt].nil?
|
47
|
+
xml.wsdl :PanTilt, {
|
48
|
+
"x" => options[:position][:pan_tilt][:x],
|
49
|
+
"y" => options[:position][:pan_tilt][:y],
|
50
|
+
"space" => options[:position][:pan_tilt][:space]
|
51
|
+
}
|
52
|
+
end
|
53
|
+
unless options[:position][:zoom].nil?
|
54
|
+
xml.wsdl :Zoom, {
|
55
|
+
"x" => options[:position][:zoom][:x],
|
56
|
+
"space" => options[:position][:zoom][:space]
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
unless options[:speed].nil?
|
61
|
+
xml.wsdl(:Speed) do
|
62
|
+
unless options[:speed][:pan_tilt].nil?
|
63
|
+
xml.wsdl :PanTilt, {
|
64
|
+
"x" => options[:speed][:pan_tilt][:x],
|
65
|
+
"y" => options[:speed][:pan_tilt][:y],
|
66
|
+
"space" => options[:speed][:pan_tilt][:space]
|
67
|
+
}
|
68
|
+
end
|
69
|
+
unless options[:speed][:zoom].nil?
|
70
|
+
xml.wsdl :Zoom, {
|
71
|
+
"x" => options[:speed][:zoom][:x],
|
72
|
+
"space" => options[:speed][:zoom][:space]
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
send_message message do |success, result|
|
80
|
+
callback cb, success, result
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
|
3
|
+
module ONVIF
|
4
|
+
module PtzAction
|
5
|
+
class ContinuousMove < Action
|
6
|
+
# options 的结构
|
7
|
+
# {
|
8
|
+
# profile_token: "xxxxxxx",//[ReferenceToken] A reference to the MediaProfile where the operation should take place.
|
9
|
+
# velocity: { //optional
|
10
|
+
# pan_tilt: { //optional
|
11
|
+
# x: 1, //[float]
|
12
|
+
# y: 2, //[float]
|
13
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace", //[anyURI]
|
14
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace
|
15
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace
|
16
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace
|
17
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace
|
18
|
+
# },
|
19
|
+
# zoom: { //optional
|
20
|
+
# x: 1,//[float]
|
21
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace",//[anyURI]
|
22
|
+
# }
|
23
|
+
# },
|
24
|
+
# timeout: '' //optional [duration]
|
25
|
+
# }
|
26
|
+
def run options, cb
|
27
|
+
message = create_ptz_onvif_message
|
28
|
+
message.body = ->(xml) do
|
29
|
+
xml.wsdl(:ContinuousMove) do
|
30
|
+
xml.wsdl :ProfileToken, options[:profile_token]
|
31
|
+
unless options[:velocity].nil?
|
32
|
+
xml.wsdl(:Velocity) do
|
33
|
+
unless options[:velocity][:pan_tilt].nil?
|
34
|
+
xml.wsdl :PanTilt, {
|
35
|
+
"x" => options[:velocity][:pan_tilt][:x],
|
36
|
+
"y" => options[:velocity][:pan_tilt][:y],
|
37
|
+
"space" => options[:velocity][:pan_tilt][:space]
|
38
|
+
}
|
39
|
+
end
|
40
|
+
unless options[:velocity][:zoom].nil?
|
41
|
+
xml.wsdl :Zoom, {
|
42
|
+
"x" => options[:velocity][:zoom][:x],
|
43
|
+
"space" => options[:velocity][:zoom][:space]
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
xml.wsdl :Timeout, options[:timeout] unless options[:timeout].nil?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
send_message message do |success, result|
|
52
|
+
callback cb, success, result
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
require_relative '../helper/ptz_common'
|
3
|
+
|
4
|
+
module ONVIF
|
5
|
+
module PtzAction
|
6
|
+
class GetConfiguration < Action
|
7
|
+
include PtzCommon #get_configuration_optional_value , get_speed, get_pan_tilt_limits, get_zoom_limits
|
8
|
+
# p_c_token 的结构
|
9
|
+
# p_c_token = "xxxxx" //[ReferenceToken] Token of the requested PTZConfiguration.
|
10
|
+
def run p_c_token, cb
|
11
|
+
message = create_ptz_onvif_message
|
12
|
+
message.body = ->(xml) do
|
13
|
+
xml.wsdl(:GetConfiguration) do
|
14
|
+
xml.wsdl :PTZConfigurationToken, p_c_token
|
15
|
+
end
|
16
|
+
end
|
17
|
+
send_message message do |success, result|
|
18
|
+
if success
|
19
|
+
xml_doc = Nokogiri::XML(result[:content])
|
20
|
+
root_doc = xml_doc.at_xpath("//tptz:PTZConfiguration")
|
21
|
+
pan_tilt_limits_range = root_doc.at_xpath("tt:PanTiltLimits/tt:Range")
|
22
|
+
zoom_limits_range = root_doc.at_xpath("tt:ZoomLimits/tt:Range")
|
23
|
+
configuration = {
|
24
|
+
name: value(root_doc, 'tt:Name'),
|
25
|
+
use_count: value(root_doc, 'tt:UseCount'),
|
26
|
+
token: attribute(root_doc, 'token'),
|
27
|
+
node_token: value(root_doc, 'tt:NodeToken')
|
28
|
+
}
|
29
|
+
configuration = get_configuration_optional_value root_doc, configuration
|
30
|
+
configuration = get_speed root_doc, "DefaultPTZSpeed", configuration
|
31
|
+
configuration[:default_ptz_timeout] = value(root_doc, "tt:DefaultPTZTimeout")
|
32
|
+
configuration[:pan_tilt_limits] = {
|
33
|
+
range: get_pan_tilt_limits(pan_tilt_limits_range)
|
34
|
+
}
|
35
|
+
configuration[:zoom_limits] = {
|
36
|
+
range: get_zoom_limits(zoom_limits_range)
|
37
|
+
}
|
38
|
+
configuration[:extension] = ""
|
39
|
+
callback cb, success, configuration
|
40
|
+
else
|
41
|
+
callback cb, success, result
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
require_relative '../helper/ptz_common'
|
3
|
+
|
4
|
+
module ONVIF
|
5
|
+
module PtzAction
|
6
|
+
class GetConfigurationOptions < Action
|
7
|
+
include PtzCommon #get_speed, get_pan_tilt_limits, get_zoom_limits, get_space_muster
|
8
|
+
# c_token 的结构
|
9
|
+
# c_token = "xxxxx" //[ReferenceToken] Token of an existing configuration that the options are intended for.
|
10
|
+
def run c_token, cb
|
11
|
+
message = create_ptz_onvif_message
|
12
|
+
message.body = ->(xml) do
|
13
|
+
xml.wsdl(:GetConfigurationOptions) do
|
14
|
+
xml.wsdl :ConfigurationToken, c_token
|
15
|
+
end
|
16
|
+
end
|
17
|
+
send_message message do |success, result|
|
18
|
+
if success
|
19
|
+
xml_doc = Nokogiri::XML(result[:content])
|
20
|
+
root_doc = xml_doc.xpath("//tptz:PTZConfigurationOptions")
|
21
|
+
pt_control_direction = root_doc.at_xpath("tptz:PTControlDirection")
|
22
|
+
configuration = {}
|
23
|
+
configuration = get_space_muster(root_doc, "Spaces", nil)
|
24
|
+
unless pt_control_direction.nil?
|
25
|
+
eflip_mode = []; reverse_mode = []
|
26
|
+
pt_control_direction.xpath("tt:EFlip/tt:Mode").each do |mode|
|
27
|
+
eflip_mode << mode.content
|
28
|
+
end
|
29
|
+
pt_control_direction.xpath("tt:Reverse/tt:Mode").each do |mode|
|
30
|
+
reverse_mode << mode.content
|
31
|
+
end
|
32
|
+
configuration[:PTControlDirection] = {
|
33
|
+
eflip: {
|
34
|
+
mode: eflip_mode,
|
35
|
+
extension: ""
|
36
|
+
},
|
37
|
+
reverse: {
|
38
|
+
mode: reverse_mode,
|
39
|
+
extension: ""
|
40
|
+
}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
configuration[:ptz_timeout] = get_min_max(root_doc, "tt:PTZTimeout")
|
44
|
+
configuration[:extension] = ""
|
45
|
+
callback cb, success, configuration
|
46
|
+
else
|
47
|
+
callback cb, success, result
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
require_relative '../helper/ptz_common'
|
3
|
+
|
4
|
+
module ONVIF
|
5
|
+
module PtzAction
|
6
|
+
class GetConfigurations < Action
|
7
|
+
include PtzCommon #get_configuration_optional_value , get_speed, get_pan_tilt_limits, get_zoom_limits
|
8
|
+
def run cb
|
9
|
+
message = create_ptz_onvif_message
|
10
|
+
message.body = ->(xml) do
|
11
|
+
xml.wsdl(:GetConfigurations)
|
12
|
+
end
|
13
|
+
send_message message do |success, result|
|
14
|
+
if success
|
15
|
+
xml_doc = Nokogiri::XML(result[:content])
|
16
|
+
configurations = []
|
17
|
+
xml_doc.xpath("//tptz:PTZConfiguration").each do |root_node|
|
18
|
+
pan_tilt_limits_range = root_node.at_xpath("tt:PanTiltLimits/tt:Range")
|
19
|
+
zoom_limits_range = root_node.at_xpath("tt:ZoomLimits/tt:Range")
|
20
|
+
configuration = {
|
21
|
+
name: value(root_node, 'tt:Name'),
|
22
|
+
use_count: value(root_node, 'tt:UseCount'),
|
23
|
+
token: attribute(root_node, 'token'),
|
24
|
+
node_token: value(root_node, 'tt:NodeToken')
|
25
|
+
}
|
26
|
+
configuration = get_configuration_optional_value root_node, configuration
|
27
|
+
configuration = get_speed root_node, "DefaultPTZSpeed", configuration
|
28
|
+
configuration[:default_ptz_timeout] = value(root_node, "tt:DefaultPTZTimeout")
|
29
|
+
configuration[:pan_tilt_limits] = {
|
30
|
+
range: get_pan_tilt_limits(pan_tilt_limits_range)
|
31
|
+
}
|
32
|
+
configuration[:zoom_limits] = {
|
33
|
+
range: get_zoom_limits(zoom_limits_range)
|
34
|
+
}
|
35
|
+
configuration[:extension] = ""
|
36
|
+
configurations << configuration
|
37
|
+
end
|
38
|
+
callback cb, success, configurations
|
39
|
+
else
|
40
|
+
callback cb, success, result
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require_relative '../action'
|
2
|
+
require_relative '../helper/ptz_common'
|
2
3
|
|
3
4
|
module ONVIF
|
4
5
|
module PtzAction
|
5
6
|
class GetNode < Action
|
7
|
+
include PtzCommon
|
6
8
|
# node_token 的结构 //[ReferenceToken] Token of the requested PTZNode.
|
7
9
|
def run node_token ,cb
|
8
10
|
message = create_ptz_onvif_message
|
@@ -14,8 +16,22 @@ module ONVIF
|
|
14
16
|
send_message message do |success, result|
|
15
17
|
if success
|
16
18
|
xml_doc = Nokogiri::XML(result[:content])
|
17
|
-
preset_token =
|
18
|
-
|
19
|
+
preset_token = xml_doc.at_xpath('//tptz:PTZNode')
|
20
|
+
ptz_node = {
|
21
|
+
name: value(preset_token, "tt:Name"),
|
22
|
+
token: attribute(preset_token, "token")
|
23
|
+
}
|
24
|
+
ptz_node = get_space_muster(preset_token, "SupportedPTZSpaces", ptz_node)
|
25
|
+
ptz_node[:maximum_number_of_presets] = value(preset_token, "tt:MaximumNumberOfPresets")
|
26
|
+
ptz_node[:home_supported] = value(preset_token, "tt:HomeSupported")
|
27
|
+
ptz_node[:auxiliary_commands] = []
|
28
|
+
unless preset_token.at_xpath("tt:AuxiliaryCommands").nil?
|
29
|
+
ptz_node[:auxiliary_commands] = []
|
30
|
+
preset_token.xpath("tt:AuxiliaryCommands").each do |command|
|
31
|
+
ptz_node[:auxiliary_commands] << command.content
|
32
|
+
end
|
33
|
+
end
|
34
|
+
callback cb, success, ptz_node
|
19
35
|
else
|
20
36
|
callback cb, success, result
|
21
37
|
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require_relative '../action'
|
2
|
+
require_relative '../helper/ptz_common'
|
2
3
|
|
3
4
|
module ONVIF
|
4
5
|
module PtzAction
|
5
6
|
class GetNodes < Action
|
6
|
-
|
7
|
-
def run
|
7
|
+
include PtzCommon
|
8
|
+
def run cb
|
8
9
|
message = create_ptz_onvif_message
|
9
10
|
message.body = ->(xml) do
|
10
11
|
xml.wsdl(:GetNodes)
|
@@ -12,8 +13,24 @@ module ONVIF
|
|
12
13
|
send_message message do |success, result|
|
13
14
|
if success
|
14
15
|
xml_doc = Nokogiri::XML(result[:content])
|
15
|
-
|
16
|
-
|
16
|
+
ptz_nodes = []
|
17
|
+
xml_doc.xpath('//tptz:PTZNode').each do |preset_token|
|
18
|
+
ptz_node = {
|
19
|
+
name: value(preset_token, "tt:Name"),
|
20
|
+
token: attribute(preset_token, "token")
|
21
|
+
}
|
22
|
+
ptz_node = get_space_muster(preset_token, "SupportedPTZSpaces", ptz_node)
|
23
|
+
ptz_node[:maximum_number_of_presets] = value(preset_token, "tt:MaximumNumberOfPresets")
|
24
|
+
ptz_node[:home_supported] = value(preset_token, "tt:HomeSupported")
|
25
|
+
unless preset_token.at_xpath("tt:AuxiliaryCommands").nil?
|
26
|
+
ptz_node[:auxiliary_commands] = []
|
27
|
+
preset_token.xpath("tt:AuxiliaryCommands").each do |command|
|
28
|
+
ptz_node[:auxiliary_commands] << command.content
|
29
|
+
end
|
30
|
+
end
|
31
|
+
ptz_nodes << ptz_node
|
32
|
+
end
|
33
|
+
callback cb, success, ptz_nodes
|
17
34
|
else
|
18
35
|
callback cb, success, result
|
19
36
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
require_relative '../helper/ptz_common'
|
3
|
+
|
4
|
+
module ONVIF
|
5
|
+
module PtzAction
|
6
|
+
class GetPresets < Action
|
7
|
+
include PtzCommon #get_speed()
|
8
|
+
# p_token 的结构
|
9
|
+
# p_token = "xxxxx" //[ReferenceToken] A reference to the MediaProfile where the operation should take place.
|
10
|
+
def run p_token, cb
|
11
|
+
message = create_ptz_onvif_message
|
12
|
+
message.body = ->(xml) do
|
13
|
+
xml.wsdl(:GetPresets) do
|
14
|
+
xml.wsdl :ProfileToken, p_token
|
15
|
+
end
|
16
|
+
end
|
17
|
+
send_message message do |success, result|
|
18
|
+
if success
|
19
|
+
xml_doc = Nokogiri::XML(result[:content])
|
20
|
+
presets = []
|
21
|
+
xml_doc.xpath('//tptz:Preset').each do |node|
|
22
|
+
preset = {
|
23
|
+
name: value(node, 'tt:Name'),
|
24
|
+
token: attribute(node, "token")
|
25
|
+
}
|
26
|
+
preset = get_speed node, "PTZPosition", preset
|
27
|
+
presets << preset
|
28
|
+
end
|
29
|
+
callback cb, success, presets
|
30
|
+
else
|
31
|
+
callback cb, success, result
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
|
3
|
+
module ONVIF
|
4
|
+
module PtzAction
|
5
|
+
class GotoHomePosition < Action
|
6
|
+
# options 的结构
|
7
|
+
# {
|
8
|
+
# profile_token: "xxxxxxx",//[ReferenceToken] A reference to the MediaProfile where the operation should take place.
|
9
|
+
# speed: { //optional
|
10
|
+
# pan_tilt: { //optional
|
11
|
+
# x: 1, //[float]
|
12
|
+
# y: 2, //[float]
|
13
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace", //[anyURI]
|
14
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace
|
15
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace
|
16
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace
|
17
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace
|
18
|
+
# },
|
19
|
+
# zoom: { //optional
|
20
|
+
# x: 1,//[float]
|
21
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace",//[anyURI]
|
22
|
+
# }
|
23
|
+
# }
|
24
|
+
# }
|
25
|
+
def run options, cb
|
26
|
+
message = create_ptz_onvif_message
|
27
|
+
message.body = ->(xml) do
|
28
|
+
xml.wsdl(:GotoHomePosition) do
|
29
|
+
xml.wsdl :ProfileToken, options[:profile_token]
|
30
|
+
unless options[:speed].nil?
|
31
|
+
xml.wsdl(:Speed) do
|
32
|
+
unless options[:speed][:pan_tilt].nil?
|
33
|
+
xml.wsdl :PanTilt, {
|
34
|
+
"x" => options[:speed][:pan_tilt][:x],
|
35
|
+
"y" => options[:speed][:pan_tilt][:y],
|
36
|
+
"space" => options[:speed][:pan_tilt][:space]
|
37
|
+
}
|
38
|
+
end
|
39
|
+
unless options[:speed][:zoom].nil?
|
40
|
+
xml.wsdl :Zoom, {
|
41
|
+
"x" => options[:speed][:zoom][:x],
|
42
|
+
"space" => options[:speed][:zoom][:space]
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
send_message message do |success, result|
|
50
|
+
callback cb, success, result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
|
3
|
+
module ONVIF
|
4
|
+
module PtzAction
|
5
|
+
class GotoPreset < Action
|
6
|
+
# options 的结构
|
7
|
+
# {
|
8
|
+
# profile_token: "xxxxxxx",//[ReferenceToken] A reference to the MediaProfile where the operation should take place.
|
9
|
+
# preset_token: "xxxxxx", //[ReferenceToken] A requested preset token.
|
10
|
+
# speed: { //optional
|
11
|
+
# pan_tilt: { //optional
|
12
|
+
# x: 1, //[float]
|
13
|
+
# y: 2, //[float]
|
14
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace", //[anyURI]
|
15
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace
|
16
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace
|
17
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace
|
18
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace
|
19
|
+
# },
|
20
|
+
# zoom: { //optional
|
21
|
+
# x: 1,//[float]
|
22
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace",//[anyURI]
|
23
|
+
# }
|
24
|
+
# }
|
25
|
+
# }
|
26
|
+
def run options, cb
|
27
|
+
message = create_ptz_onvif_message
|
28
|
+
message.body = ->(xml) do
|
29
|
+
xml.wsdl(:GotoPreset) do
|
30
|
+
xml.wsdl :ProfileToken, options[:profile_token]
|
31
|
+
xml.wsdl :PresetToken, options[:preset_token]
|
32
|
+
unless options[:speed].nil?
|
33
|
+
xml.wsdl(:Speed) do
|
34
|
+
unless options[:speed][:pan_tilt].nil?
|
35
|
+
xml.wsdl :PanTilt, {
|
36
|
+
"x" => options[:speed][:pan_tilt][:x],
|
37
|
+
"y" => options[:speed][:pan_tilt][:y],
|
38
|
+
"space" => options[:speed][:pan_tilt][:space]
|
39
|
+
}
|
40
|
+
end
|
41
|
+
unless options[:speed][:zoom].nil?
|
42
|
+
xml.wsdl :Zoom, {
|
43
|
+
"x" => options[:speed][:zoom][:x],
|
44
|
+
"space" => options[:speed][:zoom][:space]
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
send_message message do |success, result|
|
52
|
+
callback cb, success, result
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
|
3
|
+
module ONVIF
|
4
|
+
module PtzAction
|
5
|
+
class GotoHomePosition < Action
|
6
|
+
# options 的结构
|
7
|
+
# {
|
8
|
+
# profile_token: "xxxxxxx",//[ReferenceToken] A reference to the MediaProfile where the operation should take place.
|
9
|
+
# translation: {
|
10
|
+
# pan_tilt: { //optional
|
11
|
+
# x: 1, //[float]
|
12
|
+
# y: 2, //[float]
|
13
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace", //[anyURI]
|
14
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace
|
15
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace
|
16
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace
|
17
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace
|
18
|
+
# },
|
19
|
+
# zoom: { //optional
|
20
|
+
# x: 1,//[float]
|
21
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace",//[anyURI]
|
22
|
+
# }
|
23
|
+
# }
|
24
|
+
# speed: { //optional
|
25
|
+
# pan_tilt: { //optional
|
26
|
+
# x: 1, //[float]
|
27
|
+
# y: 2, //[float]
|
28
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace", //[anyURI]
|
29
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace
|
30
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace
|
31
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace
|
32
|
+
# // http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace
|
33
|
+
# },
|
34
|
+
# zoom: { //optional
|
35
|
+
# x: 1,//[float]
|
36
|
+
# space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace",//[anyURI]
|
37
|
+
# }
|
38
|
+
# }
|
39
|
+
# }
|
40
|
+
def run options, cb
|
41
|
+
message = create_ptz_onvif_message
|
42
|
+
message.body = ->(xml) do
|
43
|
+
xml.wsdl(:GotoHomePosition) do
|
44
|
+
xml.wsdl :ProfileToken, options[:profile_token]
|
45
|
+
xml.wsdl(:Translation) do
|
46
|
+
unless options[:translation][:pan_tilt].nil?
|
47
|
+
xml.wsdl :PanTilt, {
|
48
|
+
"x" => options[:translation][:pan_tilt][:x],
|
49
|
+
"y" => options[:translation][:pan_tilt][:y],
|
50
|
+
"space" => options[:translation][:pan_tilt][:space]
|
51
|
+
}
|
52
|
+
end
|
53
|
+
unless options[:translation][:zoom].nil?
|
54
|
+
xml.wsdl :Zoom, {
|
55
|
+
"x" => options[:translation][:zoom][:x],
|
56
|
+
"space" => options[:translation][:zoom][:space]
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
unless options[:speed].nil?
|
61
|
+
xml.wsdl(:Speed) do
|
62
|
+
unless options[:speed][:pan_tilt].nil?
|
63
|
+
xml.wsdl :PanTilt, {
|
64
|
+
"x" => options[:speed][:pan_tilt][:x],
|
65
|
+
"y" => options[:speed][:pan_tilt][:y],
|
66
|
+
"space" => options[:speed][:pan_tilt][:space]
|
67
|
+
}
|
68
|
+
end
|
69
|
+
unless options[:speed][:zoom].nil?
|
70
|
+
xml.wsdl :Zoom, {
|
71
|
+
"x" => options[:speed][:zoom][:x],
|
72
|
+
"space" => options[:speed][:zoom][:space]
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
send_message message do |success, result|
|
80
|
+
callback cb, success, result
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
|
3
|
+
module ONVIF
|
4
|
+
module PtzAction
|
5
|
+
class RemovePreset < Action
|
6
|
+
# options 的结构
|
7
|
+
# {
|
8
|
+
# profile_token: "xxxxxxx", //[ReferenceToken] A reference to the MediaProfile where the operation should take place.
|
9
|
+
# preset_token: "xxxxxxx" //[ReferenceToken] A requested preset token.
|
10
|
+
# }
|
11
|
+
def run options ,cb
|
12
|
+
message = create_ptz_onvif_message
|
13
|
+
message.body = ->(xml) do
|
14
|
+
xml.wsdl(:RemovePreset) do
|
15
|
+
xml.wsdl :ProfileToken, options[:profile_token]
|
16
|
+
xml.wsdl :PresetToken, options[:preset_token]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
send_message message do |success, result|
|
20
|
+
callback cb, success, result
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative '../action'
|
2
|
+
|
3
|
+
module ONVIF
|
4
|
+
module PtzAction
|
5
|
+
class SetPreset < Action
|
6
|
+
# options 的结构
|
7
|
+
# {
|
8
|
+
# profile_token: "xxxxxxx", //[ReferenceToken] A reference to the MediaProfile where the operation should take place.
|
9
|
+
# preset_name: "xxxxx", // optional; [string] A requested preset name.
|
10
|
+
# preset_token: "xxxxxxx" //optional; [ReferenceToken] A requested preset token.
|
11
|
+
# }
|
12
|
+
def run options ,cb
|
13
|
+
message = create_ptz_onvif_message
|
14
|
+
message.body = ->(xml) do
|
15
|
+
xml.wsdl(:SetPreset) do
|
16
|
+
xml.wsdl :ProfileToken, options[:profile_token]
|
17
|
+
xml.wsdl :PresetName, options[:preset_name] unless options[:preset_name].nil?
|
18
|
+
xml.wsdl :PresetToken, options[:preset_token] unless options[:preset_token].nil?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
send_message message do |success, result|
|
22
|
+
if success
|
23
|
+
xml_doc = Nokogiri::XML(result[:content])
|
24
|
+
preset_token = value(xml_doc, '//tptz:PresetToken')
|
25
|
+
callback cb, success, preset_token
|
26
|
+
else
|
27
|
+
callback cb, success, result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/ruby-onvif-client.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_onvif_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jimxl
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: em_ws_discovery
|
@@ -86,9 +86,20 @@ files:
|
|
86
86
|
- lib/ruby_onvif_client/client.rb
|
87
87
|
- lib/ruby_onvif_client/message.rb
|
88
88
|
- lib/ruby_onvif_client/path.rb
|
89
|
+
- lib/ruby_onvif_client/ptz/goto_home_position.rb
|
90
|
+
- lib/ruby_onvif_client/ptz/remove_preset.rb
|
91
|
+
- lib/ruby_onvif_client/ptz/set_preset.rb
|
89
92
|
- lib/ruby_onvif_client/ptz/get_nodes.rb
|
93
|
+
- lib/ruby_onvif_client/ptz/goto_preset.rb
|
94
|
+
- lib/ruby_onvif_client/ptz/get_configuration.rb
|
90
95
|
- lib/ruby_onvif_client/ptz/stop.rb
|
96
|
+
- lib/ruby_onvif_client/ptz/continuous_move.rb
|
97
|
+
- lib/ruby_onvif_client/ptz/relative_move.rb
|
98
|
+
- lib/ruby_onvif_client/ptz/get_configurations.rb
|
99
|
+
- lib/ruby_onvif_client/ptz/get_presets.rb
|
100
|
+
- lib/ruby_onvif_client/ptz/get_configuration_options.rb
|
91
101
|
- lib/ruby_onvif_client/ptz/get_node.rb
|
102
|
+
- lib/ruby_onvif_client/ptz/absolute_move.rb
|
92
103
|
- lib/ruby_onvif_client/device_management.rb
|
93
104
|
- lib/ruby_onvif_client/media.rb
|
94
105
|
- lib/ruby_onvif_client/media/get_video_encoder_configuration.rb
|
@@ -104,6 +115,7 @@ files:
|
|
104
115
|
- lib/ruby_onvif_client/media/set_video_encoder_configuration.rb
|
105
116
|
- lib/ruby_onvif_client/media/get_video_encoder_configurations.rb
|
106
117
|
- lib/ruby_onvif_client/media/get_stream_uri.rb
|
118
|
+
- lib/ruby_onvif_client/helper/ptz_common.rb
|
107
119
|
- lib/ruby_onvif_client/action.rb
|
108
120
|
- lib/ruby_onvif_client/ptz.rb
|
109
121
|
- lib/ruby_onvif_client/device_discovery.rb
|