First shot at a tutorial. It helps to document the thought processes!
Home energy and environment monitoring using an Arduino Mega board and AsyncLabs WiFi Shield 1.0
An Arduino Mega board is used:
To allow extra interrupts for counts
To provide extra digital IO's for 'future' expansion
Use of the I2C bus to interface to sensors.
Arduino mega and Asynclabs WiFi Shield
The WiFi Shield 1.0 is not a direct fit to the Mega board, it was designed for the Duemilanove and a few mods need to be made to get the shield working with it. This is because the Mega and Duemilanove boards shift things like the SPI, Interrupt and the I2C bus pins about. Rather than using the pin bending method suggested on the asynclabs forum I have simply reallocated pins 10,11 and 12 and 13 as inputs and crosswired them to matching pins on the mega that implement the SPI bus ie pins 53,52,51 and 50 ( SS, SCK, MOSI and MISO ) on the mega are wired across to pins 10,13, 12 and 11 respectively. A few small changes in the Arduino libraries and you are up and running with the WiFi ( see resource 2 )
A MAX 393 is used to multiplex the I2C bus to both a sensortechnics CSDX barometric pressure sensor
http://www.sensortechnics.com/download/csdx-632.pdf and an temperature and humidity sensor from DigiPico http://www.farnell.com/datasheets/484571.pdf both of which use I2C bus Address 0x78. The Max 393 http://datasheets.maxim-ic.com/en/ds/MAX391-MAX393.pdf is basically 4 single pole analog switches on a chip 2 no and 2 nc contacts. Wiring it up as 2
dpst switches allows the I2C bus to be directed to either one device or the other ( or neither ). Digital outputs 48 and 49 control the switches
< CCT Diagram here >
3 4N25 Opto Isolators are used to interface to external devices. Both to isolate any potentially harmful voltages applied or induced and to provide a significant load ( 10ma ) to get around the noisy environment.
The electric meter I fitted has a transistor output and produces 1 pulse per 0.001 kW/Hr = 1 pulse per watt hour
The gas meter ( A6 Model ) is widely fitted in UK homes and takes a stock standard door reed switch taped just about anywhere near the digits to produce 1 transition per 10 dm3 ( 1 litre of gas )
The water meter is an industry standard and has a reed contact outputting 1 transition per litre.
Electricity count is low going edge triggered and increments on interrupt 1
Gas count is is low going edge triggered and increments on interrupt 4
Water count is low going edge triggered and increments on interrupt 5
The meter counts are simple increments and flow rates must be derived by calculating units used between readings. In this mode the Arduino is acting like 3 simple consumption meters. Reading the device at any time is like sticking your head in the outdoor box and 'reading the meter'
Mains status is monitored by a digital input monitoring the battery charger output.
Visible Outdoor Light and IR levels are read on the I2C bus from a Taos device http://www.farnell.com/datasheets/49661.pdf
Future expansions might include interface to an SMS modem to allow interactive control of attached devices.
#include <WiServer.h>
#include <Wire.h>
#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2
#define select_press 48 // High to select I2C bus to pressure sensor
#define select_temp 49 // High to select I2C bus to temp/humidity sensor
// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {<YOUR REQUIRED IP ADDRESS>}; // IP address of WiShield
unsigned char gateway_ip[] = {<YOUR NETWORK GATEWAY ADDRESS>}; // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network
const prog_char ssid[] PROGMEM = {"<YOUR AP SSID GOES HERE>"}; // max 32 bytes
// Set this variable according to your WiFi setup.
unsigned char security_type = 1; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2
// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"<YOUR PASSPHRASE HERE>"}; // max 64 characters
// WEP 128-bit HEX keys
prog_uchar wep_keys[] PROGMEM = { 0x9E,0x6A,0xF4,0x23,0xE6,0x51,0xD3,0xD2,0x06,0x85,0x92,0x13,0x9C, // Key 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Key 3
};
// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;
unsigned char ssid_len;
unsigned char security_passphrase_len;
float hum = 0;
float tmp = 0;
float press = 0;
unsigned int light = 0;
unsigned int ir = 0;
long water = 0;
long elec = 0;
long gas = 0;
int mains;
unsigned char StID[7];
float t;
unsigned int i = 0;
unsigned int r = 0;
int z;
unsigned long ctr =0;
byte z_val_l, z_val_h, x_val_l, x_val_h, y_val_l, y_val_h;
int z_val, x_val, y_val;
// End of wireless configuration parameters ----------------------------------------
// This is our page serving function that generates web pages
boolean sendPage(char* URL)
{
// Check if the requested URL matches "/"
if (strcmp(URL, "/") == 0)
{
WiServer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
WiServer.println("<eeml>\n<environment>");
WiServer.print("<data id=\"0\">\n<value>");
WiServer.print(elec);
WiServer.println("</value>\n</data>");
WiServer.print("<data id=\"1\">\n<value>");
WiServer.print(gas);
WiServer.println("</value>\n</data>");
WiServer.print("<data id=\"2\">\n<value>");
WiServer.print(water);
WiServer.println("</value>\n</data>");
WiServer.print("<data id=\"3\">\n<value>");
WiServer.print(tmp);
WiServer.println("</value>\n</data>");
WiServer.print("<data id=\"4\">\n<value>");
WiServer.print(hum);
WiServer.println("</value>\n</data>");
WiServer.print("<data id=\"5\">\n<value>");
WiServer.print(press);
WiServer.println("</value>\n</data>");
WiServer.print("<data id=\"6\">\n<value>");
WiServer.print(light);
WiServer.println("</value>\n</data>");
WiServer.print("<data id=\"7\">\n<value>");
WiServer.print(ir);
WiServer.println("</value>\n</data>");
WiServer.print("<data id=\"8\">\n<value>");
WiServer.print(mains);
WiServer.println("</value>\n</data>");
WiServer.println("</environment>\n</eeml>");
return true;
}
// URL not found
return false;
}
void setup()
{
pinMode(13,OUTPUT); // led output
pinMode(19,INPUT); // interrupt pins
pinMode(18,INPUT);
pinMode(3,INPUT);
digitalWrite(19,HIGH); // Pull ups
digitalWrite(18,HIGH);
digitalWrite(3,HIGH);
pinMode(9,INPUT); // Mga / demilove conversion for wifi shield
pinMode(10,INPUT);
pinMode(11,INPUT);
pinMode(12,INPUT);
pinMode(select_press,OUTPUT); // Pressure / temp bus selectors
pinMode(select_temp,OUTPUT);
digitalWrite(select_press,LOW);
digitalWrite(select_temp,LOW);
// Initialize WiServer and have it use the sendMyPage function to serve pages
WiServer.init(sendPage);
WiServer.enableVerboseMode(true);
Wire.begin();
attachInterrupt(1,incElec,FALLING);
attachInterrupt(4,incGas,FALLING);
attachInterrupt(5,incWater,FALLING);
Serial.begin(115200);
i=0;
}
void loop()
{
// Run WiServer
WiServer.server_task();
// Roughly every minute to read the sensors
if (i++ > 50000 && ~WiServer.sendInProgress())
{
readLightIr();
// set mux to read the pressure sensor
digitalWrite(select_press,LOW);
digitalWrite(select_temp,HIGH);
readTempHum();
digitalWrite(select_temp,LOW);
digitalWrite(select_press,HIGH);
readPressure();
digitalWrite(select_press,LOW);
readMains();
i=0;
}
}
void readPressure()
{
Wire.requestFrom(0x78, 2);
while(Wire.available())
{
x_val = Wire.receive();
x_val *= 256;
x_val += Wire.receive();
x_val -= 400;
}
t = (float)x_val;
t /= 10.666;
t +=795;
press = t;
}
void readTempHum()
{
// set mux to read temp and humidity
Wire.requestFrom(0x78, 4);
while(Wire.available())
{
x_val = Wire.receive();
x_val *= 256;
x_val += Wire.receive();
y_val = Wire.receive();
y_val *= 256;
y_val += Wire.receive();
}
hum = (float) x_val / 327.68;
tmp = ((float) y_val / 198.593) -40;
}
void readLightIr()
{
// Placeholder till the sensor gets here :)
Wire.requestFrom(0x39, 2);
light = 32768;
Wire.requestFrom(0x3A, 2);
ir = 32768;
}
void readMains()
{
// read the mains hardware and set the mains state - placeholder
mains = 1;
}
void incWater() // Interrupt driven
{
water++;
}
void incElec() // Interrupt driven
{
elec++;
}
void incGas() // Interrupt driven
{
gas++;
}
RESOURCES
1 - Asynclabs http://www.asynclabs.com/
2 - Wifi to mega adaptations http://asynclabs.com/forums/viewtopic.php?f=13&t=19&hilit=mega&start=10




Re: Arduino and WiFi Shields
Thanks for the tutorial! Now added to http://community.pachube.com/arduino, to the tutorial menu and available at this URL: http://community.pachube.com/arduino/wifishield