# Monitor your plants & the weather with an awesome wall-mounted dashboard ### Victor Krook - vk222ii In this project we're going to build a system that allows us to track and monitor the temperature, humidity and the moisture in our plants and display it on a wall-mounted dashboard. We're going to store the data in a database runing locally, so you'll have full control of all the dataflow! ![](https://i.imgur.com/ewm0Scz.jpg) Estimated time: **10 hours** Esimated price: **30-50$** --- Objective === The reason behind this project is: 1. Learn more about iot and popular iot-protocols. 2. To stop our poor plants from drying out, we need to monitor them! 3. The temperature forecasts are usually poor, so it's better to measure it ourselves. 4. The data will be saved for further analysis, but the main objective of the data-storage is to give an intuition of how the weather has been lately. 5. Following this guide will open up many doors that will allow anyone to set up full-stack iot system. This can be done either locally at home, or in the cloud. 6. After this, you could even start developing your own iot-solutions towards a buisness. --- Material === ## Sensor-node 1. **Mictrocontroller**, I use a NodeMcu ESP8266, which is a single core mcu, max CPU frequency at 160 MHz and a flash of 4Mb. Any mcu with Wifi will do though. I'm using Micropython to program it, but you could choose any way of programming it as you'd like. This guide only covers Micropython though. 3. **Temperature sensor**, I use a DHT11 which also measures humidity. I also had an MCP9808 temperature sensor laying around, which I'll also use. This should give slightly more reliable measurements. 4. **Moisture sensors**, I use three FC28 Soil hygrometer. As the name impies, this will measure the moisture in the soil. 5. **Multiplexer** ***(optional)***, on ESP8266, there's only 1 ADC so to read multiple values this comes handy. 5. **4.7k resistor Ω** (if you're using DHT11/22). The DATA-pin on DHT11/22 sensors needs to pulled high. 6. **Wires**, how much depends on your placement of sensors. Think of where you want to place the sensor. Wires are always useful though so might as well buy a few meters. 7. **Some type of case** for the system. If you have a 3D-printer that's awesome. 8. **A switch** ***(optional)***, useful when debugging. 9. **Soldering Iron** ***(optional)***, but **highly** recommended. 10. **Glue**, I used superglue and hotglue. This is the bare minimum if you just want get the measurements and put the data to a server. If you also want to display it on a wall-mounted monitor, you'll need a monitor (surprise!?). I had an old PC-screen that I sacrificed, what brand or what type really shouldn't matter. Even if you have an old laptop, [DIY Perks](https://www.youtube.com/watch?v=CfirQC99xPc) has a really good guide for you how to use the screen. ## Wall-mounted monitor ***(optional)*** 10. **PC-screen**, I had an old LG-screen laying around. 11. **Raspberry Pi**, I use a Raspberry Pi W Zero. 12. **HDMI-converters**, completely depends on your Screen! 13. **Some nice LEDS** ***(completely mandatory)***, I use RGB-leds. 14. **A switch** ***(optional)***, needs to be able to handle ~230V AC. 15. **Distance sensor** ***(optional)***, I use a Ultrasonic HC-SR04 this is if you want to turn on/off the monitor with your hand. (Who doens't want to do that?) 16. **A frame** ***(optional)***, for the screen. This really depends on what type of screen you choose and how it looks. 17. **Home server** ***(very optional)***. This depends if you want to store the data in the cloud or at home. If you want to store it at home you could use your Raspberry Pi for this, however with the W Zero, it's really slow so then I would a recommend more powerful Pi. ## Links and prices I bought all my stuff from internet, here's some links and their estimated prices. | Item | Link | Price $ (roughly) | | -------- | -------- | -------- | | NodeMcu ESP8266 | [Click](https://pchbutik.se/nytt-pa-lager/1341-nodemcu-lua-wifi-development-board-based-on-the-esp8266-cp2102-internet-of-thing.html?search_query=nodemcu&results=10) | 7 | | DHT11 | [Click](https://pchbutik.se/sensor-givare/246-temperatur-och-fuktsensor-2-sensorer-till-arduino.html?search_query=dht11&results=6) | 5 | | MCP9808 | [Click](https://www.adafruit.com/product/1782) | 5 | | FC28 | [Click](https://pchbutik.se/sensor-givare/1201-aktiv-sensor-for-jordfukt-justerbar-passar-arduino-mm.html?search_query=jordfukt&results=5) | 3 | |TC4051B (multiplexer, any analog will do) | [Click](https://www.electrokit.com/produkt/74hc4052-dip-16-dual-4ch-analog-multiplexer/) | 1 | | RGB leds | [Click](https://pchbutik.se/komponenter/233-10-st-lysdiod-5mm-rgb-gemensam-anod-diffus-lins.html?search_query=rgb+leds&results=17) | 3 | | HC-SR04 | [Click](https://pchbutik.se/sensor-givare/35-2-st-ultraljuds-distans-matare-hc-sr04-passar-till-arduino.html?search_query=HC-SR04&results=22) | 3 | | Resistor, wires, switches etc | [Click](https://www.electrokit.com/) | 5 | |Superglue|[Click](https://www.clasohlson.com/se/Superlim/p/Pr313100000)|3| | Raspberry Pi W Zero | [Click](https://www.electrokit.com/produkt/raspberry-pi-zero-w-board/) | 12 | |HDMI to HDMI mini adapter | [Click](https://www.inet.se/produkt/8903279/deltaco-adapter-mini-hdmi-hane-till-hdmi-hona?gclid=CjwKCAjwi_b3BRAGEiwAemPNUzhSSy4Gl8Ed9UiveefMoXd9Gu2l4pU3G2N_KcLb_BkxjERK_0LurhoCn7YQAvD_BwE) | 8 | | Total | | ~35-60 | **Note:** Depending on how much effort and style you put into this, the price range really varies. If you want to have a nice frame around your screen, that will probably cost a bit more etc. --- Computer setup === **Note:** All code can be found on [this](https://github.com/victorhook/iot-course-project) github page. Having the code in the guide wouldn't be possible as it would be too long. ## Flash firmware If you want to program your mcu with Micropython we'll first need to flash it. To build the firmware, we need the esp-open-sdk toolchain, which you can either install via docker or directly to your PC. Depending on your platform, these steps might look slightly different. The easiest way is to follow the documentation [here](https://github.com/micropython/micropython/tree/master/ports/esp8266) to set it up on your system. Once you have your toolchain set up you can build the firmware with the following (assumes you are in the [Micropython](https://github.com/micropython/micropython) repository): ``` make -C ports/esp8266 submodules make -C mpy-cross cd ports/esp8266 make ``` This should put a binary in firmware file in `build-GENERIC/` (mine was named `firmware-combined.bin`). To put the file into the mcu we can use [esptool](https://pypi.org/project/esptool/) which can be installed with pip; `pip install esptool`. Before we flash it, we can erase the current flash: `esptool.py --port /dev/ttyUSB0 erase_flash` (choose your port-name) To flash it: `esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 "NAME_OF_YOUR_BIN_FILE.bin"` If all goes well you should see something like: ![](https://i.imgur.com/mdLrdYo.png) If it works, we can try it with any serial port terminal, I prefer [picocom](https://developer.ridgerun.com/wiki/index.php/Setting_up_Picocom_-_Ubuntu), which you can install with `sudo apt install picocom` (if you're a using debian-based distro). This will allow us to access the REPL, which comes extremly handy when debugging. `picocom /dev/ttyUSB0 -b 115200` ![](https://i.imgur.com/g9eptwX.png) We're in the REPL! If everything goes well, you should see something like the above. If there's any issues, I'd recommend reading the installation guides, because covering all details here would be too much. ## Transfering code Even though writing code in the REPL is really cool, and a nice way to impress your friends, it's not really efficient. When developing code, you can use any editor you'd like. I personally use VS Code. To transfer the code to the mcu we'll be using a tool called [ampy](https://github.com/scientifichackers/ampy) and can be installed easly with `pip install adafruit-ampy`. This is a cli tool that allows basic functionality like file transfers to and from the mcu. Another handy tool to have is [rshell](https://github.com/dhylands/rshell), which allows normal shell-like commands. --- #### Handy tip `picocom` and `ampy` requires port and baudrate arguments when used. To skip doing this manually every time you can put an alias for it: `echo 'alias ampy="ampy -p /dev/ttyUSB0 -b 115200"' >> ~/.bashrc` `echo 'alias picocom="picocom -p /dev/ttyUSB0 -b 115200"' >> ~/.bashrc` Once we have written some code, we probably want to try it first. We can either run it straight away or transfer it to the mcu and the run it. Here's some useful commands to use: Run file from local dir `ampy run "FILENAME".py` Send a file `ampy put "FILENAME".py` Read a file `ampy get "FILENAME".py` See all files `ampy ls` Using `ctrl-D` in the REPL allows us to paste raw code and run it straight away. This is handy if you just want to try a little piece of code. Use `ctrl-D` to exit the RAW-paste mode. --- ## Servers (if you're handling data locally) To receive and handle the data we need a running server. I'm using my Nas, which is running FreeNas. In this, I can create a seperate jail with its own network stack and IP. You can use a Raspberry Pi for this as well, if you're using a Pi to power the monitor, this could work perfect, although I would recommend a more powerful Pi than Pi Zero. Details on the softwares to use will come later on, under **Platforms**. --- Putting everything together === Bring out your soldering iron, engineering skills and buckle up! ## Sensor-node Here's the components that we'll need. Now we'll just connect everything, you can do this by normal jumper-wires or solder it (highly recommended). ![](https://i.imgur.com/JN31l0g.jpg) The schematic below shows the wiring. Depending on what sensors you choose, it might be different. Note that I'm using a pin, **D8** as Vin for all sensors. ![](https://i.imgur.com/AjGxpml.png) **Yellow** is GPIO5 - SCL, bad color choice... **Note:** The switch should be **normally closed**, I simply couldn't find a symbol for it :smile:, it's required for deepsleep wakeup on the ESP8266. If we didn't have a switch here we would have to remove the solder every time we wanted to debug (bad idea). 1. **Soldering!** The **+** of the battery is attached to Vin and **-** to GND. This lets us bypass the onboard voltage regulator and thus saving alot of energy! After a few hours of soldering, this is what it looked like: ![](https://i.imgur.com/m1ZZHpk.jpg =400x) 2. **Create a case**. If you have a 3D-printer, great! Either way, feel free to use whatever you want! I used [tinkercad](https://www.tinkercad.com/) to make my models. I'll have the .STL files on the github page. If you're planning on having it outside, you need to pay extra attention to the case! ![](https://i.imgur.com/5CUalsd.jpg =400x) 3. After creating the case and doing a bunch of wiring, gluing etc, this is the end result. ![](https://i.imgur.com/AQdG8dH.png =400x) --- ## Monitor The steps here will vary on what type of screen you're using, but here's the steps I took: --- **WARNING:** When working with the screen without its protection-case be vary careful. Most screens takes 230V AC as input and touching wrong places could be deadly. --- An old LG-screen I haven't used in years. ![](https://i.imgur.com/qfxG1B0.jpg =600x) 1. Removed the outer case ![](https://i.imgur.com/yDu9Dvd.jpg =600x) 2. Ensure that the screen still works. Here I'm booting up my Pi. ![](https://i.imgur.com/OnwQI9f.jpg =600x) 3. Figure out how you're going to power the Pi, you should be able to find some 5V DC on the electronics. I found a sweet spot here. If you can't find it, or feel unceratin about it, you can simply power the Pi seperately. ![](https://i.imgur.com/hurM4Pd.jpg =600x) 4. Not going to lie, I bought the outer frame (I happen to know someone who creates frames for a living). You could of course make one yourself though! ![](https://i.imgur.com/OxsT5TZ.jpg =600x) 5. Added a switch between the power cable. ![](https://i.imgur.com/6WSSqq4.jpg =600x) 5. Connect the leds and the HC-SR04 sensor with the Pi. This is a horrible schematic, but I bet your setup will differ. I'm using RBG-leds, so they have 4 pins. I also "hacked" the **"on"**-button with the help of a Mosfet, which allows me to turn on the screen with software from the Pi. [Great scott](https://www.youtube.com/watch?v=o4_NeqlJgOs) has a great tutorial on mosfets if you're curious. ![](https://i.imgur.com/XUDK8Z0.png =600x) 6. Here's everything soldered and wired. You can see an IR-sensor in the down-center. This wasn't a good idea and later replaced with an ultrasonic sensor, **HC-SR04**. ![](https://i.imgur.com/PxqhqeV.jpg =600x) 7. Did some DIY wall-mounts, worked like a charm. 1 pair on the wall, the other pair on the monitor ![](https://i.imgur.com/WfQfB3I.jpg =600x) ![](https://i.imgur.com/gN7Agwx.jpg =600x) 8. Try it out, sweet! ![](https://i.imgur.com/gLaYrgG.jpg =600x) ## Energy consumption The mcu reads the sensors every 10 minutes and each measurement + sending the data takes ~4-5 sec. To power the ESP8266, I use two 1.5V AA-batteries, which (when new) gives ~3.2V. According to [sparkfun](https://learn.sparkfun.com/tutorials/esp8266-thing-hookup-guide/powering-the-thing) the ESP8266 can function on 1.7-3.6V. According to my measurements, in operation mode, the ESP8266 consumes ~80 mA at ~3.2V. This is quite low compared to other online sources and according to the [documenation](https://www.espressif.com/sites/default/files/9b-esp8266-low_power_solutions_en_0.pdf) from esperiff, the ESP8266 should consume as little as ~20 µA in deepsleep. My multimeter shows 1 mA, but goes crazy when measuring in the µA-range (think I've burned a fuse...), so I'll guess it's somewhere in between. Let's say it's not as good as in the datasheet, but about 0.1mA. This gives an average consumption of`( (595 * 0.0001) + (0.08 * 5) ) / 600 ≈ 0.8 mA`. Not too bad! On two normal 1.5V [battery](https://en.wikipedia.org/wiki/AA_battery), this should last 522-3721 hours, which means 21-155 days. This is a very rough estimate, and the time obviously changes dramatically if the consumption is higher or lower, but it also shows that Wifi isn't the best iot-protocol when battery is a big concern. Luckily, my system is at home, so I can easly change battery when needed. --- Platform === I'm running everything locally, which gives great control and insight into how the flow of data works. Every piece of software used in the project is open-source which means it's completely free. This works very well for a hobbeist like us ***makers***, but has its limitations. 1. You need to do a bit of system administration, to get things going. 2. If you want to access your servers from outside home, you need to open up ports. This is very easy to do on a normal home router, but you should be careful when doing this. 3. You need a machine that's always running. If you have a Pi/Nas, that's no problem. So if you're planning on scaling this, it's worth checking out some cloud solutions, but this is a **great** way to learn! What we need: | Service | Software | | -------- | -------- | | MQTT-broker | [mosquitto](https://github.com/eclipse/mosquitto) | | MQTT-client | [Node-red](https://nodered.org/) | | Database | [mysql](https://github.com/mysql/mysql-server) | | Data visualizer | [Grafana](https://grafana.com/) | I'm using a Nas to run mosquitto, mysql and Node-red. It runs Freenas, so the commands below might look slightly different for you. The easiest way is, as usual, to check out the installation guides on the documentation pages. The steps that are needed for the programs are: 1. Install the program 2. Enable it as service to the service-handler of your os (systemd, rc etc) 3. Start the service `service SERVICE_NAME start`. ## mosquitto This acts as the middle-man between the sensors and the backend server. When the sensors publishes messages, the broker forwards them to the subscribers that matches the topic (how this is done depends on the QoS of client). All you need is to install it; `pkg install mosquitto` and then load it into the service handler: `echo mosquitto_enable="yes" >> /etc/rc.conf` and start it with `service mosquitto start`. ## mysql This can be installed with `pkg install mysql57-client mysql57-server`. Then we can enable it, start it and create a new user. ``` sysrc mysql_enable="yes" service mysql-server start # start service service mysql-server status # check if everything OK cd /usr/local/bin mysql_secure_installation # start secure installation mysql -u root -p password newpass # set new root password mysql -u root -p # login CREATE USER 'username'@'ip' IDENFITIED BY 'password'; GRANT ALL PRIVILEGES ON * . * TO 'username'@'ip'; FLUSH PRIVILEGES; ``` To set up a database we can do: ``` CREATE DATABASE sensors; CREATE TABLE weather (time DATETIME, temperature int, humidity int); CREATE TABLE plants (time DATETIME, basil int, thyme int, oregano int); ``` This will give the following structure: | Time | Temperature | Humidity | | -------- | -------- | -------- | | 2020-06-29 18:32:22 | 23 | 32 | You should obviously adjust the parameters and names to your choice! ## Node-red Node-red, is an awesome tool to work in a flow-driven way, that let's us subscribe to the MQTT-broker and store the data to the mysql-database. You can also easly set up triggers to handle certain events. Node-red requries npm and can then be installed with`npm install -g --unsafe-perm node-red`. To enable it as a service we'll use [pm2](https://github.com/Unitech/pm2) and can be done with: ``` npm install -g pm2 # install pm2 start /usr/bin/node-red -- -v # start it pm2 save pm2 startup ``` Once Node-red is started you can open a browser and go to `your.ip.here.pls:1880`. First, configure the MQTT-broker with the server-ip that we have configured. ![](https://i.imgur.com/wXAwH3B.png) And install a pallete called `node-red-node-mysql` to send queries to mysql. Then we can add our mysql-server as database. ![](https://i.imgur.com/w4k0xjr.png) Now we're set up! I've created the following flow where we subscribe to all topics from the sensors, attach a datetime-string to it and save it to mysql. ![](https://i.imgur.com/rJJ2ACQ.png) The code for the functions is found on the github page. To try it, you can create an inject-node that publishes some data to the MQTT-broker like this: ![](https://i.imgur.com/CkboeeN.png) Check if the database has received the queries! ## Grafana To display the data we'll be using Grafana. I'm running it locally on the Raspberry Pi. This software is very easy to work with and handles pretty much everything for us! To install it: ``` sudo apt update && sudo apt upgrade -y # update system sudo apt install libfontconfig1 -y # install req-library for grafana wget https://dl.grafana.com/oss/release/grafana-rpi_7.0.3_armhf.deb # download ARMv6 version sudo dpkg -i grafana-rpi_7.0.3_armhf.deb # install with package-manager sudo vim /etc/grafana/grafana.ini # enable autonomous view (needed for kiosk mode) sudo sed -i -e 's/;enabled = false/enabled = true/' /etc/grafana/grafana.ini # enable anonymous auth ``` Now you can go to `your.ip.here.pls:3000`, login with `admin, admin` and then choose your datasource and enter the credentials. Click `Save & test` to see if it work! ## Kiosk-mode Raspberry Pi To display it to the monitor I'm using chromium, openbox and X-server. You can install these with: ``` sudo raspi-config # enable autologin sudo apt update && sudo apt upgrade # update before installning sudo apt intsall --no-install-recommends xserver-org x11-server-utils # X-Server sudo apt install xinit openbox # Openbox (Window Manager) sudo apt install --no-install-recommends chronium-browser # Web browser ``` Now we need to edit /etc/X11/openbox/autostart ``` > sudo vim /etc/X11/openbox/autostart # Disable any form of screen saver / screen blanking / power management xset s off xset s noblank xset -dpms # Start Chromium in kiosk mode sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' ~/.config/chromium/'Local State' sed -i 's/"exited_cleanly":false/"exited_cleanly":true/; s/"exit_type":"[^"]\+"/"exit_type":"Normal"/' ~/.config/chromium/Default/Preferences chromium-browser --disable-infobars --kiosk 'http://GRAFANA-URL-HERE' # Start X on boot echo "[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]] && startx -- -nocursor" >> ~/.profile ``` Now you can reboot, and the Pi should open the url in the `autostart` file. If you're using a different window-manager or have any difficulties, there's quite good documentation on this. You can also check out [grafana-kiosk](https://github.com/grafana/grafana-kiosk) which seems really cool. ## LED-&-motion-detection-control ***(Optional)*** To control the leds and turn on/off the screen with a distance-sensor I made a python script which, together with a unit file is loaded into systemd on the Pi. This script will control the leds and the power to the display. Together with the HC-SR04 we can turn it on with our hand, awesome! The code is found in the github repository. --- Code on sensor-node === Found [here](https://github.com/victorhook/iot-course-project/tree/master/src/sensor-node), together with every rest of the code :slightly_smiling_face: --- Transmitting the data === ## Data-flow ![](https://i.imgur.com/6PklS6t.png) 1. ESP8266 takes a sensor-reading every 10 minutes and sends it through wifi, using the MQTT protocol. After this, the mcu goes to deepsleep mode. The packets sent are **publish**-packets, going to the MQTT-broker (**mosquitto**) that is running on the Nas. 2. Node-red subscribes to the desired topics, like `sensors/weather` and gets the packets from the broker, once they have been published from the ESP8266. 3. Once the Node-red client has received the data, it's stored to mysql database. 4. Grafana is constantly querying mysql for new data, and receives it if there is. This data is then displayed on the monitor. ## Protocol Wifi is great for sending data **really** fast, with the cost of having short range and high power consumption. The range is no problem for this project, but the power consumption could be. Ideally, you'd like to use a low-energy protocol, like Bluetooth, ZigBee, Lora or normal 433 RF modules. The good thing with wifi is that we need no gateway to get our data into IP, and since I'm have the sensors close, changing the battery every few months will be fine (I think). In this project, I'm not using any encryption so anyone sniffing the network could see the data. I don't really mind anyone sniffing my plant moisture, but if you're scaling it, this could be an issue. This can be fixed with MQTT authentication or secure protocols, like tls. MQTT allows great scaling capabailities and gives a very natural flow to the communication. ## Data format The actualy data is formatted as JSON, since it's very easy to work with, and a logical way to send data with MQTT. This comes with a lot of overhad, compared to encoding data and here we have to choose between efficiency and readability/ease to work with. I Choose ease & readabilty. --- Presenting the data === The data is saved to the database as soon as the message is published, which means every 10 minutes. I think this is a pretty good frequency when measuring temperature & moisutre, but to save battery it could be less often. ## Database The reason behind mysql is that it's easy to set-up, extremly common and completely free. The data is stored as long as I want it there (or the disk becomes full, which it won't...). If you were short on disk-space, or performance (it takes longer time to query bigger databases), you can remove some of the old samples. For instance, you could keep only the average temperature of the day after a month has passed. It might only be interesting with details during the previous week etc. This could save a tremendous ammount of data. ## Visualization With the help of Grafana, it's really easy to set up some nice-looking visualization of the data. You can put a ton of different filters to show exactly what you want! ![](https://i.imgur.com/9VITPv5.png) **Tip:** If you want to use images, you can put the image in the img-directory of grafana, on my pi it was in `/usr/share/grafana/public/img`. Now grafana knows about them and you can create a Text-panel and create an img-tag with html `<img src="/public/img/NAME_OF_IMG.jpg">`. ## Triggers Working with Node-red is truly awesome because it allows us to create trigger events very easly. This flow compares the new temperature with the highest temperature record in the database. If the new temperature is higher, an email is sent to me, informing that we got a new highscore! (and to put on sunscreen...) ![](https://i.imgur.com/6XnYx4B.png) The code can of course be found on github. --- Finalizing the design! === If you've followed the guide, you might end up with something like this! ![](https://i.imgur.com/hTSRHs5.jpg) ![](https://i.imgur.com/ewm0Scz.jpg) ![](https://i.imgur.com/kDFgO8i.jpg) {%youtube TaCLDOGH7ps %} --- Hope you learned something new! :smiley: