Not content with the single room temperature I can obtain from my Heatmiser, I have started work on a solution using the DS18b20 one-wire temperature sensors.
These are slightly more expensive than analogue sensors, but they are pre-calibrated and in my opinion much nicer to use.
I bought a pack of 10 from China for under US$9 which is amazing value compared to local options.
Using the simple, but extremely useful details at http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html I was up and running in no time at all. This site appealed over others as it specifically tells you how to identify each DS18b20 you have on your network, and get it's address - something which most other tutorials miss, and instead just return all sensors, which is useless if you wish to monitor specific ones (and have multiple on the same network).
I didn't have any 4.7K resistors to hand, so paralleled up a couple of 10k's which seem to work fine - infact I think even a 10k would work over short distances from my testing. I've not bothered with parasitic power.
With this example up and running, I decided to dig out my poor-mans ethernet controller again, and see if I could make it do anything interesting. With a little head-scratching and some could-be-improved code, I have a little web server running on an Arduino now which reports the current temperature.
Due to the fact I can't work out out to pass floats with PSTR I ended up multiplying the temperature by 100 to get into an int and then casting the float to an int. If anyone has a better suggestion I'm all ears.
The code is pretty straight forward, and 90% of it is from the jcw library.
// Present a "Will be back soon web page", as stand-in webserver.
// 2011-01-30 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
#include <EtherCard.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define STATIC 0 // set to 1 to disable DHCP (adjust myip/gwip values below)
#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer = { 0x28, 0xE8, 0x94, 0x3C, 0x02, 0x00, 0x00, 0x2B };
#if STATIC
// ethernet interface ip address
static byte myip[] = { 192,168,1,200 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
#endif
// ethernet mac address - must be unique on your network
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[500]; // tcp/ip send and receive buffer
void setup(){
Serial.begin(57600);
Serial.println("\n[backSoon]");
sensors.begin();
sensors.setResolution(insideThermometer, 10);
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
#if STATIC
ether.staticSetup(myip, gwip);
#else
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
#endif
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
}
//byte Ethernet::buffer[500];
BufferFiller bfill;
static word homePage() {
sensors.requestTemperatures();
float tempC = sensors.getTempC(insideThermometer)*100;
Serial.println(tempC);
int tempCi = (int)tempC;
bfill = ether.tcpOffset();
bfill.emit_p(PSTR(
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"Pragma: no-cache\r\n"
"\r\n"
"<title>RBBB server</title>"
"<h1>Temp: $D</h1>"),
tempCi);
return bfill.position();
}
void printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
if (tempC == -127.00) {
Serial.print("Error getting temperature");
} else {
Serial.print(tempC);
}
}
void loop(){
Serial.print("Getting temperatures...\n\r");
sensors.requestTemperatures();
Serial.print("Inside temperature is: ");
printTemperature(insideThermometer);
Serial.print("\n\r");
word len = ether.packetReceive();
word pos = ether.packetLoop(len);
if (pos) // check if valid tcp data is received
ether.httpServerReply(homePage()); // send web page data
}
Following my experiments I decided to approach this from a different way. I now run a webclient on the Arduino which fetches a PHP page every so often with a bunch of temperatures in the query string. The code for this is below:
#include <EtherCard.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define STATIC 0 // set to 1 to disable DHCP (adjust myip/gwip values below)
#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress Office = { 0x28, 0xE8, 0x94, 0x3C, 0x02, 0x00, 0x00, 0x2B };
DeviceAddress Outside = { 0x28, 0xE8, 0x94, 0x3C, 0x02, 0x00, 0x00, 0x2B };
DeviceAddress Master = { 0x28, 0xE8, 0x94, 0x3C, 0x02, 0x00, 0x00, 0x2B };
DeviceAddress Howard = { 0x28, 0xE8, 0x94, 0x3C, 0x02, 0x00, 0x00, 0x2B };
byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
char website[] PROGMEM = "<hostname of remote server>";
uint32_t timer;
byte Ethernet::buffer[700];
Stash stash;
char buffer[25];
void setup ()
{
Serial.begin(57600);
Serial.println("\n[DS18b20 HTTP Updater]");
sensors.begin();
sensors.setResolution(Office, 12);
sensors.setResolution(Outside, 12);
sensors.setResolution(Master, 12);
sensors.setResolution(Howard, 12);
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
Serial.println("Please wait. Resolving DNS...");
if (!ether.dnsLookup(website))
Serial.println("DNS failed");
ether.printIp("DNS Resolved...Server IP: ", ether.hisip);
}
void loop () {
ether.packetLoop(ether.packetReceive());
if (millis() > timer)
{
timer = millis() + 30000;
sensors.requestTemperatures();
float tempOffice = sensors.getTempC(Office);
float tempOutside = sensors.getTempC(Outside);
float tempMaster = sensors.getTempC(Master);
float tempHoward = sensors.getTempC(Howard);
updateTemp(tempOffice, tempOutside, tempMaster, tempHoward);
}
}
static void updateTemp ( float tempOffice, float tempOutside, float tempMaster, float tempHoward )
{
byte sd = stash.create();
stash.print("GET /heatmiser/update_temp.php?");
stash.print("Office=");
stash.print(tempOffice);
stash.print("&Outside=");
stash.print(tempOutside);
stash.print("&Master=");
stash.print(tempMaster);
stash.print("&Howard=");
stash.print(tempHoward);
stash.print(" HTTP/1.0 \r\n");
stash.println("\r\n");
stash.save();
Stash::prepare(PSTR("$H"), sd);
ether.tcpSend();
}
There is some PHP on my server which decodes the query string and adds the data to the database. Currently each of the 4 sensors actually reference the same ds19b20 but that's just for testing, I have a bag full of them I plan to add over the coming days around the house.
Downside to this code is that it requires each sensor to be hardcoded, but that gives them friendly names rather than just index ID's which would mean you didn't know which sensor was which.