Giter Club home page Giter Club logo

emxsys / callattendant Goto Github PK

View Code? Open in Web Editor NEW
111.0 9.0 38.0 14.54 MB

A python-based automated call attendant, call blocker, and voice messaging system running on a Raspberry Pi. Screens callers and block robocalls and scams with a low-cost Raspberry Pi and modem.

Home Page: https://emxsys.github.io/callattendant/

License: MIT License

Python 78.80% HTML 18.23% Shell 0.26% CSS 2.71%
python uml telephony modem raspberry-pi call-blocker voice-messages flask call-screener rational-unified-process

callattendant's Introduction

Call Attendant

PyPI PyPI - License PyPI - Status GitHub Workflow Status

pip install callattendant

The Call Attendant (callattendant) is an auto attendant with an integrated call blocker and voice messaging system running on a Raspberry Pi. It stops annoying robocalls and spammers from interrupting your life. Let the Call Attendant intercept and block robocallers and telemarketers before the first ring on your landline.

The callattendant provides international support with configurable phone number formats, with flexible and editable blocked-number and permitted-number lists.

If you're at all interested in this project, please provide some feedback by giving it a star, or even better, get involved by filing issues, joining the forum and/or submitting pull requests. Thanks!

Support Links

Table of Contents

Overview

The Call Attendant (callattendant) is a python-based, automated call attendant that runs on a lightweight Raspberry Pi, or other Linux-based system, coupled with a US Robotics 5637 USB modem.

How it works

The Raspberry Pi and modem are connected to your home phone system in parallel with your phone handset(s). When an incoming call is received, the call goes to both your phone and the callattendant. During the period of the first ring the callattendant analyzes the caller ID, and based on your configuration, determines if the call should be blocked or allowed. Blocked calls can be simply hung up on, or routed to the voice message system. Calls that are allowed will simply ring your home phone like normal. Calls can be sent to the integrated voice mail system if you choose. The callattendant's filtering mechanisms include an online lookup service, a permitted number list, a blocked number list and pattern matching on the caller's number and/or name.

Features include:

  • A call blocker that intercepts robocallers and blocked numbers at or before the first ring
  • Permitted numbers pass straight through to the local phone system for normal call ringing and answering
  • Visual indicators to show whether the incoming call is from a permitted, blocked, or unknown number
  • Call details, permitted numbers, and blocked numbers are available in a web-based user interface
  • Calls can be handled by a voice messaging system that optioanlly requires human interaction, e.g, "Press 1 to leave a message"

You can review call history, voice messages, permitted and blocked numbers, and performing caller management through the Call Attendant's web interface. Here is an example of the home page with metrics and a convienient list of recent calls. For a complete description see the User Guide.

Screenshots of the home page as seen on an IPad Pro and a Pixel 2 phone

Dashboard-Responsive

Documentation

The project wiki on GitHub contains the documentation for the Call Attendant:

  • See the Wiki Home for complete installation, configuration, and operation instructions.
  • See the User Guide section for the web interface instructions.
  • The Developer Guide section describes the software architecture and software development plan, and shows you how to setup your software development environment.
  • The Advanced section addresses more complex setups and situations. For instance, Running as a Service.

Hardware Requirements

The callattendant uses the following hardware:

Photo of the required hardware: a Raspberry Pi 3B+ and USR5637 modem

Raspberry Pi and USR5637 Modem


Quick Start

Hardware

You will need a Raspberry Pi running Raspbian or better with access to the Internet for the software installation, and ultimately for the the online robocaller lookups. For the project, you will need a modem of some sort to do the telephony communications. The U.S. Robotics USR5637 56K USB Modem has been proven effective. For some installs, it just works, no config needed. It showed up as /dev/ttyACM0.


Software

The installation calls for Python3.X.

Setup a Virtual Environment

Optional

The following instructions create and activate a virtual environment named venv within the current folder:

# Install virtualenv - if not installed
sudo apt install virtualenv

# Create the virtual environment
virtualenv venv --python=python3

# Activate it
source venv/bin/activate

Now you're operating with a virtual Python. To check, issue the which command and ensure the output points to your virtual environment; and also check the Python version:

$ which python
/home/pi/venv/bin/python

$ python --version
Python 3.7.3

