HUZZAH32 – ESP32

ESP32-based Feather with VROOM32 module that is considered and upgrade to the prior ESP8266.  

  • 240 MHz dual core Tensilica LX6 microcontroller
  • dual-core ESP32 chip
  • 520 KB SRAM
  • 4 MB of SPI FLASH in VROOM32 module
  • WiFi and Bluetooth Classic/LE
  • 802.11b/g/n HT40 Wi-Fi transceiver
  • 2x spare UARTS accessible in the Feather Arduino IDE
  • 3x SPI (only one configured in Feather Arduino IDE)
  • 2x I2C (only one configured in Feather Arduino IDE)
  • 2x analog output on A0 and A1 (also may be used for analog input)
  • A2, A3, A4 analog or digital input
  • Many more GPIO

Adafruit PN 3405

Adafruit hookup guide

Pinout diagram

 

Hardware

Built-in red LED on 13

Only read analog inputs on ADC #2 (A12,A11,A10,A8,A6) after WiFi has initialized (shared with WiFi module)

Pin 12 has internal pullup and is used for booting.

It uses a lot of current, so make sure if using USB it is fully powered.  

A2, A3, & A3 use ADC #1, are analog inputs (not analog output), and may be read with the WiFi initialized.   A2 & A3 are analog input only (ADC #2), BUT you cannot read them when the WiFi has started.  

A13 pin is not exposed, but may be referenced to measure the battery voltage (divided by 2, so double to get actual measurement).  

The ESP32 consumes about 250 mA from the 500 mA 3.3V regulator.  

GPIO Recommendations

  • A1,A1 for analog output
  • A2,A3,A4 for analog input
  • 21,33, 32 for DIO

 

Software

In order to have the 'Adafruit ESP32 Feather' board option to appear in the Arduino 1.8 or later IDE, you must add the following to the 'Additional Boards Manager URLs:'.   https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json Then in the Arduino IDE, select 'Tools', 'Board', 'ESP32 Arduino','Adafruit ESP32 Feather'.  

Configure in the Arduino IDE as Adafruit ESP32 Feather board and 921600 baud.   Install the SiLabs CP2104 Driver before connecting the Feather to your PC's powered USB port.  

How To Program the Adafruit Huzzah32 on the Arduino IDE

For ESP32 WiFi library, see: https://github.com/espressif/arduino-esp32#using-through-arduino-ide

 

Low Power

Normal power consumption is 100 mA + higher spikes with WiFi connection.

The ESP32 has two sleep modes:

  • Light sleep where WiFi is disconnected, but the internal clock and memory is kept, allowing you to wake up where you left off in the middle of the code.   You need to re-initialize the WiFi and any external hardware.   Adafruit ESP32 Feather V2 power consumption is 2 mA.  
  • Deep sleep
  • requires full initialization of everything except the real time clock (the real time clock keeps running so it can wake up the ESP32).   Adafruit ESP32 Feather V2 consumption is 100 uA.  

GitHub Example

Adafruit Low Power Usage - Adafruit ESP32 Feather V2

 

HTTPS GET

The sketch below will recover robustly from a lost WiFi connection.   It also implements a HTTP GET to Postman, but without secure communication or authentication (not recommended for production).   Only 11% of dynamic memory is used by this sketch (thanks to the ESP32 WiFi coprocessor).  


/*
  Adafruit Feather HUZZAH32 – ESP32 

  AF_Feather_HUZZAH32_ESP32_HTTP_GET.ino

  Adafruit P/N 3405

  For ESP32 library, see:
    https://github.com/espressif/arduino-esp32#using-through-arduino-ide

  This script will recover robustly from a lost WiFi connection,
  attempting a connection every 60 sec for 31 sec. 
  Built in LED does burst blink every ~1000 ms when WiFi not connected
  and it is attempt to connect, otherwise it will be on constantly. 
  
 
 */

// In Arduino IDE, install library:
//  https://github.com/espressif/arduino-esp32#using-through-arduino-ide

// In Arduino IDE, select 'Tools','Board','ESP32 Arduino','Adafruit ESP32 Feather'
// Find USB port in Windows by looking at ...

/////////////////////////////////////////////////////////////////////////
// Built in LED(s) & LiPoly Battery

const uint8_t pinBuiltInLED = 13;  

const byte pinLiPoly = A13;

/////////////////////////////////////////////////////////////////////////
// 3.7/4.2V LiPo battery voltage

