Fritzbox call overview

All, this is my first post and I have been playing around with Openhab 2 and HabPanel since 2 weeks now. Thank you all for providing this great scripts and tweaks. Please let me briefly share how I tweaked the scripts and rules to have the last calls read into items and presentend them in a template:

(1) I took the initial script posted at the start of this thread and added one line at the end to create a short file with 10 lines only. Then I wrote a 1-liner called extrac.sh which gives back only one line of the caller log, by providing the line number, e.g. “./extract.sh 5” gives you call number 5 from the short file.

grep “^1|^2|^3|^4” -m 10 /etc/openhab2/persistence/fritzcalls.txt > /etc/openhab2/persistence/fritzcalls-short.txt

extract.sh:

#!/bin/bash
head -$1 /etc/openhab2/persistence/fritzcalls-short.txt | tail -1 | grep ''

(2) Items definition:

Group gFritzCalls

String fritzCall1 “Call 1” (gFritzCalls)
String fritzCall2 “Call 2” (gFritzCalls)
String fritzCall3 “Call 3” (gFritzCalls)
String fritzCall4 “Call 4” (gFritzCalls)
String fritzCall5 “Call 5” (gFritzCalls)
String fritzCall6 “Call 6” (gFritzCalls)

(3) Rules: obviously the one getting (and shortening) the Fritz caller log. And then the one raeding the files into the above items by going through the group:

rule “Update calllist”
when
Time cron “0 0/2 * ? * * *” // every two minutes
then
logInfo(“Fritzbox”," Calllist wird neu geladen")
executeCommandLine("/etc/openhab2/scripts/callmonitor.sh")

end

rule “Update callitems”
when
Time cron “0 0/5 * * * ?”
then

		val index = 1 
		gFritzCalls.members.forEach [ item | 
		postUpdate(item,executeCommandLine("/etc/openhab2/scripts/extract.sh " + index, 1000))
		index++
		]

end

(4) Template in HabPanel, having the phone icons stored as fritz-1.gif etc. representing the call type from the call-list. Splitting the items by “;”

<table class="table-standard">
  <caption>Anrufe</caption>
  <tr>
  <th>Typ</th>
  <th>Datum</th>
  <th>Name</th>
  <th>Nummer</th>
  <th>Dauer</th>
  </tr>
<tr ng-repeat="item in itemsInGroup('gFritzCalls')" align="left" cellpadding="2px" border="none">
    <td><img src="/static/icons/own/fritz-{{itemValue(item.name).split(';')[0]}}.gif"</td>
  <td>{{itemValue(item.name).split(';')[1]}}</td>
  <td>{{itemValue(item.name).split(';')[2]}}</td>
  <td>{{itemValue(item.name).split(';')[3]}}</td>
  <td>{{itemValue(item.name).split(';')[6]}}</td>
  </tr>

(5) Result: > I am very happy with the result!

2 Likes

Did someone use this script in HABpanel without the matrix theme?

I want to have it in a nice widget there, but I do not really know how :confused:

Greetings

Hi StefanJ, all

I did like you approach of the extract.sh…and the rule passing it to the 6 last caller item.
Took me a bit to get it to run as I am not familiar with Linux and these script languages.

So the basics are now running and the 6 call items are properly populated every 5Min…whilst the list is pulled from the fritzbox every 2Min…

Now coming the my 2 issues with habpanel. I do use OH2.2 displaying on GoogleChrome.
Created the icons on /etc/openhab2/icons/classic as I don’t know where the “static” folder is located.

Problem #1
Icons do not display. I tried .svg , .png and .gif … none of them are displayed. Do they need to be of a specific size e.g.48x48 or so ? Mine are 200x200 I think… Any suggestions welcome.

Problem #2
Cellspacing does not work on the table . it looks crap compared to yours…Tried several on cellspacing and cellpadding but I am an angularJS rookie. Any suggestions welcome too

See result picture and current widget code below…

<table class="table-standard">
  <caption>Anrufe</caption>
  <tr>
  <th>Typ</th>
  <th>Datum</th>
  <th>Name</th>
  <th>Nummer</th>
  <th>Dauer</th>
  </tr>
