# Tutorial: Build a plant guardian! ###### Adam Paulander, ap223vi ## Table of Contents [ToC] ## Project: In this tutorial you will learn how to make a "Plant Guardian". Simply put, it's a device that not only reads and logs your plants soil moisture, but it also comes with a "remote watering"-feature, eradicating the need for you to have someone look after your plants while you're out there exploring the world. **Estimated time for this project: 2h - 5h? Honestly, I have no idea - that's a very rough estimation.** ### Objective: Historically, I've never had any problems keeping my plants alive and well. Now that's history, because I decided that we needed a lime tree - and proclaimed that it was me and my fiances "love tree". (I would regret saying this later on). Lime trees are highly sensitive when it comes to drought and demads daily watering to stay alive. Being a full time student while also being a full time father to two toddlers - this proved too much for me to handle. When I, for the fifth(!) time, stood there making plant-cpr, saving our precious "love tree" from a certain and gruesome death, I came to the conclusion that something needed to be done. Enter: Plant Guardian. The purpose of my project is to be able to monitor the demanding tree, while also being able to water it with a click of a button from my phone, giving me more time with my kids and less time walking up to a tree to see if it needs watering. This will all be possible with something called AdafruitIO. You'll learn more about it further down the tutorial. Hopefully, this project will give me insights on how to create a fairly simple IoT project, while also making my life (if only by small margins) a tad bit easier. :deciduous_tree: ## Materials: | Product Name | Product Picture |Purchased at |Price| Amount | Buy here | |--------------------|------------------------------------|---------------------------|-----|-------------|-------------------------------| |LoPy4 |![](https://i.imgur.com/FvAeocs.png)|pycom.io |€38.45| 1x |[Purchase Here][Lopy4] | |Expansion Board 3.0 |![](https://i.imgur.com/6PmaeLm.png)|pycom.io |€17.60| 1x |[Purchase Here][ExpansionBoard]| |Soil Sensor |![](https://i.imgur.com/C0XUKaX.jpg)|electrokit.com |€2.83 | 1x |[Purchase Here][SoilSensor] | |Water Pump |![](https://i.imgur.com/cAMNDPi.jpg)|electrokit.com |€2.83 | 1x |[Purchase Here][WaterPump] | |Relay Module 5v |![](https://i.imgur.com/JfIyu1n.jpg)|electrokit.com |€3.81 | 1x |[Purchase Here][RelayModule] | |Breadboard |![](https://i.imgur.com/XJWXIs4.jpg)|electrokit.com |€5.77 | 1x |[Purchase Here][Breadboard] | |5v Outlet |![](https://i.imgur.com/AwhMR4M.jpg)|electrokit.com |€14.56| 1x |[Purchase Here][5vOutlet] | |Adapter D/C (female)|![](https://i.imgur.com/iproHkV.jpg)|electrokit.com |€1.96 | 1x |[Purchase Here][DC_adapter] | |Wires (MM) |![](https://i.imgur.com/lw9Gaxy.jpg)|electrokit.com |€2.83 | 1x |[Purchase Here][WiresM] | |Wires (M/F) |![](https://i.imgur.com/EfU7Ure.jpg)|electrokit.com |€2.83 | 1x |[Purchase Here][WiresMF] | |Plastic Box (small) |![](https://i.imgur.com/K55nYBC.jpg)|electrokit.com |€2.83 | 2x (**optional**)|[Purchase Here][CaseS] | |Plastic Box (large) |![](https://i.imgur.com/Gt6anI3.jpg)|electrokit.com |€2.83 | 1x (**optional**)|[Purchase Here][CaseL] | [Lopy4]: https://pycom.io/product/lopy4/ [ExpansionBoard]: https://pycom.io/product/expansion-board-3-0/ [SoilSensor]: https://www.electrokit.com/produkt/jordfuktighetssensor/ [WaterPump]: https://www.electrokit.com/produkt/vattenpump-mini-5v/ [RelayModule]: https://www.electrokit.com/produkt/relamodul-5v/ [Breadboard]: https://www.electrokit.com/produkt/kopplingsdack-400-anslutningar/ [5vOutlet]: https://www.electrokit.com/produkt/batterieliminator-5v-3a/ [dc_adapter]: https://www.electrokit.com/produkt/adapter-dc-jack-skruvplint/ [WiresM]: https://www.electrokit.com/produkt/labbsladd-20-pin-15cm-hane-hane/ [WiresMF]: https://www.electrokit.com/produkt/labbsladd-20-pin-15cm-hona-hane/ [CaseS]: https://www.electrokit.com/produkt/apparatlada-1551fbk-svart-50x35x15mm/ [CaseL]: https://www.electrokit.com/produkt/apparatlada-1591bbk-svart-112x62x31mm/ ### Description: :::info **CaseS and CaseL** are higly recommended for you to read, so do NOT skip that section at the very least, if you intended to skip the Description part of this tutorial. ::: **LoPy4** has a variaty of options when it comes to connectivity, supports threading and micropython. It will be well suited for carrying out this project. **Expansion Board 3.0** will give us easy access to the REPL on our computer and make wiring neater. The **Soil Sensor** is going to - *bear with me* - be the sensor that we collect soil moisture data from in this project. Incredible right? It has the ability to read both analog and digital values (Sensor YL-69). I decided to go with a **Water Pump** this project. You could get flowing water with a magnetic valve with a water source placed above it, however, I saw some risks with having a bottle standing upside-down in a house with two toddlers, so I went with the pump. To add to it, I didn't know if the pressure from a waterbottle would be enough to make the magnetic valve work and I didn't care to find out, since I by then already had chosen the water pump. The **Relay Module 5V** is there to turn the pump on and off, or rather, is told to let electric current flow through it or not. Now, I decided to have this relay, as I did not know if the GPIO pins would be enough to power the water pump by themselves. To prevent electric backlash to the board, you also need a second power source. *A simple introduction to relays can be found in Video 1 - Relays below:* {%youtube 1_YfuH_AcxQ %} *Video 1 - Relays* The **Breadboard** is just gonna make it easier for us with wiring. You could go with welding if you feel comfortable with that and want a neater end result. I do however recommend having a breadboard to make sure everything is properly connected before welding it in place (welding is kind of permanent you know). **5v outlet** and **dc adapter (female)** will be our power source to the water pump and will also be connected through the 5v relay. **Wires** is needed, to, well, wire everything together. Therefore I've bought some. I suggest you do so as well. **CaseS** and **CaseL**: These parts are optional. For starters, the **CaseL** is a little too small for this project. I would therefore recommend buying a larger case if you'd like to have a neater end result. It ended up with me having to leave the AC adapter outside the box, because there simply wasn't enough space left, and that's not very pretty. If you WANT to do the same mistake and struggle as I did, buy the one presented in the Materials list. If not, the one in the link below will probably serve you better: :link: [CaseL that actually got some space.][CaseLOption] [CaseLOption]: https://www.electrokit.com/produkt/apparatlada-1591tsbk-svart-120x80x55mm/ Case in point (pun intended), these cases helps protecting the physical parts of the project and makes it look less worse. ## Setup So you've got your LoPy4 and Expansion Board out of the box? Great! Let's get started. :::info Windows 7 users: The expansion boards work "out of the box" on Windows 8 and higher, but not with Windows 7. Here's a guide on how to make it work: https://docs.pycom.io/gettingstarted/software/drivers/ ::: ### Pycom Assemble! First of all, we want to mount the LoPy4 to the expansion board. As seen in Picture 1, you want to mount the LoPy4 with the text "pycom" facing the same way. If it looks like in Picture 2, you're doing it wrong. In case you're still in doubt because of my dubious photo skills, here's a link to the official site on how to do it: https://docs.pycom.io/gettingstarted/ | | | |-------------------------------------------------------------------|---------| |![](https://i.imgur.com/tNcDrl9.jpg) *Picture 1, Lopy & EB assembled correct* |![](https://i.imgur.com/LddEEqX.jpg) *Picture 2, Lopy & EB assembled wrong* | Now that you've done that, we can plug it into our computer with a micro-USB cable. The light on your LoPy4 should be flashing blue about each every five seconds after being plugged in. :::info Make sure that you use a micro-USB cable that is able to transmit data, as some older cables isn't capable of doing that. ::: Congratulations! You've assembled and connected your Pycom device to your computer! ### Updating firmware Now that your LoPy4 is connected to the computer, you should update its firmware. :::info This tutorial ONLY covers the installation steps for Windows. ::: ### Know thy port First, we want to know which port our LoPy4 is connected to. To know this, we'll have to use our Device Manager (DM). To open the DM, click start and write "cmd" and click enter. Now write "devmgmt.msc" and press "Enter". The Device Manager should now have opened up for you. Look for something called "Ports" and expand it. My DM recognizes two different USB ports (COM1 and COM3) as seen in Picture 3. To see which one your LoPy4 is connected to, simply unplug your LoPy4's USB-cable and look which one disappears: that's the port you want to chose in the installer later on. Now plug your device back in, or we'll have some problem installing its new firmware... ![](https://i.imgur.com/Hs7W2qg.png) *Picture 3, update firmware DM* ### Download the Firmware Updater You can download the Firmware Updater for your LoPy4 here: https://pycom.io/downloads/ :::info Download the file that corresponds to your OS. ::: When downloaded, you open the downloaded file. When the installation starts, start by pressing "Install". Now wait until the installation is complete and click "Finish". This should open a new sort of installer that looks something like Picture 3. ![](https://i.imgur.com/wpz1tnm.png) *Picture 4, update Welcome* If it looks like in Picture 3, you can just press "Continue" and follow the instructions on the next slide (Picture 4) and then press "Continue". ![](https://i.imgur.com/gYdMcfE.png) *Picture 5, update Setup Instructions* Now we come to a new slide which lets us decide which port we would like to install the firmware to (Picture 5) and luckily, we know which one it should be by now. Choose "High Speed Transfer" (it just makes it all quicker to install) and click "Continue". ![](https://i.imgur.com/ToBqDny.png) *Picture 6, update Communication* Wait for the installation to complete and follow the new instructions and finally click "Done" to finish the installation. ## Installing IDE & plugin ### IDE Visual Studio Code (VS code) is the IDE that I have chosen for this project, mainly because I've been using it before and know my way around it. You could use Atom as well, but if you're completely new to this, I would recommend you to go with VS code, as I won't cover Atom in this tutorial. You can download VS code HERE: https://code.visualstudio.com/ You can download Atom HERE: https://atom.io/ In the installation, you should choose Python as the language you will be programming in. Feel free to install other languages as well if you'd like, but Python is mandatory for this project to work. When you're starting the IDE for the first time, you'll be asked to create a project. Do that. ### Plug-in Now that you've installed VS code (yes, I assumed you followed my advice), you can open it and move on to install the Pymakr plugin. Here's a guide on how to do that: https://docs.pycom.io/gettingstarted/software/vscode/ Note that in order to use Pymakr, you'll **need** Node.js installed on your computer. When installing the plugin, it will search for Node.js on your computer and if it doesn't find it, you'll get the option to install it from there (again, this is if you use VS code). You can also install Node.js manually here: https://nodejs.org/en/ ### How to upload code to LoPy4 Now that Pymakr is up and running, we can start accessing our device. You'll find something looking like this (Picture 7) in the lower parts of your IDE: ![](https://i.imgur.com/uROT2tp.png) *Picture 7, REPL In the blue bar, press "Download". This will download the files currently on your LoPy4. Two files should now be visable: "main" and "boot" Note that all of our code will go into "main". To make sure that everything is working you can follow this guide for a simple "led-program" that makes your device flash in some different colors: https://docs.pycom.io/tutorials/basic/rgbled/ When you've entered the code, you can press "Upload" in the blue bar to upload the code to your device. Press "run" if you just want to run the current file that is open. Does it work? Great! Let's move on to the next step! ## Put everything together! :::info Safety first: Make sure that nothing electric is plugged in when assembling the parts! :lightning: ::: ### Circuit Diagram This is how everything will be connected when assembled correctly (Picture 8). Follow the curcuit diagram and make sure you dubble check that everything is wired correctly. ![](https://i.imgur.com/EiLuGHD.png) *Picture 8, Circuit diagram* ### Some explanations: |Wire | Meaning | |-------|-----------------| |RED: |VIN (+) | |BLACK: |GND (-) | |GREEN: |SM-sensor read | |ORANGE:|SM-sensor control| |BLUE: |Relay signal | Soil sensors of this type corrodes easily when electric current are flowing through it. To prolong its lifespan, we'll therefore connect it to P9, making it a GPIO that we can turn ON and OFF. By doing this, we can turn the sensor ON only when we need to read the soil moisture value and switch it OFF while we wait for the next reading. You might've noticed by now that we're gonna have two power sources. The USB-cable (or a battery if you'd like) powering the expansion board and the AC adapter powering the water pump. This is because of the relay module we use to turn the water pump ON or OFF. This guide is a great example on how relay modules can be used and why we need two power sources: https://www.circuitbasics.com/setting-up-a-5v-relay-on-the-arduino/ The rest of the wiring is pretty straight forward: The expansion board will power both the relay module and the SM-sensor, while the AC adapter will power the water pump (going through the relay). ## Platform: AdafruitIO As I mentioned at the start of this tutorial, I've chosen to use **AdafruitIO** as my platform. It requires WiFi connection to work and is incredibly easy to set up with UMQTT (the protocol we'll send our data with). It's free to use and gets us 5 dashboards, 30 days of data storage and 30 data points per minute. If you feel like you need more, you can always subscribe to AdafruitIO+. You can read more about the platform here: https://learn.adafruit.com/welcome-to-adafruit-io In terms of usage, it saves each our data points into a "feed". Each feed is saved for 30 days each, which is more than enough for this project. If you want your data to be stored longer than that, this platform won't be for you. It provides an easy way of creating dashboards, where we'll be able to look at our feed and create a button that turns on the water pump while being pressed. A great guide on how to connect your device to AdafruitIO and setup the feeds and dashboard can be found here: https://core-electronics.com.au/tutorials/internet-of-things-with-pycom-and-adafruit-io.html You'll notice a lot of similarities in my code and the code provided by the guide above. This is because I used that guide and code when creating this project. Big shout-out to **core-electronics** for a well-made and easy guide! Something that I noticed however is that the guides link to simple(.py) (a library file we'll need for our code to work) is dead. The updated version is called simple2(.py) and can be found here: https://github.com/fizista/micropython-umqtt.simple2 Go ahead and download it now, as we'll be using it in the next step of the tutorial anyway. ## The code You can copy all of the code at the bottom of this segment into your main(.py). I won't explain every single bit of the code, but some parts of it that you can edit to fit your preference. :::info Haven't created an AdafriutIO account yet? Go ahead and do that here: https://io.adafruit.com. ::: :::info Didn't download the simple2(.py) file? Go ahead and do that here: https://github.com/fizista/micropython-umqtt.simple2 ::: ### Create a lib Create a directory called "lib" in VS code and add the downloaded simple2(.py) file into it as shown in Picture 9. ![](https://i.imgur.com/JL4ShJB.png) *Picture 9, lib* ### Enter your WiFi SSAO and PASSWORD ``` python=18 SSID = 'your-SSID-here' # Enter your SSID here. PWRD = 'your-WIFI-password-here' # Enter your PASSWORD here. ``` ### AdafruitIO credentials Setup your AdafruitIO credentials by editing these lines: ``` python=25 AIO_SERVER = "io.adafruit.com" AIO_PORT = 1883 AIO_USER = "USERNAME" # Your AdafruitIO username AIO_KEY = "AIO KEY" # Your AdaruitIO key AIO_CLIENT_ID = ubinascii.hexlify(machine.unique_id()) AIO_CONTROLLER_FEED = "LINK HERE" # Link to your Controller feed AIO_MOISTURE_FEED = "LINK HERE" # Link to your Soil moisture sensor feed ``` Your AdafruitIO key and username can be found in AdafruitIO, under the tab "My Key" as shown in Picture 10: ![](https://i.imgur.com/eEm4KCu.png) *Picture 10, AdafriuitIO key* The links to your feeds can be found in each corresponding feed. 1. Press the tab "feeds" in AdafruitIO 2. Click on the feed you want the link for. 3. On the right side of the page, press "Feed Info". 4. You'll see three links. We will be using the MQTT link for this project. You'll need two feed-links: one for the soil moisture sensor and one for controlling the water pump. ### Pins setup Now, you don't have to change anything here, but if you'd like to switch the pins you're using, you should edit that in these lines: Pin 16 (used for reading the SM-sensor): ``` python=16 soil_moisture_pin = adc.channel(pin = 'P16') ``` Pin 9 (used to power the SM-sensor): ``` python=17 sm_control_pin = Pin('P9', mode = Pin.OUT) ``` Pin 10 (used for controlling the Relay Module): ``` python=18 relay_control_pin_out = Pin('P10', mode = Pin.OUT) ``` ### How often you want to send data You can change how often you'd like to read and send data from your SM-sensor here: ``` python=10 DATA_INTERVAL = 3600000 # How often we send data from our SM-sensor to AdafruitIO. (milliseconds) ``` Note that it's in milliseconds. I've chosen to read and send data on an hourly basis (1h = 3600s = 3600000ms) ### The code to copy: :::spoiler **Main Code** ``` python=1 from machine import Pin from simple2 import MQTTClient import time import network import pycom import ubinascii import machine import micropython DATA_INTERVAL = 3600000 # How often we send data from our SM-sensor to AdafruitIO. (Milliseconds) last_sent = 0 # How long since last data sent. (Milliseconds) first_sent = 0 # This makes sure we send data the first iteration, even though we haven't reached DATA_INTERVAL yet. #Pins setup adc = machine.ADC() sm_read_pin = adc.channel(pin = 'P16') sm_control_pin = Pin('P9', mode = Pin.OUT) relay_control_pin_out = Pin('P10', mode = Pin.OUT) #WiFi credentials SSID = 'your-SSID-here' # Enter your SSID here. PWRD = 'your-WIFI-password-here' # Enter your PASSWORD here. #AdafruitIO credentials AIO_SERVER = "io.adafruit.com" AIO_PORT = 1883 AIO_USER = "USERNAME" # Your AdafruitIO username AIO_KEY = "AIO KEY" # Your AdaruitIO key AIO_CLIENT_ID = ubinascii.hexlify(machine.unique_id()) AIO_CONTROLLER_FEED = "LINK HERE" # Link to your Controller feed (control for water pump) AIO_MOISTURE_FEED = "LINK HERE" # Link to your Soil moisture sensor feed pycom.heartbeat(False) time.sleep(0.1) pycom.rgbled(0xff0000) #Connecting to WiFi wlan = network.WLAN(mode = network.WLAN.STA) wlan.connect(SSID, auth=(network.WLAN.WPA2, PWRD)) while not wlan.isconnected(): machine.idle() print("Has WiFi connection...") #Function that answers to calls from AdafruitIO (our button) def activate_pump(topic, msg, tmp_z, tmp_x): relay_control_pin_out.value(0) print("Controller: ", msg) if msg == b"1": relay_control_pin_out.value(1) elif msg == b"0": relay_control_pin_out.value(0) else: print("Something went wrong.") def read_soil_moisture(): global DATA_INTERVAL global last_sent global first_sent ## Checks if there has been an hour since the last data sent and that it's not the first iteration. if ((time.ticks_ms() - last_sent) < DATA_INTERVAL and first_sent == 1): return sm_control_pin.value(0) sm_control_pin.value(1) time.sleep(2) val = 1069 - sm_read_pin.voltage() sm_control_pin.value(0) print("Publishing: {0} to {1} ... ".format(val, AIO_MOISTURE_FEED), end='') try: client.publish(topic=AIO_MOISTURE_FEED, msg=str(val)) print("DONE") except Exception as e: print("FAILED") finally: last_sent = time.ticks_ms() if (first_sent == 0): first_sent = 1 return #MQTT connection to Adafruit IO client = MQTTClient(AIO_CLIENT_ID, AIO_SERVER, AIO_PORT, AIO_USER, AIO_KEY) #Subscribed messages will be delivered to this callback client.set_callback(activate_pump) client.connect() client.subscribe(AIO_CONTROLLER_FEED) print("Connected to %s, subscribed to %s topic" % (AIO_SERVER, AIO_CONTROLLER_FEED)) pycom.rgbled(0x002200) #Status green: online to Adafruit IO try: while True: client.check_msg() read_soil_moisture() finally: client.disconnect() client = None wlan.disconnect() wlan = None pycom.rgbled(0x000022) print("Disconnected from Adafruit IO.") ``` ::: It's collapsed mate. ## Connectivity Now that we've handled the code, let's talk about the connectivity of this project. ### WiFi Firstly, I do not have any access to the LoRaWAN or Sigfox networks from where I live and Bluetooth in all glory, but it doesn't really fit for this project. Secondly, our device is constantly listening for calls from AdafruitIO, since we're controlling the water pump from there with our button. This means that the device will have to be turned on all the time. If we only sent data from our SM-sensor, we could have put our LoPy4 to deepsleep between the readings, making it more power efficient. In this case, LoRaWAN or Sigfox would've been prefferable to save battery consumption. Not to mention that we'd increase the range of our device by a lot. This isn't the case however and since WiFi carries messages with faster speed than LoRaWAN and Sigfox, we'll have more accurate control over our water pump with our button. ### Send Data How often do we send data? I have chosen to send data every hour, but you're free to change the intervals by editing the code. (*You can see where to change this in the section "The code - How often you want to send data"*) ### Protocol The protocol we're using to send data is called MQTT and is lightweight. I used it for the simple reason of it having a very easy setup. You can read more about the MQTT protocol here: https://mqtt.org/faq/ ## Presenting the data Building a dashboard is pretty straight forward when using AdafruitIO, so we'll dive right into it. 1. As I mentioned in the Platform: AdafruitIO, we'll need two feeds for our device and code to work: one for controlling the pump and one that recieves data from the SM-sensor. ![](https://i.imgur.com/KiScFeC.png) *Picture 11, feeds* 2. To create a dashboard, click on the "dashboard" tab and click "view all". Click the blue button called "New Dashboard" and enter the name for your dashboard. The description is optional. 3. Click on your newly created dashboard. It should be an empty black screen with an option button in the upper right corner. Click that one and press "Create new block". 4. Click on the "toggle"-block (the on/off switch) and you should see something like this (Picture 12): ![](https://i.imgur.com/qu8io7Y.png) *Picture 12, connect a feed* Select your controller_feed (or whatever you named the feed that controls your water pump) and press "next step". The next step has two important values that we need to fill in in order for our code to work, and that is "Button On Value" and "Button Off Value". Set "Button On Value" to "1" and "Buttton Off Value" to "0" (both without the ""). Press "Create Block" and you've created your button! 5. Now create a second block, but this time a "Line Chart". The only thing you need to edit when creating it is for how long the line will go back in time. I'm currently running a "live" one, but that's mainly for testing purposes. Great! You've created the dashboard! The data that we have will be saved in our feeds for 30 days before it's deleted (free user). ![](https://i.imgur.com/XGbCKGj.png) *Picture 13, dashboard 1* ![](https://i.imgur.com/EWExJlL.png) *Picture 14, dashboard 2* ## Finalizing the design This is the end result of my device (Picture 15 and Picture 16). ![](https://i.imgur.com/fcVwvED.jpg) *Picture 15, final product* ![](https://i.imgur.com/QqZWv5t.jpg) *Picture 16, final product 2* ### Final thoughts This project turned out well, but there are ofcourse some improvements that I'll probably make. Especially switching over from the current two-legged SM-sensor to a sensor that doesn't have the copper exposed, which will negate corrosion. I did buy such a sensor at the start of the project, but it turned out that I had to modify the library files for it to work. I'm a procrastinator by nature, so I simply didn't have time to learn how to do this in order for me to get this tutorial done before its due date. The second adjustment I'll make is to mount it into a larger case and third would be to improve the code (threading, intervals to check connectivity, reconnect when connection is lost etc). Now, that's just the current parts. If I have time, I'll probably fully automate the watering, add some other sensors (temperature, humidity etc.), but that's gonna have to wait. If I'm really bold, I could connect it to a magnetic valve and connect it to the house water system... But with my current knowledge, that could end in a small inside flooding while on vacation, so I'll probably hold off on that one. So, all in all, I'm happy with the result and I've learned alot along the way. However, there are some grains in my eyes that I'll have to take care of in due time, even though I won't be reading this course by then.