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


#include <Wire.h> // Required for I2C communication with most sensors
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL343.h> 
#include <esp_now.h>
#include <WiFi.h>

// ===============================================================
// 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); // <-- 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 > MOVEMENT_THRESHOLD) {
        if (!movement_detected_flag) {
            // *** TRANSITION: From Still to Moving ***
            Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT DETECTED !!!"); // <-- 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 !!!"); // <-- 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 > 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); 
}
