Climate Recipees format thoughts and node.js library


#1

A while ago, I started a JavaScript library called Grow.js in hopes of starting to make progress on Climate Recipes that can be used outside of the context of the personal food computer.

Grow.js constructs an event emitter with utilities for parsing Climate Recipees, calibrating sensors, creating basic PID controllers, and monitoring a stream of events. I’ll introduce the key concepts of targets, cycles, and phases (which from the looks of the openag_recipe_bag repo on GitHub, this community largely seems familiar with); then follow it up with a complete example.

Your thoughts would be wonderfully helpful. Open question, how can we move forward and begin to standardize Climate Recipees?

Targets

Targets create listeners for events from sensors and emit alerts or correction events. min, max, and ideal are currently supported.

const Grow = require('Grow.js');
const example = new Grow();

example.startGrow({
  targets: {
    temperature: {
      min: 17,
      ideal: 22,
      max: 28,
    }
  }
});

// Grow.js uses the node event emitter api
// See https://nodejs.org/dist/latest-v8.x/docs/api/events.html
example.on('alert', (message)=> {
  console.log(message);
});

// Here we emit a temperature event, it's ideal so nothing happens
example.emit('temperature', 22);

// If a value falls below a threshhold we emit an alert event
example.emit('temperature', 10);
// { temperature: 'low' }

// Likewise if the value is above the threshold
example.emit('temperature', 30);
// { temperature: 'high' }

If an ideal is specified for a target a PID controller is created and emits correction events. Continuing from the above example…

    example.on('corrections', (key, correction)=> {
      console.log(key);
      console.log(correction);
    });
    example.emit('temperature', 17);
    // temperature
    // 0.04050000000000009

You can use the correction to control heaters, dosing pumps, and more! For control over the PID controller’s parameters you can pass in options under a pid property:

example.registerTargets({
  temperature: {
    min: 17,
    ideal: 22,
    max: 28,
    pid: {
      k_p: 1,
      k_i: 2,
      k_d: 2,
      dt: 10
    }
  }
});

There are more aproaches aside from PID controllers that would be great to explore for controlling environments with sensors and actuators.

Cycles

Cycles are functions that are called at specific times in succession (for example, during the course of a day).

Cycles are also a way of defining moving targets. For example, you might have a different target daytime and nighttime temperature:

example.parseCycles({
  day: {
    schedule: 'after 7:00am',
    targets: {
      temperature: {
        ideal: 22
      }
    }
  },
  night: {
    schedule: 'after 7:00pm',
    targets: {
      temperature: {
        ideal: 18
      }
    }
  }
})

In the example above the ‘day’ event will be emitted after 7:00am. Various internet of things devices such as lights can listen for those events, and respond accordingly (such as turning the lights on).

We use later.js to parse the schedules.

Phases

Cycles and targets aren’t enough to fully express a organism’s life cycle. Phases are a way to create groups of cycles and/or targets.

A plants life cycle might be broke up into the following phases:

  • Seedling
  • Vegatative
  • Flowering
  • Harvest

Each might have different environmental conditions with regards to lighting, pH, nutrients, temperature, etc.

Phases may have a length attribute which specifies how long they last.

In some cases may require a human to transition the grow system towards the next phase (such as transplanting seedlings, or replacing the water in the resevoir). In other words, phases may automatically or manually transition into the next phase.

Basic example

const Grow = require('Grow.js');

const climaterecipe = new Grow({
  "name":"Basic climate recipee",
  "description": "Metadata goes here.",
  "version":"0.1.0",
  "phases":{
    "vegetative":{
      "length": "28 days"
      "targets":{
        "ph":{
          "min":6,
          "ideal":6.15,
          "max":6.3
        },
        "ec":{
          "min":1400,
          "ideal":1500,
          "max":1700
        },
        "humidity":{
          "min":51,
          "max":61
        },
        "temperature":{
          "min":17,
          "max":28
        }
      },
      "cycles":{
        "day":{
          "schedule":"after 6:00am",
          "targets":{
            "temperature":{
              "ideal":22
            }
          }
        },
        "night":{
          "schedule":"after 9:00pm",
          "targets":{
            "temperature":{
              "ideal":18
            }
          }
        }
      }
    },
    "bloom":{
      "length": "32 days"
      "targets":{
        "ph":{
          "min":6,
          "ideal":6.15,
          "max":6.3
        },
        "ec":{
          "min":1400,
          "ideal":1500,
          "max":1700
        },
        "humidity":{
          "min":51,
          "max":59
        },
        "temperature":{
          "min":17,
          "max":28
        }
      },
      "cycles":{
        "day":{
          "schedule":"after 7:00am",
          "targets":{
            "temperature":{
              "ideal":22
            }
          }
        },
        "night":{
          "schedule":"after 7:00pm",
          "targets":{
            "temperature":{
              "ideal":22
            }
          }
        }
      }
    }
  }
});

