Advertisement
kodilivetv

ESP32 ADXL345 RAIN SENSOR

Mar 25th, 2025 (edited)
512
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.67 KB | Software | 0 0
  1. /*
  2.   This sketch configures an ESP32 module to monitor motion using an ADXL345 accelerometer,
  3.   sends boot count information via Telegram, and manages power consumption through deep sleep modes.
  4.  
  5.   Key functionalities:
  6.   - Monitors activity on the Y-axis using the ADXL345 accelerometer, with configurable thresholds.
  7.   - Connects to WiFi and sends updates via Telegram on each boot, including the boot count.
  8.   - If no significant activity is detected within a few seconds after ADXL345 setup begins, the ESP32 enters deep sleep mode.
  9.   - Deep sleep is managed based on the boot count:
  10.     - Boots 1-2: The ESP32 can wake up on external activity (GPIO14).
  11.     - Boot 3: The ESP32 sleeps for an extended period (2 minutes), then resets the boot count.
  12.   - Includes brownout protection and visual feedback (LED) on boot and before entering deep sleep.
  13.  
  14.   Libraries used:
  15.   - ADXL345_WE: For controlling and configuring the ADXL345 accelerometer.
  16.       https://wolles-elektronikkiste.de/en/adxl345-the-universal-accelerometer-part-1 (English)
  17.       https://github.com/wollewald/ADXL345_WE
  18.   - AsyncTelegram2: For sending messages through Telegram.
  19.       https://github.com/cotestatnt/AsyncTelegram2
  20.  
  21.   Configure WiFi and Telegram token parameters.
  22.  
  23.   This project is being used to detect rain events. The bottom of a plastic container was cut and the opening, now facing up, covered with cellophane;
  24.   the adxl345 was glued to the cellophane, which bounces with the drops of rain, triggering the interrupt.
  25. */
  26.  
  27. #include "driver/rtc_io.h"
  28.  
  29. #include<Wire.h>
  30. #include<ADXL345_WE.h>
  31. #define ADXL345_I2CADDR 0x53 // 0x1D if SDO = HIGH
  32. const int int2Pin = 14;
  33. volatile bool in_activity = false; // in_activity: either activity or inactivity interrupt occured
  34.  
  35. #include "soc/soc.h"           // Brownout error fix
  36. #include "soc/rtc_cntl_reg.h"  // Brownout error fix
  37.  
  38. #include <WiFiClientSecure.h>
  39. WiFiClientSecure client;
  40.  
  41. #include <AsyncTelegram2.h> // https://github.com/cotestatnt/AsyncTelegram2
  42. AsyncTelegram2 myBot(client);
  43. const char * network = "696969"; // SSID WiFi network
  44. const char * pass = "696969"; // Password  WiFi network
  45. const char * token = "696969"; // () Telegram token
  46. int64_t userid = 696969;
  47. //int64_t userid = -696969; //
  48. #define MYTZ "WET0WEST,M3.5.0/1,M10.5.0/2" // POSIX timezone string for Lisbon
  49.  
  50. /* There are several ways to create your ADXL345 object:
  51.  * ADXL345_WE myAcc = ADXL345_WE()                -> uses Wire / I2C Address = 0x53
  52.  * ADXL345_WE myAcc = ADXL345_WE(ADXL345_I2CADDR) -> uses Wire / ADXL345_I2CADDR
  53.  * ADXL345_WE myAcc = ADXL345_WE(&wire2)          -> uses the TwoWire object wire2 / ADXL345_I2CADDR
  54.  * ADXL345_WE myAcc = ADXL345_WE(&wire2, ADXL345_I2CADDR) -> all together
  55.  */
  56. ADXL345_WE myAcc = ADXL345_WE(ADXL345_I2CADDR);
  57.  
  58. int activity_counter = 0;
  59. bool goToSleep = false;
  60.  
  61. #define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
  62. #define LONG_SLEEP_TIME 10 * 60 /* Time ESP32 will sleep (in seconds) if bootCount = 4 */
  63. #define WAKEUP_GPIO GPIO_NUM_14 /* GPIO pin used for external wakeup */
  64.  
  65. RTC_DATA_ATTR int bootCount = 0;
  66.  
  67. byte ledPin = 13; // ESP32-room-32
  68.  
  69. portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
  70.  
  71. void IRAM_ATTR in_activityISR() {
  72.  
  73.   portENTER_CRITICAL(&mux);
  74.   in_activity = true;
  75.   portEXIT_CRITICAL(&mux);
  76.  
  77. }
  78.  
  79. void sendToTelegram() {
  80.  
  81.   Serial.print("Connecting to ");
  82.   Serial.println(network);
  83.  
  84.   WiFi.begin(network, pass);
  85.  
  86.   int wifi_start_counter = 0;
  87.   while (WiFi.status() != WL_CONNECTED) {
  88.     Serial.print(".");
  89.     wifi_start_counter++;
  90.     if (wifi_start_counter >= 10) {
  91.       //enterDeepSleep();
  92.       break;
  93.     }
  94.     delay(1000);
  95.   }
  96.  
  97.   Serial.println("");
  98.   Serial.println("WiFi connected!");
  99.  
  100.   // Sync time with NTP
  101.   configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
  102.   client.setCACert(telegram_cert);
  103.   // Set the Telegram bot properies
  104.   myBot.setUpdateTime(2000);
  105.   myBot.setTelegramToken(token);
  106.  
  107.   // Check if all things are ok
  108.   Serial.print("\nTest Telegram connection... ");
  109.   myBot.begin() ? Serial.println("OK") : Serial.println("NOK");
  110.  
  111.   // Send a welcome message to user when ready
  112.   //  char welcome_msg[64];
  113.   //  snprintf(welcome_msg, 64, "BOT @%s online.\nTry with /takePhoto command.", myBot.getBotName());
  114.   //  myBot.sendTo(userid, welcome_msg);
  115.  
  116.   char bootCountMsg[64];
  117.   snprintf(bootCountMsg, 64, "Boot count is: %d", bootCount);
  118.   myBot.sendTo(userid, bootCountMsg);
  119.  
  120.   //  const char* message = "/clip";
  121.   //  // Send the message to the Telegram channel
  122.   //  bool sent = myBot.sendTo(userid, message);
  123.  
  124. }
  125.  
  126. void blinkLED(int numBlinks, int blinkInterval) {
  127.   for (int i = 0; i < numBlinks; i++) {
  128.     digitalWrite(ledPin, HIGH); // Turn on the LED
  129.     delay(blinkInterval);
  130.     digitalWrite(ledPin, LOW); // Turn off the LED
  131.     delay(blinkInterval);
  132.   }
  133. }
  134.  
  135. void setup() {
  136.   WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // disable brownout detector
  137.  
  138.   Wire.begin(33, 32);
  139.   Serial.begin(9600); Serial.println();
  140.   pinMode(int2Pin, INPUT);
  141.   pinMode(ledPin, OUTPUT);
  142.  
  143.   blinkLED(3, 200); // Blink the LED 3 times with a 200ms interval to indicate wake up
  144.  
  145.   Serial.println("ADXL345_Sketch - Activity and Inactivity Interrupts");
  146.   Serial.println();
  147.  
  148.     //Increment boot number and print it every reboot
  149.   ++bootCount;
  150.   Serial.println("Boot number: " + String(bootCount));
  151.   Serial.println();
  152.  
  153.   sendToTelegram();
  154.    
  155.   if (!myAcc.init()) {
  156.     Serial.println("ADXL345 not connected!");
  157.   }
  158.  
  159. /* Choose the data rate         Hz
  160.     ADXL345_DATA_RATE_3200    3200
  161.     ADXL345_DATA_RATE_1600    1600
  162.     ADXL345_DATA_RATE_800      800
  163.     ADXL345_DATA_RATE_400      400
  164.     ADXL345_DATA_RATE_200      200
  165.     ADXL345_DATA_RATE_100      100
  166.     ADXL345_DATA_RATE_50        50
  167.     ADXL345_DATA_RATE_25        25
  168.     ADXL345_DATA_RATE_12_5      12.5  
  169.     ADXL345_DATA_RATE_6_25       6.25
  170.     ADXL345_DATA_RATE_3_13       3.13
  171.     ADXL345_DATA_RATE_1_56       1.56
  172.     ADXL345_DATA_RATE_0_78       0.78
  173.     ADXL345_DATA_RATE_0_39       0.39
  174.     ADXL345_DATA_RATE_0_20       0.20
  175.     ADXL345_DATA_RATE_0_10       0.10
  176. */
  177.   myAcc.setDataRate(ADXL345_DATA_RATE_200);
  178.   Serial.print("Data rate: ");
  179.   Serial.print(myAcc.getDataRateAsString());
  180.  
  181. /* Choose the measurement range
  182.     ADXL345_RANGE_16G    16g    
  183.     ADXL345_RANGE_8G      8g    
  184.     ADXL345_RANGE_4G      4g  
  185.     ADXL345_RANGE_2G      2g
  186. */
  187.   myAcc.setRange(ADXL345_RANGE_2G);
  188.   Serial.print("  /  g-Range: ");
  189.   Serial.println(myAcc.getRangeAsString());
  190.   Serial.println();
  191.  
  192.   attachInterrupt(digitalPinToInterrupt(int2Pin), in_activityISR, RISING);
  193.  
  194. /* Three parameters have to be set for activity:
  195.     1. DC / AC Mode:
  196.         ADXL345_DC_MODE - Threshold is the defined one (parameter 3)
  197.         ADXL345_AC_MODE - Threshold = starting acceleration + defined threshold
  198.     2. Axes, that are considered:
  199.         ADXL345_000  -  no axis (which makes no sense)
  200.         ADXL345_00Z  -  z
  201.         ADXL345_0Y0  -  y
  202.         ADXL345_0YZ  -  y,z
  203.         ADXL345_X00  -  x
  204.         ADXL345_X0Z  -  x,z
  205.         ADXL345_XY0  -  x,y
  206.         ADXL345_XYZ  -  all axes
  207.     3. Threshold in g
  208. */
  209.   myAcc.setActivityParameters(ADXL345_AC_MODE, ADXL345_0Y0, 0.1);
  210.  
  211. /* You can choose the following interrupts:
  212.     Variable name:           Triggered, if:
  213.     ADXL345_OVERRUN      -   new data replaces unread data
  214.     ADXL345_WATERMARK    -   the number of samples in FIFO equals the number defined in FIFO_CTL
  215.     ADXL345_FREEFALL     -   acceleration values of all axes are below the threshold defined in THRESH_FF
  216.     ADXL345_INACTIVITY   -   acc. value of all included axes are < THRESH_INACT for period > TIME_INACT
  217.     ADXL345_ACTIVITY     -   acc. value of included axes are > THRESH_ACT
  218.     ADXL345_DOUBLE_TAP   -   double tap detected on one incl. axis and various defined conditions are met
  219.     ADXL345_SINGLE_TAP   -   single tap detected on one incl. axis and various defined conditions are met
  220.     ADXL345_DATA_READY   -   new data available
  221.  
  222.     Assign the interrupts to INT1 (INT_PIN_1) or INT2 (INT_PIN_2). Data ready, watermark and overrun are
  223.     always enabled. You can only change the assignment of these which is INT1 by default.
  224.  
  225.     You can delete interrupts with deleteInterrupt(type);
  226. */
  227.   myAcc.setInterrupt(ADXL345_ACTIVITY, INT_PIN_2);
  228.   myAcc.readAndClearInterrupts();  
  229. }
  230.  
  231. /* In the main loop some checks are done:
  232.     getActTapStatus() returns which axes are responsible for activity interrupt as byte (code in library)
  233.     getActTapStatusAsString() returns the axes that caused the interrupt as string
  234.     readAndClearInterrupts(); returns the interrupt type as byte (code in library)
  235.     checkInterrupt(intSource, type) returns if intSource is type as bool
  236. */
  237.  
  238. void loop() {
  239.   if ((millis() % 1000) == 1) {
  240.     xyzFloat g = myAcc.getGValues();
  241.     Serial.print("g-x   = ");
  242.     Serial.print(g.x);
  243.     Serial.print("  |  g-y   = ");
  244.     Serial.print(g.y);
  245.     Serial.print("  |  g-z   = ");
  246.     Serial.print(g.z);
  247.     Serial.print("  |  act-cnt   = ");
  248.     ++activity_counter;
  249.     Serial.println(activity_counter);
  250.   }
  251.  
  252.   if(in_activity == true) {
  253.       ++activity_counter;
  254.       //byte actTapSource = myAcc.getActTapStatus();
  255.       //Serial.println(actTapSource, BIN);
  256.       String axes = myAcc.getActTapStatusAsString();
  257.       byte intSource = myAcc.readAndClearInterrupts();
  258.      
  259.       if(myAcc.checkInterrupt(intSource, ADXL345_ACTIVITY)){
  260.         Serial.print("Activity at: ");
  261.         Serial.println(axes);
  262.       }
  263.      
  264.     delay(1000);
  265.     myAcc.readAndClearInterrupts();
  266.     in_activity = false;
  267.   }
  268.  
  269.   if(activity_counter >= 20) goToSleep = true;
  270.  
  271.   if(goToSleep == true) {
  272.     Serial.println("goToSleep == true");
  273.     Serial.println();
  274.  
  275.     if (bootCount >= 1 && bootCount <= 2) {
  276.  
  277.       // Configure external wakeup on GPIO14
  278.       esp_sleep_enable_ext0_wakeup(WAKEUP_GPIO, 1); // 1 = High, 0 = Low
  279.       rtc_gpio_pullup_dis(WAKEUP_GPIO);
  280.       rtc_gpio_pulldown_en(WAKEUP_GPIO);
  281.       Serial.println("Setup ESP32 to wake up on GPIO14 trigger");
  282.  
  283.     } else if (bootCount == 3) {
  284.  
  285.       // Sleep for 10 minutes instead of sending more than 3 consecutive notifications
  286.       bootCount = 0;
  287.       esp_sleep_enable_timer_wakeup(LONG_SLEEP_TIME * uS_TO_S_FACTOR);
  288.       Serial.println("Setup ESP32 to sleep for 10 * 60 seconds and reset bootCount");
  289.  
  290.     }
  291.  
  292.     // Go to sleep now
  293.     blinkLED(2, 1000); // Blink the LED 3 times with a 200ms interval to indicate wake up
  294.     Serial.println("Going to sleep now");
  295.     Serial.flush();
  296.     esp_deep_sleep_start();
  297.     Serial.println("This will never be printed");
  298.     Serial.println();
  299.   }
  300.  
  301. }
  302.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement