A river or lake can be a great source of fun and relaxation. But if the river becomes dirty and contaminated, all the fun is gone. Many people depend on river water to feed their livestock and cannot afford to give their animals dirty water.
Imagine living right next to a river (if you are not), you would not want to wake up in the middle of the night with your house flooded because of the river. Or what if your neighbour decides to dump some petrol in the river, you would not want your animals getting sick.
MyRiver solves all of those problems, it can operate in isolated areas thanks to Sigfox so that everyone has access to the device. The device will read the pH of the water, its pollution level using an innovative method, and its water level. You will be able to monitor the river live on your phone or computer anywhere thanks to Wia. This way you can know if there is a problem with the stream and allows you to act before it is too late. It will notify you if there is a problem with the river immediately.
Video
Image
The device is based on the Arduino MKR FOX, it is designed for remote use, the user can place the device in a river or lake and monitor it from anywhere. Thanks to the SAM D's low power mode, the device can work for an extended period of time on 2AA batteries.
The device takes readings every 30 minutes, going to sleep afterwards, the sleeping period can be reset, though the minimum sleep time must be 20 minutes.
The MKR FOX reads the pH of the river using a pH sensor, it also gets its water level, using a water level sensor, and it senses if it is polluted by insoluble substances by shining an LED at a photoresistor, if the photoresistor reading is low, it means that a solid substance (oil, petrol, mercury, etc.) is present in the river. The device then sends all the data to Sigfox, where it is relayed on to Wia, processed and visualised. The user is notified on the state of the river. Below is an image of the functionality overview.
The buffer will be sent to Sigfox encoded as HEX, Sigfox will relay the data to Wia, the data will then pass through a flow, the data will be converted back to string and then into the sensor values. They will then be processed and the user will be notified if the values are out of bounds.
Below is another image illustrating the project's code overview, described below.
Read Sensors
will read the pH, water level and photoresistor sensor values and store them in variables.Format Buffer
will merge all the values into a 12 Byte buffer that can be sent to Sigfox.Parse Data
will parse the buffer to Sigfox.
The MKR FOX can only send 12 bytes through Sigfox, this means that all the sensor values have to be merged into the 12 bytes, each sensor's maximum raw value is 1024 (as they are all analog), so each sensor represents one third of the buffer (4 bytes). The Arduino has to merge the values and add zeros to the start of each value until the value has 4 bytes. The image below illustrates this process.
The Arduino receives the sensor values as integers, it then converts the integers into strings and adds zeros to the start of each value until it has 4 bytes, for example, if the photoresistor value is 620, one zero will be added, 0620. But if the water level sensor is equal to 24, two zeros are added, 0024. The device then merges the values together into a 12 bytes buffer and sends the data to SigFox.
The Device in ActionBelow are a number of photos displaying the functionality of the project, for a better view of them, refer to the video above.
The user operating this project will benefit in:
- Easily monitoring a river's water level, ph and pollution level from anywhere at any time
- Receiving a notification if the river is polluted by soluble or insoluble substances or is flooding
- Ease of use and mounting
- Works in any Sigfox covered country
Step 1: Required Apparatus
This project requires all the components to be soldered together, there are not too many things apart from the sensors. The list of materials is noted below.
- 1, Arduino MKR FOX 1200
- 1, pH Sensor
- 1, Water Level Sensor
- 1, Photoresistor
- 1, White LED
- 2, Resistors (220Ω)
- Jumper Wires
Step 2: Connecting the Circuit
The project's circuit diagram can be a bit confusing as the components are not placed on a breadboard, if you have any difficulty with it, try downloading the Fritzing file below and moving the wires around on your computer.
- Circuit Overview
The images below will illustrate how the circuit should look when completed.
- Preparing the MKR FOX
The images below will guide you through connecting the battery box and antenna to the MKR FOX, Note that the battery box must be connected after sensors are connected. Other wiring and setup is found under constructing the project / Final.
Step 3: Acknowledging the Code
There are 3 main parts to the code:
- Read Sensors
- Format Buffer
- Parse Data
These sections are explained below.
- Read Sensors
struct GetValue // created Structures to ease out loops
{
int riverLevel() // get level of the river
{
const int val = analogRead(A2);
if(proDebug)
{
Serial.print(" River Level "); Serial.println(val);
}
return val;
}
int riverPh() // get ph of the river
{
const int val = (analogRead(A1) / 5 * 3.3);
if(proDebug)
{
Serial.print(" River Ph "); Serial.println(val);
}
return val;
}
int riverPol() // get pollution level of the river
{
const int val = analogRead(A3);
if(proDebug)
{
Serial.print(" River Pollution "); Serial.println(val);
}
return val;
}
};
The structure above contains loops that read each sensor value, there is a separate loop for each value.
- Format Buffer
String data(int level, int ph, int pol) // merge sensor values into buffer
{
int values[3] = {level, ph, pol};
String newValues;
for(int i = 0; i < 3; i++) // will run through all values, adding 0s to the start
{
if(values[i] < 10)
{
newValues += "000";
Serial.println("Option 1");
}
else if(values[i] < 100)
{
newValues += "00";
Serial.println("Option 2");
}
else if(values[i] < 1000)
{
newValues += "0";
Serial.println("Option 3");
}
else {};
newValues += values[i];
Serial.print(" Run "); Serial.print(i); Serial.print("/3 "); Serial.println(newValues);
}
return newValues;
}
The loop above intakes the 3 sensor values and then places them into an array. It then loops through each value, adding zeros to the start of each value until the value is 4 bytes in size, it then adds each value to a string which is then returned.
- Parse Data
void parseData(String data) // send buffer to SigFox
{
SigFox.beginPacket();
SigFox.print(data);
int ret = SigFox.endPacket();
}
This section intakes the string to parse and then sends the value to Sigfox.
Step 4: Setting Up Wia Sigfox Integration
This step will illustrate how to set up Wia to receive messages from Sigfox, Wia is a professional IoT platform that allows the user to visualise data using widgets on the web or on the mobile app, it also allows the user to create a block code called a flow, which allows the user to process the data. Data is represented by an event.
To get started, make sure you have a Sigfox account and a Wia account. Also download the Wia app on iOS or Android to allow you to receive notifications. The images below will illustrate connecting Sigfox and Wia.
- Set the Type to
Data Uplink
- Set the Channel to
URL
- There is no need to fill in the Custom Payload Configuration
- Set the URL Pattern to "https://api.wia.io/v1/events"
- Set the HTTPMethod to
POST
- Create a header named
Authorisation
with the valueBearer
(this value will be edited later on) - Set ContentType to
application/json
- Copy the code from this link into the body of the webhook.
- Lastly, click OK and you are done.
Step 5: Setting Up the Wia Flow
This section will take a little longer to complete, the flow will convert the data received from HEX to String, it will then parse the string into the 3 sensor values and then convert them to integers, it will then convert the value of river pollution and river level to a High or Ok descriptor and the raw ph value to the actual ph value, it will then notify the user if the value is out of bounds.
The guide below will illustrate this process step-by-step. You will be instructed to insert certain pieces of code in Wia Functions, these pieces of code are inserted below, just copy and paste the code into the function. The data to include in the emails are also inserted below, work with them like with the functions.
Wia Functions
- processPayload
if(input.body)
{
output.body.name = "value";
output.body.data = toByteArrayStr(input.body.data.sigfoxData);
}
function toByteArrayStr(sigfoxData)
{
let result = Buffer(sigfoxData, 'hex');
return result.toString('utf8');
}
- processPollution
if(input.body.data)
{
let data = input.body.data;
if(data == "POLLUTED")
{
output.body.name = "waterLevel";
output.body.data = data;
}
else
{
while(1);
}
}
- processPh
let minVal = 6.5;
let maxVal = 8.5;
if(input.body.data)
{
let data = input.body.data;
if(data > maxVal || data < minVal)
{
output.body.name = "waterPh";
output.body.data = data;
}
else
{
while(1);
}
}
- processLevel
if(input.body.data)
{
let data = input.body.data;
if(data == "HIGH")
{
output.body.name = "waterLevel";
output.body.data = data;
}
else
{
while(1);
}
}
- riverPollution
let minVal = 200;
let maxVal = 0;
if(input.body.data.sigfoxData)
{
let data = input.body.data.sigfoxData;
let processedData = toByteArrayStr(data);
let newData = cutString(processedData);
output.body.name = "waterPollution";
output.body.data = processData(newData);
}
function toByteArrayStr(sigfoxData)
{
let result = Buffer(sigfoxData, 'hex');
return result.toString('utf8');
}
function cutString(data)
{
let newVal = data[8]; newVal += data[9]; newVal += data[10]; newVal += data[11];
let finalVal = parseInt(newVal);
return finalVal;
}
function processData(data)
{
if(data < minVal)
{
return "POLLUTED";
}
else
{
return "OK";
}
}
- riverPh
let minVal = 300;
let maxVal = 600;
if(input.body.data.sigfoxData)
{
let data = input.body.data.sigfoxData;
let processedData = toByteArrayStr(data);
let newData = cutString(processedData);
let finalVal = (newData / 73.1428571);
let valueToSend = finalVal.toFixed(2);
output.body.name = "waterPh";
output.body.data = valueToSend;
}
function toByteArrayStr(sigfoxData)
{
let result = Buffer(sigfoxData, 'hex');
return result.toString('utf8');
}
function cutString(data)
{
let newVal = data[4]; newVal += data[5]; newVal += data[6]; newVal += data[7];
let finalVal = parseInt(newVal);
return newVal;
}
- riverLevel
let minVal = 0;
let maxVal = 200;
if(input.body.data.sigfoxData)
{
let data = input.body.data.sigfoxData;
let processedData = toByteArrayStr(data);
let newData = cutString(processedData);
output.body.name = "waterLevel";
output.body.data = processData(newData);
}
function cutString(data)
{
let newVal = data[0]; newVal += data[1]; newVal += data[2]; newVal += data[3];
let finalVal = parseInt(newVal);
return finalVal;
}
function toByteArrayStr(sigfoxData)
{
let result = Buffer(sigfoxData, 'hex');
return result.toString('utf8');
}
function processData(data)
{
if(data > maxVal)
{
return "HIGH";
}
else
{
return "OK";
}
}
Wia Emails
- riverPollutionEmail
Automatic Messaging System
Data
Warning - myWater device ${trigger.source.device.id} detected a problem in the stream.
Warning - Water Is Polluted by Insoluble Substances.
Information
Device ${trigger.source.device.id}
Raw Data ${input.body.data}
- riverPhEmail
Automatic Messaging System
Data
Warning - myWater device ${trigger.source.device.id} detected a problem in the stream.
Warning - Water Ph is not Appropriate. Water is Contaminated.
Information
Device ${trigger.source.device.id}
Raw Data ${input.body.data}
- riverLevelEmail
Automatic Messaging System
Data
Warning - myWater device ${trigger.source.device.id} detected a problem in the stream.
Warning - Water Level is too High, River may be flooding.
Information
Device ${trigger.source.device.id}
Raw Data ${input.body.data}
Setting Up the Variables
When the data is received by Wia, it has to be processed, if the data is between a minimum and maximum value, the value is safe, the pH and water level sensor's limits have been set, but the user has to manually set the photoresistor's limit, a test has to be made to determine this value, the steps below will instruct you how to do this.
The first step is to fill a 1/2L transparent bottle of water with... clean tap water.
Next, turn the device on and ensure that the circuit is connected as in the project's schematics.
Now tape the LED on one side of the bottle and the photoresistor on the opposite.
Plug the MKR fox into the Mac/PC and upload the fallowing code to the device.
void setup()
{
pinMode(1, OUTPUT);
Serial.begin(9600);
while(!Serial) {};
digitalWrite(1, HIGH);
}
void loop()
{
const int val = analogRead(A3);
Serial.println(val);
delay(5000);
}
Now open the Serial Monitor and look at the reading, note the reading down, it could be 400 or 15, depending on many factors, once you have used a 1or2L transparent water bottle filled with tap water, your can trust your reading.
Now, add a dark ingredient to the water, I used soil, you can use coffee, black tea or other dark stuff around the house, mix well.
Now look at the reading on the Serial Monitor, note that down too.
Compare the two results, let's say that the clean water outputted 400 and the dirty outputted 50, to find the marginal value for the Wia flow, go up a bit over the dirty water output, so around 100 for us. If you get 20 and 5 as your values, then the marginal value would be around 8.
Now fallow the images below that illustrate the process of editing the marginal value on Wia
There is another variable that the user has to set, proDebug
, if it is enabled, the Arduino requires connection through USB to a computer and the Serial Monitor must be open, the Arduino prints to the Serial Monitor in this mode, it is ideal for troubleshooting. proDebug defaults to false
for operating on the field.
Libraries
- Sigfox - copyright (c) 2016 Arduino LLC GNU Lesser General Public Licence this library is in the public domain
- ArduinoLowPower (c) 2016 Arduino LLC GNU Lesser General Public Licence this library is in the public domain
Final
The last step is to connect your Arduino to a PC/Mac and upload the sketch, make sure that the battery box is connected to the Arduino and the circuit is ok. The next steps will guide you through making an enclosure for the project.
I have decided to create my enclosure out of a bottle of water, I think it is a great and ecological way to embrace the project in. The device looks like the picture below.
If you like the idea of the enclosure, you can scroll through the images below, illustrating how the enclosure was made, feel free to make one yourself.
The last thing to do is place the device in the river. To do this, go to the river you wish to implement MyRiver on during High Tide, this is essential to ensure that the device is not alerting that the river is flooding when it is actually just the tide.
Place some tape on the top of the water bottle to prevent water from seeping into the bottle and destroying everything.
We went to a local, dirty river to test the project out, all the alarms went off correctly.
When placing the probe in the water, ensure that the water is at the bottom of the water level sensor but is covering the photoresistor entirely. Secure the project to the shore using tape or a hammer and screws, and it should look like this (or better).
Relaxing in your house, looking out the window at the once beautiful and delightful river rushing in front of you. But instead of the beautiful fresh river, you see a green slimy one, you might want to move house in that case.
And if the river decides to flood into your house in the middle of the night while you are sleeping, you will certainly decide to move.
I thought of these problems and how to solve them all in one device, and I came up with MyRiver.
If you are in the city and living beside a river, it will warn you in time if the river decides to ruin your day in any way or if your neighbour is dumping oil in the river. Or if you are on a farm, MyRiver will warn you that the river is dirty before you give the water to your animals, and will give you time to bring the animals in before the river floods.
But just reading the pH of the river was not enough, as insoluble substances like mercury or other metals do not effect the Ph of the water. So we came up with a new method to detect those substances, unique to this project, a photoresistor reading the amount of light from an LED penetrating the water. This way any water impurity can be detected.
Comments