# Tutorial on how to build a sleep conditions monitoring system
* Created by Martin Laak (student id: ml225en)
* July 2021
* Short project overview: I wanted to improve my sleep quality. I wanted to measure different attributes that can contribute to my sleep quality, like light, temperature and humidity. On an advance level I also want to measure blood-oxygen and heart rate to assess my sleep throut the night. It could also be usefull for catching sleep apnea episodes (with theoxygen sensor).
* Time it will take: about 1h
## Objectives
* Why I chose this project?
I am not happy with my sleep quality, I am hoping to improve it with the help of this IoT device.
* What purpose does it serve?
It records both the conditions in my room and data about my sleep. Also in the future it could be used as a remote monitoring system to monitor a persons condition (heart rate and co2) and their surroundings (ambiant temperature ...).
* What insights will it give?
I am hoping to study which factors improve my sleep and which don't. As a remote monitoring system it could alert if something is wrong with the person (for example falling blood oxygen level).
## Materials
| NAME | PRICE | COMMENT |
| -------- | -------- | -------- |
| **LoPy4** | 414 sek |The Iot board (the microcontroller), based on ESP32. Programmable with MicroPython. This will be the brain of the whole thing. I bought it on Rs: (Rs 162-8047) https://se.rs-online.com/ |
| **Pycom expansion board** | 247 sek |The extension board for the IoT board. Makes it easyer to program and connect. I bought it on Rs: (Rs 125-9534) https://se.rs-online.com/ |
|Any breadboard, for example **Luxorparts Kopplingsdäck 400 anslutningar 2-pack**|90 sek|Breadboard makes it easier to connect cables. I bought it on Kjell: https://www.kjell.com/
|Jumper cables (female to female) and for advanced also male to female, for example **SUNFOUNDER 120 st jumper-kablar**|73 sek|Jumper cables to connect things. I bought on Amazon: https://www.amazon.se/
<!-- And one of the following options -->
Grove components. Grove sensor boards by seeeduino are reliable and easy to connect. <!--They usually contain all the resistors that might be needed.--> They are designed to be connected to grove enabled IoT devices (with grove connectors), which LoPy4 is not, however with grove-to-jumper cables, these moduls can be connected to anything.
| NAME | PRICE | COMMENT |
| -------- | -------- | -------- |
|**Grove - 4 pin Male Jumper**|18 sek|These cables are used to connect grove sensor modules to non-grove boards. Can be bought on Mouser: (Mouser 713-110990210) https://www.mouser.se/ (I bought it on amazon but they no longer sell it)
|**Grove Beginner Kit for Arduino**|206 sek|This kit includes arduino uno with grove connectors (not needed by us) and a selection of grove modules (needed by us). The easiest and probably cheapest way to get all the needed modules. Can be bought on Mouser: (Mouser 713-110061162) https://www.mouser.se/ (I bought it on amazon but they no longer sell it)
| - - Grove Light Sensor|included| The light sensor is used to meausere the ambient light in the room. It can tell when the lights are switched off in the room (thus going to bed time) and also light levels throughout the night. This sensor will be connected to an analog port and it's analog voltage level read (corresponds to light intensity)
| - - Grove Temperature & Humidity Sensor|included|This DHT11 sensor gives ambient temperature and humidity readings. I am interested in how these things influence the sleep quality and also how these change doring the night also. This sensor will be connected to a digital port and there is a library to help communicate with this sensor.
| - - Grove - Barometer Sensor (BMP280)|included| Can air pressure influence sleep quality? Barometric pressure change is known to affect health issues. Sleep? Maybe this is why I sleep better on some days than others? Would be interesting to find out. As a bonus this module also measures temperature, so I can use it in combination with the other sensor to improve temperature measurement. This BMP280 sensor will be connected through I2C connection.
Advanced level (requires soldering, unless you can find the MAX30102 sensor with the right headers sodered. I am exceptionally bad at soldering but it seems I got the soldering done - after a few hours. Should take less than a minute for a person who knows how to solder.)
| Name | Price | Comment |
| -------- | -------- | -------- |
|**MAX30102 pulsoximeter**|65 sek|This module can be used to measure pulse and blood oxygen level. It shines bright light (both red and infrared) to the finger and bathed on reflecting light, pulse and oxygen can be calculated. https://www.amazon.se/
|angled 2.4mm pin headers, for example **Luxorparts Stiftlist 4-pack 40x1 Vinklad**|30 sek|The module above comes with straight headers to solder. If we want to attach the module to a finger, angled headers are better https://www.kjell.com/
<!--
| O2 | Name | Price | Comment |
| -------- | -------- | -------- | -------- |
||Grove Light Sensor|25 sek|
||Grove Temperature & Humidity Sensor|55 sek|
||BMP280 sensor|?|
| O3 | Name | Price | Comment |
| -------- | -------- | -------- | -------- |
||Grove Light Sensor|25 sek|
||Grove Temperature & Humidity Sensor|55 sek|
||BMP280 sensor|?|
-->
<!--
| Name | Price | Comment |
| -------- | -------- | -------- |
|MPU-6050 3-axlig gyroskop|73 sek| https://www.amazon.se/|
|TCA9548A I2C IIC multiplexer|57 sek|
|MC34063A|105 sek|
|MAX30100 pulsoximeter|84 sek|
|MAX30102 pulsoximeter|65 sek|
|Stiftlist 40 stift, 2-vinklad (5x)|132 sek
|Stiftlist | 36 sek
-->
## Computer setup
* What IDE did I choose?
I chose Visual Studio Code
* How the code is uploaded?
The code needs to be uploaded through visual studio ide using the right plugin as described below.
* Step by step quide:
### Updating firmware
First firmware of LoPy4 needs to be updated. With this step you also connect the board to your Pybytes account.
There is an excellent video about that https://youtu.be/2THov7819GA so I don't think I can really add anything to it. Please whatch the video.
### Vidual studio plugin
There is an excellent tutorial: https://docs.pycom.io/gettingstarted/software/vscode/
You should probably read that first and then come back here.
Essentially what you need to do is to install Visual Studio Code (from https://code.visualstudio.com/), then install node.js (from https://nodejs.org/en/ needed for the plugin). And then install the Pymakr VSCode Extension https://marketplace.visualstudio.com/items?itemName=pycom.Pymakr
Then we need to check the if installation went well. We might need to restart Visual Studio.

Then we need to open a folder where all the files are going to be.

It is also possible to make a new folder in your desired location.

The folder can be empty at first.
Visual studio will ask if you trust the folder

Click yes.
Now click download to download files from the board to your computer. It warns that it might overwright your files if you already have files with the same name in your chooses directory. Click Yes (upper part of the screen)

Just in case click on Download one more time, sometimes it forgets to download some files.
Now you should be seeing something like this:

You can take the code from the Code section of this tutorial and paste it in the main.py
Please note that it is possible to create new files and folders.

Now you can create a forlder lib and place all the library files there that are mentioned in the Code section of this instruction.
Now you can upload the code to your board

Later when you do changes, then you can save and upload the codechanges the same way.
## Putting it together
Diagram.


The LoPy4 sits on the extension board.
The 3.3v and ground pins from the Pycom board are connected to the side rows (the +-) of the breadboard. All the modules power and ground lines go to these side rows for power. Light sensors data line (yellow) is connecting to the port P16 of the Pycom board. The grove-to-jumper cable also has white cable that will remain unconnected. DHT11 Temperature and Humidity sensor yellow data line is connected to the port P3. The white line will again remain unused. For I2C connection, Pycom board port P9 is SDA and port P10 is SCL. The BMP280 white cable connects to P9 (SDA) through the breadboard and yellow cable connects to P10 (SCL) through breadboard. For the maxim30102 board, the voltage and ground are clearly marked, they should be connected to the breadboard power lane. And SDA SCL on module should be connected to P9(SDA) and P10(SCL) through the breadboard. We do not need pullup resistors for maxim30102, since the Grove BMP280 module is on the same I2C line and it already has the pullup resistors (enough for the whole line).
The voltage of 3.3v is used everywhere in this project.
Grove Temperature and Humidity module (other grove modules are similar):

Max30102 pulse and blood oxygen module (had to solder the header, did a terryble job on that) Pictured taped up and raw.

## Platform
The platform I chose is pybytes since it is simple and works very well with LoPy4. It is in the cloud and I am using the free version.
## Code
```python=
#filename main.py
import time,pycom,logging,machine,os,sys
from machine import sleep,Timer,I2C
from lib.dth import DTH
from lib.MAX30102 import MAX30102
from lib.heartbeat import HeartBeat
from lib.bmp280 import BMP280
pycom.heartbeat(False)
logging.basicConfig(level=logging.INFO)
#setup I2C
i2c = I2C(0, I2C.MASTER, pins=('P9','P10'))
print(i2c.scan())
#set up bmp280 sensor
bmp280_sensor = BMP280(i2c,addr=119)
#setup the light sensor
light_sensor = machine.ADC().channel(pin="P16",attn=machine.ADC.ATTN_11DB)
#setup the temperature and humidity sensor
temphumid_sensor = DTH('P3',0)
time.sleep(2)
#setup heart rate and blood oxygen sensor
pulse_sensor = MAX30102(i2c=i2c)
pulse_sensor.setup_sensor()
pulse_sensor.setSampleRate(800)
pulse_sensor.setFIFOAverage(8)
time.sleep(1)
print(pulse_sensor.readTemperature())
heartbeat_detector = HeartBeat()
tick_nr = 1
beat_nr = 0
last_beat_nr = 0
in_function = False
tick_nr = 1
beat_nr = 0
last_beat_nr = 0
in_function = False
# this function will be called every 0.01sec and it works with pulse sensor
# every 1000nds time (10sec) it sends sensor data to pybytes
def timer_function(handler):
global tick_nr
global beat_nr
global last_beat_nr
global in_function
try:
if in_function: #just in case, if last function call is nor ended, let's not start a new.
return
in_function = True
#working with heartbeat
ch = pulse_sensor.check()
if pulse_sensor.available():
red_level = pulse_sensor.popRedFromStorage()
ir_level = pulse_sensor.popIRFromStorage()
if heartbeat_detector.checkForBeat(ir_level):
print("beat ",beat_nr)
beat_nr = beat_nr + 1
if beat_nr%2==0:
pycom.rgbled(0x000033)
else:
pycom.rgbled(0x000000)
tick_nr = tick_nr + 1
#every 10 seconds send sensor data (1000ticks = 10sec)
if tick_nr % 1000 == 0:
#read measurements
bmp280_sensor.force_measure()
th_sensor_result = temphumid_sensor.read()
light = light_sensor()
temp = (th_sensor_result.temperature+bmp280_sensor.temperature)/2.0
humid = th_sensor_result.humidity
pulse = (beat_nr-last_beat_nr)*6
pascals = bmp280_sensor.pressure
#display and send measurements
print(light,temp,humid,pascals,pulse)
pybytes.send_signal(1,light)
pybytes.send_signal(2,temp)
pybytes.send_signal(3,humid)
pybytes.send_signal(4,pascals)
pybytes.send_signal(5,pulse)
last_beat_nr = beat_nr
print("done it")
in_function = False
except Exception as e:
print("Error happened::",e,sys.exc_info())
in_function = False
#set the function run every 0.01 sec - means 100x a sec
timer_handler = Timer.Alarm(timer_function,0.01,periodic=True)
```
Libraries to dowload to lib folder:
* https://raw.githubusercontent.com/dafvid/micropython-bmp280/master/bmp280.py
* https://raw.githubusercontent.com/JurassicPork/DHT_PyCom/pulses_get/dth.py
* https://raw.githubusercontent.com/kandizzy/esp32-micropython/master/PPG/ppg/heartbeat.py
* https://raw.githubusercontent.com/n-elia/MAX30102-MicroPython-driver/main/src/lib/logging.py
* https://raw.githubusercontent.com/n-elia/MAX30102-MicroPython-driver/main/src/lib/MAX30102.py
NB on the last one, need to remove all references to SoftI2C, PyCom does not have it. Alspo don't need it because we give it our own I2C object.
References to the git repos at the end of this document.
## Data connectivity
Data is sent every 10 seconds over wify through AMQP protocol to pybytes platform.
## Data presentation
Data is visualized through pybytes platform. Data is saved pybytes every 10 seconds. Currently it is not going anywhere from pybytes.

## Finalizing the design


The hearbeat sensor only works when perfectly placed on finger. Maybe needs some structural change around the heartbeat sensor or meybe we need a better algorhytm for detecting a heartbeat (the sensor only gives back reflectance values). The algorhytm for blood oxygen calculation was too complex and I did not find a python version of it. I will probably do it sometime later. Interesting project, I will keep working on it.
## Referenses
* https://github.com/n-elia/MAX30102-MicroPython-driver
* https://github.com/kandizzy/esp32-micropython/tree/master/PPG/ppg
* https://github.com/JurassicPork/DHT_PyCom/tree/pulses_get
* https://github.com/dafvid/micropython-bmp280