Project in progress
A Community Data Driven Air Quality Monitoring System

A Community Data Driven Air Quality Monitoring System © LGPL

My system rely on community data collection. Each user has a smog / air quality monitoring system and share collected data via Bluetooth.

  • 809 views
  • 0 comments
  • 5 respects

Components and supplies

About this project

Smog has been a serious problem in major cities in China PRC. In Beijing or similar cities, every year, there are few months that smog endanger people's health. However, the data collected and reported by the institutes do not reflect the reality because of limited samples collected.

My system rely on community data collection. Each user has a smog / air quality monitoring system and share collected data via Bluetooth and internet. An Bluetooth app will collect data, and then data will upload to a cloud services to share with other users in real time. This setup can truthfully represent the air quality in Beijing and similar cities.

The device will be small, portable, and battery powered. The device also include a local permanent storage using SD or micro SD card.

I propose a new architecture that enables BLE links between BLE Central (Sensors) to computer, PC, MAC, and Linux. In this architecture, there is a BLE Central and a BLE bridge. Both BLE Central and BLE bridge are Arduino 101.

This is how it works. The BLE Central collect sensor data and store them locally to an ASCII file. When BLE Central is connected to BLE bridge, user can send commands via BLE bridge to view live sensor data.

Because BLE bridge connect to host PC, MAC, or Linux via USB, different apps can be created native to that host. So far, not all operating systems fully support BLE. Programming BLE in C / C++ is extremely difficult.

By using a BE bridge architecture, it eliminates the steep learning curve of BLE programming.

The project is divided into THREE phases.

  • Phase1, working prototype + local data storage. Completed
  • Phase2, working prototype + local data storage + Bluetooth link to an App. Completed
  • Phase3, working prototype + local data storage + Bluetooth link to an App + a server to share data uploaded from an App. Ongoing

Code

BLE CentralArduino
BLE Central + VOC Sensor + SD Card
/*
    2017 Co-Making the Future Contest Entry
    Arduino 101
    BLE Center Service = Predefined BLE Service = "Environmental Sensing"
    Environmental Sensing UUID = 0x181A
    Last revised 2017-06-23 Wai Yung
 */


#include <CurieBLE.h>
#include <SparkFunCCS811.h>
#include <SPI.h>
#include <SD.h>


#define WY_ServiceName                  "AirQQQ_181A"
#define WY_ServiceUUID                  "181A"
#define NumOfByte_TxTx                  4               // Maximum 20 bytes
#define NumOfByte_RxRx                  NumOfByte_TxTx
#define TxTxIntervalMilliSecond_Debug   10000           // 10 Seconds interval = Debug
#define TxTxIntervalMilliSecond_Default 60000           // 60 Seconds interval = Default
#define NoDataOffset                    0
#define Working_SerialBaudRate          115200

#define Delay_Rx2Tx                     1000
#define Delay_BLEScan                   3000
#define Delay_VocSensor                 500
#define Delay_SdCard                    1000

#define Delay_Short                     1000
#define Delay_Medium                    6000
#define Delay_Long                      8000

#define CCS811_ADDR                     0x5B


/*
    1.   Predefined BLE 16 bit UUID 0x181A
    2.   Reference1 = www.bluetooth.com/specifications/gatt/services
         Reference2 = learn.adafruit.com/introduction-to-bluetooth-low-energy/gatt
         Reference3 = github.com/sparkfun/CCS811_Air_Quality_Breakout/blob/master/Libraries/Arduino/examples/BasicReadings/BasicReadings.ino
    3.   Last revised 2017-06-23 Wai Yung
 */


BLEService            WY_Service        (WY_ServiceUUID);
BLELongCharacteristic WY_Characteristic (WY_ServiceUUID, BLERead | BLEWrite | BLENotify);

CCS811                VocSensor         (CCS811_ADDR);

File                  VocSensorDataFile;


const long     Pre_Register_Write                   = 0x20000000L;
const long     Pre_Register_Read                    = 0x40000000L;

const long     Pre_SensorData_CO2                   = 0xE0000000L;
const long     Pre_SensorData_TVOC                  = 0xF0000000L;

const long     Cmd_DoNothing                        = 0x00000000L;

const long     Cmd_LedBuiltin_On                    = 0x00000001L;
const long     Cmd_LedBuiltin_Off                   = 0x00000002L;
const long     Cmd_LedBuiltin_Toggle                = 0x00000003L;
const long     Cmd_LedBuiltin_Blink                 = 0x00000004L;
const long     Cmd_LedBuiltin_Read                  = 0x00000005L;
const long     Cmd_Streaming_Start                  = 0x00000006L;
const long     Cmd_Streaming_Stop                   = 0x10000006L;

const long     Cmd_WR2Reg_StreamingInterval_Debug   = 0x00000010L | Pre_Register_Write;
const long     Cmd_WR2Reg_StreamingInterval_Default = 0x00000020L | Pre_Register_Write;

      long     s32TxTx           = Cmd_DoNothing;
      long     s32RxRx           = Cmd_DoNothing;
      
      short    u16RxRxLength     = 0;
      
      bool     booIsTxTxNow      = false;

      uint16_t u16VocSensor_CO2  = 0;  // VocSensor data = 16 unsigned
      uint16_t u16VocSensor_TVOC = 0;  // VocSensor data = 16 unsigned

      uint32_t u32VocSensor_CO2  = 0;  // BLE Tx    data = 32 unsigned
      uint32_t u32VocSensor_TVOC = 0;  // BLE Tx    data = 32 unsigned

      uint32_t u32NewMilliSecond = millis ();
      uint32_t u32OldMilliSecond = millis ();

      uint32_t u32Reg_StreamingInterval = TxTxIntervalMilliSecond_Default;  // Default, can be changed via BLE command


void WY_ToggleLed ()
{
    bool booStatus = digitalRead (LED_BUILTIN);

    booStatus = !booStatus;

    digitalWrite (LED_BUILTIN, booStatus);
}


void WY_BlinkLed ()
{
    bool booStatus = digitalRead (LED_BUILTIN);

    booStatus = !booStatus;  digitalWrite (LED_BUILTIN, booStatus);  delay (100);
    booStatus = !booStatus;  digitalWrite (LED_BUILTIN, booStatus);
}


void WY_ReadLed ()
{
    bool booStatus = digitalRead (LED_BUILTIN);

    if (booStatus == true) WY_Characteristic.setValue (0x00000001);
    else                   WY_Characteristic.setValue (0x00000000);
}


void setup ()
{
    Serial.begin (Working_SerialBaudRate);
    pinMode (LED_BUILTIN, OUTPUT);

    digitalWrite (LED_BUILTIN, LOW);  delay (1000);
    digitalWrite (LED_BUILTIN, HIGH); delay (1000);
    digitalWrite (LED_BUILTIN, LOW);  delay (1000);
    digitalWrite (LED_BUILTIN, HIGH); delay (1000);
    digitalWrite (LED_BUILTIN, LOW);  delay (1000);
    digitalWrite (LED_BUILTIN, HIGH); delay (1000);
    digitalWrite (LED_BUILTIN, LOW);  delay (1000);
    digitalWrite (LED_BUILTIN, HIGH); delay (1000);
    digitalWrite (LED_BUILTIN, LOW);  delay (1000);
    digitalWrite (LED_BUILTIN, HIGH); delay (1000);
    digitalWrite (LED_BUILTIN, LOW);  delay (1000);
    digitalWrite (LED_BUILTIN, HIGH); delay (1000);


    CCS811Core::status VocSensorReturnCode = VocSensor.begin();

    if (VocSensorReturnCode != CCS811Core::SENSOR_SUCCESS)
    {
        Serial.println (F("CCS811Core .begin() returned with an error"));

        while (1)
        {
            WY_BlinkLed ();
        }
    }


    Serial.println (F("BLE Start now"));

    BLE.begin ();                                      // Step1 = Begin initialization
    BLE.setLocalName             (WY_ServiceName);     // Step2 = Set advertised local name and service UUID:
    BLE.setAdvertisedService     (WY_Service);         // Step3 = Set advertised service
    WY_Service.addCharacteristic (WY_Characteristic);  // Step4 = Add characteristic to the service
    BLE.addService               (WY_Service);         // Step5 = Add service
    WY_Characteristic.setValue   (s32TxTx);            // Step6 = Set initial value for the characeristic:
    BLE.advertise ();                                  // Step7 = Start advertising

    Serial.println (F("AirQuality Peripheral"));
}


