Lillypad
Milk level notifying system
Made by Vishal Pallikandi
The Lillypad is a platform like device that you keep in you refrigerator. Placing your milk bottle on it allows you to receive automatic SMS notifications when you are running out of milk. It can also update a status incase you acknowledge the notification so that, others back at home can know if you have read the message.
Created: January 28th, 2015
Description:
The Lillypad is a platform like device that you keep in you refrigerator. Placing your milk bottle on it allows you to receive automatic SMS notifications when you are running out of milk. It can also update a status incase you acknowledge the notification so that, others back at home can know if you have read the message. It does so by changing the color of the button's glow from red to green.
Working:
The heart of the Lillypad is a Spark core which serves as the brain and also connects to wi-fi. A pressure sensor keeps track of the weight of any object placed on the platform indirectly through pressure and, a custom made capacitive sensor is used to make the glowing touch button. The sensor is just a piece of aluminium foil wrapped around a circular piece of card and hidden behind the button's surface.The capacitive touch sensor works simply by creating a rising edge on a 'send pin' and observing how long the capacitance of the sensor takes to charge through a high resistance. This response is read from a 'receive pin' and the difference in time between send and receive response is indicative of the capacitance. Since capacitance can be created across an insulator, the sensor is able to penetrate the touch surface and respond to the capacitance of the human body.
The glow under the capacitive button is created by a pair of LEDs placed under the button. I used the IFTTT (If this, then that) service to send out SMS notifications and receive acknowledgements.
// URLs for Debugging
// https://api.spark.io/v1/devices/<your device ID>/pressure?access_token=<your access token>
// https://api.spark.io/v1/devices/<your device ID>/sendSMS?access_token=<your access token>
#define LED D7 // Indicator to debug the touch button
// touch button events
#define tEVENT_NONE 0
#define tEVENT_TOUCH 1
#define tEVENT_RELEASE 2
// minimum poll time before checking for next touchbutton event
#define POLL_TIME 20
//LED colors
#define red 1
#define green 2
#define blue 3
#define cyan 4
#define off 0
// RGB LED Pins
#define R A5
#define G A4
#define B A3
// pressure sensor
int pressure=0; //For pressure storage
int fiveVolt=A0; //Supply for the sensor
int pressureS=A1; //Pin for pressure sensing
int checkFlag=0; //To know if event is over
int sentFlag=0;
// touch button
int sPin = D3; //send pin
int rPin = D2; //recieve pin
unsigned long tS; //send- time stamp
unsigned long tR; //recieve time stamp
long tReading; //time delay reading
long tBaseline; //running average of time delay before reading
//SMS acknowledgement flag
int message_Ack=0; //SMS acknowledgement flag
// int sendSMS=0; //SMS send flag
int glow=off;
void setup() {
//RGB LED
pinMode(R, OUTPUT);
digitalWrite(R, HIGH);
pinMode(G, OUTPUT);
digitalWrite(G, HIGH);
pinMode(B, OUTPUT);
digitalWrite(B, HIGH);
//pressure sensor
pinMode(fiveVolt, OUTPUT);
pinMode(pressureS, INPUT);
Spark.variable("pressure", &pressure, INT);
Spark.variable("sentFlag", &sentFlag, INT);
//Spark.variable("sendSMS", &sendSMS, INT);
digitalWrite(fiveVolt,HIGH);
// Indicator to debug the touch button
pinMode(LED, OUTPUT);
//touch sensor
pinMode(sPin,OUTPUT);
attachInterrupt(rPin,touchSense,RISING);
// first reading to calibrate touchbutton without placement of a finger
tBaseline = touchSampling();
//SMS acknowledgement on the cloud
Spark.function("messageAck",messageAck);
}
void loop() {
static unsigned long lastUpdate = 0;
//basic fuction
pressure=analogRead(pressureS);
if (pressure<=80)
checkFlag=1;
delay(100);
if (analogRead(pressureS)>200&&checkFlag==1)
{
delay(1000);
if (analogRead(pressureS)<1000&&sentFlag==0)
{
//sendSMS=1;
Spark.publish("sendSMS");
sentFlag=1;
}
checkFlag=0;
}
if (analogRead(pressureS)>=1000&&sentFlag==1)
{
sentFlag=0;
message_Ack=0;
}
//Update touchsensor every POLL_TIME [ms]
if (millis() > lastUpdate + POLL_TIME)
{
int touchEvent = touchEventCheck();
if (touchEvent == tEVENT_TOUCH)
{
digitalWrite(LED, HIGH);
if (message_Ack==1)
{glow=green;
ledControl(glow,0);
}
else
{glow=red;
ledControl(glow,0);
}
}
if (touchEvent == tEVENT_RELEASE)
{
digitalWrite(LED, LOW);
glow=off;
ledControl(glow,255);
}
lastUpdate = millis();
}
}
void touchSense()
{
tR = micros();
}
// sample touch sensor 32 times and get average RC delay [usec]
long touchSampling()
{
long tDelay = 0;
int mSample = 0;
for (int i=0; i<32; i++)
{
// discharge capacitance at rPin
pinMode(rPin, OUTPUT);
digitalWrite(sPin,LOW);
digitalWrite(rPin,LOW);
// revert to high impedance input
pinMode(rPin,INPUT);
// timestamp & transition sPin to HIGH and wait for interrupt in a read loop
tS = micros();
tR = tS;
digitalWrite(sPin,HIGH);
do
{
// wait for transition
} while (digitalRead(rPin)==LOW);
// accumulate the RC delay samples
// ignore readings when micros() overflows
if (tR>tS)
{
tDelay = tDelay + (tR - tS);
mSample++;
}
}
// calculate average RC delay [usec]
if (mSample>0)
{
tDelay = tDelay/mSample;
}
else
{
tDelay = 0; // this is an error condition!
}
//autocalibration using exponential moving average on data below trigger point
if (tDelay<(tBaseline + tBaseline/4))
{
tBaseline = tBaseline + (tDelay - tBaseline)/8;
}
/*
Serial.println(tDelay, tBaseline);
*/
return tDelay;
}
//touch events:
// tEVENT_NONE no change
// tEVENT_TOUCH sensor is touched (Low to High)
// tEVENT_RELEASE sensor is released (High to Low)
int touchEventCheck()
{
int touchSense; // current reading
static int touchSenseLast = LOW; // last reading
static unsigned long touchDebounceTimeLast = 0; // debounce timer
int touchDebounceTime = 50; // debounce time
static int touchNow = LOW; // current debounced state
static int touchLast = LOW; // last debounced state
int tEvent = tEVENT_NONE; // default event
// read touch sensor
tReading = touchSampling();
// touch sensor is HIGH if trigger point 1.25*Baseline
if (tReading>(tBaseline + tBaseline/8))
{
touchSense = HIGH;
}
else
{
touchSense = LOW;
}
// debounce touch sensor
// if state changed then reset debounce timer
if (touchSense != touchSenseLast)
{
touchDebounceTimeLast = millis();
}
touchSenseLast = touchSense;
// accept as a stable sensor reading if the debounce time is exceeded without reset
if (millis() > touchDebounceTimeLast + touchDebounceTime)
{
touchNow = touchSense;
}
// set events based on transitions between readings
if (!touchLast && touchNow)
{
tEvent = tEVENT_TOUCH;
}
if (touchLast && !touchNow)
{
tEvent = tEVENT_RELEASE;
}
// update last reading
touchLast = touchNow;
return tEvent;
}
int messageAck(String statusSTR)
{
message_Ack=1;
return 1;
}
//function to control the color of the RGB LED
void ledControl(int color,int value)
{
//Wipe out previous values of the LED
analogWrite(R, 255);
analogWrite(G, 255);
analogWrite(B, 255);
//change the color according to 'color'
if (color==red)
analogWrite(R, value);
if (color==green||cyan)
analogWrite(G, value);
if (color==blue||cyan)
analogWrite(B, value);
}
Click to Expand
The Lillypad is a platform like device that you keep in you refrigerator. Placing your milk bottle on it allows you to receive automatic SMS notifications when you are running out of milk. It can also update a status incase you acknowledge the notification so that, others back at home can know if you have read the message.