Random Reboots with Voice PE

My PE seems to reboot every 6 hours or so I think, i haven’t been able to time it exactly. I have it connected to a Motorola (fast) charger from a few years back, and it seems to work okay with it.

The problem is, it wants to reboot and as it’s connected to my computer speakers with sub for better sound, it emits a loud thump when it reboots (Standard loss of connection sound nothing the PE does).

ESPHome indicates the following which I believe is the cause, but I’m not 100% certain:

INFO Successfully resolved home-assistant-voice-0a519b @ 192.168.1.15 in 0.001s
INFO Successfully connected to home-assistant-voice-0a519b @ 192.168.1.15 in 0.012s
INFO Successful handshake with home-assistant-voice-0a519b @ 192.168.1.15 in 0.084s
[02:36:00][D][power_supply:050]: Disabling power supply.
WARNING home-assistant-voice-0a519b @ 192.168.1.15: Connection error occurred: [Errno 104] Connection reset by peer
INFO Processing unexpected disconnect from ESPHome API for home-assistant-voice-0a519b @ 192.168.1.15
WARNING Disconnected from API
INFO Successfully resolved home-assistant-voice-0a519b @ 192.168.1.15 in 1.130s
INFO Successfully connected to home-assistant-voice-0a519b @ 192.168.1.15 in 0.008s
INFO Successful handshake with home-assistant-voice-0a519b @ 192.168.1.15 in 0.050s
[11:31:54][D][api:146]: Accept 192.168.1.167
[11:31:54][D][api.connection:1466]: Home Assistant 2025.8.0 (192.168.1.167) connected
[11:31:54][D][light:052]: ‘voice_assistant_leds’ Setting:
[11:31:54][D][light:069]: Brightness: 66%
[11:31:54][D][light:076]: Red: 100%, Green: 0%, Blue: 0%
[11:31:54][W][micro_wake_word:356]: Wake word detection is already running
[11:31:54][D][light:052]: ‘voice_assistant_leds’ Setting:
[11:31:54][D][light:065]: State: OFF
[11:31:54][D][light:126]: Effect: ‘None’
[11:32:04][D][power_supply:050]: Disabling power supply.

In an effort to confirm the power supply, I bought a USB tester which gives a standard output of 5.10V on average for output, and when I have it connected to the PE, I average around 4.996 to 5.024 when idle or no activity. The amperage is well below the 2A max so I don’t think it’s that, but would this be an acceptable voltage in this case?

I saw where another user had a similar issue with theirs and tracked it to their power supply, but I think this is doing okay so I’m not ready to consider it a bad one.

Edited to add that my Wifi signal is quite strong and the unit is about 1’ away from the router separated by a wall, so there is some dampening, but nothing out of the ordinary. The only disadvantage I have is I live in an Apartment building which as you may guess is overly saturated with everyone else’s Wifi networks.

Two options:

  1. Fix the underlying problem as to why it reboots. Connection issues in ESPHome are fickle to isolate. The underlying code certainly needs more work.
  2. Add a relay to your amp outlet in series with the speaker leads, and turn it on in software from ESPHome/ HomeAssistant after a short delay from power up. That way the thump may be generated, but it doesn’t blow up the speakers. One relay set of contacts per audio channel. Use a DPDT relay for stereo, driven by one of your spare pins through suitable driver transistor/diode/resistor combination.

This is why it keeps rebooting.

[16:16:01.878][D][debug:079]: Reset Reason: Reboot request from esphome.ota

This happens daily. I know I can reset it and not have ESPHome take it over, but I want to keep it under this for now.

Does anyone else have this problem with the ESPHome controlling it?

Any long wires acting as WiFi antenna picking up interference?

Update all your software, including ESPHome, clear your ESPHome cache and recompile, as some of the recent code changes may help.

Post your code (formatted) from the ESPHomr compile and run log - there may be options that can tweak or debug things.

The Voice Assistant PE is connected to it’s own network which I found improved stability to just one reboot per day. That itself is about 3’ below the unit which is a WiFi Extender so there is certainly a strong signal.

Build log: uNDucH.txt (On my server)

Thanks.
There are a number of compiler warnings.
A long compile!
Post your ESPHome yaml code also.

I note the ESPHome OTA2 code was modified in the last few months with lots of changes, so you may have unearthed a bug.

What platform are you running under? Brand, Model, and memory size?
HomeAssistant?
ESPHome?

Thank you for looking at this, I figured the long compile time was because I cleared the cache.

My ESPHome File.

substitutions:
  name: home-assistant-voice-0a519b
  friendly_name: Home Assistant Voice
packages:
  Nabu Casa.Home Assistant Voice PE: github://esphome/home-assistant-voice-pe/home-assistant-voice.yaml
esphome:
  name: ${name}
  name_add_mac_suffix: false
  friendly_name: ${friendly_name}
api:
  encryption:
    key: REDACTED JUST IN CASE :)


wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

#CODE BELOW FROM:  https://github.com/eyalgal/simple-timer-card/blob/cd925cf4c2c68c32f6157fd03d369211e518e348/voice-pe.md
globals:
  # Finished latches (do not persist across reboot)
  - id: t1_finished
    type: bool
    restore_value: no
    initial_value: 'false'
  - id: t2_finished
    type: bool
    restore_value: no
    initial_value: 'false'
  - id: t3_finished
    type: bool
    restore_value: no
    initial_value: 'false'

  # Finished timestamps (ms since boot). 0 means not set.
  - id: t1_finished_ts
    type: uint32_t
    restore_value: no
    initial_value: '0'
  - id: t2_finished_ts
    type: uint32_t
    restore_value: no
    initial_value: '0'
  - id: t3_finished_ts
    type: uint32_t
    restore_value: no
    initial_value: '0'

# Sensors / text_sensors (3 slots; copy the pattern to add more)
sensor:
  - platform: template
    id: timer_count
    name: "Timers Count"
    accuracy_decimals: 0

  - platform: template
    id: timer_1_seconds_left
    name: "Timer 1 Seconds Left"
    unit_of_measurement: "s"
    accuracy_decimals: 0
  - platform: template
    id: timer_1_total_seconds
    name: "Timer 1 Total Seconds"
    unit_of_measurement: "s"
    accuracy_decimals: 0

  - platform: template
    id: timer_2_seconds_left
    name: "Timer 2 Seconds Left"
    unit_of_measurement: "s"
    accuracy_decimals: 0
  - platform: template
    id: timer_2_total_seconds
    name: "Timer 2 Total Seconds"
    unit_of_measurement: "s"
    accuracy_decimals: 0

  - platform: template
    id: timer_3_seconds_left
    name: "Timer 3 Seconds Left"
    unit_of_measurement: "s"
    accuracy_decimals: 0
  - platform: template
    id: timer_3_total_seconds
    name: "Timer 3 Total Seconds"
    unit_of_measurement: "s"
    accuracy_decimals: 0

text_sensor:
  - platform: template
    id: timer_1_name
    name: "Timer 1 Name"
  - platform: template
    id: timer_1_state
    name: "Timer 1 State"

  - platform: template
    id: timer_2_name
    name: "Timer 2 Name"
  - platform: template
    id: timer_2_state
    name: "Timer 2 State"

  - platform: template
    id: timer_3_name
    name: "Timer 3 Name"
  - platform: template
    id: timer_3_state
    name: "Timer 3 State"

# Auto-clear sticky "finished" after 10 seconds (TTL)
interval:
  - interval: 5s
    then:
      - lambda: |-
          auto clear_slot = [&](int slot){
            switch(slot){
              case 1: id(timer_1_name).publish_state("");
                      id(timer_1_state).publish_state("idle");
                      id(timer_1_seconds_left).publish_state(0);
                      id(timer_1_total_seconds).publish_state(0);
                      id(t1_finished) = false;
                      id(t1_finished_ts) = 0; break;
              case 2: id(timer_2_name).publish_state("");
                      id(timer_2_state).publish_state("idle");
                      id(timer_2_seconds_left).publish_state(0);
                      id(timer_2_total_seconds).publish_state(0);
                      id(t2_finished) = false;
                      id(t2_finished_ts) = 0; break;
              case 3: id(timer_3_name).publish_state("");
                      id(timer_3_state).publish_state("idle");
                      id(timer_3_seconds_left).publish_state(0);
                      id(timer_3_total_seconds).publish_state(0);
                      id(t3_finished) = false;
                      id(t3_finished_ts) = 0; break;
            }
          };

          const uint32_t now = millis();
          const uint32_t TTL = 10000;  // hardcoded 10s sticky finished

          if (id(t1_finished) && id(t1_finished_ts) != 0 && (uint32_t)(now - id(t1_finished_ts)) > TTL) clear_slot(1);
          if (id(t2_finished) && id(t2_finished_ts) != 0 && (uint32_t)(now - id(t2_finished_ts)) > TTL) clear_slot(2);
          if (id(t3_finished) && id(t3_finished_ts) != 0 && (uint32_t)(now - id(t3_finished_ts)) > TTL) clear_slot(3);

