Sari la conținut
ELFORUM - Forumul electronistilor

MQTT publish-subscribe


XAN77

Postări Recomandate

Am o problemă stupidă, sunt convins că greșesc cu ceva da nu văd încă ce.

Am trecut jucăriile din casă pe MQTT, folosind ca broker un pi zero 2 w. Jucării însemnând momentan 5 clienți esp8266 cu senzori ce publică temperaturi/umidități din care unu e pe centrala cu lemne și 2 clienți tot 8266 pe post de ceasuri cu display matrici de leduri ce fac subscribe la anumite topicuri publicate de clienții esp8266. Toate topicurile le văd pe un dashboard node-red de care se ocupă pi zero 2 w, practic o pagină web.

Am încercat azi ca unu din ceasuri, ce făcea subscribe la 2 topicuri (temperatura si umiditate de la un dht11 pus la un esp01) și funcționa bine, să mai facă subscribe la încă un topic. Practic vreau ca pe lângă temperatura și umiditatea din camera unde este ceasul publicate de un esp01, să mai afișez și o temperatura de la un alt client (turul centralei termice).

Ei chestia asta nu a mers în sensul că al 3-lea topic la care face subscribe (în funcția reconnect) nu funcționează, valoarea afișată pe display este 00. Am schimbat ordinea la cele 3 subscribe-uri și mereu cel ce nu merge este al 3-lea. Deci nu am o greșeală la una din linii, cea care este pusă a 3-a în cod e cea care nu merge adică pare că nu primește date de la broker pentru topicul respectiv. Nu cred să fie o limită la numărul de topicuri la care se  poate abona un client mqtt dar nu-mi dau seama de ce naiba nu-mi merge un subscribe în plus față de codul anterior ce mergea perfect.

Ca să am totuși cele 3 valori ce mă interesează, am schimbat codul clientului ce publică temp și umid din cameră și am mixat valorile făcând un singur string publicat într-un singur topic, astfel la recepție să am doar 2 subscribe-uri una din care extrag temp și umid și a doua unde am temperatura de la centrală. Dar nu-mi place această improvizație , mă încurcă și în node-red cu acele 2 valori cuplate într-un singur string.

Sper că m-am făcut înțeles. Vreo idee ce aș putea încerca?

 

Atașez codul, e scris în ArduinoIDE și e împărțit în câteva tab-uri, ca să fie mai ușor de urmărit. Importante sunt funcțiile callback și reconnect. Iar valorile de interes le țin în variabile tip int pentru că afișez doar valori întregi fără zecimale, respectiv ti=temperatură cameră, hi=umiditate camera și ti_c=temperatură centrală.

 

tabul principal ce conține funcția loop si asigura includerea taburilor urmatoare

#include "1_declarari.h"
#include "3_functii.h"
#include "4_setup.h"
 
void loop() {
  ArduinoOTA.handle();
  
  if (!client.connected()) { reconnect(); }
  client.loop();

  make_clock(0);
  matrix.write();     // Send bitmap to display
  diy_wait_ms(1000);  // delay executat in pasi de 100ms intre care se executa niste verificari
  
  make_clock(1);  // afisez cu puncte intre ora si minute
  matrix.write(); // Send bitmap to display
  diy_wait_ms(1000);
  
  make_clock(0);
  matrix.write(); // Send bitmap to display
  diy_wait_ms(1000);

  make_senzor_data(); // pregateste datele de afisat intrun bitmap
  matrix.write();     // Send bitmap to display
  diy_wait_ms(1000);

  make_centrala_data(); // pregateste datele de afisat intrun bitmap
  matrix.write();     // Send bitmap to display
  diy_wait_ms(1000);  
}

 

tabul declarari, unele variabile posibil sa nu fie folosite

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
#include <time.h>
#include <ESP8266mDNS.h>    //For OTA
#include <WiFiUdp.h>        //For OTA
#include <ArduinoOTA.h>     //For OTA

const char* ssid = "...........";
const char* password = "...............";
const char* mqtt_server = "192.168.1.12";

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

int wait = 70; // In milliseconds
int spacer = 1;
int width  = 5 + spacer; // The font width is 5 pixels
int m;
int ti, ti_c; // folosite la afisarea temp si umid pe displayul local LED
int hi;
int pinCS = D4; 
int numberOfHorizontalDisplays = 6;
int numberOfVerticalDisplays   = 1;
char time_value[20];
char un_string[25];
// LED Matrix Pin -> ESP8266 Pin
// Vcc            -> 3v  (3V on NodeMCU 3V3 on WEMOS)
// Gnd            -> Gnd (G on NodeMCU)
// DIN            -> D7  (Same Pin for WEMOS) GPIO.13
// CS             -> D4  (Same Pin for WEMOS) GPIO.2
// CLK            -> D5  (Same Pin for WEMOS) GPIO.14
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

 

tabul functii

void display_message(String message){
   for ( int i = 0 ; i < width * message.length() + matrix.width() - spacer; i++ ) {
    //matrix.fillScreen(LOW);
    int letter = i / width;
    int x = (matrix.width() - 1) - i % width;
    int y = (matrix.height() - 8) / 2; // center the text vertically
    while ( x + width - spacer >= 0 && letter >= 0 ) {
      if ( letter < message.length() ) {
        matrix.drawChar(x, y, message[letter], HIGH, LOW, 1); // HIGH LOW means foreground ON, background off, reverse to invert the image
      }
      letter--;
      x -= width;
    }
    matrix.write(); // Send bitmap to display
    delay(wait/2);
  }
}

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); display_message("..wait for wifi.."); }
  randomSeed(micros());
  //Serial.println("");
  //Serial.println("WiFi connected");
  //Serial.println("IP address: ");
  //Serial.println(WiFi.localIP());
}

void callback(String 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]);
  }
  if (topic == "centrala/esp8266/ds18b20/tur")         ti_c = ( payload[0] - 48 ) * 10  +  ( payload[1] - 48 );
  if (topic == "dormitor/esp8266/ds18b20/temperature") ti   = ( payload[0] - 48 ) * 10  +  ( payload[1] - 48 );
  if (topic == "dormitor/esp8266/ds18b20/humidity")    hi   = ( payload[0] - 48 ) * 10  +  ( payload[1] - 48 );
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266-Dormitor-clock";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      client.subscribe("centrala/esp8266/ds18b20/tur");
      client.subscribe("dormitor/esp8266/ds18b20/temperature");
      client.subscribe("dormitor/esp8266/ds18b20/humidity");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void make_clock (int puncte){
  matrix.drawChar(2,0, time_value[0], HIGH,LOW,1); // H
  matrix.drawChar(8,0, time_value[1], HIGH,LOW,1); // HH  
  matrix.drawChar(14,0,time_value[2], HIGH,LOW,1); // HH:
  matrix.drawChar(20,0,time_value[3], HIGH,LOW,1); // HH:M
  matrix.drawChar(26,0,time_value[4], HIGH,LOW,1); // HH:MM
  matrix.drawPixel(16,1,1);
  matrix.drawPixel(17,1,1);
  matrix.drawPixel(17,2,1);
  matrix.drawPixel(17,4,1);
  matrix.drawPixel(16,5,1);
  matrix.drawPixel(17,5,1);
  if (puncte == 0) matrix.drawChar(14,0,0, HIGH,LOW,1); // daca puncte = 0, sterge punctele
}

void make_senzor_data(){
  matrix.drawChar(2,0, ti/10+48, HIGH,LOW,1); // H
  matrix.drawChar(8,0, ti%10+48, HIGH,LOW,1); // HH  
  matrix.drawChar(14,0,0, HIGH,LOW,1); // HH:
  matrix.drawChar(20,0,hi/10+48, HIGH,LOW,1); // HH:M
  matrix.drawChar(26,0,hi%10+48, HIGH,LOW,1); // HH:MM
  matrix.drawPixel(15,0,1);
  matrix.drawPixel(14,1,1);
  matrix.drawPixel(16,1,1);
  matrix.drawPixel(14,2,1);
  matrix.drawPixel(16,2,1);
  matrix.drawPixel(15,3,1);  
}

void make_centrala_data(){
  matrix.drawChar(2,0, 'T', HIGH,LOW,1); // T
  matrix.drawChar(8,0, 'u', HIGH,LOW,1); // u
  matrix.drawChar(14,0, 'r', HIGH,LOW,1); // r
  matrix.drawChar(20,0, ti_c/10+48, HIGH,LOW,1); // H
  matrix.drawChar(26,0, ti_c%10+48, HIGH,LOW,1); // HH 
  }

void verificari(){
  //verific ora 2:05 ca sa fac reset
  if ( time_value[0]=='0' && time_value[1]=='2' && time_value[3]=='0' &&
       time_value[4]=='5' && time_value[6]=='0' && time_value[7]=='0') ESP.restart();

  //verific ora exacta penrtu display mesaj
  if ( time_value[3]=='0' && time_value[4]=='0' && time_value[6]=='0' && time_value[7]=='0' ) {
      matrix.fillScreen(LOW);
      matrix.write();
      display_message(un_string); // la ora xx:00:00 face o defilare de text        
  }

  time_t now = time(nullptr);
  String time = String(ctime(&now));
  time.trim();
  //timpu e sub forma ”Sat Jul  3 10:41:56 2021”
  time.substring(11,21).toCharArray(time_value, 12); //extrage timpul din string intrun char array
  time.toCharArray(un_string, 25);// copi in char array continutul stringului time  
}

