Skip to content

Instantly share code, notes, and snippets.

@rdeprey
Last active November 9, 2021 16:36
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rdeprey/6395b808c9b72213d8a3f298a63efaca to your computer and use it in GitHub Desktop.
Save rdeprey/6395b808c9b72213d8a3f298a63efaca to your computer and use it in GitHub Desktop.
Automatic Plant Waterer
{
"name": "plant-waterer",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"node-schedule": "^1.3.2",
"onoff": "^6.0.0",
"mcp-spi-adc": "^3.1.0"
}
}
// Make sure that you're using Node v16.x and up
// Setup the sensor input
const mcpadc = require('mcp-spi-adc');
const Gpio = require('onoff').Gpio;
const schedule = require('node-schedule');
const completelyWet = 395;
const completelyDry = 780;
const pumpRelay = new Gpio(17, 'high'); // IMPORTANT: Use 'high' if relay uses low level trigger
function getSensorReadings(sensor) {
return new Promise((resolve, reject) => {
sensor.read((readError, reading) => {
if (readError) {
return reject(new Error(`There was an error getting the sensor reading:
${readError}`));
}
return resolve(reading);
});
});
};
function getMoistureLevel() {
const readingPromises = [];
let readings = {};
readings.rawValues = [];
readings.values = [];
return new Promise((resolve, reject) => {
const sensor = mcpadc.open(5, {speedHz: 20000}, (error) => {
if (error) {
return reject(new Error(`There was an error accessing the sensor: ${error}`));
}
let iterator = 50; // Just need a large number of readings to try for better accuracy
while (iterator >= 0) {
readingPromises.push(getSensorReadings(sensor)
.then(reading => {
readings.rawValues.push(reading.rawValue);
readings.values.push(reading.value);
}).catch(error => {
return reject(error);
})
);
iterator--;
}
return Promise.all(readingPromises).then(() => {
const averageRawValue = readings.rawValues.reduce((a, b) => a + b, 0) / 50;
const averageValue = readings.values.reduce((a, b) => a + b, 0) / 50;
// Set the value to a percentage based on the max reading
return resolve({
rawValue: averageRawValue,
value: averageValue,
soilDrynessPercentage: averageRawValue > 0 ? ((averageRawValue / completelyWet) * 100).toFixed(0) : 0,
});
});
});
});
};
function shouldWater(moistureLevel) {
// Adjust this value based on your sensor and the needs of your plant
// Value represents a percentage
if (moistureLevel <= 45) {
return true;
}
return false;
};
function waterThePlant() {
return new Promise((resolve, reject) => {
pumpRelay.read(async (error, status) => {
if (error) {
return reject(new Error(`There was an error getting the pump relay status: ${error}`));
}
const moistureLevel = await getMoistureLevel();
const needsWater = shouldWater(moistureLevel.soilDrynessPercentage);
if (status !== 0 && needsWater) {
pumpRelay.writeSync(0); // closes the circuit and starts the pump
}
return resolve({
status: `The plant is being watered.`,
});
});
});
};
function stopWateringPlant() {
return new Promise((resolve, reject) => {
pumpRelay.read((error, status) => {
if (error) {
return reject(new Error(`There was an error getting the pump relay status: ${error}`));
}
if (status !== 1) {
pumpRelay.writeSync(1); // opens the circuit and stops the pump
}
return resolve({
status: `The plant is not being watered.`,
});
});
});
};
const shouldWaterPlant = () => {
// Run every day at 7 a.m.
return schedule.scheduleJob('0 7 * * *', async () => {
if (shouldWater) {
// Water the plant for three seconds
setTimeout(() => {
waterThePlant();
setTimeout(() => {
stopWateringPlant();
}, 3000);
}, 3000);
}
});
};
shouldWaterPlant();
@rdeprey
Copy link
Author

rdeprey commented Sep 12, 2021

Hi @LowCulture, I think that I found the issue. I think it's related to newer versions of Node and the onoff package. I didn't run into this with Node 13.x, but I could replicate it with Node 16.x and onoff version ^5.0.0.

I came across this exact error reported to the onoff package here, fivdi/onoff#170, and they mentioned that they fixed it in version 6. I tested using onoff version ^6.0.0 and Node 16.9.1 and that worked for me. Would you mind updating onoff to at least version 6.0.0 and seeing if it works for you?

@LowCulture
Copy link

That did it, thank you for your help with this!

@rdeprey
Copy link
Author

rdeprey commented Oct 3, 2021

I'm glad it's working now. :) Thanks for bringing this up - I'm going to update the post for the latest Node so that others don't run into this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment