TL;DR; Use esptool.py to upload your firmware over USB since it will automatically put your board in flash mode.

Materials
– ESP8266 Board – https://www.amazon.com/gp/product/B010N1SPRK (HiLetgo ESP8266 NodeMCU CP2102 ESP-12E)
– VSCode (optional, but recommended)
– PlatformIO
– esptool.py
– MicroUSB Cable
– Wifi

Assumptions
– Your OS is Ubuntu 18.04

The ESP8266 NodeMCU board can be a little finnicky. The main gotcha being that the board needs to be put into “Flash Mode” in order to upload firmware to it. This is usually done automatically by the USB by pulling one of the gpio pins down (the one attached to the FLASH button on the board). But, for some reason platformio’s [upload] does not do this, so we have to use esptool.py. This blog post should act as a document to setting up these boards with as little headache as possible and as a bonus there will be some code at the end that enables Over the Air Updates for wifi-enabled boards.

First download VSCode with PlatformIO [here] and follow the instructions for enabling the extension.

Next install esptool.py by installing python and pip with sudo apt install python python-pip and then installing esptool.py with pip install esptool.py. esptool should then be available through the command line with esptool.py -h

Then create a new platformio project.

Open Platformio Home and then New Project!

Use these settings for the new project. “NodeMCU 1.0 (ESP-12E Module)” is the important bit.

If you choose not to use vscode with platformio, then your platformio.ini file should look like this

1
2
3
4
[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino

main.cpp is where the magic happens

Place this script in your main.cpp file for testing. It should cause the blue LED to blink

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <Arduino.h>

void setup() {
pinMode(0, OUTPUT);
pinMode(2, OUTPUT);
}

void loop() {
Serial.begin(9600);
digitalWrite(2, HIGH);
Serial.println("Turning On");
delay(1000);
digitalWrite(2, LOW);
Serial.println("Turning Off");
delay(1000);
}

Next hit “Build” in your platformio project settings. This will create a *.bin file for you in your project directory at ~/Documents/PlatformIO/Projects/{project_name}/.pioenvs/nodemcuv2/firmware.bin. Now you can upload your scripts with esptool! Plug in your arduino board and then run the below command

1
esptool.py --port /dev/ttyUSB0 write_flash 0x00000000 ~/Documents/PlatformIO/Projects/nodemcutest/.pioenvs/nodemcuv2/firmware.bin

You should expect some output like the below…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
esptool.py v2.5.1
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
MAC: 80:7d:3a:75:de:ef
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 252016 bytes to 183741...
Wrote 252016 bytes (183741 compressed) at 0x00000000 in 16.2 seconds (effective 124.1 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

Now the board should have a flashing blue light! And, if you pop over to vscode and hit “Monitor” then you should see something like the following in your console

1
2
3
4
5
6
7
8
9
--- Miniterm on /dev/ttyUSB0  9600,8,N,1 ---
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
Turning Off
Turning On
Turning Off
Turning On
Turning Off
Turning On
Turning Off

Now you know how flash new firmware to your board! Also, as promised, put the below code into main.cpp and upload it using esptool to enable OTA updates.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

// Change This!
const char* ssid = "SSID_changeme";
const char* password = "PASSWORD_changeme";

// Change this function to be whatever you want your board to do!
void run() {
// Turn Blue LED On
digitalWrite(2, HIGH);
Serial.println("Turning On"); // Prints to serial port
delay(1000);

// Turn Blue LED Off
digitalWrite(2, LOW);
Serial.println("Turning Off");
delay(1000);


Serial.print("Local IP Address: ");
Serial.println(WiFi.localIP());
}

void setup() {
// Set Pin 2 as Output so we can signal the LED
pinMode(2, OUTPUT);

// Begin Serial with 9600 baud rate
Serial.begin(9600);

WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Restarting Board...");
delay(5000);
ESP.restart();
}

// Port defaults to 8266
// ArduinoOTA.setPort(8266);

// Hostname defaults to esp8266-[ChipID]
// ArduinoOTA.setHostname("myesp8266");

// No authentication by default
// ArduinoOTA.setPassword((const char *)"123");

ArduinoOTA.onStart([]() {
Serial.println("Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("Local IP Address: ");
Serial.println(WiFi.localIP());

}

void loop() {
// Will listen for OTA Updates and Handle them
ArduinoOTA.handle();

run();
}

Now you can use platformio to upload OTA (When uploading OTA you do not need esptool to put the system into FLASH mode. For some reason platformio just works now…). But in order to do so, you must change the upload_port inside your platformio.ini file to the local ip address of your board. You can get this ip address if you monitor your board after you upload the OTA code with esptool. You can also run nmap on your local network to discover your board ip. It should have a hostname similar to ESP_75AAAA.lan.

1
2
3
4
5
6
7
8
9
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:nodemcuv2]

platform = espressif8266 board = nodemcuv2 framework = arduino upload_port = 192.168.15.123

With the above platformio.ini, you should be able to press [upload] in platformio and successfully upload new firmware! Now you can feel free to tape your esp8266 to the wall with a battery pack and still push updates to it. Thanks for reading!

Troubleshooting
Sometimes my boards will get stuck with a solid blue light if I do something like cancel an upload halfway through. I’ve had good success with “unsticking” these boards by holding the “FLASH” button for a second or two then just tapping the “RESET” button. (While the FLASH button is held down).

2023-03-09

⬆︎TOP