Benutzer:Zephyr/Telefonat als Auslöser für Aktionen

Aus FHEMWiki
< Benutzer:Zephyr
Version vom 14. August 2014, 15:03 Uhr von Ph1959de (Diskussion | Beiträge) (Kategorieeintrag aus "privater" Seite entfernt)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Callmonitor mit Anruferliste und Zusatzfunktionen

Dieser Eintrag basiert hauptsächlich auf der Diskussion "Callmonitor für Anfänger" im FHEM-Forum [1].

Der hier gezeigte Beispielcode ist einem Post [[2]] in oben genannter Diskussion entnommen. Er umfasst alle Bestandteile zum Anzeigen einer rollierenden Anruferliste.

Die Zusatzfunktionen (z.B. Floorplan- Seitenwechsel mit Anzeige des Anrufers und dessen gleichzeitiger Ansage über TTS) sind auskommentiert. Sie können als Anregung verstanden werden.

Achtung: Größtes Problem bei der Implementierung scheint zu sein, dass die Bezeichnung des Callmonitors nicht einheitlich durchgehalten wird. In diesem Beispiel heißt er: "my_callmonitor"

Aufgabenstellung

Wie die Anruferliste erstellt wird und wie die Voraussetzungen für auszulösende Aktionen eingebunden werden wird im Abschnitt "Lösung" schrittweise erklärt. Die Anforderungen an die Anruferliste und auszulösende Aktionen werden folgend kurz dargestellt.

Anforderungen an die Anruferliste

  • Liste mit der Möglichkeit die letzten fünf über die Fritz!Box angenommenen und getätigten Anrufe darzustellen
  • die Liste soll den letzen Anruf in der ersten Zeile anzeigen
  • der Status des Anrufes ist über ein Symbol ersichtlich
  • Name und Nummer des Angerufenen / Anrufenden sind ersichtlich

Anforderungen an die Möglichkeit Aktionen auszulösen

  • Aktionen können in Abhängigkeit von Status des Anrufes ausgeführt werden
  • Aktionen können auch gekapselt werden

durchzuführende Schritte

Die Reihenfolge ist hier unerheblich. Die Liste soll lediglich einen groben Überblick über die folgenden einzelnen Schritte zur Orientierung geboten werden

  • 99_myUtilsTelefon.pm erstellen (bitte zuerst durchführen)
  • UserReadings im Callmonitor in FHEM einrichten
  • Readingsgroup erstellen, die die UserReadings anzeigt
  • Notify erstellen, das die Telefonaktionen aufruft
  • in Abhängigkeit vom Anrufstatus auszulösende Aktionen einbinden

Anwendungsbeispiele

Voraussetzungen

Aktivierter Callmonitor in der Fritz!Box

Damit das Modul Callmonitor in FHEM überhaupt arbeitet, muss zuerst in der Fritz!Box der Callmonitor eingeschalten werden. Das geht am einfachsten, indem man von einem direkt an die Fritz!Box angeschlossenen Telefon die Nummer #96*5* wählt.

Funktionierendes Modul Callmonitor in FHEM

Ist bereits das Modul Callmonitor in FHEM aktiv, muss es natürlich nicht extra eingerichtet werden. Wie das funktioniert erklärt sehr gut der Artikel FB CALLMONITOR.

Anlegen einer Datei 99_myUtilsTelefon.pm

Die Datei 99_myUtilsTelefon.pm wird den Perlcode aufnehmen, der die Anruferliste sowie die damit verknüpften Aktionen ausführt. Das Prinzip, um die 99_myUtilsTelefon.pm zu erstellen die exakt das gleich wie wenn man eine 99 myUtils anlegen möchte. In unserem konkreten Fall soll die Datei allerdings den Namen 99_myUtilsTelefon.pm erhalten.

Bitte diesen Schritt nun ausführen, damit später das Script nur noch in die 99_myUtilsTelefon.pm kopiert werden muss.

Natürlich muss auch die 99_myUtilsTelefon.pm nach jeder Anpassung an eigene Bedürfnisse neu geladen werden.

Lösung

In die fhem.cfg :

# Logfile der Anrufe (Fritzbox)
define FileLog_my_callmonitor FileLog /opt/fhem/log/my_callmonitor-%Y.log my_callmonitor
attr FileLog_my_callmonitor logtype text
attr FileLog_my_callmonitor room 4_Logdaten

