ESP un centro 4 periferiche

Buongiorno a tutti,
ho interfacciato un esp12 con un esp8266 generico con la configurazione AP->Client e tutto va bene, leggo i dati raccolti da AP quando mi collego come client e li metto a TFT correttamente con il sistema trasmetti message ma.. sto cercando di fare di piu' e qui il mio problema : vorrei avere un centro che raccoglie i dati di 4 periferiche (sensori) e non so che configurazione scegliere, se qualcuno mi da un suggerimento (non troppo complicato) provo a tradurlo in software.
Grazie

Non è molto chiara la tua richiesta, ad ogni modo trattandosi di MCU tutte delle stessa famiglia, credo che la soluzione più efficace sia quella di usare il protocollo ESP-NOW proprietario di Espresif per i suoi device.

Trovi molta documentazione online

Buongiorno cotestant,
grazie per la segnalazione, mi spaventa un pò riprendere ad inparare un modo di colloquiare nuovo ma ci provero'.
Con il sistema Ap-Client o server qualcosa ho imparato e mi arrangicchio, volevo fare una cosa semplice come in figura che allego, ma nella mia minima conoscenza non so se sia possibile senza appoggiarsi alla rete di casa.
Mi sapresti dare un consiglio al di fuori del protocollo ESP-NOW?
grazie

Questa sembra proprio la tipica situazione per cui è stato sviluppato il protocollo ESP-NOW

Ad ogni modo, puoi arrivare agli stessi obiettivi anche con altri sistemi.

Tu parti di "AP client", si ma client di cosa? Quale protocollo stai usando? Copio/incollo parte di una risposta di qualche tempo fa:

Quindi ricapitolando quando metti il NodeMCU in Access Point mode, stai fornendo una "connessione" alla rete wireless di tipo hardware agli altri dispositivi (ESP-NOW lavora più o meno a quel livello), che sia connessa ad internet o meno è di secondaria importanza.

A questo punto devi decidere che tipo di comunicazioni vuoi implementare su questo mezzo di trasmissione. In rete troverai una gran quantità di "tutorial" e sono quasi certo che il 90% di essi ti mostrerà come implementare una connessione HTTP client/server.

Se va bene o meno per i tuoi scopi sta a te deciderlo: ad esempio il protocollo HTTP prevede che il server risponda al client solo a seguito di una richiesta e non il contrario.
Ad occhio e croce direi che va bene per le tue esigenze; il client ogni tot fa una connessione al server inviando i dati aggiornati, chiusura della connessione e fine. Ma se un giorno avrai l'esigenza di dover invertire il flusso di informazioni, il protocollo in questione è inadeguato.

Grazie della risposta esaustiva, mi ha indirizzato ad un tipo di realizzazione che posso fare, qualcosina ho gia fatto con HTTP.
Ieri , visto che sono un tipo curioso, ho letto un pò del protocollo ESP-NOW e ho provato ad installare un esempio con le sue librerie esp-now-master.
Su ESP32 viene installato correttamente (ne avevo solo 1 a disposizione) mentre su esp8266 si rifiuta e mi da' errore .
A parte la curiosità di capite come mai , sabato dovrebbero arrivarmi 2 ESP32 e continuero' con le prove, difficile che io mi dia per vinto :slight_smile:
grazie,
Arrigo

[/quote]
il client ogni tot fa una connessione al server inviando i dati aggiornati, chiusura della connessione e fine
[/quote]
Questo l'ho gia' fatto: ESP lolin 12E come server con scrittura su TFT ili 9341 e Cient esp8266 configurato AP per creare una rete propria che invia dati contattando il server
Per me lo scoglio e' rappresentato dal fatto che volevo piu' periferiche come ho letto sarebbe semplice con ESP-NOW, vedro' cosa riesco a fare dopo l'arrivo degli ESP32

