A LoRaWAN device to measure drinking water quality which can be deployed over a wide area.
Some design considerations:
- One year battery life.
- Weatherproof and durable.
- Measure basic water quality indicators every hour.
Water quality measurements are expensive and the logistics of obtaining, storing, and doing something with the data is complicated. Where you want to measure is often out-of-the-way. Hardware options include some sort of cellular device, but that's a relatively high initial cost plus a recurring cost over the life of the device.
So What's the Solution?Helium is introducing a LoRaWAN network in the US and Canada. It will provide large coverage areas through the use of what they call Hotspots (check your area's coverage). In LoRa parlance, these are LoRaWAN gateways or concentrators. They are providing the transport for our sensor data. Assuming you have coverage, a lot of the hard work of setting up such a wide-area network is done for you. If you don't have coverage, you can setup your own Hotspot. There is an incentive to running one, in that you earn an amount of money for each packet of information routed through.
As for water quality measurements, that has been simplified as well with the sensors we'll be using.
But What's LoRaWAN?LoRa is the physical layer and provides Long Range communications and occupies OSI layer 1. LoRaWAN is a communication protocol (OSI layer 2 and 3). It uses the LoRa layer to provide two way wireless communication. Why not WiFi? Because WiFi can't go more than a couple hundred meters (at best), whereas LoRa can go for kilometers (hundreds of kilometers).
Ok, Sounds Awesome. What Now?Time for a disclaimer here. I own μFire LLC. We make water sensors and provide InfluxDB hosting. No surprise, those are the devices and services this article will be using. Making these little devices is part of what I do.
Let's make some design choices.
We will need a microcontroller. Heltec Automation makes a nice line of LoRaWAN compatible ESP32-based development boards. I like the Wireless Stick Lite, so we will be using that for this project.
It has:
- lithium battery charging/level reading hardware on-board
- WiFi, BLE, and LoRaWAN interfaces
- low power design
- controllable power-supply pin to power sensors
- Arduino compatible
We need some water sensors. This project will use:
- oneIsolated EC Probe Interface with a conductivity probe
- twoIsolated ISE Probe Interfaces with a pH and ORP probe
- we'll also need a waterproof temperature sensor which we will also get from μFire.
μFire sensors all use Qwiic/STEEMA QT I2C connectors. So this step is pretty simple. On the Heltec board, connect the blue wire to pin 32, the yellow to 33, the black to a ground pin, and the red to the Vext pin.
Before we move on, a quick explanation of the pins and how they were chosen. The black ground pins are nothing special, there are a few available for use on the Heltec board. The red wire is power, the blue and yellow pins are SDC and SCL. On the ESP32, you can pick any two pins you want for the I2C bus, so I picked 32 and 33 because they aren't being used for anything else. The red wire connects to the VExt pin.
What is a Vext pin? It is a power pin that the controller can turn on and off. This is great for battery devices because you can just turn it off and the connected sensors don't draw any power at all. Then when you want some readings, you turn it back on.
Anyways, now just connect the Heltec board to an EC or ISE board, then connect the other two in the same way. The last thing to connect is the temperature sensor. It could connect to any board, but for this project, it will connect to the EC board. It's just a keyed, push-fit connector.
We are now left with a bunch of sensors daisy-chained to a Heltec board, laying on the tabletop. We want this to be able to sit outside, and near water, so that's not going to work. Let's put it in a box.
Make an EnclosureFor this project, I will use a Bud Industries plastic box. We will need to drill some holes in the side of the box to mount the sensors. For this, we need a 9 mm fortsner drill bit. Why such an oddly specific named drill bit? Because it works when you are drilling soft, low melting point plastic like the one used in the enclosure. If you use a spade bit, you'll make a melted mess. A wood bit will jump and skip all over the place, even if you think you're being smart by drilling a pilot hole.
The method I use to get good and repeatable results is to make an outline in Inkscape. Do some quick math, in our case we will be drilling one hole for EC, one for pH, one for ORP, and one for a temperature sensor. The side I want to mount all these things on is 119mm inches long, so divide that by 4 and you get about 30mm between holes.
Do some Inkscaping and you might end up with something like this:
Print that and tape it to your box. Poke a little hole in the center, mark it with a sharpie, and drill them out. Be careful, go slowly, and apply a minimum amount of pressure or you'll melt or chip the plastic. You'll know you're doing it right if you get really bored while drilling and don't make a melted mess.
Hopefully things work out well and you end up with an enclosure with the planned holes and not some expensive lump of plastic.
Use the included washer, hex nut, and gasket to mount the sensors. From the enclosure moving out, the gasket should be touching the enclosure on the inside, followed by the washer followed by the hex nut on the outside. This will ensure the gasket is being pressed tightly against the enclosure, keeping water out.
The temperature sensor is different. We will use a PG7 cable gland. Make sure you get some that include a sealing gasket.
Throw the Heltec board in there with the battery connected. You can secure them with double sided tape, velcro, or some mounting screws. Keep it connected with a USB cable to program it later.
InfluxDB is a time-series database. It's easy to use and ideal for sensor measurement storage. It also very conveniently comes with an integrated graphing component called Chronograf. With the two, you can record sensor information and then display it any way you want. For this project we will be using μFire Net to take care of all this for us.
You can set it up on your own if you like. This project uses InfluxDB version 2, which is significantly different than version 1. You'll also need an MQTT server if you go this route.
Anyways, μFire Net will set you up with everything needed in this project. You won't need to make any changes to the initially provided setup, but you will need a few pieces of information
- The Address: the website address where all this lives.
- Organization: when you initially login, you will set this. Don't use spaces, since it will cause issues with other software.
- Bucket: Once you login, go to the side menu and choose Load Data / Buckets. Click Create Bucket in the right corner and remember the name you give it. For this project, I called mine wq.
- Token: After you make your bucket, you need to make a token. From the menu, click Load Data / Tokens and click Generate. You have a couple options here, for the most secure token, create one with just read/write access to the bucket you created.
Next thing to set up is the Helium side of things. You'll need to make a Helium Console account.
Click the Integrations link on the left and select MQTT in the Add a Custom Integration section.
Scroll down a bit and you'll see a section titled Step 2.
This is where you need to put in your MQTT server information. For me, my μFire Net account I'm using is awesome.ufire.net. My Endpoint line would look like this:
mqtts://awesome:password@awesome.ufire.net:8883
For the Topic section, put helium.
What this step is doing is telling Helium to send an MQTT message each time a message is received from our device. In the next step we'll be building a small python script that will subscribe to the same MQTT server and topic, parse the information, and insert it into our InfluxDB.
Now go to the Devices page and click Add Device.
Pick any name. Dev EUI, App EUI, and App Key are automatically generated and are the bits of information you'll need a few steps later to enter into your Arduino sketch.
Next thing is to create a label, so go to the Label page and click Add Label, give it any name you want and in Step 2, pick the name of the MQTT integration you made. Then click Create Label & Manage.
On the next screen that opens, click Add this Label to a Device in the right corner. Check your device in the list, then check the integration. This will connect the Integration to the Device.
MQTT BridgeThe flow of information is this:
1. Our device will send out sensor measurements
2. A Helium Hotspot will pick them up and send them along to their server.
3. Once at the server, it will look to see what integrations are configured. In our case it will publish an MQTT message on our server with a bunch of information. It's encoded and we can't do anything with it yet.
4. A python script will also be subscribed to our MQTT server, listening for those messages. It will decode it and then insert it into our database.
You'll need to install a few packages to get this script going.
pip3 install influxdb-client
pip3 install msgpack
pip3 install paho-mqtt
influxdb-client is the offical InfluxDB Python client library.
msgpack is a sort of like JSON, but binary. They have a nice website that explains it better than I can. I chose to encode my sensor data using MsgPack rather than just a binary pack because it allows you to decouple your data from your source. If you just sent binary packed payloads (think [4 byte float]-[4 byte long]-[4 byte uint32]), then you need to know on both sides, what those bytes represent. Using MsgPack, we can send a message that in JSON might look like this:
{"batt":3.7,"ec_uS":500}
We can then decode that in our MQTT script and get the same thing, not just a bunch of random bytes. It's bigger than just binary information, but I think the trade-off is worth it.
paho-mqtt is the MQTT library I'm using.
Copy this Gist on your computer (or wherever you want to run it).
You'll need to edit a few lines.
ufire_server to your InfluxDB server, my line looks like awesome.ufire.net
mqtt_port to your MQTT port. Mine is 8883.
mqtt_username to your MQTT username
mqtt_password your MQTT password
influx_bucket to the InfluxDB bucket you were supposed to remember from a few steps back
influx_token to your InfluxDB token from a few steps back
influx_organization to your InfluxDB organization name from above
After making those changes, run it:
python3 helium-influx-bridge.py
You may be interested in running this in the background, use this:
nohup python3 helium-influx-bridge.py &
This script was written for Linux-based systems. You'll need to tinker around with the SSL certificate paths if you want to run this on Windows. It also assumes the MQTT server is the same as the InfluxDB server, just with different ports.
Remember this needs to always be running or we don't get our sensor measurements. You might want to turn it into a service on a machine somewhere.
On to the CodeThis project will be Arduino-based so if you don't like using my choice of microcontroller, you can switch it to anything else (like a TTGO LoRa32 or Heltec CubeCell) with a minimal amount of code changes.
First, you will need to setup the Heltec board within the Arduino IDE. Follow Heltec's instructions. Helium also has instructions.
Next, grab Heltec's LoRaWAN library, follow their instructions. You will need to make a change, so get yourself to the ESP32_LoRaWAN folder in your Arduino's libraries directory. Open ESP32_LoRaWAN.cpp and change the following lines:
this:
#define LORAWAN_DEFAULT_DATARATE DR_5
to this:
#define LORAWAN_DEFAULT_DATARATE DR_3
and this:
channelsMaskTemp[0] = 0x00FF;
channelsMaskTemp[1] = 0x0000;
channelsMaskTemp[2] = 0x0000;
channelsMaskTemp[3] = 0x0000;
channelsMaskTemp[4] = 0x0000;
channelsMaskTemp[5] = 0x0000;
to this:
channelsMaskTemp[0] = 0xFF00;
channelsMaskTemp[1] = 0x0000;
channelsMaskTemp[2] = 0x0000;
channelsMaskTemp[3] = 0x0000;
channelsMaskTemp[4] = 0x0000;
channelsMaskTemp[5] = 0x0000;
The changes switch the frequencies the device uses to send data, and the data rate.
Head over to this Gist and copy/paste it into a new project in the Arduino IDE.
First, you'll need to make a few changes.
Head back to Helium's Devices page and find the device you created a few steps ago. Click it and you'll see this.
If you click the little diagonal arrows, it will expand the long strings of numbers.
Ensure you see msb displayed, then click the copy icon. Copy it into the Arduino sketch as the value for DevEui[].
Do the same for AppEui[]and AppKey[].
Now pick a couple things in the Tools menu. Make sure you pick "Wireless Stick Lite" for the Board and "REGION_US915" for LoRaWAN Region.
Upload the sketch and run it. Open your serial terminal and you'll see a little blurb about going to a website and getting a license key. Follow the instructions and paste the output into license[4]. Re-upload and you'll be presented with a series of attempts at the device joining the LoRaWAN network. It will typically take a few tries before things progress.
Once the device connects, you should see some activity in your Helium Console under the Device page.
You should be seeing output from the MQTT script.
And now we can setup InfluxDB
InfluxDB DashboardsNow some InfluxDB and Chronograf basics to let you make your own dashboards.
Chronograf is organized by dashboards. Dashboards are collections of visualizations called cells that you can organize in a grid. The visualizations can be a line graph, gauge, heatmap or a handful of others. You can customize a few options, then add them to a dashboard. In the dashboard, you can resize and move it around.
So to get started, create a new dashboard by clicking the Dashboards icon on the left and clicking Create Dashboard in the right corner. Next, click Add Cell.
This is where you do a lot of clicking around. Have a look at this picture:
The FROM list shows all the buckets (databases), then you are presented with a series of filters to get to the data you want.
- The first Filter chooses the set of records we are interested in. In our MQTT bridge, we called it wq.
- Once you click wq you can see all the measurements for wq, but notice how I changed the second Filter to eui. You could use the same wq record for several different devices. In LoRaWAN terms, EUI is a unique identifier for devices, so we added an eui field in the MQTT step to do just that. I only have one device, so I only had one choice, but if you had several, you would be able to pick which device you wanted measurements from.
- In the next Filter, you can pick all the individual measurements our device took.
- Click Submit and you get a chart.
From here, you can click the Customize button and see what options there are for how the cell looks. When you are happy, click the green check and it will be added to the dashboard we created.
You can now click and drag and drop until you get something you like.
You can do something simple, you can split your dashboards into:
- historical: with graphs from hours, days or weeks in the past
- instant: with the most recent measurement displayed in a gauge
- fleet status: you can also monitor the health of your sensors by tracking their battery levels, RSSI and SNR.
And at this point, we are done!
OPTIONAL: Add a DispalyWe already got to a point where our stack is working and we have a minimum viable product. There are some easy additions though. Let's add a screen so we can just look at our box and see the measurements.
Since we are going for battery power, an E-Paper display is the best choice. They don't use any current unless you are actively updating the display and is easy to read in sunlight.
For this project, I picked this Waveshare 2.9" E-Paper display.
Remember, this project is using a Heltec Wireless Stick Lite. It has a LoRa modem on-board which communicates through the chip's SPI interface. We are going to use those same SPI pins to connect our display. The board I linked above comes with all the wires you'll need.
Connect:
- Display VCC to Heltec 3.3v
- Display GND to Heltec GND
- Display DIN to Heltec 27
- Display CLK to Heltec 5
- Display CS to Heltec 18
- Display DC to Heltec 10
- Display RST to 9
- Display BUSY to Heltec 12
The pin numbers use the gray outlined numbers in the pinout diagram.
Once you have it connected, make a new Arduino IDE project. Copy the main file here, and add another New Tab called paper.h and copy the paper.h file from the Gist.
Open paper.h and click the link in the comment next to this line at the very top to install the GxEPD2 library.
#include <GxEPD2_BW.h> // click to install: http://librarymanager/All#GxEPD2
If you take a look through the code, it's nearly exactly the same. Most of the work is done in paper.h. Upload the sketch and you should have a display that gets updated at each interval.
OPTIONAL: Add Solar ChargingAnother easy addition to our device is adding a small solar panel to charge the battery. I found a solar panel lip charging circuit on AliExpress.
The connections are easy. The solar panel wires go SOLAR - and +, BATT IN - and + to the battery, and SYS OUT - and + to the Heltec board's battery connector on the bottom. You might need to swap the little 2-pin connectors to get everything connected. The Heltec board uses an SH2.5 connector for the battery, most of the solar panel charging circuits use PH2.
OPTIONAL: Add Air Temperature and HumidityYou might be interested in the air temperature and humidity. Adding those measurements is easy. Get yourself an SH20 sensor and connect it to an open Qwiic connector.
There are lots of examples to show how to use this sensor. You can also throw in VPD and dew point.
Take a look at the examples, you need the obvious things like the #include and class initialization line. You'll need to add a line to the payload. Yours might look like this:
payload["temp_C"] = sht20.temperature();
payload["hum_RH"] = sht20.humidity();
You'll also need to modify your ArduinoJson variables. Go to their website and use their Assistant to have it do it all for you.
EXTRA: More UsesAs you may have guessed, this setup is useful for more than just monitoring your drinking water.
Other uses might be:
- Hydroponics or Aquaponics: Measuring EC, pH and temperature are vitally important. Maybe you wouldn't care for ORP.
- Pools or Spas: pH and ORP would be good to monitor here. ORP can be used to help manage your chlorine use. EC may be of less use here.
- Fertigation: Close to hydroponics, but in more of a large farm setting. That might make the use of LoRaWAN even more beneficial, allowing monitoring over a large area.
Comments