History of events - Last download: ' . $hash->{helper}{HistoryTime} . '
Doorbell
Motion-Sensor
Picture
Timestamp
#
Picture
Timestamp
';
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_FW_detailFn - hash->{helper}{MaxHistory} : " . $hash->{helper}{MaxHistory};
### For all entries in Picture-Array do
for (my $i=0; $i <= ($hash->{helper}{MaxHistory} - 1); $i++) {
my $ImageHtmlCodeDoorbell;
my $ImageHtmlCodeMotion;
### Create proper html code for image triggered by doorbell
if ($HistoryDoorbell[$i]{data} ne "") {
### If element contains an error message
if ($HistoryDoorbell[$i]{data} =~ m/Error/) {
$ImageHtmlCodeDoorbell = $HistoryDoorbell[$i]{data};
}
### If element does not contain an error message
else {
### Create proper html code including popup
my $ImageHtmlCodeBig = "
" . $HistoryDoorbell[$i]{timestamp} . "
";
my $PopupfunctionCode = "onclick=\"FW_okDialog(\'" . $ImageHtmlCodeBig . "\') \" ";
$ImageHtmlCodeDoorbell = '';
}
}
else {
$ImageHtmlCodeDoorbell = 'No image available';
}
### Create proper html code for image triggered by motionsensor
if ($HistoryMotion[$i]{data} ne "") {
### If element contains an error message
if ($HistoryMotion[$i]{data} =~ m/Error/) {
$ImageHtmlCodeMotion = $HistoryMotion[$i]{data};
}
### If element does not contain an error message
else {
### Create proper html code including popup
my $ImageHtmlCodeBig = "
$info"
# TestDescription')\">Testtitle
return($htmlCode );
}
####END####### Display of html code preceding the "Internals"-section ##########################################END#####
###START###### Define Subfunction for INFO REQUEST ############################################################START####
sub DoorBird_Info_Request($$) {
my ($hash, $option) = @_;
my $name = $hash->{NAME};
my $command = "info.cgi";
my $method = "GET";
my $header = "Accept: application/json";
my $err = " ";
my $data = " ";
my $json;
### Obtain data
($err, $data) = DoorBird_BlockGet($hash, $command, $method, $header);
### Remove Newlines for better log entries
my $ShowData = $data;
$ShowData =~ s/[\t]//g;
$ShowData =~ s/[\r]//g;
$ShowData =~ s/[\n]//g;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Info_Request - err : " . $err if(defined($err));
Log3 $name, 5, $name. " : DoorBird_Info_Request - data : " . $ShowData if(defined($ShowData));
### If no error has been handed back
if ($err eq "") {
### If the option is asking for the JSON string
if (defined($option) && ($option =~ /JSON/i)) {
return $data;
}
### If the option is asking for nothing special
else {
### Check if json can be parsed into hash
eval
{
$json = decode_json(encode_utf8($data));
1;
}
or do
{
### Log Entry for debugging purposes
Log3 $name, 3, $name. " : DoorBird_Info_Request - Data cannot parsed JSON : Info_Request";
return $name. " : DoorBird_Info_Request - Data cannot be parsed by JSON for Info_Request";
};
my $VersionContent = $json-> {BHA}{VERSION}[0];
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Info_Request - json : " . $json;
### Initiate Bulk Update
readingsBeginUpdate($hash);
foreach my $key (keys %{$VersionContent}) {
### If the entry are information about connected relays
if ( $key eq "RELAYS") {
### Save adresses of relays into hash
@{$hash->{helper}{RelayAdresses}} = @{$VersionContent -> {$key}};
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Info_Request - No of connected relays : " . @{$VersionContent -> {$key}};
Log3 $name, 5, $name. " : DoorBird_Info_Request - Adresses of relays : " . join(",", @{$VersionContent -> {$key}});
Log3 $name, 5, $name. " : DoorBird_Info_Request - {helper}{RelayAdresses} : " . join(",", @{$hash->{helper}{RelayAdresses}});
### Delete all Readings for Relay-Addresses
readingsDelete($hash, "RelayAddr_.*");
### For all registred relays do
my $RelayNumber =0;
foreach my $RelayAddress (@{$VersionContent -> {$key}}) {
$RelayNumber++;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Info_Request - Adress of " . sprintf("%15s %-s", "Relay_" . sprintf("%02d", $RelayNumber), ": " . $RelayAddress);
### Update Reading
readingsBulkUpdate($hash, "RelayAddr_" . sprintf("%02d", $RelayNumber), $RelayAddress);
}
}
### For all other entries
else {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Info_Request - Content of" . sprintf("%15s %-s", $key, ": " . $VersionContent -> {$key});
### Update Reading
readingsBulkUpdate($hash, $key, $VersionContent -> {$key} );
}
}
### Update Reading for Firmware-Status
readingsBulkUpdate($hash, "Firmware-Status", "up-to-date");
### Execute Readings Bulk Update
readingsEndUpdate($hash, 1);
### Download SIP Status Request
DoorBird_SipStatus_Request($hash,"");
### Check for Firmware-Updates
DoorBird_FirmwareStatus($hash);
return "Readings have been updated!\n";
}
}
### If error has been handed back
else {
$err =~ s/^[^ ]*//;
return "ERROR!\nError Code:" . $err;
}
}
####END####### Define Subfunction for INFO REQUEST #############################################################END#####
###START###### Firmware-Update Status for DorBird unit ########################################################START####
sub DoorBird_FirmwareStatus($) {
my ($hash) = @_;
### Obtain values from hash
my $name = $hash->{NAME};
### Create Timestamp
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
my $TimeStamp = sprintf ( "%04d-%02d-%02d %02d:%02d:%02d",$year+1900, $mon+1, $mday, $hour, $min, $sec);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_FirmwareStatus - Checking firmware status on doorbird page";
my $FirmwareVersionUnit = ReadingsVal($name, "FIRMWARE", 0);
### Download website of changelocks
my $html = GetFileFromURL("https://www.doorbird.com/changelog");
### Get the latest firmware number
my $result;
if ($html =~ /(?<=Firmware version )(.*)(?=\n=====)/) {
$result = $1;
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_FirmwareStatus - result : " . $result;
### If the latest Firmware is installed
if (int($FirmwareVersionUnit) == int($result)) {
### Update Reading for Firmware-Status
readingsSingleUpdate($hash, "Firmware-Status", "up-to-date", 1);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_FirmwareStatus - Latest firmware is installed!";
}
### If the latest Firmware is NOT installed
elsif (int($FirmwareVersionUnit) < int($result)) {
### Update Reading for Firmware-Status
readingsSingleUpdate($hash, "Firmware-Status", "Firmware update required!", 1);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_FirmwareStatus - DoorBird requires firmware update!";
}
### Something went wrong
else {
### Update Reading for Firmware-Status
readingsSingleUpdate($hash, "Firmware-Status", "unknown", 1);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_FirmwareStatus - An error occured!";
}
return;
}
####END####### Firmware-Update Status for DorBird unit #########################################################END#####
###START###### Define Subfunction for LIVE VIDEO REQUEST ######################################################START####
sub DoorBird_Live_Video($$) {
my ($hash, $option) = @_;
### Obtain values from hash
my $name = $hash->{NAME};
my $url = $hash->{helper}{URL};
### Create complete command URL for DoorBird depending on whether SessionIdSecurity has been enabled (>0) or disabled (=0)
my $UrlPrefix = "http://" . $url . "/bha-api/";
my $UrlPostfix;
if ($hash->{helper}{SessionIdSec} > 0) {
$UrlPostfix = "?sessionid=" . $hash->{helper}{SessionId};
}
else {
my $username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
my $password = DoorBird_credential_decrypt($hash->{helper}{".PASSWORD"});
$UrlPostfix = "?http-user=". $username . "&http-password=" . $password;
}
my $VideoURL = $UrlPrefix . "video.cgi" . $UrlPostfix;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Live_Video - VideoURL : " . $VideoURL ;
Log3 $name, 5, $name. " : DoorBird_Live_Video - VideoURL : Created";
### If VideoStreaming shall be switched ON
if ($option eq "on") {
### Update Reading
readingsSingleUpdate($hash, ".VideoURL", $VideoURL, 1);
### Refresh Browser Window
FW_directNotify("#FHEMWEB:$FW_wname", "location.reload()", "") if defined($FW_wname);
}
### If VideoStreaming shall be switched OFF
elsif ($option eq "off") {
### Update Reading
readingsSingleUpdate($hash, ".VideoURL", "", 1);
### Refresh Browser Window
FW_directNotify("#FHEMWEB:$FW_wname", "location.reload()", "") if defined($FW_wname);
}
### If wrong parameter has been transfered
else
{
### Do nothing - Just return
return("ERROR!\nWrong Parameter used");
}
return
}
####END####### Define Subfunction for LIVE VIDEO REQUEST #######################################################END#####
###START###### Define Subfunction for LIVE AUDIO REQUEST ######################################################START####
sub DoorBird_Live_Audio($$) {
my ($hash, $option) = @_;
### Obtain values from hash
my $name = $hash->{NAME};
my $url = $hash->{helper}{URL};
### Create complete command URL for DoorBird depending on whether SessionIdSecurity has been enabled (>0) or disabled (=0)
my $UrlPrefix = "http://" . $url . "/bha-api/";
my $UrlPostfix;
if ($hash->{helper}{SessionIdSec} > 0) {
$UrlPostfix = "?sessionid=" . $hash->{helper}{SessionId};
}
else {
my $username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
my $password = DoorBird_credential_decrypt($hash->{helper}{".PASSWORD"});
$UrlPostfix = "?http-user=". $username . "&http-password=" . $password;
}
my $AudioURL = $UrlPrefix . "audio-receive.cgi" . $UrlPostfix;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Live_Audio - AudioURL : " . $AudioURL ;
### If AudioStreaming shall be switched ON
if ($option eq "on") {
### Update Reading
readingsSingleUpdate($hash, ".AudioURL", $AudioURL, 1);
### Refresh Browser Window
FW_directNotify("#FHEMWEB:$FW_wname", "location.reload()", "") if defined($FW_wname);
}
### If AudioStreaming shall be switched OFF
elsif ($option eq "off") {
### Update Reading
readingsSingleUpdate($hash, ".AudioURL", "", 1);
### Refresh Browser Window
FW_directNotify("#FHEMWEB:$FW_wname", "location.reload()", "") if defined($FW_wname);
}
### If wrong parameter has been transfered
else
{
### Do nothing - Just return
return("ERROR!\nWrong Parameter used");
}
return
}
####END####### Define Subfunction for LIVE VIDEO REQUEST #######################################################END#####
###START###### Define Subfunction for LIVE IMAGE REQUEST ######################################################START####
sub DoorBird_Image_Request($$) {
my ($hash, $option) = @_;
### Obtain values from hash
my $name = $hash->{NAME};
my $username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
my $password = DoorBird_credential_decrypt($hash->{helper}{".PASSWORD"});
my $url = $hash->{helper}{URL};
my $command = "image.cgi";
my $method = "GET";
my $header = "Accept: application/json";
my $err = " ";
my $data = " ";
my $json = " ";
my $ImageFileName = " ";
### Create complete command URL for DoorBird
my $UrlPrefix = "https://" . $url . "/bha-api/";
my $UrlPostfix = "?http-user=". $username . "&http-password=" . $password;
my $ImageURL = $UrlPrefix . $command . $UrlPostfix;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Image_Request _____________________________________________________________";
# Log3 $name, 5, $name. " : DoorBird_Image_Request - ImageURL : " . $ImageURL ;
### Update Reading
readingsSingleUpdate($hash, ".ImageURL", $ImageURL, 1);
### Get Image Data
($err, $data) = DoorBird_BlockGet($hash, $command, $method, $header);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Image_Request - err : " . $err;
# Log3 $name, 5, $name. " : DoorBird_Image_Request - data : " . $data;
### Encode jpeg data into base64 data and remove lose newlines
my $ImageData = MIME::Base64::encode($data);
$ImageData =~ s{\n}{}g;
### Create Timestamp
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
my $ImageTimeStamp = sprintf ( "%04d-%02d-%02d %02d:%02d:%02d",$year+1900, $mon+1, $mday, $hour, $min, $sec);
my $ImageFileTimeStamp = sprintf ( "%04d%02d%02d-%02d%02d%02d" ,$year+1900, $mon+1, $mday, $hour, $min, $sec);
### Save picture and timestamp into hash
$hash->{helper}{Images}{Individual}{Data} = $ImageData;
$hash->{helper}{Images}{Individual}{Timestamp} = $ImageTimeStamp;
### Refresh Browser Window
FW_directNotify("#FHEMWEB:$FW_wname", "location.reload()", "") if defined($FW_wname);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Image_Request - hash - ImageFileDir : " . $hash->{helper}{ImageFileDir};
### If pictures supposed to be saved as files
if ($hash->{helper}{ImageFileDir} ne "0") {
### Get current working directory
my $cwd = getcwd();
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Image_Request - working directory : " . $cwd;
### If the path is given as UNIX file system format
if ($cwd =~ /\//) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Image_Request - file system format : LINUX";
### 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};
}
### Check whether the last "/" at the end of the path has been given otherwise add it an create complete path
if ($hash->{helper}{ImageFileDir} =~ /\/\z/) {
$ImageFileName .= $ImageFileTimeStamp . "_snapshot.jpg";
}
else {
$ImageFileName .= "/" . $ImageFileTimeStamp . "_snapshot.jpg";
}
}
### If the path is given as Windows file system format
if ($hash->{helper}{ImageFileDir} =~ /\\/) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Image_Request - 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};
}
### Check whether the last "/" at the end of the path has been given otherwise add it an create complete path
if ($hash->{helper}{ImageFileDir} =~ /\\\z/) {
$ImageFileName .= $ImageFileTimeStamp . "_snapshot.jpg";
}
else {
$ImageFileName .= "\\" . $ImageFileTimeStamp . "_snapshot.jpg";
}
}
### Save filename of last snapshot into hash
$hash->{helper}{Images}{LastSnapshotPath} = $ImageFileName;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Image_Request - ImageFileName : " . $ImageFileName;
### Open file or write error message in log
open my $fh, ">", $ImageFileName or do {
### Log Entry
Log3 $name, 2, $name. " : DoorBird_Image_Request - open file error : " . $! . " - ". $ImageFileName;
};
### Write the base64 decoded data in file
print $fh decode_base64($ImageData) if defined($fh);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Image_Request - write file : Successfully written " . $ImageFileName;
### Close file or write error message in log
close $fh or do {
### Log Entry
Log3 $name, 2, $name. " : DoorBird_Image_Request - close file error : " . $! . " - ". $ImageFileName;
}
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Image_Request - ImageData size : " . length($ImageData);
Log3 $name, 5, $name. " : DoorBird_Image_Request - ImageTimeStamp : " . $ImageTimeStamp;
return;
}
####END####### Define Subfunction for LIVE IMAGE REQUEST #######################################################END#####
###START###### Define Subfunction for LAST EVENT IMAGE REQUEST ################################################START####
sub DoorBird_LastEvent_Image($$$) {
my ($param, $err, $data) = @_;
my $hash = $param->{hash};
### Obtain values from hash
my $name = $hash->{NAME};
my $event = $param->{event};
my $timestamp = $param->{timestamp};
my $ReadingImage;
if ($event =~ m/doorbell/ ){
$ReadingImage = "doorbell_snapshot_" . sprintf("%03d", $param->{doorbellNo});
}
elsif ($event =~ m/motion/ ){
$ReadingImage = "motion_snapshot";
}
elsif ($event =~ m/keypad/ ){
$ReadingImage = "keypad_snapshot";
}
else {
### Create Log entry
Log3 $name, 2, $name. " : DoorBird_LastEvent_Image - Unknown event. Breaking up";
### Exit sub
return
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image ___________________________________________________________";
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - err : " . $err if (defined($err ));
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - length data : " . length($data) if (defined($data ));
#Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - param : " . join("\n", @{[%{$param}]}) if (defined($param));
### If error message available
if ($err ne "") {
### Create Log entry
Log3 $name, 3, $name. " : DoorBird_LastEvent_Image - Error : " . $err if (defined($err ));
### Write Last Image into reading
readingsSingleUpdate($hash, $ReadingImage, "No image data", 1);
}
### if no error message available
else {
### If any image data available
if (defined $data) {
### Predefine Image Data and Image-hash and hash - reference
my $ImageData;
my $ImageTimeStamp;
my $ImageFileTimeStamp;
my $ImageFileName;
my %ImageDataHash;
my $ref_ImageDataHash = \%ImageDataHash;
### If http response code is 200 = OK
if ($param->{code} == 200) {
### Encode jpeg data into base64 data and remove lose newlines
$ImageData = MIME::Base64::encode($data);
$ImageData =~ s{\n}{}g;
### Create Timestamp
my $httpHeader = $param->{httpheader};
$httpHeader =~ s/^[^_]*X-Timestamp: //;
$httpHeader =~ s/\n.*//g;
### If timestamp from history image has NOT been done since the timestamp from the event
if ((int($timestamp) - int($httpHeader)) > 0){
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - timestamp from history image has NOT been done since the timestamp from the event.";
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - Image timestamp : " . $httpHeader;
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - Event timestamp : " . $timestamp;
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - dt : " . (int($timestamp) - int($httpHeader));
### If timestamp from the event is NOT older than WaitForHistory from current time => Try again
if ((time - int($timestamp)) <= $hash->{helper}{WaitForHistory}){
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - timestamp of event is not older than Attribute WaitForHistory: Still time to try again";
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - Event timestamp : " . $timestamp;
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - current timestamp : " . time;
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - Attr WaitForHistory : " . $hash->{helper}{WaitForHistory};
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - dt : " . int(time - int($timestamp));
### Try again: Initiate communication and close
HttpUtils_NonblockingGet($param);
### Exit routine
return;
}
else {
### Log Entry for debugging purposes
Log3 $name, 2, $name. " : DoorBird_LastEvent_Image - timestamp of event is older than than Attribute WaitForHistory: Proceeding without waiting any longer...";
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - Event timestamp : " . $timestamp;
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - current timestamp : " . time;
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - Attr WaitForHistory : " . $hash->{helper}{WaitForHistory};
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - dt : " . int(time - int($timestamp));
### Write Last Image into reading
readingsSingleUpdate($hash, $ReadingImage, "No image data", 1);
}
}
### If timestamp from history picture has been done since the timestamp from the event
else {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - timestamp from history image has been done since the timestamp from the event.";
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - Image timestamp : " . $httpHeader;
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - Event timestamp : " . $timestamp;
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - dt : " . (int($timestamp) - int($httpHeader));
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($httpHeader);
$ImageTimeStamp = sprintf ( "%04d-%02d-%02d %02d:%02d:%02d",$year+1900, $mon+1, $mday, $hour, $min, $sec);
$ImageFileTimeStamp = sprintf ( "%04d%02d%02d-%02d%02d%02d" ,$year+1900, $mon+1, $mday, $hour, $min, $sec);
### Save picture and timestamp into hash
$hash->{helper}{Images}{Individual}{Data} = $ImageData;
$hash->{helper}{Images}{Individual}{Timestamp} = $ImageTimeStamp;
### Refresh Browser Window
FW_directNotify("#FHEMWEB:$FW_wname", "location.reload()", "") if defined($FW_wname);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - hash - ImageFileDir : " . $hash->{helper}{ImageFileDir};
### If pictures supposed to be saved as files
if ($hash->{helper}{ImageFileDir} ne "0") {
### Get current working directory
my $cwd = getcwd();
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - working directory : " . $cwd;
### If the path is given as UNIX file system format
if ($cwd =~ /\//) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - file system format : LINUX";
### 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};
}
### Check whether the last "/" at the end of the path has been given otherwise add it an create complete path
if ($hash->{helper}{ImageFileDir} =~ /\/\z/) {
$ImageFileName .= $ImageFileTimeStamp . "_" . $event . ".jpg";
}
else {
$ImageFileName .= "/" . $ImageFileTimeStamp . "_" . $event . ".jpg";
}
}
### If the path is given as Windows file system format
if ($hash->{helper}{ImageFileDir} =~ /\\/) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - 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};
}
### Check whether the last "/" at the end of the path has been given otherwise add it an create complete path
if ($hash->{helper}{ImageFileDir} =~ /\\\z/) {
$ImageFileName .= $ImageFileTimeStamp . "_" . $event . ".jpg";
}
else {
$ImageFileName .= "\\" . $ImageFileTimeStamp . "_" . $event . ".jpg";
}
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - ImageFileName : " . $ImageFileName;
### Open file or write error message in log
open my $fh, ">", $ImageFileName or do {
### Log Entry
Log3 $name, 2, $name. " : DoorBird_LastEvent_Image - open file error : " . $! . " - ". $ImageFileName;
};
### Write the base64 decoded data in file
print $fh decode_base64($ImageData) if defined($fh);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - write file : Successfully written " . $ImageFileName;
### Close file or write error message in log
close $fh or do {
### Log Entry
Log3 $name, 2, $name. " : DoorBird_LastEvent_Image - close file error : " . $! . " - ". $ImageFileName;
};
### Write Last Image into reading
readingsSingleUpdate($hash, $ReadingImage, $ImageFileName, 1);
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - ImageData - event : " . length($ImageData);
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - Type of event : " . $event;
}
### If http response code is 204 = No permission to download the event history
elsif ($param->{code} == 204) {
### Create Log entry
Log3 $name, 3, $name. " : DoorBird_LastEvent_Image - Error 204 : User not authorized to download event history";
### Create Error message
$ImageData = "Error 204: The user has no permission to download the event history.";
$ImageTimeStamp =" ";
### Write Last Image into reading
readingsSingleUpdate($hash, $ReadingImage, "No image data", 1);
}
### If http response code is 404 = No picture available to download the event history
elsif ($param->{code} == 404) {
### Create Log entry
Log3 $name, 5, $name. " : DoorBird_LastEvent_Image - Error 404 : No picture available to download event history. Check settings in DoorBird APP.";
### Create Error message
$ImageData = "Error 404: No picture available to download in the event history.";
$ImageTimeStamp =" ";
### Write Last Image into reading
readingsSingleUpdate($hash, $ReadingImage, "No image data", 1);
}
### If http response code is none of one above
else {
### Create Log entry
Log3 $name, 3, $name. " : DoorBird_LastEvent_Image - Unknown http response code : " . $param->{code};
### Create Error message
$ImageData = "Error : " . $param->{code};
$ImageTimeStamp =" ";
### Write Last Image into reading
readingsSingleUpdate($hash, $ReadingImage, "No image data", 1);
}
}
else {
### Write Last Image into reading
readingsSingleUpdate($hash, $ReadingImage, "No image data", 1);
}
}
return;
}
####END####### Define Subfunction for LAST EVENT IMAGE REQUEST #################################################END#####
###START###### Define Subfunction for OPEN DOOR ###############################################################START####
sub DoorBird_Open_Door($$) {
my ($hash, $option) = @_;
my $name = $hash->{NAME};
my $command = "open-door.cgi?r=" . $option;
my $method = "GET";
my $header = "Accept: application/json";
my $username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
my $err;
my $data;
my $json;
### Activate Relay
($err, $data) = DoorBird_BlockGet($hash, $command, $method, $header);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Open_Door - err : " . $err;
Log3 $name, 5, $name. " : DoorBird_Open_Door - data : " . $data;
### If no error message is available
if ($err eq "") {
### Check if json can be parsed into hash
eval {
$json = decode_json(encode_utf8($data));
1;
}
or do {
### Log Entry for debugging purposes
Log3 $name, 3, $name. " : DoorBird_Open_Door - Data cannot be parsed by JSON for: Open_Door";
return $name. " : DoorBird_Open_Door - Data cannot be parsed by JSON for Open_Door";
};
### Create return messages and log entries based on error codes returned
if ($json->{BHA}{RETURNCODE} eq "1") {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Open_Door - Door ". $option . " successfully triggered.";
### Create popup message
return "Door ". $option . " successful triggered.";
}
elsif ($json->{BHA}{RETURNCODE} eq "204") {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Open_Door - Error 204: The user " . $username . "has no “watch-always” - permission to open the door.";
### Create popup message
return "Error 204: The user " . $username . "has no “watch-always” - permission to open the door.";
}
else {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Light_On - ERROR! - Return Code:" . $json->{BHA}{RETURNCODE};
return "ERROR!\nReturn Code:" . $json->{BHA}{RETURNCODE};
}
}
### If error message is available
else {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Light_On - ERROR! - Error Code:" . $err;
### Create error message
$err =~ s/^[^ ]*//;
return "ERROR!\nError Code:" . $err;
}
}
####END####### Define Subfunction for OPEN DOOR ################################################################END#####
###START###### Define Subfunction for LIGHT ON ################################################################START####
sub DoorBird_Light_On($$) {
my ($hash, $option) = @_;
my $name = $hash->{NAME};
my $command = "light-on.cgi";
my $method = "GET";
my $header = "Accept: application/json";
my $username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
my $err;
my $data;
my $json;
### Activate Relay
($err, $data) = DoorBird_BlockGet($hash, $command, $method, $header);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Light_On - err : " . $err;
Log3 $name, 5, $name. " : DoorBird_Light_On - data : " . $data;
### If no error message is available
if ($err eq "") {
### Check if json can be parsed into hash
eval {
$json = decode_json(encode_utf8($data));
1;
}
or do {
### Log Entry for debugging purposes
Log3 $name, 3, $name. " : DoorBird_Light_On - Data cannot be parsed by JSON for: Light_On";
return $name. " : DoorBird_Light_On - Data cannot be parsed by JSON for Light_On";
};
### Create return messages and log entries based on error codes returned
if ($json->{BHA}{RETURNCODE} eq "1") {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Light_On - Light successfully triggered.";
### Create popup message
return "Light successful triggered.";
}
elsif ($json->{BHA}{RETURNCODE} eq "204") {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Light_On - Error 204: The user " . $username . "has no “watch-always” - permission to switch the light ON.";
### Create popup message
return "Error 204: The user " . $username . "has no “watch-always” - permission to switch the light ON.";
}
else {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Light_On - ERROR! - Return Code:" . $json->{BHA}{RETURNCODE};
return "ERROR!\nReturn Code:" . $json->{BHA}{RETURNCODE};
}
}
### If error message is available
else {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Light_On - ERROR! - Error Code:" . $err;
### Create error message
$err =~ s/^[^ ]*//;
return "ERROR!\nError Code:" . $err;
}
}
####END####### Define Subfunction for LIGHT ON #################################################################END#####
###START###### Define Subfunction for LIVE AUDIO TRANSMIT #####################################################START####
sub DoorBird_Transmit_Audio($$) {
my ($hash, $option) = @_;
### Obtain values from hash
my $name = $hash->{NAME};
my $Username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
my $Password = DoorBird_credential_decrypt($hash->{helper}{".PASSWORD"});
my $Url = $hash->{helper}{URL};
my $Sox = $hash->{helper}{SOX};
my $SipDevice = $hash->{helper}{SipDevice};
my $SipNumber = $hash->{helper}{SipNumber};
my $AudioDataPathOrig = $option;
my @ListSipDevices = devspec2array("TYPE=SIP");
my $err;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - ---------------------------------------------------------------";
### If device of TYPE = SIP exists
if (@ListSipDevices > 0) {
### If file exists
if (-e $AudioDataPathOrig) {
### Create new filepath from old filepath
my $AudioDataNew;
my $AudioDataSizeNew;
my $AudioDataPathNew = $AudioDataPathOrig;
$AudioDataPathNew =~ s/\..*//;
my $AudioDataPathTemp = $AudioDataPathNew . "_tmp.wav";
$AudioDataPathNew .= ".ulaw";
### Delete future new file and temporary file if exist
unlink($AudioDataPathTemp);
unlink($AudioDataPathNew);
### Create Sox - command
my $SoxCmd = $Sox . " -V " . $AudioDataPathOrig . " -r 8000 -b 8 -c 1 -e u-law " . $AudioDataPathTemp;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - Original Path exists : " . $AudioDataPathOrig;
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - Temp Path created : " . $AudioDataPathTemp;
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - New Path created : " . $AudioDataPathNew;
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - Sox System-Command : " . $SoxCmd;
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - SipDeviceAttribute : " . $SipDevice;
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - SipNumber : " . $SipNumber;
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - ListSipDevices : " . Dumper(@ListSipDevices);
### Convert file
system ($SoxCmd);
### Rename temporary file in .ulaw
$err = rename($AudioDataPathTemp, $AudioDataPathNew);
### Get new filesize
$AudioDataSizeNew = -s $AudioDataPathNew;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - New Filesize : " . $AudioDataSizeNew;
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - rename response message : " . $err;
### If the a name for a SIP - TYPE device has been provided as per attribute
if (defined($SipDevice)) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - Attribute for SIP device: " . $SipDevice;
### If SIP device provided in attribute exists
if (defined($defs{$SipDevice})) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - SIP device in Attribute exists";
}
### If SIP device provided in attribute does NOT exists
else {
### Take the first available SIP device
$SipDevice= $ListSipDevices[0];
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - SIP device in Attribute does NOT exist";
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - SipDevice chosen : " . $SipDevice;
}
}
### If the a name for a SIP - TYPE device has NOT been provided as per attribute
else {
### Take the first available SIP device
$SipDevice= $ListSipDevices[0];
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - SIP device has not been provided in Attribute";
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - SipDevice chosen : " . $SipDevice;
}
### Use SIP device and transfer filepath
my $FhemCommand = "set " . $SipDevice . " call " . $SipNumber . " 30 " . $AudioDataPathNew;
fhem($FhemCommand);
return "The audio file: " . $AudioDataPathOrig . " has been passed to the fhem device " . $SipDevice;
}
### If Filepath does not exist
else {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Transmit_Audio - Path doesn't exist : " . $AudioDataPathOrig;
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - ---------------------------------------------------------------";
return "The audio file: " . $AudioDataPathOrig . " does not exist!"
}
}
### If no device TYPE = SIP exists
else {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Transmit_Audio - No device with TYPE=SIP exists. Install SIP device first";
Log3 $name, 5, $name. " : DoorBird_Transmit_Audio - ---------------------------------------------------------------";
return "No device with TYPE=SIP exists. Install SIP device first"
}
}
####END####### Define Subfunction for LIVE AUDIO TRANSMIT ######################################################END#####
###START###### Define Subfunction for HISTORY IMAGE REQUEST ###################################################START####
### https://wiki.fhem.de/wiki/HttpUtils#HttpUtils_NonblockingGet
sub DoorBird_History_Request($$) {
my ($hash, $option) = @_;
### Obtain values from hash
my $Name = $hash->{NAME};
my $Username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
my $Password = DoorBird_credential_decrypt($hash->{helper}{".PASSWORD"});
my $PollingTimeout = $hash->{helper}{PollingTimeout};
my $url = $hash->{helper}{URL};
my $Method = "GET";
my $Header = "Accept: application/json";
my $err;
my $data;
my $UrlPostfix;
my $CommandURL;
### Create Timestamp
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
my $ImageTimeStamp = sprintf ( "%04d-%02d-%02d %02d:%02d:%02d",$year+1900, $mon+1, $mday, $hour, $min, $sec);
### Create first part command URL for DoorBird
my $UrlPrefix = "https://" . $url . "/bha-api/";
### If the Itereation is started for the first time = new polling
if ($hash->{helper}{HistoryDownloadCount} == 0) {
### Delete arrays of pictures
@{$hash->{helper}{Images}{History}{doorbell}} = ();
@{$hash->{helper}{Images}{History}{motionsensor}} = ();
$hash->{helper}{HistoryTime} = $ImageTimeStamp;
$hash->{helper}{HistoryDownloadActive} = true;
}
### Define STATE message
my $CountDown = $hash->{helper}{MaxHistory}*2 - $hash->{helper}{HistoryDownloadCount};
### Update STATE of device
readingsSingleUpdate($hash, "state", "Downloading history: " . $CountDown, 1);
### Create the URL Index which is identical every 2nd: 1 1 2 2 3 3 4 4 5 5 6 6
my $UrlIndex=int(int($hash->{helper}{HistoryDownloadCount})/int(2))+1;
### As long the maximum ammount of Images for history events is not reached
if ($UrlIndex <= $hash->{helper}{MaxHistory}) {
### If the counter is even, download an image based on the doorbell event
if (0 == $hash->{helper}{HistoryDownloadCount} % 2) {
### Create Parameter for CommandURL for doorbell events
$UrlPostfix = "history.cgi?event=doorbell&index=" . $UrlIndex;
}
### If the counter is odd, download an image based on the motion sensor event
else {
### Create Parameter for CommandURL for motionsensor events
$UrlPostfix = "history.cgi?event=motionsensor&index=" . $UrlIndex;
}
}
### If the requested maximum number of Images for history events is reached
else {
### Reset helper
$hash->{helper}{HistoryDownloadActive} = false;
$hash->{helper}{HistoryDownloadCount} = 0;
### Update STATE of device
readingsSingleUpdate($hash, "state", "connected", 1);
### Refresh Browser Window
FW_directNotify("#FHEMWEB:$FW_wname", "location.reload()", "") if defined($FW_wname);
### Return since Routine is finished or wrong parameter has been transfered.
return
}
### Create complete command URL for DoorBird
$CommandURL = $UrlPrefix . $UrlPostfix;
### Define Parameter for Non-BlockingGet
my $param = {
url => $CommandURL,
timeout => $PollingTimeout,
user => $Username,
pwd => $Password,
hash => $hash,
method => $Method,
header => $Header,
incrementalTimout => 1,
callback => \&DoorBird_History_Request_Parse
};
### Initiate communication and close
HttpUtils_NonblockingGet($param);
return;
}
sub DoorBird_History_Request_Parse($) {
my ($param, $err, $data) = @_;
my $hash = $param->{hash};
### Obtain values from hash
my $name = $hash->{NAME};
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request ___________________________________________________________";
Log3 $name, 5, $name. " : DoorBird_History_Request - Download Index : " . $hash->{helper}{HistoryDownloadCount};
Log3 $name, 5, $name. " : DoorBird_History_Request - err : " . $err if (defined($err ));
Log3 $name, 5, $name. " : DoorBird_History_Request - length data : " . length($data) if (defined($data ));
# Log3 $name, 5, $name. " : DoorBird_History_Request - param : " . join("\n", @{[%{$param}]}) if (defined($param));
### If error message available
if ($err ne "") {
### Create Log entry
Log3 $name, 3, $name. " : DoorBird_History_Request - Error : " . $err if (defined($err ));
}
### if no error message available
else {
### If any image data available
if (defined $data) {
### Predefine Image Data and Image-hash and hash - reference
my $ImageData;
my $ImageTimeStamp;
my $ImageFileTimeStamp;
my $ImageFileName;
my %ImageDataHash;
my $ref_ImageDataHash = \%ImageDataHash;
### If http response code is 200 = OK
if ($param->{code} == 200) {
### Encode jpeg data into base64 data and remove lose newlines
$ImageData = MIME::Base64::encode($data);
$ImageData =~ s{\n}{}g;
### Create Timestamp
my $httpHeader = $param->{httpheader};
$httpHeader =~ s/^[^_]*X-Timestamp: //;
$httpHeader =~ s/\n.*//g;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($httpHeader);
$ImageTimeStamp = sprintf ( "%04d-%02d-%02d %02d:%02d:%02d",$year+1900, $mon+1, $mday, $hour, $min, $sec);
$ImageFileTimeStamp = sprintf ( "%04d%02d%02d-%02d%02d%02d" ,$year+1900, $mon+1, $mday, $hour, $min, $sec);
}
### If http response code is 204 = Nno permission to download the event history
elsif ($param->{code} == 204) {
### Create Log entry
Log3 $name, 3, $name. " : DoorBird_History_Request - Error 204 : User not authorized to download event history";
### Create Error message
$ImageData = "Error 204: The user has no permission to download the event history.";
$ImageTimeStamp =" ";
}
### If http response code is 404 = No picture available to download the event history
elsif ($param->{code} == 404) {
### Create Log entry
Log3 $name, 5, $name. " : DoorBird_History_Request - Error 404 : No picture available to download event history. Check settings in DoorBird APP.";
### Create Error message
$ImageData = "Error 404: No picture available to download in the event history.";
$ImageTimeStamp =" ";
}
### If http response code is none of one above
else {
### Create Log entry
Log3 $name, 3, $name. " : DoorBird_History_Request - Unknown http response code : " . $param->{code};
### Create Error message
$ImageData = "Error : " . $param->{code};
$ImageTimeStamp =" ";
}
### Create the URL Index which is identical every 2nd: 1 1 2 2 3 3 4 4 5 5 6 6
my $UrlIndex=int(int($hash->{helper}{HistoryDownloadCount})/int(2))+1;
### If the counter is even, download an image based on the doorbell event
if (0 == $hash->{helper}{HistoryDownloadCount} % 2) {
my $HistoryDownloadCount = $hash->{helper}{HistoryDownloadCount};
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - doorbell - HistoryCount: " . $HistoryDownloadCount;
### Save Image data and timestamp into hash
$ref_ImageDataHash->{data} = $ImageData;
$ref_ImageDataHash->{timestamp} = $ImageTimeStamp;
### Save image hash into array of hashes
push (@{$hash->{helper}{Images}{History}{doorbell}}, $ref_ImageDataHash);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - hash - ImageFileDir : " . $hash->{helper}{ImageFileDir};
### If pictures supposed to be saved as files
if ($hash->{helper}{ImageFileDir} ne "0") {
### Get current working directory
my $cwd = getcwd();
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - working directory : " . $cwd;
### If the path is given as UNIX file system format
if ($cwd =~ /\//) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - file system format : LINUX";
### 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};
}
### Check whether the last "/" at the end of the path has been given otherwise add it an create complete path
if ($hash->{helper}{ImageFileDir} =~ /\/\z/) {
$ImageFileName .= $ImageFileTimeStamp . "_doorbell.jpg";
}
else {
$ImageFileName .= "/" . $ImageFileTimeStamp . "_doorbell.jpg";
}
}
### 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_Request - 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};
}
### Check whether the last "/" at the end of the path has been given otherwise add it an create complete path
if ($hash->{helper}{ImageFileDir} =~ /\\\z/) {
$ImageFileName .= $ImageFileTimeStamp . "_doorbell.jpg";
}
else {
$ImageFileName .= "\\" . $ImageFileTimeStamp . "_doorbell.jpg";
}
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - ImageFileName : " . $ImageFileName;
### Open file or write error message in log
open my $fh, ">", $ImageFileName or do {
### Log Entry
Log3 $name, 2, $name. " : DoorBird_History_Request - open file error : " . $! . " - ". $ImageFileName;
};
### Write the base64 decoded data in file
print $fh decode_base64($ImageData) if defined($fh);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - write file : Successfully written " . $ImageFileName;
### Close file or write error message in log
close $fh or do {
### Log Entry
Log3 $name, 2, $name. " : DoorBird_History_Request - close file error : " . $! . " - ". $ImageFileName;
}
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - Index - doorbell : " . $UrlIndex;
Log3 $name, 5, $name. " : DoorBird_History_Request - ImageData - doorbell : " . length($ImageData);
}
### If the counter is odd, download an image based on the motion sensor event
else {
my $HistoryDownloadCount = $hash->{helper}{HistoryDownloadCount} - 50;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - motion - HistoryCount : " . $HistoryDownloadCount;
### Save Image data and timestamp into hash
$ref_ImageDataHash->{data} = $ImageData;
$ref_ImageDataHash->{timestamp} = $ImageTimeStamp;
### Save image hash into array of hashes
push (@{$hash->{helper}{Images}{History}{motionsensor}}, $ref_ImageDataHash);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - hash - ImageFileDir : " . $hash->{helper}{ImageFileDir};
### If pictures supposed to be saved as files
if ($hash->{helper}{ImageFileDir} ne "0") {
### Get current working directory
my $cwd = getcwd();
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - working directory : " . $cwd;
### If the path is given as UNIX file system format
if ($cwd =~ /\//) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - file system format : LINUX";
### 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};
}
### Check whether the last "/" at the end of the path has been given otherwise add it an create complete path
if ($hash->{helper}{ImageFileDir} =~ /\/\z/) {
$ImageFileName .= $ImageFileTimeStamp . "_motionsensor.jpg";
}
else {
$ImageFileName .= "/" . $ImageFileTimeStamp . "_motionsensor.jpg";
}
}
### 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_Request - 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};
}
### Check whether the last "/" at the end of the path has been given otherwise add it an create complete path
if ($hash->{helper}{ImageFileDir} =~ /\\\z/) {
$ImageFileName .= $ImageFileTimeStamp . "_motionsensor.jpg";
}
else {
$ImageFileName .= "\\" . $ImageFileTimeStamp . "_motionsensor.jpg";
}
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - ImageFileName : " . $ImageFileName;
### Open file or write error message in log
open my $fh, ">", $ImageFileName or do {
### Log Entry
Log3 $name, 2, $name. " : DoorBird_History_Request - open file error : " . $! . " - ". $ImageFileName;
};
### Write the base64 decoded data in file
print $fh decode_base64($ImageData) if defined($fh);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - write file : Successfully written " . $ImageFileName;
### Close file or write error message in log
close $fh or do {
### Log Entry
Log3 $name, 2, $name. " : DoorBird_History_Request - close file error : " . $! . " - ". $ImageFileName;
}
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - Index - motionsensor : " . $UrlIndex;
Log3 $name, 5, $name. " : DoorBird_History_Request - ImageData- motionsensor: " . length($ImageData);
}
}
### If no image data available
else {
### Create second part command URL for DoorBird based on iteration cycle
if (($hash->{helper}{HistoryDownloadCount} > 0) && $hash->{helper}{HistoryDownloadCount} <= 50) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - No Image doorbell : " . $hash->{helper}{HistoryDownloadCount};
}
elsif (($hash->{helper}{HistoryDownloadCount} > 50) && $hash->{helper}{HistoryDownloadCount} <= 100) {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - No Image motionsensor : " . ($hash->{helper}{HistoryDownloadCount} -50);
}
else {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_History_Request - ERROR! Wrong Index b) : " . $hash->{helper}{HistoryDownloadCount};
}
}
}
### Increase Download Counter and download the next one
$hash->{helper}{HistoryDownloadCount}++;
DoorBird_History_Request($hash, "");
return
}
####END####### Define Subfunction for HISTORY IMAGE REQUEST ####################################################END#####
###START###### Define Subfunction for LIST FAVOURITES #########################################################START####
sub DoorBird_List_Favorites($$) {
my ($hash, $option) = @_;
my $name = $hash->{NAME};
my $command = "favorites.cgi";
my $method = "GET";
my $header = "Accept: application/json";
my $err = " ";
my $data = " ";
my $json;
### Obtain data
($err, $data) = DoorBird_BlockGet($hash, $command, $method, $header);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Get - List_Favourites - err : " . $err;
Log3 $name, 5, $name. " : DoorBird_Get - List_Favourites - data : " . $data;
### If no error has been handed back
if ($err eq "") {
### If the option is asking for the JSON string
if (defined($option) && ($option =~ /JSON/i)) {
return $data;
}
### If the option is asking for nothing special
else {
### Check if json can be parsed into hash
eval
{
$json = decode_json(encode_utf8($data));
1;
}
or do
{
### Log Entry for debugging purposes
Log3 $name, 3, $name. " : DoorBird_Get - Data cannot be parsed by JSON for : List_Favourites";
return $name. " : DoorBird_Get - Data cannot be parsed by JSON for List_Favourites";
};
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Get - json : " . $json;
### Delete all Readings for Relay-Addresses
fhem( "deletereading $name Favorite_.*" );
### Initiate Bulk Update
readingsBeginUpdate($hash);
### For every chapter in the List of Favourites (e.g. SIP, http)
foreach my $FavoritChapter (keys %{$json}) {
### For every item in the List of chapters (e.g. 0, 1, 5 etc.)
foreach my $FavoritItem (keys %{$json->{$FavoritChapter}}) {
### Create first part of Reading
my $ReadingName = "Favorite_" . $FavoritChapter . "_" . $FavoritItem;
### Update Reading
readingsBulkUpdate($hash, $ReadingName . "_Title", $json->{$FavoritChapter}{$FavoritItem}{title});
readingsBulkUpdate($hash, $ReadingName . "_Value", $json->{$FavoritChapter}{$FavoritItem}{value});
### Log Entry for debugging purpose
Log3 $name, 5, $name. " : DoorBird_List_Favorites --------------------------------";
Log3 $name, 5, $name. " : DoorBird_List_Favorites - Reading : " . $ReadingName;
Log3 $name, 5, $name. " : DoorBird_List_Favorites - _Title : " . $json->{$FavoritChapter}{$FavoritItem}{title};
Log3 $name, 5, $name. " : DoorBird_List_Favorites - _Value : " . $json->{$FavoritChapter}{$FavoritItem}{title};
}
}
### Execute Readings Bulk Update
readingsEndUpdate($hash, 1);
return "Readings have been updated!\nPress F5 to refresh Browser.";
}
}
### If error has been handed back
else {
$err =~ s/^[^ ]*//;
return "ERROR!\nError Code:" . $err;
}
}
####END####### Define Subfunction for LIST FAVOURITES ##########################################################END#####
###START###### Define Subfunction for LIST SCHEDULES ##########################################################START####
sub DoorBird_List_Schedules($$) {
my ($hash, $option) = @_;
my $name = $hash->{NAME};
my $command = "schedule.cgi";
my $method = "GET";
my $header = "Accept: application/json";
my $err = " ";
my $data = " ";
my $json;
### Obtain data
($err, $data) = DoorBird_BlockGet($hash, $command, $method, $header);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Get - List_Schedules - err : " . $err;
Log3 $name, 5, $name. " : DoorBird_Get - List_Schedules - data : " . $data;
### If no error has been handed back
if ($err eq "") {
### If the option is asking for the JSON string
if (defined($option) && ($option =~ /JSON/i)) {
return $data;
}
### If the option is asking for nothing special
else {
### Check if json can be parsed into hash
eval
{
$json = decode_json(encode_utf8($data));
1;
}
or do
{
### Log Entry for debugging purposes
Log3 $name, 3, $name. " : DoorBird_List_Schedules - Data : " . $data;
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Get - Data cannot be parsed by JSON for : List_Schedules";
return $data;
};
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Get - json : " . $json;
### Delete all Readings for Relay-Addresses
fhem( "deletereading $name Schedule_.*" );
### Initiate Bulk Update
readingsBeginUpdate($hash);
### For every chapter in the Array of elements
foreach my $Schedule (@{$json}) {
### Create first part of Reading
my $ReadingNameA = "Schedule_" . $Schedule->{input} . "_";
### If Parameter exists
if ($Schedule->{param} ne "") {
### Add Parameter
$ReadingNameA .= $Schedule->{param} . "_";
}
### For every chapter in the Array of elements
foreach my $Output (@{$Schedule->{output}}) {
my $ReadingNameB = $ReadingNameA . $Output->{event} ."_";
### If Parameter exists
if ($Output->{param} ne "") {
### Add Parameter
$ReadingNameB .= $Schedule->{param} . "_";
}
else {
### Add Parameter
$ReadingNameB .= "x_";
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Get - Schedules - ReadingName : " . $ReadingNameB;
# my $ReadingValue = $Output->($Output);
# Log3 $name, 5, $name. " : DoorBird_Get - Schedules - ReadingValue : " . $ReadingValue;
}
}
### Execute Readings Bulk Update
readingsEndUpdate($hash, 1);
return "Readings have been updated!\nPress F5 to refresh Browser.";
}
}
### If error has been handed back
else {
$err =~ s/^[^ ]*//;
return "ERROR!\nError Code:" . $err;
}
}
####END####### Define Subfunction for LIST SCHEDULES ###########################################################END#####
###START###### Define Subfunction for RESTART #################################################################START####
sub DoorBird_Restart($$) {
my ($hash, $option) = @_;
my $name = $hash->{NAME};
my $command = "restart.cgi";
my $method = "GET";
my $header = "Accept: application/json";
my $username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
my $err;
my $data;
my $json;
### Activate Relay
($err, $data) = DoorBird_BlockGet($hash, $command, $method, $header);
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_Restart - err : " . $err;
Log3 $name, 5, $name. " : DoorBird_Restart - data : " . $data;
### If no error has been handed back
if ($err eq "") {
### Log Entry
Log3 $name, 3, $name. " : DoorBird_Restart - Reboot request successfully transmitted to DoorBird";
return "Reboot request successfully transmitted to DoorBird\nData: " . $data;
}
### If error has been handed back
else {
### Cut off url from error message
$err =~ s/^[^ ]*//;
### Log Entry
Log3 $name, 2, $name. " : DoorBird_Restart - Reboot command failed. ErrorMsg: " . $err;
return "ERROR!\nError Code:" . $err . "\nData: " . $data;
}
}
####END####### Define Subfunction for RESTART ##################################################################END#####
###START###### Define Subfunction for SIP Status REQUEST ######################################################START####
sub DoorBird_SipStatus_Request($$) {
my ($hash, $option) = @_;
my $name = $hash->{NAME};
my $command = "sip.cgi?action=status";
my $method = "GET";
my $header = "Accept: application/json";
my $err = " ";
my $data = " ";
my $json;
### Obtain data
($err, $data) = DoorBird_BlockGet($hash, $command, $method, $header);
### Remove Newlines for better log entries
my $ShowData = $data;
$ShowData =~ s/[\t]//g;
$ShowData =~ s/[\r]//g;
$ShowData =~ s/[\n]//g;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- err : " . $err if(defined($err));
# Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- data : " . $ShowData if(defined($ShowData));
### If no error has been handed back
if ($err eq "") {
### If the option is asking for the JSON string
if (defined($option) && ($option =~ /JSON/i)) {
return $data;
}
### If the option is asking for nothing special
else {
### Check if json can be parsed into hash
eval
{
$json = decode_json(encode_utf8($data));
1;
}
or do
{
### Log Entry for debugging purposes
Log3 $name, 3, $name. " : DoorBird_SipStatus_Req- Data cannot parsed JSON : Info_Request";
return $name. " : DoorBird_SipStatus_Req- Data cannot be parsed by JSON for Info_Request";
};
my $VersionContent = $json-> {BHA}{SIP}[0];
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- json : " . Dumper($json);
### Initiate Bulk Update
readingsBeginUpdate($hash);
foreach my $key (keys %{$VersionContent}) {
### If the entry are information about connected INCOMING_CALL_USER
if ( $key eq "INCOMING_CALL_USER") {
### Split all Call User in array
my @CallUserArray = split(";", $VersionContent -> {$key});
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- CallUser : " . Dumper(@CallUserArray);
### Count Number of current readings containing call user
my $CountCurrentCallUserReadings = 0;
foreach my $CurrentCallUserReading (keys(%{$hash->{READINGS}})) {
if ($CurrentCallUserReading =~ m/SIP_INCOMING_CALL_USER_/){
$CountCurrentCallUserReadings++;
}
}
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- CountCurrentCallUserReadings : " . $CountCurrentCallUserReadings;
Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- CallUserArray : " . @CallUserArray;
### If the number of call user in DoorBird unit is smaller than the number of Call user readings then delete all respective readings first
if (@CallUserArray < $CountCurrentCallUserReadings) {
fhem("deletereading $name SIP_INCOMING_CALL_USER_.*");
}
### For every Call-User do
my $CallUserId;
foreach my $CallUser (@CallUserArray) {
### Increment Counter
$CallUserId++;
### Delete "sip:" if exists
$CallUser =~ s/^[^:]*://;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- Content of" . sprintf("%15s %-s", "SIP_INCOMING_CALL_USER_" . sprintf("%02d",$CallUserId), ": " . "sip:" . $CallUser);
### Update Reading
readingsBulkUpdate($hash, "SIP_INCOMING_CALL_USER_" . sprintf("%02d",$CallUserId), "sip:" . $CallUser);
}
}
### If the entry are information about connected relais
elsif ( $key =~ m/relais:/) {
### Extract number, swap to Uppercase and concat to new Readingsname
my ($RelaisNumer) = $key =~ /(\d+)/g;
my $NewReadingsName = uc($key);
$NewReadingsName =~ s/:.*//;
$NewReadingsName = "SIP_" . $NewReadingsName . "_" . sprintf("%02d",$RelaisNumer);
### Update Reading
readingsBulkUpdate($hash, $NewReadingsName, $VersionContent -> {$key});
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- Content of" . sprintf("%15s %-s", $key, ": " . $VersionContent -> {$key});
Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- Content of" . sprintf("%15s %-s", "NewReadingsName", ": " . $NewReadingsName);
Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- Content of" . sprintf("%15s %-s", "RelaisNumber", ": " . $RelaisNumer);
}
### For all other entries
else {
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_SipStatus_Req- Content of" . sprintf("%15s %-s", $key, ": " . $VersionContent -> {$key});
### Update Reading
readingsBulkUpdate($hash, "SIP_" . $key, $VersionContent -> {$key} );
}
}
### Update Reading for Firmware-Status
readingsBulkUpdate($hash, "Firmware-Status", "up-to-date");
### Execute Readings Bulk Update
readingsEndUpdate($hash, 1);
### Check for Firmware-Updates
DoorBird_FirmwareStatus($hash);
return "Readings have been updated!\n";
}
}
### If error has been handed back
else {
$err =~ s/^[^ ]*//;
return "ERROR!\nError Code:" . $err;
}
}
####END####### Define Subfunction for SIP Status REQUEST #####################################################END#####
###START###### Encrypt Credential #############################################################################START####
sub DoorBird_credential_encrypt($) {
my ($decoded) = @_;
my $key = getUniqueId();
my $encoded;
return $decoded if( $decoded =~ /\Qcrypt:\E/ );
for my $char (split //, $decoded) {
my $encode = chop($key);
$encoded .= sprintf("%.2x",ord($char)^ord($encode));
$key = $encode.$key;
}
return 'crypt:'.$encoded;
}
####END####### Encrypt Credential ##############################################################################END#####
###START###### Decrypt Credential #############################################################################START####
sub DoorBird_credential_decrypt($) {
my ($encoded) = @_;
my $key = getUniqueId();
my $decoded;
return $encoded if( $encoded !~ /crypt:/ );
$encoded = $1 if( $encoded =~ /crypt:(.*)/ );
for my $char (map { pack('C', hex($_)) } ($encoded =~ /(..)/g)) {
my $decode = chop($key);
$decoded .= chr(ord($char)^ord($decode));
$key = $decode.$key;
}
return $decoded;
}
####END####### Decrypt Credential ##############################################################################END#####
###START###### Blocking Get ###################################################################################START####
sub DoorBird_BlockGet($$$$) {
### https://wiki.fhem.de/wiki/HttpUtils#HttpUtils_BlockingGet
### Extract subroutine parameter from caller
my ($hash, $ApiCom, $Method, $Header) = @_;
### Obtain values from hash
my $name = $hash->{NAME};
my $username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
my $password = DoorBird_credential_decrypt($hash->{helper}{".PASSWORD"});
my $url = $hash->{helper}{URL};
my $PollingTimeout = $hash->{helper}{PollingTimeout};
### Create complete command URL for DoorBird
my $UrlPrefix = "https://" . $url . "/bha-api/";
my $CommandURL = $UrlPrefix . $ApiCom;
### Log Entry for debugging purposes
Log3 $name, 5, $name. " : DoorBird_BlockingGet - CommandURL : " . $CommandURL;
my $param = {
url => $CommandURL,
user => $username,
pwd => $password,
timeout => $PollingTimeout,
hash => $hash,
method => $Method,
header => $Header
};
### Initiate communication and close
my ($err, $data) = HttpUtils_BlockingGet($param);
return($err, $data);
}
####END####### Blocking Get ####################################################################################END#####
1;
###START###### Description for fhem commandref ################################################################START####
=pod
=item device
=item summary Connects fhem to the DoorBird IP door station
=item summary_DE Verbindet fhem mit der DoorBird IP Türstation
=begin html
DoorBird
The DoorBird module establishes the communication between the DoorBird - door intercommunication unit and the fhem home automation based on the official API, published by the manufacturer.
Please make sure, that the user has been enabled the API-Operator button in the DoorBird Android/iPhone APP under "Administration -> User -> Edit -> Permission -> API-Operator".
The following packet - installations are pre-requisite if not already installed by other modules (Examples below tested on Raspberry JESSIE):
The name of the device. Recommendation: "myDoorBird".
<IPv4-address> :
A valid IPv4 address of the KMxxx. You might look into your router which DHCP address has been given to the DoorBird unit.
<Username> :
The username which is required to sign on the DoorBird.
<Password> :
The password which is required to sign on the DoorBird.
Set
The set function is able to change or activate the following features as follows:
set Light_On
: Activates the IR lights of the DoorBird unit. The IR - light deactivates automatically by the default time within the Doorbird unit
set Live_Audio <on:off>
: Activate/Deactivate the Live Audio Stream of the DoorBird on or off and toggles the direct link in the hidden Reading .AudioURL
set Live_Video <on:off>
: Activate/Deactivate the Live Video Stream of the DoorBird on or off and toggles the direct link in the hidden Reading .VideoURL
set Open Door <Value>
: Activates the Relay of the DoorBird unit with the given address. The list of installed relay addresses are imported with the initialization of parameters.
set Restart
: Sends the command to restart (reboot) the Doorbird unit
set Transmit_Audio <Path>
: Converts a given audio file and transmits the stream to the DoorBird speaker. Requires a datapath to audio file to be converted and send. The user "fhem" needs to have write access to this directory.
Get
The get function is able to obtain the following information from the DoorBird unit:
get History_Request
: Downloads the pictures of the last events of the doorbell and motion sensor. (Refer to attribute MaxHistory)
get Image_Request
: Downloads the current Image of the camera of DoorBird unit.
get Info_Request
: Downloads the current internal setup such as relay configuration, firmware version etc. of the DoorBird unit. The obtained relay adresses will be used as options for the Open_Door command.
Attributes
The following user attributes can be used with the DoorBird module in addition to the global ones e.g. room.
disable :
Stops the device from further reacting on UDP datagrams sent by the DoorBird unit.
The default value is 0 = activated
KeepAliveTimeout :
Timeout in seconds without still-alive UDP datagrams before state of device will be set to "disconnected".
The default value is 30s
MaxHistory :
Number of pictures to be downloaded from history for both - doorbell and motion sensor events.
The default value is "50" which is the maximum possible.
PollingTimeout :
Timeout in seconds before download requests are terminated in cause of no reaction by DoorBird unit. Might be required to be adjusted due to network speed.
The default value is 10s.
UdpPort :
Port number to be used to receice UDP datagrams. Ports are pre-defined by firmware.
The default value is port 6524
SipDevice :
Name of the fhem SIP device which is registered in the DoorBird unit as those ones who are allowed to call the DoorBird. Refer to SIP.
The default value is the first SIP device in fhem.
SessionIdSec :
Time in seconds for how long the session Id shall be valid, which is required for secure Video and Audio transmission. The DoorBird kills the session Id after 10min = 600s automatically. In case of use with CCTV recording units, this function must be disabled by setting to 0.
The default value is 540s = 9min.
SipNumber :
The telephone number under which the DoorBird unit is registered and can be called.
The default value is **620
ImageFileDir :
The relative (e.g. "images") or absolute (e.g. "/mnt/NAS/images") with or without trailing "/" directory path to which the image files supposed to be stored.
The default value is 0 = disabled
EventReset :
Time in seconds after wich the Readings for the Events Events (e.g. "doorbell_button", "motions sensor", "keypad") shal be reset to "idle".
The default value is 5s
WaitForHistory :
Time in seconds after wich the module shall wait for an history image triggered by an event is ready for download. Might be adjusted if fhem-Server and Doorbird unit have large differences in system time.
The default value is 7s
=end html
=begin html_DE
DoorBird
Das DoorBird Modul ermöglicht die Komminikation zwischen der DoorBird Interkommunikationseinheit und dem fhem Automationssystem basierend auf der API des Herstellers her.
Für den vollen Funktionsumfang muss sichergestellt werden, dass das Setting "API-Operator" in der DoorBird Android/iPhone - APP unter "Administration -> User -> Edit -> Permission -> API-Operator" gesetzt ist.
Die folgenden Software - Pakete müssen noch zusätzlich installiert werden, sofern dies nicht schon durch andere Module erfolgt ist. (Die Beispiele sind auf dem Raspberry JESSIE gestestet):
Der Name des Device unter fhem. Beispiel: "myDoorBird".
<IPv4-Addresse> :
Eine gültige IPv4 - Addresse der DoorBird-Anlage. Ggf. muss man im Router nach der entsprechenden DHCP Addresse suchen, die der DoorBird Anlage vergeben wurde.
<Username> :
Der Username zum einloggen auf der DoorBird Anlage.
<Passwort> :
Das Passwort zum einloggen auf der DoorBird Anlage.
Set
Die Set - Funktion ist in der lage auf der DoorBird - Anlage die folgenden Einstellungen vorzunehmen bzw. zu de-/aktivieren:
set Light_On
: Schaltet das IR lichht der DoorBird Anlage ein. Das IR Licht schaltet sich automatisch nach der in der DoorBird - Anlage vorgegebenen Default Zeit wieder aus.
set Live_Audio <on:off>
: Aktiviert/Deaktiviert den Live Audio Stream der DoorBird - Anlage Ein oder Aus und wechselt den direkten link in dem versteckten Reading .AudioURL.
set Live_Video <on:off>
: Aktiviert/Deaktiviert den Live Video Stream der DoorBird - Anlage Ein oder Aus und wechselt den direkten link in dem versteckten Reading .VideoURL.
set Open Door <Value>
: Aktiviert das Relais der DoorBird - Anlage mit dessen Adresse. Die Liste der installierten Relais werden mit der Initialisierung der Parameter importiert.
set Restart
: Sendet das Kommando zum rebooten der DoorBird - Anlage.
set Transmit_Audio <Path>
: Konvertiert die angegebene Audio-Datei und sendet diese zur Ausgabe an die DoorBird - Anlage. Es benötigt einen Dateipfad zu der Audio-Datei zu dem der User "fhem" Schreibrechte braucht (z.B.: /opt/fhem/audio).
Get
Die Get - Funktion ist in der lage von der DoorBird - Anlage die folgenden Informationen und Daten zu laden:
get History_Request
: Lädt die Bilder der letzten Ereignisse durch die Türklingel und dem Bewegungssensor herunter. (Siehe auch Attribut MaxHistory)
get Image_Request
: Lädt das gegenwärtige Bild der DoorBird - Kamera herunter.
get Info_Request
: Lädt das interne Setup (Firmware Version, Relais Konfiguration etc.) herunter. Die übermittelten Relais-Adressen werden als Option für das Kommando Open_Door verwendet.
Attributes
Die folgenden Attribute können mit dem DoorBird Module neben den globalen Attributen wie room verwednet werden.
disable :
Stoppt das Gerät von weiteren Reaktionen auf die von der DoorBird ß Anlage ausgesendeten UDP - Datageramme Der Default Wert ist 0 = aktiviert
KeepAliveTimeout :
Timeout in Sekunden ohne "still-alive" - UDP Datagramme bevor der Status des Gerätes auf "disconnected" gesetzt wird.
Der Default Wert ist 30s
MaxHistory :
Anzahl der herunterzuladenden Bilder aus dem Historien-Archiv sowohl für Ereignisse seitens der Türklingel als auch für den Bewegungssensor.
Der Default Wert ist "50" = Maximum.
PollingTimeout :
Timeout in Sekunden before der Download-Versuch aufgrund fehlender Antwort seitens der DoorBird-Anlage terminiert wird. Eine Adjustierung mag notwendig sein, sobald Netzwerk-Latenzen aufteten.
Der Default-Wert ist 10s.
UdpPort :
Port Nummer auf welcher das DoorBird - Modul nach den UDP Datagrammen der DoorBird - Anlage hören soll. Die Ports sind von der Firmware vorgegeben.
Der Default Port ist 6524
SessionIdSec :
Zeit in Sekunden nach welcher die Session Id erneuert werden soll. Diese ist für die sichere Übertragung der Video und Audio Verbindungsdaten notwendig. Die DoorBird-Unit devalidiert die Session Id automatisch nach 10min. Für den Fall, dass die DoorBird Kamera an ein Überwachungssystem angebunden werden soll, muss diese Funktion ausser Betrieb genommen werden indem man den Wert auf 0 setzt 0.
Der Default Wert ist 540s = 9min.
SipDevice :
Name des fhem SIP Device mit wessen Nummer in der DoorBird - Anlage hinterlegt wurde die die DoorBird - Anlage anrufen dürfen. Refer to SIP.
Der Default Wert ist das erste SIP device in fhem.
SipNumber :
Die Telefonnummer unter der die DoorBird / Anlage registriert und erreicht werden kann.
Der Default Wert ist **620
ImageFileDir :
Der relative (z.B. "images") oder absolute (z.B. "/mnt/NAS/images") Verzeichnispfad mit oder ohne nachfolgendem Pfadzeichen "/" in welchen die Bild-Dateien gespeichert werden sollen.
Der Default Wert ist 0 = deaktiviert
EventReset :
Zeit in Sekunden nach welcher die Readings für die Events (z.B. "doorbell_button", "motions sensor", "keypad")wieder auf "idle" gesetzt werden sollen.
Der Default Wert ist 5s
WaitForHistory :
Zeit in Sekunden die das Modul auf das Bereitstellen eines korrespondierenden History Bildes zu einem Event warten soll. Muss ggf. adjustiert werden, sobald deutliche Unterschiede in der Systemzeit zwischen fhemßServer und DoorBird Station vorliegen.
Der Default Wert ist 7s
=end html_DE
=encoding utf8
=for :application/json;q=META.json 73_DoorBird.pm
{
"abstract": "Connects fhem to the DoorBird IP door station",
"description": "The DoorBird module establishes the communication between the DoorBird - door intercommunication unit and the fhem home automation based on the official API, published by the manufacturer. Please make sure, that the user has been enabled the API-Operator button in the DoorBird Android/iPhone APP under Administration -> User -> Edit -> Permission -> API-Operator.",
"x_lang": {
"de": {
"abstract": "Verbindet fhem mit der DoorBird IP Türstation",
"description": "Das DoorBird Modul ermöglicht die Komminikation zwischen der DoorBird Interkommunikationseinheit und dem fhem Automationssystem basierend auf der API des Herstellers her. Für den vollen Funktionsumfang muss sichergestellt werden, dass das Setting \"API-Operator\" in der DoorBird Android/iPhone - APP unter Administration -> User -> Edit -> Permission -> API-Operator gesetzt ist."
}
},
"license": [
"GPL_2"
],
"author": [
"Matthias Deeke "
],
"x_fhem_maintainer": [
"Sailor"
],
"keywords": [
"Doorbird",
"Intercom"
],
"prereqs": {
"runtime": {
"requires": {
"Alien::Base::ModuleBuild": 0,
"Alien::Sodium": 0,
"Crypt::Argon2": 0,
"Crypt::NaCl::Sodium": 0,
"Cwd": 0,
"Data::Dumper": 0,
"Encode": 0,
"HttpUtils": 0,
"IO::Socket": 0,
"JSON": 0,
"LWP::UserAgent": 0,
"MIME::Base64": 0,
"constant": 0,
"strict": 0,
"utf8": 0,
"warnings": 0,
"perl": 5.014
},
"recommends": {
},
"suggests": {
}
}
},
"x_prereqs_os_debian": {
"runtime": {
"requires": {
"sox": 0,
"libsox-fmt-all": 0,
"libsodium-dev": 0
},
"recommends": {
},
"suggests": {
}
}
}
}
=end :application/json;q=META.json
=cut