Buonasera,
oggi ho potuto dedicarmi al mio progettino e debbo ringraziare mooolto cotestatnt perche' complice la mia testa dura e la perseveranza ho scovato in rete questo articolo che tratta proprio degli esp8266 con protocollo ESP-NOW con tanto di spiegazione dettagliata ed esempio, una manna, provato e.... funziona tutto !!!.
quindi per me il problema è risolto ma... non so come mettere risolto al post :slight_smile:
Grazie

Dovresti avere un qualcosa simile ad un check da "attivare" sul post che consideri risolutivo...

Mi sa che ho bisogno ancora di aiuto, funziona tutto ma la scheda TX ogni tanto da i numeri, nel vero senso della parola, puo' essere che la frequenza o la velocità di interrogazione dei sensori esterni sia critica? metto la figura del risultato con l'errore; al limite adesso potrei intercettare l'errore e spedire ad esempio T=0 e U=0 e sarebbe evidente l'errore senza quella scritta enorme.
Qalche suggerimento? Grazie

So che la foto e' pietosa ma e' un circuito buttato li per provare l'ESP-NOW
Chiedo comprensione !! :slight_smile: :crazy_face:

Metti lo sketch completo perché così è difficile azzardare un'ipotesi.

Fai qualche verifica di correttezza/coerenza dei dati ricevuti?

Si hai ragione ma la fretta...

/*
  Scheda TX trasmissione dati configurazione tanti a uno
  ricordare di assegnare correttamente BOARD_ID   */
#include <ESP8266WiFi.h>
#include <espnow.h>
#include "Adafruit_Sensor.h"
#include "Adafruit_AM2320.h"
Adafruit_AM2320 am2320 = Adafruit_AM2320();

//inserire il MAC Address della scheda ricevente
uint8_t broadcastAddress[] = {0x5C, 0xCF, 0x7F, 0x23, 0xF0, 0xAB};

// Setto scheda ID (ESP Sender #1 = BOARD_ID 1, ESP Sender #2 = BOARD_ID 2, ecc)
#define BOARD_ID 2  //BALCONE OVE ST                                                                                                          
// la struttura per TX trasmissione dati
// deve corrispondere alla struttura del RX
typedef struct struct_message {
  int id; int x; int y;
} struct_message;
// Creare una struct_message chiamata test
//per memorizzare le variabili da inviare
struct_message myData;
//ritardo tra un invio e l'altro
unsigned long lastTime = 0;
unsigned long timerDelay = 10000;
int T;
int H;
// Callback quando i dati vengono inviati
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
  Serial.print("\r\nStato dell'ultimo pacchetto inviato: ");
  if (sendStatus == 0) {
    Serial.println("Consegna ok");
  }
  else {
    Serial.println("Consegna fallita");
  }
}

void setup() {
  // inizializzo la seriale
  Serial.begin(115200);
  // Setto il device come una stazione Wi-Fi
  am2320.begin();
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  // Inizializzo ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Errore inizializzazione ESP-NOW");
    return;
  }
  // Setto il ruolo di ESP-NOW
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  //Quando ESP-NOW avviato con successo effettuiamo la registrazione
  // per Send_cb per ottenere lo stato del pacchetto trasmesso
  esp_now_register_send_cb(OnDataSent);
  // Registro peer
  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
}

void loop() {
  T = (am2320.readTemperature() - 3);
  H = (am2320.readHumidity() + 8);
  if ((millis() - lastTime) > timerDelay) {
    // Imposto i valori da trasmettere
    myData.id = BOARD_ID;
    myData.x = T;
    myData.y = H;
    // invio il messaggio via ESP-NOW
    esp_now_send(0, (uint8_t *) &myData, sizeof(myData));
    lastTime = millis();
  }
}

Ho utilizzato un esempio molto scarno di Rui Santos aggiungendo/modificando per quello che mi serviva.
Non ho fatto nulla per il controllo errore, pensavo fare due o tre letture, tenere buone quelle inferiore a 100 e fare la media ,ma mi sono accorto che in situazioni particolari disturbi ecc l'errore fotografato si presenta persistente magari per vari minuti, da li il sospetto di aver generato un errore di programmazione
Grazie dell'aiuto

Per completezza aggiungo anche il programma scheda RX sempre con ESP

/*ESP8266_esp_now_RX con sensore BMP280
*/
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include "Adafruit_Sensor.h"
#include "Adafruit_AM2320.h"
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <espnow.h>
#include <BME280I2C.h>
#define P0 1013.25
#define TFT_DC 2
#define TFT_CS 15
#define SDA 4
#define SCL 5
int tmp2;
Adafruit_AM2320 am2320 = Adafruit_AM2320();
BME280I2C bme;    // Default : forced mode, standby time = 1000 ms
// Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off,
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// struttura per ricezione dati
typedef struct struct_message {
  int id; int x; int y;
} struct_message;
// Creo struct_message chiamato myData
struct_message myData;
// Creo la struttura per leggere i dati di ogni scheda
struct_message board1;
struct_message board2;
//Creo un array con tutte le strutture
struct_message boardsStruct[2] = {board1, board2};

// Funzione di callback che verrà eseguita quando i dati vengono ricevuti
void OnDataRecv(uint8_t * mac_addr, uint8_t *incomingData, uint8_t len) {
  char macStr[18];
  Serial.print("Dati ricevuti da : ");
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  Serial.println(macStr); Serial.println();
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.printf("Board ID %u: %u bytes\n", myData.id, len);
  //Aggiorno le strutture con i nuovi dati in arrivo
  boardsStruct[myData.id - 1].x = myData.x;
  boardsStruct[myData.id - 1].y = myData.y;
  Serial.printf("x value: %d \n", boardsStruct[myData.id - 1].x);
  Serial.printf("y value: %d \n", boardsStruct[myData.id - 1].y);
  Serial.println();
}

void setup() {
  // Initializzo la Seriale
  Serial.begin(115200);
  Wire.begin();
  bme.begin();
  am2320.begin();
  switch (bme.chipModel())
  {
    case BME280::ChipModel_BME280:
      Serial.println("Trovato il sensore BME280! OK.");
      break;
    case BME280::ChipModel_BMP280:
      Serial.println("Trovato il sensore BME280! Non è disponibile Humidity ");
      break;
    default:
      Serial.println("Sensore NON riconosciuto! Errore!");
  }
  tft.begin();
  Serial.println();
  tft.fillScreen(ILI9341_WHITE);
  tft.setRotation(3);
  tft.setCursor(20, 50);
  tft.setTextColor(ILI9341_BLUE);
  tft.setTextSize(2); tft.println("Inizializzazione\n");
  Serial.println();
  Serial.println("Inizializzo ESP-NOW");
  // Imposta il dispositivo come stazione Wi-Fi
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  // Inizializza ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Errore inizializzando ESP-NOW");
    tft.setTextColor(ILI9341_RED);
    tft.setCursor(20, 90);
    tft.setTextSize(3); tft.println("ESP_NOW KO!");
    return;
  }
  // se ESPNow avviato con successo, si registra per
  // ottenere informazioni sul packer recv
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
  tft.setTextColor(ILI9341_RED);
  tft.setCursor(20, 90);
  tft.setTextSize(3); tft.println("ESP_NOW OK");
  delay(3000);
  tft.setCursor(20, 130);
  tft.setTextColor(ILI9341_BLUE);
  tft.setTextSize(2); tft.println("Fine Setup\n");
  tft.setTextColor(ILI9341_WHITE);
  Serial.println("Fine setup");

}

