#include #include #include ; #include #include ; #include ; #include ; #include #include ; #include ; #include extern "C" { #include "user_interface.h" // this is for the RTC memory read/write functions } /////////// user variables ///////////////// #define SLEEPTIME 60000000 // 1000000 is 1 second String thingspeak_ChannelNumber = "INSERT_CH_NUM"; String thingspeak_WriteAPIKey = "INSERT_KEY"; #define ifttt_url "https://maker.ifttt.com/trigger/[EVENT]/with/key/[KEY]" // replace [EVENT] and [KEY] as required #define dist_threshold 800 // threshold in mm for door open / closed determination #define doorDetects 5 // ifttt alarm will trigger when door is detected open consectively x times //////////////////////////////////////////// #define BMP_SDA 2 // SDA pin #define BMP_SCL 4 // SCL Pin #define WIFICONF_PIN 5 #define US100_TX 12 // Ultrasonic TX #define US100_RX 13 // Ultrasonic RX #define powPin 14 // Power for Ultrasonic // ESP8266 RTC mem is 128 blocks of 4 bytes starting at 64 // First 2 bytes used for data admin // Remaining 126 block used for data // Each rtcValues data structure is 12 bytes therefore // a max of 42 points can be stored in the 126 data blocks #define RTCMEMORYSTART 66 // start of rtc data blocks [66] #define RTCBUFFER 30 // #of records before upload [30] #define RTCMEMORYLEN 126 // #of rtc blocks available for data typedef struct { //rtc data admin byte doorCount; boolean wificonfMode; byte valueCounter; char rtcInit; } rtcManagementStruc; rtcManagementStruc rtcManagement; typedef struct { //rtc data int16_t usTemperature; //use unt16_t as int is 32bits on esp8266 int16_t usDistance; //use unt16_t as int is 32bits on esp8266 float rtcTemperature; float rtcPressure; } rtcStore; rtcStore rtcValues; // New serial channel Instance SoftwareSerial portUS100(US100_RX, US100_TX); // New bmp280 Instance Adafruit_BMP280 bmp; // I2C // New WiFiManager Instance WiFiManager wifiManager; unsigned long aliveTime; int mmDist = 0; int usTemp = -99; float temperature = -99; float pressure = -99; void setup() { ////////////////////////////////////////////////////////////////////////////////////////////////// //initialise serial Serial.begin(115200); delay(1); Serial.println(); Serial.println("------ Restarted - serial up ------"); //initialise wire library Wire.begin(BMP_SDA, BMP_SCL); Wire.setClock(100000); //confirm normal deepsleep wake switch (ESP.getResetInfoPtr()->reason) { case REASON_DEEP_SLEEP_AWAKE: break; default: Serial.println("reboot issue"); Serial.println("Didn't boot from sleep..."); delay(15000); // give a few secs extra to settle break; } yield(); ////////////////////////////////////////////////////////////////////////////////////////////////// // read RTC memory and initialise if necessary system_rtc_mem_read(64, &rtcManagement, sizeof(rtcManagement)); // initialize System after first start if (rtcManagement.rtcInit != 'Y' ) { rtcManagement.doorCount = 0; rtcManagement.wificonfMode = false; rtcManagement.valueCounter = 0; rtcManagement.rtcInit = 'Y'; system_rtc_mem_write(64, &rtcManagement, sizeof(rtcManagement)); Serial.println("Initialisation values set..."); } ////////////////////////////////////////////////////////////////////////////////////////////////// // wifi config page enable pinMode(WIFICONF_PIN, INPUT_PULLUP); // Set pin as an input w/ pull-up if (digitalRead(WIFICONF_PIN) == LOW) { // check if wifi config pin is set if (rtcManagement.wificonfMode == false) { // check if wifi is on, if not restart with wifi on rtcManagement.wificonfMode = true; system_rtc_mem_write(64, &rtcManagement, sizeof(rtcManagement)); Serial.println("WIFICONFIG pin detected - no wifi, restarting with wifi"); ESP.deepSleep(100 , WAKE_RF_DEFAULT); yield(); } else { Serial.println("WiFi config jumper detected, starting portal"); wifiManager.startConfigPortal("ESP_ALERT_CONFIG"); } } wifiManager.setConfigPortalTimeout(1); // prevent wifi config page for all other times; conserve battery if fault ////////////////////////////////////////////////////////////////////////////////////////////////// // Collect data from us100 // turn on ultrasonic sensor pinMode(powPin, OUTPUT); digitalWrite(powPin, HIGH); portUS100.begin(9600); // get distance from US100 int us_trys = 20; while ((mmDist == 0) && (us_trys > 0)) { us_trys--; portUS100.flush(); // clears the buffer serial port portUS100.write(0x55); // distance measuring order portUS100.flush(); // send all before moving on int us_waits = 10; while ((portUS100.available() < 2) && (us_waits > 0)) { delay(1); us_waits--; } if (us_waits > 0) { // must be 2 bytes available unsigned int MSByteDist = portUS100.read(); // reading both bytes unsigned int LSByteDist = portUS100.read(); mmDist = MSByteDist * 256 + LSByteDist; // distance if ((mmDist < 1) && (mmDist > 10000)) { // checking the distance within range mmDist = 0; } } } Serial.print("Distance to object: "); Serial.print(mmDist); Serial.println(" mm"); // get temperature from US100 us_trys = 20; while ((usTemp == -99) && (us_trys > 0)) { us_trys--; portUS100.flush(); // clears the buffer serial port portUS100.write(0x50); // temperature measuring order portUS100.flush(); // send all before moving on int us_waits = 10; while ((portUS100.available() < 1) && (us_waits > 0)) { delay(1); us_waits--; } if (us_waits > 0) { // byte must be available int tempByte = portUS100.read(); // reading byte usTemp = tempByte - 45; // temperature } } Serial.print("US100 Temperature: "); Serial.print(usTemp); Serial.println(" *C"); // turn off ultrasonic sensor digitalWrite(powPin, LOW); ////////////////////////////////////////////////////////////////////////////////////////////////// // if door is closed reset counter otherwise increase counts yield(); if (mmDist < dist_threshold && mmDist > 0) { Serial.println("Open door detected..."); rtcManagement.doorCount = rtcManagement.doorCount + 1; } else { rtcManagement.doorCount = 0; } Serial.print("Door triggers: ");Serial.print(rtcManagement.doorCount);Serial.print(" of ");Serial.println(doorDetects); ///////////////////////////////////////////////////////////////////////////////////////////////// // Collect data from BMP280 // bmp280 read collects the last value from the buffer, and a new value is sampled and put in the // buffer, if we are sleeping / switching the power to the bmp280 read should be called twice, // once to add a fresh value to the buffer and the second to collect the fresh value. // int read_trys = 10; while (temperature == -99 && read_trys > 0) { read_trys--; if (bmp.begin(0x76)) { temperature = bmp.readTemperature(); // trigger once to initiate new values pressure = bmp.readPressure() / 100; delay(100); temperature = bmp.readTemperature(); // trigger second time to read previous result pressure = bmp.readPressure() / 100; Serial.print("BMP280 Temperature: "); Serial.print(temperature); Serial.println(" *C"); Serial.print("Pressure: "); Serial.print(pressure); Serial.println(" hPa"); } } ////////////////////////////////////////////////////////////////////////////////////////////// // write temperature and pressure to RTC memory rtcValues.usTemperature = usTemp; rtcValues.usDistance = mmDist; rtcValues.rtcTemperature = temperature; rtcValues.rtcPressure = pressure; int rtcPos = RTCMEMORYSTART + rtcManagement.valueCounter; if (rtcManagement.valueCounter == RTCMEMORYLEN) { // memory full, shift data in rtc to erase oldest value Serial.println("RTC memory full, shifting data, droping oldest reading..."); rtcManagement.valueCounter = rtcManagement.valueCounter - (sizeof(rtcValues)/4); byte rtcMemory[(RTCMEMORYLEN-1)*sizeof(rtcValues)]; system_rtc_mem_read(RTCMEMORYSTART + (sizeof(rtcValues)/4), &rtcMemory, (RTCMEMORYLEN-1)*sizeof(rtcValues)); system_rtc_mem_write(RTCMEMORYSTART, &rtcMemory, (RTCMEMORYLEN-1)*sizeof(rtcValues)); } system_rtc_mem_write(rtcPos, &rtcValues, sizeof(rtcValues)); rtcManagement.valueCounter = rtcManagement.valueCounter + (sizeof(rtcValues)/4); Serial.print("Data Points: ");Serial.print(rtcManagement.valueCounter/(sizeof(rtcValues)/4)); Serial.print(" of ");Serial.println(RTCMEMORYLEN /(sizeof(rtcValues)/4)); system_rtc_mem_write(64, &rtcManagement, sizeof(rtcManagement)); yield(); ////////////////////////////////////////////////////////////////////////////////////////////////// // if flag is set send door alarm using IFTTT webhook service if (rtcManagement.doorCount >= doorDetects) { if (wifiManager.autoConnect()) { HTTPClient http; http.begin(ifttt_url, "C0:5D:08:5E:E1:3E:E0:66:F3:79:27:1A:CA:1F:FC:09:24:11:61:62"); //fingerprint from IFTTTWebhook Library by John Romkey int httpCode = http.GET(); http.end(); } else { Serial.println("Failed to connect, going back to sleep"); } } /////////////////////////////////////////////////////////////////////////////////// // retrieve data readings from RTC memory & send // prepare bulk update as JSON string if (rtcManagement.valueCounter >= (RTCBUFFER*sizeof(rtcValues)/4)) { String jsonStr = "{ \"write_api_key\": \"" + thingspeak_WriteAPIKey + "\", \"updates\": ["; for (int i = 0; i < RTCBUFFER; i++) { int rtcPos = RTCMEMORYSTART + i*(sizeof(rtcValues)/4); system_rtc_mem_read(rtcPos, &rtcValues, sizeof(rtcValues)); jsonStr += "{ \"delta_t\": 60, \"field1\": " + String(rtcValues.rtcTemperature); jsonStr += ", \"field2\": " + String(rtcValues.usTemperature); jsonStr += ", \"field3\": " + String(rtcValues.rtcPressure); jsonStr += ", \"field4\": " + String(rtcValues.usDistance); jsonStr += "}"; if (i < RTCBUFFER-1) { jsonStr += ","; } } jsonStr += "] }"; String data_length = String(jsonStr.length()+1); // Send data to thingspeak wifiManager.autoConnect(); WiFiClient client; int retries = 5; while (!client.connect("api.thingspeak.com", 80) && (retries > 0)) { retries = retries-1; delay(10); } if (client.connected()) { client.println("POST /channels/" + thingspeak_ChannelNumber + "/bulk_update.json HTTP/1.1"); client.println("Host: api.thingspeak.com"); client.println("Connection: close"); client.println("Content-Type: application/json"); client.println("Content-Length: "+data_length); client.println(); client.println(jsonStr); delay(250); //Wait to receive the response client.parseFloat(); int resp = client.parseInt(); Serial.println("Response code:"+String(resp)); // Print response code client.stop(); if (resp == 202) { Serial.println("Data Sent, confirmed receipt"); rtcManagement.valueCounter = 0; system_rtc_mem_write(64, &rtcManagement, sizeof(rtcManagement)); } else { Serial.println("Connected but confirm receipt failed, going back to sleep"); } } else { Serial.println("Failed to connect, going back to sleep"); } } yield(); /////////////////////////////////////////////////////////////////////////////////// // go to sleep // determine time to sleep aliveTime = millis(); long sleepRemaining; if (SLEEPTIME >= (aliveTime * 1000) ) { sleepRemaining = SLEEPTIME - (aliveTime * 1000); Serial.println("------ Going to Sleep ------"); } else { sleepRemaining = 100; Serial.println("------ No time for sleep ------"); } // determine if wifi needed after sleep if ((rtcManagement.valueCounter/(sizeof(rtcValues)/4) >= (RTCBUFFER-1)) || rtcManagement.doorCount >= (doorDetects - 1)){ ESP.deepSleep(sleepRemaining, WAKE_RF_DEFAULT); } else { ESP.deepSleep(sleepRemaining, WAKE_RF_DISABLED); } yield(); delay(100); } ///////////////////////////////////////////////////////////////////////////////////////// void loop() {}