Sergio CuencaLazar GueorguievAnthony Keung
Published © GPL3+

Lane of Things "Classroom Theory"

We are collecting data on how long students leave a classroom for and for what reasons.

IntermediateShowcase (no instructions)2 hours810
Lane of Things "Classroom Theory"

Things used in this project

Hardware components

Photon
Particle Photon
×1
Breadboard (generic)
Breadboard (generic)
×1
Resistor 1k ohm
Resistor 1k ohm
×4
Jumper wires (generic)
Jumper wires (generic)
×14
SparkFun Rocker Switch-SPST (round)
×4
Baltic Birch Wood
×1

Software apps and online services

Data.Sparkfun
Particle Build Web IDE
Particle Build Web IDE
MakerCase

Hand tools and fabrication machines

Laser cutter (generic)
Laser cutter (generic)

Story

Read more

Custom parts and enclosures

Enclosure

The sketch of our box and all of the components inside.

Case plans

A picture of the outline generated by MakerCase. We plugged in our desired dimensions and MakerCase created an outline for a box to be cut out in a laser cutter.

Case Plans (Illustrator File)

A file of our case plans in a .ai format so that you can cut out this exact box with a laser cutter instantly.

Schematics

Fritzing diagram

Code

Code for Particle Photon

Arduino
This finds the duration of a student's absence based on how long one of the four switches is pressed in the "on" position. It takes the data and publishes it to SparkFun's Phant Database.
// This #include statement was automatically added by the Particle IDE.
//This allows you to publish the data to phant. You have to add this line of code by searching "Spark Fun Phant" in the library search in the Particle IDE
#include <SparkFunPhant.h>

const char server[] = "data.sparkfun.com"; // Phant destination server
const char publicKey[] = "mKy8jEy1rLi5DjjWY3W4"; // Phant public key - HAS TO BE CHANGED
const char privateKey[] = "kzeV01eWnYS8nDDaz7ax"; // Phant private key  - HAS TO BE CHANGED
Phant phant(server, publicKey, privateKey); // Create a Phant object

const int POST_RATE = 3000; // Time between posts, in ms.
unsigned long lastPost = 0; // global variable to keep track of last post time

// This #include statement was automatically added by the Particle IDE.
//Allows us to use the real world clock. You have to add this line of code by searching "Spark Time" in the library search in the Particle IDE.
#include <SparkTime.h>
SparkTime rtc;
UDP UDPClient;

//a long that holds the current time, gets updated automatically
unsigned long currentTime;

//Declaring variables for each switch as an input.
const int switchBathroom = 0;
const int switchWater = 1;
const int switchPersonal = 2;
const int switchTeacher = 3;
    
//Creating counters that will keep track of how many times 1 of the 4 switches are turned on and off    
int bathroomCounter = 0; //If someone goes to the bathroom
int waterCounter = 0; //If someone goes to get water
int personalCounter = 0; //If someone leaves for a personal reason ie locker visit
int teacherCounter = 0; //If someone leaves to run an errand for a teacher

//Booleans that will be used to exit a conditional for each switch. This allows 4 switches to be on simultaneously 
boolean switchOnBathroom = true; 
boolean switchOnWater = true;
boolean switchOnPersonal = true;
boolean switchOnTeacher = true;

//All the variables used to keep track of time of absence for bathroom 
int bathroomTimeMins; //Total duration in mins
int bathroomTimeSecs; //Total duration in secs
int bathroomTimeInitialMins; //Time in mins when student leaves
int bathroomTimeInitialSecs; //Time in secs when student leaves
int bathroomTimeFinalMins; //Time in mins when student arrives
int bathroomTimeFinalSecs; //Time in secs when student arrives

//All the variables used to keep track of time of absence for water
int waterTimeMins; //Total duration in mins
int waterTimeSecs; //Total duration in secs
int waterTimeInitialMins; //Time in mins when student leaves
int waterTimeInitialSecs; //Time in secs when student leaves
int waterTimeFinalMins; //Time in mins when student arrives
int waterTimeFinalSecs; //Time in secs when student arrives

