Questo post integra il post precedente. Descrive un sensore di temperatura con ESP8266 che invia la temperatura corrente al termometro presentato nell'ultimo articolo ogni cinque minuti. Nella pausa tra due misurazioni, l'ESP8266 viene messo in modalità di sonno profondo in cui quasi non consuma energia. Il protocollo ESP Now viene utilizzato per inviare i dati, che inviano i dati direttamente all'indirizzo MAC del termometro senza la necessità di impostare una connessione.
Lo usiamo Modulo ESP8266-E12 con adattatore, perché contrariamente al modulo ESP8266-01 questo ha portato al perno di riattivazione GPIO-16 e non ha LED permanentemente accesi sulla tensione di alimentazione. Abbiamo bisogno del perno di riattivazione per il sonno profondo e il LED di alimentazione utilizza solo energia inutilmente.
circuito:
Il filo arancione collega il perno di attivazione all'ingresso di ripristino e garantisce che il modulo venga riavviato al termine dell'interruzione del sonno. Il sensore è collegato al GPIO2 (filo bianco).
Per caricare il programma è necessario un adattatore FDTI per programmare ESP8266 tramite l'interfaccia seriale.
Colleghiamo l'adattatore FDTI con il connettore GND e TX con RX e RX con TX. Inoltre, il Flash Pin GPIO 0 deve essere collegato a terra (filo verde) in modo che ESP8266 passi in modalità di programmazione.
Il filo verde deve essere rimosso dopo la programmazione. Se DEBUG era impostato su true nello schizzo, i messaggi del modulo possono essere tracciati tramite l'interfaccia seriale.
Attenzione: Una fornitura di ESP8266 da parte della scheda FDTI provoca arresti anomali quando viene chiamata la funzione scanNetwork perché il consumo corrente è quindi troppo elevato.
Sketch:
Per compilare la scheda
regolare !!
/* Sensore di temperatura WLAN ESP Ora con il termometro Se nessun indirizzo MAC è stato ancora determinato il sensore è alla ricerca di una WLAN con termometro SSID Quando trova l'AP, si ricorda l'indirizzo MAC purché l'alimentazione non sia stata interrotta Il protocollo ESP Now è molto veloce, quindi solo un tempo molto breve (noi) flussi di corrente più elevati. Il sensore invia i dati di temperatura e quindi entra per 5 minuti Sonno profondo in modo che venga utilizzata pochissima energia e quello Il sensore può quindi funzionare con batterie. */ // libreria per WiFi #include <ESP8266WiFi.B> // Librerie per sensore di temperatura DS18B20 #include <OneWire.B> // Libreria per ESP Now #include <Dallas Temperatura.B> esterno "C" { #include <espnow.B> } // Flag di debug se false vengono soppressi tutti i messaggi di debug // per risparmiare elettricità aggiuntiva #define DEBUG vero // Costanti per WiFi #define WIFI_CHANNEL 1 #define send_timeout 2450 // Timeout di 245 millisecondi // Pin per sensore di temperatura const byte autobus = 2;// pin GPIO2 // Struttura dei dati per lo scambio di dati struct DATEN_STRUKTUR { galleggiante Temp = 0; }; // Struttura dei dati per la memoria RTC con checksum per validità // controlla che l'indirizzo MAC sia salvato struct DATI DI MEMORIA { uint32_t crc32; uint8_t mac[6]; }; // Dati globali volatile bool callbackCalled; DATI DI MEMORIA statinfo; OneWire OneWire(autobus); Dallas Temperatura sensori(&OneWire); // array per memorizzare gli indirizzi dei sensori Indirizzo dispositivo indirizzi; // Sottoprogramma per il calcolo del checksum uint32_t calculateCRC32(const uint8_t *dati, size_t lunghezza) { uint32_t crc = 0xffffffff; mentre (lunghezza--) { uint8_t c = *dati++; per (uint32_t io = 0x80; io > 0; io >>= 1) { bool po ' = crc & 0x80000000; se (c & io) { po ' = !po '; } crc <<= 1; se (po ') { crc ^= 0x04c11db7; } } } ritorno crc; } // Scrive la struttura dei dati statinfo con il checksum corretto nella memoria RTC vuoto UpdateRtcMemory() { uint32_t crcOfData = calculateCRC32(((uint8_t*) &statinfo) + 4, taglia di(statinfo) - 4); statinfo.crc32 = crcOfData; ESP.rtcUserMemoryWrite(0,(uint32_t*) &statinfo, taglia di(statinfo)); } // sucht nach einem geeigneten AccessPoint vuoto ScanForSlave() { bool slaveFound = 0; int8_t scanResults = Wi-Fi.scanNetworks(); // ripristina su ogni scansione Se (DEBUG) Seriale.println("Scansione eseguita"); Se (scanResults == 0) { Se (DEBUG) Seriale.println("Nessun dispositivo WiFi trovato in modalità AP"); } altro { Se (DEBUG) Seriale.Stampa("Trovato "); Se (DEBUG) Seriale.Stampa(scanResults); Se (DEBUG) Seriale.println(" dispositivi "); per (int io = 0; io < scanResults; ++io) { // Stampa SSID e RSSI per ogni dispositivo trovato Corda SSID = Wi-Fi.SSID(io); int32_t RSSI = Wi-Fi.RSSI(io); Corda BSSIDstr = Wi-Fi.BSSIDstr(io); Se (DEBUG) { Seriale.Stampa(io + 1); Seriale.Stampa(": "); Seriale.Stampa(SSID); Seriale.Stampa(" ("); Seriale.Stampa(RSSI); Seriale.Stampa(")"); Seriale.println(""); } ritardo(10); // Controlla se il dispositivo corrente inizia con "Termometro" Se (SSID.indice di("Termometro") == 0) { // SSID di interesse Se (DEBUG) { Seriale.println("Trovato uno schiavo."); Seriale.Stampa(io + 1); Seriale.Stampa(": "); Seriale.Stampa(SSID); Seriale.Stampa(" ["); Seriale.Stampa(BSSIDstr); Seriale.Stampa("]"); Seriale.Stampa(" ("); Seriale.Stampa(RSSI); Seriale.Stampa(")"); Seriale.println(""); } int Mac[6]; // wir ermitteln die MAC Adresse und speichern sie im RTC Memory Se ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x%c", &Mac[0], &Mac[1], &Mac[2], &Mac[3], &Mac[4], &Mac[5] ) ) { per (int ii = 0; ii < 6; ++ii ) { statinfo.Mac[ii] = (uint8_t) Mac[ii]; } UpdateRtcMemory(); } slaveFound = 1; // Nachdem der AP gefunden wurde können wir abbrechen rompere; } } } Se (DEBUG) { Se (slaveFound) { Seriale.println("Slave Found, processing .."); } altro { Seriale.println("Slave Not Found, riprovando."); } } // RAM freigeben Wi-Fi.scanDelete(); } // function um eine Sensoradresse zu drucken vuoto printAddress(DeviceAddress Adressen) { per (uint8_t io = 0; io < 8; io++) { Se (Adressen[io] < 16) Seriale.Stampa("0"); Seriale.Stampa(Adressen[io], ESADECIMALE); } } vuoto impostare() { Se (DEBUG) { Seriale.inizio(115200); Seriale.println("Inizio"); } pinMode(autobus,INPUT_PULLUP); // Wir ermitteln die Anzah der Sensoren am Eindraht-Bus Sensori.inizio(); Se (DEBUG) { Seriale.Stampa(Sensori.getDeviceCount(), Dicembre); Seriale.println("Sensoren gefunden."); } // Nun prüfen wir ob einer der Sensoren am Bus ein Temperatureatur Sensor ist Se (!Sensori.getAddress(Adressen,0)) { Se (DEBUG) Seriale.println("Kein Temperatursensor vorhanden!"); } // adressen anzeigen Se (DEBUG) { Seriale.Stampa("Indirizzo:"); printAddress(Adressen); Seriale.println(); } // Nun setzen wir noch die gewünschte Auflösung (9, 10, 11 o 12 bit) Sensori.setResolution(Adressen,10); // Zur Kontrolle les wir den Wert wieder aus Se (DEBUG) { Seriale.Stampa("Auflösung ="); Seriale.Stampa(Sensori.getResolution(Adressen), dicembre); Seriale.println(); } Sensori.requestTemperatures(); // Commando um die Temperaturen auszulesen // Wir lesen aus dem RTC Memory ESP.rtcUserMemoryRead(0, (uint32_t*) &statinfo, taglia di(statinfo)); Se (DEBUG) Seriale.println("RTC Fatto"); uint32_t crcOfData = calculateCRC32(((uint8_t*) &statinfo) + 4, taglia di(statinfo) - 4); Wi-Fi.modalità(WIFI_STA); // Modalità stazione per nodo sensore esp-now Se (DEBUG) Seriale.println("WifiMode"); Se (statinfo.crc32 != crcOfData) { // wir haben keine gültige MAC Adresse Se (DEBUG) Seriale.println("Scan vor Slave"); ScanForSlave(); Se (DEBUG) { Seriale.printf("Questo mac:% s", Wi-Fi.indirizzo MAC().c_str()); Seriale.printf("mac target:% 02x% 02x% 02x% 02x% 02x% 02x", statinfo.Mac[0], statinfo.Mac[1], statinfo.Mac[2], statinfo.Mac[3], statinfo.Mac[4], statinfo.Mac[5]); Seriale.printf(", canale:% i \ n", WIFI_CHANNEL); } } Se (esp_now_init() != 0) { Se (DEBUG) Seriale.println("*** Init ESP_Now non riuscito"); ESP.ricomincia(); } // Controller ESP Now esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); // Initisieren Peer Daten esp_now_add_peer(statinfo.Mac, ESP_NOW_ROLE_SLAVE, WIFI_CHANNEL, NULLO, 0); // wir registrieren die Funktion, die nach dem Senden aufgerufen werden soll esp_now_register_send_cb([](uint8_t* Mac, uint8_t sendStatus) { Se (DEBUG) { Seriale.Stampa("send_cb, status ="); Seriale.Stampa(sendStatus); Seriale.Stampa(", per mac:"); carbonizzare macString[50] = {0}; sprintf(macString,"% 02X:% 02X:% 02X:% 02X:% 02X:% 02X", statinfo.Mac[0], statinfo.Mac[1], statinfo.Mac[2], statinfo.Mac[3], statinfo.Mac[4], statinfo.Mac[5]); Seriale.println(macString); } callbackCalled = vero; }); // Flag auf false setzen callbackCalled = falso; // Temperaturmessung starten Sensori.requestTemperatures(); ritardo(750); // 750 ms warten bis die Messung fertig ist // Temperaturwert holen und in Satenstruktur zum Senden speichern DATEN_STRUKTUR dati; dati.Temp = Sensori.getTempC(Adressen); uint8_t bs[taglia di(dati)]; // Datenstruktur in den Sendebuffer kopieren memcpy(bs, &dati, taglia di(dati)); // Invia un termometro inviato esp_now_send(NULLO, bs, taglia di(dati)); // NULL significa inviare a tutti i peer Se (DEBUG) { Seriale.Stampa("Temperatur:"); Seriale.Stampa(dati.Temp); Seriale.println("° C"); } } vuoto ciclo continuo() { // warten bis Daten gesendet wurden Se (callbackCalled || (millis() > send_timeout)) { Se (DEBUG) Seriale.println("Dormire"); ritardo(100); // Per 300 Sekunden in den Tiefschlafmodus // dann erfolgt ein Reset und der ESP8266 wird neu gestartet // Daten im RTC Memory werden beim Reset nicht gelöscht. ESP.sonno profondo(300E6); } }
Testen:
Nachdem das Modul mit Strom versorgt wurde kennt es noch keine gültige MAC-Indirizzo dei termometri. Es versucht ein offenes Netzwerk mit der SSID "Thermometer" zu finden. Da das Thermometer etwa fünf Minuten nach dem Start seine SSID versteckt, müssen wir einen Neustart des Thermometers auslösen. Nun sollte das Sensor Modul das Thermometer finden und alle fünf Minuten den aktuellen Temperaturwert übermitteln. Das Thermometer sollte abwechselnd die lokale Temperatur (Häuschen Symbol) und die Temperatur vom Sensor Modul (Baum Symbol) anzeigen.
5 commenti
esp tester
Tolles Projekt!
Peter
Wie weit können die Module denn voneinander entfernt sein?
Peter
Tolles Projekt! Ist es möglich mehrere entfernte Module zu betreiben?
Viele Grüße Peter
Carsten Jürges
Wenn kein “Thermometer” gefunden wird, landet irgendeine MAC-Adresse in statinfo und das war’s dann erstmal. Daher habe ich Funktion DeleteRtcMemory spendiert, den CRC-Wert “zerstört”. Diese Funktionen wird aufgerufen, wenn das Senden nicht erfolgreich (sendStatus) war …
Dann gibt es beim nächsten Start einen neuen Verbindungsversuch …
Jörg
Super, genau so etwas habe ich gesucht.
Vielen Dank für die interessanten Projektvorstellungen.