Intelligent watering



I am working on intelligent watering feature in my MLH farmware. Good news is that it looks like it works. Bad news is that it will not likely to help people who expect it to work out of the box. If you don’t afraid of Python and willing to fork my project - here you go - please note this is not a mainline branch, so people who are using it already are not affected.

The idea is to let farmware decide how much water each plant needs basing on the

  • plant name
  • plant age
  • past rains in your area

Here are the ideas that I put together:

  • you need to run Netatmo farmware in the sequence before MLH to get up-to-date weather reading
  • put AFTER sequence that has ‘water’ and ‘mlh’ in it is name (for example “Water [MLH]”) to engage intelligent watering mode (see below for explanations). If this name is not found - MLH works as usual
  • In the code I hardcoded a matrix that specifies how much water each plant needs each day (unfortunately openfarm doesn’t have this info afaik). most likely you’ll need to update this matrix as it only has my plants and reflects my understanding of the watering which might differ from yours
  • farmware skips watering if there was a big rain 2 days ago or good rain yesterday or rain today (see code to for details)
  • otherwise it waters each eligible plant according to the matrix and makes a record to avoid double watering this day.

AFTER sequence:
You need to create a sequence that waters one plant; name it so it has “water” and “mlh”. For example ‘Water [MLH]’. The simplest sequence would be

  • open valve
  • wait 1000ms
  • close valve
    Before MLH farmware calls this sequence it updates the duration to the calculated value - this is how each plant gets individual amount of water. In my case 1000ms=80ml. In your case it might be different.

Possible improvements:

  • it is impractical to dispense small water quantities per plant. For example it is not a good idea to water each carrot. I am working on detecting carrot patch box and water all carrots at once (without stopping water for every plant)
  • I want to plugin to some water forecast service to avoid watering if rain is expected soon

Thank you,


A friend of mine gave me an idea to use plant spread and plant age as the gauge of amount of watering needed.
This eliminates the need of hardcoded matrix and brings this farmware close to public use.

implemented in 2.3.7


Hello Eugene,
Since you seems to be the most experienced expert in writing farmware I hope you don’t mind if I ask you some questions.

I am also creating my watering sequence derived from your MLH.

My biggest problem is that my farmbot is not running very stable and disconnects/e-stops quite frequently.
This results in the problem that my watering sequence stops in the middle and if I restart it starts from the beginning again.

My idea was to store the last X position (somewhere: I tried the os.environ but that does not work right after a e-stop), and then resume from that position. For now I added a new variable in the manifest with the “starting X position”, that I can at least manually resume from a certain X Position but I rather have my farmbot auto-restart after an e-stop.

Do you have a better idea where to put this kind of information (Last watered X Position)?




This is exactly the problem I met myself. Did you try to use the following parameters?

  • FILTER BY META DATA [(‘last_watering’,’!today’)]
  • SAVE IN META DATA [(‘last_watering’,‘today’)]

This shall do the trick. All successfully watered plants will be marked as ‘last_watering’:'2018-05-27’
and they won’t be considered for the watering the same day.

hope it helps. There are more tricks in readme.



Here something interesting I came across today:

Anyone interested in decoding this formula? :smiley:


Optimal movement is not a piece of cake. It is a NP full problem (i.e. you can’t solve it precisely for any decent number of plants).

I created an approximate solution that works as following:

  1. select closest plant to 0,0
  2. go over the plants with the same name
  3. select next closest plant to current head position
  4. go to 2

when doing #2 I start not with the plant selected on a step 3, but rather with a plant with the same name but located in the corner (if multiple plants of this type found) - see what happened with Carrot
#2 is implemented as a greedy algorithm, I simply go to the next nearest plant that has the same name.

It looks good for me but it may have problems with your setup. Let me know if you have suggestions.

Thank you,


Looks awesome!
I have a very unreliable internet connection - at least for the AMQP/MQTT side of the robot. My web-apps do not have that problem.

Quick questions:
in case the Bot disconnects / E-Stops, I want the watering sequence to continue where it left of. Do you have this in your code as well?

I am trying to figure out if I can talk directly with the Bot (PI) instead of sending my commands up to the cloud and back down to the bot even though I am “standing right next to it” (aka same subnet with my controlling service).
Is there any way I can reroute “just” the celery script to my local PC (without installing the full setup)? or even better directly send commands to the PI without going through the cloud?



in case the Bot disconnects / E-Stops, I want the watering sequence to continue where it left of.

Yes, this is possible
there are 2 ways to do it

- FILTER BY META DATA:              [('plant_stage','planted'), ('last_watering','!today')]
- SAVE IN META DATA:                [('last_watering','today')]

or Intelligent Watering.
see more in documentation:

Is there any way I can reroute “just” the celery script to my local PC (without installing the full setup)? or even better directly send commands to the PI without going through the cloud?

Assuming that you don’t mind to Python: Yes, you shall not use MQTT if you are in the same subnet. Even if you are on public Internet - you can setup port forwarding on your router and send commands directly to your bot

  # ------------------------------------------------------------------------------------------------------------------
    def log(self, message, message_type='info'):

            if not self.local:
                log_message = '[{}] {}'.format(self.app_name, message)
                node = {'kind': 'send_message', 'args': {'message': log_message, 'message_type': message_type}}
                response = + 'api/v1/celery_script', data=json.dumps(node),headers=self.headers)
                message = log_message
        except: pass



Hey @etcipnja interesting approach you have chosen!
How do you adjust the spread according to the plant age? Which age would be = 100% spread?
Did you try this out already? When I see the spreads which are shown in the farmdesigner they hardly match… moreover I have seen that plants will all of a sudden jump and then stay without growing for some while if temperatures and sun prohibit this, so I guess you´re approach won´t work very well… But I am happy to be convinced :slight_smile:

What I am currently looking at is replacing the rubbish farmbot soil sensor by a permanent one with which I can then ultimately trigger watering… everything else is a very complex algorithm in my opinion (humidity, temps, rain of the last days and forecasts of the coming days) which I am far away from I guess…


@Klimbim you are right on that plants grow on they own schedule and there is no formula that fits all.
Originally I had a big matrix that set watering for every plan by name and age. Later I replaced it with the function of spread and age (see self.coming_of_age - this is when I believe plant gets its full spread and height).

BTW: I consider farmbot project as an extreme way to learn Python. So I don’t care much if I have crop or not. Also it is a lot of fun!
Yes, I use my intelligent watering for watering my garden and adjust variables on the fly. This is why I do not want to claim that it is ready for everybody to use out of the box.

Here are my assumptions that you may find in the the code

        self.ml_per_sec=80.0    #my pump produces 80ml/sec
        self.coming_of_age=7*15 #I believe that in 15 weeks plant becomes an adult (i.e. takes the full height and spread)
        self.magic_d2lm=3       #Magic mutiplier to convert plant size to ml needed for watering
        self.small_rain=1       #1mm is a small rain (cancells watering today)
        self.medium_rain=10     #10mm is a medium rain (cancells watering today and tomorrow)
        self.big_rain=20        #20mm is a big rain (cancells watering today, tomorrow and day after tomorrow)

Thank you