I’ve created my first project which is a project for opening and closing a door that lets my chickens in and out. It also checks their water level every hour and fills as needed. The door opens in the AM and closes in the PM. 4 minutes after the door is activated it publishes the status of the door and the water to an IFTTT applet. I created this because I travel quite a bit and I don’t like to bother friends/relatives to daily check on the hens. I have been having an issue where it will randomly just breathe green. When this happens the door and water activities don’t happen and the LCD will not update indicating to me that the application code is locked up. It has taken anywhere from 2 days to 7 days for this to happen. Based on the current time shown on the LCD when it locks up the only function that should be running is loop. The LCD has never indicated a lock up time when any other functions are activated. My code is based strictly on a 24 hour period. There are no multi-day activities at all. When I first started troubleshooting this I activated an iFTTT app that notifies me when the photon goes offline and online. That was happening over 60 times per day. So, I rewrote the code to strip it down to the bare essentials. I also changed to another home network that seemed to have a stronger signal and I added STARTUP(WiFi.setListenTimeout(60)); to hopefully kick it out of listening mode if it got locked into it. These made it so it was going offline/online less than 10 times per day. It ran for almost 7 days this time but this morning it happened again and the LCD read 0535. Nothing should have been happening at this point. Everything I’ve read on the forum indicates this is a problem of application code being locked in a loop. If that is the case I can’t see it in my code and why will it run multiple days just fine and then fail when all code is on a 24 hour time frame? I’m gong to try and post the code below. I haven’t been able to find guidance on how to post the code in a scrolling window like most folks do. So, sorry for the inconvenience and thanks for whatever suggestions you might have to stop this problem.
STARTUP(WiFi.setListenTimeout(60));//added this to the code to try and prevent photon from locking into listening mode
// This #include statement was automatically added by the Particle IDE.
#include <LiquidCrystal_I2C_Spark.h>
LiquidCrystal_I2C*lcd;
int waterSensorPin = 7;//sets pin A3 as input for the water level sensor
int waterSensor;//creates variable for storing value of waterSensorPin
int solenoidActivatePin = A2;//sets pinA4 as output to relay that controls water solenoid
int topSensorPin = 2; // Sets the top door sensor as pin A2
int topSensor;//Variable for storing topSensorPin value
int bottomSensorPin = 3; //Sets bottom door sensor as pin A3
int bottomSensor;//Variable for storing topSensorPin value
int motorOpenPin = 4; //Sets pin A4 to drive door open motor
int motorClosePin = 5; //Sets pin A5 to drive door close motor
int lowPowerOn = 6;//Allows the photon to turn on the 3.3 volt power supply when needed to check the door sensors
int doorStatus;//creates a variable for storing value of current door status, Open, Closed, In Transit
int openHour;//Creates variable for storing open time hour
int openMinute;//Creates variable for storing open time minute
int closeHour;//Creates variable for storing close time hour
int closeMinute;//Creates variable for storing close time minute
int publishDoorStatus;//Creates variable to ensure that the doorStatus is only published once per event
//int testTime = 100;//Used for troubleshooting to slow serial output to make it readable
void setup() {
WiFi.selectAntenna(ANT_EXTERNAL);
WiFi.setCredentials("**************", "***************");
Serial.begin(9600);
delay(100);
pinMode(lowPowerOn, OUTPUT);//Makes lowPowerOn a digital output pin
digitalWrite(lowPowerOn, HIGH);//Initializes lowPowerOn to HIGH to turn off 3.3Vol power supply to save battery
pinMode(topSensorPin, INPUT);// Makes the topSensor pin a digital Input
pinMode(bottomSensorPin, INPUT);//Makes the bottomSensor pin a digital input
pinMode(motorOpenPin, OUTPUT);//Makes the motorOpen drive pin a digital output
digitalWrite(motorOpenPin, HIGH);//Sets the motorOpen output to high for the relay
pinMode(motorClosePin, OUTPUT);//Makes the motorClose output pin a digital output
digitalWrite(motorClosePin, HIGH);//Sets the motorOpen output pin to high for the relay
pinMode(waterSensorPin, INPUT);//declares water sensor pin as an input
pinMode(solenoidActivatePin, OUTPUT);//declares solenoid activate pin as an output
digitalWrite(solenoidActivatePin, HIGH);//initializes solenoidActivatePin as HIGH so the relay will not activate
openHour = 06;//Sets a time to open door
openMinute = 30;
closeHour = 19;//Sets a time to close the door
closeMinute = 00;
lcd = new LiquidCrystal_I2C(0x3F, 16, 2); //address of the I2C module for the LCD, sets it for 2 rows and 16 columns
lcd->init(); //Initializes the LCD
lcd->backlight(); //turns on LCD backlight
lcd->clear(); //clears the LCD screen
Time.zone(-5);//Sets the Central Time Zone
}
void loop()
{
Particle.connect();//added to increase the frequency that the photon tries to connect to the cloud to prevent lock up
delay(100);
displaySet();//calls function to update the LCD
waterMonitor();//calls function to check water level
if((openHour == Time.hour()) && ((Time.minute() >= openMinute) && (Time.minute() <= openMinute +1)))
{//when current time matches open time triggers functions to open door adds minute because it takes more than 1 minute to open door
checkSensor();//triggers function to check door top and bottom sensor and determine door status
openMotor();//uses sensor data and calls function to activate door motor to open
}
if((closeHour == Time.hour()) && ((Time.minute() >= closeMinute) && (Time.minute() <= closeMinute +1)))
{//when current time matches close time triggers functions to close door adds minute because it takes more than 1 minute to close door
checkSensor();//triggers function to check door top and bottom sensor and determine door status
closeMotor();//uses sensor data and calls function to activate door motor to close
}
if((Time.minute() == openMinute +2) || (Time.minute() == closeMinute +2))
{//turns off 3.3v power supply to sensors to save LEDs and battery
digitalWrite(lowPowerOn, HIGH);
}
if(((openHour == Time.hour()) && (Time.minute() == (openMinute +4))) || ((closeHour == Time.hour()) && (Time.minute() == closeMinute +4)))
{//triggers function to publish door and water status 4 minutes after door is activated to open or close
statusPublish();
}
}
void displaySet()//updates LCD with every loop
{
lcd->clear();
lcd->setCursor(1, 0);
lcd->print("TIME OPEN CLOSE");
lcd->setCursor(1, 1);
if(Time.hour() < 10)
{
lcd->print("0");
}
lcd->print(Time.hour());
lcd->setCursor(3, 1);
if(Time.minute() < 10)
{
lcd->print("0");
}
lcd->print(Time.minute());
lcd->setCursor(6, 1);
if(openHour <10)
{
lcd->print("0");
}
lcd->print(openHour);
lcd->setCursor(8, 1);
if(openMinute < 10)
{
lcd->print("0");
}
lcd->print(openMinute);
lcd->setCursor(11, 1);
if(closeHour < 10)
{
lcd->print("0");
}
lcd->print(closeHour);
lcd->setCursor(13, 1);
if(closeMinute < 10)
{
lcd->print("0");
}
lcd->print(closeMinute);
return;
}
void waterMonitor()//checks water sensor and activates solenoid to fill if neededd
{
waterSensor = digitalRead(waterSensorPin);
if ((Time.minute() == 10) && (waterSensor == HIGH))//added time component to prevent flooding if there is a sensor malfunction
{
digitalWrite(solenoidActivatePin, LOW);
lcd->init();//use this at every point there is a major draw on the battery to prevent LCD from displaying gibberish
}
else//shut off water if full or a minute has passed
{
digitalWrite(solenoidActivatePin, HIGH);
lcd->init();//use this at every point there is a major draw on the battery to prevent LCD from displaying gibberish
}
}
void checkSensor()//checks top and bottom sensor and assigns a status value
{
digitalWrite(lowPowerOn, LOW);//Turns on 3.3Volt power supply which powers sensor and LED's through relay
delay(500);
topSensor = digitalRead(topSensorPin);//Assigns the value of topSensoPin to variable topSensor
delay(100);
bottomSensor = digitalRead(bottomSensorPin);//Assigns the value of bottomSensorPin to variable bottomSensor
delay(100);
//Serial.println("Comparing the status of the door sensors to determine door status value");//Used in Troubleshooting
//delay(testTime);
if ((topSensor == LOW) && (bottomSensor == LOW))
{
doorStatus = 100;//Gives doorStatus a value of 100 which means the door is all the way open
}
if ((topSensor == HIGH) && (bottomSensor ==HIGH))
{
doorStatus = 200;//Gives doorStatus a value of 200 which means the door is all the way closed
}
if (topSensor != bottomSensor)
{
doorStatus = 300;//Gives doorStatus a value of 300 which means the door is in transit
}
return;
}
void openMotor()//activates motor to open if conditions met
{
if ((doorStatus == 200) || (doorStatus == 300))//turns motor on if door is closed or in transit
{
digitalWrite(motorOpenPin, LOW);
delay(1000);
}
else//shuts motor off when conditions no longer met
{
digitalWrite(motorOpenPin, HIGH);
}
lcd->init();//initializes LCD to prevent gibberish on the lcd due to power fuctuations caused by motor
return;
}
void closeMotor()//activates motor to close if conditions met
{
if((doorStatus == 100) || (doorStatus == 300))//activates motor if door is open or in transit
{
digitalWrite(motorClosePin, LOW);
delay(1000);
}
else//shuts off motor when conditions no longer met
{
digitalWrite(motorClosePin, HIGH);
}
lcd->init();//initializes LCD to prevent gibberish on screen due to motor power fluctuations
return;
}
void statusPublish()//publishes door status and water status when called to IFTTT
{
if (doorStatus != publishDoorStatus)//if there has been a change in door status publishes to IFTTT
{
if(doorStatus == 100)//publishes that the door has opened all the way
{
Particle.publish("statusOfDoor", "Open");
}
if(doorStatus == 200)//publishes that the door has closed all the way
{
Particle.publish("statusOfDoor", "Closed");
}
if(doorStatus == 300)//publishes that door is not in it's expected state
{
Particle.publish("statusOfDoor", "Fault");
}
delay(1000);
if(waterSensor == HIGH)//publishes that water is low
{
Particle.publish("statusOfWater", "NotFull");
}
if(waterSensor == LOW)//publishes that water level is where it is expected
{
Particle.publish("statusOfWater", "Full");
}
}
publishDoorStatus = doorStatus;//sets publishDoorStatus so that everything is only published once per call
return;
}