MAC Detector ESP32 - AZ-Delivery

Hallo zusammen,

heute wollen wir euch ein Projekt vorstellen auf welches wir durch eine Kundenanfrage aufmerksam wurden. Wir zeigen euch einen MAC-Adressen Detektor mit unserem ESP32 Dev Board C.

Mehr Hardware als dieses Board ist nicht erforderlich. Der Mac-Detector scannt kontiniuerlich nach den im Code hinterlegten Adressen und gibt diese, sobald sich ein Gerät nähert, im Seriellen Monitor aus. Dafür nutzen wir den Promiscuous Mode der sich beim ESP32 deutlich unkomplizierter benutzen lässt als noch beim Vorgänger ESP8266. Die Anwesenheitserkennung funktioniert recht zuverlässig, allerdings gilt es zu beachten, dass der Scanner erst etwas ausgibt wenn das WiFi-Gerät "wach ist" und kommuniziert. So kann es mitunter etwas dauern bis die Adresse im Seriellen Monitor erscheint. Je nach verwendetem Gerät und dessen Konfiguration sparen diese oft Energie und schalten dabei ungenutze Komponenten ab. Als besonders Kommunikationsfreudig haben sich dabei diverse iPhones erwiesen.

Einfach unter //adress list die gewünschten Adressen eintragen, fertig.

Hier der Code:

 

#include <WiFi.h>
#include <Wire.h>

#include "esp_wifi.h"


String maclist[64][3]; 
int listcount = 0;

String KnownMac[10][2] = {  // adress list
  {"Chef1","8C1ABF8A6A36"},
  {"Chef2","E894BA82BC83"},
  {"NAME","MACADDRESS"},
  {"NAME","MACADDRESS"},
  {"NAME","MACADDRESS"},
  {"NAME","MACADDRESS"},
  {"NAME","MACADDRESS"},
  {"NAME","MACADDRESS"},
  {"NAME","MACADDRESS"}
  
};

String defaultTTL = "60"; // Maximum time (Apx seconds) elapsed before device is consirded offline

const wifi_promiscuous_filter_t filt={
    .filter_mask=WIFI_PROMIS_FILTER_MASK_MGMT|WIFI_PROMIS_FILTER_MASK_DATA
};

typedef struct { 
  uint8_t mac[6];
} __attribute__((packed)) MacAddr;

typedef struct { 
  int16_t fctl;
  int16_t duration;
  MacAddr da;
  MacAddr sa;
  MacAddr bssid;
  int16_t seqctl;
  unsigned char payload[];
} __attribute__((packed)) WifiMgmtHdr;


  
#define maxCh 13 //max Channel -> US = 11, EU = 13, Japan = 14


int curChannel = 1;


void sniffer(void* buf, wifi_promiscuous_pkt_type_t type) { //This is where packets end up after they get sniffed
  wifi_promiscuous_pkt_t *p = (wifi_promiscuous_pkt_t*)buf;
  int len = p->rx_ctrl.sig_len;
  WifiMgmtHdr *wh = (WifiMgmtHdr*)p->payload;
  len -= sizeof(WifiMgmtHdr);
  if (len < 0){
    Serial.println("Receuved 0");
    return;
  }
  String packet;
  String mac;
  int fctl = ntohs(wh->fctl);
  for(int i=8;i<=8+6+1;i++){ // This reads the first couple of bytes of the packet. This is where you can read the whole packet replaceing the "8+6+1" with "p->rx_ctrl.sig_len"
     packet += String(p->payload[i],HEX);
  }
  for(int i=4;i<=15;i++){ // This removes the 'nibble' bits from the stat and end of the data we want. So we only get the mac address.
    mac += packet[i];
  }
  mac.toUpperCase();

  
  int added = 0;
  for(int i=0;i<=63;i++){ // checks if the MAC address has been added before
    if(mac == maclist[i][0]){
      maclist[i][1] = defaultTTL;
      if(maclist[i][2] == "OFFLINE"){
        maclist[i][2] = "0";
      }
      added = 1;
    }
  }
  
  if(added == 0){ // If its new. add it to the array.
    maclist[listcount][0] = mac;
    maclist[listcount][1] = defaultTTL;
   // Serial.println(mac);
    listcount ++;
    if(listcount >= 64){
      Serial.println("Too many addresses");
      listcount = 0;
    }
  }
}


void setup() {

  Serial.begin(115200);

  wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  esp_wifi_init(&cfg);
  esp_wifi_set_storage(WIFI_STORAGE_RAM);
  esp_wifi_set_mode(WIFI_MODE_NULL);
  esp_wifi_start();
  esp_wifi_set_promiscuous(true);
  esp_wifi_set_promiscuous_filter(&filt);
  esp_wifi_set_promiscuous_rx_cb(&sniffer);
  esp_wifi_set_channel(curChannel, WIFI_SECOND_CHAN_NONE);
  
  Serial.println("starting!");
}

