Soil Hydration Monitor How To: Raspberry Pi Pico x PLSx3-W x MQTT x InfluxDB x Grafana

Monitor soil hydration for healthier plants by getting SMS updates and visualising data with Grafana.

Raspberry Pi Pico x Sparkfun Soil Moisture Sensor x PLSx3-W x MQTT x InfluxDB x Grafana

This is a beginner friendly user guide to show how to measure the soil moisture levels of your house or office plant and receive updates of the moisture levels via text message. This is particularly useful if you have plants at work , second home, or remote area without wifi you want to monitor from a distance since the notifications happen over the cellular network. First we will connect a moisture sensor to a Raspberry Pi Pico. Then we will use Thonny and MicroPython to program and calibrate our sensor. Next we will familiarize ourself with AT commands to program the PLSx3-W Cellular Module for SMS communication. Then we will connect our Pi Pico to the Module via UART in order to send the SMS commands from the Pi Pico. We will program the device to send soil moisture updates as SMS at 8am and 8pm and an alert message if the soil moisture gets below 20%. Next we will connect the soil moisture data to a database. First we will establish and test a MQTT publish/subscribe connection locally using a free online broker, EMQX. Then we will setup InfluxDB and save the data published on our MQTT server. Last, we will setup Grafana locally and use it to visualize the data.

Materials:

Hardware:

Software:

Set up Thonny and Pi Pico on Ubuntu

  1. Set up Raspberry Pi Pico: Connect your Raspberry Pi Pico to your computer using a micro-USB cable. Hold down on the button on the Pico while plugging it into the computer. Let go of the button. Your computer should now recognize the device.
  2. Install Thonny: Download and install the Thonny Python IDE on your computer. Thonny provides a simple environment for writing and running Python code for Microcontrollers. https://thonny.org/
  3. Open Thonny: Launch Thonny on your computer.
  4. Configure Thonny for Raspberry Pi Pico: Go to the “Options” menu in Thonny and select “Configure Interpreter”. In the “Interpreter” tab, choose “MicroPython (Raspberry Pi Pico)” from the list of options. If the option is not available, make sure you have the latest version of Thonny installed.
  5. Select the Pico’s Port: In the Thonny toolbar, click on the “Select interpreter” button (gear icon) and choose the correct serial port associated with your Raspberry Pi Pico.
  6. You are now ready to start programming your Pico. Here is the official the Pi Pico documentation: https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython

Connect Soil Moisture Sensor to Pi Pico

  1. Connect the Raspberry Pi Pico to your computer via the Micro USB cable.
  2. Connect one end of a jumper wire to the VCC pin on the SparkFun Soil Moisture Sensor. Connect the other end to the 3V3 (3.3V) pin on the Raspberry Pi Pico.
  3. Connect one end of another jumper wire to the GND pin on the SparkFun Soil Moisture Sensor. Connect the other end to a GND pin on the Raspberry Pi Pico.
  4. Connect one end of another jumper wire to the SIG (Signal) pin on the SparkFun Soil Moisture Sensor. Connect the other end to any GPIO pin on the Raspberry Pi Pico. We are using GPIO 26 for this example.

Test the Sensor

Let’s get some simple code running to test the sensor.

  1. Copy and paste the following code into Thonny and save onto your Pi Pico.
  2. Press run.

from machine import ADC, Pin, UART
 import utime

 print("Welcome to Soil Moisture Detection Services")

soil = ADC(Pin(26)) # Soil moisture PIN reference

 ###Calibraton values
 #max\_moisture=
 #min\_moisture=

### seconds delay between readings
 readDelay = 1 #second

 while True:
     print('\n')

    ### read moisture value and convert to percentage into the calibration range
     # moisture = ((soil.read\_u16()-min\_moisture)/(max\_moisture-min\_moisture))\*100

# print values

print("moisture: " + "%.2f" % moisture +"% (adc: "+str(soil.read\_u16())+")")

The terminal should now display moisture values every 1 second.

Calibrate the sensor

  1. Uncomment the min_moisture variable and record the moisture ADC value under min_moisture.
  2. Prepare a bowl of water and dip the sensor end into it avoiding getting the wires wet and record the wet value as max_moisture.
  3. Uncomment the line # print(“moisture: " + “%.2f” % moisture +”% (adc: “+str(soil.read_u16())+”).
  4. Run your code again.
  5. You should now see the soil moisture displayed as a percentage.