float LiPoBatteryVoltage(byte vBatPin) {
  // max voltage of 3.7 V LiPoly battery is 4.2 V
  // Reports 4200 to 4370 mV WITHOUT battery
  // pinMode() NOT required.
  // mV varies by +/- 2 mV
  float LiPoBat_mV = analogRead(vBatPin);
  //Serial.print("ADC = "); Serial.println(LiPoBat_mV);
  LiPoBat_mV *= 2.0;    // voltage was divided by resistor, so double
  LiPoBat_mV *= 3300.0;    // multiply by 3.3V referene voltage
  LiPoBat_mV *= 1.1;    // Reference voltage on ESP32 is 1.1V
  LiPoBat_mV /= 4095.0; // convert from ADC to voltage (12-bit)
  return LiPoBat_mV;
} // LiPoBatteryVoltage

/////////////////////////////////////////////////////////////////////////
// blinkLEDnoDelay()
unsigned long LEDblinkPeriod = 8;
unsigned long LEDblinkLast = 0;
uint8_t LEDblinkPWM = 0;
bool LEDblinkState = false;
uint8_t LEDlastMode = 0;

void blinkLEDnoDelay(byte pin, byte mode) {
  // Blink the LED on 'pin' without using delay() according to
  // the 'mode' argument defined below. 
  // pin must support PWM. 
  // 
  // mode:
  //  0 = breathing
  //  1 = blink slow constantly
  //  2 = blink fast constantly
  //  3 = slow burst every 1 second
  //  4 = fast burst every 1 second
  //
  // Required global variables: LEDblinkPeriod, LEDblinkLast, LEDblinkPWM, LEDblinkState, LEDlastMode
  if (mode == 0) {
    // breathing
    LEDblinkPeriod = 8;
    if (LEDlastMode != mode) {
      LEDblinkPWM = 0;
      LEDblinkState = true;
      digitalWrite(pin, LOW);
    }
    if (millis() - LEDblinkLast >= LEDblinkPeriod) {
        if (LEDblinkPWM > 254) LEDblinkState = false;
        if (LEDblinkPWM < 1) LEDblinkState = true;
        if (LEDblinkState) {
            LEDblinkPWM++;
        } else {
            LEDblinkPWM--;
        }
        analogWrite(pin, LEDblinkPWM);
        LEDlastMode = mode;
        LEDblinkLast = millis();
    }
  } else if (mode == 1) {
    // blink slow constantly
    LEDblinkPeriod = 1000;
    if (millis() - LEDblinkLast >= LEDblinkPeriod) {
        digitalWrite(pin, LEDblinkState);
        LEDblinkState = !LEDblinkState;
        LEDlastMode = mode;
        LEDblinkLast = millis();
    }
  } else if (mode == 2) {
    // blink fast constantly
    LEDblinkPeriod = 100;
    if (millis() - LEDblinkLast >= LEDblinkPeriod) {
        digitalWrite(pin, LEDblinkState);
        LEDblinkState = !LEDblinkState;
        LEDlastMode = mode;
        LEDblinkLast = millis();
    }
  } else if (mode == 3) {
    // slow burst every 1 second
    // Slow 4 blinks (lazy burst) followed by 1 sec pause
    if (LEDlastMode != mode) {
      LEDblinkPWM = 0;
      LEDblinkState = true;
      LEDblinkPeriod = 100;
    }
    if (millis() - LEDblinkLast >= LEDblinkPeriod) {
        if (LEDblinkPWM < 7) {
          if (LEDblinkPWM == 0) LEDblinkState = true;
          digitalWrite(pin, LEDblinkState);
          LEDblinkPeriod = 100;
          LEDblinkState = !LEDblinkState;
          LEDblinkPWM++;
        } else {
          digitalWrite(pin, LOW);
          LEDblinkPWM = 0;
          LEDblinkPeriod = 1000;
        }
        LEDlastMode = mode;
        LEDblinkLast = millis();
    }
  } else if (mode == 4) {
    // fast burst every 1 second
    // Fast 4 blinks (burst) followed by 1 sec pause
    if (LEDlastMode != mode) {
      LEDblinkPWM = 0;
      LEDblinkState = true;
      LEDblinkPeriod = 25;
    }
    if (millis() - LEDblinkLast >= LEDblinkPeriod) {
        if (LEDblinkPWM < 7) {
          if (LEDblinkPWM == 0) LEDblinkState = true;
          digitalWrite(pin, LEDblinkState);
          LEDblinkPeriod = 25;
          LEDblinkState = !LEDblinkState;
          LEDblinkPWM++;
        } else {
          digitalWrite(pin, LOW);
          LEDblinkPWM = 0;
          LEDblinkPeriod = 1000;
        }
        LEDlastMode = mode;
        LEDblinkLast = millis();
    }
  } // mode
}   // blinkLEDnoDelay()


