41  MQTT in project greenhouse

41.1 MQTT in the greenhouse (how control & sensing works)

In the greenhouse we use MQTT as a lightweight “message bus” that lets devices publish sensor data and receive control commands.

Why MQTT?

  • One broker, many devices: sensors and controllers don’t need to know about each other directly—everything goes through the broker.
  • Safer control: students don’t need to wire high-voltage loads or power electronics. The high-voltage / high-current parts (e.g., irrigation solenoids, pumps, fans) are already installed and protected (relays, fuses, enclosures, labeling).
  • Faster labs: you focus on data + logic + automation, not on dangerous wiring.

41.2 Broker + login details

Use these details:

  • Wi-Fi SSID: agrotech
  • Wi-Fi password: 1Afuna2gezer
  • MQTT broker: 192.168.0.102
  • MQTT port: 1883
  • MQTT username: mqtt-user
  • MQTT password: 1234

41.3 MQTT basics you need for this course

41.3.1 Topics

A topic is a string path (like folders). Devices publish messages to topics; other devices subscribe to topics.

Example control topic:

  • /greenhouse/outside/irrigation/solenoid5

41.3.2 Payloads

For most greenhouse actuators we use a simple convention:

  • 0 → OFF / closed
  • 1 → ON / open

So publishing 1 to a solenoid topic opens that valve; publishing 0 closes it.


41.4 What is available in the greenhouse

Below is the current set of available MQTT endpoints. Each endpoint has:

  • topic
  • direction: control (subscribe) or telemetry (publish)
  • expected payload format
  • notes / safety constraints

41.4.1 Actuators (control topics)

All actuator topics expect a binary payload:

  • 0 → OFF / closed
  • 1 → ON / open

These devices are already wired through protected relays. You should only control them via MQTT.

41.4.1.1 Outside irrigation & fertigation

Device Topic Payload Meaning
Solenoid 1 (outside irrigation) /greenhouse/outside/irrigation/solenoid1 0 / 1 0=closed, 1=open
Solenoid 2 (outside irrigation) /greenhouse/outside/irrigation/solenoid2 0 / 1 0=closed, 1=open
Solenoid 3 (outside irrigation) /greenhouse/outside/irrigation/solenoid3 0 / 1 0=closed, 1=open
Solenoid 4 (outside irrigation) /greenhouse/outside/irrigation/solenoid4 0 / 1 0=closed, 1=open
Solenoid 5 (outside irrigation) /greenhouse/outside/irrigation/solenoid5 0 / 1 0=closed, 1=open
Solenoid 6 (outside irrigation) /greenhouse/outside/irrigation/solenoid6 0 / 1 0=closed, 1=open
Solenoid 7 (outside irrigation) /greenhouse/outside/irrigation/solenoid7 0 / 1 0=closed, 1=open
Solenoid 8 (outside irrigation) /greenhouse/outside/irrigation/solenoid8 0 / 1 0=closed, 1=open
Fertigation pump /greenhouse/outside/irrigation/fertigation 0 / 1 0=off, 1=on

⚠️ Note: Do not leave solenoids or the fertigation pump ON unattended. Always send 0 when finished testing.


41.4.1.2 220 V sockets (inside greenhouse)

These topics control mains-voltage sockets inside the greenhouse. Each one corresponds to the top socket in its socket array.

Device Topic Payload Meaning
Socket 1 (220 V) /greenhouse/sockets/socket1 0 / 1 0=off, 1=on
Socket 5 (220 V) /greenhouse/sockets/socket5 0 / 1 0=off, 1=on
Socket 6 (220 V) /greenhouse/sockets/socket6 0 / 1 0=off, 1=on

⚠️ Safety: These are high-voltage outputs. Never connect or disconnect loads while powered. Use MQTT only.


41.4.2 Sensors (telemetry topics)

Sensors in the greenhouse publish data to MQTT topics. You do not send commands to these topics — you only subscribe to read values.

All sensor messages use plain numeric payloads (no JSON).


41.4.2.1 Outside irrigation flow sensor

These topics report the pulse output of the outside flow meter connected to the irrigation system.

Sensor Topic Payload Meaning
Flow pulses per second /greenhouse/sensors/outside_flow/pulse_per_sec number instantaneous pulse rate (pulses·s⁻¹)
Total flow pulses /greenhouse/sensors/outside_flow/pulse_total integer cumulative pulse count since last reset

