.cpp
file in the respective folders. For example, anything dealing with the battery management system (BMS) should go in the src/devices/bms
(things could change but general idea)..cpp
files that you create require a [name].cpp
and a [name].h
file. For the [name].h
you should organize your files like this.#ifndef BATTMANAGE_H_
#define BATTMANAGE_H_
#include <Arduino.h>
#include "../../config.h"
#include "../Device.h"
class BatteryManagerConfiguration : public DeviceConfiguration {
public:
float packCapacity;
float packAHRemaining;
float highVoltLimit;
float lowVoltLimit;
float highCellLimit;
float lowCellLimit;
float highTempLimit;
float lowTempLimit;
};
class BatteryManager : public Device {
public:
BatteryManager();
~BatteryManager();
float getPackVoltage();
float getPackCurrent();
float getSOC();
float getHighestTemperature();
float getLowestTemperature();
DeviceType getType();
void setup();
void handleTick();
void loadConfiguration();
void saveConfiguration();
//a bunch of boolean functions. Derived classes must implment
//these functions to tell everyone else what they support
virtual bool hasPackVoltage() = 0;
virtual bool hasPackCurrent() = 0;
virtual bool hasTemperatures() = 0;
virtual bool isChargeOK() = 0;
virtual bool isDischargeOK() = 0;
protected:
float packVoltage;
float packCurrent;
float SOC; //state of charge in percent
float lowestCellV, highestCellV;
float lowestCellTemp, highestCellTemp;
//should be some form of discharge and charge limit. I don't know if it should be % or amps
//some BMS systems will report one way and some the other.
int dischargeLimit, chargeLimit;
bool allowCharge, allowDischarge;
private:
};
#endif
Key notes when setting up the .h
file.
DeviceConfiguration
. The DeviceConfiguration should contain instance variables of all the ways that you would like to set the settings of the device. For example, if we’re making a fan device some examples of instance variables in the DeviceConfiguration
class would be like maxFanVoltage, minFanVoltage, etc. These are typically variables that are not changed often and only changed periodically. (Not a physical reason but more of a code styling reason.BatteryManager
class, this is where all of the brain of the device class should go. Must have’s include:
For the .cpp
file you should write all of the necessary Constructor, Destructor, and initializing of functions. An example is below
#include "BatteryManager.h"
BatteryManager::BatteryManager() : Device()
{
packVoltage = 0;
packCurrent = 0;
SOC = 0;
}
BatteryManager::~BatteryManager()
{
}
DeviceType BatteryManager::getType() {
return (DEVICE_BMS);
}
void BatteryManager::handleTick() {
}
void BatteryManager::setup() {
BatteryManagerConfiguration *config = (BatteryManagerConfiguration *) getConfiguration();
ConfigEntry entry;
entry = {"CAPACITY", "Capacity of battery pack in ampere-hours", &config->packCapacity, CFG_ENTRY_VAR_TYPE::FLOAT, {.floating = 0.0}, {.floating = 100000.0}, 2, nullptr};
cfgEntries.push_back(entry);
entry = {"VOLTLIMHI", "High limit for pack voltage in volts", &config->highVoltLimit, CFG_ENTRY_VAR_TYPE::FLOAT, {.floating = 0.0}, {.floating = 800.0}, 1, nullptr};
cfgEntries.push_back(entry);
entry = {"VOLTLIMLO", "Low limit for pack voltage in volts", &config->lowVoltLimit, CFG_ENTRY_VAR_TYPE::FLOAT, {.floating = 0.0}, {.floating = 800.0}, 1, nullptr};
cfgEntries.push_back(entry);
entry = {"CELLLIMHI", "High limit for cell voltage in volts", &config->highCellLimit, CFG_ENTRY_VAR_TYPE::FLOAT, {.floating = 0.0}, {.floating = 5.0}, 3, nullptr};
cfgEntries.push_back(entry);
entry = {"CELLLIMLO", "Low limit for cell voltage in hundredths of a volt", &config->lowCellLimit, CFG_ENTRY_VAR_TYPE::FLOAT, {.floating = 0.0}, {.floating = 5.0}, 3, nullptr};
cfgEntries.push_back(entry);
entry = {"TEMPLIMHI", "High limit for pack and cell temperature in degrees C", &config->highTempLimit, CFG_ENTRY_VAR_TYPE::FLOAT, {.floating = 0.0}, {.floating = 255.0}, 1, nullptr};
cfgEntries.push_back(entry);
entry = {"TEMPLIMLO", "Low limit for pack and cell temperature in degrees C", &config->lowTempLimit, CFG_ENTRY_VAR_TYPE::FLOAT, {.floating = -255.0}, {.floating = 255.0}, 1, nullptr};
cfgEntries.push_back(entry);
#ifndef USE_HARD_CODED
if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM
}
else { //checksum invalid. Reinitialize values and store to EEPROM
//prefsHandler->saveChecksum();
}
#else
#endif
//TickHandler::getInstance()->detach(this);
//TickHandler::getInstance()->attach(this, CFG_TICK_INTERVAL_MOTOR_CONTROLLER_DMOC);
}
float BatteryManager::getPackVoltage()
{
return packVoltage;
}
float BatteryManager::getPackCurrent()
{
return packCurrent;
}
float BatteryManager::getSOC()
{
return SOC;
}
float BatteryManager::getHighestTemperature()
{
return highestCellTemp;
}
float BatteryManager::getLowestTemperature()
{
return lowestCellTemp;
}
void BatteryManager::loadConfiguration() {
BatteryManagerConfiguration *config = (BatteryManagerConfiguration *)getConfiguration();
Device::loadConfiguration(); // call parent
//if (prefsHandler->checksumValid()) { //checksum is good, read in the values stored in EEPROM
prefsHandler->read("Capacity", &config->packCapacity, 100.0f);
prefsHandler->read("AHRemaining", &config->packAHRemaining, 50.0f);
prefsHandler->read("HVHighLim", &config->highVoltLimit, 385.0f);
prefsHandler->read("HVLowLim", &config->lowVoltLimit, 240.0f);
prefsHandler->read("CellHiLim", &config->highCellLimit, 3.900f);
prefsHandler->read("CellLowLim", &config->lowCellLimit, 2.400f);
prefsHandler->read("TempHighLim", &config->highTempLimit, 60.0f);
prefsHandler->read("TempLowLim", &config->lowTempLimit, -20.0f);
}
void BatteryManager::saveConfiguration() {
BatteryManagerConfiguration *config = (BatteryManagerConfiguration *)getConfiguration();
Device::saveConfiguration(); // call parent
prefsHandler->write("AHRemaining", config->packAHRemaining);
prefsHandler->write("Capacity", config->packCapacity);
prefsHandler->write("HVHighLim", config->highVoltLimit);
prefsHandler->write("HVLowLim", config->lowVoltLimit);
prefsHandler->write("CellHiLim", config->highCellLimit);
prefsHandler->write("CellLowLim", config->lowCellLimit);
prefsHandler->write("TempHighLim", config->highTempLimit);
prefsHandler->write("TempLowLim", config->lowTempLimit);
prefsHandler->saveChecksum();
}
rawSignal.input1 = systemIO.getAnalogIn(5);