Saturday, November 10, 2012

Smartmeter revisited

Einstein once said that only two things were infinite: The universe and human stupidity. The former even he wasn't sure about, and the latter I found out the hard way. But I'll start from the top:

I've had my smartmeter running for a while now and since the readings looked plausible I assumed they were accurate. Well, they weren't.

The meters I use generate 2000 pulses of 90ms length for every consumed kWh, and the way I counted them was to collect them for five seconds and then transmit a summary. After a while I found out two things about my power consumption:

  1. The water heater (a continuous-flow-type) consumes an insane amount of power, and
  2. The computer running the metering software also was a bit too greedy for my taste.

I couldn't do anything about the water heater because it's installed permanently and after all it's not even mine, but I could try and tame it's power consumption by reducing the water pressure and/or the flow speed by using a water saving shower head. As a side effect I'd also reduce my water consumption. Two birds with one stone! And the PC running the metering software also had to go.

To get rid of the PC I had to rewrite the metering software from scratch, because the software from the volkszaehler.org project I was using is based on a full-fledged LAMP-stack (Linux, Apache, MySQL, PHP). The main problem was the MySQL-database, as this keeps every reading I ever took and has to access them all at once every time I'd wanted to view my consumption graph (remember, I took readings every five seconds, so there were a LOT of values in there).

I opted to use something called RRDTool instead. This is a nifty little tool, well known to sysadmins around the world to keep stats about routers and switches, system loads and whatnot. Since there are usually a lot of data sources too keep track of, the databases have to be kept small. The way it achieves this is to use fixed size databases of different resolutions and aggregation functions to consolidate older data.

While I was at it, I also changed the way I collected the pulses from the meters from the five-second-summary-method to transmitting every pulse as it came in. This is where things started to go South...

Before...


But the really stupid thing I did was changing something that drastically influenced my power consumption (the shower head) and the way I collected and processed the consumption data at the same time.

The result was that I grossly overestimated the savings from changing the shower head and thought I'd cut my consumption by about 50%, since that was what my new readings suggested. I never even bothered to check the "official" meter from the power company, which finally bit me in the ass when the next power bill came in.

...after...


Only then did I find out that my readings were way off! They may have looked plausible, but weren't anywhere near my true consumption.

After this wake up call I started to investigate the error. At first it looked like the new way of counting pulses was to blame, so I changed that back to the old way. That gave me way higher readings but by then I had grown suspicious if those were correct. They also weren't.

So the new method was obviously loosing pulses while the old way was counting pulses that weren't there. The one thing both had in common was the way they went into the controller:

When idle the controller was in sleep mode and an incoming pulse would cause an interrupt to wake up the controller and send out a packet or increment a counter, respectively. Since the driver for the RFM12 transceiver is also heavily based on interrupts I figured that might have been the problem. I also had some code to blink an LED using the Arduino delay() function, which is a really bad idea when using interrupts at the same time, but I threw that out first and it didn't fix the problem.

So I changed the code to poll the inputs instead of sleeping and waiting for interrupts and that seemed to help with the lost pulses.

But things only got weirder: Now some pulses were counted twice. So I started counting milliseconds between pulses and it turned out there was some kind of bouncing about 75ms after some pulses, while others looked OK.

I knew that mechanical buttons tend to bounce, but this bouncing would occur in the first ten ms after the button was pressed, not 75ms later! 75ms is close to eternity, even for a tiny and slow 8 bit microcontroller. A real computer could go fetch a coffe and have a smoke in 75ms! Also there weren't any mechanical switches anywhere near the circuit I've built. The pulses are generated digitally by the counters, go to an optocoupler and straight to the controller.

But I didn't want to rip the whole thing out of my breaker box and dissect it with an oscilloscope, so I just wrote a little routine that ignores every state change that occurs less than 90ms after the input went low. Think of it as a really slow debouncing routine.

and the real thing (hopefully)


So far my readings look OK, there still is some 0.03kWh error per day, give or take, but that's nowhere near what my old code produced.

As usual, the code can be found in my github account:




No comments:

Post a Comment