diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index 6e9480b..72501d0 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -391,4 +391,55 @@ void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor){ getdisplay().fillRect(xm+t, ym+t, 20-(2*t), 15-(2*t), bcolor); } +// Solar graphic with fill level +void solarGraphic(uint x, uint y, int pcolor, int bcolor){ + // Show battery + int xb = x; // X position + int yb = y; // Y position + int t = 4; // Line thickness + int percent = 75; + // Battery corpus 100x80 with fill level + int level = int((100.0 - percent) * (80-(2*t)) / 100.0); + getdisplay().fillRect(xb, yb, 100, 80, pcolor); + if(percent < 99){ + getdisplay().fillRect(xb+t, yb+t, 100-(2*t), level, bcolor); + } + // Plus pol 20x15 + int xp = xb + 20; + int yp = yb - 15 + t; + getdisplay().fillRect(xp, yp, 20, 15, pcolor); + getdisplay().fillRect(xp+t, yp+t, 20-(2*t), 15-(2*t), bcolor); + // Minus pol 20x15 + int xm = xb + 60; + int ym = yb -15 + t; + getdisplay().fillRect(xm, ym, 20, 15, pcolor); + getdisplay().fillRect(xm+t, ym+t, 20-(2*t), 15-(2*t), bcolor); +} + +// Generator graphic with fill level +void generatorGraphic(uint x, uint y, int pcolor, int bcolor){ + // Show battery + int xb = x; // X position + int yb = y; // Y position + int t = 4; // Line thickness + int percent = 35; + + // Battery corpus 100x80 with fill level + int level = int((100.0 - percent) * (80-(2*t)) / 100.0); + getdisplay().fillRect(xb, yb, 100, 80, pcolor); + if(percent < 99){ + getdisplay().fillRect(xb+t, yb+t, 100-(2*t), level, bcolor); + } + // Plus pol 20x15 + int xp = xb + 20; + int yp = yb - 15 + t; + getdisplay().fillRect(xp, yp, 20, 15, pcolor); + getdisplay().fillRect(xp+t, yp+t, 20-(2*t), 15-(2*t), bcolor); + // Minus pol 20x15 + int xm = xb + 60; + int ym = yb -15 + t; + getdisplay().fillRect(xm, ym, 20, 15, pcolor); + getdisplay().fillRect(xm+t, ym+t, 20-(2*t), 15-(2*t), bcolor); +} + #endif \ No newline at end of file diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h index e679ee1..a58b95b 100644 --- a/lib/obp60task/OBP60Extensions.h +++ b/lib/obp60task/OBP60Extensions.h @@ -62,5 +62,7 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone); // Calulate sunset and sunrise void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor); // Battery graphic with fill level +void solarGraphic(uint x, uint y, int pcolor, int bcolor); // Solar graphic with fill level +void gerenratorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic with fill level #endif \ No newline at end of file diff --git a/lib/obp60task/OBP60Hardware.h b/lib/obp60task/OBP60Hardware.h index 293c4ae..3143b18 100644 --- a/lib/obp60task/OBP60Hardware.h +++ b/lib/obp60task/OBP60Hardware.h @@ -19,8 +19,12 @@ #define SHT21_I2C_ADDR 0x40 // Addr. 0x40 (fix) // AS5600 #define AS5600_I2C_ADDR 0x36 // Addr. 0x36 (fix) - // INA226 + // INA219 #define SHUNT_VOLTAGE 0.075 // Shunt voltage in V by max. current (75mV) + #define INA219_I2C_ADDR1 0x40 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery + #define INA219_I2C_ADDR2 0x41 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels + #define INA219_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator + // INA226 #define INA226_I2C_ADDR1 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery #define INA226_I2C_ADDR2 0x44 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels #define INA226_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator diff --git a/lib/obp60task/PageBattery2.cpp b/lib/obp60task/PageBattery2.cpp index a88ad40..0af6aef 100644 --- a/lib/obp60task/PageBattery2.cpp +++ b/lib/obp60task/PageBattery2.cpp @@ -386,7 +386,7 @@ static Page *createPage(CommonData &common){ * and will will provide the names of the fixed values we need */ PageDescription registerPageBattery2( - "Battery2", // Name of page + "Battery2", // Name of page createPage, // Action 0, // Number of bus values depends on selection in Web configuration {}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h) diff --git a/lib/obp60task/PageGenerator.cpp b/lib/obp60task/PageGenerator.cpp index 432ae47..596614b 100644 --- a/lib/obp60task/PageGenerator.cpp +++ b/lib/obp60task/PageGenerator.cpp @@ -2,18 +2,26 @@ #include "Pagedata.h" #include "OBP60Extensions.h" +#include "movingAvg.h" // Lib for moving average building class PageGenerator : public Page { bool init = false; // Marker for init done bool keylock = false; // Keylock -int genPercentage = 0; // Generator power level +int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s public: PageGenerator(CommonData &common){ common.logger->logDebug(GwLog::LOG,"Show PageGenerator"); } virtual int handleKey(int key){ + // Change average + if(key == 1){ + average ++; + average = average % 4; // Modulo 4 + return 0; // Commit the key + } + // Code for keylock if(key == 11){ keylock = !keylock; // Toggle keylock @@ -33,36 +41,51 @@ public: bool holdvalues = config->getBool(config->holdvalues); String flashLED = config->getString(config->flashLED); String batVoltage = config->getString(config->batteryVoltage); - int generatorMaxPower = config->getInt(config->genPower); + int genPower = config->getInt(config->genPower); + String batType = config->getString(config->batteryType); String backlightMode = config->getString(config->backlight); String powerSensor = config->getString(config->usePowSensor3); - double value1 = 0; // Generator voltage - double value2 = 0; // Generator current - double value3 = 0; // Generator power consumption + double value1 = 0; // Battery voltage + double value2 = 0; // Battery current + double value3 = 0; // Battery power consumption + double valueTrend = 0; // Average over 10 values + int genPercentage = 0; + + // Get voltage value + String name1 = "VGen"; - // Get values - value1 = commonData.data.generatorVoltage; // Live data - value2 = commonData.data.generatorCurrent; - value3 = commonData.data.generatorPower; - genPercentage = value3 / generatorMaxPower * 100; // Power level calculation - if(genPercentage < 0){ // Limiting values - genPercentage = 0; - } - if(genPercentage > 99){ - genPercentage = 99; - } + // Read values + value1 = commonData.data.batteryVoltage; // Live data + value2 = commonData.data.batteryCurrent; + value3 = commonData.data.batteryPower; + genPercentage = value3 * 100 / (double)genPower; // Load value bool valid1 = true; - // Optical warning by limit violation (unused) + // Limits for battery level + if(genPercentage < 0) genPercentage = 0; + if(genPercentage > 99) genPercentage = 99; + + // Optical warning by limit violation if(String(flashLED) == "Limit Violation"){ - setBlinkingLED(false); - setFlashLED(false); + // Over voltage + if(value1 > 14.8 && batVoltage == "12V"){ + setBlinkingLED(true); + } + if(value1 <= 14.8 && batVoltage == "12V"){ + setBlinkingLED(false); + } + if(value1 > 29.6 && batVoltage == "24V"){ + setBlinkingLED(true); + } + if(value1 <= 29.6 && batVoltage == "24V"){ + setBlinkingLED(false); + } } // Logging voltage value if (value1 == NULL) return; - LOG_DEBUG(GwLog::LOG,"Drawing at PageGenerator, V:%f C:%f P:%f", value1, value2, value3); + LOG_DEBUG(GwLog::LOG,"Drawing at PageGenerator, Type:%s %s:=%f", batType, name1, value1); // Draw page //*********************************************************** @@ -81,14 +104,20 @@ public: pixelcolor = GxEPD_WHITE; bgcolor = GxEPD_BLACK; } - /// Set display in partial refresh mode + // Set display in partial refresh mode getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update // Show name getdisplay().setTextColor(textcolor); getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setCursor(10, 65); - getdisplay().print("Gen."); + getdisplay().print("Bat."); + + // Show batery type + getdisplay().setTextColor(textcolor); + getdisplay().setFont(&Ubuntu_Bold8pt7b); + getdisplay().setCursor(90, 65); + getdisplay().print(batType); // Show voltage type getdisplay().setTextColor(textcolor); @@ -101,33 +130,49 @@ public: getdisplay().setFont(&Ubuntu_Bold16pt7b); getdisplay().print("V"); - // Show generator power level + // Show solar power getdisplay().setTextColor(textcolor); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setCursor(10, 200); - if(generatorMaxPower <= 999) getdisplay().print(generatorMaxPower, 0); - if(generatorMaxPower > 999) getdisplay().print(float(generatorMaxPower/1000.0), 1); + if(genPower <= 999) getdisplay().print(genPower, 0); + if(genPower > 999) getdisplay().print(float(genPower/1000.0), 1); getdisplay().setFont(&Ubuntu_Bold16pt7b); - if(generatorMaxPower <= 999) getdisplay().print("W"); - if(generatorMaxPower > 999) getdisplay().print("kw"); + if(genPower <= 999) getdisplay().print("w"); + if(genPower > 999) getdisplay().print("kW"); // Show info getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(10, 235); getdisplay().print("Installed"); getdisplay().setCursor(10, 255); - getdisplay().print("Type"); + getdisplay().print("Battery Type"); - // Show generator icon + // Show battery with fill level batteryGraphic(150, 45, genPercentage, pixelcolor, bgcolor); // Show average settings getdisplay().setTextColor(textcolor); getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(150, 145); - getdisplay().print("Avg: 1s"); + switch (average) { + case 0: + getdisplay().print("Avg: 1s"); + break; + case 1: + getdisplay().print("Avg: 10s"); + break; + case 2: + getdisplay().print("Avg: 60s"); + break; + case 3: + getdisplay().print("Avg: 300s"); + break; + default: + getdisplay().print("Avg: 1s"); + break; + } - // Show power level in percent + // Show fill level in percent getdisplay().setTextColor(textcolor); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setCursor(150, 200); @@ -145,7 +190,7 @@ public: } if(powerSensor == "INA226"){ getdisplay().print("INA226"); - i2cAddr = " (0x" + String(INA226_I2C_ADDR3, HEX) + ")"; + i2cAddr = " (0x" + String(INA226_I2C_ADDR1, HEX) + ")"; } getdisplay().print(i2cAddr); getdisplay().setCursor(270, 80); @@ -210,6 +255,8 @@ public: getdisplay().setTextColor(textcolor); getdisplay().setFont(&Ubuntu_Bold8pt7b); if(keylock == false){ + getdisplay().setCursor(10, 290); + getdisplay().print("[AVG]"); getdisplay().setCursor(130, 290); getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]"); if(String(backlightMode) == "Control by Key"){ // Key for illumination diff --git a/lib/obp60task/PageSolar.cpp b/lib/obp60task/PageSolar.cpp index 75631d4..5abaa4c 100644 --- a/lib/obp60task/PageSolar.cpp +++ b/lib/obp60task/PageSolar.cpp @@ -2,18 +2,34 @@ #include "Pagedata.h" #include "OBP60Extensions.h" +#include "movingAvg.h" // Lib for moving average building class PageSolar : public Page { bool init = false; // Marker for init done bool keylock = false; // Keylock -int solPercentage = 0; // Solar power level +int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s +bool trend = true; // Trend indicator [0|1], 0=off, 1=on +double raw = 0; public: PageSolar(CommonData &common){ common.logger->logDebug(GwLog::LOG,"Show PageSolar"); } virtual int handleKey(int key){ + // Change average + if(key == 1){ + average ++; + average = average % 4; // Modulo 4 + return 0; // Commit the key + } + + // Trend indicator + if(key == 5){ + trend = !trend; + return 0; // Commit the key + } + // Code for keylock if(key == 11){ keylock = !keylock; // Toggle keylock @@ -33,36 +49,46 @@ public: bool holdvalues = config->getBool(config->holdvalues); String flashLED = config->getString(config->flashLED); String batVoltage = config->getString(config->batteryVoltage); - int solarMaxPower = config->getInt(config->solarPower); + int solPower = config->getInt(config->solarPower); + String batType = config->getString(config->batteryType); String backlightMode = config->getString(config->backlight); - String powerSensor = config->getString(config->usePowSensor2); + String powerSensor = config->getString(config->usePowSensor1); double value1 = 0; // Solar voltage double value2 = 0; // Solar current - double value3 = 0; // Solar power consumption + double value3 = 0; // Solar output power + double valueTrend = 0; // Average over 10 values + double solPercentage = 0; // Solar load + + // Get voltage value + String name1 = "VSol"; - // Get values - value1 = commonData.data.solarVoltage; // Live data + // Get raw value for trend indicator + value1 = commonData.data.solarVoltage; // Live data value2 = commonData.data.solarCurrent; value3 = commonData.data.solarPower; - solPercentage = value3 / solarMaxPower * 100; // Power level calculation - if(solPercentage < 0){ // Limiting values - solPercentage = 0; - } - if(solPercentage > 99){ - solPercentage = 99; - } + solPercentage = value3 * 100 / (double)solPower; // Load value bool valid1 = true; - // Optical warning by limit violation (unused) + // Optical warning by limit violation if(String(flashLED) == "Limit Violation"){ - setBlinkingLED(false); - setFlashLED(false); + // Over voltage + if(value1 > 14.8 && batVoltage == "12V"){ + setBlinkingLED(true); + } + if(value1 <= 14.8 && batVoltage == "12V"){ + setBlinkingLED(false); + } + if(value1 > 29.6 && batVoltage == "24V"){ + setBlinkingLED(true); + } + if(value1 <= 29.6 && batVoltage == "24V"){ + setBlinkingLED(false); + } } // Logging voltage value - if (value1 == NULL) return; - LOG_DEBUG(GwLog::LOG,"Drawing at PageSolar, V:%f C:%f P:%f", value1, value2, value3); + LOG_DEBUG(GwLog::LOG,"Drawing at PageSolar, Type:%iW %s:=%f", solPower, name1, value1); // Draw page //*********************************************************** @@ -101,33 +127,27 @@ public: getdisplay().setFont(&Ubuntu_Bold16pt7b); getdisplay().print("V"); - // Show solar power level + // Show solar power getdisplay().setTextColor(textcolor); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setCursor(10, 200); - if(solarMaxPower <= 999) getdisplay().print(solarMaxPower, 0); - if(solarMaxPower > 999) getdisplay().print(float(solarMaxPower/1000.0), 1); + if(solPower <= 999) getdisplay().print(solPower, 0); + if(solPower > 999) getdisplay().print(float(solPower/1000.0), 1); getdisplay().setFont(&Ubuntu_Bold16pt7b); - if(solarMaxPower <= 999) getdisplay().print("W"); - if(solarMaxPower > 999) getdisplay().print("kw"); + if(solPower <= 999) getdisplay().print("w"); + if(solPower > 999) getdisplay().print("kW"); // Show info getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(10, 235); getdisplay().print("Installed"); getdisplay().setCursor(10, 255); - getdisplay().print("Power"); + getdisplay().print("Solar Modul"); - // Show solar icon - batteryGraphic(150, 45, solPercentage, pixelcolor, bgcolor); + // Show battery with fill level + solarGraphic(150, 45, pixelcolor, bgcolor); - // Show average settings - getdisplay().setTextColor(textcolor); - getdisplay().setFont(&Ubuntu_Bold8pt7b); - getdisplay().setCursor(150, 145); - getdisplay().print("Avg: 1s"); - - // Show power level in percent + // Show load level in percent getdisplay().setTextColor(textcolor); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setCursor(150, 200); @@ -142,6 +162,7 @@ public: if(powerSensor == "off") getdisplay().print("Internal"); if(powerSensor == "INA219"){ getdisplay().print("INA219"); + i2cAddr = " (0x" + String(INA219_I2C_ADDR2, HEX) + ")"; } if(powerSensor == "INA226"){ getdisplay().print("INA226"); @@ -210,6 +231,8 @@ public: getdisplay().setTextColor(textcolor); getdisplay().setFont(&Ubuntu_Bold8pt7b); if(keylock == false){ + getdisplay().setCursor(10, 290); + getdisplay().print("[AVG]"); getdisplay().setCursor(130, 290); getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]"); if(String(backlightMode) == "Control by Key"){ // Key for illumination @@ -238,7 +261,7 @@ static Page *createPage(CommonData &common){ * and will will provide the names of the fixed values we need */ PageDescription registerPageSolar( - "Solar", // Name of page + "Solar", // Name of page createPage, // Action 0, // Number of bus values depends on selection in Web configuration {}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)