Week 9

Radio, WiFi, Bluetooth (IoT)

Radio, WiFi, Bluetooth (IoT)
Live Light Sensing App

Goal

I worked with Shavonna to create a web app that can display the level of light detected in a room remotely. The application could theoretically be used to monitor light levels during remote experiments. In order to do this, we used an ESP32 Feather microcontroller with Wifi communication functinality. We referenced a Random Nerd Tutorial that contained steps for using the ESP32 Feather microcontroller to connect to a live database (Google Firebase). In this way, the web app could routinely retrieve data from the ESP32 Feather microcontroller wirelessly via WiFi communication. Further, the login authentication setup allowed multiple users' data to be observed simultaneously from different computers.

Fabrication

We used a voltage divider circuit configuration—with a 1kΩ resistor and photoresistor in series—to send the light sensing data to pin 36 of the ESP32 Feather microcontroller. The circuit is shown to the right. The Arduino Code shown at the bottom of the page includes a section dedicated to classifying the light level based on the input from the light sensor. Both the integer input and string light intensity classifier were stored in a firebase live database under my user profile.

Light Sensor Circuit
Light Sensor Circuit
Sensor App Login
Sensor Readings App Login Page
Sensor App
Screenshot of Sensor Readings App

We created a simple interface using html to allow users to login and view their sensor data retrieved from the live databse. The javascript files for login authentication and data retrieval are located at the bottom of the page. Once a user successfully enters their username and password, they are shown page containing the light level and intensity classification. Screenshots of the web app are shown above.

Set-Up

You can access the web app here.

Try logging in with User: chibbyu@gmail.com and Password: password

Web App Demo
Web App Demo

Code

Javascript Files: Authetentication Login Script, Database Retrieval Script

The Arduino Code:


            #include 
            #if defined(ESP32)
              #include 
            #elif defined(ESP8266)
              #include 
            #endif
            #include 
            #include 
            // #include 
            // #include 

            // Provide the token generation process info.
            #include "addons/TokenHelper.h"
            // Provide the RTDB payload printing info and other helper functions.
            #include "addons/RTDBHelper.h"

            // Insert your network credentials
            #define WIFI_SSID "MAKERSPACE"
            #define WIFI_PASSWORD "12345678"

            // Insert Firebase project API Key
            #define API_KEY "AIzaSyAon2ynHDelmzsgpDOaxDtV4IzfppnIXps"

            // Insert Authorized Email and Corresponding Password
            #define USER_EMAIL "chibbyu@gmail.com"
            #define USER_PASSWORD "password"

            // Insert RTDB URLefine the RTDB URL
            #define DATABASE_URL "https://esp-firebase-week-9-default-rtdb.firebaseio.com/"

            // Define sensing pin
            #define LIGHT_SENSOR_PIN 36

            // Define Firebase objects
            FirebaseData fbdo;
            FirebaseAuth auth;
            FirebaseConfig config;

            // Variable to save USER UID
            String uid;

            // Variables to save database paths
            String databasePath;
            String lightPath;
            String levelPath;

            // BME280 sensor
            //Adafruit_BME280 bme; // I2C
            //float temperature;

            // Timer variables (send new readings every three minutes)
            unsigned long sendDataPrevMillis = 0;
            unsigned long timerDelay = 10000;

            // Initialize BME280
            // void initBME(){
            //  if (!bme.begin(0x76)) {
            //    Serial.println("Could not find a valid BME280 sensor, check wiring!");
            //    while (1);
            //  }
            //}

            int light = analogRead(LIGHT_SENSOR_PIN);
            String lightlevel = "";

            // Initialize WiFi
            void initWiFi() {
              WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
              Serial.print("Connecting to WiFi ..");
              while (WiFi.status() != WL_CONNECTED) {
                Serial.print('.');
                delay(1000);
              }
              Serial.println(WiFi.localIP());
              Serial.println();
            }

            // Write integer values to the database
            void sendInt(String path, int value){
              if (Firebase.RTDB.setFloat(&fbdo, path.c_str(), value)){
                Serial.print("Writing value: ");
                Serial.print (value);
                Serial.print(" on the following path: ");
                Serial.println(path);
                Serial.println("PASSED");
                Serial.println("PATH: " + fbdo.dataPath());
                Serial.println("TYPE: " + fbdo.dataType());
              }
              else {
                Serial.println("FAILED");
                Serial.println("REASON: " + fbdo.errorReason());
              }
            }

            void sendStr(String path, String level){
              if (Firebase.RTDB.setString(&fbdo, path.c_str(), level)){
                Serial.print("Writing value: ");
                Serial.print (level);
                Serial.print(" on the following path: ");
                Serial.println(path);
                Serial.println("PASSED");
                Serial.println("PATH: " + fbdo.dataPath());
                Serial.println("TYPE: " + fbdo.dataType());
              }
              else {
                Serial.println("FAILED");
                Serial.println("REASON: " + fbdo.errorReason());
              }
            }

            void setup(){
              Serial.begin(9600);

              // Initialize BME280 sensor
             // initBME();
              initWiFi();

              // Assign the api key (required)
              config.api_key = API_KEY;

              // Assign the user sign in credentials
              auth.user.email = USER_EMAIL;
              auth.user.password = USER_PASSWORD;

              // Assign the RTDB URL (required)
              config.database_url = DATABASE_URL;

              Firebase.reconnectWiFi(true);
              fbdo.setResponseSize(4096);

              // Assign the callback function for the long running token generation task */
              config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h

              // Assign the maximum retry of token generation
              config.max_token_generation_retry = 5;

              // Initialize the library with the Firebase authen and config
              Firebase.begin(&config, &auth);

              // Getting the user UID might take a few seconds
              Serial.println("Getting User UID");
              while ((auth.token.uid) == "") {
                Serial.print('.');
                delay(1000);
              }
              // Print user UID
              uid = auth.token.uid.c_str();
              Serial.print("User UID: ");
              Serial.println(uid);

              // Update database path
              databasePath = "/UsersData/" + uid;

              // Update database path for sensor readings
              lightPath = databasePath + "/light"; // --> UsersData//light
              levelPath = databasePath + "/level"; // --> UsersData//level
            }

            void loop(){
              // Send new readings to database
              if (Firebase.ready() && (millis() - sendDataPrevMillis > timerDelay || sendDataPrevMillis == 0)){
                sendDataPrevMillis = millis();

                // Get latest sensor readings
                light = analogRead(LIGHT_SENSOR_PIN);

                // Get Description
                    if (light < 40) {
                    lightlevel = "Dark";
                  } else if (light < 800) {
                    lightlevel = "Dim";
                  } else if (light < 2000) {
                    lightlevel = "Light";
                  } else if (light < 3200) {
                    lightlevel = "Bright";
                  } else {
                    lightlevel = "Very bright";
                  }

                // Send readings to database:
                sendInt(lightPath, light);
                sendStr(levelPath, lightlevel);
                
              }
            }