// CallButton_BASE_ESP8266_NOW
// CLClab306 1/31/24
// Code adapted from:
// https://RandomNerdTutorials.com/esp-now-two-way-communication-esp8266-nodemcu/
//
// CLEAR button on GPIO5 (D1)
// Buzzer on GPIO13 (D7)
// WS2812B D-in on GPIO12 (D6)
// REMEMBER to Enter MAC addresses of CallButton_Caller 

////////// *****REPLACE WITH CallButton_Caller MAC Address***** //////////
uint8_t broadcastAddress[] = {0x48, 0xE7, 0x29, 0x58, 0xA9, 0x94}; // D1 mini pro

#include <ESP8266WiFi.h>
#include <espnow.h>
#include <Adafruit_NeoPixel.h>

#define clearCall 5             // D1 = GPIO5 (pushbutton input)
#define buzzer 13               // D7 = GPIO13 (buzzer output)
#define DATA_PIN 12             // D6 = GPIO12 neopixel D-In (neopixel output)
#define NUM_LEDS 1

// Define the neopixel array
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUM_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800);

int DATA = 0;
int callFLG = 0;

// sends Clear command to CallButton_Caller when clearCall Button goes LOW 
ICACHE_RAM_ATTR void sendClearCaller() 
  {
    detachInterrupt(digitalPinToInterrupt(clearCall)); // avoid switch bounce
    clear();
  }

void clear()
  {
    pixels.setPixelColor(0, pixels.Color(0,0,0));     // LED off
    pixels.show();
    digitalWrite(buzzer, LOW);                        // buzzer off
    callFLG = 0;
    DATA = 999;
    esp_now_send(broadcastAddress, (uint8_t *) &DATA, sizeof(DATA));
    Serial.println("Clear command sent to CallButton_Caller");
    attachInterrupt(digitalPinToInterrupt(clearCall), sendClearCaller, FALLING);
  }

void setup()
  {
    Serial.begin(115200);
    while (! Serial); delay(10);
    Serial.println(); Serial.println();
    Serial.println(F("CallButton_BASE_ESP8266_NOW"));
    pixels.setBrightness(255);
    pixels.begin();
    pinMode(buzzer,OUTPUT);
    pinMode(clearCall,INPUT_PULLUP);   
    for(int x = 0; x < 5; x++)
      {
        pixels.setPixelColor(0, pixels.Color(0,255,0)); // 5 Green flashes = Ready
        pixels.show();       
        delay(100);
        pixels.setPixelColor(0, pixels.Color(0,0,0));   
        pixels.show();   
        delay(100);
      }
    DATA = 0;
    setupESP_NOW();       // Set ESP-NOW Role
    delay(500);
    clear(); 
  }

void loop()
  {
    if(callFLG == 1)
      {
        // flashing RED+buzzer when called
        pixels.setPixelColor(0, pixels.Color(255,0,0));     
        pixels.show();
        digitalWrite(buzzer, HIGH);
        delay(1000);
        pixels.setPixelColor(0, pixels.Color(0,0,0));     
        pixels.show();
        digitalWrite(buzzer, LOW);
        delay(500);
      }
  }

// Callback when data is sent
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) 
  {
    // Serial.print("Send Status: ");
    if (sendStatus == 0)  
      {
        Serial.println("Delivery success"); Serial.println();
      }
    else  
      {
        Serial.println("Delivery FAIL");
        pixels.setPixelColor(0, pixels.Color(255,255,0)); // Yellow = send failure
        pixels.show();  
      }
  }

// Callback when incoming data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) 
  {
    memcpy(&DATA, incomingData, sizeof(DATA));
    Serial.print("Bytes received: "); Serial.println(len);
    Serial.print("CallButton_Caller #"); Serial.println(DATA);
    if(DATA == 1)                                           // Call request?
      {
        DATA = 555; 
        esp_now_send(broadcastAddress, (uint8_t *) &DATA, sizeof(DATA));
        Serial.println("Sent feedback to CallButton_Caller");
        callFLG = 1;
        delay(100);
      }
  }

void setupESP_NOW()
  {
    // Set device as a Wi-Fi Station
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();  
    // Init ESP-NOW
    if (esp_now_init() != 0) 
      {
        Serial.println("Error initializing ESP-NOW");
        return;
      }
    // Set ESP-NOW Role
    esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
    // Register for a callback function that will be called when data is received
    esp_now_register_recv_cb(OnDataRecv);
    esp_now_register_send_cb(OnDataSent);
    // Register peer
    esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_COMBO, 1, NULL, 0);
    Serial.println("ESP-NOW setup done.");
    delay(500);
  }
