# Combined Sensor Alert System
Model: gemma-4-e4b-it
Created: 6/8/2026, 9:42:45 AM
Exported from: LM Studio 0.4.15+2

### User
can you combine these two codes so that when i move too fast the esp sends the words "TOO FAST" to the other esp32c3. im doing wireless comms. and using an adxel343

/*
    MASTER SKETCH: Movement Detector Sender (ESP-NOW) - FINAL VERSION
*/



#include &lt;Wire.h&gt; // Required for I2C communication with most sensors
#include &lt;Adafruit_Sensor.h&gt;
#include &lt;Adafruit_ADXL343.h&gt; 
#include &lt;esp_now.h&gt;
#include &lt;WiFi.h&gt;


// ===============================================================
// 1. GLOBAL CONFIGURATION & OBJECTS (Top of the file)
// ===============================================================


// --- Sensor Object Initialization ---
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345); 


// --- Movement Detection Variables ---
const float MOVEMENT_THRESHOLD = 1; // Tune this value! (Delta magnitude threshold)


// Tracking variables for the previous reading (MUST BE GLOBAL)
float last_accel_x = 0.0;
float last_accel_y = 0.0;
float last_accel_z = 0.0;


// State tracking flag (Controls if we print "DETECTED" or "SUBSIDED")
bool movement_detected_flag = false; 



// --- ESP-NOW MAC ADDRESS & STRUCTURES ---
uint8_t broadcastAddress[] = {0x94, 0xa9, 0x90, 0x6c, 0xd5, 0x9c};


typedef struct struct_message {
    char a[32]; // For status text ("Movement detected" or "Movement subsided")
    int b;      // Integer (e.g., scaled reading)
    float c;    // Float (e.g., magnitude or raw float data)
    bool d;     // Boolean (Movement Detected Flag)
} struct_message;


struct_message myData;


esp_now_peer_info_t peerInfo;



// --- SENSOR VARIABLES (Used by the main loop for calculation) ---
float accelX = 0.0, accelY = 0.0, accelZ = 0.0; // Global variables for sensor readings



// ===============================================================
// 2. CALLBACK FUNCTION (MUST BE GLOBAL)
// ===============================================================
void OnDataSent(const wifi_tx_info_t *txInfo, esp_now_send_status_t status) { 
    Serial.print("\r\n[ESP-NOW Status] Last Packet Send Status:\t");
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}



// ===============================================================
// 3. SETUP FUNCTION (Initialization)
// ===============================================================
void setup() {
    // Initialize Serial Monitor
    Serial.begin(115200);
    
    // Set device as a Wi-Fi Station (Required for ESP-NOW)
    WiFi.mode(WIFI_STA);


    // --- Sensor Initialization ---
    Wire.begin(); // Initialize I2C bus for the sensor
    if(!accel.begin()) {
        Serial.println("ERROR: ADXL343 not found! Check wiring.");
    } else {
        accel.setRange(ADXL343_RANGE_16_G);
        Serial.println("ADXL343 Sensor Initialized Successfully.");
    }


    // 1. INITIALIZE ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }


    // 2. REGISTER SEND CALLBACK
    esp_now_register_send_cb(OnDataSent);
    
    // 3. CHANNEL SYNCHRONIZATION (CRITICAL FIX!)
    WiFi.setChannel(1); // &lt;-- Use the channel that works for your setup!



    // 4. REGISTER PEER INFO
    memcpy(peerInfo.peer_addr, broadcastAddress, 6);
    peerInfo.channel = 0;  
    peerInfo.encrypt = false;
    
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
        Serial.println("Failed to add peer");
        return;
    }
    Serial.println("\n=========================================");
    Serial.println("Sender Setup Complete. Ready to transmit.");
    Serial.println("=========================================\n");
}



// ===============================================================
// 4. SENSOR READING FUNCTION (Replaces the simulation)
// ===============================================================
void readAccelerometerData() {
    sensors_event_t event;
    if (accel.getEvent(&event)) { // Check if reading was successful
        float current_x = event.acceleration.x;
        float current_y = event.acceleration.y;
        float current_z = event.acceleration.z;


        // Calculate the magnitude of acceleration (Total force vector)
        float current_magnitude = sqrt(current_x * current_x + current_y * current_y + current_z * current_z);


        // Calculate the change in magnitude since the last reading
        float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
        float delta_magnitude = abs(current_magnitude - last_magnitude);


        // Update the global variables used by the main loop() logic
        accelX = current_x;
        accelY = current_y;
        accelZ = current_z;
        
        // Return the calculated delta magnitude so we can use it in the loop() state machine
        Serial.printf("Sensor Read: X=%.2f, Y=%.2f, Z=%.2f | Delta Mag: %.2f\n", accelX, accelY, accelZ, delta_magnitude);


    } else {
        Serial.println("ERROR reading sensor data!");
    }
}



// ===============================================================
// 5. MAIN LOOP (State Machine & Sending)
// ===============================================================
void loop() {
    // --- STEP A: Read Sensor Data and Calculate Change ---
    // We must capture the delta magnitude here to use it for state detection
    float current_delta_magnitude;
    readAccelerometerData(); 


    // NOTE: Since readAccelerometerData now prints, we rely on its internal logic 
    // to calculate the necessary values. For simplicity in this final merge, 
    // we will re-calculate the delta here based on the global variables updated above.
    float current_magnitude = sqrt(accelX * accelX + accelY * accelY + accelZ * accelZ);
    float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
    current_delta_magnitude = abs(current_magnitude - last_magnitude);



    // --- STEP B: State Change Detection (The core logic) ---
    if (current_delta_magnitude &gt; MOVEMENT_THRESHOLD) {
        if (!movement_detected_flag) {
            // *** TRANSITION: From Still to Moving ***
            Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT DETECTED !!!"); // &lt;-- PRINT ON CHANGE
            Serial.println("========================================\n");


            strcpy(myData.a, "Movement detected"); 
            myData.b = 1;                                     
            myData.c = current_magnitude;                      // Send the actual magnitude
            myData.d = true;                                   



        } else {
             // Already moving: just update payload without printing status text
             strcpy(myData.a, "Movement detected"); 
             myData.b = 1;
             myData.c = current_magnitude;
             myData.d = true;
        }


    } else {
        if (movement_detected_flag) {
            // *** TRANSITION: From Moving to Still ***
            Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT SUBSIDED !!!"); // &lt;-- PRINT ON CHANGE
            Serial.println("========================================\n");


            strcpy(myData.a, "Movement subsided"); 
            myData.b = 0;                                     
            myData.c = current_magnitude;                      // Send the low magnitude
            myData.d = false;                                  
        } else {
             // Still still: just update payload without printing status text
             strcpy(myData.a, "Movement subsided"); 
             myData.b = 0;
             myData.c = current_magnitude;
             myData.d = false;
        }
    }


    // --- STEP C: Send Data (Network Transmission) ---
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    
    if (result == ESP_OK) {
        Serial.println("Data packet sent successfully."); 
    } else {
        Serial.println("ERROR: Failed to send data packet."); 
    }


    // --- STEP D: Update State for Next Cycle & Sensor History ---
    movement_detected_flag = (current_delta_magnitude &gt; MOVEMENT_THRESHOLD); // Set flag based on current detection
    last_accel_x = accelX;
    last_accel_y = accelY;
    last_accel_z = accelZ;


    // Wait for a short period to keep the loop responsive but not overwhelming.
    delay(500); 
}


other code

#include &lt;Wire.h&gt;
#include &lt;Adafruit_Sensor.h&gt;
#include &lt;Adafruit_ADXL343.h&gt;



/* Assign a unique ID to this sensor at the same time */
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345);



// --- Movement Detection Variables ---


// Threshold 1: Detects general movement (Original logic)
const float MOVEMENT_THRESHOLD = 0.8; // Example: Detect movement if magnitude change exceeds 0.8G


// Threshold 2: Detects *fast* movement (New Logic)
// This threshold determines how large the difference between consecutive readings must be 
// to trigger a "slow down" warning. You will need to tune this heavily!
const float FAST_MOVEMENT_THRESHOLD = 1.5; // Example: Trigger if change in acceleration vector magnitude exceeds 1.5G



// Tracking variables for the previous reading (for both general and fast detection)
float last_accel_x = 0.0;
float last_accel_y = 0.0;
float last_accel_z = 0.0;


// Variables to track the state of the alerts
bool movement_detected_flag = false;
bool fast_movement_warning_active = false;



void setup(void)
{
  Serial.begin(9600);
  while (!Serial);
  Serial.println("ADXL343 Movement Detector Initializing..."); Serial.println("");


  /* Initialise the sensor */
  if(!accel.begin())
  {
    Serial.println("Ooops, no ADXL343 detected ... Check your wiring!");
    while(1);
  }


  /* Set the range to whatever is appropriate for your project */
  accel.setRange(ADXL343_RANGE_16_G);



  Serial.println("ADXL343 initialized. Ready to detect movement.");
}



