VoIP stack for Home assistant and ESPHome

:telephone: VoIP Stack 2026.7.0: Home Assistant is a phone now. Yes, a real one. And your ESPs too.

This release changes the category of the project.

It started as an ESPHome full-duplex intercom.

It is now a local SIP/VoIP system built around Home Assistant.

Home Assistant can now act as a SIP softphone, call router, RTP bridge/resampler, local SIP registrar and optional SIP trunk endpoint. ESPHome devices become real SIP/SDP/RTP endpoints too: they can call each other, call Home Assistant, receive calls from Home Assistant, call registered softphones and, with a trunk configured, call or receive calls from external phone numbers.

This is the stable 2026.7.0 SIP/VoIP migration release.

It is a major breaking upgrade from the old intercom call model to SIP/SDP/RTP, so test custom YAMLs on spare hardware before upgrading devices installed in places where temporary audio glitches or call-routing regressions would be a problem.

Why this matters

With a SIP trunk configured, this is no longer just “an intercom card”.

You can build things like:

Scenario What happens
:telephone_receiver: Mobile phone calls home Your real mobile/landline call reaches Home Assistant through the SIP trunk, and HA can ring the softphone card or route the call to an ESP device
:door: Doorbell calls a real phone An ESP door station can call Home Assistant, an internal ESP, a registered softphone or an external number routed through HA
:house: Home Assistant as a house phone The Lovelace card can ring, answer, decline, hang up and start calls as Home Assistant itself
:pager: ESP room phones ESPHome devices can call each other by phonebook name or extension
:telephone: Standard SIP softphones Zoiper, Linphone, baresip or pjsua can register directly to Home Assistant and become internal contacts
:globe_showing_europe_africa: Call home from outside Call your SIP trunk number from anywhere and route the inbound call to HA or internal devices
:mobile_phone_with_arrow: Call external numbers from ESPs ESP devices can call phonebook contacts that resolve to external trunk numbers

No Asterisk box required beside Home Assistant for the normal local use case.

External calls: mobile phones, landlines and the outside world

This is the part that makes the project stop looking like a gadget and start looking like a tiny local phone system.

With the optional SIP trunk enabled, Home Assistant can register to a provider or PBX trunk.

That means:

Direction Example
External → Home Assistant Call your trunk number from a mobile phone and make the HA softphone card ring
External → ESP Call your trunk number and route the call to a door panel, room phone or wall display
ESP → external Press a button or select a contact on an ESP and call a mobile or landline through HA
HA → external Use the Lovelace softphone card to call a public number
Softphone → external Register Zoiper/Linphone to HA and call out through the trunk
External → internal extension Use DTMF / route hints to reach a local contact such as 101

So yes: a doorbell can call your phone, your phone can call home, and Home Assistant can sit in the middle doing the routing.

Provider behavior varies, especially around codecs, DTMF and NAT, so trunk feedback is especially useful.

Component showcase

Icon Component Role
:house: voip_stack Home Assistant integration SIP softphone, B2BUA/router, bridge, resampler, phonebook publisher, local registrar and optional trunk client
:telephone: VoIP Stack Lovelace card HA softphone UI and ESP mirror/control UI
:pager: esphome-voip-stack ESPHome SIP phone component: SIP/SDP/RTP, call FSM, phonebook, entities, actions and triggers
:speaker_high_volume: esphome-audio-stack Full-duplex ESPHome audio backend with I2S/codec ownership, AEC, AFE and clean mic/speaker surfaces
:brain: esphome-runtime-controller Deterministic reducer for Voice Assistant, media, TTS, timers, VoIP, mute, LEDs and display state
:books: Phonebook / dial plan Central routing model shared between HA, ESP devices, registered softphones and trunk contacts

Home Assistant is now a phone

The Home Assistant card has a real softphone mode.

It can:

  • ring on incoming calls;
  • answer from browser, wall tablet or Companion app;
  • decline with a SIP reason;
  • hang up active calls;
  • place outbound calls;
  • dial a phonebook contact, extension, SIP URI or external number;
  • bridge calls toward ESPs, registered softphones or the optional trunk.

There are two card modes:

Mode Use it for
ha_softphone Home Assistant itself is the phone
Hybrid / ESP mirror The card mirrors and controls a selected ESP phone

If an ESP calls Home Assistant, the HA softphone card rings.

If Home Assistant calls an ESP, the ESP rings.

If auto-answer is enabled on either side, the call can be accepted automatically.

ESPHome devices are SIP phones now

ESP devices do not register to a PBX.

They are local SIP user agents. Home Assistant learns them through ESPHome, reads their endpoint identity, publishes them into the shared phonebook and routes calls when needed.

Each ESP can be one of four endpoint types:

Mode Media path Example
full_duplex Microphone TX + speaker RX Door intercom, room phone, wall panel
mic_only Microphone TX only Monitor microphone, outdoor call station
speaker_only Speaker RX only Paging speaker, announcement target
control_only SIP signaling and state only LVGL panel, button panel, call-state display

Mic-only and speaker-only are first-class modes, not broken full-duplex devices.

Phonebook-driven routing

The central phonebook is now the dial plan.

A contact can represent:

  • an ESP endpoint;
  • Home Assistant itself;
  • a registered SIP softphone;
  • a manual SIP URI;
  • an internal extension;
  • an external number through the optional trunk;
  • a routed target handled by Home Assistant.

Routing follows the data available for the selected contact:

Contact data Route
Direct SIP endpoint Compatible ESPs can call it directly
Name or extension only ESP sends the call to Home Assistant
Registered softphone HA routes to the active SIP registration
External number HA uses the configured SIP trunk
No valid route HA rejects the call with a readable reason

The phonebook is also pushed automatically to online ESP devices when HA contacts, ESP endpoints or registered softphones change.

Voice Assistant integration

VoIP Stack can optionally expose Assist intents.

That means voice satellites can call, answer, decline or hang up using voice commands.

Examples:

Call Kitchen
Call Garage
Answer
Decline
Hang up

Spoken names are resolved against the live phonebook, so you do not need to hardcode every low-level route in YAML.

Full voice device: media, TTS, wake word and VoIP on the same ESP

One of the goals of this release is keeping the “everything device” viable:

  • media playback;
  • Music Assistant / Sendspin;
  • TTS;
  • Micro Wake Word;
  • Voice Assistant;
  • AEC / AFE;
  • ringtone;
  • VoIP calls;
  • LVGL display state.

The maintained full-experience profiles now use a shared media/source path and the runtime reducer model so callbacks report state instead of fighting over LEDs, displays and audio policy.

On my current tested full voice ESP32-S3 profile, the complete stack can coexist around the 22–23% CPU range, depending on hardware profile and enabled features.

ESP Audio Stack split

The reusable audio backend now lives here:

ESPHome Audio Stack

It provides:

  • full-duplex I2S ownership;
  • shared codec bus support;
  • split RX/TX bus support;
  • TDM support;
  • hardware codec backends;
  • speaker reference handling for AEC;
  • software AEC through Espressif ESP-SR;
  • full AFE pipeline with noise suppression, VAD, AGC and dual-mic Speech Enhancement;
  • ESPHome microphone and speaker platforms on top.

Supported codec families currently include ES7210, ES8311, ES8388, ES8374 and ES8389.

ESPHome VoIP Stack split

The ESP SIP component now lives here:

ESPHome VoIP Stack

It provides:

  • SIP signaling over UDP or TCP;
  • SDP offer/answer;
  • RTP media;
  • jitter buffer;
  • call FSM;
  • endpoint identity publishing;
  • local phonebook;
  • per-direction PCM negotiation;
  • ESPHome actions, triggers, conditions and entities.

RTP media is UDP in both SIP transport modes.

Runtime Controller split

The runtime arbitration component now lives here:

ESPHome Runtime Controller

It solves the classic “last callback wins” problem on complex ESPHome devices.

Instead of Voice Assistant, media, VoIP, timers, mute and connectivity all writing directly to LEDs or display state, they report facts. The reducer resolves one coherent device state.

That means fewer stuck LEDs, fewer display races, fewer ducking bugs and fewer YAML goblin rituals.

Screenshots and demos

Tested / maintained target families

The maintained YAMLs focus mainly on ESP32-S3 and ESP32-P4 voice hardware.

Examples include:

Target Notes
Waveshare ESP32-S3 Audio Board Full voice / VoIP profile target
Spotpear Ball v2 Voice UI, Assistant, media and VoIP testing
Waveshare ESP32-P4 Touch Display-heavy P4 target, still useful for tuning and feedback
Generic ESP32-S3 with I2S mic/speaker Native and audio-stack profiles
INMP441 + MAX98357A-style builds Useful for simple duplex tests
XMOS / external DSP front-ends Can use native ESPHome audio paths when echo cancellation is already handled in hardware

Installation

Home Assistant

VoIP Stack is available through HACS.

Search for:

VoIP Stack

Then install, restart Home Assistant and add the integration from:

Settings → Devices & services → Add integration → VoIP Stack

Use the custom repository flow only if you intentionally want to test main or development builds directly:

https://github.com/n-IA-hane/esphome-intercom

Default ports:

Purpose Default
SIP 5060
RTP base 40000

The integration automatically registers the Lovelace card.

ESPHome: VoIP only

external_components:
  - source: github://n-IA-hane/esphome-voip-stack@main
    components: [voip_stack]

ESPHome: VoIP + lightweight AEC

external_components:
  - source: github://n-IA-hane/esphome-voip-stack@main
    components: [voip_stack]
  - source: github://n-IA-hane/esphome-audio-stack@main
    components: [esp_audio_stack, esp_aec]

ESPHome: VoIP + full AFE

external_components:
  - source: github://n-IA-hane/esphome-voip-stack@main
    components: [voip_stack]
  - source: github://n-IA-hane/esphome-audio-stack@main
    components: [esp_audio_stack, esp_afe]

ESPHome: runtime reducer

external_components:
  - source: github://n-IA-hane/esphome-runtime-controller@main
    components: [runtime_controller]

Or use the ready package for full voice + VoIP profiles:

packages:
  runtime_controller: github://n-IA-hane/esphome-runtime-controller/packages/runtime_controller/full_controller.yaml@main

Upgrade notes

This is a breaking migration from the old project-specific call-control model to SIP/SDP/RTP.

Please review custom YAMLs before upgrading.

Important notes:

  • ESP devices are local SIP phones, but they do not REGISTER to a provider or PBX.
  • Home Assistant owns external trunk registration.
  • RTP media is UDP even when SIP signaling uses TCP.
  • Audio is negotiated per direction.
  • AFE/AEC microphone output remains 16 kHz by design.
  • HA bridging is the supported path for incompatible direct media formats.
  • UDP high-rate audio is limited by datagram size.
  • Use TCP signaling when routed/VPN/remote network behavior is uncertain.
  • Do not expose random SIP/RTP ports directly to the public internet unless you enjoy packet goblins chewing your logs.

Migration from the old intercom thread

If you were using the previous intercom releases, this is the new direction of the project.

The old simple use case still works:

ESP button → Home Assistant rings → answer → talk → hang up

The difference is that the foundation is now SIP/VoIP, so the same setup can grow into:

ESP ↔ ESP
ESP ↔ Home Assistant
Home Assistant ↔ registered softphone
ESP ↔ registered softphone through HA
Home Assistant ↔ external phone number through trunk
ESP ↔ external phone number through trunk

Links

Feedback wanted

