This guide walks through how I set up outbound voice calls from Home Assistant — where HA calls my mobile phone and plays a spoken TTS message. I use a Fritz!Box router with a Vodafone SIP connection, the TECH7Fox Asterisk add-on, and Google Translate TTS with ffmpeg for audio generation.
I also cover every debugging step I went through, so if something breaks for you, you know how to diagnose it.
My Setup
-
Home Assistant OS on Raspberry Pi
-
Vodafone cable connection in Baden-Württemberg, Germany
-
Fritz!Box router with Vodafone SIP connection
-
TECH7Fox Asterisk add-on (Home Assistant add-on store)
-
File Editor add-on (to edit Asterisk config files)
How It Works
HA Automation → script.make_tts_call → Google TTS → ffmpeg → Asterisk → Fritz!Box → Vodafone SIP → Your Phone
-
An automation triggers
script.make_tts_callwith a message and phone number -
HA generates a TTS audio file via Google Translate (free, no API key)
-
ffmpeg converts the MP3 to a WAV format Asterisk can play
-
Asterisk dials the primary number via Fritz!Box
-
If no answer after 30 seconds, it dials a fallback number
-
When answered, the voice message plays (repeated twice)
Phase 1 — Fritz!Box: Create an Internal SIP Account
Fritz!Box acts as your SIP proxy — it handles the Vodafone connection and Asterisk registers as an internal phone.
-
Open your browser → go to
fritz.box -
Go to Telephony → Telephony Devices → Configure New Device
-
Select Telephone (with and without answering machine)
-
Select LAN/WLAN (IP telephone)
-
Set name:
HomeAssistant -
Set username
HomeAssistant -
Set a password (e.g.
hapass123) — write this down -
Fritz!Box assigns an internal number like
**620— write this down -
Click Apply
Phase 2 — Install Asterisk Add-on
-
In HA go to Settings → Add-ons → Add-on Store
-
Click the three dots (top right) → Repositories
-
Add:
https://github.com/TECH7Fox/asterisk-hass-addons -
Search Asterisk → Install
-
Enable Start on boot and Watchdog → click Start
The add-on will create its config directory at:
/addon_configs/3e123456_asterisk/asterisk/custom/
Note: the folder ID (
3e123456_asterisk) may differ on your installation. Check/addon_configs/after first start.
Phase 3 — Configure Asterisk
Asterisk config files go in /addon_configs/3e123456_asterisk/asterisk/custom/. Use the File Editor add-on to create these files.
pjsip.conf
Important: This Asterisk version uses PJSIP, not the older SIP channel. Using
SIP/in dial strings will fail with “No channel type registered for ‘SIP’”.
Replace 620, hapass123, and HomeAssistant with the values from your Fritz!Box setup.
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5060
[fritzbox-auth]
type=auth
auth_type=userpass
username=HomeAssistant
password=hapass123
[fritzbox-aor]
type=aor
contact=sip:192.168.178.1
[fritzbox]
type=endpoint
outbound_auth=fritzbox-auth
aors=fritzbox-aor
from_user=HomeAssistant
from_domain=192.168.178.1
context=from-internal
disallow=all
allow=ulaw
allow=alaw
send_pai=yes
trust_id_outbound=yes
[fritzbox-reg]
type=registration
outbound_auth=fritzbox-auth
server_uri=sip:192.168.178.1
client_uri=sip:[email protected]
retry_interval=60
extensions.conf
This handles two scenarios:
-
[outbound]— simple single call with playback -
[alert-with-fallback]— calls primary number, falls back to secondary if no answer, sets caller name
[outbound]
exten => s,1,Answer()
same => n,Wait(2)
same => n,Playback(/media/ha_alert)
same => n,Hangup()
[alert-with-fallback]
exten => _+.,1,Answer()
same => n,Set(PRIMARY=${CUT(EXTEN,_,1)})
same => n,Set(SECONDARY=${CUT(EXTEN,_,2)})
same => n,Set(CALLERID(name)=Home Alert)
same => n,Dial(PJSIP/${PRIMARY}@fritzbox,30,A(/media/ha_alert))
same => n,GotoIf($["${DIALSTATUS}" = "ANSWER"]?done)
same => n,Dial(PJSIP/${SECONDARY}@fritzbox,30,A(/media/ha_alert))
same => n(done),Hangup()
Key design decisions:
-
Both numbers are encoded in the extension using
_as separator:Local/+49XXX_+49YYY@alert-with-fallback -
Answer()at the start stabilizes the LOCAL channel — without it, the channel dies after the firstDial()times out and the fallback never fires -
A(/media/ha_alert)plays the audio file to the called party immediately when they answer -
/nflag on the LOCAL channel disables optimization that was killing the channel between retries -
30-second ring timeout per number
Restart the Asterisk add-on after creating/modifying these files.
Phase 4 — TTS Audio Generation
Add these shell commands to your configuration.yaml:
shell_command:
generate_tts: "curl -s 'https://translate.google.com/translate_tts?ie=UTF-8&q={{ message | urlencode }}&tl=en&client=tw-ob' -A 'Mozilla/5.0' -o /media/ha_alert.mp3"
convert_tts: "ffmpeg -y -i /media/ha_alert.mp3 -filter_complex 'aevalsrc=0:c=mono:s=8000:d=1[silence];[0:a][silence][0:a]concat=n=3:v=0:a=1[out]' -map '[out]' -ar 8000 -ac 1 -acodec pcm_s16le /media/ha_alert.wav"
-
generate_tts— downloads TTS audio from Google Translate (free, no API key required) -
convert_tts— converts MP3 to 8kHz mono WAV (required by Asterisk) and repeats the message twice with a 1-second pause between
Note: Do not combine these into one command using
&&in a YAML>block — the line folding causes the&&to be passed incorrectly to the shell.
Restart HA after adding these.
Phase 5 — The Script
Create a reusable script in Settings → Scripts → Add Script → Edit in YAML:
alias: Make TTS Call
fields:
phone:
description: Primary phone number
example: "+4917XXXXXXXX"
fallback_phone:
description: Fallback phone number if primary does not answer
example: "+4917YYYYYYYY"
message:
description: Message to speak
example: "Motion detected at front door"
sequence:
- service: shell_command.generate_tts
data:
message: "{{ message }}"
- service: shell_command.convert_tts
- service: hassio.addon_stdin
data:
addon: 3e123456_asterisk
input: "channel originate Local/{{ phone }}_{{ fallback_phone }}@alert-with-fallback/n application Wait 120"
mode: single
Phase 6 — Using It in Automations
Add this to any automation’s action:
- service: script.make_tts_call
data:
phone: "+4917XXXXXXXX"
fallback_phone: "+4917YYYYYYYY"
message: "Motion detected at the front door"
Or with dynamic AI-generated messages (see bonus section below).
Debugging with Developer Tools
Throughout the setup, I used Developer Tools → Actions to test every step independently. Here is the full debugging sequence in order.
1. Verify the SIP peer connected to Fritz!Box
action: hassio.addon_stdin
data:
addon: 3e123456_asterisk
input: "pjsip show endpoints"
2. Make a test call using a built-in Asterisk sound
action: hassio.addon_stdin
data:
addon: 3e123456_asterisk
input: "channel originate PJSIP/+4917XXXXXXXX@fritzbox application Playback tt-monkeys"
If your phone rings and plays a monkey sound — Fritz!Box and Asterisk are connected correctly.
3. Verify a dialplan context loaded correctly
action: hassio.addon_stdin
data:
addon: 3e123456_asterisk
input: "dialplan show alert-with-fallback"
4. Reload dialplan without restarting add-on
action: hassio.addon_stdin
data:
addon: 3e123456_asterisk
input: "dialplan reload"
5. Test TTS generation
action: shell_command.generate_tts
data:
message: "Motion detected at front door"
Then check /media/ in File Editor for ha_alert.mp3.
6. Test WAV conversion
action: shell_command.convert_tts
Then check /media/ for ha_alert.wav.
7. Test full call with fallback
action: hassio.addon_stdin
data:
addon: 3e123456_asterisk
input: "channel originate Local/+4917XXXXXXXX_+4917YYYYYYYY@alert-with-fallback/n application Wait 120"
Hope this helps someone avoid the hours of debugging I went through! Feel free to ask questions in the comments.