/** * Author : Anatole SCHRAMM-HENRY * Created the : 11/07/2021 * This is a quick and dirty firmewire to get save the data in the database */ #include #include #include #include #include "RF24.h" #include "definition.h" #include "credentials.h" #define NRF_1_CE 15 //chip enable #define NRF_2_CE 16 //chip enable #define NRF_1_CS 5 //chip select #define NRF_2_CS 4 //chip select #define CHAN 108 //0-125 #define RECV_CHECK 5000 //We test every 5s if we received something #define WIFI_CHECK_TIMEOUT 20000 DataPacket p; RF24 NRF_1(NRF_1_CE, NRF_1_CS); RF24 NRF_2(NRF_2_CE, NRF_2_CS); PCF8574 PCF(0x20); //Wifi event handlers WiFiEventHandler gotIp, lostConnection; HttpClient DBHost(DB_SERVER, PATH); Dictionary postData; const uint8_t ADDR[] = "WEST1", ADDR2[] = "ABCDE"; uint64_t timeStamp(0), irqSaver(0); uint32_t freeMem(0); uint16_t biggestContigMemBlock(0); uint8_t frag(0); volatile boolean IRQFlag(false); IRAM_ATTR void NRFIRQsHandler(void *p) { Serial.println("NRF IRQs detected !"); *(boolean *)p = true; } void setup() { //We do not need to read on the serial bus delay(1000); Serial.println("\nSetup begin"); Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY); //We set the RXD0 as a GPIO pinMode(D9, FUNCTION_3); pinMode(D9, INPUT); attachInterruptArg(D9,&(NRFIRQsHandler), (void *)&IRQFlag, FALLING); //We set the WiFi part up : gotIp = WiFi.onStationModeGotIP(&(gotIpFunc)); lostConnection = WiFi.onStationModeDisconnected(&(lostConnectionFunc)); //To prevent wear and tear on the flash mem WiFi.persistent(false); WiFi.disconnect(true); WiFi.softAPdisconnect(true); Serial.println("Connecting to the access point"); WiFi.begin(SSID, PWD); //We initialize the dictionary postData.add("accessCode", DictionaryHelper::StringEntity(ACCESS_CODE)); postData.add("deviceType", DictionaryHelper::StringEntity(DEV_TYPE)); postData.add("packetUID", DictionaryHelper::StringEntity(NULL)); postData.add("battery", DictionaryHelper::StringEntity(NULL)); postData.add("light", DictionaryHelper::StringEntity(NULL)); postData.add("bmp_tmp", DictionaryHelper::StringEntity(NULL)); postData.add("pressure", DictionaryHelper::StringEntity(NULL)); postData.add("humidity", DictionaryHelper::StringEntity(NULL)); postData.add("compensated_humidity", DictionaryHelper::StringEntity(NULL)); postData.add("htu_tmp", DictionaryHelper::StringEntity(NULL)); Serial.printf("\nNRF 1 %s\n",NRF_1.begin() ? "started" : "error"); if(!NRF_1.isChipConnected()) Serial.println("NRF 1 is missing"); else Serial.println("NRF 1 is detected"); NRF_1.setChannel(CHAN); NRF_1.setPALevel(RF24_PA_MIN); NRF_1.setDataRate(RF24_250KBPS); NRF_1.setRetries(8,15); NRF_1.openReadingPipe(1, ADDR); NRF_1.startListening(); Serial.printf("NRF 2 %s\n",NRF_2.begin() ? "started" : "error"); if(!NRF_2.isChipConnected()) Serial.println("NRF 2 is missing"); else Serial.println("NRF 2 is detected"); NRF_2.setChannel(CHAN); NRF_2.setPALevel(RF24_PA_MIN); NRF_2.setDataRate(RF24_250KBPS); NRF_2.setRetries(8,15); NRF_2.openReadingPipe(1, ADDR); NRF_2.startListening(); memset(&p, 0, sizeof p); //Setting the I2C pins and the PCF8574 Wire.begin(0,2); Serial.printf("PCF %s\n", PCF.begin() ? "found" : "not found"); PCF.pinMode(PCF8574::P2, OUTPUT); PCF.pinMode(PCF8574::P3, OUTPUT); PCF.pinMode(PCF8574::P4, OUTPUT); Serial.println("End setup"); } void loop() { //We check if we got and IRQ from one, both NRFs if(IRQFlag || (millis() - irqSaver > RECV_CHECK)) { bool tx_ok, tx_fail, rx_ready; //We read the PCFs IO to check which NRF raised the IRQ : if(!PCF.digitalRead(PCF8574::P1)) //IRQs are active low { if(!IRQFlag) Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!IRQ MISSED FOR NRF 1"); Serial.printf("NRF 1 triggered the IRQs\n Checking why :\n"); NRF_1.whatHappened(tx_ok, tx_fail, rx_ready); if(tx_ok) { Serial.println("NRF 1 TX_OK"); } if(tx_fail) { Serial.println("NRF 1 TX_FAIL"); } if(rx_ready) { Serial.printf("NRF 1 Received %u bytes with sig(%s) : \n",NRF_1.getPayloadSize(), NRF_1.testRPD()?"good":"bad"); NRF_1.read(&p, sizeof(p)); debugStruct(&p); if(p.header == WEATHER_STATION) { insertIntoDB(); } } } if(!PCF.digitalRead(PCF8574::P0)) //IRQs are active low { if(!IRQFlag) Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!IRQ MISSED FOR NRF 1"); Serial.printf("NRF 2 triggered the IRQs\n Checking why :\n"); NRF_2.whatHappened(tx_ok, tx_fail, rx_ready); if(tx_ok) { Serial.println("NRF 2 TX_OK"); } if(tx_fail) { Serial.println("NRF 2 TX_FAIL"); } if(rx_ready) { Serial.printf("NRF 2 Received %u bytes with sig(%s) : \n",NRF_2.getPayloadSize(), NRF_2.testRPD()?"good":"bad"); NRF_2.read(&p, sizeof(p)); debugStruct(&p); if(p.header == WEATHER_STATION) { insertIntoDB(); } } } //We check if the RX fifo the NRFs are full //If yes, it means we have a big problem since packets can be thrown away without notice //Could be due to missed IRQs (very bad) if(NRF_1.rxFifoFull()) { Serial.println("NRF 1 FIFO FULL !!!!!!!!!!!!"); NRF_1.flush_rx(); } if(NRF_2.rxFifoFull()) { Serial.println("NRF 2 FIFO FULL !!!!!!!!!!!!"); NRF_2.flush_rx(); } IRQFlag = false; irqSaver = millis(); } //Here we check if we are still connected if(millis() - timeStamp > WIFI_CHECK_TIMEOUT) { //PCF.togglePin(PCF8574::P2); //PCF.togglePin(PCF8574::P3); //PCF.togglePin(PCF8574::P4); ESP.getHeapStats(&freeMem, &biggestContigMemBlock, &frag); printf("Memory Info :\n - Free Mem > %u\n - Heap frag > %u\n - Max block > %u\nSign strength : %d\n", freeMem, frag, biggestContigMemBlock,WiFi.RSSI()); Serial.println("Checking wifi link : "); if(WiFi.isConnected()) { Serial.println("Link is established, nothing to be done."); } else { Serial.println("We try to reconnect..."); WiFi.begin(SSID,PWD); } timeStamp = millis(); } } /** * Part where we declare our event handlers */ void gotIpFunc(const WiFiEventStationModeGotIP &event) { Serial.printf("Got connected to station : ip address : %u.%u.%u.%u \n", event.ip[0], event.ip[1], event.ip[2], event.ip[3]); } void lostConnectionFunc(const WiFiEventStationModeDisconnected &event) { Serial.println("Lost connection, will try to reconnect ..."); } void insertIntoDB(void) { char buffer[100] = ""; //We get the values and put it in our dictionary sprintf(buffer ,"%u", p.id); postData("packetUID")->setString(buffer); sprintf(buffer, "%.5f", p.battery); postData("battery")->setString(buffer); sprintf(buffer, "%u", p.ldr); postData("light")->setString(buffer); sprintf(buffer, "%f", p.bmpTemp); postData("bmp_tmp")->setString(buffer); sprintf(buffer, "%f", p.bmpPress); postData("pressure")->setString(buffer); sprintf(buffer, "%f", p.humidity); postData("humidity")->setString(buffer); sprintf(buffer, "%f", p.compensatedHumidity); postData("compensated_humidity")->setString(buffer); sprintf(buffer, "%f", p.htuTemp); postData("htu_tmp")->setString(buffer); if(DBHost.sendHttpQuery(HttpClient::HttpRequestMethod::POST, NULL, &postData)) { Serial.println("Data posted successfully"); HttpClient::HTTP_CODE response = DBHost.isReplyAvailable(2000); Serial.printf("Got response code : %u\n", response); DBHost.stop(); } else { Serial.println("Failed to post data"); DBHost.stop(); } } void debugStruct(DataPacket *p) { Serial.println("##############DATA##############"); Serial.print("ID : "); Serial.println(p->id); Serial.print("HEADER : "); Serial.println(p->header); Serial.printf("BATT : %.5f V\n", p->battery); Serial.print("LDR : "); Serial.println(p->ldr); Serial.print("BMP TEMP : "); Serial.print(p->bmpTemp); Serial.println(" *C"); Serial.print("BMP PRESS : "); Serial.print(p->bmpPress); Serial.println(" Pa"); Serial.print("HUM : "); Serial.print(p->humidity); Serial.println(" %"); Serial.print("COM HUM : "); Serial.print(p->compensatedHumidity); Serial.println(" %"); Serial.print("HTU TEMP : "); Serial.print(p->htuTemp); Serial.println(" *C"); }