Make manual start/stopp button override sensorreadings/function

I am making a homeautomation-project build into a box with LCD, WiFi, RtC, 5 buttons and a Arduino Mega. I will explain the function only by the chain I have problem with. Tell me if you need more info:

I have a fan over my stove. For controlling the fan start/stop I use measured values from DHT11-sensors. When the measured value gets over an x value the fan will start by the help of a relay, and when it gets under same x value the fan stops again. This goes for both temp and humidity. The temp and humidityvalues are calibrated in the code because it is some shitty sensors with some shitty capability.

In my LCD I have a menu for changing the setpoint x, both temp and humidity. I also, in the same menu, have the possibility to start and stop the fan manually by chosing on/off with a marker. My wish is, that when I turn the fan on manually the fan would be on until I choose to shut it of again...but it only stays on until the next time sensor-values goes into updateFanRelay(). updateFanRelay() stops the fan again because it sees the exemplaric values from the sensor-readings. It says...oooh the fan have to stop...the values are great!!

So please...how do I get it right? The sensorreadings and updateFanRelay() have to go on working at the same time as the manual override in the LCD blocks the Fan in the desired mode on/off..until I change it my self in the menu.

And please tell me if you think I can write the code in some other way. I still yet have a lot to learn and I am very greatful for all help I can get. I am sorry but I dont know how to get the rownumbers with the code-copy.

Code next, have to split the code in many parts:

Part 1:

//Include the libraries
#include <LiquidCrystal.h>
#include <LiquidMenu.h>
#include "Button.h"
#include "DHT.h"
#include <RtcDS3231.h>
#include <SoftwareSerial.h>
#include <WiFiEsp.h>
#include <Wire.h>

// Pin mapping for the display
const byte LCD_RS = 22;
const byte LCD_E = 23;
const byte LCD_D4 = 24;
const byte LCD_D5 = 25;
const byte LCD_D6 = 26;
const byte LCD_D7 = 27;
//LCD R/W pin to ground
//10K potentiometer to VO
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

// Button objects instantiation
const bool pullup = true;
Button left(28, pullup);
Button right(29, pullup);
Button up(31, pullup);
Button down(30, pullup);
Button enter(32, pullup);

// Variables used for PWM and FAN control with callback functions.
const byte pwmPin = 8;
byte pwmLevel = 0;
const byte fan1pin = 2;
const byte fan2pin = 3;

//User input for fangroup 1 start/stopp setpoint ground value
int rfSetpoint1 = 55; //User input via the LCD
int tempSetpoint1 = 22; //User input via the LCD

//User input for fangroup 2 start/stopp setpoint ground value
int rfSetpoint2 = 55;   //User input via the LCD, this is ground values
int tempSetpoint2 = 22; //User input via the LCD, this is ground values

//User input for humidity and temp-sensor 1 calibration
const int calibSetUpHum1 = -9;
const int calibSetUpTemp1 = 0;

//User input for humidity and temp-sensor 2 calibration
const int calibSetUpHum2 = 0;
const int calibSetUpTemp2 = 2;


// Variables for controlling a pin and displaying the state with text.
// char* is used for adding changing text to the LiquidLine object.
const byte ledPin = LED_BUILTIN;
bool ledState = LOW;
char* ledState_text;
char* Fan1State_text; //For putting the on/off text on the LCD-display
char* Fan2State_text; //For putting the on/off text on the LCD-display

const byte analogPin = A5;      //Not used for now
unsigned short analogValue = 0; //Not used for now


LiquidLine welcome_line1(5, 0, "Mainpanel");
LiquidLine welcome_line2(3, 1, "HomeAutomation");
LiquidLine welcome_line3(0, 3, "(L)(R)(Dwn)(Up)(ENT)"); //[ L | R |Dwn|Up|ENT]
LiquidScreen welcome_screen(welcome_line1, welcome_line2, welcome_line3);

