Wednesday, July 29, 2015

HVAC Efficiency Monitoring

"I wonder how the air conditioning is doing, it seems to run all the time." I was asking myself that question and thought about checking the temperature at the vents... maybe comparing it to the return duct. It would also be dependent on the outside air temperature (at least for air conditioning).

Now I know.

Results:




The Recipe

  1. Arudino Uno
  2. Ethernet Shield
  3. Four One Wire Dallas Temp Sensors (DS18B20)
  4. Cat 6 cable
  5. Code 
  6. EasyIoT Software
Mix One Arduino Uno and an Ethernet Sheild, add four parts Temp Sensors at the end of many feet of Cat6. Season with some code and you get hundredths of a degree every 5 seconds dumped into EasyIoT.



There are four temperature sensors installed. One on either side of the furance (inlet and outlet), one measuring the outside air, and one in the attic.

The "HVAC Difference" is the HVAC Outlet minus the HVAC Inlet. A positive number means the heater is running, a negative number means the air conditioning is running.

With this simple setup, I found some pretty interesting things.

The Air Conditioning is Working Great



The difference between the Inlet and Outlet is between -25 and -30 degrees F.  That's really good. Some might say too good, but we run a 3M Filtrete Ultra Allergen Reduction Filter which reduces airflow across the coils.

The Attic Gets Very Hot


I had no idea it gets over 110 in the attic. I'm going to look into an attic fan now.

Outside Air Temp is Hard to Measure


I think the wind and sun are throwing it off.  I know it isn't getting over 100, so it must be the sun.

It is very cool to see the temperature at such precision and frequency.

The Outlet Temperature of the Air Conditioning is Very Dynamic


It is interesting to see how quickly the outlet air duct (about 6 inches from the coil) warms back up to the temperature of the attic (where the coil is located). The inlet temperature is similar.

The Air Conditioner Leaks a Little into the Attic


When the attic is very hot, you can see the temperature change slightly when the air conditioner is running.

Outside Air Does Impact How Much It Can Cool the Air


This makes sense, but it is interesting to see at this detail.

Summary

I'm amazed at how much time I've spent looking over these graphs. I'm not sure why it is so interesting and it does make sense when you look at it... but there is something about it.

Code


/*
 *
 * Pins
 * 1 Serial RX
 * 2 Serial TX
 * 3
 * 4 Ethernet Sheild
 * 5 Temp Sensor 1 (HVAC INLET)
 * 6 Temp Sensor 2 (HVAC OUTLET)
 * 7 Temp Sensor 3 (ATTIC)
 * 8 Temp Sensor 4 (OUTSIDE)
 * 9
 * 10 Ethernet Sheild
 * 11 Ethernet Sheild
 * 12 Ethernet Sheild
 * 13 Ethernet Sheild
 *
 * A0
 * A1
 * A2
 * A3
 * A4
 * A5
 *
 */

#include <OneWire.h>
#include <DallasTemperature.h>
#include <Client.h>
#include <Ethernet.h>
#include <SPI.h>
#include <Base64.h>
#include <stdlib.h>

#define ONE_WIRE_BUS 7
#define TEMPERATURE_PRECISION 12

OneWire oneWire1(5);
DallasTemperature sensors1(&oneWire1);
OneWire oneWire2(6);
DallasTemperature sensors2(&oneWire2);
OneWire oneWire3(7);
DallasTemperature sensors3(&oneWire3);
OneWire oneWire4(8);
DallasTemperature sensors4(&oneWire4);

DeviceAddress AnAddress;

byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x50, 0xB8};
EthernetClient client;

#define USER_PWD_LEN 40
char unameenc[USER_PWD_LEN];

// EasyIoT server definitions
#define EIOT_USERNAME    "arduinosensors"
#define EIOT_PASSWORD    "veryhardpassword"
#define EIOT_IP_ADDRESS  "10.69.0.50"
#define EIOT_PORT        88

char* EIOT_NODE[] = {"N1S0", "N2S0", "N3S0", "N4S0", "N5S0"};

unsigned long interval = 5000; // the time we need to wait
unsigned long previousMillis = 0; // millis() returns an unsigned long.



void setup() {

  sensors1.begin();
  sensors1.getAddress(AnAddress, 0);
  sensors1.setResolution(AnAddress, TEMPERATURE_PRECISION);

  sensors2.begin();
  sensors2.getAddress(AnAddress, 0);
  sensors2.setResolution(AnAddress, TEMPERATURE_PRECISION);

  sensors3.begin();
  sensors3.getAddress(AnAddress, 0);
  sensors3.setResolution(AnAddress, TEMPERATURE_PRECISION);

  sensors4.begin();
  sensors4.getAddress(AnAddress, 0);
  sensors4.setResolution(AnAddress, TEMPERATURE_PRECISION);

  if (Ethernet.begin(mac) == 0) {
    while (true);
  }
  delay(1000);

  char uname[USER_PWD_LEN];
  String str = String(EIOT_USERNAME) + ":" + String(EIOT_PASSWORD);
  str.toCharArray(uname, USER_PWD_LEN);
  memset(unameenc, 0, sizeof(unameenc));
  base64_encode(unameenc, uname, strlen(uname));

}


void loop() {
  if ((unsigned long)(millis() - previousMillis) >= interval) {
    previousMillis = millis();

    sensors1.requestTemperatures();
    sensors2.requestTemperatures();
    sensors3.requestTemperatures();
    sensors4.requestTemperatures();
    float tempC;
    float tempF;
    float tempHvacIn;
    float tempHvacOut;

    tempF = -999;

    sensors1.getAddress(AnAddress, 0);
    tempC = sensors1.getTempC(AnAddress);
    tempF = DallasTemperature::toFahrenheit(tempC);
    tempHvacIn = tempF;
    if (client.connect(EIOT_IP_ADDRESS, EIOT_PORT)) {
      client.println("POST /Api/EasyIoT/Control/Module/Virtual/" + String(EIOT_NODE[0]) + "/ControlLevel/" + String(tempF) + " HTTP/1.1");
      client.println("Host: " + String(EIOT_IP_ADDRESS));
      client.println("Connection: close");
      client.println("Authorization: Basic " + String(unameenc) + " ");
      client.println("Content-Length: 0");
      client.println("");
      client.stop();
    }

    tempF = -999;

    sensors2.getAddress(AnAddress, 0);
    tempC = sensors2.getTempC(AnAddress);
    tempF = DallasTemperature::toFahrenheit(tempC);
    tempHvacOut = tempF;
    if (client.connect(EIOT_IP_ADDRESS, EIOT_PORT)) {
      client.println("POST /Api/EasyIoT/Control/Module/Virtual/" + String(EIOT_NODE[1]) + "/ControlLevel/" + String(tempF) + " HTTP/1.1");
      client.println("Host: " + String(EIOT_IP_ADDRESS));
      client.println("Connection: close");
      client.println("Authorization: Basic " + String(unameenc) + " ");
      client.println("Content-Length: 0");
      client.println("");
      client.stop();
    }

    tempF = -999;
    sensors3.getAddress(AnAddress, 0);
    tempC = sensors3.getTempC(AnAddress);
    tempF = DallasTemperature::toFahrenheit(tempC);
    if (client.connect(EIOT_IP_ADDRESS, EIOT_PORT)) {
      client.println("POST /Api/EasyIoT/Control/Module/Virtual/" + String(EIOT_NODE[2]) + "/ControlLevel/" + String(tempF) + " HTTP/1.1");
      client.println("Host: " + String(EIOT_IP_ADDRESS));
      client.println("Connection: close");
      client.println("Authorization: Basic " + String(unameenc) + " ");
      client.println("Content-Length: 0");
      client.println("");
      client.stop();
    }

    tempF = -999;
    sensors4.getAddress(AnAddress, 0);
    tempC = sensors4.getTempC(AnAddress);
    tempF = DallasTemperature::toFahrenheit(tempC);
    if (client.connect(EIOT_IP_ADDRESS, EIOT_PORT)) {
      client.println("POST /Api/EasyIoT/Control/Module/Virtual/" + String(EIOT_NODE[3]) + "/ControlLevel/" + String(tempF) + " HTTP/1.1");
      client.println("Host: " + String(EIOT_IP_ADDRESS));
      client.println("Connection: close");
      client.println("Authorization: Basic " + String(unameenc) + " ");
      client.println("Content-Length: 0");
      client.println("");
      client.stop();
    }

    if (client.connect(EIOT_IP_ADDRESS, EIOT_PORT)) {
      client.println("POST /Api/EasyIoT/Control/Module/Virtual/" + String(EIOT_NODE[4]) + "/ControlLevel/" + String(tempHvacOut - tempHvacIn) + " HTTP/1.1");
      client.println("Host: " + String(EIOT_IP_ADDRESS));
      client.println("Connection:close");
      client.println("Authorization: Basic " + String(unameenc) + " ");
      client.println("Content-Length: 0");
      client.println("");
      client.stop();
    }
  }
}