void loop ()
{
    BLEDevice The_BLE_Central = BLE.central ();  // Listen for BLE peripherals to connect

    delay (Delay_Short);

    if (The_BLE_Central)  // If a central is connected to peripheral
    {
        Serial.print   (F("Connected to central, MAC = "));  // Display the central MAC address
        Serial.println (The_BLE_Central.address ());

        while (The_BLE_Central.connected ())  // While BLE central is still connected to peripheral
        {
            // If the remote device write to the characteristic,
            // Use the value to control the LED
            //
            if (WY_Characteristic.written ())
            {
                u16RxRxLength = WY_Characteristic.valueLength ();
                      s32RxRx = WY_Characteristic.value ();

                Serial.print   (F("u16RxRxLength = "));
                Serial.println (u16RxRxLength, DEC);

                Serial.print   (F("s32RxRx = "));
                Serial.println (s32RxRx, DEC);

                if      (s32RxRx == Cmd_LedBuiltin_On)                    {digitalWrite (LED_BUILTIN, HIGH);}
                else if (s32RxRx == Cmd_LedBuiltin_Off)                   {digitalWrite (LED_BUILTIN, LOW);}
                else if (s32RxRx == Cmd_LedBuiltin_Toggle)                {WY_ToggleLed ();}
                else if (s32RxRx == Cmd_LedBuiltin_Blink)                 {WY_BlinkLed  ();}
                else if (s32RxRx == Cmd_LedBuiltin_Read)                  {WY_ReadLed   ();}

                else if (s32RxRx == Cmd_Streaming_Start)                  {booIsTxTxNow = true;}
                else if (s32RxRx == Cmd_Streaming_Stop)                   {booIsTxTxNow = false;}

                else if (s32RxRx == Cmd_WR2Reg_StreamingInterval_Debug)   {u32Reg_StreamingInterval = TxTxIntervalMilliSecond_Debug;}
                else if (s32RxRx == Cmd_WR2Reg_StreamingInterval_Default) {u32Reg_StreamingInterval = TxTxIntervalMilliSecond_Default;}
            }

            // If BLE Central BLE Pherial is connected, device need to take measurement
            //
            u32NewMilliSecond = millis ();

            if (u32NewMilliSecond - u32OldMilliSecond >= u32Reg_StreamingInterval)
            {
                u32OldMilliSecond = u32NewMilliSecond;

                if (VocSensor.dataAvailable ())
                {
                    //  If so, have the sensor read and calculate the results
                    //
                    VocSensor.readAlgorithmResults ();
  
                    delay (Delay_VocSensor);
  
                    u16VocSensor_CO2  = VocSensor.getCO2  ();
                    u16VocSensor_TVOC = VocSensor.getTVOC ();
  
                    u32VocSensor_CO2  = ((uint32_t) u16VocSensor_CO2)  & 0x0000FFFFL;  // 16 bit to 32 bit Extension
                    u32VocSensor_TVOC = ((uint32_t) u16VocSensor_TVOC) & 0x0000FFFFL;  // 16 bit to 32 bit Extension
  
                    u32VocSensor_CO2  = u32VocSensor_CO2  | Pre_SensorData_CO2;        // Add prefix
                    u32VocSensor_TVOC = u32VocSensor_TVOC | Pre_SensorData_TVOC;       // Add prefix
                }

                if (booIsTxTxNow == true)
                {
                    if (WY_Characteristic.setValue (u32VocSensor_CO2) == false)
                    {
                        Serial.println (F("Characteristic.setValue u32VocSensor_CO2 FAILED"));
                    }

                    delay (Delay_VocSensor);

                    if (WY_Characteristic.setValue (u32VocSensor_TVOC) == false)
                    {
                        Serial.println (F("Characteristic.setValue u32VocSensor_TVOC FAILED"));
                    }

                    if (!SD.begin ())
                    {
                        Serial.println (F("SD Card is not present"));
                    }
                    
                    delay (Delay_SdCard);
                    
                    VocSensorDataFile = SD.open ("VocData.txt", FILE_WRITE);
                    
                    if (VocSensorDataFile)
                    {
                        VocSensorDataFile.print   (u32VocSensor_CO2,  DEC);  // 1.  VOC Sensor CO2  raw reading
                        VocSensorDataFile.print   (", ");                    // 2.  Comma separated
                        VocSensorDataFile.println (u32VocSensor_TVOC, DEC);  // 3.  VOC Sensor TVOC raw reading + new line

                        VocSensorDataFile.close();
                    }

                    WY_ToggleLed ();
                }
            }
        }

        booIsTxTxNow = false;
        s32TxTx      = Cmd_DoNothing;

        Serial.print   (F("Disconnected from central, MAC = "));  // If BLE central disconnect, display central MAC
        Serial.println (The_BLE_Central.address ());
    }


    // If BLE Central BLE Pherial not connected, still need to take measurement
    //
    u32NewMilliSecond = millis ();
  
    if (u32NewMilliSecond - u32OldMilliSecond >= u32Reg_StreamingInterval)
    {
        u32OldMilliSecond = u32NewMilliSecond;

        if (VocSensor.dataAvailable ())
        {
            //  If so, have the sensor read and calculate the results
            //
            VocSensor.readAlgorithmResults ();
            
            delay (Delay_VocSensor);
            
            u16VocSensor_CO2  = VocSensor.getCO2  ();
            u16VocSensor_TVOC = VocSensor.getTVOC ();
            
            u32VocSensor_CO2  = ((uint32_t) u16VocSensor_CO2)  & 0x0000FFFFL;  // 16 bit to 32 bit Extension
            u32VocSensor_TVOC = ((uint32_t) u16VocSensor_TVOC) & 0x0000FFFFL;  // 16 bit to 32 bit Extension
            
            u32VocSensor_CO2  = u32VocSensor_CO2  | Pre_SensorData_CO2;        // Add prefix
            u32VocSensor_TVOC = u32VocSensor_TVOC | Pre_SensorData_TVOC;       // Add prefix
            
            if (WY_Characteristic.setValue (u32VocSensor_CO2) == false)
            {
                Serial.println (F("Characteristic.setValue u32VocSensor_CO2 FAILED"));
            }
            
            delay (Delay_VocSensor);
            
            if (WY_Characteristic.setValue (u32VocSensor_TVOC) == false)
            {
                Serial.println (F("Characteristic.setValue u32VocSensor_TVOC FAILED"));
            }
            
            if (!SD.begin ())
            {
                Serial.println (F("SD Card is not present"));
            }
            
            delay (Delay_SdCard);
            
            VocSensorDataFile = SD.open ("VocData.txt", FILE_WRITE);
            
            if (VocSensorDataFile)
            {
                VocSensorDataFile.print   (u32VocSensor_CO2,  DEC);  // 1.  VOC Sensor CO2  raw reading
                VocSensorDataFile.print   (", ");                    // 2.  Comma separated
                VocSensorDataFile.println (u32VocSensor_TVOC, DEC);  // 3.  VOC Sensor TVOC raw reading + new line
                
                VocSensorDataFile.close ();
            }
        }
    }


    delay (Delay_Medium);
    Serial.println (F("BLE Central ready to connect again"));
}
BLE Bridge SketchArduino
BLE Bridge only. Download this sketch to a second Arduino 101, connect to PC, open terminal at 115200, enter commands
/*
    2017 Co-Making the Future Contest Entry
    Arduino 101
    Serial-to-BLE Bridge
    Last revised 2017-06-23 Wai Yung
 */