LiquidLine analog_line(0, 0, "Analog: ", analogValue); //Not used for now
LiquidLine ledState_line(0, 1, "LED is ", ledState_text);
LiquidScreen screen2(analog_line, ledState_line);

LiquidLine pwm_line(0, 0, "PWM level: ", pwmLevel);
LiquidScreen pwm_screen(pwm_line);

LiquidLine fan1_line1(0, 0, "ECO-VENT KAMIN");  //Menu for controlling Fan1 and changing its temp- humiditysetpoint.
LiquidLine fan1_line2(0, 1, "Fan 1 mode: ", Fan1State_text);
LiquidLine fan1_line3(0, 2, "Temp set  : ", tempSetpoint1, " C");
LiquidLine fan1_line4(0, 3, "RF set    : ", rfSetpoint1, " %");
LiquidScreen fan1_screen(fan1_line1, fan1_line2, fan1_line3, fan1_line4);

LiquidLine fan2_line1(0, 0, "ECO-VENT TORKRUM"); //Menu for controlling Fan2 and changing its temp- humiditysetpoint.
LiquidLine fan2_line2(0, 1, "Fan 2 mode: ", Fan2State_text);
LiquidLine fan2_line3(0, 2, "Temp set  : ", tempSetpoint2, " C");
LiquidLine fan2_line4(0, 3, "RF set    : ", rfSetpoint2, " %");
LiquidScreen fan2_screen(fan2_line1, fan2_line2, fan2_line3, fan2_line4);

LiquidLine pool_line(0, 0, "POOLSYSTEM 8X4"); //Menu for, in the future, controlling the poolstuff.
LiquidLine pool1_line(0, 1, "Circ pump mode : OFF");
LiquidLine pool2_line(0, 2, "Side lamp mode : OFF");
LiquidLine pool3_line(0, 3, "Front lamp mode: OFF");
LiquidScreen pool_screen(pool_line, pool1_line, pool2_line, pool3_line);

LiquidMenu menu(lcd);

//Function to be attached to the tempSetpoint1 (fan1) object.
void tempSetpoint1_up() { //Raises the tempsetpoint for Fan1 via the LCD-display.
  if (tempSetpoint1 == 0) {
    tempSetpoint1 ++;    
  } else {
    tempSetpoint1 ++;
  }
}

void tempSetpoint1_down() { //Lower the tempsetpoint for Fan1 via the LCD-display
  if (tempSetpoint1 == 0) {
    tempSetpoint1 --;
  } else {
    tempSetpoint1 --;
  }
}

// Function to be attached to the rfSetpoint1 (fan1) object.
void rfSetpoint1_up() { //Raises the humiditysetpoint for Fan1 via the LCD-display
  if (rfSetpoint1 == 0) {
    rfSetpoint1 ++;    
  } else {
    rfSetpoint1 ++;
  }
}

void rfSetpoint1_down() { //Lower the humiditysetpoint for Fan1 via the LCD-display
  if (rfSetpoint1 == 0) {
    rfSetpoint1 --;
  } else {
    rfSetpoint1 --;
  }
}

//Function to be attached to the tempSetpoint2 (fan2) object.
void tempSetpoint2_up() { //Raises the tempsetpoint for Fan2 via the LCD-display.
  if (tempSetpoint2 == 0) {
    tempSetpoint2 ++;    
  } else {
    tempSetpoint2 ++;
  }
}

void tempSetpoint2_down() { //Lower the tempsetpoint for Fan2 via the LCD-display.
  if (tempSetpoint2 == 0) {
    tempSetpoint2 --;
  } else {
    tempSetpoint2 --;
  }
}

// Function to be attached to the rfSetpoint2 (fan2) object.
void rfSetpoint2_up() { //Raises the humiditysetpoint for Fan2 via the LCD-display
  if (rfSetpoint2 == 0) {
    rfSetpoint2 ++;    
  } else {
    rfSetpoint2 ++;
  }
}

void rfSetpoint2_down() { //Lower the humiditysetpoint for Fan2 via the LCD-display
  if (rfSetpoint2 == 0) {
    rfSetpoint2 --;
  } else {
    rfSetpoint2 --;
  }
}

