Improve discoverability of hidden or forgotten food in the fridge, even if you're not at home. Private project repo: https://github.com/daraghbyrne/advancediot2017/tree/master/students/mpowel/final-sprint
At the beginning of this course, I was aiming to solve for well intentioned consumers who waste food on accident due to lack of visibility and forgetfulness.
I reframed that objective into an actionable design challenge.
Improve discoverability of hidden or forgotten food in the fridge, even while the user is not at home.
And came up with the following solution.
Create a smart device that monitors food freshness, sets smart timers based on the contents in the container and provides helpful, delightful and subtle reminders so you don't forget about the food that got pushed to the back of the fridge.
//=============================================================================
// Webhook Function
//=============================================================================
void doWebhookSMS(){
if( state == 0 ){
Particle.publish("smart_food_webhook_sms", "Hey! Smartware here. Put me in the fridge to start my 7 day timer or reply SET to set the timer manually.", PRIVATE);
delay(50);
state = STATE_SMS_SENT;
}else if( state == STATE_TURN_ON && hasSentColdSMS == 0){
Particle.publish("smart_food_webhook_sms", "Aaa, nice and cool. Your smartware timer has started.", PRIVATE);
hasSentColdSMS = 1;
}else if( state == 1 ){
Particle.publish("smart_food_webhook_sms", "Aaa, nice and cool. Your smartware timer has started.", PRIVATE);
}else if( state == 2 && hasElapsed2 == 1 && hasSentElapsed2 == 0 ){ // Send SMS after 2 days
Particle.publish("smart_food_webhook_sms", "Food waste costs the average American family up to $2,000/year, but youre not average are you? ;)", PRIVATE);
}else if( state == 2 && has3daysLeft == 1 && hasSent3daysLeft == 0 ){ // Send SMS 3 days before complete
Particle.publish("smart_food_webhook_sms", "30-40 percent of food produced in the US gets wasted. 43 percent of that happens at the hands of the consumer. Eat leftovers. Check. Save the world. Check.", PRIVATE);
}else if( state == 2 && has1dayLeft == 1 && hasSent1dayLeft == 0 ){ // Send SMS 1 day before complete
Particle.publish("smart_food_webhook_sms", "Remember to eat your leftovers! The smartware timer ends tomorrow.", PRIVATE);
}else if( state == STATE_TURN_OFF ){
Particle.publish("smart_food_webhook_sms", "I hope you enjoyed your leftovers! Shutting down now.", PRIVATE);
}else if( state == STATE_GAS_HIGH && hasSentStinkySMS == 0){
Particle.publish("smart_food_webhook_sms", "Whewwwww, thats getting ripe. Check your leftovers, my ditigal sniffer detected something funky.", PRIVATE);
hasSentStinkySMS = 1; // only send one message
}
}
Click to Expand
And can take in SMS messages as cloud variables via a Ruby gem integration. For details on how to get a Ruby app speaking with your Particle Photon, see here: https://github.com/monkbroc/particlerb
//=============================================================================
// Meet Smartware, your smart tupperware! Food freshness with confidence.
//=============================================================================
// HOW IT WORKS //
// The user switches the device on and neopixel breathes white light.
// User sets timer through text messaging and the lights blink blue
// (int times based on # of days set).
// To start the timer, just put the tupperware in the fridge. It will start
// once the temperature drops below 40F.
// The next time you open the fridge, you'll be sure not to miss your tupperware
// at the back of the fridge and the countdown will show how much time you have
// to eat it.
// Once time is up, the neopixel blinks yellow. If at any point, the VOC gas
// reading goes above a 600, the neopixel will flash red until the dish is
// removed from the fridge.
// The device automatically turns off when the tupperware temperature sensor
// is >50F for more than 30 mins.
// DEMO ADJUSTMENTS //
// In the demo version, "Days" are converted to minutes
// Counter starts when temperature is <60F
// Shut off triggered if temp >75F, no time delay
// Depending on exterior encasement, red light may need to change to white
//=============================================================================
// Libraries Used
//=============================================================================
#include "OneWire.h"
#include "spark-dallas-temperature.h"
#include "neopixel.h"
#include "math.h"
#include "string"
//=============================================================================
// State Change
//=============================================================================
# define STATE_WELCOME 0 // Breath white until button is pushed
# define STATE_TURN_ON 1 // Blinks blue twice: Push of button triggers blink, changes state, and starts timer
# define STATE_TIMER 2 // Turn on green LEDs based on preset timer
# define STATE_THROW_OUT 3 // 5 blinks yellow: Time passed set threshold
# define STATE_TURN_OFF 4 // Blinks blue twice (same as turn on)
# define STATE_WAIT 5 // LEDs off. Click button again to turn on
# define STATE_SMS_SENT 6 // State to avoid duplicate SMS messages
# define STATE_GAS_HIGH 7 // Wipe red: Gas sensor >600
//=============================================================================
// Neopixel Controls
//=============================================================================
// IMPORTANT: Set pixel COUNT, PIN and TYPE
#define PIXEL_COUNT 16
#define PIXEL_PIN D3
#define PIXEL_TYPE WS2812
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
//=============================================================================
// Temperature Sensor Controls
//=============================================================================
OneWire oneWire(A0); // Pass oneWire reference to Dallas Temperature.
DallasTemperature dallas(&oneWire);
double temperature = 0.0; // Temperature varibale in Degrees Celsius
double temperatureF = 0.0; // Temperature variable in Degrees Farenheight
double tempFSmoothedValue = 0.0; // Smoothed Temperature variable
// Low Pass Filter (temp)
#define filterSamples 5
int tempFSampleArray [filterSamples];
//=============================================================================
// Variable Identification
//=============================================================================
//Initialize and store a value in the state to get things started
int state = 0; // Start things off with breathing white & initial sms
int buttonPin = D1; // Button for interrupt
int buttonValue = HIGH; // Button for interrupt initial value
int set_smartware = 7; // Initial timer set to 7 days
String set_smartware_str = ""; // Global variable for user input coming from app.rb
int INTERVAL_TIME = 0;
int timeElapsed = 0;
bool hasElapsed2 = 0; // Use as trigger to send SMS after 2 days
bool hasSentElapsed2 = 0; // Stops duplicates from being sent
bool has3daysLeft = 0; // Use as trigger to send SMS 3 days before complete
bool hasSent3daysLeft = 0; // Stops duplicates from being sent
bool has1dayLeft = 0; // Use as trigger to send SMS 1 day before complete
bool hasSent1dayLeft = 0; // Stops duplicates from being sent
bool hasSentStinkySMS = 0;
bool hasSentColdSMS = 0;
// Low Pass Filter (gas)
#define filterGasReading 12
int gasReadingArray [filterGasReading]; // array for holding raw sensor values for sensor2
int gasReadingRawValue = 0;
int gasReadingSmoothedValue = 0;
// Neopixel colors
int red = 0xff0000;
int blue = 0x0000ff;
int green = 0x00ff00;
int yellow = 0xFFFF00;
//=============================================================================
// SMS / MMS handler for app.rb responses
//=============================================================================
void handleSMSEvent(const char *event, const char *data) {
Serial.println("handler started");
Serial.println(data); // data is coming from linked app.rb
set_smartware_str = (data);
}
//=============================================================================
// Setup
//=============================================================================
void setup(){
Serial.begin(9600); // Start the serial monitor
// Low pass filter smoothening array to smooth temp readings
for(int i = 0; i < filterSamples; i++){
tempFSampleArray[i]= 0;
}
// Initiate the temperature sensor library
dallas.begin();
// Cloud variables
Particle.variable("temperatureF", &temperatureF, DOUBLE);
Particle.variable("melsGasVar", &gasReadingSmoothedValue, INT);
// Initiate the Neopixels. Set them all to off
strip.begin();
strip.show();
strip.setBrightness(3);
// Set time to EST and track once started
Time.zone(-4);
// Attach an interrupt using the button (turns device on)
pinMode( buttonPin, INPUT_PULLUP );
attachInterrupt( buttonPin, getButtonValueOn, RISING);
// Initiate the array
for(int i=0; i<filterGasReading; i++)
{
gasReadingArray[i]= 0;
}
// Subscribe to incoming messages coming through app.rb
Particle.subscribe("smart_food/sms/incoming", handleSMSEvent);
}
//=============================================================================
// Run this loop Continuously
//=============================================================================
void loop(){
readTemperature(); // Continuously check temp reading
doMonitorGas(); // Continuously monitor gas sensor
switch( state ){
case STATE_WELCOME: // Breathe white + welcome SMS goes out
doWelcomeState();
break;
case STATE_SMS_SENT: // Breathe white, stop sending SMS
doWelcomeState();
break;
case STATE_TURN_ON: // Blink blue
doTurnOn();
break;
case STATE_TIMER: // Green count down
doCountDown();
break;
case STATE_GAS_HIGH: // Blink red: Gas sensor >600
blinkRed(1);
break;
case STATE_THROW_OUT: // Blink yellow, time elapsed
doThrowOutReminder();
break;
case STATE_TURN_OFF: // Blinks blue twice then shuts off
doTurnOff();
break;
}
delay(50);
}
//=============================================================================
// Webhooks
//=============================================================================
void doWebhookSMS(){
if( state == 0 ){
Particle.publish("smart_food_webhook_sms", "Hey! Smartware here. Put me in the fridge to start my 7 day timer or reply SET to set the timer manually.", PRIVATE);
delay(50);
state = STATE_SMS_SENT;
}else if( state == STATE_TURN_ON && hasSentColdSMS == 0){
Particle.publish("smart_food_webhook_sms", "Aaa, nice and cool. Your smartware timer has started.", PRIVATE);
hasSentColdSMS = 1;
}else if( state == 1 ){
Particle.publish("smart_food_webhook_sms", "Aaa, nice and cool. Your smartware timer has started.", PRIVATE);
}else if( state == 2 && hasElapsed2 == 1 && hasSentElapsed2 == 0 ){ // Send SMS after 2 days
Particle.publish("smart_food_webhook_sms", "Food waste costs the average American family up to $2,000/year, but youre not average are you? ;)", PRIVATE);
}else if( state == 2 && has3daysLeft == 1 && hasSent3daysLeft == 0 ){ // Send SMS 3 days before complete
Particle.publish("smart_food_webhook_sms", "30-40 percent of food produced in the US gets wasted. 43 percent of that happens at the hands of the consumer. Eat leftovers. Check. Save the world. Check.", PRIVATE);
}else if( state == 2 && has1dayLeft == 1 && hasSent1dayLeft == 0 ){ // Send SMS 1 day before complete
Particle.publish("smart_food_webhook_sms", "Remember to eat your leftovers! The smartware timer ends tomorrow.", PRIVATE);
}else if( state == STATE_TURN_OFF ){
Particle.publish("smart_food_webhook_sms", "I hope you enjoyed your leftovers! Shutting down now.", PRIVATE);
}else if( state == STATE_GAS_HIGH && hasSentStinkySMS == 0){
Particle.publish("smart_food_webhook_sms", "Whewwwww, thats getting ripe. Check your leftovers, my ditigal sniffer detected something funky.", PRIVATE);
hasSentStinkySMS = 1; // only send one message
}
}
//=============================================================================
// Welcome state
//=============================================================================
void doWelcomeState(){
breatheWhite();
doWebhookSMS();
}
//=============================================================================
// Blink twice when on button is clicked
//=============================================================================
void doTurnOn(){
if( state == STATE_TURN_ON ){ // Once the button is pushed, the device turns on
blinkBlue(5);
delay(50);
doWebhookSMS(); // Send "timer turned on" SMS triggered by temp
state = STATE_TIMER;
}
}
//=============================================================================
// Light transition for duration of the time interval
//=============================================================================
long startedIntervalAt = -1;
// c++ for includes: if(str1.find(str2) != std::string::npos){
/*set_smartware = set_smartware_str.toInt(); // turns user input (string) to int*/
void doCountDown(){
String nan_trick = ":"; // All non integer inputs should include ":"
char * checking; // set up for string function to check if one string contains another substring
checking = strstr(set_smartware_str, nan_trick);
if( checking != NULL || set_smartware_str == "" ){ // this function checks to see if a response like "bye" or "set" was entered
set_smartware = 7; // if NAN or the user hasn't input a value, leave default timer.
}else{ // set smartware based on user input
set_smartware = set_smartware_str.toInt(); // turn user input (string) to int
if ( set_smartware > 30 ) { // if user sets something too large
set_smartware = 30; // default max is 30 days
}
}
Serial.println( set_smartware ); // check to make sure we're not getting any NANs
INTERVAL_TIME = (4000 * set_smartware); // SMS incoming messages used to set duration
if( startedIntervalAt == -1 ) // if start, keep record of time elapsed
startedIntervalAt = millis();
timeElapsed = millis() - startedIntervalAt; // check time passed
// light up a certain number of pixels based on time elapsed.
int numPixelsToLight = map( timeElapsed, 0, INTERVAL_TIME, 0, strip.numPixels() );
for( int i = 0; i < strip.numPixels(); i++ ){
if( i <= numPixelsToLight ){
strip.setPixelColor(i, strip.Color( 127,255,0 )); //green chartreuse
}else{
strip.setPixelColor(i, 0); // turn all pixels off
}
}
strip.show();
if( timeElapsed > INTERVAL_TIME){ // if beyond time, let's move on
state = STATE_THROW_OUT;
hasElapsed2 = 0; // Use as trigger to send SMS after 2 days
has3daysLeft = 0; // Use as trigger to send SMS 3 days before complete
has1dayLeft = 0; // Use as trigger to send SMS 1 day before complete
doWebhookSMS();
}else if(timeElapsed > INTERVAL_TIME - 4000 ){ //&& timeElapsed > INTERVAL_TIME - 2300
has1dayLeft = 1;
hasElapsed2 = 0;
has3daysLeft = 0;
doWebhookSMS();
delay(10);
hasSent1dayLeft = 1; // Stops duplicates from being sent
}else if(timeElapsed > INTERVAL_TIME - 7000 ){ //&& timeElapsed > INTERVAL_TIME - 7000
has3daysLeft = 1;
hasElapsed2 = 0;
has1dayLeft = 0;
doWebhookSMS();
delay(10);
hasSent3daysLeft = 1; // Stops duplicates from being sent
}else if(timeElapsed > 4000 ){ //&& timeElapsed < 4000
hasElapsed2 = 1;
has3daysLeft = 0;
has1dayLeft = 0;
doWebhookSMS();
delay(10);
hasSentElapsed2 = 1; // Stops duplicates from being sent
}
delay( 100 );
}
//=============================================================================
// Timer done, time to toss food
//=============================================================================
void doThrowOutReminder(){
blinkYellow( 2 );
}
//=============================================================================
// Bring temp sensor to >80, blink Red as warning and turn all lights off
//=============================================================================
void doTurnOff(){
blinkBlue( 2 );
wipeDownNeoPixels();
blinkBlue( 5 );
TurnOffLEDs();
doWebhookSMS(); // send "device turned off" message triggered by temp
state = STATE_WAIT;
}
//=============================================================================
// Button methods
//=============================================================================
void getButtonValueOn(){
if(state == STATE_WELCOME){ //If STATE_WELCOME, button turns countdown on
state = STATE_TURN_ON;
}else if(state == STATE_THROW_OUT || state == STATE_TIMER ){
state = STATE_TURN_OFF;
}else{
state = STATE_WELCOME; //Otherwise reset to STATE_WELCOME
doTurnOn();
startedIntervalAt = -1;
}
}
//=============================================================================
// Breathing light pattern
//=============================================================================
float breatheWhite(){
// Calc the sin wave for the breathing white led
float val = (exp(sin(millis()/2000.0*M_PI)) - 0.36787944)*108.0;
uint16_t i;
uint32_t c = strip.Color(val, val, val);
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, c );
}
strip.show();
}
//=============================================================================
// Blink Helpers
//=============================================================================
void wipeDownNeoPixels(){ // Wipe down red
for (int i=strip.numPixels() - 1; i >= 0; i--) {
strip.setPixelColor(i, 255, 0, 0 );//red
strip.show();
delay( 200 );
}
}
void blinkBlue( int times ){ // Blink blue int number of times
for( int i = 0 ; i < times; i++ ){
TurnOnBlue();
delay(150);
TurnOffLEDs();
delay(150);
}
}
void blinkRed( int times ){ // Blink red int number of times
for( int i = 0 ; i < times; i++ ){
TurnOnRed();
delay(150);
TurnOffLEDs();
delay(150);
}
}
void blinkYellow( int times ){ // Blink yellow int number of times
for( int i = 0 ; i < times; i++ ){
TurnOnYellow();
delay( 150);
allNeopixelsOff();
delay( 150);
}
}
void TurnOnRed(){ // Turn all LEDs on (red)
int i;
for(i=0; i < 16; i++)
{
strip.setPixelColor(i, red);
strip.show();
}
}
void TurnOnBlue(){ // Turn all LEDs on (blue)
int i;
for(i=0; i < 16; i++)
{
strip.setPixelColor(i, blue);
strip.show();
}
}
void TurnOnYellow(){ // Turn all LEDs on (yellow)
int i;
for(i=0; i < 16; i++)
{
strip.setPixelColor(i, yellow);
strip.show();
}
}
void TurnOffLEDs(){ // Turn all LEDs off
int i;
for(i=0; i < 16; i++)
{
strip.setPixelColor(i, 0x000000);
strip.show();
}
}
//=============================================================================
// Additional Neopixel Helpers
//=============================================================================
void allNeopixelsOn(){
for (int i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color( 10,10,10 )); // turn all pixels on
}
strip.show();
}
void allNeopixelsOff(){
for (int i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, 0); // turn all pixels off
}
strip.show();
}
//=============================================================================
// VOC Sensor Helper
//=============================================================================
void doMonitorGas(){
time_t time = Time.now();
String tStr = Time.format(time, TIME_FORMAT_ISO8601_FULL); // 2017-04-05T07:08:47-05:00
Serial.print( tStr ); //track the time and date the data was sent
Serial.print( ", "); // In order to use data in CSV file, separate w/ comma
gasReadingRawValue = analogRead(A3); // grab gas sensor reading from pin A0
if ( gasReadingRawValue <= 0){ // remove extreme values
delay(1);
}else if( gasReadingRawValue >= 290 && state == STATE_TIMER ){
state = STATE_GAS_HIGH;
// Flashes red if gas reading goes above normal & still in count down.
// Normal varies based on food. Current solution doesn't adjust for food type
doWebhookSMS();
}else if( gasReadingRawValue >= 290 && state == STATE_THROW_OUT ){
state = STATE_GAS_HIGH;
// Flashes red if gas reading goes above normal & count down just ended.
// Normal varies based on food. Current solution doesn't adjust for food type
doWebhookSMS();
}else{
gasReadingRawValue = analogRead(A3);
gasReadingSmoothedValue = digitalSmooth( gasReadingRawValue , gasReadingArray );
}
Serial.print("\tRaw gas reading:,");
Serial.print(gasReadingRawValue);
Serial.print( ",\tSmoothed gas reading:,");
Serial.print(gasReadingSmoothedValue);
Serial.print( ",");
}
//=============================================================================
// Low Pass Filter to smooth gas readings
//=============================================================================
int digitalSmoothGas(int gasDataValue, int * gasSensorSampleArray ){
int j, k, temp, top, bottom;
long total;
static int i;
static int sorted[filterGasReading];
boolean done;
// increment counter and roll over if necc. - % (modulo operator) rolls over variable
i = (i + 1) % filterGasReading;
gasSensorSampleArray[i] = gasDataValue; // input new data into the oldest slot
for (j=0; j<filterGasReading; j++){ // transfer data array into anther array for sorting and averaging
sorted[j] = gasSensorSampleArray[j];
}
done = 0; // flag to know when we're done sorting
while(done != 1){ // simple swap sort, sorts numbers from lowest to highest
done = 1;
for (j = 0; j < (filterGasReading - 1); j++){
if (sorted[j] > sorted[j + 1]){ // numbers are out of order - swap
temp = sorted[j + 1];
sorted [j+1] = sorted[j] ;
sorted [j] = temp;
done = 0;
}
}
}
// throw out top and bottom 15% of samples - limit to throw out at least one from top and bottom
// +1 makes up for asymmetry caused by integer rounding
bottom = max(((filterGasReading * 15) / 100), 1);
top = min((((filterGasReading * 85) / 100) + 1 ), (filterGasReading - 1));
k = 0;
total = 0;
for ( j = bottom; j< top; j++){
total += sorted[j]; // total remaining indices
k++;
}
return total / k; // divide by number of samples
}
//=============================================================================
// Temperature Control Functions
//=============================================================================
void readTemperature(){ // Function gets temp reading from Dallas temp sensor
dallas.requestTemperatures(); // Request temperature
sin( 23423 );
float tempC = dallas.getTempCByIndex(0); // Get the temperature in Celcius
if ( tempC <= -100 || tempC >= 50 ){ // Eemove extreme values
delay(2);
}else{
temperature = (double)tempC; // Convert to double
float tempF = DallasTemperature::toFahrenheit( tempC ); // Convert to Fahrenheit
temperatureF = (double)tempF; // Convert to double
}
tempFSmoothedValue = digitalSmooth( temperatureF , tempFSampleArray ); // Smooth temp reading
Serial.print( "\tRaw Temp = ");
Serial.print( temperatureF );
Serial.println( ", ");
Serial.print( "\tSmoothed Temp = ");
Serial.print( tempFSmoothedValue );
Serial.println( ", ");
checkTemperature(); // Adjust heater output based on temp reading
}
void checkTemperature(){ // Start timer when put in fridge
if(tempFSmoothedValue > 61 && tempFSmoothedValue < 72 && state == STATE_SMS_SENT){
state = STATE_TURN_ON; // Triggers doTurnOn(); Blink, send SMS message, start counter
}else if (tempFSmoothedValue > 72 && state == STATE_TIMER ){ // or after countdown passes threshold
state = STATE_TURN_OFF; // Triggers doTurnOff (); Blink, send shutdown SMS, turn off
}else if (tempFSmoothedValue > 72 && state == STATE_GAS_HIGH){ // or after countdown passes threshold
state = STATE_TURN_OFF; // Triggers doTurnOff (); Blink, send shutdown SMS, turn off
}
}
//=============================================================================
// Low Pass Filter to smooth Temperature readings
//=============================================================================
//Low pass filter to smooth the temerature readings
int digitalSmooth(int dataValue, int * sensorSampleArray ){
int j, k, temp, top, bottom;
long total;
static int i;
static int sorted[filterSamples];
boolean done;
// increment counter and roll over if necc. - % (modulo operator) rolls over variable
i = (i + 1) % filterSamples;
sensorSampleArray[i] = dataValue; // input new data into the oldest slot
for (j=0; j<filterSamples; j++){ // transfer data array into anther array for sorting and averaging
sorted[j] = sensorSampleArray[j];
}
done = 0; // flag to know when we're done sorting
while(done != 1){ // simple swap sort, sorts numbers from lowest to highest
done = 1;
for (j = 0; j < (filterSamples - 1); j++){
if (sorted[j] > sorted[j + 1]){ // numbers are out of order - swap
temp = sorted[j + 1];
sorted [j+1] = sorted[j] ;
sorted [j] = temp;
done = 0;
}
}
}
// throw out top and bottom 15% of samples - limit to throw out at least one from top and bottom
bottom = max(((filterSamples * 15) / 100), 1);
top = min((((filterSamples * 85) / 100) + 1 ), (filterSamples - 1));
// the + 1 is to make up for asymmetry caused by integer rounding
k = 0;
total = 0;
for ( j = bottom; j< top; j++){
total += sorted[j]; // total remaining indices
k++;
}
return total / k; // divide by number of samples
}
Click to Expand
require 'json'
require "sinatra"
require 'shotgun'
require 'active_support/all'
require "active_support/core_ext"
require 'rake'
require 'particle' # require particle gem to talk to the photon
require 'twilio-ruby' # connect to twilio
# enable sessions for this project
enable :sessions
# Load environment variables using Dotenv. If a .env file exists, it will
# set environment variables from that file (useful for dev environments)
configure :development do
require 'dotenv'
Dotenv.load
end
# CREATE A CLient
client = Twilio::REST::Client.new ENV["TWILIO_ACCOUNT_SID"], ENV["TWILIO_AUTH_TOKEN"]
particle_client = Particle::Client.new( access_token: ENV['PARTICLE_ACCESS_TOKEN'] )
# Use this method to check if your ENV file is set up
get "/" do
"Hello world!"
end
get "/from" do
ENV["TWILIO_FROM"]
end
# Test sending an SMS
# change the to to your number
get "/send_sms" do
client.account.messages.create(
:from => "+XXXXXXXXXX",
:to => "+1XXXXXXXXXX",
:body => "Hey there. This is a test"
)
"Sent message"
end
# Hook this up to your Webhook for SMS/MMS through the console
get '/incoming_sms' do
session["counter"] ||= 0
count = session["counter"]
sender = params[:From] || ""
body = params[:Body] || ""
body = body.downcase.strip
body_toint = body.to_i
event_data = ""
print session["counter"]
print session["last_context"]
if body.include? "off" or body.include? "quiet"
event_data = "notifoff : #{ body }"
message = "Notifications have been turned off."
elsif body.include? "on"
event_data = "notifon : #{ body }"
message = "Notifications are now on."
elsif body.starts_with? "set"
event_data = "settime : #{ body }"
message = "How many days do you want the timer to last? Depending on the food, 5-15 days is usually best. (Reply with just a number.)"
elsif body_toint < 4 and body_toint > 0
event_data = "#{ body }" # Removing to extract int more easily - "numdays_short:"
message = "Timer set for #{ body } days. Fun fact, savethefood.com says most food can be stored more than 3 days. To reset timer, type any number >3 or if you want to keep as is, just place me in the fridge."
elsif body_toint >= 4 and body_toint <= 30
event_data = "#{ body }" # Removing to extract int more easily - numdays_OK:
message = "Great! Timer is for #{body} days. Go ahead and place me in the fridge."
elsif body_toint > 30
event_data = "numdays_long : #{ body }"
message = "Whoaaaa, #{ body } days?! My batteries wont last that long. Lets stay under a month. Enter a number 1-30."
elsif body.include? "bye"
event_data = "bye:#{ body }"
message = get_bye
else
event_data = "error:#{ body }"
message = get_error
end
particle_client.publish(name: "smart_food/sms/incoming/#{sender}", data: event_data)
session["counter"] += 1
twiml = Twilio::TwiML::Response.new do |r|
r.Message message
end
content_type 'text/xml'
twiml.text
end
error 401 do
"Sorry, I didn't get that."
end
def get_context
session["last_context"] || nil
end
BYE = ["Cheerio.", "Tata for now.", "Hasta la vista, baby"]
def get_bye
return BYE.sample
end
ERROR_SAMPLES = ["Sorry, I did not get that. Type SET to adjust the timer. Otherwise, put me in the fridge.", "Hmmm, je ne comprende pas. Please enter a value 1-30 or place me in the fridge.", "WHAT DID YOU SAY TO ME?! Oh, sorry. Wrong chat. But could you repeat that?"]
def get_error
return ERROR_SAMPLES.sample
end
Click to Expand
Improve discoverability of hidden or forgotten food in the fridge, even if you're not at home.
Private project repo: https://github.com/daraghbyrne/advancediot2017/tree/master/students/mpowel/final-sprint
May 16th, 2017