Notes:

  • pulse_per_sec is updated continuously and reflects current flow activity
  • pulse_total is retained on the broker, so new subscribers immediately receive the last value
  • Conversion from pulses to volume (e.g. liters) depends on the flow meter calibration and is done client-side

41.4.2.2 Typical usage

  • Subscribe to pulse_per_sec to detect whether irrigation is currently flowing
  • Subscribe to pulse_total to compute total water usage over time
  • Combine flow data with solenoid control topics to verify that irrigation commands worked as expected

41.5 How to test MQTT without writing code

You can test control and telemetry immediately using an MQTT client.

41.5.1 Phone apps

  • Android: MQTT Client Lite (works well)
  • iPhone: search “MQTT client” in the App Store (common options include clients like MQTTAnalyzer / MQTT Client—availability changes)

What to do:

  1. Add a new connection:

    • Host: 192.168.0.102
    • Port: 1883
    • Username/password: (provided privately)
  2. Subscribe to a telemetry topic to watch values (e.g., flow).

  3. Publish to a control topic:

    • Topic: /greenhouse/outside/irrigation/solenoid5
    • Message: 1 to open, 0 to close

41.6 Safety + good practice rules

  • Always send 0 when you’re done testing a solenoid/relay.

  • Don’t leave actuators ON unattended.

  • If something behaves unexpectedly, check:

    • retained messages
    • topic spelling (leading / matters)
    • whether your payload is exactly 0 or 1
  • Never publish credentials in notebooks, screenshots, or repos.


41.7 Where this fits in the code below

In the Arduino/ESP code, you’ll see:

  • Wi-Fi connect → join agrotech
  • MQTT connect → broker 192.168.0.102:1883
  • subscribe (optional) to control topics
  • publish telemetry (optional) to sensor topics
  • publish 0/1 commands to control relays/solenoids

41.8 Control irrigation solenoid in the greenhouse

Use the code below to control the irrigation solenoid outside the greenhouse.

Code usage: connect a jumper to A4. Whenever you touch the jumper, the solenoid will be open, otherwise it will be closed.

Download code
#include <WiFi.h>
#include <PubSubClient.h>

// WiFi credentials
const char* ssid = "agrotech";          // Replace with your WiFi SSID
const char* password = "1Afuna2gezer";  // Replace with your WiFi Password

// MQTT broker details
const char* mqtt_server = "192.168.0.102";    // IP address of Home Assistant
const int mqtt_port = 1883;                   // Default MQTT port
const char* mqtt_user = "mqtt-user";          // MQTT username
const char* mqtt_password = "1234";           // MQTT password
const char* mqtt_topic = "/greenhouse/outside/irrigation/solenoid5"; // MQTT topic

// Touch pin configuration
#define TOUCH_PIN A4  // Use GPIO 4 as touch pin (T0 on ESP32)

// MQTT client and WiFi client
WiFiClient espClient;
PubSubClient client(espClient);

// State variable to track touch pin state
bool send_message = false;

void setup_wifi() {
  Serial.print("Connecting to WiFi: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nWiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  // Attempt to reconnect to the MQTT broker
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP32Client", mqtt_user, mqtt_password)) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" Retrying in 5 seconds...");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);

  // Initialize WiFi
  setup_wifi();

  // Set up MQTT
  client.setServer(mqtt_server, mqtt_port);

  // Ensure the ESP32 starts connected to the MQTT broker
  reconnect();
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  // Read the state of the touch pin
  bool is_touched = touchRead(TOUCH_PIN) < 40;  // If the value is less than 40, the pin is being touched

  // Send "1" if the pin is being touched
  if (is_touched) {
    if (!send_message) {
      client.publish(mqtt_topic, "1");
      Serial.println("Sent: 1");
      send_message = true;  // Set flag to avoid sending multiple times while touching
    }
  } 
  // Send "0" if the pin is not being touched
  else {
    if (send_message) {
      client.publish(mqtt_topic, "0");
      Serial.println("Sent: 0");
      send_message = false;  // Reset the flag when pin is no longer touched
    }
  }

  // Optional: Small delay to avoid flooding the MQTT server with messages
  delay(100);  // Adjust the delay if necessary
}