Later, when you install the callattendant software, it will be placed within the virtual environment folder (under lib/python3.x/site-packages to be exact). The virtual environment, when activated, alters your PATH so that the system looks for python and its packages within this folder hierarchy.

Install the Software

The software is available on PyPI. Install and update using pip:

# Using the virtual environment you use "pip" to install the software
pip install callattendant

# You must use "pip3" on the Pi if your not using a virtual environment
pip3 install callattendant

If your not using the virtual environment, you may need to reboot or logoff/login to update the $PATH for your profile in order to find and use the callattendant command.


Operation

The callattendant package includes a callattendant command to start the system. Run this command the first time with the --create-folder option to create the initial data and files in the default data folder: ~/.callattendant. This is a hidden folder off the root of your home directory. You can override this location with the --data-path option.

Usage: callattendant --config [FILE] --data-path [FOLDER]
Options:
-c, --config [FILE]       load a python configuration file
-d, --data-path [FOLDER]  path to data and configuration files
-f, --create-folder       create the data-path folder if it does not exist
-h, --help                displays this help text
# Creating the default data folder with the default configuration
callattendant --create-folder

# Using the default configuration
callattendant

# Using a customized config file in an alternate, existing location
callattendant --config myapp.cfg --data-path /var/lib/callattendant

You should see output of the form:

Command line options:
  --config=app.cfg
  --data-path=None
  --create-folder=False
[Configuration]
  BLOCKED_ACTIONS = ('greeting', 'voice_mail')
  BLOCKED_GREETING_FILE = /home/pi/.local/lib/python3.7/site-packages/callattendant/resources/blocked_greeting.wav
  BLOCKED_RINGS_BEFORE_ANSWER = 0
  BLOCK_ENABLED = True
  BLOCK_NAME_PATTERNS = {'V[0-9]{15}': 'Telemarketer Caller ID'}
  BLOCK_NUMBER_PATTERNS = {}
  BLOCK_SERVICE = NOMOROBO
  CONFIG_FILE = app.cfg
  DATABASE = callattendant.db
  DATA_PATH = /home/pi/.callattendant
  DB_FILE = /home/pi/.callattendant/callattendant.db
  DEBUG = False
  ENV = production
  PERMITTED_ACTIONS = ('greeting', 'record_message')
  PERMITTED_GREETING_FILE = /home/pi/.local/lib/python3.7/site-packages/callattendant/resources/general_greeting.wav
  PERMITTED_RINGS_BEFORE_ANSWER = 6
  PERMIT_NAME_PATTERNS = {}
  PERMIT_NUMBER_PATTERNS = {}
  PHONE_DISPLAY_FORMAT = ###-###-####
  PHONE_DISPLAY_SEPARATOR = -
  ROOT_PATH = /home/pi/.local/lib/python3.7/site-packages/callattendant
  SCREENED_ACTIONS = ('greeting', 'record_message')
  SCREENED_GREETING_FILE = /home/pi/.local/lib/python3.7/site-packages/callattendant/resources/general_greeting.wav
  SCREENED_RINGS_BEFORE_ANSWER = 0
  SCREENING_MODE = ('whitelist', 'blacklist')
  TESTING = False
  VERSION = 1.1.0
  VOICE_MAIL_GOODBYE_FILE = /home/pi/.local/lib/python3.7/site-packages/callattendant/resources/goodbye.wav
  VOICE_MAIL_GREETING_FILE = /home/pi/.local/lib/python3.7/site-packages/callattendant/resources/general_greeting.wav
  VOICE_MAIL_INVALID_RESPONSE_FILE = /home/pi/.local/lib/python3.7/site-packages/callattendant/resources/invalid_response.wav
  VOICE_MAIL_LEAVE_MESSAGE_FILE = /home/pi/.local/lib/python3.7/site-packages/callattendant/resources/please_leave_message.wav
  VOICE_MAIL_MENU_FILE = /home/pi/.local/lib/python3.7/site-packages/callattendant/resources/voice_mail_menu.wav
  VOICE_MAIL_MESSAGE_FOLDER = /home/pi/.callattendant/messages
Initializing Modem
Opening serial port
Looking for modem on /dev/ttyACM0
******* Conextant-based modem detected **********
Serial port opened on /dev/ttyACM0
Modem initialized
{MSG LED OFF}
Starting the Flask webapp
Running the Flask server
Waiting for call...
 * Serving Flask app "userinterface.webapp" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off

Make a few calls to yourself to test the service. The standard output will show the progress of the calls. Then navigate to http://<pi-address>|<pi-hostname>:5000 in a web browser to checkout the web interface.

Press ctrl-c to shutdown the system


Web Interface

URL: http://<pi-address>|<pi-hostname>:5000

To view the web interface, simply point your web browser to port 5000 on your Raspberry Pi. For example, in your Raspberry Pi's browser, you can use:

http://localhost:5000/

See the User Guide for more information.


Configuration

The Call Attendant's behavior can be controlled by a configuration file. To override the default configuration, open the the ~/.callattenant/app.cfg and edit its contents.

nano ~/.callattendant/app.cfg

Then specify the configuration file and path on the command line, e.g.:

callattendant --config app.cfg

See the Configuration section in the project's wiki for more information.


callattendant's People

Contributors

emxsys avatar zomgreg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

callattendant's Issues

Front end fails to initialize due to call to missing table field.

Error:

Unhandled exception in thread started by <function flaskThread at 0x737973f0>
Traceback (most recent call last):
  File "/home/pi/testing/callattendant/src/userinterface/webapp.py", line 123, in flaskThread
    call_details()
  File "/home/pi/testing/callattendant/src/userinterface/webapp.py", line 62, in call_details
    result_set = screening.utils.query_db(get_db(), query, arguments)
  File "/home/pi/testing/callattendant/src/screening/utils.py", line 29, in query_db
    cur = db.execute(query, args)
sqlite3.OperationalError: no such column: b.Reason

Likely this is because the whitelist table contains no Reason field.

I will submit a PR with what I think is the fix.

Add Call History page

Add a page to display the call history for a phone number.

Consider adding a filter/search to the Call Log.

Add pagination to the call log

Add pagination to the call_details.htm to reduce the overhead of displaying multiple years of call data on a single page.

Add Manage Caller page

Add a page to manage a caller's inclusion in the permitted and/or blocked numbers lists. Re:; #13

Consider adding a link to the caller's call history page (TBD).

Error when adding a user to whitelist

192.168.1.106 - - [03/Aug/2020 17:44:39] "GET /manage_caller/3 HTTP/1.1" 200 -
Adding LNAME FNAME to whitelist
[2020-08-03 17:44:41,309] ERROR in app: Exception on /manage_caller/3 [POST]
Traceback (most recent call last):
File "/home/pi/p3/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/home/pi/p3/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/pi/p3/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/pi/p3/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/home/pi/p3/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/home/pi/p3/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functionsrule.endpoint
File "/home/pi/projects/callattendant/src/userinterface/webapp.py", line 236, in manage_caller
whitelist = Whitelist(get_db())

Refactor Modem class

Refactor the Modem class into an BasicModem base class and a USRobotics5637Modem derived class.

  • Base class has serial port and send, receive responsibilities.

  • Subclass has call handling responsibilities

  • Eliminate coupling from Modem to CallAttendant; use a callback instead.

Add a Messages table for tracking voice messages

A Messages table is need to enhance the handling of voices messages. It should do the following:

  • Manage the played/unplayed status of voice messages
  • Provide high performance (via joins) when displaying call lists with associated voice messages
  • Future: Possibly hold the message data in a Blob field.
CREATE TABLE IF NOT EXISTS Message (
                    MessageID INTEGER PRIMARY KEY AUTOINCREMENT,
                    CallLogID INTEGER,
                    Played BOOLEAN DEFAULT 0 NOT NULL CHECK (Played IN (0,1)),
                    Filename TEXT,
                    DateTime TEXT,
                    FOREIGN KEY(CallLogID) REFERENCES CallLog(CallLogID));

Record voice message

Add ability to record messages from callers. The messages should be uniquely identify to caller records in the call log.

Add Dashboard page

Add a Dashboard page to be used as the root route (index.html). The dashboard would include:

  • Metrics
  • Recent calls (short list)
  • Top callers (permitted/screened and blocked; names, numbers and counts)
  • Number of callers last 14 days (stacked bar graph - chart.js)
  • Voice message notifications

