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";