OTA updates not working for D1 mini board / esp8266

Hi, thanks for your reply.

Everything works fine via serial, I can flash the devices with a serial connection and the boards work. When I try to update them OTA afterwards, it fails. When I have it connected via serial to read the logs and try to update OTA I get the output from above, these logs are from the device via serial while tyring to update OTA:

[17:33:08.111][D][esphome.ota:451]: Starting handshake from 192.168.178.29
[17:33:08.114][V][esphome.ota:182]: Features: 0x03
[17:33:08.125][V][esphome.ota:589]: Auth: Nonce is 1739d905aa9cb9261ea0d5758b6244e40d5041b534bd9a1bc6962
3833bc4c5cd
[17:33:08.175][V][esphome.ota:649]: Auth: CNonce is 94ee64eb95feae690f9d60d849256c69f9c0677cb6d91f58b6ff
f8cbd05671ff
[17:33:08.186][V][esphome.ota:653]: Auth: Result is a64eced715bcf1f6e3aa4cfe3d636e71eb9c3f1f64e5a0f2c713
8f2f662ddebc
[17:33:08.194][V][esphome.ota:655]: Auth: Response is a64eced715bcf1f6e3aa4cfe3d636e71eb9c3f1f64e5a0f2c7
138f2f662ddebc
[17:33:08.200][V][esphome.ota:267]: Size is 334424 bytes
[17:33:08.205][D][esphome.ota:451]: Starting update from 192.168.178.29
[17:33:08.211][W][component:422]: esphome.ota set Warning flag: unspecified
[17:33:08.214]sleep disable
[17:33:08.219][D][ota.esp8266:120]: OTA begin: start=0x003A9000, size=334424
[17:33:08.228][V][esphome.ota:294]: Update: Binary MD5 is 9b22479fcd2a9e6815481c406b04e51b

So the device recognizes the connection and seems to start the update, but does not progress. From my computer where I start the update, the logs end with the timeout:

INFO Connecting to 192.168.178.39 port 8266…
INFO Connected to 192.168.178.39
INFO Uploading /home/a/Projects/esphome/2026/config/.esphome/build/soil-1/.pioenvs/soil-1/firmware.bin (473296 bytes)
DEBUG Device support OTA version: 2
INFO Compressed to 334424 bytes
DEBUG Auth: SHA256 Nonce is 1739d905aa9cb9261ea0d5758b6244e40d5041b534bd9a1bc69623833bc4c5cd
DEBUG Auth: SHA256 CNonce is 94ee64eb95feae690f9d60d849256c69f9c0677cb6d91f58b6fff8cbd05671ff
DEBUG Auth: SHA256 Result is a64eced715bcf1f6e3aa4cfe3d636e71eb9c3f1f64e5a0f2c7138f2f662ddebc
DEBUG MD5 of upload is 9b22479fcd2a9e6815481c406b04e51b
ERROR Error receiving acknowledge chunk OK: timed out
WARNING Failed to upload to [‘192.168.178.39’]

Here, it also connects fine and starts the update, but doesn’t get a response and times out as it seems.

As mentioned, OTA worked fine on those same boards some long time ago, so I do not assume a hardware failure.

My yaml is here:

ota:
  - platform: esphome
    password: "b19314a78d807e93102a1e0fbd9f612f"

substitutions:
  analog_update_interval: 1s

esphome:
  name: soil-1
  friendly_name: soil-1

esp8266:
  board: d1_mini

logger:
#   level: VERY_VERBOSE

api:
  encryption:
    key: "4Dit5XzeKwNyC3R+fnLGPJ9J0UU/kXRdqYBf8pOx54Y="

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  # manual_ip:
  #   static_ip: 192.168.178.39
  #   gateway: 192.168.178.1
  #   subnet: 255.255.255.0

i2c:
  scan: true
  id: bus_a

# button:
#   - platform: safe_mode
#     name: "Soil-1 Safe Mode Button"

