Skip to content

Commit c103c40

Browse files
Merge branch 'master' of github.com:ZoneMinder/zoneminder
2 parents 0d93742 + dc7d89b commit c103c40

50 files changed

Lines changed: 4098 additions & 2129 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

db/zm_create.sql.in

Lines changed: 45 additions & 42 deletions
Large diffs are not rendered by default.

db/zm_update-1.39.15.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--
2+
-- This updates a 1.39.14 database to 1.39.15
3+
--
4+
-- Add a control entry for the HiSilicon Hi3510 CGI PTZ protocol used by
5+
-- many inexpensive IP cameras (e.g. Tenvis TH661).
6+
--
7+
8+
INSERT INTO `Controls`
9+
(`Name`, `Type`, `Protocol`, `CanReset`, `HasPresets`, `NumPresets`, `CanSetPresets`,
10+
`CanMove`, `CanMoveDiag`, `CanMoveCon`, `CanPan`, `CanTilt`)
11+
SELECT 'HiSilicon Hi3510 CGI', 'Ffmpeg', 'HiSilicon_Hi3510_CGI', 1, 1, 10, 1, 1, 1, 1, 1, 1
12+
FROM DUAL
13+
WHERE NOT EXISTS (SELECT 1 FROM `Controls` WHERE `Protocol` = 'HiSilicon_Hi3510_CGI');

db/zm_update-1.39.16.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--
2+
-- Add a model-specific Controls entry for the LTS CMIP1342WE-28MDA.
3+
--
4+
-- This is a fixed ColorVu camera (no PTZ, no motorised focus/iris). Its white
5+
-- light is driven through the HikVision/LTS ISAPI supplement-light interface
6+
-- (ISAPI/Image/channels/1/supplementLight: colorVuWhiteLight/eventIntelligence/
7+
-- irLight/close), so only CanLight and CanReboot apply. CanReset stays 0 because
8+
-- the HikVision module implements reboot but no reset.
9+
--
10+
INSERT INTO `Controls`
11+
(`Name`,`Type`,`Protocol`,`CanReset`,`CanReboot`,`CanLight`)
12+
SELECT 'LTS CMIP1342WE-28MDA','Ffmpeg','HikVision',0,1,1
13+
FROM DUAL
14+
WHERE NOT EXISTS (SELECT 1 FROM `Controls` WHERE `Name`='LTS CMIP1342WE-28MDA');
15+
16+
--
17+
-- Same for the LTS CMIP3CD42WI-28AISP: another fixed ColorVu camera with the
18+
-- same white-light interface and no PTZ/focus/iris.
19+
--
20+
INSERT INTO `Controls`
21+
(`Name`,`Type`,`Protocol`,`CanReset`,`CanReboot`,`CanLight`)
22+
SELECT 'LTS CMIP3CD42WI-28AISP','Ffmpeg','HikVision',0,1,1
23+
FROM DUAL
24+
WHERE NOT EXISTS (SELECT 1 FROM `Controls` WHERE `Name`='LTS CMIP3CD42WI-28AISP');

