Sleep Environment Monitor



Everyone knows how important it is to sleep well, both for staying energized and productive and, more importantly, for maintaining good long-term health. Some individuals naturally sleep better than others. Nowadays, we understand that certain behaviors on our part can help, such as adhering to schedules (getting 8 hours of sleep and going to bed before 11 PM for instance), regularly engaging in physical activity, or avoiding screens two hours before bedtime. Through traveling and trying out different rooms, I've noticed that depending on the location, sleep quality can be affected. While we know that the quality of the mattress or pillow can have an impact, it's more challenging to measure the external environment's influence on sleep quality and whether it contributes to restful nights.

Therefore, for this class project, I've chosen to create a system that will help monitor and identify if certain external factors might be causing poor sleep. This could provide insights into what needs improvement (better ventilation, adjusting the temperature, etc.).

Project Description

The idea behind this project is to gather measurements of various physical metrics that can impact sleep. Five metrics have been selected: the amount of light, sound levels, temperature, humidity, and the CO2 concentration (or rather, the CO2 equivalent) in the room. These physical aspects are known to affect sleep, and we are familiar with the scales used to determine if sleep quality is affected.

The values will be collected through sensors managed by an ESP32 and stored in a Firebase database. The user can initiate the recording from a web interface at bedtime and can visualize the progression of measurements throughout the night on the same interface. This will also allow the evaluation of whether certain periods during the night are better than others. An overall score for the surrounding environment's quality, derived from the five metrics, will be displayed by the web interface.


System overview

To use the system, a user utilizes a web interface. Authentication is necessary to protect the data. Multiple users can be connected and use the system simultaneously. On the web interface, the user can either view data from previous recordings or start a new recording. The hardware must be powered on, connected to the internet, and possess the correct identification values to access the remote database. The user needs to place it in the room where they want to take measurements, then they can start and stop the recording from the web interface. The web application and the ESP32 do not communicate directly but access data stored in the cloud within a Firebase database. The database contains the measurements as well as the system state, indicating whether a recording is ongoing or not, allowing for the preservation of the state even after disconnecting from the web application. When a recording is in progress, the data updates in real-time on the web application.

The diagram below provides an overview of the global system logic:



  • BOARD:
    • LOLIN32 v1.0.0 - based on the ESP-WROOM-32 module that integrates WIFI and bluetooth
    • BH1750: a digital ambient light sensor for I2C bus interface
    • CCS811: an ultra-low power digital gas sensor solution which integrates a metal oxide (MOX) gas sensor to detect a wide range of Volatile Organic Compounds (VOCs) for indoor air quality monitoring (I2C interface)
    • HDC2010: a low power and high accuracy integrated humidity and temperature sensor (I2C interface)
    • Dabble soundmeter: Dabble is a Smartphone app that offers modules to control hardware via Bluetooth and especially to access Smartphone sensors. Used in this project to connect to a smartphone's microphone and get a soundmeter.

Circuit Diagram

Real-life view


Used methods for quality rating

For each measurement, the system assigns an overall score calculated from five criteria. The overall score for the recording is the average of these overall scores. As this score is derived from 5 criteria, each criterion constitutes 1/5 or 20% of the score. The calculation is not based on a continuous function but rather on intervals. Each measurement is divided into 5 intervals, and depending on which interval the measured value falls into, it contributes 0, 5, 10, 15, or 20% to the score. In fact, a sixth interval is added which represents the threshold limit. If the value is exceptionally poor and exceeds this interval, it is considered to significantly degrade sleep quality and even outweigh the other criteria. Consequently, the score is lowered by 10%.

These intervals were estimated based on recommendations found in literature (for example, ideal temperature or brightness in a bedroom) and by comparing values to references (what does 40 dB correspond to, for instance). For further information about information sources, please refer to the references section.

To summarize, here are the value intervals and the points they contribute for each measured parameter:

Code & Structure

The application logic is divided into three parts:

  • Administration of the Firebase database
  • The hardware code based on Arduino
  • The web application code made in HTML, JS, and CSS
  • Data structure

The data is organized by users. For greater stability, the system state, i.e., whether a recording is in progress or not, is directly saved in the database. This allows for the disconnection of the web interface or even the ESP32 without crashing the system. Recordings are organized by an ID, and each recording contains multiple measurements taken at regular intervals. Each measurement includes the five metrics collected by the system, along with a timestamp and the overall score evaluated for that specific measurement. The following schema outlines the database structure:

  • Rules and access rights

