mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 06:39:11 +00:00
new module IPCAM added
git-svn-id: https://svn.fhem.de/fhem/trunk@1788 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
9d59b94a66
commit
bde0aa63c2
@ -57,6 +57,7 @@
|
||||
- feature: FhemUtils/release.pm for the new update process added. (M. Fischer)
|
||||
- bugfix: correct one-time relative at commands after reboot
|
||||
- feature: ZWave added
|
||||
- feature: module IPCAM added. (M. Fischer)
|
||||
|
||||
- 2011-12-31 (5.2)
|
||||
- bugfix: applying smallscreen attributes to firefox/opera
|
||||
|
285
fhem/FHEM/95_IPCAM.pm
Normal file
285
fhem/FHEM/95_IPCAM.pm
Normal file
@ -0,0 +1,285 @@
|
||||
################################################################
|
||||
# $Id: $
|
||||
#
|
||||
# (c) 2012 Copyright: Martin Fischer (m_fischer at gmx dot de)
|
||||
# All rights reserved
|
||||
#
|
||||
# This script 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.
|
||||
#
|
||||
# The GNU General Public License can be found at
|
||||
# http://www.gnu.org/copyleft/gpl.html.
|
||||
# A copy is found in the textfile GPL.txt and important notices to the license
|
||||
# from the author is found in LICENSE.txt distributed with these scripts.
|
||||
#
|
||||
# This script 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.
|
||||
#
|
||||
################################################################
|
||||
|
||||
package main;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub IPCAM_getSnapshot($);
|
||||
sub IPCAM_guessFileFormat($);
|
||||
|
||||
my %gets = (
|
||||
"image" => "",
|
||||
"last" => "",
|
||||
"snapshots" => "",
|
||||
);
|
||||
|
||||
#####################################
|
||||
sub
|
||||
IPCAM_Initialize($$)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{DefFn} = "IPCAM_Define";
|
||||
$hash->{UndefFn} = "IPCAM_Undef";
|
||||
$hash->{GetFn} = "IPCAM_Get";
|
||||
$hash->{AttrList} = "delay credentials path query snapshots storage ".
|
||||
"do_not_notify:1,0 showtime:1,0 ".
|
||||
"loglevel:0,1,2,3,4,5,6 disable:0,1";
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
IPCAM_Define($$) {
|
||||
my ($hash, $def) = @_;
|
||||
|
||||
# define <name> IPCAM <camip:port>
|
||||
# define webcam IPCAM 192.168.1.58:81
|
||||
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
|
||||
return "Wrong syntax: use 'define <name> IPCAM <camip:port>'"
|
||||
if(@a != 3);
|
||||
|
||||
my $name = $a[0];
|
||||
my $auth = $a[2];
|
||||
|
||||
$hash->{AUTHORITY} = $auth;
|
||||
$hash->{STATE} = "Defined";
|
||||
$hash->{SEQ} = 0;
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
IPCAM_Undef($$) {
|
||||
my ($hash, $name) = @_;
|
||||
|
||||
delete($modules{IPCAM}{defptr}{$hash->{NAME}});
|
||||
RemoveInternalTimer($hash);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
IPCAM_Get($@) {
|
||||
my ($hash, @a) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $seqImages;
|
||||
my $seqDelay;
|
||||
my $seqWait;
|
||||
my $storage = (defined($attr{$name}{storage}) ? $attr{$name}{storage} : "");
|
||||
|
||||
# check syntax
|
||||
return "argument is missing @a"
|
||||
if(int(@a) != 2);
|
||||
# check argument
|
||||
return "Unknown argument $a[1], choose on of ".join(" ", sort keys %gets)
|
||||
if(!defined($gets{$a[1]}));
|
||||
# check attributes
|
||||
return "Attribute 'path' is missing. Please add this attribute first!"
|
||||
if(!defined($attr{$name}) || (defined($attr{$name}) && !defined($attr{$name}{path})));
|
||||
return "Attribute 'path' is defined but empty."
|
||||
if(defined($attr{$name}{path}) && $attr{$name}{path} eq "");
|
||||
return "Attribute 'query' is defined but empty."
|
||||
if(defined($attr{$name}{query}) && $attr{$name}{query} eq "");
|
||||
|
||||
my $arg = $a[1];
|
||||
|
||||
if($arg eq "image") {
|
||||
|
||||
return "Attribute 'storage' is missing. Please add this attribute first!"
|
||||
if(!$storage);
|
||||
|
||||
$seqImages = int(defined($attr{$name}{snapshots}) ? $attr{$name}{snapshots} : 1);
|
||||
$seqDelay = int(defined($attr{$name}{delay}) ? $attr{$name}{delay} : 0);
|
||||
$seqWait = 0;
|
||||
|
||||
# housekeeping after number of sequence has changed
|
||||
my $readings = $hash->{READINGS};
|
||||
foreach my $r (sort keys %{$readings}) {
|
||||
if($r =~ /snapshot\d+/) {
|
||||
my $n = $r;
|
||||
$n =~ s/snapshot//;
|
||||
delete $readings->{$r} if( $r =~ m/snapshot/ && int($n) > $seqImages);
|
||||
Log 5, "IPCAM $name remove old reading: $r";
|
||||
|
||||
}
|
||||
}
|
||||
$hash->{READINGS}{snapshots}{VAL} = 0;
|
||||
for (my $i=0;$i<$seqImages;$i++) {
|
||||
InternalTimer(gettimeofday()+$seqWait, "IPCAM_getSnapshot", $hash, 0);
|
||||
$seqWait = $seqWait + $seqDelay;
|
||||
}
|
||||
return undef;
|
||||
|
||||
} elsif(defined($hash->{READINGS}{$arg})) {
|
||||
|
||||
if(defined($hash->{READINGS}{$arg}{VAL})) {
|
||||
return "$name $arg => $hash->{READINGS}{$arg}{VAL}";
|
||||
} else {
|
||||
return "$name $arg => undef";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
IPCAM_getSnapshot($) {
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $camAuth = $hash->{AUTHORITY};
|
||||
my $camURI;
|
||||
my $camPath;
|
||||
my $camQuery;
|
||||
my $camCredentials;
|
||||
my $imageFile;
|
||||
my $imageFormat;
|
||||
my $lastSnapshot;
|
||||
my $snapshot;
|
||||
my $dateTime;
|
||||
my $seqImages = int(defined($attr{$name}{snapshots}) ? $attr{$name}{snapshots} : 1);
|
||||
my $seq = int(defined($hash->{SEQ}) ? $hash->{SEQ} : 0);
|
||||
my $storage = (defined($attr{$name}{storage}) ? $attr{$name}{storage} : "");
|
||||
|
||||
if(!$storage) {
|
||||
RemoveInternalTimer($hash);
|
||||
return "Attribute 'storage' is missing. Please add this attribute first!";
|
||||
}
|
||||
|
||||
$camPath = $attr{$name}{path};
|
||||
$camQuery = $attr{$name}{query}
|
||||
if(defined($attr{$name}{query}) && $attr{$name}{query} ne "");
|
||||
|
||||
$camURI = "http://$camAuth/$camPath";
|
||||
$camURI .= "?$camQuery" if($camQuery);
|
||||
|
||||
if($camURI =~ m/{USERNAME}/ || $camURI =~ m/{PASSWORD}/) {
|
||||
|
||||
if(defined($attr{$name}{credentials})) {
|
||||
if(!open(CFG, $attr{$name}{credentials})) {
|
||||
Log 1, "IPCAM $name Cannot open credentials file: $attr{$name}{credentials}";
|
||||
RemoveInternalTimer($hash);
|
||||
return undef;
|
||||
}
|
||||
my @cfg = <CFG>;
|
||||
close(CFG);
|
||||
my %credentials;
|
||||
eval join("", @cfg);
|
||||
$camURI =~ s/{USERNAME}/$credentials{$name}{username}/;
|
||||
$camURI =~ s/{PASSWORD}/$credentials{$name}{password}/;
|
||||
}
|
||||
}
|
||||
|
||||
$dateTime = TimeNow();
|
||||
|
||||
$snapshot = GetFileFromURL($camURI);
|
||||
|
||||
$imageFormat = IPCAM_guessFileFormat(\$snapshot);
|
||||
|
||||
my @imageTypes = qw(JPEG PNG GIF TIFF BMP ICO PPM XPM XBM SVG);
|
||||
|
||||
if( ! grep { $_ eq "$imageFormat"} @imageTypes) {
|
||||
Log 1, "IPCAM $name Wrong or not supported image format: $imageFormat";
|
||||
RemoveInternalTimer($hash);
|
||||
return undef;
|
||||
}
|
||||
|
||||
Log GetLogLevel($name,5), "IPCAM $name Image Format: $imageFormat";
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
if($seq < $seqImages) {
|
||||
$seq++;
|
||||
$lastSnapshot = $name."_snapshot.".lc($imageFormat);
|
||||
$imageFile = $name."_snapshot".$seq.".".lc($imageFormat);
|
||||
if(!open(FH, ">$storage/$lastSnapshot")) {
|
||||
Log 1, "IPCAM $name Can't write $storage/$lastSnapshot: $!";
|
||||
RemoveInternalTimer($hash);
|
||||
readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
|
||||
return undef;
|
||||
}
|
||||
print FH $snapshot;
|
||||
close(FH);
|
||||
Log 5, "IPCAM $name snapshot $storage/$lastSnapshot written.";
|
||||
if(!open(FH, ">$storage/$imageFile")) {
|
||||
Log 1, "IPCAM $name Can't write $storage/$imageFile: $!";
|
||||
RemoveInternalTimer($hash);
|
||||
readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
|
||||
return undef;
|
||||
}
|
||||
print FH $snapshot;
|
||||
close(FH);
|
||||
Log 5, "IPCAM $name snapshot $storage/$imageFile written.";
|
||||
readingsUpdate($hash,"last",$lastSnapshot);
|
||||
$hash->{STATE} = "last: $dateTime";
|
||||
$hash->{READINGS}{"snapshot$seq"}{TIME} = $dateTime;
|
||||
$hash->{READINGS}{"snapshot$seq"}{VAL} = $imageFile;
|
||||
}
|
||||
|
||||
Log GetLogLevel($name,4), "IPCAM $name image: $imageFile";
|
||||
|
||||
if($seq == $seqImages) {
|
||||
readingsUpdate($hash,"snapshots",$seq);
|
||||
$seq = 0;
|
||||
}
|
||||
readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
|
||||
$hash->{SEQ} = $seq;
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
IPCAM_guessFileFormat($) {
|
||||
my ($src) = shift;
|
||||
my $header;
|
||||
my $srcHeader;
|
||||
|
||||
open(my $s, "<", $src) || return "can't open source image: $!";
|
||||
$src = $s;
|
||||
|
||||
my $reading = read($src, $srcHeader, 64);
|
||||
return "error while reading source image: $!" if(!$reading);
|
||||
|
||||
local($_) = $srcHeader;
|
||||
return "JPEG" if /^\xFF\xD8/;
|
||||
return "PNG" if /^\x89PNG\x0d\x0a\x1a\x0a/;
|
||||
return "GIF" if /^GIF8[79]a/;
|
||||
return "TIFF" if /^MM\x00\x2a/;
|
||||
return "TIFF" if /^II\x2a\x00/;
|
||||
return "BMP" if /^BM/;
|
||||
return "ICO" if /^\000\000\001\000/;
|
||||
return "PPM" if /^P[1-6]/;
|
||||
return "XPM" if /(^\/\* XPM \*\/)|(static\s+char\s+\*\w+\[\]\s*=\s*{\s*"\d+)/;
|
||||
return "XBM" if /^(?:\/\*.*\*\/\n)?#define\s/;
|
||||
return "SVG" if /^(<\?xml|[\012\015\t ]*<svg\b)/;
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
# vim: ts=2:et
|
||||
|
||||
1;
|
@ -516,3 +516,6 @@
|
||||
|
||||
- Sun Jun 17 2012 (M. Fischer)
|
||||
- CULflash routine from updatefhem removed. CULflash is a standalone module from now.
|
||||
|
||||
- Sat Aug 11 2012 (M. Fischer)
|
||||
- Added new module IPCAM
|
||||
|
@ -96,6 +96,7 @@
|
||||
<a href="#FS20">FS20</a>
|
||||
<a href="#HMS">HMS</a>
|
||||
<a href="#HMLAN">HMLAN</a>
|
||||
<a href="#IPCAM">IPCAM</a>
|
||||
<a href="#IPWE">IPWE</a>
|
||||
<a href="#IT">IT</a>
|
||||
<a href="#ITACH_RELAY">ITACH_RELAY</a>
|
||||
@ -7881,6 +7882,172 @@ Terminating
|
||||
<br>
|
||||
</ul>
|
||||
|
||||
|
||||
<a name="IPCAM"></a>
|
||||
<h3>IPCAM</h3>
|
||||
<ul>
|
||||
<br>
|
||||
|
||||
<a name"IPCAMdefine"></a>
|
||||
<b>Define</b>
|
||||
<ul>
|
||||
<code>define <name> IPCAM <ip[:port]></code>
|
||||
<br><br>
|
||||
|
||||
Defines a network camera device to trigger snapshots on events.<br><br>
|
||||
|
||||
Network cameras (IP cameras) usually have a build-in function to create
|
||||
snapshot images. This module enables the event- or time-controlled
|
||||
recording of these images.<br>
|
||||
In addition, this module allows the recording of many image formats like
|
||||
JPEG, PNG, GIF, TIFF, BMP, ICO, PPM, XPM, XBM and SVG. The only requirement
|
||||
is that the recorded image must be accessible via a URL.<br>
|
||||
So it is also possible to record images of e.g. a public Weather Camera
|
||||
from the internet or any picture of a website.<br><br>
|
||||
|
||||
Examples:<br><br>
|
||||
A local ip-cam takes 5 snapshots with 10 seconds delay per call:<br>
|
||||
<ul>
|
||||
<code>define ipcam IPCAM 192.168.1.205</code><br>
|
||||
<code>attr ipcam delay 10</code><br>
|
||||
<code>attr ipcam path snapshot.cgi?user=foo&pwd=bar</code><br>
|
||||
<code>attr ipcam snapshots 5</code><br>
|
||||
<code>attr ipcam storage /srv/share/surveillance/snapshots</code><br>
|
||||
</ul><br>
|
||||
|
||||
A notify on a motiondetection of a specified device:<br>
|
||||
<ul>
|
||||
<code>define MOTION.not.01 notify GH.ga.SEC.MD.01:.*on.* get ipcam image</code><br>
|
||||
</ul><br>
|
||||
|
||||
Send an eMail after snapshots are taken:<br>
|
||||
<ul>
|
||||
<code>define MOTION.not.02 notify ipcam:.*snapshots.* { myEmailFuntion("ipcam") }</code><br>
|
||||
</ul><br>
|
||||
|
||||
A public web-cam takes only 1 snapshot per call:<br>
|
||||
<ul>
|
||||
<code>define schloss IPCAM http://www2.braunschweig.de/webcam/schloss.jpg</code><br>
|
||||
<code>attr schloss path webcam/schloss.jpg</code><br>
|
||||
<code>attr schloss storage /srv/share/surveillance/snapshots</code><br>
|
||||
</ul><br>
|
||||
|
||||
An at-Job takes every hour a snapshot:<br>
|
||||
<ul>
|
||||
<code>define snapshot_schloss at +*00:01:00 get schloss image</code><br>
|
||||
</ul><br>
|
||||
|
||||
</ul>
|
||||
|
||||
<b>Set</b> <ul>N/A</ul><br>
|
||||
|
||||
<a name="IPCAMget"></a>
|
||||
<b>Get</b>
|
||||
<ul>
|
||||
<code>get <name> <value></code>
|
||||
<br><br>
|
||||
where <code>value</code> is one of:<br>
|
||||
<ul>
|
||||
<li>
|
||||
<code>image</code><br>
|
||||
Get one or more images of the defined IP-Cam. The number of images<br>
|
||||
and the time interval between images can be specified using the<br>
|
||||
attributes <code>snapshots</code> and <code>delay</code>.
|
||||
</li>
|
||||
<li>
|
||||
<code>last</code><br>
|
||||
Show the name of the last snapshot.
|
||||
</li>
|
||||
<li>
|
||||
<code>snapshots</code><br>
|
||||
Show the total number of a image sequence.
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
<a name="IPCAMattr"></a>
|
||||
<b>Attributes</b>
|
||||
<ul>
|
||||
<li>
|
||||
credentials<br>
|
||||
Defines the location of the credentials file.<br>
|
||||
If you prefer to store your cam credentials in a file instead be a part of the
|
||||
URI (see attributes <code>path</code> and <code>query</code>), set the full path
|
||||
with filename on this attribute.<br>
|
||||
Example: <code>attr ipcam3 credentials /etc/fhem/ipcam.conf</code><br><br>
|
||||
|
||||
The credentials file has the following structure:<br>
|
||||
<pre>
|
||||
#
|
||||
# Webcam credentials
|
||||
#
|
||||
$credentials{<name_cam1>}{username} = "<your_username>";
|
||||
$credentials{<name_cam1>}{password} = "<your_password>";
|
||||
$credentials{<name_cam2>}{username} = "<your_username>";
|
||||
$credentials{<name_cam2>}{password} = "<your_password>";
|
||||
...
|
||||
</pre>
|
||||
Replace <code><name_cam1></code> respectively <code><name_cam2></code>
|
||||
with the names of your defined ip-cams and <code><your_username></code> respectively
|
||||
<code><your_password></code> with your credentials (all without the brackets
|
||||
<code><</code> and <code>></code>!).
|
||||
</li>
|
||||
<li>
|
||||
delay<br>
|
||||
Defines the time interval between snapshots in seconds.<br>
|
||||
If more then one snapshot is taken, then it makes sense to define a short delay
|
||||
between the snapshots. On the one hand, the camera is not addressed in short intervals
|
||||
and the second may be better represented movements between images.<br>
|
||||
Example: <code>attr ipcam3 delay 10</code>
|
||||
</li>
|
||||
<li><a href="#disable">disable</a></li>
|
||||
<li><a href="#do_not_notify">do_not_notify</a></li>
|
||||
<li><a href="#loglevel">loglevel</a></li>
|
||||
<li>
|
||||
path<br>
|
||||
Defines the path and query component of the complete <a href="http://de.wikipedia.org/wiki/Uniform_Resource_Identifier" target="_blank">URI</a> to get a snapshot of the
|
||||
camera. Is the full URI of your ip-cam for example <code>http://CAMERA_IP/snapshot.cgi?user=admin&pwd=password</code>,
|
||||
then only the path and query part is specified here (without the leading slash (/).<br>
|
||||
Example: <code>attr ipcam3 path snapshot.cgi?user=admin&pwd=password</code><br><br>
|
||||
|
||||
If you prefer to store the credentials in a file (take a look at the attribute <code>credentials</code>)
|
||||
you have to set the placeholder <code>USERNAME</code> and <code>PASSWORD</code> in the path string. These placeholders
|
||||
will be replaced with the values from the credentials file.<br>
|
||||
Example: <code>attr ipcam3 path snapshot.cgi?user=USERNAME&pwd=PASSWORD</code>
|
||||
</li>
|
||||
<li><a href="#showtime">showtime</a></li>
|
||||
<li>
|
||||
snapshots<br>
|
||||
Defines the total number of snapshots to be taken with the <code>get <name> image</code> command.
|
||||
If this attribute is not defined, then the default value is 1.<br>
|
||||
The snapshots are stored in the given path of the attribute <code>storage</code> and are
|
||||
numbered sequentially (starts with 1) like <code>snapshot1</code>, <code>snapshot2</code>, etc.
|
||||
Furthermore, an additional file <code>last</code> will be saved, which is identical with
|
||||
the last snapshot-image. The module checks the imagetype and stores all these files with
|
||||
the correct extension, e.g. <code>snapshot1.jpeg</code>.<br>
|
||||
All files are overwritten on every <code>get <name> image</code> command.<br>
|
||||
Example: <code>attr ipcam3 snapshots 5</code>
|
||||
</li>
|
||||
<li>
|
||||
storage<br>
|
||||
Defines the location for the file storage of the snapshots.<br>
|
||||
Example: <code>attr ipcam3 storage /srv/share/surveillance/snapshots</code>
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
<a name="IPCAMevents"></a>
|
||||
<b>Generated events</b>
|
||||
<ul>
|
||||
<li>last: <name_of_device>_snapshot.<image_extension></li>
|
||||
<li>snapshots: <total_number_of_taken_snapshots_at_end></li>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<a name="IPWE"></a>
|
||||
<h3>IPWE</h3>
|
||||
<ul>
|
||||
@ -8641,7 +8808,7 @@ KlikAanKlikUit, NEXA, CHACON, HomeEasy UK. <br> You need to define an RFXtrx433
|
||||
Example:
|
||||
<ul>
|
||||
<code>define lamp ZWave 00ce2074 9</code><br>
|
||||
<code>attr lamp classes SWITCH_BINARY BASIC MANUFACTURER_SPECIFIC VERSION SWITCH_ALL ASSOCIATION METER CONFIGURATION ALARM<code><br>
|
||||
<code>attr lamp classes SWITCH_BINARY BASIC MANUFACTURER_SPECIFIC VERSION SWITCH_ALL ASSOCIATION METER CONFIGURATION ALARM</code><br>
|
||||
</ul>
|
||||
</ul>
|
||||
<br>
|
||||
@ -11199,4 +11366,7 @@ The .gnuplot file consists of 3 parts:
|
||||
</li>
|
||||
|
||||
</body>
|
||||
<!--
|
||||
vim: ts=2:et
|
||||
//-->
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user