Timing issues

Hi everyone. I am having a couple of issues with my IoT thermostat project.

I have a room and set temperature on my thermostat and am keeping those variables updated on Firebase. I have 2 push buttons on my thermostat and they can increase/decrease the set temperature.

At first I was able to use an interrupt on my push buttons to trigger a boolean value and update the new set temperature to Firebase and it worked great (calling Firebase API in interrupt service routine gave me a ton of errors).

Here is the ISR:

 void pin_ISR_Increase() {

  interruptTrigger = true;
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();

  if (interrupt_time - last_interrupt_time > 350) {
    setTemperature++;
  }
  last_interrupt_time = interrupt_time;
}

My issue now is I am trying to have it so not only can I use the push buttons to update the set temperature on Firebase, but at the same time try and read the set temperature from Firebase in case I change the value on Firebase, or in the future my Android application.

This will allow me have controls on the device itself and change the set temperature from the Android app and they will stay synchronized.

When I try to do this now however, I am running into the issue where my push buttons are not changing the temperature anymore.

Here is a small sample of my code:

  if (interruptTrigger == true) {
    setFirebaseSetTemperature();
    interruptTrigger = false;
  } else {
    getFirebaseSetTemperature();
  }
}

It seems to just be hitting the else statement constantly, even when it does hit the if statement when debugging in Serial monitor it doesn't change the temperature value.

Are there any better ways to to read and write from Firebase in a timely manner?

A couple more issues I've run into:

Does anyone have any recommendations for running a task every x amount of seconds? I also have code to push the room temperature to Firebase, but it's not necessary to constantly do this every loop. I have considered using for loops to run certain portions of the code every few times around, but it didn't work too well. My idea next is to try using millis() like I did with my interrupts.

Serial.println has been acting very funny in the monitor all of a sudden. For example Serial.println("Current temp: " + setTemperature);

would only print "rrent temp" in serial monitor, yet Serial.println(setTemperature); would print the integer like I wanted it to.

And lastly, the push buttons I have require a slight delay between each press to increment/decrement the tmperature, I've tried adjusting my debounce algorithmn in the ISRs but can't improve the response time anymore. Do better push buttons exist that can deliver very instant responses when spamming the buttons or is a 0.5-1 second delay between each press is as good as I am going to get?

How could you possibly need an interrupt in something that reacts as slowly as room temperature - or humans pressing buttons.

Just use polling,

And if you need more help post the complete program

...R

Well I figured I'd use the interrupts for detecting a push button pressed down to increment/decrement the temperature, rather than continuously polling in the loop if the buttons were pressed or not.

Sure thing though here it is:

#include <LiquidCrystal.h>
#include <ESP8266WiFi.h>
#include <FirebaseArduino.h>
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"

//LiquidCrystal lcd(D4, D5, D0, D1, D2, D3);
SSD1306  display(0x3c, D1, D2);

#define firebaseURL "removed"
#define authCode "removed"

#define wifiName "removed"
#define wifiPass "removed"
String path = "thermostat"; 


const int buttonPinIncrease = D7;
const int buttonPinDecrease = D8;
volatile int buttonState = 0;
boolean interruptTrigger;


const int tempSensorPin = A0;
const int LEDPin = 13;
int setTemperature = 75;


void setup() {
  interruptTrigger = false;
  // Set baud rate
  Serial.begin(115200);
 

  // Configure inputs, outputs, and interrupts
  //configureLED();
  //configureLCD();
  configureISR();

  setupWifi();
  setupFirebase();
}

void loop() {
  float voltage = getVoltage();
  float tempCelsius = (voltage - 0.5) * 100;
  float tempFahrenheit = (tempCelsius * 9.0 / 5.0) + 32.0;
  
  //printToLCD(voltage, tempFahrenheit);


  setFirebaseRoomTemperature(tempFahrenheit);

  //printToSerial(voltage, tempCelsius, tempFahrenheit);
  if (interruptTrigger == true) {
    setFirebaseSetTemperature();
    interruptTrigger = false;
  } else {
    getFirebaseSetTemperature();
  }
}

void setFirebaseRoomTemperature(int roomTemperature) {
  
  Firebase.setInt(path + "/roomTemperature", roomTemperature);
  
}

void setFirebaseSetTemperature() {
  
  Firebase.setInt(path + "/setTemperature", setTemperature);
}

void getFirebaseSetTemperature() {

  setTemperature = Firebase.getInt(path + "/setTemperature");
}

void setupFirebase() {

  Firebase.begin(firebaseURL, authCode);
}

void setupWifi() {

  WiFi.begin(wifiName, wifiPass);
  Serial.println();
  Serial.println("Connecting to WiFi network...");

  while (WiFi.status() != WL_CONNECTED) {
    
    Serial.println(".");
    delay(500);
  }

  Serial.println();
  Serial.println("Connected to " + WiFi.SSID());
  Serial.print("Local IP address: ");
  Serial.println(WiFi.localIP());
}

// ISR for when button is used to increase temp
void pin_ISR_Increase() {

  interruptTrigger = true;
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();

  if (interrupt_time - last_interrupt_time > 350) {
    setTemperature++;
  }
  last_interrupt_time = interrupt_time;
}

// ISR for when button is used to decrease temp
void pin_ISR_Decrease() {
  
  interruptTrigger = true;
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();

  if (interrupt_time - last_interrupt_time > 350) {
    setTemperature--; 
  }
  last_interrupt_time = interrupt_time;
}

void configureLED() {
  
  // Pin 13 set as digital output
  pinMode(LEDPin, OUTPUT);
}

void configureISR() { 

  // Configurate button for ISR
  pinMode (buttonPinIncrease, INPUT);
  pinMode (buttonPinDecrease, INPUT);
  attachInterrupt(buttonPinIncrease, pin_ISR_Increase, RISING);
  attachInterrupt(buttonPinDecrease, pin_ISR_Decrease, RISING);
}

float getVoltage() {

  // Read analog value from temp sensor
  int analogInput = analogRead(tempSensorPin);

  // Convert analog value to voltage
  float voltage = analogInput * 3.3;
  voltage /= 1024.0;
  return voltage;
}

void printToSerial(float voltage, float tempCelsius, float tempFahrenheit) {

  // Print voltage to console
  Serial.print(voltage);
  Serial.println(" Volts");

  // Print degrees in C to console
  Serial.print(tempCelsius);
  Serial.println(" degrees C");

  // Print degrees in F to console
  Serial.print(tempFahrenheit);
  Serial.println(" degrees F");

  Serial.print("Current set temperature: ");
  Serial.println(setTemperature);
}

Ideally I just want to detect an incoming set temperature change from Firebase (or my Android app) right away, vice versa with the push buttons updating Firebase. So you can modify the set temperature from the thermo itself with the buttons, or through my Android app.

Then for sending the room temperature to Firebase I'd like to do what maybe every 30 seconds to a minute for demoing purposes. It really doesn't need to be updated all the time.

Just looking for an ideal way to make sure the read/write to Firebase for the set temperature happens when it is supposed to.

This code

void loop() {
 
  // .....

  if (interruptTrigger == true) {
    setFirebaseSetTemperature();
    interruptTrigger = false;
  } else {
    getFirebaseSetTemperature();
  }
}

will call the getFireBaseSetTemperature() function hundreds or thousands of times per second. The decision to check the Firebase setting should be completely separate from the decision to update the setting in response to a button.

You already have the concept for timing calls to check the temperature in this code from one of your ISRs

  if (interrupt_time - last_interrupt_time > 350) {
    setTemperature--;
  }
  last_interrupt_time = interrupt_time;

Just put similar code in loop() and get the setting every 30 seconds or whatever seems reasonable.

And use the same idea again for sending the room temperature.

...R

Thank you for the suggestions. I thought it would yield better performance and make more sense to use interrupts on the push buttons, etc, but polling seems to work much better.

I am now able to read/write to Firebase for the set temperature instantly, along with reporting the room temperature at a nice interval with great performance all around.

Here's how it looks now

#include <LiquidCrystal.h>
#include <ESP8266WiFi.h>
#include <FirebaseArduino.h>
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"

//LiquidCrystal lcd(D4, D5, D0, D1, D2, D3);
SSD1306  display(0x3c, D1, D2);

#define firebaseURL "removed"
#define authCode "removed"

#define wifiName "removed"
#define wifiPass "removed"
String path = "thermostat"; 


const int buttonPinIncrease = D7;
const int buttonPinDecrease = D8;
volatile int buttonState = 0;
boolean interruptTrigger;
unsigned long last_increase_time;
unsigned long last_decrease_time;
unsigned long last_roomTemp_time;
unsigned long last_getSetTemp_time;


const int tempSensorPin = A0;
const int LEDPin = 13;
int setTemperature = 75;

float voltage, tempCelsius, tempFahrenheit;