//All the variables used to keep track of time of absence for personal reasons
int personalTimeMins; //Total duration in mins
int personalTimeSecs; //Total duration in secs
int personalTimeInitialMins; //Time in mins when student leaves
int personalTimeInitialSecs; //Time in secs when student leaves
int personalTimeFinalMins; //Time in mins when student arrives
int personalTimeFinalSecs; //Time in secs when student arrives

//All the variables used to keep track of time of absence for teacher errands
int teacherTimeMins; //Total duration in mins
int teacherTimeSecs; //Total duration in secs
int teacherTimeInitialMins; //Time in mins when student leaves
int teacherTimeInitialSecs; //Time in secs when student leaves
int teacherTimeFinalMins; //Time in mins when student arrives
int teacherTimeFinalSecs; //Time in secs when student arrives

//booleans that will be used in the postToPhant method in order to dictate which values get pushed
boolean postPhantBathroom = false;
boolean postPhantWater = false;
boolean postPhantPersonal = false;
boolean postPhantTeacher = false;

void setup()
{
    Serial.begin(9600); 
    
    rtc.begin(&UDPClient, "time.nist.gov"); //Setting up connection with RTC
    rtc.setTimeZone(-6); //Setting the time zone
    
    //Declaring each switch as an input
    pinMode(switchBathroom , INPUT_PULLDOWN);
    pinMode(switchWater , INPUT_PULLDOWN);
    pinMode(switchPersonal , INPUT_PULLDOWN);
    pinMode(switchTeacher , INPUT_PULLDOWN);
    
}