void loop(void)
{
  // 1. Read the current sensor data
  sensors_event_t event;
  accel.getEvent(&event);


  float current_x = event.acceleration.x;
  float current_y = event.acceleration.y;
  float current_z = event.acceleration.z;



  // 2. Calculate the magnitude of acceleration (Total force vector)
  // Magnitude = sqrt(X^2 + Y^2 + Z^2)
  float current_magnitude = sqrt(current_x * current_x + current_y * current_y + current_z * current_z);



  // 3. Calculate the change in magnitude since the last reading (General Movement Proxy)
  float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
  // The difference between current and previous magnitude is a good indicator of change.
  float delta_magnitude = abs(current_magnitude - last_magnitude);



  // 4. *** NEW: Calculate the rate of change (Fast Movement Proxy) ***
  // This measures how much the *vector* has changed, not just the total force magnitude.
  float delta_x = abs(current_x - last_accel_x);
  float delta_y = abs(current_y - last_accel_y);
  float delta_z = abs(current_z - last_accel_z);


  // The magnitude of the change vector (how much the reading jumped)
  float rate_of_change_magnitude = sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z);



  // 5. Detection Logic & Output
  
  // --- A. Fast Movement Check (The new requirement) ---
  if (rate_of_change_magnitude &gt; FAST_MOVEMENT_THRESHOLD) {
    if (!fast_movement_warning_active) {
      Serial.println("\n****************************");
      Serial.print("!!! WARNING: SLOW DOWN !!! ");
      Serial.print("Rate of Change Magnitude: ");
      Serial.print(rate_of_change_magnitude);
      Serial.println(" (Too fast!)");
      Serial.println("****************************\n");
      fast_movement_warning_active = true; // Set flag to prevent spamming
    }
  } else {
    // If the change is small, reset the warning flag
    if (fast_movement_warning_active) {
        Serial.println("\n[INFO] Movement rate stabilized.");
    }
    fast_movement_warning_active = false;
  }



  // --- B. General Movement Check (Original logic) ---
  if (delta_magnitude &gt; MOVEMENT_THRESHOLD) {
    if (!movement_detected_flag) {
      Serial.println("=============================");
      Serial.print("MOVEMENT DETECTED! Delta Magnitude: ");
      Serial.println(delta_magnitude);
      Serial.println("=============================");
      movement_detected_flag = true; // Set flag to prevent spamming
    }
  } else {
    // If the change is small, reset the general movement flag
    if (movement_detected_flag) {
        Serial.println("[INFO] Movement subsided.");
    }
    movement_detected_flag = false;
  }



  // 6. Update state for the next loop iteration
  last_accel_x = current_x;
  last_accel_y = current_y;
  last_accel_z = current_z;



  // Small delay to keep readings stable and prevent overwhelming serial output
  delay(50); 
}

### User
can you combine these two codes so that when i move too fast the esp sends the words "TOO FAST" to the other esp32c3. im doing wireless comms. and using an adxel343

/*
    MASTER SKETCH: Movement Detector Sender (ESP-NOW) - FINAL VERSION
*/



#include &lt;Wire.h&gt; // Required for I2C communication with most sensors
#include &lt;Adafruit_Sensor.h&gt;
#include &lt;Adafruit_ADXL343.h&gt; 
#include &lt;esp_now.h&gt;
#include &lt;WiFi.h&gt;


// ===============================================================
// 1. GLOBAL CONFIGURATION & OBJECTS (Top of the file)
// ===============================================================


// --- Sensor Object Initialization ---
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345); 


// --- Movement Detection Variables ---
const float MOVEMENT_THRESHOLD = 1; // Tune this value! (Delta magnitude threshold)


// Tracking variables for the previous reading (MUST BE GLOBAL)
float last_accel_x = 0.0;
float last_accel_y = 0.0;
float last_accel_z = 0.0;


// State tracking flag (Controls if we print "DETECTED" or "SUBSIDED")
bool movement_detected_flag = false; 



// --- ESP-NOW MAC ADDRESS & STRUCTURES ---
uint8_t broadcastAddress[] = {0x94, 0xa9, 0x90, 0x6c, 0xd5, 0x9c};


typedef struct struct_message {
    char a[32]; // For status text ("Movement detected" or "Movement subsided")
    int b;      // Integer (e.g., scaled reading)
    float c;    // Float (e.g., magnitude or raw float data)
    bool d;     // Boolean (Movement Detected Flag)
} struct_message;


struct_message myData;


esp_now_peer_info_t peerInfo;



// --- SENSOR VARIABLES (Used by the main loop for calculation) ---
float accelX = 0.0, accelY = 0.0, accelZ = 0.0; // Global variables for sensor readings



// ===============================================================
// 2. CALLBACK FUNCTION (MUST BE GLOBAL)
// ===============================================================
void OnDataSent(const wifi_tx_info_t *txInfo, esp_now_send_status_t status) { 
    Serial.print("\r\n[ESP-NOW Status] Last Packet Send Status:\t");
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}



