Callmonitor für Anfänger

Begonnen von coolice, 25 Januar 2014, 13:07:36

Vorheriges Thema - Nächstes Thema

Spartacus

Hallo,
wenn ich Pauls Zitat aus der CommandRef richtig deute, dann funzt das mit dem phonebook nur, wenn fhem auf der Fritte läuft!

Das hilft mir jedoch nicht, da fhem bei mir auf einem pi läuft. Ein Export des phonebooks macht auch keinen Sinn, da die Fritte mit google synchronisiert und somit auf den pi nicht aktuell wäre.

Schön wäre es deshalb, wenn der Callmonitor auch mit dem google Adressbuch synchronisieren würde, oder auf das Telefonbuch in der Fritte zugreifen könnte. Habe aber keine Ahnung, ob das technisch geht.

Christian
Fhem-System: 1 x raspberry PI Typ B, 1 x enOcean PI Typ B | Enocean: PTM210, FMS61NP, FAM14, 2 x FSR14-4x, FTS14-EM | LaCrosse: 2 x TX29D über Jeelink V3 | 1-Wire: 2 x DS18B20 über DS9490R

Markus Bloch

Hallo,

eine Nutzung der Google-Kontakte online ist so direkt ohne weiteres nicht möglich.

Das Problem besteht hier weniger in der technischen Natur, als eher in der rechtlichen. Die Rahmenbedingungen sind hier aufgrund von Datenschutz nicht ganz so einfach. Man muss eine Applikation bei Google registrieren und beschreiben, welche Schnittstellen sie nutzen möchte (z.B. Contacts-API). Dazu gehört dann ein Applikationsnahme, sowie Verantwortlicher inkl. Email + Nutzungsbedingungen/Datenschutzerklärung.

Diese Sachen kann ich aber selbst nicht so ohne weiteres machen, da ich nicht der Eigentümer dieses Projektes bin. Hier müsste eine generelle Regelung gefunden werden.

Daher wird aktuell nur das FritzBox Telefonbuch lokal unterstützt. Dieses wird (sofern FHEM auf der FritzBox läuft) sofort erkannt, oder man macht einen export des Telefonbuchs im XML Format und hinterlegt es auf dem FHEM System (Pfadangabe durch reverse-search-phonebook-file)

Viele Grüße

Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Spartacus

Hallo Markus,
danke für die Aufklärung! War ja nur so eine Idee. Und der Zugriff des Moduls auf das phonebook derFritte via Telnet ist dann offenbar auch nicht möglich, oder? Ich meine mal von einem Contact Connection Wizard gelesen zu haben. Aber keine Ahnung, ob man dazu etwas auf der Fritte installieren muss...

Gruß,
Christian.
Fhem-System: 1 x raspberry PI Typ B, 1 x enOcean PI Typ B | Enocean: PTM210, FMS61NP, FAM14, 2 x FSR14-4x, FTS14-EM | LaCrosse: 2 x TX29D über Jeelink V3 | 1-Wire: 2 x DS18B20 über DS9490R

Roaster

Dazu noch meinen Senf ;)

Meine Kontakte sitzen weder auf der FBF noch bei Google, sondern auf einem lokalen Cardav Server, den ich lieber (zusätzlich) mit einbeziehen würde.
Weiß nicht ob da in Zukunft noch etwas machbar ist.

Apropos Google. Bei den Google-Kalendern kann man doch irgendwo eine URL kopieren, die Zugriff auf die Kalender erlaubt und zwar ohne Authentifizierung, wenn ich mich richtig erinnere. Ist dies vielleicht auch mit den Kontakten möglich? In jedem Fall wird der Callmonitor wohl CalDav bzw. hier Cardav unterstützen müssen um die Kontakte abzugreifen.

Michael

Markus Bloch

Ich habe gerade mal einen Blick in meine Google Contacts geworfen. So wie es bei Google Calender möglich ist eine URL freizugeben ist bei Contacts leider nicht möglich.

Man kann als angemeldeter User einen einmaligen Export aller Kontakte zum aktuellen Zeitpunkt machen (z.B. im vCard Format). Was möglich wäre, ist ein solches *.vcf File via Attribut an FB_CALLMONITOR zu geben um dort die Rufnummernauflösung zu machen.

