It is a simple IoT solution for plant life monitoring and maintenance, based on STM32NUCLEO boards and expansion modules. This branch is the post-eSAME development branch.

Dependencies:   BLE_API X_NUCLEO_IDB0XA1 X_NUCLEO_IKS01A1 mbed

Fork of BLE_GreenYourLife_STM32 by Green Building Team

This branch is the main continuation of the original project. You can find it here.

main.cpp

Committer:
kaiserhaz
Date:
2016-12-05
Revision:
4:e5550110184d
Parent:
3:c460d60ffda6

File content as of revision 4:e5550110184d:

/************************ STM32NUCLEO IOT Contest ******************************
 *
 *                   Green Building IoT Solution for
 *                Plant Life Monitoring And Maintenance
 *
 *                           Authored by
 *                        Dien Hoa Truong
 *                 Muhammad Haziq Bin Kamarul Azman
 *                        
 *                            for the
 *            eSAME 2016 STM32NUCLEO IoT Contest in Sophia-Antipolis
 *
 *  main.cpp | Program main
 *
 *  See LICENCE.txt for information on copyrights
 *
 ******************************************************************************/

/** Includes **/
#include "mbed.h"                                                               // ARM mbed               library
#include "x_nucleo_iks01a1.h"                                                   // STM32NUCLEO board      library
#include "ble/BLE.h"                                                            // Bluetooth LE           library
#include "GreenBuildingService.h"                                               // Green Building service library



/** Defines **/
#define GB_SOIL_MOISTURE_MAX 70                                                 // Soil moisture threshold value



/** Device declarations **/

// Board-specific
PwmOut pumpPWM(PC_8);                                                           // PWM motor control out pin
DigitalOut led1(LED1, 1);                                                       // Debug pin instance
AnalogIn moisture_sensor(PB_1);                                                 // Moisture sensor
static X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance(D14, D15); // Expansion board instance
static HumiditySensor   *humidity_sensor = mems_expansion_board->ht_sensor;     // Expansion board humidity sensor instance
static TempSensor       *temp_sensor     = mems_expansion_board->ht_sensor;     // Expansion board temperature sensor instance

// BLE-specific
BLE&                  ble = BLE::Instance(BLE::DEFAULT_INSTANCE);               // BLE device instance
const static char     DEVICE_NAME[] = "GB-Sensor";                              // Device name
static const uint16_t uuid16_list[] = {GreenBuildingService::UUID_GREEN_BUILDING_SERVICE};
GreenBuildingService *gbServicePtr;                                             // Service pointer

// Program-specific
float getMoistureValue();
float getHumidityValue();
float getTemperatureValue();
void errorLoop(void);
void activateFastSensorPoll();
void deactivateFastSensorPoll();
void pumpActivateCallback(void);
void pumpDeactivateCallback(void);

Ticker sanityTicker;
Ticker sensorPollTicker;
Ticker fastSensorPollTicker;
Timeout pumpWaitTimeout;
uint8_t usersConnected;
bool sensorPolling;
bool fastSensorPolling;
bool pumpActivate;
bool waitOnce;
bool bleActive;
bool pumpActive;


/** Callbacks **/

// BLE-specific callback
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)    // Callback for everytime the connection gets disconnected
{
    ble.gap().startAdvertising();                                               // Restart advertising
    if((!pumpActive)||(!usersConnected))
        deactivateFastSensorPoll();
    bleActive = false;
    --usersConnected;
//    printf("\r\n> BLE  : Disconnected. Advertising restarted.");
}

void connectionCallback(const Gap::ConnectionCallbackParams_t *params)          // Callback for everytime the connection is established
{
    ble.gap().stopAdvertising();                                                // Stop advertising
    activateFastSensorPoll();
    bleActive = true;
    ++usersConnected;
//    printf("\r\n> BLE  : Connected to %x. Accept no subsequent connections.", params->peerAddr);
}

void onBleInitError(BLE &ble, ble_error_t error)
{
//    printf("\r\n> BLE  : Init error encountered. Error returned: %d", error);
    errorLoop();
}

void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
    BLE&        ble   = params->ble;
    ble_error_t error = params->error;

    if (error != BLE_ERROR_NONE) {                                              // Check to see init errors
        onBleInitError(ble, error);
        errorLoop();
    }

    if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {                         // If this is not default instance (double instanciation?)
//        printf("\r\n> BLE  : BLE controller instance is invalid.");
        errorLoop();
    }
    
    ble.gap().onDisconnection(disconnectionCallback);                           // Register disconnection callback
    ble.gap().onConnection(connectionCallback);                                 // Register connection callback

    gbServicePtr = new GreenBuildingService(ble);                               // Init service with initial value
    
    /* Setup advertising. */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,(uint8_t *)uuid16_list, sizeof(uuid16_list));
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(1000); /* 1000ms */
    ble.gap().startAdvertising();
    
//    printf("\r\n> BLE  : BLE Init done.");
}

// Helper functions for retrieving data from sensors
float getMoistureValue()
{
    float moisture = 0;
    for (int i = 1;i<=10;i++) {
        moisture += moisture_sensor.read();                                     // Get ten samples
    }
    moisture = moisture / 10;
    moisture = moisture * 3300;                                                 // Change the value to be in the 0 to 3300 range
    moisture = moisture / 33;                                                   // Convert to percentage
    return moisture;
}

float getHumidityValue()
{
    float humidity = 0;
    humidity_sensor->GetHumidity(&humidity);
    return humidity;
}

float getTemperatureValue()
{
    float temperature = 0;
    temp_sensor->GetTemperature(&temperature);
    return temperature;
}


// Miscellaneous callbacks & functions
void sanityCallback(void)
{
    led1 = !led1;                                                               // Blink LED1 to indicate system sanity
}

void sensorPollCallback(void)
{
    sensorPolling = true;
}

void fastSensorPollCallback(void)
{
    fastSensorPolling = true;
}

void pumpActivateCallback(void)
{
    pumpActivate = true;
}

void pumpDeactivateCallback(void)
{
    pumpActivate = false;
}

void activateFastSensorPoll(void)
{
    fastSensorPolling = true;
    fastSensorPollTicker.attach(&fastSensorPollCallback, 0.9);
}

void deactivateFastSensorPoll(void)
{
    fastSensorPolling = false;
    fastSensorPollTicker.detach();
}


void errorLoop(void)
{
    sanityTicker.detach();
    sensorPollTicker.detach();
    ble.shutdown();
//    printf("\r\n> ERROR : Error encountered. Infinite looping.");
    while(true)
    {
        led1 != led1;        
    }
}



/** Pre-main inits **/



/** Main loop **/
int main(void)
{
    pumpPWM.write(1);
    pumpPWM.period(1.0f);
    
    printf("\r\n/**\r\n * Green Building Sensor Device: Debug Info\r\n */");
    
    sensorPolling = false;
    fastSensorPolling = false;
    pumpActivate = false;
    waitOnce = true;
    bleActive = false;
    pumpActive = false;
    
    sanityTicker.attach(sanityCallback, 1.1);                                   // LED sanity checker
    sensorPollTicker.attach(sensorPollCallback, 4.9);                           // Sensor poll ticker
    
    printf("\r\n> MAIN : Tickers initialized.");
 
    volatile GreenBuildingService::PlantEnvironmentType_t peVal;                // Plant environment var
    uint8_t pumpWaitTime = 3;                                                   // Pump waiting time
 
    ble.init(bleInitComplete);                                                  // Pass BLE init complete function upon init
    
//    while(ble.hasInitialized() == false);
    
    printf("\r\n> MAIN : BLE Init procedure done.");
    
    // Infinite loop
    while (true) {
        
        if(sensorPolling || fastSensorPolling)
        {
            sensorPolling = false;                                              // Deassert polling bit
            fastSensorPolling = false;
            
            peVal.soilMoisture   = (uint8_t) getMoistureValue();                // Update all measurements
            peVal.airHumidity    = (uint8_t) getHumidityValue();
            peVal.airTemperature = (int8_t)  getTemperatureValue();
            
            if(ble.getGapState().connected)                                     // Update characteristic if connected
                gbServicePtr->updatePlantEnvironment(peVal);
            
//            printf("\r\n> MAIN : Current soil moisture    = %d", peVal.soilMoisture);
//            printf("\r\n> MAIN : Current air humidity     = %d", peVal.airHumidity);
//            printf("\r\n> MAIN : Current air temperature  = %d", peVal.airTemperature);
            printf("%d\t%d\t%d\r\n", peVal.airTemperature, peVal.airHumidity, peVal.soilMoisture);
            
            // If moisture is below 50% of max when user is present
            //    or if less than 30% of max
            if( ( ((peVal.soilMoisture < 0.5*GB_SOIL_MOISTURE_MAX) &&  ble.getGapState().connected)   ||
                  ((peVal.soilMoisture < 0.3*GB_SOIL_MOISTURE_MAX) && !ble.getGapState().connected) ) &&
                waitOnce
            )
            {
                pumpWaitTimeout.attach(&pumpActivateCallback, pumpWaitTime);    // Waiting time is hard coded but may be calculated, I think
                activateFastSensorPoll();
                waitOnce = false;
                pumpActive = true;
            }
            else if((peVal.soilMoisture >= 0.6*GB_SOIL_MOISTURE_MAX) && pumpActivate) // Stop condition: when soil moisture is at 60% of max
            {
                pumpPWM.write(1);
                pumpWaitTimeout.detach();
                pumpDeactivateCallback();
                if(!bleActive)
                    deactivateFastSensorPoll();
                waitOnce = true;
                pumpActive = false;
            }
            
            if(pumpActivate)
            {
//                printf("\r\n> MAIN : Activating water pump.");
                pumpPWM.write(0.7);                
                pumpActivate = false;
                pumpWaitTimeout.attach(&pumpActivateCallback, 1);
            }
            
        }
        else
            ble.waitForEvent();                                                 //Low power wait for event   
        
    }
}