Hi there,
Since the 2025.11~ version of home assistant, when I activate voice assistant (either via wake word or manually) from my modified Sonoff TXs with microphone, the homeassistant python process goes up to 100% and remains stuck until I force restart it. This didn’t happen with earlier versions. Rolling back to the October release (without reflashing any of the esphome devices) fixed the issue.
There are no log evidences in Home Assistant. This problem seems to only happen with my custom made TXs. It doesn’t happen with:
- M5 Stack Atom Echo
- Voice assistant PE Device
- Web browser / Mobile application
I’ve attached a stripped down configuration of my Sonoff Txs:
substitutions:
name: "int-camera-xxxx"
friendly_name: "Camera xxxx"
audio_lrclk_pin: GPIO4
audio_bclk_pin: GPIO2
audio_sdata_pin: GPIO15
play_sample_rate: "48"
use_ip_address: xxx.xxx.x.xxx
wifi_ssid: !secret wifi_dmz_ssid
wifi_password: !secret wifi_dmz_password
mic_lrclk_pin: GPIO1
mic_bclk_pin: GPIO3
mic_sdata_pin: GPIO0
vibra_time: 75ms
vibra_motor_pin: GPIO21
pa_power_pin: GPIO26
touchpanel_power_pin: GPIO5
esphome:
name: ${name}
friendly_name: ${friendly_name}
project:
name: Sonoff.TxUltimate
version: "2.0"
esp32:
board: esp32dev
flash_size: 8MB
cpu_frequency: 240MHz
framework:
type: esp-idf
#psram:
# mode: octal
# speed: 40MHz
logger:
# hardware_uart: UART2
level: DEBUG
baud_rate: 0
api:
# encryption:
# key: !secret api_key
ota:
platform: esphome
password: !secret ota_pwd
wifi:
ssid: ${wifi_ssid}
password: ${wifi_password}
use_address: ${use_ip_address}
ap:
password: !secret ap_pwd
output:
- platform: gpio
pin: ${vibra_motor_pin}
id: vibra_output
speaker:
- id: audio_out
platform: i2s_audio
dac_type: external
i2s_dout_pin: ${audio_sdata_pin}
i2s_audio_id: audio_i2s
i2s_comm_fmt: stand_msb
timeout: never
channel: mono
bits_per_sample: 16bit
sample_rate: ${play_sample_rate}000
buffer_duration: 500ms
button:
- id: vibra
platform: output
name: "${friendly_name} Vibration"
output: vibra_output
duration: ${vibra_time}
entity_category: config
- platform: safe_mode
name: "${friendly_name} (Safe Mode)"
- platform: restart
name: "${friendly_name} Restart"
- platform: template
name: Start/Stop assistant
id: start_assistant
entity_category: config
on_press:
- if:
condition:
voice_assistant.is_running
then:
- voice_assistant.stop
else:
- voice_assistant.start
switch:
- platform: gpio
id: pa_power
pin: ${pa_power_pin}
name: "PA Power"
internal: true
restore_mode: ALWAYS_ON
- platform: gpio
name: "touch panel power"
pin:
number: ${touchpanel_power_pin}
inverted: true
id: touch_power
internal: true
restore_mode: RESTORE_DEFAULT_ON
i2s_audio:
- id: audio_i2s
i2s_lrclk_pin: ${audio_lrclk_pin}
i2s_bclk_pin: ${audio_bclk_pin}
- id: audio_mic_i2s
i2s_lrclk_pin: ${mic_lrclk_pin}
i2s_bclk_pin: ${mic_bclk_pin}
microphone:
- platform: i2s_audio
i2s_audio_id: audio_mic_i2s
i2s_din_pin: ${mic_sdata_pin}
adc_type: external
id: asr_mic
pdm: false
channel: left
sample_rate: 16000
voice_assistant:
id: va
microphone: asr_mic
speaker: audio_out
# media_player: va_media_player
use_wake_word: false
noise_suppression_level: 4
auto_gain: 31dBFS
volume_multiplier: 15.0
#media_player:
# - platform: speaker
# id: va_media_player
# name: Media Player
# codec_support_enabled: false
# buffer_size: 6000
## task_stack_in_psram: false
# volume_initial: 100%
# announcement_pipeline:
# format: WAV
# speaker: audio_out
(Tried with either media_player and speaker)
This is the atom echo configuration (correctly working with HA) I’m actually using:
substitutions:
name: m5stack-atom-echo
friendly_name: M5Stack Atom Echo
esphome:
name: ${name}
name_add_mac_suffix: true
friendly_name: ${friendly_name}
min_version: 2025.5.0
esp32:
board: m5stack-atom
cpu_frequency: 240MHz
framework:
type: esp-idf
logger:
api:
ota:
- platform: esphome
id: ota_esphome
password: !secret ota_pwd_sec
wifi:
networks:
- ssid: !secret wifi_dmz_ssid
password: !secret wifi_dmz_password
use_address: xxx.xxx.x.xxx
button:
- platform: factory_reset
id: factory_reset_btn
name: Factory reset
i2s_audio:
- id: i2s_audio_bus
i2s_lrclk_pin: GPIO33
i2s_bclk_pin: GPIO19
microphone:
- platform: i2s_audio
id: echo_microphone
i2s_din_pin: GPIO23
adc_type: external
pdm: true
sample_rate: 16000
correct_dc_offset: true
speaker:
- platform: i2s_audio
id: echo_speaker
i2s_dout_pin: GPIO22
dac_type: external
bits_per_sample: 16bit
sample_rate: 16000
channel: stereo # The Echo has poor playback audio quality when using mon audio
buffer_duration: 60ms
media_player:
- platform: speaker
name: None
id: echo_media_player
announcement_pipeline:
speaker: echo_speaker
format: WAV
codec_support_enabled: false
buffer_size: 6000
volume_min: 0.4
files:
- id: timer_finished_wave_file
file: https://github.com/esphome/wake-word-voice-assistants/raw/main/sounds/timer_finished.wav
on_announcement:
- if:
condition:
- microphone.is_capturing:
then:
- script.execute: stop_wake_word
- light.turn_on:
id: led
blue: 100%
red: 0%
green: 0%
brightness: 100%
effect: none
on_idle:
- script.execute: start_wake_word
- script.execute: reset_led
voice_assistant:
id: va
micro_wake_word:
microphone:
microphone: echo_microphone
channels: 0
gain_factor: 4
media_player: echo_media_player
noise_suppression_level: 2
auto_gain: 31dBFS
on_listening:
- light.turn_on:
id: led
blue: 100%
red: 0%
green: 0%
effect: "Slow Pulse"
on_stt_vad_end:
- light.turn_on:
id: led
blue: 100%
red: 0%
green: 0%
effect: "Fast Pulse"
on_tts_start:
- light.turn_on:
id: led
blue: 100%
red: 0%
green: 0%
brightness: 100%
effect: none
on_end:
# Handle the "nevermind" case where there is no announcement
- wait_until:
condition:
- media_player.is_announcing:
timeout: 0.5s
# Restart only mWW if enabled; streaming wake words automatically restart
- if:
condition:
- lambda: |-
return strcmp(id(wake_word_engine_location).current_option(), "On device") == 0;
then:
- wait_until:
- and:
- not:
voice_assistant.is_running:
- not:
speaker.is_playing:
- lambda: id(va).set_use_wake_word(false);
- micro_wake_word.start:
- script.execute: reset_led
on_error:
- light.turn_on:
id: led
red: 100%
green: 0%
blue: 0%
brightness: 100%
effect: none
- delay: 2s
- script.execute: reset_led
on_client_connected:
- delay: 2s # Give the api server time to settle
- script.execute: start_wake_word
on_client_disconnected:
- script.execute: stop_wake_word
on_timer_finished:
- script.execute: stop_wake_word
- wait_until:
not:
microphone.is_capturing:
- switch.turn_on: timer_ringing
- light.turn_on:
id: led
red: 0%
green: 100%
blue: 0%
brightness: 100%
effect: "Fast Pulse"
- wait_until:
- switch.is_off: timer_ringing
- light.turn_off: led
- switch.turn_off: timer_ringing
binary_sensor:
# button does the following:
# short click - stop a timer
# if no timer then restart either microwakeword or voice assistant continuous
- platform: gpio
pin:
number: GPIO39
inverted: true
name: Button
disabled_by_default: true
entity_category: diagnostic
id: echo_button
on_multi_click:
- timing:
- ON for at least 50ms
- OFF for at least 50ms
then:
- if:
condition:
switch.is_on: timer_ringing
then:
- switch.turn_off: timer_ringing
else:
- script.execute: start_wake_word
- timing:
- ON for at least 10s
then:
- button.press: factory_reset_btn
light:
- platform: esp32_rmt_led_strip
id: led
name: None
disabled_by_default: true
entity_category: config
pin: GPIO27
default_transition_length: 0s
chipset: SK6812
num_leds: 1
rgb_order: grb
effects:
- pulse:
name: "Slow Pulse"
transition_length: 250ms
update_interval: 250ms
min_brightness: 50%
max_brightness: 100%
- pulse:
name: "Fast Pulse"
transition_length: 100ms
update_interval: 100ms
min_brightness: 50%
max_brightness: 100%
script:
- id: reset_led
then:
- if:
condition:
- lambda: |-
return strcmp(id(wake_word_engine_location).current_option(), "On device") == 0;
- switch.is_on: use_listen_light
then:
- light.turn_on:
id: led
red: 100%
green: 89%
blue: 71%
brightness: 60%
effect: none
else:
- if:
condition:
- lambda: |-
return strcmp(id(wake_word_engine_location).current_option(), "On device") == 0;
- switch.is_on: use_listen_light
then:
- light.turn_on:
id: led
red: 0%
green: 100%
blue: 100%
brightness: 60%
effect: none
else:
- light.turn_off: led
- id: start_wake_word
then:
- if:
condition:
and:
- not:
- voice_assistant.is_running:
- lambda: |-
return strcmp(id(wake_word_engine_location).current_option(), "On device") == 0;
then:
- lambda: id(va).set_use_wake_word(false);
- micro_wake_word.start:
- if:
condition:
and:
- not:
- voice_assistant.is_running:
- lambda: |-
return strcmp(id(wake_word_engine_location).current_option(), "In Home Assistant") == 0;
then:
- lambda: id(va).set_use_wake_word(true);
- voice_assistant.start_continuous:
- id: stop_wake_word
then:
- if:
condition:
lambda: |-
return strcmp(id(wake_word_engine_location).current_option(), "In Home Assistant") == 0;
then:
- lambda: id(va).set_use_wake_word(false);
- voice_assistant.stop:
- if:
condition:
lambda: |-
return strcmp(id(wake_word_engine_location).current_option(), "On device") == 0;
then:
- micro_wake_word.stop:
switch:
- platform: template
name: Use listen light
id: use_listen_light
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
entity_category: config
on_turn_on:
- script.execute: reset_led
on_turn_off:
- script.execute: reset_led
- platform: template
id: timer_ringing
optimistic: true
restore_mode: ALWAYS_OFF
on_turn_off:
# Turn off the repeat mode and disable the pause between playlist items
- lambda: |-
id(echo_media_player)
->make_call()
.set_command(media_player::MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_OFF)
.set_announcement(true)
.perform();
id(echo_media_player)->set_playlist_delay_ms(speaker::AudioPipelineType::ANNOUNCEMENT, 0);
# Stop playing the alarm
- media_player.stop:
announcement: true
on_turn_on:
# Turn on the repeat mode and pause for 1000 ms between playlist items/repeats
- lambda: |-
id(echo_media_player)
->make_call()
.set_command(media_player::MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_ONE)
.set_announcement(true)
.perform();
id(echo_media_player)->set_playlist_delay_ms(speaker::AudioPipelineType::ANNOUNCEMENT, 1000);
- media_player.speaker.play_on_device_media_file:
media_file: timer_finished_wave_file
announcement: true
- delay: 15min
- switch.turn_off: timer_ringing
select:
- platform: template
entity_category: config
name: Wake word engine location
id: wake_word_engine_location
optimistic: true
restore_value: true
options:
- In Home Assistant
- On device
initial_option: On device
on_value:
- if:
condition:
lambda: return x == "In Home Assistant";
then:
- micro_wake_word.stop:
- delay: 500ms
- lambda: id(va).set_use_wake_word(true);
- voice_assistant.start_continuous:
- if:
condition:
lambda: return x == "On device";
then:
- lambda: id(va).set_use_wake_word(false);
- voice_assistant.stop:
- delay: 500ms
- micro_wake_word.start:
micro_wake_word:
on_wake_word_detected:
- voice_assistant.start:
wake_word: !lambda return wake_word;
vad:
models:
- model: okay_nabu
- model: hey_mycroft
- model: hey_jarvis
This is the log from the Tx device when activating the assistant:
[22:18:38.130][D][button:022]: 'Start/Stop assistant' Pressed.
[22:18:38.131][D][voice_assistant:478]: State changed from IDLE to START_MICROPHONE
[22:18:38.131][D][voice_assistant:485]: Desired state set to START_PIPELINE
[22:18:38.134][D][voice_assistant:207]: Starting Microphone
[22:18:38.135][D][ring_buffer:034]: Created ring buffer with size 16384
[22:18:38.137][D][voice_assistant:478]: State changed from START_MICROPHONE to STARTING_MICROPHONE
[22:18:38.159][D][voice_assistant:478]: State changed from STARTING_MICROPHONE to START_PIPELINE
[22:18:38.171][D][voice_assistant:228]: Requesting start
[22:18:38.172][D][voice_assistant:478]: State changed from START_PIPELINE to STARTING_PIPELINE
[22:19:01.746][I][safe_mode:042]: Boot seems successful; resetting boot loop counter
[22:19:01.754][D][esp32.preferences:149]: Writing 1 items: 0 cached, 1 written, 0 failed
[22:19:40.185][W][api.connection:1978]: Home Assistant 2025.12.4 (172.16.0.5): Reading failed SOCKET_READ_FAILED errno=104
[22:19:40.203][D][voice_assistant:478]: State changed from STARTING_PIPELINE to STOP_MICROPHONE
[22:19:40.204][D][voice_assistant:485]: Desired state set to IDLE
[22:19:40.212][D][voice_assistant:478]: State changed from STOP_MICROPHONE to STOPPING_MICROPHONE
[22:19:40.223][D][voice_assistant:478]: State changed from STOPPING_MICROPHONE to IDLE
[22:20:01.838][D][api:136]: Accept 172.16.0.5
[22:20:01.853][D][api.connection:1398]: Home Assistant 2025.12.4 (172.16.0.5) connected
[22:19:40.185][W][api.connection:1978]: Home Assistant 2025.12.4 (172.16.0.5): Reading failed SOCKET_READ_FAILED errno=104 ← this appears due to the HA Force restart.
From the log it seems the device keeps waiting for a response from HA, but it hangs indefitively.
This is a backtrace taken with gbd when the process remains stuck:
Thread 1 "python3" received signal SIGINT, Interrupt.
0x00007f614f0eb0ae in _PyEval_EvalFrameDefault ()
from /usr/local/lib/libpython3.13.so.1.0
(gdb) bt
#0 0x00007f614f0eb0ae in _PyEval_EvalFrameDefault ()
from /usr/local/lib/libpython3.13.so.1.0
#1 0x00007f614f1ce0b8 in ?? () from /usr/local/lib/libpython3.13.so.1.0
#2 0x00007f614b7649e8 in ?? ()
from /usr/local/lib/python3.13/lib-dynload/_asyncio.cpython-313-x86_64-linux-musl.so
#3 0x00007f614b7668b0 in ?? ()
from /usr/local/lib/python3.13/lib-dynload/_asyncio.cpython-313-x86_64-linux-musl.so
#4 0x00007f614f0d9ce7 in _PyObject_MakeTpCall ()
from /usr/local/lib/libpython3.13.so.1.0
#5 0x00007f614f0f35e5 in _PyEval_EvalFrameDefault ()
from /usr/local/lib/libpython3.13.so.1.0
#6 0x00007f610ba011c7 in __pyx_f_13aioesphomeapi_10connection_13APIConnection_process_packet ()
from /usr/local/lib/python3.13/site-packages/aioesphomeapi/connection.cpython-313-x86_64-linux-musl.so
#7 0x00007f610b889031 in __pyx_f_13aioesphomeapi_13_frame_helper_5noise_19APINoiseFrameHelper__handle_frame ()
from /usr/local/lib/python3.13/site-packages/aioesphomeapi/_frame_helper/noise.cpython-313-x86_64-linux-musl.so
#8 0x00007f610b887373 in __pyx_f_13aioesphomeapi_13_frame_helper_5noise_19APINoiseFrameHelper_data_received ()
--Type <RET> for more, q to quit, c to continue without paging--
from /usr/local/lib/python3.13/site-packages/aioesphomeapi/_frame_helper/noise.cpython-313-x86_64-linux-musl.so
#9 0x00007f610b8882b4 in __pyx_pw_13aioesphomeapi_13_frame_helper_5noise_19APINoiseFrameHelper_9data_received ()
from /usr/local/lib/python3.13/site-packages/aioesphomeapi/_frame_helper/noise.cpython-313-x86_64-linux-musl.so
#10 0x00007f614f0dc129 in PyObject_Vectorcall ()
from /usr/local/lib/libpython3.13.so.1.0
#11 0x00007f614f0ed816 in _PyEval_EvalFrameDefault ()
from /usr/local/lib/libpython3.13.so.1.0
#12 0x00007f614f144d9c in ?? () from /usr/local/lib/libpython3.13.so.1.0
#13 0x00007f614f25b722 in ?? () from /usr/local/lib/libpython3.13.so.1.0
#14 0x00007f614f092130 in ?? () from /usr/local/lib/libpython3.13.so.1.0
#15 0x00007f614f1046c6 in ?? () from /usr/local/lib/libpython3.13.so.1.0
#16 0x00007f614f0eee11 in _PyEval_EvalFrameDefault ()
from /usr/local/lib/libpython3.13.so.1.0
#17 0x00007f614f1bac3e in PyEval_EvalCode ()
from /usr/local/lib/libpython3.13.so.1.0
#18 0x00007f614f1d5220 in ?? () from /usr/local/lib/libpython3.13.so.1.0
#19 0x00007f614f1046c6 in ?? () from /usr/local/lib/libpython3.13.so.1.0
#20 0x00007f614f0dc129 in PyObject_Vectorcall ()
from /usr/local/lib/libpython3.13.so.1.0
#21 0x00007f614f0ed816 in _PyEval_EvalFrameDefault ()
--Type <RET> for more, q to quit, c to continue without paging--
from /usr/local/lib/libpython3.13.so.1.0
#22 0x00007f614f1efd69 in ?? () from /usr/local/lib/libpython3.13.so.1.0
#23 0x00007f614f1eec3d in Py_RunMain ()
from /usr/local/lib/libpython3.13.so.1.0
#24 0x00007f614f1a8767 in Py_BytesMain ()
from /usr/local/lib/libpython3.13.so.1.0
#25 0x00007f614f699496 in libc_start_main_stage2 (main=0x562481618190, argc=5,
argv=0x7ffd68d24b98) at src/env/__libc_start_main.c:95
#26 0x0000562481618056 in _start ()
(gdb)
This is my configuration:
- Home Assistant OS 16.3 Running on Proxmox
- Home Assistant 2025.12.4
- ESPHome 2025.12.2
- All my devices (Sonoffs, Atom echo, Voice assistant PE) use the same Assistant profile
The sonoff microphone and speaker do work correctly: The media_player works if i try to stream something via HA and the microphone correctly detects my wake word (not included in the stripped down yaml) or my voice with older version of HA, so I really don’t understand where the problem could be.
Can you please help me? I’ve really tried any sort of different configuration / setting, but I haven’t find a way to solve the problem
Thanks!