MKR1000 - Skenování WiFi sítě

Zápisník experimentátora

Hierarchy: Arduino MKR1000

V tomto článku si vyzkoušíme skenování WiFi sítě pomocí Arduina MKR1000. Budeme vycházet ze vzorového příkladu, který je dodáván ke knihovně WiFi101, program ale upravíme tak, aby se výsledek zobrazoval na displeji Nokia 5110.

Skenování WiFi sítě je vděčný projekt pro každého zvědavce. Poskládáte si skener a můžete s ním vyrazit na sídliště a sledovat, jaké sítě se tam nacházejí. Nebo budete jen tak sedět za stolem a sledovat, co všechno se nachází ve vaší blízkosti. Například já vidím od mého stolu na 5-7 sítí. Dvě z toho jsou u mě doma a okolní se nacházejí někde v blízkých bytech.

Nokia 5110

Tento displej rád používám v mých projektech. Klasické Arduino na 5 V potřebuje na jeho ovládání level shifter. Toto vše může při MKR1000 odpadnout, protože používá stejně jako displej 3,3 V. Čili celé zapojení scvrkne do propojení několika řidičů.

K ovládání displeje budeme používat knihovnu Adafruit_PCD8544. Dá se nainstalovat i v správci knihoven, ale má to jeden háček. Je zapotřebí minimálně verze 1.0.1, která umí spolupracovat s mikrokontroléry SAMD21. V době psaní článku byla již úprava na GitHub, ale nebyla ještě k dispozici ve správci knihoven. Proto ji bylo nutné z GitHub stáhnout ručně a přepsat s ní nainstalovanou knihovnu.

WiFi101

Další potřebnou knihovnou je WiFi101. Tato se dá nainstalovat i ve správci knihoven. V době psaní článku tam byla verze 0.11.0.

IDE

Celé zapojení jsem testoval v IDE 1.6.12.

Chování programu

Program jsem zmodifikovat podle původního vzorového příkladu ke knihovně WiFi101 ScanNetworks. Ten vypisoval nalezené WiFi sítě na sériový port. To vše jsem v kódu nechal, i když jsem některé funkce mírně upravil. Doplnil jsem výpisy na displeji Nokia 5110.

Funguje to tak, že se prohledá seznam WiFi sítí a ten se postupně zobrazuje na displeji. Příklad je dobře viditelný na přiložených obrázcích. Vypisuje:

  • pořadové číslo sítě
  • SSID sítě - Toto je název sítě. Abych majitelům sítí zachoval nějaké soukromí, na obrázku jsou vždy dva poslední znaky nahrazeny znakem otazníku. Ve zdrojovém textu si to můžete v případě potřeby vypnout a vidět celý název sítě.
  • sílu signálu
  • šifrování

Výpis se mění každé dvě sekundy. Po vypsání všech sítí se zase vyhledá aktuální seznam WiFi sítí a pokračuje se jeho výpisem.

Includování knihoven a nastavení displeje.

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <WiFi101.h>

// Software SPI (slower updates, more flexible pin options):
// pin 1 - Serial clock out (SCLK)
// pin 2 - Serial data out (DIN)
// pin 3 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 5 - LCD reset (RST)
Adafruit_PCD8544 nokia = Adafruit_PCD8544(1, 2, 3, 4, 5);

Nastavení. Kontrast si možná budete muset doladit. Hodnoty nad 60 vedou k velkému šumu na displeji, pod 50 pravděpodobně nebudete nic vidět. Součástí nastavení je i zobrazení intra funkcí drawIntro. To sestává ze zobrazení dvou obrazovek informací. Na chvíli se zobrazí i MAC adresa mikrokontroléru.

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

  nokia.begin();
  nokia.setContrast(60);
  nokia.clearDisplay();   // clears the screen and buffer
  drawIntro();
  nokia.clearDisplay();
  nokia.display();

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    nokia.setCursor(0, 0);
    nokia.print("WiFi shield not present");
    nokia.display();
    // don't continue:
    while (true);
  }

  // Print WiFi MAC address:
  printMacAddress();
}

Takto vypadá kód intra.

void drawIntro()
{
  nokia.setCursor(0, 0);
  nokia.print("WiFi Scan Network");
  Serial.println("WiFi Scan Network");
  nokia.setCursor(0, 20);
  nokia.print("www.arduinoslovakia.eu");
  nokia.display();
  delay(2000);
  nokia.clearDisplay();
  nokia.setCursor(0, 0);
  nokia.print("List of all WiFi networks.");
  Serial.println("List of all WiFi networks.");
  nokia.display();
  delay(2000);
}

Zobrazení MAC adresy. V původním kódu to vypisovali po jednotlivých bajtech. Ale funkce print neformátuje dobře hexadecimální čísla, menší než 0F a zobrazuje je jako F. V mikrokontroléru MKR1000 máme ale dostatek paměti, abychom si mohli dovolit komfortní vypisování funkcí sprintf. A vypadá to i hezčí.

void printMacAddress() {
  // the MAC address of your Wifi shield
  byte mac[6];
  char draw[30];

  // print your MAC address:
  WiFi.macAddress(mac);
  sprintf(draw, "MAC:%02X:%02X:%02X:%02X:%02X:%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);

  nokia.clearDisplay();
  nokia.setCursor(0, 0);
  nokia.print(draw);
  Serial.println(draw);

  nokia.display();
}

Hlavní cyklus programu. Periodicky se volá funkce listNetworks, která se stará o vykreslování.

void loop() {
  // scan for existing networks:
  Serial.println("Scanning available networks...");
  nokia.clearDisplay();
  nokia.setCursor(0, 0);
  nokia.print("Scanning...");
  nokia.display();
  listNetworks();
}

Samotná funkce na vypisování informací na sériový port (původní kod) a displej Nokia 5110 (nový kód). Na vypisování textů využívá proměnné draw a ssid. Všimněte si, jak se využívá funkce strlen (vrací délku řetězce) na zamaskování posledních dvou znaků SSID. Veškeré výpisy jsou opět připravovány pomocí funkce sprintf.

void listNetworks() {
  char draw[30];
  char ssid[M2M_MAX_SSID_LEN];
  
  // scan for nearby networks:
  int numSsid = WiFi.scanNetworks();
  if (numSsid == -1)
  {
    Serial.println("Couldn't get a wifi connection");
    while (true);
  }

  // print the list of networks seen:
  Serial.print("Number of available networks: ");
  Serial.println(numSsid);

  // print the network number and name for each network found:
  for (int thisNet = 0; thisNet < numSsid; thisNet++) {
    strcpy(ssid,WiFi.SSID(thisNet));
    int dl=strlen(ssid);
    if(dl>2) { // hide some details
      ssid[dl-2]='?';
      ssid[dl-1]='?';
    }
    
    Serial.print(thisNet+1);
    Serial.print(") ");
    Serial.print(ssid);
    Serial.print("\tSignal: ");
    Serial.print(WiFi.RSSI(thisNet));
    Serial.print(" dBm");
    Serial.print("\tEncryption: ");
    Serial.println(getEncryptionType(WiFi.encryptionType(thisNet)));
    Serial.flush();

    nokia.clearDisplay();
    nokia.setCursor(0, 0);
    sprintf(draw,"Net: %d/%d",thisNet+1,numSsid);
    nokia.print(draw);
    nokia.setCursor(0, 8);
    nokia.print(ssid);
    nokia.setCursor(0, 24);
    sprintf(draw,"Sig: %d dBm",WiFi.RSSI(thisNet));
    nokia.print(draw);
    nokia.setCursor(0, 32);
    sprintf(draw,"Enc: %s",getEncryptionType(WiFi.encryptionType(thisNet)));
    nokia.print(draw);
    nokia.display();

    delay(2000);
  }
}

Následující funkci jsem kompletně přepsal. Původní kód přímo vypisoval na sériový port. Nyní funkce pouze vrátí pointer na textový řetězec.

const char S_WEP[]="WEP";
const char S_TKIP[]="WPA";
const char S_CCMP[]="WPA2";
const char S_NONE[]="None";
const char S_AUTO[]="Auto";
const char S_UNKNOWN[]="Unkn.";

const char* getEncryptionType(int thisType) {
  // read the encryption type and print out the name:
  switch (thisType) {
    case ENC_TYPE_WEP:
      return S_WEP;
    case ENC_TYPE_TKIP:
      return S_TKIP;
    case ENC_TYPE_CCMP:
      return S_CCMP;
    case ENC_TYPE_NONE:
      return S_NONE;
    case ENC_TYPE_AUTO:
      return S_AUTO;
    default:
      return S_UNKNOWN;
  }
}

Zdrojový kód

Zdrojový kód se nachází na GitHub.

Video

Video k článku je na Youtube. Ve videu je vidět skenování WiFi sítí kolem mě a připojení WiFi bodu z mobilního telefonu a akční kamery Xiaomi Yi.


04.07.2017


Menu