~/blog/plant-monitor/prototype
Published on

Homemade plant irrigation monitor - [Part 3] - OLED screen and fitting everyting inside a usable form factor

Authors
  • avatar
    Name
    Branimir Kirilov
    Twitter

Intro

In the previous part of this blog series, I delved into the intricacies of connecting the ESP board securely, ensuring seamless data transmission to Firebase RTDB. However, the current setup leaves much to be desired—picture the sensor, board, and shield casually dangling from their wires. It's not exactly the polished setup I envision when integrating this into a real plant or garden.

Connection OLED screen and displaying data to it

In the past chapters, I mentioned an OLED display as an optional requirement. Right now all of the data is already present in RTDB and can be fetched and distributed by any application I choose therefore an external display is not needed at all. Moreover, it will significantly shorten the battery life. However, I want to connect an external display just for the fun of it and the things I'll learn.

The display that I'll be using is a 0.96" 128x64 inexpensive I2C OLED 101864. It has only 4 pins and this is the connection scheme. (I already have the moisture sensor connected to the ground (G) pin, so I had to solder a common wire between them).

oled screen connection

Next,the Adafruit libraries need to be installed in order to control the OLED. If you are using Arduino IDE, open it and click Sketch -> Include Library -> Manage Libraries. Search for Adafruit, scroll down to the Adafruit Gfx library and Adafruit SSD1306 and install them.

Here's a tiny code snippet that you can use to test the display and the connection. Alternatively, you can use one of the examples that come with the SSD1306 library.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup()   {
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  delay(2000);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  display.println("Hello world");
  display.display();
}

void loop() {
}

After uploading, you should see the text "Hello world" text on the screen.

Integrating the display to the existing Sketch

I would like the display to print all the information on it during the connection and the interaction with RTDB (like a Linux terminal). For this, I'll define a new method that will take input parameters and print them both on the display and on the serial monitor. This way I can debug issues with connectivity and sensor data easily while only looking at the OLED screen (or by inspecting the serial when the device is connected via USB).

// Initializes the OLED screen on startup
void initializeOledAndShowStartupScreen() {
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  delay(2000);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  logMessage("Waking up!");
  delay(2000);
}
// Appends a (formatted) message to the display and to serial output
// Formats the display output in 3 lines of 2 rows. When the buffer is full, clears the bottom most line and puts a new one on top (like a stack)
// Also accepts variable arguments
void logMessage(const char* format, ...) {
  va_list args;
  va_start(args, format);

  // Get current time
  timeClient.update();
  hours = timeClient.getHours() + 2; // convert to my time zone
  minutes = timeClient.getMinutes();
  seconds = timeClient.getSeconds();

  char buffer[128];
  vsnprintf(buffer, sizeof(buffer), format, args);

  // Format hours and minutes with leading zeros
  String formattedHours = (hours < 10) ? "0" + String(hours) : String(hours);
  String formattedMinutes = (minutes < 10) ? "0" + String(minutes) : String(minutes);

  String logMessage = formattedHours + ":" + formattedMinutes + "> " + String(buffer);
  currentLine = (currentLine + 1) % MAX_LINES;
  logLines[currentLine] = logMessage;

  display.clearDisplay();

  for (int i = 0; i < MAX_LINES; i++) {
    int lineIndex = (currentLine - i + MAX_LINES) % MAX_LINES;
    display.setCursor(0, i * 16);
    display.println(logLines[lineIndex]);
  }

  display.display();
  va_end(args);

  Serial.println(logMessage);
}

Now I will use the function everywhere I want to print something, which will output both to the screen and to the Serial. For example:

  int getSensorReading() {
  int sensorReading = analogRead(SensorPin);
  logMessage("Sensor: %d \n", sensorReading);
  return sensorReading;
}

Full source code can be found on Github

This is how it looks after I uploaded the sketch:

Brainstorming a box / container

Now that I added the display, the initial idea I had for the form factor of the device has changed:

  1. The enclosure needs to be water resistant (so I can put it in my garden)
  2. The internals should be easily accessible (to charge the battery and update the sketch if needed)
  3. The sensor should be outside, so it can be plugged into the soil
  4. The display should be visible, but inside the weather-resistant container

With the new requirement, I would have to make sure that a part of the box is transparent so that the display readings can be observed from outside.

The plan I have is to form the device based on a gardening tool whose name I don't really know, but I'll call seed hole puncher ... you guessed it it's used to punch holes in the ground ... where seeds grow. This is what it looks like.

seed hole puncher image

Now imagine that the pointy peak it has is the soil moisture sensor and everything else is fitted inside of the handle. Also, the handle is straight, like a GoPro grip with a transparent part on the top. I have the vision but I'm definitely not sure how I would create this out of thin air.

I don't have access to a 3D printer or anything of this sort so I had to use things I find at home or at the nearest hardware store. I went shopping and found a cheap snow-cleaning brush for cars. It was made out of thin plastic that could easily be cut and manipulated. I also grabbed a few sterile containers that would serve the purpose of a transparent removable cap on the top.

After a bit of R&D and a lot of performant ( ͡° ͜ʖ ͡° red duct tape I ended up with something that represented my vision, or at least a prototype of it.

full prototype closed

full prototype opened

full prototype opened

It seems that this meets all of my requirements! Now, let's test this on the basil that we take care of in our kitchen.

full prototype opened

Testing and battery considerations

As I mentioned above, the display would certainly affect the battery life. But how much damage it would do? I decided to make some measurements and to find out. I brought up my multimeter and I set it to measure amps. Then I connected the positive wire of the battery to the red probe on the multimeter and the negative (black) probe to the + of the ESP board. This gave me a reading of the current draw of the device. During start the whole thing uses ~150mA and peaks up to ~250mA while connecting to WiFi and sending data. This lasts about ~10 seconds, after this the device goes to deep-sleep. When this happens my multimeter shows no current draw at all, perhaps it's not that good and can't measure consumption this low. From sources I found online such as this one, I estimated that the display would use around 8.5mA with 50% pixels illuminated at the default brightness, while the Wemos D1 mini v4 around 84µA (source here). This source also mentions that it can peak up to a whopping ~450mA, which is a lot for this type of board.

Using this cool calculator the estimated time with the display always on at the default brightness is 11 days with a single battery.

full prototype opened

If I run the calculator again but this time with the data without the display, the results are entirely different - ~380 days.

full prototype opened

Conclusions

All of the above were just estimations so I decided to actually test how long would it last with the OLED on. The results were terrible - 4 and a half days of measurements on 4h long intervals and the battery died! This would definitely not work for a real garden. The display has to come off and this would be my next step. If you followed along to this point, you can just revert the code from this topic and disconect the additional wires from the ESP board. Everything else should remain the same.

Considering the calculations above, testing how long a battery would last will take some time. I'll publish a follow-up on this topic once the test concludes. Stay posted!