Skip to content

OTA firmware update library for ESP32-WROOM-32 with WiFi connectivity and ArduinoOTA

License

Notifications You must be signed in to change notification settings

trailcurrentoss/OtaUpdateLibraryWROOM32

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OtaUpdateLibraryWROOM32

Over-The-Air (OTA) firmware update handler for ESP32-WROOM-32 with WiFi connectivity and serial-only status feedback.

Overview

This library provides Over-The-Air (OTA) firmware update capability for ESP32-WROOM-32 microcontrollers. It temporarily connects to WiFi, enables ArduinoOTA to receive firmware uploads, waits for a configurable duration, and then automatically disconnects to free up WiFi resources for other system components (such as CAN bus operations).

Key Features:

  • Temporary WiFi connection for OTA updates
  • ArduinoOTA integration for firmware reception
  • Configurable OTA window timeout
  • Automatic WiFi disconnection after OTA window
  • Serial status output (no visual feedback hardware required)
  • MAC address-based device identification
  • mDNS support for easy device discovery

Hardware Requirements

  • ESP32-WROOM-32 microcontroller
  • WiFi connectivity (integrated into ESP32)
  • Dual OTA partition scheme on flash (recommended for safe updates)

Installation

Add this library to your PlatformIO platformio.ini:

lib_deps =
    git@github.com:trailcurrentoss/OtaUpdateLibraryWROOM32.git

Configuration

WiFi Credentials

Credentials can be provided from compile-time constants or read from NVM (Non-Volatile Memory) at runtime.

Option 1: Compile-time Credentials (Secrets.h)

Store credentials in a Secrets.h file (not tracked in Git):

// src/Secrets.h (add to .gitignore)
const char* ssid = "YOUR_SSID_HERE";
const char* password = "YOUR_PASSWORD_HERE";

Create a template file for documentation:

// src/Secrets.h.template
const char* ssid = "YOUR_SSID_HERE";
const char* password = "YOUR_PASSWORD_HERE";

Option 2: Runtime Credentials from NVM (ESP32 Preferences)

Load credentials from ESP32 Preferences and pass them to the OTA handler:

#include <Preferences.h>
#include <OtaUpdate.h>

Preferences prefs;

void setup() {
  Serial.begin(115200);

  // Read WiFi credentials from NVM
  prefs.begin("wifi", true);  // true = read-only
  String ssid = prefs.getString("ssid", "");
  String password = prefs.getString("password", "");
  prefs.end();

  // Safe to pass temporary String objects - library copies credentials internally
  OtaUpdate otaUpdate(180000, ssid.c_str(), password.c_str());
}

Memory Safety: The library internally copies credentials, so it's safe to pass temporary strings from NVM reads. The strings do not need to remain valid after construction.

Saving to Preferences:

void saveWiFiCredentials(const char* ssid, const char* password) {
  Preferences prefs;
  prefs.begin("wifi", false);  // false = read-write
  prefs.putString("ssid", ssid);
  prefs.putString("password", password);
  prefs.end();
}

## Usage Example

### Basic Usage

```cpp
#include <Arduino.h>
#include <OtaUpdate.h>
#include "Secrets.h"

// Create OTA update handler (3-minute window, 180000 ms)
OtaUpdate otaUpdate(180000, ssid, password);

void setup() {
  Serial.begin(115200);
  delay(100);

  Serial.println("Device initialized");
  Serial.printf("Hostname: %s\n", otaUpdate.getHostName().c_str());
}

void loop() {
  // Normal operation happens here
  delay(1000);
}

// Call from external trigger (e.g., CAN message):
void triggerOTA() {
  Serial.println("OTA triggered!");
  otaUpdate.waitForOta();  // Blocks until upload or timeout
  Serial.println("Resuming normal operation");
}

CAN Bus Triggered OTA

#include <TwaiTaskBased.h>
#include <OtaUpdate.h>

OtaUpdate otaUpdate(180000, ssid, password);

void onCanRx(const twai_message_t &msg) {
  // OTA trigger: CAN message ID 0x0 with MAC address
  if (msg.identifier == 0x0) {
    char targetHostname[14];
    String currentHostname = otaUpdate.getHostName();

    // Extract target MAC from CAN data
    sprintf(targetHostname, "esp32-%02X%02X%02X",
            msg.data[0], msg.data[1], msg.data[2]);

    // Check if this message is for us
    if (currentHostname.equals(targetHostname)) {
      Serial.println("OTA trigger received - entering OTA mode");
      otaUpdate.waitForOta();
      Serial.println("OTA complete - resuming normal operation");
    }
  }
}

void setup() {
  Serial.begin(115200);

  // Set up CAN with OTA callback
  TwaiTaskBased::onReceive(onCanRx);
  TwaiTaskBased::begin(GPIO_NUM_15, GPIO_NUM_13, 500000);

  Serial.println("CAN bus initialized - OTA ready");
}

void loop() {
  // CAN communication handled by FreeRTOS tasks
  delay(1000);
}

API Reference

Constructor

OtaUpdate(unsigned long waitForUploadTimeMs, const char* ssid, const char* password)

Initialize the OTA update handler.

Parameters:

  • waitForUploadTimeMs - Duration in milliseconds to wait for firmware upload (default: 30000 = 30 seconds)
  • ssid - WiFi network name. Internally copied for safe storage (default: empty string)
  • password - WiFi network password. Internally copied for safe storage (default: empty string)

Memory Safety: The library makes internal copies of the SSID and password strings, so it is safe to pass temporary strings or strings read from NVM. The source strings do not need to remain valid after construction.

Example (Compile-time):

// 3-minute OTA window
OtaUpdate otaUpdate(180000, "SSID", "Password");

Example (NVM):

String ssid = readFromNVM();
String password = readFromNVM();
// Safe to pass temporary Strings - library copies them internally
OtaUpdate otaUpdate(180000, ssid.c_str(), password.c_str());
// ssid and password can now go out of scope safely

Methods

void waitForOta()

Enter OTA update mode. This method blocks until either:

  • A firmware upload is completed and the device reboots, OR
  • The OTA window timeout expires

Operations during this call:

  1. Connects to configured WiFi network
  2. Initializes ArduinoOTA listening for firmware uploads
  3. Waits for upload or timeout
  4. Disconnects from WiFi
  5. Returns to caller

Serial Output Example:

[OTA] === OTA Update Mode ===
[OTA] Connecting to WiFi network: SSID
.....
[OTA] WiFi connected!
[OTA] IP address: 192.168.1.100
[OTA] Hostname: esp32-8A3B4C
[OTA] ArduinoOTA initialized and listening for uploads
[OTA] Ready to receive firmware on: esp32-8A3B4C
[OTA] Waiting for firmware upload...
[OTA] OTA update window: 180 seconds
OTA Progress: 45%
OTA Progress: 100%
OTA End
[OTA] OTA update window closed
[OTA] WiFi disconnected
[OTA] Resuming normal operation
[OTA] ========================

Example:

Serial.println("Entering OTA mode...");
otaUpdate.waitForOta();
Serial.println("OTA window closed, resuming normal operation");

String getHostName()

Get the WiFi hostname of this device.

Format: esp32-XXXXXX where XXXXXX is the last 3 bytes of the MAC address in hexadecimal.

Returns:

  • String containing the device hostname (e.g., "esp32-8A3B4C")

Example:

String hostname = otaUpdate.getHostName();
Serial.println("My hostname: " + hostname);
// Output: My hostname: esp32-8A3B4C

OTA Upload Procedure

From PlatformIO (Local)

  1. Trigger OTA mode on the device (via CAN, button, etc.)

  2. Update platformio.ini with the device hostname:

[env:esp32dev]
upload_protocol = espota
upload_port = esp32-XXXXXX  ; Replace XXXXXX with your device's MAC
  1. Build and upload during the OTA window:
pio run --target upload

Dual Partition OTA (Recommended)

For safe updates with automatic rollback capability, configure dual OTA partitions:

partitions.csv:

# Name,   Type, SubType, Offset,  Size, Flags
nvs,data,nvs,0x9000,0x5000,
otadata,data,ota,0xE000,0x2000,
app0,app,ota_0,0x10000,0x1A0000,
app1,app,ota_1,0x1B0000,0x1A0000,
spiffs,data,spiffs,0x350000,0x89000,
coredump,data,coredump,0x3D9000,0x10000,

Add to platformio.ini:

board_build.partitions = partitions.csv

CAN Bus Protocol Integration

OTA Trigger Message Format

CAN Message: Unicast OTA trigger via CAN ID 0x0

Field Value Description
CAN ID 0x0 OTA trigger identifier
Data[0] MAC byte 0 Target device MAC (byte 3 of full MAC)
Data[1] MAC byte 1 Target device MAC (byte 4 of full MAC)
Data[2] MAC byte 2 Target device MAC (byte 5 of full MAC)
Data[3-7] Reserved Reserved for future use

Example: Device with MAC address AA:BB:CC:8A:3B:4C should be targeted with:

  • CAN ID: 0x0
  • Data: [0x8A, 0x3B, 0x4C, ...]

Serial Output

All status messages are prefixed with [OTA] for easy filtering/logging:

[OTA] === OTA Update Mode ===
[OTA] Connecting to WiFi network: SSID
[OTA] WiFi connected!
[OTA] IP address: 192.168.1.100
[OTA] Hostname: esp32-8A3B4C
[OTA] ArduinoOTA initialized and listening for uploads
[OTA] Ready to receive firmware on: esp32-8A3B4C
[OTA] Waiting for firmware upload...
[OTA] OTA update window: 180 seconds
[OTA] OTA update window closed
[OTA] WiFi disconnected
[OTA] Resuming normal operation

Troubleshooting

WiFi Connection Fails

Symptoms: Device times out connecting to WiFi

Solutions:

  • Verify SSID and password in Secrets.h
  • Check WiFi network is available and 2.4GHz (5GHz not supported by ESP32)
  • Verify device is in WiFi range
  • Check for WiFi MAC address filtering on router

OTA Upload Fails

Symptoms: Upload fails during PlatformIO OTA

Solutions:

  • Verify device hostname matches upload_port in platformio.ini
  • Ensure you're uploading during the OTA window (check serial monitor)
  • Check firewall isn't blocking UDP port 5555 and TCP port 3232
  • Try again during a longer OTA window

Device Doesn't Respond to OTA Trigger

Symptoms: Sending CAN OTA trigger doesn't activate OTA mode

Solutions:

  • Verify CAN message ID is 0x0
  • Check target MAC address bytes match device hostname
  • Verify device is receiving CAN messages (check RX callback logs)
  • Check serial output for OTA trigger messages

Performance Notes

  • WiFi connection typically takes 3-5 seconds
  • OTA upload speed depends on firmware size (typically 50-100 KB/sec)
  • WiFi is automatically disabled after OTA window to avoid interference with CAN
  • CAN bus operations resume immediately after OTA disconnection

Security Considerations

  • WiFi Credentials:
    • Compile-time: Store in src/Secrets.h file, add to .gitignore to prevent accidental credential commits
    • Runtime (NVM): Store encrypted in ESP32 Preferences if possible. Use ESP32's secure boot and flash encryption features for additional protection
  • OTA Authentication: ArduinoOTA supports optional password protection (not configured in this version)
  • MAC-based Targeting: Requires physical access to device to obtain MAC address for OTA targeting
  • WiFi in NVM: Never commit credentials to version control, even in encrypted form. Use NVM for runtime configuration only

Version History

  • 0.1.0 - NVM-compatible credential handling: library now safely copies WiFi credentials internally, enabling runtime configuration from ESP32 Preferences or other NVM sources
  • 0.0.1 - Initial release for ESP32-WROOM-32

License

MIT License

About

OTA firmware update library for ESP32-WROOM-32 with WiFi connectivity and ArduinoOTA

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages