How to Change the MAC Address of ESP8266?

Each ESP8266, like every other WiFi network interface card, comes with a MAC address that identifies itself to the network. Sometimes you want to change the MAC address of an ESP8266. How to do that?

ESP8266 has the built-in MAC address

ESP8266 Arduino core does not provide an API to change ESP8266's WiFi MAC address. While there is a WiFi.macAddress function, it actually retrieves the current WiFi MAC address, instead of setting it. However, Espressif SDK offers an API to change the WiFi STA MAC address:

bool wifi_set_macaddr(uint8 if_index, uint8 *macaddr);

This API is declared in user_interface.h. To get access in this API, you'll need to include this header.

extern "C" {
#include <user_interface.h>
}
``

It is important to wrap the `#include` line in a `extern "C"` block, because Espressif SDK is written in C, while ESP8266 Arduino code is compiled as C++.

After including `user_interface.h`, you can call the `wifi_set_macaddr` API as follows:

```c
uint8_t mac[6] {0xb8, 0xd7, 0x63, 0x00, 0xfe, 0xef};
wifi_set_macaddr(STATION_IF, mac);

This changes ESP8266's MAC address to b8:d7:63:00:fe:ef.

While you are at it, it might be a good idea to also rename the ESP8266. You can disguise the ESP8266 as a smartphone or computer if you want.

WiFi.hostname("AwesomeSensor");

Both wifi_set_macaddr and WiFi.hostname must be called before WiFi.begin() which initiates the WiFi connection.

ESP8266 shows up as AwesomeSensor with a random MAC address

Unicast vs Multicast MAC Address

An often-overlooked issue is that, the MAC address of an ESP8266 must be a unicast MAC address. In a MAC address, the least significant bit of the first octet indicates whether the MAC address is unicast or multicast. If that bit is 0 (i.e. the first byte is an even number), it is a unicast MAC address. If that bit is 1 (i.e. the first byte is an odd number), it is a multicast MAC address.

Espressif SDK does not allow setting ESP8266's MAC address to a multicast address. If a multicast MAC address is mistakenly passed to wifi_set_macaddr API, the function would return false, and the MAC would not be changed.

In case you are wondering why your chosen MAC is ineffective, this might be the reason. It is particularly important if you are trying to generate random MAC addresses.

A Little Library for Changing ESP8266 MAC Address

I made a little library to change the STA MAC address on an ESP8266. It offers a changeMac function to set the MAC address, and a makeRandomMac function to generate a random unicast MAC address. Just drop these two files into your project.

ChangeMac.hpp source code

#ifndef CHANGE_MAC_HPP
#define CHANGE_MAC_HPP

#include <cstdint>

void
makeRandomMac(uint8_t mac[6]);

bool
changeMac(const uint8_t mac[6]);

#endif // CHANGE_MAC_HPP

ChangeMac.cpp source code

#include "ChangeMac.hpp"
#include <Arduino.h>
extern "C" {
#include <user_interface.h>
}

void
makeRandomMac(uint8_t mac[6])
{
  for (size_t i = 0; i < 6; ++i) {
    mac[i] = random(256);
  }
  mac[0] = mac[0] & ~0x01;
}

bool
changeMac(const uint8_t mac[6])
{
  return wifi_set_macaddr(STATION_IF, const_cast<uint8*>(mac));
}

The library can be used in an Arduino sketch as follows:

#include <ESP8266WiFi.h>
#include "ChangeMac.hpp"

const char* ssid     = "yoursunny.com";
const char* password = "8044578669";

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

  Serial.println();
  Serial.println();

  uint8_t mac[6];
  makeRandomMac(mac);
  changeMac(mac);
  Serial.print("MAC address is ");
  Serial.println(WiFi.macAddress());

  WiFi.hostname("AwesomeSensor");

  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
}

Serial monitor showing random MAC addresses

Tags: ESP8266 WiFi