Skip to content

Commit fe181a5

Browse files
authored
Modify M5 Stack ATOM ECHO to support all voice assistant features (#99)
1 parent 7cc8870 commit fe181a5

File tree

1 file changed

+67
-40
lines changed

1 file changed

+67
-40
lines changed

m5stack-atom-echo/m5stack-atom-echo.yaml

Lines changed: 67 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
substitutions:
22
name: m5stack-atom-echo
33
friendly_name: M5Stack Atom Echo
4-
micro_wake_word_model: okay_nabu # alexa, hey_jarvis, hey_mycroft are also supported
54

65
esphome:
76
name: ${name}
87
name_add_mac_suffix: true
98
friendly_name: ${friendly_name}
10-
min_version: 2025.2.0
9+
min_version: 2025.5.0
1110

1211
esp32:
1312
board: m5stack-atom
13+
cpu_frequency: 240MHz
1414
framework:
1515
type: esp-idf
1616

@@ -42,14 +42,17 @@ microphone:
4242
i2s_din_pin: GPIO23
4343
adc_type: external
4444
pdm: true
45+
sample_rate: 16000
46+
correct_dc_offset: true
4547

4648
speaker:
4749
- platform: i2s_audio
4850
id: echo_speaker
4951
i2s_dout_pin: GPIO22
5052
dac_type: external
51-
bits_per_sample: 32bit
52-
channel: right
53+
bits_per_sample: 16bit
54+
sample_rate: 16000
55+
channel: stereo # The Echo has poor playback audio quality when using mon audio
5356
buffer_duration: 60ms
5457

5558
media_player:
@@ -70,14 +73,7 @@ media_player:
7073
condition:
7174
- microphone.is_capturing:
7275
then:
73-
- if:
74-
condition:
75-
lambda: return id(wake_word_engine_location).state == "On device";
76-
then:
77-
- micro_wake_word.stop:
78-
else:
79-
- voice_assistant.stop:
80-
- script.execute: reset_led
76+
- script.execute: stop_wake_word
8177
- light.turn_on:
8278
id: led
8379
blue: 100%
@@ -87,14 +83,18 @@ media_player:
8783
effect: none
8884
on_idle:
8985
- script.execute: start_wake_word
86+
- script.execute: reset_led
9087

9188
voice_assistant:
9289
id: va
93-
microphone: echo_microphone
90+
micro_wake_word:
91+
microphone:
92+
microphone: echo_microphone
93+
channels: 0
94+
gain_factor: 4
9495
media_player: echo_media_player
9596
noise_suppression_level: 2
9697
auto_gain: 31dBFS
97-
volume_multiplier: 2.0
9898
on_listening:
9999
- light.turn_on:
100100
id: led
@@ -118,8 +118,25 @@ voice_assistant:
118118
brightness: 100%
119119
effect: none
120120
on_end:
121-
- delay: 100ms
122-
- script.execute: start_wake_word
121+
# Handle the "nevermind" case where there is no announcement
122+
- wait_until:
123+
condition:
124+
- media_player.is_announcing:
125+
timeout: 0.5s
126+
# Restart only mWW if enabled; streaming wake words automatically restart
127+
- if:
128+
condition:
129+
- lambda: return id(wake_word_engine_location).state == "On device";
130+
then:
131+
- wait_until:
132+
- and:
133+
- not:
134+
voice_assistant.is_running:
135+
- not:
136+
speaker.is_playing:
137+
- lambda: id(va).set_use_wake_word(false);
138+
- micro_wake_word.start:
139+
- script.execute: reset_led
123140
on_error:
124141
- light.turn_on:
125142
id: led
@@ -134,11 +151,9 @@ voice_assistant:
134151
- delay: 2s # Give the api server time to settle
135152
- script.execute: start_wake_word
136153
on_client_disconnected:
137-
- voice_assistant.stop:
138-
- micro_wake_word.stop:
154+
- script.execute: stop_wake_word
139155
on_timer_finished:
140-
- voice_assistant.stop:
141-
- micro_wake_word.stop:
156+
- script.execute: stop_wake_word
142157
- wait_until:
143158
not:
144159
microphone.is_capturing:
@@ -241,27 +256,37 @@ script:
241256
- light.turn_off: led
242257
- id: start_wake_word
243258
then:
244-
- wait_until:
245-
and:
246-
- media_player.is_idle:
247-
- speaker.is_stopped:
248259
- if:
249260
condition:
250-
lambda: return id(wake_word_engine_location).state == "On device";
261+
and:
262+
- not:
263+
- voice_assistant.is_running:
264+
- lambda: return id(wake_word_engine_location).state == "On device";
251265
then:
252-
- voice_assistant.stop
253-
- micro_wake_word.stop:
254-
- delay: 1s
255-
- script.execute: reset_led
256-
- script.wait: reset_led
266+
- lambda: id(va).set_use_wake_word(false);
257267
- micro_wake_word.start:
258-
else:
259-
- if:
260-
condition: voice_assistant.is_running
261-
then:
262-
- voice_assistant.stop:
263-
- script.execute: reset_led
268+
- if:
269+
condition:
270+
and:
271+
- not:
272+
- voice_assistant.is_running:
273+
- lambda: return id(wake_word_engine_location).state == "In Home Assistant";
274+
then:
275+
- lambda: id(va).set_use_wake_word(true);
264276
- voice_assistant.start_continuous:
277+
- id: stop_wake_word
278+
then:
279+
- if:
280+
condition:
281+
lambda: return id(wake_word_engine_location).state == "In Home Assistant";
282+
then:
283+
- lambda: id(va).set_use_wake_word(false);
284+
- voice_assistant.stop:
285+
- if:
286+
condition:
287+
lambda: return id(wake_word_engine_location).state == "On device";
288+
then:
289+
- micro_wake_word.stop:
265290

266291
switch:
267292
- platform: template
@@ -321,7 +346,7 @@ select:
321346
condition:
322347
lambda: return x == "In Home Assistant";
323348
then:
324-
- micro_wake_word.stop
349+
- micro_wake_word.stop:
325350
- delay: 500ms
326351
- lambda: id(va).set_use_wake_word(true);
327352
- voice_assistant.start_continuous:
@@ -330,14 +355,16 @@ select:
330355
lambda: return x == "On device";
331356
then:
332357
- lambda: id(va).set_use_wake_word(false);
333-
- voice_assistant.stop
358+
- voice_assistant.stop:
334359
- delay: 500ms
335-
- micro_wake_word.start
360+
- micro_wake_word.start:
336361

337362
micro_wake_word:
338363
on_wake_word_detected:
339364
- voice_assistant.start:
340365
wake_word: !lambda return wake_word;
341366
vad:
342367
models:
343-
- model: ${micro_wake_word_model}
368+
- model: okay_nabu
369+
- model: hey_mycroft
370+
- model: hey_jarvis

0 commit comments

Comments
 (0)