These connected devices help good friends drink together remotely. They can drink in unison and be alerted when each takes a drink so they can cheers together in real time.

0

INSPIRATION

As people move away from home, they leave their friends and social circles behind. Chatting over the phone and via Skype can bring them together for small talk and catch up conversations, but they are missing together times when they would get together  to share a drink and relax. 

0

CONCEPT

Nobody likes to drink alone! With 'Cheers!', you will never have to again. By drinking with these connected devices, two friends can drink simultaneously and get notified to cheers on every sip.

When friend 1 fills their glass, fried 2 gets an alert that friend one is drinking. Friend 2 can then fill their glass and they are both in synchronization to socialize together. On each sip, the other friend will get notified and they too can raise their glass to the sound of a clink.

The NeoPixle LED ring indicates how much alcohol the other person has taken, and it changes color and pattern according to the stage of the social drinking procedures. A pressure sensor can judge the weight of the glass, thus detecting the change of liquid level and  monitors when a glass is filled, as the volume decreases, and when it is emptied thus signalling to the other friend they have finished their drink.

0
Storyboard
274017347200288351
0

Bill of Materials

  • NeoPixle LED ring
  • FSR sensor
  • speaker
  • resistors
  • jumpwires
  • wine cup
  • foam core casing
0
0
/*   ___ _                   _
  / __| |_  ___ ___ _ _ __| |
 | (__| ' \/ -_) -_) '_(_-<_|
  \___|_||_\___\___|_| /__(_)
*/

#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
0
Circuit
20170216013204
0
Prototype
569337105682453807
x
Share this Project

Courses

49-713 Designing for the Internet of Things

· 26 members

A hands-on introductory course exploring the Internet of Things and connected product experiences.


Focused on
About

These connected devices help good friends drink together remotely. They can drink in unison and be alerted when each takes a drink so they can cheers together in real time.

Created

February 13th, 2017