void loop() {
  delay(15000);
  tft.fillScreen(ILI9341_BLACK);
  printBME280Data(&Serial);
  delay(500);
  tft.setTextColor(ILI9341_GREEN);
  tft.setCursor(20, 30);
  tft.print("-----------------------");
  int Ti = (am2320.readTemperature() - 3);
  int Hi = (am2320.readHumidity() + 8);
  tft.setTextColor(ILI9341_BLUE);
  tft.setCursor(20, 50); tft.println("Interno");
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(20, 80);
  //tft.print("Temp. "); tft.print(tmp2); tft.print("^C");
  tft.print("Temp. "); tft.print(Ti); tft.print("^C");
  tft.setCursor(165, 80);
  tft.print("Umid. "); tft.print(Hi); tft.print("%");
  tft.setTextColor(ILI9341_GREEN);
  tft.setCursor(20, 100);
  tft.print("-----------------------");
  delay(1000);
  // Accedere alle variabili per scheda1
  int board1X = boardsStruct[0].x;
  int board1Y = boardsStruct[0].y;
  tft.setTextColor(ILI9341_BLUE);
  tft.setCursor(20, 120); tft.println("Balcone Est");
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(20, 150);
  tft.print("Temp. "); tft.print(board1X); tft.print("^C");
  tft.setCursor(165, 150);
  tft.print("Umid. "); tft.print(board1Y); tft.print("%");
  tft.setTextColor(ILI9341_GREEN);
  tft.setCursor(20, 170);
  tft.print("-----------------------");
  delay(1000);
  //Accedere alle variabili per scheda2
  int board2X = boardsStruct[1].x;
  int board2Y = boardsStruct[1].y;
  tft.setTextColor(ILI9341_BLUE);
  tft.setCursor(20, 190); tft.print("Balcone Ovest");
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(20, 220);
  tft.print("Temp. "); tft.print(board2X); tft.print("^C");
  tft.setCursor(165, 220);
  tft.print("Umid. "); tft.print(board2Y); tft.print("%");
delay(1000);
}

void printBME280Data(Stream* client) {
  float temp(NAN), hum(NAN), pres(NAN);
  BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
  BME280::PresUnit presUnit(BME280::PresUnit_Pa);
  bme.read(pres, temp, hum, tempUnit, presUnit);
  delay(300);
  client->print("Temp: ");
  client->print(temp);
   client->print("°" + String(tempUnit == BME280::TempUnit_Celsius ? 'C' : 'F'));
  client->print("\t\tHumidity: ");
  client->print(hum);
  client->print("% RH");
  client->print("\t\tPressure: ");
  client->print(pres);
  int  pres2 = (pres / 100) + 55;
  client->println("Pa");
  tft.setTextColor(ILI9341_RED);
  tft.setCursor(20, 10);
  tft.print("Pressione rel. "); tft.print(pres2); tft.print(" hPa");
  delay(1000);
}

risulta un po pesante perchè specie la parte gestione TFT è stata scritta al volo senza badare a ripetizioni, sicuramente potrebbe essere riscritto più in modo piu' conciso,
grazie per eventuali suggerimenti

Ho dato un'occhiata più approfondita al protocollo ESP-NOW ed in teoria ogni pacchetto di dati inviato contiene al suo interno 4 byte FCS (Frame Check Sequence Checks) quindi mi aspetto che quando la funzione di callback viene eseguita, tutti i dati ricevuti sono corretti perché i byte FCS sono come ci si aspetta.

In realtà, googlando un po' ho trovato qualche issue dove alcuni utenti segnalano che i messaggi con FCS non corretto vengono presi per buoni lo stesso, cosa che potrebbe spiegare il problema che hai riscontrato.

Potrebbe però essere anche la libreria Adafruit_AM2320 che ogni tanto ti ritorna alcuni valori sballati: io aggiungerei come prima cosa qualche println() di debug sui valori che leggi prima di inviare il pacchetto cosi da verificare questa ipotesi.

In ricezione puoi facilmente controllare se i valori che ricevi sono coerenti in quanto si tratta di temperatura ed umidità ambientali, grandezze che non possono assumere chissà quali valori nel mondo reale (ad esempio: temperatura -40/60°C, umidità 0/100%)

Un ulteriore step potrebbe essere quello di aggiungere un tuo checksum "interno" alla struttura che calcoli con uno dei classici algoritmi CRC8/CRC16 nel caso quanto segnalato nella issue sia effettivamente vero.