void purge(){ // This manages the TTL
  for(int i=0;i<=63;i++){
    if(!(maclist[i][0] == "")){
      int ttl = (maclist[i][1].toInt());
      ttl --;
      if(ttl <= 0){
        //Serial.println("OFFLINE: " + maclist[i][0]);
        maclist[i][2] = "OFFLINE";
        maclist[i][1] = defaultTTL;
      }else{
        maclist[i][1] = String(ttl);
      }
    }
  }
}

void updatetime(){ // This updates the time the device has been online for
  for(int i=0;i<=63;i++){
    if(!(maclist[i][0] == "")){
      if(maclist[i][2] == "")maclist[i][2] = "0";
      if(!(maclist[i][2] == "OFFLINE")){
          int timehere = (maclist[i][2].toInt());
          timehere ++;
          maclist[i][2] = String(timehere);
      }
      
     // Serial.println(maclist[i][0] + " : " + maclist[i][2]);
      
    }
  }
}

void showpeople(){ // This checks if the MAC is in the reckonized list and then displays it on the OLED and/or prints it to serial.
  String forScreen = "";
  for(int i=0;i<=63;i++){
    String tmp1 = maclist[i][0];
    if(!(tmp1 == "")){
      for(int j=0;j<=9;j++){
        String tmp2 = KnownMac[j][1];
        if(tmp1 == tmp2){
          forScreen += (KnownMac[j][0] + " : " + maclist[i][2] + "\n");
          Serial.print(KnownMac[j][0] + " : " + tmp1 + " : " + maclist[i][2] + "\n -- \n");
        }
      }
    }
  }
}

void loop() {
    //Serial.println("Changed channel:" + String(curChannel));
    if(curChannel > maxCh){ 
      curChannel = 1;
    }
    esp_wifi_set_channel(curChannel, WIFI_SECOND_CHAN_NONE);
    delay(1000);
    updatetime();
    purge();
    showpeople();
    curChannel++;
    
    
}

 

In einem folgendem Beitrag werden wir versuchen die Anwesenheitserkennung mittels BLE umzusetzten. Bis zum nächsten mal :)

Esp-32Projekte für anfänger

5 comments

Bas

Bas

Hans, THX! this did the trick

String packet;
String mac;
String packet3;

int fctl = ntohs(wh→fctl); for (int i = 8; i <= 8 + 6 + 1; i++) { String packet2 = String(p→payload[i], HEX); if (packet2.length() == 1) { packet3 = “0” + packet2; packet += packet3; } else { packet += packet2; } }
Hans

Hans

Bei diesem code werden nicht alle Mac-Adressen richtig erkannt.
Beispiel:
Korrekte mac-adresse vom Gerät: D4:AE:05:0D:D7:28
Der Code erkennt: D4AE5DD728
Die 0 fehlen.

Erklärung:
Hexadezimal: D4:AE:05:0D:D7:28
Dezimal: 212:174:5:13:215:1C

- Dezimal 05 ist Hexa 5. Das 0 wird gestrichen.
- Dezimal 13 ist Hexa D. Das 0 wird gestrichen.

Der fehlerhafte code-abschnitt habe ich für mich wie folgt gelöst:

String packet; String packet3; String mac; int fctl = ntohs(wh→fctl); for (int i = 8; i <= 8 + 6 + 1; i++) { String packet2 = String(p→payload[i], HEX); if (packet2.length() == 1) { packet3 = “0” + packet2; packet += packet3; } else { packet += packet2; } }
Markus Hopfner

Markus Hopfner

Guten Tag (nochmals),

wollte Sie nur nochmals darauf Aufmerksam machen das der Code nicht mit MAC-Adressen mit zwei Nullen in folge funktioniert.

mfg

Markus

Markus Hopfner

Markus Hopfner

Guten Tag,
zuerst einmal vielen dank für den Code.

Mir ist aufgefallen das er nicht funktioniert wenn die MAC eine Doppelnull hat, da wird eine verschluckt. können Sie mir sagen wieso?

Mfg Markus

Willy

Willy

Das ist ein interessantes Projekt. Kann ich auch die MAC-Adressen mit einem ESP8266 scannen?
Genauer gesagt will ich den Amazon Dash-Button im WLAN erkennen. Der ESP8266 ist der Hotspot mit dem sich der DASH-Button verbindet. Aber ich weiss nicht wie ich die MAC-Adresse erkennen kann das der Dash-Button sich verbunden hat. Die MAC-Adresse des Dash-Button kenne ich.

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery