Smart Cities - Phone for Seniors with Vision Impairment

From Sensors in Schools
Jump to navigation Jump to search

Building a simple telphone for seniors with vision impairment

Building a simple telephone for seniors with vision impairments using a Raspberry Pi can be an enriching and functional project. Below are the steps to create a device that allows seniors to call loved ones, leveraging either the internet (e.g., VoIP) or interfacing with a traditional mobile phone. The design emphasizes ease of use, accessibility, and practicality.

Project Overview

  • Features: Large, Accessible Buttons:
  • Physical buttons for calling predefined contacts.
  • Tactile feedback for easy navigation.
  • Voice Assistance: Text-to-Speech (TTS) for confirmation of actions.
  • Simple voice commands to perform tasks.
  • Internet Calling: Using VoIP services like SIP (Session Initiation Protocol).
  • Mobile Phone Interface (Optional): Interfacing with a traditional mobile phone via Bluetooth.
  • Speaker and Microphone: High-quality audio input/output for calls.


Materials Required

  • Raspberry Pi (Model 3, 4, or Zero 2 W recommended for performance).
  • MicroSD card with Raspberry Pi OS installed.
  • USB speaker or 3.5mm-compatible speaker.
  • USB microphone or headset with a mic.
  • Large tactile buttons or a numeric keypad.
  • Breadboard and jumper wires (for prototyping buttons).
  • A touchscreen or an e-ink display (optional for feedback).
  • USB or Bluetooth module (for mobile interfacing, optional).
  • Power supply for the Raspberry Pi.


Step 1: Setting Up the Raspberry Pi

Install the OS: Install Raspberry Pi OS on the MicroSD card using the Raspberry Pi Imager. Enable SSH, Wi-Fi, and audio support. Update and Upgrade: Run the following commands:

sudo apt update
sudo apt upgrade
  • Install Required Libraries: Install libraries for GPIO, audio processing, and VoIP:
sudo apt install python3-pip pyaudio alsa-utils libportaudio2
pip3 install gpiozero pyttsx3

To use Linphone on a Raspberry Pi for making calls to Australian mobile phones, you will need to install Linphone on your Raspberry Pi, configure it with a VoIP service provider (e.g., SIP provider), and integrate it with Python for initiating calls. Linphone is a powerful, open-source, SIP-based VoIP client that supports both voice and video calls.

Steps to Set Up Linphone for Calling Australian Mobile Phones:

1. Install Linphone on Raspberry Pi

First, you need to install Linphone on your Raspberry Pi. There are a few ways to install it, but the easiest method is using the Raspberry Pi OS repository.

Step 1.1: Install Linphone from the official repository:

sudo apt update
sudo apt install linphone

Alternatively, you can download the Linphone package for Raspberry Pi from the official Linphone download page.

2. Choose a VoIP Service Provider (SIP Provider)

You need a SIP (Session Initiation Protocol) provider that allows you to make calls to Australian mobile numbers. Some reliable SIP providers include:

VoIP.ms (Offers pay-as-you-go plans, and supports calls to landlines and mobiles).

For this tutorial, we will use VoIP.ms as an example. They offer good pricing for calls to Australian mobile numbers.

Step 2.1: Create an Account with VoIP.ms

Visit the VoIP.ms website and create an account. After logging in, you'll be able to obtain a SIP username and password to use in Linphone. Top up your balance to ensure you have credit to make calls to Australian mobile numbers.

Step 2.2: Configure VoIP.ms SIP Credentials

Once you’ve signed up, you'll need the following credentials:

SIP username
SIP password
SIP server (e.g., sip.voip.ms)

3. Configure Linphone for VoIP.ms SIP Account

Step 3.1: Set up Linphone with VoIP.ms

Once Linphone is installed, launch it and configure it with your SIP provider (e.g., VoIP.ms):

  • Open Linphone from the Raspberry Pi’s application menu.
  • Click on the Settings (gear icon) in Linphone.
  • Go to the Accounts tab.
  • Click on Add to add a new SIP account.
