Chamal Ayesh Wickramanayaka
Published © MIT

Micro Agriculture with AI

Food shortage is the next global crisis we are about experience after Covid-19 pandemic and the effect of this is much bigger than Covid-19.

IntermediateWork in progressOver 2 days441
Micro Agriculture with AI

Things used in this project

Story

Read more

Schematics

Wiring ESP 32 with water pump via relay module

Code

Bluetooth powered water pump

Arduino
#include "BLEDevice.h"
#include <Wire.h>

#define bleServerName "Wio Micro Agro"
#define ONBOARD_LED 2
#define PUMP_PIN 3

static BLEUUID pumpServiceUUID("180f");
static BLEUUID pumpCharacteristicUUID("2a19");
static boolean doConnect = false;
static boolean connected = false;
static BLEAddress *pServerAddress;
static BLERemoteCharacteristic* pumpCharacteristic;
const uint8_t notificationOn[] = {0x1, 0x0};
const uint8_t notificationOff[] = {0x0, 0x0};
char* pumpChar;

boolean newPumpState = false;

bool connectToServer(BLEAddress pAddress) {
  BLEClient* pClient = BLEDevice::createClient();
  pClient->connect(pAddress);
  Serial.println(" - Connected to server");
  BLERemoteService* pRemoteService = pClient->getService(pumpServiceUUID);
  if (pRemoteService == nullptr) {
    Serial.print("Failed to find our service UUID: ");
    Serial.println(pumpServiceUUID.toString().c_str());
    return (false);
  }
 
  pumpCharacteristic = pRemoteService->getCharacteristic(pumpCharacteristicUUID);

  if (pumpCharacteristic == nullptr) {
    Serial.print("Failed to find our characteristic UUID");
    return false;
  }
  Serial.println(" - Found our characteristics");
  pumpCharacteristic->registerForNotify(pumpNotifyCallback);
  return true;
}

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    if (advertisedDevice.getName() == bleServerName) { 
      advertisedDevice.getScan()->stop();
      pServerAddress = new BLEAddress(advertisedDevice.getAddress()); 
      doConnect = true; 
      Serial.println("Device found. Connecting!");
    }
  }
};
 
static void pumpNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, 
                                        uint8_t* pData, size_t length, bool isNotify) {
  pumpChar = (char*)pData;
  newPumpState = true;
}

void setup() {
  Serial.begin(115200);
  Serial.println("Starting Arduino BLE Client application...");
  BLEDevice::init("");
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  pBLEScan->start(30);
  pinMode(ONBOARD_LED, OUTPUT);
  pinMode(PUMP_PIN, OUTPUT);  
}

void loop() {
  if (doConnect == true) {
    if (connectToServer(*pServerAddress)) {
      Serial.println("We are now connected to the BLE Server.");
      pumpCharacteristic->getDescriptor(BLEUUID((uint16_t)0x4545))->writeValue((uint8_t*)notificationOn, 2, true);
      connected = true;
    } else {
      Serial.println("We have failed to connect to the server; Restart your device to scan for nearby BLE server again.");
    }
    doConnect = false;
  }
  std::string value =   pumpCharacteristic->readValue();
  Serial.print("Pump state by BLE server = ");
  Serial.println(value.c_str());
  if(value=="on"){
    Serial.println("On");
    digitalWrite(ONBOARD_LED, HIGH);
    digitalWrite(PUMP_PIN, HIGH);
  }
  else{
    Serial.println("Off");
    digitalWrite(ONBOARD_LED, LOW);
    digitalWrite(PUMP_PIN, LOW);    
  }
  delay(1000);
}

Wio sensor hub and LCD display complete code

Arduino
#include <Arduino.h>
#include <SensirionI2CSht4x.h>
#include <Wire.h>
#include "TFT_eSPI.h"
 
SensirionI2CSht4x sht4x;
int sensorPin = A0;
int sensorValue = 0;

TFT_eSPI tft;
TFT_eSprite spr = TFT_eSprite(&tft);
 
void setup() {
    Serial.begin(115200);
    while (!Serial) {
        delay(100);
    }
    Wire.begin();
    uint16_t error;
    char errorMessage[256];
    sht4x.begin(Wire);
    uint32_t serialNumber;
    error = sht4x.serialNumber(serialNumber);
    if (error) {
        Serial.print("Error trying to execute serialNumber(): ");
        errorToString(error, errorMessage, 256);
        Serial.println(errorMessage);
    } else {
        Serial.print("Serial Number: ");
        Serial.println(serialNumber);
    }
    tft.begin();
    tft.setRotation(3);
    spr.createSprite(TFT_HEIGHT, TFT_WIDTH);          
}
 
