A smart farm dashboard using Node-RED and MQTT provides a centralised real-time visualisation platform for all IoT sensors across a farm — temperature, humidity, soil moisture, water flow, and equipment status — in a single web interface accessible from any device. This guide covers building a complete farm data pipeline from ESP32 field nodes through MQTT broker to Node-RED dashboard with data persistence and alerting.
Table of Contents
- Farm Dashboard Architecture
- MQTT Protocol for Farm IoT
- ESP32 Sensor Publisher
- Node-RED Installation and Setup
- Dashboard Flows Configuration
- Data Persistence with InfluxDB
- Alert Configuration
- Frequently Asked Questions
Farm Dashboard Architecture
The complete stack:
- Field nodes: ESP32 devices with various sensors, connected via WiFi or LoRa gateway
- MQTT broker: Mosquitto on Raspberry Pi or cloud VM (manages publish/subscribe)
- Node-RED: Flow-based visual programming for data processing and dashboard
- InfluxDB: Time-series database for historical sensor data storage
- Grafana (optional): Advanced charting from InfluxDB data
- Alert engine: Node-RED email/Telegram/SMS alerts on threshold breaches
All components run on a single Raspberry Pi 4 (4GB RAM) serving a farm of up to 50 sensor nodes. For larger operations, deploy on a cloud VM (AWS Lightsail, Rs 1,000/month, or DigitalOcean).
MQTT Protocol for Farm IoT
MQTT (Message Queuing Telemetry Transport) is a lightweight publish/subscribe protocol designed for IoT devices with limited bandwidth:
- Topics: Hierarchical address system, e.g.,
farm/field1/soil/moisture - QoS 0: Fire-and-forget (use for sensor data, no acknowledgement overhead)
- QoS 1: At-least-once delivery (use for alerts and commands)
- Retained messages: Broker stores last message — new subscribers get current value immediately
- Last Will: Broker sends alert if node disconnects unexpectedly (device monitoring)
ESP32 Sensor Publisher
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
#include <ArduinoJson.h>
const char* ssid = "FarmWiFi";
const char* password = "farmpassword";
const char* mqttHost = "192.168.1.100"; // Raspberry Pi IP
const int mqttPort = 1883;
const char* nodeId = "field1";
WiFiClient wifiClient;
PubSubClient mqtt(wifiClient);
Adafruit_BME280 bme;
unsigned long lastPublish = 0;
void reconnectMQTT() {
while (!mqtt.connected()) {
String clientId = "esp32-" + String(nodeId);
// Last Will: notify dashboard if device disconnects
if (mqtt.connect(clientId.c_str(), nullptr, nullptr,
("farm/" + String(nodeId) + "/status").c_str(), 1, true, "offline")) {
mqtt.publish(("farm/" + String(nodeId) + "/status").c_str(), "online", true);
Serial.println("MQTT connected");
} else {
delay(5000);
}
}
}
void publishSensorData() {
float temp = bme.readTemperature();
float humid = bme.readHumidity();
float press = bme.readPressure() / 100.0;
int soil = map(analogRead(34), 4095, 1500, 0, 100);
// Publish as JSON
StaticJsonDocument<200> doc;
doc["temp"] = round(temp * 10) / 10.0;
doc["humidity"] = round(humid * 10) / 10.0;
doc["pressure"] = round(press * 10) / 10.0;
doc["soil"] = soil;
doc["ts"] = millis() / 1000;
char payload[200];
serializeJson(doc, payload);
String topic = "farm/" + String(nodeId) + "/sensors";
mqtt.publish(topic.c_str(), payload, true); // Retained=true
// Also publish individual values for simple Node-RED nodes
mqtt.publish(("farm/" + String(nodeId) + "/temp").c_str(), String(temp, 1).c_str(), true);
mqtt.publish(("farm/" + String(nodeId) + "/humidity").c_str(), String(humid, 1).c_str(), true);
mqtt.publish(("farm/" + String(nodeId) + "/soil").c_str(), String(soil).c_str(), true);
Serial.printf("Published: T:%.1f H:%.1f Soil:%d%%n", temp, humid, soil);
}
// Command callback (for remote control of relays etc.)
void onMessage(char* topic, byte* payload, unsigned int len) {
String msg = String((char*)payload, len);
String t = String(topic);
Serial.println("CMD: " + t + " = " + msg);
// Handle commands like "farm/field1/cmd/pump" -> "on"/"off"
if (t.endsWith("/pump")) {
// Control pump relay
}
}
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
bme.begin(0x76);
pinMode(34, INPUT);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("nWiFi OK: " + WiFi.localIP().toString());
mqtt.setServer(mqttHost, mqttPort);
mqtt.setCallback(onMessage);
reconnectMQTT();
mqtt.subscribe(("farm/" + String(nodeId) + "/cmd/#").c_str());
}
void loop() {
if (!mqtt.connected()) reconnectMQTT();
mqtt.loop();
if (millis() - lastPublish > 60000) { // Publish every minute
publishSensorData();
lastPublish = millis();
}
}
Node-RED Installation and Setup
On Raspberry Pi (or Ubuntu server):
# Install Node.js and Node-RED
curl -sL https://deb.nodesource.com/setup_18.x | sudo bash -
sudo apt install -y nodejs
sudo npm install -g --unsafe-perm node-red
# Install Mosquitto MQTT broker
sudo apt install -y mosquitto mosquitto-clients
sudo systemctl enable mosquitto
# Install Node-RED dashboard and MQTT modules
cd ~/.node-red
npm install node-red-dashboard node-red-contrib-influxdb node-red-contrib-telegrambot
# Start Node-RED (auto-start via systemd)
node-red-start
# Access at http://raspberrypi:1880
Dashboard Flows Configuration
Key Node-RED flows to create:
- MQTT subscribe -> JSON parse -> Dashboard gauge: Each sensor topic creates a gauge widget showing current value
- MQTT subscribe -> Threshold check -> Alert: If value exceeds threshold, send Telegram/email
- MQTT subscribe -> InfluxDB write: Persist all sensor data for historical charts
- Dashboard button -> MQTT publish -> ESP32: Remote relay control from dashboard
- Schedule node -> Dashboard chart -> InfluxDB query: Daily/weekly trend charts
Example Node-RED flow JSON for a temperature gauge (import via clipboard):
[{"id":"mqtt-in","type":"mqtt in","topic":"farm/+/temp",
"broker":"mosquitto","name":"All Temp Sensors"},
{"id":"gauge","type":"ui_gauge","group":"field-overview",
"min":0,"max":50,"label":"Temperature","format":"{{value}} C",
"name":"Temperature Gauge"}]
Data Persistence with InfluxDB
InfluxDB is a time-series database optimised for IoT sensor data:
# Install InfluxDB 2.x on Raspberry Pi / Ubuntu
wget -q https://repos.influxdata.com/influxdata-archive_compat.key
gpg --dearmor < influxdata-archive_compat.key > /etc/apt/trusted.gpg.d/influxdata.gpg
echo 'deb [signed-by=/etc/apt/trusted.gpg.d/influxdata.gpg] https://repos.influxdata.com/debian stable main' | tee /etc/apt/sources.list.d/influxdata.list
apt update && apt install influxdb2
systemctl enable influxdb
# Create bucket and API token via web UI at http://localhost:8086
Node-RED’s node-red-contrib-influxdb writes each sensor reading to a measurement (table) named after the sensor type. Grafana then queries InfluxDB to create historical trend charts, accessible remotely via ngrok or VPN.
Alert Configuration
Set up Telegram bot alerts in Node-RED:
- Create Telegram bot via @BotFather, get API token
- Install
node-red-contrib-telegrambotin Node-RED - Add Telegram sender node, configure with your bot token and chat ID
- Threshold check function: if soil moisture below 30% for more than 2 hours, send alert
- Deduplication: Track alert state — send once when threshold breached, once when resolved
Frequently Asked Questions
Can Node-RED and Mosquitto run on the same Raspberry Pi as the LoRa gateway?
Yes. A Raspberry Pi 4 (4GB) comfortably runs Mosquitto, Node-RED, InfluxDB, and LoRa packet forwarder simultaneously. CPU usage stays below 20% with 50 sensor nodes publishing every minute. For 200+ nodes, move InfluxDB to an external SSD or cloud.
Is MQTT secure enough for farm data?
Basic Mosquitto requires adding authentication (username/password in mosquitto.conf) and TLS certificates for any internet-exposed deployment. For local farm network (WiFi only), basic auth is sufficient. Never expose Mosquitto port 1883 to the internet without TLS.
How much storage do I need for 1 year of sensor data?
With 20 sensors publishing every minute: 20 x 60 x 24 x 365 = 10.5 million readings/year. At approximately 50 bytes per reading in InfluxDB compressed format, this is about 500MB/year. A 32GB SD card stores 30+ years of data at this rate.
Can I access the farm dashboard remotely when away from the farm?
Yes. Options: 1) Tailscale VPN (free, easy setup — install on Raspberry Pi and your phone), 2) ngrok tunnel (free tier, 1 connection, temporary URL), 3) Cloudflare Tunnel (free, permanent URL, best for always-on access). Avoid port forwarding directly from your home router.
Add comment