ESP8266 don't send any data to MQTT Broker

HI all

so, the goal is i want the value of "waterlevel" is published to my MQTT Broker (installed on my main PC running Arch Linux), i've learned how to publish a topic to MQTT Server from my MCU from various resources onine, this time i used OpenAI's ChatGPT to generate a dummy value, and publish it to my MQTT Broker, and it works!, so nothing is wrong with my MQTT Broker. I applied it to my project code, it succesfully connected to the Wi-Fi, however my MQTT Broker (which is currently subscribed to the topic "topic") is not receiving any data...anybody knows what's wrong? :frowning_face:

Here is my Project code :

//Declaration of Library :
#include <ESP8266WiFi.h>  //Wi-Fi Networking Library
#include <PubSubClient.h> //MQTT Publish & Subscribe Client

// Declaration of I/O :
//Sensors :
const int tank_sensor = A0;
const int soil_sensor = D0;
//Actuators :
const int buzzerPin = D1;
const int PumpPin = D3;

const char* ssid = "Rizki Rizka"; //Wi-Fi SSID
const char* password = "8520032522013"; //Wi-Fi Password
const char* mqtt_server = "192.168.100.79"; //IP Address of MQTT Broker

// Pure value from reading the sensors:
int waterlevel;
int soillevel;

// Status stored from reading the sensor value :
boolean LowWater = false;
boolean NeedWatering = false;

// MQTT & Wi-Fi Client name :
WiFiClient espClient;
PubSubClient client(espClient);

void connectwifi(){
  WiFi.begin(ssid, password); //connect to wifi network
  
  while (WiFi.status() != WL_CONNECTED) { //wait until ESP8266 connects to wifi network
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  
  Serial.print("Connected to WiFi: ");
  Serial.println(WiFi.SSID()); //print connected wifi network name
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP()); //print IP address

  if (WiFi.status() == WL_CONNECT_FAILED){
    Serial.println("Connection Failed");
  }else{
    
  }
  
}

void setup() {
  
  // Start a Serial Communication :
  Serial.begin(115200);
  
  // Declare Buzzer and Pump (Relay) as output :
  pinMode(buzzerPin, OUTPUT);
  pinMode(PumpPin, OUTPUT);

  // Change the state value to HIGH because we use a Low Level Trigger Buzzer & Relay :
  digitalWrite(buzzerPin, HIGH);
  digitalWrite(PumpPin, HIGH);
  
  //Call the Netowrk Function to connect to Wi-Fi :
  connectwifi();
  // Set the port of the MQTT Server :
  client.setServer(mqtt_server, 1883);
}

void watchsensors() {
  waterlevel = analogRead(tank_sensor);
  soillevel = digitalRead(soil_sensor);


  if (waterlevel <300){
    LowWater = true;
  }else{
    LowWater = false;
  }
}

void lowWaterlvl(){
  
  static unsigned long previousMillis = 0;  // Store the previous time
  unsigned long currentMillis = millis();   // Get the current time

  static int state = 0;  // Store the current state
  static int beepDuration = 150;  // Store the beep duration
  if (currentMillis - previousMillis >= beepDuration) {  // If the beep duration has passed
    previousMillis = currentMillis;  // Update the previous time

    switch (state) {
      case 0:
        digitalWrite(buzzerPin, LOW);  // Turn the buzzer on
        state = 1;  // Go to the next state
        break;
      case 1:
        digitalWrite(buzzerPin, HIGH);  // Turn the buzzer off
        state = 2;  // Go to the next state
        break;
      case 2:
        digitalWrite(buzzerPin, LOW);  // Turn the buzzer on
        state = 3;  // Go to the next state
        break;
      case 3:
        digitalWrite(buzzerPin, HIGH);  // Turn the buzzer off
        state = 4;  // Go to the next state
        break;
      case 4:
        // Do nothing
        state = 5;  // Go to the next state
        break;
      case 5:
        state = 0;  // Reset to the first state
        break;
    }
  }
}

void printInfo(){
  // Print The Water Level :
  Serial.print("Water Level : ");
  Serial.println(waterlevel);
  delay(200);


  // Print the Soil Level :
  Serial.print("The soil is currently : ");
  Serial.println("nyc");
}

