Sari la conținut
ELFORUM - Forumul electronistilor

Extragere valori senzori din mesajul MQTT în stil JSON trimis de Tasmota


XAN77

Postări Recomandate

Vă salut, Am o nouă mică dilemă. M-am apucat să reconfigurez jucăriile din casă ce trimit date la un broker mqtt, în general esp01/nodemcu cu senzori, punând pe toate firmware Tasmota, întrucât mi s-a părut mie interesant că pentru modificări ulterioare nu necesită reprogramare ci doar configurare, plus că se poate integra în Homeassistant sau alte aplicații.

Pe de altă parte am și module ce au cod făcut în ArduinoIDE pe care nu pot pune Tasmota pentru că au display cu afișare ”complexă”, afișează date din mai multe topicuri mqtt, succesiv și în diverse stiluri, ceea ce nu am găsit cum pot face cu Tasmota. Acestea sunt de regulă ceasurile din camere, ce au display matriceal 8x32 puncte cu MAX7219.

M-am lovit astfel de problema necesității de a extrage valorile trimise de senzori din mesajele ce le trimite Tasmota, care sunt mai stufoase decât trimiteam eu cu cod diy. Mesajele respectă stilul JSON, adică reprezintă obiecte (din câte am înțeles). Cel din camera mică unde am un esp01 cu un singur senzor 18b20 trimite mesajul:

{"Time":"2024-02-21T19:03:02","DS18B20":{"Id":"0417315443FF","Temperature":24.4},"TempUnit":"C"}

Și ăsta e unul simplu, alte mesaje sunt mai stufoase dacă sunt mai mulți senzori, dacă au și umiditate etc.

Momentan extrag temperatura folosind poziția caracterelor din șir, în exemplul de mai sus primu caracter e la poziia 75. Dar e penibilă soluția pentru că dacă am mai multe temperaturi în mesaj, poziția acestora se poate schimba dacă unu din ele capătă valori din mai multe sau mai puține caractere. Momentan e ok că nu o să am în cameră sub 10 sau peste 99 grade, dar nu e elegant. Aș vrea să folosesc JSON și să extrag exact obiectele, adică valoarea  "Temperature" pentru senzorul "DS18B20", indiferent câte caractere are, dacă are - în față sau nu etc.

Dar nu am reușit să înțeleg perfect cum se lucrează cu JSON și nu am reușit să scriu cod pentru a face asta.

Dacă are cineva un exemplu sau, și mai bine, timp ca să editeze codul meu de mai jos, dau o bere virtuală :rade:

Am încercat să chelesc un cod de alte bălării, să fie cât mai simplu. nodemcu cu display cu 4 matrici chinezesc, ce dă subscribe la topicul ce l-am luat cu copy din consola Tasmota, extrag din șir valorile temperaturii și o afișez cu scroll, defilare de la dreapta la stânga cu funcția display_message.

Scuze de postarea lungă. Nu am grabă în a rezolva speța. E util însă pe viitor să pot folosi JSON.

 

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>

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

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

int wait = 70; // In milliseconds
int spacer = 1;
int width  = 5 + spacer; // The font width is 5 pixels
int m;
int ti, ti_c, ti_cr; // folosite la afisarea temp si umid pe displayul local LED
int hi;
int pinCS = D4; 
int numberOfHorizontalDisplays = 6;
int numberOfVerticalDisplays   = 1;
char tasmota_message[150];
char temp_value[6];

Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

//ruleaza un text de la dreapta la stanga
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);
  client.loop();
  }
}

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 == "tele/%cameramica%/SENSOR") {
    for (int i = 0; i < length; i++) {
      tasmota_message[i] = payload[i];
    }
  }
  temp_value[0] = tasmota_message[75];
  temp_value[1] = tasmota_message[76];
  temp_value[2] = tasmota_message[77];
  temp_value[3] = tasmota_message[78];
  temp_value[4] = tasmota_message[93];
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "camera-mica";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str() , "x_dadu", "Pecineaga1" )) {
      Serial.println("subscribed and connected"); 
      client.subscribe("tele/%cameramica%/SENSOR");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void verificari(){
client.loop(); 
}

//face delay din bucati de 100ms, intre care face alte verificari
void diy_wait_ms (int timp){
  client.loop(); 
  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
  }  
}


void setup() {
  Serial.begin(115200);
  matrix.setIntensity(1); // 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);
}

 
void loop() {
  
  if (!client.connected()) { reconnect(); }
  client.loop();

  matrix.fillScreen(LOW);
  matrix.write();
  display_message(temp_value);
  diy_wait_ms(1000);
  client.loop();
}

 

Link spre comentariu
  • Răspunsuri 4
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

Top autori în acest subiect

E foarte sinmplu cu ArduinoJson, intrii aici pe assistant dai copy paste la Json-ul tau sa iti da codul gata facut

https://arduinojson.org/v7/assistant/#/step1

 

// Stream& input;

JsonDocument doc;

DeserializationError error = deserializeJson(doc, input);

if (error) {
  Serial.print("deserializeJson() failed: ");
  Serial.println(error.c_str());
  return;
}

const char* Time = doc["Time"]; // "2024-02-21T19:03:02"

const char* DS18B20_Id = doc["DS18B20"]["Id"]; // "0417315443FF"
float DS18B20_Temperature = doc["DS18B20"]["Temperature"]; // 24.4

const char* TempUnit = doc["TempUnit"]; // "C"

 

Editat de Bandi Szasz
Link spre comentariu

Vă salut și vă mulțumesc. Da merge codul generat pe siteul respectiv. Am bâjbâit un pic până am pus componentele codului unde trebuie, unele declarări de variabile sau constante la început în afara funcțiilor ca să fie globale să le pot accesa în loop(). În setup() nu am mai pus nimic, majoritatea liniilor de cod le am în funcția callback. Am modificat acum unu din ceasurile mele și afișez una din temperaturile a 3 senzori în paralel, extrăgând doar obiectul respectiv, în cazul meu cu: 

JsonObject ds18b20 = doc["DS18B20-1"];

 

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