void loop() {
    uint16_t error;
    char errorMessage[256];
    float temperature;
    float humidity;
    float moisture;
    String pump = "OFF";        
    error = sht4x.measureHighPrecision(temperature, humidity);
    if (error) {
        Serial.print("Error trying to execute measureHighPrecision(): ");
        errorToString(error, errorMessage, 256);
        Serial.println(errorMessage);
    }
    delay(1000);
    // read the value from the sensor:
    sensorValue = analogRead(sensorPin);
    moisture = map(sensorValue, 1023, 0, 100, 0);   
    delay(1000);
    // Drawing header
    spr.fillSprite(TFT_WHITE);
    spr.fillRect(0, 0, 320, 50, TFT_OLIVE);
    spr.setTextColor(TFT_WHITE);
    spr.setTextSize(3);
    spr.drawString("Wio Micro Agro", 30, 15);
    spr.drawFastVLine(150, 50, 190, TFT_OLIVE);
    spr.drawFastHLine(0, 140, 320, TFT_OLIVE);
    // Display 
    spr.fillRect(0, 50, 150, 90, TFT_RED);
    spr.setTextColor(TFT_WHITE);
    spr.setTextSize(2);
    spr.drawString("Temperature",10,65);
    spr.setTextSize(3);
    spr.drawNumber(temperature, 50,95);
    spr.drawString("C", 90,95);
    
    // Display humidity
    spr.fillRect(0, 140, 150, 100, TFT_NAVY);
    spr.setTextColor(TFT_WHITE);
    spr.setTextSize(2);
    spr.drawString("Humidity",25,160);
    spr.setTextSize(3);
    spr.drawNumber(humidity, 30,190);
    spr.drawString("%RH", 70,190);
    
    // Display soil moisture
    spr.fillRect(150, 50, 170, 90, TFT_DARKGREEN);
    spr.setTextColor(TFT_WHITE);
    spr.setTextSize(2);
    spr.drawString("Soil Moisture",160,65);
    spr.setTextSize(3);
    spr.drawNumber(moisture, 200,95);
    spr.drawString("%", 240, 95);

    // Display water pump status
    spr.fillRect(150, 140, 170, 100, TFT_YELLOW);    
    spr.setTextColor(TFT_BLACK);
    spr.setTextSize(2);
    spr.drawString("Water Pump",180,160);
    spr.setTextSize(3);
    spr.drawString(pump, 205,190);
    spr.pushSprite(0,0);
    delay(50);
}

Connecting tempereture, humidity and soil moisture sensors to Wio Terminal

Arduino
#include <Arduino.h>
#include <SensirionI2CSht4x.h>
#include <Wire.h>
 
SensirionI2CSht4x sht4x;
int sensorPin = A0;
int sensorValue = 0;

 
void setup() {
 
    Serial.begin(115200);
    while (!Serial) {
        delay(100);
    }
 
    Wire.begin();
 
    uint16_t error;
    char errorMessage[256];
 
    sht4x.begin(Wire);
 
    uint32_t serialNumber;
    error = sht4x.serialNumber(serialNumber);
    if (error) {
        Serial.print("Error trying to execute serialNumber(): ");
        errorToString(error, errorMessage, 256);
        Serial.println(errorMessage);
    } else {
        Serial.print("Serial Number: ");
        Serial.println(serialNumber);
    }
}
 
void loop() {
    uint16_t error;
    char errorMessage[256];
 
    delay(1000);
 
    float temperature;
    float humidity;
    error = sht4x.measureHighPrecision(temperature, humidity);
    if (error) {
        Serial.print("Error trying to execute measureHighPrecision(): ");
        errorToString(error, errorMessage, 256);
        Serial.println(errorMessage);
    } else {
        Serial.print("Temperature:");
        Serial.print(temperature);
        Serial.print("\t");
        Serial.print("Humidity:");
        Serial.println(humidity);
    }
    // read the value from the sensor:
    sensorValue = analogRead(sensorPin);
    Serial.print("Moisture = " );
    Serial.println(sensorValue);
}

Complete Wio Terminal Code with sensors and BLE

Arduino
#include <Arduino.h>
#include <Wire.h>
#include "TFT_eSPI.h"
#include <SensirionI2CSht4x.h>
#include <rpcBLEDevice.h>
#include <BLEServer.h>

#define SERVICE_UUID "180f"
#define CHARACTERISTIC_UUID "2a19"
#define DESCRIPTOR_UUID "4545"

BLECharacteristic *pCharacteristic;

SensirionI2CSht4x sht4x;
int sensorPin = A0;
int sensorValue = 0;

TFT_eSPI tft;
TFT_eSprite spr = TFT_eSprite(&tft);

