# Pycom mini weather station for bathing spots
Name: Isac Johansson
Student credentials: ij222jw
All project files are avaliable at my [Github](https://github.com/isac-johansson/applied-iot-1dt305), including code, 3d files and schematics.
## Summary
This project is part of the course Applied IoT 1DT305 at Linnaeus University in Sweden. The aim for this project is to measure water and air temperature together with humidity at a nearby bathing spot. The data will then be sent over the LoRa network. At the time being its presented via the Pybytes platform but the goal is to eventually have it presented on a website with public access.
### Time to make
| Product | Time (hours) | Time accumulated (hours) |
| -------- | -------- | -------- |
| Coding + configuration | 3.0 | 3.0 |
| Soldering | 1.0 | 4.0 |
| 3D designing | 2.0 | 6.0 |
| 3D printing | 3.5 | 9.5 |
| Assembling | 0.5 | 10.0 |
## Objective
I made this project as I want to know the water and air temperature at the nearby bathing spot. It will help me decide if it's worth going for a swim or not. In the long term it will also give me insights to historical temperature changes from year to year.
## Material
| Product | Where to buy | Price (usd) |
| -------- | -------- | -------- |
| Pycom Lopy4 | Antratek.com | 43 |
| Pycom expansion board| Antratek.com | 22 |
| LoRa antenna | Antratek.com | 10 |
| Resistors 4.7k, 2 pcs | Ebay.com | 0.3 |
| Battery with JST-PH connector, 2000mAh | Electrokit.com | 18 |
| JST-PH connector | Electrokit.com | 0.1 |
| Temperature sensor, DS18S20 (waterproof) | Ebay.com | 7 |
| Temperature and humidity sensor, DHT22 | Electrokit.com | 3 |
| Pin connectors | Electrokit.com | 1 |
| Prototype board | Ebay.com | 0.3 |
| 3D printer filament, material: PETG | Sunlu.com | 1 |
| Screws M2 6mm, 4 pcs | Hobbyking.com | 0.3 |
| **Total, VAT included** | | **Approx. $106** |
I chose to use LoRa as the main way of communicating due to its low power consumption together with a fairly long range and established network in most larger cities.
Both sensors used in this project are readily avaliable and cheap. Since I wanted to measure both air and water temperature I had to use different sensors. Instead of using two DS18S20 sensors, which are waterproof, I chose to use the common DHT22 sensor. This gave me the possibility to measure both temperature and humidity, a nice thing to have. Both sensors have a wide userbase, with a great number of libraries as a result.
## Computer setup
Prerequisites: MacOS.
First of all you need to download and install Node.js from https://nodejs.org/en/. This is a requirement for the plugin Pymakr to work. Pymakr is the link between your IDE and Pycom device. It enables you to upload the Python code to the board. If you are on a Mac, you will not need to install any additional drivers.
I first tried to use Visual Studio Code as the IDE but due to shortcommings with syntax highlighting (most likely a user error from my part) I decided to switch to Atom IDE instead, which worked great. Atom IDE is avaliable at https://atom.io. When Atom is up and running you now need to install the Pymakr plugin by going into Atoms settings and clicking on the Packages menu and then search for "Pymakr" and install it. That's it!
The guide to flashing the Pycom device firmware is found in the section **Pybytes setup**.
## Platform
I chose to use the Pybytes platform as it's a fairly simple setup and fulfills this projects basic needs. The platform uses MQTT as its protocol and Pybytes is a cloud based platform. The data is sent over LoRa with The Things Network (TTN) connected to Pybytes. This enables the weather station to operate on a single charge of battery for quite some time (estimating at least two months). The Pybytes setup is described in the next section.
As Pybytes handles the LoRa connection and setup with TTN, it's very user friendly. This works by entering a Pybytes activation token when flashing the Pycom board (also described in the next section). The Lopy4 will then automatically connect to the preferred network(s).
I thought about using Datacake as the main platform, but since Pybytes provides such a simple solution and setup I decided to stick with it.
The data is stored in the Pybytes database for one month, which is enough for this project as there is no need to store it for longer periods of time. In the future it might be interesting to look into having the data transferred to a private database.
The Pybytes platsform makes it possible to display the data in different types of graphs/tables and then having them displayed on the Dashboard. This is how my data is presented in Pybytes:

## Pybytes setup
Since Pybytes handles the connection with TTN (for LoRa), all you need to do is to configure Pybytes and flash the Pycom board. The LoRa connection will be handled by Pybytes TTN account.
First of all, you'll need to create a Pybytes account. Once that is done, you will need to add a device via USB. Click on the device you're using (Lopy4 in my case).

Mark the type of network(s) you want to use and in which priority. If the first one is not avaliable when powering on the Pycom device, it will try the second, and so on.

If the Pycom device is unable to connect to LoRa later on, try selecting LoRa ABP instead of LoRa OTAA. This solved my LoRa problems.

We are now ready to flash the firmware and connect it to Pybytes. Select Provisioning --> Offline firmware updater and click on "Generate new activation token". This will be pasted into the application Pycom firmware updater which you will download in the next step.

### Flashing the firmware
You will now have to flash the firmware on Pycom device, which will also update it. You will find the Pycom Firmware Update application at https://docs.pycom.io/updatefirmware/device/. Download it and open the application.
When updating the firmware, select the Pybytes firmware version. You will need the expansion board whenever you connect the Pycom to the computer. Make sure to position the Lopy4 correctly when connection it to the expansion board (the LED on the Lopy4 should be facing the micro USB port).
If the Pycom board isn't recognized by the computer, change the USB cable. If it still doesen't work, change to yet another one. This is probably the most common problem when trying to get everything working as most micro usb cables are not intended to be used for data transfer.
In the Pycom firmware updater, select the Pybytes firmware and follow the steps. No other selections should be needed. When asked about the Pybytes activation token, paste in the code from the Pybytes website. If you do not get the Pybytes registration prompt, go back or restart the application and tick the box "Force update Pybytes registration" under the Communication section.
Then the firmware is updated, the device will automatically connect to the selected networks when powered on. No further user input or code will be needed to connect to the selected network(s).

Back on the Pybytes website we have to define what the different signals from the device are. In the code provided, signal 0 = Water temperature, signal 1 = Air temperature and signal 2 = Humidity. When Pybytes receives data from the device it will now know what the different values relate to. After adding all the signals you can click on each one of them and specify how you want the data to be presented and if you would like to have it visible on the Dashboard.

## The code
The Pybytes setup automatically configures the Lopy4 to connect to the specified networks and in the arranged order when setting up the device.
The library used for the sensors (with some slight modifications) is provided by [JurassicPork](https://github.com/JurassicPork/DHT_PyCom) and MicroPython [OneWire](https://github.com/micropython/micropython/tree/master/drivers/onewire) library.
Data is sent once every 15 minutes due to the regulatory 1% duty cycle limitation of LoRa, as well as keeping power consumption low. Between data cycles, the Lopy4 goes to deepsleep to preserve battery.
Since the deepsleep mode executes the `boot.py` (followed by `main.py`) once it wakes up, there's no need for a while loop.
Where's not a whole lot of code needed to make this work. When powering up the device it will get the sensor readings. It will then round the values to one decimal and print the values on the screen (if having the device connected to Atom IDE on the computer). Lastly it will send the data to Pybytes and then go to sleep for 15 minutes/900 seconds/900000 milliseconds. Here you can see that `t1` is defined as signal 0,`t2` is defined as signal 1 and`h1` is defined as signal 2. This will make the Pybytes platform know which signal refers to what type of value.
The code does not take into account for possible faulty values, mainly because the data is not critical in any aspect. This will be a task for future iterations to implement.
This is what `main.py` looks like:
```python=
import temp_sensors
import time
import pycom
# Turn off LED
pycom.heartbeat(False)
print("The Pycom device is awake.")
# Give the device some time to get readings
time.sleep(1)
temp1 = temp_sensors.get_temp_DS18S20(10)
temp2 = temp_sensors.get_temp_DHT22(3)
humidity = temp_sensors.get_humidity_DHT22(3)
if temp1 and temp2 and humidity is not None:
# Round the returned values
t1 = round(temp1, 1)
t2 = round(temp2, 1)
h1 = round(humidity, 1)
print("\nTemperature DS18B20: " + str(t1))
print("Temperature DHT22: " + str(t2))
print("Humidity DHT22: " + str(h1))
print("\n---------------------------------------")
pybytes.send_signal(0, t1)
pybytes.send_signal(1, t2)
pybytes.send_signal(2, h1)
# Give the device some time to send the data
time.sleep(2)
# Send data every 15 minutes = 900 seconds
print("\nThe Pycom device is going to sleep.")
pybytes.deepsleep(1000*900)
```
When you've imported the code into Atom IDE and the board is connected via USB, all you need to do is to upload the code to the Lopy4.

## Putting everything together
Make sure **not** to connect the battery to the 3.3V pin as it will fry the Lopy4, I learned this the hard way. Make sure to connect it to VIN and Ground. The 3.3V pin is for output only, i.e. powering sensors etc.
**Pycom Lopy4**
This is the brain of the whole operation. This little thing makes it possible to read values from the sensors send them via a wide range of networks including Wifi, Bluetooth, LoRa and Sigfox. This project will use the LoRa network.
**DS18S20**
Waterproof sensor (looks different in reality). It's a digital sensor.
**DHT22**
Temperature and humidity sensor. This is more accurate than the DTH11 version. It's a digital sensor.
**4.7k resistors**
A 4.7k resistor is needed between VCC and the data pin according to the datasheet.
**LoRa antenna**
Antenna for 868MHz/915MHz fequencies.
**LiPo battery**
2000mAh 3.7V. It will hopefully last at least 2 months on a single charge.
A very basic power consumption calculation based on this [Pycom forum thread](https://forum.pycom.io/topic/3763/battery-consumption-in-datasheet/2):
Formula
`(N * D * IA + (T - N * D) * IS) / T`
T = 3600 (1 hour)
N = 4 (wakes up 4 times an hour)
D = 10 (stays awake for 10 seconds)
IA = 100 mA (average power consumption while awake)
IS = 0.010 mA (10 µA, average power consumption while sleeping)
Battery consumption per hour:
`(4 * 10 * 100 + (3600 - 4 * 10) * 0.010) / 3600 = 1.121mAh`
Total days of operation on a 2000mAh battery:
`Battery capacity / (24 hours * 1.121)`
`2000/24*1.12 = 93.42 days`
A very rough estimate shows that a battery of 2000mAh will last for three months. I expect the battery to last for at least two months on a single charge.
### Schematics

**3D printing**
To have everything neatly packed together I designed an enclosure specifically for this project. The provided STL files can be sliced and used with any 3D printer. The provided gcode file is sliced especially for Prusa MK3S/MK3S+ and designed not to need any supports.
I chose to print the enclosure in PETG (polyethylene terephthalate), a material commonly used in plastic bottles. It has a better heat resistance than PLA and due to the fact that it will be placed outdoors, it's the better choice.
The enclosure was designed in Autodesk Fusion 360 and both STL-, Fusion- and gcode-files are provided as this guide won't go into details regarding the 3D design process. If you intend to use the 3d files I asume you alredy have the knowledge needed.
**Fusion 360**


**PrusaSlicer**

### Assembly



All the parts needed.

Put double sided tape on the backside of the battery and place it inside the box. Screw on the antenna connector.

Connect the LoRa antenna to the antenna connector.

Place in the PCB and connect the battery to the JST connector. The PCB can look a bit different depending on how you managed to wire it up.

Connect the Lopy4 to the pin connectors and attach the antenna cable to the top left connector (if in Europe).

Now connect the DS18S20 (the waterproof temperature sensor).

Pull the DHT22 sensor cable through the hole on the back side of the top plate.


Use some double sided tape or glue to keep the sensor in place.

Connect the DHT22 sensor to the PCB.

But on the top plate and fasten the four screws.

We are now done with the assembly!
## Final result

### Final thoughts and ideas for future iterations
This has been a very fun project to make and definately not my last IoT project. I hope to continue and increase the level of complexity on the next project. The next project will probably be a Kayak emergency beacon with a Fipy and PyTrack. Basically a GPS tracker with an accelerometer to detect if you would ever roll over and fall into the water. The device will then send a distress message with coordinates. This was my initial project idea but it proved to be a bit too complicated for my newly acquired Python skills.
I intend to improve the code and implement a battery warning when running low on power. I would also like to migrate the data to my own database for greater control and long term storing. As the complexity improves I also intend to migrate to Datacake or another platform as they can provide far greater functionality than Pybytes. But for now it works great.