scripts/ZoneMinder/lib/ZoneMinder/Control.pm

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -484,9 +484,10 @@ sub parse_ControlAddress {
484484
# Has no scheme at the beginning, so won't parse as a URI
485485
$address = 'http://'.$address;
486486
}
487-
# To support older installs which likely have non-url encoded passwords we use a dumber regexp than URI uses
488-
if ($address =~ /^(?<PROTOCOL>(https?|rtsp):\/\/)?(?<USERNAME>[^:@]+)?:?(?<PASSWORD>[^\/@]+)?@(?<ADDRESS>[^:\/]+)/) {
489-
$address = $+{PROTOCOL}.($+{USERNAME} ? join(':', $+{USERNAME}, URI::Escape::uri_escape($+{PASSWORD})).'@' : '').$+{ADDRESS};
487+
# To support older installs which likely have non-url encoded passwords we use a dumber regexp than URI uses.
488+
# Don't escape % so that url-encoded passwords (e.g. %40 for @) pass through and decode below.
489+
if ($address =~ /^(?<PROTOCOL>(https?|rtsp):\/\/)?(?<USERNAME>[^:@]+)?:?(?<PASSWORD>[^\/@]+)?@(?<ADDRESS>.+)$/) {
490+
$address = $+{PROTOCOL}.($+{USERNAME} ? join(':', $+{USERNAME}, URI::Escape::uri_escape($+{PASSWORD}, '^A-Za-z0-9\-_.~%')).'@' : '').$+{ADDRESS};
490491
}
491492
my $uri = URI->new($address);
492493
$uri = URI->new('http://'.$address) if ref($uri) eq 'URI::_foreign';
@@ -496,17 +497,8 @@ sub parse_ControlAddress {
496497
@$self{'username','password'} = $uri->userinfo() =~ /^(.*):(.*)$/;
497498
$$self{password} = URI::Escape::uri_unescape($$self{password});
498499
}
499-
# Check if it is a host and port or just a host
500-
if ( $$self{host} =~ /([^:]+):(.+)/ ) {
501-
$$self{host} = $1;
502-
$$self{port} = $2 ? $2 : $$self{port};
503-
} elsif ($uri->scheme() eq 'http') {
504-
$$self{port} = 80;
505-
$uri->port($$self{port});
506-
} elsif ($uri->scheme() eq 'https') {
507-
$$self{port} = 443;
508-
$uri->port($$self{port});
509-
}
500+
# URI gives the explicit port if present, otherwise the scheme default (http 80, https 443, rtsp 554)
501+
$$self{port} = $uri->port();
510502
$$self{address} = $uri->host_port();
511503
$$self{uri} = $uri;
512504
$$self{BaseURL} = $uri->canonical();
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
# ==========================================================================
2+
#
3+
# ZoneMinder HiSilicon Hi3510 CGI Control Protocol Module
4+
# Contributed by Turgut Kalfaoglu, based on the FoscamCGI module
5+
# by Jan M. Hochstein, adapted for the HiSilicon Hi3510 CGI interface.
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License
9+
# as published by the Free Software Foundation; either version 2
10+
# of the License, or (at your option) any later version.
11+
#
12+
# This program is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with this program; if not, write to the Free Software
19+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20+
#
21+
# ==========================================================================
22+
#
23+
# Tested: Tenvis TH661
24+
#
25+
# Many inexpensive IP cameras built on the HiSilicon Hi3510 SoC expose
26+
# this CGI interface (cgi-bin/hi3510/ptzctrl.cgi) rather than the older
27+
# Foscam decoder_control.cgi protocol. Credentials are passed as
28+
# usr/pwd query parameters.
29+
#
30+
# On ControlAddress use the format:
31+
# USERNAME:PASSWORD@ADDRESS:PORT
32+
# eg: admin:mypassword@192.168.1.142:80
33+
#
34+
# If the password contains special characters such as @ or :, url-encode
35+
# them (e.g. @ as %40).
36+
#
37+
# Presets 1-8 are stored on the camera. Preset 9 starts a horizontal
38+
# patrol (hscan), preset 10 starts a vertical patrol (vscan).
39+
#
40+
# ==========================================================================
41+
42+
package ZoneMinder::Control::HiSilicon_Hi3510_CGI;
43+
44+
use 5.006;
45+
use strict;
46+
use warnings;
47+
48+
require ZoneMinder::Control;
49+
50+
our @ISA = qw(ZoneMinder::Control);
51+
52+
use ZoneMinder::Logger qw(:all);
53+
use ZoneMinder::Config qw(:all);
54+
55+
use Time::HiRes qw( usleep );
56+
use URI::Escape qw( uri_escape );
57+
58+
sub open {
59+
my $self = shift;
60+
$self->loadMonitor();
61+
62+
use LWP::UserAgent;
63+
$self->{ua} = LWP::UserAgent->new;
64+
$self->{ua}->agent('ZoneMinder Control Agent/'.ZoneMinder::Base::ZM_VERSION);
65+
66+
# Parse username/password/host/port out of ControlAddress
67+
$self->guess_credentials();
68+
$$self{username} = 'admin' unless defined $$self{username};
69+
$$self{password} = '' unless defined $$self{password};
70+
$$self{port} = 80 unless $$self{port};
71+
72+
$self->{state} = 'open';
73+
}
74+
75+
sub sendCmd {
76+
my $self = shift;
77+
my $cmd = shift;
78+
my $result = undef;
79+
$self->printMsg($cmd, 'Tx');
80+
81+
my $url = 'http://'.$$self{host}.':'.$$self{port}.'/cgi-bin/hi3510/'.$cmd.
82+
'&usr='.uri_escape($$self{username}).'&pwd='.uri_escape($$self{password});
83+
84+
my $req = HTTP::Request->new(GET=>$url);
85+
my $res = $self->{ua}->request($req);
86+
87+
if ( $res->is_success ) {
88+
$result = !undef;
89+
} else {
90+
Error("Command failed: '".$res->status_line()."'");
91+
}
92+
93+
return $result;
94+
}
95+
96+
# This makes use of the ZoneMinder Auto Stop Timeout on the Control tab
97+
sub autoStop {
98+
my $self = shift;
99+
my $autostop = shift;
100+
if ( $autostop ) {
101+
Debug('Auto Stop');
102+
usleep($autostop);
103+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=stop');
104+
}
105+
}
106+
107+
# Reboot the camera
108+
sub reset {
109+
my $self = shift;
110+
Debug('Camera Reset');
111+
$self->sendCmd('param.cgi?cmd=sysreboot');
112+
}
113+
114+
# Up Arrow
115+
sub moveConUp {
116+
my $self = shift;
117+
Debug('Move Up');
118+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=up');
119+
$self->autoStop($self->{Monitor}->{AutoStopTimeout});
120+
}
121+
122+
# Down Arrow
123+
sub moveConDown {
124+
my $self = shift;
125+
Debug('Move Down');
126+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=down');
127+
$self->autoStop($self->{Monitor}->{AutoStopTimeout});
128+
}
129+
130+
# Left Arrow
131+
sub moveConLeft {
132+
my $self = shift;
133+
Debug('Move Left');
134+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=left');
135+
$self->autoStop($self->{Monitor}->{AutoStopTimeout});
136+
}
137+
138+
# Right Arrow
139+
sub moveConRight {
140+
my $self = shift;
141+
Debug('Move Right');
142+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=right');
143+
$self->autoStop($self->{Monitor}->{AutoStopTimeout});
144+
}
145+
146+
# Diagonal moves are not supported by the camera so we emulate them
147+
sub moveConUpRight {
148+
my $self = shift;
149+
Debug('Move Up-Right');
150+
$self->moveConUp();
151+
$self->moveConRight();
152+
}
153+
154+
sub moveConDownRight {
155+
my $self = shift;
156+
Debug('Move Down-Right');
157+
$self->moveConDown();
158+
$self->moveConRight();
159+
}
160+
161+
sub moveConUpLeft {
162+
my $self = shift;
163+
Debug('Move Up-Left');
164+
$self->moveConUp();
165+
$self->moveConLeft();
166+
}
167+
168+
sub moveConDownLeft {
169+
my $self = shift;
170+
Debug('Move Down-Left');
171+
$self->moveConDown();
172+
$self->moveConLeft();
173+
}
174+
175+
# Stop
176+
sub moveStop {
177+
my $self = shift;
178+
Debug('Move Stop');
179+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=stop');
180+
}
181+
182+
# Horizontal patrol
183+
sub horizontalPatrol {
184+
my $self = shift;
185+
Debug('Horizontal Patrol');
186+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=hscan');
187+
}
188+
189+
# Vertical patrol
190+
sub verticalPatrol {
191+
my $self = shift;
192+
Debug('Vertical Patrol');
193+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=vscan');
194+
}
195+
196+
# Stop patrol
197+
sub horizontalPatrolStop {
198+
my $self = shift;
199+
Debug('Patrol Stop');
200+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=stop');
201+
}
202+
203+
# Recall Camera Preset
204+
# Presets 1-8 are stored on the camera, preset 9 = hscan, preset 10 = vscan
205+
sub presetGoto {
206+
my $self = shift;
207+
my $params = shift;
208+
my $preset = $self->getParam($params, 'preset');
209+
Debug("Goto Preset $preset");
210+
211+
if ( $preset >= 1 && $preset <= 8 ) {
212+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=goto&-number='.($preset-1));
213+
} elsif ( $preset == 9 ) {
214+
$self->horizontalPatrol();
215+
} elsif ( $preset == 10 ) {
216+
$self->verticalPatrol();
217+
}
218+
}
219+
220+
# Set Camera Preset
221+
sub presetSet {
222+
my $self = shift;
223+
my $params = shift;
224+
my $preset = $self->getParam($params, 'preset');
225+
Debug("Set Preset $preset");
226+
227+
if ( $preset >= 1 && $preset <= 8 ) {
228+
$self->sendCmd('ptzctrl.cgi?-step=0&-act=set&-number='.($preset-1));
229+
}
230+
}
231+
232+
1;

0 commit comments

Comments
 (0)