Things used in this project


Emon curent monitoring circuit diagram


Arduino power monitor codeC/C++
Runs on the Arduino pro mini to monitor the power usage of the tea maker
#include "EmonLib.h"                                 // Include Emon Library
EnergyMonitor Emon1;                                 // Create an instance

int LedPin = 5;
int BasketDownPin = 2;                               // Will pulse this pin 10ms when the basket drops
int BasketUpPin = 3;                                 // Will pulse this pin 10ms when the basket raises
double IrmsBase = 0.0;                               // Baseline current sampled at startup
int BaseLen = 5;
double Baseline[5];                            // History for baseline so we update baseline overtime
String States[3] = {"Waiting", "Heating", "Basket"};
int HistLen = 4; 
int StateHist[4] = {0,0,0,0};                    // Stores the state history
int TrigerState[3] = {2,2,2};                  // When the history array shows Basket Motion (3 events)
boolean Heating = false;                             // Flag to indicate we have started heating
boolean Basket = false;                              // Flag to indicate basket in motion
boolean Brewing = false;                             // Flag to indicate we have started brewing
boolean Done = false;                                // Flag to indicate we have finished brewing

void setup()
  //Serial.begin(9600);                                // Serial for debugging 
  Emon1.current(1, 13.43);                           // Current: input pin, manual calibration constant
  pinMode(LedPin, OUTPUT);                           // Calibration process:
  pinMode(BasketDownPin, OUTPUT);
  pinMode(BasketUpPin, OUTPUT);
  digitalWrite(BasketDownPin, LOW);
  digitalWrite(BasketUpPin, LOW);
  digitalWrite(LedPin, HIGH);                        // Baseline capture, power up LED on
  double sum = 0.0;
  int samples = 10;
  for (int i=0; i <= samples; i++){                  // Sample Irms and average to create baseline
      sum = sum + Emon1.calcIrms(1480);
      digitalWrite(LedPin, LOW);  
      digitalWrite(LedPin, HIGH);  
  double bootBase = sum/samples;                     // set the baseline Irms for sensing tea maker states
  initialBaseline(bootBase);                         // Baseline capture done

void loop()
  digitalWrite(BasketDownPin, LOW);
  digitalWrite(BasketUpPin, LOW);
  double irms = Emon1.calcIrms(1480);                   // Calculate Irms only
  int teaStat = senseStatus(irms);
  if (histCheck(1)){                                   // if we have applied heat for a little bit then
    Heating = true;                                    // We're heating water!
    Brewing = false;                                   // Reset all state
    Basket = false;
    Done = false;
  if (Heating && !Basket && !Brewing && histCheck(2)){ // if we were heating, and not brewing and the basket is not moving, but now the basket IS moving...                                        
    printTrans("DOWN");                                // basket going down!
    digitalWrite(BasketDownPin, HIGH);
    digitalWrite(BasketDownPin, LOW);
    Heating = false;                                   //done heating
    Brewing = false;                                   //not yet brewing
    Basket = true;                                     //basket is moving
  if (!Heating && !Basket && Brewing && histCheck(2)){ // if we are not heating and not moing the basket and were brewing but now the basket is moving...
    printTrans("UP");                                  // basket coming up!
    digitalWrite(BasketUpPin, HIGH);
    digitalWrite(BasketUpPin, LOW);
    Brewing = false;                                   // Must be done brewing
    Basket = true;                                     // basket is moving
    Done = true;
  if (!Done && Basket && histCheck(0)){                 // if not done and the basket was in motion and we are waiting now...
    Basket = false;                                     // basket is done moving
    Brewing = true;                                     // We are brewing!!
  if (Done && Basket && !Brewing && histCheck(0)){      // if done, the basket was moving, brew is done and we are waiting now...
    Basket = false;                                     // All done with the brew cycle

// Fairly certain this is causing more problems than it solves
//  if (Done && !Heating && !Basket && !Brewing && histCheck(0)){  // To adjust for drift
//    updateBaseline(irms);                               // update our baseline when not in a cycle
//  }
  //printStatus(irms, teaStat);  
  delay(10); //if not printing serial, delay.

// Pushes the current tea Status value to the top of the
// StatHist array, shifts all existing values right.
void saveStat(int teaStat){
  int temp[HistLen];
  temp[0] = teaStat;
  for(int x=0; x < (HistLen-1); x++){
    temp[x+1] = StateHist[x];
  for(int x=0; x < HistLen; x++){
    StateHist[x] = temp[x];

// Senses our teamaker state by looking at RMS current.
// Based on what component is on, heater vs motor vs base
// there are different levels of current used. The heater is 
// 100x the base current, and the motor is 1.5x the base current.
int senseStatus(double irms){
 String tStat;
 if (irms >= (IrmsBase * 100)){
   return 1; // Heating
 else if (irms >= (IrmsBase * 1.4) && irms < (IrmsBase * 10)){
   return 2; // Basket Motion
 else {
   return 0; // Waiting

// Look back at the previous status values
// and see if they all match the tStat value
boolean histCheck(int tStat){
  int x = 0;
  while (x < HistLen){
    if (tStat == StateHist[x]){
      x++; //move on to check the next
    else {
      return false;  
  return true;

// Initialize our history to the boot baseline
void initialBaseline(double allBase){
  for (int x=0; x < BaseLen; x++){
     Baseline[x] = allBase;
  IrmsBase = allBase;

// Compute updated average based on new Irms sample
// Store it in our Baseline and update the global
void updateBaseline(double newBase){
  // add to top of array
  double temp[BaseLen];
  temp[0] = newBase;
  for(int x=0; x < (BaseLen-1); x++){
    temp[x+1] = Baseline[x];
  for(int x=0; x < BaseLen; x++){
    Baseline[x] = temp[x];

  double sum = 0.0;
  for (int x=0; x < BaseLen; x++){
    sum = sum + Baseline[x]; 
  IrmsBase = sum/BaseLen;

// Simple time-based LED flasher
boolean LEDon = false;
void updateBrewLight(){
  if (Brewing && !Done){                                        
     if (!LEDon){
       digitalWrite(LedPin, HIGH);
       LEDon = true;
     else {
       digitalWrite(LedPin, LOW);
       LEDon = false;
  if (!Brewing){
    digitalWrite(LedPin, HIGH);

// Simple debugging print function
void printStatus(double irms, int teaStat){
  Serial.print(irms);		       // Irms current
  Serial.print(" ");
  Serial.print(States[teaStat]);               // Waiting, Heating, Basket Motion
  // Print the state array 
  Serial.print(" [");
  for(int x=0; x < HistLen; x++){
  Serial.print(" Bsl:");
  // Print the baseline history
  Serial.print(" [");
  for(int x=0; x < BaseLen; x++){
  // print our boolean states
  Serial.print(" Htg:");
  Serial.print(" Bsk:");
  Serial.print(" Brw:");
  Serial.print(" Dn:");
  Serial.println(" ");

void printTrans(String updown){
  Serial.println("!!!!!!! BASKET TIME !!!!!!!");
  Serial.print("!!!!!!! GOING ");
  Serial.println(" !!!!!!!");

Arduino audio/wav player codeC/C++
Run on the arduino uno with the Adafruit wav shield
#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"

SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the filesystem on the card
FatReader f;      // This holds the information for the file we're play

WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

byte PrevValUpin = HIGH; // Storing the previous reading to "debounce" startup of the current sense board
byte PrevValDpin = HIGH;

int DownPinNum = 8; // The pins to sense the up/down signals
int UpPinNum = 9;

// this handy function will return the number of bytes currently free in RAM, great for debugging!   
int freeRam(void)
  extern int  __bss_end; 
  extern int  *__brkval; 
  int free_memory; 
  if((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__bss_end); 
  else {
    free_memory = ((int)&free_memory) - ((int)__brkval); 
  return free_memory; 

void sdErrorCheck(void)
  if (!card.errorCode()) return;
  Serial.println("\n\rSD I/O error: ");
  Serial.print(card.errorCode(), HEX);
  Serial.print(", ");
  Serial.println(card.errorData(), HEX);

void setup() {
  // set up serial port
  // Set the output pins for the DAC control. This pins are defined in the library
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  // Listening on these pins for triggers
  pinMode(DownPinNum, INPUT);  // Basket down
  pinMode(UpPinNum, INPUT);  // Basket up

  if (!card.init()) {         //play with 8 MHz spi (default faster!)  
    Serial.println("Card init. failed!");  // Something went wrong, lets print out why
    while(1);                            // then 'halt' - do nothing!
  // enable optimize read - some cards may timeout. Disable if you're having problems
// Now we will look for a FAT partition!
  uint8_t part;
  for (part = 0; part < 5; part++) {     // we have up to 5 slots to look in
    if (vol.init(card, part)) 
      break;                             // we found one, lets bail
  if (part == 5) {                       // if we ended up not finding one  :(
    Serial.println("No valid FAT partition!");
    sdErrorCheck();      // Something went wrong, lets print out why
    while(1);                            // then 'halt' - do nothing!
  // Lets tell the user about what we found
  Serial.print("Using partition ");
  Serial.print(part, DEC);
  Serial.print(", type is FAT");
  Serial.println(vol.fatType(),DEC);     // FAT16 or FAT32?
  // Try to open the root directory
  if (!root.openRoot(vol)) {
    Serial.println("Can't open root dir!"); // Something went wrong,
    while(1);                             // then 'halt' - do nothing!
  delay(5000); // wait a few seconds for the secondary board to boot

void loop() {
  byte downPin;
  byte upPin;
  downPin = digitalRead(DownPinNum);
  upPin = digitalRead(UpPinNum);
  if (PrevValDpin == LOW && downPin == HIGH){
  if (PrevValUpin == LOW && upPin == HIGH){
  PrevValDpin = downPin;
  PrevValUpin = upPin;

// Plays a full file from beginning to end with no pause.
void playcomplete(char *name) {
  // call our helper to find and play this name
  while (wave.isplaying) {
  // do nothing while its playing
  // now its done playing

void playfile(char *name) {
  // see if the wave object is currently doing something
  if (wave.isplaying) {// already playing something, so stop it!
    wave.stop(); // stop it
  // look in the root directory and open the file
  if (!, name)) {
    putstring("Couldn't open file "); Serial.print(name); return;
  // OK read the file and turn it into a wave object
  if (!wave.create(f)) {
    putstring_nl("Not a valid WAV"); return;
  // ok time to play! start playback;
Emon Lib
Power monitoring library


Brian Chamberlain

Software Engineer and Hardware Hacker



Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback


Similar projects you might like

Starry Night Prom
  • 2,425
  • 18

How did I stand out at prom? In a light up dress of course!

Arduino 101 Packet Radio IMU
  • 152
  • 2


Packet Radio on your Arduino 101 - The Arduino 101 Orientation Visualizer redone with Packet Radio!

The Trump Button
  • 1,287
  • 9

Full instructions

The famous connected button to order your favorite drink using Sigfox network.

  • 25
  • 1

Full instructions

The game in a dot matrix display P10 16x32 pixels

Beat The Heat Car Seat
  • 100
  • 2

Work in progress

A device that prevents caretakers from leaving loved ones in unattended vehicles, which can possibly be unsafe due to the environment.

Third Eye for The Blind
  • 1,054
  • 13

Full instructions

An innovative wearable technology for visually impaired peoples.

ProjectsCommunitiesTopicsContestsLiveAppsBetaFree StoreBlogAdd projectSign up / Login