class MyCallbacks : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    std::string rxValue = pCharacteristic->getValue();

    if (rxValue.length() > 0) {
      Serial.println("*********");
      Serial.print("Received Value: ");
      for (int i = 0; i < rxValue.length(); i++)
        Serial.print(rxValue[i]);

      Serial.println();
      Serial.println("*********");
    }
  }
};

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    delay(100);
  }
  Serial.println("Starting BLE work!");
  BLEDevice::init("Wio Micro Agro");
  BLEServer *pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);

  pCharacteristic->setAccessPermissions(GATT_PERM_READ | GATT_PERM_WRITE);
  BLEDescriptor *pDescriptor = pCharacteristic->createDescriptor(
    DESCRIPTOR_UUID,
    ATTRIB_FLAG_VOID | ATTRIB_FLAG_ASCII_Z,
    GATT_PERM_READ | GATT_PERM_WRITE,
    2);
  pCharacteristic->setValue("OFF");
  pCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();

  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  Serial.println("Characteristic defined! Now you can read it in your phone!");

  Wire.begin();
  uint16_t error;
  char errorMessage[256];
  sht4x.begin(Wire);
  uint32_t serialNumber;
  error = sht4x.serialNumber(serialNumber);
  if (error) {
    Serial.print("Error trying to execute serialNumber(): ");
    errorToString(error, errorMessage, 256);
    Serial.println(errorMessage);
  } else {
    Serial.print("Serial Number: ");
    Serial.println(serialNumber);
  }
  tft.begin();
  tft.setRotation(3);
  spr.createSprite(TFT_HEIGHT, TFT_WIDTH);
}

void loop() {
  uint16_t error;
  char errorMessage[256];
  float temperature;
  float humidity;
  float moisture;
  String pump = "OFF";
  error = sht4x.measureHighPrecision(temperature, humidity);
  if (error) {
    Serial.print("Error trying to execute measureHighPrecision(): ");
    errorToString(error, errorMessage, 256);
    Serial.println(errorMessage);
  }
  delay(100);
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);
  moisture = map(sensorValue, 1023, 0, 100, 0);
  delay(100);
  // Drawing header
  spr.fillSprite(TFT_WHITE);
  spr.fillRect(0, 0, 320, 50, TFT_OLIVE);
  spr.setTextColor(TFT_WHITE);
  spr.setTextSize(3);
  spr.drawString("Wio Micro Agro", 30, 15);
  spr.drawFastVLine(150, 50, 190, TFT_OLIVE);
  spr.drawFastHLine(0, 140, 320, TFT_OLIVE);
  // Display
  spr.fillRect(0, 50, 150, 90, TFT_RED);
  spr.setTextColor(TFT_WHITE);
  spr.setTextSize(2);
  spr.drawString("Temperature", 10, 65);
  spr.setTextSize(3);
  spr.drawNumber(temperature, 50, 95);
  spr.drawString("C", 90, 95);
  // Display humidity
  spr.fillRect(0, 140, 150, 100, TFT_NAVY);
  spr.setTextColor(TFT_WHITE);
  spr.setTextSize(2);
  spr.drawString("Humidity", 25, 160);
  spr.setTextSize(3);
  spr.drawNumber(humidity, 30, 190);
  spr.drawString("%RH", 70, 190);
  // Display soil moisture
  spr.fillRect(150, 50, 170, 90, TFT_DARKGREEN);
  spr.setTextColor(TFT_WHITE);
  spr.setTextSize(2);
  spr.drawString("Soil Moisture", 160, 65);
  spr.setTextSize(3);
  spr.drawNumber(moisture, 200, 95);
  spr.drawString("%", 240, 95);
  // Display water pump status
  spr.fillRect(150, 140, 170, 100, TFT_YELLOW);
  spr.setTextColor(TFT_BLACK);
  spr.setTextSize(2);
  spr.drawString("Water Pump", 180, 160);
  spr.setTextSize(3);
  spr.drawString(pump, 205, 190);
  spr.pushSprite(0, 0);
  delay(50);
  // Check the soil moisture level and trigger the water pump.
  if (moisture <= 50) {
    static char value[20];
    sprintf(value, "%d", "on");
    pCharacteristic->setValue(value);
    pump = "ON";
  } else {
    static char value[20];
    sprintf(value, "%d", "off");
    pCharacteristic->setValue(value);
    pump = "OFF";
  }
}

Credits

Chamal Ayesh Wickramanayaka

Chamal Ayesh Wickramanayaka

21 projects • 25 followers
Experienced software engineer with a passion for AI, IoT, and innovation, continuously seeking to learn and embrace new technologies.

Comments