//This sketch controls a motor that rolls and unrolls reemay over greenhouse crops
//The inputs are : button pushes (for manual control/testing), reed switches (stop at end),light sensor (analog), temperature probe(digital)
//The button pushes and reed switch pushes are debounced which complicates the code but seems needed
//the analog light sensor is smoothed using a running average
//The ouputs are: three relays control a single 24 vdc motor driving the reemay roller. The relays are arranged so that the motor can be reversed or stopped.
// The other output is a digital LED that turns: blue=covered (night); green=opening; yellow= open (day); red=closing
//eventually there will be an output that is a connection to the farmer's phone that reports the greenhouse data and the status of the reemay mover.
//For help contact Lu: [email protected]
#include <OneWire.h> // includes software for temperature sensor
#include <DallasTemperature.h> // includes software for temperature sensor
#include <FastLED.h> // include library for controlling led
//===================================BEGIN DECLARATIONS=================================
////#include "reemay.h" // #defines for this project
#define VERSION_ID F( "reemay version 5 modified 9/19/2024" )
#define RELAY_ONE_PIN 6 // const int relayone = 6;
#define RELAY_TWO_PIN 7 //const int relaytwo = 7;
#define RELAY_THREE_PIN 8 //const int relaythree = 8;
#define BUTTON_PIN 2 // push button to create INTERRUPTION must be on pin 2 or 3.
#define ONE_WIRE_BUS 4
#define reedButton_PIN 3 // the number of the reed pin Lu had this PIN 9
#define LED_PIN 10 // declare which pin is the led output pin
#define NUM_LEDS 1 // specify the number of leds on the digital led
#define THERMISTORNOMINAL 10000 // resistance at 25 degrees C
#define TEMPERATURENOMINAL 25 // temp. for nominal resistance (almost always 25 C)
#define numTempSamples 30 // how many temperaturesamples to take and average, more takes longer but is more 'smooth'
#define BCOEFFICIENT 3950 // The beta coefficient of the thermistor (usually 3000-4000)
#define SERIESRESISTOR 10000 // the value of the 'other' resistor
#define LUMINOSITY_SAMPLE_SIZE 100
#define LUMINOSITY_BOUNDARIES 30/100 // to exclude extra mesures from average calculation. Procentage
#define LUMINOSITY_SAMPLE_DELAY 50
#define PHOTORESISTOR_PIN A0 //input pin for light sensor
// the following are the user adjustable open and close temperatures in degrees F.
const int morning_open_temperature = 82; //test= 82.0, greenhouse= 40.0
const int night_close_temperature = 78; //test = 78.0 , greenhouse = 34.0
const int daytime_close_temperature = 76; // test = 76.0 , greenhouse = 32.0
const int lightThreshold = 400; //daylight detector-- a number between 0 and 1023 where 1023 is the brightest and 0 is the darkest
//const int buttonPin = 5; // the number of the pushbutton pin
//delarations for motor control: three simple relays in reversing configuration
//constants for motor relay pins. To change the pin assignments, open the reemay.h file
const int relay_one_pin = 6;
const int relay_two_pin = 7;
const int relay_three_pin = 8;
//const int reedButton = 9; // the number of the reed pin
// motor_state is a variable for the 4 possible motor states :
// motor_state=0 : motor is stopped before opening (night)
// motor_state=1 : motor is opening (morning sun up)
// motor_state=2 : motor is stopped before closing (day)
// motot_state=3 : motor is closing (evening sun down)
int motor_state = 0; // counter for the 4 possible modes of operation of the motor
// the following variables for the button debouncer are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 35; // the debounce time; increase if the output flickers -- in my sample it is 50
//end delarations for button sensing subroutine
//begin delarations for reed switch sensor
// constants won't change. These set the pin numbers for the reed switch input:
// changing variables for the reed switch debouncer:
int reedState; // the current reading from the input pin
int lastReedState = LOW; // the previous reading from the input pin
// the following variables for the reed swtich debouncer are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastReedDebounceTime = millis(); // the last time the output pin was toggled
unsigned long reedDebounceDelay = 50; // the debounce time; increase if the output flickers
//end declarations for reed switch sensor
//set up for the light and temperature sensors values
// the readings array is initialized with zeros
// the smoothing function takes a RUNNING AVERAGE of the readings
//const int samplesizeLIGHT = 30; //this is the number of readings in the average
//int readings[samplesizeLIGHT] = {0}; // the readings from the analog input
//const int inputPinLIGHT = A0; //input pin for light sensor
bool daylight_state = false; //boolean value for daylight true=day, false=night
// end of delarations for subroutine for sensing light
float tempF;
// create an array of the crgb type for the led in this case the number of leds is 1 (duh)
CRGB leds[NUM_LEDS];
// define the integer variables for the red, green, and blue intensities (0-255)
int g=0;
int r=0;
int b=0;
//end delarations for digital LED
//begin delarations for motor safety timer subroutine
unsigned long motor_start_time = 0; //this variable stores the millis() when the motor starts
unsigned long motor_time_limit = 10000; //this sets a limit on the run time of the motor (in milliseconds)
//end declarations for motor safety timer subroutine
// Data wire is plugged into digital pin 4 on the Arduino
// Setup a oneWire instance to communicate with any OneWire device
OneWire oneWire(ONE_WIRE_BUS);
// Pass oneWire reference to DallasTemperature library
DallasTemperature sensors(&oneWire);
//end of delarations for subroutine for digital temperature sensor
volatile unsigned long lastTimeButtonPressed = millis();
volatile bool buttonPressed = false;
void advance_motor_state()
{ motor_state = (motor_state + 1) % 4;
control_motor_and_leds();
Serial.print("Motor advancing to state = ");
Serial.print( motor_state);
Serial.print(" daylight_state = ");
Serial.print(daylight_state);
Serial.print(" tempF = ");
Serial.print(tempF);
Serial.print(" Millis = ");
Serial.println(millis());
}
void buttonPressedInterrupt()
{ Serial.print(" From ButtonInter current motor_state = ");
Serial.print(motor_state);
Serial.print(" lastTimeButtonPressed = ");
Serial.print(lastTimeButtonPressed);
Serial.print(" millis = ");
Serial.print(millis());
Serial.print(" debounceDelay = ");
Serial.println(debounceDelay);
if ((motor_state == 0 || motor_state == 2) && (millis() - lastTimeButtonPressed > debounceDelay))
{ Serial.print(" Fom inside ButtonInter current motor_state = ");
Serial.println(motor_state);
lastTimeButtonPressed = millis();
buttonPressed = true;
} }
void reedPressedInterrupt()
{ Serial.print(" From reedInter current motor_state = ");
Serial.print(motor_state);
Serial.print(" lastReedDebounceTime = ");
Serial.print(lastReedDebounceTime);
Serial.print(" millis = ");
Serial.print(millis());
Serial.print(" reedDebounceDelay = ");
Serial.println(reedDebounceDelay);
if ((motor_state == 1 || motor_state == 3) && (millis() - lastReedDebounceTime > reedDebounceDelay))
{ Serial.print(" Fom inside reedInter current motor_state = ");
Serial.println(motor_state);
lastReedDebounceTime = millis();
lastReedState = HIGH;
} }
void delay_till_pressed(unsigned long ms)
{ unsigned long start = millis();
while (buttonPressed == false && lastReedState == LOW && millis() - start < ms);
}
// ==========================================END DECLARATIONS===============================
//========================================BEGIN SET UP======================================
void setup() {
//declare pins as output and input
pinMode(BUTTON_PIN, INPUT); // Lu used pinMode(buttonPin, INPUT);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), // Links the PIN to interrupt procedure
buttonPressedInterrupt,
RISING);
pinMode(reedButton_PIN, INPUT); // Lu used pinMode(buttonPin, INPUT);
attachInterrupt(digitalPinToInterrupt(reedButton_PIN), // Links the PIN to interrupt procedure
reedPressedInterrupt,
RISING);
// pinMode(buttonPin, INPUT); //this is the input push button This was Lu setting
pinMode(relay_one_pin, OUTPUT); //these three are for the relays that run the motor fwd, rev, and stop
pinMode(relay_two_pin, OUTPUT);
pinMode(relay_three_pin, OUTPUT);
// initialize serial communication:
Serial.begin(115200); // Lu used Serial.begin(9600);
//set motor relays to LOW
digitalWrite(relay_one_pin,LOW);
digitalWrite(relay_two_pin,LOW);
digitalWrite(relay_three_pin,LOW);
//begin set up for digital LED
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
//end set up for digital LED
}
//. =====================================END SET UP===========================================
// =====================================BEGIN MAIN LOOP========================================
void loop( void )
{ int desired_motor_state = motor_state;
read_light_sensor(); // subroutine to read light sensor to detect day/night. reads value between 0-1023 where 0 is dark.
read_digital_temp (); //subroutine to read digital temperature. Takes 96 milliseconds
if ( daylight_state == true && tempF > morning_open_temperature ) desired_motor_state = 2;
if ( tempF < daytime_close_temperature || ( tempF < night_close_temperature && daylight_state == false)) desired_motor_state = 0;
if ( desired_motor_state != motor_state || buttonPressed == true)
{ advance_motor_state();
motor_start_time = millis();
delay_till_pressed(motor_time_limit); // awaits till reedButton got pressed - reed moove completed
if (millis() - motor_start_time >= motor_time_limit) // moove time got exeeded, stop the process
{ Serial.print("Error: ");
Serial.print("The motor tried to run for too long !!");
for(;;){} // Idles the program
} else
{ advance_motor_state(); // reed move succeeded
Serial.print("motor safety timer operational, run-time milliseconds = ");
Serial.println( millis() - motor_start_time);
}
} else delay_till_pressed(1*30*1000); // 10*60*1000 ten minutes delay
}
//=============================================END OF MAIN LOOP===================================================
void read_light_sensor ()
{ unsigned long sum=0, sum1=0;
unsigned long luminosity[LUMINOSITY_SAMPLE_SIZE];
unsigned int good_count = LUMINOSITY_SAMPLE_SIZE;
for (int i=0; i<LUMINOSITY_SAMPLE_SIZE; i++)
{ luminosity[i] = analogRead(PHOTORESISTOR_PIN), delay_till_pressed(LUMINOSITY_SAMPLE_DELAY);
sum += luminosity[i];
}
sum = sum/LUMINOSITY_SAMPLE_SIZE;
Serial.print("Luminocity sum =");
Serial.print(sum);
for (int i=0; i<LUMINOSITY_SAMPLE_SIZE; i++)
// Next episode eliminates all bad readings (above/below LUMINOSITY_BOUNDARIES) and everage only good readings
if ( abs(sum - luminosity[i])/sum > LUMINOSITY_BOUNDARIES ) good_count--;
else sum1+=luminosity[i];
if (sum1 / good_count <= lightThreshold)
daylight_state = true;
else daylight_state = false;
Serial.print(" sum1 =");
Serial.print(sum1/good_count);
Serial.print(" Daylighte_state = ");
Serial.print(daylight_state);
}
void read_digital_temp (){
//========================================begin subroutine to get digital temperature=========================================
//this is the code subroutine to get the temperatures from a DS18B20 digital sensor
// Send the command to get temperatures
sensors.setResolution(9); //sets the resolution to 9 bit so the temperature is read fast
sensors.requestTemperatures();
tempF= ((sensors.getTempCByIndex(0) * 9.0) / 5.0 + 32.0);
delay(5); //short delay
Serial.print(" tempF = ");
Serial.print(tempF);
Serial.print(" Current motor_state = ");
Serial.println(motor_state);
}
//===========================================end subroutine to get digital temperature====================================================
// ============================================begin subroutine to control motor and leds==============================================
// set the LED and switch the motor:
// if counter== 0 (reemay is closed, motor is off, led is blue (nightime)
// if counter== 1 (temperature has warmed, light increased, so open reemay and turn led green)
// if counter== 2 (reemay is open, motor is off, led is yellow (daytime)
// if counter== 3 (temperature has fallen, darkness has come, so close reemay and turn red led on)
// if counter ==4 (reemay is closed, motor is off, led is blue, pushcounter is reset to 0
void control_motor_and_leds ()
{ switch( motor_state )
{ case 0: //instructions for relays (all off)
// digitalWrite(relay_one_pin,LOW);
// digitalWrite(relay_two_pin,LOW);
// digitalWrite(relay_three_pin,LOW);
g=0; r=0; b=200; //set led to blue
break;
case 1: //instructions for relays:motor forward (green) one=high,two=low, three= low
// digitalWrite(relay_one_pin,HIGH);
// digitalWrite(relay_two_pin,LOW);
// digitalWrite(relay_three_pin,LOW);
g=200; r=0; b= 0; //set led to green
break;
case 2: //instructions for relays (all off)
// digitalWrite(relay_one_pin,LOW);
// digitalWrite(relay_two_pin,LOW);
// digitalWrite(relay_three_pin,LOW);
g=200; r=200; b=0; //set led to yellow
break;
case 3: //instructions for relays; motor reverse (red): one=low, two=high, three=high
// digitalWrite(relay_one_pin,LOW);
// digitalWrite(relay_two_pin,HIGH);
// digitalWrite(relay_three_pin,HIGH);
g=0; r=200; b=0; //set led to red
}
for (int i = 0; i < NUM_LEDS; i++) //this loop is for if there's more than one LED
{ leds[i] = CRGB(r,g,b);
FastLED.show(); //turn led on
}
Serial.print("From Light switch. Motor moveding to state ");
Serial.println(motor_state);
Serial.print("Lights turned to red=");
Serial.print(r);
Serial.print(", green=");
Serial.print(g);
Serial.print(", blue=");
Serial.print(b);
Serial.print(" Millis=");
Serial.println(millis());
buttonPressed = false;
lastReedState = LOW;
}
// =============================== EOF ==========================================