void loop() 
{
    //Sets the currentTime variable equal to the current time dictated by the real time clock
    currentTime = rtc.now();
    
    //If a switch is turned on for one of the four reasons, then the counter for each individual reason will increase by one
    /**We set the boolean to false so that the counter only increase by one for everytime the switch is turned on and off; 
    we don't want the counter to continue to be added while the switch is on. We have four different booleans so that multiple
    switches can be on at the same time. 
    **/ 
    if((digitalRead(switchBathroom) == HIGH) && (switchOnBathroom))
    {
        bathroomCounter++;
        switchOnBathroom = false;
        
        bathroomTimeInitialMins = rtc.minute(currentTime);
        bathroomTimeInitialSecs = rtc.second(currentTime);
    }
    if((digitalRead(switchWater) == HIGH) && (switchOnWater))
    {
        waterCounter++;
        switchOnWater = false;
        
        waterTimeInitialMins = rtc.minute(currentTime);
        waterTimeInitialSecs = rtc.second(currentTime);
    }
    if((digitalRead(switchPersonal) == HIGH) && (switchOnPersonal))
    {
        personalCounter++;
        switchOnPersonal = false;
        
        personalTimeInitialMins = rtc.minute(currentTime);
        personalTimeInitialSecs = rtc.second(currentTime);
    }
    if((digitalRead(switchTeacher) == HIGH) && (switchOnTeacher))
    {
        teacherCounter++;
        switchOnTeacher = false;
        
        teacherTimeInitialMins = rtc.minute(currentTime);
        teacherTimeInitialSecs = rtc.second(currentTime);
    }
    
    //Once the switch is turned off, the boolean conditions will be set to true so the next time someone turns on the switch, the counter will increase by 1
    //We then call methods to find the duration of the person's absence in minutes and seconds 
    //Finally we post our data to phant
    if((digitalRead(switchBathroom) == LOW) && (!(switchOnBathroom)))
    {
        switchOnBathroom = true;
        
        bathroomTimeFinalMins = rtc.minute(currentTime);
        bathroomTimeFinalSecs = rtc.second(currentTime);
        
        bathroomTimeMins = diffTimeMins(bathroomTimeInitialMins , bathroomTimeFinalMins);
        bathroomTimeSecs = diffTimeSecs(bathroomTimeInitialSecs, bathroomTimeFinalSecs);
        
        if(bathroomTimeFinalSecs < bathroomTimeInitialSecs)
        {
            bathroomTimeMins--;
        }
        
        postPhantBathroom = true;
        postToPhant();
        postPhantBathroom = false; 
        
    }
    if((digitalRead(switchWater) == LOW) && (!(switchOnWater)))
    {
        switchOnWater = true;
        
        waterTimeFinalMins = rtc.minute(currentTime);
        waterTimeFinalSecs = rtc.second(currentTime);
        
        waterTimeMins = diffTimeMins(waterTimeInitialMins , waterTimeFinalMins);
        waterTimeSecs = diffTimeSecs(waterTimeInitialSecs, waterTimeFinalSecs);
        
        if(waterTimeFinalSecs < waterTimeInitialSecs)
        {
            waterTimeMins--;
        }
        
        postPhantWater = true;
        postToPhant();
        postPhantWater = false;
        
    }
    if((digitalRead(switchPersonal) == LOW) && (!(switchOnPersonal)))
    {
        switchOnPersonal = true;
        
        personalTimeFinalMins = rtc.minute(currentTime);
        personalTimeFinalSecs = rtc.second(currentTime);
        
        personalTimeMins = diffTimeMins(personalTimeInitialMins , personalTimeFinalMins);
        personalTimeSecs = diffTimeSecs(personalTimeInitialSecs , personalTimeFinalSecs);
        
        if(personalTimeFinalSecs < personalTimeInitialSecs)
        {
            personalTimeMins--;
        }
        
        postPhantPersonal = true;
        postToPhant();
        postPhantPersonal = false;
        
    }
    if((digitalRead(switchTeacher) == LOW) && (!(switchOnTeacher)))
    {
        switchOnTeacher = true;
        
        teacherTimeFinalMins = rtc.minute(currentTime);
        teacherTimeFinalSecs = rtc.second(currentTime);
        
        teacherTimeMins = diffTimeMins(teacherTimeInitialMins , teacherTimeFinalMins);
        teacherTimeSecs = diffTimeSecs(teacherTimeInitialSecs, teacherTimeFinalSecs);
        
        if(teacherTimeFinalSecs < teacherTimeInitialSecs)
        {
            teacherTimeMins--;
        }
        
        postPhantTeacher = true;
        postToPhant();
        postPhantTeacher = false;
    }
}

//Finds the duration of absence in mins
int diffTimeMins(int initialMins , int finalMins)
{
    if(finalMins > initialMins)
    {
        return (finalMins - initialMins);
    }
    else if(finalMins == initialMins)
    {
        return 0;
    }
    else
    {
        return ((60 - initialMins) + finalMins);
    }
}

//Finds the duration of absence in secs
int diffTimeSecs(int initialSecs , int finalSecs)
{
    if(finalSecs > initialSecs)
    {
        return (finalSecs - initialSecs);
    }
    else if(finalSecs == initialSecs)
    {
        return 0;
    }
    else
    {
        return ((60 - initialSecs) + finalSecs);
    }
}

