I am running two 2-state state machines, controlling a fan and a humidifier.
Desired behaviour is:
The fan runs for onTimeMinutesPerUnit per timeframe (e..g 1 minute per 15 minutes), and the humidifer has an "on" transition when the relative humidity drops below rhLowerBound and turns off when it goes above rhUpperBound.
This works for a while, until what I assume is a timing error in my code occurs, and the fan gets stuck in an on state, running permanently, while the humidifier is off, regardless of how low the humidity is. Restarting the arduino makes everything work again.
- I don't believe the sensor library is crashing because that has nothing to do with the fan. I don't believe I have pin conflicts since I am using D5-7.
- I am worried that maybe the relays are getting "stuck" during operation (using pre purchased relay modules).
- I am worried that I have a stupid timing issue that causes transition issues, but I am not so sure, since the fan getting stuck shouldn't affect the humidifer.
- I don't think it makes sense to "blame" the delay() function, but I have no idea what else the problem could be (except sticky relays).
Cheers for any help.
Here's a paste of the code:
#include "DHT.h"
#include <stdint.h>
#include <stdlib.h>
#define RELAY_FAN_PIN (7UL)
#define RELAY_HUMID_PIN (5UL)
#define SENSOR_HUMID_PIN (6UL)
#define MILLISECONDS_PER_MINUTE (60000UL)
//#define DEBUG
const uint32_t STATE_OFF = LOW;
const uint32_t STATE_ON = HIGH;
typedef enum
{
PER_10_MINUTES = 10,
PER_15_MINUTES = 15,
PER_30_MINUTES = 30,
PER_40_MINUTES = 40,
PER_45_MINUTES = 45,
PER_HOUR = 60
} timeframe_t;
typedef struct
{
uint32_t currentState;
uint32_t controlPin;
uint32_t onPeriodMs;
uint32_t offPeriodMs;
uint32_t onTimeMs;
uint32_t offTimeMs;
} fanData_t;
typedef struct
{
uint32_t currentState;
float rhUpperBound;
float rhLowerBound;
uint32_t controlPin;
DHT *sensor;
} humidifierData_t;
DHT dht(SENSOR_HUMID_PIN, DHT11);
fanData_t fanInstance;
humidifierData_t hmdInstance;
void initFan(fanData_t *fan, uint32_t controlPin, uint32_t onTimeMinutesPerUnit, timeframe_t timeframe);
void initHumidifier(humidifierData_t *hmd, uint32_t controlPin, DHT *sensor, float rhLowerBound, float rhUpperBound);
void manageFan(fanData_t *fan);
void manageHumidity(humidifierData_t *hmd);
void setup() {
// put your setup code here, to run once:
initHumidifier(&hmdInstance, RELAY_HUMID_PIN, &dht, 87.F, 90.F);
initFan(&fanInstance, RELAY_FAN_PIN, 1, PER_15_MINUTES);
#ifdef DEBUG
Serial.begin(9600);
#endif
}
void loop() {
// put your main code here, to run repeatedly:
manageFan(&fanInstance);
manageHumidity(&hmdInstance);
delay(5000);
}
void initHumidifier(humidifierData_t *hmd, uint32_t controlPin, DHT *sensor, float rhLowerBound, float rhUpperBound)
{
hmd->currentState = STATE_ON;
hmd->rhUpperBound = rhUpperBound;
hmd->rhLowerBound = rhLowerBound;
hmd->controlPin = controlPin;
hmd->sensor = sensor;
sensor->begin();
pinMode(hmd->controlPin, OUTPUT);
}
void initFan(fanData_t *fan, uint32_t controlPin, uint32_t onTimeMinutesPerUnit, timeframe_t timeframe)
{
fan->currentState = STATE_ON;
fan->onPeriodMs = onTimeMinutesPerUnit * MILLISECONDS_PER_MINUTE;
if (onTimeMinutesPerUnit < timeframe)
{
fan->offPeriodMs = (timeframe - onTimeMinutesPerUnit)* MILLISECONDS_PER_MINUTE;
}
else
{
fan->offPeriodMs = 0UL;
}
fan->controlPin = controlPin;
fan->offTimeMs = millis();
pinMode(fan->controlPin, OUTPUT);
fan->onTimeMs = millis();
}
void manageFan(fanData_t *fan)
{
uint32_t currentTime = millis();
if (fan->currentState == STATE_ON)
{
#ifdef DEBUG
Serial.print("Fan is on! Time (ms) till off: ");
Serial.println(fan->onPeriodMs - (currentTime - fan->onTimeMs));
#endif
if ((currentTime - fan->onTimeMs) >= fan->onPeriodMs)
{
fan->currentState = STATE_OFF;
fan->offTimeMs = millis();
}
}
else if (fan->currentState == STATE_OFF)
{
#ifdef DEBUG
Serial.print("Fan is off! Time (ms) till on: ");
Serial.println(fan->offPeriodMs - (currentTime - fan->offTimeMs));
#endif
if ((currentTime - fan->offTimeMs) >= fan->offPeriodMs)
{
fan->currentState = STATE_ON;
fan->onTimeMs = millis();
}
}
digitalWrite(fan->controlPin, fan->currentState);
}
void manageHumidity(humidifierData_t *hmd)
{
float currentRh = hmd->sensor->readHumidity();
if (hmd->currentState == STATE_ON)
{
#ifdef DEBUG
Serial.print("Humidifier is on! ");
#endif
if (currentRh >= hmd->rhUpperBound)
{
hmd->currentState = STATE_OFF;
}
}
else
{
//Serial.print("Humidifier is off! ");
if (currentRh <= hmd->rhLowerBound)
{
hmd->currentState = STATE_ON;
}
}
digitalWrite(hmd->controlPin, hmd->currentState);
#ifdef DEBUG
Serial.print("Current Humidity: ");
Serial.print(currentRh);
Serial.print(" Humidity Lower: ");
Serial.print(hmd->rhLowerBound);
Serial.print(" Humidity Upper: ");
Serial.println(hmd->rhUpperBound);
Serial.print("Current Temp: ");
float currentTemp = hmd->sensor->readTemperature();
Serial.println(currentTemp);
#endif
}