// Function to be attached to the pwm_line object.
void pwm_up() {
  if (pwmLevel < 225) {
    pwmLevel += 25;
  } else {
    pwmLevel = 250;
  }
  analogWrite(pwmPin, pwmLevel);
}

// Function to be attached to the pwm_line object.
void pwm_down() {
  if (pwmLevel > 25) {
    pwmLevel -= 25;
  } else {
    pwmLevel = 0;
  }
  analogWrite(pwmPin, pwmLevel);
}

// Function to be attached to the fan1_line2 object, starts and stops the Fan1 from the LCD-display.
void fan1_up() {
  digitalWrite(fan1pin, HIGH);
  
}

void fan1_down() {
  digitalWrite(fan1pin, LOW);
}

// Function to be attached to the fan2_line2 object, starts and stops the Fan2 from the LCD-display
void fan2_up() {
  digitalWrite(fan2pin, HIGH);
  
}

void fan2_down() {
  digitalWrite(fan2pin, LOW);
}

//Declare and initialise global arrays for WiFi settings
char ssid[] = "Telia-68651D";
char pass[] = "1DE0E3729E";

// Declare and initialise global variables/arrays for Thingspeak connection
const char server[] = "thingspeak.com";
const char thingspeakAPIKey[] = "ARFSZBIOMX8UA6AQ";
const int postingInterval = 60;

//Create new RTC module object
RtcDS3231 rtcModule;

//Create new DHT object
#define DHT1PIN 4     // Digital pin for Temp and Humidity-sensor 1
#define DHT2PIN 5     // Digital pin for Temp and Humidity-sensor 2

// Uncomment whatever type you're using!
#define DHT1TYPE DHT11   // DHT 11
#define DHT2TYPE DHT11   // DHT 11

//Initialise DHT-sensor
DHT dht1(DHT1PIN, DHT1TYPE);
DHT dht2(DHT2PIN, DHT2TYPE);

//Create new client object
WiFiEspClient client;

//Create WiFi module object on GPIO pin 10 (RX) and 11 (TX)
SoftwareSerial MySerial(10, 11);

//Declare and initialise variable for radio status
int status = WL_IDLE_STATUS;

//Declare global variables for time and temperature in RTC-module
int hours;
int minutes;
int seconds;
float temp;

//Declare global variables for humidity and temperature in DHT11-sensor
float t1;
float t2;
float h1;
float h2;

//Declare global variables/arrays for timing
int oldMinute;      //This is for updating the time (minutes)
char lastSent[20]; //This is the last time Thingspeak has got its input

Part 2:

void setup() {

  //Serial for debugging
  Serial.begin(115200);
  
  // Use GP10 Pins as output.
  pinMode(2, OUTPUT); //Relay 1
  pinMode(3, OUTPUT); //Relay 2
  //pinMode(analogPin, INPUT);
  //pinMode(ledPin, OUTPUT);
  pinMode(pwmPin, OUTPUT);
  pinMode(fan1pin, OUTPUT);//For starting/stopping Fan1
  pinMode(fan2pin, OUTPUT);//For starting/stopping Fan2
  
  // Enable I2C communication
  Wire.begin();

  // set up the LCD's number of columns and rows:
  lcd.begin(20, 4);
  // Print a message to the LCD.
  lcd.print("Startar"); //One in a row of Starting... that shows in the display under startup.
  
  // Function to attach functions to LiquidLine objects.
  pwm_line.attach_function(1, pwm_up);  //Not used for now
  pwm_line.attach_function(2, pwm_down);//Not used for now

  fan1_line2.attach_function(1, fan1_up);           //Start Fan1 manual via display
  fan1_line2.attach_function(2, fan1_down);         //Stop Fan1 manual via display
  fan1_line3.attach_function(1, tempSetpoint1_up);  //Raise the tempsetpoint via display where the Fan1 will start if temp goes higher
  fan1_line3.attach_function(2, tempSetpoint1_down);//Lower the tempsetpoint via display where the Fan1 will start if temp goes higher
  fan1_line4.attach_function(1, rfSetpoint1_up);    //Raise the humiditysetpoint via display where Fan1 will start if the humidity goes higher
  fan1_line4.attach_function(2, rfSetpoint1_down);  //Lower the humiditysetpoint via display where Fan1 will start if the humidity goes higher
  
  fan2_line2.attach_function(1, fan2_up);           //Start Fan2 manual via display
  fan2_line2.attach_function(2, fan2_down);         //Stop Fan2 manual via display
  fan2_line3.attach_function(1, tempSetpoint2_up);  //Raise the tempsetpoint via display where the Fan2 will start if temp goes higher
  fan2_line3.attach_function(2, tempSetpoint2_down);//Lower the tempsetpoint via display where the Fan2 will start if temp goes higher
  fan2_line4.attach_function(1, rfSetpoint2_up);    //Raise the humiditysetpoint Fan2 via display
  fan2_line4.attach_function(2, rfSetpoint2_down);  //Lower the humiditysetpoint Fan2 via display

  
  menu.add_screen(welcome_screen);
  menu.add_screen(fan1_screen);
  menu.add_screen(fan2_screen);
  menu.add_screen(pool_screen);
  menu.add_screen(screen2);
  menu.add_screen(pwm_screen);
  lcd.print("."); //Starting...
  
  //Start DHT-sensors
  dht1.begin();
  dht2.begin();

  // Start RTC module
  rtcModule.Begin();

  // add dot to start up animation
  lcd.print(".");
  
  // Initialise serial for ESP module
  MySerial.begin(9600);

  // Initialise ESP module
  WiFi.init(&MySerial);

  //Add dot to start up animation
  lcd.print(".");
  
  // Check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi-klient kan inte nås");
    // Dont continue
    while (true);
  }

  // Attempt to connect to WiFi network
  while (status != WL_CONNECTED) {
    Serial.print("Försöker ansluta till SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);

    // Add dot to start up animation
    lcd.print(".");
  }
  printWifiStatus();
  printLCD();
}

Part 3:

void loop() {
  //Read the status of the Fans on/off.
  bool Fan1State = digitalRead(fan1pin);
  bool Fan2State = digitalRead(fan2pin);
  
  //For future connection to the poolrelay.
  //bool Pool1State = digitalRead(pool1pin);
  //bool Pool2State = digitalRead(pool2pin);
  //bool Pool3State = digitalRead(pool3pin);
  
  // Check all the buttons
  if (right.check() == LOW) {
    Serial.println(F("RIGHT button clicked"));
    menu.next_screen();
  }
  if (left.check() == LOW) {
    Serial.println(F("LEFT button clicked"));
    menu.previous_screen();
  }
  if (up.check() == LOW) {
    Serial.println(F("UP button clicked"));
    // Calls the function identified with one
    // for the focused line.
    menu.call_function(1);
  }
  if (down.check() == LOW) {
    Serial.println(F("DOWN button clicked"));
    menu.call_function(2);
  }
  if (enter.check() == LOW) {
    Serial.println(F("ENTER button clicked"));
    // Switches focus to the next line.
    menu.switch_focus();
  }
  
  
  // Periodically switches the state of the LED.(If I take away the next 4 rows everything flips out :)
  static unsigned long lastMillis = 0;
  static unsigned int period = 3000;
  if (millis() - lastMillis > period) {
    lastMillis = millis();
    
    //Used for putting the on/off text on LCD regarding manual start/stop Fan1 via display.
    Serial.print("Fläkt nr 1 i läge: ");
    if (Fan1State == HIGH) {
      // Changes the text that is printed on the display.
      Fan1State_text = (char*)"ON";
      Serial.println(Fan1State_text);
      menu.update();
    } else {
      Fan1State = LOW;
      Fan1State_text = (char*)"OFF";
      Serial.println(Fan1State_text);
      menu.update();
    }
    //Used for putting the on/off text on LCD regarding manual start/stop Fan2 via display.
    Serial.print("Fläkt nr 2 i läge: ");
    if (Fan2State == HIGH) {
      // Changes the text that is printed on the display.
      Fan2State_text = (char*)"ON";
      Serial.println(Fan2State_text);
      menu.update();
    } else {
      Fan2State = LOW;
      Fan2State_text = (char*)"OFF";
      Serial.println(Fan2State_text);
      menu.update();
    }

    //The ledState is not going to be used for now.
    Serial.print("LED turned ");
    if (ledState == LOW) {
      ledState = HIGH;
      // Changes the text that is printed on the display.
      ledState_text = (char*)"ON";
      Serial.println(ledState_text);
      menu.update();
    } else {
      ledState = LOW;
      ledState_text = (char*)"OFF";
      Serial.println(ledState_text);
      menu.update();
    }
    digitalWrite(ledPin, ledState);

    //Analogvalue is not going to be used for now.
    // The 'analogValue' is updated every second.
    analogValue = analogRead(analogPin);
    static unsigned short lastAnalogValue = 0;
    if (analogValue != lastAnalogValue) {
      lastAnalogValue = analogValue;
      menu.update();
  
    }
  }
  
  updateTime();  
  
  // Update channel on Thingspeak (every postingInterval). At the same time do the other updates.
  if (seconds % postingInterval == 0) {
    updateTemp();
    updateTempHum();
    updateFanRelay();
    sendThingspeak();
  }

  client.flush();
  client.stop();
  //delay(500);//If I have a delay here the LCD-buttons will be much slower
}

