Blynk+ESP8266+MQTT+Nodered

Hi everyone,

I used to have several devices on one Auth-token, but since Blynk made this impossible I decided to find out how I can have the several ESP8266 devices combined and communicating. I thought the best way to make that work was by installing MQTT and Nodered on a Raspberry Pi and have the communication between Phone and ESP8266 along Blink, along Nodered and MQTT. Now I’m struggling already a long time to get this working.

To start I build some testcase from a Wemos D1 with an US-sensor which publishes its measured value to a topic called “test” and also another Wemos which is subscribed to the topic “test” and shows the value on the serial monitor. Sofar this works.

I also made a flow in Nodered injecting a number (=8) to the topic test, and 2 subscription nodes subscribed to test in order to show incoming messages in the debug screen as well as on a gauge. Activating the injection button results in a debug message on the debug screen, so I would say the Nodered itself is working, but I would also assume that the injected value from Nodered should be received by the Wemos since it is also subscribed to the test-topic. And the other way around: I expected to have the results from the sensor on the Wemos also to be shown in the debug screen of Nodered, but both are not the case.

I tested with the program MQTT-Viewer and there I do see the test-topic messages of the Wemos, but no results of Nodered. Also: publishing something from MQTT-Viewer is received by the Wemos, but not with Nodered. Nodered is installed on the RPI and the RPI is running at the same Wifi network as the Wemos.

When uploading my code to the Wemos I see the following warning message:

