how to set up a water supply monitoring system with sensor hub

This tutorial focuses on monitoring a house's water supply and setting up the sensor system and back-end infrastructure using Chirpstack, InfluxDB, Grafana, and Node-RED. This system not only monitors the sensors but also issues alerts when action is required.

In regions with unstable water supplies, a water tank and a booster pump are essential. However, this setup can also be used on farms to ensure a reliable water supply for livestock watering stations.

The system setup measures two important values of the water supply system:

  1. The water level in the tank
  2. The external water supply pressure

The entire system is battery-powered, with all sensors connected to a single RAK2560 Sensor Hub. This design reduces installation costs, as only one data collection unit is needed.

system-sensor.png

Figure 1: Water Supply System

Requirements

1. Sensor Setup

2. Gateway

3. Back-End Services

  • Installed on VPS, but could be AWS or other cloud services

Sensor Hardware Setup

The sensor setup utilizes the RAK2560 Sensor Hub to collect data from various sensors and transmit it through the LoRaWAN gateway to back-end services.

The RAK2560 operates independently of a permanent power supply by utilizing the RAK9154 Solar Battery Lite. This battery option features a large 5.2 Ah battery and a solar panel for recharging. The Solar Battery Lite communicates its battery and charging status to the RAK2560.

All sensors connect to the RAK2560 Sensor Hub via the Sensor Probe IO:

  • The water level sensor and the pyranometer are available as Sensor Hub solutions, requiring no additional configuration.
  • The water pressure sensor is a third-party sensor connected via a generic Sensor Probe IO. This Sensor Probe IO facilitates the connection of third-party sensors with RS485 or 4-20 mA interfaces to the Sensor Hub. 

To connect the sensors to the Sensor Hub, two cable types are used depending on the installation layout:

Detailed setup instructions for connecting third-party sensors are available in the following tutorials:

Water Supply Monitoring System Overview

system-sensor-lr.png

Figure 2: Water Supply System Parts

🗒️
NOTE

The setup is not finalized. The cables between the Sensor Hub and the sensors will be protected in electric wire mouldings.

 

Water level sensor installation

water-level-sensor-lr.png

Figure 3: Inside the Tank Level Sensor

Water pressure sensor installation

water-pressure-sensor-detail.png

Figure 4: In-line Water Pressure Sensor

 

Pyranometer sensor setup

pyranometer-detail.png

Figure 5: RAK Pyranometer Sensor

Solar Battery Lite setup

sensorhub-solar-detail.png

Figure 6: Sensor Hub And Solar Battery

 

Sensor Wiring and Connections

The Solar Battery Lite, water level sensor, and pyranometer each include a pre-installed Sensor Probe IO. These sensors connect directly to the Sensor Hub and require no additional wiring or configuration.

Connect the 3rd-Party Sensor to the Sensor Hub Probe IO

The third-party PT-306 water pressure sensor requires a Generic Sensor Probe IO for connection to the Sensor Hub. Before wiring, refer to the sensor’s datasheet to obtain the necessary electrical and connection parameters.

Electrical Parameters

The 4–20 mA sensors output a DC signal based on the measured value. To ensure correct integration with the Sensor Hub, verify the following parameters:

  • Output signal type
  • Measurement range
  • Power supply requirements

For example, the PT-306 water pressure sensor outputs a 4–20 mA signal with a measurement range of 0 to 16 bar. The sensor requires a 24 VDC supply for proper operation.

Here are the key specifications from the manufacturer’s datasheet:

  • Output: 4–20 mA current loop
  • Measurement range: 0 to 16 bar
  • Supply voltage: 24 VDC

pt-306-english-datasheet.png

Figure 7: Pressure Sensor Datasheet

Connection Diagram

The sensor cable connects to the Sensor Probe IO using screw terminals. Before wiring, remove any factory-installed connectors to expose the individual wires.

4–20 mA sensors typically have two or three wires. The PT-306 uses a 3-wire configuration. The complete wiring diagram is available in the manufacturer’s datasheet.

pt-306-english-datasheet-2.png

Figure 8: Pressure Sensor Pinout

 

Electrical Connection Between the Sensor and the Probe IO

Inside the Probe IO are 2 screw terminals. The pin assignment of each terminal is printed on the side of the enclosure.

For this 4-20mA sensor, only 2 of these terminals are required. 

1. Using the wire colors from the sensor datasheet and the Sensor Hub screw terminal description, the wires can be connected to the matching pins.

 

probeio-connection-diagramm.png

Figure 9: Probe IO Connection for the Pressure Sensor

 

The full description of the screw terminals can be found in the Probe IO datasheet.

⚠️
IMPORTANT

Do not connect the Probe IO to the Sensor Hub while adding the sensor wires to the screw terminal.

 

2. While connecting the wires, make sure they are securely fixed with the screws and that no bare parts of the wires are connecting neighboring wires or the PCB of the Probe IO.

probeio-wiring.png

Figure 10: Probe IO Pressure Sensor Connected

Now the Probe IO can be connected to the Sensor Hub.

Configure the RAK2560 Sensor Hub

The Sensor Hub is configured with our WisToolBox mobile application over USB. To connect the mobile application to the Sensor Hub, follow the Quick Start Guide for WisToolBox mobile.

The setup of the Sensor Hub is split into two parts.

  • LoRaWAN setup
  • Sensor setup

LoRaWAN Configuration

The first step is to connect the Sensor Hub to your LoRaWAN network server. RAK provides several guides with step-by-step instructions for different platforms:

Refer to the relevant guide based on your LoRaWAN server and application.

Sensor Configuration

The second step is to configure the sensors connected to the Sensor Hub.

For standard Sensor Hub sensors, such as the Solar Battery Lite, water level sensor, and pyranometer, no manual configuration is required. After connection, these sensors are automatically detected by the Sensor Hub.

In WisToolBox, open the SENSOR PROBE tab to view all connected sensors. All four sensors should be listed automatically.

For each sensor, you can configure:

  • Measurement interval
  • Alarm thresholds (if needed)

wistoolbox-probeio-overview.png

Figure 11: WisToolBox Sensor Probe Tab

 

Solar Battery Life Setup

In the SENSOR PROBE tab in WisToolBox, two Generic Probe IOs are shown, each with different serial numbers. Select the one with the lower serial number, which is 00289. It will display the setup for the Solar Battery Lite, including:

  • Battery Value
  • Current
  • Battery Capacity
  • Battery Temperature
ℹ️
Tip

If the selected Generc Probe IO does not show Battery related data, choose the other one.

Ignore the the two "Unknown" labeled values. These are used for debug in case the Solar Battery Lite has a problem.

 

Scrolling down will show the reading interval for the sensor, minimum is 60 seconds, here it is set to 120 seconds.

wistoolbox-battery-lite.png

Figure 12: WisToolBox Reading Interval Parameter

Pyranometer Sensor Setup

1. In the SENSOR PROBE tab in WisToolBox, open the Pyranometer section. As this sensor is present in the Sensor Hub, it will already display the sensor values.

2. At the lower end of the screen, set the reading interval for this sensor to 120 seconds.

wistoolbox-pyranometer.png

Figure 13: WisToolBox Reading Interval Updated

Water Pressure Sensor Setup

As this is a third-party 4-20 mA sensor, it is not present in the Sensor Hub and requires additional setup steps.

1. In the SENSOR PROBE tab, open the second Generic Probe IO tab.

water-pressure-sensor-setup-1.png

Figure 14: Sensor Probe Empty Tab

 

2. Since the Generic Probe IO has not been configured yet, only its default IO options are displayed.

3. To configure the water pressure sensor, open the Analog Input: 4–20 mA tab in WisToolBox.

4. Enter the following sensor parameters:

  • Name: Sensor name
  • Offset: 0.000000 
  • Min value: 0 bar
  • Max value: 160 bar
⚠️
IMPORTANT

The default setup for pressure sensors in the Sensor Hub uses hectopascal (hPa) units, with a range of 0.1 to 6553.5 hPa. However, the sensor provides data in bar, with a range of 0 to 16 bar.