# Mirror logic (Voice Assistant provides a timers vector sorted by soonest end)
voice_assistant:
  on_timer_tick:
    - lambda: |-
        auto clear_slot_if_not_finished = [&](int slot){
          bool finished = (slot==1? id(t1_finished) : slot==2? id(t2_finished) : id(t3_finished));
          if (!finished) {
            switch(slot){
              case 1: id(timer_1_name).publish_state("");
                      id(timer_1_state).publish_state("idle");
                      id(timer_1_seconds_left).publish_state(0);
                      id(timer_1_total_seconds).publish_state(0); break;
              case 2: id(timer_2_name).publish_state("");
                      id(timer_2_state).publish_state("idle");
                      id(timer_2_seconds_left).publish_state(0);
                      id(timer_2_total_seconds).publish_state(0); break;
              case 3: id(timer_3_name).publish_state("");
                      id(timer_3_state).publish_state("idle");
                      id(timer_3_seconds_left).publish_state(0);
                      id(timer_3_total_seconds).publish_state(0); break;
            }
          }
        };

        clear_slot_if_not_finished(1);
        clear_slot_if_not_finished(2);
        clear_slot_if_not_finished(3);

        const int count = (int) timers.size();
        id(timer_count).publish_state(count);
        auto clamp_nonneg = [](int v){ return v < 0 ? 0 : v; };

        if (count > 0 && !id(t1_finished)) {
          const auto &t = timers[0];
          id(timer_1_name).publish_state(t.name.c_str());
          id(timer_1_state).publish_state(t.is_active ? "active" : "paused");
          id(timer_1_seconds_left).publish_state(clamp_nonneg((int)t.seconds_left));
          id(timer_1_total_seconds).publish_state(clamp_nonneg((int)t.total_seconds));
        }
        if (count > 1 && !id(t2_finished)) {
          const auto &t = timers[1];
          id(timer_2_name).publish_state(t.name.c_str());
          id(timer_2_state).publish_state(t.is_active ? "active" : "paused");
          id(timer_2_seconds_left).publish_state(clamp_nonneg((int)t.seconds_left));
          id(timer_2_total_seconds).publish_state(clamp_nonneg((int)t.total_seconds));
        }
        if (count > 2 && !id(t3_finished)) {
          const auto &t = timers[2];
          id(timer_3_name).publish_state(t.name.c_str());
          id(timer_3_state).publish_state(t.is_active ? "active" : "paused");
          id(timer_3_seconds_left).publish_state(clamp_nonneg((int)t.seconds_left));
          id(timer_3_total_seconds).publish_state(clamp_nonneg((int)t.total_seconds));
        }

  on_timer_finished:
    - lambda: |-
        // Latch the first non-latched slot as "finished" for 10s
        auto latch = [&](int slot){
          switch(slot){
            case 1: id(t1_finished) = true; id(t1_finished_ts) = millis(); break;
            case 2: id(t2_finished) = true; id(t2_finished_ts) = millis(); break;
            case 3: id(t3_finished) = true; id(t3_finished_ts) = millis(); break;
          }
          // Show finished: keep name and total, remaining = 0, state = finished
          if (slot==1) {
            id(timer_1_name).publish_state(timer.name.c_str());
            id(timer_1_state).publish_state("finished");
            id(timer_1_seconds_left).publish_state(0);
            id(timer_1_total_seconds).publish_state((int)timer.total_seconds);
          } else if (slot==2) {
            id(timer_2_name).publish_state(timer.name.c_str());
            id(timer_2_state).publish_state("finished");
            id(timer_2_seconds_left).publish_state(0);
            id(timer_2_total_seconds).publish_state((int)timer.total_seconds);
          } else {
            id(timer_3_name).publish_state(timer.name.c_str());
            id(timer_3_state).publish_state("finished");
            id(timer_3_seconds_left).publish_state(0);
            id(timer_3_total_seconds).publish_state((int)timer.total_seconds);
          }
        };

        if (!id(t1_finished)) { latch(1); }
        else if (!id(t2_finished)) { latch(2); }
        else if (!id(t3_finished)) { latch(3); }
        // If all three are latched, the oldest will auto-clear within 10s

  on_timer_cancelled:
    - lambda: |-
        // Treat cancel as dismiss: clear latches and reset everything
        id(t1_finished) = false; id(t1_finished_ts) = 0;
        id(t2_finished) = false; id(t2_finished_ts) = 0;
        id(t3_finished) = false; id(t3_finished_ts) = 0;

        id(timer_count).publish_state(0);
        id(timer_1_name).publish_state("");
        id(timer_1_state).publish_state("idle");
        id(timer_1_seconds_left).publish_state(0);
        id(timer_1_total_seconds).publish_state(0);
        id(timer_2_name).publish_state("");
        id(timer_2_state).publish_state("idle");
        id(timer_2_seconds_left).publish_state(0);
        id(timer_2_total_seconds).publish_state(0);
        id(timer_3_name).publish_state("");
        id(timer_3_state).publish_state("idle");
        id(timer_3_seconds_left).publish_state(0);
        id(timer_3_total_seconds).publish_state(0);

  on_timer_started:
    - lambda: |-
        // New timer should show live data, so drop any finished latches
        id(t1_finished) = false; id(t1_finished_ts) = 0;
        id(t2_finished) = false; id(t2_finished_ts) = 0;
        id(t3_finished) = false; id(t3_finished_ts) = 0;

I did use a custom timer card which the dev for that figured out a way to display the Voice PE timers. It works! And I use it regularly.

https://github.com/eyalgal/simple-timer-card/blob/cd925cf4c2c68c32f6157fd03d369211e518e348/voice-pe.md

I do want to STRESS that even before adding the above code, the random reboots were happening. In other words, I simply took ownership via EspHome as recommended and then just used that until this Timer code came out. So, I do not think this the extra code is the issue .

As for the Platform, its HAOS Supervised in a VM within Proxmox with 6GB of RAM allocated and a total of 256gb of storage between two 128gb drives. I admit, it’s an older machine (15 year old Dell PC) but it’s still plenty fast for things like this and other apps I host.