basic code. it will have a button displayed in HA, press button to tell esphome to download new firmware.

esphome:
  name: tank-sensor-1
  friendly_name: Tank Sensor 1

esp8266:  # or esp32
  board: d1_mini

wifi:
  ssid: !secret remote_wifi
  password: !secret remote_pass
  fast_connect: true
  power_save_mode: HIGH

# ✅ MQTT — works everywhere, port 1883 only forwarded
mqtt:
  broker: home.findme.com
  port: 1883
  username: !secret mqtt_remote
  password: !secret mqtt_remote_pass
  discovery: true
  discovery_prefix: homeassistant
  keepalive: 15
  clean_session: false

# ✅ HTTP REQUEST OTA — WORKS BEHIND ANY NAT / ROUTER
ota:
  - platform: http_request
    # Firmware hosted ANYWHERE public: GitHub, Google Drive, free file host, etc.
    url: "https://your-file-host.com/tank-sensor-1.ota.bin"
    md5_url: "https://your-file-host.com/tank-sensor-1.ota.bin.md5"

# ✅ OPTIONAL: Button in HA to trigger update (NO extra work)
button:
  - platform: template
    name: "Update Firmware"
    icon: "mdi:cloud-download"
    on_press:
      then:
        - ota.http_request.flash:
            url: "https://your-file-host.com/tank-sensor-1.ota.bin"
            # md5_url: "..."  # optional, safer

# ✅ YOUR SENSOR — UNCHANGED
binary_sensor:
  - platform: gpio
    pin:
      number: GPIO5
      mode: INPUT_PULLUP
      inverted: true
    name: "Tank Full"
    id: tank_full
    filters:
      - delayed_on_off: 200ms
    on_state:
      - mqtt.publish:
          topic: sensor/tank/need_refill
          payload: !lambda 'return id(tank_full).state ? "No" : "Yes";'

text_sensor:
  - platform: template
    name: "Need Refill"
    id: needrefill
    update_interval: 60s
    lambda: |-
      return id(tank_full).state ? "No" : "Yes";