void setup() {
  interruptTrigger = false;
  // Set baud rate
  Serial.begin(115200);
  
  display.init();

  display.flipScreenVertically();

  display.setContrast(255);
  display.clear();
  display.setFont(ArialMT_Plain_10);

  // Configure inputs, outputs, and interrupts
  //configureLED();
  //configureLCD();
  //configureISR();

  setupWifi();
  setupFirebase();

  last_increase_time = 0;
  last_decrease_time = 0;

  last_roomTemp_time = 0;
  last_getSetTemp_time = 0;

  voltage = getVoltage();
  tempCelsius = (voltage - 0.5) * 100;
  tempFahrenheit = (tempCelsius * 9.0 / 5.0) + 32.0;

  setTemperature = getFirebaseSetTemperature(); // so program boots with setTemperature from Firebase initally

  printToLCD();
  
}

void loop() {

  //printToSerial(voltage, tempCelsius, tempFahrenheit);

  unsigned long curr_roomTemp_time = millis();
  if ((curr_roomTemp_time - last_roomTemp_time) > 10000) {
    voltage = getVoltage();
    tempCelsius = (voltage - 0.5) * 100;
    tempFahrenheit = (tempCelsius * 9.0 / 5.0) + 32.0;
    last_roomTemp_time = curr_roomTemp_time;
    setFirebaseRoomTemperature(tempFahrenheit);
    printToLCD();
  }
  
  unsigned long curr_increment_time = millis();
  if ((digitalRead(D7) == 1) && ((curr_increment_time - last_increase_time) > 200)) {
    setTemperature++;
    setFirebaseSetTemperature(setTemperature);
    last_increase_time = curr_increment_time;
    printToLCD();
  }

  unsigned long curr_decrement_time = millis();
  if ((digitalRead(D8) == 1) && ((curr_decrement_time - last_decrease_time) > 200)) {
    setTemperature--;
    setFirebaseSetTemperature(setTemperature);
    last_decrease_time = curr_decrement_time;
    printToLCD();
  }

  unsigned long curr_getSetTemp_time = millis();
  if ((curr_getSetTemp_time - last_getSetTemp_time) > 500) {
    setTemperature = getFirebaseSetTemperature();
    last_getSetTemp_time = curr_getSetTemp_time;
    printToLCD();
  }
  
}

void setFirebaseRoomTemperature(int roomTemperatureFirebase) {
  
  Firebase.setInt(path + "/roomTemperature", roomTemperatureFirebase);
  
}

void setFirebaseSetTemperature(int setTemperatureFirebase) {
  
  Firebase.setInt(path + "/setTemperature", setTemperatureFirebase);
}

int getFirebaseSetTemperature() {

  return (Firebase.getInt(path + "/setTemperature"));
}

void setFirebaseHeat(boolean heat) {
  
  Firebase.setBool(path + "/heat", heat);
}

void setupFirebase() {

  Firebase.begin(firebaseURL, authCode);
}

void setupWifi() {

  String periods = ".";
  
  WiFi.begin(wifiName, wifiPass);
  Serial.println();
  Serial.println("Connecting to WiFi network...");

  display.clear();

  while (WiFi.status() != WL_CONNECTED) {
    
    Serial.println(".");
    display.drawString(0, 15, "Connecting to WiFi" + periods);
    periods += ".";
    display.display();
    delay(500);
  }

  Serial.println();
  Serial.println("Connected to " + WiFi.SSID());
  Serial.print("Local IP address: ");
  Serial.println(WiFi.localIP());
  display.clear();
  display.drawString(0, 15, "Connected to " + String(WiFi.SSID()));
  display.display();
  delay(3000);
  
}

void configureLED() {
  
  // Pin 13 set as digital output
  pinMode(LEDPin, OUTPUT);
}

float getVoltage() {

  // Read analog value from temp sensor
  int analogInput = analogRead(tempSensorPin);

  // Convert analog value to voltage
  float voltage = analogInput * 3.3;
  voltage /= 1024.0;
  return voltage;
}

void printToSerial(float voltage, float tempCelsius, float tempFahrenheit) {

  // Print voltage to console
  Serial.print(voltage);
  Serial.println(" Volts");

  // Print degrees in C to console
  Serial.print(tempCelsius);
  Serial.println(" degrees C");

  // Print degrees in F to console
  Serial.print(tempFahrenheit);
  Serial.println(" degrees F");

  Serial.print("Current set temperature: ");
  Serial.println(setTemperature);
}

void printToLCD() {

  String heat;
  boolean heatBool;
  int roomTemperature = tempFahrenheit;

  display.clear();
  display.drawString(0, 15, "Room temperature: " + String(roomTemperature));
  display.drawString(0, 30, "Set temperature: " + String(setTemperature));

  if (setTemperature > tempFahrenheit) {
    heat = "ON";
    heatBool = true;
    setFirebaseHeat(heatBool);
  } else {
    heat = "OFF";
    heatBool = false;
    setFirebaseHeat(heatBool);
  }

  display.drawString(0, 45, "Heat: " + heat);
  display.display();
  
}