Below are three videos showing the functionality of my first IoT Project. The source code for this project is available at the bottom of this post.



Source code for the project below;

#include <BLEAttribute.h>
#include <BLECentral.h>
#include <BLECharacteristic.h>
#include <BLECommon.h>
#include <BLEDescriptor.h>
#include <BLEPeripheral.h>
#include <BLEService.h>
#include <BLETypedCharacteristic.h>
#include <BLETypedCharacteristics.h>
#include <BLEUuid.h>
#include <Servo.h>
#include <Wire.h>
#include <ADXL345.h>

// Global objects
BLEPeripheral blePeripheral;
BLEService ServoRead("11111111111"); // Analog Read Service
BLEService ServoWrite("22222222222"); // Analog Write Service
BLEService LEDWriteAccelRead("33333333333"); //Digital Write/Read Service

ADXL345 adxl; //variable adxl is an instance of the ADXL345 library

// Analogue Read Characteristic
BLEIntCharacteristic Position_R("0x0010", BLERead);

// Analogue Read Characteristic
BLEIntCharacteristic Position_W("0x0020", BLEWrite);

// Digital Characterisitcs
BLEIntCharacteristic LEDChar("0x0030", BLEWrite);  // remote clients will be able to change and read the LED state
BLEUnsignedShortCharacteristic XAxisChar("0x0031", BLERead | BLENotify);  // Axis variables set to notify and read to allow it to be read as it changes
BLEUnsignedShortCharacteristic YAxisChar("0x0032", BLERead | BLENotify);
BLEUnsignedShortCharacteristic ZAxisChar("0x0033", BLERead | BLENotify);

int x,y,z;  
int pos = 0;   // variable to store the servo position
Servo myservo;    // create servo object to control a servo
                  // twelve servo objects can be created on most boards

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);    // initialize serial communication
  pinMode(13, OUTPUT);   // initialize the LED on pin 13 to
  pinMode(LED_BUILTIN, OUTPUT);  // This is the LED that will be controlled
  digitalWrite(LED_BUILTIN,LOW); 

  blePeripheral.setLocalName("BRNCLGN");
  
  // add the service UUID
  blePeripheral.setAdvertisedServiceUuid(ServoRead.uuid());
  blePeripheral.setAdvertisedServiceUuid(ServoWrite.uuid());
  blePeripheral.setAdvertisedServiceUuid(LEDWriteAccelRead.uuid());
  
  // Add the Analog Read service
  blePeripheral.addAttribute(ServoRead);
  blePeripheral.addAttribute(Position_R); // add the read-only characteristic

  // Add the Analog Write service
  blePeripheral.addAttribute(ServoWrite);
  blePeripheral.addAttribute(Position_W); // add the analogue-write characteristic

  //Add the Digital Write/Read Service
  blePeripheral.addAttribute(LEDWriteAccelRead);
  blePeripheral.addAttribute(LEDChar); // add the LED characteristic
  blePeripheral.addAttribute(XAxisChar); // add the X characteristic
  blePeripheral.addAttribute(YAxisChar); // add the Y characteristic
  blePeripheral.addAttribute(ZAxisChar); // add the Z characteristic

  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  ADXLSetup();    
  LEDChar.setValue(0); // Set initial value of brightness (0)
  
  blePeripheral.begin();
  Serial.println("Bluetooth device active, waiting for connections...");
}

