in the end I found my final configuration… the 8ohm 3W speaker gives a great change in the volume of the device making it decidedly very acceptable and functional for a room without adding other cables or complicated connections.
You just have to solder the two cables and the result is great (the speaker is the 8Ohm version posted above).
if you remove the Reset button of the case you can also unplug the wires and put the cover back on. (alternatively you can also connect two 4Ohm speakers in parallel to bring the resistance to 8Ohm for a more diffused effect)
Hi,
I’m very interested in your version, but could you please look at 25.6.1 version in which we have fully functional countinued conversation mode? Could you incorporate your changes to this yaml version retaining continued conversation mode?
Small followup: I’ve managed to modify the newest yaml (25.6.1) incorporating your changes and everything is working like a charm since 2 days Here is the modified yaml:
substitutions:
name: atom-echo-sypialnia
friendly_name: Atom Echo sypialnia
esphome:
name: ${name}
name_add_mac_suffix: false
friendly_name: ${friendly_name}
min_version: 2025.5.0
esp32:
board: m5stack-atom
cpu_frequency: 240MHz
framework:
type: esp-idf
logger:
api:
encryption:
key: "your key"
ota:
- platform: esphome
password: "your password"
id: ota_esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "Atom-Echo-Sypialnia"
password: "your password"
captive_portal:
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
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:
- if:
condition:
switch.is_on: call_script_message
then:
- logger.log: "calling script with message (instead of playing directly to media player)"
- homeassistant.service:
service: !lambda 'return id(script_id).state.c_str();'
data:
message: !lambda 'return x;'
else:
- if:
condition:
switch.is_on: use_remote_media_player
then:
- logger.log: "using remote media player"
- speaker.volume_set: 10%
- homeassistant.service:
service: tts.cloud_say
data:
entity_id: !lambda 'return id(media_player_entity_id).state.c_str();'
message: !lambda 'return x;'
else:
- logger.log: "using internal speaker"
- speaker.volume_set: 100%
- 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 id(wake_word_engine_location).state == "On device";
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:
- speaker.volume_set: 100%
- switch.turn_on: timer_ringing
- light.turn_on:
id: led
red: 0%
green: 100%
blue: 0%
brightness: 100%
effect: "Fast Pulse"
- if:
condition:
switch.is_on: call_alarm_script
then:
- logger.log: "calling alarm script"
- homeassistant.service:
service: !lambda 'return id(alarm_script_id).state.c_str();'
- wait_until:
- switch.is_off: timer_ringing
- light.turn_off: led
- switch.turn_off: timer_ringing
- speaker.volume_set: 10%
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:
- logger.log: "single button short click"
- 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:
- logger.log: "single button long click"
- 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 id(wake_word_engine_location).state == "On device";
- 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 id(wake_word_engine_location).state != "On device";
- 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 id(wake_word_engine_location).state == "On device";
then:
- lambda: id(va).set_use_wake_word(false);
- micro_wake_word.start:
- if:
condition:
and:
- not:
- voice_assistant.is_running:
- lambda: return id(wake_word_engine_location).state == "In Home Assistant";
then:
- lambda: id(va).set_use_wake_word(true);
- voice_assistant.start_continuous:
- id: stop_wake_word
then:
- if:
condition:
lambda: return id(wake_word_engine_location).state == "In Home Assistant";
then:
- lambda: id(va).set_use_wake_word(false);
- voice_assistant.stop:
- if:
condition:
lambda: return id(wake_word_engine_location).state == "On device";
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
name: Use remote media player
id: use_remote_media_player
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
entity_category: config
on_turn_on:
- logger.log: "use remote media player turned on"
- logger.log:
format: "current media player entity: %s"
args: ["id(media_player_entity_id).state.c_str()"]
on_turn_off:
- logger.log: "use remote media player turned off"
- logger.log:
format: "current media player entity: %s"
args: ["id(media_player_entity_id).state.c_str()"]
- platform: template
name: Call script with message
id: call_script_message
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
entity_category: config
on_turn_on:
- logger.log: "call script with message turned on"
on_turn_off:
- logger.log: "call script with message turned off"
- platform: template
name: Call alarm script
id: call_alarm_script
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
entity_category: config
on_turn_on:
- logger.log: "call alarm script turned on"
on_turn_off:
- logger.log: "call alarm script turned off"
- 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
text:
- platform: template
name: Media Player Entity ID
id: media_player_entity_id
mode: text
optimistic: true
restore_value: true
entity_category: config
on_value:
then:
- logger.log:
format: "Set new media player entity: %s"
args: ["x.c_str()"]
- platform: template
name: Script ID
id: script_id
mode: text
optimistic: true
restore_value: true
entity_category: config
on_value:
then:
- logger.log:
format: "Set new script: %s"
args: ["x.c_str()"]
- platform: template
name: Script on Alarm ID
id: alarm_script_id
mode: text
optimistic: true
restore_value: true
entity_category: config
on_value:
then:
- logger.log:
format: "Set new alarm script: %s"
args: ["x.c_str()"]
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
Now, thanks to you, I’m totally happy with my two echos. One of them is constantly switched to an external speaker via VLC and another is linked to my Windows computer speakers via HASS.Agent and switched back to internal echo speaker by an automation when the HASS.Agent player becomes unavalilable (after Windows shutting down). Both are working with continued conversation with zero problems Thank you for your yaml