<tr ng-repeat="item in itemsInGroup('ZZ_FritzCalls')" align="left" cellpadding="2px" border="none">
    <td><img src="/etc/openhab2/icons/classic/fritz-{{itemValue(item.name).split(';')[0]}}.svg"</td>
  <td>{{itemValue(item.name).split(';')[1]}}</td>
  <td>{{itemValue(item.name).split(';')[2]}}</td>
  <td>{{itemValue(item.name).split(';')[3]}}</td>
  <td>{{itemValue(item.name).split(';')[6]}}</td>
  </tr>

Why you don’t listen to the CallMonitor of the Fritzbox … Downloading every Minute is Bad :wink:

This is my very old Perl Script that listen to the Internal CallMonitor of the Fritzbox

The complete Script are to big … so a paste only the Listening Part :wink:

#!/usr/bin/perl -w

#Version 0.8
#written by eiGelbGeek 2017

#FritzBox_IP
my $FRITZBOX="192.168.20.1"; 

#Hier wird der Fritzbox Anrufmonitor belauscht
my $sock = new IO::Socket::INET (
        PeerAddr => $FRITZBOX,
        PeerPort => '1012',
        Proto => 'tcp'
        );
        die "Could not create socket: $!\n" unless $sock;


while(<$sock>)
        {            
            if ($_ =~ /RING/)
            {
               #... Do something
            }
            
            if ($_ =~ /CALL/)
            {
                #... Do something
            }
            
            if ($_ =~ /CONNECT/)
            {
               #... Do something
            }
            
            if ($_ =~ /DISCONNECT/)
            {
                #... Do something
            }
        }

Hi Kevin,

whats the difference between a perl script that is permanently doing a while loop to a rule that is triggered every 2 min ? Is the rule more CPU intensive ?..

For incoming calls I could trigger it via the Item fbox_Ringing changed from OFF to ON rule (see below) but then I guess I will run into the same issue. How do I get access to the last 6 calls without downloading the caller list?

Is there a possibility of incCall.getValue(1), incCall.getValue(2), incCall.getValue(2), incCall.getValue(3) …etc.? However this one is only triggered when I receive a call, or ?

rule "Eingehender Anruf"
when
  Item fbox_Ringing changed from OFF to ON
then
	// Daten des CallType auslesen
	val incCall = fbox_IncomingCall.state as StringListType
	val callerNumber = incCall.getValue(1)
	
	// Die Variablen anlegen und mit der Nummer bzw. Namen des Anrufers füllen
	LastCallName   = fbAnrufName.state.toString()
	
	// Die eigene Rufnummer aus der Variable entfernen
	LastCallName = LastCallName.removeStart("999999##")                   //(99999=your tel #no)
	
	// Prüfen ob der Anrufer unbekannt ist
	if(LastCallName.startsWith("Name not found for")) {
		// Den Namen mit Unbekannt füllen
		LastCallName = "Unbekannt"
	}
	// Die Daten in die Items eintragen
	postUpdate(fbox_LastNumber, callerNumber)
	postUpdate(fbox_LastName, LastCallName)
	logInfo("RuleLastCall", "Der Anruf von " + callerNumber + " (" + LastCallName + ")" + " wurde als Letzter Anrufer gespeichert.")
end

The UI display problem I managed in the meanwhile with “cellpadding=“25px” cellspacing=“25px” border=“none””

Hi, thank you for that tutorial and all your work!
I changed the script for me to use items (updated via REST api). By that, I do not need the extra html file and also not the habpanel-reload.js for the reload. And for me it get’s easier to understand what happens :smiley:
Another advantage (and the reason I changed it) is that I can use my standard widget with 4 rows, which you can see here:

New messages are shown by a blinking icon, playback works and after playing, the icon stops blinking and gets grey.
I only want to show the missed calls and the recorded messages (the last 4 events).
Here are the items:

String AbMessage
Call   fboxIncomingCall    "Incoming call: [%1$s to %2$s]"     {fritzboxtr064="callmonitor_ringing" } 
Call   fboxOutgoingCall    "Outgoing call: [%1$s to %2$s]"     {fritzboxtr064="callmonitor_outgoing" }
String Anruf_1_Name "Anruf 1 Name [%s]"
String Anruf_2_Name "Anruf 2 Name [%s]"
String Anruf_3_Name "Anruf 3 Name [%s]"
String Anruf_4_Name "Anruf 4 Name [%s]"
String Anruf_1_DatumZeit "Anruf 1 Zeit [%s]"
String Anruf_2_DatumZeit "Anruf 2 Zeit [%s]"
String Anruf_3_DatumZeit "Anruf 3 Zeit [%s]"
String Anruf_4_DatumZeit "Anruf 4 Zeit [%s]"
String Nachricht_1_Datei "Nachricht 1 Datei [%s]"
String Nachricht_2_Datei "Nachricht 2 Datei [%s]"
String Nachricht_3_Datei "Nachricht 3 Datei [%s]"
String Nachricht_4_Datei "Nachricht 4 Datei [%s]"
Switch Nachricht_1_Neu "Nachricht 1 Neu"
Switch Nachricht_2_Neu "Nachricht 2 Neu"
Switch Nachricht_3_Neu "Nachricht 3 Neu"
Switch Nachricht_4_Neu "Nachricht 4 Neu"

Here’s the script:

#!/bin/bash
#
# Check and adapt the following environment variables to your needs:

# fritzbox URL for tr-064 calls
BASEURL="http://fritz.box:49000"
# user:password used to authenticate
USER="user:pw"
# openhab directory containing sounds subdirectory
OPENHAB_DIR=/etc/openhab2
# temporary directory
TMP=/tmp

# number of calls to show
COUNT=40
# number of answering machines
TAM_COUNT=1


### Function definitions ###

function getElement() {
  text=$1
  name=$2
 
  echo "$text" | sed -e "s/.*<$name>//" -e "s#</$name>.*##"
}

function arrayContains() {
  local e
  for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
  return 1
}

function soapCall() {

  URL=$1
  URN=$2
  ACTION=$3
  ELEMENT=$4
  PARAMETERS=${5:-}

  cat >$TMP/soapEnvelope-$$ <<EOF
<?xml version='1.0' encoding='utf-8'?>
<s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'>
 <s:Body>
  <u:$ACTION xmlns:u='$URN'>${PARAMETERS}</u:$ACTION>
 </s:Body>
</s:Envelope>
EOF

  RESPONSE=$(curl -s --anyauth --user $USER $URL -H 'Content-Type: text/xml; charset="utf-8"' -H "SoapAction:$URN#$ACTION" --data @$TMP/soapEnvelope-$$)

  rm $TMP/soapEnvelope-$$

  if [ "x${ELEMENT}x" != "xx" ]; then
    echo $RESPONSE | grep $ELEMENT | sed -e "s/.*<$ELEMENT>//" -e "s#</$ELEMENT>.*##"
  else 
    echo $RESPONSE
  fi
}

function removeTamMessages() {
  rm $TMP/tam${1:-[0-9]}.xml 2>/dev/null
}

function downloadMissingTamMessages() {
  tamidx=0
  while [ $tamidx -lt $TAM_COUNT ]; do 
    if [ ! -f $TMP/tam${tamidx}.xml ]; then
      echo -n "downloading message list for TAM $tamidx..."
      URL=$(soapCall "$BASEURL/upnp/control/x_tam" "urn:dslforum-org:service:X_AVM-DE_TAM:1" GetMessageList NewURL "<NewIndex>${tamidx}</NewIndex>")
	  wget --quiet -O - $URL | awk '/<Message>/,/<\/Message>/ { printf $0 } /<\/Message>/ { print }'>$TMP/tam${tamidx}.xml 
      echo "$(stat -c%s $TMP/tam${tamidx}.xml) bytes."
    fi

    tamidx=$(expr $tamidx + 1)
  done
}

function getTamMsg() {
  mdate=$1

  for tamxml in $TMP/tam${2:-[0-9]}.xml; do
    while read message; do
      date=$(getElement "$message" Date)

      if [ "${date}" == "${mdate}" ]; then
        echo "$message"
        return 0
      fi
    done < $tamxml
  done

  return 1
}

function updateCallOverview() {
  downloadMissingTamMessages

  URL=$(soapCall "$BASEURL/upnp/control/x_contact" "urn:dslforum-org:service:X_AVM-DE_OnTel:1" GetCallList NewCallListURL)

  callidx=0
  echo -n "downloading call list..."
  wget --quiet -O - $URL | grep Call > $TMP/calls.xml
  echo "$(stat -c%s $TMP/calls.xml) bytes."

  zaehler=0
  while read call; do
    type=$(getElement "$call" Type)
    caller=$(getElement "$call" Caller)
    called=$(getElement "$call" Called)
    name=$(getElement "$call" Name)
    date=$(getElement "$call" Date)
    duration=$(getElement "$call" Duration)
    path=$(getElement "$call" Path)

    message=$(getTamMsg "$date")

    [ "x${message}x" != "xx" ] && isTamMsg=1 || isTamMsg=0
    [ "x$(getElement "$message" New)x" == "x1x" ] && isNewTamMsg=1 || isNewTamMsg=0

    echo "processing call $date (isTamMsg=$isTamMsg isNewTamMsg=$isNewTamMsg)..."

    if [ "$path" == "$call" ]; then
      path=""

      # in case this call has no associated recording, check if there is a TAM message with the
      # same time and skip this call 
      if [ $isTamMsg -eq 1 ]; then
        echo "skipped (also has a TAM message)."
        continue
      fi

    else 
      soundfile=${OPENHAB_DIR}/sounds/`basename $path`.wav
	  soundfilename=`basename $path`

      # collect all current soundfiles to be able to delete the old ones
      files[callidx]=$soundfile

      if [ ! -f $soundfile ]; then
        echo -n "fetching ${soundfile}..."

        curl -o $soundfile "${BASEURL}$path&$SID"

        echo "$(stat -c%s $soundfile) bytes."
      fi
	  
    fi

    # 1 incoming
    # 2 missed
    # 3 outgoing
    # 9 active incoming
    #10 rejected incoming
    #11 active outgoing 
    if [ "x${path}x" != "xx" ]; then
	  zaehler=$((zaehler+1))
      if [ $isNewTamMsg -eq 1 ]; then
		curl -s -X PUT --header "Content-Type: text/plain" --header "Accept: application/json" -d "ON" "http://openhabianpi:8080/rest/items/Nachricht_${zaehler}_Neu/state"
	  else
		curl -s -X PUT --header "Content-Type: text/plain" --header "Accept: application/json" -d "OFF" "http://openhabianpi:8080/rest/items/Nachricht_${zaehler}_Neu/state"
	  fi
	  curl -s -X PUT --header "Content-Type: text/plain" --header "Accept: application/json" -d "$soundfilename" "http://openhabianpi:8080/rest/items/Nachricht_${zaehler}_Datei/state"
	  curl -s -X PUT --header "Content-Type: text/plain" --header "Accept: application/json" -d "${name:-$caller}" "http://openhabianpi:8080/rest/items/Anruf_${zaehler}_Name/state"
	  curl -s -X PUT --header "Content-Type: text/plain" --header "Accept: application/json" -d "$date" "http://openhabianpi:8080/rest/items/Anruf_${zaehler}_DatumZeit/state"
    elif [ $type -eq 2 ]; then
	  zaehler=$((zaehler+1))
	  curl -s -X PUT --header "Content-Type: text/plain" --header "Accept: application/json" -d "OFF" "http://openhabianpi:8080/rest/items/Nachricht_${zaehler}_Neu/state"
	  curl -s -X PUT --header "Content-Type: text/plain" --header "Accept: application/json" -d "none" "http://openhabianpi:8080/rest/items/Nachricht_${zaehler}_Datei/state"
	  curl -s -X PUT --header "Content-Type: text/plain" --header "Accept: application/json" -d "${name:-$caller}" "http://openhabianpi:8080/rest/items/Anruf_${zaehler}_Name/state"
	  curl -s -X PUT --header "Content-Type: text/plain" --header "Accept: application/json" -d "$date" "http://openhabianpi:8080/rest/items/Anruf_${zaehler}_DatumZeit/state"
    fi
    
    callidx=$(expr $callidx + 1)
    if [ $callidx -eq $COUNT ]; then
      break
    fi
    if [ $zaehler -eq 4 ]; then
	  break
	fi
  done < $TMP/calls.xml
  rm $TMP/calls.xml
  echo $zeile

  # remove old files
  for file in ${OPENHAB_DIR}/sounds/rec.[0-9].[0-9][0-9][0-9].wav; do
    arrayContains "$file" "${files[@]}"
    if [ $? -ne 0 -a -f $file ]; then
      rm ${file} 2>/dev/null
      echo "removed old recording $file."
    fi 
  done
}