/*
    Reference1 = www.bluetooth.com/specifications/gatt/services
    Reference2 = learn.adafruit.com/introduction-to-bluetooth-low-energy/gatt
 */


#include <CurieBLE.h>


#define WaiYung_ServiceName             "AirQQQ_181A"
#define WaiYung_ServiceUUID             "181A"
#define NumOfByte_TxTx                  4               // Maximum 20 bytes
#define NumOfByte_RxRx                  NumOfByte_TxTx
#define TxTxIntervalMilliSecond_Debug   10000           // 10 Seconds interval = Debug
#define TxTxIntervalMilliSecond_Default 60000           // 60 Seconds interval = Default
#define NoDataOffset                    0
#define Working_SerialBaudRate          115200

#define Delay_Rx2Tx                     1000
#define Delay_BLEScan                   3000
#define Delay_SdCard                    1000

#define Delay_Short                     1000
#define Delay_Medium                    6000
#define Delay_Long                      8000


const byte      Pre_SensorData_CO2                      = 0xE0;
const byte      Pre_SensorData_TVOC                     = 0xF0;

const byte      Cmd_DoNothing                       [4] = {0x00, 0x00, 0x00, 0x00};

const byte      Cmd_LedBuiltin_On                   [4] = {0x01, 0x00, 0x00, 0x00};
const byte      Cmd_LedBuiltin_Off                  [4] = {0x02, 0x00, 0x00, 0x00};
const byte      Cmd_LedBuiltin_Toggle               [4] = {0x03, 0x00, 0x00, 0x00};
const byte      Cmd_LedBuiltin_Blink                [4] = {0x04, 0x00, 0x00, 0x00};
const byte      Cmd_LedBuiltin_Read                 [4] = {0x05, 0x00, 0x00, 0x00};

