/* Author: Kåre-Benjamin Hammervold Rørvik og Nils Kristian Rossing 31.12.2020 On behald of NTNU. Edited 29.12.2020 Et oppsett med BME 280 sensor koblet via I2C til ESP32. En ESP32 som står i Station Mode og fungerer som sensor node. Sender datapakker over ESP-NOW. Sender og mottar data over WiFi opp mot CoT. Bytter mellom WiFi og ESP-NOW. Antall meldinger sendt vises på displayet, temperatur fuktighet og trykk i rotering. Sketchen er testet med variantene: ESP32 DEV MODULE og DOIT ESP-32 DEVKIT V1 Sensordata skrives ut i konsollen (serial monitor). BME280 | ESP-32 ---------------------------------- SCL/SCK: | D22 SDA/DATA: | D21 VDD: | 3V3 (3.3V) GND: | GND Det er anbefalt å koble opp en kondensator (avkoppling) mellom GND og VDD på sensorer. F.eks.: 0.1uF keramisk kondensator. // Sources: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html https://randomnerdtutorials.com/esp-now-esp8266-nodemcu-arduino-ide/?fbclid=IwAR0pH-ilF45ceHlyqjB1Im5oDkOJUtxJ7g1TDABbaSOkiBep5xYlsH1y5_M */ #include #include #include #include // Adressen til mottakeren ved ESP-NOW kommunikasjon, dette er MAC addressen skrevet på hex format. uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0x9E, 0x9F, 0x70}; Adafruit_BME280 bme280; unsigned long delayTime; // Teller antall meldinger som er sendt, starter på 0. int consecutive_messages = 0; // Teller antall målinger som er gjort. int consecutive_meassures = 0; // Transmitted data typedef struct { int instance; float temperature; float humidity; float pressure; String source; } ESPNOWData; // Oppretter et packet objekt for strukturen ESPNOWData. ESPNOWData packet; void setup() { Serial.begin(115200); initESPNOW(); checkBME280(); } void loop() { // Høster inn data til packet. preparePacket(); // Skriver ut temperatur, fuktighet og trykk fra packet til monitor og sjekker om verdiene er gyldige consecutive_meassures = sensorValuesToMonitor(consecutive_meassures); // Sender data i packet. transmitData(); delay(2000); } void initESPNOW(){ // Init ESP-NOW med en promise structure. // ESP-32 må være konfigurert i Station Mode for at ESP-NOW skal kunne benyttes. WiFi.mode(WIFI_STA); // esp_now_init() vil returnere enten ESP_OK eller ESP_ERR_ESPNOW_INTERNAL // Disse antyder om ESP-NOW er konfigurert korrrekt eller ikke. // ESP_OK betyr at alt er riktig konfigurert, ESP_ERR_ESPNOW_INTERNAL er en feilmelding. // Den kan sees på som aktiv lav: ESP_OK = 0 = LOW, ESP_ERR_ESPNOW_INTERNAL = 1 = HIGH. int initStatus = esp_now_init(); // Funksjoner som aktiveres og returnerer en status: Serial.println("---------------ESP-NOW-----------------"); if (initStatus == ESP_OK){ // Setter opp en callback for å hente ut informasjon om sendingen. esp_now_register_send_cb(activateOnCallback); // Registrerer peer esp_now_peer_info_t peerInfo; memcpy(peerInfo.peer_addr, broadcastAddress, 6); peerInfo.channel = 0; peerInfo.encrypt = false; Serial.println("ESP-NOW er konfigurert riktig"); if (esp_now_add_peer(&peerInfo) == ESP_OK){ Serial.println("... og Peer er lagt til"); } else { Serial.println("... Noe gikk galt etter konfigureringen, Peer kunne ikke bli lagt til?"); Serial.println("Programmet restartes etter ti sekunder"); delay(10000); ESP.restart(); } Serial.println("ESP-NOW er klar til bruk"); } else { Serial.println("ESP-NOW er ikke konfigurert riktig, programmet restartes etter ti sekunder"); delay(10000); ESP.restart(); } Serial.println("----------------------------------------"); } void checkBME280() { // En TRUE/FALSE variabel (bool) som sjekker om sensoren er detektert og oppfører seg som forventet. // bme280.begin tar inn addressen på I2C buss (0x76) og sjekker på denne addressen. bool readyCheck = bme280.begin(0x76); //Sjekker om sensoren er klar, hvis ikke henger systemet i while og sjekker om sensoren blir detektert. if (!readyCheck) { Serial.println("BME 280 er ikke funnet, se over skjematikken og koden"); Serial.println("Sjekk at: SCL/SCK er koblet til D22 og SDA/DATA på D21"); Serial.println("Programmet resetartes om sensoren blir riktig detektert"); while (1){ // Står i loop... // Men om sensoren detekteres restartes programmet. readyCheck = bme280.begin(0x76); // Et delay kan ofte være greit for å unnga timing problemer, og unødvendig prossesering. // Ulike størrelser kan testes. delay(1000); if(readyCheck){ ESP.restart(); } } } Serial.println("BME 280 er klar og fungerer som forventet"); } void transmitData(){ esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &packet, sizeof(packet)); if (result == ESP_OK) { Serial.println("Alt er klart, og data sendes..."); consecutive_messages += 1; } else { Serial.println("Data kan ikke sendes fordi noe er feilkonfigurert..."); } } void preparePacket(){ packet.pressure = bme280.readPressure(); packet.instance = consecutive_messages; packet.temperature = bme280.readTemperature(); packet.source = "D4"; packet.humidity = bme280.readHumidity(); } // callback when data is sent void activateOnCallback(const uint8_t *mac_addr, esp_now_send_status_t status) { if (status == ESP_NOW_SEND_SUCCESS){ Serial.println("Data har blitt sendt og er mottatt av mottakeren!"); } else { Serial.println("Noe gikk galt, sendingen var ikke vellykket"); } } int sensorValuesToMonitor(int successfullMeassures) { //Skriver ut temperatur, fuktighet og trykk verdiene som ligger i packet objektet //Sjekker om tall er i gydlighetsområdet, hvis ikke kjøres en restart. successfullMeassures ++; Serial.println("---------------------"); Serial.print("Antall målinger på rad: "); Serial.println(successfullMeassures); Serial.print("Temperatur: "); Serial.print(packet.temperature); Serial.println(" *C"); Serial.print("Trykk: "); Serial.print(packet.pressure/100); Serial.println(" hPa"); Serial.print("Fuktighet: "); Serial.print(packet.humidity); Serial.println(" %"); Serial.println("---------------------"); Serial.println(); if(((packet.temperature < -30 || packet.humidity < -30) || packet.temperature > 100 || packet.humidity > 100)){ Serial.print("Verdier er utenfor gydlighetsområdet, det antas en error, en restart påfølger om 5 sekunder"); delay(5000); ESP.restart(); } return successfullMeassures; }