// ===============================================================
// 3. SETUP FUNCTION (Initialization)
// ===============================================================
void setup() {
    // Initialize Serial Monitor
    Serial.begin(115200);
    
    // Set device as a Wi-Fi Station (Required for ESP-NOW)
    WiFi.mode(WIFI_STA);


    // --- Sensor Initialization ---
    Wire.begin(); // Initialize I2C bus for the sensor
    if(!accel.begin()) {
        Serial.println("ERROR: ADXL343 not found! Check wiring.");
    } else {
        accel.setRange(ADXL343_RANGE_16_G);
        Serial.println("ADXL343 Sensor Initialized Successfully.");
    }


    // 1. INITIALIZE ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }


    // 2. REGISTER SEND CALLBACK
    esp_now_register_send_cb(OnDataSent);
    
    // 3. CHANNEL SYNCHRONIZATION (CRITICAL FIX!)
    WiFi.setChannel(1); // &lt;-- Use the channel that works for your setup!



    // 4. REGISTER PEER INFO
    memcpy(peerInfo.peer_addr, broadcastAddress, 6);
    peerInfo.channel = 0;  
    peerInfo.encrypt = false;
    
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
        Serial.println("Failed to add peer");
        return;
    }
    Serial.println("\n=========================================");
    Serial.println("Sender Setup Complete. Ready to transmit.");
    Serial.println("=========================================\n");
}



// ===============================================================
// 4. SENSOR READING FUNCTION (Replaces the simulation)
// ===============================================================
void readAccelerometerData() {
    sensors_event_t event;
    if (accel.getEvent(&event)) { // Check if reading was successful
        float current_x = event.acceleration.x;
        float current_y = event.acceleration.y;
        float current_z = event.acceleration.z;


        // Calculate the magnitude of acceleration (Total force vector)
        float current_magnitude = sqrt(current_x * current_x + current_y * current_y + current_z * current_z);


        // Calculate the change in magnitude since the last reading
        float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
        float delta_magnitude = abs(current_magnitude - last_magnitude);


        // Update the global variables used by the main loop() logic
        accelX = current_x;
        accelY = current_y;
        accelZ = current_z;
        
        // Return the calculated delta magnitude so we can use it in the loop() state machine
        Serial.printf("Sensor Read: X=%.2f, Y=%.2f, Z=%.2f | Delta Mag: %.2f\n", accelX, accelY, accelZ, delta_magnitude);


    } else {
        Serial.println("ERROR reading sensor data!");
    }
}



// ===============================================================
// 5. MAIN LOOP (State Machine & Sending)
// ===============================================================
void loop() {
    // --- STEP A: Read Sensor Data and Calculate Change ---
    // We must capture the delta magnitude here to use it for state detection
    float current_delta_magnitude;
    readAccelerometerData(); 


    // NOTE: Since readAccelerometerData now prints, we rely on its internal logic 
    // to calculate the necessary values. For simplicity in this final merge, 
    // we will re-calculate the delta here based on the global variables updated above.
    float current_magnitude = sqrt(accelX * accelX + accelY * accelY + accelZ * accelZ);
    float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
    current_delta_magnitude = abs(current_magnitude - last_magnitude);



    // --- STEP B: State Change Detection (The core logic) ---
    if (current_delta_magnitude &gt; MOVEMENT_THRESHOLD) {
        if (!movement_detected_flag) {
            // *** TRANSITION: From Still to Moving ***
            Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT DETECTED !!!"); // &lt;-- PRINT ON CHANGE
            Serial.println("========================================\n");


            strcpy(myData.a, "Movement detected"); 
            myData.b = 1;                                     
            myData.c = current_magnitude;                      // Send the actual magnitude
            myData.d = true;                                   



        } else {
             // Already moving: just update payload without printing status text
             strcpy(myData.a, "Movement detected"); 
             myData.b = 1;
             myData.c = current_magnitude;
             myData.d = true;
        }


    } else {
        if (movement_detected_flag) {
            // *** TRANSITION: From Moving to Still ***
            Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT SUBSIDED !!!"); // &lt;-- PRINT ON CHANGE
            Serial.println("========================================\n");


            strcpy(myData.a, "Movement subsided"); 
            myData.b = 0;                                     
            myData.c = current_magnitude;                      // Send the low magnitude
            myData.d = false;                                  
        } else {
             // Still still: just update payload without printing status text
             strcpy(myData.a, "Movement subsided"); 
             myData.b = 0;
             myData.c = current_magnitude;
             myData.d = false;
        }
    }


    // --- STEP C: Send Data (Network Transmission) ---
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    
    if (result == ESP_OK) {
        Serial.println("Data packet sent successfully."); 
    } else {
        Serial.println("ERROR: Failed to send data packet."); 
    }


    // --- STEP D: Update State for Next Cycle & Sensor History ---
    movement_detected_flag = (current_delta_magnitude &gt; MOVEMENT_THRESHOLD); // Set flag based on current detection
    last_accel_x = accelX;
    last_accel_y = accelY;
    last_accel_z = accelZ;


    // Wait for a short period to keep the loop responsive but not overwhelming.
    delay(500); 
}


other code

#include &lt;Wire.h&gt;
#include &lt;Adafruit_Sensor.h&gt;
#include &lt;Adafruit_ADXL343.h&gt;



/* Assign a unique ID to this sensor at the same time */
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345);



// --- Movement Detection Variables ---


// Threshold 1: Detects general movement (Original logic)
const float MOVEMENT_THRESHOLD = 0.8; // Example: Detect movement if magnitude change exceeds 0.8G


// Threshold 2: Detects *fast* movement (New Logic)
// This threshold determines how large the difference between consecutive readings must be 
// to trigger a "slow down" warning. You will need to tune this heavily!
const float FAST_MOVEMENT_THRESHOLD = 1.5; // Example: Trigger if change in acceleration vector magnitude exceeds 1.5G



// Tracking variables for the previous reading (for both general and fast detection)
float last_accel_x = 0.0;
float last_accel_y = 0.0;
float last_accel_z = 0.0;


// Variables to track the state of the alerts
bool movement_detected_flag = false;
bool fast_movement_warning_active = false;



void setup(void)
{
  Serial.begin(9600);
  while (!Serial);
  Serial.println("ADXL343 Movement Detector Initializing..."); Serial.println("");


  /* Initialise the sensor */
  if(!accel.begin())
  {
    Serial.println("Ooops, no ADXL343 detected ... Check your wiring!");
    while(1);
  }


  /* Set the range to whatever is appropriate for your project */
  accel.setRange(ADXL343_RANGE_16_G);



  Serial.println("ADXL343 initialized. Ready to detect movement.");
}



void loop(void)
{
  // 1. Read the current sensor data
  sensors_event_t event;
  accel.getEvent(&event);


  float current_x = event.acceleration.x;
  float current_y = event.acceleration.y;
  float current_z = event.acceleration.z;



  // 2. Calculate the magnitude of acceleration (Total force vector)
  // Magnitude = sqrt(X^2 + Y^2 + Z^2)
  float current_magnitude = sqrt(current_x * current_x + current_y * current_y + current_z * current_z);



  // 3. Calculate the change in magnitude since the last reading (General Movement Proxy)
  float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
  // The difference between current and previous magnitude is a good indicator of change.
  float delta_magnitude = abs(current_magnitude - last_magnitude);



  // 4. *** NEW: Calculate the rate of change (Fast Movement Proxy) ***
  // This measures how much the *vector* has changed, not just the total force magnitude.
  float delta_x = abs(current_x - last_accel_x);
  float delta_y = abs(current_y - last_accel_y);
  float delta_z = abs(current_z - last_accel_z);


  // The magnitude of the change vector (how much the reading jumped)
  float rate_of_change_magnitude = sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z);



  // 5. Detection Logic & Output
  
  // --- A. Fast Movement Check (The new requirement) ---
  if (rate_of_change_magnitude &gt; FAST_MOVEMENT_THRESHOLD) {
    if (!fast_movement_warning_active) {
      Serial.println("\n****************************");
      Serial.print("!!! WARNING: SLOW DOWN !!! ");
      Serial.print("Rate of Change Magnitude: ");
      Serial.print(rate_of_change_magnitude);
      Serial.println(" (Too fast!)");
      Serial.println("****************************\n");
      fast_movement_warning_active = true; // Set flag to prevent spamming
    }
  } else {
    // If the change is small, reset the warning flag
    if (fast_movement_warning_active) {
        Serial.println("\n[INFO] Movement rate stabilized.");
    }
    fast_movement_warning_active = false;
  }



  // --- B. General Movement Check (Original logic) ---
  if (delta_magnitude &gt; MOVEMENT_THRESHOLD) {
    if (!movement_detected_flag) {
      Serial.println("=============================");
      Serial.print("MOVEMENT DETECTED! Delta Magnitude: ");
      Serial.println(delta_magnitude);
      Serial.println("=============================");
      movement_detected_flag = true; // Set flag to prevent spamming
    }
  } else {
    // If the change is small, reset the general movement flag
    if (movement_detected_flag) {
        Serial.println("[INFO] Movement subsided.");
    }
    movement_detected_flag = false;
  }



  // 6. Update state for the next loop iteration
  last_accel_x = current_x;
  last_accel_y = current_y;
  last_accel_z = current_z;



  // Small delay to keep readings stable and prevent overwhelming serial output
  delay(50); 
}