const byte      Cmd_Streaming_Start                 [4] = {0x06, 0x00, 0x00, 0x00};  // By default, BLE send 0x06 as LSByte
const byte      Cmd_Streaming_Stop                  [4] = {0x06, 0x00, 0x00, 0x10};  // By default, BLE send 0x06 as LSByte, 0x10 as MSByte

const byte      Cmd_WR2Reg_StreamingInterval_Debug  [4] = {0x10, 0x00, 0x00, 0x20};
const byte      Cmd_WR2Reg_StreamingInterval_Default[4] = {0x20, 0x00, 0x00, 0x20};

const byte      Cmd_Disconnect_Arduino101BLE        [4] = {0x40, 0x40, 0x40, 0x40};

      byte      byCmdPrefix                             = 0x00;

//    byte      byTxTx[4]                               = {Cmd_DoNothing[0], Cmd_DoNothing[1], Cmd_DoNothing[2], Cmd_DoNothing[3]};  // In case to build custom commands on the fly

      long      lgRxRx        = 0x00000000L;
      
      uint16_t  u16RxRxLength = 0;

const String    Def_DoNothing                        = "DoNothing";

const String    Def_LedBuiltin_On                    = "LedBuiltin_On";
const String    Def_LedBuiltin_Off                   = "LedBuiltin_Off";
const String    Def_LedBuiltin_Toggle                = "LedBuiltin_Toggle";
const String    Def_LedBuiltin_Blink                 = "LedBuiltin_Blink";
const String    Def_LedBuiltin_Read                  = "LedBuiltin_Read";

const String    Def_Streaming_Start                  = "Streaming_Start";
const String    Def_Streaming_Stop                   = "Streaming_Stop";

const String    Def_WR2Reg_StreamingInterval_Debug   = "WR2Reg_StreamingInterval_Debug";
const String    Def_WR2Reg_StreamingInterval_Default = "WR2Reg_StreamingInterval_Default";

const String    Def_Disconnect_Arduino101BLE         = "Disconnect_Arduino101BLE";

      String    Str_UserCmd                          = Def_DoNothing;


      BLEDevice AirQQQPeripheral;