Set up and test module

  1. Insert the SIM card into the DevKit.
  2. Plug the module into your computer with a usb cable and press the IGN button of the devkit. The on button should come on. The power light should be on and the toggle switched to USB. ASC0 should also be switched to USB.
  3. Now we can open CuteCom to test sending AT commands to the module.
  4. Open terminal on your laptop and dmesg to see which port the Devkit is plugged into.
  5. Type sudo cutecom and enter password to open Cutecom and select the port which is connected to the module.
  6. Press open in Cutecom. You should see a ^SYSSTART message.
  7. Type AT into the command line. You should get an AT OK in response which how we know the communication channel is working.

Connect Pico to PLSx3-W

The next step is to create a UART connection between the Pico and the DevKit/PLSx3-W Module in order to control the module through AT commands from the Pico.

Hardware Connection:

  1. Connect the left RXD0 pin of the Module to the RX pin (GPIO 1) on the Raspberry Pi Pico. RX stands for Receive. (Note: if you are familiar with UART connections, it may seem counter-intuitive to connect the RX to RX since in most other cases, it is RX to TX. However, for this module, it was designed RX to RX.)
  2. Connect the left TXD0 pin of the Module to the TX pin (GPIO 0) on the Raspberry Pi Pico. TX stands for Transmit.
  3. Connect the GND (ground) pin of the Module to a GND pin on the Raspberry Pi Pico.
  4. Connect the RTSO pin on the module with Pin 4 of the Pico.
  5. Connect the CTSO pin with Pin 2 of the Pico.

Now we will connect Tracebox to “sniff” between the modules output and the Pico’s input in order to display the exchange of data via CuteCom on our laptop:

  1. ­UPDATE to include split pin
  2. Connect the RX pin the Tracebox to the RX pin the module.
  3. Plug the USB cable of the Tracebox into your laptop.
  4. Open CuteCom on your computer by typing sudo cutecom
  5. Select the port which the Tracebox is connected to and press open

Test Pico to Module Connection

  1. We need to add some code to program the new pins and test the connection with a simple AT command.
  2. The following code defines the UART pin connection between the Pi Pico and the module by setting the parity, baude rate, bits and flow to insure a reliable reading data.
  3. The def ok() function send an AT command to the module and waits to receive the OK response as a test to make sure the connection is correctly established. We will use the ok() function throughout this project to ensure our commands have been received and implemented by the module successfully.
  4. Copy and paste the code into Thonny and press run.
  5. Press RST on the module and when you see <break> and then a few seconds later ^SYSSTART then press run on Thonny.
  6. You should now be able to see the AT OK messages being sent back and forth between the module and the Pi Pico in the terminal CuteCom and the Thonny shell.

# import required modules
from machine import ADC, Pin, UART
import utime
import binascii
import sys

def ok():
    counter = 0
    while True:
        counter += 1
        utime.sleep(1)
        if counter == 5:
            print("AT_Error, Timed out")
            sys.exit()
        else:
            if uart.any():
                data = uart.read()
                print(data)
                if "OK" in data:
                    print("OK received!")
                    break
        
#### START OF MAIN HERE ####       

input = Pin(0, Pin.OUT)

uart = UART(0, baudrate=115200, tx=Pin(0), rx=Pin(1), cts=Pin(2), rts=Pin(3))
uart.init(bits=8, parity=None, stop=1, flow=UART.RTS | UART.CTS)

print("Welcome to Soil Moisture Detection Services")

# use variables instead of numbers:
soil = ADC(Pin(26)) # Soil moisture PIN reference

#Calibraton values
max_moisture=53700
min_moisture=43200

readDelay = 10 # seconds delay between loop iterations
drySoil = 0

while True:
    print('\n')
    # read moisture value and convert to percentage into the calibration range
    moisture = ((soil.read_u16()-min_moisture)/(max_moisture-min_moisture))*100
    # print values
    print("moisture: " + "%.2f" % moisture +"% (adc: "+str(soil.read_u16())+")")
    
    uart.write("at\r\n")
    ok()

    utime.sleep(readDelay) # set a delay between readings


Send SMS Soil Moisture Update

