/* CallButton_Caller_ESP8266_NOW
 * CLClab306 01/31/24
 * Code adapted from:
 * https://RandomNerdTutorials.com/esp-now-two-way-communication-esp8266-nodemcu/
 * 
 * CALL button on GPIO5 (D1)
 * WS2812B D-in on GPIO12 (D6)
 * REMEMBER to Enter MAC address of CallButton_BASE 
*/

////////// ******REPLACE WITH CallButton_BASE MAC Address***** //////////
uint8_t broadcastAddress[] = {0x48, 0xE7, 0x29, 0x58, 0x96, 0x2A}; // D1 mini pro

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

#define callBase  5             // D1 = GPIO5 (pushbutton input pin)
#define DATA_PIN 12             // D6 = GPIO12 neopixel D-In (neopixel output pin)
#define NUM_LEDS 1

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

const int callBUTTON = 1;       // callBUTTON #1

int clrFLG = 0;
int newCALL = 0;
int numBASEs = 0;
int DATA = 0;

uint8_t all_cont[1]; uint8_t encrypt_cont[1];

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

// sends CALL command to CallButton_Base when callBase Button goes LOW 
ICACHE_RAM_ATTR void sendCall() 
  {
    detachInterrupt(digitalPinToInterrupt(callBase));     // avoid switch bounce
    esp_now_send(broadcastAddress, (uint8_t *) &callBUTTON, sizeof(callBUTTON));
    Serial.print("CALL Button #"); Serial.print(callBUTTON);
    Serial.println(" sent to CallButton_BASE");           // call BASE
  }

void setup()
  {
    Serial.begin(115200);
    while (!Serial);
      {
        //wait for serial
      }
    Serial.println(); Serial.println();
    Serial.println(F("Callbutton_Caller_ESP8266_NOW"));
    pixels.setBrightness(255);
    pixels.begin();
    pinMode(callBase,INPUT_PULLUP);  
    setupESP_NOW();                   // Set ESP-NOW Role
    sendCall();                      // Power-ON automatically sends Call to Base
  }

void loop()
  {
    if (newCALL == 1)
      {
        for(int x = 0; x < 5; x++)
          {
            pixels.setPixelColor(0, pixels.Color(0,0,0)); // 5 Red flashes = Call Received by BASE
            pixels.show();       
            delay(150);
            pixels.setPixelColor(0, pixels.Color(255,0,0)); // pixel stays Red until cleared by Base
            pixels.show();
            delay(150);
          } 
        newCALL = 0; 
      } 
    if (clrFLG == 1)
      {
        delay(50);
        clrFLG = 0;
        for(int x = 0; x < 5; x++)
          {
            pixels.setPixelColor(0, pixels.Color(0,255,0)); // 5 Green flashes = Cleared by BASE
            pixels.show();       
            delay(150);
            pixels.setPixelColor(0, pixels.Color(0,0,0));   
            pixels.show();
            delay(150);
          }
      }
  }

// 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(" = "); Serial.println(DATA);
    if(DATA == 555)           // BASE received new call
      {
        Serial.println("CallButton_Base received Call");
        newCALL = 1;
      }
    else if(DATA == 999)      // CLEAR Command from BASE
      {
        Serial.println("CallButton_Base sent Clear Command");
        clrFLG = 1;
        attachInterrupt(digitalPinToInterrupt(callBase), sendCall, FALLING);    
      }
    else
      {
        Serial.println("Incorrect feedback from CallButton_BASE");
        Serial.println( );
        pixels.setPixelColor(0, pixels.Color(255,255,0)); // Yellow = feeback failure
        pixels.show();
        attachInterrupt(digitalPinToInterrupt(callBase), sendCall, FALLING); 
      }
  }

// Callback when data is sent
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) 
  {
    if (sendStatus == 0)    Serial.println("Request delivered");
    else  
      {
        Serial.println("Request FAILED");
        pixels.setPixelColor(0, pixels.Color(255,255,0)); // Yellow = send failure
        pixels.show();
      }
  }


