Keekoon

From ZoneMinder Wiki
Revision as of 17:38, 22 July 2016 by Gerdesj (talk | contribs) (Gerdesj moved page User:Keekoon to Keekoon: Err, forgot which space I was in.)
Jump to navigationJump to search

Introduction

-- PICCY --

http://www.keekoonvision.com/ produce a series of IP cameras that are marketed as baby monitors and sold directly via outlets such as Amazon. They are low cost and feature pan and tilt. This page was written after full testing of the KK002 model. The other current models at time of writing (July 2016) are the KK001 and KK003 and are expected to work with the same settings.

Camera Features

Some pertinent features and things to know:

  • 720p - RTSP, H264, 1M pixel
  • Pan and tilt with six presets
  • Two way audio (not tested)
  • Wifi and ethernet (100Mbs-1)
  • IR night vision
  • Three metre long power lead
  • Indoor only
  • Minimal but functional web interface

Initial Installation

Recycle the Quick Start guide and throw away the mini CD. Connect via ethernet cable to your network. It will DHCP an IP address by default and the web interface is on port 80. Default username is admin with no password. To get to the settings, click on the "Non IE web browsers" link. At the bottom right there is a gear shaped icon for "Setting".

Set an admin password and optionally setup additional users and passwords. Optionally set ntp and for Zoneminder usage, go through the other settings disabling anything that might add load on the built in processor.

If you want to use Wifi then browse to Network -> Wifi. Select the correct SSID, click on connect and fill in the pre shared key. Finally select the newly created "Station Profile" and select Activate. A correctly activated profile will have a yellow tick on a green square icon next to it. If you have a red square then most likely you have got the pre shared key wrong.

Zoneminder specifics

Tested Versions

Monitor Settings

These are known good settings:

Source
Parameter Setting
Remote Protocol RTSP
Remote Method RTP/RTSP
Remote Host Name admin:password@camera.example.co.uk
Remote Host Port 554
Remote Host Path /rtsp_live0
Capture Width 1280
Capture Height 780

Control

Shortly this script will be pending inclusion into the distro but is reproduced here in case it doesn't make it or you have an older version of ZM. Instructions for use are in the comments under Usage. You should not have to change the script itself in any way.

# ==========================================================================
#
# ZoneMinder Keekoon Control Protocol Module
# This code was mostly derived from other ZM Control modules
#
# ==========================================================================
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# ==========================================================================
#
# Tested: KK002 (22 July 2016)
#
# Usage:
# ======
#
# Copy this file to say /usr/share/perl5/ZoneMinder/Control (Debian/Ubuntu)
#
# Create a new Control Capabilities:
#   Main:    Name Keekoon, Type = Remote, Protocol = Keekoon
#   Move:    Can Move, Can Move Diagonally, Can Move Continous
#   Pan:     Can Pan
#   Tilt:    Can Tilt
#   Presets: Has Presets, Num Presets = 6, Can Set Presets
#
# Set the ControlAddress in the camera definition, use the format:
#   http(s)://username:password@address:port
#
#   eg : http://admin:adminpass@10.10.10.1:80
#   or : https://admin:password@mycamera.example.co.uk:80
#
#   Return Location to Preset 1
#   Auto Stop Timeout = 0.5      is a good starting point
#
# ===========================================================================
# Problems: Enable debug and watch /tmp/zm_debug.log.<int> The
#           correct debug log can be found by date stamp.
#           Enable/disable the Source for the camera in the web GUI
#           each time you edit this script.  If the pid doesn't
#           change then you have not restarted it.    
# Errors like this:
# [Error in response to Request:'400 URL must be absolute']
# means that you have not specified all the parts in ControlAddress or the
# Regex has failed to parse it correctly
#
# =========================================================================
# Notes:  
# Example command from docs, at http://www.keekoonvision.com/for-developers-a: 
# Up: http://camera_ip:web_port/decoder_control.cgi?command=0&user=username&pwd=password
# However the camera actually uses basic auth and not user= etc
#
# Test URLs with something like this
# curl -XGET -u user:pass "http://cam.example.co.uk:80/decoder_control.cgi?command=1
#
# These cameras have a default admin user but can have six more defined
# with membership of three groups
# https is not directly supported but could be via say HA Proxy, so that
# is included rather than hardstrapping http://
# ==========================================================================

package ZoneMinder::Control::Keekoon;

use 5.006;
use strict;
use warnings;

require ZoneMinder::Control;

our @ISA = qw(ZoneMinder::Control);

use ZoneMinder::Logger qw(:all);
use ZoneMinder::Config qw(:all);
use Time::HiRes qw( usleep );

sub new
{

    my $class = shift;
    my $id = shift;
    my $self = ZoneMinder::Control->new( $id );
    my $logindetails = "";
    bless( $self, $class );
    srand( time() );
    return $self;
}

our $AUTOLOAD;

sub AUTOLOAD
{
    my $self = shift;
    my $class = ref( ) || croak( "$self not object" );
    my $name = $AUTOLOAD;
    $name =~ s/.*://;
    if ( exists($self->{$name}) )
    {
        return( $self->{$name} );
    }
    Fatal( "Can't access $name member of object of class $class" );
}

sub open
{
    my $self = shift;

    $self->loadMonitor();

    use LWP::UserAgent;

    $self->{ua} = LWP::UserAgent->new;
    $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION );

    $self->{state} = 'open';

    Info( "Open" );

}

sub close
{
    my $self = shift;
    $self->{state} = 'closed';
}

sub printMsg
{
    my $self = shift;
    my $msg = shift;
    my $msg_len = length($msg);

    Debug( $msg."[".$msg_len."]" );
}

sub sendCmd
{
    my $self = shift;
    my $cmd = shift;
    my $result = undef;

    my ( $PROTOCOL, $USER, $PASS, $ADDR, $PORT ) 
        = $self->{Monitor}->{ControlAddress} =~ /^(https?):\/\/(.*):(.*)@(.*):(\d+)$/;
    my $URL = $PROTOCOL."://".$ADDR.":".$PORT."/decoder_control.cgi?command=".$cmd;

    Debug( "ControlAddress from camera Control setting:".$self->{Monitor}->{ControlAddress} );
    Debug( "URL parsed from ControlAddress:".$URL);

    my $req = HTTP::Request->new( GET=>$URL );
    
    # Do Basic Auth
    $req->authorization_basic($USER, $PASS);
    
    my $res = $self->{ua}->request($req);

    if ( $res->is_success )
    {
        $result = !undef;
    }
    else
    {
        Error( "Error in response to Request:'".$res->status_line()."'" );
    }

    return( $result );
}

# Set autoStop timeout on the Control tab for the camera
sub autoStop
{
    my $self = shift;
    my $stop_command = shift;
    my $autostop = shift;
    
    if( $stop_command && $autostop)
    {
        Debug( "Auto Stop" );
        usleep( $autostop );
        my $cmd = $stop_command;
        $self->sendCmd( $cmd );
    }
}

sub moveConUp
{
    my $self = shift;
    my $cmd = "0";
    my $stop_command = "1";
    Debug( "Move Up" );
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

sub moveConDown
{
    my $self = shift;
    my $cmd = "2";
    my $stop_command = "3";
    Debug( "Move Down" );
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

sub moveConLeft
{
    my $self = shift;
    my $cmd = "4";
    my $stop_command = "5";
    Debug( "Move Left" );
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

sub moveConRight
{
    my $self = shift;
    my $cmd = "6";
    my $stop_command = "7";
    Debug( "Move Right" );
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

sub moveConUpRight
{
    my $self = shift;
    Debug( "Move Diagonally Up Right" );
    $self->moveConUp( );
    $self->moveConRight( );
}

sub moveConDownRight
{
    my $self = shift;
    Debug( "Move Diagonally Down Right" );
    $self->moveConDown( );
    $self->moveConRight( );
}

sub moveConUpLeft
{
    my $self = shift;
    Debug( "Move Diagonally Up Left" );
    $self->moveConUp( );
    $self->moveConLeft( );
}

sub moveConDownLeft
{
    my $self = shift;
    Debug( "Move Diagonally Down Left" );
    $self->moveConDown( );
    $self->moveConLeft( );
}

# SET: 30,32,34,36,38,40 for presets 1-6
sub presetSet
{
    my $self = shift;
    my $params = shift;
    my $preset = $self->getParam( $params, 'preset' );

    Debug( "Set Preset No: " . $preset );

    if (( $preset >= 1 ) && ( $preset <= 6 )) {
        my $cmd = (($preset*2) + 28);
        $self->sendCmd( $cmd );
        Debug( "Set preset cmd: " . $cmd );
    }
    
}

# GOTO: 31,33,35,37,39,41 for presets 1-6
sub presetGoto
{
    my $self = shift;
    my $params = shift;
    my $preset = $self->getParam( $params, 'preset' );
    Debug( "Goto Preset No: " . $preset );

    if (( $preset >= 1 ) && ( $preset <= 6 )) {
        my $cmd = (($preset*2) + 29);
        $self->sendCmd( $cmd );
        Debug( "Goto Preset cmd: " . $cmd );
    }
    
}

1;