User Tools

Site Tools


smartyplants

Smartyplants

Introduction

This will be a smart plant monitoring/watering solution some day. Until this happens, all progress and docs is kept here. The clou is to have Arduino Nanos as slaves with sensors close to the plants while having a single, central Raspberry Pi Zero W to read out, process and display all sensory information. The central unit can be any computer running linux and having USB ports, tho. Connections from master to slaves are established - who'd have thought - using USB and powered USB-hubs.

Actually, there are thought to be 2 types of Arduino 'slaves':

Plants slaves

One of these (along with its sensors) is meant to be with each plant that is to be monitored. So far, we have a soil moisture sensor and a light-sensitive resistor. To be added soon are sensors for air quality, UV radiation, soil PH, soil temperature.

Room slaves

One or more of these, along with multiple rH, temperature and light sensors (to monitor and/or average different spots), will be placed around the room.

Setup

Raspberry Pi

OS

  • Perform a Raspbian Lite (Torrent, ZIP) install.
  • Fill /root, /etc/skel, /etc/profile.d/, /etc/screenrc, /etc/vimrc
  • Make sure to setup SSH according to the newest CipherLi.st recommendations.
  • Remove pi user, add (and use) your own. Do not use the root user when unnecessary.

Software

# apt-get install \
   arduino-mk bc bsd-mailx curl ncftp \
   ifstat logwatch make molly-guard \
   psmisc rsync screen tcpdump vim snoopy \
   strace ssmtp sudo ntp gawk procps
   
# apt-get purge nano

Arduino Nano

Code

smartypants.ino:

#include <Average.h>

int delayLength = 250;
int inputValue;

int lightSensorPin	= A0;
int lightSensorLedPin = 9;
int lightSensorValue = 0;
float lightSensorThreshold = 353.5;
bool lightSensorLast = false;
Average<int> lightSensorAvg(32);
int lightSensorMinAt = 0;
int lightSensorMaxAt = 0;

int soilSensorPin = A1;
int soilSensorLedPin = 10;
int soilSensorValue	= 0;
float soilSensorThreshold	= 250;
bool soilSensorLast	= false;
Average<int> soilSensorAvg(32);
int soilSensorMinAt = 0;
int soilSensorMaxAt = 0;

void setup() {
	pinMode(lightSensorLedPin, OUTPUT);
	pinMode(soilSensorLedPin, OUTPUT);
	Serial.begin(9600);
	
	lightSensorValue = analogRead(lightSensorPin);
	if(lightSensorValue > 0) Serial.print("PASS: ");
	else Serial.print("FAIL: ");
	Serial.print("LIGHT: ");
	Serial.println(lightSensorValue);

	soilSensorValue = analogRead(soilSensorPin);
	if(soilSensorValue > 0) Serial.print("PASS: ");
	else Serial.println("FAIL: ");
	Serial.print("SOIL: ");
	Serial.println(soilSensorValue);
	
	if(lightSensorValue > 0 && soilSensorValue > 0)	Serial.println("PASS: POST - GO");
	else {
		Serial.println("FAIL: POST - STOP");
		while(1);
	}
	
}

void loop(){
	lightSensorValue = analogRead(lightSensorPin);
	lightSensorAvg.push(lightSensorValue);
	if (lightSensorAvg.mean() < lightSensorThreshold) {
    	digitalWrite(lightSensorLedPin, HIGH);
		if (lightSensorLast == false) {
			Serial.print("ALERT: LIGHT: ");
			Serial.println(lightSensorAvg.mean());
			lightSensorLast = true;
		}
	} else {
		digitalWrite(lightSensorLedPin, LOW);
		if (lightSensorLast == true) {
			Serial.print("OK: LIGHT: ");
			Serial.println(lightSensorAvg.mean());
			lightSensorLast = false;
		}
	}
	soilSensorValue = analogRead(soilSensorPin);
	soilSensorAvg.push(soilSensorValue);
	if(soilSensorAvg.mean() > soilSensorThreshold){
		digitalWrite(soilSensorLedPin, HIGH);
		if(soilSensorLast == false){
			Serial.print("ALERT: SOIL: ");
			Serial.println(soilSensorAvg.mean());
			soilSensorLast = true;
  	  	}
	} else {
		digitalWrite(soilSensorLedPin, LOW);
		if(soilSensorLast == true){
			Serial.print("OK: SOIL: ");
			Serial.println(soilSensorAvg.mean());
			soilSensorLast = false;
		}
	}
	
	if(Serial.available() > 0){
		inputValue = Serial.read();
		switch(inputValue){
			// L or l
			case 76:
			case 108:
				// light sensor
				Serial.print("LIGHT: cur: ");
				Serial.print(lightSensorValue);
				Serial.print(", avg: ");
				Serial.print(lightSensorAvg.mean());
				Serial.print(", mode: ");
				Serial.print(lightSensorAvg.mode());
				Serial.print(", min: ");
				Serial.print(lightSensorAvg.minimum(&lightSensorMinAt));
				Serial.print(" at ");
				Serial.print(lightSensorMinAt);
				Serial.print(", max: ");
				Serial.print(lightSensorAvg.maximum(&lightSensorMaxAt));
				Serial.print(" at ");
				Serial.print(lightSensorMaxAt);
				Serial.print(", stddev: ");
				Serial.print(lightSensorAvg.stddev());
				Serial.println();
			break;
			// S or s
			case 83:
			case 115:
				// soil sensor
				Serial.print("SOIL: cur: ");
				Serial.print(soilSensorValue);
				Serial.print(", avg: ");
				Serial.print(soilSensorAvg.mean());
				Serial.print(", mode: ");
				Serial.print(soilSensorAvg.mode());
				Serial.print(", min: ");
				Serial.print(soilSensorAvg.minimum(&soilSensorMinAt));
				Serial.print(" at ");
				Serial.print(soilSensorMinAt);
				Serial.print(", max: ");
				Serial.print(soilSensorAvg.maximum(&soilSensorMaxAt));
				Serial.print(" at ");
				Serial.print(soilSensorMaxAt);
				Serial.print(", stddev: ");
				Serial.print(soilSensorAvg.stddev());
				Serial.println();
			break;
			// T or t
			case 84:
			case 116:
			Serial.print("THRES: LIGHT: ");
			Serial.print(lightSensorThreshold);
			Serial.print(", SOIL: ");
			Serial.print(soilSensorThreshold);
			Serial.println();
			break;
			default:
				Serial.println("HELP: l/L: LIGHT, s/S: SOIL, t/T: THRES");	
			break;
		}
	}
	else{
		delay(delayLength);
	}
}

/* EOF */

Makefile:

PROJECT_DIR       = /root/smartyplants
ARDUINO_LIBS      = Average
ARDMK_DIR         = /usr/share/arduino
ARDUINO_DIR       = /usr/share/arduino
USER_LIB_PATH    :=  $(PROJECT_DIR)/lib
BOARD_TAG         = nano328
MONITOR_BAUDRATE  = 9600
AVR_TOOLS_DIR     = /usr
AVRDUDE          = /usr/bin/avrdude
CFLAGS_STD        = -std=gnu11
CXXFLAGS_STD      = -std=gnu++11
CXXFLAGS         += -pedantic -Wall -Wextra
MONITOR_PORT      = /dev/ttyUSB*
CURRENT_DIR       = $(shell basename $(CURDIR))
OBJDIR            = $(PROJECT_DIR)/bin/$(BOARD_TAG)/$(CURRENT_DIR)
check-syntax:
	$(CXX) -c -include Arduino.h   -x c++ $(CXXFLAGS)   $(CPPFLAGS)  -fsyntax-only *.ino
include $(ARDMK_DIR)/Arduino.mk

NOTE: Use make help to find out what to do. One useful chain of targets would be:

# make check-syntax && make && make upload && make monitor

Wiring

smartyplants.txt · Last modified: 2017/10/25 22:58 by flo