diff --git a/fhem/FHEM/73_DoorBird.pm b/fhem/FHEM/73_DoorBird.pm
index c63829332..d868a9c81 100644
--- a/fhem/FHEM/73_DoorBird.pm
+++ b/fhem/FHEM/73_DoorBird.pm
@@ -59,6 +59,7 @@ use LWP::UserAgent;
use constant false => 0;
use constant true => 1;
use Data::Dumper;
+use File::Spec::Functions ':ALL';
###START###### Initialize module ##############################################################################START####
sub DoorBird_Initialize($)
@@ -89,6 +90,7 @@ sub DoorBird_Initialize($)
"VideoDurationDoorbell " .
"VideoDurationMotion " .
"VideoDurationKeypad " .
+ "HistoryFilePath:1,0 " .
"EventReset " .
"SessionIdSec:slider,0,10,600 " .
"WaitForHistory " .
@@ -188,6 +190,7 @@ sub DoorBird_Define($$)
$hash->{helper}{EventReset} = AttrVal($name, "EventReset", 5);
$hash->{helper}{WaitForHistory} = AttrVal($name, "WaitForHistory", 7);
$hash->{helper}{CameraInstalled} = false;
+ $hash->{helper}{HistoryFilePath} = 0;
$hash->{helper}{SessionId} = 0;
$hash->{helper}{UdpMessageId} = 0;
$hash->{helper}{UdpMotionId} = 0;
@@ -265,7 +268,7 @@ sub DoorBird_InitializeDevice($)
DoorBird_OpenSocketConn($hash);
### Initialize Readings
- DoorBird_Info_Request($hash, "");
+ DoorBird_Info_Request($hash, "");
DoorBird_Image_Request($hash, "");
DoorBird_Live_Video($hash, "off");
@@ -538,6 +541,30 @@ sub DoorBird_Attr(@)
$hash->{helper}{VideoDurationKeypad} = "0";
}
}
+ ### Check whether HistoryFilePath attribute has been provided
+ elsif ($a[2] eq "HistoryFilePath") {
+ ### Check whether HistoryFilePath is defined
+ if (defined($a[3])) {
+ ### Set helper in hash
+ $hash->{helper}{HistoryFilePath} = $a[3];
+
+ if ($a[3] == true) {
+ ### Update the history list for images and videos
+ DoorBird_History_List($hash);
+ }
+ else {
+ ### Delete all reading entries to files
+ fhem("deleteReading " . $name . " HistoryFilePath.*");
+ }
+ }
+ else {
+ ### Set helper in hash
+ $hash->{helper}{HistoryFilePath} = "0";
+
+ ### Delete all reading entries to files
+ fhem("deleteReading " . $name . " HistoryFilePath.*");
+ }
+ }
### Check whether VideoFileFormat attribute has been provided
elsif ($a[2] eq "VideoFileFormat") {
### Check whether VideoFileFormat is defined
@@ -907,6 +934,10 @@ sub DoorBird_Set($@)
### Call Subroutine and hand back return value
return DoorBird_Transmit_Audio($hash, $option)
}
+ ### TEST
+ elsif ($command eq "Test") {
+ DoorBird_History_List($hash);
+ }
### ADD OR CHANGE FAVORITE
### DELETE FAVORITE
### ADD OR UPDATE SCHEDULE ENTRY
@@ -2550,6 +2581,9 @@ sub DoorBird_Image_Request($$) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Image_Request - write file : Successfully written " . $ImageFileName;
+ ### Update the history list for images and videos
+ DoorBird_History_List($hash);
+
### Close file or write error message in log
close $fh or do {
### Log Entry
@@ -2771,6 +2805,9 @@ sub DoorBird_LastEvent_Image($$$) {
### Write Last Image into reading
readingsSingleUpdate($hash, $ReadingImage, $ImageFileName, 1);
+
+ ### Update the history list for images and videos
+ DoorBird_History_List($hash);
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - ImageData - event : " . length($ImageData);
@@ -3519,6 +3556,9 @@ sub DoorBird_History_Request_Parse($) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - write file : Successfully written " . $ImageFileName;
+ ### Update the history list for images and videos
+ DoorBird_History_List($hash);
+
### Close file or write error message in log
close $fh or do {
### Log Entry
@@ -3555,6 +3595,284 @@ sub DoorBird_History_Request_Parse($) {
}
####END####### Define Subfunction for HISTORY IMAGE REQUEST ####################################################END#####
+###START###### Define Subfunction for history list update as readings #########################################START####
+sub DoorBird_History_List($) {
+ my ($hash) = @_;
+
+ ### Obtain values from hash
+ my $name = $hash->{NAME};
+
+ ### If the HistoryFile List shall be created
+ if ($hash->{helper}{HistoryFilePath} == true) {
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List ___________________________________________________________";
+ Log3 $name, 5, $name. " : DoorBird_History_List - The HistoryList has been activated. Processing...";
+
+ ### Delete all older reading entries to files
+ #fhem("deleteReading " . $name . " HistoryFilePath.*", 1);
+
+ foreach my $DeleteReading (keys %{$hash->{READINGS}}) {
+ if ($DeleteReading =~ m/HistoryFilePath/ ){
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - Delete Reading : " . $DeleteReading;
+
+ ### Delete Reading
+ readingsDelete($hash, $DeleteReading);
+ }
+ }
+
+ ### Get current working directory
+ my $cwd = getcwd();
+
+ ### If the ImageFileDir has been defined and images are taken
+ if ((defined($hash->{helper}{ImageFileDir})) && (($hash->{helper}{ImageFileDir} =~ m/\/fhem\/www/)) || (($hash->{helper}{ImageFileDir} =~ m/\\fhem\\www/))){
+ my $ImageFileName;
+ my @ImageFileList;
+
+ ### If the path is given as UNIX file system format
+ if ($cwd =~ /\//) {
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - file system format : UNIX";
+
+ ### Find out whether it is an absolute path or an relative one (leading "/")
+ if ($hash->{helper}{ImageFileDir} =~ /^\//) {
+ $ImageFileName = $hash->{helper}{ImageFileDir};
+ }
+ else {
+ $ImageFileName = $cwd . "/" . $hash->{helper}{ImageFileDir};
+ }
+ }
+
+ ### If the path is given as Windows file system format
+ if ($hash->{helper}{ImageFileDir} =~ /\\/) {
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - file system format : WINDOWS";
+
+ ### Find out whether it is an absolute path or an relative one (containing ":\")
+ if ($hash->{helper}{ImageFileDir} != /^.:\//) {
+ $ImageFileName = $cwd . $hash->{helper}{ImageFileDir};
+ }
+ else {
+ $ImageFileName = $hash->{helper}{ImageFileDir};
+ }
+ }
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - ImageFileName : " . $ImageFileName;
+
+ ### Get list of directory items
+ if (opendir(FileSearch,$ImageFileName)) {
+ @ImageFileList = readdir(FileSearch);
+ close FileSearch;
+
+ ### Define Types to be searched for
+ my @FileTypes = ("motionsensor", "doorbell", "keypad", "snapshot", "manual");
+
+ readingsBeginUpdate($hash);
+
+ foreach my $SearchType (@FileTypes) {
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - SearchType : " . $SearchType;
+
+ ### Extract all Filenames which matches the SearchType
+ my @ImageFileListSearch = grep {/$SearchType/} @ImageFileList;
+
+ ### Extract all Filenames which matches the file extension
+ my @ImageFileListExt = grep {/jpg/} @ImageFileListSearch;
+
+ # Sort list
+ @ImageFileListExt=sort(@ImageFileListExt);
+
+ ### Get the last n elements (hash->{helper}{MaxHistory})
+ @ImageFileListExt = ($hash->{helper}{MaxHistory} >= @ImageFileListExt) ? @ImageFileListExt : @ImageFileListExt[-$hash->{helper}{MaxHistory}..-1];
+
+ # Sort list
+ @ImageFileListExt=sort({$b cmp $a} @ImageFileListExt);
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - ImageFileListSearch : \n" . Dumper(@ImageFileListExt);
+
+ ### Update Readings
+ my $index = 0;
+ foreach my $FileName (@ImageFileListExt){
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - FileName : " . $FileName;
+
+ ### Extract timestamp from Filename
+ my $TimeStamp = substr($FileName,0,4) . "-" . substr($FileName, 4,2) . "-" . substr($FileName, 6,2) . " ";
+ $TimeStamp .= substr($FileName,9,2) . ":" . substr($FileName,11,2) . ":" . substr($FileName,13,2);
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - TimeStamp : " . $TimeStamp;
+
+ ### Complete relative path from /opt/fhem/www/tablet to $hash->{helper}{ImageFileDir}
+ my $FilePath = abs2rel(rel2abs($ImageFileName), rel2abs("/opt/fhem/www/tablet"));
+ my $ReadingsValue = $FilePath . "/" . $FileName;
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - FilePath : " . $FilePath;
+
+ ### Create ReadingsName for Imagepath and write reading
+ my $ReadingsName = "HistoryFilePath_" . $SearchType . "_Image_" . sprintf("%02d", $index);
+ readingsBulkUpdate($hash, $ReadingsName, $ReadingsValue);
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - ReadingsName-Image : " . $ReadingsName;
+ Log3 $name, 5, $name. " : DoorBird_History_List - ReadingsValue-Image : " . $ReadingsValue;
+
+
+ ### Create ReadingsName for Timestamp and write reading
+ $ReadingsName = "HistoryFilePath_" . $SearchType . "_Image_" . sprintf("%02d", $index) . "_Timestamp";
+ readingsBulkUpdate($hash, $ReadingsName, $TimeStamp);
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - ReadingsName-Timestamp : " . $ReadingsName;
+ Log3 $name, 5, $name. " : DoorBird_History_List - ReadingsValue-Timestamp : " . $TimeStamp;
+
+ ### Increase Index
+ $index++;
+ }
+ }
+ }
+ else {
+ ### Log Entry for warning
+ Log3 $name, 2, $name. " : DoorBird_History_List - The Attribute \"ImageFileDir\" leads to an directory which produced an error! - Does it actually exist?";
+ }
+ }
+ else {
+ ### Log Entry for warning
+ Log3 $name, 4, $name. " : DoorBird_History_List - The ImageFileDir has not been provided or has not been created below the web-folder e.g. \"/opt/fhem/www/doorbird-images/\"";
+ }
+ ### If the VideoFileDir has been defined and Videos are taken
+ if ((defined($hash->{helper}{VideoFileDir})) && (($hash->{helper}{VideoFileDir} =~ m/\/fhem\/www/) || (($hash->{helper}{ImageFileDir} =~ m/\\fhem\\www/)))){
+ my $VideoFileName;
+ my @VideoFileList;
+
+ ### If the path is given as UNIX file system format
+ if ($cwd =~ /\//) {
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - file system format : UNIX";
+
+ ### Find out whether it is an absolute path or an relative one (leading "/")
+ if ($hash->{helper}{VideoFileDir} =~ /^\//) {
+ $VideoFileName = $hash->{helper}{VideoFileDir};
+ }
+ else {
+ $VideoFileName = $cwd . "/" . $hash->{helper}{VideoFileDir};
+ }
+ }
+
+ ### If the path is given as Windows file system format
+ if ($hash->{helper}{VideoFileDir} =~ /\\/) {
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - file system format : WINDOWS";
+
+ ### Find out whether it is an absolute path or an relative one (containing ":\")
+ if ($hash->{helper}{VideoFileDir} != /^.:\//) {
+ $VideoFileName = $cwd . $hash->{helper}{VideoFileDir};
+ }
+ else {
+ $VideoFileName = $hash->{helper}{VideoFileDir};
+ }
+ }
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - VideoFileName : " . $VideoFileName;
+
+ ### Get list of directory items
+ if (opendir(FileSearch,$VideoFileName)) {
+ @VideoFileList = readdir(FileSearch);
+ close FileSearch;
+
+ ### Define Types to be searched for
+ my @FileTypes = ("motionsensor", "doorbell", "keypad", "snapshot", "manual");
+
+ readingsBeginUpdate($hash);
+
+ foreach my $SearchType (@FileTypes) {
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - SearchType : " . $SearchType;
+
+ ### Extract all Filenames which matches the SearchType
+ my @VideoFileListSearch = grep {/$SearchType/} @VideoFileList;
+
+ ### Extract all Filenames which matches the file extension
+ my @VideoFileListExt = grep {/$hash->{helper}{VideoFileFormat}/} @VideoFileListSearch;
+
+ # Sort list
+ @VideoFileListExt=sort(@VideoFileListExt);
+
+ ### Get the last n elements (hash->{helper}{MaxHistory})
+ @VideoFileListExt = ($hash->{helper}{MaxHistory} >= @VideoFileListExt) ? @VideoFileListExt : @VideoFileListExt[-$hash->{helper}{MaxHistory}..-1];
+
+ # Sort list
+ @VideoFileListExt=sort({$b cmp $a} @VideoFileListExt);
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - VideoFileListSearch : \n" . Dumper(@VideoFileListExt);
+
+ ### Update Readings
+ my $index = 0;
+ foreach my $FileName (@VideoFileListExt){
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - FileName : " . $FileName;
+
+ ### Extract timestamp from Filename
+ my $TimeStamp = substr($FileName,0,4) . "-" . substr($FileName, 4,2) . "-" . substr($FileName, 6,2) . " ";
+ $TimeStamp .= substr($FileName,9,2) . ":" . substr($FileName,11,2) . ":" . substr($FileName,13,2);
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - TimeStamp : " . $TimeStamp;
+
+ ### Complete relative path from /opt/fhem/www/tablet to $hash->{helper}{VideoFileDir}
+ my $FilePath = abs2rel(rel2abs($VideoFileName), rel2abs("/opt/fhem/www/tablet"));
+ my $ReadingsValue = $FilePath . "/" . $FileName;
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - FilePath : " . $FilePath;
+
+ ### Create ReadingsName for Videopath and write reading
+ my $ReadingsName = "HistoryFilePath_" . $SearchType . "_Video_" . sprintf("%02d", $index);
+ readingsBulkUpdate($hash, $ReadingsName, $ReadingsValue);
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - ReadingsName-Video : " . $ReadingsName;
+ Log3 $name, 5, $name. " : DoorBird_History_List - ReadingsValue-Video : " . $ReadingsValue;
+
+
+ ### Create ReadingsName for Timestamp and write reading
+ $ReadingsName = "HistoryFilePath_" . $SearchType . "_Video_" . sprintf("%02d", $index) . "_Timestamp";
+ readingsBulkUpdate($hash, $ReadingsName, $TimeStamp);
+
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - ReadingsName-Timestamp : " . $ReadingsName;
+ Log3 $name, 5, $name. " : DoorBird_History_List - ReadingsValue-Timestamp : " . $TimeStamp;
+
+ ### Increase Index
+ $index++;
+ }
+ }
+ }
+ else {
+ ### Log Entry for warning
+ Log3 $name, 2, $name. " : DoorBird_History_List - The Attribute \"VideoFileDir\" leads to an directory which produced an error! - Does it actually exist?";
+ }
+ }
+ else {
+ ### Log Entry for warning
+ Log3 $name, 4, $name. " : DoorBird_History_List - The VideoFileDir has not been provided or has not been created below the web-folder e.g. \"/opt/fhem/www/doorbird-videos/\"";
+ }
+
+ ### Initiate Readings Update
+ readingsEndUpdate($hash, 1);
+ }
+ else {
+ ### Log Entry for debugging purposes
+ Log3 $name, 5, $name. " : DoorBird_History_List - The HistoryList has been disabled. Not Links to pictures are provided.";
+ }
+}
+####END####### Define Subfunction for history list update as readings ##########################################END#####
+
###START###### Define Subfunction for VIDEO REQUEST ###########################################################START####
sub DoorBird_Video_Request($$$$) {
my ($hash, $duration, $event, $timestamp) = @_;
@@ -3709,6 +4027,9 @@ sub DoorBird_Video_Request($$$$) {
### Log Entry for debugging purposes
Log3 $name, 2, $name. " : DoorBird_Video_Request - Video-Request ha not been implemented for Windows file system. Contact fhem forum and WIKI.";
}
+
+ ### Update the history list for images and videos after the video has been taken
+ InternalTimer(gettimeofday()+$duration+3,"DoorBird_History_List", $hash, 0);
}
### If attribute to video directory has NOT been set
else {
@@ -4163,6 +4484,22 @@ sub DoorBird_BlockGet($$$$) {
}
####END####### Blocking Get ####################################################################################END#####
+###START###### Calculate relative path ########################################################################START####
+sub DoorBird_Rel_Path($$) {
+ my ($start,$target) = @_;
+ $start =~ s:/[^/]+:/:; # remove trailing filename
+ my @spath = grep {$_ ne ''} split(/\//,$start);
+ my @tpath = grep {$_ ne ''} split(/\//,$target);
+
+ # strip common start of the path
+ while ( @spath && @tpath && $spath[0] eq $tpath[0]) {
+ shift @spath;
+ shift @tpath;
+ }
+
+ return ("../"x(@spath)).join('/', @tpath);
+}
+####END####### Calculate relative path #########################################################################END#####
###START###### Processing Change Log ##########################################################################START####
# Changelog parser for DoorBird changelog as of 2020-02-22 (or earlier) containing multiple product lines.
@@ -4436,7 +4773,13 @@ sub DoorBird_findNewestFWVersion($$$)
OpsModeList :
"" = disabledHistoryFilePath : "0" = disabledOpsModeList : HistoryFilePath : "0" = disabled