The IntelliGrator!

Does the IntelliGrow software cater directly to your needs?

Is it missing something you would like?

In this article I will show how I leveraged Autogrow’s Open API and SDK in order to add a feature that doesn’t already exist in the software offering — specifically, a solar trigger.

IntelliGrow, despite being very useful and packed full of features does not support such a function, since it is designed mainly for use in single room control with an NFT style irrigation setup.

So why do this? It may actually not be a useful thing to do for the type of system these devices are typical use for, but as an experiment I want to see if I can add a new feature.

Solar Triggers

Firstly, what are solar triggers? As plants are exposed to light their transpiration increases, therefore the amount of water they need goes up. By using the accumulated or integrated light as a trigger point the amount of irrigations are done proportionally to the level of light the plants are receiving.

The System

In-order for this to work I need a few things

  • 1 x IntelliClimate
  • 1 x Environment Sensor
  • 1 x IntelliDose
  • At least one connected irrigation valve
  • 1 x IntelliLink/Gateway (connection to IntelliGrow)
  • An IntelliGrow Account (if you don’t have one you can find all the info here — https://autogrow.com/intelligrow/
  • The Autogrow Golang SDK (go-jelly)

I have set up my system like so,

After connecting the IntelliClimate and IntelliDose to the IntelliLink and the IntelliLink to the internet, I can setup IntelliGrow. Then I can see the devices come online:

As you can see I am currently getting 55W/m2 (from a fixed light source for test purposes) as my light reading. So how can I use this to trigger an irrigation?

Getting the go-jelly SDK

I have created a new project aptly named IntelliGrator (IntelliGrow Solar Integrator) and have installed the go-jelly SDK using the standard go get command:

go get github.com/autogrow/go-jelly

I can then use the IntelliGrow client inside any golang projects by importing the package:

import "github.com/autogrow/go-jelly/ig"

What information does the application need?

There are a few things the application will need to know in order for this to work correctly:

  • My IntelliGrow username & password
  • Where the light reading I am going to be integrating is coming from (the source IntelliClimate)
  • The device(s) who will action an irrigation (the target IntelliDose)
  • Sample rate (since it’s impractical to sample every second I set a window in which the light reading should be sampled)
  • Trigger level (how much should be integrated before triggering an irrigation in J/m2)
  • Reset at midnight flag (we can reset the accumulator only after an irrigation event has occurred or reset at midnight every day as well)

All this information is stored in a YAML configuration file.

I have made it so the source can be specified as a growroom or a particular IntelliClimate (by specifying the device name or serial number). The same fields are used for the target IntelliDose. I can select what source and target I am using by leaving the fields blank except the one I want.

Note that if the target is a growroom every IntelliDose in that room will get the force irrigation request

I had to create a few functions to parse my configuration file in correctly that I will not go into detail about here, you can check out the code on Github if you’re interested. The config file needs to be passed to the program using the -c command line flag.

So based on the example configuration file above, the IntelliGrator will:

  1. accumulate the light readings from growroom 1 every 10 seconds
  2. wait for the accumulated light to reaches 360J/m2
  3. trigger an irrigation to the IntelliDose with the ID of ASLID17081001
  4. reset the accumulation at midnight

Getting a new client

Using the username and password from the config file structure, I create a new IntelliGrow client from the ig package mentioned above.

If the client is unable to be created the program will just exit and print the error message.

Once I have a valid client I can get my devices by calling the c.GetDevices() method. The client will pull down the information about all the IntelliClimates and IntelliDoses I have added to my IntelliGrow account allowing them to be accessed via the various methods on the client. This also sorts the devices into Growroom objects, mirroring the Device/Growroom relationships setup in IntelliGrow.

The Main

Now for the main for loop of the program. This is going to run based on the sample time I specified inside the config file (10 seconds). Since the goal of the program is to integrate light and check it against the trigger level, there is nothing else for the loop to do until a new sample is requested. After running this it was impractical to print the result every sample so I’ve added a print status ticker that will just print my information about the readings every minute.

The trigger level I specified in the config file is in J/m2 whereas the light reading from IntelliGrow is in W/cm2. So to convert the J/m2 to a W/cm2 value it needs to be multiplied by 1,000,000.

So every 10 seconds the main loop will run, pulling the current light reading from Growroom “1” using the getLightReading method. If this reading ever goes invalid I can detect it via the second return value (a boolean) and simply stop accumulating until they become valid again.

Since integrated light should be accumulated every second, but we don’t want to hit the API every second, we need to multiply the current value by the sample time. This should get a fairly accurate figure that is then added to the accumulation.

It also does a rudimentary check to see if midnight has passed (it would be better to run parallel to the integration logic). The day is captured every loop and if the new day is different from the day of the last loop it is determined that midnight has passed. Thus, the irrigation counter and the accumulation is reset to zero and a message logged to the terminal.

The last part of the loop actually compares the accumulated light level with the trigger level. If the accumulated light has exceeded the trigger level, I call the triggerIrrigation method. This increments the irrigation count and clears the accumulation. A message is also logged to the terminal.

Get Light Reading

Based on the configuration file settings passed in, the function will return the light reading from either a growroom or a specific IntelliClimate device. The light reading is returned with a valid flag to indicate if any errors occur while trying to get it. In which case the errors will be printed to the terminal before returning a zero-reading and a false to indicate the operation failed.

Trigger Irrigation

Based on the configuration file settings passed in one of two things happen. When a growroom is set as the target, the function will pull all the dosers out of that growroom and call their ForceIrrigation method. Otherwise a single IntelliDose is requested from the client and the same method called on that device alone.

Running It

I compile the program using the standard go build method and run it, specifying the configuration file in the arguments:

go build
./intelligrator -c config.yml

After waiting for awhile I decided to modify the trigger time for testing purposes as 360J/m2 can take a bit of time to accumulate.

Setting the trigger level to 0.01 J/m2 I was able to test the functionality almost immediately.

As you can see the program is integrating the current light level up until the trigger point, at which time it triggers an irrigation incrementing the counter. Then it starts accumulating the light from zero again.

Does it work?

Yes. By utilizing the go-jelly SDK along with my Intelli devices and IntelliGrow account I was able to add solar triggered irrigation functionality to my system. Though a very crude implementation with lots of room for improvement I was able to get something up and running relatively quickly and easily.