void sendThingspeak() {
   if (client.connectSSL(server, 443)) {
    Serial.println("Ansluten till server.");
    client.println("GET /update?api_key=" + String(thingspeakAPIKey) +
                   "&field1=" + String(temp) + "&field2=" + String(t1) + "&field3=" + String(h1) + "&field4=" + String(t2) + "&field5=" + String(h2) + " HTTP/1.1");
    client.println("Host: api.thingspeak.com");
    client.println("Connection: close");
    client.println();
    Serial.println("Information skickad till server.");

    // Save sent time as char-array. Later used for showing the time when info were last sent to thingspeak.
    sprintf(lastSent, "Sent: %02d:%02d:%02d", hours, minutes, seconds);

    // Update time on display
    printLCD();
    delay(500);
  }
}

void updateTime() {
  oldMinute = minutes;
  RtcDateTime now = rtcModule.GetDateTime();

  // Save time in variables
  hours = now.Hour();
  minutes = now.Minute();
  seconds = now.Second();

  // Update screen on minute update
  if (minutes != oldMinute) {
    printLCD();
  }
}

void printLCD() {
  // This prints the time and values on the LCD and shows up in intervals.
  // Format and print time on LCD
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.clear();
  lcd.setCursor(0, 0);
  char timeString[6];
  sprintf(timeString, "%02d:%02d", hours, minutes);
  lcd.print("Tid: ");
  lcd.print(timeString);
  lcd.setCursor(0, 2);
  lcd.print("Vardagsrum:");
  lcd.setCursor(0, 4);
  lcd.print("H:");
  lcd.print(h1);
  lcd.setCursor(12, 4);
  lcd.print("T:");
  lcd.print(t1);
}

void updateTemp() {

  // Read temperature
  RtcTemperature rtcTemp = rtcModule.GetTemperature();
  temp = rtcTemp.AsFloat();
}