void blinkLED(byte ledPIN){
  //  consumes 300 ms.
  for(uint8_t i = 5; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(30);
    digitalWrite(ledPIN, LOW);
    delay(30);
  }    
} //blinkLED()


void blinkERR(byte ledPIN){
  // S-O-S
  const uint8_t S = 150, O = 300;
  for(uint8_t i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(S);
    digitalWrite(ledPIN, LOW);
    delay(S);
  }    
  delay(200);
  for(uint8_t i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(O);
    digitalWrite(ledPIN, LOW);
    delay(O);
  }    
  delay(200);
  for(uint8_t i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(S);
    digitalWrite(ledPIN, LOW);
    delay(S);
  }    
  delay(200);
} // blinkERR()

/////////////////////////////////////////////////////////////////////////
//  ESP32 WiFi
//    https://github.com/espressif/arduino-esp32#using-through-arduino-ide


#include <WiFi.h>
#include <WiFiMulti.h>
WiFiMulti WiFiMulti;
unsigned long countWiFiReConnect = 0;

bool connectToWiFi() {
  // Connect to a WiFi network
  // This subroutine will take several seconds to execute.
  // Note:
  //  It is reported to take 200 to 1000 ms to connect to WiFi
  //  WiFiMulti.run() takes ~ 5028 ms to execute.
  unsigned int loopCount = 0;

  if (countWiFiReConnect == 0) {
    // First WiFi connection since boot
    
    // Add a list of WiFi hotspots...
    WiFiMulti.addAP("SSID", "passpasspass");
  
    // Connect to a WiFi hotspot...
    Serial.print("Connecting to WiFi...");
    while(WiFiMulti.run() != WL_CONNECTED) {
      // Try for up to 31 sec to connect to WiFi...
      loopCount++;
      if (loopCount < 10) {
        Serial.print(".");
        blinkLED(pinBuiltInLED);  // consumes 300 ms
      } else {
        digitalWrite(pinBuiltInLED, HIGH);
        Serial.println("");
        // Exit and do other things, returning in timer_https_post ms
        return false;
      }
    }
    digitalWrite(pinBuiltInLED, LOW);
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.println("");
    
  } else {
    // Reconnect to WiFi hotspot...
    // NOTE:  
    // Wi-Fi events can be useful to detect that a connection was lost and try to reconnect right after (use the SYSTEM_EVENT_AP_STADISCONNECTED event). 
    // https://randomnerdtutorials.com/solved-reconnect-esp32-to-wifi/
    // However, my testing has shown this sketch to be very robust.
    
    // Reonnect to a WiFi hotspot...
    WiFi.disconnect();
    Serial.print("Reconnecting to WiFi...");
    while(WiFiMulti.run() != WL_CONNECTED) {
      // Try for up to 31 sec to connect to WiFi...
      loopCount++;
      if (loopCount < 10) {
        Serial.print(".");
        blinkLED(pinBuiltInLED);  // consumes 300 ms
      } else {
        digitalWrite(pinBuiltInLED, HIGH);
        Serial.println("");
        // Exit and do other things, returning in timer_https_post ms
        return false;
      }
    }
    digitalWrite(pinBuiltInLED, LOW);
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  }  

  if (WiFiMulti.run() == WL_CONNECTED) {
    Serial.print("WiFi reconnects: ");
    Serial.print(countWiFiReConnect);
    Serial.println("\n");
    countWiFiReConnect++;
  } else {
    return false;
  }
  return true;
  
} //connectToWiFi()

unsigned long lastConnectionTime = 0;   // last time you connected to the server, in milliseconds

// Time in millis() of the last successful WiFi connection to the server.
unsigned long lastWiFiTxSuccess = millis();

// timer_https_post
const unsigned long timer_https_post = 60000;  
unsigned long timer_https_post_lap = millis();  

