DIY VoicePuck - A lightweight voice assistant

Here is my take on the voice assistant hype.

A ‘smaller then google home’ sized puck. I tried to make the yaml as light weighted as possible so it will compile on lower end systems. A second objective was to minimise the use of external code as much as possible. Other objectives where easy to make and using readily available parts that don’t cost much
All information and 3D files are found here
VoicePuck

UPDATE Version 2

While version 1 works it still suffered from stalls from time to time. The ESP32-S3-BOX version that I also have showed to be far more stable. Because of this I abandoned to ‘no external files’ concept and went for the full blown version and took the ESP32-S3-BOX version as start. I stripped everything that deals with the screen and the buttons on the box. I’ve added my own sensors and other tools. Things I like to see and control in HA such as diagnostics, request and response sensors and timer info. The hardware stayed the same so this installs directly on the VoicePuck. This version is a lot heavier when compiling. My advise is to start with cleaning your build files and start compiling. When it fails just restart again. File locks will occure but they will be cleared. Files that are already compiled will be skipped so the processor load on lower end systems will handle in the end a full compile.

UPDATE Version 3
With this version you can have continuous conversations without the need to say the wake word every time.

7 Likes

Thanks for the share, really neat :ok_hand:

UPDATE Version 2

While version 1 works it still suffered from stalls from time to time. The ESP32-S3-BOX version that I also have showed to be far more stable. Because of this I abandoned to ‘no external files’ concept and went for the full blown version and took the ESP32-S3-BOX version as start. I stripped everything that deals with the screen and the buttons on the box. I’ve added my own sensors and other tools. Things I like to see and control in HA such as diagnostics, request and response sensors and timer info. The hardware stayed the same so this installs directly on the VoicePuck. This version is a lot heavier when compiling. My advise is to start with cleaning your build files and start compiling. When it fails just restart again. File locks will occure but they will be cleared. Files that are already compiled will be skipped so the processor load on lower end systems will handle in the end a full compile.

Looks like a nice project!
Since im a cheapskate and dont want to invest 50+ bucks into the -box version I am going to try this…

Just to clarify and dumb it down: you just used the same core/essential-hardware like the S3-box version and used the bare minimum of the s3-box version in your V2, didn’t you?

looking at the schematics: Can a single LED be used instead to make wiring easier? If yes: how should that be conneced and if not: how does the wiring of the 3 WS2812B LEDs look like? Schematics are a little bit unclear in that case…

Yes, the V2 yaml is the same as the S3-Box version without all the screen elements. These are replaced for HA sensors for timer, request and response info.

You can drop the extra LEDs if you want and just use the on board RGB LED.
If you do then make sure you change this to the onboard LED gpio and the number of leds to 1

light:
  - platform: esp32_rmt_led_strip
    rgb_order: GRB
    pin: GPIO48 # On board light
    num_leds: 1
1 Like

New version available

UPDATE Version 3
With this version you can have continuous conversations without the need to say the wake word every time.

Version 4.0

Based on the IDF framework

# ESP Voice Assistant
# 10 Oct 2025 (v 4.0.0) - last compile date
#  Work without a screen but with I2s amp and mic
#   Added some LED's for interacting
#   Request and response sensors in HA
#
# by A.A. van Zoelen
# Based on the work of Giants


substitutions:
  # Phases of the Voice Assistant
  # IDLE: The voice assistant is ready to be triggered by a wake-word
  voice_assist_idle_phase_id: '1'
  # LISTENING: The voice assistant is ready to listen to a voice command (after being triggered by the wake word)
  voice_assist_listening_phase_id: '2'
  # THINKING: The voice assistant is currently processing the command
  voice_assist_thinking_phase_id: '3'
  # REPLYING: The voice assistant is replying to the command
  voice_assist_replying_phase_id: '4'
  # NOT_READY: The voice assistant is not ready 
  voice_assist_not_ready_phase_id: '10'
  # ERROR: The voice assistant encountered an error
  voice_assist_error_phase_id: '11'  
  # MUTED: The voice assistant is muted and will not reply to a wake-word
  voice_assist_muted_phase_id: '12'