### Assistant
This is a complex merge because you are combining two different communication paradigms:

1.  **Code Set 1 (The Sender):** Uses **ESP-NOW** for wireless transmission, relies on structured data (`struct_message`), and has a specific state machine structure.
2.  **Code Set 2 & 3 (The Logic):** Use standard `void setup()`/`void loop()` structure, calculate two types of movement thresholds ($\text{MOVEMENT\_THRESHOLD}$ and $\text{FAST\_MOVEMENT\_THRESHOLD}$), and print status messages to the Serial Monitor.

To combine them correctly, we need to:
1.  Keep all the **ESP-NOW** networking code from Code Set 1 (the Sender).
2.  Integrate the **Fast Movement Detection Logic** ($\text{rate\_of\_change\_magnitude}$) from Code Sets 2/3 into the main loop of Code Set 1.
3.  Modify the payload structure (`myData`) to send "TOO FAST" when the fast threshold is crossed, while still handling general movement detection.

Here is the combined and refactored code for your **MASTER SKETCH (Sender)**.

### Combined ESP-NOW Sender Sketch

```cpp
/*
    COMBINED MASTER SKETCH: Movement Detector Sender (ESP-NOW)
    Combines General Movement Detection with Fast Movement Warning via ESP-NOW.
*/

#include &lt;Wire.h&gt; // Required for I2C communication with most sensors
#include &lt;Adafruit_Sensor.h&gt;
#include &lt;Adafruit_ADXL343.h&gt; 
#include &lt;esp_now.h&gt;
#include &lt;WiFi.h&gt;

// ===============================================================
// 1. GLOBAL CONFIGURATION & OBJECTS (Top of the file)
// ===============================================================

// --- Sensor Object Initialization ---
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345); 

// --- Movement Detection Variables ---
// Threshold for general movement detection (from Code Set 1)
const float MOVEMENT_THRESHOLD = 0.8; // Using the lower value from the second set as a good default
// Threshold for fast movement warning (from Code Sets 2/3)
const float FAST_MOVEMENT_THRESHOLD = 1.5; // Tune this heavily!

// Tracking variables for the previous reading (MUST BE GLOBAL)
float last_accel_x = 0.0;
float last_accel_y = 0.0;
float last_accel_z = 0.0;

// State tracking flags
bool general_movement_detected_flag = false; // Tracks if movement is generally happening
bool fast_movement_warning_active = false;   // Tracks if the "TOO FAST" warning was recently sent

// --- ESP-NOW MAC ADDRESS & STRUCTURES ---
uint8_t broadcastAddress[] = {0x94, 0xa9, 0x90, 0x6c, 0xd5, 0x9c};

typedef struct struct_message {
    char a[32]; // Status text: "Movement detected", "TOO FAST", or "Movement subsided"
    int b;       // Integer payload (e.g., general movement flag)
    float c;     // Float payload (e.g., magnitude or rate of change)
    bool d;      // Boolean flag (True if any significant event occurred)
} struct_message;

struct_message myData;

esp_now_peer_info_t peerInfo;

// --- SENSOR VARIABLES (Used by the main loop for calculation) ---
float accelX = 0.0, accelY = 0.0, accelZ = 0.0; // Global variables for sensor readings


// ===============================================================
// 2. CALLBACK FUNCTION (MUST BE GLOBAL)
// ===============================================================
void OnDataSent(const wifi_tx_info_t *txInfo, esp_now_send_status_t status) { 
    Serial.print("\r\n[ESP-NOW Status] Last Packet Send Status:\t");
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}


// ===============================================================
// 3. SETUP FUNCTION (Initialization)
// ===============================================================
void setup() {
    // Initialize Serial Monitor
    Serial.begin(115200);
    
    // Set device as a Wi-Fi Station (Required for ESP-NOW)
    WiFi.mode(WIFI_STA);

    // --- Sensor Initialization ---
    Wire.begin(); // Initialize I2C bus for the sensor
    if(!accel.begin()) {
        Serial.println("ERROR: ADXL343 not found! Check wiring.");
    } else {
        accel.setRange(ADXL343_RANGE_16_G);
        Serial.println("ADXL343 Sensor Initialized Successfully.");
    }

    // 1. INITIALIZE ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }

    // 2. REGISTER SEND CALLBACK
    esp_now_register_send_cb(OnDataSent);
    
    // 3. CHANNEL SYNCHRONIZATION (CRITICAL FIX!)
    WiFi.setChannel(1); // &lt;-- Use the channel that works for your setup!

    // 4. REGISTER PEER INFO
    memcpy(peerInfo.peer_addr, broadcastAddress, 6);
    peerInfo.channel = 0;  
    peerInfo.encrypt = false;
    
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
        Serial.println("Failed to add peer");
        return;
    }
    Serial.println("\n=========================================");
    Serial.println("Sender Setup Complete. Ready to transmit.");
    Serial.println("=========================================\n");
}


// ===============================================================
// 4. SENSOR READING FUNCTION (Reads and calculates all necessary metrics)
// ===============================================================
void readAccelerometerData() {
    sensors_event_t event;
    if (accel.getEvent(&event)) { // Check if reading was successful
        float current_x = event.acceleration.x;
        float current_y = event.acceleration.y;
        float current_z = event.acceleration.z;

        // 1. Calculate Total Magnitude (For general movement)
        float current_magnitude = sqrt(current_x * current_x + current_y * current_y + current_z * current_z);

        // 2. Calculate General Delta Magnitude (Change in total force vector magnitude)
        float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
        float delta_magnitude = abs(current_magnitude - last_magnitude);

        // 3. Calculate Rate of Change (Vector jump magnitude)
        float delta_x = abs(current_x - last_accel_x);
        float delta_y = abs(current_y - last_accel_y);
        float delta_z = abs(current_z - last_accel_z);
        float rate_of_change_magnitude = sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z);

        // Update the global variables used by the main loop() logic
        accelX = current_x;
        accelY = current_y;
        accelZ = current_z;
        
        Serial.printf("Sensor Read: X=%.2f, Y=%.2f, Z=%.2f | Delta Mag: %.2f | Rate of Change: %.2f\n", 
                      accelX, accelY, accelZ, delta_magnitude, rate_of_change_magnitude);

    } else {
        Serial.println("ERROR reading sensor data!");
    }
}


// ===============================================================
// 5. MAIN LOOP (State Machine & Sending)
// ===============================================================
void loop() {
    // --- STEP A: Read Sensor Data and Calculate Change Metrics ---
    readAccelerometerData(); 

    // Recalculate metrics based on the updated global variables for clarity in logic block
    float current_magnitude = sqrt(accelX * accelX + accelY * accelY + accelZ * accelZ);
    float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
    float current_delta_magnitude = abs(current_magnitude - last_magnitude);

    // Rate of change calculation (re-run for the logic block)
    float delta_x = abs(accelX - last_accel_x);
    float delta_y = abs(accelY - last_accel_y);
    float delta_z = abs(accelZ - last_accel_z);
    float rate_of_change_magnitude = sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z);


    // --- STEP B: Determine the Primary Alert State (Priority Order) ---
    String status_text = "Movement subsided"; // Default state
    bool send_alert = false;
    int payload_b = 0;

    // 1. Check for FAST MOVEMENT (Highest Priority)
    if (rate_of_change_magnitude &gt; FAST_MOVEMENT_THRESHOLD) {
        if (!fast_movement_warning_active) {
            status_text = "TOO FAST";
            send_alert = true;
            payload_b = 2; // Use a unique code for TOO FAST
            Serial.println("\n****************************");
            Serial.print("!!! WARNING: SLOW DOWN !!! ");
            Serial.print("Rate of Change Magnitude: ");
            Serial.print(rate_of_change_magnitude);
            Serial.println(" (Too fast!)");
            Serial.println("****************************\n");
        } else {
             // If already active, just update the payload but don't print status text again
             status_text = "TOO FAST";
             send_alert = true;
             payload_b = 2;
        }
    } 
    // 2. Check for GENERAL MOVEMENT (Medium Priority)
    else if (current_delta_magnitude &gt; MOVEMENT_THRESHOLD) {
        if (!general_movement_detected_flag) {
            status_text = "Movement detected";
            send_alert = true;
            payload_b = 1; // Code for general movement
            Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT DETECTED !!!"); 
            Serial.println("========================================\n");
        } else {
             // Already moving, just update payload
             status_text = "Movement detected";
             send_alert = true;
             payload_b = 1;
        }
    } 
    // 3. Still State (Lowest Priority)
    else {
        if (general_movement_detected_flag || fast_movement_warning_active) {
            status_text = "Movement subsided";
            send_alert = true; // Send a packet to confirm the state change
            payload_b = 0;
             Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT SUBSIDED !!!"); 
            Serial.println("========================================\n");
        } else {
            // If nothing changed and no alert was active, we might skip sending to save bandwidth
            status_text = "Movement subsided";
            send_alert = false; // Skip transmission if state hasn't meaningfully changed
        }
    }

    // --- STEP C: Prepare Payload for Transmission ---
    strcpy(myData.a, status_text.c_str()); 
    myData.b = payload_b;
    myData.c = current_magnitude; // Always send the current magnitude as a key metric
    myData.d = (send_alert);     // Set flag based on whether we decided to send an alert

    // --- STEP D: Send Data (Network Transmission) ---
    if (send_alert) {
        esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
        
        if (result == ESP_OK) {
            Serial.println("Data packet sent successfully."); 
        } else {
            Serial.println("ERROR: Failed to send data packet."); 
        }
    } else {
         // Optional: Print a message if we are intentionally skipping transmission
         // Serial.println("No significant state change detected; skipping transmission.");
    }


    // --- STEP E: Update State for Next Cycle & Sensor History ---
    general_movement_detected_flag = (current_delta_magnitude &gt; MOVEMENT_THRESHOLD); 
    fast_movement_warning_active = (rate_of_change_magnitude &gt; FAST_MOVEMENT_THRESHOLD);

    last_accel_x = accelX;
    last_accel_y = accelY;
    last_accel_z = accelZ;


    // Wait for a short period. Reduced delay to capture fast changes better.
    delay(100); 
}
```

