Grow.js

Easily create new IoT devices and connect them to a Grow-IoT instance.

Usage no npm install needed!

<script type="module">
  import GrowJs from 'https://cdn.skypack.dev/Grow.js';
</script>

README

Grow.js

Build Status Code Climate Join the chat at https://gitter.im/CommonGarden/Grow.js

Grow.js is an extension of Thing.js with extra utilities for growers.

Installation

npm install Grow.js

Grow.js

Grow.js is an extension of Thing.js, which is an exstension of the node event emitter class. See Thing.js for more information about the Thing api which Grow.js inherits and for connecting to to Grow-IoT. You can also use Grow.js by itself with out connecting to a Grow-IoT instance.

This readme, covers Grow.js specific features like sensor calibration, setting up event listeners for monitoring evnvironment data, scheduling, and parsing 'Growfiles.'

Grow Files

There are three main components to a Grow file:

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();

// Start a Grow by passing in a valid growfile
example.startGrow({
  targets: {
    temperature: {
      min: 17,
      ideal: 22,
      max: 28,
    }
  }
});

// Uses node event emitter api
example.on('alert', (message)=> {
  console.log(message);
});

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

// Likewise if it 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...

    testGrow.on('corrections', (key, correction)=> {
      console.log(key);
      console.log(correction);
    });
    testGrow.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:

  temperature: {
    min: 17,
    ideal: 22,
    max: 28,
    pid: {
      k_p: 1,
      k_i: 2,
      k_d: 2,
      dt: 10
    }
  },

Calibration

Grow.js contains some utilities for calibrating sensors. The calibrate() method takes an eventname, and calibration data in the form of a list that has in the format [measuredValue, knowValue]. Calibration data can be a list of the lists for example:

let calibration_data = [[10, 11], [20.5, 21], [30, 29]]

example.calibrate('temperature', calibration_data)

// New calibration points can be added like so
example.calibrate('temperature', [25, 24.9])

The predict() method uses available calibration data to run a regression on the known values. It takes an eventname argument and a value.

example.predict('temperature', 31)

If no calibration data is defined for the event it simply returns the value.

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).

Phases

Cycles and targets aren't enough to fully express a plant'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 climaterecipe = {
  "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
            }
          }
        }
      }
    }
  }
};

example.startGrow(climaterecipe)

Climate recipees in Grow.js are serialized as JSON, which means the same recipees can play well in JavaScript, Python, C++, and more! Interoperability and standardization are things we should strive for.

There is lot's of future work to be done! As a potential forum for working on such projects, I think a W3C community group would be great.

If you have thoughts or suggestions, I would love to hear them.

Developing

Code is written in ES6, and compiled using rollup.

npm run build builds the library.

npm run test builds the library, and runs tests in the test folder.

The documentation is written in jsdoc, built using Mr-Doc, and on the gh-pages branch of this repo.

License

Grow.js is released under the 2-Clause BSD License, sometimes referred to as the "Simplified BSD License" or the "FreeBSD License".