Awesome
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".