It is a simple IoT solution for plant life monitoring and maintenance, based on STM32NUCLEO boards and expansion modules.

Dependencies:   BLE_API X_NUCLEO_IDB0XA1 X_NUCLEO_IKS01A1 mbed

GreenYourLife, A Plant Life Monitoring and Maintenance System

Elaborated By Engineers, Designed For The World

Introduction

A healthy ecosystem is one where all the actors in it work in synergy: each of them playing a part that serves the other. Plants play an important part in regulating our quality of life. In the modern world, they would often times be placed in buildings and houses, as decorations or as medicinal and therapeutic purposes. Whatever the reason, GreenYourLife is here to help you manage them.

GreenYourLife is an Internet of Things (IoT) solution that will allow you to perform the following:

  • Follow your plant's well-being on your connected device (smartphone, etc.)
  • Maintain your plant's well-being automatically

We've developed an indoor plant monitoring system with the STM32NUCLEO development board. The system will collect the plant's environmental data (air temperature, air humidity and soil moisture) and transfer them to your connected device. The data collected will then be stored on a cloud server, where you can follow the progress of your plant life.

How it works

Plant maintanence

Our concept of maintanence is the automatic catering of the plant's needs. In this version, we focus on water supply. Future versions may indeed include more than that.

On-board sensors on the STM32NUCLEO will obtain measurements of 3 main parameters on the plant surrounding:

  1. Air temperature
  2. Air humidity
  3. Soil moisture

Based on these values, the software then acts upon the water pump: activating it when in need of water and deactivating it if not.

Plant monitoring

Plant monitoring, for us, is the follow-up of the plant's health by monitoring environment quality and plant nutritions. In this version, we only monitor the three parameters listed above. Future version may include more advanced and smarter monitoring technique.

The STM32NUCLEO device acts as a Bluetooth server and awaits connection from any client (smartphone, etc.). Upon connection, the server updates the plant environment parameters at a fixed interval. The client application will then transfer these received characteristics to the cloud.

Details

Hardware

The target platform is the STM32NUCLEO L476RG development board with two additional modules:

  • the IDB05A1 Bluetooth LE expansion board, which uses a BlueNRG coprocessor
  • and the IKS01A1 MEMS sensor expansion board

There are several additional materials that constitute the system:

  • a Funduino Soil Moisture Sensor, hooked up to 5V at pin PB_1
  • a relay, hooked up to 3.3V at pin PC_8 and controlled by a PWM pulse
  • a DC water pump

Software

We have used the ARM mbed platform for general code bring-up. We've used the following libraries:

  • mbed library by ARM
  • BLE_API library by the Bluetooth Low Energy team
  • X_NUCLEO_IDB0XA1 library by the ST Microelectronics team
  • X_NUCLEO_IKS01A1 library by the ST Microelectronics team

The acquired data on the client device is then sent to a cloud server that we hosted on ThingSpeak, so that people can remotely access the data. It is available at the GreenYourLife channel .

Reference

