Try   HackMD

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/

Grove components. Grove sensor boards by seeeduino are reliable and easy to connect. 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/

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.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

The folder can be empty at first.

Visual studio will ask if you trust the folder

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Just in case click on Download one more time, sometimes it forgets to download some files.

Now you should be seeing something like this:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Later when you do changes, then you can save and upload the codechanges the same way.

Putting it together

Diagram.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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):

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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

#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:

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