Automating the process of ‘When to water’

Based on current soil moisture (dryness) level

A flea looking thing holding a watering can wrongly, next to a flower.  It is trying to understand when to water the plant.

Even as a plant lover, It’s difficult to understand when or how often to water your plants. Each plant has different soil texture and moisture requirements. And that is even before considering nutrients or light.

In the posts up until now, I’ve covered building a system that measures the moisture level (dryness) of soil in a given area around a plant. Now it’s time to make decisions based on that measurement. This post details how that will happen.


Process Variable and Setpoint

Our process variable is the dryness level in the soil that we are measuring. This is the thing we want to control, and ensure meets some ‘requirement’ of the plant that is living in it.

The setpoint is the thing that will vary from plant to plant. We want to choose a dryness level that gives the plant the optimum amount of time between waterings to allow its roots to do the things they need to do, prior to being immersed in the feeding waters that will keep the plant alive.

Using these two things together, we can determine when it’s time to water the plant.


Let’s see some code:

Reducing the responsibility of all functions involved tends to result in more testable code, so above I’ve got this operation about as simplified as it can get. the function would receive the current value from the sensor, and compare that against the setpoint in the controller. After that further functions would need to be invoked based on whatever the responsibilities of the system are.

Any logic that stands in the way of watering that is not limited specifically to comparing the process variable against the setpoint is removed from the function. That is the point of “interlocks”, and these interlocks are determined in another context within the program. Doing this allows for isolating the considerations, properly naming them when they are combined, and breaking complexity down into smaller bits so it can be more easily reasoned about.

Interlocks?

This is just a term that is used in some industry that prevents a certain action from happening unless happy and safe conditions are met. Watering a plant is a great example of a thing that should definitely be verified to be safe to do. Some reasons for that are:

  • If the reservoir that a pump is in doesn’t have enough water, the pump can be destroyed

  • if self-eval checks fail, this can throw an interlock condition and request human verification

  • If there are other conditions that should prevent watering, like sunlight is too intense and the watering mechanism sprays the plants instead of watering the soil, this would be another reason to wait to water until the evening (unless the dryness level is dangerously high)

I view interlocks as auxiliary conditionals that can all be combined into one category that can ‘override’ the original and base-level logic of a function. In this case that happens to be watering a plant.

Conclusion

The key thing to take away here is that answering the reality based question ‘When to water a plant’ is a thing that’s worthy of it’s own specific and tested code, even though it’s fairly simple in theory. I’ve seen tasks like this abstracted to the nth degree to where so many contingencies and diverters stand in between the simple question, “should I water or not”.

Previous
Previous

My Docker Installation Experience

Next
Next

Ending the Rust 365 Challenge Early