Each ESP32 has a unique MAC address that is hardcoded into the chip and plays an important role in facilitating effective communication between the devices. However, there are times when you may need to assign a new MAC address to your ESP32. For example, you might want to do this for network security purposes, such as implementing a MAC address whitelist that allows only selected devices to connect to a Wi-Fi network.
In such instances, the following tutorial will be invaluable. It provides step-by-step instructions on how to find the current MAC address of your ESP32 and how to set a new one.
What�s a MAC Address?
A MAC (short for �media access control�) address is a series of numbers and letters that serves as a unique identifier for a network device. MAC addresses consist of 12 hexadecimal characters grouped into six pairs, such as AA:BB:CC:DD:EE:FF.
Each device that connects to a network is equipped with a network interface controller (NIC), which incorporates the electronic circuitry necessary for communication via a specific network protocol, such as Wi-Fi, Bluetooth, or Ethernet. Manufacturer assigns a unique MAC address to each NIC (if there are multiple) during the production process, and this address is permanently stored in the device�s hardware.
We need these addresses to be able to send or receive data over the network. While IP addresses identify a network connection, MAC addresses identify hardware. However, unlike IP addresses, which change frequently, MAC addresses are static because they are only used within the local network.
Although the MAC address is usually burned into the device�s hardware, many systems, including the ESP32, allow overriding it through software. But keep in mind that the custom MAC address is temporary and will reset to the manufacturer default upon chip reset, unless you program the ESP32 to set it on every boot.
MAC Address on ESP32
The ESP32 has several MAC addresses, one for each network interface it supports, including the following:
- Wi-Fi Station (STA)
- Wi-Fi Access Point (AP)
- Bluetooth Interface (Classic and BLE)
- Ethernet
Only the first one, known as the Base MAC Address, is saved in eFuse or external storage, and it is used to generate MAC addresses for other interfaces.
The Wi-Fi Station (STA) uses the base MAC address. In contrast, the Wi-Fi Access Point (AP) MAC address is derived by incrementing the last octet of the base MAC address by one. Similarly, the Bluetooth MAC address is derived by adding two to the last octet of the base address, and the Ethernet MAC address by adding three to the last octet of the base address.
Interface | MAC Address | Example |
Wi-Fi Station | base_mac | 80:7D:3A:CB:12:5C |
Wi-Fi SoftAP | base_mac +1 to the last octet | 80:7D:3A:CB:12:5D |
Bluetooth | base_mac +2 to the last octet | 80:7D:3A:CB:12:5E |
Ethernet | base_mac +3 to the last octet | 80:7D:3A:CB:12:5F |
For more information, please refer to the Espressif documentation.
Finding the MAC Address
To find the MAC address on an ESP32, you can use the Espressif IoT Development Framework (ESP-IDF) or the Arduino IDE. The example provided here will be for the Arduino IDE.
First, ensure you have the ESP32 board support installed in your Arduino IDE:
Here�s a simple sketch to print out the MAC address of the device:
#include <WiFi.h>
void setup(){
Serial.begin(115200);
// Variable to store the MAC address
uint8_t baseMac[6];
// Get MAC address of the WiFi station interface
esp_read_mac(baseMac, ESP_MAC_WIFI_STA);
Serial.print("Station MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
// Get the MAC address of the Wi-Fi AP interface
esp_read_mac(baseMac, ESP_MAC_WIFI_SOFTAP);
Serial.print("SoftAP MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
// Get the MAC address of the Bluetooth interface
esp_read_mac(baseMac, ESP_MAC_BT);
Serial.print("Bluetooth MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
// Get the MAC address of the Ethernet interface
esp_read_mac(baseMac, ESP_MAC_ETH);
Serial.print("Ethernet MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
}
void loop(){
}
After uploading the code, open the Serial Monitor and set the baud rate to 115200. Then, press the EN button on the ESP32. You should see the MAC addresses for each network interface being printed to the Serial Monitor.
Code Explanation:
The code begins by including the WiFi library which provides the necessary functions for handling Wi-Fi operations on the ESP32.
#include "WiFi.h"
Inside the setup() function, we begin with initiating the Serial communication at a baud rate of 115200 bps.
Serial.begin(115200);
A variable named baseMac is declared to store the MAC address. This variable is an array of six uint8_t
elements, which are unsigned 8-bit integers, perfect for holding MAC address bytes which range from 00 to FF (Hex).
uint8_t baseMac[6];
The ESP32�s built-in function esp_read_mac()
is then called with baseMac
and ESP_MAC_WIFI_STA
as arguments to read the Wi-Fi Station interface�s MAC address and store it in the baseMac
array.
esp_read_mac(baseMac, ESP_MAC_WIFI_STA);
The Serial Monitor then prints �Station MAC: �, followed by the MAC address. A for
loop runs through the first five elements of the baseMac
array, formatting each byte into two hexadecimal digits followed by a colon. After the loop, the sixth element of the baseMac
array is printed without a trailing colon, marking the end of the MAC address.
Serial.print("Station MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
The process is repeated for the Wi-Fi AP MAC address, this time with the ESP_MAC_WIFI_SOFTAP
argument to read the MAC address for the Wi-Fi Access Point interface.
esp_read_mac(baseMac, ESP_MAC_WIFI_SOFTAP);
Serial.print("SoftAP MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
Next, the Bluetooth interface MAC is obtained by calling esp_read_mac()
with ESP_MAC_BT
.
esp_read_mac(baseMac, ESP_MAC_BT);
Serial.print("Bluetooth MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
Similarly, the Ethernet interface MAC is read with ESP_MAC_ETH
.
esp_read_mac(baseMac, ESP_MAC_ETH);
Serial.print("Ethernet MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
The loop() function is empty because the MAC addresses are printed only once when the ESP32 is reset.
void loop(){
}
Changing the MAC Address
The following code changes the base MAC address of an ESP32 and then displays the updated MAC addresses for each network interface.
It�s important to note that you only need to change the base MAC address on an ESP32, as all other MAC addresses for different network interfaces (Wi-Fi AP, Bluetooth, and Ethernet) are automatically updated since they are derived from the base address with specific offsets.
Before uploading the code, it�s essential to make one modification. You must update the newMAC
variable with your custom MAC address:
uint8_t newMAC[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
After making the change, go ahead and upload the code.
#include <WiFi.h>
#include <esp_wifi.h>
// Define your new MAC address
uint8_t newMAC[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
void setup(){
Serial.begin(115200);
// Disable WiFi
WiFi.mode(WIFI_OFF);
Serial.println("[OLD]---");
FindMACAddress();
// Set the new MAC address
if (esp_base_mac_addr_set(newMAC) == ESP_OK) {
Serial.println("MAC address set successfully");
} else {
Serial.println("Failed to set MAC address");
}
Serial.println();
Serial.println("[NEW]---");
FindMACAddress();
}
void loop(){
}
void FindMACAddress(){
// Get the MAC address of the Wi-Fi station interface
uint8_t baseMac[6];
// Get MAC address for WiFi station
esp_read_mac(baseMac, ESP_MAC_WIFI_STA);
Serial.print("Station MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
// Get the MAC address of the Wi-Fi AP interface
esp_read_mac(baseMac, ESP_MAC_WIFI_SOFTAP);
Serial.print("SoftAP MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
// Get the MAC address of the Bluetooth interface
esp_read_mac(baseMac, ESP_MAC_BT);
Serial.print("Bluetooth MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
// Get the MAC address of the Ethernet interface
esp_read_mac(baseMac, ESP_MAC_ETH);
Serial.print("Ethernet MAC: ");
for (int i = 0; i < 5; i++) {
Serial.printf("%02X:", baseMac[i]);
}
Serial.printf("%02X\n", baseMac[5]);
Serial.println();
}
After uploading the code, open the Serial Monitor and set the baud rate to 115200. Then, press the EN button on the ESP32. You should see both the old and new MAC addresses for the Wi-Fi station, Wi-Fi access point, Bluetooth, and Ethernet interfaces.
Please keep in mind that, as explained previously, the modifications made do not permanently overwrite the MAC address set by the manufacturer. Thus, each time you reset the board or upload new code, it will revert to its default MAC address, unless you program the ESP32 to set it on every boot.
Code Explanation:
The code begins by including the WiFi.h
and esp_wifi.h
libraries, which provide functions necessary for Wi-Fi operations and specific ESP32 Wi-Fi features.
#include <WiFi.h>
#include <esp_wifi.h>
A new MAC address is then defined as an array of six hexadecimal bytes.
uint8_t newMAC[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
In setup(), the Serial Monitor is initialized and Wi-Fi is turned off to ensure that the new MAC address is set before any Wi-Fi activity begins.
WiFi.mode(WIFI_OFF);
Next, the function FindMACAddress()
is called to print the current MAC addresses for various interfaces. The FindMACAddress()
function is basically the previous code segment that retrieves and prints the MAC addresses, wrapped in a function for modularity and reusability.
FindMACAddress();
The esp_base_mac_addr_set()
function is then called with the new MAC address. If successful, a confirmation message is printed. If it fails, an error message is displayed.
if (esp_base_mac_addr_set(newMAC) == ESP_OK) {
Serial.println("MAC address set successfully");
} else {
Serial.println("Failed to set MAC address");
}
After setting the new MAC address, the FindMACAddress()
function is called again to display the new MAC addresses.
FindMACAddress();
Finally, the loop() function is left empty because the code only needs to run once at startup.
void loop(){
}