Go Down

Topic: HVAC controller log / Introduction (Read 12807 times) previous topic - next topic


Jun 11, 2014, 02:59 am Last Edit: Jun 11, 2014, 03:02 am by draythomp Reason: 1
Yes, I have lots of code posted for various things, and my usage of TimeAlarm is in there.  It may be hard to find where I used it, so here's a rewrite of 'blink' using time alarm.  The big difference is that loop() really doesn't do anything, the processor is available for whatever you want to do.  The caution is to remove all delay() calls and convert them to Alarm.delay() calls which does the same thing, but doesn't lock up the processor, as well as allow the time to tick by so things can happen.

Code: [Select]
Just an example of how one timer can set off another in an endless

#include <Time.h>
#include <TimeAlarms.h>

// When the timer fires, it will come here automatically
void lightOn(){
 digitalWrite(13, HIGH);
 Alarm.timerOnce(1, lightOff);  // in 5 seconds, turn the light off

void lightOff(){
 digitalWrite(13, LOW);
 Alarm.timerOnce(1, lightOn);  // in 5 seconds turn the light on

void setup()
 Serial.println("Just for fun");
 pinMode(13, OUTPUT);  // we're going to use the on board LED  
 setTime(0,0,0,1,1,13); // This is only to make the routines work
                        // however, if you want something based on
                        // time of day, you'll have to figure out
                        // a way of setting the time correctly
                        // and keeping it current.
 Alarm.delay(0);         // You'll have to replace all the delay()
                        // calls with one of these.  I used zero here
                        // because we don't actually need any delay.
 lightOn();             // This is a priming call to get it all started.

void  loop()
 // the loop really doesn't have to have anything in it for
 // the timers and alarms to work except the Alarm.delay()
 // this lets the alarm code run to see if anything needs to
 // be done
 Alarm.delay(0);  // we don't actually need to spend any time here.

And, naturally, I still have the wrong time in the comments ... sigh.


Sunday update. I have a crude smoothing function for the temperature reading. I say crude because when the unit powers on the first 4 temp readings are  low because the array is full of zeros.

In the next few days I'd like to figure out a way around this, and then start on "run protection". I dont want to turn the AC off, and then turn it back on unless 10 minutes has passed. I feel like this will be a tricky.

Code: [Select]
// include the libraries for gizmos
#include <LiquidCrystal.h>
#include <dht11.h>

dht11 DHT11; // Figure out what this line does
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // initialize the library with the numbers of the interface pins

// These constants won't change:
const int ACledPin = 8;      // Air Conditioner LED (RED)
const int HTledPin = 9;      // Heat LED (YELLOW)
const int threshold = 75;    // an arbitrary threshold level that's in the range of the analog input

const int RELAY_01 = 6;    // RELAY 1 PIN 9
const int RELAY_02 = 10;   // RELAY 2 PIN 10

// START ADDITIONS ////////////////////////////////////////////////////////////////////////////////////////////////
const int numReadings = 5;
float readings[numReadings];      // the readings from the analog input
int index = 0;                    // the index of the current reading
float total = 0;                  // the running total

float get_smoothed_temp() {
    total = total - readings[index]; // remove oldest reading
    readings[index] = DHT11.fahrenheit();
    total += readings[index];
    index = (index + 1) % numReadings;
    return (total / numReadings);
// END ADDITIONS ////////////////////////////////////////////////////////////////////////////////////////////////

void setup() {
  DHT11.attach(7);       // Attach DHT11 sensor to pin 7
  lcd.begin(16, 2);      // set up the LCD's number of columns and rows:
  Serial.begin(9600);    // Serial setup
  for (int thisReading = 0; thisReading < numReadings; thisReading++) readings[thisReading] = 0; // initialize all the readings to 0:


  pinMode(ACledPin, OUTPUT);  // initialize pin 8 as output
  pinMode(HTledPin, OUTPUT);  // initialize pin 9 as output
  pinMode(RELAY_01, OUTPUT);  // initialize pin 6 as output
  pinMode(RELAY_02, OUTPUT);  // initialize pin 10 as output

  // Leaves the relays in default "off" (no noise/click)
  digitalWrite(RELAY_01, HIGH);
  digitalWrite(RELAY_02, HIGH);


void loop() {

  float analogValue = (get_smoothed_temp()); // trying to set up the temp reading as an int variable
////////////// if then ////////////////
// if the analog value is high enough, turn on the LED:
  if (analogValue > threshold) {
    digitalWrite(ACledPin, HIGH);
    digitalWrite(HTledPin, LOW);
    digitalWrite(RELAY_01, HIGH);
    digitalWrite(RELAY_02, LOW);
  else {
    digitalWrite(ACledPin, LOW);
    digitalWrite(HTledPin, HIGH);
    digitalWrite(RELAY_01, LOW);
    digitalWrite(RELAY_02, HIGH);

Serial.println(analogValue);  // print the analog value:

// Set up the LCD Stuff
  lcd.setCursor(0, 0);      // Set cursor to top left
  lcd.print("Real F:");
  lcd.setCursor(0, 1);
  lcd.print("AVG  F:");
  lcd.print(analogValue, 1);




In your loop only turn the compressor on when a flag is set.  Then when the compressor shuts off set the flag to false and set a timer to fire in 10 minutes.  When the timer callback happens, set the flag to true.  This will force a 10 minute wait between compressor cycles.

Code: [Select]
#include <Time.h>
#include <TimeAlarms.h>

boolean compressorAllowed;

To set the timer when you turn off the compressor, it would look something like this:

Alarm.timerOnce(10 * 60, allowCompressor); // let the compressor back on in 10 minutes

The call back would look like this:

void allowCompressor(){
    compressorAllowed = true; This is your flag

Then, somwhere in your loop:

If (compressorAllowed){

Nothing to it, but you'd have to give up that delay call.  If it were me, I'd make my loop() look something like this"

Code: [Select]
void loop(){

And in setup, I'd set up timers to handle everything:

alarm.timerRepeat(1, goCheckTheTemperatureAndDoStuff);  // This is the every second go check for something to do
alarm.timerRepeat(dowFriday,5,30,30,goBuyFlowersForThatGoodLookingChick); // This is to keep the people you're ignoring happy

But, that's just me.


I say crude because when the unit powers on the first 4 temp readings are  low because the array is full of zeros.

Instead of setting the array elements to zero in setup, call get_smoothed_temp in the loop.


The smoothing algorithm is showing zero because it's filled with zeros to begin with and you haven't  taken enough sample to change it yet.  My algorithm starts at a negative number and step up to room temperature over a few seconds.  If you want it to show something else while it stabilized, just fill it with that value.  Say, fill it with 70, then it will show 70 and change a bit as it stabilizes.

Me, I like the numbers changing until it reaches room temp; it tells me it's alive.


Jun 23, 2014, 01:37 am Last Edit: Jun 23, 2014, 08:48 pm by LVLAaron Reason: 1
Quick update. I've put my code aside for now and forked something I found on github. It was far from complete but I have most of it figured out now. Things are working well. I took some time off to get one of the Adafruit i2c RGB LCD's with buttons, etc. Pretty nice little kit.

Full sketch; https://gist.github.com/LVLAaron/73ace539b51b306ccb9b
(Too big to post here)

The milestone for me is that I now understand how to use millis()

- Next step is to sort out the way the relays function. Right now if the AC is ON the relay is what I will refer to as "off" which means the Arduino pin is set to HIGH. If something happened to the Arduino and it died unexpectedly, all of the relays would be "on" and I would essentially be turning on the HEAT/AC/FAN all at the same time. I'll need to work on flip/flopping the code to work around that.

- Following that I want to work on the LCD menus. As it stands, if you press select to adjust your temperature thresholds there is no way to get back to the first/opening screen that just displays the temperature.

Go Up