# Tutorial on how to build a Pycom LoPy4 weather station #### by Emelie Fogelström (ef223av) For this project, a weather station was built, using a Pycom LoPy4 together with a CCS811 sensor and a BE280 sensor, both from Adafruit. All measured values was sent to Ubidots IoT cloud, using MQ Telemetry Transport (MQTT). Estimated time for reproducing this project is 18 hours. ### Objective The purpose of this project is a smart weather station that I can access from my phone, even when I'm not at home. I chose this project for three reasons: 1. At the moment I live in a small town outside of Oslo, Norway. The weather changes a lot here and it can be very interesting to measure these changes. 2. In my former house I had a burglar alarm combined with a smoke detector. There were three "issues" with that solution: * The smoke alarm went off several times a week even though there were no fire. * The company that provided the service did not do that job for free i.e. it was expensive * I have dogs so I couldn't use the burglar alarm when they were at home. I decided, for now, to add an extra temperature sensor to my weather station to measure temperature inside my current home. In case the temperature rise above 50 degrees celsius, I will get a call to my cellphone with a message telling me something is wrong. 3. My intention is to move abroad, to a large city in the future and then the gas sensor will be very useful due to high levels of pollution in big cities. This project will hopefully be a good ground to stand on, to develop further in the future when my needs for measuring weather changes. ### Material List of material for this project: | Material | Quantity | Purchased | Price | | --------- | -------- | --------- | ----- | | LoPy4 | 1 | Electrokit| ~ 350 SEK | | Expansion board | 1 | Electrokit| ~ 150 SEK | | Breadboard | 1 | Electrokit| 59 SEK | | USB 2.0 | 1 | Electrokit| 39 SEK | | MCP9700 Temp sensor | 1 | Electrokit| 8 SEK | | Adafruit CCS811 sensor | 1 | Elfa Distrelec| 230 NOK | | Adafruit BME280 sensor | 1 | Elfa Distrelec| 250 NOK | | Wires (male + male) | 10 | Electrokit| 12 SEK | | Wires (male + female) | 10 | - | free | | Solder iron | 1 | - | free | #### LoPy4 The LoPy4 is a Micropython-programmable IoT platform for connected things. It can act as a LoRa nano gateway and is a multi-bearer development platform (LoRa, Sigfox, WiFi and BLE) suitable for LoRa and Sigfox networks. It is the brain of the project and is programmable with MicroPython and uses the Pymakr plugins for fast IoT application development. For this project I used WiFi for connection. ![LoPy!](https://pycom.io/wp-content/uploads/2018/08/lopySide-1.png =360x) Fig. 1. LoPy4 with headers. Pycom.io #### Expansion board The expansion board is used to connect all the sensors and power. You can also easily connect an antenna if needed. ![Expansion board 3.1](https://i.imgur.com/YKgBENP.png =400x) Fig. 2. Expansion board 3.1 https://core-electronics.com.au/ #### Sensors For this project, three different sensors is used. The easiest one is the MCP9700 temperature sensor, an analog temperature sensor, used to measure indoor temperature. The CCS811 is used to measure gases like CO2, alcohol and ketones while the BME280 is used to measure outdoor temperature, pressure and humidity. ![Adafruit CCS811 gas sensor](https://i.imgur.com/mG8hVbG.png =400x) ![Adafruit BME280 sensor](https://i.imgur.com/ncF4rEj.png =230x) Fig 3. Adafruit CCS811 gas sensor and Adafruit BME280 sensor https://www.elfadistrelec.no & https://core-electronics.com.au/ ![MCP9700 Temp sensor](https://i.imgur.com/zdOhhvC.png =200x) Fig 4. MCP9700 Temperature sensor https://sg.cytron.io/ #### Wiring The wires are used to connect the sensors to the Lopy4. To make wiring easier, a breadboard is used, but optional. ![wires](https://i.imgur.com/bLxfQbk.png =300x) ![](https://i.imgur.com/ljpv4wn.png =300x) Fig 5. Wires and breadboard https://www.kjell.com/se/ #### Soldering You'll also need to solder the pins on the Adafruit sensors, for reliable electrical contact. ![Solder iron](https://i.imgur.com/VwnZUPN.png =350x) Fig 6. Solder iron from https://www.kjell.com/se/ --- ### Computer setup I followed these steps to get started: #### Windows 7 drivers If you, for some reason, still use Windows 7, you will need to install drivers to support the expansion board. Instructions for this is found [here](https://docs.pycom.io/gettingstarted/installation/drivers/). #### Expansion board & LoPy4 firmware update (if needed) Before connecting your module to the Expansion board, you may update its firmware. The expansion board 3.1 should be up to date (which mine were) but if you have problems with the set up you might need to update the expansion board firmware. Instruction to do so can be found [here](https://docs.pycom.io/pytrackpysense/installation/firmware/). To update the firmware on Lopy4, you first need to connect the module to the expansion board. The small white square (surrounding the LED) on the LoPy4 should be positioned over the USB socket on the expansion board. When the module is attached to the expansion board, you are ready to update the firmware. Instructions and download link for this can be found [here](https://docs.pycom.io/gettingstarted/installation/firmwaretool/#app). ![](https://i.imgur.com/mX8DC33.png =400x) Fig 7. Lopy4 connected to expansion board #### Software update To write and run code on the Lopy4 you need an IDE like Atom or VS Code together with the PyMakr plugin extension or you can simply use the solution on Pycoms webpage (which for now is not recommended). You may also need to install Node.js if you choose to work with VS vode. For this project, Atom has been used. To download Atom, go to Atom.io and choose the download suitable for your OS. When Atom is installed you need to install the PyMakr plugin as well. PyMakr will help you upload, download and run your code on your device easily. Only a button click is needed. Simply get PyMakr by searching for PyMakr in Atom and click install. A complete guide can be found here: [Atom](https://docs.pycom.io/pymakr/installation/atom/) or if you prefer [VS Code](https://docs.pycom.io/pymakr/installation/vscode/). When PyMakr is installed and configured, you are ready to write and upload your first code to the device. To get started you firstly need to create a new project. This is done by adding a new folder to wherever you would like your project to be located. You will also need another folder as well, for your sensor libraries, which you create by adding a new folder called 'lib', to your project folder. When the folders are created, open your project folder in Atom. To add files to your project, you can simply right click on the folder you want your file to be located in and add new file. A simple first project to help you get familiar with Micropython is to code a blinking LED. Instructions for this is found on [Pycom's website](https://docs.pycom.io/gettingstarted/programming/first-project/#controlling-the-on-board-led). When you have written your first program, you simply upload your code to your device by connecting it to your computer via a USB cable and then press the upload button in PyMakr. Make sure you have saved your files before uploading them. ### Putting everything together Before putting everything together, you'll have to solder the Adafruit sensors to their pins. For instructions on how to do this and how to wire the sensors, go to Adafruit's instruction pages: Instructions for [CCS811](https://learn.adafruit.com/adafruit-ccs811-air-quality-sensor?view=all) Instructions for [BME280](https://learn.adafruit.com/adafruit-bme280-humidity-barometric-pressure-temperature-sensor-breakout/overview) ![Soldering](https://i.imgur.com/tMhEqiQ.png) Fig 8. Soldering the sensor to its pins #### Wiring Instructions on wiring the sensors can be found in the instructions for [CCS811](https://learn.adafruit.com/adafruit-ccs811-air-quality-sensor?view=all) and for [BME280](https://learn.adafruit.com/adafruit-bme280-humidity-barometric-pressure-temperature-sensor-breakout/overview). The two sensors are connected to the same bus (I2C) and connected to each other. Instructions for the MCP9700 senor is found [here](https://www.losant.com/blog/how-to-read-the-tmp36-temperature-sensor-with-pycom-and-sigfox). The diagram below shows how I made my wiring. ![Circuit diagram](https://i.imgur.com/DI0ayXi.png =600x) Fig 9. Circuit diagram #### Power consumption: Because I installed my device in my home, I don't have to take the power consumption in count, but if you want to power your device with a battery, here is a simple power consumption calculation. I recommend you to put your device in deep sleep when not sending, to minimize power consumption and not read the MCP9700 temperature sensor every second as is done on my device. Idle 30 mA Deep sleep 18.5 mA Wifi AP 93 mA sending ~15 sec CCS811 sensor 0.7 mA BME280 sensor 0.8 mA #### Power consumption calculation: Deep sleep: 18.5mA/60min = 0.3mA * 59min = 17.7min * 24h = 424.8mA Idle: 30mA/60min = 0.5mA * 59min = 29.5min * 24h = 708mA Sending: 93mA/60min = 1.55mA * 24min = 37.2mA CCS811: 0.7mA/60min = 0.01167 * 24 min = 0.28mA BME280: 0.8mA/60min = 0.01333 * 24 min = 0.32mA ##### Total: 745.8mA per day or 462.6mA when using deep sleep. ### Platform For this project, four different platforms have been tested and evaluated. First I tried Pycoms own platform, Pybytes but for this project I found it to simple and I soon moved on to Adafruit.io instead. With Adafruit I was able to both upload and download information from the cloud and also use triggers, but it was still to simple for this project because the Dashboard was missing some, for me, important features like highest and lowest value in a time period. I also tried Thinger.io which I could not find any triggers in so I simply moved on to Ubidots, which had most of the functionality I needed for this project, for example the possibility to get a phone call when a value is out of range. I find very helpful and I also like the easy solution to download values from the cloud to my Android application. I have therefor chosen to use Ubidots for this project. Ubidots is a online cloud solution which can be used for free. It is easy to configure and upload and download values from the database and there are many possibilities when it comes to displaying the information. It is also possible to integrate the dashboard on your website and should also be possible to integrate it in an Android application but unfortunately that feature seams to be broken at the moment. --- ### The code The libraries used for the sensors and MQTT can be found here: [MQTT.py](https://github.com/pycom/pycom-libraries/blob/master/examples/mqtt/mqtt.py) [CCS811.py](https://github.com/Notthemarsian/CCS811/blob/master/CCS811.py) [BME280](https://randomnerdtutorials.com/micropython-bme280-esp32-esp8266/) (You'll need to change the BME280 default address to 0x77 if you use the Adafruit sensor). Place the files in your lib folder. The code below is placed in the main folder in the boot.py file and main.py file. #### boot.py ```python= from network import WLAN # Connect to WiFi # SSID is your WiFi connection name and PASSWORD your WiFi password wlan = WLAN(mode=WLAN.STA) wlan.connect("SSID", auth=(WLAN.WPA2, "PASSWORD"), timeout=5000) ``` #### main.py ```python= import pycom import _thread from machine import I2C from network import WLAN import machine import time from mqtt import MQTTClient import CCS811 import BME280 #MQTT callback def sub_cb(topic, msg): print(msg) # if not connected to wifi, set machine as idle/inactive while not wlan.isconnected(): machine.idle() # Connect to MQTT client in ubidots and connect # Use your token (accessed on Ubidots webpage) and leave password empty. # Port is 1883 and device_id is found in config file. client = MQTTClient("device_id", "industrial.api.ubidots.com",user="your_token", password="", port=1883) client.set_callback(sub_cb) client.connect() ############ define pins ############ #i2c ("Inter-Integrated Circuit") is the multi master bus used to connect the sensors to the lopy4 i2c = I2C(0) i2c = I2C(0, I2C.MASTER) i2c = I2C(0, pins=('P9', 'P10')) i2c.init(I2C.MASTER, baudrate=10000) ccs = CCS811.CCS811(i2c=i2c) # CCS811 is the gas sensor. Uses addr=90 bme = BME280.BME280(i2c=i2c) # BME280 is the pressure, humidity and outdoor temp sensor. Uses addr=119 adc = machine.ADC() apin = adc.channel(pin='P16') # Analog indoor temperature sensor # Outdoor sensors are running in a speparete thred to not interfear with the indoor temperature sensor, which needs # to read values more often to detect high temperature values in case of a fire. def outdoorThread(): while True: if ccs.data_ready() : co2 = ccs.eCO2 voc = ccs.tVOC temp = bme.temperature hum = bme.humidity pres = bme.pressure # Only when co2 is over 400, values will be sent to Ubidots if co2 > 400: client.publish("/v1.6/devices/WeatherStation", '{"CO2": ' + str(co2) + ', "Temperature": ' + str(temp) + ', "VOC": ' + str(voc) + ', "Humidity": ' + str(hum) + ', "Pressure": ' + str(pres) +'}') time.sleep(900) # Start new thread _thread.start_new_thread(outdoorThread, ()) # i, value to increment to know when to send valeus (only every 15 minutes if temperature is not higher than 50 degC) i = 0 while True: millivolts = apin.voltage() # Analog temperature measured in millivolts degC = (millivolts - 500.0) / 10.0 # Convert millivolts to celsius # If temperature is higher than 50 degrees celsius or if i value is 900 if(degC > 50 or i == 900): # Send values to Ubidots client.publish("/v1.6/devices/WeatherStation", '{"IndoorTemperature": ' + str(degC) +'}') i = 1 # Decrement i value to 1, to start count again, until reached 900 else: i+=1 time.sleep(1) ``` ### Transmitting the data / connectivity For this project I have chosen to work with WiFi and MQTT. Unfortunately I have no LoRa network close to me but if you have a LoRa network to connect to, it could be a good backup if your WiFi disconnects for some reason. LoRa is also a better choice if you need your device to be powered by a battery source because it is less power hungry than WiFi, but if you, like me, plan to run the device at home, you don't have to plan for power consumption. MQTT is chosen because it's a lightweight messaging protocol for small sensors and mobile devices and suitable for IoT. The device sends values to the cloud every 15 minutes (or 96 times a day). Because the weather doesn't change every minute, I felt no need to send data more often. All values are stored in Ubidots own database and the only thing you need to do is to connect to Ubidots own MQTT broker and publish to your own account/device and Ubidots will handle the rest for you. ### Presenting the data In the dashboard you can choose between many different widgets depending on your needs. I have chosen one widget for every sensor and also a graph to show how the different values changes over time. I have also chosen to show yesterdays highest and lowest temperature. ![Dashboard](https://i.imgur.com/iJ1a8DR.png) Fig 10. Ubidots dashboard ![Graph](https://i.imgur.com/t4GwV6j.png) Fig 11. Ubidots graph The values are stored in Ubidots own database every time data is sent. The values are stored as long as Ubidots stores them and I have chosen to have a trigger (phone call) for indoor temperature over 50 degrees celsius. I am also sending all values to my own Android application, which also alerts me in case the temperature rises over 50 degrees celsius. ![](https://i.imgur.com/V4Oo6Ff.png) ![](https://i.imgur.com/ahYpm4L.png) Fig 12. Trigger when indoor temperature rises above 50 degrees celsius. Because Ubidots provide the database I have no control over it and I'm not sure whether it's possible to use an external database together with Ubidots. I send all values to my Android application to be able to access them wherever I am. I also use a external API to determine what icon to display (sun/cloud/rain, day/night) and the graphs in the dashboard are created by using a graph method in Android. ![App](https://i.imgur.com/7YuC8LQ.png) ![App dashboard](https://i.imgur.com/6gk5NEW.png) Fig 13. My Android application, showing current values and statistic over last 100 values. ### Finalizing the design Because of Corona, I haven't been able to finalize my project the way I wanted. My plan was to go to my parents in Sweden and use my fathers 3D-printer but I will have to wait until the Corona situation has calmed. For now, I have only tested the sensors by attaching the device to the wall and putting the sensors outside my door. My plan is to make one box for the Pycom device and the breadboard and one for the outdoor sensors. Both boxes need to be open on one side, so my plan is to make some kind of net on one side, to allow air and humidity to enter the boxes. ![Setup](https://i.imgur.com/vfsjOQa.png) Fig 14. Testing the sensors awaiting 3D-printed boxes. I have notices that the cheap sensor (MCP9700) is not very accurate and my recommendation is to choose another sensor for more accurate measurement. Otherwise the project went well for me. I wish I was able to get Grafana to work but Ubidots is a great alternative in this case. ### Youtube video presentation: <iframe width="560" height="315" src="https://www.youtube.com/embed/tFgz4MPyzDA" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>