Tuesday, 23 April 2013

Temperature monitoring system V0.2

Here is version 0.2 of my Arduino project of Temperature Monitoring System.
It is based on a JY-MCU basic AVR board with ENC28J60 Ethernet interface and a 1-wire bus to provide a local web server with real time temperature readings of any number of 1-Wire thermometers. In addition, it can be configured to post the readings to COSM data feed.

This is running at my house for quite some time and is posting indoors and outdoors readings every 10 min to the following COSM feed: https://cosm.com/feeds/100389


The hardware description can be found in my other post.
To compile the project download the JY-MCU hardware profile for Arduino and the following libraries:

  1. EtherCard
  2. EEPROMex
  3. OneWire
  4. DallasTemperature
The code can be download from here: TempServer V0.2.ino

The server use DHCP to configure the TCP/IP stack and then start (led 7 remains on while setting up, then led 8 start to blink for normal operation).
The configuration link on the main page will bring up the COSM configuration page where you can configure the posting interval, the feed id and the COSM API key (to reset this configuration, hold switch 1 when the program starts).

In the next versions I am planning to enhance the following (not in a particular order):
  1. Enable to name each sensor for display in the list and for posting the date to COSM.
  2. Log up to 96 past readings in the device EEPROM (every 15 min for 24 hours).
  3. Show the min/max of the logged values.
  4. Show graph of the logged values.
  5. Use network time to make sure date logging and posting is done properly even when the device restarts frequently (currently, the posting of data is done after the device is constantly on for the selected posting time, that is, if the post of data is every 10 min, and the device restart every 7 min for some reason, no data will ever be posted).
  6. Improve the posting code to retry on HTTP errors (currently the code ignore the returned HTTP code and does not check for time out).
The main challenge to accomplish items 1 and 2 is the limitation of the EEPROM size (1KB), but with limiting the name to 15 characters and 10 bit per reading, I can support up to 10 devices on the bus.

Please let me know your thoughts (especially if you willing to give it go).

Friday, 29 March 2013

Back on-line with home made power regulator

Here is the MIC5209 with 2 capacitors to form my new 3.3v power regulator

Attached and soldered to the back side of the JY-MCY to power it

This provides 3.3v directly to the power select pin, so I must remove the power selection jumper

This will do for now (fingers crossed).
Back to programming...

Tuesday, 26 March 2013

Power failure of the 3.3V LDO

My web-server is down with a power failure, so no capturing of temperatures on the coldest spring in UK for years.

The 3.3V voltage regulator on the JY-MCU board is cocked (overloaded).
After investigating the details, looks like I was lucky it worked so far, for more than a month.


The JY-MCU board use the XC6202P332 by TOREX.
This voltage regulator can supply maximum output current of 150mA.
This is more than enough for powering the ATmega32 and LEDs.

However, the ENC28J60 needs up to 180mA to transmit data (120mA to receive).
This is way to much for the XC6202P332 to cope with.

I ordered a more powerful regulator from ICREL, a MIC5209-3.3YS that can source up to 500mA.

Stay tuned for the modified board with the new regulator.

Friday, 22 February 2013

12bit Result From DS18S20

During my development using the DallasTemperature library to build my temperature web server I noticed that there is no API to get the 12 bit word value of the temperature reading and all you can get is a float value in Celsius or Fahrenheit.
Although most of the time it make sense to get a float value to render, a float value use 32 bit and will reduce the amount of readings I can store in RAM or EEPROM by half (or even more if I use 3 bytes to store two 12 bit values).

Getting the 12 bit value for DS12B20, DS1822 or DS1225 is simple, just combine byte 0 (Temp LSB) and byte 1 (Temp MSB) of the device scratch pad:

int rawTemperature = (((int)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];

However, for the DS18S20, this will return the 9 bit result, and there is additional formula you need to apply to get the 12 bit result as specified in the documentation:

Resolutions greater than 9 bits can be calculated using the data from the temperature, COUNT REMAIN and COUNT PER °C registers in the scratchpad. Note that the COUNT PER °C register is hard-wired to 16 (10h). After reading the scratchpad, the TEMP_READ value is obtained by truncating the 0.5°C bit (bit 0) from the temperature data (see Figure 2). The extended resolution temperature can then be calculated using the following equation:

TEMPERATURE = TEMP_READ - 0.25 +
              (COUNT_PER_C - COUNT_REMAIN)/COUNT_PER_C
This was implemented in the library with the following statement:

return (float)(rawTemperature >> 1) - 0.25 + ((float)(scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) / (float)scratchPad[COUNT_PER_C]);

Apart from the performance impact of floating point calculations (see this), the result is a float number, and not the 12 bit I am looking for.

Let's implement it with integers to calculate the 1/16 of the Celsius degree value, this is the integer result we get from any other device.
  1. Truncating the 0.5 bit - use a simple & mask: raw & 0xFFFE
  2. Convert to 12 bit value (1/16 of °C) - shift left: (raw & 0xFFFE)<<3
  3. Subtracting 0.25 (1/4 °C of 1/16) or 0.25/0.0625 = 4: ((raw & 0xFFFE)<<3)-4
  4. Add the count (count per c - count remain), count per c is constant of 16, and no need to dived by 16 since we are calculating to the 1/16 of °C: +16 - COUNT_REMAIN
Full expression:
((rawTemperature & 0xFFFE) << 3) - 4 + 16 - scratchPad[COUNT_REMAIN]
We can simplify it to:
((rawTemperature & 0xFFFE) << 3) + 12 - scratchPad[COUNT_REMAIN]
The next step is to extend the library with a getTemp function that returns the raw 12 bit temperature value no matter what device you use:

// Construct the integer value
int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];

// For DS18S20, use COUNT_REMAIN to calculate the 12 bit value
if (deviceAddress[0] == DS18S20MODEL) rawTemperature = ((rawTemperature & 0xFFFE) << 3) + 12 - scratchPad[COUNT_REMAIN];

// Retunr a 12 bit value
return rawTemperature; 

Then getTempC is nothing but division by 16:

return (float)getTemp() * 0.0625;

The actual code use static utility functions like rawToCelsius, that one can use to perform the conversion later on after storing the 12 bit raw value.

I will post the updated library later on after some QA.

UPDATE: This is now merged into the DallasTemperature library. Thank you Miles.

Thursday, 24 January 2013

A basic temperature web server

With the help of jQuery Mobile , 1-Wire libraries and yet, another Ethernet library - EtherCard, a proper page is up and running.


Only 2 sensors at the moment, one inside and one outside as you can imagine.
Although the 1-Wire bus and the software can have many more, the other sensors I have across the house are too far from the router and I need to get a wire across.
The 1-Wire hardware is very simple: the bus is connected to an I/O pin with a pull-up resistor to VCC, the strong pull-up to allow temperature conversion with parasite power is achieved by setting the pin to output high by software to get more current into the bus.
The code use the DallasTemperature library by Miles Burton, which use the OneWire library to manage the bus itself.

The main challenge is to fit the code and the web content (html, css, js) on the small program memory the processor have (30KB), and to make sure each response does not exceed the TCP/IP buffer size I have allocated (1KB).
jQuery CDN to my rescue!
This has 2 advantages: a) I don't need to store the jQuery on the processor. b) the files are probably already got into my device cache when I browsed other mobile sites.

The HTML:

<!DOCTYPE html>
<html>
<head>
  <meta name='viewport' content='width=device-width, initial-scale=1' />
  <title>TempServer</title>
  <link rel='stylesheet' href='//code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css' />
  <link rel='stylesheet' href='main.css' />
  <script src='//code.jquery.com/jquery-1.8.2.min.js'></script>
  <script src='//code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js'></script>
  <script src='//stevenlevithan.com/assets/misc/date.format.js'></script>
  <script src='main.js'></script>
</head>
<body>
  <div id='main' data-role='page'>
    <div data-role='header' data-position='fixed'>
      <h3>Is it hot?</h3>
    </div>
    <div data-role='content'>
      <ul id='list' data-role='listview' data-inset='true'></ul>
      <p id='info'></p>
    </div>
  </div>
</body>
</html>

The Java Script (not minified):

$(document).ready(function () {
    reload();
});

function reload() {
    $.getJSON('list.json', function (data) {
        var items = [];

        $.each(data.list, function (key, val) {
            items.push('<li id="' + val.id + '"><a><h3>' + val.name +
            '</h3><p>' + val.id + '</p><p class="ui-li-aside">' + 
            val.val.toFixed(1) + ' &deg;C</p></a></li>');
        });

        $('#list').html(items.join('')).
            trigger('create').listview('refresh');

        var time = new Date(data.uptime);
        $('#info').html(
            'Uptime: ' + time.format('isoTime') +
            ' (' + data.free + ' bytes free)');
    });

    setTimeout(reload, 10000);
}

