How to blink LED until a new message is received through MQTT - Node MCU

I'm trying to build a program with NodeMCU and Node-Red, connecting them via an MQTT broker.
Once the Node-Red published a message, NodeMCU checks the received message and blinks the Built-in LED accordingly until a new message was published by Node-Red.

However, with my code, the blinking does not happen. It only turns on the LED once the message is received and waits until a new message.

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

// Change the credentials below, so your ESP8266 connects to your router
const char* ssid = "removed";
const char* password = "removed";

// Change the variable to your Raspberry Pi IP address, so it connects to your MQTT broker
const char* mqtt_server = "test.mosquitto.org";

// Initializes the espClient. You should change the espClient name if you have multiple ESPs running in your home automation system
WiFiClient espClient22;
PubSubClient client(espClient22);


//Connect your NodeMCU to your router
void setup_wifi() {
  delay(10);
  
  Serial.println();
 
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi connected - NodeMCU IP address: ");
  Serial.println(WiFi.localIP());
}

void blinkLoop(int del) {
  digitalWrite(LED_BUILTIN, LOW);   // Turn the LED on (Note that LOW is the voltage level
  // but actually the LED is on; this is because
  // it is active low on the ESP-01)
  Serial.print("Blinking at ");
  Serial.println(del);
  delay(del);                      // Wait for a second
  digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
  delay(del);                      // Wait for two seconds (to demonstrate the active low LED)
}

// This functions is executed when some device publishes a message to a topic that your NodeMCU is subscribed to
void callback(String topic, byte* message, unsigned int length) {
  Serial.print("\nMessage arrived on topic: ");
  Serial.print(topic);
  Serial.print(" with value of : ");
  String messageInfo;
  
  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    messageInfo += (char)message[i];
  }
  Serial.println();
  int warningVal = messageInfo.toInt();

  // If a message is received on the topic room/lamp, you check if the message is either on or off. Turns the lamp GPIO according to the message
  if(topic=="warning"){
      Serial.print("Warning received ");
      if (warningVal < 3){
        Serial.print(warningVal);
        Serial.println(" < 3");
        blinkLoop(3000);
        
       // digitalWrite(LED_BUILTIN, HIGH);
       // Serial.print("On");
      }
      else if (warningVal < 6) {
        Serial.print(warningVal);
        Serial.println(" < 6");
        blinkLoop(1000);
       // digitalWrite(LED_BUILTIN, LOW);
       // Serial.print("Off");
      }
      else if (warningVal < 15) {
        Serial.print(warningVal);
        Serial.println(" < 15");
        blinkLoop(500);
      }
  }
  Serial.println();
}

// reconnects your ESP8266 to your MQTT broker
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    
    if (client.connect("ESP8266Client22")) {
      Serial.println("connected");  
      client.subscribe("warning");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

// sets ESP GPIOs to Outputs, starts the serial communication at a baud rate of 9600
// Set  mqtt broker and set the callback function
// The callback function is what receives messages and actually controls the LEDs
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

//  ensures that the NodeMCU is connected to MQTT broker
void loop() {

  if (!client.connected()) {
    reconnect();
  }
  if(!client.loop())
    client.connect("ESP8266Client22");
  }

You have gone about implementing the blinking in completely the wrong way by using delay(), which blocks program execution

Instead, use millis() for the blinking timing
See Serial input basics - updated

The reason that the LED blinks only once in your current code is that you only call it from the callback() function and that function is only called once on receipt of a message. You could set a boolean to true in callback() and call blinkLoop() in loop() only if the boolean is true

1 Like

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