//face delay din bucati de 100ms, intre care citeste ntp.server plus alte verificari
void diy_wait_ms (int timp){
  timp=timp/100;
  for (int i=0; i<timp; i++) {   // splituisc un delay de 500ms in 5 de 100
    delay(100);
    verificari();             // ca sa fac niste verificari mai des
  }  
}

 

tabul setup

void setup() {
  Serial.begin(115200);
  matrix.setIntensity(0); // Use a value between 0 and 15 for brightness
  matrix.setRotation(0, 1);    // The first display is position upside down
  matrix.setRotation(1, 1);    // The first display is position upside down
  matrix.setRotation(2, 1);    // The first display is position upside down
  matrix.setRotation(3, 1);    // The first display is position upside down
  matrix.fillScreen(LOW);
  matrix.write(); 
  
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  Serial.print("Configuring OTA device...");
  //  TelnetServer.begin();   //Necesary to make Arduino Software autodetect OTA device  
  ArduinoOTA.onStart([]() {Serial.println("OTA starting...");});
  ArduinoOTA.onEnd([]() {Serial.println("OTA update finished!");Serial.println("Rebooting...");});
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {Serial.printf("OTA in progress: %u%%\r\n", (progress / (total / 100)));});  
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();

  configTime(2 * 3600, 0, "ro.pool.ntp.org", "time.nist.gov");
  //setenv("TZ", "GMT-1BST",1); era in softu initial
}

 

Una peste alta mișto sistemul ăsta cu MQTT și node-red.

Editat de x_dadu
adăugare cuvânt lipsă
Link spre comentariu
  • Răspunsuri 19
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

  • XAN77

    10

  • Viorel A

    2

Top autori în acest subiect

m-am conectat acum pe serial, după ce vin 2 mesaje, cele 2 topicuri care sunt primite corect, îmi apare un ”Attempting MQTT connection...connected” deci se execută functia reconnect. Sa inteleg ca se deconectează...de ce oare nu știu !

Link spre comentariu

Vezi in fisierul de configurare de la mqtt.
Dar este posibil sa fie deja enable log.
asa ca intra pe Rpi si incearca:


tail -f /var/log/mosquitto/mosquitto.log

 

si vezi ce apare cand face clientul subscribe.

Link spre comentariu

pi@raspberrypi:~ $ tail -f /var/log/mosquitto/mosquitto.log
tail: cannot open '/var/log/mosquitto/mosquitto.log' for reading: Permission denied
tail: no files remaining
pi@raspberrypi:~ $

 

dar am deschis fițierul cu sudo nano ... dar nu-mi dau seama ce ar trebui să văd. Observ că cam toți clienții se deconectează singuri (client xxx is closed its connection, ceva de genu). Dau paste din acel log:

1643933114: New client connected from 192.168.1.21:53519 as ESP8266-Dormitor-clockaa7 (p2, c1, k15).
1643933119: Client ESP8266-Dormitor-clockf492 closed its connection.
1643933120: Client ESP8266-Living-clock9119 closed its connection.
1643933624: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643935425: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643937226: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643939027: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643940673: Client ESP8266Client closed its connection.
1643940678: New connection from 192.168.1.20:63345 on port 1883.
1643940678: New client connected from 192.168.1.20:63345 as ESP8266Client (p2, c1, k15).
1643940828: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643942629: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643944430: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643944493: Client ESP8266ClientCentrala closed its connection.
1643944498: New connection from 192.168.1.13:60346 on port 1883.
1643944498: New client connected from 192.168.1.13:60346 as ESP8266ClientCentrala (p2, c1, k15).
1643946231: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643947990: Client ESP8266-Living-clock69ab has exceeded timeout, disconnecting.
1643947991: New connection from 192.168.1.9:60937 on port 1883.
1643947991: New client connected from 192.168.1.9:60937 as ESP8266-Living-clock4840 (p2, c1, k15).
1643948032: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643949833: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643951634: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643953435: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643955236: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643957037: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643958838: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643960639: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643962440: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643964241: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643966042: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643967843: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643969644: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643971445: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643973246: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.
1643975047: Saving in-memory database to /var/lib/mosquitto//mosquitto.db.


 

Link spre comentariu

In primul rand trebuie sa deconectezi ceilalti clienti si sa lasi conectat doar clientul:
192.168.1.21 ESP8266-Dormitor-clock (adica cel care-ti face probleme. asta ca sa-ti vina mai usor se te uiti prin log)

Si te poti uita la ce mesaje noi apar in log cu:
sudo tail -f /var/log/mosquitto/mosquitto.log

Si trebuie si facut mai verbose logul mqtt ...

 

