Oltre ad altre piccole estensioni, vorrei presentare oggi un altro dispositivo remoto che fornisce valori misurati dai sensori I2C BMP280 e / o BME280 al nostro centro casa intelligente.
Il circuito si basa su a D1 Mini e i sensori BMP280 e BME280, Poiché questi sensori possono avere un indirizzo I2C di 0X77 o 0X76, il programma scopre automaticamente quale sensore è stato collegato a quale indirizzo. Senza modifiche fornite da AZ Delivery, il BMP280 ha l'indirizzo 0X77 e il BME 280 l'indirizzo 0X76.
Il circuito è molto semplice. L'orologio I2C è collegato a D1 di D1 Mini e la linea dati a D2 di D1 Mini. Con BMP280, la linea Chipselect deve essere collegata a 3,3 V in modo che BMP280 si avvii in modalità I2C. Sul D1 Mini colleghiamo l'ingresso RESET al pin D0 (filo viola). Il programma mette l'ESP8266 in modalità di sospensione profonda al termine del lavoro. Questa connessione riattiva ESP8266 dopo il tempo impostato. Questa connessione deve essere rimossa per il lampeggiamento.
Sketch:
/* Sensore di pressione WLAN BMP280 eo BME280 ESP Ora su ArduiTouch SmartHome Se il dispositivo non ha un indirizzo MAC del server valido verrà effettuata una ricerca per trovare una WLAN con SSID ATSmartHome L'indirizzo MAC del server verrà salvato fino a quando l'alimentazione non verrà interrotto. Il protocollo ESP Now è molto veloce, quindi sarà la corrente più alta per la rete consumato solo per un breve periodo (noi). Dopo aver inviato i valori, il dispositivo passa per cinque minuti in modalità di sospensione profonda con un consumo energetico molto basso. */ // libreria per WiFi #include <ESP8266WiFi.B> // librerie per usare BMP280 e BME280 #include <Adafruit_Sensor.B> #include <Adafruit_BME280.B> #include <Adafruit_BMP280.B> // libreria per il protocollo di messaggio utilizzato #include "AT_MessageBuffer.h" // libreria per ESP Now esterno "C" { #include <espnow.B> } // SSID da cercare #define GW_SSID "ATSmartHome" // flag per attivare i messaggi di debug #define DEBUG vero #define send_timeout 2000 // timeout di 2 secondi // definisce i canali per i due sensori #define CHANNEL_TEMP_BME 0 #define CHANNEL_PRESS_BME 1 #define CHANNEL_ALT_BME 2 #define CHANNEL_HUM_BME 3 #define CHANNEL_TEMP_BMP 4 #define CHANNEL_PRESS_BMP 5 #define CHANNEL_ALT_BMP 6 #define SEALEVELPRESSURE_HPA (1013.25) // Struttura dei dati per salvare l'indirizzo MAC del server // e un checksum nella memoria RTC struct DATI DI MEMORIA { uint32_t crc32; // checksum per la convalida uint8_t mac[6]; }; // Variabili globali volatile bool callbackCalled; booleano hasBme = 0; booleano hasBmp = 0; // Indirizzo MAC e canale WLAN DATI DI MEMORIA statinfo; AT_MessageBuffer msg; Adafruit_BME280 bme; // I2C Adafruit_BMP280 bmp; // I2C // funzione per calcolare il 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 MAC MAC e checksum nella memoria RTC vuoto UpdateRtcMemory() { uint32_t crcOfData = calculateCRC32(((uint8_t*) &statinfo) + 4, sizeof(statinfo) - 4); statinfo.crc32 = crcOfData; ESP.rtcUserMemoryWrite(0,(uint32_t*) &statinfo, sizeof(statinfo)); } // cerca il punto di accesso vuoto ScanForSlave() { bool schiavo TROVATO = 0; int8_t risultati della scansione = WiFi.reti di scansione(); // ripristina su ogni scansione se (DEBUG) serial.println("Scansione eseguita"); se (risultati della scansione == 0) { se (DEBUG) serial.println("Nessun dispositivo WiFi trovato in modalità AP"); } altro { se (DEBUG) serial.stampare("Trovato"); se (DEBUG) Seriale.Stampare(scanResults); Se (DEBUG) Seriale.println(" dispositivi "); Per (Int Ho = 0; Ho < scanResults; ++Ho) { Stampa SSID e RSSI per ogni dispositivo trovato Stringa Ssid = Wifi.Ssid(Ho); int32_t Rssi = Wifi.Rssi(Ho); int32_t Chl = Wifi.Canale(Ho); Stringa BSSIDstr = Wifi.BSSIDstr(Ho); Se (DEBUG) { Seriale.Stampare(Ho + 1); Seriale.Stampare(": "); Seriale.Stampare(Ssid); Seriale.Stampare(" /"); Seriale.Stampare(Chl); Seriale.Stampare(" ("); Seriale.Stampare(Rssi); Seriale.Stampare(")"); Seriale.println(""); } Ritardo(10); Verificare se il dispositivo corrente inizia con ATSmartHome' Se (Ssid == GW_SSID) { SSID di interesse Se (DEBUG) { Seriale.println("Trovato uno schiavo."); Seriale.Stampare(Ho + 1); Seriale.Stampare(": "); Seriale.Stampare(Ssid); Seriale.Stampare(" ["); Seriale.Stampare(BSSIDstr); Seriale.Stampare("]"); Seriale.Stampare(" ("); Seriale.Stampare(Rssi); Seriale.Stampare(")"); Seriale.println(""); } Int Mac[6]; ottenere il MAC del server e salvare nella memoria RTC 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 Ⅱ = 0; Ⅱ < 6; ++Ⅱ ) { statinfo.Mac[Ⅱ] = (uint8_t) Mac[Ⅱ]; } AggiornamentoRtcMemory(); } slaveFound = 1; non più ricerca dopo AP è stato trovato Pausa; } } } Se (DEBUG) { Se (slaveFound) { Seriale.println("Slave trovato, elaborazione.."); } Altro { Seriale.println("Schiavo non trovato, riprovare."); } } rilasciare RAM Wifi.scanDelete(); } funzione per initilizzare il sensore BME provare entrambi gli indirizzi validi 77 o 76 Boolean initBme() { Boolean Stato = Bme.Iniziare(0x77 (in via di sinfamin2); Se (!Stato) Stato = Bme.Iniziare(0x76 (in inglese)); Se (!Stato) { Seriale.println("Impossibile trovare un sensore BME280 valido, controllare il cablaggio!"); hasBme = False; Mentre (1); } Ritorno Stato; } funzione per initilizzare il sensore BMP provare entrambi gli indirizzi validi 77 o 76 Boolean initBmp() { Boolean Stato = Bmp.Iniziare(0x77 (in via di sinfamin2); Se (!Stato) Stato = Bmp.Iniziare(0x76 (in inglese)); Se (!Stato) { Seriale.println("Impossibile trovare un sensore BME280 valido, controllare il cablaggio!"); hasBme = False; Mentre (1); } Se (Stato) { /- Impostazioni predefinite dal foglio dati. */ Bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, In modalità operativa. */ Adafruit_BMP280::SAMPLING_X2, Temperatura. sovracampionamento Adafruit_BMP280::SAMPLING_X16, // Sovracampionamento della pressione Adafruit_BMP280::FILTER_X16, Filtro . */ Adafruit_BMP280::STANDBY_MS_500); Ora di standby. */ } Ritorno Stato; } Vuoto Installazione() { Se (DEBUG) { Seriale.Iniziare(115200); Seriale.println("Avvia"); } ottenere l'indirizzo MAC locale per utilizzarlo come ID dispositivo Stringa strmac = Wifi.Macaddress(); Se (DEBUG) { Seriale.Stampare("Il mio indirizzo MAC"); Seriale.println(strmac); } Msg.setId (informazioni in stato in stato(strmac); Msg.Chiaro(); hasBme = initBme(); Se (hasBme && DEBUG) { Seriale.println("Trovato Sensore BME"); } hasBmp = initBmp(); Se (hasBmp && DEBUG) { Seriale.println("Trovato Sensore BMP"); } leggere il server MAC dalla memoria RTC Spagnolo.rtcUserMemoryLettura(0, (uint32_t*) &statinfo, Sizeof(statinfo)); Se (DEBUG) Seriale.println("RTC fatto"); uint32_t crcOfData (crcOfData) = calculateCRC32 (errore(((uint8_t*) &statinfo) + 4, Sizeof(statinfo) - 4); Wifi.Modalità(WIFI_STA); Modalità stazione per il nodo del sensore esp-now Se (DEBUG) Seriale.println("Modalità Wifi"); Se (statinfo.crc32 (in questo crc32) != crcOfData (crcOfData)) { se il checksum diverso non abbiamo un server MAC valido Se (DEBUG) Seriale.println("Scansione per schiavo"); ScanForSlave(); per (uint8_t i - 0; i<6;i) statinfo.mac[i] Se (DEBUG) { Seriale.Printf("Questo mac: %s,", Wifi.Macaddress().c_str()); Seriale.Printf("mac di destinazione: %02x%02x%02x%02x%02x%02x%02x", statinfo.Mac[0], statinfo.Mac[1], statinfo.Mac[2], statinfo.Mac[3], statinfo.Mac[4], statinfo.Mac[5]); } } Se (esp_now_init() != 0) { Se (DEBUG) Seriale.println(Errore ESP_Now inc: "z"); Spagnolo.Riavviare(); } ESP Ora Controller Wifi.setAutoConnect(falso); esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); uint8_t ch = esp_now_get_peer_channel(statinfo.Mac); Se (DEBUG) Seriale.printf("Canale =% i \ r \ n",ch); // inizializza i dati peer int res = esp_now_add_peer(statinfo.Mac, ESP_NOW_ROLE_CONTROLLER, 1, NULLO, 0); Se (res==0) Seriale.println("Erfolgreich gepaart"); // registra il callback 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; }); // imposta flag su false callbackCalled = falso; // avvia la misurazione // legge i valori e salva per l'invio Se (hasBme) { Se (DEBUG){ Seriale.Stampa("Temperatura ="); Seriale.Stampa(bme.readTemperature()); Seriale.println("* C"); Seriale.Stampa("Pressione ="); Seriale.Stampa(bme.readPressure() / 100.0f); Seriale.println("hPa"); Seriale.Stampa("Circa. Altitudine ="); Seriale.Stampa(bme.readAltitude(SEALEVELPRESSURE_HPA)); Seriale.println("m"); Seriale.Stampa("Umidità ="); Seriale.Stampa(bme.readHumidity()); Seriale.println(" %"); } msg.addCelsius(bme.readTemperature(), CHANNEL_TEMP_BME); msg.addHektoPascal(bme.readPressure()/100.0f, CHANNEL_PRESS_BME); msg.addMeter(bme.readAltitude(SEALEVELPRESSURE_HPA), CHANNEL_ALT_BME); msg.addPercent(bme.readHumidity(), CHANNEL_HUM_BME); } Se (hasBmp) { Se (DEBUG) { Seriale.Stampa(F("Temperatura =")); Seriale.Stampa(bmp.readTemperature()); Seriale.println("* C"); Seriale.Stampa(F("Pressione =")); Seriale.Stampa(bmp.readPressure()); Seriale.println(" Papà"); Seriale.Stampa(F("Altitudine approssimativa =")); Seriale.Stampa(bmp.readAltitude(SEALEVELPRESSURE_HPA)); / * Adattato alle previsioni locali! * / Seriale.println("m"); } msg.addCelsius(bmp.readTemperature(), CHANNEL_TEMP_BMP); msg.addHektoPascal(bmp.readPressure()/100.0f, CHANNEL_PRESS_BMP); msg.addMeter(bmp.readAltitude(SEALEVELPRESSURE_HPA), CHANNEL_ALT_BMP); } // copia la struttura dati in sendbuffer uint8_t buf[255]; uint8_t sz; sz = 255; Se (msg.fillBuffer(&buf[0], &sz)) esp_now_send(NULLO, buf, sz); // NULL significa inviare a tutti i peer } vuoto ciclo continuo() { // attendi l'invio dei dati Se (callbackCalled || (millis() > send_timeout)) { Se (DEBUG) Seriale.println("Dormire"); ritardo(100); // passa per 10 secondi in modalità di sospensione profonda // wakeup by reset // reset non cancella i dati in RTCmemory ESP.sonno profondo(10E6); } }
Damit dieser Sketch kompiliert werden kann, benötigt man neben den Bibliotheken für die Sensoren, die neueste Version meiner ATMessageBuffer Bibliothek.
Den Code des Sketchs trova a man in a Beispielen der neuen Version der ATSmartHome Bibliothek.
Nachdem die Smart-Home Zentrale auf den neuesten Stand gebracht wurde, kompilieren wir den Sketch and lden ihn in den D1 Mini. Nur kurzer Zeit sollte im unteren blauen Balken der Smarthome Zentrale die MAC Address of D1 Mini erscheinen. Wir klicken einmal lange (mehr als 3 s) auf diese MAC Adresse. Es wird die Registrierungsseite angezeigt. Wir können dem Gerät einen Namen geben und nachdem wir auf Speichern geklickt haben sollten wir die neuen Messwerte auf dem Display sehen. Wenn an der Smarthome Zentrale beve andere Geräte registriert waren, kann es auch sein, dass die neuen Kanäle auf einer der weiteren Seiten angezeigt werden. Con la registrazione automatica, come nel caso in cui si visualizzasse e si visualizzasse la luce nel tempo, è possibile visualizzare i widget e.
Un lungo clic sui widget ti porta alla loro pagina di configurazione e puoi cambiarne l'aspetto e la posizione. L'immagine seguente mostra una possibile configurazione se utilizziamo entrambi i sensori BMx contemporaneamente.
Infine, una piccola estensione sul sito Web della sede centrale di Smarthome. Se viene visualizzato un widget attuatore, è possibile accendere o spegnere il dispositivo remoto allo stesso modo del centro di controllo Smarthome stesso. Per il widget attuatore vedere anche la parte 3 di questa serie
Ecco i collegamenti a tutte le parti precedenti:
Buon divertimento :)
10 commenti
Franz Patzal
Hi Greg,
look in part 6:
Ein wichtiger Hinweis zu Beginn!
Die ArduiTouch Smarthome Zentrale funktioniert nur mit dem ESP32 stabil. Es zeigte sich, dass auf Grund des deutlich geringeren RAM des ESP8266 kein stabiler Betrieb möglich ist. Ich habe daher die Version für den ESP8266 wieder aus dem Repository entfernt. Die aktuelle Version der ATSmartHome Bibliothek kann nicht mehr mit dem Sketch für ESP8266 kompiliert werden!
Greg
Hi. I am trying to follow the examples fro the SmartHome project, but it refers to the library ESP8266WiFi.H, even for ESP32 examples . Where can I find this library?
Many thanks!
Greg.
Wolfgang Händel
Hallo Herr Lechner….
Bis auf die etwas begrenzte Reichweite der Arduitouch Zentrale funktioniert bei mir alles recht gut.
Was das Herz des Smarthome Einsteigers natürlich höher schlagen lassen würde, wäre ein Sensormodul für ein binäres Signal (Klingeltaster, Bewegungssensor, Dämmerungssensor uvm.)
Das binäre Signal eines solchen Moduls müsste in der Zentrale ausgewertet werden und bestimmte Funktionen (wie z.B. das Relaismodul aus Teil 3) auslösen.
Haben sie so etwas geplant? Meines Erachtens gehört so etwas zu den Standard-Features eines SmartHome-Systems.
Ansonsten vielen Dank für die interessanten Blogs zum Thema SmartHome und für die Mühe, die sie sich damit gegeben haben bzw. noch geben..
Wolfie
Siegl Reinhard
Hallo
Ich bekomme die Smart Home V" nicht zum laufen.Es stoppt schon bei #include “SPIFFS.h”.
Bei der alten Smart Home konnte ich alle Beiträge nachbauen.
Danke für die Unterstützung schon im Vorraus.
Matthias H.
Hallo Herr Lechner,
könnte man die Stimmungslaterne https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/mehrere-feuer-programme-fuer-unsere-stimmungslaterne?pos=3&_sid=3afeceff9&ss=r nicht mit der Smarthome Zenrale steuern?
Reinhard Schneider
Wie das mit den Fehlern so ist, es hat sich auch bei mir einer eingeschlichen.
Richtig muss es für 5 min deep-sleep heißen:
ESP.deepSleep(300*10E6);
Reinhard Schneider
Leider haben sich in das o.g. Programm einige kleine Fehler eingeschlichen:
1. /function to initilize BMP Sensor
….
Richtig:
Serial.println(“Could not find a valid BMP280 sensor, check wiring!”);
hasBmp = false;
2. In der Beschreibung heißt es
Für 5 Minuten müsste es heißen:….
After sending the values, the device switches for five minutes into a deep sleep mode with very low power consumption.
Der Code ist aber in void loop()
….
//go for 10 seconds into deep sleep mode
//wakeup by reset
//reset does not delete data in RTCmemory
ESP.deepSleep(10E6);
ESP.deepSleep(600*10E6);
Reinhard Schneider
Das obige Programm läuft nur mit der Version 0.15.0 von “ESPiLight”.
Die aktuelle Version 0.16.0 erzeugt Fehlermeldungen.
Ist eine Anpassung des ino-Files geplant?
Joe
Bei den Daten der beiden Sensoren kann man sagen das es Roh-Daten sind.
Jetzt muß man nur eine Kalibrierung mit einem Referenz-Meßgerät höherer Genauigkeit durchführen. Und dann die Rohdaten entsprechen mit einem Justage-Wert belegen.
Es wird immer eine geringfügige Abweichung zwischen den Sensoren geben.
(Rauschen, Eigentemperatur etc, Meßfehler).
Die redudante Messung ist in Bereichen bei denen der Ausfall, starker Unterschied der Meßwerte, ermittelt werden muß. Rreinraum, technische zu überwachende Prozeße.
Temperatur-Differenzen werden auch genutzt um Strömungen, in dem Fall Luft, zu ermitteln.
Also nicht vergessen Justage-Wert und Kalibrierung.
Marcus Klein
Beide Sensoren sind offenbar recht nah beieinander untergebracht. Sie messen trotzdem eine Differenz von einem kompletten Grad Celsius. Das ist ein absolutes No-Go, wenn man damit versucht Heimautomatisierung zu betreiben und die Heizung zu steuern. Daraus folgt direkt, dass der Heizkreis am Sensor mit der kleineren Temperatur immer heizt und der Kreis am Sensor mit der größeren Temperatur immer aus ist. Bei einem Grad Unterschied und nicht verschlossenen Türen zwischen den beiden Räumen und gut isolierter Hütte, wandert die Wärme ausreichend zwischen den beiden Räumen. Das trägt nicht wirklich zum Wohnkomfort bei, sondern stört diesen besonders.
Wie gedenken Sie, diesen Fehler zu kompensieren?