//Takes our 12 data points and posts them to phant
//We add values of "-11" as markers. Bc all of our switches arent't pressed all at once, we upload "-11" so we know to delete those values later
int postToPhant()
{    
    // Use phant.add(<field>, <value>) to add data to each field.
    // Phant requires you to update each and every field before posting,
    // make sure all fields defined in the stream are added here.
    if(postPhantBathroom)
    {
        phant.add("bathroom_counter", bathroomCounter);
        phant.add("bathroom_minutes", bathroomTimeMins);
        phant.add("bathroom_seconds", bathroomTimeSecs);
    
        phant.add("water_counter", -11);
        phant.add("water_minutes", -11);
        phant.add("water_seconds", -11);
        
        phant.add("personal_counter", -11);
        phant.add("personal_minutes", -11);
        phant.add("personal_seconds", -11);
        
        phant.add("teacher_counter", -11);
        phant.add("teacher_minutes", -11);
        phant.add("teacher_seconds", -11);
    }
    if(postPhantWater)
    {
        phant.add("bathroom_counter", -11);
        phant.add("bathroom_minutes", -11);
        phant.add("bathroom_seconds", -11);
        
        phant.add("water_counter", waterCounter);
        phant.add("water_minutes", waterTimeMins);
        phant.add("water_seconds", waterTimeSecs);
        
        phant.add("personal_counter", -11);
        phant.add("personal_minutes", -11);
        phant.add("personal_seconds", -11);
        
        phant.add("teacher_counter", -11);
        phant.add("teacher_minutes", -11);
        phant.add("teacher_seconds", -11);
    }
    if(postPhantPersonal)
    {
        phant.add("bathroom_counter", -11);
        phant.add("bathroom_minutes", -11);
        phant.add("bathroom_seconds", -11);
        
        phant.add("water_counter", -11);
        phant.add("water_minutes", -11);
        phant.add("water_seconds", -11);
        
        phant.add("personal_counter", personalCounter);
        phant.add("personal_minutes", personalTimeMins);
        phant.add("personal_seconds", personalTimeSecs);
        
        phant.add("teacher_counter", -11);
        phant.add("teacher_minutes", -11);
        phant.add("teacher_seconds", -11);
    }
    if(postPhantTeacher)
    {
        phant.add("bathroom_counter", -11);
        phant.add("bathroom_minutes", -11);
        phant.add("bathroom_seconds", -11);
        
        phant.add("water_counter", -11);
        phant.add("water_minutes", -11);
        phant.add("water_seconds", -11);
        
        phant.add("personal_counter", -11);
        phant.add("personal_minutes", -11);
        phant.add("personal_seconds", -11);
        
        phant.add("teacher_counter", teacherCounter);
        phant.add("teacher_minutes", teacherTimeMins);
        phant.add("teacher_seconds", teacherTimeSecs);
    }
        	
    TCPClient client;
    char response[512];
    int i = 0;
    int retVal = 0;
    
    if (client.connect(server, 80)) // Connect to the server
    {
		// Post message to indicate connect success
        Serial.println("Posting!"); 
		
		// phant.post() will return a string formatted as an HTTP POST.
		// It'll include all of the field/data values we added before.
		// Use client.print() to send that string to the server.
        client.print(phant.post());
        delay(1000);
		// Now we'll do some simple checking to see what (if any) response
		// the server gives us.
        while (client.available())
        {
            char c = client.read();
            Serial.print(c);	// Print the response for debugging help.
            if (i < 512)
                response[i++] = c; // Add character to response string
        }
		// Search the response string for "200 OK", if that's found the post
		// succeeded.
        if (strstr(response, "200 OK"))
        {
            Serial.println("Post success!");
            retVal = 1;
        }
        else if (strstr(response, "400 Bad Request"))
        {	// "400 Bad Request" means the Phant POST was formatted incorrectly.
			// This most commonly ocurrs because a field is either missing,
			// duplicated, or misspelled.
            Serial.println("Bad request");
            retVal = -1;
        }
        else
        {
			// Otherwise we got a response we weren't looking for.
            retVal = -2;
        }
    }
    else
    {	// If the connection failed, print a message:
        Serial.println("connection failed");
        retVal = -3;
    }
    client.stop();	// Close the connection to server.
    return retVal;	// Return error (or success) code.
}

Credits

Sergio Cuenca

Sergio Cuenca

-1 projects • 0 followers
Lazar Gueorguiev

Lazar Gueorguiev

-1 projects • 0 followers
Lane Tech College Prep 17' | Northwestern University 21'
Anthony Keung

Anthony Keung

-1 projects • 0 followers
Ball is Life

Comments