Username: Enter your SIP username from VoIP.ms.
Password: Enter your SIP password from VoIP.ms.
Domain: Enter sip.voip.ms (or another VoIP provider’s SIP server).
  • Enable Account enabled.
  • Save the configuration.

Step 3.2: Test Linphone

To ensure your configuration works, you can make a test call to a VoIP number or another SIP user. If the call connects successfully, you are ready to proceed with making calls to Australian mobile phones.

4. Using Python for Linphone Integration

To integrate Linphone with Python, you will need to use the Linphone Python bindings. This allows Python scripts to interact with Linphone, making it possible to initiate calls programmatically.


Using Linphone on a Raspberry Pi with Python requires some preparation because the Python bindings for Linphone are not always straightforward to install via pip. Here's a simpler approach to make Python communicate with Linphone.

1. Use Linphone's CLI and Control It via Python

Linphone provides a command-line interface (CLI) that you can use to control it. Python can communicate with the CLI to send commands and receive outputs.

Step 1: Install Linphone CLI

Install the Linphone CLI on your Raspberry Pi:

sudo apt update
sudo apt install linphone-cli

Verify the installation:

linphonec --version

You should see the version of Linphone CLI installed.

Step 2: Run Linphone CLI

Start the Linphone CLI in a terminal:

linphonec

You'll see a prompt like:

linphonec>

You can now issue commands to make calls, answer calls, and control Linphone.

Example commands:

Register your SIP account:

Username, domain, password

linphonec> register sip:123456@voip.ms sydney1.voip.ms <password>

Make a call:

linphonec> call sip:+614XXXXXXXX@sydney1.voip.ms

Hang up:

linphonec> terminate

Quit:

linphonec> quit

Help: Also useful for finding the correct command syntax. This assisted with the initial registration process.

linphonec> help register
linphonec> help advanced

Step 3: Automate with Python

You can use Python to automate Linphone CLI commands using the subprocess module.

Example Python Script

This script shows how to register, make a call, and hang up using Linphone CLI.


import subprocess
import selectors
import time

def send_command(process, command, delay=1):
    """Sends a command to linphonec and captures the output."""
    # Write command to the process
    process.stdin.write(command + "\n")
    process.stdin.flush()
    time.sleep(delay)  # Allow some time for output

    # Use selectors for non-blocking reading
    sel = selectors.DefaultSelector()
    sel.register(process.stdout, selectors.EVENT_READ)

    output = []
    timeout = time.time() + 5  # Set a timeout for reading (5 seconds)
    while time.time() < timeout:
        events = sel.select(timeout=1)
        for key, _ in events:
            line = key.fileobj.readline()
            if line:
                output.append(line.strip())
                print(line.strip())  # Optional: Print real-time output for debugging
            if "Ready" in line or "success" in line:  # Adjust the stopping condition
                sel.close()
                return "\n".join(output)

    sel.close()
    return "\n".join(output)

# Start linphonec
process = subprocess.Popen(
    ["linphonec"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True,
    bufsize=1  # Line-buffered I/O
)

try:
    # Register command
    register_command = "register sip:123456@voip.ms sydney1.voip.ms <myPassword>"
    response = send_command(process, register_command)
    print("Register Response:", response)

    # Quit linphonec
    quit_response = send_command(process, "quit")
    print("Quit Response:", quit_response)
finally:
    # Cleanup
    process.stdin.close()
    process.stdout.close()
    process.stderr.close()
    process.terminate()

ey Changes

  • Non-blocking I/O with Selectors: The selectors module monitors stdout for readable events without blocking the script indefinitely.
  • Timeout Handling: Added a 5-second timeout to prevent readline() from hanging forever if linphonec doesn't produce output.
  • Dynamic Stopping Condition: Stops reading when specific keywords like "Ready" or "success" are detected in the output.
  • Real-Time Debugging Output: Prints each line of output as it's read, making it easier to debug what linphonec is returning.
  • Adjust the Stopping Condition: Replace "Ready" or "success" in the send_command function with specific keywords or patterns you expect from linphonec.
  • Testing Interactivity: If the script still hangs, verify the behavior of linphonec manually by typing the same commands in a terminal.

Python code with GPIO buttons

Here's the modified Python code that integrates GPIO buttons for calling and terminating a call while keeping the existing functionality.

Key Modifications:

  • Added GPIO Initialization: Configures GPIO pins for the call and terminate buttons.
  • Loop for Button Interaction: Monitors the buttons and sends the corresponding SIP commands.
  • Uses send_command Function: Handles the command execution and ensures proper output handling.


import subprocess
import selectors
import time
import RPi.GPIO as GPIO

# GPIO Pin Configuration
CALL_BUTTON_PIN = 18  # GPIO pin for the call button
END_BUTTON_PIN = 23   # GPIO pin for the terminate button

# Configure GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(CALL_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # Pull-up resistor for call button
GPIO.setup(END_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # Pull-up resistor for end button

def send_command(process, command, delay=1):
    """Sends a command to linphonec and captures the output."""
    process.stdin.write(command + "\n")
    process.stdin.flush()
    time.sleep(delay)

    # Use selectors for non-blocking reading
    sel = selectors.DefaultSelector()
    sel.register(process.stdout, selectors.EVENT_READ)

    output = []
    timeout = time.time() + 5  # Set a timeout for reading (5 seconds)
    while time.time() < timeout:
        events = sel.select(timeout=1)
        for key, _ in events:
            line = key.fileobj.readline()
            if line:
                output.append(line.strip())
                print(line.strip())  # Optional: Print real-time output for debugging
            if "Ready" in line or "success" in line:  # Adjust the stopping condition
                sel.close()
                return "\n".join(output)

    sel.close()
    return "\n".join(output)

# Start linphonec process
process = subprocess.Popen(
    ["linphonec"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True,
    bufsize=1  # Line-buffered I/O
)

try:
    # Send the register command
    register_command = "register sip:435211@example.com mypassword sip:proxy.example.com"
    response = send_command(process, register_command)
    print("Register Response:", response)

    print("Ready for button interactions...")

    while True:
        # Check if the call button is pressed
        if GPIO.input(CALL_BUTTON_PIN) == GPIO.LOW:  # Button pressed (LOW)
            print("Call button pressed. Initiating call...")
            call_command = "call sip:+61412978633@sydney1.voip.ms"
            response = send_command(process, call_command)
            print("Call Response:", response)
            time.sleep(0.5)  # Debounce delay

        # Check if the end button is pressed
        if GPIO.input(END_BUTTON_PIN) == GPIO.LOW:  # Button pressed (LOW)
            print("End button pressed. Terminating call...")
            terminate_command = "terminate"
            response = send_command(process, terminate_command)
            print("Terminate Response:", response)
            time.sleep(0.5)  # Debounce delay

        time.sleep(0.1)  # Short delay to prevent high CPU usage

finally:
    print("Cleaning up resources...")
    GPIO.cleanup()  # Clean up GPIO
    quit_response = send_command(process, "quit")
    print("Quit Response:", quit_response)
    process.stdin.close()
    process.stdout.close()
    process.stderr.close()
    process.terminate()

Python with GPIO pins as buttons

Here's the modified Python code that integrates GPIO buttons for calling and terminating a call while keeping the existing functionality.

Key Modifications:

  • Added GPIO Initialization: Configures GPIO pins for the call and terminate buttons.
  • Loop for Button Interaction: Monitors the buttons and sends the corresponding SIP commands.
  • Uses send_command Function: Handles the command execution and ensures proper output handling.
import subprocess
import selectors
import time
import RPi.GPIO as GPIO

# GPIO Pin Configuration
CALL_BUTTON_PIN = 18  # GPIO pin for the call button
END_BUTTON_PIN = 23   # GPIO pin for the terminate button

# Configure GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(CALL_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # Pull-up resistor for call button
GPIO.setup(END_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # Pull-up resistor for end button

def send_command(process, command, delay=1):
    """Sends a command to linphonec and captures the output."""
    process.stdin.write(command + "\n")
    process.stdin.flush()
    time.sleep(delay)

    # Use selectors for non-blocking reading
    sel = selectors.DefaultSelector()
    sel.register(process.stdout, selectors.EVENT_READ)

    output = []
    timeout = time.time() + 5  # Set a timeout for reading (5 seconds)
    while time.time() < timeout:
        events = sel.select(timeout=1)
        for key, _ in events:
            line = key.fileobj.readline()
            if line:
                output.append(line.strip())
                print(line.strip())  # Optional: Print real-time output for debugging
            if "Ready" in line or "success" in line:  # Adjust the stopping condition
                sel.close()
                return "\n".join(output)

    sel.close()
    return "\n".join(output)

# Start linphonec process
process = subprocess.Popen(
    ["linphonec"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True,
    bufsize=1  # Line-buffered I/O
)

try:
    # Send the register command
    register_command = "register sip:435211@example.com mypassword sip:proxy.example.com"
    response = send_command(process, register_command)
    print("Register Response:", response)

    print("Ready for button interactions...")

    while True:
        # Check if the call button is pressed
        if GPIO.input(CALL_BUTTON_PIN) == GPIO.LOW:  # Button pressed (LOW)
            print("Call button pressed. Initiating call...")
            call_command = "call sip:+61412978633@sydney1.voip.ms"
            response = send_command(process, call_command)
            print("Call Response:", response)
            time.sleep(0.5)  # Debounce delay

        # Check if the end button is pressed
        if GPIO.input(END_BUTTON_PIN) == GPIO.LOW:  # Button pressed (LOW)
            print("End button pressed. Terminating call...")
            terminate_command = "terminate"
            response = send_command(process, terminate_command)
            print("Terminate Response:", response)
            time.sleep(0.5)  # Debounce delay

        time.sleep(0.1)  # Short delay to prevent high CPU usage

finally:
    print("Cleaning up resources...")
    GPIO.cleanup()  # Clean up GPIO
    quit_response = send_command(process, "quit")
    print("Quit Response:", quit_response)
    process.stdin.close()
    process.stdout.close()
    process.stderr.close()
    process.terminate()

How It Works:

  • Registration: The script sends the registration command to linphonec upon startup.

Button Press Detection:

  • When the call button is pressed, the call command is sent to initiate the call.
  • When the end button is pressed, the terminate command is sent to end the call.
  • Debouncing: A short delay prevents multiple signals from being processed due to button bounce.
  • Cleanup: Ensures GPIO pins are cleaned up and the Linphone process is terminated gracefully when the script exits.

Wiring the Buttons:

  • Connect one side of each button to the respective GPIO pin (e.g., GPIO 18 for the call button, GPIO 23 for the end button).
  • Connect the other side of each button to ground (GND).
  • Use internal pull-up resistors (GPIO.PUD_UP) to ensure stable signals.

Adding GPIO Pin commands to respond to button presses

To incorporate buttons connected to GPIO pins for initiating and terminating a call in your Python code, you can use the RPi.GPIO library. Here's how you can modify the existing script:

import subprocess
import RPi.GPIO as GPIO
import time

# Configure GPIO pins
CALL_BUTTON_PIN = 18  # Pin to initiate the call
END_BUTTON_PIN = 23   # Pin to terminate the call

# Configure GPIO settings
GPIO.setmode(GPIO.BCM)
GPIO.setup(CALL_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(END_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Linphone commands
linphonec_command = "linphonec"
call_command = "call sip:+61412978633@sydney1.voip.ms"
terminate_command = "terminate"

def send_command(process, command):
    """Sends a command to the Linphone process."""
    process.stdin.write(f"{command}\n")
    process.stdin.flush()

# Start Linphonec in subprocess
process = subprocess.Popen(
    linphonec_command,
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True
)

try:
    print("Ready for button inputs...")

    while True:
        # Check if the call button is pressed
        if GPIO.input(CALL_BUTTON_PIN) == GPIO.LOW:
            print("Call button pressed.")
            send_command(process, call_command)
            time.sleep(0.5)  # Debounce delay

        # Check if the end button is pressed
        if GPIO.input(END_BUTTON_PIN) == GPIO.LOW:
            print("End button pressed.")
            send_command(process, terminate_command)
            time.sleep(0.5)  # Debounce delay

        time.sleep(0.1)  # Short delay to avoid high CPU usage

except KeyboardInterrupt:
    print("Exiting...")

finally:
    # Clean up GPIO and terminate Linphone process
    GPIO.cleanup()
    send_command(process, "quit")
    process.terminate()
    process.wait()


  • GPIO Setup: CALL_BUTTON_PIN and END_BUTTON_PIN are configured as input pins with pull-up resistors.

When a button is pressed, it pulls the pin low (GPIO.LOW).

  • Linphone Commands: The call_command is triggered when the call button is pressed.

The terminate_command is triggered when the end button is pressed.

  • Debouncing: A short delay (time.sleep(0.5)) is added after a button press to prevent multiple triggers due to bouncing.
  • Graceful Exit: The script listens for a KeyboardInterrupt (Ctrl+C) to clean up GPIO and terminate the Linphone process properly.

Wiring the Buttons

  • Connect one leg of each button to its respective GPIO pin (CALL_BUTTON_PIN and END_BUTTON_PIN).
  • Connect the other leg of each button to the ground (GND).
  • The pull-up configuration ensures the GPIO pin is normally HIGH until the button is pressed.

Testing

  • Run the script on your Raspberry Pi.
  • Press the call button to initiate the call.
  • Press the end button to terminate the call.

Configuring GPIO Pins and resistors

When wiring a GPIO pin to a button, you should use either a pull-up or pull-down resistor to ensure the GPIO pin has a defined logic level when the button is not pressed. Here’s a step-by-step explanation:

Why Use a Resistor?

Without a pull-up or pull-down resistor, the GPIO pin would be in a "floating" state when the button is not pressed. This can lead to unpredictable behavior, as the pin could pick up electrical noise and produce erratic results.

Wiring Options

1. Pull-Down Resistor

  • The GPIO pin is pulled to low (0V) when the button is not pressed.
  • When the button is pressed, it connects the GPIO pin to high (3.3V on a Raspberry Pi).

Connection:

  • One leg of the button to 3.3V.
  • The other leg of the button to the GPIO pin.
  • A resistor (e.g., 10kΩ) connects the GPIO pin to GND.

2. Pull-Up Resistor

  • The GPIO pin is pulled to high (3.3V) when the button is not pressed.
  • When the button is pressed, it connects the GPIO pin to low (0V).

Connection:

  • One leg of the button to GND.
  • The other leg of the button to the GPIO pin.
  • A resistor (e.g., 10kΩ) connects the GPIO pin to 3.3V.

Internal Pull-Up/Pull-Down Resistors

Raspberry Pi GPIO pins have built-in software-configurable pull-up and pull-down resistors. This means you can avoid using external resistors by enabling the internal ones in your code.

Wiring Diagram for Pull-Down Resistor

[3.3V] ----- Button ----- GPIO Pin
                   |
                  [10kΩ]
                   |
                 [GND]

Wiring Diagram for Pull-Up Resistor

[GPIO Pin] ----- Button ----- GND
                   |
                  [10kΩ]
                   |
                [3.3V]

Using Internal Pull-Up/Pull-Down in Python You can configure the GPIO pins with internal resistors in your code using the GPIO.setup() method from the RPi.GPIO library. Example:

Pull-Up Configuration

GPIO.setup(button_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

Pull-Down Configuration

GPIO.setup(button_pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

Which to Use?

Pull-down is commonly used because pressing the button brings the pin high, which can be more intuitive (button pressed = logical 1). Pull-up is equally valid and often used in pre-existing designs.

Adding Speech Synthesis

To add simple speech synthesis to your code so that you can say "Call Edmond now..." when the call button is pressed, you can use the pyttsx3 library for text-to-speech synthesis. This library works offline and is compatible with Raspberry Pi.

Here's how you can modify your code to include speech synthesis:

Updated Code with Speech Synthesis import subprocess import RPi.GPIO as GPIO import time import pyttsx3 # Library for speech synthesis

  1. Configure GPIO pins

CALL_BUTTON_PIN = 18 # Pin to initiate the call END_BUTTON_PIN = 23 # Pin to terminate the call

  1. Configure GPIO settings

GPIO.setmode(GPIO.BCM) GPIO.setup(CALL_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(END_BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)

  1. Linphone commands

linphonec_command = "linphonec" call_command = "call sip:+61412978633@sydney1.voip.ms" terminate_command = "terminate"

  1. Initialize speech synthesis engine

engine = pyttsx3.init()

def speak(message):

   """Speak a given message."""
   engine.say(message)
   engine.runAndWait()

def send_command(process, command):

   """Sends a command to the Linphone process."""
   process.stdin.write(f"{command}\n")
   process.stdin.flush()
  1. Start Linphonec in subprocess

process = subprocess.Popen(

   linphonec_command,
   stdin=subprocess.PIPE,
   stdout=subprocess.PIPE,
   stderr=subprocess.PIPE,
   text=True

)

try:

   print("Ready for button inputs...")
   speak("System is ready for button inputs.")
   while True:
       # Check if the call button is pressed
       if GPIO.input(CALL_BUTTON_PIN) == GPIO.LOW:
           print("Call button pressed.")
           speak("Calling Edmond now.")
           send_command(process, call_command)
           time.sleep(0.5)  # Debounce delay
       # Check if the end button is pressed
       if GPIO.input(END_BUTTON_PIN) == GPIO.LOW:
           print("End button pressed.")
           speak("Ending the call.")
           send_command(process, terminate_command)
           time.sleep(0.5)  # Debounce delay
       time.sleep(0.1)  # Short delay to avoid high CPU usage

except KeyboardInterrupt:

   print("Exiting...")
   speak("Shutting down. Goodbye.")

finally:

   # Clean up GPIO and terminate Linphone process
   GPIO.cleanup()
   send_command(process, "quit")
   process.terminate()
   process.wait()

Explanation of Changes Added Speech Synthesis: Installed pyttsx3 (pip install pyttsx3). Initialized the speech engine using pyttsx3.init(). Added the speak() function to convert text to speech. Speech on Actions: When the system is ready: speak("System is ready for button inputs."). When the call button is pressed: speak("Calling Edmond now."). When the end button is pressed: speak("Ending the call."). When exiting: speak("Shutting down. Goodbye."). Install Dependencies Run the following command on your Raspberry Pi to install the required library:

pip install pyttsx3 Notes Voice Customization: You can customize the voice, rate, and volume of the speech by adjusting the pyttsx3 engine settings. For example: engine.setProperty('rate', 150) # Speed of speech engine.setProperty('volume', 0.9) # Volume (0.0 to 1.0) Performance: The speech synthesis might introduce slight delays, but they are generally negligible for this use case. Testing: Test the speech synthesis and ensure the GPIO buttons work as intended.

5. Write Python Code to Make Calls

Now that you have Linphone installed and configured, you can write a Python script to make calls to Australian mobile numbers. Below is a simple Python example that uses Linphone to place a call.

Step 5.1: Python Code to Make Calls with Linphone

import linphone
import time

# Initialize the Linphone core
core = linphone.Core()

# Define the SIP credentials (replace with your actual credentials)
sip_username = 'your_sip_username'  # VoIP.ms SIP username
sip_password = 'your_sip_password'  # VoIP.ms SIP password
sip_domain = 'sip.voip.ms'          # VoIP.ms SIP server

# Register with VoIP.ms SIP server
identity = f"sip:{sip_username}@{sip_domain}"
account = core.create_account(identity, sip_password)

# Define the phone number to call (Australian mobile number)
to_number = "+61XXXXXXXXX"  # Replace with the actual Australian mobile number

# Make the call
call = core.invite(to_number)

# Wait for the call to be answered
while call.state != linphone.CallState.Ended:
    time.sleep(1)

# End the call when finished
core.delete_call(call)
print(f"Call ended with status: {call.state}")

# Cleanup the core (close Linphone session)
core.destroy()

How This Code Works:

The script initializes the Linphone core, registers with your VoIP.ms SIP account, and then makes a call to the Australian mobile number. The script waits until the call is answered and then ends the call after it's completed.

6. Test the Call

Run the script:

python3 linphone_call.py

If everything is set up correctly, your Raspberry Pi will make a call to the provided Australian mobile number, and you'll be able to talk through the microphone and speaker on the Raspberry Pi.

7. Troubleshooting

If you don’t hear anything or can’t make calls, check the SIP account settings in Linphone. Make sure your Raspberry Pi’s microphone and speaker are working. If there are issues with audio, ensure that your Pi has the correct audio input and output devices selected.

Conclusion

You can use Linphone on your Raspberry Pi, along with a VoIP service provider like VoIP.ms, to make calls to Australian mobile numbers. This setup allows you to initiate and manage calls programmatically using Python.

By using SIP, you're able to make voice calls over the internet, bypassing traditional phone lines, and leveraging a low-cost solution for international calls.

Step 2: Adding Physical Buttons

  • Connect Buttons to GPIO: Connect large tactile buttons to GPIO pins on the Raspberry Pi using jumper wires and a breadboard. Each button corresponds to a contact.
  • Write a Button Script: Create a Python script to detect button presses and initiate calls:
from gpiozero import Button
from subprocess import call
import pyttsx3

# Define buttons and actions
button1 = Button(17)  # GPIO pin 17
button2 = Button(27)  # GPIO pin 27
engine = pyttsx3.init()

def call_contact(contact_name):
    engine.say(f"Calling {contact_name}")
    engine.runAndWait()
    call(["linphonec", "-c", contact_name])  # Replace with actual VoIP command

button1.when_pressed = lambda: call_contact("Alice")
button2.when_pressed = lambda: call_contact("Bob")

print("System ready. Press buttons to make calls.")
while True:
    pass


  • Run the Script:
  • Save the script (e.g., call_buttons.py) and execute it:
python3 call_buttons.py

Step 3: Setting Up VoIP (Internet Calling)

Install a SIP Client: Install a lightweight VoIP client such as Linphone:

sudo apt install linphone-cli

Configure SIP Account:Sign up for a VoIP service provider (e.g., Linphone, Asterisk, or Twilio) and configure the SIP client. Test Calls: Test internet calls using the command line:

linphonec
> call sip:example@domain.com

Step 4: Mobile Phone Interface (Optional)

Bluetooth Pairing: Install Bluetooth tools:

sudo apt install bluetooth bluez

Pair the Raspberry Pi with the mobile phone:

bluetoothctl
  • Use Bluetooth Protocols: Use protocols like HFP (Hands-Free Profile) to route calls through the Raspberry Pi:
  • Install and configure ofono and pulseaudio.
  • Test Call Routing: Verify audio routing from the mobile phone to the Raspberry Pi.

Step 5: Accessibility Features

Text-to-Speech Feedback: Add TTS for actions like confirming button presses and errors:

engine.say("Call in progress.")
engine.runAndWait()

Voice Commands (Optional): Install voice recognition libraries like SpeechRecognition:

pip3 install SpeechRecognition

Step 6: Enclosure Design

  • Build a Custom Case: Use a 3D-printed or handmade case to house the Raspberry Pi, buttons, speaker, and microphone.
  • Label buttons with Braille or large text for accessibility.
  • Add Power Backup: Include a portable battery pack for uninterrupted usage.

Step 7: Deployment and Testing

  • Predefine Contacts: Configure contact details in the script or VoIP client.
  • Test Audio Quality: Test speaker and microphone placement for optimal clarity.
  • Stress-Test for Usability: Simulate real-world use with seniors to refine the interface.