Now that our module is set up to send text messages in the format we need, we can write the code to send a text.

  1. First we need to set up the text settings which only need to be executed once. Uncomment the lines under ### set up text message settingsand run the code once through. Then the lines can be commented out again.
  2. Next we need to set up the text message mode using the at command AT+cmgfand setting it to 1. This needs to happen once every time the module is restarted. The function def text_mode() takes care of this and sets the variable text_setup to 1 when the process is complete.
  3. In the next step, we will check the time every minute and if it is 8am or 8pm, we will send an update text. This can be set to whatever time you want to get your update messages.
  4. Next we will use the at command AT+CMGS="0177540XXXX",129\r\nto send a text message. This command sets up the text message, then in the next line, we write the message and when we press enter (b’\x1A’) the message gets sent. The 129 in the at command specifies the format of the text message. Consult the at-command handbook if a different number format is required.
  5. The last step in the text message procedure is to send a time to water plants message if the plant needs watering. This we do by checking if the soil moisture is below 20% and if it is, we send another text. Then we set the dry_soil variable to 1 so we don’t get a text every 1 minute informing of the dry soil. At our usual soil update, we will get an addition message that the plant needs to be watered.

# import required modules
from machine import ADC, Pin, UART
import utime
import binascii
import sys

def ok():
    counter = 0
    while True:
        counter += 1
        utime.sleep(1)
        if counter == 5:
            print("AT_Error, Timed out")
            sys.exit()
        else:
            if uart.any():
                data = uart.read()
                print(data)
                if "OK" in data:
                    print("OK received!")
                    break

def text_mode():
    uart.write("AT+cmgf?\r\n")
    utime.sleep(1)
    if uart.any():
        data = uart.read()
        print(data)
        if '0' in data:
            uart.write("AT+cmgf=1\r\n")
    
        
#### START OF MAIN HERE ####       

input = Pin(0, Pin.OUT)

uart = UART(0, baudrate=115200, tx=Pin(0), rx=Pin(1), cts=Pin(2), rts=Pin(3))
uart.init(bits=8, parity=None, stop=1, flow=UART.RTS | UART.CTS)

print("Welcome to Soil Moisture Detection Services")

# use variables instead of numbers:
soil = ADC(Pin(26)) # Soil moisture PIN reference

#Calibraton values
max_moisture=53700
min_moisture=43200

readDelay = 10 # seconds delay between loop iterations
drySoil = 0
mqtt_setup = 0
text_setup = 0
siss_string = ""


while True:
    print('\n')
    # read moisture value and convert to percentage into the calibration range
    moisture = ((soil.read_u16()-min_moisture)/(max_moisture-min_moisture))*100
    # print values
    print("moisture: " + "%.2f" % moisture +"% (adc: "+str(soil.read_u16())+")")
    
    uart.write("at\r\n")
    ok()
    
    if moisture > 20:
        drySoil = 0
    
   
    ### Send text every 12 hours at 8:00 and 20:00 updating on soil moisture
    
    ### set up text message settings
       
    #uart.write("AT+CSCS=\"UCS2\"\r\n")
    #uart.write("AT+CPMS=\"SM\",\"SM\",\"SM\"\r\n")
    #uart.write("AT+cmgf=1\r\n")
    #uart.write("ate1\r\n")
    
   if text_setup == 0:   
        text_mode()
        text_setup = 1
    
    current_time = utime.localtime()

    print("Time: " + str(current_time[3]) + ":" + str(current_time[4]))
    if (current_time[3]==8 and current_time[4]==0) or (current_time[3]==20 and current_time[4]==0):
        print("sending moisture update")

        uart.write("AT+CMGS=\"01775XXXXXX\",129\r\n")                                  #insert own phone number
        utime.sleep(1)
        uart.write("Soil moisture update: " + "%.2f" % moisture +"% (adc: "+str(soil.read_u16())+")")
        utime.sleep(1)
        if drySoil == 1:
            uart.write("Soil dry: Water plant today.")
        utime.sleep(1)
        uart.write(b'\x1A')
   
    ### If moisture is too low, send warning text message
    if moisture < 20 and drySoil == 0:
        print("Time to water Plants")

        uart.write("AT+CMGS=\"01775XXXXXX\",129\r\n")                                  #insert own phone number
        utime.sleep(1)
        uart.write("Soil moisture below 20%, time to water plant")
        utime.sleep(1)
        uart.write(b'\x1A')
        utime.sleep(1) #in order to not get bombarded with text messages every minute
        drySoil = 1        

    utime.sleep(readDelay) # set a delay between readings

Set up MQTT topic locally

Now that we have set up our text message functionality, we can now start with setting up data transfer process so we can continuously get our raw data sent to a database every minute. This will allow us to see the gradual changes in soil moisture as well as give us the framework to compare data values if we want to add more sensors in the future.

We will set up the mqtt topic using a free online broker called eqmx and run it locally on our computer to make sure it works. We will use the library Mosquitto to deploy the protocol.

  1. Save the publish and subscribe code in two different files making sure to include the .py file type.
  2. Open the files with a text editor and change the topic and client id as you please.
  3. Then open two different terminal tabs, navigate to the folder which contain the files and type “python3 sub.py” into terminal to run the programs. Do the same for the pub.py file. You should now see the publish and subscribe test messages being sent back and forth.

pub.py

# python 3.6

import random
import time

from paho.mqtt import client as mqtt_client


broker = 'broker.emqx.io'
port = 1883
topic = "helenasTestBroker"
# Generate a Client ID with the publish prefix.
client_id = f'publish-{random.randint(0, 1000)}'
# username = 'emqx'
# password = 'public'

def connect_mqtt():
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    # client.username_pw_set(username, password)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client


def publish(client):
    msg_count = 1
    while True:
        time.sleep(1)
        msg = f"messages: {msg_count}"
        result = client.publish(topic, msg)
        # result: [0, 1]
        status = result[0]
        if status == 0:
            print(f"Send `{msg}` to topic `{topic}`")
        else:
            print(f"Failed to send message to topic {topic}")
        msg_count += 1
        if msg_count > 5:
            break


def run():
    client = connect_mqtt()
    client.loop_start()
    publish(client)
    client.loop_stop()


if __name__ == '__main__':
    run()


sub.py

# python3.6

import random

from paho.mqtt import client as mqtt_client


broker = 'broker.emqx.io'
port = 1883
topic = "helenasTestBroker"
# Generate a Client ID with the subscribe prefix.
client_id = f'subscribe-{random.randint(0, 100)}'
# username = 'emqx'
# password = 'public'


def connect_mqtt() -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    # client.username_pw_set(username, password)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client


def subscribe(client: mqtt_client):
    def on_message(client, userdata, msg):
        print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")

    client.subscribe(topic)
    client.on_message = on_message


def run():
    client = connect_mqtt()
    subscribe(client)
    client.loop_forever()


if __name__ == '__main__':
    run()


Set up internet service context and setup MQTT on module

Now that we have our MQTT broker set up, we can now work on getting the internet service context on the module set up to send MQTT messages.

  1. at^sica=0,5 is used to active and deactivate the context.
  2. at^SISC=1 to open and close connection.
  3. at^siss to set the internet service context variables. In the mqtt_settup() function, we first check if the context variables have already been set and if not, insert them. You can see that the variables are the same ones we used in our pub.py code.

def at_siss(siss_string, srvType, at_command):

    if srvType in siss_string:
        print("Already contains " + srvType)
    else:
        uart.write(at_command)
        ok()

def mqtt_setup_function():
        
        # impliment IS settings
        uart.write("at^sica=0,5\r\n")
        ok()
#         uart.write("at^SISC=1\r\n")
#         ok()

        uart.write("at^siss?\r\n")
        utime.sleep(1)
        if uart.any():
            siss_string = uart.read()
            print(siss_string)
                         
        at_siss(siss_string, "Mqtt", "at^siss=1,srvType,\"Mqtt\"\r\n")
        at_siss(siss_string, "\"conId\",\"5\"", "at^siss=1,conId,\"5\"\r\n")
        at_siss(siss_string, "broker.emqx.io", "at^siss=1,address,\"mqtt://broker.emqx.io\"\r\n")
        at_siss(siss_string, "publish", "at^siss=1,cmd,\"publish\"\r\n")
        at_siss(siss_string, "hcContLen\",\"5", "at^siss=1,hcContLen,5\r\n")
        at_siss(siss_string, "f", "at^siss=1,clientId,\"f\"\r\n")
        at_siss(siss_string, "helenasTestBroker", "at^siss=1,Topic,\"helenasTestBroker\"\r\n")

