Arduino to monitor electricity usage

Introduction

To monitor electricity consumption of a house I have proposed a light sensor to detect the flashing of the LED on the electricity meter that indicates energy is flowing. In previous blogs I have covered the selection of light sensor and its electrical connection to an Arduino Uno. Now it is time to look at the programming.

To Pull or not to pull?

As discussed in IOT Devices – to push or to pull there’s a choice to be made. I had selected the Arduino Uno as the hardware. To enable communication the device it was fitted with a W5000 Ethernet shield and an ethernet cable connecting the shield to the home router.

The Arduino was wired up as in Connect light sensor (TSL251) to Arduino Uno with the two sensors connected to the Arduino interrupt pins.

Code structure

The code breaks down into five sections

  1. include and define statements.

    There are six #include statements

    1. string.h – this is pretty standard
    2. avr/wdt.h – this is needed so that the watchdog timer can be manipulated.
    3. SPI.h – The ethernet shield is accessed over SPI.
    4. Ethernet.h – The http server is used from this package.
    5. EthernetUdp.h – To synchronise the Arduino timer a call is made an NTP server over UDP.
    6. TimerLib.h – Rather than manage counters and timers the TimerLib package is used to provide sensible time values (year, month, day and hours, minutes)

    define statements are used to give ‘useful’ names to

    1. Names of devices
    2. The Arduino pins
    3. Sensor constants
  2. Variable definitions

    Since there are two sensors we can think of the input as two ‘channels’. Variable are identical for each except those for channel 1 and prefixed with “chan1_” and those for channel 2 are prefixed with “chan2_” By convention the house mains meter is attached to channel 1 and the solar panels meter is attached to channel 2.

    A future update to the code will be to define a channel structure and to use it so that there’s less code duplication.

  3. Library initialisation A server is initialised using the EthernetServer class to listen on port 80.

    An EthernetUDP connection is created. This is then used by for getting date and time information via NTP .

  4. Interrupts

    The light sensors are connected to the Arduino’s two interrupt pins. The interrupt service routines ( (ISR) are deliberately as simple as they can be. Each channel has chanX_pulse variable which is incremented. The ISR then returns.

    //==== Interrupt routines for input channels ==
    // See https://arduino.stackexchange.com/questions/8758/arduino-interruption-on-pin-        
    // change/8926#8926 
    // Note: we don't read the pin. We rely on the h/w triggering an interrupt on a rising edge.
    
    void chan1_isr() {
        chan1_pulse++;
    }
    
    void chan2_isr() {
        chan2_pulse++;
    }
    
  5. setup() function As well as the usual Arduino initialisation the ISRs are attached to the interrupt pins in the setup() function
    // Set up the pins
    pinMode(DigitalPin2, INPUT);
    attachInterrupt(0, chan1_isr, RISING);
    pinMode(DigitalPin3, INPUT);
    attachInterrupt(1, chan2_isr, RISING);
    

    Following this the setup function initialises the Ethernet server and an NTP client to get the current date and time.

  6. Main loop() function

    The main loop continuously runs through the following

    Check the Ethernet server. If a connection has occurred then (confusingly) a client is attached.

    • A non-blocking read() call is made to obtain the first character in the server buffer.
    • The character is checked. If the character is not a line ending then a boolean is set to note that processing has detected a non blank line. Control passes to the remainder of the loop.
    • A line ending character after a blank line denotes the end of the http request block. This results in the generation of an HTTP response block. This is constructed via a sequence of client.println() statements to write the header and the HTML page with the readings from the channels.
    • When all the data has been written to the connection the connection is closed.

    The rest of the main loop handles to data channels.

    • If no power is flowing through a meter its LED will be lit continuously. A call to the millis() function gives the number of milliseconds since the Arduino was powered on. By calling this function and saving the value the code calculates the duration of the LED light pulse. Most are short but a ‘pulse’ longer than NO_POWER_THRESHOLD (set to 10 seconds) is used to set a boolean variable called chanX_no+power (where X is 1 or 2).
    • The chanX_pulse is added to the pulses running total and immediately cleared.
    • Using the values from the millis() function a simple state machine is used to determine the phase of the day.
      • Night time is easily detected by the absence of any power flowing from the panels. Its LED is on continuously.
      • Dawn is determined by the first pulse while in ‘Night’. However noise on the sensor or its wiring can create a false trigger so if another pulse fails to be detected then the state moves back to Night.
      • Dawn continues for a fixed length of time (DAY_THRESHOLD) and as long as the meter’s LED remains off.
      • Day continues as long as the panel meter’s LED remains off. This implies some power is flowing. On a dull day this may not be much so the time between LED pulses will be long.
      • Dusk is triggered by the panel’s meter LED coming on continuously. If the LED goes out then the state reverts to Day otherwise, after NIGHT_THRESHOLD milliseconds the state moves to Night. The remainder of the loop calculates some totals such as the total power seen by each channel for the previous night and the previous day and running totals for the current night and day.

References

  1. Arduino Ethernet Library