Updated Sketch for voice assistant.
This commit is contained in:
		| @@ -1,15 +1,13 @@ | |||||||
| substitutions: | substitutions: | ||||||
|   name: "m5stack-atom-echo" |   name: m5stack-atom-echo | ||||||
|   friendly_name: "M5Stack Atom Echo" |   friendly_name: M5Stack Atom Echo | ||||||
|  |   micro_wake_word_model: okay_nabu  # alexa, hey_jarvis, hey_mycroft are also supported | ||||||
|  |  | ||||||
| esphome: | esphome: | ||||||
|   name: ${name} |   name: ${name} | ||||||
|   friendly_name: ${friendly_name} |  | ||||||
|   name_add_mac_suffix: False |   name_add_mac_suffix: False | ||||||
|   project: |   friendly_name: ${friendly_name} | ||||||
|     name: m5stack.atom-echo-voice-assistant |   min_version: 2025.2.0 | ||||||
|     version: "24.7.24" |  | ||||||
|   min_version: 2024.9.0 |  | ||||||
|  |  | ||||||
| esp32: | esp32: | ||||||
|   board: m5stack-atom |   board: m5stack-atom | ||||||
| @@ -25,25 +23,12 @@ api: | |||||||
|  |  | ||||||
| ota: | ota: | ||||||
|   - platform: esphome |   - platform: esphome | ||||||
|     password: !secret ota |  | ||||||
|     id: ota_esphome |     id: ota_esphome | ||||||
|   - platform: http_request |     password: !secret ota | ||||||
|     id: ota_http_request |  | ||||||
|  |  | ||||||
| update: |  | ||||||
|   - platform: http_request |  | ||||||
|     id: update_http_request |  | ||||||
|     name: Firmware |  | ||||||
|     source: https://firmware.esphome.io/voice-assistant/m5stack-atom-echo/manifest.json |  | ||||||
|  |  | ||||||
| http_request: |  | ||||||
|  |  | ||||||
| wifi: | wifi: | ||||||
|   on_connect: |   on_connect: | ||||||
|     - delay: 5s  # Gives time for improv results to be transmitted |     - delay: 5s  # Gives time for improv results to be transmitted | ||||||
|     - ble.disable: |  | ||||||
|   on_disconnect: |  | ||||||
|     - ble.enable: |  | ||||||
|   ssid: Voltage-legacy |   ssid: Voltage-legacy | ||||||
|   password: !secret voltage_legacy_psk |   password: !secret voltage_legacy_psk | ||||||
|   use_address: ${name}.home |   use_address: ${name}.home | ||||||
| @@ -54,22 +39,11 @@ wifi: | |||||||
|     ssid: "Raspiaudio Fallback Hotspot" |     ssid: "Raspiaudio Fallback Hotspot" | ||||||
|     password: !secret fallback_psk |     password: !secret fallback_psk | ||||||
|  |  | ||||||
| improv_serial: |  | ||||||
|  |  | ||||||
| esp32_improv: |  | ||||||
|   authorizer: none |  | ||||||
|  |  | ||||||
| logger: | logger: | ||||||
|  |  | ||||||
| dashboard_import: |  | ||||||
|   package_import_url: github://esphome/firmware/voice-assistant/m5stack-atom-echo.adopted.yaml@main |  | ||||||
|  |  | ||||||
| captive_portal: | captive_portal: | ||||||
|  |  | ||||||
| button: | button: | ||||||
|   - platform: safe_mode |  | ||||||
|     id: button_safe_mode |  | ||||||
|     name: Safe Mode Boot |  | ||||||
|   - platform: factory_reset |   - platform: factory_reset | ||||||
|     id: factory_reset_btn |     id: factory_reset_btn | ||||||
|     name: Factory reset |     name: Factory reset | ||||||
| @@ -91,16 +65,52 @@ speaker: | |||||||
|     id: echo_speaker |     id: echo_speaker | ||||||
|     i2s_dout_pin: GPIO22 |     i2s_dout_pin: GPIO22 | ||||||
|     dac_type: external |     dac_type: external | ||||||
|     channel: mono |     bits_per_sample: 32bit | ||||||
|  |     channel: right | ||||||
|  |     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: | ||||||
|  |             - if: | ||||||
|  |                 condition: | ||||||
|  |                   lambda: return id(wake_word_engine_location).state == "On device"; | ||||||
|  |                 then: | ||||||
|  |                   - micro_wake_word.stop: | ||||||
|  |                 else: | ||||||
|  |                   - voice_assistant.stop: | ||||||
|  |             - script.execute: reset_led | ||||||
|  |       - light.turn_on: | ||||||
|  |           id: led | ||||||
|  |           blue: 100% | ||||||
|  |           red: 0% | ||||||
|  |           green: 0% | ||||||
|  |           brightness: 100% | ||||||
|  |           effect: none | ||||||
|  |     on_idle: | ||||||
|  |       - script.execute: start_wake_word | ||||||
|  |  | ||||||
| voice_assistant: | voice_assistant: | ||||||
|   id: va |   id: va | ||||||
|   microphone: echo_microphone |   microphone: echo_microphone | ||||||
|   speaker: echo_speaker |   media_player: echo_media_player | ||||||
|   noise_suppression_level: 2 |   noise_suppression_level: 2 | ||||||
|   auto_gain: 31dBFS |   auto_gain: 31dBFS | ||||||
|   volume_multiplier: 2.0 |   volume_multiplier: 2.0 | ||||||
|   vad_threshold: 3 |  | ||||||
|   on_listening: |   on_listening: | ||||||
|     - light.turn_on: |     - light.turn_on: | ||||||
|         id: led |         id: led | ||||||
| @@ -125,10 +135,7 @@ voice_assistant: | |||||||
|         effect: none |         effect: none | ||||||
|   on_end: |   on_end: | ||||||
|     - delay: 100ms |     - delay: 100ms | ||||||
|     - wait_until: |     - script.execute: start_wake_word | ||||||
|         not: |  | ||||||
|           speaker.is_playing: |  | ||||||
|     - script.execute: reset_led |  | ||||||
|   on_error: |   on_error: | ||||||
|     - light.turn_on: |     - light.turn_on: | ||||||
|         id: led |         id: led | ||||||
| @@ -137,28 +144,21 @@ voice_assistant: | |||||||
|         blue: 0% |         blue: 0% | ||||||
|         brightness: 100% |         brightness: 100% | ||||||
|         effect: none |         effect: none | ||||||
|     - delay: 1s |     - delay: 2s | ||||||
|     - script.execute: reset_led |     - script.execute: reset_led | ||||||
|   on_client_connected: |   on_client_connected: | ||||||
|     - if: |     - delay: 2s  # Give the api server time to settle | ||||||
|         condition: |     - script.execute: start_wake_word | ||||||
|           switch.is_on: use_wake_word |  | ||||||
|         then: |  | ||||||
|           - voice_assistant.start_continuous: |  | ||||||
|           - script.execute: reset_led |  | ||||||
|   on_client_disconnected: |   on_client_disconnected: | ||||||
|     - if: |  | ||||||
|         condition: |  | ||||||
|           switch.is_on: use_wake_word |  | ||||||
|         then: |  | ||||||
|     - voice_assistant.stop: |     - voice_assistant.stop: | ||||||
|           - light.turn_off: led |     - micro_wake_word.stop: | ||||||
|   on_timer_finished: |   on_timer_finished: | ||||||
|     - voice_assistant.stop: |     - voice_assistant.stop: | ||||||
|     - switch.turn_on: timer_ringing |     - micro_wake_word.stop: | ||||||
|     - wait_until: |     - wait_until: | ||||||
|         not: |         not: | ||||||
|           microphone.is_capturing: |           microphone.is_capturing: | ||||||
|  |     - switch.turn_on: timer_ringing | ||||||
|     - light.turn_on: |     - light.turn_on: | ||||||
|         id: led |         id: led | ||||||
|         red: 0% |         red: 0% | ||||||
| @@ -166,25 +166,15 @@ voice_assistant: | |||||||
|         blue: 0% |         blue: 0% | ||||||
|         brightness: 100% |         brightness: 100% | ||||||
|         effect: "Fast Pulse" |         effect: "Fast Pulse" | ||||||
|     - while: |  | ||||||
|         condition: |  | ||||||
|           switch.is_on: timer_ringing |  | ||||||
|         then: |  | ||||||
|           - lambda: id(echo_speaker).play(id(timer_finished_wave_file), sizeof(id(timer_finished_wave_file))); |  | ||||||
|           - delay: 1s |  | ||||||
|     - wait_until: |     - wait_until: | ||||||
|         not: |         - switch.is_off: timer_ringing | ||||||
|           speaker.is_playing: |  | ||||||
|     - light.turn_off: led |     - light.turn_off: led | ||||||
|     - switch.turn_off: timer_ringing |     - switch.turn_off: timer_ringing | ||||||
|     - if: |  | ||||||
|         condition: |  | ||||||
|           switch.is_on: use_wake_word |  | ||||||
|         then: |  | ||||||
|           - voice_assistant.start_continuous: |  | ||||||
|           - script.execute: reset_led |  | ||||||
|  |  | ||||||
| binary_sensor: | binary_sensor: | ||||||
|  |   # button does the following: | ||||||
|  |   # short click - stop a timer | ||||||
|  |   # if no timer then restart either microwakeword or voice assistant continuous | ||||||
|   - platform: gpio |   - platform: gpio | ||||||
|     pin: |     pin: | ||||||
|       number: GPIO39 |       number: GPIO39 | ||||||
| @@ -204,23 +194,7 @@ binary_sensor: | |||||||
|               then: |               then: | ||||||
|                 - switch.turn_off: timer_ringing |                 - switch.turn_off: timer_ringing | ||||||
|               else: |               else: | ||||||
|                 - if: |                 - script.execute: start_wake_word | ||||||
|                     condition: |  | ||||||
|                       switch.is_off: use_wake_word |  | ||||||
|                     then: |  | ||||||
|                       - if: |  | ||||||
|                           condition: voice_assistant.is_running |  | ||||||
|                           then: |  | ||||||
|                             - voice_assistant.stop: |  | ||||||
|                             - script.execute: reset_led |  | ||||||
|                           else: |  | ||||||
|                             - voice_assistant.start: |  | ||||||
|                     else: |  | ||||||
|                       - voice_assistant.stop |  | ||||||
|                       - delay: 1s |  | ||||||
|                       - script.execute: reset_led |  | ||||||
|                       - script.wait: reset_led |  | ||||||
|                       - voice_assistant.start_continuous: |  | ||||||
|       - timing: |       - timing: | ||||||
|           - ON for at least 10s |           - ON for at least 10s | ||||||
|         then: |         then: | ||||||
| @@ -257,7 +231,7 @@ script: | |||||||
|     then: |     then: | ||||||
|       - if: |       - if: | ||||||
|           condition: |           condition: | ||||||
|             - switch.is_on: use_wake_word |             - lambda: return id(wake_word_engine_location).state == "On device"; | ||||||
|             - switch.is_on: use_listen_light |             - switch.is_on: use_listen_light | ||||||
|           then: |           then: | ||||||
|             - light.turn_on: |             - light.turn_on: | ||||||
| @@ -268,28 +242,45 @@ script: | |||||||
|                 brightness: 60% |                 brightness: 60% | ||||||
|                 effect: none |                 effect: none | ||||||
|           else: |           else: | ||||||
|             - light.turn_off: led |  | ||||||
|  |  | ||||||
| switch: |  | ||||||
|   - platform: template |  | ||||||
|     name: Use wake word |  | ||||||
|     id: use_wake_word |  | ||||||
|     optimistic: true |  | ||||||
|     restore_mode: RESTORE_DEFAULT_ON |  | ||||||
|     entity_category: config |  | ||||||
|     on_turn_on: |  | ||||||
|       - lambda: id(va).set_use_wake_word(true); |  | ||||||
|             - if: |             - if: | ||||||
|                 condition: |                 condition: | ||||||
|             not: |                   - lambda: return id(wake_word_engine_location).state != "On device"; | ||||||
|               - voice_assistant.is_running |                   - 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: | ||||||
|  |       - wait_until: | ||||||
|  |           and: | ||||||
|  |             - media_player.is_idle: | ||||||
|  |             - speaker.is_stopped: | ||||||
|  |       - if: | ||||||
|  |           condition: | ||||||
|  |             lambda: return id(wake_word_engine_location).state == "On device"; | ||||||
|           then: |           then: | ||||||
|             - voice_assistant.start_continuous |  | ||||||
|       - script.execute: reset_led |  | ||||||
|     on_turn_off: |  | ||||||
|             - voice_assistant.stop |             - voice_assistant.stop | ||||||
|       - lambda: id(va).set_use_wake_word(false); |             - micro_wake_word.stop: | ||||||
|  |             - delay: 1s | ||||||
|             - script.execute: reset_led |             - script.execute: reset_led | ||||||
|  |             - script.wait: reset_led | ||||||
|  |             - micro_wake_word.start: | ||||||
|  |           else: | ||||||
|  |             - if: | ||||||
|  |                 condition: voice_assistant.is_running | ||||||
|  |                 then: | ||||||
|  |                   - voice_assistant.stop: | ||||||
|  |                   - script.execute: reset_led | ||||||
|  |             - voice_assistant.start_continuous: | ||||||
|  |  | ||||||
|  | switch: | ||||||
|   - platform: template |   - platform: template | ||||||
|     name: Use listen light |     name: Use listen light | ||||||
|     id: use_listen_light |     id: use_listen_light | ||||||
| @@ -303,26 +294,67 @@ switch: | |||||||
|   - platform: template |   - platform: template | ||||||
|     id: timer_ringing |     id: timer_ringing | ||||||
|     optimistic: true |     optimistic: true | ||||||
|     internal: true |  | ||||||
|     restore_mode: ALWAYS_OFF |     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: |     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 |       - delay: 15min | ||||||
|       - switch.turn_off: timer_ringing |       - switch.turn_off: timer_ringing | ||||||
|  |  | ||||||
| external_components: | select: | ||||||
|   - source: github://pr#5230 |   - platform: template | ||||||
|     components: |     entity_category: config | ||||||
|       - esp_adf |     name: Wake word engine location | ||||||
|     refresh: 0s |     id: wake_word_engine_location | ||||||
|   - source: |     optimistic: true | ||||||
|       type: git |     restore_value: true | ||||||
|       url: https://github.com/jesserockz/esphome-components |     options: | ||||||
|       ref: main |       - In Home Assistant | ||||||
|     components: [file] |       - On device | ||||||
|     refresh: 0s |     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 | ||||||
|  |  | ||||||
| esp_adf: | micro_wake_word: | ||||||
|  |   on_wake_word_detected: | ||||||
| file: |     - voice_assistant.start: | ||||||
|   - id: timer_finished_wave_file |         wake_word: !lambda return wake_word; | ||||||
|     file: https://github.com/esphome/firmware/raw/main/voice-assistant/sounds/timer_finished.wav |   vad: | ||||||
|  |   models: | ||||||
|  |     - model: ${micro_wake_word_model} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user