void loop() {
  // listen for BLE connections
  BLECentral central = blePeripheral.central();

  // if a central is connected to this peripheral:
  if (central) {
    Serial.print("Connected to central: ");
    // print the central's MAC address:
    Serial.println(central.address());

    // turn on the LED to indicate the connection:
    digitalWrite(13, HIGH);

    while (central.connected()) {
      
      if (LEDChar.written()) {  // did central write?
        LEDWrite(); //
      }
      else {
        LEDRead(); // return the current value to central
      }
      
      if (Position_W.written()) { //if the position varaible is written
        AnalogueWrite(); // update the read-only BLE char, print new position to screen
      }
      
      adxl.readXYZ(&x, &y, &z); //read the accelerometer values and store them in variables  x,y,z
      
      if (x!=XAxisChar.value() or y!=XAxisChar.value() or z!=XAxisChar.value()){ // if the x,y,z values have changed since the last reading
        DigitalRead(); //update BLE chars and print to screen
      }    
      
      delay(2500);// Wait a few seconds between measurements.
    }

    // when the central disconnects, turn off the LED:
    digitalWrite(13, LOW);
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
  delay(10000);
  Serial.println("Waiting for a connection");
}

void LEDWrite(){
  if (LEDChar.value()) // did central write a non-zero value?
  {
    digitalWrite(LED_BUILTIN,HIGH); // if so, then turn on the LED
    Serial.print("\nLED On\n");
  }
  else
  {
    digitalWrite(LED_BUILTIN,LOW); // turn off the LED
    Serial.print("\nLED Off\n");
  }
}

void LEDRead(){
  // Update the characteristic on the
  LEDChar.setValue(digitalRead(LED_BUILTIN));
}

void DigitalRead(){
  XAxisChar.setValue(x); //update XAxis BLE char 
  YAxisChar.setValue(y); //update YAxis BLE char 
  ZAxisChar.setValue(z); //update ZAxis BLE char 
  Serial.print("\nX = "); //print vars to screen
  Serial.print(x,HEX);
  Serial.print("\nY = "); 
  Serial.print(y,HEX);
  Serial.print("\nZ = "); 
  Serial.print(z,HEX);
}

void AnalogueWrite(){
  int pos=Position_W.value();
  Position_R.setValue(Position_W.value());
  myservo.write(pos);              // tell servo to go to position in variable 'pos'
  Serial.print("\nServo position = "); 
  Serial.print(pos);
  Serial.print("degrees\n");
}

void ADXLSetup(){
  // ADXL Setup
  adxl.powerOn();
  
  //set activity/ inactivity thresholds (0-255)
  adxl.setActivityThreshold(75); //62.5mg per increment
  adxl.setInactivityThreshold(75); //62.5mg per increment
  adxl.setTimeInactivity(10); // how many seconds of no activity is inactive?
  
  //look of activity movement on this axes - 1 == on; 0 == off 
  adxl.setActivityX(1);
  adxl.setActivityY(1);
  adxl.setActivityZ(1);
  
  //look of inactivity movement on this axes - 1 == on; 0 == off
  adxl.setInactivityX(1);
  adxl.setInactivityY(1);
  adxl.setInactivityZ(1);
  
  //look of tap movement on this axes - 1 == on; 0 == off
  adxl.setTapDetectionOnX(0);
  adxl.setTapDetectionOnY(0);
  adxl.setTapDetectionOnZ(1);
  
  //set values for what is a tap, and what is a double tap (0-255)
  adxl.setTapThreshold(50); //62.5mg per increment
  adxl.setTapDuration(15); //625us per increment
  adxl.setDoubleTapLatency(80); //1.25ms per increment
  adxl.setDoubleTapWindow(200); //1.25ms per increment
  
  //set values for what is considered freefall (0-255)
  adxl.setFreeFallThreshold(7); //(5 - 9) recommended - 62.5mg per increment
  adxl.setFreeFallDuration(45); //(20 - 70) recommended - 5ms per increment
  
  //setting all interrupts to take place on int pin 1
  //I had issues with int pin 2, was unable to reset it
  adxl.setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_FREE_FALL_BIT,    ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_INACTIVITY_BIT,   ADXL345_INT1_PIN );
  
  //register interrupt actions - 1 == on; 0 == off  
  adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT,  1);
  adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);
  adxl.setInterrupt( ADXL345_INT_INACTIVITY_BIT, 1);
}