Climate recipees in Grow.js are serialized as JSON, which means the same recipees can play well in JavaScript, Python, C++, and more!

As a potential forum for standardizing climate recipees, I think a W3C community group would be great if anyone is interested. There’s already an Agriculture Community group, perhaps that would be a good forum to discuss standardization of climate recipees?


#2

@JakeHart
There are a stack of issues here, which we all keep struggling with; though each coming at it with a different set of strengths.

  1. How much do we separate prescription from implementation? I think you are right that JSON is likely our language of definition, with multiple implementations (Java, Python, …). JSON lacks the specificity of XML, but I am not finding anyone having the nerve to take on the weight of XML.
  2. Cycles: we definitely need t.hem, but there is a question of how many and what they are. What do we do with lettuce, where we don’t have a flowering a flowering cycle; do we leave it out or have some “NULL” values? You are combining plant growth stages with agricultural activities (ie. flowering is a plant stage, harvest is what a person does to the plant). I think we will want to split plant growth stages from agricultural activities (which may be timed to occur at a growth stage). There is a lot on growth stages, unfortunately little consistency. Plants like corn and soybeans are quite standardized, but attempts to define common stages across plants are still a struggle (ie Plant Ontology). I would be inclined to have a closed list of ‘canonical’ cycles, with those that are omitted in the recipe are assumed to not be performed. The recipe needs to specify what is to be done (agricultural activities), regardless of whether they are automated or manual. We also need to allow definition for predictable activities and ‘as needed’ activities.
  3. Naming: cycles are just one naming issue, we need to come up with our ‘ontology’ for all our names. Is this ‘ideal’ or ‘target’?
  4. Units: you list temperature, but do not state if this is Centigrade or Fahrenheit (I assume Centigrade). The link @Webb.Peter provided is a good start.

I appreciate your work on this.


#3

JSON does lack the specificity of XML, but JSON-LD is much more specific than plain old JSON and more intuitive than XML (in my opinion). Might be an option to consider: https://json-ld.org/

Thanks for you’re thoughts! I will read through the documents you linked and will be posting some more of my own soon too when I get a chance.


#4

@webbhm
I am thinking that names related to cycles would be a mapping thing. The cycle is created based on the various criteria. Then an association could be made with specific plant names.
So for leafy vegetables you could create a cycle definition. You could associate this with lettuce or cabbage or possibly even basil.
The point is they are feature similar. After association, you select your plant and define you cycle values.


#5

We definitely need cycles, the question is how complex this gets. Can you clarify with some examples?

I think you are getting into what I refer to as a ‘template’ and ‘plan’ pattern; there could be a general cycle template for leafy vegs, and then a specific plan for lettuce.
From my agriculture work, I am use to grouping this as:
Pre-Planting (prepare soil)
Planting (actually putting the seed in the ground)
Growing
Haravest
Post-Harvest

Within these activities there can be multiple (schedules and un-scheduled) ‘treatments’; these may or may not be cyclic. These can be:
Fertilizer
Pesticidecs
Irrigation
Lights (in greenhouse systems)

Then there is a third category of observations. Again, these could by cyclic (daily, weekly) or ad-hoc

Some of this is also tied to plant life cycles.


#6

I think your thoughts are spot on with what I was thinking. (Better articulated)


#7

@pspeth
This is the stuff that can kill us and makes collaboration difficult. While things like temperature and leaf length are scientific (they objectively exist ‘out there’ (at least if you are not post-modernist)); defining a protocol or experimental procedure exists only in our heads. We don’t discover an experimental process, we create and define one. As such it is possible for a dozen different people to have a dozen different (valid) processes.

The only solution I have found is to define our goals and scope our effort, and let that drive what should be ‘in’ and ‘out’ of the process. Otherwise we will end up arguing over procedures for tracking the phases of the moon and what size crystals we set amongst the plants.