esphome:
  name: "esp-assistant-vp"
  friendly_name: ESP Assistant VP
  project:
    name: AA_van_Zoelen.VoicePuck
    version: '4.0.0'
  on_boot:
    priority: 600
    then:
      - light.turn_on:
          id: led_strip
          blue: 0%
          red: 0%
          green: 100%
          brightness: 50%
          effect: "scanning"
      - delay: 30s
      - if:
          condition:
            lambda: return id(init_in_progress);
          then:
            - lambda: id(init_in_progress) = false;
            - light.turn_off:
                id: led_strip
      

esp32:
  board: esp32-s3-devkitc-1
  cpu_frequency: 240MHz
  variant: esp32s3
  flash_size: 16MB
  framework:
    type: esp-idf
    version: recommended
    sdkconfig_options:
      CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
      CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
      CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB: "y"

      CONFIG_SPIRAM_RODATA: "y"
      CONFIG_SPIRAM_FETCH_INSTRUCTIONS: "y"

      CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST: "y"
      CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY: "y"

      CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC: "y"
      CONFIG_MBEDTLS_SSL_PROTO_TLS1_3: "y" 

#network:
#  enable_ipv6: true

# Enable logging
logger:

# Enable Home Assistant API
api:
#  encryption:
#    key: !secret api_key 
  actions:
    - action: start_va
      then:
        - voice_assistant.start
    - action: stop_va
      then:
        - voice_assistant.stop

ota:
  - platform: esphome
#    password: "----------------"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  output_power: 8.5dB
  # If the device connects, or disconnects, to the Wifi: Run the script to refresh the LED status
  on_connect:
    - light.turn_off:
        id: led_strip      
  on_disconnect:
    - light.turn_on:
        id: led_strip
        blue: 0%
        red: 100%
        green: 0%
        brightness: 98%
        effect: "Fast Pulse"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: !secret fallback_ssid
    password: !secret fallback_password

psram:
  mode: octal
  speed: 80MHz

i2s_audio:
  - id: i2s_in
    i2s_lrclk_pin: GPIO18  #WS 
    i2s_bclk_pin: GPIO2 #SCK
  - id: i2s_out
    i2s_lrclk_pin: GPIO6
    i2s_bclk_pin: GPIO7

microphone:
  - platform: i2s_audio
    id: mic_id
    adc_type: external
    i2s_audio_id: i2s_in
    i2s_din_pin: GPIO4 #SD
    channel: left
    

speaker:
  - platform: i2s_audio
    id: speaker_id
    i2s_audio_id: i2s_out
    dac_type: external
    i2s_dout_pin:   
      number: GPIO8 #DIN Pin of the MAX98357A Audio Amplifier
    sample_rate: 48000
    buffer_duration: 90ms

  - platform: mixer
    id: mixer_speaker_id
    output_speaker: speaker_id
    source_speakers:
      - id: announcement_spk_mixer_input
      - id: media_spk_mixer_input

  - platform: resampler
    id: media_spk_resampling_input
    output_speaker: media_spk_mixer_input
  - platform: resampler
    id: announcement_spk_resampling_input
    output_speaker: announcement_spk_mixer_input

globals:
  # Global initialisation variable. Initialized to true and set to false once everything is connected. Only used to have a smooth "plugging" experience
  - id: init_in_progress
    type: bool
    restore_value: no
    initial_value: 'true'
  # Global variable tracking the phase of the voice assistant (defined above). Initialized to not_ready
  - id: voice_assistant_phase
    type: int
    restore_value: no
    initial_value: ${voice_assist_not_ready_phase_id}
  # Variable for tracking TTS triggering 
  - id: is_tts_active
    type: bool
    restore_value: no
    initial_value: 'false'
  # Variable for tracking built-in continued conversations 
  - id: question_flag
    type: bool
    restore_value: no
    initial_value: 'false'
  # Variable for tracking ww
  - id: last_wake_word
    type: std::string
    restore_value: no
    initial_value: '""'

light:
  - platform: esp32_rmt_led_strip
    rgb_order: GRB
    pin: GPIO17 #GPIO48 # On board light
    num_leds: 3
    chipset: WS2812
    name: "Status LED"
    id: led_strip
    disabled_by_default: True
    entity_category: config
    icon: mdi:led-on
    default_transition_length: 0s
    effects:
      - pulse:
          name: "Slow Pulse"
          transition_length: 770ms
          update_interval: 770ms
          min_brightness: 10%
          max_brightness: 20%
      - pulse:
          name: "Fast Pulse"
          transition_length: 100ms
          update_interval: 100ms
          min_brightness: 60%
          max_brightness: 80%
      - addressable_scan:
          name: "Scanning"
          move_interval: 120ms
          scan_width: 1
      - pulse:
          name: "Waiting for wake word"
          min_brightness:  15%
          max_brightness: 35%
          transition_length: 3s      # defaults to 1s
          update_interval: 3s


media_player:
  - platform: speaker
    name: None
    id: speaker_media_player_id
    media_pipeline:
        speaker: media_spk_resampling_input
        num_channels: 1
    announcement_pipeline:
        speaker: announcement_spk_resampling_input
        num_channels: 1
    on_announcement:
      - mixer_speaker.apply_ducking:
          id: media_spk_mixer_input
          decibel_reduction: 25
          duration: 0.2s
    on_state:
      - delay: 0.7s
      -  if:
          condition:
            and:
              - not:
                  voice_assistant.is_running:
              - not:
                  media_player.is_announcing:
          then:
            - mixer_speaker.apply_ducking:
                id: media_spk_mixer_input
                decibel_reduction: !lambda |-
                  return id(ducking_decibel).state;
                duration: 1.0s
    files:
      - id: alarm_sound
        #file: https://github.com/mitrokun/esp32s3-voice_assistant/raw/main/alarm.flac # 48000 Hz sample rate, mono or stereo audio, and 16 bps
        file: sounds/alarm.flac
      - id: beep
        #file: https://github.com/mitrokun/esp32s3-voice_assistant/raw/main/r2d2d.flac
        file: sounds/r2d2d.flac
 
voice_assistant:
  id: va
  microphone:
    microphone: mic_id
    gain_factor: 16
  media_player: speaker_media_player_id
  micro_wake_word: mww
  noise_suppression_level: 2.0
  auto_gain: 0 dbfs
  volume_multiplier: 1

  # When the voice assistant connects to HA:
  # Set init_in_progress to false (Initialization is over).
  # If the switch is on, start the voice assistant
  on_client_connected:
    - lambda: id(init_in_progress) = false; 
    - if:
        condition:
          switch.is_on: voice_enabled
        then:
          - micro_wake_word.start
          - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id};
        else:
          - lambda: id(voice_assistant_phase) = ${voice_assist_muted_phase_id};
    - light.turn_on:
        id: led_strip
        blue: 10%
        red: 10%
        green: 100%
        effect: "Waiting for wake word"
    - delay: 5s
    - light.turn_off:
        id: led_strip  


  # When the voice assistant disconnects to HA: 
  # Stop the voice assistant
  on_client_disconnected:
    - lambda: id(voice_assistant_phase) = ${voice_assist_not_ready_phase_id};  
    - micro_wake_word.stop

  on_listening:
    # Reset flags
    - lambda: |-
        id(voice_assistant_phase) = ${voice_assist_listening_phase_id};
        id(is_tts_active) = false;
        id(question_flag) = false;
    # Microphone operation indicator (red led)
    - light.turn_on:
        id: led_strip
        blue: 0%
        red: 100%
        green: 0%
        brightness: 50%
        effect: "Fast Pulse"
    # Waiting for speech for 4 seconds, otherwise exit
    - script.execute: listening_timeout

  on_stt_vad_start:
    # Turn off the script if speech is detected
    - script.stop: listening_timeout

  on_stt_vad_end:
    - light.turn_off:
        id: led_strip  
    - lambda: id(voice_assistant_phase) = ${voice_assist_thinking_phase_id};

  on_stt_end:
  # Event for HA with recognized speech
  - homeassistant.event:
      event: esphome.stt_text
      data:
        text: !lambda return x;

  on_intent_progress:
    - if:
        condition:
          # A nonempty x variable means a streaming TTS url was sent to the media player
          lambda: 'return !x.empty();'
        then:
          - lambda: id(voice_assistant_phase) = ${voice_assist_replying_phase_id};
          # Set the flag when the stage is reached
          - lambda: |-
              id(is_tts_active) = true;
          # Start a script that would potentially enable the stop word if the response is longer than a second
          - script.execute: activate_stop_word_once

  on_tts_start:
    - if:
        condition:
          # The intent_progress trigger didn't start the TTS Reponse
          lambda: 'return id(voice_assistant_phase) != ${voice_assist_replying_phase_id};'
        then:
          - lambda: id(voice_assistant_phase) = ${voice_assist_replying_phase_id};
          # Start a script that would potentially enable the stop word if the response is longer than a second
          - script.execute: activate_stop_word_once
    # Finding a question mark at the end of a sentence.
    - lambda: |-
        bool is_question = false;
        if (!x.empty() && x.back() == '?') {
          is_question = true;
        }
        id(question_flag) = is_question;

  on_tts_end:
    - if:
        condition:
          switch.is_on: extended_dialog
        then:
          - lambda: |-
              id(is_tts_active) = true;

  on_timer_finished:
    then:
      - switch.turn_on: timer_ringing

  on_end:
    # Additional check for microphone LED
    - if:
        condition:
          - light.is_on: led_strip
        then:
          - light.turn_off:
              id: led_strip  

    - wait_until:
        condition:
          - media_player.is_announcing:
        timeout: 0.5s

    - wait_until:
        not:
          voice_assistant.is_running:
    - delay: 0.5s
     
    # New start of the pipeline if the conditions are met
    - if:
        condition:
          and:
            - switch.is_on: continued_conversation_enabled
            - lambda: 'return !id(question_flag);'
            - lambda: 'return id(is_tts_active);'
            - lambda: 'return id(last_wake_word) != "Stop";'
        then:
          - voice_assistant.start:
              wake_word: !lambda return id(last_wake_word);
        else: 
          # Stop ducking audio.
          - mixer_speaker.apply_ducking:
              id: media_spk_mixer_input
              decibel_reduction: !lambda |-
                return id(ducking_decibel).state;
              duration: 1.0s
          - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id};

  # When the voice assistant encounters an error: 
  # Wait 1 second and set the correct phase (idle or muted depending on the state of the switch)
  on_error:
    - if:
        condition:
          lambda: return !id(init_in_progress);
        then:
          - lambda: id(voice_assistant_phase) = ${voice_assist_error_phase_id};  
          - delay: 1s
          - if:
              condition:
                switch.is_on: voice_enabled
              then:
                - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id};
              else:
                - lambda: id(voice_assistant_phase) = ${voice_assist_muted_phase_id};