ads1115:
  - address: 0x48
    i2c_id: bus_a

sensor:
  - platform: ads1115
    multiplexer: 'A0_GND'
    gain: 6.144
    name: "A0"
    id: ads_A0
    icon: "mdi:flash-triangle-outline"
    update_interval: ${analog_update_interval}
  - platform: template
    name: "A0 Level"
    id: a0_lvl
    update_interval: ${analog_update_interval}
    icon: "mdi:water"
    unit_of_measurement: "%"
    lambda: |-
      return id(ads_A0).state;
    filters:
      - clamp:
          min_value: 2.0
          max_value: 3.8
      - calibrate_linear:
         method: least_squares
         datapoints:
          - 2.0 -> 0
          - 3.8 -> 100
      - round: 0
      - lambda: return 100 - x;
  - platform: ads1115
    multiplexer: 'A1_GND'
    gain: 6.144
    name: "A1"
    id: ads_A1
    icon: "mdi:flash-triangle-outline"
    update_interval: ${analog_update_interval}
  - platform: template
    name: "A1 Level"
    id: a1_lvl
    update_interval: ${analog_update_interval}
    icon: "mdi:water"
    unit_of_measurement: "%"
    lambda: |-
      return id(ads_A1).state;
    filters:
      - clamp:
          min_value: 2.0
          max_value: 3.8
      - calibrate_linear:
         method: least_squares
         datapoints:
          - 2.0 -> 0
          - 3.8 -> 100
      - round: 0
      - lambda: return 100 - x;
  - platform: ads1115
    multiplexer: 'A2_GND'
    gain: 6.144
    name: "B0"
    id: ads_B0
    icon: "mdi:flash-triangle-outline"
    update_interval: ${analog_update_interval}
  - platform: template
    name: "B0 Level"
    id: b0_lvl
    update_interval: ${analog_update_interval}
    icon: "mdi:water"
    unit_of_measurement: "%"
    lambda: |-
      return id(ads_B0).state;
    filters:
      - clamp:
          min_value: 2.0
          max_value: 3.8
      - calibrate_linear:
         method: least_squares
         datapoints:
          - 2.0 -> 0
          - 3.8 -> 100
      - round: 0
      - lambda: return 100 - x;
  - platform: ads1115
    multiplexer: 'A3_GND'
    gain: 6.144
    name: "B1"
    id: ads_B1
    icon: "mdi:flash-triangle-outline"
    update_interval: ${analog_update_interval}
  - platform: template
    name: "B1 Level"
    id: b1_lvl
    update_interval: ${analog_update_interval}
    icon: "mdi:water"
    unit_of_measurement: "%"
    lambda: |-
      return id(ads_B1).state;
    filters:
      - clamp:
          min_value: 2.0
          max_value: 3.8
      - calibrate_linear:
         method: least_squares
         datapoints:
          - 2.0 -> 0
          - 3.8 -> 100
      - round: 0
      - lambda: return 100 - x;
  - platform: ina219
    address: 0x40
    update_interval: ${analog_update_interval}
    current:
      name: "INA219 Current0"
      id: cur0
    power:
      name: "INA219 Power0"
      id: pow0
    bus_voltage:
      name: "INA219 Bus Voltage0"
      id: bus0
    
switch:
  - platform: gpio
    name: "Relais A"
    id: relaisA
    pin:
      number: D5
  - platform: gpio
    name: "Relais B"
    id: relaisB
    pin:
      number: D6

I tried setting manual ip config and the safe mode button, and still OTA updates just stop and the device becomes unresponsive.

I start the updates via cli with

$ esphome -v upload config/soil-1.yaml

On Github I found some older issues with the D1 mini boards and OTA updates, but they all were resolved with esphome updates, so I suspect some kind of regression and think about opening an issue on Github. Before that, I wanted to rule out any user error here :slight_smile:

Before all that playing around I updated my local esphome installation and my current version is 2026.2.4