Thursday, December 23, 2010

The Emerald Isle with a frosting of snow

This is a beautiful image of Ireland taken at about 11am this morning (23 December 2010) which I grabed from the ESA's Miravi service. This image is cropped to show just the island of Ireland and is contrast enhanced. The last week or so has been a particularly severe cold snap with record low temperatures for December. The Corrib lake is seen to be partially covered by ice.

The original image is here, (12MB).

There is a similar image available from the Irish Met Office here.

Tuesday, December 14, 2010

Arduino powered Christmas tree star

This is a quick little hack to put a little sparkle on the top of your Christmas tree. You'll need the following:
  • an Arduino (and suitable power supply eg USB connection to a laptop)
  • a nice powerful red-green-blue LED such as this one from Seeed Studio
  • a power supply for the LED (the Arduino cannot provide the required current). I used 4 x NiMH AA cells.
  • 3 x  NPN transistors that saturate with Ic as close as possible to the maximum allowed current for the LED. I used 3 x BC547 as it was the only ones I had handy. Unfortunately that saturates at only 100mA (I'm allowed up to 350mA per channel for this LED), but it was sufficient for the effect to be successful.
  • 3 x resistors (150 ohms or so) to limit the transistor base current which will be sourced from the Arduino PWM IO pins
  • a length of 4 core cable that will run the length of your tree down to your bread board
  • a breadboard (this is a very temporary hack)
A word of caution: while the voltage is low, the currents running up to the RBG LED are sufficient to pose a small (but non negligible) fire hazard should something go wrong (eg LED failure or a short circuit).  Only operate this while in the room and power off while not attended.

I soldered the LED onto a square of strip board and attached it to my star Christmas tree ornament.

This particular RGB LED can sink up to 350mA per channel (1A in total). There is no way you can source this much current directly from the Arduino IO pins.  Instead the Arduino switches transistors which in turn drive the LED current. The BC547 transistors I had on hand saturate at only 100mA but I found this sufficient for a reasonably good effect.

The transistor base current is provided by pins 9, 10 and 11 of the Arduino. These pins are capable of a simulated digital-to-analog conversion using pulse width modulation (PWM). A 150 ohm resistor limits the base current to about 33mA (the Arduino's limit is 40mA per pin). This is sufficient to ensure the transistor is fully on (saturated).  Failure to fully saturate the transistor can lead to excessive heat dissipation in the transistor. There is no need for a LED current limiting resistor – the transistor performs that function.

The following sketch is my "supernova" program. The idea is to use this as a lighting the tree ceremony. First the star slowly comes to life in a supernova effect (with buckets of artistic licence) and when it reaches full brightness you then power up all the other traditional lighting.

Here is a video of the effect:


You can easily adapt the sketch for other effects.

/*
 * Christmas tree star LED driver. Simulate "supernova" effect
 * with lots of artistic licence. You need 3 x transistors 
 * to power LEDs.
 *
 *
 * See blog post:
 * http://jdesbonnet.blogspot.com/2010/12/arduino-powered-christmas-tree-star.html
 *
 * Joe Desbonnet
 * jdesbonnet@gmail.com
 * This is public domain code. No copyright is asserted.
 */

// Define pins for Red, Green and Blue LEDs.
int LEDR = 9; 
int LEDG = 10;
int LEDB = 11;

void setup()  { 
  // nothing to setup
} 

void loop()  { 
    int i;
    
    setRGB(0,0,0);
    
    // Fist a red faint red glow... growing slowly
    for (i = 0; i < 16; i++) {
        setRGB(i,0,0);
        delay(500);
    }
    
    // Getting brighter faster now
    for (i = 16; i < 64; i++) {
        setRGB(i,0,0);
        delay(100);
    }
    
    // Add some gree to make the light yellow (like dawn)
    for (i = 64; i < 200; i++) {
        setRGB(i,i-64,0);
        delay(100);
    }
    
    // Now a bit of blue
    for (i = 200; i < 255; i++) {
        setRGB(i,i-64,i-200);
        delay(100);
    }
    
    // Flash
    setRGB(255,220,128);
    delay(10);
    setRGB(0,0,0);
        
    delay (100);
    
    // Another flash    
    setRGB(255,255,200);
    delay(10);
    setRGB(0,0,0);
    
    delay (100);
        
      
    // More flashes, with random color variations and intervals
    for (i = 0; i < 32; i++) {
      setRGB (random(192,255),
            random(192,255),
            random(192,255) );
      delay(20);
      setRGB(0,0,0);
       
      delay (random(50,200));
    }
 
   // End of program... switch LED on full all channels (~ white)
   setRGB(255,255,255);
   
   // Loop forever
   while (1);

}

void setRGB (int r, int g, int b) {
  analogWrite(LEDR,r);
  analogWrite(LEDG,g);
  analogWrite(LEDB,b);
}

Tuesday, November 30, 2010

Hot water tank experiment

I've been wondering why my hot water takes an unusually long time to heat up in recently. When I first moved in almost 8 years ago it seemed that it took only about 20 minutes to get piping hot water. Nowadays it takes 40 minutes or more ... and even then it's not that hot.

I was curious about the temperature profiles of my hot water tank as it was being heated by my natural gas powered water heater ("boiler" or "furnace"). As is normal in Ireland, household hot water is provided from hot water storage tank which is heated via heat exchanger by the central heating system.

The following is the temperature at the heat exchanger inlet and outlet of the hot water tank. Temperature was measured with DS18B20 temperature sensors which were taped to the pipe near the tank.

A few things struck me as being interesting about this graph. First there is a brief but noticeable dip in inlet temperature when the system is first switched on. This is clearly the cold water ahead of the pump/heater entering the heat exchanger. There is a quick rise in temperature with the outlet temperature following the input minus a temperature drop (due to heat transferred to the water in the tank) and a time lag (due to the transit time of water in the heat exchanger). However the most striking feature is the temperature cycling.

It seems that my heater cannot transfer heat to the tank fast enough. The water in the heat exchanger circuit reaches the heater's target water flow temperature (user settable from 30°C-85°C) and the flame cuts off. The pump continues to pump until the temperature drops below some threshold and the cycle repeats. The duty cycle is about 50 seconds flame on, and 180 seconds flame off.

There is another interesting effect during the cooling phase: a brief increase in temperature for about 30 seconds before dropping again. I believe this artifact is because the heater flame is on for less time that it takes for the water to circulate around the system. So there is a hot spot which makes a second round through the system.

I re-ran the experiment with a higher heater temperature:

It looked identical (excepted at elevated temperatures). But only when I looked at the numbers more closely while writing this post did I realize that the period between cycles had increased from about 230 seconds to 330 seconds. So perhaps if I set the heater at the max temperature I could increase the period to a sufficiently long time to heat the water in the tank in just one cycle.

The following graph is from a third run. This time the heater was set at the max temperature (supposedly 85°C) and I set the tank thermostat at 40°C.

Unfortunately there was still cycling, 4 in total, but the cycle period was considerable longer than any than the previous runs. More importantly the duty cycle was much better: 500 seconds of flame on, 100 seconds flame off for the first cycle; 220s on/100s off for second, 180s on / 100s off for third, and 140s on for the last cycle. The tank thermostat cut off the heater at about 1800 seconds (30 minutes) into the experiment.

Conclusion:

For fast hot water, running the heater as hot as possible works best (at least for me). At some point the heater temperature must have been turned low which explains why in recent years it seems to be taking ages for the water to heat. However all this probably makes no difference to the energy efficiency of the system.

Tuesday, November 2, 2010

Hotpoint Aquarius FDW60 dishwasher drain pump repair

A few years ago our 2004 Hotpoint dishwasher (Aquarius FDW60) started failing in mid cycle with a flashing "Eco" and "Fast" LED. The underlying cause was that the grey water drain pump wasn't pumping. There was precious little information about reparing the device on the internet. Faced with a repair bill of at least €140 we were close dumping and replacing it. I figured there was nothing to lose by investigating the problem myself and after a little puzzling over the layout of the various inards of the device I eventually located the drain pump, disconnect it, manually rotated the impeller a few times with a srewdriver, reconnected it... and sure enough everything was back to normal.



Two years later after flawless operation, the problem has returned. This time I thought I'd document the repair procedure in case it's of use to anyone else.

First a caveat: don't try this unless you are comfortable with DIY repair and have at least a basic understanding of electrical safety. The instructions here worked for me, but may not be the "correct" way of doing things. If you do decide to proceed YOU DO SO AT YOUR OWN RISK. Also, if there is any warrantee remaining on the appliance it may be voided by your attempt to repair. Feel free to add feedback below if you have any interesting information to add.

The tools you need for this are:

  • Phillips head screwdriver (number 2), but you might get away with a flat head
  • Torch (optional)
  • Bucket (optional)
  • Rag (optional)
  • Brush and/or vacuum cleaner (optional)
  • FDW60 manual (optional)

Empty any water remaining in the dishwasher. Remove the filters and drawers (the top drawer requires that you to remove a plastic stopper at the end of the drawer rail). Use a rag to mop up any remaining water in the drain well. Switch of the unit and remove power at the wall socket or fuse.

Before disconnecting the cold water in ensure that the water supply to the appliance is OFF. This is usually accomplished by means of a valve leaver near where the hose connects to the water supply. Leaver perpendicular to the pipe usually means OFF. Have a bucket and rag ready to catch any residual water in the hose.



Same applies to the grey water outlet hose. This water may have a foul oder -- so be prepared.



Ensure that the power cord and the two water hoses are free to move as you gently pull the appliance out.


Place some newspaper on the ground and have some rags on the ready. Stuff a rag in the drain well to absorb residual water. Gently lay the appliance on its side. Be prepared from some water to seap out. The bottom of the appliance is now exposed. Use a brush or vacuum cleaner to clean the bottom.


Double check that you have electrically disconnected the appliance (don't just rely on the appliance on/off button!). Best to physically disconnect the power cord from the wall socket. If you can't do this then trip the fuse associated with the appliance. Verify there is no power by switching the device on and ensure the power neon does not light.

The bottom panel can be removed by unscrewing 6 (Phillips Head Size 2, I think) screws marked by red arrows in photo. You may need to temporarly remove the front legs to access two of the front screws(just twist the leg until it comes out).


Most of the essential dishwasher components are now accessible. The drain pump can be removed by unscrewing one screw (see photo) and twisting the pump assembly.



The impeller should now be visible inside the pump chamber. Use a pen or screw driver to rotate the impeller a few revolutions. There will be some resistance due to the pump motor – that is normal.


Ensure that there are no foreign objects stuck in the chamber (use a torch to illuminate the chamber while rotating the impeller). In my case I found a pumpkin seed!


Reattach the pump assembly (be careful to ensure the o-ring seal is still there).

Replace the bottom panel. Bring the unit upright. Reconnect power and water hoses. Run a "Prewash" cycle to test.

That should be it!

Boot note: On my first attempt at reattaching the pump assembly I failed to engage all three posts of the bayonet twist lock mechanism (the one at the back which isn't easy seen had not engaged). This resulted in water leaking during my test which caused the float switch activate. This manifests itself as as flashing "Eco" LED and the drain pump runs continuously. Once the pump was attached properly everything ran smoothly.

Update (24 Jan 2011): I've added additional information about the this dishwasher's controller board in this blog post.

Update (7 Mar 2011): A Hotpoint technician told me that this can often be solved without removing/opening the unit by using something like a wire coat hanger to unstick the drain pump impeller. I've never tried this, so I can't comment on its effectiveness and it probably won't help if there is a foreign object lodged in there.

Update (25 May 2011): Impeller got stuck again today. This time I tried the coat hanger trick that was suggested to me by the Hotpoint technician. It worked! I had to do it twice... first time the pump started working, but it sounded rough and then jammed again. The second time it again sounded rough for a few seconds but recovered and seems to be fully back to normal now. There was probably a foreign object in the pump chamber that got expelled eventually. You need a wire coat hanger and make a right angle bend like this:


The horizontal part (running parallel to my measuring tape) goes into the drain hole. See photo of the underside of the dishwasher above to get an idea of what's going on. About 10cm - 11cm is what you need to reach the impeller. Then just wiggle it... all it takes is just the slightest movement of the impeller to unstick it. Of course if you have a large foreign object stuck in there this probably won't help – you'll need to disassemble the pump as described in the main part of this post.

Thursday, October 28, 2010

Computer interface to a low cost electronic kitchen scale (part 1)

On a few occasions I was looking for a low cost electronic weigh scales with a computer interface. It seems they don't exist. There are electronic kitchen scales for as little as €15, but as soon as you require a computer interface you're into specialized scientific/point-of-sale equipment and the starting price jumps to €400+.

I had a spare low cost kitchen scale lying around that was purchased in Maplin (model KS108) a few years ago. Opening it up one can see the weight/force (also known as a "load cell") sensor is a cantilever beam anchored to the base of the unit with strain gauges glued to the top and bottom of the beam. The strain gauges are covered in a white epoxy for environmental protection. A weight (force) applied to the business end of the beam causes the beam to bend slightly causing the strain gauges on top to stretch and those on the bottom to compress.


A commonly used configuration comprises 4 strain gauges wired in a "full bridge" Wheatstone bridge. All four resistors of the bridge (see schematic further down) are strain gauges. Two on the top (R1, R4) and two on the bottom (R2, R3). This configuration provides good sensitivity to bending, and automatically compensates for resistance variation due to temperature.


The interface to the sensor comprises 4 wires: the red and black wires are are the 'excite' (labeled E+ and E- on the PCB) and white and blue are the sense wires (labeled S+ and S-).

The changes in resistance of individual strain gauges are too small to measure accurately by direct measurement. However in a Wheatstone bridge configuration the tiny changes in resistance causes the bridge to unbalance and measurable potential difference is generated on on the sense wires.

I was hoping to piggy back my own sensor electronics without interfering with the operation of the scale. Unfortunately it seems the scale's electronics was interfering with my ability to measure anything. So I cut the sensor wires and attached a simple plug / socket to allow the sensor to be connected to my system but still have the option to revert back to the original configuration if required.

After disconnecting the sensor from the scale's PCB I was able to measure a small voltage difference on the sense wires. But only 1.4mV when 1kg is applied. This is far too small to be measured directly by the ADC (each step of a 0–5V 10 bit ADC is about 5mV).

The two sense wires are connected to an op amp in differential configuration (a ST Microelectronics TS954 dual rail-to-rail op amp) set at moderately high gain produces a signal useable by an ADC.
Normally the Rg resistor is set set to the same value as Rf. In this configuration Vo is 0V when no force is applied to the sensor and can swing up the the supply rail (5V).

If Rg is omitted, at rest (zero force) the output from the op amp (Vo) is about 2.5V. Depending on how the sense wires are connected to the op amp, Vo can swing from 2.5V to 5V or from 2.5V down to 0V (the ground rail). So it seems we lose half of the ADC's dynamic range. However we can put this situation to good use.

Let's call the voltage change due to the application of force on the sensor as ΔV. Instead of wiring the excite wires to the power/ground rail, two digital IO output lines (D0 and D1 in the schematic) are used to excite the sensor. With D0 set to logic high (5V) and D1 set to logic low (0V) a measurement is taken: a0 = 2.5V + ΔV. By toggling the IO lines the excitation polarity is reversed and another measurement is taken: a1 = 2.5V - ΔV. The difference (Δa = a0 - a1) is 2.5V + ΔV - 2.5V + ΔV = 2ΔV. The measuring resolution is doubled. Another advantage of this setup is that is helps eliminate common mode interference.

A word of caution: one must allow sufficient time for the signal to settle after changing the excitation polarity. As can be seen from the oscilloscope trace (taken at Vo where a grid square = 200µs x 1V) at least 500µs is required for the sense voltage to settle after a reverse in direction.



To illustrate this noise reduction in action, I deliberately introduced mains noise by pinching one of the sense wires with my fingers. I wrote a Arduino sketch to take 300 samples with alternating polarities (and allowing 750µs settling time). In the chart below, one can see a0 and a1 have 50Hz mains noise of amplitude ~ 15 ADC units, but the noise in Δa has an amplitude of only ~ 5 ADC units.


Calibration

Ideally a calibration weight kit (expensive!) is used for calibration. But this is not intended to be a super accurate scales. I am aiming for ±0.5g. For that resolution there is a calibration kit (literally) in your pocket: coins are minted to precise specifications. Freshly minted coins are best, but any clean coin in reasonable condition will suffice for this purpose.

The following calibration chart was obtained by mounting Euro 10c (4.10g), 20c (5.74g) and 50c (7.80g) coins on the scales.

Using Gnuplot to plot and curve fit the data to the equation of a line: Δa(x) = c + mx
where x is the mass in grams applied to the scale.

Gnuplot curve fit reports:
c               = 17.3111          +/- 0.09565      (0.5525%)
m               = 2.49864          +/- 0.0006569    (0.02629%)


As can be seen from the residuals plot there is excellent linearity (the residuals are random and ranging from -0.8 to +0.8 ADC units with a root-mean-square of just 0.376). The slope or sensitivity (m) has a value of 2.49864 (let's call that 2.5) which means that each gram added registers a Δa of 2.5 ADC units, or each ADC increment is 1/2.5 = 0.4g. Combined with the noise (the spread in residuals) and it seems we are safely in the ±0.5g area.

An Arduino was used for the initial prototyping. The following sketch (below) excites the sensor in both direction, takes a time averaged ADC of Δa and spits it out on the serial port.

In part 2 I will discuss the interfacing to a computer, the computer side software and possible applications.



/**
 * Take measurement from weigh scales sensor and output to serial
 * port. By reversing polarity of excite signal can reduce common
 * mode noise. Take 256 samples and get mean before outputing 
 * result -- this helps reduce noise and adds extra resolution.
 * Joe Desbonnet, 28 Oct 2010. jdesbonnet@gmail.com. 
 */
 
 // Define bridge excite digital IO lines
#define D0 3
#define D1 2

// Use ADC port 0
#define AN0 0
 
// Delain in microseconds to allow signal to settle 
// after excite polarity reversal
#define DELAY 800

void setup()   {
  
  Serial.begin(115200); 
  
  pinMode(D0, OUTPUT);
  pinMode(D1, OUTPUT);
}

void loop()                     
{
  
  // Get zero point ('tare') of scale
  int tare = measure ();
  
  while (true) {
     Serial.println ( measure() - tare );
     delay (1000);
  }
  
}

int measure () {
  int i,a0,a1;
  long s;
  for (i = 0; i < 256; i++) {
    digitalWrite (D0,HIGH);
    digitalWrite (D1,LOW);
    delayMicroseconds(DELAY);
    a0 = analogRead(AN0);
     
    // reverse polarity
    digitalWrite (D0,LOW);
    digitalWrite (D1,HIGH);
    delayMicroseconds(DELAY);
    a1 = analogRead(AN0);
    
    s += (long) (a0 - a1);
      
   } // next i
   
   // Don't care about polarity
   if ( s < 0) {
       s = -s;
   }
   
   // As there is a large number of samples being averaged we
   // can probably extract another bit or two from the ADC.
   // Going to be conservative and going for one extra bit.
   // So instead of dividing by 256, will divide by just 128
   // instead (ie right shift 7 bits).
   return s>>7;
}

Thursday, September 30, 2010

'Smart' electricity meter based on Efergy Elite monitor, part 1

Update (16 April 2011): I've got a follow-up post (part 2) which I describe a more efficient signal decoding technique using PIC interrupts and timers and allows for simple multitasking.

This series of posts describes how I hacked a low cost (€37 from Maplin) Efergy Elite electricity monitor to obtain real time power use data and to record and chart this data with the aim of understanding how electricty is used in the home and how to reduce consumption.

Describing the entire solution in one go is going to result in an excessively long post, so I'm going to break this into several parts over the next few weeks. In this post I'll describe the process involved in getting access to the raw data from the sensor unit.

The term 'smart' in the title is a misnomer. All I want to do here is record real time (at least several samples per minute) power use into a computer system. A true 'smart' meter will do telemetering, facilitate demand based tariffs, feed-in tariffs etc.

The problem with low cost energy monitors is you only get the current instantaneous usage and perhaps hourly, daily and weekly averages.

What I want is something that looks like this:


In this chart I can see my coffee machine (left on accidentally), the oven (not much I can do about that) and the fridge. From that chart I can figure the base load due to broadband router, WiFi access point, DVR etc and work out the average use of my fridge (by estimating the duty cycle and subtracting the power level while on from the base load).

So, how did I arrive at this chart?

I had an Efergy Elite electricity monitor which I received as a gift a few years ago. The product comprises a current transformer sensor which clips on to the utility meter outside. This transmits a power reading every 6 seconds over a 433MHz radio to the receiver unit indoors. The receiver has a LCD which displays instantaneous power use, and hourly, daily weekly averages (and other less interesting stuff like CO2 emissions). Photos of the sensor, receiver and internal electronics are here. There is no computer interface to tap into this data, so one needed to be hacked in.

There is a block diagram of my solution:


Looking at the receiver unit electronics, there is a test pad located near the radio part of the PCB. (The A72C01AUF chip to the bottom left of the test pad does all the radio heavy lifting both in the sensor and  receiver).


Looking at the signal at this point with an oscilloscope one can see there is burst of logic level (0/5V) signals every 6 seconds. This would seem to be the base band output from the radio.  An oscilloscope isn't the most useful tool for decoding digital IO if there are more than a few bits involved. I put a recently purchased Saleae 'Logic' (logic analyzer) on the task and this is what the signal looked like:



This signal didn't seem to make much sense. So I also simultaneously recorded the sensor's digital input line to the transmitter (pin 18 on the sensor's MCU – which by the way is a GSSP 22682X01 – a difficult chip to locate a datasheet for).


Thanks to the logic analyzer's big picture it seems there is an initial block of what looks like random noise preceding the actual data (I'm guessing this is just noise from the radio transmitter powering up).

Now looking more closely at the actual data:

The data is encoded using a digital equivalent of Frequency Shift Keying (FSK). A logic 0 is represented by three long pulses of 2ms duration in total (a low frequency) and a logic 1 by 4 shorter pulses totaling 2ms also (a high frequency).

Decoding this could be achieved with analog circuitry but this would involve a handful of (relatively) expensive passive components. Instead I chose a pure digital technique. I used a simple pattern matching algorithm to look for 3 successive long pulses or 4 successive short pulses and ignore anything else (code appended below).

From bits to bytes

So now I have a string of logic '0's and '1's. The next problem is to determine where the byte boundaries are.

Fortunately each data packet starts with the following 4 bytes: 0xAB 0xAB 0xAB 0x2D. This helps with synchronization. When looking for the start of data I shove the bits into a shift register until I get a byte value of 0xAB. I take all subsequent bits as groups of 8 to form the bytes of data. After the first 0xAB I ignore all subsequent byte values of 0xAB until I get a 0x2D. I am now at the start of the packet payload.

A typical packets look like this:
AB, AB, AB, 2D, 00, 0B, 5A, 40, 98, 00, 02, 00, 41
After some experimentation this is what I believe the packet consists of:

0Sync, always 0xAB
1Sync, always 0xAB
2Sync, always 0xAB
3Sync end,  always 0x2D
4? always 0x00
5Device address high byte (always 0x0D for my device)
6Device address low byte  (always 0x5A for my device)
7sbssaaaa where s = bits of sampling period, b = battery low indicator (0 = low) and aaaa is the upper 4 bits of sensor A. 0-00---- = 6s sampling, 1-01---- = 12s sampling, 0-10---- = 18s sampling. It's odd that ‘b’ is sandwiched in among s bits.
8Least significant 8 bits of sensor input A (nearest MCU edge of board)
9? probably upper 4 bits of sensor B and C.
10Least significant 8 bits of sensor input B (middle)
11Least significant 8 bits of sensor input C
12Checksum (arithmetical sum of bytes 4 - 11).


So in summary, each packet comprises a unique sensor address, the sampling rate, a battery low flag and 3 x 12 bit ADC values for each of the sensor's three inputs  (normal domestic power is single phase, so only one input is used. A three phase system would use all three inputs) and finally a checksum of the contents of the packet for data integrity.

I soldered a small (12F675) PIC MCU to a piece of veroboard (pictured right) and wrote a program to decode the baseband signal from the radio and convert that to actual data.

The PIC code used to decode the radio baseband signal is listed below (this excerpt is not the full PIC application – contact me if you need the lot):

The next problem is to figure how to translate these ADC values to Amps (and by multiplying by 230V to Watts) and how to feed this data to a database for recording and visualization. These will be covered in subsequent posts.

Related Links
Updates to post:


#include 
#include "efergy_config.h"
#include "efergy_elite_decode.h"


byte getPulseWidth();
byte getBit ();
byte getByte ();
void resync();

byte t3,t4,tm;


/**
 * Decode baseband radio signal from Efergy Elite receiver.
 * 
 * Packet consists of a radio preamble of what seems
 * like random noise for about 200ms followed by a quiet period
 * of 100ms followed by data for 200ms. Encoding is a FSK type
 * scheme.
 * Logic 0 is represented by 3 cycles of "low" frequency square 
 * wave (period 8t per cycle). 
 * Logic 1 is represented by 4 cycles of "high" frequncy square
 * wave (period 6t per cycle).
 * Logic 0 and Logic 1 have the same period of 24t which is
 * very approx 2ms [confirm]. Ie t ~= 83 microseconds.
 *
 *    +---+   +---+   +---+
 *    |   |   |   |   |        = Logic 0
 * +--|   +---+   +---+
 *   +--+  +--+  +--+  +--+
 *   |  |  |  |  |  |  |       = Logic 1
 * +-+  +--+  +--+  +--+
 *
 * Decoding this not but looking at frequency, but looking
 * for 3 long pulses in succession or 4 short pulses. 
 * 
 * Data has 3 bytes of synchronization: 0xAB, 0xAB, 0x2D.
 * Look initially for 0xAB to get byte boundary synchronization. 
 * Then look for 0x2D to flag start of actual data.
 *
 * All inter-pulse calculation must be complete 
 * within 64x5 microseconds ie ~ 300 microseconds or 300 instructions @ 4MHz)
 */

byte decodeEfergy(unsigned char *buf) {
 byte i,bitc=0, bytec=0, b=0;
 byte t,pt;
 //byte bufIndex=0;
 unsigned int rt=0;

 t3=0x1a; // short pulse duration of 3t
 t4=0x23; // long pulse duration of 4t
 tm = 0x1e; // mean of short and long pulse, ie 3.5t

resync:

 // Look for sync bit sequence
 // TODO: update: just look for AB followed by 2D.

 // Get byte boundary sync
 while (b != 0xAB) {
  b = (b<<1) | getBit();
 }
 for (i = 0; i < 8; i++) {
  b = (b<<1) | getBit();
 }
 if (b != 0xAB) {
  goto resync;
 }

 for (i = 0; i < 8; i++) {
  b = (b<<1) | getBit();
 }
 if (b != 0x2D) {
  goto resync;
 }


 b=0;

 // 9 bytes left to retrieve

 do {
  b = (b<<1) | getBit();

  bitc++;
  if (bitc == 8) {
 
   buf[bytec++] = b;
   b=bitc=0;
  }
 } while (bytec < 9);

 // Calculate checksum
 byte cs = 0;
 for (i = 0; i < 8; i++) {
  cs += buf[i];
 }

 // Display checksum fail if they don't match
 if (cs != buf[8]) {
  return 4;
 }

 return 0;
}

byte getByte () {
 byte i,b;
 for (i = 0; i < 8; i++) {
  b = (b<<1) | getBit();
 }
 return b;
}

byte getBit () {
 char t;
 byte nshort=0,nlong=0;

 while (1) {
 
  t = getPulseWidth();

  if ( t < tm) {
   nshort++;
  } else {
   nlong++;
  }

  // Check for anomalous condition
  if ( (nshort>0) && (nlong>0) ) {
   nshort=nlong=0;   
   if ( t < tm) {
    nshort=1;
   } else {
    nlong=1;
   }
  }

  if (nshort == 4) {
   return 1;
  }
  if (nlong == 3) {
   return 0;
  }
 }
}

byte getPulseWidth() {
 byte t=0;
 while (RADIOBB_PIN) {
  CLRWDT();
 }
 while ( ! RADIOBB_PIN) {
  t++;
 }
 return t;
}

void resync () {

 byte pt,t;

 restart_resync:

 // Can have either 3t (short) or 4t (long) pulse. Get pulses of
 // two different lengths. 3t is the short pulse, 4t is the long one.
 pt = getPulseWidth();
 do {
  t = getPulseWidth()+2;
 } while (t - pt < 4);
 t -= 2;


 if (pt < t) {
  t3 = pt;
  t4 = t;
 } else {
  t3 = t;
  t4 = pt;
 }

 if (t4 < 0x1A) {
  //TXREG='s';
  goto restart_resync;
 }
 if (t4 > 0x30) {
  //TXREG='l';
  goto restart_resync;
 }

 // Didn't have to do this at the sensor, but receiver has a lot more incoming crud
 if ( ((t4>>2)*3 ^ t3) & 0b11111100 ) {   // (t4/4)*3  ~= t3 (ignoring 2 LSB of precision)
  //TXREG='?';
  goto restart_resync;
 }
 

 // tm is mean of t3 and t4
 tm = (t3+t4)>>1;

 byte b=0;

 // Look for sync bit sequence
 while (b != 0xAB) {
  b = (b<<1) | getBit();
 }
 
}

Sunday, August 22, 2010

Mapping cell coverage in the Glengarriff Valley

As a follow up to my Froyo on a Stick experiment, I wondered why the signal in the Glengarriff valley was so spotty and where it was coming from.

I found two apps in the Android Market which report and log cell data: "Antennas" and "RF Signal Tracker". I enabled the logging on both apps and cycled around the area. In the immediate vicinity of where I was staying the signal was almost non-existent. But not far away there was acceptable signal levels.

It turns out these apps not only record cell ID, and signal strength, but also (from somewhere?!) downloads the location of the cell towers.

Plotting this data on Google Maps yielded some answers. It turns out the tower was to the north and not the east as I had originally thought. The signal into the valley was being attenuated by a ridge of the Caha Pass a little higher than the tower (despite no line-of-sight, diffraction of radio waves allows some signal through).  On either side of the ridge were peaks exceeding 400m elevation: so it would appear this constrained reception to a beam within the valley.

My data would appear to confirm this. Within the yellow wedge it seemed possible to get a signal (red dots indicate points where I could connect). In the grey wedge a signal was mostly not obtainable.

Data acquisition and visualization

I ran both "Antennas" and "RF Signal Strength" together. The UI in the latter app wasn't very good... it was slow to respond and would frequently hang. Fortunately the logging function worked. The "Antennas" UI on the other hand appeared to work better, but failed to log much data.

The data from "RF Signal Strength" looks like this:

_id,latitude,longitude,rssi,logdate,mcc,mnc,lac,cellid,site_lat,site_lng,tech,ber,callstate,roaming
1,51766086,-9613348,-99,14 Aug 2010 13:56:03,272,1,47,11011,52181474,-1357067,GPRS,-1,IDLE,NO
2,51766086,-9613348,-99,14 Aug 2010 13:56:26,272,1,47,11011,52181474,-1357067,GPRS,-1,IDLE,NO
3,51766086,-9613348,-99,14 Aug 2010 13:56:27,272,1,47,11011,52181474,-1357067,GPRS,-1,IDLE,NO

I wrote a script (Java + Javascript) to plot this on Google Maps Terrain layer. Then copied a screen grab into Google Draw Tool to annotate.

Froyo on a stick

When faced with an impossibly weak cell signal and an Android phone, what can you do?

Recently while on holiday in the Glengarriff valley, west County Cork, I was faced with this problem.

Android 2.2 (aka "Froyo") has a cool feature that allows the phone to become a WiFi access point. This is intended to be a convenient way to allow a laptop to use the phone's internet connection. Normally the phone would be sitting right next to the laptop. But it doesn't have to be so close. A line-of-sight range of more than 20 meters is possible.

At my location I was getting tantalizing brief connections to the cell network (Vodafone IE), and occasionally the odd GPRS IP packet might make it through. But nothing close to usable.

As a rule of thumb you can improve a weak radio signal by raising the height of the antenna.  So I got several planks of wood. Strapped them together with duct tape to form a make shift antenna mast  about 8m in height. I switched the mobile hotspot feature on, taped the phone to the top of the mast and raised it.

And sure enough I was able to get a usable [*] connection where none existed before.


[*] The connection was only GPRS and there was still packet loss... but sufficient to get email in and out. Perhaps another few meters might have made the difference.

Saturday, July 31, 2010

Leaving the immersion water heater on – mildly expensive or financial ruin?

I recently stumbled across this blog post about the horrors of forgetting to switch off the immersion water heater. Now that I have my real time energy monitor I thought it would be interesting to see how financially crippling "leaving the immersion on" would actually be.

Here is the result:


Conclusion

There is two phases in "leaving the immersion on" phenomenon:

  1. The initial heating of the water cylinder from cold to target temperature (set by the thermostat in the heater)
  2. Short bursts of about 5 minutes every hour or so to keep the water at target temperature
Phase 1 does take a huge whack of energy. About 6kW for well over 1 hour in my case. And that's in summer when cold water isn't that cold.

However if left on indefinitely and no hot water is consumed, the only additional energy required is to keep the cylinder at the target temperature. With modern well insulated cylinders it's not that much (relatively speaking). In my case a 5 minute burst of 6kW every 1.5 hours. That works out at about €1.20 / day or €8.40 / week assuming no hot water is consumed.

The blog post referred to above mentioned the ESB (power utility company) estimated the cost to be about €20 / week. Allowing for colder weather and reasonable hot water use that sounds about right. (I am assuming electricity costs €0.15/kWh unit.)

BTW: physics sanity check: my cylinder is 117 liters. Heating water from 20C to 80C ie ΔT of 60C. Requires 60 x 4.4kJ x 117 = 30888kJ. At 6kW that requires 30888/6 seconds = 5148 seconds = 1.43 hours. Which approximately squares with what I'm seeing above.

Friday, July 30, 2010

What most energy monitors don't tell you!



I received a Efergy Elite energy monitor (sold in Maplin and other retailers) as a Christmas gift few years go. The Elite provides current use, daily and weekly average and all that green CO₂ nonsense. While useful for tracking down unnecessary drains it doesn't give you a true picture of electricity use throughout the day.

The Efergy Elite comprises a wireless sensor and a receiver/display unit. The sensor is a clamp ammeter which clips to the output from your ESB electricity meter. It transmits real time power use [*] to the receiver every 6 seconds. The receiver unit displays the current consumption and computes daily and weekly averages – not a huge amount of extra info that your electricity bill won't tell you.

Despite getting all this juicy data every 6 seconds the Elite won't share it with you. There is no computer port.  So I hacked it.

I soldered a wire on the baseband signal from the radio receiver, into a cheap little PIC MCU for some decoding and at the other end a stream of numbers every 6 seconds. Bung that into a graphing package and you get a chart like that above.



[*] Actually it can only sense current. So you assume that the supply is at a constant 230V rms and you can calculate the power (power = V*I). It's not accurate enough for billing, but certainly good enough for consumer energy monitoring.