void WY_BlinkLed ()
{
    bool booStatus = digitalRead (LED_BUILTIN);

    booStatus = !booStatus;  digitalWrite (LED_BUILTIN, booStatus);  delay (100);
    booStatus = !booStatus;  digitalWrite (LED_BUILTIN, booStatus);
}


void setup ()
{
    Serial.begin (Working_SerialBaudRate);
    pinMode (LED_BUILTIN, OUTPUT);

    digitalWrite (LED_BUILTIN, LOW);  delay (1000);
    digitalWrite (LED_BUILTIN, HIGH); delay (1000);
    digitalWrite (LED_BUILTIN, LOW);  delay (1000);
    digitalWrite (LED_BUILTIN, HIGH); delay (1000);
    digitalWrite (LED_BUILTIN, LOW);  delay (1000);
    digitalWrite (LED_BUILTIN, HIGH); delay (1000);

    Serial.println (" ");
    Serial.print   (F("BLE Central = "));
    Serial.println (WaiYung_ServiceName);

    BLE.begin ();                           // 1.   Initialize Arduino 101 BLE

    delay (Delay_Short);
}


void loop ()
{
    BLE.scanForUuid (WaiYung_ServiceUUID);  // 2.   Start scanning BLE peripherals

    delay (Delay_Short);

    AirQQQPeripheral = BLE.available ();    // 3.   Check if a peripheral has been discovered

    delay (Delay_Short);

    if (AirQQQPeripheral)
    {
        Serial.print   (F("BLE Peripheral discovered at address "));     // 1.   Discovered a peripheral, print out address
        Serial.println (AirQQQPeripheral.address ());
        Serial.print   (F("BLE Peripheral localName is "));              // 2.   Discovered a peripheral, local name
        Serial.println (AirQQQPeripheral.localName ());
        Serial.print   (F("BLE Peripheral service UUID is "));           // 3.   Discovered a peripheral, advertised service
        Serial.println (AirQQQPeripheral.advertisedServiceUuid ());
        Serial.println (" ");
        Serial.println (" ");

        BLE.stopScan ();                                                 // 4.   Because of discovering a peripheral, stop BLE scanning

        if (AirQQQPeripheral.connect ())
        {
            Serial.println (F("BLE Peripheral is connected"));
        }
        else
        {
            Serial.println (F("BLE Peripheral is NOT connected"));
            while (1) {WY_BlinkLed ();}
        }


        Serial.println (F("Ready to retrieve BLE peripheral attributes"));
    
        if (AirQQQPeripheral.discoverAttributes ())
        {
            Serial.println (F("BLE Peripheral attributes discovered"));
        }
        else
        {
            Serial.println (F("BLE Peripheral attributes NOT discovered"));
            while (1) {WY_BlinkLed ();}
        }


        Serial.println (F("Ready to retrieve BLE peripheral characteristic"));
    
        BLECharacteristic AirQQQCharacteristic = AirQQQPeripheral.characteristic (WaiYung_ServiceUUID);
    
        if (!AirQQQCharacteristic)
        {
            Serial.println (F("BLE Peripheral DO NOT have AirQQQCharacteristic"));
            while (1) {WY_BlinkLed ();}
        }
        else if (!AirQQQCharacteristic.canWrite ())
        {
            Serial.println (F("BLE Peripheral DO NOT accept AirQQQCharacteristic command"));
            while (1) {WY_BlinkLed ();}
        }


        Serial.println (F("Ready to send command to BLE peripheral"));
        
        if (AirQQQPeripheral.connected ())
        {
            AirQQQCharacteristic.writeValue (Cmd_DoNothing, NumOfByte_TxTx);  // 5.   Tx command
            Serial.println (F("Sent command Cmd_StreamingStart to BLE peripheral"));
        }
        else
        {
            Serial.println (F("Error when sending ommand to BLE peripheral"));
            while (1) {WY_BlinkLed ();}
        }


        Serial.println (" ");
        Serial.println (" ");


        if (AirQQQCharacteristic.canRead ())
        {
            Serial.println (F("BLE peripheral can handle READ"));
        }
        else
        {
            Serial.println (F("BLE peripheral CANNOT handle READ"));
            while (1) {WY_BlinkLed ();}
        }


        if (AirQQQCharacteristic.canWrite ())
        {
            Serial.println (F("BLE peripheral can handle WRITE"));
        }
        else
        {
            Serial.println (F("BLE peripheral CANNOT handle WRITE"));
            while (1) {WY_BlinkLed ();}
        }


        if (AirQQQCharacteristic.canNotify ())
        {
            Serial.println (F("BLE peripheral can handle NOTIFY"));
        }
        else
        {
            Serial.println (F("BLE peripheral CANNOT handle NOTIFY"));
            while (1) {WY_BlinkLed ();}
        }


        if (AirQQQCharacteristic.canSubscribe ())
        {
            Serial.println (F("BLE peripheral can handle SUBSCRIBE"));
            AirQQQCharacteristic.subscribe ();
        }
        else
        {
            Serial.println (F("BLE peripheral CANNOT handle SUBSCRIBE"));
            while (1) {WY_BlinkLed ();}
        }


        Serial.print   (F("BLE Peripheral maximum size = "));
        Serial.println (AirQQQCharacteristic.valueSize (), DEC);


        while (1)
        {
            // Bridge from BLE to Serial
            //
            if (AirQQQCharacteristic.valueUpdated ())
            {
                u16RxRxLength = AirQQQCharacteristic.valueLength ();
                       lgRxRx = AirQQQCharacteristic.longValue ();

                Serial.print   (F("u16RxRxLength in decimal = "));
                Serial.println (u16RxRxLength, DEC);
                Serial.print   (F("lgRxRx in decimal = "));
                Serial.println (lgRxRx, DEC);

                byCmdPrefix = (lgRxRx >> 24);  // MSByte = Sensor data prefix

                if (byCmdPrefix == Pre_SensorData_CO2)
                {
                    Serial.print   (F("VocSensor CO2  raw reading = "));
                    Serial.println (lgRxRx, DEC);
                }

                if (byCmdPrefix == Pre_SensorData_TVOC)
                {
                    Serial.print   (F("VocSensor TVOC raw reading = "));
                    Serial.println (lgRxRx, DEC);
                }
            }


            delay (Delay_Rx2Tx);


            if (AirQQQPeripheral.connected ())
            {
                AirQQQCharacteristic.writeValue (Cmd_DoNothing, NumOfByte_TxTx);
//              Serial.println (F("Sent command Cmd_StreamingStart to BLE peripheral"));
            }
            else
            {
                Serial.println (F("Error when sending ommand to BLE peripheral"));
                break;
            }

            delay (Delay_Rx2Tx);
            

            // Bridge from Serial to BLE
            //
            if (Serial.available () > 0)
            {
                Str_UserCmd = Serial.readStringUntil (';');

                Serial.println (" ");
                Serial.print   (F("Original  UserCmd = "));
                Serial.println (Str_UserCmd);

                Str_UserCmd.toLowerCase ();

                Serial.print   (F("LowerCase UserCmd = "));
                Serial.println (Str_UserCmd);
                Serial.println (" ");

                if      (Str_UserCmd.equalsIgnoreCase (Def_LedBuiltin_On))                    {AirQQQCharacteristic.writeValue (Cmd_LedBuiltin_On,                    NumOfByte_TxTx);  Serial.println (F("Matched = Cmd_LedBuiltin_On"));}
                else if (Str_UserCmd.equalsIgnoreCase (Def_LedBuiltin_Off))                   {AirQQQCharacteristic.writeValue (Cmd_LedBuiltin_Off,                   NumOfByte_TxTx);  Serial.println (F("Matched = Cmd_LedBuiltin_Off"));}
                else if (Str_UserCmd.equalsIgnoreCase (Def_LedBuiltin_Toggle))                {AirQQQCharacteristic.writeValue (Cmd_LedBuiltin_Toggle,                NumOfByte_TxTx);  Serial.println (F("Matched = Cmd_LedBuiltin_Toggle"));}
                else if (Str_UserCmd.equalsIgnoreCase (Def_LedBuiltin_Blink))                 {AirQQQCharacteristic.writeValue (Cmd_LedBuiltin_Blink,                 NumOfByte_TxTx);  Serial.println (F("Matched = Cmd_LedBuiltin_Blink"));}
                else if (Str_UserCmd.equalsIgnoreCase (Def_LedBuiltin_Read))                  {AirQQQCharacteristic.writeValue (Cmd_LedBuiltin_Read,                  NumOfByte_TxTx);  Serial.println (F("Matched = Cmd_LedBuiltin_Read"));}

                else if (Str_UserCmd.equalsIgnoreCase (Def_Streaming_Start))                  {AirQQQCharacteristic.writeValue (Cmd_Streaming_Start,                  NumOfByte_TxTx);  Serial.println (F("Matched = Cmd_Streaming_Start"));}
                else if (Str_UserCmd.equalsIgnoreCase (Def_Streaming_Stop))                   {AirQQQCharacteristic.writeValue (Cmd_Streaming_Stop,                   NumOfByte_TxTx);  Serial.println (F("Matched = Cmd_Streaming_Stop"));}

                else if (Str_UserCmd.equalsIgnoreCase (Def_WR2Reg_StreamingInterval_Debug))   {AirQQQCharacteristic.writeValue (Cmd_WR2Reg_StreamingInterval_Debug,   NumOfByte_TxTx);  Serial.println (F("Matched = Cmd_WR2Reg_StreamingInterval_Debug"));}
                else if (Str_UserCmd.equalsIgnoreCase (Def_WR2Reg_StreamingInterval_Default)) {AirQQQCharacteristic.writeValue (Cmd_WR2Reg_StreamingInterval_Default, NumOfByte_TxTx);  Serial.println (F("Matched = Cmd_WR2Reg_StreamingInterval_Default"));}

                else if (Str_UserCmd.equalsIgnoreCase (Def_Disconnect_Arduino101BLE))
                     {
                         AirQQQPeripheral.disconnect ();

                         Serial.println (" ");
                         Serial.println (F("Disconnect Arduino101 BLE"));
                         Serial.println (F("Going into sleep now"));
                         Serial.println (F("You must use hardware reset to restart everything"));
                         Serial.println (" ");

                         while (1);
                     }

                Str_UserCmd = Def_DoNothing;  // Reset user command to default.  Otherwise, resend the same command again by mistake
            }
        }
    }

    Serial.println (F("Ready to BLE scan again"));

    delay (Delay_BLEScan);
}

