tl:dr; if you're doing OTA with PlatformIO and an ESP-01 module with 1MB of Flash, don't forget to add
board_build.ldscript = eagle.flash.1m.ld in your platformio.ini file.
To finish the project I have to fit the ESP-01 inside the small space in the plastic inner case, just above the existing PCB.
But I can't even fit the ESP-01 as it is: the pin headers make the module too tall. I tried replacing them with 90-degree headers, but now the module would be too long and won't fit either direction.
So I had to remove the headers altogether and solder the pins directly to wires to the existing PCB. This will remove any possibility to reprogram the module in case I need software updates.
But WiFi-based modules like the ESP8266 can luckily be programmed over-the-air (aka OTA). With OTA I wouldn't worry about doing any physical connection to the module; as long as the module is powered, connected to WiFi and at a known IP address, I can reprogram it.
So I looked through tutorials, all basically saying that I should add some code snippets in my sketch, take care about running them as regularly as possible, and not running anything while the transfer is in progress.
Not so fast...
But every attempt I did, the OTA update always failed. Sometimes with unknown errors, but mostly with "Error Not enough space" or similar.
I knew this can happen for some ESP-01 modules with 512kB of Flash memory. The rationale is that for OTA you must have at least double the space taken by the sketch. My sketch was ~300kB big so a 512kB chip wouldn't do. I used modules I bought years ago so without much thinking I ordered a few ESP-01S, guaranteed to have at least 1MB of flash.
Once the new modules arrived, and programmed them with my now OTA-powered sketch... the same error happened again :( Turns out that even my "old" modules had 1MB of flash. So why do I keep getting space-related errors?
The problem has to do SPIFFS (SPI Flash File System). See, the ESP8266 doesn't have to use the entire flash memory for code. Part of it can be used to store files, e.g. configuration or webpages, that you don't want or need to replace when uploading a new sketch.
By default, at least when building sketches with PlatformIO, a lot of flash is dedicated to SPIFFS; can't say how much, but just too much to allow OTA. But there's a way to use less or no flash memory for SPIFFS. On Arduino IDE, that's pretty simple: The Tools > Flash Size gives plenty of options. On PlatformIO that's less intuitive: you have to use a different "linker script" than the one used by default. This can be done by adding the following line to
board_build.ldscript = eagle.flash.1m.ld
This will tell to make a firmware file suitable for 1MB of flash, with no space reserved for SPIFFS.
Once I added that line and uploaded the firmware via serial - for the last time -, I finally experienced a successful OTA update:
That kind of stroke in the fish's tail indicates that the flash is being written. I think that happens because one of the GPIO pins connected to the motor driver is set to input with pull-up resistor, causing the motor to fully go on one direction until the new firmware starts running.