|
| 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