ESP32 Wifi and Promiscuous mode

I'm working on a project where I need to calculate the RSSI values from a receiver using ESP32. I have two separate codes: one calculates RSSI in promiscuous mode (without WiFi connection) and the other calculates RSSI while connected to a hotspot and Blynk. However, I'm having trouble combining these two methods.

Problem:

I want the default behavior to be promiscuous mode when the device is not connected to a hotspot. Once the ESP32 connects to a hotspot, it should switch to using ESP-NOW for RSSI calculations. When the device disconnects from the hotspot, it should revert back to promiscuous mode for RSSI calculations.

No matter what I try, I can't seem to combine the two methods effectively.

Code 1: RSSI in Promiscuous Mode (without Blynk and Hotspot)

#include <esp_now.h>
#include <WiFi.h>
#include <algorithm>
#include <esp_wifi.h>  // Required for promiscuous mode

// ESP-NOW Receiver MAC Address
uint8_t receiverMacAddress[] = {0x20, 0x43, 0xA8, 0x63, 0x35, 0xA8};

// Hardware Pins
#define BUTTON1_PIN 15
#define BUTTON2_PIN 23
#define LED1_PIN 5
#define LED2_PIN 21

// RSSI Settings
#define SAMPLES 30
#define WINDOW_SIZE 5
#define DEAD_BAND_SPEED 0.05
#define MIN_DEADBAND 0.1
#define MAX_DEADBAND 2.0

// Kalman Filter Parameters
const float Q = 0.1;  // Process noise
const float R = 1.5;  // Measurement noise

struct PacketData {
  byte activeButton;
};

struct PacketData2 {
  int rssiValue;
};

// Global Variables
float rssiSamples[SAMPLES];
float kalmanFilteredRSSI = 0;
int sampleIndex = 0;
int latestRSSI = 0;
float kalmanRSSI = 0;
float kalmanP = 1;
float prevRSSI = 0;
unsigned long prevTime = 0;
PacketData data;
PacketData2 data2;
bool lastButton1State = false;
bool lastButton2State = false;
bool button1Active = false;
bool button2Active = true; 
// Enhanced Filtering Functions
float applyMovingAverage(float newValue) {
    static float buffer[WINDOW_SIZE] = {0};
    static byte index = 0;
    static float sum = 0;
    
    sum -= buffer[index];
    buffer[index] = newValue;
    sum += buffer[index];
    index = (index + 1) % WINDOW_SIZE;
    
    return sum / WINDOW_SIZE;
}

float kalmanUpdate(float measurement) {
    kalmanP = kalmanP + Q;
    float K = kalmanP / (kalmanP + R);
    kalmanRSSI = kalmanRSSI + K * (measurement - kalmanRSSI);
    kalmanP = (1 - K) * kalmanP;
    return kalmanRSSI;
}

float calculateDynamicDeadband() {
    float variance = 0;
    for(int i=0; i<SAMPLES; i++) {
        variance += pow(rssiSamples[i] - kalmanFilteredRSSI, 2);
    }
    variance /= SAMPLES;
    return constrain(DEAD_BAND_SPEED * (1 + variance*0.1), MIN_DEADBAND, MAX_DEADBAND);
}

void updateRSSI() {
    // Take burst samples
    float burstSamples[5];
    for(int i=0; i<5; i++) {
        burstSamples[i] = latestRSSI;
        delay(2);
    }
    
    // Median filter
    std::sort(burstSamples, burstSamples+5);
    float medianRSSI = burstSamples[2];
    
    // Apply processing chain
    float smoothed = applyMovingAverage(medianRSSI);
    kalmanFilteredRSSI = kalmanUpdate(smoothed);
}

void promiscuousRxCB(void *buf, wifi_promiscuous_pkt_type_t type) {
    if (type == WIFI_PKT_MGMT) {
        wifi_promiscuous_pkt_t *pkt = (wifi_promiscuous_pkt_t *)buf;
        latestRSSI = pkt->rx_ctrl.rssi;
    }
}

void OnDataRecv(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len) {
    memcpy(&data2, incomingData, sizeof(data2));
    
    if (data2.rssiValue != 0) {
        rssiSamples[sampleIndex] = data2.rssiValue;
        sampleIndex = (sampleIndex + 1) % SAMPLES;
        updateRSSI();

        float dynamicDeadband = calculateDynamicDeadband();
        if (abs(kalmanFilteredRSSI - prevRSSI) < dynamicDeadband) {
            kalmanFilteredRSSI = prevRSSI;
        }

        prevTime = millis();
        prevRSSI = kalmanFilteredRSSI;

        Serial.printf("Raw: %6.2f | Filtered: %6.2f | Deadband: %4.2f\n", 
                    data2.rssiValue, kalmanFilteredRSSI, dynamicDeadband);
    }
}

void setup() {
    Serial.begin(115200);
    WiFi.mode(WIFI_STA);
    
    // Initialize hardware
    pinMode(BUTTON1_PIN, INPUT_PULLUP);
    pinMode(BUTTON2_PIN, INPUT_PULLUP);
    pinMode(LED1_PIN, OUTPUT);
    pinMode(LED2_PIN, OUTPUT);
    digitalWrite(LED1_PIN, LOW);
    digitalWrite(LED2_PIN, HIGH); // LED2 דלוק כברירת מחדל

    // Initialize ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("ESP-NOW Init Failed");
        ESP.restart();
    }

    esp_now_peer_info_t peerInfo;
    memset(&peerInfo, 0, sizeof(peerInfo));
    memcpy(peerInfo.peer_addr, receiverMacAddress, 6);
    peerInfo.channel = 0;
    peerInfo.encrypt = false;
    
    if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        ESP.restart();
    }

    // Register callbacks
    esp_now_register_recv_cb(OnDataRecv);
    esp_wifi_set_promiscuous(true);
    esp_wifi_set_promiscuous_rx_cb(&promiscuousRxCB);

    Serial.println("Transmitter Ready - System OFF (Default)");
}

void loop() {
    // Button handling
    bool currentButton1State = !digitalRead(BUTTON1_PIN);
    if (currentButton1State && !lastButton1State) {
        button1Active = true;
        button2Active = false;
        data.activeButton = 1;
        digitalWrite(LED1_PIN, HIGH);
        digitalWrite(LED2_PIN, LOW);
        Serial.println("🔴 System ON");
    }
    lastButton1State = currentButton1State;

    bool currentButton2State = !digitalRead(BUTTON2_PIN);
    if (currentButton2State && !lastButton2State) {
        button1Active = false;
        button2Active = true;
        data.activeButton = 2;
        digitalWrite(LED1_PIN, LOW);
        digitalWrite(LED2_PIN, HIGH);
        Serial.println("🟢 System OFF");
    }
    lastButton2State = currentButton2State;

    // Send data
    esp_now_send(receiverMacAddress, (uint8_t *)&data, sizeof(data));
    delay(30);
}

Code number 2 (Blynk and hotspot on RSSI is good, when Blynk and hotspot off RSSI is bad):

#define BLYNK_TEMPLATE_ID "--"
#define BLYNK_TEMPLATE_NAME "--"
#define BLYNK_AUTH_TOKEN "--"

#include <esp_now.h>
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>

// WiFi Credentials
char ssid[] = "---";
char pass[] = "---";

// ESP-NOW Receiver MAC Address
const uint8_t receiverMacAddress[] = {0x20, 0x43, 0xA8, 0x63, 0x35, 0xA8};

// Hardware Pins
#define BUTTON1_PIN 15
#define BUTTON2_PIN 23
#define LED1_PIN 5
#define LED2_PIN 21

// RSSI Settings
#define WINDOW_SIZE 7
#define RSSI_TIMEOUT 2000   // ms
#define CONTROL_SEND_INTERVAL 30 // ms
#define RSSI_SEND_INTERVAL 100 // ms

// Kalman Filter Parameters
const float Q = 0.01;  // Process noise
const float R = 2.0;   // Measurement noise

