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


#include <Adafruit_ADXL343.h> // Include the necessary library header
#include <esp_now.h>
#include <WiFi.h>


// --- GLOBAL VARIABLES & CONFIGURATION ---


// *** CRITICAL: REPLACE THIS WITH THE RECEIVER'S ACTUAL MAC ADDRESS ***
uint8_t broadcastAddress[] = {0x94, 0xa9, 0x90, 0x6c, 0xd5, 0x9c};


// Structure definition (MUST MATCH RECEIVER)
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 (MUST BE DECLARED GLOBALLY) ---
float accelX = 0.0, accelY = 0.0, accelZ = 0.0; // Global variables for sensor readings
const float MOVEMENT_THRESHOLD = 8; // Tune this value!


// --- STATE MANAGEMENT VARIABLES (For tracking movement state) ---
bool wasMovingLastCycle = false;



// 3. 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");
}


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

    Serial.println("--- Initializing Sender ---");

    // 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("Sender Setup Complete. Ready to transmit.");
}


void loop() {
    // 1. Read Sensor Data (This function must be implemented with your ADXL343 calls)
    readAccelerometerData(); // This function reads the sensor and populates X, Y, Z

    // 2. Calculate Movement Magnitude
    float magnitude = sqrt(accelX * accelX + accelY * accelY + accelZ * accelZ);

    // 3. Check Threshold (THE DECISION POINT)
    bool isCurrentlyMoving = (magnitude > MOVEMENT_THRESHOLD);


    if (isCurrentlyMoving && !wasMovingLastCycle) {
        // --- TRANSITION: From Still to Moving ---
        Serial.println("\n========================================");
        // *** THIS PRINTS TO THE SENDER'S SERIAL MONITOR ***
        Serial.println("!!! MOVEMENT DETECTED !!!"); 
        Serial.println("========================================\n");

        // Populate the structure with "Movement detected"
        strcpy(myData.a, "Movement detected"); 
        myData.b = 1;                                     // Set a dummy value
        myData.c = magnitude;                              // Send the actual calculated magnitude as float C
        myData.d = true;                                   // Set boolean flag to TRUE


    } else if (!isCurrentlyMoving && wasMovingLastCycle) {
        // --- TRANSITION: From Moving to Still ---
        Serial.println("\n========================================");
        // *** THIS PRINTS TO THE SENDER'S SERIAL MONITOR ***
        Serial.println("!!! MOVEMENT SUBSIDED !!!"); 
        Serial.println("========================================\n");

        // Populate the structure with "Movement subsided"
        strcpy(myData.a, "Movement subsided"); 
        myData.b = 0;                                     // Set a dummy value (e.g., 0)
        myData.c = magnitude;                              // Send the current low magnitude
        myData.d = false;                                  // Set boolean flag to FALSE


    } else {
        // --- CONTINUOUS STATE: No state change, just update data and send ---
        // We still need to prepare the message for sending even if the status text doesn't change.
        if (isCurrentlyMoving) {
            strcpy(myData.a, "Movement detected"); 
            myData.b = 1;
            myData.c = magnitude;
            myData.d = true;
        } else {
            strcpy(myData.a, "Movement subsided"); // Keep sending the 'subsided' status if still below threshold
            myData.b = 0;
            myData.c = magnitude;
            myData.d = false;
        }
    }


    // 4. Send Data (Send on every loop cycle to keep the receiver updated)
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    
    if (result == ESP_OK) {
        Serial.println("Data packet sent successfully."); // Log successful transmission attempt
    } else {
        Serial.println("ERROR: Failed to send data packet."); // Log failure
    }


    // 5. Update State for Next Cycle
    wasMovingLastCycle = isCurrentlyMoving;

    delay(100); // Check for movement every half second
}


/* =============================================================== */
/* !!! ACTION REQUIRED: REPLACE THIS WITH YOUR ADXL343 LIBRARY CALLS !!! */
void readAccelerometerData() {
    // --- TEMPORARY SIMULATION FOR TESTING THE NETWORK LINK ONLY ---
    static unsigned long last_read_time = 0;
    if (millis() - last_read_time > 100) { 
        // Simulate random movement for testing the state change logic
        float random_factor = sin(millis() / 500.0); // Creates a smooth wave pattern
        accelX = cos(millis() / 300.0) * 2 + (random() % 100 - 50) / 10.0; // Oscillates around 0 with noise
        accelY = sin(millis() / 400.0) * 1.5 + (random() % 100 - 50) / 10.0;
        accelZ = 1.0 + cos(millis() / 600.0) * 0.5 + (random() % 100 - 50) / 10.0; // Keep Z near 1G baseline
        last_read_time = millis();
    }
    // --- END SIMULATION ---

    Serial.printf("Sensor Read: X=%.2f, Y=%.2f, Z=%.2f | Magnitude: %.2f\n", accelX, accelY, accelZ, sqrt(accelX * accelX + accelY * accelY + accelZ * accelZ));
}
