9 Commits

7 changed files with 61 additions and 45 deletions

6
.env.sample Normal file
View File

@@ -0,0 +1,6 @@
FRITZ_USERNAME="fritzab2matrix"
FRITZ_PASSWORD="S0meSecretPa5sw02d"
FRITZ_IP="192.168.178.1"
FRITZ_TMP="/tmp"
FRITZ_VOICEBOX_PATH="fritz.nas/FRITZ/voicebox"
FRITZ_TAM='{"0" : "!roomhash1:matrix.org", "1" : "!roomhash2:matrix.org"}'

View File

@@ -3,7 +3,8 @@
__FritzAB2Matrix__ reads out the answering machine (_TAM_) of a _Fritz!Box_ in your LAN and posts the messages into a private chat in the __matrix__ network. While you could let your _Fritz!Box_ send the messages by mail - unencrypted of course - the matrix chat is __e2e encrypted__. Which kindly acknowledges the privacy of any caller that leaves a message for you. __FritzAB2Matrix__ reads out the answering machine (_TAM_) of a _Fritz!Box_ in your LAN and posts the messages into a private chat in the __matrix__ network. While you could let your _Fritz!Box_ send the messages by mail - unencrypted of course - the matrix chat is __e2e encrypted__. Which kindly acknowledges the privacy of any caller that leaves a message for you.
Uses the python based cmd-line-tool [matrix-commander](https://github.com/8go/matrix-commander) so the matrix-commander.py in this repo is just a copy of that file to ease testing. Uses the python based cmd-line-tool [matrix-commander](https://github.com/8go/matrix-commander) so the matrix-commander.py in this repo is just a copy of that file to ease testing.
## Features
* Since _v0.1.1_ __Multitam__ is integrated so that you can check multiple answering machines __and__ post the messages to different matrix rooms. (Use _FRITZ\_TAM_ variable in .env file)
## Installation ## Installation
If you like to test this repository you are recommended to use one of the following two options. If you like to test this repository you are recommended to use one of the following two options.
### Necessary preparations for both cases ### Necessary preparations for both cases
@@ -23,11 +24,12 @@ If you like to test this repository you are recommended to use one of the follow
* Inside the repo run `pip install --upgrade pip && pip install -r requirements.txt` * Inside the repo run `pip install --upgrade pip && pip install -r requirements.txt`
* Create an `.env` file with your favourite editor: * Create an `.env` file with your favourite editor:
``` ```
FRITZ_USERNAME="fritzab" FRITZ_USERNAME="fritzab2matrix"
FRITZ_PASSWORD="SomeRand0mPa55word" FRITZ_PASSWORD="S0meSecretPa5sw02d"
FRITZ_IP="192.168.178.1" FRITZ_IP="192.168.178.1"
FRITZ_VOICEBOX_PATH="fritz.nas/FRITZ/voicebox" FRITZ_TMP="/tmp"
FRITZ_TMP="/tmp" # FRITZ_VOICEBOX_PATH="fritz.nas/FRITZ/voicebox"
FRITZ_TAM='{"0" : "!roomhash1:matrix.org", "1" : "!roomhash2:matrix.org"}'
``` ```
__.env__ __.env__
@@ -53,6 +55,8 @@ Provided you have docker and docker-compose installed on your system:
* With docker that means that you need to open an _interactive shell_ in the running container (`docker-compose -f docker/docker-compose.yml exec app /bin/bash` and run this command there. * With docker that means that you need to open an _interactive shell_ in the running container (`docker-compose -f docker/docker-compose.yml exec app /bin/bash` and run this command there.
* Follow the appearing dialog and input your matrix account data. * Follow the appearing dialog and input your matrix account data.
* After all that the running docker container should watch your box and your TAM messages should be posted in the chosen matrix chat. * After all that the running docker container should watch your box and your TAM messages should be posted in the chosen matrix chat.
### Special Thx ### Special Thx
Gratitude to all people that enabled that project by their passionate work and will to share it! Gratitude to all people that enabled that project by their passionate work and will to share it!
@@ -63,4 +67,4 @@ Especially to
* https://github.com/jiaaro/pydub/ * https://github.com/jiaaro/pydub/
* https://git.savannah.nongnu.org/cgit/fbvbconv-py.git/ * https://git.savannah.nongnu.org/cgit/fbvbconv-py.git/

View File

@@ -1,8 +1,9 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM ubuntu:latest FROM python:alpine
ENV TZ=Europe/Berlin ENV TZ=Europe/Berlin
ENV UNBUFFERED=1
WORKDIR /app WORKDIR /app
VOLUME /app VOLUME /app
@@ -10,23 +11,18 @@ VOLUME /app
COPY . . COPY . .
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone; \ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone; \
/bin/bash -c 'apt update && apt install -y libolm-dev python3-pip ffmpeg htop; \ apk --no-cache update && apk add --no-cache --virtual .build-deps \
pip install update pip && pip install -r requirements.txt ;' gcc \
cargo \
libffi-dev \
openssl-dev \
ENTRYPOINT ["./fritzab2matrix.py "] zlib-dev \
jpeg-dev ; \
apk add --no-cache ffmpeg speex; \
pip install --no-cache-dir upgrade pip; \
pip install --no-cache-dir -r requirements.txt ; \
apk del --no-cache .build-deps;
ENTRYPOINT ["python3", "-u", "fritzab2matrix.py "]

View File

@@ -7,7 +7,7 @@ services:
context: ../. context: ../.
dockerfile: ./docker/Dockerfile dockerfile: ./docker/Dockerfile
working_dir: /app working_dir: /app
entrypoint: ./fritzab2matrix.py # entrypoint: /bin/sh -c "export UNBUFFERED=1 && python3 -u ./fritzab2matrix.py"
volumes: volumes:
- ../.:/app - ../.:/app

View File

@@ -6,7 +6,7 @@ from pydub import AudioSegment
from libs.monitoring import endedCall from libs.monitoring import endedCall
from libs.message import conversion as conv from libs.message import conversion as conv
import urllib.request import urllib.request
import xmltodict import xmltodict, json
import sys, os import sys, os
import smbclient import smbclient
@@ -18,11 +18,18 @@ env_user = os.environ.get('FRITZ_USERNAME')
env_pass = os.environ.get('FRITZ_PASSWORD') env_pass = os.environ.get('FRITZ_PASSWORD')
env_ip = os.environ.get('FRITZ_IP') env_ip = os.environ.get('FRITZ_IP')
env_voicebox = os.environ.get('FRITZ_VOICEBOX_PATH') env_voicebox = os.environ.get('FRITZ_VOICEBOX_PATH')
env_tam = json.loads(os.environ.get('FRITZ_TAM'))
env_tmp = os.environ.get('TEMP_DIR') env_tmp = os.environ.get('TEMP_DIR')
if env_voicebox is None: if env_voicebox is None:
env_voicebox = "/fritz.nas/FRITZ/voicebox/" env_voicebox = "/fritz.nas/FRITZ/voicebox/"
if env_tam is None:
env_tam = {
"0" : "!MxRrNGhFuQwnIeEWnX:ismus.net"
}
print(env_tam)
if env_tmp is None: if env_tmp is None:
env_tmp = "/tmp" env_tmp = "/tmp"
@@ -48,7 +55,7 @@ def get_message_list(url):
return messages return messages
def fritzab2matrix(): def fritzab2matrix(tam):
### CHECK AND GET MESSAGES FROM FRITZBOX ### ### CHECK AND GET MESSAGES FROM FRITZBOX ###
############################################ ############################################
@@ -60,12 +67,10 @@ def fritzab2matrix():
## Get info about messages from the main answering machine ## Get info about messages from the main answering machine
message_list = fc.call_action("X_AVM-DE_TAM1", "GetMessageList", NewIndex=0) message_list = fc.call_action("X_AVM-DE_TAM1", "GetMessageList", NewIndex=tam)
message_list_url = message_list['NewURL'] message_list_url = message_list['NewURL']
l = get_message_list(message_list_url) l = get_message_list(message_list_url)
if l['Root'] == None or l['Root']['Message'] == None: if l['Root'] == None or l['Root']['Message'] == None:
return False return False
@@ -94,17 +99,17 @@ def fritzab2matrix():
# Download and convert the speex files to wav # Download and convert the speex files to wav
smb_url = build_download_url(a['Index']) smb_url = build_download_url(a['Index'])
speex_fd = download_speex_file(smb_url) speex_fd = download_speex_file(smb_url)
conv.speex_convert(speex_fd, os.path.join(env_tmp,"message.wav")) conv.speex_convert(speex_fd, os.path.join(env_tmp,"message{}.wav".format(tam)))
# Convert wav to ogg # Convert wav to ogg
msg = AudioSegment.from_wav(os.path.join(env_tmp,"message.wav")) msg = AudioSegment.from_wav(os.path.join(env_tmp,"message{}.wav".format(tam)))
# Only if message is longer than 5 seconds ... # Only if message is longer than 5 seconds ...
if msg.duration_seconds > 5.0: if msg.duration_seconds > 5.0:
# ... export to ogg ... # ... export to ogg ...
msg.export(os.path.join(env_tmp,"message.ogg"), format="ogg", tags=msg_tags) msg.export(os.path.join(env_tmp,"message{}.ogg".format(tam)), format="ogg", tags=msg_tags)
# ... and send message and file to Matrix Room # ... and send message and file to Matrix Room
command = "python3 matrix-commander.py -a " + os.path.join(env_tmp,"message.ogg") + " -m '{}'".format(msg_info) command = "python3 matrix-commander.py --room {} -a ".format(env_tam[tam]) + os.path.join(env_tmp,"message{}.ogg".format(tam)) + " -m '{}'".format(msg_info)
os.system(command) os.system(command)
else: else:
@@ -115,7 +120,7 @@ def fritzab2matrix():
print("** " + msg_info) print("** " + msg_info)
# Mark processed messages as 'read' # Mark processed messages as 'read'
fc.call_action("X_AVM-DE_TAM1", "MarkMessage", NewIndex=0, NewMessageIndex=int(a['Index']), NewMarkedAsRead=1) fc.call_action("X_AVM-DE_TAM1", "MarkMessage", NewIndex=tam, NewMessageIndex=int(a['Index']), NewMarkedAsRead=1)
else: else:
# Show that message is already read # Show that message is already read
@@ -123,20 +128,24 @@ def fritzab2matrix():
# ## For testing purposes only # ## For testing purposes only
# if a['Date'].endswith('20:53'): # if a['Date'].endswith('20:53'):
# fc.call_action("X_AVM-DE_TAM1", "MarkMessage", NewIndex=0, NewMessageIndex=int(a['Index']), NewMarkedAsRead=0) # fc.call_action("X_AVM-DE_TAM1", "MarkMessage", NewIndex=1, NewMessageIndex=int(a['Index']), NewMarkedAsRead=0)
continue continue
continue continue
def multitam(tams):
for tam in tams.keys():
print("Check TAM {}.".format(tam))
fritzab2matrix(tam)
if __name__ == "__main__": if __name__ == "__main__":
fritzab2matrix()
multitam(env_tam)
### Monitor the FritzBox and trigger the main script whenever a call disconnects ### ### Monitor the FritzBox and trigger the main script whenever a call disconnects ###
################################################################################### ###################################################################################
endedCall(fritzab2matrix, env_ip) endedCall(multitam,env_tam, env_ip)

View File

@@ -4,7 +4,7 @@ from fritzconnection.core.fritzmonitor import FritzMonitor
### Monitor the calls of a fritzbox continously ### ### Monitor the calls of a fritzbox continously ###
################################################### ###################################################
def watch_disconnect(monitor, event_queue, func, healthcheck_interval=10): def watch_disconnect(monitor, event_queue, func, tams, healthcheck_interval=10):
while True: while True:
try: try:
event = event_queue.get(timeout=healthcheck_interval) event = event_queue.get(timeout=healthcheck_interval)
@@ -17,11 +17,11 @@ def watch_disconnect(monitor, event_queue, func, healthcheck_interval=10):
print(event) print(event)
if 'DISCONNECT' in event: if 'DISCONNECT' in event:
print("Anruf beendet. Jetzt den AB checken.\n") print("Anruf beendet. Jetzt den AB checken.\n")
func() func(tams)
def endedCall(func, fritz_ip='192.168.1.1'): def endedCall(func, tams, fritz_ip='192.168.1.1'):
""" """
Call this to trigger a given function if a call is disconnected Call this to trigger a given function if a call is disconnected
""" """
@@ -29,7 +29,7 @@ def endedCall(func, fritz_ip='192.168.1.1'):
# as a context manager FritzMonitor will shut down the monitor thread # as a context manager FritzMonitor will shut down the monitor thread
with FritzMonitor(address=fritz_ip) as monitor: with FritzMonitor(address=fritz_ip) as monitor:
event_queue = monitor.start() event_queue = monitor.start()
watch_disconnect(monitor, event_queue, func) watch_disconnect(monitor, event_queue, func, tams)
except (OSError, KeyboardInterrupt) as err: except (OSError, KeyboardInterrupt) as err:
print(err) print(err)

View File

@@ -1,3 +1,4 @@
requests
fritzconnection fritzconnection
python-dotenv python-dotenv
xmltodict xmltodict
@@ -7,12 +8,12 @@ pydub
# for matrix-commander # for matrix-commander
aiohttp aiohttp
aiofiles<0.5.0,>=0.4.0 aiofiles
argparse argparse
asyncio asyncio
datetime datetime
markdown markdown
matrix-nio[e2e]>=0.14.1 matrix-nio
Pillow Pillow
python_magic python_magic
uuid uuid