Dar poate este mult mai simpla erroare si nu este din serverul de mqtt.
Dar daca vrei sa mai inveti ceva... te chinui putin si mergi si pe calea asta :)
 

 

 

Link spre comentariu
Acum 6 minute, Liviu.Mihaiu a spus:

In primul rand trebuie sa deconectezi ceilalti clienti si sa lasi conectat doar clientul:
192.168.1.21 ESP8266-Dormitor-clock (adica cel care-ti face probleme. asta ca sa-ti vina mai usor se te uiti prin log)

Si te poti uita la ce mesaje noi apar in log cu:
sudo tail -f /var/log/mosquitto/mosquitto.log  am executat comanda asta și merge, nuș cum dar mi-a dat date numai despre clock dormitor pun mai jos ce mi-a dat

Si trebuie si facut mai verbose logul mqtt ... ce înseamnă asta și cum fac ?

 

Dar poate este mult mai simpla erroare si nu este din serverul de mqtt.
Dar daca vrei sa mai inveti ceva... te chinui putin si mergi si pe calea asta :) sigur, de ce nu, măcar am observat că clienții par a se deconecta singuri mereu
 

 

 

 

1644855891: New client connected from 192.168.1.21:55748 as ESP8266-Dormitor-clock (p2, c1, k15).
1644855922: Client ESP8266-Dormitor-clock closed its connection.
1644855927: New connection from 192.168.1.21:61822 on port 1883.
1644855927: New client connected from 192.168.1.21:61822 as ESP8266-Dormitor-clock (p2, c1, k15).
1644855957: Client ESP8266-Dormitor-clock closed its connection.
1644855962: New connection from 192.168.1.21:54001 on port 1883.
1644855962: New client connected from 192.168.1.21:54001 as ESP8266-Dormitor-clock (p2, c1, k15).
1644855992: Client ESP8266-Dormitor-clock closed its connection.
1644855997: New connection from 192.168.1.21:49349 on port 1883.
1644855997: New client connected from 192.168.1.21:49349 as ESP8266-Dormitor-clock (p2, c1, k15).
1644856027: Client ESP8266-Dormitor-clock closed its connection.
1644856032: New connection from 192.168.1.21:55585 on port 1883.
1644856032: New client connected from 192.168.1.21:55585 as ESP8266-Dormitor-clock (p2, c1, k15).
1644856063: Client ESP8266-Dormitor-clock closed its connection.
1644856068: New connection from 192.168.1.21:62618 on port 1883.
1644856068: New client connected from 192.168.1.21:62618 as ESP8266-Dormitor-clock (p2, c1, k15).
1644856098: Client ESP8266-Dormitor-clock closed its connection.

 

Link spre comentariu

Ce vad eu ciudat este ca ClientID din log nu este conform cu:
 

String clientId = "ESP8266-Dormitor-clock";
    clientId += String(random(0xffff), HEX);

 

Adica trebuia sa fie un string+xxxx , unde xxxx un alt string aleator in hexa.
Nu cumva clientID are a limita de caractere pe care ai depasit-o ? Ia vezi in documentatie.
Nu cred ca asta este marea ta problema. Dar ia incearca cu ceva mai scurt, "ESP-Dorm-CLK". Si vezi iar in log.
Trebuie sa apara de fiecare data alt clientID.


Eu ma opresc aici. Poate mai are si altcineva alte idei.

 

Editat de Vizitator
Link spre comentariu

Îmi cer scuze, am comentat eu, adică anulat acea linie ce adaugă în coadă acel număr aleatoriu, că am zis că o fi de acolo, că de, dacă nu înțeleg necesitatea acelei adăugiri o iau băbește. De aceea acum are numele curat fără acel hex în coadă.

Link spre comentariu

Verifica ce ai in  linia #define MQTT_KEEPALIVE din PubSub.h ... aici ar trebui sa ai o valoare mai mare decat intervalul la care transmit clientii.

De asemenea verifica daca cei 3 clienti au id-uri diferite ..

Dar daca ai intervale mari la care transmit clientii date cred ca ar fi mai simplu sa le trasmita cu retain in felul asta vei avea la fiecare citire ultimele date transmise.

Link spre comentariu
11 minutes ago, x_dadu said:

Îmi cer scuze, am comentat eu, adică anulat acea linie ce adaugă în coadă acel număr aleatoriu, că am zis că o fi de acolo, că de, dacă nu înțeleg necesitatea acelei adăugiri o iau băbește. De aceea acum are numele curat fără acel hex în coadă.

Gresit. Lasa stringul aleator. Redu din denumirea clientului. Asa cum am zis mai sus.

Si incearca sa mai citesti si documentatia. Nu mai merge pe 'babeste'.
Acum am citit in RFC, si zice ca trebuie sa fie maxim 23 lungime "clientID".  Tu ai depasit.

Editat de Vizitator
Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum



×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări