Project showcase
Energy Consumption Logger

Energy Consumption Logger © GPL3+

Counting the energy consumption from the (Ferraris) meter using a reflex optocoupler. The impulses are counted by a Arduino Uno.

  • 3,372 views
  • 0 comments
  • 11 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)

About this project

The Ferraris Energy Meter is an energy meter with a rotating disc. The rotation speed depends on the energy consumption. Counting the rotation will give a value for the current consumption.

The rotating disc has a little black mark on the side. The black mark is detected by a little optocoupler and a comparator which was described here.

The impulses are counted by the Arduino UNO. Every 15 minutes the counter is stored on a SD-Card together with the current timestamp. The counter is reset to zero after this. Therefore the log file will contain 15 minute counts of energy consumption together with date and time of logging.

A RTC is used to store the current date and time even on power loss. The RTC shield also contains a SD-Card interface and some space for your own components. To set the RTC to the correct date and time a Bluetooth module is connected. To save energy this BT module is only powered for 5 minutes after reset or if a button on the RTC shield was pressed. The power line of the BT module is controlled by a transistor which is controlled by one of the Arduino IO ports.


Code

EnergieZaehlerArduino
#include <AltSoftSerial.h>
#include <LowPower.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>
#include <string.h>
#include <stdlib.h>

// logging intervall in minutes
#define INTERVALL     15
// CS pin for SD card
#define CHIPSELECT    10

/* PINS: */
#define PIN_SOFT_RX  8 // soft serial
#define PIN_SOFT_TX  9
#define PIN_CNTR_IN  2 // counter (opto-coupler)
#define PIN_CNTR_OUT 4 // GND for counter opto-coupler
#define PIN_BUTTON   3 // button
#define PIN_LED      7 // LED on card adapter
#define PIN_BT_POWER 6 // power for BT adapter

RTC_DS1307 rtc;
AltSoftSerial mySerial(PIN_SOFT_RX, PIN_SOFT_TX); // RX, TX


volatile unsigned long counterRisingMillis = 0;
volatile int counter = 0;
volatile unsigned long wakeupRisingMillis = 0;
volatile long startUpSeconds = 0;

void handleRTC();
void counterPinRising();
void counterPinFalling();
void wakeupPinRising();
void wakeupPinFalling();
void doDebugOutput(char line, int row, int col);

void setup()
{
	Serial.begin(115200);

	// set the data rate for the SoftwareSerial port
	mySerial.begin(9600);
	mySerial.print("AT");
	delay(1000);
	while (mySerial.available())
		Serial.write(mySerial.read());
	Serial.println();
	mySerial.print("AT+NAMEenergie1");
	delay(1000);
	while (mySerial.available())
		Serial.write(mySerial.read());
	Serial.println();
	mySerial.print("AT+PIN1134");
	delay(1000);
	while (mySerial.available())
		Serial.write(mySerial.read());
	Serial.println();

	Serial.println("Hello from EnergieZaehler. (Send 's')");
	mySerial.println("Hello from EnergieZaehler. (Send 's')");

	if (!rtc.begin())
	{
		doDebugOutput("Couldn't find RTC.", 0, 1);
	}

	if (!rtc.isrunning())
	{
		doDebugOutput("RTC is NOT running.", 0, 1);
	}

	// make sure that the default chip select pin is set to
	// output, even if you don't use it:
	pinMode(CHIPSELECT, OUTPUT);
	// see if the card is present and can be initialized:
	if (!SD.begin(CHIPSELECT))
	{
		doDebugOutput("Card failed.", 0, 1);
	}

	// raise an interrupt whenever PIN 2 sees an L/H change
	// set PIN 2 as INPUT with pull-up
	pinMode(PIN_CNTR_IN, INPUT); //counter
	digitalWrite(PIN_CNTR_IN, HIGH);
	pinMode(PIN_CNTR_OUT, OUTPUT); // GND connection for opto-coupler in ferraris-sensor module
	digitalWrite(PIN_CNTR_OUT, LOW);
	pinMode(PIN_BUTTON, INPUT); // wakeup button
	digitalWrite(PIN_BUTTON, HIGH);
	attachInterrupt(digitalPinToInterrupt(PIN_CNTR_IN), counterPinRising, RISING);
	attachInterrupt(digitalPinToInterrupt(PIN_CNTR_IN), counterPinFalling, FALLING);
	attachInterrupt(digitalPinToInterrupt(PIN_BUTTON), wakeupPinRising, RISING);
	attachInterrupt(digitalPinToInterrupt(PIN_BUTTON), wakeupPinFalling, FALLING);

	pinMode(PIN_BT_POWER, OUTPUT); // BT power
	digitalWrite(PIN_BT_POWER, HIGH);
	pinMode(PIN_LED, OUTPUT); // live led
	digitalWrite(PIN_LED, LOW);

	startUpSeconds = 0;
}

void loop()
{
	static long lastWriteSeconds = 0;
	DateTime now = rtc.now();

	handleRTC(now);

	digitalWrite(PIN_LED, HIGH);
	delayMicroseconds(50);
	digitalWrite(PIN_LED, LOW);

	if (((now.minute() % INTERVALL) == 0) && (now.secondstime() - lastWriteSeconds) > ((INTERVALL - 1) * 60))
	{
		// skip the first write attempt (don't write incomplete data)
		if (lastWriteSeconds == 0)
		{
			doDebugOutput("Skip first write attempt.", 0, 1);
		}
		else
		{
			// open the file. note that only one file can be open at a time,
			// so you have to close this one before opening another.
			File dataFile = SD.open("datalog.txt", FILE_WRITE);
			if (dataFile)
			{
				// if the file is available, write to it:
				char dataString[32];
				sprintf(dataString, "%02d.%02d.%04d %02d:%02d:%02d\t%d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(), counter);
				dataFile.println(dataString);
				dataFile.close();
				doDebugOutput("Wrote datalog.txt.", 0, 1);
			}
			else
			{
				// if the file isn't open, pop up an error:
				doDebugOutput("Error opening datalog.txt", 0, 1);
			}
		}
		lastWriteSeconds = now.secondstime();
		counter = 0;
	}

	if (Serial.available())
	{
		if (Serial.read() == 's')
		{
			char buffer[32];
			sprintf(buffer, "%02d.%02d.%04d %02d:%02d:%02d\t%d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(), counter);
			Serial.println("Current Date/Time, current counter:");
			Serial.println(buffer);
			memset(buffer, 0, sizeof(buffer));
			Serial.readBytesUntil('\n', buffer, sizeof(buffer));
			Serial.print(strlen(buffer), DEC);
			Serial.print(": ");
			Serial.println(buffer);
			if (strlen(buffer) >= 20)
			{
				int DD = atoi(buffer + 1);
				int MM = atoi(buffer + 4);
				int YY = atoi(buffer + 7);
				int hh = atoi(buffer + 12);
				int mm = atoi(buffer + 15);
				int ss = atoi(buffer + 18);
				rtc.adjust(DateTime(YY, MM, DD, hh, mm, ss));
				now = rtc.now();
				sprintf(buffer, "%02d.%02d.%04d %02d:%02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second());
				Serial.println("New Date/Time:");
				Serial.println(buffer);
			}
			else
			{
				Serial.println("To set Date/Time: s DD.MM.YYYY HH:MM:SS");
			}
		}
	}

	if (mySerial.available())
	{
		char chr = mySerial.read();
		if (chr == 's')
		{
			char buffer[32];
			sprintf(buffer, "%02d.%02d.%04d %02d:%02d:%02d\t%d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(), counter);
			mySerial.println("Current Date/Time, current counter:");
			mySerial.println(buffer);
			memset(buffer, 0, sizeof(buffer));
			mySerial.readBytesUntil('\n', buffer, sizeof(buffer));
			mySerial.print(strlen(buffer), DEC);
			mySerial.print(": ");
			mySerial.println(buffer);
			if (strlen(buffer) >= 20)
			{
				int DD = atoi(buffer + 1);
				int MM = atoi(buffer + 4);
				int YY = atoi(buffer + 7);
				int hh = atoi(buffer + 12);
				int mm = atoi(buffer + 15);
				int ss = atoi(buffer + 18);
				rtc.adjust(DateTime(YY, MM, DD, hh, mm, ss));
				now = rtc.now();
				sprintf(buffer, "%02d.%02d.%04d %02d:%02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second());
				mySerial.println("New Date/Time:");
				mySerial.println(buffer);
			}
			else
			{
				mySerial.println("To set Date/Time: s DD.MM.YYYY HH:MM:SS");
			}
		}
	}
}

void doDebugOutput(const char *line, int row, int col)
{
	Serial.println(line);
	mySerial.println(line);
}

void handleRTC(DateTime now)
{
	if (startUpSeconds == 0)
	{
		startUpSeconds = now.secondstime();
	}

	// use low power sleep after 5 minutes up-time (to allow serial communication during the first 5 minutes)
	if ((now.secondstime() - startUpSeconds) > (5 * 60))
	{
		// disable BT module
		digitalWrite(PIN_BT_POWER, LOW);
		LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
	}
	else
	{
		// enable BT module
		digitalWrite(PIN_BT_POWER, HIGH);
		delay(500);
	}
}

// Interrupt Service Routine (ISR)
void counterPinRising()
{
	counterRisingMillis = millis();
}

void counterPinFalling()
{
	// we need a signal of at least 20 ms length
	if ((millis() - counterRisingMillis) > 20)
		counter++;
}

void wakeupPinRising()
{
	wakeupRisingMillis = millis();
}

void wakeupPinFalling()
{
	// we need a signal of at least 20 ms length
	if ((millis() - wakeupRisingMillis) > 20)
		startUpSeconds = 0;
}

Schematics

Prinzip.png
Prinzip

Comments

Similar projects you might like

Energy Data Logger

Project in progress by Javi D'Ambra

  • 3,689 views
  • 5 comments
  • 9 respects

Temperature and Humidity Logger (Using Arduino)

Project showcase by lmsousa

  • 7,770 views
  • 3 comments
  • 34 respects

Mobile Weather Station Being Powered by Solar Energy

Project tutorial by Kutluhan Aktar

  • 2,543 views
  • 0 comments
  • 12 respects

SmartPhone Controlled RGB MOOD Light

Project tutorial by Prajjwal Nag

  • 3,924 views
  • 1 comment
  • 10 respects

Countdown Timer

Project tutorial by Prasantha Jayakody

  • 18,593 views
  • 13 comments
  • 31 respects
Add projectSign up / Login