Thermostat (or, its happening again)

Share

This is just a quick post at the moment because the project isn’t done and I am distracted by other things… The thermostat for the central heater in my house became unreliable a week or two ago. My wife rang around and a new one from the manufacturer of the heater was going to be $450 AUD. So, it seemed obvious to make my own. I’ve just installed the 1.0 of it, with the board layout and manufacture being done by Doug once again.

Other people seem to lack a PCB manufacturing back neighbour. I highly recommend you acquire one if possible.

Share

Adding Open Flash Charts to my home monitoring

Share

As mentioned previously, I’ve built a home temperature monitoring system on top of the beer fridge controller that Doug and I built over Christmas. I later added a hygrometer and whole of house power measurement using a Current Cost. There is also a simple server which provides a UI for the system, which previously used PNG graphs generated from Google’s Chart Server API.

I was checking out Jon’s car hacking the other day, and was impressed by his flash graphs. However, as best as I could tell he’s using a commercial flash charting tool, whereas I wanted something open source. I dug around and found Open Flash Charts which was exactly what I wanted.

Why flash charts by the way? I wanted a richer presentation than I could get with PNG, and I am unaware of a way of doing interactive graphs with HTML5 apart from writing massive amounts of javascript. I look forward to someone educating me about an alternative, but until then I will view flash graphing as a punishment for all those overly smug iPad users out there.

So, first off here is an example of a flash chart. This one is power usage at my house from Friday, compared with Wednesday:


Open Flash Charts is actually really simple to use. First off there is some javascript to load the flash component:

    <script type="text/javascript" src="http://www.stillhq.com/local/swfobject.js"></script>
    <script type="text/javascript">>
    swfobject.embedSWF(
      "http://www.stillhq.com/local/open-flash-chart.swf", "2010_04_23_2010_04_21_Watts", "600", "400",
      "9.0.0", "expressInstall.swf",
      {"data-file":"http://www.stillhq.com/json/2010.04.23;2010.04.21/Watts"}
    );
    </script>
    

This javascript relies on a couple of resources being available on your server, which I’ve put into a directory called local. You find these files in the Open Flash Chart .zip file, although you could just snarf them from my server if you want.

Then all you need to do on the HTML side is include a div with the right id where you want the graph to go. For this post, that looks like this:

    <div id="2010_04_23_2010_04_21_Watts"></div>
    

Then you just need to write the JSON which represents the graphs content. That’s well documented on the Open Flash Charts site, but you can find the JSON for my graph at http://www.stillhq.com/json/2010.04.23;2010.04.21/Watts if you want to see it.

Share

Home power measurement

Share

I’ve been spending some quality time with a Current Cost CC128 and my existing home sensor network. So far I’ve discovered that I use quite a bit of power, and that I can remotely monitor how many times a day my wife makes a cup of tea. Some example data:

You can see that it was relatively cool compared with days a few weeks ago today. That’s more obvious in the graph showing the last two weeks though:

However, it was quite humid today:

Which is why we didn’t have the evaporative cooler on, just the fan. That doesn’t seem to really affect our power usage, which really needs more analysis:

The 500 watt minimum power draw makes me unhappy. You can see over a week it never goes away:

Share

Building a hygrometer with a HS1101

Share

The next sensor I wanted to add to my home was a set of hygrometers. Specifically I wanted an exterior one, and a matching interior one. This would be useful as we have evaporative cooling, and if the humidity level outside is already high, then it doesn’t make a lot of sense to put extra water into the air. Worse than that, it can also damage my books and make the house really clammy. So, adding some sensors was the first step in some form of alerting.

I picked up two HS1101s from ebay quite cheaply (about $4 each IIRC). These devices are capacitors whose capacitance varies proportionally with relative humidity. You also need to provide a temperature at the sensor to correct the value, although the correction is pretty minor so I guess you could skip this if you really wanted to cut costs. Given I have plenty of code for Dallas 1820s now, I just dropped one of those onto the board too.

I just used the circuit from the data sheet for my design, with a few simple tweaks (like the DS1820). Here’s my surprisingly unprofessional circuit diagram:

The DS1820 stuff that’s not on the data sheet is in red. When built, it looks like this (note the crazy amount of jumper wire):

This gives us temperature on a 1-Wire pin, and an oscillator on another pin which relates to the current humidity. You’ll notice that my circuit has some extra wires, that’s because I power down the 555 / HS1101 when I’m not taking a sample. I do this because Peter H. Anderson suggested that noise would be a problem otherwise. This circuit was actually quite hard to build and get working. There are a few reasons for that:

  • The large number of jumpers on the prototype PCB.
  • The lack of documentation from other arduino hackers (with the notable exception of the rather good Peter H. Anderson page).
  • The HS1101 data sheet forgets to mention that connecting pins 1 and 8 on the 555 is assumed knowledge.
  • The values for R1 and R2 vary depending on what model 555 you are using, and are crazily specific. For the LMC555 that I used, R1 is 1238K and R2 is 562K. I got close to these values, but not exact and it did seem to affect accuracy.
  • You must use a CMOS 555. That’s buried in a six word sentence in the middle of a page on the data sheet, and I didn’t notice it for a while. With a NMOS 555, you get effectively random numbers out of the circuit. Worse than that, CMOS 555s are actually a little hard to find, and I had to get mine from Farnell.
  • I attempted to calibrate with the government weather data from the next suburb over. Unfortunately, as best as I can tell, that data is wrong. It claims that its currently as humid here as it is in Cairns in the wet season, which I deny. Calibration is an ongoing issue for me, although I have some ideas on how to progress there. It might also not matter, as I am building an identical sensor for inside the house and as long as they are both equally wrong I can still detect the “turn off the water to the evap” state that I want to.

Here’s a comparison between my data for today and the weather service’s:

The code to run the HS1101 is relatively simple:

// Temperature and humidity sensor node. Based on the FridgeControlWeb project of mine
// as well as http://www.phanderson.com/picaxe/relhum_count.html

#include <enc28j60.h>
#include <etherShield.h>
#include <ip_arp_udp_tcp.h>
#include <ip_config.h>
#include <net.h>
#include <websrv_help_functions.h>
#include <avr/io.h>
#include <math.h>

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONEWIRE 3
#define HS1101DATA 5
#define HS1101POWER 7

int count_transitions(int ms);

// How long between measurement cycles
#define SLEEP_SEC 10

OneWire oneWire(ONEWIRE);
DallasTemperature sensors(&oneWire);

unsigned long last_checked = 0, this_check = 0;

// Web server setup
#define MYWWWPORT 80
#define BUFFER_SIZE 550
#define ERROR_500 "HTTP/1.0 500 Error\r\nContent-Type: text/html\r\n\r\n<h1>500 Error</h1>"

static uint8_t mymac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x25};
static uint8_t myip[4] = {192, 168, 1, 252};
static uint8_t buf[BUFFER_SIZE + 1];
char data[BUFFER_SIZE + 1];

// The ethernet shield
EtherShield es = EtherShield();

uint16_t http200ok(void)
{
  return(es.ES_fill_tcp_data_p(buf, 0, PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n"
                                            "Pragma: no-cache\r\n\r\n")));
}

// prepare the webpage by writing the data to the tcp send buffer
uint16_t print_webpage(uint8_t *buf)
{
  uint16_t plen;
  plen = http200ok();
  plen = es.ES_fill_tcp_data_p(buf, plen, PSTR("<html><head><title>Temperature sensor</title>"
                                               "</head><body><pre>"));
  plen = es.ES_fill_tcp_data(buf, plen, data);
  plen = es.ES_fill_tcp_data_p(buf, plen, PSTR("</pre></body></html>"));

  return(plen);
}