Publish moisture data

  1. In order to pubish data, we first need to activate the internet bearer using at^sica.
  2. Then open the internet service configured with at^siss.
  3. Then we can open the internet service using at siso.
  4. At^sisw allows us to write data.
  5. We press enter (b’\x1A’) to send it and then once again close the connection using at^sisc.
  6. When you run this updated code, you should now be able to see the data being published to the sub.py terminal window which we used before.


### open connection
    uart.write("at^sica=1,5\r\n")   #state, context id
    ok()
    uart.write("at^siso=1\r\n")      #srv profie id
    ok()
    utime.sleep(5)

    ### mqtt send data

    uart.write("at^SISW=1,5\r\n")    #srv profile, req write length
    utime.sleep(2)
    
    uart.write(str(soil.read_u16()))
    utime.sleep(1)
    uart.write(b'\x1A')
    utime.sleep(1)
    
    # closes connection
    uart.write("at^SISC=1\r\n")
    ok()

Set up InfluxDB

Now that we have our data being published successfully to our MQTT broker, we want to save the data to a database. We will use InfluxDB since it is an easy to implement, time-based database.

  1. Download InfluxDB: Use the following command in your terminal to download InfluxDB: "wget https://dl.influxdata.com/influxdb/releases/influxdb2-2.0.7-amd64.deb " Note: Make sure to replace “2.0.7” with the latest version available.
  2. Install InfluxDB: Use the following command to install the package: “sudo dpkg -i influxdb2-2.0.7-amd64.deb”. This will install InfluxDB on your machine.
  3. Start the InfluxDB service: Use the following command to start the InfluxDB service: “sudo systemctl start influxdb”. To ensure that InfluxDB starts at boot, use the following command: " sudo systemctl enable influxdb"
  4. Access InfluxDB: Once installed, you can access the InfluxDB interface in your web browser at localhost:8086.
  5. Initial setup: When you first open the InfluxDB interface, you’ll be taken through an initial setup process. Here, you’ll set up your first user, organization, and bucket. The user is the username you’ll use to log in. The organization is a logical container for resources (like buckets, dashboards, and tasks). The bucket is where you’ll store your time-series data. Remember to note down your organization name and the bucket name you’ve entered during this initial setup. We’ll need these in the next step.
  6. Get your InfluxDB token: After setting up, InfluxDB will provide you with a token. This token is your authorization key for accessing your data in InfluxDB. Make sure to keep it safe. We will also use this in the next step.
  7. Install the InfluxDB client library: Because we’re planning to interact with InfluxDB using a programming language like Python, we’ll need to install the corresponding client library. For Python, you can use the following command: “pip install influxdb-client”

Subscribe to MQTT broker from InfluxDB

Now we need to add to our sub.py script to include the functionality of adding the data to our InfluxDB.

  1. Importing the necessary libraries: Start by importing the necessary modules from the InfluxDB client library. InfluxDBClient is used to connect to the InfluxDB database, Point is used to create the data points that you’ll be writing to the database, and SYNCHRONOUS is a write option that makes the write operation synchronous (i.e., the program will wait for the operation to complete before continuing).
  2. Configuration: Next we will set up some configuration variables for connecting to InfluxDB. We’ll define influxdb_url as influxdb_url = “http://localhost:8086” and define influx_token, influxdb_org, and influxdb_bucket as the variables you defined if the previous step when we were setting up our influxDB.
  3. Creating the InfluxDB client: Next, we create an instance of InfluxDBClient, which it will use to interact with the InfluxDB database.
  4. Writing data to InfluxDB: the function def write_to_influxdb(data) is used to write data to the InfluxDB database. It creates an instance of WriteApi which it uses to write to the database. It converts the received data to an integer, creates a new point with the measurement name “soil_hydration” and a field “adc_value” with the received data as its value. It then writes this point to the InfluxDB bucket.
  5. Calling the write function: Finally, the write_to_influxdb() function is called within the on_message callback function. This function is called whenever a message is received on the subscribed MQTT topic, so this is how the script writes to the InfluxDB database whenever it receives a new MQTT message.

Here is the updated sub.py source code:


# python3.6