micro_wake_word:
  models:
    - model: https://github.com/kahrendt/microWakeWord/releases/download/okay_nabu_20241226.3/okay_nabu.json
      id: okay_nabu
    - model: https://raw.githubusercontent.com/Darkmadda/ha-v-pe/refs/heads/main/hey_glados.json
      id: hey_glados
    - model: https://github.com/kahrendt/microWakeWord/releases/download/stop/stop.json
      id: stop
      internal: true
  vad:
    model: https://github.com/kahrendt/microWakeWord/releases/download/v2.1_models/vad.json
  id: mww
  stop_after_detection: false
  on_wake_word_detected:
    - if:
        condition:
          switch.is_on: timer_ringing
        then:
          - switch.turn_off: timer_ringing
        else:
          - if:
              condition:
                switch.is_on: voice_enabled
              then:
                - if:
                    condition:
                      voice_assistant.is_running:
                    # Restart the pipeline if Continued conversation is enabled
                    # Or stop it completely by saying “Stop”
                    then:
                      - lambda: id(last_wake_word) = wake_word;
                      - delay: 100ms
                      - voice_assistant.stop:
                    # Stop any other media player announcement
                    else:
                      - if:
                          condition:
                            media_player.is_announcing:
                          then:
                            - media_player.stop:
                                announcement: true
                          # Start the voice assistant and play the wake sound, if enabled
                          else:
                            - lambda: id(last_wake_word) = wake_word;
                            - script.execute:
                                id: play_sound
                                priority: true
                                sound_file: !lambda return id(beep);
                            - delay: 280ms
                            - voice_assistant.start:
                                wake_word: !lambda return wake_word;

script:
  - id: listening_timeout
    mode: restart 
    then:
      - delay: 3s
      - if:
          condition:
            lambda: |-
              return id(voice_assistant_phase) == 2;
          then:
            - light.turn_off:
                id: led_strip 
            - voice_assistant.stop:
            - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id};

  - id: activate_stop_word_once
    then:
      - delay: 1s
      # Enable stop wake word
      - if:
          condition:
            switch.is_off: timer_ringing
          then:
            - micro_wake_word.enable_model: stop
            - wait_until:
                not:
                  media_player.is_announcing:
            - if:
                condition:
                  switch.is_off: timer_ringing
                then:
                  - micro_wake_word.disable_model: stop

  - id: play_sound
    parameters:
      priority: bool
      sound_file: "audio::AudioFile*"
    then:
      - lambda: |-
          if (priority) {
            id(speaker_media_player_id)
              ->make_call()
              .set_command(media_player::MediaPlayerCommand::MEDIA_PLAYER_COMMAND_STOP)
              .set_announcement(true)
              .perform();
          }
          if ( (id(speaker_media_player_id).state != media_player::MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING ) || priority) {
            id(speaker_media_player_id)
              ->play_file(sound_file, true, false);
          }

select:
  - platform: template
    name: "Wake word sensitivity"
    optimistic: true
    initial_option: Slightly sensitive
    restore_value: true
    entity_category: config
    options:
      - Slightly sensitive
      - Slightly+ sensitive
      - Moderately sensitive
      - Very sensitive
    on_value:
      # Sets specific wake word probabilities computed for each particular model
      # Note probability cutoffs are set as a quantized uint8 value, each comment has the corresponding floating point cutoff
      # False Accepts per Hour values are tested against all units and channels from the Dinner Party Corpus.
      # These cutoffs apply only to the specific models included in the firmware: [email protected], hey_jarvis@v2, hey_mycroft@v2
      lambda: |-
        if (x == "Slightly sensitive") {
          id(okay_nabu).set_probability_cutoff(217);    // 0.85 -> 0.000 FAPH on DipCo (Manifest's default)
        } else if (x == "Slightly+ sensitive") {
          id(okay_nabu).set_probability_cutoff(191);    // 0.75
        } else if (x == "Moderately sensitive") {
          id(okay_nabu).set_probability_cutoff(176);    // 0.69 -> 0.376 FAPH on DipCo
        } else if (x == "Very sensitive") {
          id(okay_nabu).set_probability_cutoff(143);    // 0.56 -> 0.751 FAPH on DipCo
        }
  - platform: logger
    id: logger_select
    name: Logger Level
    disabled_by_default: true

button:
  - platform: restart
    name: reboot

number:
  - platform: template
    name: "Decibel Reduction"
    id: ducking_decibel
    min_value: 0
    max_value: 12
    step: 1
    initial_value: 0
    unit_of_measurement: "dB"
    set_action:
      - mixer_speaker.apply_ducking:
          id: media_spk_mixer_input
          decibel_reduction: !lambda 'return (int)x;'
          duration: 0.2s


