Wednesday, 18 September 2019

ArduinoOTA: Programming the ESP-01S via WiFi Part 1

Radio Ga Ga, Queen Youtube video 
"You had your time, you had the power
You've yet to have your finest hour ...
Radio, what's new?
Radio, someone still loves you." - Queen, Radio Ga Ga.

WiFi is a radio communications standard. The ArduinoOTA Library enables the ESP8266 to be reprogrammed over WiFi. This is especially handy if you used the ESP8266 for IoT devices and as a result mounted them in very useful but inaccessible places.

Regular IoT program updates is probably a necessity, as a cheap, portable and concealable Deauth Jammer can disable WiFi IoT devices within range. The recent Matheus Garbelini ESP32 and ESP8266 exploits mean ESP8266-based IoT devices will have to be re-programmed.

ArduinoOTA readily reprograms the NodeMCU ESP-12, but ArduinoOTA will not update the ESP-01, which has too little memory and will not update the ESP-01S with default settings. Now I could change to the ESP-12E - it is only slightly more expensive, but this also involves changing the IoT enclosure. Basically a rebuild.

It turned out that the Arduino IDE default settings for the 'Generic ESP8266 Module' assumes an ESP-01 which only has 512K memory and is not enough for ArduinoOTA. But the later and much more common modules are ESP-01S which has 1M memory.

ESP-01 and ESP-01S. Click for video. If you do not speak Spanish, just turn on the captions and set to auto-translate.


I checked mine using esptool.py:


$esptool.py --baud=115200 --port=/dev/ttyUSB0 flash_id

esptool.py v2.7
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: dc:4f:22:56:d9:bc
Uploading stub...
Running stub...
Stub running...
Manufacturer: 85
Device: 6014
Detected flash size: 1MB
Hard resetting via RTS pin...

To program it, first flash the ArduinoOTA Library BasicOTA using the usual programmer. On power-cycling the CH340, a new programming port should come up on your Arduino IDE. something like 'esp8266-xxxxxx at your_esp_ip_address'. Change your programming port to it.

To program the ESP-01S, first set Tools->Flash Size to 1M no SPIFFS. You can use the ArduinoOTA Library OTALeds sample program. Since OTALeds is for the ESP-12, make sure to change the line thus, so that the ESP-01S led gets assigned properly:

int led_pin = 1

The generic ESP-01S boards seem to work more reliably if I added a couple of Serial.print() statements in loop(). The modified program is:


#include <ESP8266WiFi.h>

#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

const char* ssid = "your_wifi_hotspot";
const char* password = "password";

//variabls for blinking an LED with Millis
const short LED_BUILTIN_ESP01 = 1; //GPIO1
const int led =LED_BUILTIN_ESP01; // ESP8266 Pin to which onboard LED is connected
unsigned long previousMillis = 0;  // will store last time LED was updated
const long interval = 1000;  // interval at which to blink (milliseconds)
int ledState = LOW;  // ledState used to set the LED
void setup() {
pinMode(led, OUTPUT);
    
  Serial.begin(115200);
  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    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("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH)
      type = "sketch";
    else // U_SPIFFS
      type = "filesystem";

    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    Serial.println("Start updating " + type);
  });
  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("IP address: ");
  Serial.println(WiFi.localIP());
}

  void loop() {
    ArduinoOTA.handle();
  
  //loop to blink without delay
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    // if the LED is off turn it on and vice-versa:
    ledState = not(ledState);
    // set the LED with the ledState of the variable:
    Serial.print("Writing to LED: "); // Seems to work better if I added debug statements
    Serial.println(ledState);  // Seems to work better if I added debug statements
    digitalWrite(led,  ledState);
    }
  }

 Good luck with your ESP-01S. Happy Trails.