# Tutorial for Pycom Fipy with Pysense 2.0 X using LoRaWAN monitoring temperature and humidity
#### by Kristoffer Nowén student kn222tm
This was my first iot device, so it was a test and learning experience. My idea was to measure temperature and humidity around the house to have something easy to get started with, and I was a little curious of what readings I will get. I use a Pycom Fipy and Pysense 2.0 X to read the data and send it with LoRaWAN and present the data with Datacake. It took me about three weeks to learn this and set it up, but if you have some familiarity with this stuff it will go really fast with a Fipy and Pysense. Maybe just a couple of hours.
## Objective
I want to see how temperature and humidity change during the day and night and in different rooms, even different places in the room, in my home. Do some places get to hot in the summer or to cold in the winter? Same goes with humidity. Does it get to high or low, and when?
Also I wanted to try IoTs out and learn a little about it.
## Material
| Object | Bought from | Price |
| -------- | -------- | -------- |
Pycom Fipy with headers | Electrokit | Bundle
Pycom Pysense 2.0 X | Electrokit | Bundle
Micro USB cable | Electrokit | Bundle
Antennae | Electrokit | Bundle
Bundle | | 1524SEK
Battery holder with a switch and JST connector | Electrokit | 29SEK
3 x AAA battery
On top is the Fipy, then the Pysense, the antennae and last the battery holder.