### Key Changes and How It Works:

1.  **Combined Logic:** The `loop()` function now executes the logic from both sets of code sequentially, prioritizing the fastest alert first.
2.  **State Management:** We use two flags:
    *   `general_movement_detected_flag`: Handles the standard "Movement Detected" vs. "Subsided."
    *   `fast_movement_warning_active`: Handles the new "TOO FAST" warning, preventing spamming of this specific alert.
3.  **Priority System:** The logic now checks in order: **Fast $\rightarrow$ General $\rightarrow$ Still**. If a fast movement is detected, it overrides any general movement status for that cycle.
4.  **Payload Update:**
    *   If the fast threshold is crossed, `myData.a` is set to `"TOO FAST"`, and `payload_b` is set to `2`.
    *   The structure of sending data remains consistent with your original ESP-NOW setup.
5.  **Sensor Reading Function (`readAccelerometerData`):** This function was updated to calculate *all three* necessary metrics ($\text{current\_magnitude}$, $\text{delta\_magnitude}$, and $\text{rate\_of\_change\_magnitude}$) in one go, making the `loop()` cleaner.

### **Crucial Next Steps (Tuning)**

This code is a structural merge. It will only work correctly if you tune these constants based on your physical setup:

1.  **`MOVEMENT_THRESHOLD`**: Tune this for general movement detection (e.g., walking vs. resting).
2.  **`FAST_MOVEMENT_THRESHOLD`**: **This is the most critical value.** You must test this extensively. If it's too low, you'll get false positives when moving normally. If it's too high, you won't detect fast movements.
3.  **`delay(100)`:** I reduced the delay from 500ms to 100ms. For detecting *fast* changes, a shorter loop cycle is necessary for accurate readings.