D:.…\PubSub_ESP8266_Example.ino: In function ‘void callback(char*, byte*, unsigned int)’:
D:.…\PubSub_ESP8266_Example.ino:109:13: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
109 | if(topic = “test”){
| ^~~~~~

I don’t exactly understand what’s wrong here, but is it possible that this message has something to do with it?

Nodered flow:

I understand that this is not a fully Blynk like subject, but only Blynk related, but I am hoping some people here are well experienced in these things and might be able to help.

Greeting Carl

I’m not following 100% what you’re saying here, but a couple of things jump out.

It’s not a great idea to have a device subscribed to a topic, and then have the same device publish to that topic. You seem to be saying that this is something you are doing, and it could lead to an endless loop of outgoing and incoming topics.

Issues with Char variable types is one of the biggest problems (as far as I’m concerned) when using PubSubClinet to publishing, subscribing and handling messages. I hate Char variables - this is probably more about my lack of understanding, but that doesn’t stop me hating them!

I explained a bit about my my approach to MQTT in this post…

The c_str() command is your friend when it comes to converting stuff to Char variable types.

I cant really comment more without seeing your code, but happy to help anyone who makes the move over to the dark side.

Pete.

@Carlimero Please edit your post, using the pencil icon at the bottom, and add triple backticks at the beginning and end of your code so that it displays correctly.
Triple backticks look like this:
```

Copy and paste these if you can’t find the correct symbol on your keyboard.

Pete.

Hello Pete,

Thank you very much for your reply. The code I made indeed does subscribe and publish to the same topic, this with a delay of 5 seconds. I also tested it with 2 Wemos devices and had the first measuring and publishing and the second subscribing and writing to the serial monitor and that worked well.

Since I am not very good at coding myself, I wrote the code mostly by copying and pasting examples from the web. Therefore also I think it’s strange that the Nodered to Wemos link is not working, as this seems so simple in all these examples.

I read your comments about the MQTTcallback function, but I don’t think it’s in the basis very different of the way the topic is handled in my callback function?

Here is my code, maybe you can see something strange in it?

/*
 Basic ESP8266 MQTT example
....
*/

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

// Update these with values suitable for your network.
const char* ssid = "";
const char* password = "";
const char* mqtt_server = "192.168.68.107";
const char* MQTT_username = ""; 
const char* MQTT_password = "";

const IPAddress remote_ip_RPI(192, 168, 68, 107); // RPI

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE	(50)
char msg[MSG_BUFFER_SIZE];
int value = 0;

// US distance sensor:
const int trigPin = 12; // D6
const int echoPin = 13; // D7

long duration;
float distance;

// Timers auxiliar variables
long now = millis();
long lastMeasure = 0;

// Ledkleuren:
#define uit         0
#define blauw       1
#define groen       2
#define magenta     3
#define rood        4
#define lichtblauw  6

int RodePin   = 0; // Rode pin voor Led = D8
int GroenePin = 2; // Groene pin voor Led = D9
int BlauwePin = 15; // Blauwe pin voor Led = D10
bool Success;

//-----------------------------------------------------------------------------------------

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

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

  randomSeed(micros());

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

//-----------------------------------------------------------------------------------------

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

  //------------------------
  
 if(topic = "test"){
      //Serial.print("Changing LED to ");
      if(messageTemp.toFloat() <= 6){
        LedAan(1);
        //Serial.println("blauw");
      }
      else if(messageTemp.toFloat() > 6){
        LedAan(2);
        //Serial.println("groen");
      }
  }
}

//-----------------------------------------------------------------------------------------

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
      
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str(), MQTT_username, MQTT_password)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("test", "hello world");
      // ... and resubscribe
      client.subscribe("test");
      //client.subscribe("test/dist");      // Evt subscribtion to 2nd topic
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

//--------------------------------------------------------------------------------------------------------------

void LedAan(int Kleurfunctie)
{
  
 switch(Kleurfunctie)
 {
 case 0: // Led uit
 analogWrite(RodePin,0);
 analogWrite(BlauwePin,0);
 analogWrite(GroenePin,0);
 break;

 case 1: // blauw
 analogWrite(RodePin,0);
 analogWrite(BlauwePin,255);
 analogWrite(GroenePin,0);
 break;
 
 case 2: // groen
 analogWrite(RodePin,0);
 analogWrite(BlauwePin,0);
 analogWrite(GroenePin,255);
 break;
 
 case 3: // magenta
 analogWrite(RodePin,255);
 analogWrite(BlauwePin,255);
 analogWrite(GroenePin,0);
 break;

 case 4: // rood
 analogWrite(RodePin,255);
 analogWrite(BlauwePin,0);
 analogWrite(GroenePin,0);
 break;

 case 6: // lichtblauw
 analogWrite(RodePin,255);
 analogWrite(BlauwePin,150);
 analogWrite(GroenePin,255);
 break;
 }
}

//--------------------------------------------------------------------------------------------------------------

void MeasureDist()
{
  // Clears the trigPin
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  // Sets the trigPin on HIGH state for 10 micro seconds
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // Reads the echoPin, returns the sound wave travel time in microseconds
  duration = pulseIn(echoPin, HIGH);
  // Calculating the distance
  distance = duration * 0.034 / 2;

  client.publish("test", String(distance).c_str());  // Publish distance value
}


//---------------------------------------------------------------

void Pinging(IPAddress remote_ip)
{
   Serial.print("Pinging ip ");
   Serial.println(remote_ip);

  if(Ping.ping(remote_ip)) 
     {
      Serial.println("Success!!");
      Success = true;
     } 
     else {
      Serial.println("Error :(");
      Success = false;
     }
     delay(5000);
}

//=======================================================================================

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  pinMode(RodePin, OUTPUT);
  pinMode(BlauwePin, OUTPUT);
  pinMode(GroenePin, OUTPUT);
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
  pinMode(echoPin, INPUT); // Sets the echoPin as an Input
  
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

//=======================================================================================

void loop() {

  //Pinging(remote_ip_RPI);
  //delay(10000);
  
  if (!client.connected()) {
    reconnect();
  }

  client.loop();
  
    // Publishes new distance every 5 seconds
  now = millis();   
  if (now - lastMeasure > 5000) 
     {
    lastMeasure = now;
    MeasureDist();
    
    //snprintf (msg, MSG_BUFFER_SIZE, "Distance = %ld", distance);
    snprintf (msg, MSG_BUFFER_SIZE, "Distance = %f", distance);
    Serial.print("Publish message: ");
    Serial.println(msg);
    client.publish("test", msg);
  }
}

Configuration of the upper MQTT-in Node in Nodered:

… and the debug-node:

It’s very different.
My code turns the Char variables into String variables before you do any if comparisons on the contents. Your does not, which is why you get this message…

Also, if you’re doing a comparison you need to use == rather than =

Pete.

Thanks Pete,

I changed the == to = in the comparison because the == did not work (the == was in the original example). I’ll do some testing, maybe I can get rid of the warning message while compiling when == is combined with your turning Char vars into Strings…

However, since changing this only effects the subscribtion side, I don’t think it will solve all of my problem, because published messages to topic “test” are not received in Nodered as well. It’s like the 2 systems (Wemos and Nodered) are both functioning on the MQTT system theirselves, but are not functioning together.

Hello Pete,

I put in your MQTTcallback function instead of my old callback and I lost the warning message while compiling, so I’m a bit further I think.

But Nodered is still not reacting on the published messages and the Wemos does still not receive the injected numbers from Nodered as well.

Okay, the first thing to do is to publish the data to a different topic to the one that the publishing device is subscribed to.

Then, ensure that only Node-Red is “subscribed” to that topic (Node-Red has an MQTT In node listening g to this new topic). Your other Wemos device must not be subscribed to this new topic at this stage.

The other test to do is to publish a value to the new topic using MQTT Explorer (download link towards the end of this post)…

This published value should be received by Node-Red, and you should also be able to see values coming from the Wemos in MQTT Explorer.

Are you using Mosquitto version 2.x ?
If so, have you set your configured to allow anonymous access using listener 1883, as this could prevent Node-Red from seeing the messages from your devices.

Pete.

I changed the code on the first Wemos to publishing on topic sensor and subscribtion to topic test. The other Wemos is not in use for now. Published values of the Wemos can be seen in the MQTT-Explorer, but are not coming in to Nodered.

I also made an injection node with MQTT-out publishing to topic test in Nodered. The published data is not reaching the Wemos, nor the MQTT-Explorer.

Adding a MQTT-in node on topic test with a debug node in Nodered turns out that Nodered obviously is in contact with MQTT as the injected value appears on the debug window.

So in short: MQTT-Explorer and Wemos are working well, Nodered itselves also, but not in combination with the Wemos and MQTT-Explorer. Nodered seems to be some sort of isolated.

I changed the “allow_anonymous”-value in the config file of MQTT to true (it was set on false) and started up MQTT again, but this makes no difference. The version of MQTT I’m using is 2.0.11.

Here is the configuration file:
image

When starting up the listener on port 1883 seems to be working:

Something I do not understand from the output of the MQTT-Explorer:

  • I see the “sensor” topic with the measured value of 5.10 from the Wemos as expected, als well as the published value of 20 to topic test out of MQTT-Explorer, but Is it expectable to have so much topics behind $SYS (39 topics) in this simple testing setup?
    image

No it’s not. Your screenshot says “Starting in local only mode. Connections will only be possible from clients running on this machine”.

The instructions say # Place your local configuration in /etc/mosquitto/conf.d/ but this never works for me, I have to place the mosquitto.conf file in /etc/mosquitto for it to work.

Yes, that’s just stuff that the broker does in the background…

image

Pete.

Hi Pete,

I never used RPI and Linux before, so this is real rocket science for me. I thought since MQTT is running on the RPI and Wemos and Nodered connect to the IP adress of the RPI they were both “running on this machine”.

To see the Mosquitto.conf file I type:

sudo nano etc/mosquitto/mosquitto.conf

so I assume the config file is already in /etc/mosquitto/ as you said?

I could try to place it in /etc/mosquitto/conf.d/ but how should I do that? And the configuration file is setup right for having not only clients on this machine? Or should I also make changes to that file?

I kept on experimenting: restarted my RPI and saw the Nodered MQTT-in and out nodes stayed unconnected now. So I tried to change the serveradress to the IP adress instead of the localhost, but accidentially forgot to fill in the security rules (user / password) and it occured to work! I really don’t understand, but I am indeed a big step further. Now I’ll try to get it working with the security.

Not sure what’s happening there, but you’ve not shared any info about how you’ve configured the security on Mosquitto.

Are you still seeing this message…

if so then it won’t work correctly.

“Running on this machine” means code that’s being executed on the RPI, not on the Wemos or a program running on your PC.

Pete.

Yes, I still become “Starting in local mode”.

Is it because I put “Anonymous” on true that it is working now? Earlier I tried to change the localhost with the IP adress of the RPI and then it did not work, the MQTT nodes did not get connected at that time.

Furthermore I did not change username and password, but the configurationfile suggest a passwordfile still exists.

What is strange actually is that I am using username and password in my Wemos code, but when I use these in Nodered it stops working.

This is the thing you need to focus on fixing.

When you view the /etc/Mosquitto folder in WinSCP what does it show in terms of file permissions?

It might be worth creating a copy of the config file in the /conf.d folder.

Pete.

I’m sorry, how can I come to WinSCP? I tried that in the Windows system console but that does not work.

And for copying the config file to the directory

/etc/mosquitto/conf.d/

what command should I type?

You need SSH enabled on the Pi. How you do this will depend on whether you’ve yo one for a headless install or not. Do a quick Google search and you’ll see how to do it.
The credentials you use in WinSCP are the ones you use when logging-in to the Pi, not your MQTT credentials.

I’m not in front of my system at the moment, but from memory you’ll need to open the existing config using:
sudo nano /etc/mosquitto/conf.d/mosquitto.conf

Then copy the contents and create the new file with:
sudo nano /etc/mosquitto/conf.d/mosquitto.conf
and paste the contents of the original file into the new one and save it.

Pete.

The file permissions in the etc/mosquitto/ folder are:
image

I’m not sure what this means.

It’s fine. Root is the owner of the .conf file, and it has permissions that allow it to be read.

Pete.