How to communicate with ESP32-WROOM-32E and program it using the same pins
Ok, I've basically figured it out.
As Sim commented, the ESP32 uses a ROM bootloader that loads firmware through UART0. That's the standard method of programming it, which I didn't understand.
Unfortunately the bootloader cannot be accessed using serial alone. A boot pin (GPIO0) needs to be held low while the device is reset to trigger the bootloader. The device can be reset using the EN pin.
Official dev boards use the serial RTS and DTR signals to toggle these pins. That pretty much tells me its the &quot;right&quot; way to do it.
Therefore, the complete answer is to comunicate with the ESP32 via UART0, and include either 2 additional signals for EN and GPIO0. Or 1 signal plus a circuit to hold boot low while toggling EN.
Documentation here: https://github.com/espressif/esptool/wiki/ESP32-Boot-Mode-Selection