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.

Committer:
kaiserhaz
Date:
Fri Dec 02 17:36:56 2016 +0000
Revision:
5:9d68ed883e95
Parent:
3:c460d60ffda6
Child:
6:35d615722597
Reworked the code for better use of resource. Seems to be a bit buggy at the moment. +, can it handle an hourly interrupt?

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kaiserhaz 0:7dce5e74ad91 1 /************************ STM32NUCLEO IOT Contest ******************************
kaiserhaz 0:7dce5e74ad91 2 *
kaiserhaz 0:7dce5e74ad91 3 * Green Building IoT Solution for
kaiserhaz 0:7dce5e74ad91 4 * Plant Life Monitoring And Maintenance
kaiserhaz 0:7dce5e74ad91 5 *
kaiserhaz 0:7dce5e74ad91 6 * Authored by
kaiserhaz 0:7dce5e74ad91 7 * Dien Hoa Truong
kaiserhaz 0:7dce5e74ad91 8 * Muhammad Haziq Bin Kamarul Azman
kaiserhaz 0:7dce5e74ad91 9 *
kaiserhaz 0:7dce5e74ad91 10 * main.cpp | Program main
kaiserhaz 0:7dce5e74ad91 11 *
kaiserhaz 0:7dce5e74ad91 12 ******************************************************************************/
kaiserhaz 0:7dce5e74ad91 13
kaiserhaz 0:7dce5e74ad91 14 /** Includes **/
kaiserhaz 0:7dce5e74ad91 15 #include "mbed.h" // ARM mbed library
kaiserhaz 0:7dce5e74ad91 16 #include "x_nucleo_iks01a1.h" // STM32NUCLEO board library
kaiserhaz 0:7dce5e74ad91 17 #include "ble/BLE.h" // Bluetooth LE library
kaiserhaz 0:7dce5e74ad91 18 #include "GreenBuildingService.h" // Green Building service library
kaiserhaz 0:7dce5e74ad91 19
kaiserhaz 0:7dce5e74ad91 20
kaiserhaz 0:7dce5e74ad91 21
kaiserhaz 0:7dce5e74ad91 22 /** Defines **/
kaiserhaz 2:326a19b95766 23 #define GB_SOIL_MOISTURE_MAX 70 // Soil moisture threshold value
kaiserhaz 5:9d68ed883e95 24 #define GB_USERS_CONNECTED_MAX 4 // Maximum connected users
kaiserhaz 5:9d68ed883e95 25 #define GB_PUMP_CYCLE_MAX 40 // Maximum pump cycle allowed
kaiserhaz 0:7dce5e74ad91 26
kaiserhaz 0:7dce5e74ad91 27
kaiserhaz 0:7dce5e74ad91 28
kaiserhaz 0:7dce5e74ad91 29 /** Device declarations **/
kaiserhaz 0:7dce5e74ad91 30
kaiserhaz 0:7dce5e74ad91 31 // Board-specific
kaiserhaz 5:9d68ed883e95 32 PwmOut pumpPWM(PC_8); // PWM motor control out pin
kaiserhaz 0:7dce5e74ad91 33 DigitalOut led1(LED1, 1); // Debug pin instance
kaiserhaz 5:9d68ed883e95 34 AnalogIn moisture_sensor(PB_1); // Moisture sensor
kaiserhaz 0:7dce5e74ad91 35 static X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance(D14, D15); // Expansion board instance
kaiserhaz 5:9d68ed883e95 36 static HumiditySensor *humidity_sensor = mems_expansion_board->ht_sensor; // Expansion board humidity sensor instance
kaiserhaz 5:9d68ed883e95 37 static TempSensor *temp_sensor = mems_expansion_board->ht_sensor; // Expansion board temperature sensor instance
kaiserhaz 0:7dce5e74ad91 38
kaiserhaz 0:7dce5e74ad91 39 // BLE-specific
kaiserhaz 0:7dce5e74ad91 40 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); // BLE device instance
kaiserhaz 0:7dce5e74ad91 41 const static char DEVICE_NAME[] = "GB-Sensor"; // Device name
kaiserhaz 5:9d68ed883e95 42 static const uint16_t uuid16_list[] = {GreenBuildingService::UUID_GREEN_BUILDING_SERVICE}; // UUID service list
kaiserhaz 0:7dce5e74ad91 43 GreenBuildingService *gbServicePtr; // Service pointer
kaiserhaz 5:9d68ed883e95 44 //Gap::Handle_t bleConnectionHandles[GB_USERS_CONNECTED_MAX]; // Connection handle tables
kaiserhaz 0:7dce5e74ad91 45
kaiserhaz 0:7dce5e74ad91 46 // Program-specific
kaiserhaz 0:7dce5e74ad91 47 float getMoistureValue();
kaiserhaz 0:7dce5e74ad91 48 float getHumidityValue();
kaiserhaz 0:7dce5e74ad91 49 float getTemperatureValue();
kaiserhaz 5:9d68ed883e95 50 void errorLoop(void);
kaiserhaz 5:9d68ed883e95 51 void activateFastSensorPoll();
kaiserhaz 5:9d68ed883e95 52 void deactivateFastSensorPoll();
kaiserhaz 5:9d68ed883e95 53 void pumpActivateCallback(void);
kaiserhaz 5:9d68ed883e95 54 void pumpDeactivateCallback(void);
kaiserhaz 0:7dce5e74ad91 55
kaiserhaz 5:9d68ed883e95 56 Ticker sanityTicker;
kaiserhaz 5:9d68ed883e95 57 Ticker sensorPollTicker;
kaiserhaz 5:9d68ed883e95 58 Ticker fastSensorPollTicker;
kaiserhaz 2:326a19b95766 59 Timeout pumpWaitTimeout;
kaiserhaz 5:9d68ed883e95 60
kaiserhaz 5:9d68ed883e95 61 uint8_t pumpWaitTime = 3; // Pump waiting time
kaiserhaz 3:c460d60ffda6 62 uint8_t usersConnected;
kaiserhaz 5:9d68ed883e95 63 bool sensorPolling;
kaiserhaz 5:9d68ed883e95 64 bool fastSensorPolling;
kaiserhaz 5:9d68ed883e95 65 bool bleActive;
kaiserhaz 5:9d68ed883e95 66 bool pumpActive;
kaiserhaz 5:9d68ed883e95 67
kaiserhaz 0:7dce5e74ad91 68
kaiserhaz 0:7dce5e74ad91 69
kaiserhaz 0:7dce5e74ad91 70 /** Callbacks **/
kaiserhaz 0:7dce5e74ad91 71
kaiserhaz 0:7dce5e74ad91 72 // BLE-specific callback
kaiserhaz 0:7dce5e74ad91 73 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) // Callback for everytime the connection gets disconnected
kaiserhaz 0:7dce5e74ad91 74 {
kaiserhaz 0:7dce5e74ad91 75 ble.gap().startAdvertising(); // Restart advertising
kaiserhaz 3:c460d60ffda6 76 if((!pumpActive)||(!usersConnected))
kaiserhaz 2:326a19b95766 77 deactivateFastSensorPoll();
kaiserhaz 2:326a19b95766 78 bleActive = false;
kaiserhaz 3:c460d60ffda6 79 --usersConnected;
kaiserhaz 0:7dce5e74ad91 80 }
kaiserhaz 0:7dce5e74ad91 81
kaiserhaz 0:7dce5e74ad91 82 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) // Callback for everytime the connection is established
kaiserhaz 0:7dce5e74ad91 83 {
kaiserhaz 5:9d68ed883e95 84 if(usersConnected>GB_USERS_CONNECTED_MAX)
kaiserhaz 5:9d68ed883e95 85 ble.disconnect(params->handle, Gap::REMOTE_USER_TERMINATED_CONNECTION); // Disconnect automatically due to connection constraint
kaiserhaz 5:9d68ed883e95 86 else
kaiserhaz 5:9d68ed883e95 87 {
kaiserhaz 5:9d68ed883e95 88 activateFastSensorPoll();
kaiserhaz 5:9d68ed883e95 89 bleActive = true;
kaiserhaz 5:9d68ed883e95 90 ++usersConnected;
kaiserhaz 5:9d68ed883e95 91 }
kaiserhaz 0:7dce5e74ad91 92 }
kaiserhaz 0:7dce5e74ad91 93
kaiserhaz 0:7dce5e74ad91 94 void onBleInitError(BLE &ble, ble_error_t error)
kaiserhaz 0:7dce5e74ad91 95 {
kaiserhaz 0:7dce5e74ad91 96 errorLoop();
kaiserhaz 0:7dce5e74ad91 97 }
kaiserhaz 0:7dce5e74ad91 98
kaiserhaz 0:7dce5e74ad91 99 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
kaiserhaz 0:7dce5e74ad91 100 {
kaiserhaz 0:7dce5e74ad91 101 BLE& ble = params->ble;
kaiserhaz 0:7dce5e74ad91 102 ble_error_t error = params->error;
kaiserhaz 0:7dce5e74ad91 103
kaiserhaz 0:7dce5e74ad91 104 if (error != BLE_ERROR_NONE) { // Check to see init errors
kaiserhaz 0:7dce5e74ad91 105 onBleInitError(ble, error);
kaiserhaz 0:7dce5e74ad91 106 errorLoop();
kaiserhaz 0:7dce5e74ad91 107 }
kaiserhaz 0:7dce5e74ad91 108
kaiserhaz 0:7dce5e74ad91 109 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { // If this is not default instance (double instanciation?)
kaiserhaz 0:7dce5e74ad91 110 errorLoop();
kaiserhaz 0:7dce5e74ad91 111 }
kaiserhaz 0:7dce5e74ad91 112
kaiserhaz 0:7dce5e74ad91 113 ble.gap().onDisconnection(disconnectionCallback); // Register disconnection callback
kaiserhaz 0:7dce5e74ad91 114 ble.gap().onConnection(connectionCallback); // Register connection callback
kaiserhaz 0:7dce5e74ad91 115
kaiserhaz 0:7dce5e74ad91 116 gbServicePtr = new GreenBuildingService(ble); // Init service with initial value
kaiserhaz 0:7dce5e74ad91 117
kaiserhaz 0:7dce5e74ad91 118 /* Setup advertising. */
kaiserhaz 0:7dce5e74ad91 119 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
kaiserhaz 0:7dce5e74ad91 120 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
kaiserhaz 0:7dce5e74ad91 121 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,(uint8_t *)uuid16_list, sizeof(uuid16_list));
kaiserhaz 0:7dce5e74ad91 122 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
kaiserhaz 0:7dce5e74ad91 123 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
kaiserhaz 0:7dce5e74ad91 124 ble.gap().startAdvertising();
kaiserhaz 0:7dce5e74ad91 125 }
kaiserhaz 0:7dce5e74ad91 126
kaiserhaz 0:7dce5e74ad91 127 // Helper functions for retrieving data from sensors
kaiserhaz 0:7dce5e74ad91 128 float getMoistureValue()
kaiserhaz 0:7dce5e74ad91 129 {
kaiserhaz 0:7dce5e74ad91 130 float moisture = 0;
kaiserhaz 0:7dce5e74ad91 131 for (int i = 1;i<=10;i++) {
kaiserhaz 0:7dce5e74ad91 132 moisture += moisture_sensor.read(); // Get ten samples
kaiserhaz 0:7dce5e74ad91 133 }
kaiserhaz 0:7dce5e74ad91 134 moisture = moisture / 10;
kaiserhaz 0:7dce5e74ad91 135 moisture = moisture * 3300; // Change the value to be in the 0 to 3300 range
kaiserhaz 0:7dce5e74ad91 136 moisture = moisture / 33; // Convert to percentage
kaiserhaz 0:7dce5e74ad91 137 return moisture;
kaiserhaz 0:7dce5e74ad91 138 }
kaiserhaz 0:7dce5e74ad91 139
kaiserhaz 0:7dce5e74ad91 140 float getHumidityValue()
kaiserhaz 0:7dce5e74ad91 141 {
kaiserhaz 0:7dce5e74ad91 142 float humidity = 0;
kaiserhaz 0:7dce5e74ad91 143 humidity_sensor->GetHumidity(&humidity);
kaiserhaz 0:7dce5e74ad91 144 return humidity;
kaiserhaz 0:7dce5e74ad91 145 }
kaiserhaz 0:7dce5e74ad91 146
kaiserhaz 0:7dce5e74ad91 147 float getTemperatureValue()
kaiserhaz 0:7dce5e74ad91 148 {
kaiserhaz 0:7dce5e74ad91 149 float temperature = 0;
kaiserhaz 0:7dce5e74ad91 150 temp_sensor->GetTemperature(&temperature);
kaiserhaz 0:7dce5e74ad91 151 return temperature;
kaiserhaz 0:7dce5e74ad91 152 }
kaiserhaz 0:7dce5e74ad91 153
kaiserhaz 0:7dce5e74ad91 154
kaiserhaz 0:7dce5e74ad91 155 // Miscellaneous callbacks & functions
kaiserhaz 0:7dce5e74ad91 156 void sanityCallback(void)
kaiserhaz 0:7dce5e74ad91 157 {
kaiserhaz 0:7dce5e74ad91 158 led1 = !led1; // Blink LED1 to indicate system sanity
kaiserhaz 0:7dce5e74ad91 159 }
kaiserhaz 0:7dce5e74ad91 160
kaiserhaz 0:7dce5e74ad91 161 void sensorPollCallback(void)
kaiserhaz 0:7dce5e74ad91 162 {
kaiserhaz 0:7dce5e74ad91 163 sensorPolling = true;
kaiserhaz 0:7dce5e74ad91 164 }
kaiserhaz 0:7dce5e74ad91 165
kaiserhaz 2:326a19b95766 166 void fastSensorPollCallback(void)
kaiserhaz 2:326a19b95766 167 {
kaiserhaz 2:326a19b95766 168 fastSensorPolling = true;
kaiserhaz 2:326a19b95766 169 }
kaiserhaz 2:326a19b95766 170
kaiserhaz 2:326a19b95766 171 void activateFastSensorPoll(void)
kaiserhaz 2:326a19b95766 172 {
kaiserhaz 2:326a19b95766 173 fastSensorPolling = true;
kaiserhaz 5:9d68ed883e95 174 fastSensorPollTicker.attach(&fastSensorPollCallback, 0.9f);
kaiserhaz 2:326a19b95766 175 }
kaiserhaz 2:326a19b95766 176
kaiserhaz 2:326a19b95766 177 void deactivateFastSensorPoll(void)
kaiserhaz 2:326a19b95766 178 {
kaiserhaz 2:326a19b95766 179 fastSensorPolling = false;
kaiserhaz 2:326a19b95766 180 fastSensorPollTicker.detach();
kaiserhaz 2:326a19b95766 181 }
kaiserhaz 2:326a19b95766 182
kaiserhaz 5:9d68ed883e95 183 void pumpSetup(void)
kaiserhaz 5:9d68ed883e95 184 {
kaiserhaz 5:9d68ed883e95 185 pumpPWM.write(1);
kaiserhaz 5:9d68ed883e95 186 pumpPWM.period(2.0f);
kaiserhaz 5:9d68ed883e95 187 }
kaiserhaz 5:9d68ed883e95 188
kaiserhaz 5:9d68ed883e95 189 void pumpActivateCallback(void)
kaiserhaz 5:9d68ed883e95 190 {
kaiserhaz 5:9d68ed883e95 191 pumpPWM.write(0.7);
kaiserhaz 5:9d68ed883e95 192 }
kaiserhaz 5:9d68ed883e95 193
kaiserhaz 5:9d68ed883e95 194 void pumpDeactivateCallback(void)
kaiserhaz 5:9d68ed883e95 195 {
kaiserhaz 5:9d68ed883e95 196 pumpPWM.write(1);
kaiserhaz 5:9d68ed883e95 197 }
kaiserhaz 2:326a19b95766 198
kaiserhaz 0:7dce5e74ad91 199 void errorLoop(void)
kaiserhaz 0:7dce5e74ad91 200 {
kaiserhaz 0:7dce5e74ad91 201 sanityTicker.detach();
kaiserhaz 0:7dce5e74ad91 202 sensorPollTicker.detach();
kaiserhaz 0:7dce5e74ad91 203 ble.shutdown();
kaiserhaz 5:9d68ed883e95 204
kaiserhaz 0:7dce5e74ad91 205 while(true)
kaiserhaz 0:7dce5e74ad91 206 {
kaiserhaz 5:9d68ed883e95 207 led1 != led1;
kaiserhaz 5:9d68ed883e95 208 printf("\n\n\n\n\n\n\n\n");
kaiserhaz 0:7dce5e74ad91 209 }
kaiserhaz 0:7dce5e74ad91 210 }
kaiserhaz 0:7dce5e74ad91 211
kaiserhaz 0:7dce5e74ad91 212
kaiserhaz 0:7dce5e74ad91 213
kaiserhaz 0:7dce5e74ad91 214 /** Pre-main inits **/
kaiserhaz 0:7dce5e74ad91 215
kaiserhaz 0:7dce5e74ad91 216
kaiserhaz 0:7dce5e74ad91 217
kaiserhaz 0:7dce5e74ad91 218 /** Main loop **/
kaiserhaz 0:7dce5e74ad91 219 int main(void)
kaiserhaz 0:7dce5e74ad91 220 {
kaiserhaz 5:9d68ed883e95 221 pumpSetup(); // Setup pump
kaiserhaz 3:c460d60ffda6 222
kaiserhaz 5:9d68ed883e95 223 sensorPolling = false;
kaiserhaz 2:326a19b95766 224 fastSensorPolling = false;
kaiserhaz 5:9d68ed883e95 225 bleActive = false;
kaiserhaz 5:9d68ed883e95 226 pumpActive = false;
kaiserhaz 0:7dce5e74ad91 227
kaiserhaz 5:9d68ed883e95 228 sanityTicker.attach(sanityCallback, 1.1f); // LED sanity checker
kaiserhaz 5:9d68ed883e95 229 sensorPollTicker.attach(sensorPollCallback, 3559.9f); // Sensor poll ticker (1 hr too long?)
kaiserhaz 0:7dce5e74ad91 230
kaiserhaz 0:7dce5e74ad91 231 volatile GreenBuildingService::PlantEnvironmentType_t peVal; // Plant environment var
kaiserhaz 5:9d68ed883e95 232 uint8_t pumpLimitCount = 0; // Pump limit counter
kaiserhaz 0:7dce5e74ad91 233
kaiserhaz 0:7dce5e74ad91 234 ble.init(bleInitComplete); // Pass BLE init complete function upon init
kaiserhaz 0:7dce5e74ad91 235
kaiserhaz 5:9d68ed883e95 236 // while(ble.hasInitialized() == false); // Buggy loop
kaiserhaz 0:7dce5e74ad91 237
kaiserhaz 0:7dce5e74ad91 238 // Infinite loop
kaiserhaz 0:7dce5e74ad91 239 while (true) {
kaiserhaz 0:7dce5e74ad91 240
kaiserhaz 2:326a19b95766 241 if(sensorPolling || fastSensorPolling)
kaiserhaz 0:7dce5e74ad91 242 {
kaiserhaz 0:7dce5e74ad91 243 sensorPolling = false; // Deassert polling bit
kaiserhaz 2:326a19b95766 244 fastSensorPolling = false;
kaiserhaz 0:7dce5e74ad91 245
kaiserhaz 0:7dce5e74ad91 246 peVal.soilMoisture = (uint8_t) getMoistureValue(); // Update all measurements
kaiserhaz 0:7dce5e74ad91 247 peVal.airHumidity = (uint8_t) getHumidityValue();
kaiserhaz 0:7dce5e74ad91 248 peVal.airTemperature = (int8_t) getTemperatureValue();
kaiserhaz 0:7dce5e74ad91 249
kaiserhaz 0:7dce5e74ad91 250 if(ble.getGapState().connected) // Update characteristic if connected
kaiserhaz 0:7dce5e74ad91 251 gbServicePtr->updatePlantEnvironment(peVal);
kaiserhaz 0:7dce5e74ad91 252
kaiserhaz 2:326a19b95766 253 printf("%d\t%d\t%d\r\n", peVal.airTemperature, peVal.airHumidity, peVal.soilMoisture);
kaiserhaz 0:7dce5e74ad91 254
kaiserhaz 2:326a19b95766 255 // If moisture is below 50% of max when user is present
kaiserhaz 2:326a19b95766 256 // or if less than 30% of max
kaiserhaz 5:9d68ed883e95 257 // and pump is not active
kaiserhaz 2:326a19b95766 258 if( ( ((peVal.soilMoisture < 0.5*GB_SOIL_MOISTURE_MAX) && ble.getGapState().connected) ||
kaiserhaz 5:9d68ed883e95 259 ((peVal.soilMoisture < 0.3*GB_SOIL_MOISTURE_MAX) && !ble.getGapState().connected) &&
kaiserhaz 5:9d68ed883e95 260 !pumpActive
kaiserhaz 5:9d68ed883e95 261 )
kaiserhaz 2:326a19b95766 262 )
kaiserhaz 2:326a19b95766 263 {
kaiserhaz 2:326a19b95766 264 activateFastSensorPoll();
kaiserhaz 2:326a19b95766 265 pumpActive = true;
kaiserhaz 5:9d68ed883e95 266 // TODO: calculate pumpWaitTime ( pumpWaitTime = f(peVal.airHumidity, peVal.airTemperature) )
kaiserhaz 5:9d68ed883e95 267 pumpWaitTimeout.attach(&pumpActivateCallback, pumpWaitTime);
kaiserhaz 2:326a19b95766 268 }
kaiserhaz 2:326a19b95766 269
kaiserhaz 5:9d68ed883e95 270 // Stop condition: when soil moisture is at 60% of max or after few pump cycles
kaiserhaz 5:9d68ed883e95 271 if(pumpActive)
kaiserhaz 2:326a19b95766 272 {
kaiserhaz 5:9d68ed883e95 273 ++pumpLimitCount;
kaiserhaz 5:9d68ed883e95 274
kaiserhaz 5:9d68ed883e95 275 if( (peVal.soilMoisture >= 0.6*GB_SOIL_MOISTURE_MAX) ||
kaiserhaz 5:9d68ed883e95 276 (pumpLimitCount>GB_PUMP_CYCLE_MAX)
kaiserhaz 5:9d68ed883e95 277 )
kaiserhaz 5:9d68ed883e95 278 {
kaiserhaz 5:9d68ed883e95 279 pumpWaitTimeout.detach();
kaiserhaz 5:9d68ed883e95 280 pumpDeactivateCallback();
kaiserhaz 5:9d68ed883e95 281 pumpActive = false; // Something not right here...
kaiserhaz 5:9d68ed883e95 282 if(!bleActive)
kaiserhaz 5:9d68ed883e95 283 deactivateFastSensorPoll();
kaiserhaz 5:9d68ed883e95 284 }
kaiserhaz 0:7dce5e74ad91 285 }
kaiserhaz 2:326a19b95766 286
kaiserhaz 5:9d68ed883e95 287
kaiserhaz 0:7dce5e74ad91 288 }
kaiserhaz 0:7dce5e74ad91 289 else
kaiserhaz 2:326a19b95766 290 ble.waitForEvent(); //Low power wait for event
kaiserhaz 0:7dce5e74ad91 291
kaiserhaz 0:7dce5e74ad91 292 }
kaiserhaz 0:7dce5e74ad91 293 }