Ho controllato e l'errore viene generato proprio nel modulo TX , pensavo ad un errore dovuto ad alimentazione, interferenze e qualsiasi altra diavoleria che influisca sull'elettronica e quindi ho portato tutto qui sulla scrivania con tensione da alimentatore da laboratorio; risultato: ogni tanto il modulo Tx genera questa serie numerica sempre uguale e senza senso (per me)

Stato dell'ultimo pacchetto inviato: Consegna ok
x= 18  y= 33
Stato dell'ultimo pacchetto inviato: Consegna ok
x= 18  y= 2147483647
Stato dell'ultimo pacchetto inviato: Consegna ok
x= 18  y= 33

questo sia per i valori x che y dove x=temperatura y= umidità rilevati da AM2320
ad essere sincero dopo che ho inserito la stringa di controllo dati mi sembra meno frequente mha....

void loop() {
  T = (am2320.readTemperature() - 3);
  H = (am2320.readHumidity() + 8);
  if ((millis() - lastTime) > timerDelay) {
    // Imposto i valori da trasmettere
    myData.id = BOARD_ID;
    myData.x = T;
    myData.y = H;
    // invio il messaggio via ESP-NOW
   esp_now_send(0, (uint8_t *) &myData, sizeof(myData));
    Serial.print("x= "); Serial.print(T); Serial.print( "  y= "); Serial.println(H);
    lastTime = millis();
  }
}

pensavo di intercettare il valore prima di metterlo a display e se uno o entrambi sbagliati (giustamente hai detto sono in un range noto) mettere a disply due valori zero, volevo scrivere Error ma non ci riesco
qualche consiglio?
Grazie per il supporto costante e le dritte !!

Secondo me ti conviene aggiornare la variabile che poi stampi sul display solo quando il valore è corretto. Inoltre leggi quei valori con una frequenza eccessiva: una volta al secondo per grandezze come temperature e umidità è anche troppo...

void loop() {
  static uint32_t aTime;
  if (millis() - aTime > 1000) {
    aTime = millis();
    float temp = (am2320.readTemperature() - 3);
    float hum = (am2320.readHumidity() + 8);
    if (temp >= -40.0 && temp <= 60.0) {
      T = temp;
    }
    if (hum >= 0.0 && hum <= 100.0) {
      H = hum;
    }
}

 
  if ((millis() - lastTime) > timerDelay) {
    // Imposto i valori da trasmettere
    myData.id = BOARD_ID;
    myData.x = T;
    myData.y = H;
    // invio il messaggio via ESP-NOW
    esp_now_send(0, (uint8_t *) &myData, sizeof(myData));
    lastTime = millis();
  }
}

Gentile come sempre ! grazie per il pezzo di software, io intanto oggi mi sono ritagliato un'oretta e ho fatto delle prove e ho "scoperto" che è il mio software che genera quel numeraccio infatti ho provato a caricare un TX su un ESP8266 "nudo" e alla seriale arriva questo

Stato dell'ultimo pacchetto inviato: Consegna ok
x= 2147483647  y= 2147483647

Stato dell'ultimo pacchetto inviato: Consegna ok
x= 2147483647  y= 2147483647

la routine di lettura quando non trova nulla da' quel numero quindi dovrei risalire a come lavora la libreria di Adafruit? pensavo anche di cercare altre librerie per fare una comparazione, pensi sia utile? non è che io sia esperto e non vorrei fare piu' danni che trovare cose utili .
Per la ricezione per eliminare quel numeraccio ho fatto semplicemente così

  //Accedere alle variabili per scheda2
  int board2X = boardsStruct[1].x;
  int board2Y = (boardsStruct[1].y+8);
  int T2 = board2X;
  int H2 = board2Y;
  if ((T2 > 100 ) || (H2 > 100)) {
    board2X = 0;
    board2Y = 0;
  };

non è molto elegante ma almeno mi scrive 0-0

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