Back to Parent

/*   ___ _                   _
  / __| |_  ___ ___ _ _ __| |
 | (__| ' \/ -_) -_) '_(_-<_|
  \___|_||_\___\___|_| /__(_)
*/

#include "neopixel.h"
#include <math.h>

// IMPORTANT: Set pixel COUNT, PIN and TYPE
#define PIXEL_PIN D0
#define PIXEL_COUNT 32
#define PIXEL_TYPE WS2812
/* | __| \| |_   _| __| _ \  / __| |    /_\ / __/ __|
   | _|| .` | | | | _||   / | (_ | |__ / _ \\__ \__ \
   |___|_|\_| |_| |___|_|_\  \___|____/_/ \_\___/___/
*/
#define glassID 1

Adafruit_NeoPixel circle = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);

//PIXEL_PIN
int pixel_position = 0;
int numberLEDs = 0;

//PRESSURE SENSOR
int fsrPin = A0;
int fsrReading = 0; //measurement
int fluidLevel = 3400;
int fillStatus = 0;
int fillThreshold = 3730;
int glassPresentThreshold = 3200;
int glassPresent = 0;

const int publishRate = 500;
int currPubRate = 500;

//OTHER GLASS
int otherGlassFluidLevel = 3400;
int otherFillStatus = 0;
int otherGlassPresent = 0; //initially assume other glass is present

//SPEAKER
int speakerPin = D1;
int val;
int melody[] = {622,698,800};
int noteDurations[] = {8,8,4};
// Track if the clink is playing
boolean isPlaying = false;
int clinkPlayCount = 0;


void setup() {
  Serial.begin( 9600 );
  circle.setBrightness(10);
  circle.begin();
  // Initialize all pixels to 'off'
  circle.show();

  Particle.variable("DebugMe",&fsrReading,INT);
  Particle.variable("DebugThem",&otherGlassFluidLevel,INT);

  pinMode(fsrPin,INPUT_PULLUP); // sets pin as input

  //subscribe to event according to which glass
  if(glassID == 1) {
    Particle.subscribe("diot2017Clink2",receiveClink,"35002b001051353338363333"); //Nick
    }
  if(glassID == 2) {
    Particle.subscribe("diot2017Clink1",receiveClink, "3d0050000f51353338363333"); //Marco
    }
}

void loop() {
//'Cheers' is activated by placing glass 1 (or 2) with filled liquid level (x) exerted on pressure sensor
// so sensor reads above normal weight for just the glass

fsrReading = analogRead(fsrPin); // pressure
   //Serial.println(fsrReading);

//from testing
fluidLevel = -0.0096*(fsrReading*fsrReading) + (2.6435*fsrReading) + 3679.1;

//check present and unfilled
if(fsrReading >= glassPresentThreshold && glassPresent == 0) {
  glassPresent = 1;
}

//check if filled
if(fsrReading >= fillThreshold && glassPresent == 1) {
  if(fillStatus == 0) {
    fillStatus = 1;
    announceCheers();
    Serial.println("1");
  }
  if(currPubRate >= publishRate) {
    currPubRate = 0;
    announceCheers();
    Serial.println("2");
  }
  currPubRate++; //control publish rate when filled
}

//check if lifted
if(fsrReading < glassPresentThreshold && glassPresent == 1) {
  glassPresent = 0;
  //filled and lifted
  if(fillStatus == 1) {
    announceCheers();
    Serial.println("3");
  }
}



//unfilled, glass present
if(fsrReading < fillThreshold && (fsrReading >= glassPresentThreshold || glassPresent == 1) && fillStatus == 1) {

  fillStatus = 0;
  announceCheers();
  Serial.println("5");
}






  // The neo pixel does a color chase to alert glass 2 (or 1) the social drink has started

  if(otherFillStatus == 1) {
    if(fillStatus == 0) {
      //you have not filled glass, and other raised his glass
      if(otherGlassPresent == 0) {
        if(clinkPlayCount == 0)
        {
          delay(1000);
          clink();
          clinkPlayCount++;
        }
        breathe(); //breathe if other guy lifts glass
        } else {
          breathe();
          //colorchase(); // alerts glass if not lifted
        }
      } else { //both filled
          if(clinkPlayCount == 0)  {
            delay(1000);
            clink();
            clinkPlayCount++;
            }
            breathe();
            //fluidlevelLED();//TODO show level
          }
        }

delay(100);
//scanner(90,90, 90, 20);
}




void receiveClink(const char *event, const char *data)
{
  otherGlassFluidLevel = atoi(data);

  if (otherGlassFluidLevel >= fillThreshold) {
    otherFillStatus = 1;
    } else {
      if(otherGlassFluidLevel > glassPresentThreshold)
        { otherFillStatus = 0;
          otherGlassPresent = 1;
        } else {
          otherGlassPresent = 0;
        }
      }
}

void announceCheers()
{
  //anounce clink to the other device
  if(glassID == 1) {
    Particle.publish("diot2017Clink1",String(fsrReading)); //Marco
    }
  if(glassID == 2) {
    Particle.publish("diot2017Clink2",String(fsrReading)); //Nick
    }
}

void colorchase()
{
  //continue loop until I fill glass or other finishes
    for(int i=0; i< circle.numPixels(); i++) {
      uint32_t c;
      if(pixel_position == i) {
        c = circle.Color(255, 255, 255);
        } else {
        c = circle.Color(0, 0, 0);
          }
      circle.setPixelColor(i, c);
      circle.show();
      delay(50);
      }
    //stop color chase
    //delay(500);
    for(int i = 0; i< circle.numPixels(); i++) {
      pixel_position++;
      if(pixel_position >= circle.numPixels()) {
        pixel_position = 0;
        }
        circle.show();
        //delay(10);
      }

    //delay(100);
}

/* Calc the sin wave for the breathing white led */
void breathe() {

  float val = (exp(sin(millis()/2000.0*M_PI)) - 0.36787944)*108.0;
  Serial.println( val );

  uint16_t i;
  uint32_t c = circle.Color(val, val, val);

  for(i=0; i< circle.numPixels(); i++) {
    circle.setPixelColor(i, c );
  }
  circle.show();
  delay(50);
  numberLEDs = circle.numPixels();
}


// "Larson scanner" = Cylon/KITT bouncing light effect
void scanner(uint8_t r, uint8_t g, uint8_t b, uint8_t wait)
{
  int i, j, pos, dir;

  pos = 0;
  dir = 1;

  for(i=0; i<((circle.numPixels()-1) * 8); i++) {
    // Draw 5 pixels centered on pos.  setPixelColor() will clip
    // any pixels off the ends of the circle, no worries there.
    // we'll make the colors dimmer at the edges for a nice pulse
    // look

    circle.setPixelColor(pos - 2, circle.Color(r/4, g/4, b/4));
    circle.setPixelColor(pos - 1, circle.Color(r/2, g/2, b/2));
    circle.setPixelColor(pos, circle.Color(r, g, b));
    circle.setPixelColor(pos + 1, circle.Color(r/2, g/2, b/2));
    circle.setPixelColor(pos + 2, circle.Color(r/4, g/4, b/4));


    circle.show();
    delay(wait);
    // If we wanted to be sneaky we could erase just the tail end
    // pixel, but it's much easier just to erase the whole thing
    // and draw a new one next time.
    for(j=-2; j<= 2; j++)
        circle.setPixelColor(pos+j, circle.Color(0,0,0));
    // Bounce off ends of circle
    pos += dir;
    if(pos < 0) {
      pos = 1;
      dir = -dir;
    } else if(pos >= circle.numPixels()) {
      pos = circle.numPixels() - 2;
      dir = -dir;
    }
  }
}

void fluidlevelLED()
{
  //continue loop until I fill glass or other finishes
  while(fillStatus == 0 && otherGlassFluidLevel > 10) {
    for(int i=0; i< circle.numPixels() - fluidLevel; i++) {
      uint32_t c;
      if(pixel_position < i) { //|| pixel_position == i-1) {
        c = circle.Color(255, 255, 255);
        } else {
          c = circle.Color(0, 0, 0);
          }
      circle.setPixelColor(i, c);
      }
    //stop color chase
    circle.show();
    //delay(500);
    pixel_position++;
    if(pixel_position >= circle.numPixels()) {
      pixel_position = 0;
      }
    delay(50);
    }
    //delay(100);
}

void clink()
{
  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < 3; thisNote++) {
    // to calculate the note duration, take one second
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000/noteDurations[thisNote];
    tone(speakerPin, melody[thisNote],noteDuration);
    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(speakerPin);
  }
}
Click to Expand

Content Rating

Is this a good/useful/informative piece of content to include in the project? Have your say!

0