Committer:
kaiserhaz
Date:
Sat Nov 26 13:38:23 2016 +0000
Revision:
0:7dce5e74ad91
Child:
1:b30300f95d4a
Initial commit.

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 * for the
kaiserhaz 0:7dce5e74ad91 11 * eSAME 2016 STM32NUCLEO IoT Contest in Sophia-Antipolis
kaiserhaz 0:7dce5e74ad91 12 *
kaiserhaz 0:7dce5e74ad91 13 * main.cpp | Program main
kaiserhaz 0:7dce5e74ad91 14 *
kaiserhaz 0:7dce5e74ad91 15 ******************************************************************************/
kaiserhaz 0:7dce5e74ad91 16
kaiserhaz 0:7dce5e74ad91 17 /** Includes **/
kaiserhaz 0:7dce5e74ad91 18 #include "mbed.h" // ARM mbed library
kaiserhaz 0:7dce5e74ad91 19 #include "x_nucleo_iks01a1.h" // STM32NUCLEO board library
kaiserhaz 0:7dce5e74ad91 20 #include "ble/BLE.h" // Bluetooth LE library
kaiserhaz 0:7dce5e74ad91 21 #include "GreenBuildingService.h" // Green Building service library
kaiserhaz 0:7dce5e74ad91 22
kaiserhaz 0:7dce5e74ad91 23
kaiserhaz 0:7dce5e74ad91 24
kaiserhaz 0:7dce5e74ad91 25 /** Defines **/
kaiserhaz 0:7dce5e74ad91 26 #define GB_SOIL_MOISTURE_MAX 100 // Soil moisture threshold value
kaiserhaz 0:7dce5e74ad91 27
kaiserhaz 0:7dce5e74ad91 28
kaiserhaz 0:7dce5e74ad91 29
kaiserhaz 0:7dce5e74ad91 30 /** Device declarations **/
kaiserhaz 0:7dce5e74ad91 31
kaiserhaz 0:7dce5e74ad91 32 // Board-specific
kaiserhaz 0:7dce5e74ad91 33 PwmOut pumpPWM(PB_10); // PWM motor control out pin
kaiserhaz 0:7dce5e74ad91 34 DigitalOut led1(LED1, 1); // Debug pin instance
kaiserhaz 0:7dce5e74ad91 35 AnalogIn moisture_sensor(A2); // Moisture sensor
kaiserhaz 0:7dce5e74ad91 36 static X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance(D14, D15); // Expansion board instance
kaiserhaz 0:7dce5e74ad91 37 static HumiditySensor *humidity_sensor = mems_expansion_board->ht_sensor; // Expansion board humidity sensor instance
kaiserhaz 0:7dce5e74ad91 38 static TempSensor *temp_sensor = mems_expansion_board->ht_sensor; // Expansion board temperature sensor instance
kaiserhaz 0:7dce5e74ad91 39
kaiserhaz 0:7dce5e74ad91 40 // BLE-specific
kaiserhaz 0:7dce5e74ad91 41 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); // BLE device instance
kaiserhaz 0:7dce5e74ad91 42 const static char DEVICE_NAME[] = "GB-Sensor"; // Device name
kaiserhaz 0:7dce5e74ad91 43 static const uint16_t uuid16_list[] = {GreenBuildingService::UUID_GREEN_BUILDING_SERVICE};
kaiserhaz 0:7dce5e74ad91 44 GreenBuildingService *gbServicePtr; // Service pointer
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 0:7dce5e74ad91 50 void errorLoop(void);
kaiserhaz 0:7dce5e74ad91 51
kaiserhaz 0:7dce5e74ad91 52 Ticker sanityTicker;
kaiserhaz 0:7dce5e74ad91 53 Ticker sensorPollTicker;
kaiserhaz 0:7dce5e74ad91 54 bool sensorPolling;
kaiserhaz 0:7dce5e74ad91 55
kaiserhaz 0:7dce5e74ad91 56
kaiserhaz 0:7dce5e74ad91 57
kaiserhaz 0:7dce5e74ad91 58 /** Callbacks **/
kaiserhaz 0:7dce5e74ad91 59
kaiserhaz 0:7dce5e74ad91 60 // BLE-specific callback
kaiserhaz 0:7dce5e74ad91 61 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) // Callback for everytime the connection gets disconnected
kaiserhaz 0:7dce5e74ad91 62 {
kaiserhaz 0:7dce5e74ad91 63 ble.gap().startAdvertising(); // Restart advertising
kaiserhaz 0:7dce5e74ad91 64 // printf("\r\n> BLE : Disconnected. Advertising restarted.");
kaiserhaz 0:7dce5e74ad91 65 }
kaiserhaz 0:7dce5e74ad91 66
kaiserhaz 0:7dce5e74ad91 67 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) // Callback for everytime the connection is established
kaiserhaz 0:7dce5e74ad91 68 {
kaiserhaz 0:7dce5e74ad91 69 // ble.gap().stopAdvertising(); // Stop advertising
kaiserhaz 0:7dce5e74ad91 70 // printf("\r\n> BLE : Connected to %x. Accept no subsequent connections.", params->peerAddr);
kaiserhaz 0:7dce5e74ad91 71 }
kaiserhaz 0:7dce5e74ad91 72
kaiserhaz 0:7dce5e74ad91 73 void onBleInitError(BLE &ble, ble_error_t error)
kaiserhaz 0:7dce5e74ad91 74 {
kaiserhaz 0:7dce5e74ad91 75 // printf("\r\n> BLE : Init error encountered. Error returned: %d", error);
kaiserhaz 0:7dce5e74ad91 76 errorLoop();
kaiserhaz 0:7dce5e74ad91 77 }
kaiserhaz 0:7dce5e74ad91 78
kaiserhaz 0:7dce5e74ad91 79 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
kaiserhaz 0:7dce5e74ad91 80 {
kaiserhaz 0:7dce5e74ad91 81 BLE& ble = params->ble;
kaiserhaz 0:7dce5e74ad91 82 ble_error_t error = params->error;
kaiserhaz 0:7dce5e74ad91 83
kaiserhaz 0:7dce5e74ad91 84 if (error != BLE_ERROR_NONE) { // Check to see init errors
kaiserhaz 0:7dce5e74ad91 85 onBleInitError(ble, error);
kaiserhaz 0:7dce5e74ad91 86 errorLoop();
kaiserhaz 0:7dce5e74ad91 87 }
kaiserhaz 0:7dce5e74ad91 88
kaiserhaz 0:7dce5e74ad91 89 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { // If this is not default instance (double instanciation?)
kaiserhaz 0:7dce5e74ad91 90 // printf("\r\n> BLE : BLE controller instance is invalid.");
kaiserhaz 0:7dce5e74ad91 91 errorLoop();
kaiserhaz 0:7dce5e74ad91 92 }
kaiserhaz 0:7dce5e74ad91 93
kaiserhaz 0:7dce5e74ad91 94 ble.gap().onDisconnection(disconnectionCallback); // Register disconnection callback
kaiserhaz 0:7dce5e74ad91 95 ble.gap().onConnection(connectionCallback); // Register connection callback
kaiserhaz 0:7dce5e74ad91 96
kaiserhaz 0:7dce5e74ad91 97 gbServicePtr = new GreenBuildingService(ble); // Init service with initial value
kaiserhaz 0:7dce5e74ad91 98
kaiserhaz 0:7dce5e74ad91 99 /* Setup advertising. */
kaiserhaz 0:7dce5e74ad91 100 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
kaiserhaz 0:7dce5e74ad91 101 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
kaiserhaz 0:7dce5e74ad91 102 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,(uint8_t *)uuid16_list, sizeof(uuid16_list));
kaiserhaz 0:7dce5e74ad91 103 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
kaiserhaz 0:7dce5e74ad91 104 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
kaiserhaz 0:7dce5e74ad91 105 ble.gap().startAdvertising();
kaiserhaz 0:7dce5e74ad91 106
kaiserhaz 0:7dce5e74ad91 107 // printf("\r\n> BLE : BLE Init done.");
kaiserhaz 0:7dce5e74ad91 108 }
kaiserhaz 0:7dce5e74ad91 109
kaiserhaz 0:7dce5e74ad91 110 // Helper functions for retrieving data from sensors
kaiserhaz 0:7dce5e74ad91 111 float getMoistureValue()
kaiserhaz 0:7dce5e74ad91 112 {
kaiserhaz 0:7dce5e74ad91 113 float moisture = 0;
kaiserhaz 0:7dce5e74ad91 114 for (int i = 1;i<=10;i++) {
kaiserhaz 0:7dce5e74ad91 115 moisture += moisture_sensor.read(); // Get ten samples
kaiserhaz 0:7dce5e74ad91 116 }
kaiserhaz 0:7dce5e74ad91 117 moisture = moisture / 10;
kaiserhaz 0:7dce5e74ad91 118 moisture = moisture * 3300; // Change the value to be in the 0 to 3300 range
kaiserhaz 0:7dce5e74ad91 119 moisture = moisture / 33; // Convert to percentage
kaiserhaz 0:7dce5e74ad91 120 return moisture;
kaiserhaz 0:7dce5e74ad91 121 }
kaiserhaz 0:7dce5e74ad91 122
kaiserhaz 0:7dce5e74ad91 123 float getHumidityValue()
kaiserhaz 0:7dce5e74ad91 124 {
kaiserhaz 0:7dce5e74ad91 125 float humidity = 0;
kaiserhaz 0:7dce5e74ad91 126 humidity_sensor->GetHumidity(&humidity);
kaiserhaz 0:7dce5e74ad91 127 return humidity;
kaiserhaz 0:7dce5e74ad91 128 }
kaiserhaz 0:7dce5e74ad91 129
kaiserhaz 0:7dce5e74ad91 130 float getTemperatureValue()
kaiserhaz 0:7dce5e74ad91 131 {
kaiserhaz 0:7dce5e74ad91 132 float temperature = 0;
kaiserhaz 0:7dce5e74ad91 133 temp_sensor->GetTemperature(&temperature);
kaiserhaz 0:7dce5e74ad91 134 return temperature;
kaiserhaz 0:7dce5e74ad91 135 }
kaiserhaz 0:7dce5e74ad91 136
kaiserhaz 0:7dce5e74ad91 137
kaiserhaz 0:7dce5e74ad91 138 // Miscellaneous callbacks & functions
kaiserhaz 0:7dce5e74ad91 139 void sanityCallback(void)
kaiserhaz 0:7dce5e74ad91 140 {
kaiserhaz 0:7dce5e74ad91 141 led1 = !led1; // Blink LED1 to indicate system sanity
kaiserhaz 0:7dce5e74ad91 142 }
kaiserhaz 0:7dce5e74ad91 143
kaiserhaz 0:7dce5e74ad91 144 void sensorPollCallback(void)
kaiserhaz 0:7dce5e74ad91 145 {
kaiserhaz 0:7dce5e74ad91 146 sensorPolling = true;
kaiserhaz 0:7dce5e74ad91 147 }
kaiserhaz 0:7dce5e74ad91 148
kaiserhaz 0:7dce5e74ad91 149 void errorLoop(void)
kaiserhaz 0:7dce5e74ad91 150 {
kaiserhaz 0:7dce5e74ad91 151 sanityTicker.detach();
kaiserhaz 0:7dce5e74ad91 152 sensorPollTicker.detach();
kaiserhaz 0:7dce5e74ad91 153 ble.shutdown();
kaiserhaz 0:7dce5e74ad91 154 printf("\r\n> ERROR : Error encountered. Infinite looping.");
kaiserhaz 0:7dce5e74ad91 155 while(true)
kaiserhaz 0:7dce5e74ad91 156 {
kaiserhaz 0:7dce5e74ad91 157 led1 != led1;
kaiserhaz 0:7dce5e74ad91 158 }
kaiserhaz 0:7dce5e74ad91 159 }
kaiserhaz 0:7dce5e74ad91 160
kaiserhaz 0:7dce5e74ad91 161
kaiserhaz 0:7dce5e74ad91 162
kaiserhaz 0:7dce5e74ad91 163 /** Pre-main inits **/
kaiserhaz 0:7dce5e74ad91 164
kaiserhaz 0:7dce5e74ad91 165
kaiserhaz 0:7dce5e74ad91 166
kaiserhaz 0:7dce5e74ad91 167 /** Main loop **/
kaiserhaz 0:7dce5e74ad91 168 int main(void)
kaiserhaz 0:7dce5e74ad91 169 {
kaiserhaz 0:7dce5e74ad91 170 printf("\r\n/**\r\n * Green Building Sensor Device: Debug Info\r\n */");
kaiserhaz 0:7dce5e74ad91 171
kaiserhaz 0:7dce5e74ad91 172 sensorPolling = false;
kaiserhaz 0:7dce5e74ad91 173
kaiserhaz 0:7dce5e74ad91 174 sanityTicker.attach(sanityCallback, 1.1); // LED sanity checker
kaiserhaz 0:7dce5e74ad91 175 sensorPollTicker.attach(sensorPollCallback, 5); // Sensor poll ticker
kaiserhaz 0:7dce5e74ad91 176
kaiserhaz 0:7dce5e74ad91 177 printf("\r\n> MAIN : Tickers initialized.");
kaiserhaz 0:7dce5e74ad91 178
kaiserhaz 0:7dce5e74ad91 179 volatile GreenBuildingService::PlantEnvironmentType_t peVal; // Plant environment var
kaiserhaz 0:7dce5e74ad91 180 uint8_t pumpCount = 0; // Pump timer
kaiserhaz 0:7dce5e74ad91 181
kaiserhaz 0:7dce5e74ad91 182 ble.init(bleInitComplete); // Pass BLE init complete function upon init
kaiserhaz 0:7dce5e74ad91 183
kaiserhaz 0:7dce5e74ad91 184 while(ble.hasInitialized() == false);
kaiserhaz 0:7dce5e74ad91 185
kaiserhaz 0:7dce5e74ad91 186 printf("\r\n> MAIN : BLE Init procedure done.");
kaiserhaz 0:7dce5e74ad91 187
kaiserhaz 0:7dce5e74ad91 188 // Infinite loop
kaiserhaz 0:7dce5e74ad91 189 while (true) {
kaiserhaz 0:7dce5e74ad91 190
kaiserhaz 0:7dce5e74ad91 191 if(sensorPolling)
kaiserhaz 0:7dce5e74ad91 192 {
kaiserhaz 0:7dce5e74ad91 193 sensorPolling = false; // Deassert polling bit
kaiserhaz 0:7dce5e74ad91 194
kaiserhaz 0:7dce5e74ad91 195 peVal.soilMoisture = (uint8_t) getMoistureValue(); // Update all measurements
kaiserhaz 0:7dce5e74ad91 196 peVal.airHumidity = (uint8_t) getHumidityValue();
kaiserhaz 0:7dce5e74ad91 197 peVal.airTemperature = (int8_t) getTemperatureValue();
kaiserhaz 0:7dce5e74ad91 198
kaiserhaz 0:7dce5e74ad91 199 if(ble.getGapState().connected) // Update characteristic if connected
kaiserhaz 0:7dce5e74ad91 200 gbServicePtr->updatePlantEnvironment(peVal);
kaiserhaz 0:7dce5e74ad91 201
kaiserhaz 0:7dce5e74ad91 202 printf("\r\n> MAIN : Current soil moisture = %d", peVal.soilMoisture);
kaiserhaz 0:7dce5e74ad91 203 printf("\r\n> MAIN : Current air humidity = %d", peVal.airHumidity);
kaiserhaz 0:7dce5e74ad91 204 printf("\r\n> MAIN : Current air temperature = %d", peVal.airTemperature);
kaiserhaz 0:7dce5e74ad91 205 printf("\r\n");
kaiserhaz 0:7dce5e74ad91 206
kaiserhaz 0:7dce5e74ad91 207 if (peVal.soilMoisture < 0.6*GB_SOIL_MOISTURE_MAX) // If moisture is below 60% of max
kaiserhaz 0:7dce5e74ad91 208 {
kaiserhaz 0:7dce5e74ad91 209 printf("\r\n> MAIN : Activating water pump.");
kaiserhaz 0:7dce5e74ad91 210 pumpPWM.write(1); // Activate pump
kaiserhaz 0:7dce5e74ad91 211 pumpCount = 0;
kaiserhaz 0:7dce5e74ad91 212 while((getMoistureValue()<0.75*GB_SOIL_MOISTURE_MAX)&&(pumpCount<40)) // Activate for 20s or until 75% max moisture
kaiserhaz 0:7dce5e74ad91 213 {
kaiserhaz 0:7dce5e74ad91 214 wait(0.5);
kaiserhaz 0:7dce5e74ad91 215 pumpCount++;
kaiserhaz 0:7dce5e74ad91 216 }
kaiserhaz 0:7dce5e74ad91 217 pumpPWM.write(0);
kaiserhaz 0:7dce5e74ad91 218 }
kaiserhaz 0:7dce5e74ad91 219 }
kaiserhaz 0:7dce5e74ad91 220 else
kaiserhaz 0:7dce5e74ad91 221 ble.waitForEvent(); // Low power wait for event
kaiserhaz 0:7dce5e74ad91 222
kaiserhaz 0:7dce5e74ad91 223 }
kaiserhaz 0:7dce5e74ad91 224 }