As seen above, the data is segregated by user. Authentication occurs through email and password, and each user is assigned a unique identifier. Each user can access only their respective data. To achieve this, access rules need to be defined as follows:

  "rules": {
    "UsersData": {
      "$user_id": {
        ".read": "auth !== null && auth.uid === $user_id",
        ".write": "auth !== null && auth.uid === $user_id",

The code is separated into two files: config.h and main.cpp. The configuration file contains #define directives to associate identifiers with tokens that are often used and necessary for the code. This can be, for example, the pin numbers of the board, the paths in the database, the user identifiers for Firebase, or the Wi-Fi codes to which the ESP must connect. Then, the Arduino code is located in the main.cpp file, which is divided into 5 parts:

  • The inclusion of libraries and files
  • The definition of global variables
  • The definition of helper functions which are the init functions, the functions specific to Firebase and the structure of our data, the other functions to operate the actions specific to our code.
//-----------------Helpers Declarations-----------------

//----init functions---------------------

void init_WiFi();
void init_BH1750();
void init_Firebase();
void initUserPaths(); // init the database paths for the specific logged in user
void init_ssenseCCS811();
void init_ssenseHDC2010();

//---------Firebase-dedicated functions--------------------
// Listeners

// Callback function that runs on database changes
void recordingStateListener(FirebaseStream data);
void streamTimeoutCallback(bool timeout);
// Functions related to the Application's database structure
int getNumberOfRecords(FirebaseData *fbdo);
bool incrementNumberOfRecords(FirebaseData * fbdo);
int getRecordSize(FirebaseData *fbdo, int recordId);
bool incrementRecordSize(FirebaseData *fbdo, int recordId);

bool sendData(FirebaseData *fbdo, float light, float sound, float co2, float temperature, float humidity, float global);
bool getAndSendDataFromSensors();

float computeGlobalGrade(float light, float sound, float co2, float  temperature, float humidity);

  • Then, as in all Arduino code, we find the setup and loop functions.

The setup function calls the begin methods of the objects that require it and the init functions that we have defined.

void setup()


  Dabble.begin(BLUETOOTH_DEVICE_NAME); // init Dabble



In the loop function, we make sure to refresh the Firebase token if it has expired and at a regular interval chosen in the configuration when the recording state is activated, we collect the sensor data, calculate the overall score, and send everything to the database. To avoid blocking the Firebase change listeners, the interval is not done with active waiting using the delay(time) function for example. Instead, at each loop, we compare the current time (retrieved with millis()) to the desired interval, from which we subtract the previous date. As the complexity and subtlety of the code have been encapsulated in helpers, the two functions setup() and loop() are concise and remain easy to understand.

void loop()
  if (Firebase.isTokenExpired())
    DebugPort.println("Refresh token");

  if (Firebase.ready() && (millis() - sendDataPrevMillis > TIME_INTERVAL || sendDataPrevMillis == 0))

    sendDataPrevMillis = millis();
    if (recordingState)
      DebugPort.println("Sending data");
      if (!getAndSendDataFromSensors())
        DebugPort.println("Error while sending data from sensors");
  • At the end of the code, you will find the declaration of all the helpers.
Web app

The web project is organized as follows:

Two files specific to Firebase:

  • firebase.json which determines the necessary configuration to host the app
  • database.rules.json which contains the access rights rules described above in the Firebase section

The source code is located in the public directory. It includes:

  • index.html: The HTML code of the application
  • 404.html: What should be displayed in case of a bad URL
  • style.css: The CSS stylesheet for formatting HTML elements
  • A scripts folder that contains JavaScript files to make the page dynamic
    • auth.js: Script specific to managing Firebase user authentication
    • chart-definition.js: Script to define the charts displaying the values (the charts are then manipulated in index.js)
    • index.js: All the rest of the script used to control the index.html page.


The index.html file is constructed as follows:

First, the header which contains notably the inclusion of external references and scripts, the inclusion of the stylesheet, or the initialization of the Firebase config.

Then a topbar that will always be displayed:

  <!--TOP BAR-->
  <div class="topnav">
    <h1 class="topnav-item">Sleep Environment Monitor</h1>
    <div class="topnav-item" id="authentication-bar" style="display: none;">

Then, depending on the connection status, there will either be the login form:

  <!--LOGIN FORM-->
  <form id="login-form" style="display: none;">

or the user interface:

  <div class="content-sign-in" id="content-sign-in" style="display: none;">

    <!-- AVERAGES -->
    <div id="average-measures">
      <!--GLOBAL SCORE-->
      <div id="global-grade-div">
      <div class="chart">

      <!--VALUES AVG-->
      <div id="avg-div">
        <div class="avgs">
          <div class="avg">
          <div class="avg">
          <div class="avg">
          <div class="avg">
          <div class="avg">

    <div id="charts-div">
      <div class="charts">
        <div class="chart">
        <div class="chart">
        <div class="chart">
        <div class="chart">
        <div class="chart">

In the end, we include the three scripts that we have defined:

    <script src="scripts/auth.js"></script>
    <script src="scripts/charts-definition.js"></script>
    <script src="scripts/index.js"></script>


This is what the final interface looks like:

First, a login page:

Then, the interface on which the user can see the latest recording and view the results, select previous recordings or start a new one.

They can see the average rating given, and the average values of each magnitude as well as the evolution during the recording.


This system provides a user-friendly interface for users to gather information on factors that can influence the quality of their sleep, without having to worry about manually measuring light, noise, temperature, humidity, and CO2 concentration.

This project aimed at controlling the quality of the sleep environment has resulted in an initial draft of a system capable of assessing external factors that influence sleep quality.

Although this project has laid the groundwork for thorough monitoring of the sleep environment, it is important to note that it is not comprehensive and does not hold medical values. The results obtained are estimations, and the scientific rigor of the evaluation remains to be improved by closely working, for example, with sleep specialists. Furthermore, for a more comprehensive project, improvements could include integrating new sensors or displaying recommendations to improve sleep based on the measured parameters.

The main objective remained to build an end-to-end IoT project and become familiar with the technical and organizational challenges in this field. In this regard, this project seems to have fulfilled its role, as I feel I have progressed and had the opportunity to go further than what the module's labs proposed.


iothings/proiecte/2023/sleepenvironmentmonitor.txt · Last modified: 2024/01/13 13:05 by taddeo.dadamo
CC Attribution-Share Alike 3.0 Unported Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0