# Callmonitor mit rollierender Anruferliste:
define my_callmonitor FB_CALLMONITOR 192.168.1.1:1012
attr my_callmonitor group Connections
attr my_callmonitor icon phone_call
attr my_callmonitor local-area-code 030
attr my_callmonitor reverse-search all
attr my_callmonitor reverse-search-cache-file /opt/fhem/callmoncache.txt
attr my_callmonitor reverse-search-phonebook-file /opt/fhem/fb_phonebook.xml
attr my_callmonitor room 5_System
attr my_callmonitor userReadings eing0 eing1 eing2 eing3 eing4 A0 A1 A2 A3 A4 B0 B1 B2 B3 B4 C0 C1 C2 C3 C4 D0 D1 D2 D3 D4 E0 E1 E2 E3 E4
attr my_callmonitor verbose 0
#attr my_callmonitor reverse-search-cache 1
#attr my_callmonitor reverse-search internal|klicktel.de|dasoertliche.de

# Anrufer Anzeigen:
#########################

# Dummy zur Anzeige des Namen:
define Dum_TelMon_ShowNa_D dummy
#attr Dum_TelMon_ShowNa_D fp_9_Telefon 23,209,0,Eingehender Anruf von:
attr Dum_TelMon_ShowNa_D group Programm
attr Dum_TelMon_ShowNa_D room 5_System

# Dummy zur Anzeige der Nummer:
define Dum_TelMon_ShowNu_D dummy
#attr Dum_TelMon_ShowNu_D fp_9_Telefon 165,278,0,Telefonnummer:
attr Dum_TelMon_ShowNu_D group Programm
attr Dum_TelMon_ShowNu_D room 5_System

# Wenn Telefon klingelt, wechsle zum FP "Telefon",zeige und sage Anrufer an:
#define Func_TelMon_Show_N notify my_callmonitor:event:.ring { \
#my $intum = ReadingsVal("my_callmonitor", "internal_number", undef);;\
#my $extnum = ReadingsVal("my_callmonitor", "external_number", undef);;\
#my $extname = ReadingsVal("my_callmonitor", "external_name", undef);;\
#\
#fhem "set Dum_TelMon_ShowNa_D $extname";;\
#fhem "set Dum_TelMon_ShowNu_D $extnum";;\
#fhem("set Dum_pageswap_D /fhem/floorplan/9_Telefon");;\
#\
#   if ($extname eq "unknown"){\
#      fhem("define Melde_Anrufer_A at +00:00:01 set TTS tts Rufnummer unterdrückt");;\
#   }\
#   else {\
#      fhem("define Melde_Anrufer_A at +00:00:01 set TTS tts $extname.");;\
#   }\
#}
#attr Func_TelMon_Show_N group Programm
#attr Func_TelMon_Show_N room 5_System

# Wenn Telefon aufgelegt, wechsle zum Haupt-FP:
#define Func_TelMon_Back_N notify my_callmonitor:event:.disconnect { \
#fhem("set Dum_pageswap_D /fhem/floorplan/0_Hauptbildschirm");;\
#}
#attr Func_TelMon_Back_N group Programm
#attr Func_TelMon_Back_N room 5_System


# Anrufliste genereieren:
#########################

# Telefonevents für Anrufliste abfangen:
define Func_TelMon_N notify my_callmonitor:.* { \
   TelefonMonitor ($EVENT);; \
}
attr Func_TelMon_N group Programm
attr Func_TelMon_N room 5_System