void watertheplant(){
  Serial.println("Not yet coded");
  digitalWrite(PumpPin, LOW);
  delay(1000);
  digitalWrite(PumpPin, HIGH);
  delay(1000);
}


void loop() {
  
  watchsensors();
  printInfo();

  //Actions :

  // Trigger Buzzer if water tank level is low :
    if (LowWater == true){
    lowWaterlvl();
  }else{
    digitalWrite(buzzerPin, HIGH);

  // Trigger Pump if Soil is Dry :
  //mqttt:
  client.loop();

  static unsigned long previousMillis = 0;
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= 1000) {
    previousMillis = currentMillis;
    client.publish("topic", String(waterlevel).c_str());
  
  }
 }
}

Please note that is wasn't done yet, so there are some function not yet realy used

And below is the code from ChatGPT as my reference :

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = "Rizki Rizka"; //replace with your wifi network name
const char* password = "8520032522013"; //replace with your wifi network password
const char* mqtt_server = "192.168.100.79"; //replace with your mqtt server IP or hostname

WiFiClient espClient;
PubSubClient client(espClient);

int waterlevel = 0;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password); //connect to wifi network
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");
  client.setServer(mqtt_server, 1883);
  reconnect();
}

void loop() {
  client.loop();

  static unsigned long previousMillis = 0;
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= 1000) {
    previousMillis = currentMillis;
    // read the value of waterlevel from your sensor here
    client.publish("topic", String(waterlevel).c_str()); //publish the waterlevel value
  }
}

void reconnect() {
  while (!client.connected()) {
    if (client.connect("ESP8266Client")) {
      Serial.println("Connected to MQTT server");
    } else {
      delay(1000);
    }
  }
}


This one works, however when i applied it to my project(the first code) it does not seems to publish anything....anyone knows what's wrong :slightly_frowning_face:

You code assumes a proper WIFi connection is made when it runs client.loop().

here is how I run client.loop()

