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
+ fhem("deletereading $name 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\n", $RelayNumber), ": " . $RelayAddress);
+
+ ### Update Reading
+ readingsBulkUpdate($hash, "RelayAddr_" . sprintf("%02d\n", $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 $username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
+ my $password = DoorBird_credential_decrypt($hash->{helper}{".PASSWORD"});
+ my $url = $hash->{helper}{URL};
+
+ ### Create complete command URL for DoorBird
+ my $UrlPrefix = "http://" . $url . "/bha-api/";
+ my $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 $username = DoorBird_credential_decrypt($hash->{helper}{".USER"});
+ my $password = DoorBird_credential_decrypt($hash->{helper}{".PASSWORD"});
+ my $url = $hash->{helper}{URL};
+
+ ### Create complete command URL for DoorBird
+ my $UrlPrefix = "http://" . $url . "/bha-api/";
+ my $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 = " ";
+
+ ### Create complete command URL for DoorBird
+ my $UrlPrefix = "http://" . $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 - ImageURL : " . $ImageURL ;
+
+ ### Update Reading
+ readingsSingleUpdate($hash, ".ImageURL", $ImageURL, 1);
+
+ ### Refresh Browser Window
+ FW_directNotify("#FHEMWEB:$FW_wname", "location.reload()", "") if defined($FW_wname);
+
+ ### 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);
+
+ ### Save picture and timestamp into hash
+ $hash->{helper}{Images}{Individual}{Data} = $ImageData;
+ $hash->{helper}{Images}{Individual}{Timestamp} = $ImageTimeStamp;
+
+ ### 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 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 = "http://" . $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 %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);
+ }
+ ### 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 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};
+ }
+
+ ### 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 - 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 - 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 = "http://" . $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.
+
+
+
+
+
+ SipNumber :
The telephone number under which the DoorBird unit is registered and can be called.
+ The default value is **620
+
+
+
+
+
+=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
+
+
+
+
+ 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
+