/*
  Smart Dog Play
  This code is part of the Smart Dog Play 2-codes CPX.
  This is the code for the main CPX that is used as the Smart Dog Play.
  The Smart Dog Play works with CPX, Blynk and Integromat.
  In this code, the functions for the CPX are implemented: control of lights, beeper and not at home mode and IR.
  LIGHTS - You can turn on the lights of the CPX and it changes everytime it moves.
  BEEPER - You can turn on the beeper sound.
  NOT AT HOME - You can turn on the not at home mode so you can get notification whenever the dog is on the couch.
  IR - With a remote controller, whenever you dog press on a button, it plays I WANT sound.
*/

#define BLYNK_PRINT SerialUSB
#define BLYNK_DEBUG SerialUSB
#define EspSerial Serial1
#define ESP8266_BAUD 9600
#include <ESP8266_Lib.h>
#include <BlynkSimpleShieldEsp8266.h>
#include <Adafruit_CircuitPlayground.h>
#include <Wire.h>
#include <SPI.h>

ESP8266 wifi(&EspSerial);
char auth[] = "**"; // <<<< FILL YOUR AUTH. KEY HERE
char ssid[] = "**"; // <<<< FILL HERE YOUR WIFI NETWORK'S NAME HERE
char pass[] = "**"; // <<<< FILL HERE YOUR WIFI NETWORK'S PASSWORD
bool beeperOn = false;
bool lightsOn = false;
bool onCouch = false;
bool notHomeOn = false;
uint8_t remoteProtocol = 0; // <<<< FILL YOUR REMOTE CONTROLLER'S PROTOCOL
uint32_t remoteValue = 0xC0C01FE; // <<<< FILL YOUR REMOTE CONTROLLER'S VALUE
uint16_t remoteBits = 32; // <<<< FILL YOUR REMOTE CONTROLLER'S BITS
uint8_t IR_protocol;
uint32_t IR_value;
uint16_t IR_bits;
const uint8_t spNOT[]       PROGMEM = {0xA1,0xCD,0x9A,0xA3,0x71,0xEC,0xA6,0x36,0x1B,0xCA,0xA4,0x56,0x9A,0xDA,0x6A,0xB1,0x4D,0x4B,0x73,0x6E,0x4F,0xDD,0x9C,0x7B,0x91,0xA5,0x3D,0x75,0x75,0xD3,0xE6,0x9C,0xFA,0x34,0xC5,0xEC,0xB8,0x4B,0xE6,0xD3,0x14,0xB3,0x6B,0xAE,0x69,0x4E,0x5D,0xCC,0x4E,0x98,0x64,0x3E,0x75,0x71,0x33,0xE6,0x9C,0xA9,0x95,0x39,0x44,0xB9,0x48,0x23,0x53,0x64,0xB7,0xE9,0xE2,0x19,0x51,0x2B,0x82,0xBB,0x88,0xC8,0x06,0x60,0xC0,0x15,0x69,0x1C,0x40,0x40,0xF1,0xA9,0xFF,0x75,0x79,0x39};
const uint8_t spWANT[]      PROGMEM = {0xAA,0x24,0xBE,0x7D,0x34,0x6C,0x9B,0x9C,0xE6,0xD1,0xF0,0x68,0x58,0xB2,0x80,0x3F,0xDD,0xD4,0xED,0x88,0x23,0xBD,0x6A,0x53,0xBE,0x27,0xCA,0x7C,0xB3,0x4C,0xF5,0x9C,0x28,0xD9,0x2F,0x57,0xF3,0x7C,0xE2,0x94,0xAE,0x5C,0x2D,0xD5,0x29,0xB2,0xDF,0x18,0xD6,0x64,0xBB,0x2E,0x7D,0x56,0x66,0xCE,0x96,0x3B,0x8E,0x64,0x16,0xCA,0xDD,0x45,0x64,0x03,0x80,0x02,0xAE,0x48,0xD3,0x00,0x02,0x9A,0x6F,0xFC,0x65,0x41,0x75};
const uint8_t spI[]         PROGMEM = {0x2B,0x2B,0xA5,0x3A,0xCD,0x9B,0x9C,0xB4,0x9A,0x8B,0x08,0x5B,0xB4,0x92,0xE2,0xDF,0x3D,0xBD,0xE6,0x89,0x4B,0x7C,0xB7,0x88,0x98,0x27,0x2D,0xFE,0xC3,0x22,0x6A,0x9E,0xB4,0xF8,0x0F,0xF7,0x68,0x78,0xB2,0x6A,0x3E,0x23,0x6C,0xE5,0xA9,0x9B,0xBA,0x8C,0xD4,0xD6,0xA7,0x6E,0xFA,0x32,0x4A,0x57,0x9F,0xB1,0xF9,0x89,0x48,0x5B,0x73,0xA6,0x16,0xCB,0x33,0x6C,0xF1,0x5A,0x7B,0x0E,0x8F,0xB0,0xDA,0x63,0x6D,0x51,0x3C,0xB2,0x16,0xB7,0xAD,0x79,0xD5,0xEC,0x9A,0x53,0xB6,0x9E,0x44,0x62,0xBB,0x4E,0xDA,0xBA,0x63,0xCD,0x99,0xCA,0x69,0xED,0x8E,0x2C,0x27,0xE5,0xFC,0x19,0x41,0x71,0x51,0x19,0x19,0x49};

void setup() {
  // Enables the Blynk's buttons
  CircuitPlayground.begin();
  SerialUSB.begin(9600);
  EspSerial.begin(ESP8266_BAUD);
  delay(10);
  Blynk.begin(auth, wifi, ssid, pass);
  CircuitPlayground.irReceiver.enableIRIn();
  Blynk.virtualWrite(V1, LOW);
  Blynk.virtualWrite(V2, LOW);
  Blynk.virtualWrite(V3, LOW);
  Blynk.setProperty(V1, "offLabel", "ACTIVE BEEPER");
  Blynk.setProperty(V1, "onLabel", "STOP BEEPER");
  Blynk.setProperty(V2, "offLabel", "ACTIVE LIGHTS");
  Blynk.setProperty(V2, "onLabel", "STOP LIGHTS");
  Blynk.setProperty(V3, "offLabel", "ACTIVE NOT AT HOME");
  Blynk.setProperty(V3, "onLabel", "STOP NOT AT HOME");
}

void loop() {
  Blynk.run();
  checkYChange(); // LIGHTS
  checkIR(); // IR
  if (beeperOn) { // BEEPER
    beeper();
  }
  if (notHomeOn) { // NOT AT HOME MODE
    checkCouch();
    delay(100);
  }
}

// Checks if there is a drastic change in the Y axis and changes the color of the lights
void checkYChange() {
  if (lightsOn) {
    float prev = CircuitPlayground.motionY();
    delay(100);
    if (CircuitPlayground.motionY() - prev > 1) {
      randomColor();
    }
  }
}

// Checks the signal of the IR remote controller, and if it receives a signal, activates "I WANT" sound
void checkIR() {
  // Check for IR input
  if (CircuitPlayground.irReceiver.getResults()) {
    //attempt to decode it
    if (CircuitPlayground.irDecoder.decode()) {
        IR_protocol=CircuitPlayground.irDecoder.protocolNum;
        IR_value= CircuitPlayground.irDecoder.value;
        IR_bits= CircuitPlayground.irDecoder.bits;
        if (IR_protocol == remoteProtocol && IR_value == remoteValue && IR_bits == remoteBits) {
          CircuitPlayground.speaker.set(255);
          CircuitPlayground.speaker.say(spI);
          CircuitPlayground.speaker.say(spWANT);
          delay(500);
        }
    }   
    CircuitPlayground.irReceiver.enableIRIn();
  }
}

// Activates the beeper sound
void beeper() {
  CircuitPlayground.speaker.set(255);
  CircuitPlayground.playTone(392.00, 75);
  delay(100);
}

// Checks if the dog is on the couch, and if so, activates a "NOT" sound and notifies via Blynk
void checkCouch() {
  if (!onCouch) {
    float prev = CircuitPlayground.motionX();
    delay(100);
    // If it senses a drastic change with the X axis
    if (CircuitPlayground.motionX() - prev > 1) {
      CircuitPlayground.speaker.set(255);
      for (int i = 0; i < 3; i++)
      {
        CircuitPlayground.speaker.say(spNOT);
        delay(500);
      }
      // Sends a notification via Blynk
      Blynk.notify("Your dog is on the couch!");
      onCouch = true;
    }
  }
}

// Generates a random color for the lights
void randomColor() {
  int rand1 = (rand() % 255);
  int rand2 = (rand() % 255);
  int rand3 = (rand() % 255);
  for (int i = 0; i < 10; i++) {
      CircuitPlayground.setPixelColor(i, rand1, rand2, rand3);
  }
}

// BLYNK: V1 for BEEPER
BLYNK_WRITE(V1) {
  int button = param.asInt();
  if (button == 1) {
    beeperOn = true;
  }

  if (button == 0) {
    beeperOn = false;
  }

  Serial.println(button);
}

// BLYNK: V2 for LIGHTS
BLYNK_WRITE(V2) {
  int button = param.asInt();
  if (button == 1) {
    lightsOn = true;
    for (int i = 0; i < 10; i++) {
      CircuitPlayground.setPixelColor(i, 0x33FF5D);
    }
  }

  if (button == 0) {
    lightsOn = false;
    CircuitPlayground.clearPixels();
  }
}

// BLYNK: V3 for NOT AT HOME
BLYNK_WRITE(V3) {
  int button = param.asInt();
  if (button == 1) {
    notHomeOn = true;
  }

  if (button == 0) {
    notHomeOn = false;
    onCouch = false;
  }
}
