Hi, I have been able to connect an Arduino WiFi to Node-RED over MQTT and I want to launch a big-scale project where I'll have multiple Arduinos with multiple sensors sending data to node. How would I organize this, have multiple nodes? This is the code I have been able to use so far:
/* This example shows how to use MQTT on the main dev boards on the market
* HOW TO USE:
* under connect method, add your subscribe channels.
* under messageReceived (callback method) add actions to be done when a msg is received.
* to publish, call client.publish(topic,msg)
* in loop take care of using non-blocking method or it will corrupt.
*
* Alberto Perro - Officine Innesto 2019
*/
#define BROKER_IP "10.0.0.90"
#define DEV_NAME "mqttdevice"
#define MQTT_USER "mqtt"
#define MQTT_PW "password"
const char ssid[] = "Xf123456";
const char pass[] = "11050927";
#include <MQTT.h>
#ifdef ARDUINO_SAMD_MKRWIFI1010
#include <WiFiNINA.h>
#elif ARDUINO_SAMD_MKR1000
#include <WiFi101.h>
#elif ESP8266
#include <ESP8266WiFi.h>
#else
#error unknown board
#endif
#include <Wire.h>
#include <Adafruit_MPL3115A2.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7);
Adafruit_MPL3115A2 baro = Adafruit_MPL3115A2();
WiFiClient net;
MQTTClient client;
unsigned long lastMillis = 0;
void connect() {
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("\nconnecting...");
while (!client.connect(DEV_NAME, MQTT_USER, MQTT_PW)) {
Serial.print(".");
delay(1000);
}
Serial.println("\nconnected!");
client.subscribe("/main_topic"); //SUBSCRIBE TO TOPIC /main_topic
}
void messageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload);
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, pass);
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
// You need to set the IP address directly.
//
// MQTT brokers usually use port 8883 for secure connections.
client.begin(BROKER_IP, 1883, net);
client.onMessage(messageReceived);
connect();
lcd.begin(16,2); // initializing the LCD 16 x 2
lcd.setBacklightPin(3,POSITIVE); // Enable or Turn On the backlight
lcd.setBacklight(HIGH);
}
void loop() {
if (! baro.begin()) {
Serial.println("Couldnt find sensor");
return;
}
float tempC = baro.getTemperature();
Serial.print(tempC); Serial.println("*C");
float altm = baro.getAltitude();
Serial.print(altm/-6); Serial.println(" meters");
client.loop();
if (!client.connected()) {
connect();
}
String txt = "Hello World!";
char data[6];
dtostrf(tempC, 5, 2, data);
// publish a message roughly every second.
if (millis() - lastMillis > 1000) {
lastMillis = millis();
client.publish("/main_topic", data); //PUBLISH TO TOPIC /main_topic MSG world
}
lcd.home();
lcd.print(altm/-6);
lcd.setCursor(0,1);
lcd.print("Meters");
lcd.setCursor(9,0);
lcd.print(tempC);
lcd.setCursor(9,1);
lcd.print("Celsius");
lcd.setCursor(7,0);
lcd.print("|");
lcd.setCursor(7,1);
lcd.print("|");
}
Or possibly use meaningful names, such as the room name for example, so that if later you change it from an arduino to a zigbee device you don't have unhelpful topics hard coded into your flows.
I currently don't have multiple Adafruit sensors but I'm planning to expand, so for this example I wrote a simple code for a message
/* This example shows how to use MQTT on the main dev boards on the market
* HOW TO USE:
* under connect method, add your subscribe channels.
* under messageReceived (callback method) add actions to be done when a msg is received.
* to publish, call client.publish(topic,msg)
* in loop take care of using non-blocking method or it will corrupt.
*
* Alberto Perro - Officine Innesto 2019
*/
#define BROKER_IP "10.0.0.90"
#define DEV_NAME "mqttdevice"
#define MQTT_USER "mqtt"
#define MQTT_PW "password"
const char ssid[] = "Xf123456";
const char pass[] = "11050927";
#include <MQTT.h>
#ifdef ARDUINO_SAMD_MKRWIFI1010
#include <WiFiNINA.h>
#elif ARDUINO_SAMD_MKR1000
#include <WiFi101.h>
#elif ESP8266
#include <ESP8266WiFi.h>
#else
#error unknown board
#endif
WiFiClient net;
MQTTClient client;
unsigned long lastMillis = 0;
void connect() {
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("\nconnecting...");
while (!client.connect(DEV_NAME, MQTT_USER, MQTT_PW)) {
Serial.print(".");
delay(1000);
}
Serial.println("\nconnected!");
client.subscribe("/sensors/message"); //SUBSCRIBE TO TOPIC /mesage_topic
}
void messageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload);
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, pass);
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
// You need to set the IP address directly.
//
// MQTT brokers usually use port 8883 for secure connections.
client.begin(BROKER_IP, 1883, net);
client.onMessage(messageReceived);
connect();
}
void loop() {
client.loop();
if (!client.connected()) {
connect();
}
String txt = "Hello World!";
// publish a message roughly every second.
if (millis() - lastMillis > 1000) {
lastMillis = millis();
client.publish("/sensors/message", txt); //PUBLISH TO TOPIC /altitude_topic MSG world
}
}
Of course I also changed the topic in the other code for the Arduino that has the sensor
One reason to use #define is to avoid embedding "magic" strings and numbers in the body of your code.
So you should define the MQTT topic you will publish to just once at the top of the program.
Your code has an MQTT topic defined (sensors/thermo) but you don't use it; down in your loop() you have
client.publish(" sensors/temp", data);
It should be client.publish( MQTT_TOPIC, data);
You have not followed my suggestion for the definition of MQTT_TOPIC as an automatic concatenation of MQTT_BASE and DEV_NAME. Your version should work fine.
Although I see where you define a string as "Hello World!", I can't see from your code how that or ºC gets into msg.payload.
Personally, I wouldn't include units in the mqtt message since I know I always use Celsius.