To avoid losing resolution, the Sensor Hub multiplies the sensor value by 10. This scaling must be taken into account in the back-end processing and visualization functions.

 

water-pressure-sensor-setup-2.png

Figure 15: Sensor Probe Default Set Up Values

5. In the Unit field, select Pressure from the drop-down menu. This menu lists all sensor types supported by the Sensor Hub.

 

water-pressure-sensor-setup-3.png

Figure 16: Sensor Probe Select Unit

6. The final step is to configure the sensor reading interval. In this case, set it to 60 seconds.

7. After all 4-20 mA settings are done and saved (through APPLY), force a removal of the Probe IO from the Sensor Hub with REMOVE SENSOR PROBE.

water-pressure-sensor-setup-5.png

Figure 17: Remove the Created Sensor Probe Profile

8. The Probe IO will reconnect automatically, and in WisToolBox, the new sensor values will be visible.

water-pressure-sensor-setup-4.png

Figure 18: The New Sensor Probe Profile is Ready

All sensors are now connected and recognized by the Sensor Hub. The next step is to configure the back-end functionality.

 

Sensor Data on the LoRaWAN Server

Connect RAK7268V2 WisGate Edge Gateway to Chirpstack

This setup uses a ChirpStack V4 LoRaWAN server to receive sensor data. The RAK7268V2 gateway is already connected to the LoRaWAN Network Server (LNS).

For instructions on connecting the gateway to ChirpStack V4 and registering an end device, refer to the RAK7268V2 LNS Guide.

 

🗒️
NOTE

If other LoRaWAN servers are used, like AWS, TTN, or Actility, the steps will be different, but following the same principle.

 

Register the Sensor Hub in the LoRaWAN Server Application

This section does not include detailed instructions, as these are standard steps for connecting sensor nodes to a LoRaWAN server.

1. Setup the LoRaWAN server and connect the gateway(s) to it. Ensure that both LoRaWAN server and the gateway(s) are setup to the same LoRaWAN region.

2. Create an application on the LoRaWAN server.

3. Establish a device profile in ChirpStack.

4. Configure the Sensor Hub within the application using:

  • OTAA: DevEUI, AppEUI, AppKey
  • ABP: DevAddress, AppSKey, NwSKey

5. Verify that the sensor data is being received by the application on the LoRaWAN server.

lns-sensor-data.png

Figure 19: Sensor Data Received by LoRaWAN Server Application

Decode the Sensor Data in the LoRaWAN Server

ChirpStack V4 allows adding a payload decoder directly in the device profile. For the Sensor Hub, RAKwireless provides a ready-to-use payload decoder named RAKwireless_Standardized_Payload for Sensor Hub.

1. In the Device Profile, go to Codec and select JavaScript functions as Payload codec.

2. Copy the content of the SensorHub.js decoder file into the Codec functions field, replacing any existing code.

 

csv4-decoder.png

Figure 20: Decoding Payload From Sensor Hub

3. Once the decoder is set up, the decoded payload is visible in the device events log.

Sample decoded payload for the water pressure sensor:

csv4-decoded.png

Figure 21: Available Decoded Events 

 

Set Up Data Visualization With InfluxDB and Grafana

⚠️
IMPORTANT

The visualization implemented here is based on the Chirpstack V4 influxDB integration and that the sensor data is parsed by a payload decoder in Chirpstack.

If other LoRaWAN servers are used, this part has to be adapted to the specific LoRaWAN server and available influxDB integrations.

 

The backend services InfluxDB and Grafana receive sensor data through the InfluxDB integration in ChirpStack V4.

Install InfluxDB and Grafana

InfluxDB and Grafana are installed using a Docker YAML file.

The local IP addresses of both applications are required for configuration. These can be retrieved using the Portainer management tool.

portainer-docker-management.png

Figure 22: Install InfluxDB and Grafana Apps

Configure InfluxDB Database

In the InfluxDB web UI, create an access token to enable access.

1. Open the Load Data menu and select API Tokens.

influxdb-token-1.png

Figure 23: InfluxDB Navigate to API Tokens 

2. Create two tokens using the GENERATE API TOKEN button: one for ChirpStack and one for Grafana.

influxdb-token-2.png

Figure 24:  InfluxDB Create API Tokens

⚠️
IMPORTANT

Make sure to copy the tokens into a safe place. They can only be read during the creation of the tokens, and these tokens will be required in the next steps!

 

3. Create an organization and a bucket for the sensor data.

influxdb-organisation-1.png

Figure 25: Create an Organization on InfluxDB

4. Use RAKwireless for both the organization and the bucket.

influxdb-organisation-2.png

Figure 26: Bucket and Organization named RAKwireless

 

Integrate Chirpstack With InfluxDB

1. In the Chirpstack web UI, open the application and select the Integrations tab.

chirpstack-integrations.png

Figure 27: Chripstack InfluxDB App

2. Fill in the connection details for the InfluxDB database.

  • InfluxDB version: v2 is used in this installation.

  • API endpoint (write): The IP address of the InfluxDB Docker instance, obtained from Portainer.

  • Organization: The organization created earlier in InfluxDB.

  • Bucket: The bucket created in InfluxDB.

  • Token: The access token generated in InfluxDB.

chirpstack-influxdb-setup.png

 

Figure 28: InfluxDB App Information for Integration

Connect Grafana to InfluxDB

1. In the Grafana web UI, navigate to Connections and select Add a new connection to set up the connection to the InfluxDB database.

grafana-connection-1.png

Figure 29: Add Connection on Grafana

 

2. Select InfluxDB as a new connection.

grafana-connection-2.png

Figure 30: Grafana Search for InfluxDB Connection

3. Set up the connection using the previously obtained IP address and token.

grafana-connection-3.png

Figure 31: InfluxDB on Grafana App Settings

  • Username: InfluxDB organization user.

  • Password: InfluxDB organization password.

  • Organization: Name of the organization created in InfluxDB.

  • Token: Access token created in InfluxDB for Grafana access.

  • Bucket: Default bucket created in InfluxDB.

grafana-connection-4.png

Figure 32: InfluxDB on Grafana App Information for Integration

4. Use the Save & test button to check if Grafana can access the database.

Verify Sensor Data in InfluxDB

1. Open the InfluxDB web UI and navigate to the Data Explorer.

2. Select the correct bucket. The easiest way to locate the data is to use the Sensor Hub's DevEUI as the first filter.

3. Use _measurement as the second filter. This will display all data received from the Sensor Hub.

influxdb_explorer-1.png

Figure 33: InfluxDB Data Explorer Filters

4. Each entry is listed with a sensor number assigned by the Sensor Hub when sending the payload.

For example:

device_frmpayload_data_barometer_11

This entry refers to the water pressure measurement from the water pressure sensor.

5. Select device_frmpayload_data_barometer_11 and apply a value filter to retrieve the pressure data.

6. Click the SUBMIT button. The graph will display the recorded pressure measurements.

influxdb_explorer-2.png

Figure 34: InfluxDB Data Explorer Value Filtered

 

🗒️
NOTE

The InfluxDB Data Explorer allows users to view the query as a Flux query, which can be directly utilized in Grafana to collect data from the InfluxDB database.

 

7. Push the SCRIPT EDITOR button to see the Flux query.

influxdb-get-flux-query.png

Figure 35: InfluxDB Data Explorer Script Editor

8. Copy and save the Flux Query, as it will be used in the Grafana dashboard later.

Create a Grafana Dashboard for Sensor Data

1. Open the Grafana web UI and go to Home > Dashboards

2. Click on the New button and select New dashboard.

grafana-new-dashboard.png

Figure 36: Grafana Add New Dashboard

3. On the next window, select the option to + Add visualization.

grafana-new-visualization.png

Figure 37: Grafana Add Visualization to the Dashboard

4. Then select InfluxDB as the data source.

grafana-select-datasource.png

Figure 38: Grafana Add InfluxDB as a Source

5. A new window will appear, showcasing the visualization details. Paste the Flux query you copied from InfluxDB DataExplorer into the query field.

grafana-copy-flux.png

Figure 39: Grafana Add Title to the Time Series and Paste the Flux Query

6. Customize the panel settings as needed. In this example, only the Panel Title was updated to Water Pressure. Additional customization options are available in the Grafana documentation.

7. Click the Apply button to add the visualization to the new dashboard.

grafana-dashboard-water-pressure.png

Figure 40: Grafana Data Visualization on the Dashboard

Now the panel with the water pressure sensor is shown in the dashboard.

8. To add the other sensor values, repeat these steps to display all sensor values on the dashboard:

grafana-all-sensors.png

Figure 41: Grafana All Variables Added to the Dashboard

Forward the Sensor Data For Processing

⚠️
IMPORTANT

The data processing implemented in this guide utilizes the ChirpStack V4 MQTT broker, with a payload decoder in ChirpStack parsing the sensor data.
If a different LoRaWAN server is used, this component must be adapted to match the server’s specific MQTT broker integration.

 

In addition to visualizing sensor data, it is possible to send alarm messages in response to events such as:

  • No water supply
  • Excessive water supply
  • Low water tank level
  • Water tank overflow

These two extensions must be installed using the NodeRED Manage Palette function before deploying the flow.

Here is a simple overview of the NodeRED flow setup for detecting events and sending alerts:

  • Preset globals: Stores the most recent sensor values for water level and water pressure.  These measured values are necessary for the functions Check Water Level and Check Water Pressure.
  • CS Uplink: Subscribes to sensor data topics from the ChirpStack MQTT broker.
  • Device Filter: Removes all irrelevant topics received from the MQTT broker by verifying the DevEUI of incoming messages. Only messages with a matching DevEUI from the Sensor Hub are forwarded for further processing.
  • Check Water Level: Analyzes the received water level measurements for overflow and low levels. The code is available in the Appendix.
  • Check Water Pressure: Evaluates the water pressure readings to identify a loss or absence of the incoming water supply. The code is available in the Appendix.
  • Alarm Email: Sends an email when a triggered condition is detected.
  • To Phone: Sends a push notification if the evaluations trigger an alarm.

The Alarm Email and To Phone functions utilize the NodeRED flows 'node-red-node-email-variable' and 'node-red-node-pushover' to send alarms. These require a specific setup that is not covered in this guide. Detailed instructions can be found in the documentation for these two flows.

 

🗒️
NOTE

Pushover is not free; it offers a 30-day evaluation period, after which a one-time payment is required to continue using the service. More information can be found on the Pushover website.

 

node-red-full-flow.png

Figure 42: NodeRED flows for setting a Phone and Email Alarm

Appendix: Node-RED Code Samples

Node-RED Check Water Level JS Code

var new_payload = [];
if (typeof (msg.payload) != "undefined") {
    if (typeof (msg.payload.object) != "undefined") {
        if (typeof (msg.payload.object.analog_in_1) != "undefined") {
            // Get global variables
            var alarm_low_level_true = global.get('alarm_low_level_true');
            var alarm_overflow_true = global.get('alarm_overflow_true');
            // Calculate current water level
            var now_level = (msg.payload.object.analog_in_1 * 0.325 - 1.25);
            // Check for low levels
            if ((now_level < 0.5) && (!alarm_low_level_true)) {
                global.set('alarm_low_level_true', true);
                msg.topic = "Water Tank Low Level Alarm";
                msg.payload = "Water Level " + now_level.toFixed(2).toString();
                return msg;
            } else if (now_level > 1.0) {
                global.set('alarm_low_level_true', false);
            }
            // Check for overflow
            if ((now_level > 1.09) && (!alarm_overflow_true)) {
                global.set('alarm_overflow_true', true);
                msg.topic = "Water Tank Overflow Alarm";
                msg.payload = "Water Level " + now_level.toFixed(2).toString();
                msg.priority = 1;
                return msg;
            } else if (now_level <= 1.07) {
                global.set('alarm_overflow_true', false);
            }
        }
    }
}
return null;

Node-RED Check Water Pressure JS Code

var new_payload = [];
var is_maynilad = false;
var now_pressure;
var last_pressure;
var low_pressure_alert = false;
var high_pressure_alert = false;
var low_pressure_threshold = 0.5;
var high_pressure_threshold = 2.5;
var measure_point = "Maynilad";
if (typeof (msg.payload) != "undefined") {
    if (typeof (msg.payload.object) != "undefined") {
        if ((typeof (msg.payload.object.barometer_11) != "undefined") || (typeof (msg.payload.object.noise_11) != "undefined")) {
            // Get global variables
            if (typeof (msg.payload.object.rak_device_serial_number_0) != "undefined") {
                if (msg.payload.object.rak_device_serial_number_0 == 30729) // Pump Pressure
                {
                    last_pressure = global.get('pressure_pump');
                    low_pressure_alert = global.get('pump_low_pressure_true');
                    high_pressure_alert = global.get('pump_over_pressure_true');
                    low_pressure_threshold = 1.5;
                    high_pressure_threshold = 3.0;
                    measure_point = "Pump";
                    // Store last value
          now_pressure = (msg.payload.object.noise_11 /
10);
                }
                if (msg.payload.object.rak_device_serial_number_0 == 31751) // Maynilad Pressure
                {
                    last_pressure = global.get('pressure_maynilad');
                    low_pressure_alert = global.get('maynilad_low_pressure_true');
                    high_pressure_alert = global.get('maynilad_over_pressure_true');
                    low_pressure_threshold = 0.4;
                    high_pressure_threshold = 3.0;
                    measure_point = "Maynilad";
            // Store last value
                  now_pressure = (msg.payload.object.barometer_11 /
10);
                    is_maynilad = true;
                }
            } else {
                // Simulation, assume Maynilad pressure
                last_pressure = global.get('pressure_maynilad');
                low_pressure_alert = global.get('maynilad_low_pressure_true');
                high_pressure_alert = global.get('maynilad_over_pressure_true');
                low_pressure_threshold = 0.4;
                high_pressure_threshold = 3.0;
                measure_point = "Maynilad";
            // Store last value
              now_pressure = (msg.payload.object.barometer_11 /
10);
                is_maynilad = true;
            }
            if (is_maynilad) {
                global.set('pressure_maynilad', now_pressure);
            } else {
                global.set('pressure_pump', now_pressure);
            }
            // Check for low pressure
            if ((now_pressure < low_pressure_threshold) && (!low_pressure_alert)) {
                if (is_maynilad) {
                    global.set('maynilad_low_pressure_true', true);
                } else {
                    global.set('pump_low_pressure_true', true);
                }
                msg.topic = measure_point + " Low Pressure Alarm";
                msg.payload = "Pressure: " + now_pressure.toFixed(2).toString() + " bar";
                return msg;
            } else if (now_pressure > low_pressure_threshold) {
                if (is_maynilad) {
                    global.set('maynilad_low_pressure_true', false);
                } else {
                    global.set('pump_low_pressure_true', false);
                }
            }
            // Check for over pressure
            if ((now_pressure > high_pressure_threshold) && (!high_pressure_alert)) {
                if (is_maynilad) {
                    global.set('maynilad_over_pressure_true', true);
                } else {
                    global.set('pump_over_pressure_true', true);
                }
                msg.topic = measure_point + " High Pressure Alarm";
                msg.payload = "Pressure: " + now_pressure.toFixed(2).toString() + " bar";
                msg.priority = 1;
                return msg;
            } else if (now_pressure < high_pressure_threshold) {
                if (is_maynilad) {
                    global.set('maynilad_over_pressure_true', false);
                } else {
                    global.set('pump_over_pressure_true', false);
                }
            }
        }
    }
}
return null;

 


bernd-giesecke.png

Bernd Giesecke

Bernd is an Electronics Engineer and Product Manager at RAKwireless with 23 years of experience in industrial and automotive hardware and software R&D. He has been supporting the Arduino open-source community since 2014.

 


Changelog

  • Version 1 - How to Setup a Water Supply Monitoring System with Sensor Hub
    • Author: Bernd Gieseck
    • Reviewer: Harold Duarte
    • Date Published: 06/11/2025

 


 

 

Updated