void httpRequest() {
  // Non secure HTTP GET
  
  const char * host = "postman-echo.com"; // ip or dns
  const char * path = "/get"; 
  const int port = 80;
  
  //const char * host = "cdn.syndication.twimg.com"; // ip or dns
  //const char * path = "/widgets/followbutton/info.json?screen_names=adafruit"; 
  //const int port = 80;

  if (lastConnectionTime > millis())  lastConnectionTime = millis();

  // If not connected to WiFi, try for 30 sec
  if (WiFiMulti.run() != WL_CONNECTED) {
    if (connectToWiFi() == false) {
      if (lastConnectionTime > 0) {
        Serial.print("Last successful HTTP GET: "); Serial.print(millis()-lastConnectionTime); Serial.println(" ms");        
      }
      return;
    }        
  } else {
    if (lastConnectionTime > 0) {
      Serial.print("Last successful HTTP GET: "); Serial.print(millis()-lastConnectionTime); Serial.println(" ms");        
    }
  }

  Serial.print("Connecting to: "); Serial.println(host);

  // Use WiFiClient class to create TCP connections
  WiFiClient client;

  digitalWrite(pinBuiltInLED, HIGH);
  if (!client.connect(host, port)) {
      Serial.println("Connection failed.");
      return;
  }
  // Connected to client ...
  digitalWrite(pinBuiltInLED, LOW);

  // send the HTTP GET request:
  client.print("GET "); client.print(path); client.println(" HTTP/1.1");
  client.print("Host: "); client.println(host);
  //client.println("followAllRedirects: true");
  client.println("User-Agent: ArduinoWiFi/1.1");
  client.println("Connection: close");   // keep-alive
  client.println(); //Don't forget extra CrLf

  // Wait for the host reply...
  digitalWrite(pinBuiltInLED, HIGH);
  unsigned long timeout = millis();
  while (client.available() == 0) {
    if (millis() - timeout > 5000) {
        Serial.println("Host response timeout!");
        client.stop();
        return;
    }    
  }
  Serial.print("Host response time to HTTP GET: "); Serial.print(millis() - timeout); Serial.println(" ms");
  digitalWrite(pinBuiltInLED, LOW);
  
  // Read all the lines of the reply from server and print them to Serial
  while(client.available() > 0) {
      String line = client.readStringUntil('\r');
      if (line.compareTo("HTTP/1.1 200 OK") == 0) {
        Serial.println("Server accepted HTTP GET (HTTP/1.1 200 OK)");
        lastWiFiTxSuccess = millis();
      } else {
        Serial.print(line);
      }
  }
  Serial.println("");

  Serial.print("Closing connection to ");
  Serial.println(host);
  Serial.println("");
  client.stop();

  // note the time that the connection was attempted:
  lastConnectionTime = millis();

} // httpRequest()

//////////////////////////////////////////////////////////////////////////////
// TimerA
// 1000000 us = 1000 ms = 1 sec = 1 Hz
const unsigned long timerAinterval = 30000;  
unsigned long timerAlap = millis();  // timer

void timerA() {
  //  Timer A
  if (timerAlap > millis())  timerAlap = millis();
  if (millis() - timerAlap > timerAinterval) { 
    // do something here every timerAinterval / 1000 sec
    Serial.print("LiPo Battery ");
    float mV = LiPoBatteryVoltage(pinLiPoly);
    Serial.print(int(mV));
    Serial.println(" mV  ");
    timerAlap = millis(); // reset the timer
  }
} // timerA()

/////////////////////////////////////////////////////////////////////////


void setup() {

  Serial.begin(115200);
  while (!Serial) {
    delay(1);
  }
  Serial.println("\nSerial ready\n");

  pinMode(pinBuiltInLED, OUTPUT);
  digitalWrite(pinBuiltInLED, LOW);

  // configure pinLiPoly for analog input
  pinMode(pinLiPoly, INPUT);

  connectToWiFi();

  httpRequest();
  
  blinkLED(pinBuiltInLED);
  Serial.println("\nSetup finished\n");
} // setup()


void loop() {

  //blinkLEDnoDelay(pinBuiltInLED, 0);
  
  
  timerA();

  // WARNING: Calling httpRequest() takes up to 3000 ms
  if (timer_https_post_lap > millis())  timer_https_post_lap = millis();
  if (millis() - timer_https_post_lap > timer_https_post) { 
    httpRequest();
    timer_https_post_lap = millis(); // reset the timer
  } // timer_https_post_lap


} // loop()

 


Do you need help developing or customizing a IoT product for your needs?   Send me an email requesting a free one hour phone / web share consultation.  

 

The information presented on this website is for the author's use only.   Use of this information by anyone other than the author is offered as guidelines and non-professional advice only.   No liability is assumed by the author or this web site.