struct PacketData {
  byte activeButton;
};

struct PacketData2 {
  int rssiValue;
};

// Global Variables
float kalmanRSSI = -70; // Initial reasonable value
float kalmanP = 1;
int latestRSSI = -70;
unsigned long lastPacketTime = 0;
bool rssiTimeout = false;
PacketData data;
PacketData2 data2;
bool lastButton1State = false;
bool lastButton2State = false;
bool button1Active = false;
bool button2Active = false;
bool blynkConnected = false;
unsigned long lastBlynkUpdate = 0;
bool wifiConnected = false;

// Moving Average Filter
float applyMovingAverage(float newValue) {
    static float buffer[WINDOW_SIZE] = {0};
    static byte index = 0;
    static float sum = 0;
    
    sum -= buffer[index];
    buffer[index] = newValue;
    sum += buffer[index];
    index = (index + 1) % WINDOW_SIZE;
    
    return sum / WINDOW_SIZE;
}

// Improved Kalman Filter with timeout handling
float kalmanUpdate(float measurement) {
    // Check for timeout
    if(millis() - lastPacketTime > RSSI_TIMEOUT) {
        rssiTimeout = true;
        return kalmanRSSI; // Return last good value
    }
    
    // Validate measurement (-100dBm to 0dBm)
    if(measurement > 0 || measurement < -100) return kalmanRSSI;
    
    rssiTimeout = false;
    kalmanP = kalmanP + Q;
    float K = kalmanP / (kalmanP + R);
    kalmanRSSI = kalmanRSSI + K * (measurement - kalmanRSSI);
    kalmanP = (1 - K) * kalmanP;
    
    return constrain(kalmanRSSI, -100, 0);
}

void OnDataRecv(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len) {
    // Get RSSI from ESP-NOW packet metadata
    latestRSSI = info->rx_ctrl->rssi;
    lastPacketTime = millis();
    
    // Apply processing chain
    float smoothed = applyMovingAverage(latestRSSI);
    kalmanRSSI = kalmanUpdate(smoothed);
    
    // Send to Blynk if connected
    if(blynkConnected && millis() - lastBlynkUpdate >= 500) {
        lastBlynkUpdate = millis();
        Blynk.virtualWrite(V1, kalmanRSSI);
    }
    
    // Debug output
    Serial.printf("RSSI: %.2f dBm\n", kalmanRSSI);
}

BLYNK_CONNECTED() {
    blynkConnected = true;
    Blynk.syncVirtual(V0);
    Blynk.virtualWrite(V0, button1Active ? 1 : 0);
    Blynk.virtualWrite(V1, kalmanRSSI);
}

BLYNK_DISCONNECTED() {
    blynkConnected = false;
}

BLYNK_WRITE(V0) {
    int buttonState = param.asInt();
    if(buttonState == 1 && !button1Active) {
        button1Active = true;
        button2Active = false;
        data.activeButton = 1;
        digitalWrite(LED1_PIN, HIGH);
        digitalWrite(LED2_PIN, LOW);
        Serial.println("🔴 System ON (from Blynk)");
    } 
    else if(buttonState == 0 && !button2Active) {
        button1Active = false;
        button2Active = true;
        data.activeButton = 2;
        digitalWrite(LED1_PIN, LOW);
        digitalWrite(LED2_PIN, HIGH);
        Serial.println("🟢 System OFF (from Blynk)");
    }
}

void maintainWiFiConnection() {
    static unsigned long lastCheck = 0;
    if(millis() - lastCheck >= 10000) { // Check every 10 seconds
        lastCheck = millis();
        if(WiFi.status() != WL_CONNECTED) {
            WiFi.disconnect();
            WiFi.begin(ssid, pass);
            wifiConnected = false;
        } else if(!wifiConnected) {
            wifiConnected = true;
            Serial.println("WiFi reconnected");
        }
    }
}

void setup() {
    Serial.begin(115200);
    
    // Initialize hardware
    pinMode(BUTTON1_PIN, INPUT_PULLUP);
    pinMode(BUTTON2_PIN, INPUT_PULLUP);
    pinMode(LED1_PIN, OUTPUT);
    pinMode(LED2_PIN, OUTPUT);
    digitalWrite(LED1_PIN, LOW);
    digitalWrite(LED2_PIN, HIGH);

    // Start WiFi in STA mode only
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, pass);
    Serial.println("Connecting to WiFi...");

    // Initialize ESP-NOW
    if(esp_now_init() != ESP_OK) {
        Serial.println("ESP-NOW Init Failed");
        ESP.restart();
    }

    esp_now_peer_info_t peerInfo;
    memset(&peerInfo, 0, sizeof(peerInfo));
    memcpy(peerInfo.peer_addr, receiverMacAddress, 6);
    peerInfo.channel = 0;
    peerInfo.encrypt = false;
    
    if(esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        ESP.restart();
    }

    esp_now_register_recv_cb(OnDataRecv);
    
    // Initialize Blynk with separate connection handling
    Blynk.config(BLYNK_AUTH_TOKEN);
    Blynk.connect(1000); // Shorter timeout
    blynkConnected = Blynk.connected();
    
    Serial.println("System Ready");
}

void loop() {
    // Handle Blynk connection separately
    static unsigned long lastBlynkReconnect = 0;
    if(!blynkConnected && millis() - lastBlynkReconnect > 5000) {
        lastBlynkReconnect = millis();
        if(WiFi.status() == WL_CONNECTED) {
            Blynk.connect(1000);
            blynkConnected = Blynk.connected();
            if(blynkConnected) Serial.println("Reconnected to Blynk");
        }
    }
    
    if(blynkConnected) {
        Blynk.run();
    }
    
    // Maintain WiFi connection
    maintainWiFiConnection();
    
    // Button handling
    bool currentButton1State = !digitalRead(BUTTON1_PIN);
    if(currentButton1State && !lastButton1State) {
        button1Active = true;
        button2Active = false;
        data.activeButton = 1;
        digitalWrite(LED1_PIN, HIGH);
        digitalWrite(LED2_PIN, LOW);
        Serial.println("🔴 System ON (Physical Button)");
        if(blynkConnected) {
            Blynk.virtualWrite(V0, 1);
        }
        delay(100); // Simple debounce
    }
    lastButton1State = currentButton1State;

    bool currentButton2State = !digitalRead(BUTTON2_PIN);
    if(currentButton2State && !lastButton2State) {
        button1Active = false;
        button2Active = true;
        data.activeButton = 2;
        digitalWrite(LED1_PIN, LOW);
        digitalWrite(LED2_PIN, HIGH);
        Serial.println("🟢 System OFF (Physical Button)");
        if(blynkConnected) {
            Blynk.virtualWrite(V0, 0);
        }
        delay(100); // Simple debounce
    }
    lastButton2State = currentButton2State;

    // Non-blocking control packet send
    static unsigned long lastControlSend = 0;
    if(millis() - lastControlSend >= CONTROL_SEND_INTERVAL) {
        esp_err_t result = esp_now_send(receiverMacAddress, (uint8_t *)&data, sizeof(data));
        lastControlSend = millis();
    }

    // Non-blocking RSSI packet send
    static unsigned long lastRSSISend = 0;
    if(millis() - lastRSSISend >= RSSI_SEND_INTERVAL) {
        data2.rssiValue = latestRSSI;
        esp_now_send(receiverMacAddress, (uint8_t *)&data2, sizeof(data2));
        lastRSSISend = millis();
    }

    // Handle RSSI timeout
    if(!rssiTimeout && millis() - lastPacketTime > RSSI_TIMEOUT) {
        rssiTimeout = true;
        Serial.println("Warning: RSSI timeout - no recent packets");
    }
}

What I Need Help With:

  • How can I effectively switch between promiscuous mode and ESP-NOW depending on the WiFi connection status?
  • How can I ensure that the RSSI values are calculated correctly in both modes without interference?
  • Any suggestions on cleaning up or combining the code better for my use case?

I would really appreciate any help or suggestions!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.