I am especially interested in real-world feedback around:

  • ESP ↔ ESP calls;
  • ESP → HA softphone calls;
  • HA softphone → ESP calls;
  • registered softphones;
  • SIP trunk inbound and outbound routing;
  • DTMF / route-hint behavior;
  • VLANs, VPNs, routed networks and weird NAT setups;
  • mixed 16 kHz / 48 kHz audio paths;
  • Waveshare S3, Spotpear, Waveshare P4 and generic ESP32-S3 profiles.

This started as an intercom.

Now Home Assistant has a local phone system living inside it. :telephone::house:

4 Likes

Can I use this project out of the box in order to set up Assist to be my answering machine when I'm away?

1 Like

Yes, with the version that has just been released, this is exactly what I focused on.

My friends are currently hammering my VoIP Stack because they find it hilarious to call my phone number and talk to the assistant, since it swears at them and tells them to fuck off.

You can create an automation so that, when an incoming call arrives, it is not sent directly to the Home Assistant softphone but is immediately routed to the Voice Assistant instead.

The assistant now has its own extension, which you can choose. You can also call it directly from a softphone by using its name. For testing, I use Zoiper: if I enter “Troiaio”, which is the name of my assistant, as the destination and place the call, I can talk to it.

I am pointing this out because, despite having worked with PBXs for years, I did not know that VoIP could use a literal string as the called destination. I had always assumed that everything had to be based on numeric extensions. This may be useful information for other users reading this as well.

In VoIP Stack, you can place SIP calls to both numeric extensions and literal string destinations. Alternatively, you can assign the assistant a conventional extension such as 1001 and call it from any VoIP endpoint known to Home Assistant.

You can also reach it through an external phone call. You call the number associated with your trunk, and the call reaches the Home Assistant VoIP Stack. It then waits for a configurable number of seconds for DTMF input before forwarding the call to the Home Assistant softphone.

If, during that time window, you enter 1001 from the calling phone, the call is routed to the Voice Assistant and you can talk to it.

1 Like

:telephone: VoIP Stack 2026.7.1: Call Home Assistant Assist, Ring Groups, Conferences And A Better Phone UI

VoIP Stack 2026.7.1 is now available through HACS.

This release turns Home Assistant’s voice assistant into a real telephone destination, adds ring groups and conference rooms, improves the Lovelace phone experience
and hardens the SIP, RTP and ESPHome audio paths for everyday use.

The short version:

You can now call your Home Assistant voice assistant from an ESP device, a SIP softphone or a real external phone number — and have a normal multi-turn spoken
conversation with it.

VoIP Stack dashboard in action


:speaking_head: Call Home Assistant Assist By Phone

VoIP Stack can now expose any Home Assistant Assist pipeline as a normal phonebook destination.

Enable Include voice assistant, choose either HA’s preferred Assist pipeline or a specific pipeline, then assign it an extension.

No extension is reserved automatically: you choose one that fits your own dial plan.

The assistant can then be called from:

  • an ESPHome VoIP device;
  • Home Assistant’s softphone;
  • Zoiper, Linphone, bareSIP or another registered SIP client;
  • another compatible SIP endpoint;
  • an external mobile or landline through an optional SIP trunk;
  • an initial Home Assistant inbound routing decision.

The assistant appears in the same shared phonebook as every other destination. You can call it by its numeric extension or, where supported by the client, directly
by its name.

The assistant can greet the caller first

When a call starts, Assist receives the original SIP caller identity as its first textual turn.

If the caller matches a phonebook entry, its friendly name is used. Otherwise, the original SIP caller string or telephone number is preserved.

This makes prompts such as these possible:

  • greet family members by name;
  • answer a door station differently from a normal internal phone;
  • act as a polite answering machine for direct Assist calls;
  • behave differently when called from a specific ESP or SIP extension.

After the initial greeting, the same telephone call stays open:

  1. Home Assistant listens through the selected STT provider;
  2. the configured conversation agent processes the request;
  3. the configured TTS provider streams the reply into the call;
  4. Assist returns to listening;
  5. the conversation continues until the caller hangs up.

