/*
* Battery Box software by Robert Nancarrow
*
* 2019/03/27 V1.0 Initial Version Rebuilt
* 2019/03/30 V1.1 Adjusted screen initialisation method
* 2019/04/12 V1.2 Backlight dimming
* 2019/10/11 V1.3 Watchdog implemented to control lockup
*
*
*
*
*
*
*
*
*/
#include <SoftwareSerial.h>
#include <SPI.h>
#include "Ucglib.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#include <avr/wdt.h>
#define receivedStringLength 80
#define vHEXLength14 14
#define vHEXLength12 12
#define vHEXLength8 8
#define vHEXLength78 78
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
Ucglib_ILI9341_18x240x320_HWSPI ucg(/*cd=*/ 7, /*cs=*/ 10, /*reset=*/ 8);
SoftwareSerial Victron = {SoftwareSerial(A3,A2)};
int fanPin = 9;
int fanSpeed = 0;
//int blPin = 6;
//int blPWM = 255; //start off
//const int lightNumReadings = 10;
//int lightReadings[lightNumReadings]; // the readings from the analog input
//int lightReadIndex = 0; // the index of the current reading
//int lightTotal = 0; // the running total
int lightAverage = 0; // the average
int lightPin = A0;
char receivedBuffer[receivedStringLength];
const char getMPPTConsumptionHistory_0[] PROGMEM = ":7501000EE\n"; // 0
const char getMPPTConsumptionHistory_1[] PROGMEM = ":7511000ED\n"; // 1
const char getMPPTConsumptionHistory_2[] PROGMEM = ":7521000EC\n"; // 2
const char getMPPTConsumptionHistory_3[] PROGMEM = ":7531000EB\n"; // 3
const char getMPPTConsumptionHistory_4[] PROGMEM = ":7541000EA\n"; // 4
const char getMPPTConsumptionHistory_5[] PROGMEM = ":7551000E9\n"; // 5
const char getMPPTConsumptionHistory_6[] PROGMEM = ":7561000E8\n"; // 6
const char getMPPTConsumptionHistory_7[] PROGMEM = ":7571000E7\n"; // 7
const char getMPPTConsumptionHistory_8[] PROGMEM = ":7581000E6\n"; // 8
const char getMPPTConsumptionHistory_9[] PROGMEM = ":7591000E5\n"; // 9
const char getMPPTConsumptionHistory_10[] PROGMEM = ":75A1000E4\n"; // 10
const char getMPPTConsumptionHistory_11[] PROGMEM = ":75B1000E3\n"; // 11
const char getMPPTConsumptionHistory_12[] PROGMEM = ":75C1000E2\n"; // 12
const char getMPPTConsumptionHistory_13[] PROGMEM = ":75D1000E1\n"; // 13
const char getMPPTConsumptionHistory_14[] PROGMEM = ":75E1000E0\n"; // 14
const char getMPPTConsumptionHistory_15[] PROGMEM = ":75F1000DF\n"; // 15
const char getMPPTConsumptionHistory_16[] PROGMEM = ":7601000DE\n"; // 16
const char getMPPTConsumptionHistory_17[] PROGMEM = ":7611000DD\n"; // 17
const char getVictronChargerVolts[] PROGMEM = ":7D5ED008C\n"; //18
const char getVictronChargerCurrent[] PROGMEM = ":7D7ED008A\n"; //19
const char getVictronLoadCurrent[] PROGMEM = ":7ADED00B4\n"; //20
const char getVictronIntTemp[] PROGMEM = ":7DBED0086\n"; //21
const char getVictronErrorCode[] PROGMEM = ":7DAED0087\n"; //22
const char getVictronPanelVolts[] PROGMEM = ":7BBED00A6\n"; //23
const char getVictronDeviceMode[] PROGMEM = ":7000200004C\n"; //24
const char getVictronDeviceState[] PROGMEM = ":70102004B\n"; //25
const char getVictronDeviceID[] PROGMEM = ":70001004D\n"; //26
const char getVictronDeviceVersion[] PROGMEM = ":154\n"; //27
const char * const VictronHEXRequest[] PROGMEM =
{
getMPPTConsumptionHistory_0,
getMPPTConsumptionHistory_1,
getMPPTConsumptionHistory_2,
getMPPTConsumptionHistory_3,
getMPPTConsumptionHistory_4,
getMPPTConsumptionHistory_5,
getMPPTConsumptionHistory_6,
getMPPTConsumptionHistory_7,
getMPPTConsumptionHistory_8,
getMPPTConsumptionHistory_9,
getMPPTConsumptionHistory_10,
getMPPTConsumptionHistory_11,
getMPPTConsumptionHistory_12,
getMPPTConsumptionHistory_13,
getMPPTConsumptionHistory_14,
getMPPTConsumptionHistory_15,
getMPPTConsumptionHistory_16,
getMPPTConsumptionHistory_17,
getVictronChargerVolts,
getVictronChargerCurrent,
getVictronLoadCurrent,
getVictronIntTemp,
getVictronErrorCode,
getVictronPanelVolts,
getVictronDeviceMode,
getVictronDeviceState,
getVictronDeviceID,
getVictronDeviceVersion
};
const unsigned int VictronHEXLength[] =
{
vHEXLength78, //getMPPTConsumptionHistory_0,
vHEXLength78, //getMPPTConsumptionHistory_1,
vHEXLength78, //getMPPTConsumptionHistory_2,
vHEXLength78, //getMPPTConsumptionHistory_3,
vHEXLength78, //getMPPTConsumptionHistory_4,
vHEXLength78, //getMPPTConsumptionHistory_5,
vHEXLength78, //getMPPTConsumptionHistory_6,
vHEXLength78, //getMPPTConsumptionHistory_7,
vHEXLength78, //getMPPTConsumptionHistory_8,
vHEXLength78, //getMPPTConsumptionHistory_9,
vHEXLength78, //getMPPTConsumptionHistory_10,
vHEXLength78, //getMPPTConsumptionHistory_11,
vHEXLength78, //getMPPTConsumptionHistory_12,
vHEXLength78, //getMPPTConsumptionHistory_13,
vHEXLength78, //getMPPTConsumptionHistory_14,
vHEXLength78, //getMPPTConsumptionHistory_15,
vHEXLength78, //getMPPTConsumptionHistory_16,
vHEXLength78, //getMPPTConsumptionHistory_17,
vHEXLength14, //getVictronChargerVolts, 18
vHEXLength14, //getVictronChargerCurrent, 19
vHEXLength14, //getVictronLoadCurrent, 20
vHEXLength14, //getVictronIntTemp, 21
vHEXLength12, //getVictronErrorCode, 22
vHEXLength14, //getVictronPanelVolts, 23
vHEXLength12, //getVictronDeviceMode, 24
vHEXLength12, //getVictronDeviceState, 25
vHEXLength14, //getVictronDeviceID, 26
vHEXLength8, //getVictronDeviceVersion 27
};
unsigned long consumptionHistory[18];
unsigned long yieldHistory[18];
// Variables for Temperature (Both case & Victron)
const int numReadingsDallas = 30;
float readingsDallas[numReadingsDallas]; // the readings from the analog input
int readIndexDallas = 0; // the index of the current reading
float totalDallas = 0; // the running total
float averageDallas = 0; // the average
float tempReadingLast = 999;
unsigned long chargerVoltage = 0;
unsigned long chargerVoltagePrev = 999;
unsigned long loadCurrent = 0;
unsigned long loadCurrentPrev = 999;
unsigned long chargerCurrent = 0;
long battCurrent = 0;
long battCurrentPrev = 999;
unsigned long deviceState = 0;
unsigned long deviceStatePrev = 999;
unsigned long panelVoltage = 0;
unsigned long panelVoltagePrev = 999;
float panelPower = 0;
float panelPowerPrev = 999;
unsigned long chargerTemp = 0;
unsigned long chargerTempPrev = 999;
unsigned long errorCode = 0;
unsigned long errorCodePrev = 999;
unsigned long deviceIDInt = 0;
unsigned long deviceIDIntPrev = 999;
char deviceVersion[4];
char deviceVersionPrev[4];
int warnLvlBit = 0;
int initialiseLCD = 1;
int initialiseFan = 1;
unsigned long heartbeatMillisPrev = 0;
boolean heartbeatBit = true;
unsigned long yieldTodayPrev = 999;
unsigned long consumptionTodayPrev = 999;
unsigned long mainOldMillis = 0;
void setup() {
TCCR1B = (TCCR1B & 0b11111000) | 0x05; //PWM freq for fan speed
watchdogSetup();
pinMode(fanPin, OUTPUT); // Set pin for output to control TIP120 Base pin
digitalWrite(fanPin, LOW);
/*
* BACKLIGHT SECTION
pinMode(blPin, OUTPUT);
analogWrite(blPin, blPWM);
*/
Victron.begin(19200);
// put your setup code here, to run once:
ucg.begin(UCG_FONT_MODE_TRANSPARENT);
ucg.setRotate90();
for (int thisReading = 0; thisReading < numReadingsDallas; thisReading++) {
readingsDallas[thisReading] = 0;
}
//for (int lightThisReading = 0; lightThisReading < lightNumReadings; lightThisReading++) {
// lightReadings[lightThisReading] = 0;
//}
populateHistory(18);
}
void watchdogSetup(void) {
cli(); // disable all interrupts
wdt_reset(); // reset the WDT timer
/*
WDTCSR configuration:
WDIE = 0: Interrupt Disable
WDE = 1 :Reset Enable
WDP3 = 1 :For 8000ms Time-out
WDP2 = 0 :For 8000ms Time-out
WDP1 = 0 :For 8000ms Time-out
WDP0 = 1 :For 8000ms Time-out
*/
// Enter Watchdog Configuration mode:
WDTCSR |= (1<<WDCE) | (1<<WDE);
// Set Watchdog settings:
WDTCSR = (0<<WDIE) | (1<<WDE) | (1<<WDP3) | (0<<WDP2) | (0<<WDP1) | (1<<WDP0);
sei();
}
void loop() {
wdt_reset();
runFan();
/*
* BACKLIGHT SECTION
//backlight();
*/
if (initialiseLCD == 1) {
ucg.clearScreen();
buildWindows();
}
getVictron();
getDallas();
populateHistory(1);
//errorCode = 167;
// BATTERY VOLTAGE //
if (chargerVoltage != chargerVoltagePrev || initialiseLCD == 1) {
if (chargerVoltage == 0) {
warnLvlBit = 0;
}
else {
warnLvlBit = 1;
}
drawTextBox(1,80,23,72,24,NULL,chargerVoltage,100,2,warnLvlBit,8);
chargerVoltagePrev = chargerVoltage;
}
// BATTERY CURRENT CALCULATED//
battCurrent = chargerCurrent - loadCurrent;
if (battCurrent != battCurrentPrev || initialiseLCD == 1) {
if (battCurrent < 0) {
warnLvlBit = 3;
}
else if (battCurrent > 0) {
warnLvlBit = 4;
}
else if (battCurrent == 0) {
warnLvlBit = 0;
}
else {
warnLvlBit = 1;
}
drawTextBox(1,80,49,72,24,NULL,battCurrent,10,2,warnLvlBit,8);
battCurrentPrev = battCurrent;
}
// LOAD CURRENT //
if (loadCurrent != loadCurrentPrev || initialiseLCD == 1) {
if (loadCurrent < 0) {
warnLvlBit = 4;
}
else if (loadCurrent > 0) {
warnLvlBit = 3;
}
else if (loadCurrent == 0) {
warnLvlBit = 0;
}
else {
warnLvlBit = 1;
}
drawTextBox(initialiseLCD,239,23,75,24,NULL,loadCurrent,10,2,warnLvlBit,8);
drawProgressBar(initialiseLCD,0,15000,loadCurrent*100, 165 , 49 , 148 , 20 ,255, 130, 0, 255, 0, 0);
loadCurrentPrev = loadCurrent;
}
// DEVICE STATE - BATTERY CHARGE STATE //
if (deviceState != deviceStatePrev || initialiseLCD == 1) {
if (deviceState == 0) {
drawTextBox(1,80,75,72,24," OFF",NULL,1,0,0,8);
}
else if (deviceState == 2) {
drawTextBox(1,80,75,72,24,"FAULT",NULL,1,0,1,8);
}
else if (deviceState == 3) {
drawTextBox(1,80,75,72,24," BULK",NULL,1,0,1,8);
}
else if (deviceState == 4) {
drawTextBox(1,80,75,72,24,"ABSRB",NULL,1,0,1,8);
}
else if (deviceState == 5) {
drawTextBox(1,80,75,72,24,"FLOAT",NULL,1,0,1,8);
}
else if (deviceState == 7) {
drawTextBox(1,80,75,72,24,"EQUAL",NULL,1,0,1,8);
}
else {
drawTextBox(1,80,75,72,24,NULL,deviceState,1,0,warnLvlBit,8);
}
deviceStatePrev = deviceState;
}
// SOLAR PANEL VOLTAGE //
if (panelVoltage != panelVoltagePrev || initialiseLCD == 1) {
if (panelVoltage == 0) {
warnLvlBit = 0;
}
else {
warnLvlBit = 1;
}
drawTextBox(1,80,130,72,24,NULL,panelVoltage,100,2,warnLvlBit,8);
panelVoltagePrev = panelVoltage;
}
// SOLAR PANEL POWER - WATTAGE - CALCULATED //
if ((panelVoltage > 0) && (chargerCurrent > 0)) {
float pV = float(min(panelVoltage,9999));
float cC = float(min(chargerCurrent,9999));
pV /= 100;
cC /= 10;
panelPower = pV * cC;
}
else {
panelPower = 0;
}
if (panelPower != panelPowerPrev || initialiseLCD == 1) {
if (panelPower == 0) {
warnLvlBit = 0;
}
else {
warnLvlBit = 1;
}
drawTextBox(initialiseLCD,80,155,72,24,NULL,panelPower,1,0,warnLvlBit,8);
panelPowerPrev = panelPower;
}
// SYSTEM BOX //
if (errorCode <= 0) {
drawHeartbeat();
}
if (chargerTemp != chargerTempPrev || averageDallas != tempReadingLast || errorCode != errorCodePrev || initialiseLCD == 1) {
if (errorCode > 0) {
drawTextBox(initialiseLCD,6,210,146,25,NULL,NULL,0,0,5,8);
ucg.setFont(ucg_font_tpss_hr);
ucg.setPrintPos(9,222);
ucg.print(F("ERR: "));
ucg.setFont(ucg_font_tpssb_hn);
ucg.print(errorCode);
}
else {
drawTextBox(initialiseLCD,6,210,146,25,NULL,NULL,0,0,4,8);
ucg.setFont(ucg_font_tpss_hr);
ucg.setPrintPos(9,222);
ucg.print(F("ERR: "));
//ucg.setFont(ucg_font_tpssb_hn);
//ucg.print(F("OK"));
drawHeartbeat();
}
//ucg.setColor(0, 0, 0);
ucg.setFont(ucg_font_tpss_hr);
ucg.setPrintPos(9,232);
ucg.print(getDeviceID(deviceIDInt));
ucg.print(F(" v"));
ucg.print(deviceVersion[3]);
ucg.print(F("."));
ucg.print(deviceVersion[0]);
ucg.print(deviceVersion[1]);
ucg.setPrintPos(60,222);
ucg.print(F("TEMP: "));
ucg.setFont(ucg_font_tpssb_hn);
ucg.print(averageDallas,1); //internal
ucg.setFont(ucg_font_tpss_hr);
ucg.print(F("/"));
ucg.setFont(ucg_font_tpssb_hn);
ucg.print((float)chargerTemp/100,1); //external
errorCodePrev = errorCode;
tempReadingLast = averageDallas;
chargerTempPrev = chargerTemp;
}
// YIELD & CONSUMPTION //
if (yieldHistory[0] != yieldTodayPrev || consumptionHistory[0] != consumptionTodayPrev || millis() - mainOldMillis > 60000 || initialiseLCD == 1) {
mainOldMillis = millis();
populateHistory(18);
drawTextBox(initialiseLCD,165,100,149,83,NULL,NULL,1,0,2,8);
drawTextBox(initialiseLCD,202,185,52,24,NULL,yieldHistory[0],100,2,1,3);
drawTextBox(initialiseLCD,262,185,52,24,NULL,consumptionHistory[0],100,2,1,3);
int totalYield = 0;
int totalConsumption = 0;
for (int i=0; i< 18; i++)
{
totalYield += yieldHistory[i];
totalConsumption += consumptionHistory[i];
}
drawTextBox(initialiseLCD,202,211,52,24,NULL,totalYield,100,2,1,3);
drawTextBox(initialiseLCD,262,211,52,24,NULL,totalConsumption,100,2,1,3);
//1 - set the maximum values that we will be working with
//Doesn't matter if it's the yield or consumption because they're the same units
int totalBars = 18; //29
int maxValue = maxValHist(totalBars);
//Serial.println(maxValue);
int pxBarWidth = 7;//4
//int pxBarHeight = 0; //for each bar- might not need this
int pxBarHeightMax = 77; //the pixel height limit
int yPosBase = 103; //the base layer is going to be this valye PLUS the max bar height
int pxBarSpace = 1; //space between bars
int xPos = 168;
//int i;
for (int i = 0; i < totalBars; i++) {
int pxBarHeightC = min(map(consumptionHistory[i], 0, maxValue, 0, pxBarHeightMax),pxBarHeightMax);
int pxBarHeightY = min(map(yieldHistory[i], 0, maxValue, 0, pxBarHeightMax),pxBarHeightMax);
int yPosC = (yPosBase + pxBarHeightMax) - pxBarHeightC;
int yPosY = (yPosBase + pxBarHeightMax) - pxBarHeightY;
//pxBarHeight = pxBarHeightMax - pxBarHeight;
//Serial.println(consumptionHistory[i]);
//Serial.println(pxBarHeight);
if (consumptionHistory[i] > yieldHistory[i]) {
setYieldGradCol();
ucg.drawGradientBox(xPos, yPosC, pxBarWidth, pxBarHeightC);
setConsGradCol();
ucg.drawGradientBox(xPos, yPosY, pxBarWidth, pxBarHeightY);
}
else if (yieldHistory[i] > consumptionHistory[i]) {
setConsGradCol();
ucg.drawGradientBox(xPos, yPosY, pxBarWidth, pxBarHeightY);
setYieldGradCol();
ucg.drawGradientBox(xPos, yPosC, pxBarWidth, pxBarHeightC);
}
else {
setNeutralGradCol();
ucg.drawGradientBox(xPos, yPosY, pxBarWidth, pxBarHeightY);
}
//ucg.drawBox(xPos, yPos, pxBarWidth, pxBarHeight);
xPos += (pxBarWidth + pxBarSpace);
}
yieldTodayPrev = yieldHistory[0];
consumptionTodayPrev = consumptionHistory[0];
}
//delay(1000);
initialiseLCD = 0;
//wdt_reset();
}
/*
void backlight() {
if (initialiseLCD == 1) {
blPWM = 255;
}
else {
if (errorCode > 0) {
blPWM = 0;
}
else {
lightAverage = max(min(analogRead(lightPin),300),15);
blPWM = map(lightAverage, 15, 300, 240, 0);
}
}
analogWrite(blPin, blPWM);
}
*/
int maxValHist(int noRecords) {
int maxVal;
int i;
for (i = 0; i < noRecords; i++) {
if (yieldHistory[i] > consumptionHistory[i]) {
if (yieldHistory[i] > maxVal) {
maxVal = yieldHistory[i];
}
}
else {
if (consumptionHistory[i] > maxVal) {
maxVal = consumptionHistory[i];
}
}
}
return maxVal;
}
void setConsGradCol() {
ucg.setColor(0, 0, 255, 0);
ucg.setColor(1, 0, 255, 0);
ucg.setColor(2, 240, 255, 0);
ucg.setColor(3, 240, 255, 0);
}
void setYieldGradCol() {
ucg.setColor(0, 255, 0, 0);
ucg.setColor(1, 255, 0, 0);
ucg.setColor(2, 255, 148, 0);
ucg.setColor(3, 255, 148, 0);
}
void setNeutralGradCol() {
ucg.setColor(0, 0, 0, 255);
ucg.setColor(1, 0, 0, 255);
ucg.setColor(2, 0, 148, 255);
ucg.setColor(3, 0, 148, 255);
}
void drawHeartbeat() {
//unsigned long heartbeatMillisPrev = 0;
//boolean heartbeatBit = true;
unsigned long heartbeatMillis = millis();
if (heartbeatMillis - heartbeatMillisPrev >= 1000) {
// save the last time you blinked the LED
heartbeatMillisPrev = heartbeatMillis;
if (heartbeatBit == true) {
heartbeatBit = false;
}
else {
heartbeatBit = true;
}
}
if (heartbeatBit == true) {
ucg.setColor(0, 0, 0);
ucg.setFont(ucg_font_tpss_hr);
ucg.setPrintPos(34,222);
//ucg.print(F("ERR: "));
ucg.print(F("OK"));
//heartbeatBit = false;
}
else {
ucg.setColor(170, 255, 0);
ucg.drawBox(30, 212, 25, 11);
ucg.setColor(0, 0, 0);
//heartbeatBit = true;
}
}
void runFan()
{
if (battCurrent > 5) {
fanSpeed = map(battCurrent, 5, 50, 80, 255);
}
else if (battCurrent < -35) {
fanSpeed = map(battCurrent, -35, -100, 80, 255);
}
else if (averageDallas > 28) {
fanSpeed = map(averageDallas, 28, 50, 80, 255);
}
else if ((initialiseLCD == 1) && (initialiseFan == 1)) {
fanSpeed = 255;
}
/*
else {
if(loadSwitch == 1) {
fanSpeed = 255;
}
else {
fanSpeed = 0;
}
}
*/
else {
fanSpeed = 0;
}
fanSpeed = min(fanSpeed,255);
analogWrite(fanPin,fanSpeed);
}
void populateHistory(int dataElements) {
int i;
for (i = 0; i < dataElements; i++) {
if (readVictron(i,VictronHEXLength[i],1) == true) {
consumptionHistory[i] = (translateResponse(receivedBuffer, 18, 8));
yieldHistory[i] = (translateResponse(receivedBuffer, 10, 8));;
}
}
}
char* getDeviceID(unsigned long deviceLong) {
char* devName;
//Serial.print("Dev Name: ");
deviceLong = (__builtin_bswap16(deviceLong)); //swap back as it's a literal
//Serial.print(deviceLong);
switch (deviceLong) {
case 0xA042:
devName = "BlueSolar MPPT 75/15";
break;
default:
// if nothing else matches, do the default
// default is optional
devName = "Unknown";
break;
}
return devName;
//Serial.println(" ");
//Serial.print("Dev Name: ");
//Serial.println(devName);
}
void drawProgressBar(int initVar, int vMin, int vMax, int vValue, int xPos, int yPos, int xLength, int yHeight, int rStart, int gStart, int bStart, int rEnd, int gEnd, int bEnd) {
int vMappedValue = map(vValue, vMin, vMax, 0, 1024);
//int xPos = 30;
//int yPos = 40;
//int xLength = 60;
//int yHeight = 30;
if (initVar == 1) {
ucg.setColor(255, 255, 255);
//ucg.drawFrame(30,40,60,30); //Outer white
ucg.drawFrame(xPos,yPos,xLength,yHeight); //Outer white
ucg.setColor(58, 58, 58);
//ucg.drawFrame(30,40,59,29); //Outer grey
ucg.drawFrame(xPos,yPos,xLength-1,yHeight-1); //Outer grey
ucg.setColor(226, 226, 226);
//ucg.drawFrame(31,41,58,28); //inner grey
ucg.drawFrame(xPos+1,yPos+1,xLength-2,yHeight-2); //inner grey
ucg.setColor(96, 96, 96);
//ucg.drawFrame(31,41,57,27); //dark grey
ucg.drawFrame(xPos+1,yPos+1,xLength-3,yHeight-3); //dark grey
ucg.setColor(226, 226, 226);
ucg.drawBox(xPos+2,yPos+2,xLength-4,yHeight-4); //bg grey
}
ucg.setColor(0, rStart, gStart, bStart);
ucg.setColor(1, rEnd, gEnd, bEnd);
ucg.setColor(2, rStart, gStart, bStart);
ucg.setColor(3, rEnd, gEnd, bEnd);
ucg.drawGradientBox(xPos+3,yPos+3,xLength-6,yHeight-6);
//add 3 to kick us off so we're at the correct start
//add 5 because that's going to be our increment
//i will increment by 7 to allow for two pixel gap leaving space of 5
ucg.setColor(226, 226, 226);
//for (int i=xPos+3+9; i <= xLength-4; i=i+11){
for (int i=xPos+2; i <= ((xPos+2)+xLength)-5; i=i+8){
//int testInt = 0;
int mapInt = map(i,xPos+2,((xPos+2)+xLength)-5,1,1024);
int setBlockWidth;
if (mapInt <= vMappedValue) {
setBlockWidth = 2;
}
else {
setBlockWidth = 8;
}
//ucg.drawBox(i,yPos+3,2,yHeight-6); //Outer white
ucg.drawBox(i,yPos+3,setBlockWidth,yHeight-6); //Outer white
}
//ucg.setColor(226, 226, 226);
// ucg.drawBox(xPos+2,yPos+2,xLength-4,yHeight-4); //white
}
void drawTextBox(int initVar, int xPos, int yPos, int xLength, int yHeight, char boxValue[], int boxValueInt, int powerOf, int decPlaces, int warnIndex, int tOffset) {
//int xPos = 30;
//int yPos = 40;
//int xLength = 60;
//int yHeight = 30;
if (initVar == 1) {
ucg.setColor(255, 255, 255);
//ucg.drawFrame(30,40,60,30); //Outer white
ucg.drawFrame(xPos,yPos,xLength,yHeight); //Outer white
ucg.setColor(58, 58, 58);
//ucg.drawFrame(30,40,59,29); //Outer grey
ucg.drawFrame(xPos,yPos,xLength-1,yHeight-1); //Outer grey
ucg.setColor(226, 226, 226);
//ucg.drawFrame(31,41,58,28); //inner grey
ucg.drawFrame(xPos+1,yPos+1,xLength-2,yHeight-2); //inner grey
ucg.setColor(96, 96, 96);
//ucg.drawFrame(31,41,57,27); //dark grey
ucg.drawFrame(xPos+1,yPos+1,xLength-3,yHeight-3); //dark grey
}
if (warnIndex == 0) { //grey
ucg.setColor(226, 226, 226);
}
else if (warnIndex == 1) { //white
ucg.setColor(255, 255, 255);
}
else if (warnIndex == 2) { //black
ucg.setColor(0, 0, 0);
}
else if (warnIndex == 3) { //orange
ucg.setColor(255, 208, 0);
}
else if (warnIndex == 4) { //green
ucg.setColor(170, 255, 0);
}
else {
ucg.setColor(255, 0, 0); //red
}
//ucg.drawBox(32,42,56,26); //white
ucg.drawBox(xPos+2,yPos+2,xLength-4,yHeight-4); //white
ucg.setPrintPos(xPos+tOffset,yPos+20); //+10 +19
if (warnIndex < 5) {
ucg.setColor(0, 0, 0);
}
else {
ucg.setColor(255, 255, 255);
}
ucg.setFont(ucg_font_logisoso16_tr);
if (boxValueInt == NULL) {
ucg.print(boxValue);
}
else if (boxValue == NULL) {
ucg.print((float)boxValueInt/powerOf,decPlaces);
}
else {
//nothing happens
}
}
void buildWindows() {
ucg.clearScreen();
drawWindow(1,0,156,104,"Battery",0,64,155,109,193,255);
drawLabel(9,40,"Voltage:");
drawLabel(9,66,"Current:");
drawLabel(9,92,"Charge:");
drawWindow(1,107,156,77,"Photovoltaics",0,64,155,109,193,255);
drawLabel(9,147,"Voltage:");
drawLabel(9,172,"Power W:");
drawWindow(1,187,156,53,"System",0,64,155,109,193,255);
drawWindow(160,0,159,74,"Load",0,64,155,109,193,255);
drawLabel(168,40,"Current:");
drawWindow(160,77,159,163,"Yield / Consumption (kWh)",0,64,155,109,193,255);
drawLabel(168,203,"Day:");
drawLabel(168,229,"All:");
drawLabel(256,203,"/");
drawLabel(256,229,"/");
}
void drawLabel(int xPos, int yPos, char labelText[]) {
ucg.setPrintPos(xPos,yPos);
ucg.setColor(0,0,0);
ucg.setFont(ucg_font_helvB10_tr);
ucg.print(labelText);
}
void drawWindow(int xPos, int yPos, int xLength, int yHeight, char boxTitle[], int rStart, int gStart, int bStart, int rEnd, int gEnd, int bEnd) {
//int xPos = 1;
//int yPos = 1;
//int xLength = 156;
//int yHeight = 156;
ucg.setColor(226, 226, 226);
//ucg.drawFrame(1,1,156,156); //Outer grey frame
ucg.drawFrame(xPos,yPos,xLength,yHeight); //Outer grey frame
ucg.setColor(58, 58, 58);
//ucg.drawFrame(2,2,155,155); // 1px lower right shadow
ucg.drawFrame(xPos+1,yPos+1,xLength-1,yHeight-1); // 1px lower right shadow
ucg.setColor(255,255,255);
//ucg.drawFrame(2,2,154,154); // 1px upper left white frame
ucg.drawFrame(xPos+1,yPos+1,xLength-2,yHeight-2); // 1px upper left white frame
ucg.setColor(96, 96, 96);
//ucg.drawFrame(3,3,153,153); // 1px lower right shadow
ucg.drawFrame(xPos+2,yPos+2,xLength-3,yHeight-3); // 1px lower right shadow
ucg.setColor(226, 226, 226);
//ucg.drawBox(3,3,152,152); // inner grey
ucg.drawBox(xPos+2,yPos+2,xLength-4,yHeight-4); // inner grey
//ucg.setColor(0, 0, 64, 155);
//ucg.setColor(1, 109, 193, 255);
//ucg.setColor(2, 0, 64, 155);
//ucg.setColor(3, 109, 193, 255);
ucg.setColor(0, rStart, gStart, bStart);
ucg.setColor(1, rEnd, gEnd, bEnd);
ucg.setColor(2, rStart, gStart, bStart);
ucg.setColor(3, rEnd, gEnd, bEnd);
//ucg.drawGradientBox(5,5,148,22); // title bar gradient
ucg.drawGradientBox(xPos+4,yPos+4,xLength-8,16); // title bar gradient
ucg.setColor(255,255,255);
ucg.setPrintPos(xPos+7,yPos+15);
ucg.setFont(ucg_font_helvB08_tr);
//ucg.setFont(ucg_font_amstrad_cpc_8f);
ucg.print(boxTitle);
}
void getVictron() {
/*
* COMMENCE VICTRON DATA COMPONENTS
* FOR SOME REASON THIS DOESN'T RUN
* CONSISTENTLY OPERATING IN IT'S
* OWN FUNCTION!
*
*/
//getVictronChargerVolts
//ucg.setPrintPos(10,20);
if (readVictron(18,VictronHEXLength[18],2) == true) {
//char chargerVoltageChar[4];
//memcpy(chargerVoltageChar, receivedBuffer + 8 /* Offset */, 4 /* Length */);
//unsigned long chargerVoltage = (__builtin_bswap16(strtoul(chargerVoltageChar, NULL, 16)));
chargerVoltage = (translateResponse(receivedBuffer, 8, 4));
//ucg.print(F(" Chg V "));
//ucg.print(chargerVoltage);
//ucg.print(F(" | "));
//ucg.print(receivedBuffer);
}
//getVictronChargerCurrent
//ucg.setPrintPos(10,35);
if (readVictron(19,VictronHEXLength[19],2) == true) {
//char chargerCurrentChar[4];
//memcpy(chargerCurrentChar, receivedBuffer + 8 /* Offset */, 4 /* Length */);
//unsigned long chargerCurrent = (__builtin_bswap16(strtoul(chargerCurrentChar, NULL, 16)));
chargerCurrent = (translateResponse(receivedBuffer, 8, 4));
//ucg.print(F(" Chg C "));
//ucg.print(chargerCurrent);
//ucg.print(F(" | "));
//ucg.print(receivedBuffer);
}
//getVictronLoadCurrent
//ucg.setPrintPos(10,50);
if (readVictron(20,VictronHEXLength[20],2) == true) {
loadCurrent = (translateResponse(receivedBuffer, 8, 4));
//ucg.print(F(" Ld C "));
//ucg.print(loadCurrent);
//ucg.print(F(" | "));
//ucg.print(receivedBuffer);
}
//getVictronIntTemp
//ucg.setPrintPos(10,65);
if (readVictron(21,VictronHEXLength[21],2) == true) {
chargerTemp = (translateResponse(receivedBuffer, 8, 4));
//ucg.print(F(" Temp "));
//ucg.print(chargerTemp);
//ucg.print(F(" | "));
//ucg.print(receivedBuffer);
}
//getVictronErrorCode
//ucg.setPrintPos(10,80);
if (readVictron(22,VictronHEXLength[22],2) == true) {
errorCode = (translateResponse(receivedBuffer, 8, 2));
//ucg.print(F(" Err C "));
//ucg.print(errorCode);
//ucg.print(F(" | "));
//ucg.print(receivedBuffer);
}
//getVictronPanelVolts
//ucg.setPrintPos(10,95);
if (readVictron(23,VictronHEXLength[23],2) == true) {
panelVoltage = (translateResponse(receivedBuffer, 8, 4));
//ucg.print(F(" PV V "));
//ucg.print(panelVoltage);
//ucg.print(F(" | "));
//ucg.print(receivedBuffer);
}
//getVictronDeviceMode
//ucg.setPrintPos(10,110);
if (readVictron(24,VictronHEXLength[24],2) == true) {
unsigned long deviceMode = (translateResponse(receivedBuffer, 8, 2));
//ucg.print(F(" Mode "));
//ucg.print(deviceMode);
//ucg.print(F(" | "));
//ucg.print(receivedBuffer);
}
//getVictronDeviceState
//ucg.setPrintPos(10,125);
if (readVictron(25,VictronHEXLength[25],2) == true) {
deviceState = (translateResponse(receivedBuffer, 8, 2));
//ucg.print(F(" State "));
//ucg.print(deviceState);
//ucg.print(F(" | "));
//ucg.print(receivedBuffer);
}
//getVictronDeviceID
//ucg.setPrintPos(10,140);
if (readVictron(26,VictronHEXLength[26],2) == true) {
deviceIDInt = (translateResponse(receivedBuffer, 8, 4));
//ucg.print(F(" ID "));
//ucg.print(deviceIDInt);
//ucg.print(F(" | "));
//ucg.print(receivedBuffer);
}
//getVictronDeviceVersion
//ucg.setPrintPos(10,155);
if (readVictron(27,VictronHEXLength[27],2) == true) {
//char deviceVersion[4];
memcpy(deviceVersion, receivedBuffer + 2, 4);
//deviceVersion[4] = '\0';
//ucg.print(F(" Vers "));
//ucg.print(deviceVersion);
//ucg.print(F(" | "));
//ucg.print(receivedBuffer);
}
/*
* END VICTRON DATA COMPONENTS
*
*/
}
...
This file has been truncated, please download it to see its full contents.
Comments