void updateTempHum() {

  //Read Temperature and Humidity
  t1 = dht1.readTemperature();
  h1 = dht1.readHumidity();
  t2 = dht2.readTemperature();
  h2 = dht2.readHumidity();

  //Calibrate the Humiditysensor 1 with the value put into calibSetUpHum1
  if (calibSetUpHum1 > 0) {
    h1 = h1 + calibSetUpHum1;
    Serial.println("Fuktsensor 1 uppkalibrerad");
  } else if (calibSetUpHum1 < 0) {
    h1 = h1 + calibSetUpHum1;
    Serial.println("Fuktsensor 1 nerkalibrerad");
  }
  //Calibrate the Temperaturesensor 1 with the value put into calibSetUpTemp1
  if (calibSetUpTemp1 > 0) {
    t1 = t1 + calibSetUpTemp1;
    Serial.println("Tempsensor 1 uppkalibrerad");
  } else if (calibSetUpTemp1 < 0) {
    t1 = t1 + calibSetUpTemp1;
    Serial.println("Tempsensor 1 nerkalibrerad");
  }
  //Calibrate the Humiditysensor 2 with the value put into calibSetUpHum2
  if (calibSetUpHum2 > 0) {
    h2 = h2 + calibSetUpHum2;
    Serial.println("Fuktsensor 2 uppkalibrerad");
  } else if (calibSetUpHum2 < 0) {
    h2 = h2 + calibSetUpHum2;
    Serial.println("Fuktsensor 2 nerkalibrerad");
  }
  //Calibrate the Temperaturesensor 2 with the value put into calibSetUpTemp2
  if (calibSetUpTemp2 > 0) {
    t2 = t2 + calibSetUpTemp2;
    Serial.println("Tempsensor 2 uppkalibrerad");
  } else if (calibSetUpTemp2 < 0) {
    t2 = t2 + calibSetUpTemp2;
    Serial.println("Tempsensor 2 nerkalibrerad");
  }
  //Check if any reads of DHT-sensor 1 and 2 failed and exit early (to try again).
  if (isnan(h1) || isnan(t1) || isnan(h2) || isnan(t2)) {
    Serial.println("Kunde inte läsa från DHT-sensorn!");
    return;
  }

  Serial.print("(Sensor 1) Humiditet: ");
  Serial.print(h1);
  Serial.print(" %\t");
  Serial.print("Temperatur: ");
  Serial.print(t1);
  Serial.print(" *C ");
  Serial.println("");
  Serial.print("(Sensor 2) Humiditet: ");
  Serial.print(h2);
  Serial.print(" %\t");
  Serial.print("Temperatur: ");
  Serial.print(t2);
  Serial.print(" *C ");
  Serial.println("");

}

void updateFanRelay() {
  
  //Stopp and start the fan nr 1 after the humiditySetpoint
  if (h1 > rfSetpoint1) {
    digitalWrite(3, HIGH);
    Serial.print("Sensor 1, Luftfuktighet hög " + String(h1, 0) + "%. Fläkt i drift");
    Serial.println("");
  }
  else {
    digitalWrite(3, LOW);
    Serial.println("Sensor 1, Luftfuktighet normal " + String(h1, 0) + "%. Fläkt stopp");
  }
  if (t1 > tempSetpoint1) {
    digitalWrite(3, HIGH);
    Serial.print("Sensor 1, Temperatur hög " + String(t1, 0) + "C. Fläkt i drift");
    Serial.println("");
  }
  else {
    digitalWrite(3, LOW);
    Serial.println("Sensor 1, Temperatur normal " + String(t1, 0) + "C. Fläkt stopp");
  }
  if (h2 > rfSetpoint2) {
    digitalWrite(2, HIGH);
    Serial.print("Sensor 2, Luftfuktighet hög " + String(h2, 0) + "%. Fläkt i drift");
    Serial.println("");
  }
  else {
    digitalWrite(2, LOW);
    Serial.println("Sensor 2, Luftfuktighet normal " + String(h2, 0) + "%. Fläkt stopp");
  }
  if (t2 > tempSetpoint2) {
    digitalWrite(2, HIGH);
    Serial.print("Sensor 2, Temperatur hög " + String(t2, 0) + "C. Fläkt i drift");
    Serial.println("");
  }
  else {
    digitalWrite(2, LOW);
    Serial.println("Sensor 2, Temperatur normal " + String(t2, 0) + "C. Fläkt stopp");
  }
}

void printWifiStatus() {

  // Print the SSID of the network
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // Print the IP address
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
}

When you have a long program just add the .ino file as an attachment. That way there is no risk of adding errors when joining up the parts.

My wish is, that when I turn the fan on manually the fan would be on until I choose to shut it of again...but it only stays on until the next time sensor-values goes into updateFanRelay(). updateFanRelay() stops the fan again because it sees the exemplaric values from the sensor-readings. It says...oooh the fan have to stop...the values are great!!

I'm not sure if I understand this correctly. I think what you have in mind is as follows ...

  • normally the automatic systems turns the fan on and off
  • sometimes you would like to be able to turn the fan on manually but the next automatic OFF should still turn it off
  • and sometimes you would like to turn it off manually but have it come on again automatically when the sensor say it should

If that is correct it should be straightforward to arrange.

I suggest you have a variable that tells the fan to be on or off. Normally the readings from the sensor will change that variable. But your button press could also change the variable. That way the button press won't affect the follow-up action by the sensors.

...R

Robin2:
When you have a long program just add the .ino file as an attachment. That way there is no risk of adding errors when joining up the parts.
I'm not sure if I understand this correctly. I think what you have in mind is as follows ...

  • normally the automatic systems turns the fan on and off
  • sometimes you would like to be able to turn the fan on manually but the next automatic OFF should still turn it off
  • and sometimes you would like to turn it off manually but have it come on again automatically when the sensor say it should

If that is correct it should be straightforward to arrange.

I suggest you have a variable that tells the fan to be on or off. Normally the readings from the sensor will change that variable. But your button press could also change the variable. That way the button press won't affect the follow-up action by the sensors.

...R

Thank you for your reply Robin2. No that wasn´t my intention. I want to be able to turn the fan on/off manually in my LCD-menu and it has to stay on/off until I turn it on/off. The problem is that it only stay on/off until the next loop.

...F

FrefiX:
Thank you for your reply Robin2. No that wasn´t my intention. I want to be able to turn the fan on/off manually in my LCD-menu and it has to stay on/off until I turn it on/off. The problem is that it only stay on/off until the next loop.

Then it sounds like you need a 3rd manual state - ON, OFF or AUTO. Your code should only act on the sensor values when AUTO is selected.

...R

Robin2:
Then it sounds like you need a 3rd manual state - ON, OFF or AUTO. Your code should only act on the sensor values when AUTO is selected.

...R

Yes, that sounds like a good idea. But do you have any idea about how i could implement that. I cannot get a grip of it codewise.

...F

You are not giving me much to go on :slight_smile:

You could have three buttons - On Off and Auto

You could have one button that cycles through On Off and Auto with each successive press.

In either case have a variable called (say) controlState which at any time has one of the characters N, F or A. And wherever you have your code for switching according to the sensor it should do something like this pseudo code

if (sensorVal == HIGH and controlState == 'A') {
   // turn on fan
}
if (sensorVal == LOW and controlState == 'A') {
   // turn off fan
}
if (controlState == 'N') {
   // turn on fan
}
if (controlState == 'F') {
   // turn off fan
}

...R

Thank you Robin2, because you got me thinking about the third state "auto".

I did it like this (and it works just as it should):

At first I put a variable for FanXModeAuto global...

int Fan1ModeAuto = 1;

Then I told the function in LCD-display to set Fan1ModeAuto = 0 when the Fan1 is manually started. Also I set Fan1ModeAuto =1 when the Fan1 is manually stopped again.

// Function to be attached to the fan1_line2 object, starts and stops the Fan1 from the LCD-display.
void fan1_up() {
  digitalWrite(fan1pin, HIGH);
  Fan1ModeAuto = 0;
}

void fan1_down() {
  digitalWrite(fan1pin, LOW);
  Fan1ModeAuto = 1;
}

Then I implemented Fan1ModeAuto = X to the updateFanRelay() function.

