# Power Consumption Logger
![[power_consumption_logger_2.png]]
## Overview
This is a simple embedded program that was intended to monitor the power operation of a heated floor unit. The idea was that it would periodically check if a pin was powered, and by extension, if the heating unit was active. This information was logged in CSV format to an attached SD card along with ambient temperature and a timestamp using an attached real time clock (RTC) module.
It all ended up being a bit more involved than I expected, but it did work in the end. This was designed to run on an [[Arduino]] Uno, and it pushed it's program memory capacity to the limit — I think it would've been the dynamic part of its RAM, which had 2KB or so. I had to optimize certain aspects of the program so that it didn't exhaust the RAM during runtime.
> [!done] Some Successes
> \+ Full utilization of system resources with a variety of modules, including a real time clock, SD card, hardware timer, and temperature sensor
> \+ Combined 3D printing, wiring, embedded programming, and new tools into a complete solution
> [!warning] Some Things That Could Be Improved
> \- While cost was a consideration, this solution could probably be reconsidered to be more intuitive — wireless logging via the Internet, etc.
> \- The program itself could almost certainly be optimized further
## Sources
[GitHub Repo Link](https://github.com/TheWhetherMan/arduino-power-logger)
## Code Samples
The entire program is given below:
```c
#include <arduino-timer.h>
#include <RTClib.h>
#include <SPI.h>
#include <SD.h>
// *** PINS ***
//const int RTC_PIN_32K = 0; // 32KHz clock output
//const int RTC_PIN_SQW = 0; // Square wave (interrupt)
//const int RTC_PIN_SCL = 0; // Serial clock line
//const int RTC_PIN_SDA = 0; // Serial data line
const byte SD_PIN_MISO = 12; // Master-in, slave-out
const byte SD_PIN_MOSI = 11; // Master-out, slave-in
const byte SD_PIN_SCK = 13; // Serial clock
const byte SD_PIN_CS = 4; // Chip select
const byte TEMP_PIN = 0; // Temperature sensor
const byte LED_PIN = 7; // Indicator LED
const byte CIRCUIT_PIN = 2; // Read state pin
// *** TEMPERATURE ***
float lastTemperature;
// *** RTC / TIME ***
char timeBuffer[20];
char monthDayBuffer[4];
RTC_DS3231 rtc;
// *** SD / LOGGING ***
const String FILE_NAME_BASE = "logs";
File logFile;
// TASKING
auto mainTimer = timer_create_default();
byte circuitState = 0;
void logAndPrint(String message, bool logTime = false, bool logToFile = true)
{
message = logTime
? readTimeToBuffer() + ": " + message
: message;
Serial.println(message);
message = message + "\r\n";
if (logToFile)
{
String filename = FILE_NAME_BASE + String(monthDayBuffer) + ".txt";
if (logFile = SD.open(filename, FILE_WRITE))
{
char logBuffer[message.length()];
message.toCharArray(logBuffer, message.length());
logFile.write(logBuffer);
logFile.flush();
logFile.close();
}
else
{
Serial.println(F("SD OPEN ERROR"));
}
}
}
String readTemperatureSensor()
{
float voltage = (analogRead(TEMP_PIN) * 5.0) / 1024;
float temperatureF = (((voltage - 0.5) * 100) * 9.0 / 5.0) + 32.0;
return String(temperatureF);
}
String readTimeToBuffer()
{
DateTime current = rtc.now();
sprintf(timeBuffer, "%02d:%02d:%02d %02d/%02d/%02d",
current.hour(), current.minute(), current.second(),
current.day(), current.month(), current.year());
sprintf(monthDayBuffer, "%02d%02d", current.month(), current.day());
return timeBuffer;
}
bool mainTimerCallback()
{
digitalWrite(LED_PIN, HIGH);
if (digitalRead(CIRCUIT_PIN) == HIGH)
{
circuitState = 0; // HIGH -> Circuit is open, pin is pulled up
}
else
{
circuitState = 1; // LOW -> Circuit is closed, pin is grounded
}
String dataMessage =
readTimeToBuffer() + "," +
readTemperatureSensor() + "," +
circuitState;
logAndPrint(dataMessage);
delay(15);
digitalWrite(LED_PIN, LOW);
return true;
}
// Use once for setting RTC
void setTime()
{
rtc.adjust(DateTime(2020, 2, 4, 21, 58, 00));
//logAndPrint(String(F("RTC updated: ")) + readTimeToBuffer(), false, false);
}
void setup()
{
Serial.begin(9600);
while (!Serial)
{
// Wait for serial connection to open
}
//logAndPrint(F("- BOOT -"), false, false);
pinMode(CIRCUIT_PIN, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
digitalWrite(LED_PIN, HIGH);
rtc.begin();
delay(250);
mainTimer.every(1000 * 10, mainTimerCallback);
if (!SD.begin(10))
{
//logAndPrint(F("Failed to initialize SD card"), false, false);
}
else
{
readTimeToBuffer();
delay(250);
String file = FILE_NAME_BASE + String(monthDayBuffer) + ".txt";
if (SD.exists(file))
{
//logAndPrint("DEL " + file, false, false);
SD.remove(file);
}
//logAndPrint("CREATE " + file, false, false);
logFile = SD.open(file, FILE_READ);
logFile.close();
logAndPrint(F("DATE,TEMP,CLOSED"));
}
digitalWrite(LED_PIN, LOW);
delay(200);
digitalWrite(LED_PIN, HIGH);
delay(200);
digitalWrite(LED_PIN, LOW);
delay(200);
digitalWrite(LED_PIN, HIGH);
delay(200);
digitalWrite(LED_PIN, LOW);
// DEBUG
//logAndPrint("TIME " + readTimeToBuffer(), false, false);
//logAndPrint("TEMP " + readTemperatureSensor() + "F", false, false);
//logAndPrint(F("- STARTED -"), false, false);
}
void loop()
{
mainTimer.tick();
}
```
#development #embedded #arduino #projects #sensors