// Float support is hard on arduinos
// (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1164927646) with tweaks
char *ftoa(char *a, double f, int precision)
{
  long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
  char *ret = a;
  long heiltal = (long)f;

  itoa(heiltal, a, 10);
  while (*a != '\0') a++;
  *a++ = '.';
  long desimal = abs((long)((f - heiltal) * p[precision]));
  itoa(desimal, a, 10);
  return ret;
}

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

int count_transitions(int ms)
{
     // configure Counter 1
     cbi(TCCR1A, WGM11);
     cbi(TCCR1A, WGM10);

     cbi(TCCR1B, WGM12);  // WGM12::WGM10 000 - Normal mode

     sbi(TCCR1B, CS12);   // CS12::CS10 111 - External clock, count on rising edge.
     sbi(TCCR1B, CS11);
     sbi(TCCR1B, CS10);

     TCNT1 = 0x0000;      // note that TCNT1 is 16-bits
     delay(ms);
     // not sure if should turn off the counter
     return(TCNT1);
}

void setup()   {
  // initialize the digital pin as an output:
  Serial.begin(9600);
  sensors.begin();

  es.ES_enc28j60Init(mymac);
  es.ES_init_ip_arp_udp_tcp(mymac, myip, MYWWWPORT);

  pinMode(HS1101POWER, OUTPUT);
}

