Hi @musicman608
I am sorry in the posting above I forgot to post the new code-version that does the serial printing for debugging.
here it is:
// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
// a detailed explanation how these macros work is given in this tutorial
// https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298
#define dbg(myFixedText, variableName) \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName);
#define dbgi(myFixedText, variableName,timeInterval) \
{ \
static unsigned long intervalStartTime; \
if ( millis() - intervalStartTime >= timeInterval ){ \
intervalStartTime = millis(); \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName); \
} \
}
#define dbgc(myFixedText, variableName) \
{ \
static long lastState; \
if ( lastState != variableName ){ \
Serial.print( F(#myFixedText " " #variableName" changed from ") ); \
Serial.print(lastState); \
Serial.print( F(" to ") ); \
Serial.println(variableName); \
lastState = variableName; \
} \
}
#define dbgcf(myFixedText, variableName) \
{ \
static float lastState; \
if ( lastState != variableName ){ \
Serial.print( F(#myFixedText " " #variableName" changed from ") ); \
Serial.print(lastState); \
Serial.print( F(" to ") ); \
Serial.println(variableName); \
lastState = variableName; \
} \
}
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <SafeString.h> // StefanL38 new library
#define Type DHT11
//Define LCD pinout
const int en = 2, rw = 1, rs = 0, d4 = 4, d5 = 5, d6 = 6, d7 = 7, bl = 3;
//Define I2C Address
const int i2c_addr = 0x27;
LiquidCrystal_I2C lcd(i2c_addr, en, rw, rs, d4, d5, d6, d7, bl, POSITIVE);
//LiquidCrystal_I2C lcd(i2c_addr, 20, 4); //, en, rw, rs, d4, d5, d6, d7, bl, POSITIVE);
int mainsLED = 2;
int genLED = 3;
int mainsDetect = 4;
int mainsPin = 5;
int genDetect = 6;
int genPin = 7;
int sensePin = 8;
int naLED = 9;
int intakeFan = 10;
int genMnLEDred = 11;
int exhaustFan = 12;
int dt = 1000;
int genDelay = 30000;
int mainsDelay = 1000;
int mainsStatus;
int genStatus;
float humidity;
float tempC;
float tempF;
DHT HT(sensePin, Type);
byte mainsDetectState;
byte genDetectState;
// StefanL38 additional variables
unsigned long myLcdTimer;
unsigned long myBlinkTimer;
unsigned long myGenOffTimer;
cSF(MainsOnOffState_SS, 8);
cSF(GenOnOffState_SS, 8);
byte myState;
const byte sm_normalOperation = 0;
const byte sm_waitForGenOn = 1;
const byte sm_waitForMainsOn = 2;
const byte sm_waitBeforeGenOff = 3;
const char myStateNames[][24] = {
"sm_normalOperation",
"sm_waitForGenOn",
"sm_waitForMainsOn",
"sm_waitBeforeGenOff"
};
void setup() {
Serial.begin(115200);
Serial.println("Setup-Start");
lcd.begin(20, 4);
HT.begin();
pinMode(mainsLED, OUTPUT);
pinMode(genLED, OUTPUT);
pinMode(mainsDetect, INPUT);
pinMode(mainsPin, OUTPUT);
pinMode(genDetect, INPUT);
pinMode(genPin, OUTPUT);
pinMode(naLED, OUTPUT);
pinMode(genMnLEDred, OUTPUT);
pinMode(intakeFan, OUTPUT);
pinMode(exhaustFan, OUTPUT);
myLcdTimer = millis(); // initialise timing-variable
}
void loop() {
readSensor();
switchOnOffFans();
//instead of delay(2000);
// check if 2000 milliseconds of time have passed by
// since last time this happened
if ( TimePeriodIsOver(myLcdTimer, 2000) ) {
// only when REALLY 2000 milliseconds have passed by
updateLcd();
printToSerial();
}
checkMainsGeneratorStatus();
myGeneratorStateMachine();
printIfStateChanged();
blinkIfMainsAndGenOff();
}
void readSensor() {
humidity = HT.readHumidity();
tempC = HT.readTemperature();
tempF = HT.readTemperature(true);
}
void switchOnOffFans() {
if ((tempF) >= 69.00) {
digitalWrite(genMnLEDred, HIGH);
digitalWrite(intakeFan, HIGH);
digitalWrite(exhaustFan, HIGH);
}
else {
digitalWrite(genMnLEDred, LOW);
digitalWrite(intakeFan, LOW);
digitalWrite(exhaustFan, LOW);
}
}
void updateLcd() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temperature: ");
lcd.print(tempF);
lcd.print(" F");
lcd.setCursor(0, 1);
lcd.print("Humidity: ");
lcd.print(humidity);
lcd.print(" % ");
lcd.setCursor(0, 2);
lcd.print("Mains Status: ");
lcd.print(MainsOnOffState_SS);
lcd.setCursor(0, 3);
lcd.print("Gentr Status: ");
lcd.print(GenOnOffState_SS);
}
void printToSerial() {
mainsStatus = digitalRead(mainsDetect);
genStatus = digitalRead(genDetect);
Serial.print(" Gen Status ");
//Serial.println(genStatus);
Serial.println(GenOnOffState_SS);
Serial.print(" Mains Status ");
//Serial.println(mainsStatus);
Serial.println(MainsOnOffState_SS);
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println(" % ");
Serial.print(" Temperature ");
Serial.print(tempF);
Serial.println(" F ");
}
void checkMainsGeneratorStatus() {
mainsDetectState = digitalRead(mainsDetect);
dbgc("01", mainsDetectState);
genDetectState = digitalRead(genDetect);
dbgc("02", genDetectState);
if ( mainsDetectState == HIGH) {
//lcd.print("On");
MainsOnOffState_SS = "On";
digitalWrite(mainsLED, HIGH);
digitalWrite(mainsPin, HIGH);
}
else {
//lcd.print("Off");
MainsOnOffState_SS = "Off";
digitalWrite(mainsLED, LOW);
digitalWrite(mainsPin, LOW);
}
if (genDetectState == HIGH) {
//lcd.print("On");
GenOnOffState_SS = "On";
digitalWrite(genLED, HIGH);
digitalWrite(genPin, HIGH);
}
else {
//lcd.print("Off");
GenOnOffState_SS = "Off";
digitalWrite(genLED, LOW);
digitalWrite(genPin, LOW);
}
}
void blinkIfMainsAndGenOff() {
if ( (mainsDetectState == LOW) && (genDetectState == LOW) ) {
// check if "dt" milliseconds have passed by
if ( TimePeriodIsOver(myBlinkTimer, dt) ) {
// only when "dt" milliseconds REALLY have passed by
digitalWrite(naLED, !digitalRead(naLED) ); // invert state of IO-pin naLED with the not-operator "!"
}
}
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
void myGeneratorStateMachine() {
switch (myState) {
case sm_normalOperation:
// check if mains-power is lost
if ( digitalRead(mainsDetect) == LOW) {
myState = sm_waitForGenOn;
}
break; // IMMIDIATELY jump down to END-OF-SWITCH
case sm_waitForGenOn:
// check if generator produces power
if ( digitalRead(genDetect) == HIGH) {
myState = sm_waitForMainsOn;
}
break; // IMMIDIATELY jump down to END-OF-SWITCH
case sm_waitForMainsOn:
// check if mains-power is back ON again
if ( digitalRead(mainsDetect) == HIGH) {
// when mains-power is really ON
myGenOffTimer = millis(); // initialise timing-variable
myState = sm_waitBeforeGenOff; // start waiting
}
break; // IMMIDIATELY jump down to END-OF-SWITCH
case sm_waitBeforeGenOff:
// check if 10000 milliseconds have passed by
if ( TimePeriodIsOver(myGenOffTimer, 10000) ) {
// when REALLY 10000 milliseconds have passed by (with mains-power on)
digitalWrite(genPin, LOW);
myState = sm_normalOperation;
}
// check if mains-power is lost
if ( digitalRead(mainsDetect) == LOW) {
// when mains-power is lost
myState = sm_waitForGenOn; // continue with waiting for generator on
}
break; // IMMIDIATELY jump down to END-OF-SWITCH
} // END-OF-SWITCH
}
void printIfStateChanged() {
static byte last_myState;
// check if variable myState has changed
if (last_myState != myState) {
// when variable myState REALLY has changed
Serial.print("myState changed from ");
Serial.print(myStateNames[last_myState]);
Serial.print(" to ");
Serial.println(myStateNames[myState]);
last_myState = myState; // update variable last_myState
}
}
It is the same logic as the code before but does serial printing.
So if you keep your arduino connected to your computer
and open the serial monitor in the serial monitor there can be seen what the code is doing.
Especially state-changes of the state-machine and changes of the mainsdetect and gendetect were printed
As you wrote about SSRs.
What is switched with this SSR? Solid State Relay?
your ventilators or your main-power?
Do these SSR's have a galvanic isolated input?
How much amperes can these SSR switch?
best regards Stefan