The Fipy, Pysense, antenna and micro USB cable were part of a bundle from Electrokit( also included some sensors, jumpwires, resistors, LED lights and a breadboard). The pysense was a substitution for something undeliverable, so it would probably raise the price. The original bundle contained an expansion board without sensors, so I did get some sensors too, but since sensors are included in the Pysense I will use one of them.
The Fipy is a microcontroller programmed by MicroPython. It controls the actions of the device and can be connected to a computer via micro USB (through the expansionboard) to upload files and change the code it is running. It can send over many different wireless networks, for example WiFi and LoRa.
The Pysense is an expansion board that you connect the Fipy to. It will supply power from an USB connection or battery and have built in sensors. The built in sensor I will be using is SI7006A20. It measures temperature and humidity with a built in analog to digital converter. Temperature accuracy is stated to be ±1° C and relative humidity ±5%. The ranges are -10° to 85°C and 0 to 100%.
Compared to DHT11 (±2°C, ±5% )and MCP9700A (±2°C) that means less work and acceptable readings. Initially the SI7006A20 was off by about +3-4°C, but when I put the Fipy to deep sleep for at least 10 minutes it started to read +1°C compared to a regular thermometer - the expected accuracy.
## Computer setup
#### IDE
I am using Windows and have worked with Atom and the Pymakr plugin. Sometimes I had a hard time starting the device in safe mode with Atom and used Visual studio code (Pymakr plugin) to reset the device, but everything else worked much better in Atom for me. You will need to install Python. I don't remember if you need Node js for atom, but you do for Visual studio code.
Download and install atom from [atom.io](https://atom.io/)
Download and install Node js from https://nodejs.org/en/
Download Python from https://www.python.org/downloads/
Then start up Atom and look for the plugin Pymakr and install it, go through File, then Setting and then Install. There you write Pymakr and choose to install it when it is found.
#### Update the fipy firmware
Download and install the Pycome Firmware Update from https://docs.pycom.io/updatefirmware/device/
This file might not be downloaded so often, so some browsers may try to reject it. Close all IDEs and connect the Fipy to the Pysense and the Pysense to the computer and run the update. You should choose type: pybytes (I think we were told to use development, unless of course if we were using Pybytes, but when I was troubleshooting to get my LoRa upload to Datacake after deepsleep and nvram_restore to work, one tip was to flash the device with Pybytes, so I did. When I tried with it flashed to development it didn't work). Port is probably automatically detected.

In advanced settings you can choose FileSystem: FatFs; Erase during update and Reset CONFIG partition and NVS partition. Check that you have the right region.

#### Update pysense firmware
You might need to update the Pysense firmware too. Instructions are found on Pycoms page https://docs.pycom.io/updatefirmware/expansionboard/
#### Upload the code
Open atom. Open a folder that will be your project. Create a new file called main.py. Here you put what you want the device to do. Also create a file called boot.py. Here you put the code to connect to a network. Create a folder in your project and call it lib. Here you will put the libraries you will use.
Make sure you save the files in Atom. Open the Pymakr plugin, there is an icon to do this in the bottom right. Connect your device with micro USB. Your device should automatically be found. You may need to select your project in the top left of the REPL command, the window that Pymakr opened. In the left panel of Pymakr there is an option to upload. It should upload the code. If the device is sleeping you need to restart it or wait till it wakes.
I used Visual Studio Code a couple of times, to put the device in safe mode and disrupt running code, to be able to upload new code. For some reason Atom couldn't do it a couple of times. Besides that Atom worked much better for me. Maybe you can flash the device also in those situations, but this was faster for me.
## Putting everything togehter
I will be using the built in sensors, so there is no need to attach any sensors.
The Fipy should be connected on top of the Pysense, with the Fipys rgb led in the same end as the Pysense micro usb connector. In the same end, the antennae should be connected, right next to the reset button on the Fipy. It can be a good idea to attach the antennae right away, because you may damage the device if you try to connect to LoRa without it.
When programming the device you should connect with the micro USB to the computer. Later you should connect the battery holder. Make sure the battery holder is not connected when you connect with the micro USB - because if it is it will try to charge the batteries.

The sensors are built into the Pysense, so they get power and can send data through it. The Pysense will provide power to the Fipy and also send the sensor data to it. The Fipy then sends the data with LoRa.
This project is meant for development only. To learn for yourself and maybe test around the house.
## Platform
I tried Pybytes with a wifi connection first. It worked fine but I felt a little limited when I set up the dashboard. Then I tested Datacake with wifi. I feel I got more possibilities in the dashboard and more control of what to do with the data. Then finally I tested Datacake with a LoRaWAN connection, on the Helium server. Pybytes doesn't have integrations for the Helium server, and I only have coverage for Helium, so that made my choice for Datacake easy. I have had some problems to get LoRa to work with my deep sleep and could have gone for wifi, since I am at home anyway, but I wanted to try to use LoRa.
Datacake is flexible and easy. You can use wifi or LoRa to send data to it and it is, reasonably, easy to connect to. There is a decoder where you put your own code to handle the incoming data. You will get a dashboard where you can create widgets that will show your latest readings and a history view for older ones. The values are stored in Datacakes database and can be viewed in Datacake or sent to you as a report in a csv file. It is based in the cloud and there is no need for you to store data by yourself unless you want to. You can also set up rules, sending email or SMS notifications in case of certain readings or if the device goes offline.
I am using the free plan. This means I can set up two devices. The data will be saved for one week, which is enough for me and I can keep the reports at home if I want.
I don't really see a point of scaling this, but you could buy cheaper microcontrollers with cheaper external sensors and set them up in more locations. Meaning more devices on datacake that have dashboards you can follow. You would then have to have a paying plan to get access to more devices on Datacake. You could pay 5 EUROs per month and device to store data one year to scale up the time span, or save your reports and organise them yourself to get a longer timespan of data.
#### Set it up
Get an account on Helium Console before you sign up on Datacake. Add a device. Give it a name. Here you see Dev EUI, APP EUI and App Key. You will use them later (can be accessed later). Save. Now you can run the boot.py to connect to LoRa on Helium, if you use the code provided in boot.py in the code section below and paste in your dev EUI, app EUI and app key. You should leave out this part
```python=
lora.nvram_restore()
if (lora.has_joined() == True):
print("Already joined to LoRa")
else:
```
You need to come back to Helium to set up an integration and flow with Datacake, but first you must do some things on Datacake.
You need to set up an account on Datacake. Then add a device. Choose your connection - LoRaWAN. Choose new product and give it a name. Now choose LoRaWan server Helium. Paste in your Dev EUI from Helium and choose a name for your device. You can start with a free plan.
Up to the left corner you have your profile. Click on it and choose Edit. Up to the left in your profile you click API. Click to show and copy the key. This is used for the Helium Datacake integration.
Go back to Helium. Choose Integrations and create a new one. Choose Datacake. Here you enter your Datacake token and then name your integration.
Now choose Flows, to the left. Click on the + sign in nodes. Drag and drop your device and integration and then connect them by drawing a line between them with your mouse. Done.
## The code
Write boot.py to connect to LoRa. This file is run first when you start the device. It sets up your connection. Then the device moves on to main.py.
Make these imports and then create an instance of LoRa.
```python=
from network import LoRa
import time
import binascii
lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
```
When you set up your device on Helium console you will get the values for dev_eui, app_eui and app_key which must be inserted here to authenticate your device when connecting.
Put in a time.sleep to make it easier to interrupt the code if you want to upload something new.
```python=
time.sleep(2)
dev_eui = binascii.unhexlify('0000000000000000')
app_eui = binascii.unhexlify('0000000000000000')
app_key = binascii.unhexlify('00000000000000000000000000000000')
```
When you call to connect you use lora.join(), choosing Lora Over The Air Authentication, giving your authentication credentials that you just put in the code.
```python=
lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0)
```
I will be putting the device in deep sleep causing it to restart and run this again, so add lora.nvram_restore to use a connection if there is already one. The nvram_restore comes before lora.join. Check if your connected. If not, do lora.join and use a while loop to see when your connected.
```python=
lora.nvram_restore()
if (lora.has_joined() == True):
print("Already joined to LoRa")
else:
lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0)
while not lora.has_joined():
time.sleep(2.5)
print('Not joined yet...')
print('Network joined!')
```
In your lib folder you should create pycoproc_2.py and SI7006A20.py and copy the code from https://github.com/pycom/pycom-libraries/tree/master/shields. This will give you the code needed to call the deep sleep and sensor functions.
Set up main.py. Make necessary imports
```python=
import time
import pycom
from pycoproc_2 import Pycoproc
import machine
from SI7006A20 import SI7006A20
import socket
```
Set up a socket. This will be used to send data.
```python=
s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)
s.setblocking(True) #I needed to make this blocking when I started using lora.nvram_restore. I think the device have to record a response from the LoRa server and use it when I restore the session. It will be changed to false below.
```
Create instance of the pycoproc class and turn of the Pycom heartbeat.
```python=
py = Pycoproc()
pycom.heartbeat(False)
```
Create instance of your sensor.
```python=
si = SI7006A20(py)
```
Use the sensor to read temperature and humidity and put in floats. Also read the battery voltage and put the value in a float. Temp should have two decimals, humidity none and battery one.
```python=
temp = round(si.temperature(), 2)
humidity = round(si.humidity())
battery = round(py.read_battery_voltage(), 1)
```
Convert temp, humidity and battery to one integer that will be sent to Datacake. This will be packed up with the decoder in Datacake and split up in three values again.
```python=
tempAndHumidity = int(temp*1000000+humidity*100+battery*10)
```
Convert that to bytes, because you have to send bytes in LoRa.
```python=
bytes_to_send = tempAndHumidity.to_bytes(4, 'big')
```
And then send it
```python=
s.send(bytes_to_send)
```
Add a time.sleep before nvram save (it was adviced when I was troubleshooting, so it has time to execute). When the device deep sleeps it will lose its LoRa connection, but you can save it and restore it, with nvram_save here and nvram_restore in boot.py. Also make the socket non-blocking so it doesn't keep waiting for a response indefinitely.
```python=
time.sleep(5)
s.setblocking(False)
lora.nvram_save()
```
Since the Fipy gets hot and will cause the sensor to read wrongly by several degrees, I put it into deep sleep for 15 minutes. This keeps it cool and saves energy.
```python=
py.setup_sleep(900)
py.go_to_sleep()
```
## Transmitting the data / connectivity
I use LoRaWAN and send data on the Helium network. Helium has an integration to Datacake. I think it is using a webhook to forward data when I upload.
I read the sensors and get float values, which I combine into an integer and then convert to bytes. To conserve bandwidth LoRa devices send readings as bytes. In Datacake I use the decoder to unpack the values and reverse the process back into my three float sensor values. The javascript code for the decoder is taken from The Introduction to Applied IoT tutorial for Datacake with a small change to accomodate three values.
The bytes are unpacked into an integer using a for loop, turned into a string and then split up into values used to create the values for temperature, humidity and battery voltage (parsed back into floats) which are returned into the fields at the end. The fields are then used in the dashboard and so on.
```javascript=
function Decoder(payload, port) {
var payload_integer = 0
for (var i = 0; i < payload.length; i++) {
payload_integer = (payload_integer << 8) | payload[i];
}
payload_string = payload_integer.toString()
values = [payload_string.slice(0,2)
,payload_string.slice(2,4)
,payload_string.slice(4,6)
,payload_string.slice(6,7)
,payload_string.slice(7)]
temp = parseFloat(values[0]+'.'+values[1])
humidity = parseFloat(values[2])
battery = parseFloat(values[3]+ '.'+values[4])
return [
{
field: "TEMPERATURE",
value: temp
},
{
field: "HUMIDITY",
value: humidity
},
{
field: "BATTERY",
value: battery
}
];
}
```
I send the data aproximately every 15 minutes.
## Presenting the data
This is my dashoboard for desktop

And this is my dashboard for smartphones

For desktop I have the current value for temperature, relative humidity and battery voltage and then a chart both for temperature and relative humidity, showing one week. This gives me an overview to easily see how values are changing over the day and the current value, updated approximately every 15 minutes.
I use a free account. That means the data is only retained for one week in the Datacake database, which is more than enough for me at this point. It was easy to set up a report that sends the data to me if I want to keep it longer. Or to pay for storage up to 12 month.
Every uploaded payload is saved in the database, provided your paying plan has enough datapoints. In my case the free plan include 500 datapoints per day. Every measurement in the payload equals one datapoint each time it is sent. 3 measures times four times per hour times 24 hours is 288, my max. I am not sure if Datacake counts the number of values in the payload or the number of fields returned. Anyway, I'm under my limit.
#### Set up the dashboard
In datacake you go to your devices. Then you click on the device to use. You will get a menu for the device. Mark Dashboard. To the right there is an icon, toggle it. Now you can add a widget. I am using Value, to display current value for batteryvoltage, temperature and humidity in three different widgets, and Chart, to display a series of values for temperature and humidity in two widgets. Give it a title and then choose Data. Here you choose which field it will display, in what unit and how many decimals. Save. You can move them around as you like. On top of the widgets there is button if you want to make a seperate one for a mobile view. After your done, remember to toggle the icon up to the right before you refresh the page, or you lose what you made.
## Finalizing the design
All in all, I think the project went well. The main purpose was to learn, which I did, and now I can learn more. I had no clear objective beyond that. I was able to set up the device and connect sensors, but opted to use the Pysense own sensors. I connected to Wifi and Lora and I hope I will be able to connect to LTE on my own later, and I could send data to Pybytes and Datacake.
My LoRa connection, or something, is not entirely stable, so maybe something could have been done better. Or I might have low coverage from the Helium network. Not all data is uploaded and the device goes offline every now and then and then comes online. I sometimes get four readings every hour and sometimes only one reading per hour, or even miss an hour. But I don't know what it is. I would probably get more stable upload of data with wifi, but drain the batteries faster, if I should want to do it that way.
The temperature readings I think got acceptable when I put the device in deep sleep. There is a heater function for getting rid of moist that might accumulate on the sensor and make the humidity readings wrong, but that will increase the temperature readings. Maybe some alternations could be made, to try and get more accurate readings. For example I could first read temperature when the device is cool, start the heater and wait a little, then read the humidity and send the values. Then go to deep sleep and repeat.
Here is a picture of the end product. The USB cable is still on because it is difficult to remove and I was adviced it is easy to break the connector if you keep removing and connecting. And I think I will test some more.
