---
# System prepended metadata

title: An exploration into sleep quality analysis using Iot

---

# An exploration into sleep quality analysis using Iot
**a project by** Jon-Erik Ersson Je223rm

For this project i built a simple sensor station with the intent to collect data while sleeping. This allows me to compile the data into my sleep diary for further analyzing. I started of with some pretty simple sensors and code, but after having completed the project i have many ideas on how to expand in the future.

If you don't have any problems with your software, the whole project should only take a couple of hours to assemble. 

## Objectives
I have long suffered from problems related to sleep and therefore i saw this as a perfect opportunity to experiment with some ideas I've had and to learn a bit about Iot and hobby electronics. Something I've been interested to get into the past year.

Since this is my first Iot project i had some simple goals in mind:
1. Learn the basics of Iot
2. Gather and display some data
3. Find a real life use case instead of just mindlessly hoarding data.
4. Get more insight into what happens when I'm sleeping

Hopefully this project will give me a bit more insight to what's going on when sleeping and how the enviroment effects sleep. I'm also planning for this give me a good basic knowledge of Iot allowing me to expand and work on more advanced projects in the future. 
## Bill of materials
Now let's take a look at the materials used in this project.
I'll explain the specifics further down. 

| Part                 | Quantity | Price estimate |
| --------             | -------- | -------- |
| Lopy4                | 1        | €38.45   |
| Expansionboard v3    | 1        | €17.60   |
| Micro USB data cable | 1        | €3,81    |
| DHT11 sensor         | 1        | €4,79    |
| Photoresistor module | 1        | €3,89    |
| Breadboard           | 1        | €5,77    |
| Jumper wires, male/male | 10    | €3,81    |
| Jumper wires, female/male | 10  | €3,81    |
| **Total**            |          | ~ €81.93 |

Shipping and vat not included

I bought all the components in a kit from [Electrokit](https://www.electrokit.com/) so price and availability may differ. Prices show here are an estimation based on availability in Sweden.

### Development board, [Lopy4](https://pycom.io/product/lopy4/)
Lopy4 is the main board is used for this project. It's programmmed with micropython and for connectivity it supports LoRa, Sigfox, WiFi and Bluetooth, making it a pretty exeptional board. For this project however i will only be using wifi. This means that the simpler and cheaper WiPy will work as well.
#### Expansion board
Now that we have a developmentboard we also need a way to connect it over USB. The expansionboard is a great way to add power and easy to access pinout points to our project. Here I'm using the Pycom Expansionboard v3.1.

*If you're going with pycom, pay attention to the version number, you might have to update the firmware if you get a v3.0. I didn't need to on my v3.1.

**Make sure you get a USB cable that works with your board. Some USB cables only supply power so make sure you get one that can handle data as well.
### Sensors
#### DHT11
The DHT11 is a digital temperature and humidity sensor. It's cheap and easy to work with.

Looking at the data sheet in we can see that it works great for normal indoor use.
![](https://i.imgur.com/MLPasrt.png)
However, with a bottom temperature range of only 0°C I'm sceptical about using it outside since it can get pretty cold around here.

The **DHT22** is another great option and can be seen as a straight upgrade.
A bit more expensive but also more accurate with a better meassuring range.
It can meassure humidity between 0 and 100% and temperature between -40 to 80°C allowing it to be used for outside temperature measurement.

*The DHT11 and DHT22 aren't the fastest senors around so we can only pull data from them every couple of seconds.

### Photoresistor
The photoresistor is an analog sensor module that meassures light levels.
The output value increases the darker it gets and decreases with more light.
It's also very cheap and easy to work with.
### Wires and breadboards
A **breadboard** isn't a necessity but a definite nice to have. I personally went with a half-sized board and it was plenty enough.

For **wires** i just went with some basic single-core male/male jumper wire. They are cheap and pretty easy to come by. Most hobby electronic stores should have these.
Female/male jumper wires can also be pretty nifty. You could for example use them between the sensor and the breadboard to get some distance or use them to connect the sensor directly to your expansionboard.

## Getting our computer ready (Arch Linux)
In order to program our pycom device we'll need something called pymakr. I'll try to go through the steps I needed to take in order to get it running. But if you're running a different system you might want to read the documentation on the official site [here.](https://pycom.io/products/supported-networks/pymakr/)

Currently I'm running instantOS, an Arch based distro, as my system and as you'll notice, this will make some things easier and some things more difficult.
### Prerequisites
First off, make sure you have nodejs installed on your system. Might as well make sure you also have python installed. They are pretty easy to install but I think both gets shippped on my system. This can easily be checked by just typing `node` or `python` in the terminal.
![](https://i.imgur.com/t7k1Iv9.png)

### Getting the right permissions
If you're on Linux there is another step we probably have to complete. In order to access the computers serial ports we need to add our user to the right group. On Arch this is typically `uucp` and on some other systems `dialout`.

We can easily add our user to a group using `usermod`
`sudo usermod -a -G uucp $USER`

*If we want to know what port is owned by who and what group has access we can type `ls -l /dev` (with the board plugged in) and then search for it. Since i already know I'm searching for ttyAMC0 i can just type `ls -l /dev/ttyACM* `
![](https://i.imgur.com/X7iMObG.png)

**If we then also want to make sure that our user is in the right group we can type `groups $USER` to see what groups our user is in.

Next up we get to choose our IDE!
### Setting up our IDE
Sadly though, we only get two choices, Visual Studio Code and Atom , since pymakr is in their extension libraries. 

And that's why i tried getting it to work in a completly different IDE called Onivim2 (with a not so good result). [**Onivim2**](https://onivim.io/) is a modal editor based on vim and VSCode that i've been trying out for a while now. And since it uses the extension ecosystem of VSCode i thought i'd try getting it to work. I got it to install but sadly that's it. It didn't work past that.

So then it was off to my next choice. [**VSCodium**](https://vscodium.com/)
It's basically a community-driven foss version of VSCode but with stripped out telemetry and licensing.
On my system I'm using **yay** as an AUR-helper, so installing VSCodium is as easy as:
* `yay codium`
* selecting the version you want
* and then letting the package manager do it's thing.

Here you can see that i already have it installed.
![](https://i.imgur.com/W6qJa51.png)

Lastly we have to get pymakr installed. If you're running Atom or VSCode you can just search for it in the extensions but since I'm using codium I'll have to install it manually. It's super easy though.
*  Head over to the pymakr download site [here](https://marketplace.visualstudio.com/items?itemName=pycom.Pymakr).
* Scroll down a bit, click the download button and download the vsix fille.
![](https://i.imgur.com/LKXRSKx.png)
* Open up codium, go to the extensions tab, click the three dots, select Install from VSIX... choose the file we downloaded.
* Let it install and were done!
* We can now access the device through the new REPL terminal in our IDE.
This i also where we'll be uploading our code.

### Updating your device
One last thing. It's usually recomended to update your devices firmware when you start working with it. And to be honest, updating my Lopy4 was both confusing and troublesome. What finaly worked for me was to update it trough device activion on Pybytes using the pymakr plugin in my IDE. After it had connected it would update itself over Wifi. I'll talk more about Pybytes in the choice of platform section.
You can also read more updating a pycom device in their official [documentation](https://docs.pycom.io/updatefirmware/device/).


## Putting the hardware together
This is probably the easiest part and will be very quick. Just connect both sensors to 3v3 and ground and then the data-pins to some available ports on the expansion board. Make sure that you connect everything to the right power-pin or you might damage your sensors. Take a look at the datasheets so you know what pins to connnect where. 
Here's how I put mine together.
![](https://i.imgur.com/VOOTAsJ.png)


## Choice of platform
I decided to start with pybytes since it was free and seemed easy to get running.
All i had to do was to: 
* Register at https://pybytes.pycom.io/
* Go to devices and register a new device
* Select the right model
* Set up networking 
* And lastly copy-pasting a string into pymakr

After using it for while however it became clear that it's lacking severly in some aspects. It's still good to get you running with your project but i just felt that it didn't have the customisability that I was looking for. And most importantly. I couldn't find an easy way to export and download my data.

After searching aroud a bit ubidots seemed like a good choice. It's a bit more complicated to set up but not too bad. There's also a lot of people using it so there's plenty to read about.
Poking around a bit i found out that a buch of stuff i wanted to make can be done directly in ubidots.
For example i could make the dashboard display data in averages. I could also setup the OpenWeather plugin allowing me to compare my data with weather data for free. And lastly, since data is stored for 30 days and easily download it gives me plenty of time to compile the data.

To get started you can sign up for a free acount at https://ubidots.com/stem/
When you have an account ready you need to send data to ubidots using your given token for your device to actually show up. When it's there it should already have your data set up as datapoints.
I actually got stuck on this part for an hour. Apparently, a while before i got everything ready to send data, my Wifi connection stopped working and i didn't notice. The device connected to the router fine it just couldn't access the internet.
So if your device is not showing up, make sure it's actually connected to the internet.

You can also check out their tutorial on setting up a pycom board using Wifi over http [here](https://help.ubidots.com/en/articles/961994-connect-any-pycom-board-to-ubidots-using-wi-fi-over-http).
## The Code
If you're new to programming this can be a bit scary but the code we're working with is pretty simple. We'll be using sensors libraries which means that getting the data from our sensors will be really easy.

Here's the file structure for the project.
```
project root folder
|-lib
|  |-dht.py
|  |-urequests.py
|-main.py
|-boot.py
|-keys.py
```

The lib folder is where we keep all the libraries were using. ureqyests is the ubidots library and dht is for the DHT11 sensor.
You can find them here:
[DHT sensor library](https://github.com/iot-lnu/applied-iot/tree/master/sensor-examples/DHT11%20%26%20DHT22%20-%20Humidity%20%26%20Temperature%20Sensor)
[ubidots library](https://github.com/jotathebest/micropython-lib/blob/master/urequests/urequests.py)

The **keys** file is where i keep ssids and passwords for my wifi connection. I also keep my ubidots token there. 
It looks something like this.
```
wifi_ssid = "ssid"
wifi_password = "password"
wifi2_ssid = "ssid"
wifi2_password = "password"
ubidots_token = "xxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

```

All that then happens in boot. py is that were connecting to Wifi, and that looks something like this.
```
nets = wlan.scan()
for net in nets:
    if net.ssid == keys.wifi_ssid: # Getting ssid from keys.py
        print('Network found!')
        wlan.connect(net.ssid, auth=(net.sec, keys.wifi_password), timeout=5000)
        while not wlan.isconnected():
            machine.idle() # save power while waiting
        print('WLAN connection succeeded!')
        print(wlan.ifconfig())
        break
```
The rest of the code is all in **main. py**

Setting up our sensors is pretty easy. 
```
# Sets up the DHT11 sensor as a variable
# The library supports both the DHT11 and DHT22 so: Type 0 = dht11, Type 1 = dht22
dht = DHT(Pin('P23', mode=Pin.OPEN_DRAIN), 0)
time.sleep(2) # This is just give it some time starting up. Instantly pulling data might give weird readings.

# Sets up the Photoresistor
LightSensorPin = 'P20'
lightPin = Pin(LightSensorPin, mode=Pin.IN)  # set up pin mode to input
# create an ADC object bits=10 means range 0-1024 the lower value the less light detected
adc = ADC(bits=10)
# attn=ADC.ATTN_11DB measures voltage from 0.1 to 3.3v
apin = adc.channel(attn=ADC.ATTN_11DB, pin=LightSensorPin)
```

The function that reads data from the DHT11 is pretty neat since it uses recursion whenever it fails to read.
```
# Functions
def read_dht():
    result = dht.read()
    while not result.is_valid(): # If result fails, use recursion until we get a valid result
        print("Failed to read from DHT")
        time.sleep(.5)
        result = read_dht()

    return result.temperature, result.humidity
```
The functions used to send data to ubidots is basically a straight copy from their setup tutorial since it works so well. 
```
# Builds the json to send the request
def build_json(variable1, value1, variable2, value2, variable3, value3):
    try:
        data = {variable1: {"value": value1},
                variable2: {"value": value2},
                variable3: {"value": value3}}
        return data
    except:
        return None

# Sends the request. 
def post_var(device, temperature, humidity, lightvalue):
    try:
        url = "https://industrial.api.ubidots.com/"
        url = url + "api/v1.6/devices/" + device
        headers = {"X-Auth-Token": TOKEN, "Content-Type": "application/json"}
        data = build_json("temperature", temperature, "humidity", humidity, "LightSensitivity", lightvalue)
        if data is not None:
            print(data)
            req = requests.post(url=url, headers=headers, json=data)
            return req.json()
        else:
            pass
    except:
        pass
```
## Getting our data on the internet 
Since I'll be keeping the device in my room I just went with Wifi and http since my connection and coverage is pretty good, plus there's usually no outages. I also travel alot between my dorm room and my parents house so lora and sigfox isn't really and option where they live. Wifi however I'm usually guaranteed to have. Even in places where the connection has been poor the Lopy have had no problem connecting to the internet.

Since ubidots already have functionality that i wanted built in, there's not a lot going on on the development board. It just reads and sends data, at the moment, every 20 minutes. I'm not going for super accurate data here. I just want to a general idea of what's going on during the night. 

*Depending on how much data you're sending, switching to a more lightweight procotol might be a better idea. Something i want to research more.

### Displaying the data
For this project I actually didn't really have a need to display data since I'm planning to just collect data that i can later compile in my sleep diary.
It's still nice to have one to glannce at once in awhile. And i definitely recommend getting comfortable handling data and dashboards in whatever platform you choose. In ubidots I found it pretty easy and intuiative to set up.

This is how my dashboard currently looks like in ubidots.
![](https://i.imgur.com/bhSk3eg.png)
 
## Final thoughts
**And here's the final project!**
![](https://i.imgur.com/QiAbQP5.jpg)

*You can see that i have connected my sensors the other way around compared to the earlier diagram. 



At the moment I'm not doing alot with the data. The main use for it right now is to use it as an extra variable in my sleep diary, hopefully giving a better perspective on my sleeping habits.
I do however have tons of ideas on how to continue from here.

For example, here are some more sensors I'm planning to set up.
* **Body temperature**
Not sure about the best way to track body temp yet.
* **Pulse**
I've played around a bit with the one i have now, i just don't have a good way to attach it and track the data yet. Requires som further experimentation.
* **Skin moisture / humidity (sweat)**
Not sure how to yet.
* **Another light sensitivity sensor in the window** 
Lets me compare it with the one in the room.
* Maybe another temperature sensor outside, instead of the weather plugin, giving me real-time data more accurate to my location
* The CCS811 air qualty sensor also seems interesting.

I'm also interested in working on some kind of database sytem where I can keep my sleep diary and at the same have sensor data being added automatically.

One other last thing I would like to work on are webhooks and power efficiency.
I think there's alot of things to improve there.