-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathgeneric-s3-full-afe.yaml
More file actions
492 lines (446 loc) · 17.4 KB
/
Copy pathgeneric-s3-full-afe.yaml
File metadata and controls
492 lines (446 loc) · 17.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# =============================================================================
# GENERIC ESP32-S3 VOIP + VA - Single I2S bus, no hardware codec
# =============================================================================
# Full-featured config: VoIP + Media Player + mixer (VA/MWW ready).
# For ESP32 boards where mic and speaker share the SAME I2S bus.
#
# Audio pipeline:
# MEMS mic → esp_audio_stack (48kHz) → esp_ae_rate_cvt x3 → esp_afe (AEC+NS+AGC) → mic_main → VA / VoIP TX / MWW
#
# Media → media_speaker_input (resampler) ────────────┐
# VA TTS → tts_speaker_input (resampler) ──────────────┼── mixer (48kHz) → hw_speaker → class-D amp
# VoIP RX → voip_speaker_input (resampler) ─────────────┘
#
# HARDWARE (adapt GPIOs to YOUR board):
# - Board: Any ESP32-S3 with PSRAM
# - Flash: requires an ESP32-S3 layout with an app slot larger than the
# default 4 MB OTA slot; 8 MB or 16 MB flash is recommended
# - Microphone: Any I2S MEMS mic on DIN pin
# - Speaker: Any I2S class-D amp on DOUT pin
# - Mic and speaker SHARE BCLK + LRCLK (same I2S bus, full-duplex)
# - LED: SK6812/WS2812 RGB (optional)
# - ESP32-S3R8/S3R8V: do not use PSRAM pins for I2S/LED; the GPIOs below
# are examples only and may need moving on those modules.
#
# GPIO PINOUT (example, change to match your wiring):
# Shared I2S: BCLK=GPIO36, LRCLK=GPIO37, DIN=GPIO35 (mic), DOUT=GPIO7 (speaker)
# LED: DATA=GPIO33
#
# =============================================================================
# =============================================================================
# PROJECT SETUP
# =============================================================================
substitutions:
# Hardware-shared identity: dropping firmware-variant suffix keeps build cache
# and HA device entity stable across rebuilds.
name: generic-s3
friendly_name: Generic S3
ext_components_source: "github://n-IA-hane/esphome-intercom@main"
voip_stack_components_source: "github://n-IA-hane/esphome-voip-stack@main"
audio_stack_components_source: "github://n-IA-hane/esphome-audio-stack@main"
runtime_controller_components_source: "github://n-IA-hane/esphome-runtime-controller@main"
assets_base: "https://github.com/n-IA-hane/esphome-intercom/raw/main/"
# Microphone ID for package mute switch
mic_id: mic_main
runtime_controller_led_preset: rgb_single
# ---------------------------------------------------------------------------
# Pinout: shared I2S bus
# ---------------------------------------------------------------------------
# BCLK/LRCLK are shared by mic and speaker on this full-duplex bus.
i2s_bclk_pin: GPIO36
i2s_lrclk_pin: GPIO37
# ---------------------------------------------------------------------------
# Pinout: microphone
# ---------------------------------------------------------------------------
i2s_din_pin: GPIO35
# ---------------------------------------------------------------------------
# Pinout: speaker
# ---------------------------------------------------------------------------
i2s_dout_pin: GPIO7
# ---------------------------------------------------------------------------
# Pinout: optional status LED
# ---------------------------------------------------------------------------
status_led_pin: GPIO33
status_led_chipset: WS2812
status_led_rgb_order: GRB
packages:
full_voice_voip_runtime: github://n-IA-hane/esphome-intercom/packages/presets/full_voice_voip_runtime.yaml@main
runtime_controller: github://n-IA-hane/esphome-runtime-controller/packages/runtime_controller/full_controller.yaml@main
voice_assistant_runtime_controls: github://n-IA-hane/esphome-intercom/packages/voice_assistant/runtime_controls.yaml@main
call_settings: github://n-IA-hane/esphome-intercom/packages/voip/call_settings.yaml@main
ha_api: github://n-IA-hane/esphome-intercom/packages/voip/ha_api_runtime.yaml@main
voice_assistant_local_commands: github://n-IA-hane/esphome-intercom/packages/voice_assistant/local_commands.yaml@main
ota_maintenance: github://n-IA-hane/esphome-intercom/packages/ota/full_audio_maintenance.yaml@main
voip_transport: github://n-IA-hane/esphome-intercom/packages/voip/transport.yaml@main
phonebook_subscribe: github://n-IA-hane/esphome-intercom/packages/voip/phonebook_subscribe.yaml@main
speaker_mute: github://n-IA-hane/esphome-intercom/packages/voip/speaker_mute_runtime.yaml@main
s3_base: github://n-IA-hane/esphome-intercom/packages/platform/esp32s3_base.yaml@main
native_diagnostics: github://n-IA-hane/esphome-intercom/packages/diagnostics/native.yaml@main
status_led: github://n-IA-hane/esphome-intercom/packages/led/status_ws2812_single.yaml@main
speaker_mixer: github://n-IA-hane/esphome-intercom/packages/audio/shared_mono_mixer_48k.yaml@main
speaker_media_player: github://n-IA-hane/esphome-intercom/packages/media_player/runtime_controller_mono_media_player_48k.yaml@main
flac_codecs_psram: github://n-IA-hane/esphome-intercom/packages/audio/flac_codecs_psram.yaml@main
audio_stack_controls: github://n-IA-hane/esphome-intercom/packages/esp_audio_stack/controls.yaml@main
afe_entities: github://n-IA-hane/esphome-intercom/packages/esp_afe/single_mic_entities.yaml@main
# =============================================================================
# BOARD AND MEMORY
# =============================================================================
# Device identity exposed to ESPHome, HA and the shared VoIP phonebook.
esphome:
name: ${name}
friendly_name: ${friendly_name}
platformio_options:
board_build.flash_mode: dio
# ESP32-S3 target and ESP-IDF tuning for the experimental single-mic AFE profile.
esp32:
board: esp32-s3-devkitc-1
flash_size: 16MB
variant: esp32s3
framework:
type: esp-idf
advanced:
compiler_optimization: PERF
sdkconfig_options:
# Allow mbedtls to allocate its working buffers in PSRAM.
CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC: "y"
# Route ESP-IDF stdout (and ESPHome logger when hardware_uart=USB_SERIAL_JTAG)
# to the built-in USB-Serial-JTAG peripheral. Required on boards where the
# USB-C connector is wired to the S3's native USB-Serial-JTAG (e.g. Freenove,
# bare ESP32-S3-DevKitC-1) rather than to an external USB-UART chip.
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG: "y"
CONFIG_ESP_CONSOLE_SECONDARY_NONE: "y"
# PSRAM gives VA, media, AFE and VoIP buffers room on generic S3 boards.
psram:
mode: quad
speed: 80MHz
# Persist user settings without excessive flash writes.
preferences:
flash_write_interval: 5min
# =============================================================================
# EXTERNAL COMPONENTS
# =============================================================================
# Project components for full VA/VoIP, runtime controller and experimental AFE.
external_components:
- source: ${voip_stack_components_source}
components: [voip_stack]
- source: ${ext_components_source}
components: [speaker, voice_assistant]
- source: ${runtime_controller_components_source}
components: [runtime_controller]
- source: ${audio_stack_components_source}
components: [esp_audio_stack, esp_afe]
# =============================================================================
# CONNECTIVITY
# =============================================================================
# Normal Wi-Fi client mode. Power save is disabled for low-latency SIP/RTP and
# reliable HA API updates.
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
power_save_mode: NONE
# Home Assistant native API for entities, service actions and phonebook sync.
api:
# OTA update endpoint used by ESPHome Dashboard and `esphome upload`.
ota:
- platform: esphome
# USB Serial/JTAG logger. Keep project domains visible while this profile is
# still marked untested.
logger:
hardware_uart: USB_SERIAL_JTAG
# DEBUG keeps SIP bridge signaling + AEC/AFE/i2s lifecycle visible.
# Mute chatty ESPHome built-ins below; project components stay at DEBUG.
level: INFO
logs:
sensor: WARN
text_sensor: WARN
binary_sensor: WARN
switch: WARN
number: WARN
button: WARN
api: WARN
api.connection: WARN
component: WARN
api.service: INFO
light: INFO
select: INFO
speaker: INFO
audio: INFO
micro_wake_word: INFO
voice_assistant: INFO
media_player: INFO
resampler: INFO
mixer_speaker: INFO
wifi: INFO
json: INFO
voip_stack: INFO
# =============================================================================
# AUDIO PIPELINE
# =============================================================================
esp_audio_stack:
id: audio_stack
i2s_lrclk_pin: ${i2s_lrclk_pin}
i2s_bclk_pin: ${i2s_bclk_pin}
i2s_din_pin: ${i2s_din_pin}
i2s_dout_pin: ${i2s_dout_pin}
sample_rate: 48000
output_sample_rate: 16000
slot_bit_width: 32
correct_dc_offset: true
processor_id: afe_processor
# No-codec AEC reference. ring_buffer is the Espressif/ADF TYPE2-style
# software reference: speaker PCM is staged in a delay-tunable ring before
# being fed to AFE. Use previous_frame only for lighter custom builds.
aec_reference: previous_frame
buffers_in_psram: true
esp_afe:
id: afe_processor
type: fd
mode: high_perf
mic_num: 1
aec_enabled: true
aec_filter_length: 4
aec_nlp_level: normal
se_enabled: false
ns_enabled: true
vad_enabled: false
continuous_vad: true
agc_enabled: true
memory_alloc_mode: more_psram
task_core: 1
task_priority: 5
ringbuf_size: 8
feed_task_core: 0
feed_task_priority: 5
feed_task_stack_size: 3072
fetch_task_core: 1
fetch_task_priority: 5
fetch_task_stack_size: 3072
feed_buf_in_psram: false
feed_ring_in_psram: true
fetch_ring_in_psram: false
microphone:
- platform: esp_audio_stack
id: mic_main
esp_audio_stack_id: audio_stack
speaker:
- platform: esp_audio_stack
id: hw_speaker
esp_audio_stack_id: audio_stack
sample_rate: 48000
bits_per_sample: 16
timeout: 1s
# =============================================================================
# MEDIA, ASSIST AND VOIP
# =============================================================================
# Generic AFE targets are intended for 8 MB or larger flash layouts, so keep
# the full VA timer alarm that the 4 MB AEC-light profile omits.
audio_file:
- id: timer_finished_sound
file: ${assets_base}assets/sounds/timer_finished.flac
micro_wake_word:
microphone: mic_main
models:
- model: alexa
voice_assistant:
microphone: mic_main
media_player: speaker_media_player
micro_wake_word: mww
noise_suppression_level: 2
auto_gain: 31dBFS
volume_multiplier: 2.0
voip_stack:
task_stacks_in_psram: true # save ~28KB internal heap on S3 by placing task stacks in PSRAM
buffers_in_psram: true # VoIP staging buffers in PSRAM; AEC/AFE buffers live in esp_audio_stack
audio:
# Primary/preferred RTP profile: 48 kHz/10 ms toward the speaker, and a
# matching 10 ms TX reframe of the 16 kHz AFE mic for peers that negotiate
# ptime 10. 32 kHz/16 ms remains an alternate advertised format.
tx_formats:
- sample_rate: 16000
pcm_format: s16le
channels: 1
frame_ms: 10
rx:
sample_rate: 48000
pcm_format: s16le
channels: 1
frame_ms: 10
# Additional accepted RX formats for direct ESP-to-ESP calls. These are valid
# only because speaker: voip_speaker_input points at the resampler; do
# not advertise additional formats when wiring voip_stack directly to a
# fixed-rate mixer input.
rx_formats:
- sample_rate: 32000
pcm_format: s16le
channels: 1
frame_ms: 16
- sample_rate: 16000
pcm_format: s16le
channels: 1
frame_ms: 10
- sample_rate: 16000
pcm_format: s16le
channels: 1
frame_ms: 16
- sample_rate: 16000
pcm_format: s16le
channels: 1
frame_ms: 32
microphone: mic_main
speaker: voip_speaker_input
ringing_timeout: 30s
delete_contact_missing_from:
updates_number: 1
# =============================================================================
# RUNTIME LOGIC AND ENTITIES
# =============================================================================
script:
- id: timer_alarm_loop
mode: single
then:
- while:
condition:
runtime_controller.is_active:
id: runtime
activity: timer_ringing
then:
- media_player.play_media:
id: speaker_media_player
media_url: "audio-file://timer_finished_sound"
announcement: true
- delay: 6s
- id: timer_alarm_auto_stop
mode: restart
then:
- delay: 15min
- runtime_controller.event:
id: runtime
event: timer_stopped
# Local BOOT button: short press controls VA/call toggle, double press changes
# contact, long press toggles microphone mute.
binary_sensor:
# BOOT button (GPIO0), multi-click
- platform: gpio
name: Boot Button
id: boot_button
pin:
number: GPIO0
inverted: true
mode:
input: true
pullup: true
on_multi_click:
# Single click: call toggle if VoIP call active, otherwise VA start/stop
- timing:
- ON for at most 500ms
- OFF for at least 400ms
then:
- if:
condition:
runtime_controller.is_active:
id: runtime
activity: timer_ringing
then:
- runtime_controller.event:
id: runtime
event: timer_stopped
else:
- if:
condition:
not:
- voip_stack.is_idle:
then:
- voip_stack.call_toggle:
else:
- if:
condition:
voice_assistant.is_running:
then:
- voice_assistant.stop:
else:
- voice_assistant.start:
# Double click: next contact
- timing:
- ON for 50ms to 500ms
- OFF for at most 300ms
- ON for 50ms to 500ms
- OFF for at least 400ms
then:
- voip_stack.next_contact:
# Long press (1-3s): toggle mute
- timing:
- ON for 1s to 3s
- OFF for at least 300ms
then:
- switch.toggle: mute
select:
- platform: template
name: AEC Mode
id: aec_mode_select
icon: mdi:tune-vertical
# Full-experience default: use the Espressif AFE pipeline. Generic single-mic
# targets stay on SR modes by default to preserve MWW spectral features while
# still using AFE-owned AEC/NS/AGC plumbing.
options:
- "fd_low_cost"
- "fd_high_perf"
initial_option: "fd_high_perf"
# Non-optimistic: HA reflects the live component mode, not the value the
# user clicked. If the switch is rejected (e.g. internal RAM fragmented)
# or the component falls back to the previous mode, the select shows the
# actual mode rather than a fictitious one.
optimistic: false
restore_value: false
set_action:
- if:
condition:
lambda: 'return id(init_in_progress);'
then:
- logger.log: "AEC mode select: skipping during boot"
else:
- if:
condition:
or:
- voice_assistant.is_running:
- not:
voip_stack.is_idle:
then:
- logger.log:
level: WARN
format: "Cannot switch AEC mode during active VA/VoIP"
else:
- logger.log:
format: "Switching AEC mode to %s"
args: ['x.c_str()']
- micro_wake_word.stop:
- esp_audio_stack.stop_and_wait: audio_stack
- wait_until:
condition:
esp_audio_stack.is_idle: audio_stack
timeout: 2s
- esp_afe.set_mode:
id: afe_processor
mode: !lambda 'return x;'
- wait_until:
condition:
lambda: 'return id(afe_processor).is_reconfigure_idle();'
timeout: 20s
- if:
condition:
lambda: 'return id(afe_processor).is_reconfigure_idle() && id(afe_processor).get_last_reconfigure_ok();'
then:
- esp_audio_stack.start: audio_stack
- delay: 300ms
- if:
condition:
switch.is_off: mute
then:
- micro_wake_word.start:
else:
- logger.log:
level: ERROR
tag: main
format: "AFE mode switch did not complete cleanly; audio restart skipped"
# Reflect actual live mode (covers rejection and silent hardware mode).
- lambda: |-
id(aec_mode_select).publish_state(id(afe_processor).get_mode_name());