Allerdings kann man so dennoch nicht auf die aktuelle Google Kontaktliste zugreifen. Dies geht nur über den komplizierten Weg, den ich weiter oben beschrieben habe.

Die Google CardDAV API setzt wie bereits oben beschrieben die Registrierung der Applikation in der DevConsole vorraus, so dass man sich dann mit OAuth2 an den Google Servern authentifizieren kann.

Viele Grüße

Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Spartacus

Hallo Markus,
ist ok! So genau kenne ich mich damit auch nicht aus.

Aber irgendwie schafft das der Contact Connection Wizard (http://software.nv-systems.net/ccw) Der kann auch die Kontakte von der Fritzbox holen...
Vielleicht ist das ein Ansatzpunkt!

Christian
Fhem-System: 1 x raspberry PI Typ B, 1 x enOcean PI Typ B | Enocean: PTM210, FMS61NP, FAM14, 2 x FSR14-4x, FTS14-EM | LaCrosse: 2 x TX29D über Jeelink V3 | 1-Wire: 2 x DS18B20 über DS9490R

Roaster

Zitat von: Spartacus am 04 Dezember 2014, 14:04:43
Aber irgendwie schafft das der Contact Connection Wizard (http://software.nv-systems.net/ccw) Der kann auch die Kontakte von der Fritzbox holen...
Vielleicht ist das ein Ansatzpunkt!

Wenn man das jetzt noch irgendwie automatisiert (per CRON Job) auf dem Raspberry zum Laufen bekommt, wäre das Spitze! Soweit ich verstanden habe, wäre dies auch mittels Mono auf einem Linux Rechner möglich...

Jemand schon Erfahrung damit?

Michael

Markus Bloch

Hallo zusammen,

generell wäre das möglich, sowas zu integrieren. Wie das ganze funktioniert ist auch soweit verständlich. Mir fehlt nur leider die Zeit es umzusetzen.

Viele Grüße und einen spendablen Nikolaus

Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

JoWiemann

Zitat von: Spartacus am 04 Dezember 2014, 14:04:43
Aber irgendwie schafft das der Contact Connection Wizard (http://software.nv-systems.net/ccw) Der kann auch die Kontakte von der Fritzbox holen...

Hi, ich wüsste nicht, dass der CCW das kann. Jedenfalls sehe ich nirgendwo einen entsprechenden Menüpunkt. Selbst JFritz, dass ja die Telefonliste von der Fritte holen kann, kann nicht das Telefonbuch holen.

Grüße Jörg

Jörg Wiemann

Slave: RPi B+ mit 512 MB, COC (868 MHz), CUL V3 (433.92MHz SlowRF); FHEMduino, Aktuelles FHEM

Master: CubieTruck; Debian; Aktuelles FHEM

fiedel

#309
ZitatSelbst JFritz, dass ja die Telefonliste von der Fritte holen kann, kann nicht das Telefonbuch holen.

Die Fritzbox- API kann das.

Aber kann der Konverter Shellkommandos?
FeatureLevel: 6.1 auf Wyse N03D ; Deb. 11 ; Perl: v5.14.2 ; IO: HM-MOD-RPI-PCB + VCCU|CUL 868 V 1.66|LinkUSBi |TEK603
HM: SEC-SCO|SCI-3-FM|LC-SW4-PCB|ES-PMSW1-PL|RC-4-2|SEN-MDIR-O|SEC-WDS-2
CUL: HMS100TF|FS20 S4A-2 ; OWDevice: DS18S20|DS2401|DS2406|DS2423

JoWiemann

Jörg Wiemann

Slave: RPi B+ mit 512 MB, COC (868 MHz), CUL V3 (433.92MHz SlowRF); FHEMduino, Aktuelles FHEM

Master: CubieTruck; Debian; Aktuelles FHEM

Avatar

Hallo,
ich habe mal eine Problem zur Revers-Suche  - FB_Callmonitor bzw. zum Telefonmonitor.
Bei mir werden die Namen aus dem Telefonbuch nicht immer aufgelöst. Auch die Revers-Suche scheint mit "search.ch" nicht immer zu funktionieren.

reverse-search search.ch
reverse-search-cache 1

Die Namen sind aber in "search.ch" zu finden. Dabei ist mir aufgefallen, wenn es eine einzelne Person/privat Person ist die gesucht wird, da geht es.
Wenn es eine Firma ist die gesucht wird, dann kommt immer - "unknown" zurückgegeben

Folgende Nummer geht nicht: 044 432 89 59
Folgende Nummer wird gefunden : 044 431 31 34

Güsse
Eric


Markus Bloch

Hallo Eric,

in der Tat. Ich hatte es nur mit einer Privat-Nummer getestet. Jetzt funktionieren auch Firmen.

Gibt es ab morgen via update.

Ein schönes Wochenende

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

coolice

Hallo zusammen. Könnte einer so nett sein und mal eine funktionierende 99_myUtilsTelefon mit Icons für eingehend angenommen, eingehend nicht angenommen, abgehend angenommen, abgehend nicht angenommen und Ab posten.
Bin auf einen Raps umgestiegen und die RG läuft nicht.

Danke vorab
Mirco

bobby1000

Hallo Mirco,
bei mir klappt es mit dieser 99_myUtilsTM

################################## # $Id: 99_myUtilsTM.pm 2014-8 by Elektrolurch $
# Version 1.6 15/10/2014 by Elektrolurch
# change: call information are stored in a hash, not in an array
# callID: can be anything
# answering_machine_1 is mapped to 'AB
# anwering_machine_2..n is mapped to AB2 ...ABn
# table is now updated during ring | call and not after disconnect
#
# events are handled:
# 1. ring | call
# 2. external_number | external | name ... -> stored in hash
# 3. call_id stores infos in %callmem{$callID} and updates table
#
# disconnect
# call_duration updates the appropriate line in table
#

# Version 1.2 now as Modul TM
# define myTM TM <fritzbox>
# <fristzbox must be of type FB_CALLMONITOR
#  a seperate  notify is  now not necessary!
# for visualization:
# values of calls are stored in A0..E0,...A4...E4
# use a readingsGroup for displaying values
# version 1.3
# methods for using calls to event "ring" and disconnect"
# acdepts perl-code and calls to fhem
# attr myTM method-ring set Lampe1 on
# attr myTM1 method-disconnect {TelefonAction($EXTERNAL_NAME);;;;}
# intern values for fhem: %EXTERNAL_NAME, %EXTERNAL_NUMBER, %INTERNAL_NUMBER
# for perl
# $EXTERNAL_NAME, $EXTERNAL_NUMBER, $INTERNAL_NUMBER
# Version 1.4
# added: set command
# set name [clear | monitor-type [all|incoming|outgoing|missed-call|all-after-disconnect]] 

# Version 1.51 (26.10.2014 18:00)
# Bugfix: AB in TM_SetValue -> requires eq not ==
# attrList added room

# Version 1.52 30.09.2014
# Bugfix: TM_UpdateValue: readingsSingleUpdate -> $update replaced 1

# Version 1.53
# alias to attrlist added

# Version  1.54
# smaller corrections handling monitor-type = 'missed-call'

# Version 1.6
# added:  attr line-filter accepts a list of ',' seperated incoming calling line numbers for filtering incoming or outgoing calls by calling line
# or a hash for mapping lines to text
# example
# attr myTM line-filter 304050,304060
# or
# attr myTM line-filter {'304050' => 'geschftl.', '304060' => 'priv'}
# line-information is stored in G0...G4
#
# added:
# $INTERNAL_CONNECTION / %INTERNAL_CONNECTION as variables for calling methods
# added: method-connect



package main;

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


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


# Symbols for call direction
# used as defaults, if appropiate Attributes are not defined
my $incoming = '->';
my $outgoing = '<-';
my $incoming_noconnect  = '0>';
my $outgoing_noconnect = '<0';
my $ab = 'AB';
my $connected = 'con';
# there is a poosible bug in updating scrren
# values are experimentell
# update = 0, use readingsBulkUpdate  for all lines
# update = 1 use readingsSingleUpdate for first line
# update = 2 use readingsSingleUpdate for all lines, causes a lot of traffic in fhem!!!

my $update = 0;

# 0...4  = 5 lines
# dont forget adapting definition of your readingsGroup!
my $maxlines = 4;

my $monitor_type = 'all';


# end default attributes
##################################

my %sets = (
'monitor-type' => 'all,incoming,outgoing,missed-call,all-after-disconnect',
'clear' => ''
);


sub myUtilsTM_Initialize($$)
{
TM_Initialize($_[0],$_[1]);
}
################################################################


sub TM_Initialize($$)
{
$modules{TM}{LOADED} = 1;
my $hash = $modules{TM};
$hash->{SetFn}     = "TM_Set";
$hash->{DefFn}     = "TM_Define";
$hash->{UndefFn}   = "TM_Undef";
$hash->{NotifyFn}  = "TM_Notify";
$hash->{AttrFn}    = "TM_Attr";
$hash->{AttrList}  = "alias disable:0,1 line-filter maxlines monitor-type:all,incoming,outgoing,missed-call,all-after-disconnect room icon group symbol-incoming symbol-incoming-noconnect symbol-outgoing symbol-outgoing-noconnect symbol-answering-machine symbol-connected update:0,1,2 method-connect method-call method-ring method-disconnect method-AB verbose:0,1,2,3,4,5,6";

return undef;
} # end sub TM_initialize
########################


sub TM_Define($$)
{
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
my $retval = undef;
my $name = $a[0];

if(!defined($a[2]))
{
$retval = "TM_define: you must specify a FB_CallMonitor object for using TM";
return $retval;
}

if (!defined($defs{$a[2]}) || ($defs{$a[2]}->{TYPE} ne 'FB_CALLMONITOR'))
{
$retval = "TM_Define: $a[2] does not exists or ist not of type FB_CALLMONITOR";
return $retval;
}

$hash->{FB} = $a[2];
$hash->{STATE} = 'initialized';
return undef;
} # end sub TM_Define
###############################


sub TM_Undef($$)
{                     
my ( $hash, $arg ) = @_;       
return undef;                 
} # end TM_Undef
################################

sub TM_Set($@)
{
my ($hash, @a) = @_;

my ($name,$rd,$val) = @a;

return "\"TM set\" no set value specified" if((int(@a) < 2) && ($rd ne '?'));
$val = 0 if ($rd eq '?');

if ($rd eq 'monitor-type')
{
my %clist;
foreach my $k (split(',',$sets{$rd})) {$clist{$k} = ''; }
return "TM set monitor-type: $val must be of ".$sets{$rd} if(!exists($clist{$val}));
readingsSingleUpdate($hash,$rd,$val,1);
$attr{$name}{'monitor-type'} = $val;
}
elsif ($rd eq 'clear')
{
my ($i,$j);
my $rhash = $hash->{READINGS};
for ($i=AttrVal($name,"maxlines",$maxlines); $i>=0; $i--)
{
foreach $j ('A'..'F')
{
delete($rhash->{$j.$i});
} # end j
} # end i
} # if clear
else
{
my @cList;
foreach my $k (sort keys %sets)
{
my $opts = undef;
$opts = $sets{$k};
if (defined($opts))
{
push(@cList,$k . ':' . $opts);
}
else
{
push (@cList,$k);
}
} # end foreach

return "Unknown argument $rd, choose one of " . join(" ", @cList);
} # end else -> error handling

return undef;
} # end sub TM_set
############################


sub TM_Store($)
{
my ($hash) = @_;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time());
my $ID = $hash->{callID};
my $name = $hash->{NAME};
my $linefilter = AttrVal($name,'line-filter',undef);
Log3($name,4,"TM_Store: linefilter $linefilter");

if($linefilter)
{
if( $linefilter =~ m/^{.*}$/ )
{
my $lf = eval $linefilter;
if( $lf &&(ref($lf) eq 'HASH'))
{
$linefilter = $lf ;
Log3($name,4,"TM_Store: filter as hash: $linefilter");
} # if valid
else
{
Log3($name,2,"TM_Store: $linefilter (line-filter) is not a valid hash");
$linefilter = undef;
} # not a valid hash

}
else # list of filters
{
my %lines;
foreach my $l ( split("[ \t,][ \t,]*",$linefilter)) {$lines{$l} = $l; }
$linefilter = \%lines;
Log3($name,4,"TM_Store: linefilter as list $linefilter");
} # list of lines

} # if $linefilter

# linefilter is undef, if no filter or
# hash contains valid internal_number
my $innumber = $hash->{mem}{"internal_number"};

if(!defined($linefilter)  ||  exists($linefilter->{$innumber}))
{
$hash->{callmem}{$ID} = {};
my $rhash = $hash->{callmem}{$ID};
my $dir = ($hash->{mem}{"direction"} eq 'incoming') ? AttrVal($name,'symbol-incoming',$incoming) : AttrVal($name,'symbol-outgoing',$outgoing);
$rhash->{A} = $dir;
$rhash->{B} = sprintf("%02d:%02d %02d.%02d.%4d",$hour,$min,$mday,($mon+1),($year+1900));
$rhash->{C} = $hash->{mem}{"external_name"};
$rhash->{D} = $hash->{mem}{"external_number"};
$rhash->{E} = (defined($hash->{mem}{"call_duration"})) ? $hash->{mem}{"call_duration"}: AttrVal($name,'symbol-connected',$connected);
# default call_duration, set after disconnect
$rhash->{F} = $ID;
if($linefilter)
{
$rhash->{G} = $linefilter->{$innumber};
}
else
{
$rhash->{G} = $innumber;
}
delete($hash->{mem});
return 1; # valid call
} # if linefilter
else
{
Log3($name,3,"TM_Store: calls from $innumber are not store, not in attr line-filter");
delete($hash->{mem});
return undef;
} #  if filtered out

return undef;
} # end sub TM_Store
############################################

sub TM_UpdateTable($)
{
my ($hash) = @_;
my $name = $hash->{NAME};
my $ID = $hash->{callID};
my $up = AttrVal($name,'update',$update);

Log3($name,4,"TM_UpdateTable: ID $ID");

# shiften der alten Inhalte
my $tt;
my ($i,$j);
my $rhash = $hash->{READINGS};
if($up <= 1)
{
readingsBeginUpdate($hash);

for ($i=AttrVal($name,"maxlines",$maxlines); $i>0; $i--)
{
foreach $j ('A'..'G')
{
my $k = $j . ($i-1);
$tt = undef;
$tt = $rhash->{$k}{VAL} if(exists($rhash->{$k}));
next if(!defined($tt));
readingsBulkUpdate($hash,$j.$i,$tt,1);
} # end j
} # end i
readingsEndUpdate($hash,1);
} # if BulkUpdate
else
{
for ($i=AttrVal($name,"maxlines",$maxlines); $i>0; $i--)
{
foreach $j ('A'..'G')
{
my $k = $j . ($i-1);
$tt = undef;
$tt = $rhash->{$k}{VAL} if(exists($rhash->{$k}));
next if(!defined($tt));
readingsSingleUpdate($hash,$j.$i,$tt,1);
} # end j
} # end i
} # else SingleUpdate

# first line with new values
if($up> 0)
{
foreach my $k ('A'..'G')
{
readingsSingleUpdate($hash,$k."0",$hash->{callmem}{$ID}{$k},1);
}
} # if SingleUpdate
else
{
readingsBeginUpdate($hash);
foreach my $k ('A'..'G')
{
readingsBulkUpdate($hash,$k."0",$hash->{callmem}{$ID}{$k},1);
}
readingsEndUpdate($hash, 1);
} # if BulkUpdate

return undef;
} # end TM_update
###########################

sub TM_UpdateValue($$$$)
{
my ($hash,$ID,$col,$val) = @_;
my $name = $hash->{NAME};
my $rhash = $hash->{READINGS};
Log3($name,5,"TM_UpdateValue: args callID: $ID col: $col val: $val");
for (my $i = 0;  $i < AttrVal($name,'maxlines',$maxlines);$i++)
{
my $rdid= 'F' . $i; # stored callID
Log3($name,6,"TM_updateValue: in loop i: $i callID: $rhash->{$rdid}{VAL}");
if(defined($rhash->{$rdid}) && $rhash->{$rdid}{VAL} eq $ID)
{
my $rd = $col . $i;
Log3($name,4,"TM_UpdateValue: updateingindex $rdid $rd $val");
if(($col eq 'A') && ($val eq '0'))
{
$val = ($rhash->{$rd}{VAL} eq AttrVal($name,'symbol-incoming',$incoming)) ? AttrVal($name,'symbol-incoming-noconnect',$incoming_noconnect) : AttrVal($name,'symbol-outgoing-noconnect',$outgoing_noconnect);
}

readingsSingleUpdate($hash,$rd,$val,1);

return undef;
} # if update
} # end i

Log3($name,1,"TM_updateValue: not found col $col id $ID val $val");
return "TM_UpdateValue: Error - ID not found";
} # end TM_UpdateValue
##########################


sub TM_Notify($$)
{
my ($hash,$d) = @_;
return "TM_notify: hash not defiened" if (!defined($hash));

my $name = $hash->{NAME};
return undef if(AttrVal($name, "disable", undef));
# Abbruch wenn das Attribut disable gesetzt
my $fb = $d->{NAME};
if ($fb ne $hash->{FB})
{
return undef;
} # if not fb

my $rhash =  $d->{CHANGED};
my $max = int(@$rhash);
# number of events / changes

for (my $i = 0; $i < $max; $i++)
{
my $s = $d->{CHANGED}[$i];
TM_Monitor($hash,$s);
} # end for i

}  # end sub TM_Notify
#####################################

sub TM_Proc($$)
{
my ($hash,$proc) = @_;
my $name = $hash->{NAME};

my $external_name = $hash->{mem}{'external_name'};
my $external_number = $hash->{mem}{'external_number'};
my $internal_number = $hash->{mem}{'internal_number'};
my $internal_connection = $hash->{mem}{'internal_connection'};

my $EXTERNAL_NAME = $external_name,
my $EXTERNAL_NUMBER = $external_number;
my $INTERNAL_NUMBER = $internal_number;
my $INTERNAL_CONNECTION = $internal_connection;

$proc =~s/\%EXTERNAL_NAME/$external_name/g;
$proc =~s/\%EXTERNAL_NUBER/$external_number/g;
$proc =~s/\%INTERNAL_NUMBER/$internal_number/g;
$proc =~s/\%INTERNAL_CONNECTION/$internal_connection/g;

if($proc =~ m/^{.*}$/)
{
$proc =~s/\$EXTERNAL_NAME/"$external_name"/g;
$proc =~s/\$EXTERNAL_NUMBER/"$external_number"/g;
$proc =~s/\$INTERNAL_NUMBER/"$internal_number"/g;
$proc =~s/\$INTERNAL_CONNECTION/"$internal_connection"/g;
} # if perl

Log3($name,3,"TM_Proc:  action $proc");

fhem($proc);

} # end sub TM_Proc
########################

sub TM_Monitor($$)
{
my ($hash,$Ev) = @_;
my $name = $hash->{NAME};

if(!defined($hash))
{
Log(1,"TM_Monitorhash nicht gefunden");
return "TM: $hash not found";
} # if error

my ($event,$arg) = split (':',$Ev);
$arg = rtrim(ltrim($arg));
$event = ltrim(rtrim($event));

my $proc;

if ($event eq "event")
{
$hash->{stat} = $arg;
Log3($name,3,"\nTM_Monitor: status:  $arg");
return undef;
} # end if event
Log3($name,4,"TM_Monitor: stat: $hash->{stat} event: $event arg: $arg");

# store all subevents
$hash->{mem}{$event} = $arg;

if ($hash->{stat} eq "ring")
{
if ($event eq "call_id")
{
$hash->{callID} = $arg;
Log3($name,3,"Anruf (ring) von $hash->{mem}{'external_name'} $hash->{mem}{'external_number'} callID: $arg");

# hier koennen wir eine anrufgesteuerte Aktion starten
$proc = AttrVal($name,'method-ring',undef);

if($proc)
{
TM_Proc($hash,$proc);
} # end method-ring

my $mot = AttrVal($name,'monitor-type',$monitor_type);
Log3($name,5,"Ring vor TM_UpdateTable mot $mot");

if(($mot eq 'all') || ($mot eq 'incoming'))
{
TM_UpdateTable($hash) if(TM_Store($hash));
} # if mode
} # end if callid
return undef;
} # end if ring events

if ($hash->{stat} eq "connect")
{
# handle answering machine
if (($event eq"internal_connection") &&
($arg =~m/Answering_Machine_.*/))
{
    $proc = AttrVal($name,'method-AB',undef);

if($proc)
{
TM_Proc($hash,$proc);
} # end method-AB
my (undef,undef,$abnr) = split('_',$arg);
$hash->{mem}{ab} = $abnr;
Log3($name,3,"Anrufbeantworter Nr. $abnr angesprochen");
return undef;
} # end if internal_connection

if ($event eq "call_id")
{
$hash->{callID} = $arg;
# method-connect
$proc = AttrVal($name,'method-connect',undef);
if($proc)
{
TM_Proc($hash,$proc);
} # end method-connect

if (exists($hash->{mem}{ab}) && $hash->{mem}{ab} > 0)
{
$hash->{callmem}{$arg}{A} = AttrVal($name,'symbol-answering-machine',$ab);
$hash->{callmem}{$arg}{A} .= $hash->{mem}{ab} if ($hash->{mem}{ab} > 1);
if(AttrVal($name,'monitor-type',$monitor_type) =~m/(all|incoming)/)
{
# update value in table
TM_UpdateValue($hash,$arg,'A',$hash->{callmem}{$arg}{A} );
Log3($name,3,"in/out symbol in table change to Answering Machine");
} # update AB,   

} # if A set to AB
delete($hash->{mem}{ab});
} # end if  callID
return undef;
} # end if connect

if ($hash->{stat} eq "call")
{
$hash->{mem}{$event} = $arg;

# method-call
$proc = AttrVal($name,'method-call',undef);
if($proc)
{
TM_Proc($hash,$proc);
} # end method-call

if ($event eq "call_id")
{
$hash->{callID} = $arg;
my $mot = AttrVal($name,'monitor-type',$monitor_type);
Log3($name,5,"Call vor TM_UpdateTable mot $mot");
if(($mot eq 'all') | ($mot eq 'outgoing'))
{
TM_UpdateTable($hash) if(TM_Store($hash));
} # if mode
} # end if callid
return undef;
} # end if call event


if ($hash->{stat} eq "disconnect")
{

if ($event eq "call_duration")
{
$hash->{mem}{"call_duration"} = sprintf("%02d:%02d", ($arg/60),$arg%60);
return undef;
} # if call_duration

if ($event eq "call_id")
{
$hash->{callID} = $arg;
$hash->{callmem}{$arg}{E} = $hash->{mem}{"call_duration"};
$proc = AttrVal($name,'method-disconnect',undef);

if($proc)
{
TM_Proc($hash,$proc);
} # end method-disconnect

my $mot = AttrVal($name,'monitor-type',$monitor_type);
Log3($name,5,"Disconnect vor TM_UpdateTable mot $mot");

if($mot eq 'missed-call')
{
if(TM_Store($hash))
{
my $aktsym = $hash->{callmem}{$arg}{A};
my $aktdur = $hash->{callmem}{$arg}{E};
Log3($name,5,"TM_Monitor: $mot aktsym: $aktsym aktdur: $aktdur");

if( ( ($aktsym eq AttrVal($name,'symbol-incoming',$incoming)) && ($aktdur  eq '00:00')) || ($aktsym eq AttrVal($name,'symbol-answering-machine',$ab))  )
{
# korrekt incoming symbol
$hash->{callmem}{$arg}{A} = AttrVal($name,'symbol-incoming-noconnect',$incoming_noconnect) if($aktdur eq '00:00');
Log3($name,5,"mode = missed-call callID: $arg connnection in mem: $hash->{callmem}{$arg}{A} duration: $hash->{callmem}{$arg}{E} ");

TM_UpdateTable($hash);
} # if TM_Store / line-filter
delete($hash->{callmem}{$arg});
delete($hash->{mem});
return undef;
}
} # if missed-call
elsif($mot eq 'all_after_disconnect')
{
Log3($name,5,"disconnect mode: all_after_disconnect");
if(TM_Store($hash))
{
TM_UpdateTable($hash);
delete($hash->{callmem}{$arg});
delete($hash->{mem});
} # if TM_Store / line-filter
} # all_after_disconnect
else
{
# update value call_duration in table
TM_UpdateValue($hash,$arg,'E',$hash->{callmem}{$arg}{E} );
# update symbols for in/outgoing with no connections
TM_UpdateValue($hash,$arg,'A',0 ) if($hash->{callmem}{$arg}{E} =~m/(<->|00:00)/);

} # update table for duration
delete($hash->{callmem}{$arg});
delete($hash->{mem});
return undef;
} # end if callid
} # end if disconnect
return undef;
} #end sub TM_Monitor
#####################################

sub TM_Attr(@)
{
my ($cmd,$name,$aName,$aVal) = @_;
my $hash = $defs{$name};

return "\n TM_Attr: " .$name  . " does not exits" if (!defined($hash));

# $cmd can be "del" or "set"
# $name is device name
# aName and aVal are Attribute name and value
if ($cmd eq "set")
{

if ($aName eq 'disable')
{
$hash->{STATE} = ($aVal == 0)?'initialized':'disabled';
}

if ($aName eq 'monitor-type')
{
return TM_Set($hash,$name,$aName,$aVal);
} # monitor-type
else
{
my @attrs = split(' ',$modules{TM}->{AttrList});
my %ats;
for(my $i = 0; $i < int(@attrs); $i++)
{
my ($a,$v) = split(':',$attrs[$i]);
$ats{$a} = $v;
} # end i

if(!exists($ats{$aName}))
{
return "TM_Attr: $aName must at least one of: ".join(',',sort keys %ats);
} # error handling

} # if else

} # end if set
return undef;
} # end ssub TM_Attr
######################

1;


und diesen Einträgen in der fhem.cfg
######################################################################################################
##################################### Anrufmonitor Callmonitor #######################################
######################################################################################################
define FB7390 FB_CALLMONITOR 192.168.1.1
attr FB7390 local-area-code 0241
attr FB7390 reverse-search all
attr FB7390 reverse-search-cache 1
attr FB7390 reverse-search-cache-file /opt/fhem/callmoncache.txt
attr FB7390 reverse-search-phonebook-file ./log/Fritz_Box_Telefonbuch.xml
attr FB7390 room System
attr FB7390 verbose 0
#
define CallMon TM FB7390
attr CallMon maxlines 4
attr CallMon monitor-type all
attr CallMon room System
attr CallMon symbol-answering-machine AB
attr CallMon symbol-connected connected
attr CallMon symbol-incoming incoming
attr CallMon symbol-incoming-noconnect incoming_noconnect
attr CallMon symbol-outgoing outgoing
attr CallMon symbol-outgoing-noconnect outgoing_noconnect
attr CallMon update 2
#
#
define Anrufliste readingsGroup <Pos>,<Art>,<Datum>,<Name>,<Nummer>,<Dauer>\
CallMon:A0,B0,C0,D0,E0 CallMon:A1,B1,C1,D1,E1 CallMon:A2,B2,C2,D2,E2 CallMon:A3,B3,C3,D3,E3 CallMon:A4,B4,C4,D4,E4
attr Anrufliste mapping {'CallMon' => '{sprintf("%d.",$ROW-1);;;;}'}
attr Anrufliste nameStyle style="font-weight:bold"
attr Anrufliste noheading 0
attr Anrufliste room Telefon
attr Anrufliste valueIcon { 'A0.incoming' => 'phone_ring_in@green', 'A0.incoming_noconnect' => 'phone_ring_in@red', 'A0.outgoing' => 'phone_ring_out@green', 'A0.outgoing_noconnect' => 'phone_ring_out@red', 'A0.AB' => 'phone_answersing@blue', 'E0.connected' => 'phone_ring@yellow', 'A1.incoming' => 'phone_ring_in@green', 'A1.incoming_noconnect' => 'phone_ring_in@red', 'A1.outgoing' => 'phone_ring_out@green', 'A1.outgoing_noconnect' => 'phone_ring_out@red', 'A1.AB' => 'phone_answersing@blue', 'E1.connected' => 'phone_ring@yellow', 'A2.incoming' => 'phone_ring_in@green', 'A2.incoming_noconnect' => 'phone_ring_in@red', 'A2.outgoing' => 'phone_ring_out@green', 'A2.outgoing_noconnect' => 'phone_ring_out@red', 'A2.AB' => 'phone_answersing@blue', 'E2.connected' => 'phone_ring@yellow', 'A3.incoming' => 'phone_ring_in@green', 'A3.incoming_noconnect' => 'phone_ring_in@red', 'A3.outgoing' => 'phone_ring_out@green', 'A3.outgoing_noconnect' => 'phone_ring_out@red', 'A3.AB' => 'phone_answersing@blue', 'E3.connected' => 'phone_ring@yellow', 'A4.incoming' => 'phone_ring_in@green', 'A4.incoming_noconnect' => 'phone_ring_in@red', 'A4.outgoing' => 'phone_ring_out@green', 'A4.outgoing_noconnect' => 'phone_ring_out@red', 'A4.AB' => 'phone_answersing@blue', 'E4.connected' => 'phone_ring@yellow' }


Hoffe das hilft weiter