# Anzeige der Anrufliste generieren:
define Anrufliste readingsGroup my_callmonitor:A0,B0,C0,D0,E0 my_callmonitor:A1,B1,C1,D1,E1 my_callmonitor:A2,B2,C2,D2,E2 my_callmonitor:A3,B3,C3,D3,E3 my_callmonitor:A4,B4,C4,D4,E4
attr Anrufliste fp_9_Telefon 370,206,0,Anrufliste
attr Anrufliste mapping &nbsp
attr Anrufliste nameStyle style="font-weight:bold"
attr Anrufliste noheading 0
attr Anrufliste nolinks 1
attr Anrufliste nostate 1
attr Anrufliste notime 1
attr Anrufliste room 0_Überblick
attr Anrufliste style style="font-size:20px"
attr Anrufliste valueIcon {'A0.out_connected' => 'phone_call_out@lightgreen', 'A0.out_notconnected' => 'phone_call_out@red','A0.in_connected' => 'phone_call_in@lightgreen','A0.in_notconnected' => 'phone_call_in@red', 'A0.AB' => 'audio_volume_mid@lightgreen', 'A1.out_connected' => 'phone_call_out@lightgreen', 'A1.out_notconnected' => 'phone_call_out@red','A1.in_connected' => 'phone_call_in@lightgreen','A1.in_notconnected' => 'phone_call_in@red', 'A1.AB' => 'audio_volume_mid@lightgreen','A2.out_connected' => 'phone_call_out@lightgreen', 'A2.out_notconnected' => 'phone_call_out@red','A2.in_connected' => 'phone_call_in@lightgreen','A2.in_notconnected' => 'phone_call_in@red', 'A2.AB' => 'audio_volume_mid@lightgreen','A3.out_connected' => 'phone_call_out@lightgreen', 'A3.out_notconnected' => 'phone_call_out@red','A3.in_connected' => 'phone_call_in@lightgreen','A3.in_notconnected' => 'phone_call_in@red', 'A3.AB' => 'audio_volume_mid@lightgreen','A4.out_connected' => 'phone_call_out@lightgreen', 'A4.out_notconnected' => 'phone_call_out@red','A4.in_connected' => 'phone_call_in@lightgreen','A4.in_notconnected' => 'phone_call_in@red', 'A4.AB' => 'audio_volume_mid@lightgreen'}
 


In die 99_myUtilsTelefon.pm :

#################################################
# $Id: 99_myUtilsTelefon.pm 1932 2012-10-06 20:15:33Z ulimaass $
package main;

use strict;
use warnings;
use POSIX;
use FritzBoxUtils;

# fuer Telefonanrufe
our @A;
our @B;
our @C;
our @D;
our @E;
our %TelefonAktionsListe;


sub myUtilsTelefon_Initialize($$) {
    my ($hash) = @_;

    #...

}
################################################################

sub SendSMS ($$) {
    my $adress = $_[0] . '@sms.kundenserver.de';
    my $body   = $_[1];
    Log( 3, "SendSMS: $adress - $body" );
    FB_mail( $adress, "", $body );

    # end sub SendSMS
}
#####################################
# Anruffunktionen ueber Fritzbox

sub FBCall ($$) {

    my $callnr   = $_[0];
    my $duration = $_[1];

    Log( 3, "FBCall: $callnr mit Dauer $duration" );

    $callnr = "ATDT" . $callnr . "#";
    my $ret = "ATD: " . `echo $callnr | nc 127.0.0.1 1011`;
    InternalTimer( gettimeofday() + $duration, "FBHangOn", "", 0 );
    return;
}

sub FBHangOn () {
    Log( 3, "FBCallHangOn aufgerufen" );

    my $ret = " ATH: " . `echo "ATH" | nc 127.0.0.1 1011`;
    $ret =~ s,[\r\n]*,,g;
    return;
}

######################################

sub TelefonAktion($$) {

    # es wird der Name und die interne angerufene Nummer uebergeben

    my ($caller) = split( '\(', $_[0] );
    $caller = ltrim( rtrim($caller) );

    my $intern = $_[1];

    # Log(3,"TelefonAktion: $caller $intern");
    # Sound ausgeben

    my $com = $main::TelefonAktionsListe{$caller};

    if ($com) {
        Log( 3, "TelefonAktion: commando: $com" );
        sig2_repeat( $com, 5, 4 );
    }    # falls commando vorhanden

}    # end sub TelefonAktion

######################################

sub TelefonMonitor($) {
    our $extnum;
    our $intnum;
    our $extname;
    our $callID;
    our $callDuration;
    # Anrufdauer als Integervariable speichern
    our $intCallDuration;  
    our $stat;
    our @lastPhoneEvent;
    my $i;
    my $j;
    our $ab;
    my $my_callmonitor = $defs{"my_callmonitor"};


    my ( $event, $arg ) = split( ':', $_[0] );
    $arg = ltrim($arg);

    # Log(3,"TM: event: $event arg: $arg");
    if ( $event eq "event" ) {
        $stat = $arg;
        return;
    }    # end if event

    if ( $stat eq "ring" ) {
        if ( $event eq "external_number" ) {
            $extnum = $arg;
            return;
        }    # if external number

        if ( $event eq "external_name" ) {
            $extname = $arg;
            return;
        }
        if ( $event eq "internal_number" ) {
            $intnum = $arg;
            return;
        }    # end if intnum

        if ( $event eq "call_id" ) {
            $callID = $arg;
            
            $lastPhoneEvent[$callID] = $stat;
            
            # hier koennen wir eine anrufgesteuerte Aktion starten
            TelefonAktion( $extname, $intnum );

            $B[$callID] = EventZeit();
            $C[$callID] = $extname;
            $D[$callID] = $extnum;
            return;
        }    # end if callid
        return;
    }    # end if ring loop

    if ( $stat eq "connect" ) {
        if ( ( $event eq "internal_connection" ) && ( $arg =~ m/Answering_Machine_.*/ ) )
        {
            $ab = "AB";
        }    # end if internal_connection
    }    # end if connect

    if ( $stat eq "call" ) {
        if ( $event eq "external_number" ) {
            $extnum = $arg;
            return;
        }    # if external number

        if ( $event eq "external_name" ) {
            $extname = $arg;
            return;
        }
        if ( $event eq "call_id" ) {
            $callID     = $arg;

            $B[$callID] = EventZeit();
            $C[$callID] = $extname;
            $D[$callID] = $extnum;
            
            $lastPhoneEvent[$callID] = $stat;
            return;
        }    # end if callid
        return;
    }    # end if callloop

    if ( $stat eq "disconnect" ) {

        if ( $event eq "call_duration" ) {
            $intCallDuration = $arg;
            $callDuration = sprintf( "%2d:%02d", ( $arg / 60 ), $arg % 60 );
            return;
        }    # if call_duration
        
        if ( $lastPhoneEvent[$callID] eq "call" ) {
            if ( $intCallDuration eq 0 ) {
                $A[$callID] = "out_notconnected";
                # hier notieren was passieren soll, wenn es ein eingehender Anruf war, der nicht angenommen wurde
            } elsif ( $intCallDuration gt 0 ) {
                $A[$callID] = "out_connected";
                # hier notieren was passieren soll, wenn es ein eingehender Anruf war, der angenommen wurde
            }
        } elsif ( $lastPhoneEvent[$callID] eq "ring") {
            if ( $intCallDuration eq 0 ) {
                $A[$callID] = "in_notconnected";
                # hier notieren was passieren soll, wenn es ein ausgehender Anruf war, der nicht angenommen wurde

                $intCallDuration = undef;
            } elsif ( $ab eq "AB" ) {
                $A[$callID] = "AB";
                $ab = undef;
                # hier notieren was passieren soll, wenn der AB dranging

                $intCallDuration = undef;
            } elsif ($intCallDuration gt 0 ){
                $A[$callID] = "in_connected";
                # hier notieren was passieren soll, wenn es ein ausgehender Anruf war, der angenommen wurde
                
                $intCallDuration = undef;
            }
        }
        
        #hier notieren was generell passieren soll, sobald ein Anruf beendet wurde (egal ob angenommen, nicht angenommen, aus- oder eingehend oder der AB dranging)

        if ( $event eq "call_id" ) {
            $callID = $arg;

            # shiften der alten Inhalte
            my $tt;
            readingsBeginUpdate($my_callmonitor);

            for ( $i = 4 ; $i > 0 ; $i-- ) {
                foreach $j ( 'A' .. 'E' ) {

                    #   $defs{"my_callmonitor"}{READINGS}{$j.($i-1)}{VAL};

                    $tt = ReadingsVal( "my_callmonitor", $j . ( $i - 1 ), "-" );
                    readingsBulkUpdate( $my_callmonitor, $j . $i, $tt );
                }    # end j
            }    # end i
            $E[$callID] = $callDuration;
            readingsBulkUpdate( $my_callmonitor, "A0", $A[$callID] );
            readingsBulkUpdate( $my_callmonitor, "B0", $B[$callID] );
            readingsBulkUpdate( $my_callmonitor, "C0", $C[$callID] );
            readingsBulkUpdate( $my_callmonitor, "D0", $D[$callID] );
            readingsBulkUpdate( $my_callmonitor, "E0", $E[$callID] );

            readingsEndUpdate( $my_callmonitor, 1 );
            $stat = "";

            return;
        }    # end if callid

    }    # end if disconnect

##############################
}    #end sub TelefonMonitor

sub EventZeit() {
    my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
      localtime( time() );
    return sprintf(
        "%2d:%02d:%02d %2d.%02d.%4d",
        $hour, $min, $sec, $mday,
        ( $mon + 1 ),
        ( $year + 1900 )
    );
}    # end sub EventZeit
###################


1;
 
 

Verwendung

Beschreibung der Funktion