ESP32 – WiFi Scanner

This source allows to scan Wireless networks nearby,

This code runs on ESP32 NodeMcu D1 Mini

/*
This sketch demonstrates how to scan WiFi networks. The API is almost the same as with the WiFi Shield library, the most obvious difference being the different file you need to include:
*/

#include <ESP8266WiFi.h>
#include <PubSubClient.h>  // for MQTT
#include <WiFiClientSecure.h> 
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>

const char* ssid = "Sotong_Purnama";
const char* password = "15sotong15";

const char* MyHostName = "ESP32 - WiFi Scanner";
const char* ntpServer1 = "pool.ntp.org";
const char* ntpServer2 = "time.nist.gov";
const long  gmtOffset_sec = 28800;  // For GMT+8
const int   daylightOffset_sec = 0;  // No daylight offset


// For Pushover
const char* title;
const char* message;
//Pushover API endpoint
const char* pushoverApiEndpoint = "https://api.pushover.net/1/messages.json";

const char* pushoverUserKey = "u6ysovfgq1nhysszxzh91qnwadch2y";   // Set the user key generated in the Pushover account settings
const char* pushoverAPIToken = "amhb2rxrc2wa8gnpbpek99g2qrh4kx";  // Set the API token generated in the Pushover account settings
const char* messagePrefix = "";  // Set a prefix for all messages

// HTTPS root certificate for api.pushover.net: DigiCert Global Root CA, expires 2031.11.10
const char pushoverCertificateRoot[] = R"=EOF=(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)=EOF=";

// Create a list of certificates with the server certificate
X509List cert(pushoverCertificateRoot);
WiFiClient espClient;
PubSubClient mqtt_client(espClient);

// Create a WiFiClientSecure object
WiFiClientSecure ipClient;

bool wifiConnected = true;

// Set your static IP address
IPAddress local_IP(192, 168, 86, 237);
// // Set your Gateway IP address
IPAddress gateway(192, 168, 86, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(8, 8, 8, 8);   // optional
IPAddress secondaryDNS(8, 8, 4, 4); // optional

// for MQTT
const char* mqtt_server = "192.168.86.225";
const unsigned mqtt_port = 1883;
const char* mqtt_user = "homeassistant";
const char* mqtt_password = "raspberrypi";
char payload[2000];

// Networks MQTT Topics
#define MQTT_PUB_TOPIC "wifiscan"
#define MQTT_PUB_SSID "wifiscan/ssid"
#define MQTT_PUB_RSSI "wifiscan/rssi"
#define MQTT_PUB_BSSID "wifiscan/bssid"
#define MQTT_PUB_CHANNEL  "wifiscan/channel"
#define MQTT_PU_ENCRYPTIONTYPE "wifiscan/encryptiontype"

// function to reconnect to the MQTT broker
void reconnect() {
  // Loop until we're reconnected
  while (!mqtt_client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (mqtt_client.connect("ESP32client",mqtt_user,mqtt_password)) {
      Serial.println("Connected to MQTT server");
      // Subscribe
      mqtt_client.subscribe("#");
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqtt_client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void sendPushover(const char* title, const char* message){
  const char* hostname;
  String IPAddress;
  //Make HTTP POST request to send notification
  if (WiFi.status() == WL_CONNECTED) {
    WiFi.setHostname(MyHostName);
    hostname = WiFi.getHostname();
    IPAddress = WiFi.localIP().toString().c_str();

    // Create a JSON object with notification details
    // Check the API parameters: https://pushover.net/api
    StaticJsonDocument<512> notification;
    notification["token"] = pushoverAPIToken;
    notification["user"] = pushoverUserKey;
    notification["message"] = IPAddress;
    notification["title"] = hostname;
    notification["url"] = "";
    notification["url_title"] = "";
    notification["html"] = "";
    notification["priority"] = "";
    notification["sound"] = "cosmic";
    notification["timestamp"] = "";

    // Serialize the JSON object to a string
    String jsonStringNotification;
    serializeJson(notification, jsonStringNotification);

 
    // Set the certificate
    ipClient.setTrustAnchors(&cert);

    // Create an HTTPClient object
    HTTPClient http;
    // Specify the target URL
    http.begin(ipClient, pushoverApiEndpoint);
    // Add headers
    http.addHeader("Content-Type", "application/json");

    // Send the POST request with the JSON data
    int httpResponseCode = http.POST(jsonStringNotification);

    // Check the response
    if (httpResponseCode > 0) {
      Serial.printf("HTTPS response code: %d\n", httpResponseCode);
      String response = http.getString();
      Serial.println("Response:");
      Serial.println(response);
    } else {
      Serial.printf("HTTPS response code: %d\n", httpResponseCode);
    }

    // Close the connection
    http.end();
  }
}

//#########################//
//          SET-UP         //
//#########################//
void setup() {
  const char* hostname;
  String IPAddress;
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  delay(2000);
  Serial.println("Start the connection process to the Wifi network");
  WiFi.begin(ssid, password);
  Serial.println("");
  Serial.println("Start the Wifi configuration");
  if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
    Serial.println("STA Failed to configure");
  }
  else
  {
    Serial.println("Wifi configuration successful");
    WiFi.setHostname("ESP32 - Wifi Scanner");
    // hostname = WiFi.getHostname();
    // IPAddress = WiFi.localIP().toString().c_str();
  }
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  delay(100);
  // defining the MQTT server
  mqtt_client.setServer(mqtt_server,mqtt_port);
  // attempting to connect to the MQTT server
  while (!mqtt_client.connected()) {
    Serial.print("Connecting to MQTT...");
    if (mqtt_client.connect("mqtt_client", mqtt_user, mqtt_password )) {
      Serial.println("connected");  
    } else {
      Serial.print("failed with state ");
      Serial.println(mqtt_client.state());
      Serial.print("Will retry in 5 seconds...");
      delay(5000);
    }
  }

  // Set time via NTP, as required for x.509 validation
  configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  Serial.print("Waiting for NTP time sync: ");
  time_t now = time(nullptr);
  while (now < 8 * 3600 * 2) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));

  // call the sendPushover function
  sendPushover(title, message);
}

//#########################//
//        MAIN LOOP        //
//#########################//
void loop() {
  String ssid;
  int32_t rssi;
  uint8_t encryptionType;
  uint8_t *bssid;
  int32_t channel;
  bool hidden;
  int scanResult;
  char buffer[300];

   // check that the MQTT connection is established
  if (!mqtt_client.connected()) {
    Serial.println("MQTT server disconnected...");
    // if it is not, then reconnect
    reconnect();
  }

  Serial.println(F("Starting WiFi scan..."));
  // scan the networks function call and analysis of results
  scanResult = WiFi.scanNetworks(/*async=*/false, /*hidden=*/true);
  if (scanResult == 0) {
    Serial.println(F("\nNo networks found"));
  } else if (scanResult > 0) {
    Serial.printf(PSTR("\n%d networks found:\n"), scanResult);
    sprintf(buffer,"\n%d networks found",scanResult);
    mqtt_client.publish(MQTT_PUB_TOPIC,buffer,false);
    // Print unsorted scan results
    for (int8_t i = 0; i < scanResult; i++) {
      WiFi.getNetworkInfo(i, ssid, encryptionType, rssi, bssid, channel, hidden);

      // get extra info
      const bss_info *bssInfo = WiFi.getScanInfoByIndex(i);
      String phyMode;
      const char *wps = "";
      if (bssInfo) {
        // reserves 12 characters/bytes to store the type of WiFi network
        phyMode.reserve(12);
        phyMode = F("802.11");
        String slash;
        if (bssInfo->phy_11b) {
          phyMode += 'b';
          slash = '/';
        }
        if (bssInfo->phy_11g) {
          phyMode += slash + 'g';
          slash = '/';
        }
        if (bssInfo->phy_11n) {
          phyMode += slash + 'n';
        }
        if (bssInfo->wps) {
          wps = PSTR("WPS");
        }

      }
      Serial.printf(PSTR("  %02d: [CH %02d] [%02X:%02X:%02X:%02X:%02X:%02X] %ddBm %c %c %-11s %3S %s\n"), i, channel, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], rssi, (encryptionType == ENC_TYPE_NONE) ? ' ' : '*', hidden ? 'H' : 'V', phyMode.c_str(), wps, ssid.c_str());
      sprintf(buffer,"%2d: [CH %02d] [%02X:%02X:%02X:%02X:%02X:%02X] %ddBm %c %c %-11s %3S %s", i, channel, bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], rssi, (encryptionType == ENC_TYPE_NONE) ? ' ' : '*', hidden ? 'H' : 'V', phyMode.c_str(), wps, ssid.c_str());
      mqtt_client.publish(MQTT_PUB_TOPIC,buffer,false);
      if(i==0){
        strcpy(payload,buffer);
      }
      else{
        strcat(payload,buffer);
      }
      yield();
 
    }  // end of For loop
  } else {
    Serial.printf(PSTR("WiFi scan error %d"), scanResult);
  }

  delay(2000);
  mqtt_client.publish(MQTT_PUB_TOPIC,payload,false);
  // resets payload
  sprintf(payload,"");
  sprintf(buffer,"");
  mqtt_client.loop();

  // Wait a bit before scanning again
  delay(10000);
}