49713 Designing for the Internet of Things
· 16 members
A hands-on introductory course exploring the Internet of Things and connected product experiences.
Our goal is to encourage people to drink 67oz water every day and stay with a healthier lifestyle.
Sophia is a busy people who care a lot about health and want to avoid dehydration. She knows that she has drink 67oz water every day but she always forgets how much water she drinks. Thus, she wants to have a smart bottle as an ambient device to reveal the water consumption amount, which can be solved by 67oz.
Our smart bottle can track how much water a user drink every day and use the length of the LED light strip to reveal the volume of water consumption.
Each adult should drink 67oz (2000ml) water every day. We designed the bottle volume is 500ml. So, people need to drink above 4 bottles that can meet the standards. When they finish 500ml, the stripe will light one LED. All of the light will light when people drink 4 bottles at least.
For this project, our team has several challenges:
How to detect the water level?
How to detect the volume of people's drinking and refilling?
How to make it ambient and unobtrusive?
When we decided using a DIY water level sensor, we began to follow the reference to make the product. We finished the circuit, but it was really hard to complete the code part. Jiangtao made a heavy contribution in that part by asking for professor's and classmates' help. The code also needs to be iterated in different versions. For instance, we tried several times to define the baseline of water level detection, 2270, 2300, ......
After a series of iterations, we made a successful outcome for our project.
#include <neopixel.h>
#define PIXEL_PIN D2
#define PIXEL_COUNT 5
#define PIXEL_TYPE WS2812
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
uint32_t colorOn = strip.Color(255, 255, 255);
uint32_t colorOff = strip.Color(0 , 0 , 0);
int switchPin = D3;
int resetbuttonPin = D4;
const int output27 = D5; // pin 27 sends a "0" or "1" (0 -3.3 V) to the waterlevel measurement circuit
const int LevelSensorPin = A4;
int flag = 0;
// 12 bits ADC pin 34 senses the voltage level of the waterlevel sensor (values 0 - 4095)
int WaterLevelValue = 0; // Variable to store the value of the Waterlevel sensor
int level = 0; // Variable of the WaterLevel
int fadeCycle = 0;
int previousAmount = 0;
int startAmount = 0;
int totalConsumed = 0;
int change = 0;
int currentAmount = 0;
// 0 1 2 3 4 5
int LEVELarray [6] = {2100,2600,3300,3750,4000} ; // Array with the level reference values to determine the waterlevel
// the "0" level is applicable when there is no water in the reservoir
// the "5" level is applicable when the reservoir is full
unsigned long elapsed = 0;
unsigned long now = 0;
unsigned long starttime = 0;
int running = 0;
int start (String e){
Particle.publish( "running", String(running));
starttime = millis();
running = 1;
return running;
}
int r = 255;
int g = 20;
int b = 147;
uint32_t colorPink = strip.Color(255, 20, 147);
int displayTimeFor = 10000;
int displayTimeFadeOut = 5000;
unsigned long startedDisplayAt= -1;
// this will be triggered when
// there is a change in consumption
// or if the button has been pressed.
bool shouldShowDisplay = false;
void setup() {
Serial.begin(115200);
pinMode(output27, OUTPUT); // Initializes the power output pin (3.3 V) for the WaterLevel Sensor circuit
digitalWrite(output27, LOW); // Set output27 to LOW; this will send 0 V to the measuring circuit
pinMode(LevelSensorPin, INPUT); // Initializes the water level sensorpin
pinMode(PIXEL_PIN, OUTPUT); // Initializes the output pin for the WaterLevel Indicator
pinMode(switchPin, INPUT_PULLUP);
pinMode(resetbuttonPin, INPUT_PULLUP);
Particle.variable( "change", change );
Particle.variable( "totalConsumed", totalConsumed );
Particle.variable( "previousAmount", previousAmount );
Particle.variable( "currentAmount", currentAmount );
Particle.variable("elapsed", elapsed);
Particle.variable("starttime", starttime);
Particle.variable("Fading", fadeCycle);
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
void loop(){
int buttonState = digitalRead( switchPin );
int resetState = digitalRead( resetbuttonPin );
// press the button
if( resetState == LOW ){
if (flag==0) {
starttime = millis(); //mark the startime
flag = 1;
}
elapsed = millis() - starttime; //caculate elapsed
}
// Handle the button push
if (flag ==1 && elapsed > 2500){ // or add another button
// turn the LED On nd off one by one
Initialization();
flag= 0;
}
if ( buttonState == LOW ) {
// the LED display should be turned on
shouldShowDisplay = true;
}
// measure the current water level
measureWaterlevel();
if( shouldShowDisplay ){
startedDisplayAt = millis(); //mark startdisplay
// set the color to pink
r = 0;
g = 0;
b = 0;
// mark the display as hidden
shouldShowDisplay = false;
}
// now we can use startedDisplayAt
// to find if the display is on
else if( startedDisplayAt == -1 ){
// set all the LEDs off
r = 0;
g = 0;
b = 0;
}
else{
// the timer is running....
int displayElapsed = millis() - startedDisplayAt;
if( displayElapsed > displayTimeFor ){
// the display time has elapsed.
// turn the display off
startedDisplayAt = -1 ;
}
else if( displayElapsed < displayTimeFor - displayTimeFadeOut ){
// display it as a solid color during the middle 5 seconds
r = 255;
g = 20;
b = 147;
}else {
int last5Sec = displayElapsed - (displayTimeFor - displayTimeFadeOut);
// fade it out over 5 seconds
r = 255 - map( last5Sec, 0, displayTimeFadeOut, 0, 255);
g = 20 - map( last5Sec, 0, displayTimeFadeOut, 0, 20);
b = 147 - map( last5Sec, 0, displayTimeFadeOut, 0, 147);
}
}
indicateAmount();
delay(50);
}
// Check for new value every 1 sec;
//this value is just for demonstration purposes and will in a practical application be far less frequent
void measureWaterlevel() {
digitalWrite(output27, HIGH); // make pin 27 HIGH
delay(100); // allow the circuit to stabilize
WaterLevelValue = analogRead(LevelSensorPin); //Read data from analog pin and store it to WaterLevelvalue variable
for (int i = 0; i < 5 ; i++){
if ((WaterLevelValue > (LEVELarray[i] * 0.94)) && (WaterLevelValue < (LEVELarray[i] * 1.06))){
level = i;
}
digitalWrite(output27, LOW); // make pin 27 LOW
Serial.print(" LEVELarray: ");
Serial.print(level);
Serial.print(" = ");
Serial.print(LEVELarray[level]);
Serial.print(" -: ");
Serial.print( i );
Serial.print(" -: ");
Serial.print(" WaterLevelValue: ");
Serial.print(WaterLevelValue);
Serial.print(" Level: ");
Serial.println(level);
}
}
void indicateAmount(){
if ( level == 0 ){ currentAmount = 0;
}
if ( level == 1 ){ currentAmount = 100;
}
if ( level == 2 ){ currentAmount = 250;
}
if ( level == 4 ){ currentAmount = 400;
}
if ( level == 5 ){ currentAmount = 500;
}
// after define the currentamount, then do the caculation
accumulateAmount();
// 0 led
if (totalConsumed < 300){
for(int t=0; t<5; t++){
strip.setPixelColor(t, 0, 0, 0);
strip.show();
}
}
// 1 led
if (totalConsumed >= 300 && totalConsumed < 800){
for(int t=0; t<1; t++){
strip.setPixelColor(t, r, g, b);
strip.show();
}
}
// 2 led
if (totalConsumed >= 800 && totalConsumed < 1200){
for(int t=0; t<2; t++){
strip.setPixelColor(t, r, g, b);
strip.show();
}
}
// 3 led
if (totalConsumed >= 1200 && totalConsumed < 1600){
for(int t=0; t<3; t++){
strip.setPixelColor(t, r, g, b);
strip.show();
}
}
// 4 led
if (totalConsumed >= 1600 && totalConsumed < 2000){
for(int t=0; t<4; t++){
strip.setPixelColor(t, r, g, b);
strip.show();
}
}
// 5 led
if (totalConsumed >= 2000){
for(int t=0; t<5; t++){
strip.setPixelColor(t, r, g, b);
strip.show();
}
}
}
void accumulateAmount(){
int consumedAmount = startAmount - currentAmount;
change = currentAmount - previousAmount;
if ( previousAmount < currentAmount ){
// the amount has changed by refilling
startAmount = currentAmount;
// trigger the display to light up
shouldShowDisplay = false; //change made
} else if ( previousAmount > currentAmount ){
// the amount has changed by drinking
totalConsumed = totalConsumed + abs(change);
// trigger the display to light up
shouldShowDisplay = true;
}
previousAmount = currentAmount;
}
void Initialization(){
//individually lightup
for(int i=0; i < 5; i++) {
strip.setPixelColor(i, colorOn );
strip.show(); //update pc
delay(200);
}
delay(1000);
for (int k = 4; k > -1 ; k--) {
strip.setPixelColor(k, colorOff);
strip.show();
delay (200);
}
delay(200);
for(int i=0; i < 5; i++) {
strip.setPixelColor(i, colorOff );
strip.show();
delay(200);
}
totalConsumed = 0;
}
Click to Expand
1. There are multiple ways to visualize information other than using UIs.
2. A better understanding of the sensors: the things happen behind the sensors are certain physical laws, for instance, using the conductivity of water to reveal the water level.
3. The structure of code is very important: a clean and structured code could fast the processing speed and enhance the stability, efficiency, easy of debugging of a system.
4. Physical limitations should be considered when making a product, some ideas should yield to the current technology.
5. The structure of a team should be given much attention because people would do a better job if they were assigned to sth that they are familiar with or at least is related to their previous background.
A hands-on introductory course exploring the Internet of Things and connected product experiences.
Our goal is to encourage people to drink 67oz water every day and stay with a healthier lifestyle.
November 21st, 2019