function mark() {
  file=${OPENHAB_DIR}/sounds/$1

  tam=$(echo $1 | cut -d "." -f 2)
  index=$(echo $1 | cut -d "." -f 3)

  soapCall "$BASEURL/upnp/control/x_tam" "urn:dslforum-org:service:X_AVM-DE_TAM:1" MarkMessage dummy "<NewIndex>$tam</NewIndex><NewMessageIndex>$index</NewMessageIndex>"
}

### the fun starts here ###
source `dirname $0`/lockRoutines
exlock_now || exit 1

echo "lock obtained"

SID=$(soapCall "$BASEURL/upnp/control/deviceconfig" "urn:dslforum-org:service:DeviceConfig:1" "X_AVM-DE_CreateUrlSID" NewX_AVM-DE_UrlSID)

removeTamMessages

if [ $# -eq 1 -a "$1" == "update" ]; then
  updateCallOverview
elif [ $# -eq 2 -a "$1" == "mark" ]; then
  mark $2
  updateCallOverview
else
  echo "`basename $0` update | mark <file>"
  exit 1
fi

removeTamMessages

And I needed to change the “play recorded call” rule:

rule "Play recorded call"
when
   Item AbMessage received command
then
   if (receivedCommand.toString == "1") {
      playSound(Nachricht_1_Datei.toString)
	  executeCommandLine("/etc/openhab2/scripts/fritzbox.sh mark " + Nachricht_1_Datei.toString)
   }
   if (receivedCommand.toString == "2") {
      playSound(Nachricht_2_Datei.toString)
	  executeCommandLine("/etc/openhab2/scripts/fritzbox.sh mark " + Nachricht_2_Datei.toString)
   }
   if (receivedCommand.toString == "3") {
      playSound(Nachricht_3_Datei.toString)
	  executeCommandLine("/etc/openhab2/scripts/fritzbox.sh mark " + Nachricht_3_Datei.toString)
   }
   if (receivedCommand.toString == "4") {
      playSound(Nachricht_4_Datei.toString)
	  executeCommandLine("/etc/openhab2/scripts/fritzbox.sh mark " + Nachricht_4_Datei.toString)
   }
   
end

And the items are shown in a widget:
anrufe.widget.json (4.5 KB)
(preview please see my first link in this post)

Maybe that helps one of you… Have fun :grinning:

1 Like

Hi to all,
get this message after loading the script:

2018-09-22 03:24:36.057 [INFO ] [.eclipse.smarthome.model.script.rule] - lock obtained

downloading message list for TAM 0...wget: missing URL

Usage: wget [OPTION]... [URL]...

Try `wget --help' for more options.

0 bytes.

downloading call list...wget: missing URL

Usage: wget [OPTION]... [URL]...

Try `wget --help' for more options.

0 bytes.

Can anyone help?
Thanks and Greetings,
Markus

Okay, found it. :slight_smile:
https doesn’t work.
But know i have this problem:

2018-09-22 03:58:11.886 [WARN ] [smarthome.model.script.actions.Audio] - Failed playing audio file: Unsupported file extension!

I use the playsound rule from Jochen.
Thanks for help,
Markus

@der_optimist : Thanks for the scripts, this made things easier, the list is working for me.

For those struggeling with no data being shown in the widget and items not getting updated:
Be aware that the name of the openhab server is hardcoded in the calls to the REST API.

I added a small variable in the top section

OPENHAB_SERVER=<your_servername_here>

and replaced

openhabianpi

in the curl statements with

$OPENHAB_SERVER

For the port value 8080 you could do something similar in case you change the standard port.
This is easier to maintain and you wont run in the same (stupid me) issue that things do not work after copy&paste :wink:

@der_optimist
Is the code for the anrufe widget complete? Because it does not close the outer table.

Also, could you please share the used icons?

Thanks!

Hello,

I’m new to OpenHab and tried your code. It works very fine, except the “Generate call overview” rule. I have a FB 7590 with Fritz!OS 7.01, and there the fboxIncomingCall.state or fboxOutgoingCall.state is newer empty, it contains a “,”. I believe the items hold a StringListType with the caller number and called number.
So I changed the rule from

to

rule "Generate Call Overview"
when
   Item fboxIncomingCall changed or
   Item fboxOutgoingCall changed 
then
   
   if ((fboxIncomingCall.state.toString == ",") && (fboxOutgoingCall.state.toString == ",") && (previousState.toString != ",")) {
     	logInfo("Fritz Call", "update call overview")
	executeCommandLine("/etc/openhab2/scripts/fritzbox.sh update")
   }
end

Perhaps there is a better way, but at least it works for me;-)

Hi Joerg.
It’s running for me too.
i only changed:

executeCommandLine("/etc/openhab2/scripts/fritzbox.sh update",10000)

10000 for secure finishing of the script i think.?

But still have this problem:

2018-09-22 03:58:11.886 [WARN ] [smarthome.model.script.actions.Audio] - Failed playing audio file: Unsupported file extension!

Greetings,
Markus

grrat work guys, but wouldn‘t it make sense to have a repo on GitHub bringing all required pieces together rather than copy&paste from somewhere to somewhere

looking forward to give it a try

Have a great New Year!:four_leaf_clover:

1 Like

I second this. :slight_smile:

I have tried the version from @der_optimist, but the widget does not fit my dashboards. I’d like to try the version from @vbier next.

@vbier, I am using your solution with the most recent changes. I copied the necessary CSS rules from the Matrix theme because I do not want to use the whole Matrix theme.

I have some small problems, probably related to latest FritzOS, maybe you have an idea what could be the cause and maybe you already have fixed it for yourself.

I had to change your rule like @JoVo described, because current version of FritzOS has that “,” in the fboxIncomingCall.state and fboxOutgoingCall.state, so that is fixed.

Still, when an incoming call with recording ends, the caller list refreshes automatically, but I only see an entry for the missed call, not for the recording. When I execute the shell script manually with “update” again and then refresh Habpanel, then I see the recording (cassette icon).
Edit: I added Thread.sleep(3000) in the rule (before the execution of the update command), then the FritzBox apparently had enough time to process the call with recording.

Next problem: When I play a recording in Habpanel, is is not marked as read in the FritzBox. I also tried executing the script manually with “mark 0”, which executes without error, but the FritzBox still states that it is new during the next “update” call (isNewTamMsg=1).

Thanks!

To be honest, I wrote this a while ago and never really used it. I am not interested in fixing it or setting up a GitHub repo.

I quickly looked into this. Change the soapCall line in the mark function in the script to:

soapCall "$BASEURL/upnp/control/x_tam" "urn:dslforum-org:service:X_AVM-DE_TAM:1" MarkMessage dummy "<NewIndex>$tam</NewIndex><NewMessageIndex>$index</NewMessageIndex><NewMarkedAsRead>1</NewMarkedAsRead>"

After that the messages are shown as read again.

1 Like

@vbier, it works great now, thank you!

Hello Sidamos, could you please explain, how to copy the necessary CSS-rules?
The last days I tried nearly every approach discussed here but on the one hand you need the matrix-theme on the other hand the widged seems to be not complete…
Don´t get me wrong - great work from all of the above developers but if you are not one of them even with google it is hard to come to a “happy end” :slight_smile:
Thanks a lot in advance
Klaus

@klausO I’ll try to put everything needed on Github ASAP.