Package and make installable via PyPi

As a user of callattendant, I want to be able to install this software via something like pip install callattendant and have the necessary dependencies automatically installed and be presented with a nice web interface at the end.

Things that should be done first:

  • 1.conf.py
  • 2. Port to python3 #36
  • 3. Create setup.py

Embellish Call Log web interface

  • Highlight whitelisted and blacklisted callers
  • Periodically refresh page
  • Add action taken
  • Add capability to add caller to whitelist or blacklist
  • Add navigation links between the call log, whitelist and blacklist pages.

Enable Voice Mail for screened and permitted callers

Add voice messaging capabilities and options for all callers:

  • Add options to enable voice mail for permitted and screen callers
  • Configure answer after n number of rings
  • Add button(s) to reset the "unplayed" status of a voice message

FYI: In North America, the standard ring cadence is "2-4", or two seconds of ringing followed by four seconds of silence (33% Duty Cycle). This information could be used to implement a time-based wait system before pickup. E.g., to wait for for n rings would be time.sleep( n * 6)

Examples:

  • 'Screened' calls could be intercepted with the general greeting and then sent to voice mail
  • 'Permitted' calls could ring n times, allowing you to answer, before being sent to voice mail

flask_paginate module not found when run as a service

The following output from `sudo journalctl --follow -u callattendant.service shows the error:

Jul 31 01:14:28 pi-blocker systemd[1]: Started Call Attendant.
Jul 31 01:14:30 pi-blocker python[9919]: Traceback (most recent call last):
Jul 31 01:14:30 pi-blocker python[9919]:   File "/home/pi/callattendant/src/callattendant.py", line 32, in <module>
Jul 31 01:14:30 pi-blocker python[9919]:     import userinterface.webapp as webapp
Jul 31 01:14:30 pi-blocker python[9919]:   File "/home/pi/callattendant/src/userinterface/webapp.py", line 33, in <module>
Jul 31 01:14:30 pi-blocker python[9919]:     from flask_paginate import Pagination, get_page_args
Jul 31 01:14:30 pi-blocker python[9919]: ImportError: No module named flask_paginate
Jul 31 01:14:30 pi-blocker systemd[1]: callattendant.service: Main process exited, code=exited, status=1/FAILURE
Jul 31 01:14:30 pi-blocker systemd[1]: callattendant.service: Unit entered failed state.
Jul 31 01:14:30 pi-blocker systemd[1]: callattendant.service: Failed with result 'exit-code'.

callattendate.service Unit File:

[Unit]
Description=Call Attendant
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/python /home/pi/callattendant/src/callattendant.py
WorkingDirectory=/home/pi/callattendant/src
Restart=on-abort

[Install]
WantedBy=multi-user.target

flask_paginate was installed via the requirements.txt file. pip show flask_paginate shows the modules.

Modem play audio (wav file) fails

After the port to Python3, the Modem class fails to play the audio file. The system stalls.
Following is the output of the Modem unit tests after pressing Ctrl-C

(python3) pi@hamshack:~/src/callattendant/src $ python hardware/modem.py
[Configuration]
  BLOCKED_ACTIONS = ('play_message',)
  BLOCKED_MESSAGE_FILE = hardware/blocked.wav
  BLOCK_ENABLED = True
  BLOCK_NAME_PATTERNS = {'V[0-9]{15}': 'Telemarketer Caller ID'}
  BLOCK_NUMBER_PATTERNS = {}
  DATABASE = callattendant.db
  DEBUG = False
  DEBUGs = True
  ENV = production
  ROOT_PATH = /home/pi/src/callattendant/src
  SCREENING_MODE = ('whitelist', 'blacklist')
  TESTING = False
Running Unit Tests....
Modem COM Port is: /dev/ttyACM0
Assert factory reset
Assert display modem settings
Assert put modem into voice mode.
Assert set compression method and sampling rate specifications.
Assert put modem into TAD mode.
Assert put modem into data transmit state.
Assert cancel data transmit state.
Play Audio Msg - Start
Play Audio Msg - playing wav file
^CTraceback (most recent call last):
  File "hardware/modem.py", line 563, in <module>
    sys.exit(test(config, phone_ringing, handle_caller))
  File "hardware/modem.py", line 534, in test
    modem.play_audio(os.path.join(currentdir, "sample.wav"))
  File "hardware/modem.py", line 234, in play_audio
    time.sleep(.12)
KeyboardInterrupt

Permitted/Blocked name should override CID name in Call Log

The Call Log is suppose to display the name from either the Permitted or Blocked table, whichever was used, if used. In the case of permitted calls, this allows friendly names to override the default CID names. In the case of blocked calls, this allows a corrective display in the case of spoofed names.

Divide by zero on new install.

There is a divide by 0 that happens on a clean install:

    percent_blocked = blocked / total * 100          
ZeroDivisionError: division by zero  

Because there have been 0 total calls. Pull request is ready.

Improve web interface

Prototype web interface subsystem:

  • Display whitelist
  • Display blacklist
  • Embellish call log

Validate configuration items

Validate the configuration after loading. The validation process should insure that all the default configuration items have permissible values. A RuntimeError should be raised otherwise.

Also, the configuration should always be printed to the standard output, not just when config["DEBUG"] is True. This will be helpful in the future when debugging an error or providing support. The configuration dump could/should be included in bug-related issues. (Issue templates?)

Play Message modal dialog should set message played status

The Message modal dialog on all associated pages should update the played status of the played voice message.

  • Requires upgrading from JQuery "slim" version to acquire AJAX capabilities

  • Consider using a common "play message" Flask template

  • Also, add a Delete button to the dialog.

Add ACTION column to call log table

Add an ACTION column to the call log table to capture the call blocker's action taken. This field records the call blocker history. Currently the history is inferred by the existence of the number in whitelist and blacklist tables. But those associations can be temporal: if they change the history is lost.

Possible values for the field include:

  • Blocked
  • Permitted
  • Screened

Generate end-user documentation in the Wiki

Create the User Guide in this project's Wiki.
Reserve the Wiki for the end-user documentation. Developer docs are in the README.

  • Add link to the User Guide to the callattendant's nav-bar branding.
  • Add a link to the User Guide to the README.
  • Add Installation instructions including service setups for Linux/Raspberry Pi
  • Add Configuration instructions
  • Add Hardware Interface instructions

Add a "New Messages Waiting" LED indicator

Create an LED indicator that indicates that new voice messages are waiting.

  • Consider adding a 7-segment LED to indicate the number of message waiting.
  • Will need a table to manage the read/unread status of messages. (#59)
  • Consider joining the new table with the call log table to show a message indicator for the calls in the Call Log page

Create flexible and robust application configuration

Refactor configuration handling to make it robust by including:

  • Default configuration if no config file
  • Accepting an external config file via the command line
  • Providing an example config file
  • Documenting the command line

Config setting to include:

  • Call blocking modes
  • Regex patterns for names
  • Regex pattern for numbers
  • Voice messaging features
  • Phone number formatting

Refine Call Log

Improve the Call Log:

  • Add "new message" | "message waiting" indicator
  • Add search/filter capability
  • Refine the layout

Part of #40

Add voice messaging menu

Add a voice messaging menu that responds to the caller's touch-tone key presses, for example:

  • "Press 1 to leave a message"
  • "Press 0 to hang up"

Improve web user interface

  • Add Dashboard page #41
  • Add CRUD support to Permitted page #38
  • Add CRUD support to Blocked page #39
  • Add voice message symbols/buttons to Call Log page
  • Add block caller buttons to Messages page
  • Improve mobile/ responsive layout
  • Add Call History page #24
  • Enable context menu on Call Log (consider: manage caller, play voice message)

System sometimes fails to answer call

Sometimes the system fails to answer an incoming call if the previous caller hangs up in the middle of the Voice Mail menu.

Potential workaround(s):

  • Configure system not to record messages:
BLOCKED_ACTIONS = ("greeting", )
  • Configure system to record messages without Voice Mail menu.
BLOCKED_ACTIONS = (""record_message")
# or
BLOCKED_ACTIONS = ("greeting", "record_message")

Prototype candidate architecture

Exhibit and demonstrate, the candidate architecture against some of the primary scenarios:

  • Screen call
  • Log call
  • Block call
  • View call log

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.