49-713 Designing for the Internet of Things
· 26 members
A hands-on introductory course exploring the Internet of Things and connected product experiences.
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.
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.
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.
/* ___ _ _
/ __| |_ ___ ___ _ _ __| |
| (__| ' \/ -_) -_) '_(_-<_|
\___|_||_\___\___|_| /__(_)
*/
#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
A hands-on introductory course exploring the Internet of Things and connected product experiences.
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.
February 13th, 2017