Wearing Face Mask
We all know that face masks have been the new accessory since the pandemic started. It is advisable that everyone should wear a mask when going in public places especially in crowded or places of business. It's the best way to reduce one's risk of getting infected or infecting another person. However, there are still lot of people like me, who tend to forget to wear a mask when going outside. We only realize it later on that we are not wearing a face mask when we encounter people outside wearing it and giving us a disapproving look. Well, stepping out of your door without wearing face mask doesn't only risk yourself but also the whole community. There are communities who take this very seriously wherein one could be arrested or punished for not wearing a mask.
Washing Hands
One more thing we need to consider and always observe during this pandemic, is proper handwashing. Proper handwashing not only reduces the spread of Coronavirus, it can prevent the spread of other viral illnesses such as cold and flu. It is a must that after returning from a public place (grocery store, work, school, concert, sporting activity, hospital, nursing home, etc.), one should wash his/her hands with soap and water and if possible, use an alcohol-based hand sanitizer. But people also always tend to forget to do that.
My SolutionAs a solution, I created a smart tag which send push notification to your smartphone that will remind you to wear a face mask when you'll go outside and tell you to sanitize yourself upon returning home.
How Does It Work?
The tag can be attached to your personal belongings like your bag, ID lace, or keys. These things are what you usually pick up when you go out so when you pick it up, the tag will detect it and will send a notification to your phone that you should wear your mask before going outside.
And upon returning to your house, the tag will also detect it and it will send you again a notification telling you to sanitize.
How I built It?Components
The tag is uses SoC(ESP32), accelerometer(ADXL335) to detect motion periodically and a 500 mAh Li-Poly Battery as a power source.
Wiring
The ADXL335 accelerometer module has 5 pins, namely
- GND-To be connected to Arduino's GND
- VCC-To be connected to Arduino's 3.3V
- X-To be connected to Analog Pin 32
- Y-To be connected to Analog Pin 33
- Z-To be connected to Analog Pin 35
Be sure to use only ADC1 pins of the ESP32 because the WiFi messes up the analog readings in ADC2 pins.
The ESP32's VIN and GND is connected to the battery. You can also hook up a switch between them so you'll get the option to turn on/off the tag.
TheBlynkApp
Download the BLYNK App in your smartphone and create an account. Create a new project and select ESP32 as your board. You'll receive your auth token in your email and place that in your code.
Inside the app, create new widgets(Timer and Notification). You no longer need to change anything in the Notification widget. But in the Timer widget, set the virtual pin to V1(because that's the virtual pin we're calling in our code) and also set the time you want for your tag to go to sleep.
Programming
The tag was programmed using Arduino IDE and runs the following code. Be sure to install the ESP32 board and download all the necessary libraries for the code to be compiled and upload to your board. I written comments along with the code for you to better understand it.
//deep sleep
#include "esp_sleep.h"
#include "sys/time.h"
RTC_DATA_ATTR static time_t last;
RTC_DATA_ATTR static uint32_t bootcount;
RTC_DATA_ATTR int previousState = 2;
#define GPIO_DEEP_SLEEP_DURATION 15
struct timeval now;
//for wifi
#include <WiFi.h>
#include <WiFiClient.h>
char ssid[] = "wifi";
char pass[] = "pass";
int attempts = 1;
//gy-61 pins. remember that *use only adc1 pins beacuse wifi is messing up the adc2 pins*
const int xpin = 32, ypin = 33, zpin = 35;
//calibrate variables
int totalx, totaly, totalz, calibratex, calibratey, calibratez;
//acceleration
float totalAcce, initialAcce, difference;
int motionCounter;
//blynk
int timer = 0;
#define BLYNK_PRINT Serial
#include <BlynkSimpleEsp32.h>
char auth[] = "Get it on your email";
void setup()
{
Serial.begin(9600);
gettimeofday(&now, NULL);
last = now.tv_sec;
Serial.println(previousState);
WiFi.begin(ssid, pass);
//check if the tag is inside the house
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
Serial.println(attempts);
attempts++;
//since the tag can't connect to home wifi and our previous states indicates that it was picked earlier, we'll change its state to 0 to indicate that it's outside
if (attempts == 5 && previousState == 1) {
previousState = 0;//indicates that it was outside the house
Serial.printf("out! enter deep sleep for 10 mins\n"); //the device will go to deep sleep for 10minutes
esp_deep_sleep(1000000LL * 15);
Serial.printf("in deep sleep\n");
}
//there are chances that we'll lost connection in the wifi even tho we didn't go outside. In that case we'll just go to deep sleep for 1 min and try to reconnect again. State wont be change.
if (attempts == 5) {
Serial.printf("wifi not detected! enter deep sleep for 2 mins\n"); //the device will go to deep sleep for 2minutes
esp_deep_sleep(1000000LL * 60);
Serial.printf("in deep sleep\n");
}
}
//if the tag is inside the house it will proceed to the following
calibrateSensor();
getInitialAcce();
//determine whether the tag is in motion or at rest
for (int i = 0; i <= 10; i++) {
getMotionChange();
if (difference >= 70) {
motionCounter++;
}
Serial.println(motionCounter);
}
//if the tag was previously outside and went inside and not in motion, it means that the owner just went home so we'll notify him to wash his/her hands
if (previousState == 0 && motionCounter < 3) {
previousState = 2; //indicates that the tag is now inside the house
Serial.println("Please Wash Your Hands");
notifyIn();
//go to deep sleep
Serial.printf("in! enter deep sleep for 10 mins\n");
esp_deep_sleep(1000000LL * 600);
Serial.printf("in deep sleep\n");
}
//if the tag was inside the house and set in motion, it means that the owner just picked the tag because maybe he'll go outside so we'll notify him to wear a facemask
if (motionCounter >= 3 && previousState == 2 || previousState == 1) {
previousState = 1; //indicates that the tag was picked
Serial.println("Please don't forget to wear mask");
notifyOut();
//go to deep sleep for 5mins and upon restart will check if the owner was outside
Serial.printf("picked! enter deep sleep for 5 mins\n");
esp_deep_sleep(1000000LL * 15);
Serial.printf("in deep sleep\n");
}
//since the tag is already inside and w/o motion, we'll check the timer from the blynk, to see if it's late at night so the tag can go to deep sleep until morning to save power
if (previousState == 2 && motionCounter < 3) {
checkTime();
if (timer == 1) {
//i set the timer in the blynk app to go to sleep when it's 8pm until 6 am, thats 10 hours so the tag will sleep for 36000 seconds.
Serial.printf("sleep! enter deep sleep for 10 hours\n");
esp_deep_sleep(1000000LL * 36000);
Serial.printf("in deep sleep\n");
}
//if it's not between 8pm and 6 am, the tag shouldn't sleep and just continue to see if it will be picked up by the owner. So we'll just set it to sleep for 30sec
else {
Serial.printf("enter deep sleep for 30secs\n");
esp_deep_sleep(1000000LL * 30);
Serial.printf("in deep sleep\n");
}
}
}
void loop()
{
}
void notifyIn() {
Blynk.config(auth);
while (Blynk.connect() == false) {
Serial.print("x");
}
Blynk.notify("Hey, Rod! Please ensure to clean and sanitize your body.");
delay(500);
}
void notifyOut() {
Blynk.config(auth);
while (Blynk.connect() == false) {
Serial.print("x");
}
Blynk.notify("Hey, Rod! Don't forget to wear mask before going outside.");
delay(500);
}
void checkTime() {
Blynk.config(auth);
while (Blynk.connect() == false) {
Serial.print("x");
}
for (int i = 0; i <= 5; i++) {
Blynk.run();
Blynk.syncAll();
}
}
BLYNK_CONNECTED() {
//get data stored in virtual pin V0 from server
Blynk.syncVirtual(V1);
}
BLYNK_WRITE(V1) {
Serial.println(param.asInt());
timer = param.asInt();
}
//calculate the difference between the initial total acceleration and current total acceleration to determine if there is motion change
void getMotionChange() {
int x = (analogRead(xpin) - calibratex);
int y = (analogRead(ypin) - calibratey);
int z = (analogRead(zpin) - calibratex);
totalAcce = pow(pow(x, 2) + pow(y, 2) + pow(z, 2), 0.5);
Serial.print(totalAcce);
Serial.println( "total acc");
Serial.print(x); //print x value on serial monitor
Serial.print("\t");
Serial.print(y); //print y value on serial monitor
Serial.print("\t");
Serial.print(z); //print z value on serial monitor
Serial.print("\n");
delay(200);
difference = abs(initialAcce - totalAcce);
Serial.print(difference);
Serial.println(" Motion Change");
}
//get the initial average reading from the sensor for calibration
void calibrateSensor() {
for (int i = 0; i <= 200; i++) {
int x = analogRead(xpin);
totalx += x;
int y = analogRead(ypin);
totaly += y;
int z = analogRead(zpin);
totalz += z;
}
calibratex = totalx / 200;
calibratey = totaly / 200;
calibratez = totalz / 200;
}
//get the initial total acceleration of the device in all axis
void getInitialAcce() {
int x = (analogRead(xpin) - calibratex);
int y = (analogRead(ypin) - calibratey);
int z = (analogRead(zpin) - calibratex);
totalAcce = pow(pow(x, 2) + pow(y, 2) + pow(z, 2), 0.5); //compute the total acceleration in all axis
Serial.print(totalAcce);
Serial.println( "initial acce");
initialAcce = totalAcce;
}
Enclosure
You can design an enclosure to your smart tag depending on your preference. You can use your 3D printer if you want. But since I don't have a 3D printer at home, I just used a cardboard and create a simple enclosure for it.
Comments