Schematics

BLE Central and Bridge Architecture
This presentation illustrate the application, architecture, data flow, and building of the system
Prototpye of BLE Central View1
Ble1 zcg03ovwsi
Prototpye of BLE Central View2
Ble2 b1xnkj9c3j
Prototpye of BLE Central View3
Ble3 5kznxab875
Prototpye of BLE Central View4
Ble4 5prvn8j60o

Comments

Similar projects you might like

Smart Garbage Monitoring System Using Arduino 101

Project tutorial by Technovation

  • 21,403 views
  • 7 comments
  • 32 respects

Arduino 101 Home BLE System

Project tutorial by Alexis Santiago Allende

  • 2,424 views
  • 0 comments
  • 11 respects

Arduino101 / tinyTILE BLE: Match-Making Sunglasses

Project tutorial by Kitty Yeung

  • 11,336 views
  • 2 comments
  • 35 respects

Cardiac Monitoring System - EKG

Project showcase by Zorzonel Vlad

  • 10,440 views
  • 7 comments
  • 34 respects

Indoor Air Quality Monitoring System

Project tutorial by Team East West University

  • 9,135 views
  • 3 comments
  • 40 respects

BluSpike - Community Driven BLE Sensor Network

Project tutorial by Team Hack.Build

  • 1,415 views
  • 1 comment
  • 6 respects
Add projectSign up / Login