/*******************************
** SOLAR BATTERY CONTROLLING **
******************************/
void checkSolarBatteryStatus()
{
// Retrieve battery state by measuring
// corresponding input pin (maximum
// value is 1024 which means that whole
// reference voltage of 5 volts is applied)
int nBatteryVoltage = analogRead(1);
// Output battery voltage,
// state of switching relay on
// controlling pin (4) as well as
// actual time to serial monitor
// (not required for regular operation)
/*
Serial.print("Current time: ");
Serial.print(now.year(), DEC);
Serial.print(now.month(), DEC);
Serial.print(now.day(), DEC);
Serial.print(now.hour(), DEC);
Serial.print(now.minute(), DEC);
Serial.print(now.second(), DEC);
Serial.print(" / ");
Serial.print("Battery voltage: ");
Serial.print(nBatteryVoltage, DEC);
Serial.print(" -- Solar circuit voltage: ");
Serial.print(nSolarCircuitVoltage, DEC);
Serial.print(" -- Relay state: ");
Serial.println((bSolarCircuitState ? "ON" : "OFF"));
*/
// If battery is fully charged,
// solar system circuit is currently OFF
// (650 counts equals to 13.73 V)
// and no external control commands were applied
if (!bSolarCircuitState && cExternalControl != 'n' && (nBatteryVoltage > 650 || cExternalControl == '1' || cExternalControl == 'y'))
{
// Increase counter if not triggered externally
// (to avoid unwanted triggering by short interferences)
nSolarSystemCheckSecurityHighVoltage++;
if (nSolarSystemCheckSecurityHighVoltage > 10 || cExternalControl == '1' || cExternalControl == 'y')
{
// Trigger current switching relay
// to turn solar system circuit ON
digitalWrite(4, HIGH);
// Setup variables for a wait loop (see below)
// to allow for switching relay operation
bSolarRelayActive = true;
nWaitCyclesUntilSolarRelayReset = 2;
}
}
else
{
// Reset counter which avoids triggering via
// temporary external interferences
nSolarSystemCheckSecurityHighVoltage = 0;
}
// If battery is depleted,
// solar system circuit is currently ON
// (613 counts equals to 12.94 V)
// and no external control commands were applied
if(bSolarCircuitState && cExternalControl != 'y' && (nBatteryVoltage < 613 || cExternalControl == '0' || cExternalControl == 'n'))
{
// Increase counter if not triggered externally
// (to avoid unwanted triggering by short interferences)
nSolarSystemCheckSecurityLowVoltage++;
if (nSolarSystemCheckSecurityLowVoltage > 10 || cExternalControl == '0' || cExternalControl == 'n')
{
// Trigger current switching relay
// to turn solar system circuit OFF
digitalWrite(4, HIGH);
// Setup variables for a wait loop (see below)
// to allow for switching relay operation
bSolarRelayActive = true;
nWaitCyclesUntilSolarRelayReset = 2;
}
}
else
{
// Reset counter which avoids triggering via
// temporary external interferences
nSolarSystemCheckSecurityLowVoltage = 0;
}
// Decrement relay activation wait counter
// (as whole function is called only once a second
// this means 2 seconds of relay activity)
if (bSolarRelayActive && nWaitCyclesUntilSolarRelayReset > 0)
{
nWaitCyclesUntilSolarRelayReset--;
}
// Deactivate solar circuit switching relay
if (bSolarRelayActive && nWaitCyclesUntilSolarRelayReset == 0)
{
digitalWrite(4, LOW);
bSolarRelayActive = false;
}
// Reset external control request flag
// in case of SOFT toggling or clearing request
if (cExternalControl != 'y' && cExternalControl != 'n')
{
cExternalControl = ' ';
}
}
/******************************
** BMS SERIAL COMMUNICATION **
******************************/
void readBMSData()
{
while (BMS.available() > 0)
{
// Read data from battery monitoring system
cBMSSerialChar = BMS.read();
// If carriage return character received
// and value of a certain property is next
// data block to expect
if (cBMSSerialChar == '\r' && bValueNext)
{
// Store battery information provided by
// BMS in floats corresponding to properties
if (sPropertyBuffer == "V")
fVolts = atof(aValueBuffer) / 1000;
else if (sPropertyBuffer == "I")
fAmps = atof(aValueBuffer) / 1000;
else if (sPropertyBuffer == "SOC")
fSOC = atof(aValueBuffer) / 10;
else if (sPropertyBuffer == "H4")
nCycles = atoi(aValueBuffer);
else if (sPropertyBuffer == "H6")
fTotalAh = atof(aValueBuffer) / 1000;
else if (sPropertyBuffer == "H9")
fDaysSinceLastSync = atof(aValueBuffer) / 86400;
// Clear buffer values
sPropertyBuffer = "";
for (int i = 0; i <= 8; i++)
aValueBuffer[i] = ' ';
iValueBufferIndex = 0;
}
// In case of a newline character
// next data block will contain a property
else if (cBMSSerialChar == '\n')
{
bPropertyNext = true;
bValueNext = false;
}
// In case of a tabulator character
// next data block will contain a value
// (of the property transmitted before)
else if (cBMSSerialChar == '\t' && bPropertyNext)
{
bPropertyNext = false;
bValueNext = true;
}
// Store incoming property characters
// in corresponding string
else if (bPropertyNext)
{
sPropertyBuffer.concat(cBMSSerialChar);
}
// Store incoming value characters
// in corresponding char array
// (in order to be able to transform it
// to a floating point number by 'atof')
else if (bValueNext)
{
aValueBuffer[iValueBufferIndex] = cBMSSerialChar;
iValueBufferIndex++;
}
}
}
/************************************
** SEND BMS DATA TO SERIAL OUTPUT **
***********************************/
void sendBMSData()
{
// Output board online timer
// (time since last reset)
Serial.print(nBoardOnlineTimer);
Serial.print(";");
// Output all battery data
Serial.print(fVolts,3);
Serial.print(";");
Serial.print(fAmps,3);
Serial.print(";");
Serial.print(fSOC,1);
Serial.print(";");
Serial.print(nCycles);
Serial.print(";");
Serial.print(fTotalAh,3);
Serial.print(";");
Serial.print(fDaysSinceLastSync,2);
Serial.print(";");
// Append current state of solar power circuit
// as well as external control flag
Serial.print(bSolarCircuitState);
Serial.print(";");
Serial.println(cExternalControl);
}
/*********************************
** LOG BMS VALUES (EVERY HOUR) **
********************************/
void logBMSValues()
{
// Output important BMS values
// to serial monitor
// (not required for regular operation)
/*
Serial.print(fVolts,3);
Serial.print(" V - ");
Serial.print(fAmps,3);
Serial.print(" A - ");
Serial.print(fSOC,1);
Serial.print(" % - Cycles: ");
Serial.print(nCycles);
Serial.print(" - Discharge: ");
Serial.print(fTotalAh,3);
Serial.print(" - Last sync: ");
Serial.print(fDaysSinceLastSync,2);
Serial.print(" - Time: ");
Serial.print(oLogTimestamp.year(), DEC);
Serial.print("/");
Serial.print(oLogTimestamp.month(), DEC);
Serial.print("/");
Serial.print(oLogTimestamp.day(), DEC);
Serial.print(" ");
Serial.print(oLogTimestamp.hour(), DEC);
Serial.print(":");
Serial.print(oLogTimestamp.minute(), DEC);
Serial.print(":");
Serial.println(oLogTimestamp.second(), DEC);
*/
// Generate filename dynamically
// so each year a new file gets
// created
// (e.g. log of 2013 = ARCHIVE3.CSV)
char filenameBMSLogYear[] = "BMS/ARCHIVE0.CSV";
filenameBMSLogYear[11] = oLogTimestamp.year()%10 + '0';
// Open file if SD card is present
// and write date as well as the current
// BMS dataset (6 variables) to it
if (bSDCardInitialized)
{
// Set green LED on
digitalWrite(3, HIGH);
File logfileBMS = SD.open(filenameBMSLogYear, FILE_WRITE);
logfileBMS.print(oLogTimestamp.year(), DEC);
logfileBMS.print("/");
logfileBMS.print(oLogTimestamp.month(), DEC);
logfileBMS.print("/");
logfileBMS.print(oLogTimestamp.day(), DEC);
logfileBMS.print(" ");
logfileBMS.print(oLogTimestamp.hour(), DEC);
logfileBMS.print(":");
logfileBMS.print(oLogTimestamp.minute(), DEC);
logfileBMS.print(":");
logfileBMS.print(oLogTimestamp.second(), DEC);
logfileBMS.print(";");
logfileBMS.print(fVolts,3);
logfileBMS.print(";");
logfileBMS.print(fAmps,3);
logfileBMS.print(";");
logfileBMS.print(fSOC,1);
logfileBMS.print(";");
logfileBMS.print(nCycles);
logfileBMS.print(";");
logfileBMS.print(fTotalAh,3);
logfileBMS.print(";");
logfileBMS.print(fDaysSinceLastSync,2);
// Finish dataset with newline
// command and close the file
// (writes buffer to SD card)
logfileBMS.println();
logfileBMS.close();
// Set green LED off
digitalWrite(3, LOW);
}
}