switch:
  - platform: template
    name: Enable Voice Assistant
    id: voice_enabled
    optimistic: true
    restore_mode: RESTORE_DEFAULT_ON
    icon: mdi:assistant
    # When the switch is turned on (on Home Assistant):
    # Start the voice assistant component
    on_turn_on:
      - if:
          condition:
            lambda: return !id(init_in_progress);
          then:      
            - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id};
            - if:
                condition:
                  not:
                    - voice_assistant.is_running
                then:
                  - micro_wake_word.start
                  - light.turn_on:
                      id: led_strip
                      blue: 15%
                      red: 0%
                      green: 15%
                      brightness: 20%
                      effect: "Slow Pulse"                  
    # When the switch is turned off (on Home Assistant):
    # Stop the voice assistant component
    on_turn_off:
      - if:
          condition:
            lambda: return !id(init_in_progress);
          then:      
            - voice_assistant.stop
            - micro_wake_word.stop
            - lambda: id(voice_assistant_phase) = ${voice_assist_muted_phase_id};
            - light.turn_off:
                id: led_strip

  - platform: template
    name: "Ring Timer"
    id: timer_ringing
    optimistic: true
    restore_mode: ALWAYS_OFF
    on_turn_off:
        # Stop playing the alarm
        - media_player.stop:
            announcement: true
    on_turn_on:
        - while:
            condition:
                switch.is_on: timer_ringing
            then:
                # Play the alarm sound as an announcement
                - media_player.speaker.play_on_device_media_file:
                    media_file: alarm_sound
                    announcement: true
                # Wait until the alarm sound starts playing
                - wait_until:
                    media_player.is_announcing:
                # Wait until the alarm sound stops playing
                - wait_until:
                    not:
                      media_player.is_announcing:
                - delay: 1000ms

  - platform: template
    name: Continued Conversation
    id: continued_conversation_enabled
    optimistic: true
    restore_mode: RESTORE_DEFAULT_ON
    icon: mdi:chat-processing-outline

  - platform: template
    name: Continued Conversation+
    id: extended_dialog
    optimistic: true
    restore_mode: RESTORE_DEFAULT_OFF
    icon: mdi:chat-plus-outline

Thanks!
Will you update the yaml on github as well, it still is on V3?

Github updated too.
Thx for the reminder!

1 Like

Hi,

I’ve build a device according to your schematics and uploaded firmware v4.
I’m using the onboard LED only.
The device seems to start and appears in the list of detected Esphome devices.
But when I try to add it to the Esphome integration or when I try to connect to it for logging, the device is crashing.
Do you have an idea what could cause that issue?

The ESP is that one: DUBEUYEW 3pcs ESP32-S3 ESP32-S3-DevKitC-1 N16R8 WiFi Module + 5.0 Bluetooth Internet Development Board 16M External Flash Extension 8M PSRAM with a Type C Cable: Amazon.de: Computer & Accessories

Thank you for your help

No idea.
But you say you build id according the schematic and use the yaml v4 but you use only the onboard led.
The problem is that the schematic include 3 rgb leds and the yaml also expect them.

So, did you change the yaml?
Will you get logging if you connect it via a usb cable?
Other then that i have no clue at the moment.

Yes, I modified the name of the device and the LED config (gpio48 and 1 led). Everything else is unchanged.
In case it is important: I’m using Home Assistant 2025.12.1 and Esphome 2025.11.5.

Log when connecting for logging or adding it to the esphome integration:

[09:18:10][D][wifi:1103]: Disabling AP
[09:18:10][D][light:091]: 'Status LED' Setting:
[09:18:10][D][light:104]:   State: OFF
[09:18:10][D][light:165]:   Effect: 'None'
[09:18:10][W][component:337]: wifi cleared Warning flag
[09:18:26]
[09:18:26]Core  1 register dump:
[09:18:26]PC      : 0x00002500  PS      : 0x00060a30  A0      : 0x820e6e51  A1      : 0x3fcee0d0  
[09:18:26]A2      : 0x3fcee478  A3      : 0x00000039  A4      : 0x00000003  A5      : 0x00000000  
[09:18:26]A6      : 0x00000000  A7      : 0x3c18af7c  A8      : 0x8207aed8  A9      : 0x00000025  
[09:18:26]A10     : 0x00000039  A11     : 0x00000003  A12     : 0x00000000  A13     : 0x3fcaa1f8  
[09:18:26]A14     : 0x00000000  A15     : 0x00000000  SAR     : 0x0000001d  EXCCAUSE: 0x00000014  
[09:18:26]EXCVADDR: 0x00002500  LBEG    : 0x400570e8  LEND    : 0x400570f3  LCOUNT  : 0x00000000  
[09:18:26]
[09:18:26]
[09:18:26]Backtrace: 0x000024fd:0x3fcee0d0 0x420e6e4e:0x3fcee0f0 0x42013017:0x3fcee110 0x420edead:0x3fcee130 0x42004c29:0x3fcee160 0x42003b39:0x3fcee180 0x42007c47:0x3fcee1c0 0x420efd29:0x3fcee220 0x4201b03d:0x3fcee240 0x4201a856:0x3fcee260 0x4201dc76:0x3fcee290 0x42009306:0x3fcee2b0
[09:18:26]
[09:18:26]
[09:18:26]
[09:18:26]
[09:18:26]ELF file SHA256: 20a4488b7
[09:18:26]
[09:18:26]Rebooting...
[09:18:26]ESP-ROM:esp32s3-20210327
[09:18:26]Build:Mar 27 2021
[09:18:26]rst:0xc (RTC_SW_CPU_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
[09:18:26]Saved PC:0x4037e362
[09:18:26]SPIWP:0xee
[09:18:26]mode:DIO, clock div:1
[09:18:26]load:0x3fce2820,len:0x158c
[09:18:26]load:0x403c8700,len:0xc80
[09:18:26]load:0x403cb700,len:0x2f40
[09:18:26]entry 0x403c8908
[09:18:26]I (24) boot: ESP-IDF 5.5.1 2nd stage bootloader
[09:18:26]I (24) boot: compile time Dec 11 2025 07:50:31
[09:18:26]I (24) boot: Multicore bootloader
[09:18:26]I (24) boot: chip revision: v0.2
[09:18:26]I (24) boot: efuse block revision: v1.3
[09:18:26]I (25) boot.esp32s3: Boot SPI Speed : 80MHz
[09:18:26]I (25) boot.esp32s3: SPI Mode       : DIO
[09:18:26]I (25) boot.esp32s3: SPI Flash Size : 16MB
[09:18:26]I (25) boot: Enabling RNG early entropy source...
[09:18:26]I (26) boot: Partition Table:
[09:18:26]I (26) boot: ## Label            Usage          Type ST Offset   Length
[09:18:26]I (26) boot:  0 otadata          OTA data         01 00 00009000 00002000
[09:18:26]I (26) boot:  1 phy_init         RF data          01 01 0000b000 00001000
[09:18:26]I (27) boot:  2 app0             OTA app          00 10 00010000 007c0000
[09:18:26]I (27) boot:  3 app1             OTA app          00 11 007d0000 007c0000
[09:18:26]I (28) boot:  4 nvs              WiFi data        01 02 00f90000 0006d000
[09:18:26]I (28) boot: End of partition table

The error points to reading a non existing address or a null pointer.
I have no system at hand to try to replicate this. I am away from home for work a few weeks.
So i can give you only some general advise like. Sorry that i can not help you further at this moment.

Update esphome to latest version.
Clean build files first.
Try a different esp32.
Try the unchanged yaml first before making changes.

I finally found the issue:
The cause of the crash was the start of the light with “Scanning” (addressable_scan). When you only have one LED (what I had configured) the system ist crashing with the next network paket it receives …

Thank you for providing the project :slight_smile:

Thank you for finding this issue and sharing the solution for your case.

1 Like