Conversation context is retained between turns.

This uses the selected native Home Assistant Assist pipeline. It is not tied to a particular provider or to my own test setup: Piper, Wyoming services, local or
cloud STT/TTS providers and other HA conversation agents follow the pipeline already configured in Home Assistant.

No second SIP port, generated satellite or separate Home Assistant VoIP integration is required.


:office_worker:Voice Assistant Calls Today Automated Secretary Scenarios Next

Calling Home Assistant Assist by phone is already fully available in 2026.7.1.

The assistant is a normal destination in the shared phonebook and can already be called:

  • directly from an ESPHome VoIP device;
  • from Home Assistant’s softphone;
  • from a registered client such as Zoiper or Linphone;
  • by its phonebook name or numeric extension;
  • from an external mobile or landline through an optional SIP trunk;
  • from an initial Home Assistant inbound routing decision.

The call remains open for a normal multi-turn conversation. Assist receives the caller identity, greets the caller, listens through the selected STT provider and
streams each TTS response back into the same telephone call until the caller hangs up.

Coming in the next versions

The next step is exposing all the remaining hooks required to build advanced answering-machine and domestic-secretary scenarios entirely with normal Home Assistant
automations.

The intended automation model is:

Incoming call
     ↓
Ring Home Assistant, a ring group or selected house phones
     ↓
Wait for a user-defined period
     ↓
If the same call is still unanswered
     ↓
Forward that existing call to Voice Assistant

The automation will be able to retain the original SIP dialog, Call-ID and caller identity while forwarding the still-ringing call to Assist.

This will make scenarios such as these possible:

Nobody answers within 30 seconds → forward the existing call to Assist
At night → ring briefly, then let Assist answer
Away from home → use Assist as an answering machine
Door station unanswered → let Assist greet the visitor
External caller unanswered → let Assist collect a message

The goal is not to introduce a second hard-coded fallback engine.

VoIP Stack will expose the necessary call events, state and forwarding actions, while the user defines the actual policy with standard Home Assistant building blocks
such as conditions, timers, presence, schedules and wait_for_trigger.

The phonebook remains the default dial plan, and Home Assistant automations become an optional programmable layer above it.

Direct internal and external calls to the Voice Assistant are already supported in 2026.7.1. Only the delayed ring first, then forward the same unanswered call
automation contract is planned for a future release.


:bell: Real Ring Groups

Endpoints can now join one or more ring groups.

Call a contact such as RG Home and all available members ring together. A group can contain:

  • Home Assistant’s softphone;
  • ESPHome phones;
  • registered SIP clients;
  • manual SIP contacts.

The first endpoint to answer wins. The remaining legs are cancelled, and late answers cannot steal or duplicate the established call.

After the call is answered, the Lovelace card shows the endpoint that actually answered instead of continuing to display only the group name.

Group contacts are generated from live membership and disappear automatically when no endpoint declares them.


:studio_microphone: Home Assistant Conference Rooms

Home Assistant can now host SIP conference rooms.

Calling a destination such as CG Home joins that conference. Endpoints with Ring on conference enabled can also be invited automatically when the room starts.

The conference focus:

  • mixes active participants;
  • applies additional audio headroom as the room grows;
  • manages invited call legs;
  • releases calls and RTP resources when participants leave.

Home Assistant, ESP devices and registered SIP phones can participate in the same conference.


:house: Home Assistant And Registered SIP Phones Are First-Class Endpoints

Home Assistant’s softphone can now publish and persist:

  • its own extension;
  • Do Not Disturb;
  • ring-group membership;
  • conference-group membership;
  • whether it should ring when a conference starts.

These values can be changed from the card or through Home Assistant services. They are stored by the integration and survive integration reloads and complete Home
Assistant restarts.

Registered clients such as Zoiper and Linphone can also have:

  • a friendly display name;
  • an extension;
  • ring-group membership;
  • conference-group membership;
  • conference-ringing preferences.

Extensions, groups, ESP endpoints, registered phones and optional trunk destinations all resolve through the same shared phonebook and dial plan.

Incoming callers do not need to exist in the phonebook. Unknown but reachable and protocol-compatible SIP callers can still ring HA or an ESP, subject to the
usual destination, DND and busy checks.


:control_knobs: A More Useful Lovelace Phone Card

The Lovelace card received a substantial usability pass.

Manual keypad

HA and ESP mirror cards can dial:

  • a phonebook name;
  • an extension;
  • a full SIP URI;
  • a telephone number.

ESP endpoint options

The ESP mirror Options view exposes supported endpoint settings such as:

  • Auto Answer;
  • Do Not Disturb;
  • extension;
  • ring groups;
  • conference groups;
  • Ring on conference.

The card remains a mirror and controller: the selected ESP is still the real owner of its call state and settings.

Shared phonebook mode

The same card can render the canonical Home Assistant VoIP phonebook.

Contacts are sorted alphabetically, the view uses the available Home Assistant Sections grid space, and longer lists scroll inside the assigned card area.

Sections and live availability

HA softphone, ESP mirror and phonebook modes respond to the width and height assigned by Home Assistant Sections.

If no card name or title is configured, the header row is omitted completely.

ESP mirror cards also follow the bound endpoint live:

  • ESP disconnects → card becomes unavailable;
  • ESP reconnects → card recovers automatically.

No dashboard reload or polling timer is required.

Scrolling at the end of a card is handed back to the surrounding dashboard, and native selectors remain readable in both light and dark themes.


:mobile_phone: Waveshare P4 Touch Phone UI

The maintained Waveshare P4 Touch profile now has an on-device telephone interface.

Its VoIP panel can switch explicitly between:

  • Contacts
  • Keyboard

The local keypad calls through the same phonebook and dial plan as the rest of the system. Calls are not implemented through a second parallel routing path.

Assist, media, timers, calls, ringtone, LEDs, display state and ducking now converge through the shared runtime controller.

This removes several “last callback wins” races that could previously leave the display, LED or audio policy in the wrong state.


:telephone_receiver: More Predictable SIP Calls

A large part of this release is less visible but important during real use.

Call setup and teardown now match the correct:

  • Call-ID;
  • CSeq;
  • SIP branch;
  • dialog tags;
  • remote peer.

Cancellation, decline, busy, answer, hangup and immediate redial have deterministic ownership and cleanup.

The Hang Up action remains available while a call is still in calling, including slow or unreachable external destinations.

A cancellation that crosses a successful answer is completed with the proper acknowledgement and teardown instead of leaving a ghost call.

Unsupported hold or codec-changing re-INVITE requests receive 488 Not Acceptable Here without destroying the existing call.

SIP authentication retries were also corrected for stricter PBX and FRITZ!Box implementations.

Home Assistant calling an   ESPHome VoIP endpoint

Cross-transport SIP call bridged by   Home Assistant


:1234: Better DTMF Routing

Initial extension routing supports:

  • standard RTP telephone-event;
  • compatible legacy SIP INFO DTMF;
  • digits entered at normal human speed.

This is the path used, for example, when an external caller reaches the trunk and enters the extension of an ESP, registered phone or Voice Assistant.

:test_tube: Experimental: DTMF Events During A Call

During an already established call bridged by Home Assistant, every DTMF key can also fire a voip_stack.dtmf event.

This enables automations such as:

Press 1 during the intercom call to open the gate.

triggers:
  - trigger: event
    event_type: voip_stack.dtmf
    event_data:
      source: Cordless
      digit: "1"

actions:
  - action: cover.open_cover
    target:
      entity_id: cover.gate

Events include the caller, callee, source leg, digit, call identifiers and transport.

This path is deliberately separate from initial extension routing:

  • an in-call key does not transfer the call;
  • audio continues normally;
  • detection happens entirely in Home Assistant;
  • no additional real-time parser is added to ESP firmware.

This feature is experimental in 2026.7.1. Use strict caller/source filters and test carefully before associating phone keys with locks, gates or other security-
sensitive devices.


:speaker_high_volume: Audio And Real-Time ESPHome Improvements

Browser and ESP audio paths received another qualification and cleanup pass.

Highlights include:

  • stateful browser codecs;
  • bounded audio queues;
  • absolute packet pacing;
  • a short browser microphone jitter buffer;
  • PCMA/G.711 level correction for normal telephone earpieces;
  • L16 48 kHz and Opus 48 kHz where supported;
  • conversion state prepared outside per-frame processing;
  • no arbitrary delays added to ESP real-time loops.

Generic software-AEC profiles now use a previous-frame reference by default.

The optional ring-buffer reference is aligned when a microphone consumer starts, so a new call cannot begin using stale playback audio accumulated before the call.

The AFE worker is persistent and event-driven. It sleeps while idle and wakes from notifications instead of relying on fixed polling delays.

Waveshare P4’s real-time I²S/AFE bridge remains in internal RAM. Its AEC path was exercised while Sendspin, TTS and bidirectional VoIP were active together.


:white_check_mark: Tested On Real Hardware And Real Calls

The release was qualified with:

  • Waveshare ESP32-S3 Audio;
  • Spotpear Ball v2;
  • Waveshare ESP32-P4 Touch;
  • generic ESP32-S3 native and audio-stack profiles;
  • Home Assistant softphone calls;
  • ESP-to-HA, HA-to-ESP and ESP-to-ESP calls;
  • registered SIP clients;
  • callers absent from the phonebook;
  • ring groups and conferences;
  • DND and Auto Answer;
  • external calls through a real SIP trunk;
  • mixed 8, 16 and 48 kHz media paths;
  • concurrent Sendspin, TTS and VoIP load.

Assist was tested both from a locally registered SIP client over Opus 48 kHz and from an external mobile caller through a PCMA 8 kHz trunk.

The external call retained one conversation over three spoken turns, including a Home Assistant control request, without RTP drops or media errors.


:warning: Important Boundaries

A few limits remain intentional:

  • ESP SIP/RTP is plaintext and belongs on a trusted LAN, VPN or behind an SBC;
  • RTP media remains UDP even when SIP signalling uses TCP;
  • full SIP hold/resume renegotiation is not implemented;
  • acoustic in-band DTMF tones are not decoded;
  • AFE/AEC microphone output remains 16 kHz by design;
  • Home Assistant bridging is the supported path when endpoints cannot negotiate compatible media directly.

:package: Installation And Upgrade

Install or upgrade VoIP Stack through HACS, then restart Home Assistant when prompted.

After upgrading, open:

Settings → Devices & services → VoIP Stack

Use Reconfigure to enable the optional Voice Assistant endpoint, choose its pipeline and assign an extension.

Users compiling the maintained ESPHome profiles should update their project sources and rebuild the relevant device firmware.

Full source, YAML examples and documentation:

GitHub - n-IA-hane/esphome-intercom: VoIP Stack for ESPHome and Home Assistant - local SIP phones, HA softphone/router, phonebook, softphone accounts and optional trunk calls · GitHub

Stable release:

Release 2026.7.1: Assist By Phone, Groups And A Stronger VoIP Stack · n-IA-hane/esphome-intercom · GitHub

I would especially appreciate real-world feedback about:

  • different SIP providers and PBXs;
  • FRITZ!Box registration;
  • direct internal and external Assist calls;
  • ideas and requirements for the upcoming answering-machine and secretary automation hooks;
  • ring and conference groups;
  • VLAN, VPN and routed-network setups;
  • mixed-codec calls;
  • custom ESPHome audio hardware.

This project started as an ESPHome intercom.

With 2026.7.1, Home Assistant can answer the telephone with its own voice assistant. :telephone::house::speaking_head:

3 Likes

That is indeed hilarious. I will try it out the end of this month. Thanks beforehand for the nice project. I’ll get in touch if I have any questions left :slight_smile:

Really packed with functionalities :slight_smile:
I wonder if / how we can make an ESP satellite call the home assistant host by voice? Would be useful for my wife who is a little bit tech impaired :wink:

This is already supported. You just need to enable the relevant option in the component’s config flow.

After that, it all depends on how accurate your assistant’s speech recognition is. I sometimes run into issues simply because it understands one word as another.

For example, suppose your Home Assistant instance is called “Home.” You say, “Call Home” to your assistant. If it correctly understands “Call Home,” the call goes through. If it understands “Call Moon,” then obviously the call fails, or the assistant replies with a generic response.

Cool!
Is “Home” in your example the actual name of my HA instance, or some other name I configure somewhere in your integration?


This.

Native SIP video is coming to the Home Assistant softphone :movie_camera::telephone:
A fairly substantial development update has landed in VoIP Stack 2026.7.2-dev.
We are now dangerously close to turning a Lovelace card into a real native SIP video phone.
Home Assistant SIP video call
The Home Assistant softphone can now negotiate and exchange video with standard SIP endpoints and PBXs using normal SIP/SDP/RTP media negotiation.

ha-sip-video-call
What is working
• Native video inside the VoIP Stack Lovelace card
• Direct H.264, VP8 and RFC 2435 JPEG
• Bidirectional browser camera video with H.264 or VP8
• Independent send and receive directions
• Manual answer or auto-answer
• Receive-only calls when the local camera is disabled
• Camera enable/disable during an active call
• Correct Calling, Ringing and In call card states
• Local hangup, remote BYE and caller CANCEL
• SIP video through authenticated PBX/trunk calls
• Optional receive-only FFmpeg conversion for H.263, H.263-1998 and H.265
The video fills the card while call identity, duration and hangup controls remain available in a responsive bottom bar.
ESPHome voice endpoints remain audio-only. The video path belongs to the Home Assistant browser softphone.
Real SIP qualification
This is no longer only a mocked browser demo.
The current build has been tested between two independent Home Assistant installations registered as normal SIP extensions through a Wildix PBX. Testing covered both call directions, ringing, answer, auto-answer, decline, CANCEL, BYE, camera-disabled calls
and live camera toggling.
The captured signaling uses normal SDP media descriptions such as:
m=video RTP/AVP 103 104
a=rtpmap:103 H264/90000
a=fmtp:103 profile-level-id=42800d;packetization-mode=1;level-asymmetry-allowed=1
a=rtpmap:104 VP8/90000
a=sendrecv
There are no Wildix-specific video parameters or proprietary media protocols involved.
Home Assistant can now control the dial plan
This release also introduces automation-native call routing.
For example, Home Assistant can ring first and forward the same unanswered call to an Assist
extension after 30 seconds:
alias: VoIP - HA unanswered to Assist
mode: parallel
For example, Home Assistant can ring first and forward the same unanswered call to an Assist
extension after 30 seconds:
alias: VoIP - HA unanswered to Assist
mode: parallel
triggers:

Is there any sensors included in this stack that will tell me if a call is incoming, and from which number? I’d like to create an automation to broadcast a TTS to my speakers on incoming calls.

Yes, I’m working on this, and it’s exactly the type of scenario I want to open up. To be able to create advanced dial plans using Home Assistant automations, I’m trying to expose as many hooks, triggers, and conditions as I can, also to cover any scenarios I haven’t considered but that might be useful to users.

1 Like

Nice job @meconiotech I was just looking into deployeing asterisk into my homelab for stuff like this, this hits the spot. what i dont understand or maybe i missed in the very well written documentation is how do i create extensions? i was expecting this to be an add-on(app) wher i could manage stuff but i just cant find where i create my extensions

Call this service from developer tool voip_stack.create_account