############################################################### # $Id$ # # 72_FRITZBOX.pm # # (c) 2014 Torsten Poitzsch < torsten . poitzsch at gmx . de > # # This module handles the Fritz!Box router and the Fritz!Phone MT-F # # Copyright notice # # This script is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # The GNU General Public License can be found at # http://www.gnu.org/copyleft/gpl.html. # A copy is found in the text file GPL.txt and important notices to the license # from the author is found in LICENSE.txt distributed with these scripts. # # This script is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # This copyright notice MUST APPEAR in all copies of the script! # ############################################################################## # # define FRITZBOX # ############################################################################## package main; use strict; use warnings; use Blocking; my $missingModul; my $missingModulTelnet; my $missingModulWeb; my $missingModulTR064; our $FRITZBOX_TR064pwd; eval "use Net::Telnet;1" or $missingModulTelnet .= "Net::Telnet "; eval "use URI::Escape;1" or $missingModul .= "URI::Escape "; eval "use MIME::Base64;1" or $missingModul .= "MIME::Base64 "; use FritzBoxUtils; ## only for web access login #sudo apt-get install libjson-perl eval "use JSON::XS;1" or $missingModulWeb .= "JSON::XS "; eval "use LWP::UserAgent;1" or $missingModulWeb .= "LWP::UserAgent "; eval "use URI::Escape;1" or $missingModulTR064 .= "URI::Escape "; # sudo apt-get install libsoap-lite-perl eval "use SOAP::Lite;1" or $missingModulTR064 .= "Soap::Lite "; eval "use Data::Dumper;1" or $missingModulTR064 .= "Data::Dumper "; sub FRITZBOX_Log($$$); sub FRITZBOX_Init($); sub FRITZBOX_Set_Cmd_Start($); sub FRITZBOX_Exec($$); sub FRITZBOX_Readout_Add_Reading ($$$$@); sub FRITZBOX_Readout_Process($$); sub FRITZBOX_SendMail($@); sub FRITZBOX_SetCustomerRingTone($@); sub FRITZBOX_SetMOH($@); sub FRITZBOX_StartRadio($@); sub FRITZBOX_Wlan_Run($); sub FRITZBOX_Web_Query($$@); our $telnet; my %fonModel = ( '0x01' => "MT-D" , '0x03' => "MT-F" , '0x04' => "C3" , '0x05' => "M2" , '0x08' => "C4" ); my %ringTone = qw { 0 HandsetDefault 1 HandsetInternalTone 2 HandsetExternalTon 3 Standard 4 Eighties 5 Alert 6 Ring 7 RingRing 8 News 9 CustomerRingTone 10 Bamboo 11 Andante 12 ChaCha 13 Budapest 14 Asia 15 Kullabaloo 16 silent 17 Comedy 18 Funky 19 Fatboy 20 Calypso 21 Pingpong 22 Melodica 23 Minimal 24 Signal 25 Blok1 26 Musicbox 27 Blok2 28 2Jazz 33 InternetRadio 34 MusicList }; my %ringToneNumber; while (my ($key, $value) = each %ringTone) { $ringToneNumber{lc $value}=$key; } my %alarmDays = qw{1 Mo 2 Tu 4 We 8 Th 16 Fr 32 Sa 64 So}; my %userType = qw{1 IP 2 PC-User 3 Default 4 Guest}; my @mohtype = qw(default sound customer); my %landevice = (); # FIFO Buffer for commands my @cmdBuffer=(); my $cmdBufferTimeout=0; my $ttsCmdTemplate = 'wget -U Mozilla -O "[ZIEL]" "http://translate.google.com/translate_tts?ie=UTF-8&tl=[SPRACHE]&q=[TEXT]"'; my $ttsLinkTemplate = 'http://translate.google.com/translate_tts?ie=UTF-8&tl=[SPRACHE]&q=[TEXT]'; my $mohUpload = '/var/tmp/fhem_moh_upload'; my $mohOld = '/var/tmp/fhem_fx_moh_old'; my $mohNew = '/var/tmp/fhem_fx_moh_new'; ####################################################################### sub FRITZBOX_Log($$$) { my ( $hash, $loglevel, $text ) = @_; my $xline = ( caller(0) )[2]; my $xsubroutine = ( caller(1) )[3]; my $sub = ( split( ':', $xsubroutine ) )[2]; $sub =~ s/FRITZBOX_//; my $instName = ( ref($hash) eq "HASH" ) ? $hash->{NAME} : $hash; Log3 $hash, $loglevel, "FRITZBOX $instName: $sub.$xline " . $text; } # End FRITZBOX_Log ####################################################################### sub FRITZBOX_Initialize($) { my ($hash) = @_; $hash->{DefFn} = "FRITZBOX_Define"; $hash->{UndefFn} = "FRITZBOX_Undefine"; $hash->{SetFn} = "FRITZBOX_Set"; $hash->{GetFn} = "FRITZBOX_Get"; $hash->{AttrFn} = "FRITZBOX_Attr"; $hash->{AttrList} = "allowShellCommand:0,1 " ."allowTR064Command:0,1 " ."boxUser " ."disable:0,1 " ."defaultCallerName " ."defaultUploadDir " ."forceTelnetConnection:0,1 " ."fritzBoxIP " ."INTERVAL " ."ringWithIntern:0,1,2 " ."telnetUser " ."telnetTimeOut " .$readingFnAttributes; } # end FRITZBOX_Initialize ####################################################################### sub FRITZBOX_Define($$) { my ($hash, $def) = @_; my @args = split("[ \t][ \t]*", $def); return "Usage: define FRITZBOX" if(@args <2 || @args >2); my $name = $args[0]; $hash->{NAME} = $name; my $msg; if ( $missingModul ) { $msg = "Cannot define a FRITZBOX device. Perl modul $missingModul is missing."; FRITZBOX_Log $hash, 1, $msg; return $msg; } # unless (qx ( [ -f /usr/bin/ctlmgr_ctl ] && echo 1 || echo 0 )) unless ( -X "/usr/bin/ctlmgr_ctl" ) { $hash->{REMOTE} = 1; FRITZBOX_Log $hash, 4, "FRITZBOX runs in remote mode"; } elsif ( $< != 0 ) { $msg = "Error - FHEM is not running under root (currently " . ( getpwuid( $< ) )[ 0 ] . ") but we need to be root"; FRITZBOX_Log $hash, 1, $msg; return $msg; } else { $hash->{REMOTE} = 0; FRITZBOX_Log $hash, 4, "FRITZBOX runs in local mode"; } $hash->{STATE} = "Initializing"; $hash->{fhem}{modulVersion} = '$Date$'; $hash->{INTERVAL} = 300; $hash->{fhem}{lastHour} = 0; $hash->{fhem}{LOCAL} = 0; $hash->{helper}{TimerReadout} = $name.".Readout"; $hash->{helper}{TimerCmd} = $name.".Cmd"; FRITZBOX_Initilize_TR064 ($hash); RemoveInternalTimer($hash->{helper}{TimerReadout}); # Get first data after 6 seconds InternalTimer(gettimeofday() + 6, "FRITZBOX_Readout_Start", $hash->{helper}{TimerReadout}, 0); return undef; } #end FRITZBOX_Define ####################################################################### sub FRITZBOX_Initilize_TR064 ($) { my ($hash) = @_; my $name = $hash->{NAME}; return if AttrVal( $name, "forceTelnetConnection", 0 ); if ($missingModulTR064) { FRITZBOX_Log $hash, 2, "Cannot use TR-064. Perl modul ".$missingModulTR064."is missing on this system. Please install."; return; } if ($missingModulWeb) { FRITZBOX_Log $hash, 2, "Cannot test TR-064 access. Perl modul ".$missingModulWeb."is missing on this system. Please install."; return undef; } my $host = AttrVal( $name, "fritzBoxIP", "fritz.box" ); FRITZBOX_Log $hash, 4, "Check if TR-064 description 'http://".$host.":49000/tr64desc.xml' exists."; my $agent = LWP::UserAgent->new( env_proxy => 1, keep_alive => 1, protocols_allowed => ['http'], timeout => 10 ); my $response = $agent->get( "http://".$host.":49000/tr64desc.xml" ); if ( $response->is_error() ) { FRITZBOX_Log $hash, 2, "Box $host doesn't have a TR-064-API."; return undef; } # Security Port anfordern FRITZBOX_Log $hash, 4, "Open TR-064 connection"; my $s = SOAP::Lite -> uri('urn:dslforum-org:service:DeviceInfo:1') -> proxy('http://'.$host.':49000/upnp/control/deviceinfo') -> getSecurityPort(); my $port = $s->result; unless( $port ) { FRITZBOX_Log $hash, 2, "Could not get secure port: $!"; return undef; } $hash->{SECPORT} = $port; # $hash->{TR064USER} = "dslf-config"; # jetzt die Zertifikatsüberprüfung (sofort) abschalten BEGIN { $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0; } # dieser Code authentifiziert an der Box sub SOAP::Transport::HTTP::Client::get_basic_credentials {return "dslf-config" => $FRITZBOX_TR064pwd;} return undef; } ####################################################################### sub FRITZBOX_Undefine($$) { my ($hash, $args) = @_; RemoveInternalTimer($hash->{helper}{TimerReadout}); RemoveInternalTimer($hash->{helper}{TimerCmd}); BlockingKill( $hash->{helper}{READOUT_RUNNING_PID} ) if exists $hash->{helper}{READOUT_RUNNING_PID}; BlockingKill( $hash->{helper}{CMD_RUNNING_PID} ) if exists $hash->{helper}{CMD_RUNNING_PID}; return undef; } # end FRITZBOX_Undefine ####################################################################### sub FRITZBOX_Attr($@) { my ($cmd,$name,$aName,$aVal) = @_; # $cmd can be "del" or "set" # $name is device name # aName and aVal are Attribute name and value my $hash = $defs{$name}; if ($cmd eq "set") { if ($aName eq "fritzBoxIP" && $aVal ne "") { $hash->{fhem}{lastHour} = 0; # Refresh all readings during next update if ($hash->{REMOTE} == 0) { $hash->{REMOTE} = 1; FRITZBOX_Log $hash, 3, "Changed to remote access because attribute 'fritzBoxIP' is defined."; } } } return undef; } # FRITZBOX_Attr ende ####################################################################### sub FRITZBOX_Set($$@) { my ($hash, $name, $cmd, @val) = @_; my $resultStr = ""; my $list = "alarm" . " call" . " customerRingTone" . " dect:on,off" . " diversity" . " guestWlan:on,off" . " moh" . " password" . " ring" . " sendMail" . " startRadio" . " tam" . " update:noArg" . " wlan:on,off"; # . " convertMOH" # . " convertRingTone" my $forceTelnet = AttrVal( $name, "forceTelnetConnection", 0 ); # set alarm if ( lc $cmd eq 'alarm') { if ( int @val > 0 && $val[0] =~ /^(1|2|3)$/ ) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); return FRITZBOX_Set_Alarm_Web ($hash, @val) unless $forceTelnet; return FRITZBOX_Set_Alarm_Telnet ($hash, @val); } } # set call elsif ( lc $cmd eq 'call') { if (int @val > 0) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); push @cmdBuffer, "call ".join(" ", @val); return FRITZBOX_Set_Cmd_Start $hash->{helper}{TimerCmd}; } # } elsif ( lc $cmd eq 'convertmoh') { # if (int @val > 0) # { # Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); # return FRITZBOX_ConvertMOH $hash, @val; # } # } elsif ( lc $cmd eq 'convertringtone') { # if (int @val > 0) # { # Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); # return FRITZBOX_ConvertRingTone $hash, @val; # } } elsif ( lc $cmd eq 'customerringtone') { if (int @val > 0) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); return FRITZBOX_SetCustomerRingTone ($hash, @val); } } elsif ( lc $cmd eq 'dect') { if (int @val == 1 && $val[0] =~ /^(on|off)$/) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); my $state = $val[0]; $state =~ s/on/1/; $state =~ s/off/0/; if ($forceTelnet) { # Telnet FRITZBOX_Exec( $hash, "ctlmgr_ctl w dect settings/enabled $state"); } else { #webcm my @webCmdArray = ( ["dect:settings/enabled" => $state] ); FRITZBOX_Web_PostCmd ($hash, \@webCmdArray); } readingsSingleUpdate($hash,"box_dect",$val[0], 1); return undef; } } elsif ( lc $cmd eq 'diversity') { if ( int @val == 2 && defined( $hash->{READINGS}{"diversity".$val[0]} ) && $val[1] =~ /^(on|off)$/ ) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); my $state = $val[1]; $state =~ s/on/1/; $state =~ s/off/0/; if ($forceTelnet) { # Telnet FRITZBOX_Exec( $hash, "ctlmgr_ctl w telcfg settings/Diversity".( $val[0] - 1 )."/Active ".$state ); } else { #webcm my @webCmdArray = ( ["telcfg:settings/Diversity".( $val[0] - 1 )."/Active " => $state] ); FRITZBOX_Web_PostCmd ($hash, \@webCmdArray); } readingsSingleUpdate($hash,"diversity".$val[0]."_state",$val[1], 1); return undef; } } elsif ( lc $cmd eq 'guestwlan') { if (int @val == 1 && $val[0] =~ /^(on|off)$/) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); push @cmdBuffer, "guestwlan ".join(" ", @val); return FRITZBOX_Set_Cmd_Start $hash->{helper}{TimerCmd}; } } elsif ( lc $cmd eq 'moh') { if (int @val > 0) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); $resultStr = FRITZBOX_SetMOH $hash, @val; if ($resultStr =~ /^[012]$/ ) { readingsSingleUpdate($hash,"box_guestWlan",$mohtype[$resultStr], 1); return undef; } else { return $resultStr; } } } # set password elsif ( lc $cmd eq 'password') { if (int @val == 1) { return FRITZBOX_storePassword ( $hash, $val[0] ); } } #set Ring elsif ( lc $cmd eq 'ring') { if (int @val > 0) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); push @cmdBuffer, "ring ".join(" ", @val); return FRITZBOX_Set_Cmd_Start $hash->{helper}{TimerCmd}; } } elsif ( lc $cmd eq 'sendmail') { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); FRITZBOX_SendMail $hash, @val; return undef; } elsif ( lc $cmd eq 'startradio') { if (int @val > 0) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); return FRITZBOX_StartRadio $hash, @val; } } elsif ( lc $cmd eq 'tam') { if ( int @val == 2 && defined( $hash->{READINGS}{"tam".$val[0]} ) && $val[1] =~ /^(on|off)$/ ) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); my $state = $val[1]; $state =~ s/on/1/; $state =~ s/off/0/; if ($forceTelnet) { # Telnet FRITZBOX_Exec( $hash, "ctlmgr_ctl w tam settings/TAM".( $val[0] - 1 )."/Active ".$state ); } elsif ($hash->{SECPORT}) { #TR-064 my @tr064CmdArray = (["X_AVM-DE_TAM:1", "x_tam", "SetEnable", "NewIndex", $val[0] - 1 , "NewEnable", $state]); FRITZBOX_TR064_Cmd( $hash, 0, \@tr064CmdArray ); } else { #webcm my @webCmdArray = ( ["tam:settings/TAM".( $val[0] - 1 )."/Active" => $state] ); FRITZBOX_Web_PostCmd ($hash, \@webCmdArray); } readingsSingleUpdate($hash,"tam".$val[0]."_state",$val[1], 1); return undef; } } elsif ( lc $cmd eq 'update' ) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); $hash->{fhem}{LOCAL}=1; FRITZBOX_Readout_Start($hash->{helper}{TimerReadout}); $hash->{fhem}{LOCAL}=0; return undef; } elsif ( lc $cmd eq 'wlan') { if (int @val == 1 && $val[0] =~ /^(on|off)$/) { Log3 $name, 3, "FRITZBOX: set $name $cmd ".join(" ", @val); push @cmdBuffer, "wlan ".join(" ", @val); return FRITZBOX_Set_Cmd_Start $hash->{helper}{TimerCmd}; } } return "Unknown argument $cmd or wrong parameter(s), choose one of $list"; } # end FRITZBOX_Set # ctlmgr_ctl r timer settings/KidsTimerXML1/ # ctlmgr_ctl r filter_profile settings/profile5/timeprofile_id # ctlmgr_ctl r filter_profile settings/profile5/name ####################################################################### sub FRITZBOX_Get($@) { my ($hash, $name, $cmd, @val) = @_; my $returnStr; if( lc $cmd eq "luaquery" && AttrVal( $name, "allowTR064Command", 0 ) && defined $hash->{SECPORT}) { # get Fritzbox luaQuery inetstat:status/Today/BytesReceivedLow # get Fritzbox luaQuery telcfg:settings/AlarmClock/list(Name,Active,Time,Number,Weekdays) Log3 $name, 3, "FRITZBOX: get $name $cmd ".join(" ", @val); return "Wrong number of arguments, usage: get $name luaQuery " if int @val !=1; $returnStr = "Result of query = '$val[0]'\n"; $returnStr .= "----------------------------------------------------------------------\n"; my $queryStr = "&result=".$val[0]; my $result = FRITZBOX_Web_Query( $hash, $queryStr) ; my $tmp; if (ref $result->{result} eq "") { $tmp = $result->{result}; } else { $tmp = Dumper ($result->{result}); } return $returnStr . $tmp; } elsif( lc $cmd eq "ringtones" ) { Log3 $name, 3, "FRITZBOX: get $name $cmd ".join(" ", @val); $returnStr = "Ring tones to use with 'set ring '\n"; $returnStr .= "----------------------------------------------------------------------\n"; $returnStr .= join "\n", sort values %ringTone; return $returnStr; } elsif( lc $cmd eq "shellcommand" && int @val && AttrVal( $name, "allowShellCommand", 0 ) ) { Log3 $name, 3, "FRITZBOX: get $name $cmd ".join(" ", @val); my $shCmd = join " ", @val; return FRITZBOX_Exec( $hash, $shCmd ); } elsif( lc $cmd eq "tr064command" && AttrVal( $name, "allowTR064Command", 0 ) ) { # http://fritz.box:49000/tr64desc.xml #get Fritzbox tr064command DeviceInfo:1 deviceinfo GetInfo #get Fritzbox tr064command X_VoIP:1 x_voip X_AVM-DE_GetPhonePort NewIndex 1 #get Fritzbox tr064command X_VoIP:1 x_voip X_AVM-DE_DialNumber NewX_AVM-DE_PhoneNumber **612 #get Fritzbox tr064command X_VoIP:1 x_voip X_AVM-DE_DialHangup #get Fritzbox tr064command WLANConfiguration:3 wlanconfig3 X_AVM-DE_GetWLANExtInfo #get Fritzbox tr064command X_AVM-DE_OnTel:1 x_contact GetDECTHandsetList #get Fritzbox tr064command X_AVM-DE_OnTel:1 x_contact GetDECTHandsetInfo NewDectID 1 #get Fritzbox tr064command X_AVM-DE_TAM:1 x_tam GetInfo NewIndex 0 #get Fritzbox tr064command X_AVM-DE_TAM:1 x_tam SetEnable NewIndex 0 NewEnable 0 #get Fritzbox tr064command InternetGatewayDevice:1 deviceinfo GetInfo #get Fritzbox tr064command LANEthernetInterfaceConfig:1 lanethernetifcfg GetStatistics Log3 $name, 3, "FRITZBOX: get $name $cmd ".join(" ", @val); return "Wrong number of arguments, usage: get $name tr064command service control action [parameterName1 parameterValue1] [parameterName2 parameterValue2] ..." if int @val <3 || int(@val) %2 !=1; $returnStr = "Result of TR064 call\n"; $returnStr .= "----------------------------------------------------------------------\n"; $returnStr = "Service='$val[0]' Control='$val[1]' Action='$val[2]'\n"; for(my $i = 1; $i <= (int @val - 3)/2; $i++) { $returnStr .= "Parameter$i='$val[2*$i+1]' => '$val[2*$i+2]'\n"; } $returnStr .= "----------------------------------------------------------------------\n"; my @tr064CmdArray = ( \@val ); my @result = FRITZBOX_TR064_Cmd( $hash, 1, \@tr064CmdArray ); my $tmp = Dumper (@result); $returnStr .= $tmp; return $returnStr; } elsif( lc $cmd eq "tr064servicelist" ) { return FRITZBOX_TR064_Get_ServiceList ($hash); } my $list = "ringTones:noArg"; $list .= " luaQuery" if AttrVal( $name, "allowTR064Command", 0 ); $list .= " tr064Command" if AttrVal( $name, "allowTR064Command", 0 ) && defined $hash->{SECPORT};; $list .= " tr064ServiceList:noArg" if AttrVal( $name, "allowTR064Command", 0 ); $list .= " shellCommand" if AttrVal( $name, "allowShellCommand", 0 ); return "Unknown argument $cmd, choose one of $list"; } # end FRITZBOX_Get ####################################################################### sub FRITZBOX_Set_Alarm_Telnet($@) { my ($hash, @val) = @_; my $name = $hash->{NAME}; my $alarm = $val[0]; shift @val; my $para = " ".join(" ", @val); my $state = 1; my $stateTxt = "on"; if ($para =~ /off/i) { $state = 0; $stateTxt = "off"; } my $time; my $timeTxt; if ($para =~ /([0-2]?\d):([0-5]\d)/ ) { if ($1<10) { $time = 0; $timeTxt = "0"; } $time .= $1.$2; $timeTxt .= $1.":".$2; $time = undef if $time > 2359; } my $day; my $dayTxt; my %alDayValues = %alarmDays; $alDayValues{0} = "once"; $alDayValues{127} = "daily"; while (my ($key, $value) = each(%alDayValues) ) { if ($para =~ /$value/i) { $day += $key ; $dayTxt .= $value." "; } } my $result = FRITZBOX_Telnet_OpenCon( $hash ); return "$name|Error|$result" if $result; readingsBeginUpdate($hash); FRITZBOX_Exec( $hash, "ctlmgr_ctl w telcfg settings/AlarmClock".($alarm-1)."/Active ".$state ); readingsBulkUpdate($hash,"alarm".$alarm."_state",$stateTxt); if (defined $time) { FRITZBOX_Exec( $hash, "ctlmgr_ctl w telcfg settings/AlarmClock".($alarm-1)."/Time ".$time ); readingsBulkUpdate($hash,"alarm".$alarm."_time",$timeTxt); } if (defined $day) { FRITZBOX_Exec( $hash, "ctlmgr_ctl w telcfg settings/AlarmClock".($alarm-1)."/Weekdays ".$day ); chop $dayTxt; readingsBulkUpdate($hash,"alarm".$alarm."_wdays",$dayTxt); } readingsEndUpdate($hash, 1); FRITZBOX_Telnet_CloseCon( $hash ); return undef; } # end FRITZBOX_Set_Alarm_Telnet ####################################################################### sub FRITZBOX_Set_Alarm_Web($@) { my ($hash, @val) = @_; my $name = $hash->{NAME}; my @webCmdArray; my $alarm = $val[0]; shift @val; my $para = " ".join(" ", @val); my $state = 1; my $stateTxt = "on"; if ($para =~ /off/i) { $state = 0; $stateTxt = "off"; } my $time; my $timeTxt; if ($para =~ /([0-2]?\d):([0-5]\d)/ ) { if ($1<10) { $time = 0; $timeTxt = "0"; } $time .= $1.$2; $timeTxt .= $1.":".$2; $time = undef if $time > 2359; } my $day; my $dayTxt; my %alDayValues = %alarmDays; $alDayValues{0} = "once"; $alDayValues{127} = "daily"; while (my ($key, $value) = each(%alDayValues) ) { if ($para =~ /$value/i) { $day += $key ; $dayTxt .= $value." "; } } readingsBeginUpdate($hash); push @webCmdArray, "telcfg:settings/AlarmClock".($alarm-1)."/Active" => $state; readingsBulkUpdate($hash,"alarm".$alarm."_state",$stateTxt); if (defined $time) { push @webCmdArray, "telcfg:settings/AlarmClock".($alarm-1)."/Time" => $time; readingsBulkUpdate($hash,"alarm".$alarm."_time",$timeTxt); } if (defined $day) { push @webCmdArray, "telcfg:settings/AlarmClock".($alarm-1)."/Weekdays" => $day; chop $dayTxt; readingsBulkUpdate($hash,"alarm".$alarm."_wdays",$dayTxt); } FRITZBOX_Web_PostCmd ($hash, \@webCmdArray); readingsEndUpdate($hash, 1); return undef; } # end FRITZBOX_Set_Alarm_Web # Starts the data capturing and sets the new readout timer ####################################################################### sub FRITZBOX_Readout_Start($) { my ($timerpara) = @_; # my ( $name, $func ) = split( /\./, $timerpara ); my $index = rindex( $timerpara, "." ); # rechter punkt my $func = substr $timerpara, $index + 1, length($timerpara); # function extrahieren my $name = substr $timerpara, 0, $index; # name extrahieren my $hash = $defs{$name}; $hash->{INTERVAL} = AttrVal( $name, "INTERVAL", $hash->{INTERVAL} ); $hash->{INTERVAL} = 60 if $hash->{INTERVAL} < 60 && $hash->{INTERVAL} != 0; if($hash->{INTERVAL} != 0) { RemoveInternalTimer($hash->{helper}{TimerReadout}); InternalTimer(gettimeofday()+$hash->{INTERVAL}, "FRITZBOX_Readout_Start", $hash->{helper}{TimerReadout}, 1); return undef if( AttrVal($name, "disable", 0 ) == 1 ); } if ( exists( $hash->{helper}{READOUT_RUNNING_PID} ) && $hash->{fhem}{LOCAL} == 1 ) { FRITZBOX_Log $hash, 1, "Old readout process still running. Killing old process ".$hash->{helper}{READOUT_RUNNING_PID}; BlockingKill( $hash->{helper}{READOUT_RUNNING_PID} ); delete($hash->{helper}{READOUT_RUNNING_PID}); } my $runFn = "FRITZBOX_Readout_Run_Web"; $runFn = "FRITZBOX_Readout_Run_Telnet" if AttrVal( $name, "forceTelnetConnection", 0 ) == 1; $hash->{helper}{READOUT_RUNNING_PID} = BlockingCall($runFn, $name, "FRITZBOX_Readout_Done", 55, "FRITZBOX_Readout_Aborted", $hash) unless exists( $hash->{helper}{READOUT_RUNNING_PID} ); } # end FRITZBOX_Readout_Start # Starts the data capturing via Telnet and sets the new timer ####################################################################### sub FRITZBOX_Readout_Run_Telnet($) { my ($name) = @_; my $hash = $defs{$name}; my $result; my $rName; my @cmdArray; my @readoutCmdArray; my $resultArray; my @roReadings; my %dectFonID; my $i; my $startTime = time(); my $slowRun = 0; if ( int(time/3600) != $hash->{fhem}{lastHour} || $hash->{fhem}{LOCAL} == 1) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->lastHour", int(time/3600); $slowRun = 1; FRITZBOX_Log $hash, 4, "Start update of slow changing device readings."; } else { FRITZBOX_Log $hash, 4, "Start update of fast changing device readings."; } my $returnStr; $result = FRITZBOX_Telnet_OpenCon( $hash ); return $name."|".encode_base64("Error|$result","") if $result; if ($slowRun == 1) { # Init and Counters push @readoutCmdArray, ["", "ctlmgr_ctl r telcfg settings/Foncontrol" ]; push @readoutCmdArray, ["", "ctlmgr_ctl r telcfg settings/Foncontrol/User/count" ]; push @readoutCmdArray, ["", "ctlmgr_ctl r dect settings/Handset/count" ]; push @readoutCmdArray, ["fhem->radioCount", "ctlmgr_ctl r configd settings/WEBRADIO/count" ]; push @readoutCmdArray, ["", "ctlmgr_ctl r user settings/user/count" ]; push @readoutCmdArray, ["", 'echo $CONFIG_AB_COUNT']; push @readoutCmdArray, ["", "ctlmgr_ctl r landevice settings/landevice/count" ]; push @readoutCmdArray, ["", "ctlmgr_ctl r tam settings/TAM/count" ]; push @readoutCmdArray, ["", "ctlmgr_ctl r telcfg settings/RefreshDiversity" ]; push @readoutCmdArray, ["", "ctlmgr_ctl r telcfg settings/Diversity/count" ]; # Box Features push @readoutCmdArray, [ "fhem->is_double_wlan", "ctlmgr_ctl r wlan settings/feature_flags/DBDC" ]; # Box model and firmware push @readoutCmdArray, [ "box_model", 'echo $CONFIG_PRODUKT_NAME' ]; push @readoutCmdArray, [ "box_oem", 'echo $OEM' ]; push @readoutCmdArray, [ "box_fwVersion", "ctlmgr_ctl r logic status/nspver" ]; push @readoutCmdArray, [ "box_fwUpdate", "ctlmgr_ctl r updatecheck status/update_available_hint" ]; push @readoutCmdArray, [ "box_tr069", "ctlmgr_ctl r tr069 settings/enabled", "onoff" ]; # Execute commands $resultArray = FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings); return $name."|".encode_base64("Error|No STDOUT from shell command.","") unless defined $resultArray; my $dectCount = $resultArray->[1]; $dectCount = 1 unless $dectCount=~ /\d/; $dectCount--; my $handsetCount = $resultArray->[2]; $handsetCount = 1 unless $dectCount=~ /\d/; $handsetCount--; my $radioCount = $resultArray->[3]; $radioCount = 0 unless $radioCount=~ /\d/; my $userCount = $resultArray->[4]; my $fonCount = $resultArray->[5]; my $lanDeviceCount = $resultArray->[6]; my $tamCount = $resultArray->[7]; my $divCount = $resultArray->[9]; # Internetradioliste erzeugen $i = 0; $rName = "radio00"; while ( $i<$radioCount || defined $hash->{READINGS}{$rName} ) { push @readoutCmdArray, [ $rName, "ctlmgr_ctl r configd settings/WEBRADIO".$i."/Name" ]; $i++; $rName = sprintf ("radio%02d",$i); } $resultArray = FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings ); my @radio = (); for (0..$radioCount-1) { if ($resultArray->[$_] ne "") { $radio[$_] = $resultArray->[$_]; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->radio->".$_, $resultArray->[$_]; } } # LanDevice-Liste erzeugen if ($lanDeviceCount > 0 ) { for (0..$lanDeviceCount-1) { push @readoutCmdArray, [ "", "ctlmgr_ctl r landevice settings/landevice".$_."/ip" ]; push @readoutCmdArray, [ "", "ctlmgr_ctl r landevice settings/landevice".$_."/name" ]; } $resultArray = FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings ); %landevice = (); for (0..$lanDeviceCount-1) { my $offset = 2 * $_; my $dIp = $resultArray->[ $offset ]; my $dName = $resultArray->[ $offset +1]; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->landevice->$dIp", $dName; $landevice{$dIp}=$dName; } } # Dect Telefonnummern bestimmen for (1..$dectCount) { # 0 Dect-Interne Nummer push @readoutCmdArray, [ "dect".$_."_intern", "ctlmgr_ctl r telcfg settings/Foncontrol/User".$_."/Intern" ]; # 1 Dect-Telefonname push @readoutCmdArray, [ "dect".$_, "ctlmgr_ctl r telcfg settings/Foncontrol/User".$_."/Name" ]; # 2 Internal Ring Tone Name push @readoutCmdArray, [ "dect".$_."_intRingTone", "ctlmgr_ctl r telcfg settings/Foncontrol/User".$_."/IntRingTone", "ringtone" ]; # 3 Alarm Ring Tone Name push @readoutCmdArray, [ "dect".$_."_alarmRingTone", "ctlmgr_ctl r telcfg settings/Foncontrol/User".$_."/AlarmRingTone0", "ringtone" ]; # 4 Radio Name push @readoutCmdArray, [ "dect".$_."_radio", "ctlmgr_ctl r telcfg settings/Foncontrol/User".$_."/RadioRingID", "radio" ]; # 5 Background image push @readoutCmdArray, [ "dect".$_."_imagePath", "ctlmgr_ctl r telcfg settings/Foncontrol/User".$_."/ImagePath" ]; # 6 Customer Ring Tone push @readoutCmdArray, [ "dect".$_."_custRingTone", "ctlmgr_ctl r telcfg settings/Foncontrol/User".$_."/G722RingTone" ]; # 7 Customer Ring Tone Name push @readoutCmdArray, [ "dect".$_."_custRingToneName", "ctlmgr_ctl r telcfg settings/Foncontrol/User".$_."/G722RingToneName" ]; # 8 UserID push @readoutCmdArray, [ "", "ctlmgr_ctl r telcfg settings/Foncontrol/User".$_."/Id" ]; } $resultArray = FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings ); for (1..$dectCount) { my $offset = $_ * 9 - 9; my $intern = $resultArray->[$offset]; my $ID = $resultArray->[ $offset + 8 ]; if ($intern) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->$intern->name", $resultArray->[ $offset + 1 ]; $dectFonID{$ID}{User} = $_; $dectFonID{$ID}{Intern} = $intern; } } # Assign data of DECT handset to DECT numbers for (0..$handsetCount) { # 0 Handset FonUser push @readoutCmdArray, [ "", "ctlmgr_ctl r dect settings/Handset".$_."/User", "" ]; # 1 Handset manufacturer push @readoutCmdArray, [ "", "ctlmgr_ctl r dect settings/Handset".$_."/Manufacturer" ]; # 2 Phone Model push @readoutCmdArray, [ "", "ctlmgr_ctl r dect settings/Handset".$_."/Model", "model" ]; # 3 Firmware Version push @readoutCmdArray, [ "", "ctlmgr_ctl r dect settings/Handset".$_."/FWVersion" ]; } $resultArray = FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings ); # Handset and DECT user can be in different orders for (0..$handsetCount) { my $offset = $_ * 4; my $dectUserID = $resultArray->[$offset]; if ($dectUserID) { my $dectUser = $dectFonID{$dectUserID}{User}; push @roReadings, "dect".$dectUser."_manufacturer|" . $resultArray->[ $offset + 1 ]; FRITZBOX_Log $hash, 5, "dect".$dectUser."_manufacturer: " . $resultArray->[ $offset + 1 ]; push @roReadings, "dect".$dectUser."_model|" . $resultArray->[ $offset + 2 ]; FRITZBOX_Log $hash, 5, "dect".$dectUser."_model: " . $resultArray->[ $offset + 2 ]; push @roReadings, "dect".$dectUser."_fwVersion|" . $resultArray->[ $offset + 3 ]; FRITZBOX_Log $hash, 5, "dect".$dectUser."_fwVersion: " . $resultArray->[ $offset + 3 ]; my $intern = $dectFonID{$dectUserID}{Intern}; push @roReadings, "fhem->$intern->brand|" . $resultArray->[ $offset + 1 ]; push @roReadings, "fhem->$intern->model|" . $resultArray->[ $offset + 2 ];; } } # Analog Fons Name for (1..$fonCount) { push @readoutCmdArray, ["fon".$_, "ctlmgr_ctl r telcfg settings/MSN/Port".($_-1)."/Name" ]; push @readoutCmdArray, ["fon".$_."_out", "ctlmgr_ctl r telcfg settings/MSN/Port".($_-1)."/MSN" ]; } $resultArray = FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings ); # Number of analog Fons for (1..$fonCount) { push @roReadings, "fon".$_."_intern|".$_ if $resultArray->[($_-1)*2]; } # Prepare new command array # Check if TAM is displayed for (0..$tamCount-1) { push @readoutCmdArray, [ "", "ctlmgr_ctl r tam settings/TAM".$_."/Display" ]; } # Check if user (parent control) is not completely blocked for (0..$userCount-1) { push @readoutCmdArray, ["", "ctlmgr_ctl r user settings/user".$_."/filter_profile_UID" ]; } #!!! Execute commands !!! $resultArray = FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings ); # Prepare new command array #Get TAM readings for (0..$tamCount-1) { $rName = "tam".($_+1); if ($resultArray->[$_] eq "1" || defined $hash->{READINGS}{$rName} ) { push @readoutCmdArray, [ $rName, "ctlmgr_ctl r tam settings/TAM". $_ ."/Name" ]; push @readoutCmdArray, [ $rName."_state", "ctlmgr_ctl r tam settings/TAM".$_."/Active", "onoff" ]; push @readoutCmdArray, [ $rName."_newMsg", "ctlmgr_ctl r tam settings/TAM".$_."/NumNewMessages" ]; push @readoutCmdArray, [ $rName."_oldMsg", "ctlmgr_ctl r tam settings/TAM".$_."/NumOldMessages" ]; } } # user profiles $i=0; $rName = "user01"; while ($i<$userCount || defined $hash->{READINGS}{$rName}) { # do not show data for unlimited, blocked or default access rights if ($resultArray->[$i+$tamCount] !~ /^filtprof[134]$/ || defined $hash->{READINGS}{$rName} ) { push @readoutCmdArray, [$rName, "ctlmgr_ctl r user settings/user".$i."/name", "deviceip" ]; push @readoutCmdArray, [$rName."_thisMonthTime", "ctlmgr_ctl r user settings/user".$i."/this_month_time", "secondsintime" ]; push @readoutCmdArray, [$rName."_todayTime", "ctlmgr_ctl r user settings/user".$i."/today_time", "secondsintime" ]; push @readoutCmdArray, [$rName."_todaySeconds", "ctlmgr_ctl r user settings/user".$i."/today_time" ]; push @readoutCmdArray, [$rName."_type", "ctlmgr_ctl r user settings/user".$i."/type", "usertype" ]; } $i++; $rName = sprintf ("user%02d",$i+1); } # Diversity $i=0; $rName = "diversity1"; while ( $i < $divCount || defined $hash->{READINGS}{$rName} ) { # Diversity number push @readoutCmdArray, [$rName, "ctlmgr_ctl r telcfg settings/Diversity".$i."/MSN" ]; # Diversity state push @readoutCmdArray, [$rName."_state", "ctlmgr_ctl r telcfg settings/Diversity".$i."/Active", "onoff" ]; # Diversity destination push @readoutCmdArray, [$rName."_dest", "ctlmgr_ctl r telcfg settings/Diversity".$i."/Destination"]; $i++; $rName = "diversity".($i+1); } # !!! Execute commands !!! FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings ); } # WLAN push @readoutCmdArray, [ "box_wlan_2.4GHz", "ctlmgr_ctl r wlan settings/ap_enabled", "onoff" ]; # 2nd WLAN push @readoutCmdArray, [ "box_wlan_5GHz", "ctlmgr_ctl r wlan settings/ap_enabled_scnd", "onoff" ]; # Gäste WLAN push @readoutCmdArray, [ "box_guestWlan", "ctlmgr_ctl r wlan settings/guest_ap_enabled", "onoff" ]; push @readoutCmdArray, [ "box_guestWlanRemain", "ctlmgr_ctl r wlan settings/guest_time_remain", ]; # Dect push @readoutCmdArray, [ "box_dect", "ctlmgr_ctl r dect settings/enabled", "onoff" ]; # Music on Hold push @readoutCmdArray, [ "box_moh", "ctlmgr_ctl r telcfg settings/MOHType", "mohtype" ]; # Power Rate push @readoutCmdArray, [ "box_powerRate", "ctlmgr_ctl r power status/rate_sumact"]; # Alarm clock for (0..2) { # Alarm clock name push @readoutCmdArray, ["alarm".($_+1), "ctlmgr_ctl r telcfg settings/AlarmClock".$_."/Name" ]; # Alarm clock state push @readoutCmdArray, ["alarm".($_+1)."_state", "ctlmgr_ctl r telcfg settings/AlarmClock".$_."/Active", "onoff" ]; # Alarm clock time push @readoutCmdArray, ["alarm".($_+1)."_time", "ctlmgr_ctl r telcfg settings/AlarmClock".$_."/Time", "altime" ]; # Alarm clock number push @readoutCmdArray, ["alarm".($_+1)."_target", "ctlmgr_ctl r telcfg settings/AlarmClock".$_."/Number", "alnumber" ]; # Alarm clock weekdays push @readoutCmdArray, ["alarm".($_+1)."_wdays", "ctlmgr_ctl r telcfg settings/AlarmClock".$_."/Weekdays", "aldays" ]; } FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings ); push @roReadings, "readoutTime|" . sprintf( "%.2f", time()-$startTime); $returnStr .= join('|', @roReadings ); FRITZBOX_Telnet_CloseCon ( $hash ); FRITZBOX_Log $hash, 4, "Captured " . @roReadings . " values"; FRITZBOX_Log $hash, 5, "Handover (".length ($returnStr)."): ".$returnStr; return $name."|".encode_base64($returnStr,""); } # End FRITZBOX_Readout_Run_Telnet # http://fritz.box/cgi-bin/webcm?wlan:settings/guest_ap_enabled=1&sid= #http://fritz.box/query.lua?sid=&network=landevice:settings/landevice/list(name,ip,mac,UID,dhcp,wlan,ethernet,active,static_dhcp,manu_name,wakeup,deleteable,source,online,speed,wlan_UIDs,auto_wakeup,guest,url,wlan_station_type,vendorname,parentname,parentuid,ethernet_port,wlan_show_in_monitor,plc,ipv6_ifid,parental_control_abuse) # FRITZBOX_Log $hash, 3, "Web connection established with $sid"; # my $urlcgi = 'http://'.$host.'/cgi-bin/webcm'; # my $response = $agent->post( $urlcgi, # [ # "sid" => $sid, # "getpage"=>"../html/query.txt", # "var:cnt"=>"1", # "var:n[0]"=>"wlan:settings/ap_enabled" # "getpage" => "../html/de/menus/menu2.html", # "errorpage" => "../html/index.html", # "var:lang" => "de", # "var:pagename" => "home", # "var:menu" => "home", # "wlan:settings/guest_ap_enabled" => "1" # ], # ); # FRITZBOX_Log $hash, 3, "Debug: ".$response->content; # Starts the data capturing via query.lua and sets the new timer ####################################################################### sub FRITZBOX_Readout_Run_Web($) { my ($name) = @_; my $hash = $defs{$name}; my $result; my $rName; my @roReadings; my %dectFonID; my %resultHash; my $startTime = time(); my $runNo; my $sid; my $slowRun = 0; if ( int(time/3600) != $hash->{fhem}{lastHour} || $hash->{fhem}{LOCAL} == 1) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->lastHour", int(time/3600); $slowRun = 1; FRITZBOX_Log $hash, 4, "Start update of slow changing device readings."; } else { FRITZBOX_Log $hash, 4, "Start update of fast changing device readings."; } my $returnStr; my $queryStr = "&radio=configd:settings/WEBRADIO/list(Name)"; # Webradio $queryStr .= "&box_dect=dect:settings/enabled"; # DECT Sender $queryStr .= "&handset=dect:settings/Handset/list(User,Manufacturer,Model,FWVersion)"; # DECT Handsets $queryStr .= "&init=telcfg settings/Foncontrol"; $queryStr .= "&dectUser=telcfg:settings/Foncontrol/User/list(Id,Name,Intern,IntRingTone,AlarmRingTone0,RadioRingID,ImagePath,G722RingTone,G722RingToneName)"; # DECT Numbers $queryStr .= "&fonPort=telcfg:settings/MSN/Port/list(Name,MSN)"; # Fon ports $queryStr .= "&alarmClock=telcfg:settings/AlarmClock/list(Name,Active,Time,Number,Weekdays)"; # Alarm Clock $queryStr .= "&diversity=telcfg:settings/Diversity/list(MSN,Active,Destination)"; # Diversity (Rufumleitung) $queryStr .= "&box_moh=telcfg:settings/MOHType"; # Music on Hold $queryStr .= "&lanDevice=landevice:settings/landevice/list(ip,name)"; # LAN devices $queryStr .= "&box_fwVersion=logic:status/nspver"; # FW Version $queryStr .= "&box_powerRate=power:status/rate_sumact"; # Power Rate $queryStr .= "&tam=tam:settings/TAM/list(Name,Display,Active,NumNewMessages,NumOldMessages)"; # TAM $queryStr .= "&box_tr069=tr069:settings/enabled"; # TR069 $queryStr .= "&box_fwUpdate=updatecheck:status/update_available_hint"; $queryStr .= "&userProfil=user:settings/user/list(name,filter_profile_UID,this_month_time,today_time,type)"; # User profiles $queryStr .= "&is_double_wlan=wlan:settings/feature_flags/DBDC"; # Box Feature $queryStr .= "&box_wlan_24GHz=wlan:settings/ap_enabled"; # WLAN $queryStr .= "&box_wlan_5GHz=wlan:settings/ap_enabled_scnd"; # 2nd WLAN $queryStr .= "&box_guestWlan=wlan:settings/guest_ap_enabled"; # Gäste WLAN $queryStr .= "&box_guestWlanRemain=wlan:settings/guest_time_remain"; $queryStr .= "&box_guestWlanRemain=wlan:settings/guest_time_remain"; $queryStr .= "&TodayBytesReceivedHigh=inetstat:status/Today/BytesReceivedHigh"; $queryStr .= "&TodayBytesReceivedLow=inetstat:status/Today/BytesReceivedLow"; $queryStr .= "&TodayBytesSentHigh=inetstat:status/Today/BytesSentHigh"; $queryStr .= "&TodayBytesSentLow=inetstat:status/Today/BytesSentLow"; $result = FRITZBOX_Web_Query( $hash, $queryStr) ; if (exists $result->{Error}) { FRITZBOX_Log $hash, 2, "Error: ".$result->{Error}; } FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->sid", $result->{sid}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->sidTime", time(); # Dect-Geräteliste erstellen $runNo = 0; foreach ( @{ $result->{dectUser} } ) { my $intern = $_->{Intern}; my $id = $_->{Id}; if ($intern) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$runNo, $_->{Name} ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$runNo."_intern", $intern ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$runNo."_alarmRingTone", $_->{AlarmRingTone0}, "ringtone" ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$runNo."_intRingTone", $_->{IntRingTone}, "ringtone" ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$runNo."_radio", $_->{RadioRingID}, "radio" ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$runNo."_custRingTone", $_->{G722RingTone} ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$runNo."_custRingToneName", $_->{G722RingToneName} ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$runNo."_imagePath", $_->{ImagePath} ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->$intern->id", $id ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->$intern->userId", $runNo; $dectFonID{$id}{Intern} = $intern; $dectFonID{$id}{User} = $runNo; } $runNo++; } # Handset der internen Nummer zuordnen foreach ( @{ $result->{handset} } ) { my $dectUserID = $_->{User}; my $dectUser = $dectFonID{$dectUserID}{User}; my $intern = $dectFonID{$dectUserID}{Intern}; if ($dectUser) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$dectUser."_manufacturer", $_->{Manufacturer}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$dectUser."_model", $_->{Model}, "model"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "dect".$dectUser."_fwVersion", $_->{FWVersion}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->$intern->brand", $_->{Manufacturer}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->$intern->model", $_->{Model}, "model"; } } # Analog Fons Name $runNo=1; foreach ( @{ $result->{fonPort} } ) { if ( $_->{Name} ) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fon".$runNo, $_->{Name}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fon".$runNo."_out", $_->{MSN}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fon".$runNo."_intern", $runNo; } $runNo++; } # Internetradioliste erzeugen $runNo = 0; $rName = "radio00"; foreach ( @{ $result->{radio} } ) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName, $_->{Name}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->radio->".$runNo, $_->{Name}; $runNo++; $rName = sprintf ("radio%02d",$runNo); } FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->radioCount", $runNo; # LanDevice-Liste erzeugen %landevice = (); foreach ( @{ $result->{lanDevice} } ) { my $dIp = $_->{ip}; my $dName = $_->{name}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->landevice->$dIp", $dName; $landevice{$dIp}=$dName; } # WLANs FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_wlan_2.4GHz", $result->{box_wlan_24GHz}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_wlan_5GHz", $result->{box_wlan_5GHz}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_guestWlan", $result->{box_guestWlan}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_guestWlanRemain", $result->{box_guestWlanRemain}; # Dect FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_dect", $result->{box_dect}, "onoff"; # Music on Hold FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_moh", $result->{box_moh}, "mohtype"; # Power Rate FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_powerRate", $result->{box_powerRate}; # Box Features FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->is_double_wlan", $result->{is_double_wlan}; # Box model and firmware FRITZBOX_Readout_Add_Reading ( $hash, \@roReadings, "box_fwVersion", $result->{box_fwVersion} ); FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_fwUpdate", $result->{box_fwUpdate}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_tr069", $result->{box_tr069}, "onoff"; # Alarm clock $runNo = 1; foreach ( @{ $result->{alarmClock} } ) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "alarm".$runNo, $_->{Name}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "alarm".$runNo."_state", $_->{Active}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "alarm".$runNo."_time", $_->{Time}, "altime"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "alarm".$runNo."_target", $_->{Number}, "alnumber"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "alarm".$runNo."_wdays", $_->{Weekdays}, "aldays"; $runNo++; } #Get TAM readings $runNo = 1; foreach ( @{ $result->{tam} } ) { $rName = "tam".$runNo; if ($_->{Display} eq "1") { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName, $_->{Name}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_state", $_->{Active}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_newMsg", $_->{NumNewMessages}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_oldMsg", $_->{NumOldMessages}; } # Löschen ausgeblendeter TAMs elsif (defined $hash->{READINGS}{$rName} ) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName,""; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_state", ""; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_newMsg",""; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_oldMsg",""; } $runNo++; } # user profiles $runNo = 1; $rName = "user01"; foreach ( @{ $result->{userProfil} } ) { # do not show data for unlimited, blocked or default access rights if ($_->{filter_profile_UID} !~ /^filtprof[134]$/ || defined $hash->{READINGS}{$rName} ) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName, $_->{name}, "deviceip"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_thisMonthTime", $_->{this_month_time}, "secondsintime"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_todayTime", $_->{today_time}, "secondsintime"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_todaySeconds", $_->{today_time}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_type", $_->{type}, "usertype"; } $runNo++; $rName = sprintf ("user%02d",$runNo); } # Diversity $runNo=1; $rName = "diversity1"; foreach ( @{ $result->{diversity} } ) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName, $_->{MSN}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_state", $_->{Active}, "onoff" ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, $rName."_dest", $_->{Destination}; $runNo++; $rName = "diversity".$runNo; } # statistics # attr global showInternalValues 0 FRITZBOX_Readout_Add_Reading $hash, \@roReadings, ".box_TodayBytesReceivedHigh", $result->{TodayBytesReceivedHigh}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, ".box_TodayBytesReceivedLow", $result->{TodayBytesReceivedLow}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, ".box_TodayBytesSentHigh", $result->{TodayBytesSentHigh}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, ".box_TodayBytesSentLow", $result->{TodayBytesSentLow}; if ($slowRun == 1) { # Box model my $host = AttrVal( $name, "fritzBoxIP", "fritz.box" ); my $url = "http://$host/cgi-bin/system_status"; my $agent = LWP::UserAgent->new( env_proxy => 1, keep_alive => 1, protocols_allowed => ['http'], timeout => 10 ); my $response = $agent->get ($url); my $content = $response->content; $content=$1 if $content =~ /(.*)<\/body>/; my @result = split /-/, $content; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_model", $result[0]; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_oem", $result[9]; } push @roReadings, "readoutTime", sprintf( "%.2f", time()-$startTime); $returnStr .= join('|', @roReadings ); FRITZBOX_Log $hash, 4, "Captured " . @roReadings . " values"; FRITZBOX_Log $hash, 5, "Handover (".length ($returnStr)."): ".$returnStr; return $name."|".encode_base64($returnStr,""); } # End FRITZBOX_Readout_Run_Web ####################################################################### sub FRITZBOX_Readout_Done($) { my ($string) = @_; unless (defined $string) { Log 1, "Fatal Error: no parameter handed over"; return; } my ($name,$string2) = split("\\|", $string, 2); my $hash = $defs{$name}; FRITZBOX_Log $hash, 4, "Back at main process"; # delete the marker for RUNNING_PID process delete($hash->{helper}{READOUT_RUNNING_PID}); $string2 = decode_base64($string2); FRITZBOX_Readout_Process ($hash, $string2); } ####################################################################### sub FRITZBOX_Readout_Process($$) { my ($hash,$string) = @_; unless (defined $hash) { Log 1, "Fatal Error: no hash parameter handed over"; return; } my $name = $hash->{NAME}; my (%values) = split("\\|", $string); FRITZBOX_Log $hash, 4, "Processing ". keys(%values)." readouts."; readingsBeginUpdate($hash); if ( defined $values{Error} ) { readingsBulkUpdate( $hash, "lastReadout", $values{Error} ); readingsBulkUpdate( $hash, "state", $values{Error} ); } else { # Statistics if ( defined $values{".box_TodayBytesReceivedLow"} && defined $hash->{READINGS}{".box_TodayBytesReceivedLow"}) { my $valueHigh = $values{".box_TodayBytesReceivedHigh"} - $hash->{READINGS}{".box_TodayBytesReceivedHigh"}{VAL}; $valueHigh *= 2**22; my $valueLow = $values{".box_TodayBytesReceivedLow"} - $hash->{READINGS}{".box_TodayBytesReceivedLow"}{VAL};; $valueLow /= 2**10; my $time = time()-time_str2num($hash->{READINGS}{".box_TodayBytesReceivedLow"}{TIME}); readingsBulkUpdate( $hash, "box_rateDown", sprintf ("%.3f", ($valueHigh+$valueLow) / $time )); } if ( defined $values{".box_TodayBytesSentLow"} && defined $hash->{READINGS}{".box_TodayBytesSentLow"}) { my $valueHigh = $values{".box_TodayBytesSentHigh"} - $hash->{READINGS}{".box_TodayBytesSentHigh"}{VAL}; my $time = time()-time_str2num($hash->{READINGS}{".box_TodayBytesSentLow"}{TIME}); my $valueLow = $values{".box_TodayBytesSentLow"} - $hash->{READINGS}{".box_TodayBytesSentLow"}{VAL};; readingsBulkUpdate( $hash, "box_rateUp", sprintf ("%.3f", ($valueHigh*2**22+$valueLow/2**10) / $time )); } my $x = 0; while (my ($rName, $rValue) = each(%values) ) { if ($rName =~ /->/) { my ($rName1,$rName2,$rName3) = split /->/, $rName; if (defined $rName3) { $hash->{$rName1}{$rName2}{$rName3} = $rValue; } else { $hash->{$rName1}{$rName2} = $rValue; } } elsif ($rName eq "box_fwVersion") { $rValue .= " (old)" if $values{box_fwUpdate} eq "1"; } elsif ($rName eq "box_model") { $rValue .= " [".$values{box_oem}."]" if $values{box_oem}; } if ($rName !~ /->|box_fwUpdate|box_oem|readoutTime/) { if ($rValue ne "") { readingsBulkUpdate( $hash, $rName, $rValue ); FRITZBOX_Log $hash, 5, "SET $rName = '$rValue'"; } elsif ( exists( $hash->{READINGS}{$rName} ) ) { delete $hash->{READINGS}{$rName}; FRITZBOX_Log $hash, 5, "Delete reading $rName."; } else { FRITZBOX_Log $hash, 5, "Ignore reading $rName."; } } } if ( defined $values{"box_wlan_2.4GHz"} ) { my $newState = "WLAN: "; if ( $values{"box_wlan_2.4GHz"} eq "on" ) { $newState .= "on"; } elsif ( $values{box_wlan_5GHz} ) { if ( $values{box_wlan_5GHz} eq "on") { $newState .= "on"; } else { $newState .= "off"; } } else { $newState .= "off"; } $newState .=" gWLAN: ".$values{box_guestWlan} ; $newState .=" (Remain: ".$values{box_guestWlanRemain}." min)" if $values{box_guestWlan} eq "on" && $values{box_guestWlanRemain} != 0; readingsBulkUpdate( $hash, "state", $newState); FRITZBOX_Log $hash, 5, "SET state = '$newState'"; } my $msg = keys( %values )." values captured in ".$values{readoutTime}." s"; readingsBulkUpdate( $hash, "lastReadout", $msg ); FRITZBOX_Log $hash, 4, $msg; } readingsEndUpdate( $hash, 1 ); } ####################################################################### sub FRITZBOX_Readout_Aborted($) { my ($hash) = @_; delete($hash->{helper}{READOUT_RUNNING_PID}); my $msg = "Error: Timeout when reading Fritz!Box data."; readingsSingleUpdate($hash, "lastReadout", $msg, 1); readingsSingleUpdate($hash, "state", $msg, 1); FRITZBOX_Log $hash, 1, $msg; } ####################################################################### sub FRITZBOX_Readout_Query($$$) { my ($hash, $readoutCmdArray, $roReadings) = @_; my @cmdArray; my $rValue; my $rName; my $rFormat; my $count = int @{$readoutCmdArray} - 1; for (0..$count) { push @cmdArray, $readoutCmdArray->[$_][1]; } my $resultArray = FRITZBOX_Exec( $hash, \@cmdArray); if (defined ($resultArray)) { $count = int @{$resultArray} -1; for (0..$count) { $rValue = $resultArray->[$_]; $rFormat = $readoutCmdArray->[$_][2]; $rFormat = "" unless defined $rFormat; $rValue = FRITZBOX_Readout_Format ($hash, $rFormat, $rValue); $rName = $readoutCmdArray->[$_][0]; if ($rName ne "") { FRITZBOX_Log $hash, 5, "$rName: $rValue"; push @{$roReadings}, $rName."|".$rValue; } } } @{$readoutCmdArray} = (); return $resultArray; } ####################################################################### sub FRITZBOX_Readout_Format($$$) { my ($hash, $format, $readout) = @_; return $readout unless defined $format; return $readout unless $readout ne "" && $format ne "" ; if ($format eq "aldays") { if ($readout eq "0") { $readout = "once"; } elsif ($readout >= 127) { $readout = "daily"; } else { my $bitStr = $readout; $readout = ""; foreach (sort {$a <=> $b} keys %alarmDays) { $readout .= (($bitStr & $_) == $_) ? $alarmDays{$_}." " : ""; } chop $readout; } } elsif ($format eq "alnumber") { my $intern = $readout; if (1 <= $readout && $readout <=2) { $readout = "FON $intern"; } elsif ($readout == 9) { $readout = "all DECT"; } elsif (60 <= $readout && $readout <=65) { $intern = $readout + 550; $readout = "DECT $intern"; } elsif ($readout == 50) { $readout = "all"; } $readout .= " (".$hash->{fhem}{$intern}{name}.")" if defined $hash->{fhem}{$intern}{name}; } elsif ($format eq "altime") { $readout =~ s/(\d\d)(\d\d)/$1:$2/; } elsif ($format eq "deviceip") { $readout = $landevice{$readout}." ($readout)" if defined $landevice{$readout}; } elsif ($format eq "model") { $readout = $fonModel{$readout} if defined $fonModel{$readout}; } elsif ($format eq "mohtype") { $readout = $mohtype[$readout] if defined $mohtype[$readout]; $readout = "" if $readout eq "er"; } elsif ($format eq "nounderline") { $readout =~ s/_/ /g; } elsif ($format eq "onoff") { $readout =~ s/er//; $readout =~ s/no-emu//; $readout =~ s/0/off/; $readout =~ s/1/on/; } elsif ($format eq "radio") { if (defined $hash->{fhem}{radio}{$readout}) { $readout = $hash->{fhem}{radio}{$readout}; } else { $readout .= " (unknown)"; } } elsif ($format eq "ringtone") { $readout = $ringTone{$readout}; } elsif ($format eq "secondsintime") { if ($readout < 243600) { $readout = sprintf "%d:%02d", int $readout/3600, int( ($readout %3600) / 60); } else { $readout = sprintf "%dd %d:%02d", int $readout/24/3600, int ($readout%24*3600)/3600, int( ($readout %3600) / 60); } } elsif ($format eq "usertype") { $readout = $userType{$readout}; } $readout = "" unless defined $readout; return $readout; } ####################################################################### sub FRITZBOX_Readout_Add_Reading ($$$$@) { my ($hash, $roReadings, $rName, $rValue, $rFormat) = @_; $rFormat = "" unless defined $rFormat; $rValue = FRITZBOX_Readout_Format ($hash, $rFormat, $rValue); push @{$roReadings}, $rName."|" . $rValue; FRITZBOX_Log $hash, 5, "$rName: $rValue"; } ####################################################################### sub FRITZBOX_Set_Cmd_Start($) { my ($timerpara) = @_; # my ( $name, $func ) = split( /\./, $timerpara ); my $index = rindex( $timerpara, "." ); # rechter punkt my $func = substr $timerpara, $index + 1, length($timerpara); # function extrahieren my $name = substr $timerpara, 0, $index; # name extrahieren my $hash = $defs{$name}; my $cmdFunction; my $timeout; my $handover; return unless int @cmdBuffer; # kill old process if timeout + 10s is reached if ( exists( $hash->{helper}{CMD_RUNNING_PID}) && time()> $cmdBufferTimeout + 10 ) { FRITZBOX_Log $hash, 1, "Old command still running. Killing old command: ".$cmdBuffer[0]; shift @cmdBuffer; BlockingKill( $hash->{helper}{CMD_RUNNING_PID} ); delete $hash->{helper}{CMD_RUNNING_PID}; return unless int @cmdBuffer; } # (re)start timer if command buffer is still filled if (int @cmdBuffer >1) { RemoveInternalTimer($hash->{helper}{TimerCmd}); InternalTimer(gettimeofday()+1, "FRITZBOX_Set_Cmd_Start", $hash->{helper}{TimerCmd}, 1); } # do not continue until running command has finished or is aborted return if exists $hash->{helper}{CMD_RUNNING_PID}; my @val = split / /, $cmdBuffer[0]; my $forceTelnet = AttrVal( $name, "forceTelnetConnection", 0 ); # Preparing SET Call if ($val[0] eq "call") { shift @val; $timeout = 60; $timeout = $val[2] if defined $val[2] && $val[2] =~/^\d+$/; $timeout += 30; $cmdBufferTimeout = time() + $timeout; $handover = $name . "|" . join( "|", @val ); $cmdFunction = "FRITZBOX_Call_Run_Web"; $cmdFunction = "FRITZBOX_Call_Run_Telnet" if $forceTelnet; } # Preparing SET guestWLAN elsif ($val[0] eq "guestwlan") { shift @val; $timeout = 10; $cmdBufferTimeout = time() + $timeout; $handover = $name . "|" . join( "|", @val ); $cmdFunction = "FRITZBOX_GuestWlan_Run_Web"; $cmdFunction = "FRITZBOX_GuestWlan_Run_Telnet" if $forceTelnet; } # Preparing SET RING elsif ($val[0] eq "ring") { shift @val; $timeout = 5; if ($val[2]) { $timeout = $val[2] if $val[2] =~/^\d+$/; } $timeout += 30; $cmdBufferTimeout = time() + $timeout; $handover = $name . "|" . join( "|", @val ); $cmdFunction = "FRITZBOX_Ring_Run_Web"; $cmdFunction = "FRITZBOX_Ring_Run_Telnet" if $forceTelnet; } # Preparing SET WLAN elsif ($val[0] eq "wlan") { shift @val; $timeout = 10; $cmdBufferTimeout = time() + $timeout; $handover = $name . "|" . join( "|", @val ); $cmdFunction = "FRITZBOX_Wlan_Run_Web"; $cmdFunction = "FRITZBOX_Wlan_Run_Telnet" if $forceTelnet; } # No valid set operation else { my $msg = "Unknown command '".join( " ", @val )."'"; FRITZBOX_Log $hash, 1, $msg; return $msg; } # Starting new command $hash->{helper}{CMD_RUNNING_PID} = BlockingCall($cmdFunction, $handover, "FRITZBOX_Set_Cmd_Done", $timeout, " FRITZBOX_Set_Cmd_Aborted", $hash); return undef; } # end FRITZBOX_Set_Cmd_Start ####################################################################### sub FRITZBOX_Set_Cmd_Done($) { my ($string) = @_; unless (defined $string) { Log 1, "Fatal Error: no parameter handed over"; return; } my ($name, $success, $result) = split("\\|", $string,3); my $hash = $defs{$name}; FRITZBOX_Log $hash, 4, "Back at main process"; shift (@cmdBuffer); delete($hash->{helper}{CMD_RUNNING_PID}); if ( $success !~ /1|2/ ) { FRITZBOX_Log $hash, 1, $result; } elsif ( $success == 1 ) { FRITZBOX_Log $hash, 4, $result; } elsif ($success == 2 ) { $result = decode_base64($result); FRITZBOX_Readout_Process ( $hash, $result ); } } ####################################################################### sub FRITZBOX_Set_Cmd_Aborted($) { my ($hash) = @_; my $lastCmd = shift (@cmdBuffer); delete($hash->{helper}{CMD_RUNNING_PID}); FRITZBOX_Log $hash, 1, "Timeout reached for: $lastCmd"; } ####################################################################### sub FRITZBOX_Call_Run_Telnet($) { my ($string) = @_; my ($name, @val) = split "\\|", $string; my $hash = $defs{$name}; return "$name|0|Error: At least one parameter must be defined." unless int @val; my $result; my @cmdArray; my $duration = 60; my $extNo = $val[0]; my %field; my $lastField; my $ttsLink; # Check if 1st parameter is a valid number return $name."|0|Error: Parameter '$extNo' not a valid phone number" unless $extNo =~ /^[\d\*\#+,]+$/; $extNo =~ s/#$//; # Check if 2nd parameter is the duration shift @val; if (int @val) { if ($val[0] =~ /^\d+$/ && int $val[0] > 0) { $duration = $val[0]; FRITZBOX_Log $hash, 5, "Extracted call duration of $duration s."; shift @val; } } # Extract text to say or play foreach (@val) { if ($_ =~ /^(say|play):/i) { $lastField = $1; $_ =~ s/^$1://; } $field{$lastField} .= $_." " if $lastField; } # Create tts link to say as moh if ( $field{say} ) { unless ($hash->{READINGS}{box_moh}) { FRITZBOX_Log $hash, 2, "Cannot do Text2Speech because box has no music on hold"; } else { chop $field{say}; # http://translate.google.com/translate_tts?ie=UTF-8&tl=[SPRACHE]&q=[TEXT]; $ttsLink = $ttsLinkTemplate; my $ttsText = substr $field{say},0,100; my $ttsLang = "de"; if ($ttsText =~ /^\((en|es|fr|nl)\)/i ) { $ttsLang = $1; $ttsText =~ s/^\($1\)\s*//i; } $ttsLink =~ s/\[SPRACHE\]/$ttsLang/; $ttsText = uri_escape($ttsText); $ttsLink =~ s/\[TEXT\]/$ttsText/; FRITZBOX_Log $hash, 5, "Created Text2Speech internet link: $ttsLink"; } } if ($field{play}) { unless ($hash->{READINGS}{box_moh}) { FRITZBOX_Log $hash, 2, "Cannot play mp3 because box has no music on hold"; } elsif ($ttsLink) { FRITZBOX_Log $hash, 3, "Ignore 'play:' because Text2Speech already defined."; } else { chop $field{play}; $ttsLink = $field{play}; FRITZBOX_Log $hash, 5, "Extracted MP3 ring tone: $ttsLink"; } } $result = FRITZBOX_Telnet_OpenCon( $hash ); return "$name|0|$result" if $result; @cmdArray = (); # Creation fhemRadioStation for ttsLink if ($ttsLink) { #Preparing 1st command array push @cmdArray, '[ -f "'.$mohUpload.'" ] && rm "'.$mohUpload.'"'; push @cmdArray, '[ -f "'.$mohOld.'" ] && rm "'.$mohOld.'"'; push @cmdArray, '[ -f "'.$mohNew.'" ] && rm "'.$mohNew.'"'; push @cmdArray, 'wget -U Mozilla -O "'.$mohUpload.'" "'.$ttsLink.'"'; push @cmdArray, '[ -f "'.$mohUpload.'" ] && echo 1 || echo 0'; push @cmdArray, '[ -e /var/flash/fx_moh ] && echo 1 || echo 0'; # Execute 1st command array $result = FRITZBOX_Exec ( $hash, \@cmdArray ); return "$name|0|Could not access '$ttsLink'" unless $result->[4] eq "1"; return "$name|0|Could locate '/var/flash/fx_moh'" unless $result->[5] eq "1"; #Prepare 2nd command array push @cmdArray, 'if [ ! -f "/var/tmp/ffmpeg_mp3.tables" ]; then playerd_tables; fi'; push @cmdArray, 'ffmpegconv -i "'.$mohUpload.'" -o "'.$mohNew.'" --limit 32 --type 6'; push @cmdArray, '[ -f "'.$mohNew.'" ] && echo 1 || echo 0'; # Execute 2nd command array $result = FRITZBOX_Exec ( $hash, \@cmdArray ); return "Could not convert '$ttsLink'" unless $result->[2] eq "1"; #Execute 3rd command array FRITZBOX_Exec( $hash, \@cmdArray ); #Prepare 4th command array push @cmdArray, 'cat /var/flash/fx_moh >"'.$mohOld.'"'; push @cmdArray, 'cat "'.$mohNew.'" >/var/flash/fx_moh'; push @cmdArray, 'killall -sigusr1 telefon'; push @cmdArray, 'rm "'.$mohUpload.'"'; push @cmdArray, 'rm "'.$mohNew.'"'; # Execute 4th command array FRITZBOX_Exec ( $hash, \@cmdArray ); } #Preparing 4th command array # switch to (dial port 1-3) to avoid ringing of internal phone my $ringWithIntern = AttrVal( $name, "ringWithIntern", 1 ); # push @cmdArray, "ctlmgr_ctl w telcfg settings/DialPort 60"; push @cmdArray, "ctlmgr_ctl w telcfg settings/DialPort $ringWithIntern" if $ringWithIntern =~ /^([1-3])$/ ; FRITZBOX_Log $hash, 4, "Call $extNo for $duration seconds"; push @cmdArray, "ctlmgr_ctl w telcfg command/Dial ".$extNo."#"; push @cmdArray, "sleep ".($duration+1); # 1s added because it takes sometime until it starts ringing push @cmdArray, "ctlmgr_ctl w telcfg command/Hangup $ringWithIntern"; push @cmdArray, "ctlmgr_ctl w telcfg settings/DialPort 50"; if ($ttsLink) { push @cmdArray, 'cat "'.$mohOld.'" >/var/flash/fx_moh'; push @cmdArray, 'killall -sigusr1 telefon'; push @cmdArray, 'rm "'.$mohOld.'"'; } # Execute command array FRITZBOX_Exec( $hash, \@cmdArray ); FRITZBOX_Telnet_CloseCon( $hash ); return $name."|1|Calling done"; } # End FRITZBOX_Call_Run_Telnet ####################################################################### sub FRITZBOX_Call_Run_Web($) { my ($string) = @_; my ($name, @val) = split "\\|", $string; my $hash = $defs{$name}; return "$name|0|Error: At least one parameter must be defined." unless int @val; my $result; my @telnetCmdArray; my @webCmdArray; my @tr064CmdArray; my $duration = 60; my $extNo = $val[0]; my %field; my $lastField; my $ttsLink; # Check if 1st parameter is a valid number return $name."|0|Error: Parameter '$extNo' not a valid phone number" unless $extNo =~ /^[\d\*\#+,]+$/; $extNo =~ s/#$//; # Check if 2nd parameter is the duration shift @val; if (int @val) { if ($val[0] =~ /^\d+$/ && int $val[0] > 0) { $duration = $val[0]; FRITZBOX_Log $hash, 5, "Extracted call duration of $duration s."; shift @val; } } # Extract text to say or play foreach (@val) { if ($_ =~ /^(say|play):/i) { $lastField = $1; $_ =~ s/^$1://; } $field{$lastField} .= $_." " if $lastField; } # Create tts link to say as moh if ( $field{say} ) { unless ($hash->{READINGS}{box_moh}) { FRITZBOX_Log $hash, 2, "Cannot do Text2Speech because box has no music on hold"; } else { chop $field{say}; # http://translate.google.com/translate_tts?ie=UTF-8&tl=[SPRACHE]&q=[TEXT]; $ttsLink = $ttsLinkTemplate; my $ttsText = substr $field{say},0,100; my $ttsLang = "de"; if ($ttsText =~ /^\((en|es|fr|nl)\)/i ) { $ttsLang = $1; $ttsText =~ s/^\($1\)\s*//i; } $ttsLink =~ s/\[SPRACHE\]/$ttsLang/; $ttsText = uri_escape($ttsText); $ttsLink =~ s/\[TEXT\]/$ttsText/; FRITZBOX_Log $hash, 5, "Created Text2Speech internet link: $ttsLink"; } } if ($field{play}) { unless ($hash->{READINGS}{box_moh}) { FRITZBOX_Log $hash, 2, "Cannot play mp3 because box has no music on hold"; } elsif ($ttsLink) { FRITZBOX_Log $hash, 3, "Ignore 'play:' because Text2Speech already defined."; } else { chop $field{play}; $ttsLink = $field{play}; FRITZBOX_Log $hash, 5, "Extracted MP3 ring tone: $ttsLink"; } } $result = FRITZBOX_Telnet_OpenCon( $hash ); return "$name|0|$result" if $result; @telnetCmdArray = (); # Creation fhemRadioStation for ttsLink if ($ttsLink) { #Preparing 1st command array push @telnetCmdArray, '[ -f "'.$mohUpload.'" ] && rm "'.$mohUpload.'"'; push @telnetCmdArray, '[ -f "'.$mohOld.'" ] && rm "'.$mohOld.'"'; push @telnetCmdArray, '[ -f "'.$mohNew.'" ] && rm "'.$mohNew.'"'; push @telnetCmdArray, 'wget -U Mozilla -O "'.$mohUpload.'" "'.$ttsLink.'"'; push @telnetCmdArray, '[ -f "'.$mohUpload.'" ] && echo 1 || echo 0'; push @telnetCmdArray, '[ -e /var/flash/fx_moh ] && echo 1 || echo 0'; # Execute 1st command array $result = FRITZBOX_Exec ( $hash, \@telnetCmdArray ); return "$name|0|Could not access '$ttsLink'" unless $result->[4] eq "1"; return "$name|0|Could locate '/var/flash/fx_moh'" unless $result->[5] eq "1"; #Prepare 2nd command array push @telnetCmdArray, 'if [ ! -f "/var/tmp/ffmpeg_mp3.tables" ]; then playerd_tables; fi'; push @telnetCmdArray, 'ffmpegconv -i "'.$mohUpload.'" -o "'.$mohNew.'" --limit 32 --type 6'; push @telnetCmdArray, '[ -f "'.$mohNew.'" ] && echo 1 || echo 0'; # Execute 2nd command array $result = FRITZBOX_Exec ( $hash, \@telnetCmdArray ); return "Could not convert '$ttsLink'" unless $result->[2] eq "1"; #Execute 3rd command array FRITZBOX_Exec( $hash, \@telnetCmdArray ); #Prepare 4th command array push @telnetCmdArray, 'cat /var/flash/fx_moh >"'.$mohOld.'"'; push @telnetCmdArray, 'cat "'.$mohNew.'" >/var/flash/fx_moh'; push @telnetCmdArray, 'killall -sigusr1 telefon'; push @telnetCmdArray, 'rm "'.$mohUpload.'"'; push @telnetCmdArray, 'rm "'.$mohNew.'"'; # Execute 4th command array FRITZBOX_Exec ( $hash, \@telnetCmdArray ); } # Preparing 4th command array to switch to (dial port 1-3) to avoid ringing of internal phone my $ringWithIntern = AttrVal( $name, "ringWithIntern", 1 ); if ($ringWithIntern =~ /^([1-3])$/) { push @webCmdArray, "telcfg:settings/DialPort" => $ringWithIntern; $result = FRITZBOX_Web_PostCmd( $hash, \@webCmdArray ); } #Preparing 5th command array to ring FRITZBOX_Log $hash, 4, "Call $extNo for $duration seconds"; if ($hash->{SECPORT}) { #ring with TR-064 push @tr064CmdArray, ["X_VoIP:1", "x_voip", "X_AVM-DE_DialNumber", "NewX_AVM-DE_PhoneNumber", $extNo."#"]; $result = FRITZBOX_TR064_Cmd( $hash, 0, \@tr064CmdArray ); } else { # ring with webcm push @webCmdArray, "telcfg:command/Dial" => $extNo."#"; $result = FRITZBOX_Web_PostCmd( $hash, \@webCmdArray ); } sleep $duration; #+1; # 1s added because it takes sometime until it starts ringing #Preparing 5th and 6th command array to stop ringing and reset dial port push @tr064CmdArray, ["X_VoIP:1", "x_voip", "X_AVM-DE_DialHangup"]; $result = FRITZBOX_TR064_Cmd( $hash, 0, \@tr064CmdArray ) if $hash->{SECPORT}; push (@webCmdArray, "telcfg:command/Hangup" => "") unless $hash->{SECPORT}; push @webCmdArray, "telcfg:settings/DialPort" => 50; $result = FRITZBOX_Web_PostCmd( $hash, \@webCmdArray ); #Preparing 7th command array to reset everything if ($ttsLink) { push @telnetCmdArray, 'cat "'.$mohOld.'" >/var/flash/fx_moh'; push @telnetCmdArray, 'killall -sigusr1 telefon'; push @telnetCmdArray, 'rm "'.$mohOld.'"'; } # Execute command array FRITZBOX_Exec( $hash, \@telnetCmdArray ); FRITZBOX_Telnet_CloseCon( $hash ); return $name."|1|Calling done"; } # End FRITZBOX_Call_Run_Web ####################################################################### sub FRITZBOX_GuestWlan_Run_Telnet($) { my ($string) = @_; my ($name, @val) = split "\\|", $string; my $hash = $defs{$name}; my $result; my @readoutCmdArray; my @roReadings; my $startTime = time(); my $state = $val[0]; $state =~ s/on/1/; $state =~ s/off/0/; $result = FRITZBOX_Telnet_OpenCon( $hash ); return "$name|0|$result" if $result; my $returnStr; $result = FRITZBOX_Exec $hash, "[ -n `ctlmgr_ctl r wlan settings/guest_pskvalue` ] && echo 1 || echo 0"; return "$name|0|Error: No password defined for guest WLAN." unless $result; # Set WLAN on if guestWLAN on push @readoutCmdArray, [ "", "ctlmgr_ctl w wlan settings/wlan_enable 1"] if $state == 1; # Set guestWLAN push @readoutCmdArray, [ "", "ctlmgr_ctl w wlan settings/guest_ap_enabled $state"]; # Wait 5 s until it is done (to avoid reading console messages) # push @readoutCmdArray, [ "", "sleep 5"]; # Read WLAN push @readoutCmdArray, [ "box_wlan_2.4GHz", "ctlmgr_ctl r wlan settings/ap_enabled", "onoff" ]; # Read 2nd WLAN push @readoutCmdArray, [ "box_wlan_5GHz", "ctlmgr_ctl r wlan settings/ap_enabled_scnd", "onoff" ]; # Read Gäste WLAN push @readoutCmdArray, [ "box_guestWlan", "ctlmgr_ctl r wlan settings/guest_ap_enabled", "onoff" ]; push @readoutCmdArray, [ "box_guestWlanRemain", "ctlmgr_ctl r wlan settings/guest_time_remain", ]; # Execute commands FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings); FRITZBOX_Telnet_CloseCon ( $hash ); FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "readoutTime", sprintf( "%.2f", time()-$startTime); $returnStr .= join('|', @roReadings ); FRITZBOX_Log $hash, 5, "Handover: ".$returnStr; return $name."|2|".encode_base64($returnStr,""); } # end FRITZBOX_GuestWlan_Run_Telnet ####################################################################### sub FRITZBOX_GuestWlan_Run_Web($) { my ($string) = @_; my ($name, @val) = split "\\|", $string; my $hash = $defs{$name}; my $result; my @webCmdArray; my @tr064CmdArray; my @roReadings; my $startTime = time(); my $state = $val[0]; $state =~ s/on/1/; $state =~ s/off/0/; # $result = FRITZBOX_Exec $hash, "[ -n `ctlmgr_ctl r wlan settings/guest_pskvalue` ] && echo 1 || echo 0"; # return "$name|0|Error: No password defined for guest WLAN." # unless $result; # Set guestWLAN, if necessary set also WLAN if ($hash->{SECPORT}) { #TR-064 if ($state == 1) { # WLAN on when Guest WLAN on push @tr064CmdArray, ["WLANConfiguration:1", "wlanconfig1", "SetEnable", "NewEnable", "1"]; push @tr064CmdArray, ["WLANConfiguration:2", "wlanconfig2", "SetEnable", "NewEnable", "1"] if $hash->{fhem}->{is_double_wlan} == 1; } my $gWlanNo = 2; $gWlanNo = 3 if $hash->{fhem}->{is_double_wlan} == 1; push @tr064CmdArray, ["WLANConfiguration:".$gWlanNo, "wlanconfig".$gWlanNo, "SetEnable", "NewEnable", $state]; $result = FRITZBOX_TR064_Cmd( $hash, 0, \@tr064CmdArray ); } else { #webcm push @webCmdArray, "wlan:settings/wlan_enable" => "1" if $state == 1; # push @webCmdArray, "active" => "on"; # FRITZBOX_Web_PostCmd ($hash, \@webCmdArray, '/wlan/wlan_settings.lua'); push @webCmdArray, "wlan:settings/guest_ap_enabled" => $state; $result = FRITZBOX_Web_PostCmd( $hash, \@webCmdArray ); } # push @webCmdArray, "autoupdate" => "on"; # push @webCmdArray, "activate_guest_access" => $val[0]; # FRITZBOX_Web_PostCmd ($hash, \@webCmdArray, '/wlan/guest_access.lua'); #POSTDATA=autoupdate=on&activate_guest_access=on&guest_ssid=Gast-WLAN&sec_mode=3&wpa_key=Baby%2412sitter&push_service=on&group_access=on&down_time_activ=on&down_time_value=240&disconnect_guest_access=on&apply= # Read WLAN-Status my $queryStr = "&box_wlan_24GHz=wlan:settings/ap_enabled"; # WLAN $queryStr .= "&box_wlan_5GHz=wlan:settings/ap_enabled_scnd"; # 2nd WLAN $queryStr .= "&box_guestWlan=wlan:settings/guest_ap_enabled"; # Gäste WLAN $queryStr .= "&box_guestWlanRemain=wlan:settings/guest_time_remain"; $result = FRITZBOX_Web_Query( $hash, $queryStr) ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_wlan_2.4GHz", $result->{box_wlan_24GHz}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_wlan_5GHz", $result->{box_wlan_5GHz}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_guestWlan", $result->{box_guestWlan}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_guestWlanRemain", $result->{box_guestWlanRemain}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->sid", $result->{sid}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->sidTime", time(); FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "readoutTime", sprintf( "%.2f", time()-$startTime); my $returnStr = join('|', @roReadings ); FRITZBOX_Log $hash, 5, "Handover: ".$returnStr; return $name."|2|".encode_base64($returnStr,""); } # end FRITZBOX_GuestWlan_Run_Web ####################################################################### sub FRITZBOX_Wlan_Run_Telnet($) { my ($string) = @_; my ($name, @val) = split "\\|", $string; my $hash = $defs{$name}; my $result; my @readoutCmdArray; my @roReadings; my $startTime = time(); my $state = $val[0]; $state =~ s/on/1/; $state =~ s/off/0/; $result = FRITZBOX_Telnet_OpenCon( $hash ); return "$name|0|$result" if $result; my $returnStr; # Set WLAN push @readoutCmdArray, [ "", "ctlmgr_ctl w wlan settings/wlan_enable $state"]; # Read WLAN push @readoutCmdArray, [ "box_wlan_2.4GHz", "ctlmgr_ctl r wlan settings/ap_enabled", "onoff" ]; # Read 2nd WLAN push @readoutCmdArray, [ "box_wlan_5GHz", "ctlmgr_ctl r wlan settings/ap_enabled_scnd", "onoff" ]; # Read Gäste WLAN push @readoutCmdArray, [ "box_guestWlan", "ctlmgr_ctl r wlan settings/guest_ap_enabled", "onoff" ]; push @readoutCmdArray, [ "box_guestWlanRemain", "ctlmgr_ctl r wlan settings/guest_time_remain", ]; # Execute commands FRITZBOX_Readout_Query( $hash, \@readoutCmdArray, \@roReadings); FRITZBOX_Telnet_CloseCon ( $hash ); FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "readoutTime", sprintf( "%.2f", time()-$startTime); $returnStr .= join('|', @roReadings ); FRITZBOX_Log $hash, 5, "Handover: ".$returnStr; return $name."|2|".encode_base64($returnStr,""); } # end FRITZBOX_Wlan_Run_Telnet ####################################################################### sub FRITZBOX_Wlan_Run_Web($) { my ($string) = @_; my ($name, @val) = split "\\|", $string; my $hash = $defs{$name}; my $result; my @webCmdArray; my @tr064CmdArray; my @roReadings; my $startTime = time(); my $state = $val[0]; $state =~ s/on/1/; $state =~ s/off/0/; # Set WLAN if ($hash->{SECPORT}) { #TR-064 push @tr064CmdArray, ["WLANConfiguration:1", "wlanconfig1", "SetEnable", "NewEnable", $state]; push @tr064CmdArray, ["WLANConfiguration:2", "wlanconfig2", "SetEnable", "NewEnable", $state] if $hash->{fhem}->{is_double_wlan} == 1; $result = FRITZBOX_TR064_Cmd( $hash, 0, \@tr064CmdArray ); } else { #webcm push @webCmdArray, "wlan:settings/wlan_enable" => $state; FRITZBOX_Web_PostCmd ($hash, \@webCmdArray); # push @webCmdArray, "active" => "on" if $val[0] eq "on"; # FRITZBOX_Web_PostCmd ($hash, \@webCmdArray, '/wlan/wlan_settings.lua'); } # Read WLAN-Status my $queryStr = "&box_wlan_24GHz=wlan:settings/ap_enabled"; # WLAN $queryStr .= "&box_wlan_5GHz=wlan:settings/ap_enabled_scnd"; # 2nd WLAN $queryStr .= "&box_guestWlan=wlan:settings/guest_ap_enabled"; # Gäste WLAN $queryStr .= "&box_guestWlanRemain=wlan:settings/guest_time_remain"; $result = FRITZBOX_Web_Query( $hash, $queryStr) ; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_wlan_2.4GHz", $result->{box_wlan_24GHz}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_wlan_5GHz", $result->{box_wlan_5GHz}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_guestWlan", $result->{box_guestWlan}, "onoff"; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "box_guestWlanRemain", $result->{box_guestWlanRemain}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->sid", $result->{sid}; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->sidTime", time(); FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "readoutTime", sprintf( "%.2f", time()-$startTime); my $returnStr = join('|', @roReadings ); FRITZBOX_Log $hash, 5, "Handover: ".$returnStr; return $name."|2|".encode_base64($returnStr,""); } # end FRITZBOX_Wlan_Run_Web ####################################################################### sub FRITZBOX_Ring_Run_Telnet($) { my ($string) = @_; my ($name, @val) = split "\\|", $string; my $hash = $defs{$name}; return "$name|0|Error: At least one parameter must be defined." unless int @val; my $result; my $curCallerName; my @cmdArray; my $duration = 5; my $intNo = $val[0]; my @FritzFons; my $ringTone; my %field; my $lastField; my $ttsLink; my $fhemRadioStation; # Check if 1st parameter are comma separated numbers return $name."|0|Error: Parameter '$intNo' not a number (only commas (,) are allowed to separate numbers)" unless $intNo =~ /^[\d,]+$/; $intNo =~ s/#$//; # Create a hash for the DECT devices whose ring tone (or radio station) can be changed foreach ( split( /,/, $intNo ) ) { if ("AVM" eq $hash->{fhem}{$_}{brand}) { FRITZBOX_Log $hash, 5, "Internal number $_ seems to be a Fritz!Fon."; push @FritzFons, $_ - 609; } } # Check if 2nd parameter is the duration shift @val; if (int @val) { if ($val[0] =~ /^\d+$/ && int $val[0] > 0) { $duration = $val[0]; FRITZBOX_Log $hash, 5, "Extracted ring duration of $duration s."; shift @val; } } # Check if next parameter is a valid ring tone if (int @val) { if ($val[0] !~ /^(msg|show|say|play):/i) { $ringTone = $val[0]; $ringTone = $ringToneNumber{lc $val[0]}; return $name."|0|Error: Ring tone '".$val[0]."' not valid" unless defined $ringTone; FRITZBOX_Log $hash, 5, "Ring tone $ringTone will be used."; shift @val; } } # Extract text to say, play or show foreach (@val) { if ($_ =~ /^(show|msg|say|play):/i) { $lastField = $1; $_ =~ s/^$1://; } $field{$lastField} .= $_." " if $lastField; } my $msg = AttrVal( $name, "defaultCallerName", "FHEM" ); if ( $field{show} ) { chop $field{show}; $msg = $field{show}; } elsif ( $field{msg} ) { chop $field{msg}; $msg = $field{msg}; } $msg = substr($msg, 0, 30); # Determine number of Internet Radio to play mp3 or say tts if ( $field{say} || $field{play} ) { foreach (keys %{$hash->{fhem}{radio}}) { if ($hash->{fhem}{radio}{$_} eq "FHEM") { $fhemRadioStation = $_; last; } } if ( not defined $fhemRadioStation && $hash->{fhem}{radioCount} ) { $fhemRadioStation = $hash->{fhem}{radioCount}-1; } } # Create tts link to play as internet radio if ( $field{say} ) { if ($fhemRadioStation) { $ringTone = 33; chop $field{say}; # http://translate.google.com/translate_tts?ie=UTF-8&tl=[SPRACHE]&q=[TEXT]; $ttsLink = $ttsLinkTemplate; my $ttsText = substr $field{say},0,100; my $ttsLang = "de"; if ($ttsText =~ /^\((en|es|fr|nl)\)/i ) { $ttsLang = $1; $ttsText =~ s/^\($1\)\s*//i; } $ttsLink =~ s/\[SPRACHE\]/$ttsLang/; $ttsText = uri_escape($ttsText); $ttsLink =~ s/\[TEXT\]/$ttsText/; FRITZBOX_Log $hash, 5, "Created Text2Speech internet link: $ttsLink"; } else { FRITZBOX_Log $hash, 2, "Cannot do Text2Speech because box has no internet radio"; } } if ($field{play}) { unless ($fhemRadioStation) { FRITZBOX_Log $hash, 2, "Cannot play mp3 because box has no internet radio"; } elsif ($ttsLink) { FRITZBOX_Log $hash, 3, "Ignore 'play:' because Text2Speech already defined."; } else { $ringTone = 33; chop $field{play}; $ttsLink = $field{play}; FRITZBOX_Log $hash, 5, "Extracted MP3 ring tone: $ttsLink"; } } $result = FRITZBOX_Telnet_OpenCon( $hash ); return "$name|0|$result" if $result; #Preparing 1st command array @cmdArray = (); # Creation fhemRadioStation for ttsLink if (int (@FritzFons) == 0 && $ttsLink) { FRITZBOX_Log $hash, 3, "No Fritz!Fon identified, parameter 'say:' will be ignored." } elsif (int (@FritzFons) && $ttsLink && $hash->{fhem}{radio}{$fhemRadioStation} ne "FHEM") { FRITZBOX_Log $hash, 3, "Create new internet radio station $fhemRadioStation: 'FHEM' for ringing with text-to-speech"; push @cmdArray, "ctlmgr_ctl w configd settings/WEBRADIO".$fhemRadioStation."/Name FHEM"; push @cmdArray, "ctlmgr_ctl w configd settings/WEBRADIO".$fhemRadioStation."/Bitmap 1023"; #Execute command array FRITZBOX_Exec( $hash, \@cmdArray ) } #Preparing 2nd command array # Change ring tone of Fritz!Fons if ($ringTone) { FRITZBOX_Log $hash, 3, "No Fritz!Fon identified, ring tone will be ignored." unless @FritzFons; foreach (@FritzFons) { push @cmdArray, "ctlmgr_ctl r telcfg settings/Foncontrol/User$_/IntRingTone"; push @cmdArray, "ctlmgr_ctl w telcfg settings/Foncontrol/User$_/IntRingTone $ringTone"; FRITZBOX_Log $hash, 4, "Change temporarily internal ring tone of Fritz!Fon DECT $_ to $ringTone"; if ($ttsLink) { push @cmdArray, "ctlmgr_ctl r telcfg settings/Foncontrol/User$_/RadioRingID"; push @cmdArray, "ctlmgr_ctl w telcfg settings/Foncontrol/User$_/RadioRingID ".$fhemRadioStation; FRITZBOX_Log $hash, 4, "Change temporarily radio station of Fritz!Fon DECT $_ to $fhemRadioStation (FHEM)"; } } } # uses name of port 0-3 (dial port 1-4) to show messages on ringing phone my $ringWithIntern = AttrVal( $name, "ringWithIntern", 0 ); if ( $ringWithIntern =~ /^([1-3])$/ ) { push @cmdArray, "ctlmgr_ctl r telcfg settings/MSN/Port".($ringWithIntern-1)."/Name"; push @cmdArray, "ctlmgr_ctl w telcfg settings/MSN/Port".($ringWithIntern-1)."/Name '$msg'"; FRITZBOX_Log $hash, 4, "Change temporarily name of calling number $ringWithIntern to '$msg'"; push @cmdArray, "ctlmgr_ctl w telcfg settings/DialPort $ringWithIntern" } elsif ($field{show}) { FRITZBOX_Log $hash, 3, "Parameter 'show:' ignored because attribute 'ringWithIntern' not defined." } # Set tts-Message push @cmdArray, 'ctlmgr_ctl w configd settings/WEBRADIO'.$fhemRadioStation.'/URL "'.$ttsLink.'"' if $ttsLink; #Execute command array $result = FRITZBOX_Exec( $hash, \@cmdArray ) if int( @cmdArray ) > 0; $intNo =~ s/,/#/g; #Preparing 3rd command array to ring and reset everything FRITZBOX_Log $hash, 4, "Ringing $intNo for $duration seconds"; push @cmdArray, "ctlmgr_ctl w telcfg command/Dial **".$intNo."#"; push @cmdArray, "sleep ".($duration+1); # 1s added because it takes sometime until it starts ringing push @cmdArray, "ctlmgr_ctl w telcfg command/Hangup **".$intNo; push @cmdArray, "ctlmgr_ctl w telcfg settings/DialPort 50" if $ringWithIntern != 0 ; # Reset internal ring tones for the Fritz!Fons if ($ringTone) { for (0 .. $#FritzFons) { push @cmdArray, "ctlmgr_ctl w telcfg settings/Foncontrol/User".$FritzFons[$_]."/IntRingTone ".$result->[2*$_]; # Reset internet station for the Fritz!Fons if ($ttsLink) { push @cmdArray, "ctlmgr_ctl w telcfg settings/Foncontrol/User".$FritzFons[$_]."/RadioRingID ".$result->[2*(int(@FritzFons)+$_)]; } } } # Reset name of calling number if ($ringWithIntern =~ /^([1-2])$/) { if ($ttsLink) { push @cmdArray, "ctlmgr_ctl w telcfg settings/MSN/Port".($ringWithIntern-1)."/Name '".$result->[4*int(@FritzFons)]."'"; push @cmdArray, "ctlmgr_ctl w telcfg command/Dial **".$intNo; push @cmdArray, "ctlmgr_ctl w telcfg command/Hangup **".$intNo; } elsif ($ringTone) { push @cmdArray, "ctlmgr_ctl w telcfg settings/MSN/Port".($ringWithIntern-1)."/Name '".$result->[2*int(@FritzFons)]."'"; } else { push @cmdArray, "ctlmgr_ctl w telcfg settings/MSN/Port".($ringWithIntern-1)."/Name '".$result->[0]."'"; } } # Execute command array FRITZBOX_Exec( $hash, \@cmdArray ); FRITZBOX_Telnet_CloseCon( $hash ); return $name."|1|Ringing done"; } # End FRITZBOX_Ring_Run_Telnet ####################################################################### sub FRITZBOX_Ring_Run_Web($) { my ($string) = @_; my ($name, @val) = split "\\|", $string; my $hash = $defs{$name}; return "$name|0|Error: At least one parameter must be defined." unless int @val; my $result; my $curCallerName; my @webCmdArray; my @tr064CmdArray; my @roReadings; my $duration = 5; my $intNo = $val[0]; my @FritzFons; my $ringTone; my %field; my $lastField; my $ttsLink; my $fhemRadioStation; my $startValue; my $startTime = time(); # Check if 1st parameter are comma separated numbers return $name."|0|Error: Parameter '$intNo' not a number (only commas (,) are allowed to separate numbers)" unless $intNo =~ /^[\d,]+$/; $intNo =~ s/#$//; # Create a hash for the DECT devices whose ring tone (or radio station) can be changed foreach ( split( /,/, $intNo ) ) { if ("AVM" eq $hash->{fhem}{$_}{brand}) { my $userId = $hash->{fhem}{$_}{userId}; FRITZBOX_Log $hash, 5, "Internal number $_ (dect$userId) seems to be a Fritz!Fon."; push @FritzFons, $hash->{fhem}{$_}{userId}; } } # Check if 2nd parameter is the duration shift @val; if (int @val) { if ($val[0] =~ /^\d+$/ && int $val[0] > 0) { $duration = $val[0]; FRITZBOX_Log $hash, 5, "Extracted ring duration of $duration s."; shift @val; } } # Check if next parameter is a valid ring tone if (int @val) { if ($val[0] !~ /^(msg|show|say|play):/i) { $ringTone = $val[0]; $ringTone = $ringToneNumber{lc $val[0]}; return $name."|0|Error: Ring tone '".$val[0]."' not valid" unless defined $ringTone; FRITZBOX_Log $hash, 5, "Ring tone $ringTone will be used."; shift @val; } } # Extract text to say, play or show foreach (@val) { if ($_ =~ /^(show|msg|say|play):/i) { $lastField = $1; $_ =~ s/^$1://; } $field{$lastField} .= $_." " if $lastField; } my $msg = AttrVal( $name, "defaultCallerName", "FHEM" ); if ( $field{show} ) { chop $field{show}; $msg = $field{show}; } elsif ( $field{msg} ) { chop $field{msg}; $msg = $field{msg}; } $msg = substr($msg, 0, 30); # Determine number of Internet Radio to play mp3 or say tts if ( $field{say} || $field{play} ) { foreach (keys %{$hash->{fhem}{radio}}) { if ($hash->{fhem}{radio}{$_} eq "FHEM") { $fhemRadioStation = $_; last; } } if ( not defined $fhemRadioStation && $hash->{fhem}{radioCount} ) { $fhemRadioStation = $hash->{fhem}{radioCount}-1; } } # Create tts link to play as internet radio if ( $field{say} ) { if ($fhemRadioStation) { $ringTone = 33; chop $field{say}; # http://translate.google.com/translate_tts?ie=UTF-8&tl=[SPRACHE]&q=[TEXT]; $ttsLink = $ttsLinkTemplate; my $ttsText = substr $field{say},0,100; my $ttsLang = "de"; if ($ttsText =~ /^\((en|es|fr|nl)\)/i ) { $ttsLang = $1; $ttsText =~ s/^\($1\)\s*//i; } $ttsLink =~ s/\[SPRACHE\]/$ttsLang/; $ttsText = uri_escape($ttsText); $ttsLink =~ s/\[TEXT\]/$ttsText/; FRITZBOX_Log $hash, 5, "Created Text2Speech internet link: $ttsLink"; } else { FRITZBOX_Log $hash, 2, "Cannot do Text2Speech because box has no internet radio"; } } # Extract play link if ( $field{play} ) { unless ($fhemRadioStation) { FRITZBOX_Log $hash, 2, "Cannot play mp3 because box has no internet radio"; } elsif ($ttsLink) { FRITZBOX_Log $hash, 3, "Ignore 'play:' because Text2Speech already defined."; } else { $ringTone = 33; chop $field{play}; $ttsLink = $field{play}; FRITZBOX_Log $hash, 5, "Extracted MP3 ring tone: $ttsLink"; } } # Store current values for fon and dect port my $queryStr = "&dectUser=telcfg:settings/Foncontrol/User/list(Id,Intern,IntRingTone,RadioRingID)"; # DECT Numbers $queryStr .= "&fonPort=telcfg:settings/MSN/Port/list(Name,MSN)"; # Fon ports FRITZBOX_Log $hash, 4, "Read current dect and fon port values from box"; $startValue = FRITZBOX_Web_Query( $hash, $queryStr, 'UTF-8') ; #Preparing 1st command array @webCmdArray = (); # Creation fhemRadioStation for ttsLink if (int (@FritzFons) == 0 && $ttsLink) { FRITZBOX_Log $hash, 3, "No Fritz!Fon identified, parameter 'say:' will be ignored." } elsif (int (@FritzFons) && $ttsLink && $hash->{fhem}{radio}{$fhemRadioStation} ne "FHEM") { FRITZBOX_Log $hash, 3, "Create new internet radio station $fhemRadioStation: 'FHEM' for ringing with text-to-speech"; push @webCmdArray, "configd:settings/WEBRADIO".$fhemRadioStation."/Name" => "FHEM"; push @webCmdArray, "ctlmgr_ctl w configd:settings/WEBRADIO".$fhemRadioStation."/Bitmap" => "1023"; #Execute command array FRITZBOX_Web_PostCmd( $hash, \@webCmdArray ) } #Preparing 2nd command array to set ring parameters # Change ring tone of Fritz!Fons if ($ringTone) { FRITZBOX_Log $hash, 3, "No Fritz!Fon identified, ring tone will be ignored." unless @FritzFons; foreach (@FritzFons) { push @webCmdArray, "telcfg:settings/Foncontrol/User".$_."/IntRingTone" => $ringTone; FRITZBOX_Log $hash, 4, "Change temporarily internal ring tone of dect".$_." to $ringTone"; if ($ttsLink) { push @webCmdArray, "telcfg:settings/Foncontrol/User".$_."/RadioRingID" => $fhemRadioStation; FRITZBOX_Log $hash, 4, "Change temporarily radio station of dect".$_." to $fhemRadioStation (FHEM)"; } } } # uses name of port 0-3 (dial port 1-4) to show messages on ringing phone my $ringWithIntern = AttrVal( $name, "ringWithIntern", 0 ); if ( $ringWithIntern =~ /^([1-3])$/ ) { if ($startValue->{fonPort}->[$ringWithIntern-1]->{Name}) { push @webCmdArray, "telcfg:settings/MSN/Port".($ringWithIntern-1)."/Name" => $msg; FRITZBOX_Log $hash, 4, "Change temporarily name of calling number fon$ringWithIntern to '$msg'"; } else { FRITZBOX_Log $hash, 2, "Error: Current name of calling number fon$ringWithIntern could not be determined -> Did not change the name."; my $temp = Dumper( $startValue ); FRITZBOX_Log $hash, 3, "Debug info: \n".$temp; } push @webCmdArray, "telcfg:settings/DialPort" => $ringWithIntern; } elsif ($field{show}) { FRITZBOX_Log $hash, 3, "Parameter 'show:' ignored because attribute 'ringWithIntern' not defined." } # Set tts-Message push @webCmdArray, 'configd:settings/WEBRADIO'.$fhemRadioStation.'/URL' => $ttsLink if $ttsLink; #Execute command array $result = FRITZBOX_Web_PostCmd( $hash, \@webCmdArray ) if int( @webCmdArray ) > 0; $intNo =~ s/,/#/g; #Preparing 3rd command array to ring FRITZBOX_Log $hash, 4, "Ringing $intNo for $duration seconds"; if ($hash->{SECPORT}) { push @tr064CmdArray, ["X_VoIP:1", "x_voip", "X_AVM-DE_DialNumber", "NewX_AVM-DE_PhoneNumber", "**".$intNo."#"]; $result = FRITZBOX_TR064_Cmd( $hash, 0, \@tr064CmdArray ); } else { push @webCmdArray, "telcfg:command/Dial" => "**".$intNo."#"; $result = FRITZBOX_Web_PostCmd( $hash, \@webCmdArray ); } sleep $duration; #+1; # 1s added because it takes sometime until it starts ringing #Preparing 4th command array to stop ringing push @tr064CmdArray, ["X_VoIP:1", "x_voip", "X_AVM-DE_DialHangup"]; $result = FRITZBOX_TR064_Cmd( $hash, 0, \@tr064CmdArray ) if $hash->{SECPORT}; push( @webCmdArray, "telcfg:command/Hangup" => "" ) unless $hash->{SECPORT}; #Preparing 5th command array to reset everything push @webCmdArray, "telcfg:settings/DialPort" => 50 if $ringWithIntern != 0 ; # Reset internal ring tones for the Fritz!Fons if ($ringTone) { foreach (@FritzFons) { my $value = $startValue->{dectUser}->[$_]->{IntRingTone}; push @webCmdArray, "telcfg:settings/Foncontrol/User".$_."/IntRingTone" => $value; FRITZBOX_Log $hash, 4, "Reset ring tone of dect$_ to $value"; # Reset internet station for the Fritz!Fons if ($ttsLink) { $value = $startValue->{dectUser}->[$_]->{RadioRingID}; push @webCmdArray, "telcfg:settings/Foncontrol/User".$_."/RadioRingID" => $value; FRITZBOX_Log $hash, 4, "Reset radio station of dect$_ to $value"; } } } # Reset name of calling number if ($ringWithIntern =~ /^([1-2])$/) { my $fonName = $startValue->{fonPort}->[$ringWithIntern-1]->{Name}; if ($fonName) {# darf nie leer sein push( @webCmdArray, "telcfg:settings/MSN/Port".($ringWithIntern-1)."/Name" => $fonName ) ; FRITZBOX_Log $hash, 4, "Reset name of calling number fon$ringWithIntern to '$fonName'"; } } # Switch of Internet Radio stations if (!$ttsLink && defined $ringTone && $ringTone ==33 ) { push @webCmdArray, "telcfg:command/Dial **".$intNo; push @webCmdArray, "telcfg:command/Hangup **".$intNo; } #set Fritzbox ring 612 show:test test say:test test # Execute command array $result = FRITZBOX_Web_PostCmd( $hash, \@webCmdArray ); if ($result->[0] == 1) { FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->sid", $result->[1]; FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "fhem->sidTime", time(); FRITZBOX_Readout_Add_Reading $hash, \@roReadings, "readoutTime", sprintf( "%.2f", time()-$startTime); } my $returnStr = join('|', @roReadings ); FRITZBOX_Log $hash, 5, "Handover: ".$returnStr; return $name."|2|".encode_base64($returnStr,""); # return $name."|1|Ringing done"; } # End FRITZBOX_Ring_Run_Web ####################################################################### sub FRITZBOX_SetMOH($@) { my ($hash, $type, @file) = @_; my $returnStr; my @cmdArray; my $result; my $name = $hash->{NAME}; my $uploadFile = '/var/tmp/fhem_moh_upload'; my $mohFile = '/var/tmp/fhem_fx_moh'; return "Error: Fritz!Box has no music on hold" unless defined $hash->{READINGS}{box_moh}; if (lc $type eq lc $mohtype[0] || $type eq "0") { FRITZBOX_Exec ($hash, 'ctlmgr_ctl w telcfg settings/MOHType 0'); return 0; } elsif (lc $type eq lc $mohtype[1] || $type eq "1") { FRITZBOX_Exec ($hash, 'ctlmgr_ctl w telcfg settings/MOHType 1'); return 1; } return "Error: Unvalid parameter '$type'" unless lc $type eq lc $mohtype[2] || $type eq "2"; # Load customer MOH file my $inFile = join " ", @file; my $uploadDir = AttrVal( $name, "defaultUploadDir", "" ); $uploadDir .= "/" unless $uploadDir =~ /\/$|^$/; if ($inFile !~ /^say:/i) { $inFile = $uploadDir.$inFile unless $inFile =~ /^\//; return "Error: Please give a complete file path or define the attribute 'defaultUploadDir'" unless $inFile =~ /^\//; return "Error: Only MP3 files can be used for 'music on hold'." unless $inFile =~ /\.mp3$/i; } $result = FRITZBOX_Telnet_OpenCon( $hash ); return "$name|0|$result" if $result; push @cmdArray, '[ -f "'.$uploadFile.'" ] && rm "'.$uploadFile.'"'; push @cmdArray, '[ -f "'.$mohFile.'" ] && rm "'.$mohFile.'"'; if ($inFile =~ /^say:/i) { FRITZBOX_Log $hash, 4, "Converting Text2Speech"; # 'wget -U Mozilla -O "[ZIEL]" "http://translate.google.com/translate_tts?ie=UTF-8&tl=[SPRACHE]&q=[TEXT]"'; my $ttsCmd = $ttsCmdTemplate; $ttsCmd =~ s/\[ZIEL\]/$uploadFile/; my $ttsText = $inFile; $ttsText =~ s/^say:\s*//i; my $ttsLang = "de"; if ($ttsText =~ /^\((en|es|fr|nl)\)/i ) { $ttsLang = $1; $ttsText =~ s/^\($1\)\s*//i; } $ttsCmd =~ s/\[SPRACHE\]/$ttsLang/; # $ttsText = ($ttsText." ") x int(60/length($ttsText)) # if length($ttsText) < 30; $ttsText = substr($ttsText,0,70); $ttsText = uri_escape($ttsText); $ttsCmd =~ s/\[TEXT\]/$ttsText/; push @cmdArray, $ttsCmd; } elsif ($inFile =~ /^(ftp|http):\/\//) { push @cmdArray, 'wget -U Mozilla -O "'.$uploadFile.'" "'.$inFile.'"'; } else { push @cmdArray, 'cp "'.$inFile.'" "'.$uploadFile.'"'; } push @cmdArray, '[ -f "'.$uploadFile.'" ] && echo 1 || echo 0'; # Execute command array $result = FRITZBOX_Exec ( $hash, \@cmdArray ); return "Could not access '$inFile'" unless $result->[3] eq "1"; #Prepare 2nd command array push @cmdArray, 'if [ ! -f "/var/tmp/ffmpeg_mp3.tables" ]; then playerd_tables; fi'; push @cmdArray, 'ffmpegconv -i "'.$uploadFile.'" -o "'.$mohFile.'" --limit 32 --type 6'; push @cmdArray, '[ -f "'.$mohFile.'" ] && echo 1 || echo 0'; # Execute 2nd command array $result = FRITZBOX_Exec ( $hash, \@cmdArray ); return "Could not convert '$inFile'" unless $result->[2] eq "1"; #Prepare 3rd command array push @cmdArray, 'cat "'.$mohFile.'" >/var/flash/fx_moh'; push @cmdArray, 'killall -sigusr1 telefon'; push @cmdArray, 'rm "'.$uploadFile.'"'; push @cmdArray, 'rm "'.$mohFile.'"'; # Execute 3rd command array $result = FRITZBOX_Exec ( $hash, \@cmdArray ); FRITZBOX_Telnet_CloseCon( $hash ); return 2; } ####################################################################### sub FRITZBOX_SetCustomerRingTone($@) { my ($hash, $intern, @file) = @_; my @cmdArray; my $result; my $name = $hash->{NAME}; my $uploadDir = AttrVal( $name, "defaultUploadDir", "" ); $uploadDir .= "/" unless $uploadDir =~ /\/$|^$/; my $inFile = join " ", @file; $inFile = $uploadDir.$inFile unless $inFile =~ /^\//; return "Error: Please give a complete file path or the attribute 'defaultUploadDir'" unless $inFile =~ /^\//; return "Error: Only MP3 or G722 files can be uploaded to the phone." unless $inFile =~ /\.mp3$|.g722$/i; my $uploadFile = '/var/InternerSpeicher/FRITZ/fonring/'.int(time()).'.g722'; push @cmdArray, 'if [ ! -d /var/InternerSpeicher/FRITZ/fonring ]; then mkdir -p "/var/InternerSpeicher/FRITZ/fonring"; fi'; push @cmdArray, '[ -x /etc/init.d/rc.preaudio.sh ] && /etc/init.d/rc.preaudio.sh start'; $inFile =~ s/file:\/\///i; # mp3 files are converted if ( $inFile =~ /\.mp3$/i ) { push @cmdArray, 'picconv.sh "file://'.$inFile.'" "'.$uploadFile.'" ringtonemp3'; # G722 files are copied } elsif ( $inFile =~ /\.g722$/i ) { push @cmdArray, "cp '$inFile' '$uploadFile'"; # all other formats fail } else { return "Error: only MP3 or G722 files can be uploaded to the phone"; } # trigger the loading of the file to the phone, file will be deleted by the box as soon as the upload has finished push @cmdArray, '/usr/bin/pbd --set-ringtone-url --book="255" --id="'.$intern.'" --url="file://'.$uploadFile.'" --name="FHEM'.int(time()).'"'; $result = FRITZBOX_Telnet_OpenCon( $hash ); return $result if $result; FRITZBOX_Exec ($hash, \@cmdArray); FRITZBOX_Telnet_CloseCon( $hash ); return "Upload of ring tone will take about 1 minute. Do not work with the phone until its done."; } ####################################################################### sub FRITZBOX_ConvertMOH ($@) { my ($hash, @file) = @_; my $name = $hash->{NAME}; my $uploadDir = AttrVal( $name, "defaultUploadDir", "" ); $uploadDir .= "/" unless $uploadDir =~ /\/$|^$/; my $inFile = join " ", @file; $inFile = $uploadDir.$inFile unless $inFile =~ /^\//; return "Error: You have to give a complete file path or to set the attribute 'defaultUploadDir'" unless $inFile =~ /^\//; return "Error: only MP3 or WAV files can be converted" unless $inFile =~ /\.mp3$|.wav$/i; $inFile =~ s/file:\/\///; my $outFile = $inFile; $outFile = substr($inFile,0,-4) if ($inFile =~ /\.(mp3|wav)$/i); my $returnStr = FRITZBOX_Exec ($hash , 'ffmpegconv -i "'.$inFile.'" -o "'.$outFile.'.moh" --limit 32 --type 6'); return $returnStr; } # end FRITZBOX_ConvertMOH ####################################################################### sub FRITZBOX_ConvertRingTone ($@) { my ($hash, @file) = @_; my $name = $hash->{NAME}; my $uploadDir = AttrVal( $name, "defaultUploadDir", "" ); $uploadDir .= "/" unless $uploadDir =~ /\/$|^$/; my $inFile = join " ", @file; $inFile = $uploadDir.$inFile unless $inFile =~ /^\//; return "Error: You have to give a complete file path or to set the attribute 'defaultUploadDir'" unless $inFile =~ /^\//; return "Error: only MP3 or WAV files can be converted" unless $inFile =~ /\.mp3$|.wav$/i; $inFile =~ s/file:\/\///; my $outFile = $inFile; $outFile = substr($inFile,0,-4) if ($inFile =~ /\.(mp3|wav)$/i); my $returnStr = FRITZBOX_Exec ($hash , 'picconv.sh "file://'.$inFile.'" "'.$outFile.'.g722" ringtonemp3'); return $returnStr; } # end FRITZBOX_ConvertRingTone ####################################################################### sub FRITZBOX_SendMail($@) { my ($hash,@val) = @_; my $lastField; my %field; my @cmdArray; foreach (@val) { if ($_ =~ /^(to|subject|body):/i) { $lastField = $1; $_ =~ s/^$1://; } $field{$lastField} .= $_." " if $lastField; } my $cmd = "/sbin/mailer send"; if ($field{body}) { chop $field{body}; $field{body} =~ s/"/\\"/g; # change none ASCII chars in octal code for ISO-8859-1 (acc. http://www.pjb.com.au/comp/diacritics.html) $field{body} =~ s/Ä|Ä/\\304/g; $field{body} =~ s/Ö|Ö/\\326/g; $field{body} =~ s/Ü|Ü/\\334/g; $field{body} =~ s/ß|ß/\\337/g; $field{body} =~ s/ä|ä/\\344/g; $field{body} =~ s/ö|ö/\\366/g; $field{body} =~ s/ü|ü/\\374/g; push @cmdArray, '/bin/echo -e "'.$field{body}.'" >/var/tmp/fhem_nachricht.txt'; $cmd .= " -i '/var/tmp/fhem_nachricht.txt'"; } chop $field{subject} if $field{subject}; $field{subject} = "Message from FHEM " unless $field{subject}; $cmd .= " -s \"".$field{subject}."\""; if ($field{to}) { chop $field{to}; $cmd .= " -t \"".$field{to}."\"" } push @cmdArray, $cmd; push @cmdArray, "rm /var/tmp/fhem_nachricht.txt" if $field{body}; FRITZBOX_Exec( $hash, \@cmdArray ); return undef; } ####################################################################### sub FRITZBOX_StartRadio($@) { my ($hash, @val) = @_; my @cmdArray; my $name = $hash->{NAME}; my $intNo = $val[0]; my $radioStation; my $radioStationName; my $result; # Check if 1st parameter is a number return "Error: 1st Parameter '$intNo' not an internal DECT number" unless $intNo =~ /^61[012345]$/; # Check if the 1st parameter is a Fritz!Fon return "Error: Internal number $intNo does not seem to be a Fritz!Fon." unless $hash->{fhem}{$intNo}{brand} eq "AVM"; # Check if remaining parameter is an internet Radio Station shift (@val); if (@val) { $radioStationName = join (" ", @val); if ($radioStationName =~ /^\d+$/) { $radioStation = $radioStationName; $radioStationName = $hash->{fhem}{radio}{$radioStation}; return "Error: Unknown internet radio number $radioStation." unless defined $radioStationName; } else { foreach (keys %{$hash->{fhem}{radio}}) { if (lc $hash->{fhem}{radio}{$_} eq lc $radioStationName) { $radioStation = $_; last; } } return "Error: Unknown internet radio station '$radioStationName'" unless defined $radioStation; } } $result = FRITZBOX_Telnet_OpenCon( $hash ); return $result if $result; # Get current ringtone my $userNo = $intNo-609; push @cmdArray, "ctlmgr_ctl r telcfg settings/Foncontrol/User".$userNo."/IntRingTone"; push @cmdArray, "ctlmgr_ctl r telcfg settings/Foncontrol/User".$userNo."/RadioRingID"; $result = FRITZBOX_Exec( $hash, \@cmdArray ); my $curRingTone = $result->[0]; my $curRadioStation = $result->[1]; # Start Internet Radio and reset ring tone push @cmdArray, "ctlmgr_ctl w telcfg settings/Foncontrol/User".$userNo."/IntRingTone 33"; push @cmdArray, "ctlmgr_ctl w telcfg settings/Foncontrol/User".$userNo."/RadioRingID $radioStation" if defined $radioStation; push @cmdArray, "ctlmgr_ctl w telcfg command/Dial **".$intNo; push @cmdArray, "ctlmgr_ctl w telcfg settings/Foncontrol/User".$userNo."/IntRingTone $curRingTone"; push @cmdArray, "ctlmgr_ctl w telcfg settings/Foncontrol/User".$userNo."/RadioRingID $curRadioStation" if defined $radioStation; # Execute command array FRITZBOX_Exec( $hash, \@cmdArray ); FRITZBOX_Telnet_CloseCon( $hash ); return undef; } #'picconv.sh "'.$inFile.'" "'.$outFile.'.g722" ringtonemp3' #picconv.sh "file://$dir/upload.mp3" "$dir/$filename" ringtonemp3 #"ffmpegconv -i '$inFile' -o '$outFile.g722' --limit 240"); #ffmpegconv -i "${in}" -o "${out}" --limit 240 #pbd --set-image-url --book=255 --id=612 --url=/var/InternerSpeicher/FRITZ/fonring/1416431162.g722 --type=1 #pbd --set-image-url --book=255 --id=612 --url=file://var/InternerSpeicher/FRITZBOXtest.g722 --type=1 #ctlmgr_ctl r user settings/user0/bpjm_filter_enable #/usr/bin/pbd --set-ringtone-url --book="255" --id="612" --url="file:///var/InternerSpeicher/claydermann.g722" --name="Claydermann" # /usr/bin/moh_upload # Executed the command on the FritzBox Shell ############################################ sub FRITZBOX_Exec($$) { my ($hash, $cmd) = @_; my $openedTelnet = 0; if ($hash->{REMOTE} == 1) { unless (defined $telnet) { return undef if (FRITZBOX_Telnet_OpenCon($hash)); $openedTelnet = 1; } my $retVal = FRITZBOX_Exec_Remote($hash, $cmd); FRITZBOX_Telnet_CloseCon ( $hash ) if $openedTelnet; return $retVal; } else { return FRITZBOX_Exec_Local($hash, $cmd); } } # Executed the command via Telnet ############################################ sub FRITZBOX_Exec_Remote($$) { my ($hash, $cmd) = @_; my @output; my $result; if (ref \$cmd eq "SCALAR") { FRITZBOX_Log $hash, 4, "Execute '".$cmd."'"; @output=$telnet->cmd($cmd); $result = $output[0]; chomp $result; my $log = join " ", @output; chomp $log; FRITZBOX_Log $hash, 4, "Result '$log'"; return $result; } elsif (ref \$cmd eq "REF") { my @resultArray = (); if ( int (@{$cmd}) > 0 ) { FRITZBOX_Log $hash, 4, "Execute " . int ( @{$cmd} ) . " command(s)"; foreach (@{$cmd}) { FRITZBOX_Log $hash, 5, "Execute '$_'"; unless ($_ =~ /^sleep/) { @output=$telnet->cmd($_); $result = $output[0] || ""; chomp $result; my $log = join "", @output; chomp $log; FRITZBOX_Log $hash, 5, "Result '$log'"; } else { FRITZBOX_Log $hash, 4, "Do '$_' in perl."; eval ($_); $result = ""; } push @resultArray, $result; } @{$cmd} = (); FRITZBOX_Log $hash, 4, "Received ".int(@resultArray)." answer(s)"; } else { FRITZBOX_Log $hash, 4, "No shell command to execute."; } return \@resultArray; } else { FRITZBOX_Log $hash, 1, "Error: wrong perl parameter"; return undef; } } # Executed the command on the fhem server (on the FritzBox Shell) ############################################ sub FRITZBOX_Exec_Local($$) { my ($hash, $cmd) = @_; if (ref \$cmd eq "SCALAR") { FRITZBOX_Log $hash, 5, "Execute '".$cmd."'"; my $result = qx($cmd); chomp $result; FRITZBOX_Log $hash, 5, "Result '$result'"; return $result; } elsif (ref \$cmd eq "REF") { if ( int (@{$cmd}) > 0 ) { FRITZBOX_Log $hash, 4, "Execute " . int ( @{$cmd} ) . " command(s)"; FRITZBOX_Log $hash, 5, "Commands: '" . join( " | ", @{$cmd} ) . "'"; my $cmdStr = join "\necho ' |#|'\n", @{$cmd}; $cmdStr .= "\necho ' |#|'"; my $result = qx($cmdStr); unless (defined $result) { FRITZBOX_Log $hash, 1, "Error: No STDOUT from shell command."; return undef; } $result =~ s/\n|\r//g; my @resultArray = split /\|#\|/, $result; for (0 .. $#resultArray) { $resultArray[$_] =~ s/\s$//; } @{$cmd} = (); FRITZBOX_Log $hash, 4, "Received ".int(@resultArray)." answer(s)"; FRITZBOX_Log $hash, 5, "Result: '" . join (" | ", @resultArray)."'"; return \@resultArray; } else { FRITZBOX_Log $hash, 4, "No shell command to execute."; } } else { FRITZBOX_Log $hash, 1, "Error: wrong perl parameter"; } } # Opens a Telnet Connection to an external FritzBox ############################################ sub FRITZBOX_Telnet_OpenCon($) { my ($hash) = @_; my $name = $hash->{NAME}; return undef unless $hash->{REMOTE} == 1; return "Error: Perl modul ".$missingModulTelnet."is missing on this system. Please install before using this modul." if $missingModulTelnet; my $host = AttrVal( $name, "fritzBoxIP", "fritz.box" ); my $pwd = FRITZBOX_readPassword($hash); my $msg; my $before; my $match; unless (defined $pwd) { $msg = "Error: No password set. Please define it with 'set $name password YourPassword'"; FRITZBOX_Log $hash, 2, $msg; # return $msg; my $pwdFile = AttrVal( $name, "pwdFile", "fb_pwd.txt"); FRITZBOX_Log $hash, 5, "Open password file '$pwdFile' to extract password"; if (open(IN, "<" . $pwdFile)) { $pwd = ; close(IN); FRITZBOX_Log $hash, 5, "Close password file"; } else { FRITZBOX_Log $hash, 2, $msg; return $msg; } } my $user = AttrVal( $name, "telnetUser", "" ); FRITZBOX_Log $hash, 4, "Open Telnet connection to $host"; my $timeout = AttrVal( $name, "telnetTimeOut", "10"); $telnet = new Net::Telnet ( Host=>$host, Port => 23, Timeout=>$timeout, Errmode=>'return', Prompt=>'/# $/'); if (!$telnet) { $msg = "Could not open telnet connection to $host: $!"; FRITZBOX_Log $hash, 2, $msg; $telnet = undef; return $msg; } FRITZBOX_Log $hash, 5, "Wait for user or password prompt."; unless ( ($before,$match) = $telnet->waitfor('/(user|login|password): $/i') ) { $msg = "Telnet error while waiting for user or password prompt: ".$telnet->errmsg; FRITZBOX_Log $hash, 2, $msg; $telnet->close; $telnet = undef; return $msg; } if ( $match =~ /(user|login): / && $user eq "") { $msg = "Telnet login requires user name but attribute 'telnetUser' not defined"; FRITZBOX_Log $hash, 2, $msg; $telnet->close; $telnet = undef; return $msg; } elsif ( $match =~ /(user|login): /) { FRITZBOX_Log $hash, 5, "Entering user name"; $telnet->print( $user ); FRITZBOX_Log $hash, 5, "Wait for password prompt"; unless ($telnet->waitfor( '/password: $/i' )) { $msg = "Telnet error while waiting for password prompt: ".$telnet->errmsg; FRITZBOX_Log $hash, 2, $msg; $telnet->close; $telnet = undef; return $msg; } } elsif ( $match eq "password: " && $user ne "") { FRITZBOX_Log $hash, 3, "Attribute 'telnetUser' defined but telnet login did not prompt for user name."; } FRITZBOX_Log $hash, 5, "Entering password"; $telnet->print( $pwd ); FRITZBOX_Log $hash, 5, "Wait for command prompt"; unless ( ($before,$match) = $telnet->waitfor( '/# $|Login failed./i' )) { $msg = "Telnet error while waiting for command prompt: ".$telnet->errmsg; FRITZBOX_Log $hash, 2, $msg; $telnet->close; $telnet = undef; return $msg; } elsif ( $match eq "Login failed.") { $msg = "Telnet error: Login failed. Wrong password."; FRITZBOX_Log $hash, 2, $msg; $telnet->close; $telnet = undef; return $msg; } # redirect console messages $telnet->cmd("setconsole -r"); FRITZBOX_Log $hash, 5, "Change command prompt"; $telnet->prompt('/ $/'); unless ($telnet->cmd("PS1=' '")) { $msg = "Telnet error: Could not change command prompt - ".$telnet->errmsg; FRITZBOX_Log $hash, 2, $msg; $telnet->close; $telnet = undef; return $msg; } return undef; } # end FRITZBOX_Telnet_OpenCon # Closes a Telnet Connection to an external FritzBox ############################################ sub FRITZBOX_Telnet_CloseCon($) { my ($hash) = @_; return undef unless $hash->{REMOTE} == 1; if (defined $telnet) { FRITZBOX_Log $hash, 4, "Close Telnet connection"; $telnet->close; $telnet = undef; } else { FRITZBOX_Log $hash, 1, "Cannot close an undefined Telnet connection"; } } # end FRITZBOX_Telnet_CloseCon ################################################# sub FRITZBOX_TR064_Cmd($$$) { my ($hash, $xml, $cmdArray) = @_; my $name = $hash->{NAME}; my $port = $hash->{SECPORT}; unless ($port) { FRITZBOX_Log $hash, 4, "TR064 not used. No security port defined."; return undef; } # Set Password for TR064 access $FRITZBOX_TR064pwd = FRITZBOX_readPassword($hash); my $host = AttrVal( $name, "fritzBoxIP", "fritz.box" ); my @retArray; foreach( @{$cmdArray} ) { next unless int @{$_} >=3 && int( @{$_} ) % 2 == 1; my( $service, $control, $action, %params) = @{$_}; my @soapParams; # {my $test="/upnp/control/test2";; $test =~ s#/upnp/control/##;; $test;;} # clean service and control $service =~ s/urn:dslforum-org:service://; $control =~ s#/upnp/control/##; my $logMsg = "service='$service', control='$control', action='$action'"; # Prepare action parameter foreach (keys %params) { $logMsg .= ", parameter".(int(@soapParams)+1)."='$_' => '$params{$_}'" ; push @soapParams, SOAP::Data->name( $_ => $params{$_} ); } FRITZBOX_Log $hash, 4, "Perform TR064 call - ".$logMsg; my $s = SOAP::Lite -> uri("urn:dslforum-org:service:".$service) -> proxy('https://'.$host.":".$port."/upnp/control/".$control, ssl_opts => [ SSL_verify_mode => 0 ] ) -> readable(1) -> call( $action => @soapParams ); if ($s->fault) { # will be defined if Fault element is in the message my $fdetail = Dumper($s->faultdetail); # returns value of 'detail' element as string or object # my $fcode = $s->faultcode; # # my $fstring = $s->faultstring; # also available # my $factor = $s->faultactor; my $ecode = $s->faultdetail->{'UPnPError'}->{'errorCode'}; my $edesc = $s->faultdetail->{'UPnPError'}->{'errorDescription'}; FRITZBOX_Log $hash, 2, "TR064-Error $ecode:$edesc ($logMsg)"; @{$cmdArray} = (); return "Error\n".$fdetail; } push @retArray, $s->body; } @{$cmdArray} = (); return @retArray; } # End of FRITZBOX_TR064_Cmd ################################################# # get Fritzbox tr064servicelist sub FRITZBOX_TR064_Get_ServiceList($) { my ($hash) = @_; my $name = $defs{NAME}; if ( $missingModulWeb ) { my $msg = "Error: Perl modul " . $missingModulWeb . "is missing on this system. Please install before using this modul."; FRITZBOX_Log $hash, 2, $msg; return $msg; } my $host = AttrVal( $name, "fritzBoxIP", "fritz.box" ); my $url = 'http://'.$host.":49000/tr64desc.xml"; my $returnStr = "_" x 100 ."\n\n"; $returnStr .= " List of TR-064 services and actions that are allowed on the device '$host'\n"; FRITZBOX_Log $hash, 5, "Getting service page $url"; my $agent = LWP::UserAgent->new( env_proxy => 1, keep_alive => 1, protocols_allowed => ['http'], timeout => 10); my $response = $agent->get( $url ); return "$url does not exist" if $response->is_error(); my $content = $response->content; my @serviceArray; # Get basic service data while( $content =~ /(.*?)<\/service>/isg ) { my $serviceXML = $1; my @service; my $service = $1 if $serviceXML =~ m/urn:dslforum-org:service:(.*?)<\/servicetype>/is; my $control = $1 if $serviceXML =~ m/\/upnp\/control\/(.*?)<\/controlurl>/is; my $scpd = $1 if $serviceXML =~ m/(.*?)<\/scpdurl>/is; push @serviceArray, [$service, $control, $scpd]; } # Get actions of each service foreach (@serviceArray) { $url = 'http://'.$host.":49000".$_->[2]; FRITZBOX_Log $hash, 5, "Getting action page $url"; my $agent = LWP::UserAgent->new( env_proxy => 1, keep_alive => 1, protocols_allowed => ['http'], timeout => 10); my $response = $agent->get( $url ); return "ServiceSCPD $url does not exist" if $response->is_error(); my $content = $response->content; # get version $content =~ /(.*?)<\/major>/isg; my $version = $1; $content =~ /(.*?)<\/minor>/isg; $version .= ".".$1; $returnStr .= "_" x 100 ."\n\n"; $returnStr .= " Service: ".$_->[0]." Control: ".$_->[1]."\n"; $returnStr .= " Spec: http://".$host.":49000".$_->[2]." Version: ".$version."\n"; $returnStr .= "-" x 100 ."\n"; while( $content =~ /(.*?)<\/action>/isg ) { my $serviceXML = $1; $serviceXML =~ /(.*?)<\/name>/is; my $action = $1; $serviceXML =~ /(.*?)<\/argumentlist>/is; my $argXML = $1; $returnStr .= " $action ("; my @argArray = ($argXML =~ /(.*?)<\/argument>/isg); my @argOut; foreach (@argArray) { $_ =~ /(.*?)<\/name>/is; my $argName = $1; $_ =~ /(.*?)<\/direction>/is; my $argDir = $1; if ($argDir eq "in") { $returnStr .= " $argName"; } else { push @argOut, $argName; } } $returnStr .= " )"; $returnStr .= " = (" if int @argOut; foreach (@argOut) { $returnStr .= " $_"; } $returnStr .= " )" if int @argOut; $returnStr .= "\n"; } } return $returnStr; } # Opens a Web connection to an external Fritzbox ############################################ sub FRITZBOX_Web_OpenCon ($) { my ($hash) = @_; my $name = $hash->{NAME}; return undef unless $hash->{REMOTE} == 1; if ($missingModulWeb) { FRITZBOX_Log $hash, 2, "Error: Perl modul ".$missingModulWeb."is missing on this system. Please install before using this modul."; return undef; } # Use old sid if last access later than 9.5 minutes my $sid = $hash->{fhem}{sid}; return $sid if defined $sid && $hash->{fhem}{sidTime}>time()-9.5*60; my $host = AttrVal( $name, "fritzBoxIP", "fritz.box" ); my $pwd = FRITZBOX_readPassword($hash); unless (defined $pwd) { FRITZBOX_Log $hash, 2, "Error: No password set. Please define it with 'set $name password YourPassword'"; return undef; } my $user = AttrVal( $name, "telnetUser", "" ); FRITZBOX_Log $hash, 4, "Open Web connection to $host"; $sid = (FB_doCheckPW($host, $user, $pwd)); if ($sid) { FRITZBOX_Log $hash, 4, "Web session opened with $sid"; return $sid; } FRITZBOX_Log $hash, 2, "Web connection could not be established. Please check your credentials (password, user)."; return undef; } # Execute commands via the web connection ############################################ sub FRITZBOX_Web_PostCmd($$@) { my ($hash, $webCmdArray, $page) = @_; my $name = $hash->{NAME}; my $sid = FRITZBOX_Web_OpenCon($hash); unless ($sid) { my @retArray = (0, "Didn't get a session ID"); return \@retArray; } # Complete the arguments if ($page) { $page .= "?sid=".$sid; push @{$webCmdArray}, "apply" => ""; } else { $page = '/cgi-bin/webcm'; } push @{$webCmdArray}, "sid" => $sid; my $host = AttrVal( $name, "fritzBoxIP", "fritz.box" ); my $url = 'http://'.$host.$page; FRITZBOX_Log $hash, 5, "Posting ".(@{$webCmdArray} /2) ." parameters to '$url'"; my $agent = LWP::UserAgent->new( env_proxy => 1, keep_alive => 1, protocols_allowed => ['http'], timeout => 10); my $response = $agent->post( $url, $webCmdArray ); @{$webCmdArray} = (); if ($response->is_error) { my @retArray = (0, "Error: ".$response->status_line); return \@retArray; } # FRITZBOX_Log $hash, 3, "Response: ".$response->content; # if ($response->content) # { # my @retArray = (0, "Command not executed"); # return \@retArray; # } my @retArray = (1, $sid); return \@retArray; } # Read box values via the web connection ############################################ sub FRITZBOX_Web_Query($$@) { my ($hash, $queryStr, $charSet) = @_; $charSet = "" unless defined $charSet; my $name = $hash->{NAME}; my $sid = FRITZBOX_Web_OpenCon( $hash ); unless ($sid) { my %retHash = ( "Error" => "Didn't get a session ID" ) ; return \%retHash; } my $host = AttrVal( $name, "fritzBoxIP", "fritz.box" ); my $url = 'http://' . $host . '/query.lua?sid=' . $sid . $queryStr; my $agent = LWP::UserAgent->new( env_proxy => 1, keep_alive => 1, protocols_allowed => ['http'], timeout => 10); my $response = $agent->get ( $url ); FRITZBOX_Log $hash, 5, "Response: ".$response->content; if ($response->is_error) { my %retHash = ("Error" => $response->status_line); return \%retHash; } ################# # FRITZBOX_Log $hash, 3, "Response: ".$response->content; ################# my $jsonResult ; if ($charSet eq "UTF-8") { $jsonResult = JSON::XS->new->utf8->decode ($response->content); } else { $jsonResult = JSON::XS->new->latin1->decode ($response->content); } $jsonResult->{sid} = $sid; return $jsonResult; } ##################################### # checks and stores FritzBox password used for telnet or webinterface connection sub FRITZBOX_storePassword($$) { my ($hash, $password) = @_; my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd"; my $key = getUniqueId().$index; my $enc_pwd = ""; if(eval "use Digest::MD5;1") { $key = Digest::MD5::md5_hex(unpack "H*", $key); $key .= Digest::MD5::md5_hex($key); } for my $char (split //, $password) { my $encode=chop($key); $enc_pwd.=sprintf("%.2x",ord($char)^ord($encode)); $key=$encode.$key; } my $err = setKeyValue($index, $enc_pwd); return "error while saving the password - $err" if(defined($err)); return "password successfully saved"; } # end FRITZBOX_storePassword ##################################### # reads the FritzBox password sub FRITZBOX_readPassword($) { my ($hash) = @_; my $name = $hash->{NAME}; my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd"; my $key = getUniqueId().$index; my ($password, $err); FRITZBOX_Log $hash, 5, "Read FritzBox password from file"; ($err, $password) = getKeyValue($index); if(defined($err)) { FRITZBOX_Log $hash, 4, "unable to read FritzBox password from file: $err"; return undef; } if(defined($password)) { if(eval "use Digest::MD5;1") { $key = Digest::MD5::md5_hex(unpack "H*", $key); $key .= Digest::MD5::md5_hex($key); } my $dec_pwd = ''; for my $char (map { pack('C', hex($_)) } ($password =~ /(..)/g)) { my $decode=chop($key); $dec_pwd.=chr(ord($char)^ord($decode)); $key=$decode.$key; } return $dec_pwd; } else { FRITZBOX_Log $hash, 4, "No password in file"; return undef; } } # end FRITZBOX_readPassword ##################################### sub FRITZBOX_fritztris($) { my ($d) = @_; $d = "" if(!$d); return "$d is not a FRITZBOX instance
" if(!$defs{$d} || $defs{$d}{TYPE} ne "FRITZBOX"); my $returnStr = ''; $returnStr .= ''; # $returnStr .= ''; $returnStr .= ''; $returnStr .= ''; $returnStr .= ''; $returnStr .= ''; $returnStr .= ''; $returnStr .= '
FritzTris'; $returnStr .= '
Start'; $returnStr .= '
Stop
'; $returnStr .= '
'; return $returnStr; } ##################################### #{my @cmd;; $cmd=webCmdArray, "active" => "on"; # FRITZBOX_Web_PostCmd ($hash, \@webCmdArray, '/wlan/wlan_settings.lua'); #
  • set <name> convertRingTone <fullFilePath> #
    # Converts the mp3-file fullFilePath to the G722 format and puts it in the same path. #
    # The file has to be placed on the file system of the Fritz!Box. #

  • #
  • set <name> convertMusicOnHold <fullFilePath> #
    # Not implemented yet. Converts the mp3-file fullFilePath to a format that can be used for "Music on Hold". #
    # The file has to be placed on the file system of the fritzbox. #

  • #
  • set <name> convertRingTone <fullFilePath> #
    # Konvertiert die mp3-Datei fullFilePath in das G722-Format und legt es im selben Pfad ab. #
    # Die Datei muss im Dateisystem der Fritz!Box liegen. #

  • #
  • set <name> convertMusicOnHold <fullFilePath> #
    # Not implemented yet. Converts the mp3-file fullFilePath to a format that can be used for "Music on Hold". #
    # The file has to be placed on the file system of the fritzbox. #

  • 1; =pod =begin html

    FRITZBOX

    (en | de)
      Controls some features of a Fritz!Box router. Connected Fritz!Fon's (MT-F, MT-D, C3, C4) can be used as signaling devices. MP3 files and Text2Speech can be played as ring tone or when calling phones.
      For detail instructions, look at and please maintain the FHEM-Wiki.

      The modul switches in local mode if FHEM runs on a Fritz!Box (as root user!). Otherwise, it tries to open a web or telnet connection to "fritz.box", so telnet (#96*7*) has to be enabled on the Fritz!Box. For remote access the password must once be set.

      The box is partly controlled via the official TR-064 interface but also via undocumented interfaces between web interface and firmware kernel. An update of FritzOS might hence lead to modul errors if AVM changes the interface.
      The modul was tested on Fritz!Box 7390 and 7490 with Fritz!OS 6.20 and higher.
      Check also the other Fritz!Box moduls: SYSMON and FB_CALLMONITOR.
      The modul uses the Perl modul 'Net::Telnet', 'JSON::XS', 'LWP', 'SOAP::Lite' for remote access.

      Define

        define <name> FRITZBOX

        Example: define Fritzbox FRITZBOX

        The FritzOS has a hidden function (easter egg).
        define MyEasterEgg weblink htmlCode { FRITZBOX_fritztris("Fritzbox") }

      Set

      • set <name> alarm <number> [on|off] [time] [once|daily|Mo|Tu|We|Th|Fr|Sa|So]
        Switches the alarm number (1, 2 or 3) on or off (default is on). Sets the time and weekday. If no state is given it is switched on.

      • set <name> call <number> [duration] [say:text|play:MP3URL]
        Calls for 'duration' seconds (default 60) the given number from an internal port (default 1 or attribute 'ringWithIntern'). If the call is taken a text or sound can be played as music on hold (moh). The internal port will also ring.

      • set <name> customerRingTone <internalNumber> <fullFilePath>
        Uploads the file fullFilePath on the given handset. Only mp3 or G722 format is allowed.
        The file has to be placed on the file system of the fritzbox.
        The upload takes about one minute before the tone is available.

      • set <name> dect <on|off>
        Switches the DECT base of the box on or off.

      • set <name> diversity <number> <on|off>
        Switches the call diversity number (1, 2 ...) on or off. A call diversity for an incoming number has to be created with the Fritz!Box web interface.
        Note! The Fritz!Box allows also forwarding in accordance to the calling number. This is not included in this feature.

      • set <name> guestWLAN <on|off>
        Switches the guest WLAN on or off. The guest password must be set. If necessary, the normal WLAN is also switched on.

      • set <name> moh <default|sound|customer> [<MP3FileIncludingPath|say:Text>]
        Example: set fritzbox moh customer say:Die Wanne ist voll
        set fritzbox moh customer /var/InternerSpeicher/warnung.mp3
        Changes the 'music on hold' of the Box. The parameter 'customer' allows to upload a mp3 file. Alternatively a text can be spoken with "say:". The music on hold has always a length of 8.2 s. It is played continousely during the broking of calls or if the modul rings a phone and the call is taken. So, it can be used to transmit little messages of 8 s.

      • set <name> password <password>
        Stores the password for remote telnet access.

      • set <name> ring <intNumbers> [duration [ringTone]] [show:Text] [say:Text | play:MP3URL]
        Example:
        set fritzbox ring 611,612 5 Budapest show:It is raining
        set fritzbox ring 611 say:(en)It is raining
        set fritzbox ring 610 play:http://raspberrypi/sound.mp3
        Rings the internal numbers for "duration" seconds and (on Fritz!Fons) with the given "ring tone" name. Different internal numbers have to be separated by a comma (without spaces).
        Default duration is 5 seconds. Default ring tone is the internal ring tone of the device. Ring tone will be ignored for collected calls (9 or 50).
        If the attribute 'ringWithIntern' is specified, the text behind 'show:' will be shown as the callers name. Maximal 30 characters are allowed.
        On Fritz!Fons the parameter 'say:' can be used to let the phone speak a message (max. 100 characters). Alternatively a MP3 link can be played with 'play:'. This creates the internet radio station 'FHEM' and uses translate.google.com for text2speech. It will always play the complete text/sound. It will than ring with standard ring tone until the end of the 'ring duration' is reached.
        If the call is taken the callee hears the "music on hold" which can also be used to transmit messages.

      • set <name> sendMail [to:<Address>] [subject:<Subject>] [body:<Text>]
        Sends an email via the email notification service that is configured in push service of the Fritz!Box. Use "\n" for line breaks in the body. All parameters can be omitted. Make sure the messages are not classified as junk by your email client.

      • set <name> startRadio <internalNumber> [name or number]
        Plays the internet radio on the given Fritz!Fon. Default is the current ring tone radio station of the phone. So, not the station that is selected at the handset. An available internet radio can be selected by its name or (reading) number.

      • set <name> tam <number> <on|off>
        Switches the answering machine number (1, 2 ...) on or off. The answering machine has to be created on the Fritz!Box web interface.

      • set <name> update
        Starts an update of the device readings.

      • set <name> wlan <on|off>
        Switches WLAN on or off.

      Get

      • get <name> ringTones
        Shows the list of ring tones that can be used.

      • get <name> shellCommand <Command>
        Runs the given command on the Fritz!Box shell and returns the result. Can be used to run shell commands not included in this modul.
        Only available if the attribute "allowShellCommand" is set.

      • get <name> tr064Command <service> <control> <action> [[parameterName1 parameterValue1] ...]
        Executes TR-064 actions (see API description of AVM)
        Example: get Fritzbox tr064Command X_AVM-DE_OnTel:1 x_contact GetDECTHandsetInfo NewDectID 1
        Only available if the attribute "allowTR064Command" is set.

      • get <name> tr064ServiceListe
        Shows a list of TR-064 services and actions that are allowed on the device.

      Attributes

      • allowShellCommand <0 | 1>
        Enables the get command "shellCommand"

      • defaultCallerName <Text>
        The default text to show on the ringing phone as 'caller'.
        This is done by temporarily changing the name of the calling internal number during the ring.
        Maximal 30 characters are allowed. The attribute "ringWithIntern" must also be specified.

      • defaultUploadDir <fritzBoxPath>
        This is the default path that will be used if a file name does not start with / (slash).
        It needs to be the name of the path on the Fritz!Box. So, it should start with /var/InternerSpeicher if it equals in Windows \\ip-address\fritz.nas

      • forceTelnetConnection <0 | 1>
        Always use telnet for remote access (instead of access via the WebGUI or TR-064).
        This attribute should be enabled for older boxes/firmwares.

      • fritzBoxIP <IP Address>
        IP address or URL of the Fritz!Box for remote telnet access. Default is "fritz.box".

      • INTERVAL <seconds>
        Polling-Interval. Default is 300 (seconds). Smallest possible value is 60.

      • telnetUser <user name>
        User name that is used for telnet access. By default no user name is required to login.
        If the Fritz!Box is configured differently, the user name has to be defined with this attribute.

      • ringWithIntern <1 | 2 | 3>
        To ring a fon a caller must always be specified. Default of this modul is 50 "ISDN:Wählhilfe".
        To show a message (default: "FHEM") during a ring the internal phone numbers 1-3 can be specified here. The concerned analog phone socket must exist.

      • telnetTimeOut <seconds>
        Maximal time to wait for an answer during a telnet session. Default is 10 s.

      • readingFnAttributes

      Readings

      • alarm1 - Name of the alarm clock 1
      • alarm1_state - Current state of the alarm clock 1
      • alarm1_target - Internal number of the alarm clock 1
      • alarm1_time - Alarm time of the alarm clock 1
      • alarm1_wdays - Weekdays of the alarm clock 1
      • box_dect - Current state of the DECT base
      • box_fwVersion - Firmware version of the box, if outdated then '(old)' is appended
      • box_guestWlan - Current state of the guest WLAN
      • box_guestWlanRemain - Remaining time until the guest WLAN is switched off
      • box_model - Fritz!Box model
      • box_moh - music-on-hold setting
      • box_model - Fritz!Box model
      • box_powerRate - current power in percent of maximal power
      • box_rateDown - average download rate in the last update interval
      • box_rateUp - average upload rate in the last update interval
      • box_tr069 - provider remote access TR069 (safety issue!)
      • box_wlan_2.4GHz - Current state of the 2.4 GHz WLAN
      • box_wlan_5GHz - Current state of the 5 GHz WLAN
      • dect1 - Name of the DECT device 1
      • dect1_alarmRingTone - Alarm ring tone of the DECT device 1
      • dect1_custRingTone - Customer ring tone of the DECT device 1
      • dect1_fwVersion - Firmware Version of the DECT device 1
      • dect1_intern - Internal number of the DECT device 1
      • dect1_intRingTone - Internal ring tone of the DECT device 1
      • dect1_manufacturer - Manufacturer of the DECT device 1
      • dect1_model - Model of the DECT device 1
      • dect1_radio - Current internet radio station ring tone of the DECT device 1
      • fon1 - Internal name of the analog FON connection 1
      • fon1_intern - Internal number of the analog FON connection 1
      • diversity1 - Own (incoming) phone number of the call diversity 1
      • diversity1_dest - Destination of the call diversity 1
      • diversity1_state - Current state of the call diversity 1
      • radio01 - Name of the internet radio station 01
      • tam1 - Name of the answering machine 1
      • tam1_newMsg - New messages on the answering machine 1
      • tam1_oldMsg - Old messages on the answering machine 1
      • tam1_state - Current state of the answering machine 1
      • user01 - Name of user/IP 1 that is under parental control
      • user01_thisMonthTime - this month internet usage of user/IP 1 (parental control)
      • user01_todaySeconds - today's internet usage in seconds of user/IP 1 (parental control)
      • user01_todayTime - today's internet usage of user/IP 1 (parental control)

    =end html =begin html_DE

    FRITZBOX

    (en | de)
      Steuert gewisse Funktionen eines Fritz!Box Routers. Verbundene Fritz!Fon's (MT-F, MT-D, C3, C4) können als Signalgeräte genutzt werden. MP3-Dateien und Text (Text2Speech) können als Klingelton oder einem angerufenen Telefon abgespielt werden.
      Für detailierte Anleitungen bitte die FHEM-Wiki konsultieren und ergänzen.

      Das Modul schaltet in den lokalen Modus, wenn FHEM auf einer Fritz!Box läuft (als root-Benutzer!). Ansonsten versucht es eine Web oder Telnet Verbindung zu "fritz.box" zu öffnen. D.h. Telnet (#96*7*) muss auf der Fritz!Box erlaubt sein. Für diesen Fernzugriff muss einmalig das Passwort gesetzt werden.

      Die Steuerung erfolgt teilweise über die offizielle TR-064-Schnittstelle und teilweise über undokumentierte Schnittstellen zwischen Webinterface und Firmware Kern. Eine Aktualisierung des FritzOS kann also zu Modul-Fehlern führen, wenn AVM diese Schnittstelle ändert.
      Das Modul wurde an der Fritz!Box 7390 und 7490 mit Fritz!OS 6.20 und höher getestet.
      Bitte auch die anderen Fritz!Box-Module beachten: SYSMON und FB_CALLMONITOR.
      Das Modul nutzt das Perlmodule 'Net::Telnet', 'JSON::XS', 'LWP', 'SOAP::Lite' für den Fernzugriff.

      Define

        define <name> FRITZBOX

        Beispiel: define Fritzbox FRITZBOX

        Das FritzOS hat eine versteckte Funktion (Osterei).
        define MyEasterEgg weblink htmlCode { FRITZBOX_fritztris("Fritzbox") }

      Set

      • set <name> alarm <Nummer> [on|off] [time] [once|daily|Mo|Tu|We|Th|Fr|Sa|So]
        Schaltet den Weckruf Nummer 1, 2 oder 3 an oder aus (Standard ist on). Setzt die Zeit und den Wochentag.

      • set <name> call <number> [Dauer] [say:Text|play:MP3URL]
        Ruf für 'Dauer' Sekunden (Standard 60 s) die angegebene Telefonnummer von einem internen Telefonanschluss an (Standard ist 1 oder das Attribut 'ringWithIntern'). Wenn der Angerufene abnimmt, hört er die Wartemusik oder den angegebenen Text oder Klang. Der interne Telefonanschluss klingelt ebenfalls.

      • set <name> customerRingTone <internalNumber> <MP3DateiInklusivePfad>
        Lädt die MP3-Datei als Klingelton auf das angegebene Telefon. Die Datei muss im Dateisystem der Fritzbox liegen.
        Das Hochladen dauert etwa eine Minute bis der Klingelton verfügbar ist.

      • set <name> dect <on|off>
        Schaltet die DECT-Basis der Box an oder aus.

      • set <name> diversity <number> <on|off>
        Schaltet die Rufumleitung (Nummer 1, 2 ...) für einzelne Rufnummern an oder aus.
        Die Rufumleitung muss zuvor auf der Fritz!Box eingerichtet werden.
        Achtung! Die Fritz!Box ermöglicht auch eine Weiterleitung in Abhängigkeit von der anrufenden Nummer. Diese Art der Weiterleitung kann hiermit nicht geschaltet werden.

      • set <name> guestWLAN <on|off>
        Schaltet das Gäste-WLAN an oder aus. Das Gäste-Passwort muss gesetzt sein. Wenn notwendig wird auch das normale WLAN angeschaltet.

      • set <name> moh <default|sound|customer> [<MP3DateiInklusivePfad|say:Text>]
        Beispiel: set fritzbox moh customer say:Die Wanne ist voll
        set fritzbox moh customer /var/InternerSpeicher/warnung.mp3
        Ändert die Wartemusik ('music on hold') der Box. Mit dem Parameter 'customer' kann eine eigene MP3-Datei aufgespielt werden. Alternativ kann mit "say:" auch ein Text gesprochen werden. Die Wartemusik hat immer eine Länge von 8,13 s. Sie wird kontinuierlich während des Makelns von Gesprächen aber auch bei Nutzung der internen Wählhilfe bis zum Abheben des rufenden Telefons abgespielt. Dadurch können über FHEM dem Angerufenen 8s-Nachrichten vorgespielt werden.

      • set <name> password <Passwort>
        Speichert das Passwort für den Fernzugriff über Telnet.

      • set <name> ring <intNummern> [Dauer [Klingelton]] [show:Text] [say:Text | play:Link] Beispiel:
        set fritzbox ring 611,612 5 Budapest show:Es regnet
        set fritzbox ring 610 say:Es regnet
        set fritzbox ring 610 play:http://raspberrypi/sound.mp3
        Lässt die internen Nummern für "Dauer" Sekunden und (auf Fritz!Fons) mit dem angegebenen "Klingelton" klingeln. Mehrere interne Nummern müssen durch ein Komma (ohne Leerzeichen) getrennt werden.
        Standard-Dauer ist 5 Sekunden. Standard-Klingelton ist der interne Klingelton des Gerätes. Der Klingelton wird für Rundrufe (9 oder 50) ignoriert.
        Wenn das Attribut 'ringWithIntern' existiert, wird der Text hinter 'show:' als Name des Anrufers angezeigt. Er darf maximal 30 Zeichen lang sein.
        Auf Fritz!Fons wird der Text (max. 100 Zeichen) hinter dem Parameter 'say:' direkt angesagt. Alternativ kann mit 'play:' auch ein MP3-Link abgespielt werden. Dabei wird die Internetradiostation 39 'FHEM' erzeugt und translate.google.com für Text2Speech genutzt. Es wird immer der komplette Text/Klang abgespielt. Bis zum Ende der 'Klingeldauer' klingelt das Telefon dann mit seinem Standard-Klingelton.
        Wenn der Anruf angenommen wird, hört der Angerufene die Wartemusik (music on hold), welche ebenfalls zur Nachrichtenübermittlung genutzt werden kann.

      • set <name> sendMail [to:<Address>] [subject:<Subject>] [body:<Text>]
        Sendet eine Email über den Emailbenachrichtigungsservice der als Push Service auf der Fritz!Box konfiguriert wurde. Mit "\n" kann einen Zeilenumbruch im Textkörper erzeut werden. Alle Parameter können ausgelassen werden. Bitte kontrolliert, dass die Email nicht im Junk-Verzeichnis landet.

      • set <name> startRadio <internalNumber> [Name oder Nummer]
        Startet das Internetradio auf dem angegebenen Fritz!Fon. Eine verfügbare Radiostation kann über den Namen oder die (Gerätewert)Nummer ausgewählt werden. Ansonsten wird die in der Box als Internetradio-Klingelton eingestellte Station abgespielt. (Also nicht die am Telefon ausgewählte.)

      • set <name> tam <number> <on|off>
        Schaltet den Anrufbeantworter (Nummer 1, 2 ...) an oder aus. Der Anrufbeantworter muss zuvor auf der Fritz!Box eingerichtet werden.

      • set <name> update
        Startet eine Aktualisierung der Gerätewerte.

      • set <name> wlan <on|off>
        Schaltet WLAN an oder aus.

      Get

      • get <name> ringTones
        Zeigt die Liste der Klingeltöne, die benutzt werden können.

      • get <name> shellCommand <Befehl>
        Führt den angegebenen Befehl auf der Fritz!Box-Shell aus und gibt das Ergebnis zurück. Kann benutzt werden, um Shell-Befehle auszuführen, die nicht im Modul implementiert sind.
        Muss zuvor über das Attribute "allowShellCommand" freigeschaltet werden.

      • get <name> tr064Command <service> <control> <action> [[parameterName1 parameterValue1] ...]
        Führt über TR-064 Aktionen aus (siehe Schnittstellenbeschreibung von AVM)
        Beispiel: get Fritzbox tr064Command X_AVM-DE_OnTel:1 x_contact GetDECTHandsetInfo NewDectID 1
        Muss zuvor über das Attribute "allowTR064Command" freigeschaltet werden.

      • get <name> tr064ServiceListe
        Zeigt die Liste der TR-064-Dienste und Aktionen, die auf dem Gerät erlaubt sind.

      Attributes

      • allowShellCommand <0 | 1>
        Freischalten des get-Befehls "shellCommand"

      • allowShellCommand <0 | 1>
        Freischalten des get-Befehls "tr064Command"

      • defaultCallerName <Text>
        Standard-Text, der auf dem angerufenen internen Telefon als "Anrufer" gezeigt wird.
        Dies erfolgt, indem während des Klingelns kurzzeitig der Name der internen anrufenden Nummer geändert wird.
        Es sind maximal 30 Zeichen erlaubt. Das Attribute "ringWithIntern" muss ebenfalls spezifiziert sein.

      • defaultUploadDir <fritzBoxPath>
        Dies ist der Standard-Pfad der für Dateinamen benutzt wird, die nicht mit einem / (Schrägstrich) beginnen.
        Es muss ein Pfad auf der Fritz!Box sein. D.h., er sollte mit /var/InternerSpeicher starten, wenn es in Windows unter \\ip-address\fritz.nas erreichbar ist.

      • forceTelnetConnection <0 | 1>
        Erzwingt den Fernzugriff über Telnet (anstatt über die WebGUI oder TR-064).
        Dieses Attribut muss bei älteren Geräten/Firmware aktiviert werden.

      • fritzBoxIP <IP-Adresse>
        IP Adresse oder ULR der Fritz!Box für Fernzugriff per Telnet. Standard ist "fritz.box".

      • INTERVAL <Sekunden>
        Abfrage-Interval. Standard ist 300 (Sekunden). Der kleinste mögliche Wert ist 60.

      • telnetUser <user name>
        Benutzername für den Telnetzugang. Normalerweise wird keine Benutzername für das Login benötigt. Wenn die Fritz!Box anders konfiguriert ist, kann der Nutzer über dieses Attribut definiert werden.

      • ringWithIntern <1 | 2 | 3>
        Um ein Telefon klingeln zu lassen, muss eine Anrufer spezifiziert werden. Normalerweise ist dies die Nummer 50 "ISDN:Wählhilfe".
        Um während des Klingelns eine Nachricht (Standard: "FHEM") anzuzeigen, kann hier die interne Nummer 1-3 angegeben werden. Der entsprechende analoge Telefonanschluss muss vorhanden sein.

      • telnetTimeOut <Sekunden>
        Maximale Zeit, bis zu der während einer Telnet-Sitzung auf Antwort gewartet wird. Standard ist 10 s.

      • readingFnAttributes

      Readings

      • alarm1 - Name des Weckrufs 1
      • alarm1_state - Aktueller Status des Weckrufs 1
      • alarm1_target - Interne Nummer des Weckrufs 1
      • alarm1_time - Weckzeit des Weckrufs 1
      • alarm1_wdays - Wochentage des Weckrufs 1
      • box_dect - Aktueller Status des DECT-Basis
      • box_fwVersion - Firmware-Version der Box, wenn veraltet dann wird '(old)' angehangen
      • box_guestWlan - Aktueller Status des Gäste-WLAN
      • box_guestWlanRemain - Verbleibende Zeit bis zum Ausschalten des Gäste-WLAN
      • box_model - Fritz!Box-Modell
      • box_moh - Wartemusik-Einstellung
      • box_powerRate - aktueller Stromverbrauch in Prozent der maximalen Leistung
      • box_rateDown - durchschnittliche Download-Geschwindigkeit in kByte/s des letzten Aktualisierungsintervals
      • box_rateUp - durchschnittliche Upload-Geschwindigkeit in kByte/s des letzten Aktualisierungsintervals
      • box_tr069 - Provider-Fernwartung TR069 (sicherheitsrelevant!)
      • box_wlan_2.4GHz - Aktueller Status des 2.4-GHz-WLAN
      • box_wlan_5GHz - Aktueller Status des 5-GHz-WLAN
      • dect1 - Name des DECT Telefons 1
      • dect1_alarmRingTone - Klingelton beim Wecken über das DECT Telefon 1
      • dect1_custRingTone - Benutzerspezifischer Klingelton des DECT Telefons 1
      • dect1_fwVersion - Firmware-Version des DECT Telefons 1
      • dect1_intern - Interne Nummer des DECT Telefons 1
      • dect1_intRingTone - Interner Klingelton des DECT Telefons 1
      • dect1_manufacturer - Hersteller des DECT Telefons 1
      • dect1_model - Modell des DECT Telefons 1
      • dect1_radio - aktueller Internet-Radio-Klingelton des DECT Telefons 1
      • fon1 - Name des analogen Telefonanschlusses 1 an der Fritz!Box
      • fon1_intern - Interne Nummer des analogen Telefonanschlusses 1
      • diversity1 - Eigene Rufnummer der Rufumleitung 1
      • diversity1_dest - Zielnummer der Rufumleitung 1
      • diversity1_state - Aktueller Status der Rufumleitung 1
      • radio01 - Name der Internetradiostation 01
      • tam1 - Name des Anrufbeantworters 1
      • tam1_newMsg - Anzahl neuer Nachrichten auf dem Anrufbeantworter 1
      • tam1_oldMsg - Anzahl alter Nachrichten auf dem Anrufbeantworter 1
      • tam1_state - Aktueller Status des Anrufbeantworters 1
      • user01 - Name von Nutzer/IP 1 für den eine Zugangsbeschränkung (Kindersicherung) eingerichtet ist
      • user01_thisMonthTime - Internetnutzung des Nutzers/IP 1 im aktuellen Monat (Kindersicherung)
      • user01_todaySeconds - heutige Internetnutzung des Nutzers/IP 1 in Sekunden (Kindersicherung)
      • user01_todayTime - heutige Internetnutzung des Nutzers/IP 1 (Kindersicherung)

    =end html_DE =cut--