void loop()
{
  int i, j, data_inset;
  char float_conv[10];
  float t;
  DeviceAddress addr;
  uint16_t plen, dat_p;
  float relhum_raw, relhum_corrected;
  int relhum_count;

  // Read temperatures, we dump the state to a buffer so we can serve it
  this_check = millis();
  if(this_check > last_checked + SLEEP_SEC * 1000)
  {
    data_inset = 0;
    sensors.requestTemperatures();
    sprintf(data + data_inset, "Sensor count: %d\n",
            sensors.getDeviceCount());
    data_inset = strlen(data);

    for(i = 0; i < sensors.getDeviceCount(); i++)
    {
      t = sensors.getTempCByIndex(i);
      sensors.getAddress(addr, i);

      data[data_inset++] = 't';
      for (j = 0; j < 8; j++)
      {
        sprintf(data + data_inset, "%02x", addr[j]);
        data_inset += 2;
      }

      sprintf(data + data_inset, ": %s\n", ftoa(float_conv, t, 2));
      data_inset = strlen(data);
    }

    // Power up the 555 / HS1101, and take a measurement. Power it down again afterwards.
    digitalWrite(HS1101POWER, HIGH);
    delay(500);
    relhum_count = count_transitions(1000);
    digitalWrite(HS1101POWER, LOW);
    sprintf(data + data_inset, "HS1101 cycles: %d\n", relhum_count);
    data_inset = strlen(data);

    relhum_raw = 557.7 - 0.0759 * relhum_count;
    sprintf(data + data_inset, "Raw humidity: %s\n", ftoa(float_conv, relhum_raw, 2));
    data_inset = strlen(data);

    relhum_corrected = (1.0 + 0.001 * (t - 25.00)) * relhum_raw;
    sprintf(data + data_inset, "Corrected humidity: %s\n",
            ftoa(float_conv, relhum_corrected, 2));

    Serial.println(data);

    last_checked = this_check;
  }

  // Handle network packets
  dat_p = es.ES_packetloop_icmp_tcp(buf, es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
  if(dat_p != 0)
  {
    if (strncmp("GET ", (char *)&(buf[dat_p]), 4) != 0){
      // head, post and other methods:
      dat_p = http200ok();
      dat_p = es.ES_fill_tcp_data_p(buf, dat_p, PSTR("<h1>200 OK</h1>"));
    }

    // just one web page in the "root directory" of the web server
    else if (strncmp("/ ", (char *)&(buf[dat_p+4]), 2) == 0){
      dat_p = print_webpage(buf);
      Serial.println("Served temperature web page");
    }

    else{
      dat_p = es.ES_fill_tcp_data_p(buf, 0, PSTR(ERROR_500));
    }

    es.ES_www_server_reply(buf, dat_p);
  }
}

As with previous circuits, I’m going to have to thank Doug for hints and tips along the way, as well as letting me steal his entire collection of 8 pin DIP sockets.

Share

The Beer Fridge saga continues

Share

Since the last update on the beer fridge, we’ve had to do some murdering of the original PCB to get it to fit in a case. In addition, we’d failed to take into account the startup power draw for the compressor (5 amps), and had to upgrade the relay we’re using from a 3 amp solid state relay. Luckily Doug had the beefier relay just sitting around in his shed. That means we’ve lost our opto-isolation because the new relay is a simple mechanical one, but we have a relay coil doing the same thing now. A new PCB will make the world a lot neater, which will be nice. Oh, we’ve also been mentioned on Hack a Day, which has generated some interesting comments on their site.

I’ve observed that sometimes the relay doesn’t turn on, even though the arduino thinks it has done so. An example can be seen here:

(Note that graph is a Google chart server image, generated by a simple visualization program I wrote in python. If you’re that way inclined, the visualization software is in my public SVN repository).

At first we thought this was a software problem with comparing ints to floats, but it continued to happen even after we fixed that bug. You can see in the graph above that during testing the compressor was “turned on” (i.e. the arduino thinks it has activated the relay), but the temperature continued to rise. A visual inspection showed that in fact the relay hadn’t turned the compressor on, and power cycling the controller (and therefore the relay) didn’t help. However, the simple expedient of hitting the relay with a screw driver handle fixed the problem, which made me think that Doug had given me a bodgy relay. This got me thinking about if it would be possible to unstick a relay in software though — its pretty easy to detect this case (temperature continues to rise despite the compressor being). I’m thinking that perhaps if you cycled the inputs over and over you might be able to get the relay to unstick.

Detecting this case in software might be generally useful anyway though… Ignoring stuck relays, it would also tell you when someone had left the door open for example. It would be nice to detect this case and then give up on the compressor for a few minutes before trying again. I wrote a quick implementation of this “door open detection” and gave it a try, but I’ve now given up on it as being too fiddly. I found problems such as when the outside world is heating up rapidly (summer mornings for example), the compressor can’t make a big enough difference to the internal temperature of the fridge, but you still really want the compressor on because something is better than nothing.

In the end it turned out the problem with the relay was that the arduino wasn’t providing enough current to pull the relay contact in reliably. This was fixed with the addition of a transistor to the board, which is yet another thing to add to the next PCB.

One of the big advantages of a microprocessor based custom thermostat is that I can implement new features that wouldn’t normally be present in a fridge. Some of these features might turn out to be bad ideas, but I view the beer fridge as a bit of an experimentation platform.

Since my extra Dallas 1820s have arrived from ebay, I also added a sensor inside the freezer. This is interesting because the freezer isn’t getting anywhere near the FDA recommended temperature (-17.7 Celsius). I tweaked the code yet again to turn on the compressor if either compartment is over temperature, but this resulted in the fridge running much too cold — it was close to freezing point in fact. I think this is probably a hardware problem with the freezer, and given its a beer fridge I’ve just written “this is not the freezer you are looking for” on the door and gone back to only monitoring the temperature of the fridge compartment. Here’s a graph of my experiments with the freezer yesterday:

Another recent software tweak is a start up delay for the compressor in order to reduce the risk of back pressure damage to the compressor. Thanks Murray! This comes with yet another LED which indicates that the compressor is currently disabled.

I think this project is nearly ready to start showing people the code. The code is also getting big enough that cutting and pasting it into blog posts is starting to get annoying. So, here are a few links:

  • The code for the arduino. This should be self explanatory, except for saying that we’re using a nuelectronics.com ethernet shield, not the standard one.
  • The visualization software. You want temperature.py to scrape the web server on the arduino and push stuff into a MySQL database, and then server.py is a simple python web server that provides the UI for visualization. The UI isn’t very good at the moment, but I shall improve it soon.
Share

Beer fridge controller 0.3

Share

Last night Doug made up the first cut of the PCB for the beer fridge controller mentioned in previous posts, and we fitted the arduino to it. There wasn’t much in the way of software changes, apart from changing the pin that the compressor runs on.

You can see here that we’ve mounted both the arduino and the Ethernet shield onto the PCB — this is just temporary until we get the PCB right. The black rectangle at the front right is a 240 volt capable relay, and the thing behind it is a 240 volt transformer which is capable of powering all the electronics on the boards. In the final PCB we wont need the arduino at all — just the Ethernet shield and the atmega 328 from the arduino. However, that didn’t work out this time around because of problems getting the Ethernet socket to fit nicely. Its clearer on this picture of the other side of the board:

See how we had to cut a hole in the PCB for the socket? That took out some of the pin holes for the atmega, and a few tracks. Its not a big problem because we’re going to iterate a little on the PCB design (and by “we”, I mean Doug). You can also see the perspex shield, which covers all the 240 volt rails, which is a nice touch. This version of the hardware is now sitting out on top of the beer fridge, and I wrote some simple scraping and visualization software for the temperature values I am seeing from the embedded hardware. You can see here the temperatures out the back of my house for this afternoon:

As I’ve mentioned before, the hardware and software can handle more than one temperature probe, so the ultimate plan is to take the opportunity to place a bunch of these probes around the house and see what interesting data we end up with.

Share

Beer fridge controller 0.2

Share

Further to yesterday’s post about the beer fridge thermostat replacement, I’ve been hacking on ethernet support for the controller. This is handy because I’d like to log the temperature and compressor state over the network, because I’m hoping that can be used to make calculations about the thermal mass of the contents of the fridge, and therefore derive how much beer is actually in the fridge at any given time.

Because the controller also supports more than one temperature probe, I’ll also add more 1-Wire temperature sensors around the house so I can determine important things like if its hot in the outside world.

The code is currently experiencing some bloat in the binary size, mainly because the ethernet library and the sprintf implementation are quite large. I’ll have to think more about that. Here’s the current code:

    #include <enc28j60.h>
    #include <etherShield.h>
    #include <ip_arp_udp_tcp.h>
    #include <ip_config.h>
    #include <net.h>
    #include <websrv_help_functions.h>
    
    #include <OneWire.h>
    #include <DallasTemperature.h>
    
    // Temperature sensor and compressor setup
    #define COMPRESSOR 9
    #define ONEWIRE 3
    
    #define HIGHTEMP 4
    #define LOWTEMP 3.6
    
    // 220L Kelvinator is 85 watts
    #define COMPRESSOR_WATTAGE 85.0
    
    #define SLEEP_SEC 10
    
    OneWire oneWire(ONEWIRE);
    DallasTemperature sensors(&oneWire);
    
    unsigned long runtime = 0, chilltime = 0, last_checked = 0, this_check = 0;
    uint8_t compressor = LOW;
    
    // Web server setup
    #define MYWWWPORT 80
    #define BUFFER_SIZE 550
    #define ERROR_500 "HTTP/1.0 500 Error\r\nContent-Type: text/html\r\n\r\n<h1>500 Error</h1>"
    
    static uint8_t mymac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x24};
    static uint8_t myip[4] = {192, 168, 1, 253};
    static uint8_t buf[BUFFER_SIZE + 1];
    char data[BUFFER_SIZE + 1];
    
    // The ethernet shield
    EtherShield es = EtherShield();
    
    uint16_t http200ok(void)
    {
      return(es.ES_fill_tcp_data_p(buf, 0, PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n"
                                                "Pragma: no-cache\r\n\r\n")));
    }
    
    // prepare the webpage by writing the data to the tcp send buffer
    uint16_t print_webpage(uint8_t *buf)
    {
      uint16_t plen;
      plen = http200ok();
      plen = es.ES_fill_tcp_data_p(buf, plen, PSTR("<html><head><title>Temperature sensor</title>"
                                                   "</head><body><pre>"));
      plen = es.ES_fill_tcp_data(buf, plen, data);
      plen = es.ES_fill_tcp_data_p(buf, plen, PSTR("</pre></body></html>"));
    
      return(plen);
    }
    
    // Float support is hard on arduinos
    // (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1164927646)
    char *ftoa(char *a, double f, int precision)
    {
      long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
    
      char *ret = a;
      long heiltal = (long)f;
      itoa(heiltal, a, 10);
      while (*a != '\0') a++;
      *a++ = '.';
      long desimal = abs((long)((f - heiltal) * p[precision]));
      itoa(desimal, a, 10);
      return ret;
    }
    
    void setup()   {
      // initialize the digital pin as an output:
      pinMode(COMPRESSOR, OUTPUT);
      Serial.begin(9600);
      sensors.begin();
    
      es.ES_enc28j60Init(mymac);
      es.ES_init_ip_arp_udp_tcp(mymac, myip, MYWWWPORT);
    }
    
    void loop()
    {
      int i, j, data_inset, delta;
      char float_conv[10];
      float t;
      DeviceAddress addr;
      uint16_t plen, dat_p;
    
      // Read temperatures, we dump the state to a buffer so we can serve it
      this_check = millis();
      if(this_check > last_checked + SLEEP_SEC * 1000)
      {
        delta = int((this_check - last_checked) / 1000);
        runtime += delta;
        if(compressor == HIGH) chilltime += delta;
    
        data_inset = 0;
        sensors.requestTemperatures();
        for(i = 0; i < sensors.getDeviceCount(); i++)
        {
          t = sensors.getTempCByIndex(i);
          sensors.getAddress(addr, i);
    
          for (j = 0; j < 8; j++)
          {
            sprintf(data + data_inset, "%02x", addr[j]);
            data_inset += 2;
          }
          sprintf(data + data_inset, ": %s\n", ftoa(float_conv, t, 2));
          data_inset = strlen(data);
        }
    
        // Control compressor
        if(t > HIGHTEMP) compressor = HIGH;
        else if(t < LOWTEMP) compressor = LOW;
        digitalWrite(COMPRESSOR, compressor);
    
        // Status dump
        sprintf(data + data_inset,
                "Compressor: %s\nRuntime: %lu\nChilltime: %lu\n%% chill: %d\nWatt hours: %d\n",
                compressor == HIGH ? "on" : "off", runtime, chilltime,
    	    int(chilltime * 100.0 / runtime),
                int(chilltime * COMPRESSOR_WATTAGE / 3600));
        Serial.println(data);
        last_checked = this_check;
      }
    
      // Handle network packets
      dat_p = es.ES_packetloop_icmp_tcp(buf, es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
      if(dat_p != 0)
      {
        if (strncmp("GET ", (char *)&(buf[dat_p]), 4) != 0){
          // head, post and other methods:
          dat_p = http200ok();
          dat_p = es.ES_fill_tcp_data_p(buf, dat_p, PSTR("<h1>200 OK</h1>"));
        }
    
        // just one web page in the "root directory" of the web server
        else if (strncmp("/ ", (char *)&(buf[dat_p+4]), 2) == 0){
          dat_p = print_webpage(buf);
          Serial.println("Served temperature web page");
        }
    
        else{
          dat_p = es.ES_fill_tcp_data_p(buf, 0, PSTR(ERROR_500));
        }
    
        es.ES_www_server_reply(buf, dat_p);
      }
    }
    
Share

Beer fridge controller 0.1

Share

On the weekend I picked up a 220 liter beer fridge for $20. Its in really good condition (ignoring some minor rust in the freezer section), and the only real problem with it is that the thermostat doesn’t work leaving the compressor on the whole time. Doug suggested that instead of just buying a new thermostat, we should build an arduino fridge controller.

I’m not really a hardware guy, but once Doug had pointed me at the Dallas 1820 1-Wire temperature sensor, and lent me some resistors, it was pretty easy to pull the software side together. Note that this version doesn’t actually do any of the compressor control — it simulates that by turning a LED on. The compressor stuff has been delegated to Doug and will be mentioned later.

You can see that the circuit is in fact really simple. There is a LED to simulate the compressor (with a resistor), and then the 1-Wire temperature sensor (with another resistor). The code is pretty simple too. Here’s my latest fancy version:

    #include <OneWire.h>
    #include <DallasTemperature.h>
    
    #define COMPRESSOR 13
    #define ONEWIRE 2
    
    #define HIGHTEMP 4
    #define LOWTEMP 3
    
    #define SLEEP_SEC 10
    
    // 220L Kelvinator is 85 watts
    #define COMPRESSOR_WATTAGE 85.0
    
    OneWire oneWire(ONEWIRE);
    DallasTemperature sensors(&oneWire);
    
    unsigned long runtime = 0, chilltime = 0;
    boolean compressor = false;
    
    void setup()   {
      // initialize the digital pin as an output:
      pinMode(COMPRESSOR, OUTPUT);
      Serial.begin(9600);
      sensors.begin();
    }
    
    void loop()
    {
      int i;
      float temperature;
      DeviceAddress addr;
    
      sensors.requestTemperatures();
    
      for(i = 0; i < sensors.getDeviceCount(); i++)
      {
        temperature = sensors.getTempCByIndex(1);
        Serial.print("Current temperature at ");
        sensors.getAddress(addr, 1);
        printAddress(addr);
        Serial.print(" is: ");
        Serial.println(temperature);
      }
    
      if(temperature > HIGHTEMP)
      {
        digitalWrite(COMPRESSOR, HIGH);
        if(!compressor)
        {
          Serial.println("Compressor on");
          compressor = true;
        }
      }
      else if(temperature < LOWTEMP)
      {
        digitalWrite(COMPRESSOR, LOW);
        if(compressor)
        {
          Serial.println("Compressor off");
          compressor = false;
        }
      }
    
      delay(SLEEP_SEC * 1000);
      runtime += SLEEP_SEC;
      if(compressor) chilltime += SLEEP_SEC;
    
      Serial.print("Efficiency: Total runtime = ");
      Serial.print(runtime);
      Serial.print(", Chill time = ");
      Serial.print(chilltime);
      Serial.print(" (");
      Serial.print(chilltime * 100 / runtime);
      Serial.print("%, ");
    
      // The compressor wattage is consumption for an hour, so work
      // out how many hours we've been operating for. Then divide by
      // 1000 to get kWh.
      Serial.print(chilltime * COMPRESSOR_WATTAGE / 3600 / 1000);
      Serial.println("kWh)");
    
      Serial.println("");
    }
    
    // Function to print a one wire device address
    void printAddress(DeviceAddress deviceAddress)
    {
      for (uint8_t i = 0; i < 8; i++)
      {
        // zero pad the address if necessary
        if (deviceAddress[i] < 16) Serial.print("0");
        Serial.print(deviceAddress[i], HEX);
      }
    }
    

The code uses the Miles Burton 1-Wire library, which was easy to use once you figure out his example code has an impossible number for the pin. The code outputs information like this over serial:

    Current temperature at 10FA473500000037 is: 21.62
    Efficiency: Total runtime = 1780, Chill time = 1770 (99%, 0.04kWh)
    

That's with it on my desk where the "compressor" is permanently "on". I'll let you know how we go with further versions.

Share

Phoenix for business

Share

You know that somewhere has to be special when people tell you that the good points of a place are that land is cheap, it’s geologically stable, and there are lots of banks. Well, that’s Phoenix and the bit they’re not mentioning is that you’re in a desert. It’s warm. Really warm. Oh, and dry.

It’s a nice spring afternoon as I write this, and it’s 108 Fahrenheit (42 Celsius). Fortunately that seems to be about as hot as it gets here.

Phoenix is so far a nice city, although I have only haven’t seen much (I’m here on business). Not very built up, and quite spread out. Some parts of town I drove through also have billboards in Spanish only.

Share