robbith
Published © GPL3+

Victron BlueSolar MPPT 75/15 based Solar Generator (12v)

12v Solar Generator using a Victron BlueSolar MPPT 75/15 Solar Charge Regulator & Arduino-based GUI for Info Display.

IntermediateShowcase (no instructions)Over 2 days3,845
Victron BlueSolar MPPT 75/15 based Solar Generator (12v)

Story

Read more

Schematics

Schematic

Schematic for the Arduino board

Board

Single sided PCB for Arduino

Code

Program

Arduino
Program for Display & Victron Communication - there is definitely tidier code out there. I will review & remove some surplus comments & add some more comments of value next iteration.
/* 
 *  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.

Credits

robbith

robbith

1 project • 3 followers
Thanks to julian.

Comments