# Unlocking Bonsai Brilliance

## Background

In the realm of software development, the pursuit of observability and data-driven decision-making has become a fundamental aspect of building and maintaining robust microservices architectures. Drawing inspiration from this ethos, I sought to apply these principles to a rather unexpected domain - the care and cultivation of my cherished Bonsai tree.

Similar to the complex systems we engineer, the art of growing a Bonsai tree involves a multitude of parameters that must be carefully balanced for optimal results. However, fine-tuning these variables can be a time-consuming process. Fortunately, certain rules of thumb exist within this horticultural art form that provide valuable guidance in our quest for nurturing these miniature living masterpieces.

> Be sure not to ***water*** your ***tree*** if the soil is still wet, but don't let the ***tree*** dry out either.

> As a beginner, use your fingers at about one centimeter deep, (0.4") to check the soil moisture. If it's slightly dry, go ahead and water your tree.

followed by:

> Avoid watering all of your trees on a daily routine, until you know exactly what you are doing.

This sounds not too exact (for me at least) given my objective is to have a good-looking tree on my desk with healthy and green leaves

## Requirements

To get started you'll need:

* Arduino-like Board
    
* Soil-Moisture Sensor
    
* Wi-Fi module (optional)
    

In this project, **NodeMCU V2 ESP8266** paired with **Soil Moisture Hygrometer Detection Humidity Sensor** was used.

## Diagram

The schematics are pretty straight-forward and as follows:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688292144995/483ecf27-37af-4026-aa4c-761981ee0f80.webp align="center")

I've settled on analogous mode for the sensor.

## Code

The prerequisites of this step are to connect your development board to a serial monitor and decide on a Baud Rate (in this example 9600). The source code is available on [Aleksandar1932/overkill-bonsai](https://github.com/Aleksandar1932/overkill-bonsai).

The next step is to write a lib that provides an API to the soil moisture sensor.

Stating by taking defining a few constants in `lib/Constants /Constants.cpp`:

```cpp
#define sensorPower 0
#define sensorPin A0

#define WET_THRESHOLD 500     // Define max value we consider soil 'wet'
#define DRY_TREHSHOLD 750     // Define min value we consider soil 'dry'
#define MEASURE_INTERVAL 1000 // Define how often we check soil moisture (milliseconds)
```

Next is the `lib/Moisture /Moisture.cpp`:

```cpp
#include <Arduino.h>
#include <Constants.h>

int readSensor()
{
    digitalWrite(sensorPower, HIGH);
    delay(10);
    int val = analogRead(sensorPin);
    digitalWrite(sensorPower, LOW);
    return val;
}

void setupSoilMoistureSensor()
{
  pinMode(sensorPower, OUTPUT);
  digitalWrite(sensorPower, LOW);
}

void logMoisture(int moisture)
{
  Serial.print("Analog Output: ");
  Serial.println(moisture);

  // Determine status of our soil
  if (moisture < WET_THRESHOLD)
  {
    Serial.println("Status: Soil is too wet");
  }
  else if (moisture >= WET_THRESHOLD && moisture < DRY_TREHSHOLD)
  {
    Serial.println("Status: Soil moisture is perfect");
  }
  else
  {
    Serial.println("Status: Soil is too dry - time to water!");
  }
}
```

At this point, the core API is defined, and the reset is implementing the presentation layer that will allow us to interact with the sensor. For this I've used [ESP8266WebServer](https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WebServer/src/ESP8266WebServer.h) for the web server and [ESP8266WiFiMulti](https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h) for Wi-Fi connectivity.

The web server implements two handlers

* on `/` will return json response containing the soil-moisture reading alongside the status (`wet`, `perfect` and `dry`) determined by the thresholds.
    
* on `/display` will return an HTML response containing the Moisture and some "prettier" UI.
    

The presentation layer alongside rest of the logic is as follows:

```cpp
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266mDNS.h>
#include <Moisture.h>
#include <Constants.h>

ESP8266WebServer server(80);
ESP8266WiFiMulti wifiMulti;

void handleMeasurement();
void handleDisplayHTML();
void connectToWifi();
void handleDisplayPrettyHTML();

void setup()
{
  Serial.begin(9600);
  connectToWifi();
  setupSoilMoistureSensor();
  server.on("/", handleMeasurement);
  server.on("/display", handleDisplayHTML);
  server.begin();
}

void loop()
{
  int moisture = readSensor();
  logMoisture(moisture);
  delay(MEASURE_INTERVAL);
  server.handleClient();
}

void handleMeasurement()
{
  int moisture = readSensor();
  server.send(200, "application/json", "{\"moisture\": " + String(moisture) + ", \"status\": \"" + (moisture < WET_THRESHOLD ? "wet" : (moisture >= WET_THRESHOLD && moisture < DRY_TREHSHOLD ? "perfect" : "dry")) + "\"}");
}

void handleDisplayHTML()
{
  server.send(200, "text/html", "<html><head><title>ESP8266 Soil Moisture Sensor</title></head><body><h1>Aleksandar's Bonsai</h1><p>Moisture: " + String(readSensor()) + "</p></body></html>");
}

void connectToWifi()
{
  wifiMulti.addAP(getenv("WIFI_SSID"), getenv("WIFI_PASSWORD"));
  Serial.println("Connecting ...");

  while (wifiMulti.run() != WL_CONNECTED)
  {
    delay(250);
    Serial.print('.');
  }
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());

  if (MDNS.begin(getenv("MDNS_HOSTNAME")))
  {
    Serial.println("mDNS responder started");
  }
  else
  {
    Serial.println("Error setting up MDNS responder!");
  }
}
```

Additionally, I've used [mDNS](https://www.ionos.com/digitalguide/server/know-how/multicast-dns/) for development purposes.

## Determining optimal thresholds

To determine the thresholds I've used this [chart](https://bonsairesourcecenter.com/moisture-meter-chart/) as a reference, but the freedom is yours to fine-tune to achieve optimal results (whatever your objective is).

## Final thoughts

The integrated solution turned out to look as:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1688293822498/42be81d2-e37e-444a-8e00-b8069531d4c0.jpeg align="center")

This implementation serves as an initial foundation for an IoT project, with future plans to expand its capabilities. I intend to enhance the system by integrating a water pump and canister, enabling automated watering when the soil moisture threshold is low. Moreover, I plan to incorporate a feedback loop using a photo-sensor directed at the leaves, providing insights into the tree's performance and enabling the determination of an optimal threshold.

In addition to these advancements, I aim to integrate the board into the Tuya platform, replacing the existing presentation layer. This integration will seamlessly incorporate the Bonsai care system into my smart-home ecosystem, enhancing its accessibility and integration with other connected devices.
