You have spent weeks dialing in your Home Assistant setup. Your Zigbee mesh is rock-solid, your dashboards are clean, and your ESP32-S3 voice satellites are positioned strategically throughout the house. But every time your smart home announces that the front gate was left open or that the laundry cycle finished, the experience falls apart. Either you are paying a latency penalty waiting for a distant cloud server to respond, or your local fallback sounds like a 1995 desktop sound card rendering robotic monotone.
Local voice synthesis shouldn’t feel like a technical compromise. You don’t need a dual-RTX 4090 server running in your basement just to hear natural, warm, human speech. By leveraging Piper TTS inside Home Assistant Operating System (HAOS), you can generate custom, broadcast-grade voice models locally on low-power hardware with sub-100 millisecond response times. Let’s walk through how to build, fine-tune, and deploy custom Piper neural voices directly into your Home Assistant environment.
To run custom Piper TTS voices in HAOS with sub-100ms latency, train or fine-tune a VITS ONNX model at medium quality (22.05 kHz), package the `.onnx` and `.onnx.json` files into the custom voice directory, register the Wyoming service integration, and configure your multi-speaker mapping inside `configuration.yaml` for optimal RAM footprint and CPU execution.
How Does the VITS Neural Model Generate High-Fidelity Speech Locally?
To optimize local voice synthesis, you first need to understand what is happening under the hood when Home Assistant transforms text strings into raw PCM audio bytes. Legacy local engines relied on concatenative synthesis (stitching together tiny pre-recorded audio fragments) or simple formant synthesis. Both methods produce grating, robotic audio because they fail to model how human pitch, emphasis, and cadence shift contextually based on sentence structure.
Piper bypasses these limitations by implementing the VITS (Variational Inference with adversarial learning for end-to-end Text-to-Speech) architecture. VITS is a generative neural network that combines three distinct components into a single, cohesive end-to-end pipeline:
- Text Encoder & Phonemizer: Incoming text strings are normalized and converted into sequence-aligned phonemes using
eSpeak-ng. The text encoder converts these phoneme sequences into an intermediate linguistic representation. - Stochastic Duration Predictor & Flow Module: Speech isn’t mechanical; the word “open” sounds different when spoken as an urgent warning versus a calm confirmation. The flow-based module uses variational inference to map linguistic features to a continuous latent representation, injecting realistic micro-variations in speech tempo and pitch pitch accent.
- Decoder (Neural Vocoder): A modified HiFi-GAN generative adversarial network converts the latent representation directly into raw, high-frequency audio waveforms.
The engineering breakthrough of Piper isn’t just that it uses VITS, but that it exports these complex neural graphs into optimized ONNX (Open Neural Network Exchange) runtime models. By executing INT8 or FP32 quantized ONNX models, low-power CPUs—such as the Intel N100 or ARM64 processors found on the Raspberry Pi 4 and 5—can compute matrix multiplications using vector instruction sets (AVX2 on x86, NEON on ARM). This yields a Real-Time Factor (RTF) of < 0.10, meaning 1 second of broadcast-quality speech is synthesized in under 100 milliseconds without requiring a discrete GPU.
What Quality Tier Should You Choose for Home Assistant Hardware?
A common pitfall when configuring Piper voices is assuming that higher quality tiers always yield a superior smart home experience. Piper voice models are compiled into three distinct quality profiles: low, medium, and high. Choosing the wrong tier for your host machine causes audio stuttering, dropped frames over Wyoming satellites, and high RAM consumption.
The primary performance bottleneck is not raw disk storage; it is the mathematical overhead of the neural vocoder at higher sampling rates. A high quality model synthesizes wideband audio at 22.05 kHz or 44.1 kHz using significantly higher hidden-layer parameter dimensions. If your HAOS host is running multi-container stacks alongside Home Assistant (such as Frigate NVR or Plex), multi-threaded TTS synthesis on a high-tier voice will trigger CPU thread contention.
The table below breaks down the technical profiles, resource requirements, and real-world performance benchmarks across host hardware tiers:
| Quality Tier | Sample Rate & Encoding | RAM Footprint | RTF (Intel N100 / Pi 5) | Optimal Home Assistant Use Case |
|---|---|---|---|---|
| Low | 16.0 kHz / 16-bit Mono | ~15 MB – 25 MB | 0.02 – 0.04 (Blazing) | Embedded microcontrollers, high-frequency sensor announcements, low-RAM Raspberry Pi 3/4 builds. |
| Medium | 22.05 kHz / 16-bit Mono | ~50 MB – 75 MB | 0.05 – 0.08 (Sub-100ms) | The Golden Middle. Perfect balance of natural vocal timbre, warmth, and low CPU load on Intel N100/Pi 5. |
| High | 22.05 kHz – 44.1 kHz wideband | ~120 MB – 250 MB | 0.18 – 0.35 (Noticeable delay) | Dedicated home audio servers (Intel i5/i7, Ryzen), long-form narrative voice outputs, multi-room hi-fi systems. |
| Multi-Speaker Medium | 22.05 kHz (Multi-ID ONNX) | ~80 MB – 110 MB | 0.06 – 0.10 (Real-time) | Multi-person smart home personas; dynamic character switching based on notification severity or target room. |
For 95% of home automation deployments, Medium quality is the target sweet spot. It provides clear, non-fatiguing vocal formants while leaving your CPU cycles free to manage the rest of your home server tasks.
How Do You Fine-Tune Custom Voices and Configure Multi-Speaker Maps?
While pre-trained public models (like en_US-lessac-medium or en_GB-algernon-medium) are clean, you may want a voice tailored specifically for your home—such as custom phrase inflection, specialized smart home terminology, or even cloning a family member’s voice for personalized alerts.
Training a Piper model from absolute scratch requires hundreds of hours of pristine audio datasets. However, you can achieve voice cloning via transfer learning (fine-tuning) using as little as 30 to 45 minutes of targeted voice recordings.
1. Preparing the Audio Dataset
Create a directory structure formatted to the LJSpeech standard. Audio samples must be recorded in uncompressed WAV format, strictly configured to 22,050 Hz sample rate, 16-bit depth, single-channel mono. Background noise, acoustic reflection (reverb), or volume fluctuations will directly degrade your trained model’s ONNX weight matrices.
Structure your transcript mapping file, metadata.csv, using pipe-delimited values:
0001|The front door lock has been unlocked by user main key.|The front door lock has been unlocked by user main key. 0002|Warning. Water leak detected under the kitchen sink.|Warning. Water leak detected under the kitchen sink. 0003|Good morning. The temperature today is seventy-two degrees.|Good morning. The temperature today is seventy-two degrees.
2. Fine-Tuning Execution via Docker
Using the official piper-train container, load a pre-trained base model checkpoint to accelerate convergence. Fine-tuning off an existing checkpoint adapts the lower layers (phoneme structures) while altering the flow module layer weights to mirror your target speaker’s voice timbre:
docker run -it -v /path/to/dataset:/dataset \ -v /path/to/output:/output \ rhasspy/piper-train:latest \ --dataset-dir /dataset \ --accelerator gpu \ --devices 1 \ --batch-size 16 \ --validation-split 0.05 \ --sample-rate 22050 \ --resume_from_checkpoint /dataset/base_models/en_US-lessac-medium.ckpt \ --max_epochs 2000
3. Exporting to Quantized ONNX & Multi-Speaker Configs
Once loss curves stabilize, export the PyTorch checkpoint into an optimized ONNX model file. If you are training a multi-speaker voice checkpoint, specify the speaker map index within the exported JSON sidecar config:
python3 -m piper_train.export_onnx \ /output/lightning_logs/version_0/checkpoints/epoch=1999-step=50000.ckpt \ /output/custom_voice_medium.onnx
The generated sidecar metadata configuration (custom_voice_medium.onnx.json) controls pitch variability, synthesis speed, and multi-speaker ID routes:
{
"audio": {
"sample_rate": 22050
},
"espeak": {
"voice": "en-us"
},
"inference": {
"noise_scale": 0.667,
"length_scale": 1.0,
"noise_w": 0.8
},
"num_speakers": 2,
"speaker_id_map": {
"jarvis_alert": 0,
"assistant_calm": 1
}
}
What Is the Step-by-Step Playbook to Deploy Custom Piper Voices in HAOS?
Now that you have your custom .onnx weight file and matching .onnx.json sidecar file, let’s step through the deployment process in Home Assistant OS using the Wyoming Protocol engine.
Step 1: Mount the Custom Voice Model into HAOS Local Storage
Access your Home Assistant file system using SSH, Samba Share, or the File Editor add-on. Create a dedicated storage directory within your local shared storage path:
Path: /share/piper/custom_voices/
Upload your generated binary model and JSON file into this folder. Ensure file permissions match standard read access and that filenames match precisely:
/share/piper/custom_voices/custom_voice_medium.onnx/share/piper/custom_voices/custom_voice_medium.onnx.json
Step 2: Configure the Local Piper Wyoming Container
If you are using the official Home Assistant Piper Add-on, configure the add-on execution parameters to scan your local storage path. Navigate to Settings > Add-ons > Piper > Configuration, enable advanced options, and append your custom voice data directory path to the data command line flags:
data_dir: /share/piper/custom_voices speaker: jarvis_alert length_scale: 0.95
Restart the Piper add-on container. Check the add-on logs to confirm successful ONNX model mapping and execution memory allocation:
[INFO] Loaded voice custom_voice_medium.onnx (sample rate: 22050Hz) [INFO] Registered Wyoming protocol engine service on port 10200
Step 3: Register the System Integration & Multi-Speaker Overrides
Open your configuration.yaml file to configure system-level TTS fallback parameters and declare audio routing parameters for the Wyoming integration protocol:
System Level Voice Routing Configuration
wyoming: piper: - host: 127.0.0.1 port: 10200 tts: - platform: wyoming name: "Piper Custom Neural Engine" voice: "custom_voice_medium-jarvis_alert" language: "en_US"
Reload the TTS integration via Developer Tools > YAML > Text-to-Speech.
Step 4: Map Multi-Room Satellites and Orchestrate Dynamic Output Automations
Now, route dynamic voice prompts out to specific room satellites (such as Wyoming Satellite ESP32-S3 boards or Snapcast multi-room audio zones). You can dynamically alter speech rate (cadence) or speaker IDs directly inside Home Assistant script execution blocks using service parameters:
action: tts.speak
target:
entity_id: tts.piper_custom_neural_engine
data:
media_player_entity_id: media_player.living_room_wyoming_satellite
message: "Security alert. Garage door key pad entered an invalid pin sequence."
options:
voice: "custom_voice_medium"
speaker: 0
length_scale: 0.85
Setting length_scale: 0.85 reduces synthesis output time by 15%, delivering a faster, more urgent vocal alert during security automations. Conversely, for bedtime routines or morning weather summaries, setting length_scale: 1.10 delivers a relaxed cadence.
Frequently Asked Questions
Why is my custom Piper voice stuttering or cutting off early on Wyoming satellites?
Stuttering or chopped audio output typically stems from a sample rate mismatch between the synthesized audio stream (e.g., 22.05 kHz) and the satellite hardware playback buffer (which often expects 16.0 kHz PCM stream limits). Ensure that your satellite audio configuration in the Wyoming integration has auto-resampling enabled, or select a medium model compiled at a compatible sample rate. Additionally, verify network throughput on Wi-Fi-based ESP32 nodes—packet loss in UDP stream delivery can simulate audio stuttering.
Can I train a custom Piper TTS voice using voice samples from a single smartphone recording?
Yes, but output fidelity depends on background noise levels and room acoustic acoustics. You can record 30–45 minutes of clear text reading via a mobile device in a soft, non-reflective room (such as a walk-in closet). Run the resulting .wav files through audio normalization filters (high-pass filter at 80Hz, RMS normalization to -23dB) prior to formatting the dataset for fine-tuning.
How does Piper TTS compare to Coqui TTS or Whisper for local smart home voice loops?
Whisper is a speech-to-text (STT) model designed for transcribing incoming audio, whereas Piper is a text-to-speech (TTS) synthesis engine. Compared to Coqui TTS (XTTS v2), which requires a dedicated GPU and several gigabytes of VRAM for real-time synthesis, Piper TTS runs on low-power host CPUs (Intel N100, Raspberry Pi 4/5) with significantly lower latency and minimal system overhead.
How do I change the speech speed and pitch of custom Piper models dynamically in Home Assistant automations?
You can dynamically adjust execution parameters by passing options within the tts.speak service call inside your Home Assistant automations. Use length_scale to adjust speed (e.g., 0.8 for faster

