1# ==========================================================================
2#
3# ZoneMinder Dericam P2 Control Protocol Module
4# Copyright (C) Roman Dissertori
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License
8# as published by the Free Software Foundation; either version 2
9# of the License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19#
20# ==========================================================================
21#
22# This module contains the implementation of the Dericam P2 device control protocol
23#
24package ZoneMinder::Control::DericamP2;
25
26use 5.006;
27use strict;
28use warnings;
29
30require ZoneMinder::Control;
31
32our @ISA = qw(ZoneMinder::Control);
33
34our %CamParams = ();
35
36# ==========================================================================
37#
38# Dericam P2 Control Protocol
39#
40# On ControlAddress use the format :
41#   USERNAME:PASSWORD@ADDRESS:PORT
42#   eg : admin:@10.1.2.1:80
43#        zoneminder:zonepass@10.0.100.1:40000
44#
45# ==========================================================================
46
47use ZoneMinder::Logger qw(:all);
48use ZoneMinder::Config qw(:all);
49
50use Time::HiRes qw( usleep );
51
52sub open
53{
54    my $self = shift;
55
56    $self->loadMonitor();
57
58    use LWP::UserAgent;
59    $self->{ua} = LWP::UserAgent->new;
60    $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION );
61
62    $self->{state} = 'open';
63}
64
65sub printMsg
66{
67    my $self = shift;
68    my $msg = shift;
69    my $msg_len = length($msg);
70
71    Debug( $msg."[".$msg_len."]" );
72}
73
74sub sendCmd
75{
76    my $self = shift;
77    my $cmd = shift;
78    my $result = undef;
79    printMsg( $cmd, "Tx" );
80
81    my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" );
82    Info( "http://".$self->{Monitor}->{ControlAddress}."/$cmd".$self->{Monitor}->{ControlDevice} );
83    my $res = $self->{ua}->request($req);
84
85    if ( $res->is_success )
86    {
87        $result = !undef;
88    }
89    else
90    {
91        Error( "Error check failed:'".$res->status_line()."'" );
92    }
93
94    return( $result );
95}
96
97sub getCamParams
98{
99    my $self = shift;
100    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=getimageattr";
101
102    my $req = $self->sendCmd( $cmd );
103    my $res = $self->{ua}->request($req);
104
105    if ( $res->is_success )
106    {
107        # Parse results setting values in %FCParams
108        my $content = $res->decoded_content;
109
110        while ($content =~ s/var\s+([^=]+)=([^;]+);//ms) {
111            $CamParams{$1} = $2;
112        }
113    }
114    else
115    {
116        Error( "Error check failed:'".$res->status_line()."'" );
117    }
118}
119
120#autoStop
121#This makes use of the ZoneMinder Auto Stop Timeout on the Control Tab
122sub autoStop
123{
124    my $self = shift;
125    my $stop_command = shift;
126    my $autostop = shift;
127    if( $stop_command && $autostop)
128    {
129        Debug( "Auto Stop" );
130        usleep( $autostop );
131        my $cmd = "decoder_control.cgi?command=".$stop_command;
132        $self->sendCmd( $cmd );
133    }
134
135}
136
137# Reset the Camera
138sub reset
139{
140    my $self = shift;
141    Debug( "Camera Reset" );
142    # Move to default position
143    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-act=home";
144    $self->sendCmd( $cmd );
145
146    # Reset all other values to default
147    $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-image_type=1&-default=on";
148    $self->sendCmd( $cmd );
149}
150
151# Reboot Camera (on Sleep button)
152sub sleep
153{
154    my $self = shift;
155    Debug( "Camera Reboot" );
156    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-act=sysreboot";
157    $self->sendCmd( $cmd );
158}
159
160# Stop the Camera
161sub moveStop
162{
163    my $self = shift;
164    Debug( "Camera Stop" );
165    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-act=stop";
166    $self->sendCmd( $cmd );
167}
168
169#Up Arrow
170sub moveConUp
171{
172    my $self = shift;
173    my $stop_command = "1";
174    Debug( "Move Up" );
175    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-act=up&-speed=45";
176    $self->sendCmd( $cmd );
177    #$self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
178}
179
180#Down Arrow
181sub moveConDown
182{
183    my $self = shift;
184    my $stop_command = "3";
185    Debug( "Move Down" );
186    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-act=down&-speed=45";
187    $self->sendCmd( $cmd );
188    #$self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
189}
190
191#Left Arrow
192sub moveConLeft
193{
194    my $self = shift;
195    my $stop_command = "5";
196    Debug( "Move Left" );
197    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-act=left&-speed=45";
198    $self->sendCmd( $cmd );
199    #$self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
200}
201
202#Right Arrow
203sub moveConRight
204{
205    my $self = shift;
206    my $stop_command = "7";
207    Debug( "Move Right" );
208    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-act=right&-speed=45";
209    $self->sendCmd( $cmd );
210    #$self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
211}
212
213#Zoom In
214sub zoomConTele
215{
216    my $self = shift;
217    Debug( "Zoom Tele" );
218    my $cmd = "decoder_control.cgi?command=18";
219    $self->sendCmd( $cmd );
220}
221
222#Zoom Out
223sub zoomConWide
224{
225    my $self = shift;
226    Debug( "Zoom Wide" );
227    my $cmd = "decoder_control.cgi?command=16";
228    $self->sendCmd( $cmd );
229}
230
231#Diagonally Up Right Arrow
232#This camera does not have builtin diagonal commands so we emulate them
233sub moveConUpRight
234{
235    my $self = shift;
236    Debug( "Move Diagonally Up Right" );
237    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-act=upright&-speed=45";
238    $self->sendCmd( $cmd );
239}
240
241#Diagonally Down Right Arrow
242#This camera does not have builtin diagonal commands so we emulate them
243sub moveConDownRight
244{
245    my $self = shift;
246    Debug( "Move Diagonally Down Right" );
247    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-act=downright&-speed=45";
248    $self->sendCmd( $cmd );
249}
250
251#Diagonally Up Left Arrow
252#This camera does not have builtin diagonal commands so we emulate them
253sub moveConUpLeft
254{
255    my $self = shift;
256    Debug( "Move Diagonally Up Left" );
257    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-act=upleft&-speed=45";
258    $self->sendCmd( $cmd );
259}
260
261#Diagonally Down Left Arrow
262#This camera does not have builtin diagonal commands so we emulate them
263sub moveConDownLeft
264{
265    my $self = shift;
266    Debug( "Move Diagonally Down Left" );
267    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-act=downnleft&-speed=45";
268    $self->sendCmd( $cmd );
269}
270
271#Set Camera Preset
272#Presets must be translated into values internal to the camera
273#Those values are: 30,32,34,36,38,40,42,44 for presets 1-8 respectively
274sub presetSet
275{
276    my $self = shift;
277    my $params = shift;
278    my $preset = $self->getParam( $params, 'preset' );
279    Debug( "Set Preset $preset" );
280
281    if (( $preset >= 1 ) && ( $preset <= 8 )) {
282        my $cmd = "cgi-bin/hi3510/param.cgi?cmd=preset&-act=set&-number=".(($preset*2) + 28);
283        $self->sendCmd( $cmd );
284    }
285}
286
287#Recall Camera Preset
288#Presets must be translated into values internal to the camera
289#Those values are: 31,33,35,37,39,41,43,45 for presets 1-8 respectively
290sub presetGoto
291{
292    my $self = shift;
293    my $params = shift;
294    my $preset = $self->getParam( $params, 'preset' );
295    Debug( "Goto Preset $preset" );
296
297    if (( $preset >= 1 ) && ( $preset <= 8 )) {
298        my $cmd = "cgi-bin/hi3510/param.cgi?cmd=preset&-act=goto&-number=".(($preset*2) + 29);
299        $self->sendCmd( $cmd );
300    }
301
302    if ( $preset == 9 ) {
303        $self->horizontalPatrol();
304    }
305
306    if ( $preset == 10 ) {
307        $self->verticalPatrol();
308    }
309}
310
311#Horizontal Patrol
312sub horizontalPatrol
313{
314    my $self = shift;
315    Debug( "Horizontal Patrol" );
316    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-act=hscan";
317    $self->sendCmd( $cmd );
318}
319
320#Vertical Patrol
321sub verticalPatrol
322{
323    my $self = shift;
324    Debug( "Vertical Patrol" );
325    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-act=vscan";
326    $self->sendCmd( $cmd );
327}
328
329# Increase Brightness
330sub irisAbsOpen
331{
332    my $self = shift;
333    my $params = shift;
334    $self->getCamParams() unless($CamParams{'brightness'});
335    my $step = $self->getParam( $params, 'step' );
336
337    $CamParams{'brightness'} += $step;
338    $CamParams{'brightness'} = 100 if ($CamParams{'brightness'} > 100);
339    Debug( "Increase Brightness" );
340    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-brightness=".$CamParams{'brightness'};
341    $self->sendCmd( $cmd );
342}
343
344# Decrease Brightness
345sub irisAbsClose
346{
347    my $self = shift;
348    my $params = shift;
349    $self->getCamParams() unless($CamParams{'brightness'});
350    my $step = $self->getParam( $params, 'step' );
351
352    $CamParams{'brightness'} -= $step;
353    $CamParams{'brightness'} = 0 if ($CamParams{'brightness'} < 0);
354    Debug( "Decrease Brightness" );
355    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-brightness=".$CamParams{'brightness'};
356    $self->sendCmd( $cmd );
357}
358
359# Increase Contrast
360sub whiteAbsIn
361{
362    my $self = shift;
363    my $params = shift;
364    $self->getCamParams() unless($CamParams{'contrast'});
365    my $step = $self->getParam( $params, 'step' );
366
367    $CamParams{'contrast'} += $step;
368    $CamParams{'contrast'} = 100 if ($CamParams{'contrast'} > 100);
369    Debug( "Increase Contrast" );
370    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-contrast=".$CamParams{'contrast'};
371    $self->sendCmd( $cmd );
372}
373
374# Decrease Contrast
375sub whiteAbsOut
376{
377    my $self = shift;
378    my $params = shift;
379    $self->getCamParams() unless($CamParams{'contrast'});
380    my $step = $self->getParam( $params, 'step' );
381
382    $CamParams{'contrast'} -= $step;
383    $CamParams{'contrast'} = 0 if ($CamParams{'contrast'} < 0);
384    Debug( "Decrease Contrast" );
385    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-contrast=".$CamParams{'contrast'};
386    $self->sendCmd( $cmd );
387}
388
389#TODO Saturation cgi-bin/hi3510/param.cgi?cmd=setimageattr&-saturation=44 [0-255]
390sub satIncrease
391{
392    my $self = shift;
393    my $params = shift;
394    $self->getCamParams() unless($CamParams{'saturation'});
395    my $step = $self->getParam( $params, 'step' );
396
397    $CamParams{'saturation'} += $step;
398    $CamParams{'saturation'} = 255 if ($CamParams{'saturation'} > 255);
399    Debug( "Increase Saturation" );
400    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-saturation=".$CamParams{'saturation'};
401    $self->sendCmd( $cmd );
402}
403
404sub satDecrease
405{
406    my $self = shift;
407    my $params = shift;
408    $self->getCamParams() unless($CamParams{'saturation'});
409    my $step = $self->getParam( $params, 'step' );
410
411    $CamParams{'saturation'} -= $step;
412    $CamParams{'saturation'} = 0 if ($CamParams{'saturation'} < 0);
413    Debug( "Decrease Saturation" );
414    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-saturation=".$CamParams{'saturation'};
415    $self->sendCmd( $cmd );
416}
417#TODO Sharpness cgi-bin/hi3510/param.cgi?cmd=setimageattr&-sharpness=37 [0-100]
418sub sharpIncrease
419{
420    my $self = shift;
421    my $params = shift;
422    $self->getCamParams() unless($CamParams{'sharpness'});
423    my $step = $self->getParam( $params, 'step' );
424
425    $CamParams{'sharpness'} += $step;
426    $CamParams{'sharpness'} = 100 if ($CamParams{'sharpness'} > 100);
427    Debug( "Increase Sharpness" );
428    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-sharpness=".$CamParams{'sharpness'};
429    $self->sendCmd( $cmd );
430}
431
432sub sharpDecrease
433{
434    my $self = shift;
435    my $params = shift;
436    $self->getCamParams() unless($CamParams{'sharpness'});
437    my $step = $self->getParam( $params, 'step' );
438
439    $CamParams{'sharpness'} -= $step;
440    $CamParams{'sharpness'} = 0 if ($CamParams{'sharpness'} < 0);
441    Debug( "Decrease Sharpness" );
442    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-sharpness=".$CamParams{'sharpness'};
443    $self->sendCmd( $cmd );
444}
445
446#TODO Hue cgi-bin/hi3510/param.cgi?cmd=setimageattr&-hue=37 [0-100]
447sub hueIncrease
448{
449    my $self = shift;
450    my $params = shift;
451    $self->getCamParams() unless($CamParams{'hue'});
452    my $step = $self->getParam( $params, 'step' );
453
454    $CamParams{'hue'} += $step;
455    $CamParams{'hue'} = 100 if ($CamParams{'hue'} > 100);
456    Debug( "Increase Hue" );
457    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-hue=".$CamParams{'hue'};
458    $self->sendCmd( $cmd );
459}
460
461sub hueDecrease
462{
463    my $self = shift;
464    my $params = shift;
465    $self->getCamParams() unless($CamParams{'hue'});
466    my $step = $self->getParam( $params, 'step' );
467
468    $CamParams{'hue'} -= $step;
469    $CamParams{'hue'} = 0 if ($CamParams{'hue'} < 0);
470    Debug( "Decrease Hue" );
471    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setimageattr&-hue=".$CamParams{'hue'};
472    $self->sendCmd( $cmd );
473}
474
4751;
476