import random

from paho.mqtt import client as mqtt_client
from influxdb_client import InfluxDBClient, Point, WritePrecision
from influxdb_client.client.write_api import SYNCHRONOUS

# MQTT broker configuration
broker = 'broker.emqx.io'
port = 1883
topic = "helenasTestBroker"
# Generate a Client ID with the subscribe prefix.
client_id = f'subscribe-{random.randint(0, 100)}'
# username = 'emqx'
# password = 'public'

# InfluxDB configuration
influxdb_url = "http://localhost:8086"
influxdb_token = 
# influxdb_token_grafana = 
influxdb_org = "Helena" 
influxdb_bucket = "soil_hydration_bucket"  # URL-encoded bucket name

client = InfluxDBClient(url=influxdb_url, token=influxdb_token)

def connect_mqtt() -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    # client.username_pw_set(username, password)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client


def subscribe(client: mqtt_client):
    def on_message(client, userdata, msg):
        print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")
        write_to_influxdb(msg.payload.decode())

    client.subscribe(topic)
    client.on_message = on_message

def write_to_influxdb(data):
    write_api = client.write_api(write_options=SYNCHRONOUS)
    
    data_int = int(data)
    point = Point("soil_hydration").field("adc_value", data_int)  # replace "measurement" with your actual measurement name
    write_api.write(influxdb_bucket, influxdb_org, point)
    
def run():
    client = connect_mqtt()
    subscribe(client)
    client.loop_forever()


if __name__ == '__main__':
    run()

****

Query and display data using Flux in InfluxDB

Replace the code in sub.py with the above code, save and restart the program in your terminal.

When you start seeing your published data displayed in the terminal, go to your influxDB interface at http://localhost:8086 navigate to the Data Explorer page and add the following query to the terminal embedded in the page:


from(bucket: "soil\_hydration\_bucket")

|\> range(start: -3h)

Click Run. You should now see your data values displayed in a table and if you switch to the graph, displayed as a time-based graph.

Set up Grafana locally and display data

Next we will set up Grafana for a more sophisticated data visualization experience.

Step 1: Install Grafana


sudo apt-get update

  1. Next, download and install Grafana again:

sudo apt-get install -y apt-transport-https

sudo apt-get install -y software-properties-common wget

wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add –

  1. Then add the Grafana repository:

echo"deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list

  1. Update your repository list again and install Grafana:

sudo apt-get update

sudo apt-get install Grafana

  1. Finally, start the Grafana server:

sudo systemctl start grafana-server

This will install a fresh instance of Grafana. When the installation is complete, you can navigate to http://localhost:3000 in your web browser to access Grafana. The default login is admin for both username and password.

Step 2: Connect our InfluxDB to Grafana

In the Grafana web interface, you need to add InfluxDB as a data source:

  1. Click on the gear icon on the left side to open the Configuration menu.
  2. Click on Data Sources.
  3. Click on Add data source.
  4. Choose InfluxDB from the list.
  5. In the settings for the InfluxDB data source, you will need to provide the URL for your InfluxDB instance (e.g., http://localhost:8086).
  6. Toggle the basic auth button and add influxDB user and password.
  7. Add the authentication details such as the bucket, organization and token from the steps before.
  8. Click Save & Test to save the data source.

Step 3: Create a Dashboard and Panel

Now that Grafana is connected to InfluxDB, you can create a dashboard and panel to visualize the data:

  1. Click on + on the left side to create a new dashboard.
  2. Click on Add new panel.
  3. In the panel settings, you can choose the data source you just added, and enter the Flux query

from(bucket: "soil\_hydration\_bucket")

|\> range(start: -3h)

  1. Customize the visualization as you wish (graph type, axes, colors, etc.).
  2. Click on Apply to save the panel.

Now you should have a Grafana dashboard that’s displaying your InfluxDB data. Grafana will update the visualizations in real time as your data changes if you set the refresh setting to your desired time interval.

Wrap up

That’s the project! You have explored every element of a data sensor project to building and programming the microcontroller sensor, getting text message updates and warnings, sending data via MQTT and displaying the data on your personal dashboard.

The ways to add to this project are endless. Add more kinds of sensors such as air or soil quality or get the data collection running on an external server.

Enjoy your happier plants now that they are getting enough water!

3 Likes