void MQTTkeepalive( void *pvParameters )
{
  sema_MQTT_KeepAlive   = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 250; //delay for ms
  for (;;)
  {
    //check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status % s WiFi status % s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    //log_i( " high watermark % d",  uxTaskGetStackHighWaterMark( NULL ) );
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete ( NULL );
}

notice I make sure there is a WiFi connection before doing the client.loop().

I've modify the code so it always look for connected Wi-Fi, but still doesn't work...anyone knows what's wrong? :frowning_face:

//Declaration of Library :
#include <ESP8266WiFi.h>  //Wi-Fi Networking Library
#include <PubSubClient.h> //MQTT Publish & Subscribe Client

// Declaration of I/O :
//Sensors :
const int tank_sensor = A0;
const int soil_sensor = D0;
//Actuators :
const int buzzerPin = D1;
const int PumpPin = D3;

const char* ssid = "Rizki Rizka"; //Wi-Fi SSID
const char* password = "8520032522013"; //Wi-Fi Password
const char* mqtt_server = "192.168.100.79"; //IP Address of MQTT Broker

// Pure value from reading the sensors:
int waterlevel;
boolean soillevel;

// Status stored from reading the sensor value :
boolean LowWater = false;
boolean NeedWatering = false;

// MQTT & Wi-Fi Client name :
WiFiClient espClient;
PubSubClient client(espClient);

void connectwifi(){
  WiFi.begin(ssid, password); //connect to wifi network
  
  while (WiFi.status() != WL_CONNECTED) { //wait until ESP8266 connects to wifi network
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  
  Serial.print("Connected to WiFi: ");
  Serial.println(WiFi.SSID()); //print connected wifi network name
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP()); //print IP address

  if (WiFi.status() == WL_CONNECT_FAILED){
    Serial.println("Connection Failed");
  }else{
    
  }
  
}

void setup() {
  
  // Start a Serial Communication :
  Serial.begin(115200);
  
  // Declare Buzzer and Pump (Relay) as output :
  pinMode(buzzerPin, OUTPUT);
  pinMode(PumpPin, OUTPUT);

  // Change the state value to HIGH because we use a Low Level Trigger Buzzer & Relay :
  digitalWrite(buzzerPin, HIGH);
  digitalWrite(PumpPin, HIGH);
  
  //Call the Netowrk Function to connect to Wi-Fi :
  connectwifi();
  // Set the port of the MQTT Server :
  client.setServer(mqtt_server, 1883);
}

void watchsensors() {
  waterlevel = analogRead(tank_sensor);
  soillevel = (digitalRead(soil_sensor) == HIGH);

  client.publish("topic", String(waterlevel).c_str());
  if (waterlevel <300){
    LowWater = true;
  }else{
    LowWater = false;
  }
}

void lowWaterlvl(){
  
  static unsigned long previousMillis = 0;  // Store the previous time
  unsigned long currentMillis = millis();   // Get the current time

  static int state = 0;  // Store the current state
  static int beepDuration = 150;  // Store the beep duration
  if (currentMillis - previousMillis >= beepDuration) {  // If the beep duration has passed
    previousMillis = currentMillis;  // Update the previous time

    switch (state) {
      case 0:
        digitalWrite(buzzerPin, LOW);  // Turn the buzzer on
        state = 1;  // Go to the next state
        break;
      case 1:
        digitalWrite(buzzerPin, HIGH);  // Turn the buzzer off
        state = 2;  // Go to the next state
        break;
      case 2:
        digitalWrite(buzzerPin, LOW);  // Turn the buzzer on
        state = 3;  // Go to the next state
        break;
      case 3:
        digitalWrite(buzzerPin, HIGH);  // Turn the buzzer off
        state = 4;  // Go to the next state
        break;
      case 4:
        // Do nothing
        state = 5;  // Go to the next state
        break;
      case 5:
        state = 0;  // Reset to the first state
        break;
    }
  }
}

void printInfo(){
  // Print The Water Level :
  Serial.print("Water Level : ");
  Serial.println(waterlevel);
  delay(200);


  // Print the Soil Level :
  Serial.print("The soil is currently : ");
  Serial.println(soillevel);
}

void watertheplant(){
  Serial.println("Not yet coded");
  digitalWrite(PumpPin, LOW);
}


void loop() {
  
  watchsensors();
  printInfo();

  //Actions :

  // Trigger Buzzer if water tank level is low :
    if (LowWater == true){
    lowWaterlvl();
  }else{
    digitalWrite(buzzerPin, HIGH);

  // Trigger Pump if Soil is Dry :
  if (soillevel == 0){
    watertheplant();
  }else{
    digitalWrite(PumpPin, LOW);
  }

  
  //mqttt:
   if ( (client.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      client.loop();
    }
  
  
  }
}

Hi!

Try this:

#define PUBLISH_INTERVAL 1  // Interval in seconds

//Declaration of Library :
#include <ESP8266WiFi.h>          //Wi-Fi Networking Library
#include <PubSubClient.h>  //MQTT Publish & Subscribe Client

// Declaration of I/O :

//Sensors :
const int tank_sensor = A0;
const int soil_sensor = D0;
//Actuators :
const int buzzerPin = D1;
const int PumpPin = D3;

const char* ssid = "Rizki Rizka"; //Wi-Fi SSID
const char* password = "8520032522013"; //Wi-Fi Password
const char* mqtt_server = "192.168.100.79"; //IP Address of MQTT Broker

// Pure value from reading the sensors:
int waterlevel;
boolean soillevel;

// Status stored from reading the sensor value :
boolean LowWater = false;
boolean NeedWatering = false;

// MQTT & Wi-Fi Client name :
WiFiClient espClient;
PubSubClient client(espClient);

String subTopic = "subtopic";
String pubTopic = "pubtopic";
String clientId = "ESP8266Client";

unsigned long intervalMillis = 0;

void connectwifi() {
  WiFi.begin(ssid, password);  //connect to wifi network

  while (WiFi.status() != WL_CONNECTED) {  //wait until ESP8266 connects to wifi network
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }

  Serial.print("Connected to WiFi: ");
  Serial.println(WiFi.SSID());  //print connected wifi network name
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());  //print IP address

  if (WiFi.status() == WL_CONNECT_FAILED) {
    Serial.println("Connection Failed");
  } else {
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");

    // Create a random client ID
    clientId += String(random(0xffff), HEX);

    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      client.subscribe(subTopic.c_str());
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

void setup() {

  // Start a Serial Communication :
  Serial.begin(115200);

  // Declare Buzzer and Pump (Relay) as output :
  pinMode(buzzerPin, OUTPUT);
  pinMode(PumpPin, OUTPUT);

  // Change the state value to HIGH because we use a Low Level Trigger Buzzer & Relay :
  digitalWrite(buzzerPin, HIGH);
  digitalWrite(PumpPin, HIGH);

  //Call the Netowrk Function to connect to Wi-Fi :
  connectwifi();
  // Set the port of the MQTT Server :
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void watchsensors() {
  waterlevel = analogRead(tank_sensor);
  soillevel = (digitalRead(soil_sensor) == HIGH);

  client.publish(pubTopic.c_str(), String(waterlevel).c_str());


  if (waterlevel < 300) {
    LowWater = true;
  } else {
    LowWater = false;
  }
}

void lowWaterlvl() {

  static unsigned long previousMillis = 0;  // Store the previous time
  unsigned long currentMillis = millis();   // Get the current time

  static int state = 0;                                  // Store the current state
  static int beepDuration = 150;                         // Store the beep duration
  if (currentMillis - previousMillis >= beepDuration) {  // If the beep duration has passed
    previousMillis = currentMillis;                      // Update the previous time

    switch (state) {
      case 0:
        digitalWrite(buzzerPin, LOW);  // Turn the buzzer on
        state = 1;                     // Go to the next state
        break;
      case 1:
        digitalWrite(buzzerPin, HIGH);  // Turn the buzzer off
        state = 2;                      // Go to the next state
        break;
      case 2:
        digitalWrite(buzzerPin, LOW);  // Turn the buzzer on
        state = 3;                     // Go to the next state
        break;
      case 3:
        digitalWrite(buzzerPin, HIGH);  // Turn the buzzer off
        state = 4;                      // Go to the next state
        break;
      case 4:
        // Do nothing
        state = 5;  // Go to the next state
        break;
      case 5:
        state = 0;  // Reset to the first state
        break;
    }
  }
}

void printInfo() {
  // Print The Water Level :
  Serial.print("Water Level : ");
  Serial.println(waterlevel);

  // Print the Soil Level :
  Serial.print("The soil is currently : ");
  Serial.println(soillevel);
}

void watertheplant() {
  Serial.println("Not yet coded");
  digitalWrite(PumpPin, LOW);
}


void loop() {

  if (WiFi.status() == WL_CONNECTED)
  {
    if (!client.connected())
    {
      reconnect();
    }
    else
    {
      client.loop();
    }
  }

  if ((millis() - intervalMillis) > (PUBLISH_INTERVAL * 1000UL)) {
    watchsensors();
    printInfo();
    intervalMillis = millis();
  }

  //Actions :

  // Trigger Buzzer if water tank level is low :
  if (LowWater == true) {
    lowWaterlvl();
  } else {
    digitalWrite(buzzerPin, HIGH);

    // Trigger Pump if Soil is Dry :
    if (soillevel == 0) {
      watertheplant();
    } else {
      digitalWrite(PumpPin, LOW);
    }
  }
}

Best regards.

Where does your code check that WiFI is connected before determining if client is connected? If WIFi is not connected how can client be connected?

Yes it worked! thank you Fernando..... i wonder, may i know what is the function of the line you told me :

client.subscribe(subTopic.c_str());

the MCU don't subscribe to any topic through the MQTT, why should it be there? just wanting to know
and

  if ((millis() - intervalMillis) > (PUBLISH_INTERVAL * 1000UL)) {
    watchsensors();
    printInfo();
    intervalMillis = millis();
  }


and the last one. Why should i use millis there? thank you so much anyway :grinning:

But isn't this already checking the two (Wi-Fi and client)? sorry i'm new to Arduino programming...

1 Like

Glad to hear.

You can remove the callback function and this lines:

String subTopic = "subtopic";
client.subscribe(subTopic.c_str());
client.setCallback(callback);

It was added for test purpose.

Without this interval the readings and publications will be a few milliseconds.

if ((millis() - intervalMillis) > (PUBLISH_INTERVAL * 1000UL)) {
    watchsensors();
    printInfo();
    intervalMillis = millis();
  }

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.