The CSS:

.ui-li-aside 
{
    font-weight:bold;
    font-size:xx-large;
}
#info
{
    margin-top:10px;
    text-align:center;
    font-size:small;
}

And the JSON response with the measures:

{
"list":[
{"id":"104938A501080057","name":"Sensor 1","val":16.188},
{"id":"28DA3E95040000CD","name":"Sensor 2","val":0.813}],
"uptime":57430902,
"free":620
}

You can get the full sketch in here: TempServer.ino

The hardware schematic is in my other post: The hardware is ready!

Now I want to utilize the 1KB EEPROM on the processor to store some temperature log and a proper name for each sensor, this will have to come with some more HTML pages to display a nice graph and edit the name for each sensor.
I hope I will have the space, the current code consume 17KB out of the 30KB available.

Thanks.

Thursday, 17 January 2013

Arduino Web Server with ENC28J60 + JY-MCU AVR

It took some time and several attempts to find an Ethernet library for ENC28J60 that works on the JY-MCU AVR board using ATmega32.

Hurray, my web server is responding!


The formal Arduino Ethernet Shield and the library to use it are built around the WIZnet W5100 Ethernet controller. The main advantage of the WIZnet W5100 over the Microchip ENC28J60 is the built in TCP/IP stack, that it, it has built in support for 4 sockets and protocols like TCP, UDP, ICMP, IPv4 ARP. While the ENC28J60 only support the physical and link (MAC) layers and the rest need to be implemented in software.

I first started with this library: https://github.com/turicas/Ethernet_ENC28J60
This library goal is to expose the same API as the standard Ethernet library that work with the W5100 and allow developers to choose between W5100 and ENC28J60 without any change to their sketch/code.
After trying the web server example and adding some debug code, I took a deeper look into the library code   to asses the list of limitations it has and how this affect the functionality.
I believe the main challenge for such library is to manage the 4 sockets and their data buffers with the limited memory available on the ATmega32 (2KB) compared to the 8KB buffer on the Ethernet chip.
Even if we split the Ethernet buffer in half (4KB RX + 4KB TX), we might get 4 different 1K packets, one for each socket, and we have no way to store them all in memory for processing. I think this is why the library is limited to one socket at a time, and in that case, what is the point in that library.

I then switched to a different library - EtherShild that is used by Nuelectronics, Andy's Life, and others.
Apparently, I was not the only one that went this road: http://arduino.cc/forum/index.php/topic,22635.0.html
At least now I have a library that works.

To make it work, I had to modify it a bit to use the SPI pin definitions from the pins_arduino.h file so the IDE will take the variant I wrote for the JY-MCU board. For some reason, both libraries assume only the Arduino standard boards instead of using the definitions in the pins_arduino.h or the just use the SPI library.

This library even comes with example to take temperature measurement from a 1-wire DS18B20 digital thermometer and show it on a web page.
I gave it a go, but had to modify it a bit to make it work with DS18S20 that use parasite power and provide readings differently:

  1. Add a strong pull-up  for 750ms between the convert temp instruction to the read instruction by setting the pin to output/high for 750ms.
  2. Change the conversion of the read to match the device resolution.


However, this sample can't handle more than one device on the bus and perform the reading during the respond to the page request and it takes about 750ms to return the page.

Next: use a proper one-wire library that can handle multiple devices on the bus and perform the reading asynchronously to web page requests.

Update: later on, when I continued my 1-wire temperature server development, I switched to another Ethernet library - EtherCard. It has a better API and support DHCP, NTP, UDP, as well as TCP client and server.

Saturday, 12 January 2013

The hardware is ready!

The two boards are connected using some cables and connectors I took out of an old PC.

Not yet with the 1-Wire bus (just a pull-up resistor to VCC).

Important: the ENC28J60 runs on 3.3V and the JY-MCU must be set to run on the same voltage (as you can see on the bottom left corner).

The connection use the standard SPI wires/pins (see previous post), reset signal and power (VCC, GND).

Next stop: web server software!


And the schematic:



IMPORTANT!
The 3.3V regulator on the JY-MCU is too small to power up the entire system.

Note for DS18B20: The device VDD pin must be grounded for operation in parasite power mode.