### User
thank you it works

### Assistant
That's fantastic news! I'm very glad the combined code structure worked for your needs.

Since the core functionality is working, here are a few **advanced tips and considerations** to help you refine or expand this system further in the future:

### 💡 Future Refinement Tips

#### 1. Payload Differentiation (For the Receiver)
Currently, all alerts send data via `myData`. If your receiving ESP32C3 needs to know *which* alert triggered it, you can use the integer payload `b` more robustly:

| Value of `myData.b` | Meaning | Action on Receiver |
| :--- | :--- | :--- |
| **0** | Movement Subsided (Idle) | Reset any local alarms/timers. |
| **1** | General Movement Detected | Trigger a "Warning" state (e.g., flashing an LED). |
| **2** | TOO FAST Warning | Trigger the highest priority alarm (e.g., siren sound, immediate action). |

#### 2. Debouncing and State Persistence
The current code uses flags (`fast_movement_warning_active`) to prevent spamming alerts when the condition remains true for several cycles. This is good! If you find that the "TOO FAST" warning needs to persist even if the reading briefly drops below the threshold (e.g., a quick jerk followed by a slight pause), you might need a **timer/counter** instead of just a boolean flag.

#### 3. Power Management
Since this is an embedded system, power consumption matters:
*   **Sleep Mode:** If the device only needs to monitor when stationary for long periods, consider putting the ESP32 into **Deep Sleep**. You would wake it up on a timer or perhaps use an external interrupt (like a simple PIR sensor) to wake it up periodically.

#### 4. Calibration and Baseline
The ADXL343 measures acceleration relative to gravity ($\approx 1G$ when still). When you are stationary, the readings should hover around $(0, 0, 1)$ or similar, depending on how you mount it. If your baseline reading drifts over time (due to temperature changes or mounting shifts), you might need a routine in `setup()` to read the average values for several seconds and use those as your *true* zero-point offset instead of assuming $(0, 0, 1)$.

Happy building! Let me know if any other challenges pop up.
