hik_ISAPI 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c238cc614d5f6b9b3c124405d90096f0b33f5cb00401a3f291bebd6151c293a8
4
+ data.tar.gz: 0c404fce16b367a021c1a1e6e732bf4899b3b6d06a4320192a3d73e2d0e72cb1
5
+ SHA512:
6
+ metadata.gz: 3e97136d972327a68d62570162938d8eb66339d9357851124fff6a46662c635970809b1662cea396c923f62b29cf67b3262f0a2abd42cab9ecc5e25b6c3e2284
7
+ data.tar.gz: d3ed39978f2906cfbe3f96806fdb853e86feec7b3dc4b04f979c4fa2277446182fd9e6a79ec4a5f97512aaa093386cbb6a95c9456876e3e1c9f7ec6cbc8e714e
data/exe/hikvision ADDED
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'hikvision'
4
+ require 'gli'
5
+
6
+ class Numeric
7
+ def duration
8
+ secs = to_i
9
+ mins = secs / 60
10
+ hours = mins / 60
11
+ days = hours / 24
12
+
13
+ "#{days} days #{hours % 24} hours #{mins % 60} minutes #{secs % 60} seconds"
14
+ end
15
+ end
16
+
17
+ class App
18
+ extend GLI::App
19
+
20
+ def self.print_kv(key, value, opts)
21
+ puts "#{opts[:'with-keys'] ? key.to_s + ': ' : ''}#{value}" if opts[key]
22
+ end
23
+
24
+ def self.set_if_in_opts(obj, setter, val, opts)
25
+ return if val.nil?
26
+
27
+ if opts.include? val
28
+ obj.send(setter, val)
29
+ else
30
+ exit_now! "\"#{val}\" is invalid, choose from: #{opts.join(', ')}", 1
31
+ end
32
+ end
33
+
34
+ flag %i[h host], required: true
35
+ flag %i[u user], required: true
36
+ flag %i[p password], required: true
37
+
38
+ version Hikvision::VERSION
39
+
40
+ pre do |gopts, _opts, _args|
41
+ @dev = Hikvision::ISAPI.new(gopts[:h], gopts[:u], gopts[:p])
42
+ exit_now! 'could not authenticate' if @dev.put('/ISAPI/Security/sessionHeartbeat').response.code == '401'
43
+ 1
44
+ end
45
+
46
+ command :uptime do |c|
47
+ c.action do
48
+ puts @dev.system.uptime.duration
49
+ end
50
+ end
51
+
52
+ command :date do |c|
53
+ c.flag :strftime, default_value: '%c'
54
+ c.action do |_gopts, opts, _args|
55
+ puts @dev.system.time.now.strftime opts[:strftime].to_s
56
+ end
57
+ end
58
+
59
+ desc 'Configurate time settings'
60
+ command :time do |c|
61
+ c.flag :"set-ntp", arg_name: 'host'
62
+ c.flag :"set-ntp-port", type: Integer, arg_name: 'port'
63
+ c.flag :"set-mode", must_match: %w[manual ntp], arg_name: 'ntp,manual'
64
+ c.switch :ntp, negatable: false
65
+ c.switch :"ntp-port", negatable: false
66
+ c.switch :mode, negatable: false
67
+
68
+ c.action do |_gopts, opts, _args|
69
+ ntp_edited = false
70
+ %i[set-ntp set-ntp-port].each do |key|
71
+ if opts[key]
72
+ ntp_edited = true
73
+ break
74
+ end
75
+ end
76
+
77
+ time =@dev.system.time
78
+ ntp = time.ntp
79
+
80
+ print_kv :ntp, ntp.host, opts
81
+ print_kv :"ntp-port", ntp.port, opts
82
+
83
+ ntp.host = opts[:"set-ntp"] if opts[:"set-ntp"]
84
+ ntp.port = opts[:"set-ntp-port"] if opts[:"set-ntp-port"]
85
+
86
+ ntp.update if ntp_edited
87
+
88
+ edited = false
89
+ [:"set-mode"].each do |key|
90
+ if opts[key]
91
+ edited = true
92
+ break
93
+ end
94
+ end
95
+
96
+ print_kv :mode, time.mode.to_s.downcase, opts
97
+
98
+ time.mode = opts[:"set-mode"] == 'ntp' ? :NTP : :manual if opts[:"set-mode"]
99
+
100
+ time.update if edited
101
+
102
+ if ntp_edited and time.mode == :manual
103
+ puts 'ntp settings altered but the device time mode is set to manual. please run with "--set-mode ntp" to set the time mode to ntp'
104
+ end
105
+ end
106
+ end
107
+
108
+ command :model do |c|
109
+ c.action do
110
+ puts @dev.system.model
111
+ end
112
+ end
113
+
114
+ command :serial do |c|
115
+ c.action do
116
+ puts @dev.system.serial
117
+ end
118
+ end
119
+
120
+ desc 'Shows the device id'
121
+ command :id do |c|
122
+ c.action do
123
+ puts @dev.system.id
124
+ end
125
+ end
126
+
127
+ desc 'Shows the device description'
128
+ command :desc do |c|
129
+ c.action do
130
+ puts @dev.system.description
131
+ end
132
+ end
133
+
134
+ command :mac do |c|
135
+ c.action do
136
+ puts @dev.system.mac_address
137
+ end
138
+ end
139
+
140
+ command :reboot do |c|
141
+ c.action do
142
+ @dev.system.reboot
143
+ end
144
+ end
145
+
146
+ desc 'List available channels'
147
+ command :channels do |c|
148
+ c.action do
149
+ puts @dev.streaming.channels.collect { |ch| ch.id }
150
+ end
151
+ end
152
+
153
+ desc 'Dumps device diagnosed data'
154
+ command :dumpdata do |c|
155
+ c.action do
156
+ puts @dev.system.diagnosed_data
157
+ end
158
+ end
159
+
160
+ command :channel do |c|
161
+ c.flag :'save-picture', arg_name: 'file', desc: 'saves picture to file'
162
+ c.flag :'set-video-codec', desc: 'sets channel video codec'
163
+ c.switch :'video-codec', negatable: false, desc: 'prints channel video codec'
164
+ c.flag :'set-audio-codec', desc: 'sets channel audio codec'
165
+ c.switch :'audio-codec', negatable: false, desc: 'prints channel audio codec'
166
+ c.switch :'disable-audio', negatable: false, desc: 'disables channel audio'
167
+ c.switch :'enable-audio', negatable: false, desc: 'enabled channel audio'
168
+ c.switch :'video-resolution', negatable: false, desc: 'prints channel video resolution'
169
+ c.switch :'video-framerate', negatable: false, desc: 'prints channel video framerate'
170
+ c.switch :'video-keyframe-interval', negatable: false, desc: 'prints channel keyframe interval'
171
+ c.switch :'video-cbr', negatable: false, desc: 'prints channel video constant bitrate value'
172
+ c.switch :'video-bitrate-type', negatable: false, desc: 'prints channel video bitrate type'
173
+ c.switch :'video-scan-type', negatable: false, desc: 'prints channel video scan type'
174
+ c.switch :'video-enabled', negatable: false, desc: 'prints if channel video is enabled'
175
+ c.switch :'audio-enabled', negatable: false, desc: 'prints if channel audio is enabled'
176
+ c.switch :enabled, negatable: false, desc: 'prints if channel is enabled'
177
+ c.switch :name, negatable: false, desc: 'prints channel name'
178
+ c.flag :'set-name', desc: 'sets channel name'
179
+ c.switch :all, negatable: false, desc: 'prints all possible information'
180
+ c.switch :'with-keys', negatable: false, desc: 'prints values with keys'
181
+
182
+ c.action do |_gopts, opts, args|
183
+ exit_now! "missing id\nusage: channel <id> [opts]", 1 if args.length != 1
184
+ id = args[0]
185
+ exit_now! 'channel id must be an integer', 1 if id.to_i.to_s != id
186
+ id = id.to_i
187
+ ch = @dev.streaming.channel(id)
188
+ exit_now! "channel id doesn't exists", 1 if ch.nil?
189
+
190
+ set_opts = %i[set-name set-video-codec set-audio-codec disable-audio enable-audio]
191
+
192
+ if opts[:all]
193
+ opts.each do |key|
194
+ next if (%w[with-keys save-picture] + set_opts.map { |o| o.to_s }).include? key[0].to_s
195
+
196
+ opts[key[0]] = true
197
+ end
198
+ end
199
+
200
+ if opts[:'save-picture']
201
+ file = File.open(opts[:'save-picture'], 'w+b')
202
+ file.write(ch.picture)
203
+ file.close
204
+ end
205
+
206
+ print_kv :name, ch.name, opts
207
+ print_kv :enabled, ch.enabled?, opts
208
+ print_kv :'video-enabled', ch.video_enabled?, opts
209
+ print_kv :'video-codec', ch.video_codec, opts
210
+ print_kv :'video-framerate', ch.video_framerate, opts
211
+ print_kv :'video-resolution', ch.video_resolution.collect { |r| r.to_s }.join('x'), opts
212
+ print_kv :'video-keyframe-interval', ch.video_keyframe_interval, opts
213
+ print_kv :'video-bitrate-type', ch.video_bitrate_type, opts
214
+ print_kv :'video-cbr', ch.video_cbitrate, opts
215
+ print_kv :'video-scan-type', ch.video_scan_type, opts
216
+ print_kv :'audio-enabled', ch.audio_enabled?, opts
217
+ print_kv :'audio-codec', ch.audio_codec, opts
218
+
219
+ edited = false
220
+ set_opts.each do |k|
221
+ next unless opts[k]
222
+
223
+ edited = true
224
+ break
225
+ end
226
+
227
+ ch.name = opts[:'set-name'] if opts[:'set-name']
228
+ set_if_in_opts(ch, :video_codec=, opts[:'set-video-codec'], ch.video_codec_opts)
229
+ set_if_in_opts(ch, :audio_codec=, opts[:'set-audio-codec'], ch.audio_codec_opts)
230
+ set_if_in_opts(ch, :audio_enabled=, false, [false]) if opts[:'disable-audio']
231
+ set_if_in_opts(ch, :audio_enabled=, true, [true]) if opts[:'enable-audio']
232
+
233
+ ch.update if edited
234
+ end
235
+ end
236
+ end
237
+
238
+ exit App.run(ARGV)
@@ -0,0 +1,82 @@
1
+ module Hikvision
2
+ class Base
3
+ class << self
4
+ private
5
+
6
+ def add_xml(method, url_path)
7
+ iv = :"@#{method}_xml"
8
+ load_method = :"load_#{method}"
9
+ define_method load_method do |options = {}|
10
+ return instance_variable_get(iv) if options.fetch(:cache, true) && instance_variable_defined?(iv)
11
+
12
+ url = url_path.respond_to?(:call) ? instance_exec(&url_path) : url_path
13
+ instance_variable_set(iv, @isapi.get_xml(url, options))
14
+ end
15
+
16
+ reload_method = method == :base ? :reload : :"reload_#{method}"
17
+ define_method reload_method do |options = {}|
18
+ send(load_method, options.merge(cache: false))
19
+ end
20
+ end
21
+
22
+ def add_getter(method, xml_method, path, opts = { cache: true }, &block)
23
+ define_method method do
24
+ v = send(:"load_#{xml_method}", opts).at_xpath(path).inner_html
25
+ v = block.call(v) if block
26
+ v
27
+ end
28
+ end
29
+
30
+ def add_list_getter(method, xml_method, path, opts = { cache: true }, &block)
31
+ define_method method do
32
+ send(:"load_#{xml_method}", opts).xpath(path).map do |v|
33
+ v = v.inner_html
34
+ v = block.call(v) if block
35
+ v
36
+ end
37
+ end
38
+ end
39
+
40
+ def add_opt_getter(method, xml_method, path, transform = nil, &block)
41
+ define_method method do
42
+ send(:"load_#{xml_method}", cache: true).at_xpath(path)[:opt].split(',').map do |v|
43
+ v = v.send(transform) if transform
44
+ v = block.call(v) if block
45
+ v
46
+ end
47
+ end
48
+ end
49
+
50
+ def add_opt_range_getter(method, xml_method, path)
51
+ define_method method do
52
+ data = send(:"load_#{xml_method}", cache: true).at_xpath(path)
53
+ data[:min].to_i..data[:max].to_i
54
+ end
55
+ end
56
+
57
+ def add_bool_getter(method, xml_method, path)
58
+ add_getter(method, xml_method, path) { |v| v == 'true' }
59
+ end
60
+
61
+ def add_setter(method, xml_method, path, *types, &block)
62
+ update_method = xml_method == :base ? :update : :"update_#{xml_method}"
63
+
64
+ if not respond_to? update_method
65
+ define_method update_method do |options = {}|
66
+ send(:"before_#{update_method}") if respond_to? :"before_#{update_method}"
67
+
68
+ options[:body] = instance_variable_get(:"@#{xml_method}_xml").to_s
69
+ @isapi.put_xml(respond_to?(:url) ? send(:url) : self.class.url, options)
70
+ end
71
+ end
72
+
73
+ define_method method do |value|
74
+ raise TypeError, "#{method}#{value} (#{value.class}) must be of type #{types}" unless types.any? { |k| value.is_a?(k) }
75
+
76
+ value = block.call(value) if block
77
+ send(:"load_#{xml_method}", cache: true).at_xpath(path).inner_html = value.to_s
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,93 @@
1
+ require 'httparty'
2
+ require 'nokogiri'
3
+
4
+ module Hikvision
5
+ class ResponseError < RuntimeError
6
+ def initialize(xml)
7
+ @xml = xml
8
+ super(status_string)
9
+ end
10
+
11
+ def status_code
12
+ @xml.at_xpath('ResponseStatus/statusCode').inner_html.to_i
13
+ end
14
+
15
+ def status_string
16
+ @xml.at_xpath('ResponseStatus/statusString').inner_html
17
+ end
18
+
19
+ def sub_status_code
20
+ @xml.at_xpath('ResponseStatus/subStatusCode').inner_html
21
+ end
22
+ end
23
+
24
+ class ISAPI
25
+ include HTTParty
26
+
27
+ attr_accessor :cache
28
+ attr_reader :streaming, :system
29
+
30
+ def initialize(ip, username, password, args = { auth_type: 'digest_auth', https: false })
31
+ @cache = {}
32
+ @auth_type = args[:auth_type]
33
+ @base_uri = "http#{args[:https] ? 's' : ''}://#{ip}"
34
+ @auth = { username: username, password: password }
35
+ @streaming = Hikvision::Streaming.new(self)
36
+ @system = Hikvision::System.new(self)
37
+ end
38
+
39
+ def get(path, options = {})
40
+ options = default_request_options.merge(options)
41
+ if @cache.has_key?(path) and options.fetch(:cache, true)
42
+ @cache[path]
43
+ else
44
+ @cache[path] = self.class.get(@base_uri + path, options)
45
+ end
46
+ end
47
+
48
+ def get_original(path, options = {})
49
+ options = default_request_options.merge(options)
50
+ if @cache.has_key?(path) and options.fetch(:cache, true)
51
+ @cache[path]
52
+ else
53
+ @cache[path] = self.class.get(path, options)
54
+ end
55
+ end
56
+
57
+ def get_xml(path, options = {})
58
+ data = get(path, options)
59
+ raise "could not get xml of #{path} code:#{data.response.code}" unless ['200'].include?(data.response.code)
60
+
61
+ Nokogiri::XML(data.body).remove_namespaces!
62
+ end
63
+
64
+ def put(path, options = {})
65
+ @cache.delete(path)
66
+ options = default_request_options.merge(options)
67
+ self.class.put(@base_uri + path, options)
68
+ end
69
+
70
+ def post(path, options = {})
71
+ @cache.delete(path)
72
+ options = default_request_options.merge(options)
73
+ self.class.post(@base_uri + path, options)
74
+ end
75
+
76
+ def put_xml(path, options = {})
77
+ data = put(path, options)
78
+
79
+ return true if data.response.code == '200'
80
+
81
+ xml = Nokogiri::XML(data.body).remove_namespaces!
82
+ raise ResponseError, xml
83
+ end
84
+
85
+ private
86
+
87
+ def default_request_options
88
+ {
89
+ "#{@auth_type}": @auth
90
+ }
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,111 @@
1
+ module Hikvision
2
+ class Streaming
3
+ class Channel < Hikvision::Base
4
+ def initialize(isapi, xml)
5
+ @isapi = isapi
6
+ @base_xml = xml
7
+ end
8
+
9
+ add_xml(:base, -> { url })
10
+ add_xml(:capabilities, -> { "#{url}/capabilities" })
11
+
12
+ add_getter(:id, :base, '//id', &:to_i)
13
+
14
+ add_getter(:name, :base, '//channelName')
15
+ add_setter(:name=, :base, '//channelName', String)
16
+ add_opt_range_getter(:name_length_opts, :capabilities, '//channelName')
17
+
18
+ add_getter(:max_packet_size, :base, '//Transport/maxPacketSize', &:to_i)
19
+
20
+ add_getter(:auth_type, :base, '//Transport/Security/certificateType')
21
+ add_setter(:auth_type=, :base, '//Transport/Security/certificateType', String)
22
+ add_opt_getter(:auth_type_opts, :capabilities, '//Transport/Security/certificateType', :to_s)
23
+
24
+ add_getter(:video_framerate, :base, '//Video/maxFrameRate') { |v| v.to_f / 100 }
25
+ add_setter(:video_framerate=, :base, '//Video/maxFrameRate', Numeric) { |v| (v * 100).to_i }
26
+ add_opt_getter(:video_framerate_opts, :capabilities, '//Video/maxFrameRate', :to_f) { |v| v / 100 }
27
+
28
+ add_getter(:video_width, :base, '//videoResolutionWidth', &:to_i)
29
+ add_setter(:video_width=, :base, '//videoResolutionWidth', Integer)
30
+ add_opt_getter(:video_width_opts, :capabilities, '//videoResolutionWidth', :to_i)
31
+
32
+ add_getter(:video_height, :base, '//videoResolutionHeight', &:to_i)
33
+ add_setter(:video_height=, :base, '//videoResolutionHeight', Integer)
34
+ add_opt_getter(:video_height_opts, :capabilities, '//videoResolutionHeight', :to_i)
35
+
36
+ add_getter(:video_cbitrate, :base, '//Video/constantBitRate', &:to_i)
37
+ add_setter(:video_cbitrate=, :base, '//Video/constantBitRate', Integer)
38
+ add_opt_range_getter(:video_cbitrate_opts, :capabilities, '//Video/constantBitRate')
39
+
40
+ add_getter(:video_vbitrate_upper_cap, :base, '//Video/vbrUpperCap', &:to_i)
41
+ add_setter(:video_vbitrate_upper_cap=, :base, '//Video/vbrUpperCap', Integer)
42
+ add_opt_range_getter(:video_vbitrate_upper_cap_opts, :capabilities, '//Video/vbrUpperCap')
43
+
44
+ add_getter(:video_keyframe_interval, :base, '//Video/keyFrameInterval') { |v| v.to_i / 1000 }
45
+ add_setter(:video_keyframe_interval=, :base, '//Video/keyFrameInterval', Numeric) { |v| (v * 1000).to_i }
46
+ add_opt_range_getter(:video_keyframe_interval_opts, :capabilities, '//Video/keyFrameInterval')
47
+
48
+ add_getter(:video_codec, :base, '//videoCodecType')
49
+ add_setter(:video_codec=, :base, '//videoCodecType', String)
50
+ add_opt_getter(:video_codec_opts, :capabilities, '//videoCodecType', :to_s)
51
+
52
+ add_getter(:video_bitrate_type, :base, '//videoQualityControlType')
53
+ add_setter(:video_bitrate_type=, :base, '//videoQualityControlType', String)
54
+ add_opt_getter(:video_bitrate_type_opts, :capabilities, '//videoQualityControlType', :to_s)
55
+
56
+ add_getter(:video_scan_type, :base, '//videoScanType')
57
+ add_setter(:video_scan_type=, :base, '//videoScanType', String)
58
+ add_opt_getter(:video_scan_type_opts, :capabilities, '//videoScanType', :to_s)
59
+
60
+ add_getter(:snapshot_image_type, :base, '//snapShotImageType')
61
+ add_setter(:snapshot_image_type=, :base, '//snapShotImageType', String)
62
+ add_opt_getter(:snapshot_image_type_opts, :capabilities, '//snapShotImageType', :to_s)
63
+
64
+ add_getter(:audio_codec, :base, '//audioCompressionType')
65
+ add_setter(:audio_codec=, :base, '//audioCompressionType', String)
66
+ add_opt_getter(:audio_codec_opts, :capabilities, '//audioCompressionType', :to_s)
67
+
68
+ add_getter(:video_smoothing, :base, '//Video/smoothing', &:to_i)
69
+ add_opt_range_getter(:video_smoothing_opts, :capabilities, '//Video/smoothing')
70
+
71
+ add_bool_getter(:audio_enabled?, :base, '//Audio/enabled')
72
+ add_setter(:audio_enabled=, :base, '//Audio/enabled', TrueClass, FalseClass)
73
+
74
+ add_bool_getter(:svc_enabled?, :base, '//Video/SVC/enabled')
75
+ add_setter(:svc_enabled=, :base, '//Video/SVC/enabled', TrueClass, FalseClass)
76
+
77
+ add_bool_getter(:enabled?, :base, '/StreamingChannel/enabled')
78
+ add_bool_getter(:video_enabled?, :base, '//Video/enabled')
79
+ add_bool_getter(:multicast_enabled?, :base, '//Transport/Multicast/enabled')
80
+ add_bool_getter(:unicast_enabled?, :base, '//Transport/Unicast/enabled')
81
+ add_bool_getter(:security_enabled?, :base, '//Transport/Security/enabled')
82
+
83
+ def video_resolution
84
+ [video_width, video_height]
85
+ end
86
+
87
+ def video_resolution=(value)
88
+ video_width = value[0]
89
+ video_height = value[1]
90
+ end
91
+
92
+ def video_resolution_opts
93
+ video_width_opts.zip(video_height_opts)
94
+ end
95
+
96
+ def picture(options = { cache: false })
97
+ @isapi.get("#{url}/picture", options).response.body
98
+ end
99
+
100
+ def url
101
+ "/ISAPI/Streaming/channels/#{id}"
102
+ end
103
+
104
+ private
105
+
106
+ def before_update
107
+ @isapi.cache.delete('/ISAPI/Streaming/channels')
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,27 @@
1
+ module Hikvision
2
+ class Streaming
3
+ def initialize(isapi)
4
+ @isapi = isapi
5
+ end
6
+
7
+ def channels
8
+ load_channels.values
9
+ end
10
+
11
+ def channel(id)
12
+ load_channels[id]
13
+ end
14
+
15
+ def load_channels(options = {})
16
+ return @channels if options.fetch(:cache, true) && instance_variable_defined?(:@channels)
17
+
18
+ @channels = {}
19
+ xml = @isapi.get_xml('/ISAPI/Streaming/channels', options)
20
+ xml.xpath('StreamingChannelList/StreamingChannel').each do |c|
21
+ channel = Channel.new(@isapi, Nokogiri::XML(c.to_s))
22
+ @channels[channel.id] = channel
23
+ end
24
+ @channels
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ module Hikvision
2
+ class System
3
+ def get_event(options = { cache: false })
4
+ @isapi.post('/ISAPI/AccessControl/AcsEvent?format=json', options).response.body
5
+ end
6
+
7
+ # 保存刷脸照片
8
+ def get_event_photo(url, file_path, options = { cache: false })
9
+ file_content = @isapi.get_original(url, options).response.body
10
+ File.open(file_path, 'wb') do |f|
11
+ f.write(file_content)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module Hikvision
2
+ class System
3
+ add_xml(:device_info, '/ISAPI/System/deviceInfo')
4
+
5
+ add_getter(:name, :device_info, '//deviceName')
6
+ add_getter(:id, :device_info, '//deviceID')
7
+ add_getter(:description, :device_info, '//deviceDescription')
8
+ add_getter(:location, :device_info, '//deviceLocation')
9
+ add_getter(:model, :device_info, '//model')
10
+ add_getter(:serial, :device_info, '//serialNumber')
11
+ add_getter(:mac_address, :device_info, '//macAddress')
12
+ add_getter(:firmware_version, :device_info, '//firmwareVersion')
13
+ add_getter(:encoder_version, :device_info, '//encoderVersion')
14
+ add_getter(:boot_version, :device_info, '//bootVersion')
15
+ add_getter(:hardware_version, :device_info, '//hardwareVersion')
16
+ add_getter(:type, :device_info, '//deviceType')
17
+
18
+ add_bool_getter(:support_beep?, :device_info, '/DeviceInfo/supportBeep')
19
+ add_bool_getter(:support_video_loss?, :device_info, '/DeviceInfo/supportVideoLoss')
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ module Hikvision
2
+ class System
3
+ def diagnosed_data(options = { cache: false })
4
+ @isapi.get('/ISAPI/System/diagnosedData', options).response.body
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Hikvision
2
+ class System
3
+ def add_face(options = { cache: false })
4
+ @isapi.post('/ISAPI/Intelligent/FDLib/FaceDataRecord?format=json', options).response.body
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ module Hikvision
2
+ class Network
3
+ class Integration < Hikvision::Base
4
+ class << self
5
+ def url
6
+ "/ISAPI/System/Network/Integrate"
7
+ end
8
+ end
9
+
10
+ def initialize(isapi)
11
+ @isapi = isapi
12
+ end
13
+
14
+ add_xml(:base, url)
15
+
16
+ add_setter(:cgi=, :base, '//CGI/enable', TrueClass, FalseClass)
17
+
18
+ add_getter(:cgi_authentication, :base, '//CGI/certificateType') { |v| v.include?("basic") ? :basic : :digest }
19
+ add_setter(:cgi_authentication=, :base, '//CGI/certificateType', Symbol) { |v| v == :basic ? "digest/basic" : v.to_s }
20
+
21
+ add_bool_getter(:cgi?, :base, '//CGI/enable')
22
+ add_bool_getter(:onvif?, :base, '//ONVIF/enable')
23
+ add_bool_getter(:isapi?, :base, '//ISAPI/enable')
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ module Hikvision
2
+ class Network < Hikvision::Base
3
+ attr_reader :integration
4
+
5
+ def initialize(isapi)
6
+ @isapi = isapi
7
+ @integration = Integration.new(isapi)
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,11 @@
1
+ module Hikvision
2
+ class System
3
+ def add_person(options = { cache: false })
4
+ @isapi.post('/ISAPI/AccessControl/UserInfo/Record?format=json', options).response.body
5
+ end
6
+
7
+ def delete_person(options = { cache: false })
8
+ @isapi.put('/ISAPI/AccessControl/UserInfo/Delete?format=json', options).response.body
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module Hikvision
2
+ class System
3
+ def reboot
4
+ @isapi.put('/ISAPI/System/reboot')
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ module Hikvision
2
+ class System
3
+ add_xml(:status, '/ISAPI/System/status')
4
+
5
+ add_getter(:uptime, :status, '//deviceUpTime', { cache: false }, &:to_i)
6
+
7
+ add_list_getter(:memory_usage, :status, '//memoryUsage', { cache: false }, &:to_i)
8
+ add_list_getter(:memory_available, :status, '//memoryAvailable', { cache: false }, &:to_i)
9
+ add_list_getter(:memory_description, :status, '//memoryDescription')
10
+ add_list_getter(:cpu_utilization, :status, '//cpuUtilization', { cache: false }, &:to_i)
11
+ add_list_getter(:cpu_description, :status, '//cpuDescription')
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ module Hikvision
2
+ class System
3
+ class Time
4
+ class Ntp < Hikvision::Base
5
+ class << self
6
+ def url
7
+ '/ISAPI/System/time/ntpServers'
8
+ end
9
+ end
10
+
11
+ def initialize(isapi)
12
+ @isapi = isapi
13
+ end
14
+
15
+ add_xml(:base, url)
16
+
17
+ add_getter(:host, :base, '//hostName')
18
+ add_setter(:host=, :base, '//hostName', String)
19
+
20
+ add_getter(:sync_interval, :base, '//synchronizeInterval', &:to_i)
21
+ add_setter(:sync_interval=, :base, '//synchronizeInterval', Integer)
22
+
23
+ add_getter(:port, :base, '//portNo', &:to_i)
24
+ add_setter(:port=, :base, '//portNo', Integer)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ require 'time'
2
+
3
+ module Hikvision
4
+ class System
5
+ class Time < Hikvision::Base
6
+ attr_reader :ntp
7
+
8
+ class << self
9
+ def url
10
+ '/ISAPI/System/time'
11
+ end
12
+ end
13
+
14
+ def initialize(isapi)
15
+ @isapi = isapi
16
+ @ntp = Ntp.new(isapi)
17
+ end
18
+
19
+ add_xml(:base, url)
20
+
21
+ add_getter(:mode, :base, '//timeMode', &:to_sym)
22
+ add_setter(:mode=, :base, '//timeMode', Symbol, String)
23
+
24
+ add_getter(:now, :base, '//localTime', cache: false) { |v| Object::Time.strptime(v, '%Y-%m-%dT%H:%M:%S%Z') }
25
+ add_setter(:now=, :base, '//localTime', Object::Time) { |v| v.strftime('%Y-%m-%dT%H:%M:%S%Z') }
26
+
27
+ add_getter(:zone, :base, '//timeZone')
28
+ add_setter(:zone=, :base, '//timeZone', String)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ module Hikvision
2
+ class System < Hikvision::Base
3
+ attr_reader :network, :time
4
+
5
+ def initialize(isapi)
6
+ @isapi = isapi
7
+ @network = Network.new(isapi)
8
+ @time = Time.new(isapi)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module Hikvision
2
+ VERSION = '0.0.1'
3
+ end
data/lib/hikvision.rb ADDED
@@ -0,0 +1,17 @@
1
+ require_relative 'hikvision/version'
2
+ require_relative 'hikvision/base'
3
+ require_relative 'hikvision/isapi'
4
+ require_relative 'hikvision/streaming'
5
+ require_relative 'hikvision/streaming/channel'
6
+ require_relative 'hikvision/system'
7
+ require_relative 'hikvision/system/time'
8
+ require_relative 'hikvision/system/time/ntp'
9
+ require_relative 'hikvision/system/device_info'
10
+ require_relative 'hikvision/system/network'
11
+ require_relative 'hikvision/system/network/integration'
12
+ require_relative 'hikvision/system/reboot'
13
+ require_relative 'hikvision/system/diagnosed_data'
14
+ require_relative 'hikvision/system/status'
15
+ require_relative 'hikvision/system/acs_event'
16
+ require_relative 'hikvision/system/face'
17
+ require_relative 'hikvision/system/person'
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hik_ISAPI
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - guopipi
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-01-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gli
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.21'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.21'
27
+ - !ruby/object:Gem::Dependency
28
+ name: httparty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.21'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.21'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.14'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.14'
55
+ description:
56
+ email:
57
+ executables:
58
+ - hikvision
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - exe/hikvision
63
+ - lib/hikvision.rb
64
+ - lib/hikvision/base.rb
65
+ - lib/hikvision/isapi.rb
66
+ - lib/hikvision/streaming.rb
67
+ - lib/hikvision/streaming/channel.rb
68
+ - lib/hikvision/system.rb
69
+ - lib/hikvision/system/acs_event.rb
70
+ - lib/hikvision/system/device_info.rb
71
+ - lib/hikvision/system/diagnosed_data.rb
72
+ - lib/hikvision/system/face.rb
73
+ - lib/hikvision/system/network.rb
74
+ - lib/hikvision/system/network/integration.rb
75
+ - lib/hikvision/system/person.rb
76
+ - lib/hikvision/system/reboot.rb
77
+ - lib/hikvision/system/status.rb
78
+ - lib/hikvision/system/time.rb
79
+ - lib/hikvision/system/time/ntp.rb
80
+ - lib/hikvision/version.rb
81
+ homepage: https://github.com/guojhq/hik_ISAPI.git
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubygems_version: 3.2.33
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Ruby Hikvision ISAPI Interface
104
+ test_files: []