void updateFanRelay() {
  
  //Stop and start the fan nr 1 after the humiditySetpoint
  if (h1 > rfSetpoint1) {
    digitalWrite(3, HIGH);
    Serial.print("Sensor 1, Luftfuktighet hög " + String(h1, 0) + "%. Fläkt i drift");
    Serial.println("");
  }
  else if (Fan1ModeAuto == 1) {
    digitalWrite(2, LOW);
    Serial.println("Sensor 1, Luftfuktighet normal " + String(h1, 0) + "%. Fläkt stopp");
  }
  else {
    Serial.println("Fläkt 1 i läge MANUELL");
  }
  if (t1 > tempSetpoint1) {
    digitalWrite(2, HIGH);
    Serial.print("Sensor 1, Temperatur hög " + String(t1, 0) + "C. Fläkt i drift");
    Serial.println("");
  }
  else if (Fan1ModeAuto == 1) {
    digitalWrite(2, LOW);
    Serial.println("Sensor 1, Temperatur normal " + String(t1, 0) + "C. Fläkt stopp");
  }
  else {
    Serial.println("Fläkt 1 i läge MANUELL");
  }

I am going to finetune it to include also the point when the sensorreadings want to stop the fan1, but it works :slight_smile:

Thank you again :slight_smile:

I wonder if this IF and ELSE IF will work properly

  if (h1 > rfSetpoint1) {
    digitalWrite(3, HIGH);
    Serial.print("Sensor 1, Luftfuktighet hög " + String(h1, 0) + "%. Fläkt i drift");
    Serial.println("");
  }
  else if (Fan1ModeAuto == 1) {

because I think it will only check Fan1ModeAuto if h1 <= rfSetpoint1

I wonder if the Fan1ModeAuto test should come first?

...R

I changed it to:

//Stopp and start the fan nr 1 after the humiditySetpoint
  if (h1 > rfSetpoint1 && Fan1ModeAuto == 1) {
    digitalWrite(3, HIGH);
    Serial.print("Sensor 1, Luftfuktighet hög " + String(h1, 0) + "%. Fläkt i drift");
    Serial.println("");
  }
  else if (Fan1ModeAuto == 1) {

Is this what you mean?

...F

Sort-of.

But I don't see the point of else if (Fan1ModeAuto == 1) {

Do you understand the effect of the change you made? Or are you just sprinkling pepper on the plate and hoping some will land on your steak? :slight_smile:

...R

Ha ha. Ok this is how I think...

else if (Fan1ModeAuto == 1) {
    digitalWrite(2, LOW);
    Serial.println("Sensor 1, Luftfuktighet normal " + String(h1, 0) + "%. Fläkt stopp");
  }
  else {
    Serial.println("Humiditet sensor 1 mäts inte. Fläkt 1 i läge MANUELL");

If I dont put else if (Fan1ModeAuto == 1) here, then it will execute digitalWrite(2, LOW) even if I have set the Fan1 in manual in the display. Then it will shut the fan off. That is not what I want, so therefor I tell it to NOT execute if Fan1ModeAuto = 0. If I have put on the fan1 manual in my display, then I dont want the digitalWrite(2, LOW) to execute.

Afterwards (in the else { statement I want the text in my serial sayin that I have put the system in MANUAL. Therefore im using it like this. But I am sure that this is not the most proffessional way. But I am running my code now, and it actually works just the way I want it to do :).

It has been a lot of sprinkling pepper...as a short answer to that question.

FrefiX:
Ha ha. Ok this is how I think...

Glad to hear it is working.

If you want feedback you need to post the complete piece of code (or the whole program).

...R

Thank you for your help. I have posted the complete code in the top of the post (Part 1, 2 and 3). But I will follow what you say about the .ino-file in the future.

Have a great time and thanks again! :slight_smile: :slight_smile:

Project attached :slight_smile:

FrefiX:
I have posted the complete code in the top of the post (Part 1, 2 and 3).

I was referring to the latest version including the changes following the advice here. However if everything is working OK then there is no need to post the new version.

...R