mirror of
https://github.com/lumapu/ahoy.git
synced 2025-06-12 23:51:39 +02:00
improved, but currently compiles with errors
This commit is contained in:
parent
2b4de00a89
commit
cc9ba1b808
12 changed files with 237 additions and 494 deletions
10
src/app.cpp
10
src/app.cpp
|
@ -7,7 +7,7 @@
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "utils/sun.h"
|
#include "utils/sun.h"
|
||||||
|
|
||||||
#include "plugins/history.h"
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
app::app() : ah::Scheduler {} {}
|
app::app() : ah::Scheduler {} {}
|
||||||
|
|
||||||
|
@ -91,10 +91,7 @@ void app::setup() {
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mTotalPowerHistory = new TotalPowerHistory();
|
mHistory.setup(this, &mSys, mConfig, &mTimestamp);
|
||||||
mTotalPowerHistory->setup(this, &mSys, mConfig);
|
|
||||||
mYieldDayHistory = new YieldDayHistory();
|
|
||||||
mYieldDayHistory->setup(this, &mSys, mConfig);
|
|
||||||
|
|
||||||
mPubSerial.setup(mConfig, &mSys, &mTimestamp);
|
mPubSerial.setup(mConfig, &mSys, &mTimestamp);
|
||||||
|
|
||||||
|
@ -154,8 +151,7 @@ void app::regularTickers(void) {
|
||||||
//everySec([this]() { mImprov.tickSerial(); }, "impro");
|
//everySec([this]() { mImprov.tickSerial(); }, "impro");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
everySec(std::bind(&TotalPowerHistory::tickerSecond, mTotalPowerHistory), "totalPowerHistory");
|
everySec(std::bind(&HistoryType::tickerSecond, mHistory), "hist");
|
||||||
everySec(std::bind(&YieldDayHistory::tickerSecond, mYieldDayHistory), "yieldDayHistory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ETHERNET)
|
#if defined(ETHERNET)
|
||||||
|
|
18
src/app.h
18
src/app.h
|
@ -24,6 +24,7 @@
|
||||||
#include "utils/scheduler.h"
|
#include "utils/scheduler.h"
|
||||||
#include "utils/syslog.h"
|
#include "utils/syslog.h"
|
||||||
#include "web/RestApi.h"
|
#include "web/RestApi.h"
|
||||||
|
#include "plugins/history.h"
|
||||||
#include "web/web.h"
|
#include "web/web.h"
|
||||||
#include "hm/Communication.h"
|
#include "hm/Communication.h"
|
||||||
#if defined(ETHERNET)
|
#if defined(ETHERNET)
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
|
|
||||||
#include <RF24.h> // position is relevant since version 1.4.7 of this library
|
#include <RF24.h> // position is relevant since version 1.4.7 of this library
|
||||||
|
|
||||||
|
|
||||||
// convert degrees and radians for sun calculation
|
// convert degrees and radians for sun calculation
|
||||||
#define SIN(x) (sin(radians(x)))
|
#define SIN(x) (sin(radians(x)))
|
||||||
#define COS(x) (cos(radians(x)))
|
#define COS(x) (cos(radians(x)))
|
||||||
|
@ -42,12 +44,11 @@
|
||||||
#define ACOS(x) (degrees(acos(x)))
|
#define ACOS(x) (degrees(acos(x)))
|
||||||
|
|
||||||
typedef HmSystem<MAX_NUM_INVERTERS> HmSystemType;
|
typedef HmSystem<MAX_NUM_INVERTERS> HmSystemType;
|
||||||
#ifdef ESP32
|
|
||||||
#endif
|
|
||||||
typedef Web<HmSystemType> WebType;
|
typedef Web<HmSystemType> WebType;
|
||||||
typedef RestApi<HmSystemType> RestApiType;
|
typedef RestApi<HmSystemType> RestApiType;
|
||||||
typedef PubMqtt<HmSystemType> PubMqttType;
|
typedef PubMqtt<HmSystemType> PubMqttType;
|
||||||
typedef PubSerial<HmSystemType> PubSerialType;
|
typedef PubSerial<HmSystemType> PubSerialType;
|
||||||
|
typedef HistoryData<HmSystemType> HistoryType;
|
||||||
|
|
||||||
// PLUGINS
|
// PLUGINS
|
||||||
#if defined(PLUGIN_DISPLAY)
|
#if defined(PLUGIN_DISPLAY)
|
||||||
|
@ -55,7 +56,6 @@ typedef PubSerial<HmSystemType> PubSerialType;
|
||||||
#include "plugins/Display/Display_data.h"
|
#include "plugins/Display/Display_data.h"
|
||||||
typedef Display<HmSystemType, Radio> DisplayType;
|
typedef Display<HmSystemType, Radio> DisplayType;
|
||||||
#endif
|
#endif
|
||||||
#include "plugins/history.h"
|
|
||||||
|
|
||||||
class app : public IApp, public ah::Scheduler {
|
class app : public IApp, public ah::Scheduler {
|
||||||
public:
|
public:
|
||||||
|
@ -244,8 +244,13 @@ class app : public IApp, public ah::Scheduler {
|
||||||
Scheduler::setTimestamp(newTime);
|
Scheduler::setTimestamp(newTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
TotalPowerHistory *getTotalPowerHistoryPtr() { return mTotalPowerHistory; };
|
uint16_t getHistoryValue(HistoryType type, uint16_t i) {
|
||||||
YieldDayHistory *getYieldDayHistoryPtr() { return mYieldDayHistory; };
|
return mHistory.valueAt(type, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t getHistoryMaxDay() {
|
||||||
|
return mHistory.getMaximumDay();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#define CHECK_AVAIL true
|
#define CHECK_AVAIL true
|
||||||
|
@ -354,8 +359,7 @@ class app : public IApp, public ah::Scheduler {
|
||||||
DisplayType mDisplay;
|
DisplayType mDisplay;
|
||||||
DisplayData mDispData;
|
DisplayData mDispData;
|
||||||
#endif
|
#endif
|
||||||
TotalPowerHistory *mTotalPowerHistory;
|
HistoryType mHistory;
|
||||||
YieldDayHistory *mYieldDayHistory;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*__APP_H__*/
|
#endif /*__APP_H__*/
|
||||||
|
|
|
@ -8,19 +8,13 @@
|
||||||
|
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "hm/hmSystem.h"
|
#include "hm/hmSystem.h"
|
||||||
|
#include "plugins/history.h"
|
||||||
#if defined(ETHERNET)
|
#if defined(ETHERNET)
|
||||||
#include "AsyncWebServer_ESP32_W5500.h"
|
#include "AsyncWebServer_ESP32_W5500.h"
|
||||||
#else
|
#else
|
||||||
#include "ESPAsyncWebServer.h"
|
#include "ESPAsyncWebServer.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class TotalPowerHistory;
|
|
||||||
class YieldDayHistory;
|
|
||||||
//#include "hms/hmsRadio.h"
|
|
||||||
#if defined(ESP32)
|
|
||||||
//typedef CmtRadio<esp32_3wSpi<>> CmtRadioType;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// abstract interface to App. Make members of App accessible from child class
|
// abstract interface to App. Make members of App accessible from child class
|
||||||
// like web or API without forward declaration
|
// like web or API without forward declaration
|
||||||
class IApp {
|
class IApp {
|
||||||
|
@ -65,10 +59,10 @@ class IApp {
|
||||||
|
|
||||||
virtual bool getProtection(AsyncWebServerRequest *request) = 0;
|
virtual bool getProtection(AsyncWebServerRequest *request) = 0;
|
||||||
|
|
||||||
virtual TotalPowerHistory *getTotalPowerHistoryPtr() = 0;
|
virtual uint16_t getHistoryValue(uint8_t type, uint16_t i) = 0;
|
||||||
virtual YieldDayHistory *getYieldDayHistoryPtr() = 0;
|
virtual uint16_t getHistoryMaxDay() = 0;
|
||||||
virtual void* getRadioObj(bool nrf) = 0;
|
|
||||||
|
|
||||||
|
virtual void* getRadioObj(bool nrf) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*__IAPP_H__*/
|
#endif /*__IAPP_H__*/
|
||||||
|
|
|
@ -36,9 +36,6 @@
|
||||||
// CONFIGURATION - COMPILE TIME
|
// CONFIGURATION - COMPILE TIME
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
// Draw power chart in MONO-Display
|
|
||||||
#define DISPLAY_CHART 1
|
|
||||||
|
|
||||||
// ethernet
|
// ethernet
|
||||||
|
|
||||||
#if defined(ETHERNET)
|
#if defined(ETHERNET)
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#define DEF_PROT_MQTT 0x0000
|
#define DEF_PROT_MQTT 0x0000
|
||||||
#define DEF_PROT_HISTORY 0x0000
|
#define DEF_PROT_HISTORY 0x0000
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t ip[4]; // ip address
|
uint8_t ip[4]; // ip address
|
||||||
uint8_t mask[4]; // sub mask
|
uint8_t mask[4]; // sub mask
|
||||||
|
|
|
@ -99,8 +99,7 @@ class Display {
|
||||||
|
|
||||||
uint8_t nrprod = 0;
|
uint8_t nrprod = 0;
|
||||||
uint8_t nrsleep = 0;
|
uint8_t nrsleep = 0;
|
||||||
uint8_t nrAvailable = 0;
|
int8_t minQAllInv = 4;
|
||||||
int8_t minQAllInv = 4;
|
|
||||||
|
|
||||||
Inverter<> *iv;
|
Inverter<> *iv;
|
||||||
record_t<> *rec;
|
record_t<> *rec;
|
||||||
|
@ -115,8 +114,6 @@ class Display {
|
||||||
nrprod++;
|
nrprod++;
|
||||||
else
|
else
|
||||||
nrsleep++;
|
nrsleep++;
|
||||||
if (iv->isAvailable())
|
|
||||||
nrAvailable++;
|
|
||||||
|
|
||||||
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
|
|
||||||
|
@ -144,7 +141,6 @@ class Display {
|
||||||
// prepare display data
|
// prepare display data
|
||||||
mDisplayData.nrProducing = nrprod;
|
mDisplayData.nrProducing = nrprod;
|
||||||
mDisplayData.nrSleeping = nrsleep;
|
mDisplayData.nrSleeping = nrsleep;
|
||||||
mDisplayData.nrAvailable = nrAvailable;
|
|
||||||
mDisplayData.totalPower = totalPower;
|
mDisplayData.totalPower = totalPower;
|
||||||
mDisplayData.totalYieldDay = totalYieldDay;
|
mDisplayData.totalYieldDay = totalYieldDay;
|
||||||
mDisplayData.totalYieldTotal = totalYieldTotal;
|
mDisplayData.totalYieldTotal = totalYieldTotal;
|
||||||
|
@ -169,17 +165,7 @@ class Display {
|
||||||
else
|
else
|
||||||
mDisplayData.utcTs = 0;
|
mDisplayData.utcTs = 0;
|
||||||
|
|
||||||
const uint32_t sunriseTime = mApp->getSunrise();
|
if (mMono ) {
|
||||||
if (mDisplayData.utcTs == 0)
|
|
||||||
mDisplayData.sunIsShining = true; // Start with sunshine :-)
|
|
||||||
else {
|
|
||||||
mDisplayData.sunIsShining = false;
|
|
||||||
// new sunrise is calculated after sunset + user-offset
|
|
||||||
if (utc > sunriseTime)
|
|
||||||
mDisplayData.sunIsShining = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mMono) {
|
|
||||||
mMono->disp();
|
mMono->disp();
|
||||||
}
|
}
|
||||||
#if defined(ESP32) && !defined(ETHERNET)
|
#if defined(ESP32) && !defined(ETHERNET)
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "config/config.h"
|
|
||||||
#include <U8g2lib.h>
|
#include <U8g2lib.h>
|
||||||
#define DISP_DEFAULT_TIMEOUT 60 // in seconds
|
#define DISP_DEFAULT_TIMEOUT 60 // in seconds
|
||||||
#define DISP_FMT_TEXT_LEN 32
|
#define DISP_FMT_TEXT_LEN 32
|
||||||
|
@ -102,13 +101,6 @@ class DisplayMono {
|
||||||
int8_t mod = (millis() / 10000) % ((range >> 1) << 2);
|
int8_t mod = (millis() / 10000) % ((range >> 1) << 2);
|
||||||
mPixelshift = mScreenSaver == 1 ? ((mod < range) ? mod - (range >> 1) : -(mod - range - (range >> 1) + 1)) : 0;
|
mPixelshift = mScreenSaver == 1 ? ((mod < range) ? mod - (range >> 1) : -(mod - range - (range >> 1) + 1)) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DISPLAY_CHART
|
|
||||||
#define DISP_WATT_ARR_LENGTH 128 // Number of WATT history values
|
|
||||||
float m_wattArr[DISP_WATT_ARR_LENGTH + 1]; // ring buffer for watt history
|
|
||||||
uint16_t m_wattListIdx; // index for next Element to write into WattArr
|
|
||||||
void drawPowerChart();
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* adapted 5x8 Font for low-res displays with symbols
|
/* adapted 5x8 Font for low-res displays with symbols
|
||||||
|
|
|
@ -9,12 +9,6 @@
|
||||||
class DisplayMono128X64 : public DisplayMono {
|
class DisplayMono128X64 : public DisplayMono {
|
||||||
public:
|
public:
|
||||||
DisplayMono128X64() : DisplayMono() {
|
DisplayMono128X64() : DisplayMono() {
|
||||||
#ifdef DISPLAY_CHART
|
|
||||||
for (uint16_t i = 0; i < DISP_WATT_ARR_LENGTH; i++)
|
|
||||||
m_wattArr[i] = 0.0;
|
|
||||||
m_wattListIdx = 0;
|
|
||||||
mDrawChart = false;
|
|
||||||
#endif
|
|
||||||
mExtra = 0;
|
mExtra = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +41,7 @@ class DisplayMono128X64 : public DisplayMono {
|
||||||
}
|
}
|
||||||
|
|
||||||
void disp(void) {
|
void disp(void) {
|
||||||
|
uint8_t pos, sun_pos, moon_pos;
|
||||||
|
|
||||||
mDisplay->clearBuffer();
|
mDisplay->clearBuffer();
|
||||||
|
|
||||||
|
@ -66,149 +61,109 @@ class DisplayMono128X64 : public DisplayMono {
|
||||||
// calculate current pixelshift for pixelshift screensaver
|
// calculate current pixelshift for pixelshift screensaver
|
||||||
calcPixelShift(pixelShiftRange);
|
calcPixelShift(pixelShiftRange);
|
||||||
|
|
||||||
#ifdef DISPLAY_CHART
|
// print total power
|
||||||
static uint32_t dataUpdateTime = mDisplayData->utcTs + 60; // update chart every minute
|
if (mDisplayData->nrProducing > 0) {
|
||||||
if (mDisplayData->utcTs >= dataUpdateTime)
|
if (mDisplayData->totalPower > 9999.0)
|
||||||
{
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0));
|
||||||
dataUpdateTime = mDisplayData->utcTs + 60; // next minute
|
else
|
||||||
m_wattArr[m_wattListIdx] = mDisplayData->totalPower;
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower);
|
||||||
m_wattListIdx = (m_wattListIdx + 1) % (DISP_WATT_ARR_LENGTH);
|
|
||||||
|
printText(mFmtText, l_TotalPower, 0xff);
|
||||||
|
} else {
|
||||||
|
printText("offline", l_TotalPower, 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mDrawChart && mDisplayData->sunIsShining && (mDisplayData->nrAvailable > 0))
|
// print Date and time
|
||||||
{
|
if (0 != mDisplayData->utcTs)
|
||||||
// print total power
|
printText(ah::getDateTimeStrShort(gTimezone.toLocal(mDisplayData->utcTs)).c_str(), l_Time, 0xff);
|
||||||
if (mDisplayData->nrProducing > 0) {
|
|
||||||
if (mDisplayData->totalPower > 9999.0)
|
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0));
|
|
||||||
else
|
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower);
|
|
||||||
printText(mFmtText, l_Time, 10);
|
|
||||||
} else {
|
|
||||||
printText("offline", l_Time, 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", mDisplayData->totalYieldDay);
|
|
||||||
printText(mFmtText, l_Status, 10);
|
|
||||||
|
|
||||||
drawPowerChart();
|
|
||||||
|
|
||||||
|
// dynamic status bar, alternatively:
|
||||||
|
// print ip address
|
||||||
|
if (!(mExtra % 5) && (mDisplayData->ipAddress)) {
|
||||||
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%s", (mDisplayData->ipAddress).toString().c_str());
|
||||||
|
printText(mFmtText, l_Status, 0xff);
|
||||||
}
|
}
|
||||||
else
|
// print status of inverters
|
||||||
#endif
|
else {
|
||||||
{
|
sun_pos = -1;
|
||||||
// print total power
|
moon_pos = -1;
|
||||||
if (mDisplayData->nrProducing > 0) {
|
setLineFont(l_Status);
|
||||||
if (mDisplayData->totalPower > 9999.0)
|
if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing)
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0));
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter");
|
||||||
else
|
else if (0 == mDisplayData->nrSleeping) {
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower);
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, " ");
|
||||||
|
sun_pos = 0;
|
||||||
printText(mFmtText, l_TotalPower, 0xff);
|
|
||||||
} else {
|
|
||||||
printText("offline", l_TotalPower, 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
// print Date and time
|
|
||||||
if (0 != mDisplayData->utcTs)
|
|
||||||
printText(ah::getDateTimeStrShort(gTimezone.toLocal(mDisplayData->utcTs)).c_str(), l_Time, 0xff);
|
|
||||||
|
|
||||||
// dynamic status bar, alternatively:
|
|
||||||
// print ip address
|
|
||||||
if (!(mExtra % 5) && (mDisplayData->ipAddress)) {
|
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%s", (mDisplayData->ipAddress).toString().c_str());
|
|
||||||
printText(mFmtText, l_Status, 0xff);
|
|
||||||
}
|
|
||||||
// print status of inverters
|
|
||||||
else {
|
|
||||||
uint8_t pos, sun_pos, moon_pos;
|
|
||||||
sun_pos = -1;
|
|
||||||
moon_pos = -1;
|
|
||||||
setLineFont(l_Status);
|
|
||||||
if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing)
|
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter");
|
|
||||||
else if (0 == mDisplayData->nrSleeping) {
|
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, " ");
|
|
||||||
sun_pos = 0;
|
|
||||||
}
|
}
|
||||||
else if (0 == mDisplayData->nrProducing) {
|
else if (0 == mDisplayData->nrProducing) {
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, " ");
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, " ");
|
||||||
moon_pos = 0;
|
moon_pos = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2d", mDisplayData->nrProducing);
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2d", mDisplayData->nrProducing);
|
||||||
sun_pos = mDisplay->getStrWidth(mFmtText) + 1;
|
sun_pos = mDisplay->getStrWidth(mFmtText) + 1;
|
||||||
snprintf(mFmtText + 2, DISP_FMT_TEXT_LEN, " %2d", mDisplayData->nrSleeping);
|
snprintf(mFmtText+2, DISP_FMT_TEXT_LEN, " %2d", mDisplayData->nrSleeping);
|
||||||
moon_pos = mDisplay->getStrWidth(mFmtText) + 1;
|
moon_pos = mDisplay->getStrWidth(mFmtText) + 1;
|
||||||
snprintf(mFmtText + 7, DISP_FMT_TEXT_LEN, " ");
|
snprintf(mFmtText+7, DISP_FMT_TEXT_LEN, " ");
|
||||||
}
|
|
||||||
printText(mFmtText, l_Status, 0xff);
|
|
||||||
|
|
||||||
pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2;
|
|
||||||
mDisplay->setFont(u8g2_font_ncenB08_symbols8_ahoy);
|
|
||||||
if (sun_pos != -1)
|
|
||||||
mDisplay->drawStr(pos + sun_pos + mPixelshift, mLineYOffsets[l_Status], "G"); // sun symbol
|
|
||||||
if (moon_pos != -1)
|
|
||||||
mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon symbol
|
|
||||||
}
|
}
|
||||||
|
printText(mFmtText, l_Status, 0xff);
|
||||||
|
|
||||||
// print yields
|
pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2;
|
||||||
mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy);
|
mDisplay->setFont(u8g2_font_ncenB08_symbols8_ahoy);
|
||||||
mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day symbol
|
if (sun_pos!=-1)
|
||||||
mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total symbol
|
mDisplay->drawStr(pos + sun_pos + mPixelshift, mLineYOffsets[l_Status], "G"); // sun symbol
|
||||||
|
if (moon_pos!=-1)
|
||||||
if (mDisplayData->totalYieldDay > 9999.0)
|
mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon symbol
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kWh", mDisplayData->totalYieldDay / 1000.0);
|
|
||||||
else
|
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay);
|
|
||||||
printText(mFmtText, l_YieldDay, 0xff);
|
|
||||||
|
|
||||||
if (mDisplayData->totalYieldTotal > 9999.0)
|
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0);
|
|
||||||
else
|
|
||||||
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal);
|
|
||||||
printText(mFmtText, l_YieldTotal, 0xff);
|
|
||||||
|
|
||||||
// draw dynamic RSSI bars
|
|
||||||
int xoffs;
|
|
||||||
if (mScreenSaver == 1) // shrink screenwidth for pixelshift screensaver
|
|
||||||
xoffs = pixelShiftRange / 2;
|
|
||||||
else
|
|
||||||
xoffs = 0;
|
|
||||||
int rssi_bar_height = 9;
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
int radio_rssi_threshold = -60 - i * 10;
|
|
||||||
int wifi_rssi_threshold = -60 - i * 10;
|
|
||||||
if (mDisplayData->RadioRSSI > radio_rssi_threshold)
|
|
||||||
mDisplay->drawBox(xoffs + mPixelshift, 8 + (rssi_bar_height + 1) * i, 4 - i, rssi_bar_height);
|
|
||||||
if (mDisplayData->WifiRSSI > wifi_rssi_threshold)
|
|
||||||
mDisplay->drawBox(mDispWidth - 4 - xoffs + mPixelshift + i, 8 + (rssi_bar_height + 1) * i, 4 - i, rssi_bar_height);
|
|
||||||
}
|
|
||||||
// draw dynamic antenna and WiFi symbols
|
|
||||||
mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy);
|
|
||||||
char sym[] = " ";
|
|
||||||
sym[0] = mDisplayData->RadioSymbol ? 'A' : 'E'; // NRF
|
|
||||||
mDisplay->drawStr(xoffs + mPixelshift, mLineYOffsets[l_RSSI], sym);
|
|
||||||
|
|
||||||
if (mDisplayData->MQTTSymbol)
|
|
||||||
sym[0] = 'J'; // MQTT
|
|
||||||
else
|
|
||||||
sym[0] = mDisplayData->WifiSymbol ? 'B' : 'F'; // Wifi
|
|
||||||
mDisplay->drawStr(mDispWidth - mDisplay->getStrWidth(sym) - xoffs + mPixelshift, mLineYOffsets[l_RSSI], sym);
|
|
||||||
mDisplay->sendBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// print yields
|
||||||
|
mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy);
|
||||||
|
mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day symbol
|
||||||
|
mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total symbol
|
||||||
|
|
||||||
|
if (mDisplayData->totalYieldDay > 9999.0)
|
||||||
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kWh", mDisplayData->totalYieldDay / 1000.0);
|
||||||
|
else
|
||||||
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay);
|
||||||
|
printText(mFmtText, l_YieldDay, 0xff);
|
||||||
|
|
||||||
|
if (mDisplayData->totalYieldTotal > 9999.0)
|
||||||
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0);
|
||||||
|
else
|
||||||
|
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal);
|
||||||
|
printText(mFmtText, l_YieldTotal, 0xff);
|
||||||
|
|
||||||
|
// draw dynamic RSSI bars
|
||||||
|
int xoffs;
|
||||||
|
if (mScreenSaver == 1) // shrink screenwidth for pixelshift screensaver
|
||||||
|
xoffs = pixelShiftRange/2;
|
||||||
|
else
|
||||||
|
xoffs = 0;
|
||||||
|
int rssi_bar_height = 9;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int radio_rssi_threshold = -60 - i * 10;
|
||||||
|
int wifi_rssi_threshold = -60 - i * 10;
|
||||||
|
if (mDisplayData->RadioRSSI > radio_rssi_threshold)
|
||||||
|
mDisplay->drawBox(xoffs + mPixelshift, 8 + (rssi_bar_height + 1) * i, 4 - i, rssi_bar_height);
|
||||||
|
if (mDisplayData->WifiRSSI > wifi_rssi_threshold)
|
||||||
|
mDisplay->drawBox(mDispWidth - 4 - xoffs + mPixelshift + i, 8 + (rssi_bar_height + 1) * i, 4 - i, rssi_bar_height);
|
||||||
|
}
|
||||||
|
// draw dynamic antenna and WiFi symbols
|
||||||
|
mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy);
|
||||||
|
char sym[]=" ";
|
||||||
|
sym[0] = mDisplayData->RadioSymbol?'A':'E'; // NRF
|
||||||
|
mDisplay->drawStr(xoffs + mPixelshift, mLineYOffsets[l_RSSI], sym);
|
||||||
|
|
||||||
|
if (mDisplayData->MQTTSymbol)
|
||||||
|
sym[0] = 'J'; // MQTT
|
||||||
|
else
|
||||||
|
sym[0] = mDisplayData->WifiSymbol?'B':'F'; // Wifi
|
||||||
|
mDisplay->drawStr(mDispWidth - mDisplay->getStrWidth(sym) - xoffs + mPixelshift, mLineYOffsets[l_RSSI], sym);
|
||||||
|
mDisplay->sendBuffer();
|
||||||
|
|
||||||
|
|
||||||
mDisplay->sendBuffer();
|
mDisplay->sendBuffer();
|
||||||
|
|
||||||
mExtra++;
|
mExtra++;
|
||||||
|
|
||||||
#ifdef DISPLAY_CHART
|
|
||||||
static uint32_t switchDisplayTime = mDisplayData->utcTs + 20;
|
|
||||||
if (mDisplayData->utcTs >= switchDisplayTime) {
|
|
||||||
switchDisplayTime = mDisplayData->utcTs + 20;
|
|
||||||
mDrawChart = !mDrawChart;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -271,46 +226,4 @@ class DisplayMono128X64 : public DisplayMono {
|
||||||
dispX += mPixelshift;
|
dispX += mPixelshift;
|
||||||
mDisplay->drawStr(dispX, mLineYOffsets[line], text);
|
mDisplay->drawStr(dispX, mLineYOffsets[line], text);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DISPLAY_CHART
|
|
||||||
bool mDrawChart ;
|
|
||||||
|
|
||||||
void drawPowerChart() {
|
|
||||||
const int hight = 40; // chart hight
|
|
||||||
|
|
||||||
// Clear area
|
|
||||||
// mDisplay->draw_rectangle(0, 63 - hight, DISP_WATT_ARR_LENGTH, 63, OLED::SOLID, OLED::BLACK);
|
|
||||||
mDisplay->setDrawColor(0);
|
|
||||||
mDisplay->drawBox(0, 63 - hight, DISP_WATT_ARR_LENGTH, hight);
|
|
||||||
mDisplay->setDrawColor(1);
|
|
||||||
|
|
||||||
// Get max value for scaling
|
|
||||||
float maxValue = 0.0;
|
|
||||||
for (int i = 0; i < DISP_WATT_ARR_LENGTH; i++) {
|
|
||||||
float fValue = m_wattArr[i];
|
|
||||||
if (fValue > maxValue)
|
|
||||||
maxValue = fValue;
|
|
||||||
}
|
|
||||||
// calc divider to fit into chart hight
|
|
||||||
int divider = round(maxValue / (float)hight);
|
|
||||||
if (divider < 1)
|
|
||||||
divider = 1;
|
|
||||||
|
|
||||||
// draw chart bars
|
|
||||||
// Start display of data right behind last written data
|
|
||||||
uint16_t idx = m_wattListIdx;
|
|
||||||
for (uint16_t i = 0; i < DISP_WATT_ARR_LENGTH; i++) {
|
|
||||||
float fValue = m_wattArr[idx];
|
|
||||||
int iValue = roundf(fValue);
|
|
||||||
iValue /= divider;
|
|
||||||
if (iValue > hight)
|
|
||||||
iValue = hight;
|
|
||||||
// mDisplay->draw_line(i, 63 - iValue, i, 63);
|
|
||||||
// mDisplay->drawVLine(i, 63 - iValue, iValue);
|
|
||||||
if (iValue>0)
|
|
||||||
mDisplay->drawLine(i, 63 - iValue, i, 63);
|
|
||||||
idx = (idx + 1) % (DISP_WATT_ARR_LENGTH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,14 +11,12 @@ struct DisplayData {
|
||||||
uint32_t utcTs=0; // indicate absolute timestamp (utc unix time). 0 = time is not synchonized
|
uint32_t utcTs=0; // indicate absolute timestamp (utc unix time). 0 = time is not synchonized
|
||||||
uint8_t nrProducing=0; // indicate number of producing inverters
|
uint8_t nrProducing=0; // indicate number of producing inverters
|
||||||
uint8_t nrSleeping=0; // indicate number of sleeping inverters
|
uint8_t nrSleeping=0; // indicate number of sleeping inverters
|
||||||
uint8_t nrAvailable=0; // number of available (comunicating) inverters
|
|
||||||
bool WifiSymbol = false; // indicate if WiFi is connected
|
bool WifiSymbol = false; // indicate if WiFi is connected
|
||||||
bool RadioSymbol = false; // indicate if radio module is connecting and working
|
bool RadioSymbol = false; // indicate if radio module is connecting and working
|
||||||
bool MQTTSymbol = false; // indicate if MQTT is connected
|
bool MQTTSymbol = false; // indicate if MQTT is connected
|
||||||
int8_t WifiRSSI=SCHAR_MIN; // indicate RSSI value for WiFi
|
int8_t WifiRSSI=SCHAR_MIN; // indicate RSSI value for WiFi
|
||||||
int8_t RadioRSSI=SCHAR_MIN; // indicate RSSI value for radio
|
int8_t RadioRSSI=SCHAR_MIN; // indicate RSSI value for radio
|
||||||
IPAddress ipAddress; // indicate ip adress of ahoy
|
IPAddress ipAddress; // indicate ip adress of ahoy
|
||||||
bool sunIsShining; // indicate if time is between sunrise and sunset
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*__DISPLAY_DATA__*/
|
#endif /*__DISPLAY_DATA__*/
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
|
|
||||||
#include "plugins/history.h"
|
|
||||||
|
|
||||||
#include "appInterface.h"
|
|
||||||
#include "config/config.h"
|
|
||||||
#include "utils/dbg.h"
|
|
||||||
|
|
||||||
void TotalPowerHistory::setup(IApp *app, HmSystemType *sys, settings_t *config) {
|
|
||||||
mApp = app;
|
|
||||||
mSys = sys;
|
|
||||||
mConfig = config;
|
|
||||||
mRefreshCycle = mConfig->inst.sendInterval;
|
|
||||||
mMaximumDay = 0;
|
|
||||||
|
|
||||||
// Debug
|
|
||||||
//for (uint16_t i = 0; i < HISTORY_DATA_ARR_LENGTH *1.5; i++) {
|
|
||||||
// addValue(i);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TotalPowerHistory::tickerSecond() {
|
|
||||||
++mLoopCnt;
|
|
||||||
if ((mLoopCnt % mRefreshCycle) == 0) {
|
|
||||||
//DPRINTLN(DBG_DEBUG,F("TotalPowerHistory::tickerSecond > refreshCycle" + String(mRefreshCycle) + "|" + String(mLoopCnt) + "|" + String(mRefreshCycle % mLoopCnt));
|
|
||||||
mLoopCnt = 0;
|
|
||||||
float totalPower = 0;
|
|
||||||
float totalPowerDay = 0;
|
|
||||||
Inverter<> *iv;
|
|
||||||
record_t<> *rec;
|
|
||||||
for (uint8_t i = 0; i < mSys->getNumInverters(); i++) {
|
|
||||||
iv = mSys->getInverterByPos(i);
|
|
||||||
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
|
||||||
if (iv == NULL)
|
|
||||||
continue;
|
|
||||||
totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec);
|
|
||||||
totalPowerDay += iv->getChannelFieldValue(CH0, FLD_MP, rec);
|
|
||||||
}
|
|
||||||
if (totalPower > 0) {
|
|
||||||
uint16_t iTotalPower = roundf(totalPower);
|
|
||||||
DPRINTLN(DBG_DEBUG, F("[TotalPowerHistory]: addValue(iTotalPower)=") + String(iTotalPower));
|
|
||||||
addValue(iTotalPower);
|
|
||||||
}
|
|
||||||
if (totalPowerDay > 0) {
|
|
||||||
mMaximumDay = roundf(totalPowerDay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void YieldDayHistory::setup(IApp *app, HmSystemType *sys, settings_t *config) {
|
|
||||||
mApp = app;
|
|
||||||
mSys = sys;
|
|
||||||
mConfig = config;
|
|
||||||
mRefreshCycle = 60; // every minute
|
|
||||||
mDayStored = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
void YieldDayHistory::tickerSecond() {
|
|
||||||
++mLoopCnt;
|
|
||||||
if ((mLoopCnt % mRefreshCycle) == 0) {
|
|
||||||
mLoopCnt = 0;
|
|
||||||
// check for sunset. if so store yield of day once
|
|
||||||
uint32_t sunsetTime = mApp->getSunset();
|
|
||||||
uint32_t sunriseTime = mApp->getSunrise();
|
|
||||||
uint32_t currentTime = mApp->getTimestamp();
|
|
||||||
DPRINTLN(DBG_DEBUG,F("[YieldDayHistory] current | rise | set -> ") + String(currentTime) + " | " + String(sunriseTime) + " | " + String(sunsetTime));
|
|
||||||
|
|
||||||
if (currentTime > sunsetTime) {
|
|
||||||
if (!mDayStored) {
|
|
||||||
DPRINTLN(DBG_DEBUG,F("currentTime > sunsetTime ") + String(currentTime) + " > " + String(sunsetTime));
|
|
||||||
float totalYieldDay = -0.1;
|
|
||||||
Inverter<> *iv;
|
|
||||||
record_t<> *rec;
|
|
||||||
for (uint8_t i = 0; i < mSys->getNumInverters(); i++) {
|
|
||||||
iv = mSys->getInverterByPos(i);
|
|
||||||
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
|
||||||
if (iv == NULL)
|
|
||||||
continue;
|
|
||||||
totalYieldDay += iv->getChannelFieldValue(CH0, FLD_YD, rec);
|
|
||||||
}
|
|
||||||
if (totalYieldDay > 0) {
|
|
||||||
uint16_t iTotalYieldDay = roundf(totalYieldDay);
|
|
||||||
DPRINTLN(DBG_DEBUG,F("addValue(iTotalYieldDay)=") + String(iTotalYieldDay));
|
|
||||||
addValue(iTotalYieldDay);
|
|
||||||
mDayStored = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (currentTime > sunriseTime) {
|
|
||||||
DPRINTLN(DBG_DEBUG,F("currentTime > sunriseTime ") + String(currentTime) + " > " + String(sunriseTime));
|
|
||||||
mDayStored = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,86 +1,123 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// 2024 Ahoy, https://ahoydtu.de
|
||||||
|
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef __HISTORY_DATA_H__
|
#ifndef __HISTORY_DATA_H__
|
||||||
#define __HISTORY_DATA_H__
|
#define __HISTORY_DATA_H__
|
||||||
|
|
||||||
#include "utils/helper.h"
|
#include <array>
|
||||||
#include "defines.h"
|
#include "../appInterface.h"
|
||||||
#include "hm/hmSystem.h"
|
#include "../hm/hmSystem.h"
|
||||||
|
#include "../utils/helper.h"
|
||||||
typedef HmSystem<MAX_NUM_INVERTERS> HmSystemType;
|
|
||||||
class IApp;
|
|
||||||
|
|
||||||
#define HISTORY_DATA_ARR_LENGTH 256
|
#define HISTORY_DATA_ARR_LENGTH 256
|
||||||
|
|
||||||
|
enum class HistoryStorageType : uint8_t {
|
||||||
|
POWER,
|
||||||
|
YIELD
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class HMSYSTEM>
|
||||||
class HistoryData {
|
class HistoryData {
|
||||||
public:
|
private:
|
||||||
HistoryData() {
|
struct storage_t {
|
||||||
for (int i = 0; i < HISTORY_DATA_ARR_LENGTH; i++)
|
uint16_t refreshCycle;
|
||||||
m_dataArr[i] = 0;
|
uint16_t loopCnt;
|
||||||
m_listIdx = 0;
|
uint16_t listIdx; // index for next Element to write into WattArr
|
||||||
m_dispIdx = 0;
|
uint16_t dispIdx; // index for 1st Element to display from WattArr
|
||||||
m_wrapped = false;
|
bool wrapped;
|
||||||
};
|
// ring buffer for watt history
|
||||||
void addValue(uint16_t value)
|
std::array<uint16_t, HISTORY_DATA_ARR_LENGTH + 1> data;
|
||||||
{
|
|
||||||
if (m_wrapped) // after 1st time array wrap we have to increas the display index
|
|
||||||
m_dispIdx = (m_listIdx + 1) % (HISTORY_DATA_ARR_LENGTH);
|
|
||||||
m_dataArr[m_listIdx] = value;
|
|
||||||
m_listIdx = (m_listIdx + 1) % (HISTORY_DATA_ARR_LENGTH);
|
|
||||||
if (m_listIdx == 0)
|
|
||||||
m_wrapped = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint16_t valueAt(int i){
|
void reset() {
|
||||||
uint16_t idx = m_dispIdx + i;
|
loopCnt = 0;
|
||||||
idx = idx % HISTORY_DATA_ARR_LENGTH;
|
listIdx = 0;
|
||||||
uint16_t value = m_dataArr[idx];
|
dispIdx = 0;
|
||||||
return value;
|
wrapped = false;
|
||||||
};
|
for(uint16_t i = 0; i < (HISTORY_DATA_ARR_LENGTH + 1); i++) {
|
||||||
|
data[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
public:
|
||||||
uint16_t m_dataArr[HISTORY_DATA_ARR_LENGTH + 1]; // ring buffer for watt history
|
void setup(IApp *app, HMSYSTEM *sys, settings_t *config, uint32_t *ts) {
|
||||||
uint16_t m_listIdx; // index for next Element to write into WattArr
|
mApp = app;
|
||||||
uint16_t m_dispIdx; // index for 1st Element to display from WattArr
|
mSys = sys;
|
||||||
bool m_wrapped;
|
mConfig = config;
|
||||||
};
|
mTs = ts;
|
||||||
|
|
||||||
class TotalPowerHistory : public HistoryData {
|
mCurPwr.reset();
|
||||||
public:
|
mCurPwr.refreshCycle = mConfig->inst.sendInterval;
|
||||||
TotalPowerHistory() : HistoryData() {
|
mYieldDay.reset();
|
||||||
mLoopCnt = 0;
|
mYieldDay.refreshCycle = 60;
|
||||||
};
|
}
|
||||||
|
|
||||||
void setup(IApp *app, HmSystemType *sys, settings_t *config);
|
void tickerSecond() {
|
||||||
void tickerSecond();
|
Inverter<> *iv;
|
||||||
uint16_t getMaximumDay() { return mMaximumDay; }
|
record_t<> *rec;
|
||||||
|
float curPwr = 0;
|
||||||
|
float maxPwr = 0;
|
||||||
|
float yldDay = -0.1;
|
||||||
|
for (uint8_t i = 0; i < mSys->getNumInverters(); i++) {
|
||||||
|
iv = mSys->getInverterByPos(i);
|
||||||
|
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
|
if (iv == NULL)
|
||||||
|
continue;
|
||||||
|
curPwr += iv->getChannelFieldValue(CH0, FLD_PAC, rec);
|
||||||
|
maxPwr += iv->getChannelFieldValue(CH0, FLD_MP, rec);
|
||||||
|
yldDay += iv->getChannelFieldValue(CH0, FLD_YD, rec);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
if ((++mCurPwr.loopCnt % mCurPwr.refreshCycle) == 0) {
|
||||||
IApp *mApp;
|
mCurPwr.loopCnt = 0;
|
||||||
HmSystemType *mSys;
|
if (curPwr > 0)
|
||||||
settings *mSettings;
|
addValue(&mCurPwr, roundf(curPwr));
|
||||||
settings_t *mConfig;
|
if (maxPwr > 0)
|
||||||
uint16_t mRefreshCycle;
|
mMaximumDay = roundf(maxPwr);
|
||||||
uint16_t mLoopCnt;
|
}
|
||||||
|
|
||||||
uint16_t mMaximumDay;
|
if (*mTs > mApp->getSunset()) {
|
||||||
};
|
if ((!mDayStored) && (yldDay > 0)) {
|
||||||
|
addValue(&mYieldDay, roundf(yldDay));
|
||||||
|
mDayStored = true;
|
||||||
|
}
|
||||||
|
} else if (*mTs > mApp->getSunrise())
|
||||||
|
mDayStored = false;
|
||||||
|
}
|
||||||
|
|
||||||
class YieldDayHistory : public HistoryData {
|
uint16_t valueAt(HistoryStorageType type, uint16_t i) {
|
||||||
public:
|
settings_t *s = (HistoryStorageType::POWER == type) ? &mCurPwr : &mYieldDay;
|
||||||
YieldDayHistory() : HistoryData(){
|
uint16_t idx = (s->dispIdx + i) % HISTORY_DATA_ARR_LENGTH;
|
||||||
mLoopCnt = 0;
|
return s->data[idx];
|
||||||
};
|
}
|
||||||
|
|
||||||
void setup(IApp *app, HmSystemType *sys, settings_t *config);
|
uint16_t getMaximumDay() {
|
||||||
void tickerSecond();
|
return mMaximumDay;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IApp *mApp;
|
void addValue(storage_t *s, uint16_t value) {
|
||||||
HmSystemType *mSys;
|
if (s->wrapped) // after 1st time array wrap we have to increase the display index
|
||||||
settings *mSettings;
|
s->dispIdx = (s->listIdx + 1) % (HISTORY_DATA_ARR_LENGTH);
|
||||||
settings_t *mConfig;
|
s->data[s->listIdx] = value;
|
||||||
uint16_t mRefreshCycle;
|
s->listIdx = (s->listIdx + 1) % (HISTORY_DATA_ARR_LENGTH);
|
||||||
uint16_t mLoopCnt;
|
if (s->listIdx == 0)
|
||||||
bool mDayStored;
|
s->wrapped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
IApp *mApp;
|
||||||
|
HMSYSTEM *mSys;
|
||||||
|
settings *mSettings;
|
||||||
|
settings_t *mConfig;
|
||||||
|
uint32_t *mTs;
|
||||||
|
|
||||||
|
storage_t mCurPwr;
|
||||||
|
storage_t mYieldDay;
|
||||||
|
bool mDayStored = false;
|
||||||
|
uint16_t mMaximumDay = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -52,10 +52,8 @@ class RestApi {
|
||||||
mRadioCmt = (CmtRadio<>*)mApp->getRadioObj(false);
|
mRadioCmt = (CmtRadio<>*)mApp->getRadioObj(false);
|
||||||
#endif
|
#endif
|
||||||
mConfig = config;
|
mConfig = config;
|
||||||
mSrv->on("/api/insertYieldDayHistory", HTTP_POST, std::bind(&RestApi::onApiPost, this, std::placeholders::_1),
|
mSrv->on("/api", HTTP_POST, std::bind(&RestApi::onApiPost, this, std::placeholders::_1)).onBody(
|
||||||
std::bind(&RestApi::onApiPostYieldDHistory, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
|
std::bind(&RestApi::onApiPostBody, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
||||||
mSrv->on("/api", HTTP_POST, std::bind(&RestApi::onApiPost, this, std::placeholders::_1))
|
|
||||||
.onBody(std::bind(&RestApi::onApiPostBody, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
|
||||||
mSrv->on("/api", HTTP_GET, std::bind(&RestApi::onApi, this, std::placeholders::_1));
|
mSrv->on("/api", HTTP_GET, std::bind(&RestApi::onApi, this, std::placeholders::_1));
|
||||||
|
|
||||||
mSrv->on("/get_setup", HTTP_GET, std::bind(&RestApi::onDwnldSetup, this, std::placeholders::_1));
|
mSrv->on("/get_setup", HTTP_GET, std::bind(&RestApi::onDwnldSetup, this, std::placeholders::_1));
|
||||||
|
@ -142,83 +140,6 @@ class RestApi {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void onApiPostYieldDHistory(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, size_t final)
|
|
||||||
{
|
|
||||||
uint32_t total = request->contentLength();
|
|
||||||
DPRINTLN(DBG_DEBUG, "[onApiPostYieldDHistory ] " + filename + " index:" + index + " len:" + len + " total:" + total + " final:" + final);
|
|
||||||
|
|
||||||
if (0 == index) {
|
|
||||||
if (NULL != mTmpBuf)
|
|
||||||
delete[] mTmpBuf;
|
|
||||||
mTmpBuf = new uint8_t[total + 1];
|
|
||||||
mTmpSize = total;
|
|
||||||
}
|
|
||||||
if (mTmpSize >= (len + index))
|
|
||||||
memcpy(&mTmpBuf[index], data, len);
|
|
||||||
|
|
||||||
if (!final)
|
|
||||||
return; // not last frame - nothing to do
|
|
||||||
|
|
||||||
mTmpSize = len + index ; // correct the total size
|
|
||||||
mTmpBuf[mTmpSize] = 0;
|
|
||||||
|
|
||||||
#ifndef ESP32
|
|
||||||
DynamicJsonDocument json(ESP.getMaxFreeBlockSize() - 512); // need some memory on heap
|
|
||||||
#else
|
|
||||||
DynamicJsonDocument json(12000)); // does this work? I have no ESP32 :-(
|
|
||||||
#endif
|
|
||||||
DeserializationError err = deserializeJson(json, (const char *)mTmpBuf, mTmpSize);
|
|
||||||
json.shrinkToFit();
|
|
||||||
JsonObject obj = json.as<JsonObject>();
|
|
||||||
|
|
||||||
|
|
||||||
// Debugging
|
|
||||||
// mTmpBuf[mTmpSize] = 0;
|
|
||||||
// DPRINTLN(DBG_DEBUG, (const char *)mTmpBuf);
|
|
||||||
|
|
||||||
if (!err && obj)
|
|
||||||
{
|
|
||||||
// insert data into yieldDayHistory object
|
|
||||||
HistoryData *p;
|
|
||||||
if (obj["maximumDay"]>0) // this is power history data
|
|
||||||
p = mApp->getTotalPowerHistoryPtr();
|
|
||||||
else
|
|
||||||
p = mApp->getYieldDayHistoryPtr();
|
|
||||||
|
|
||||||
size_t cnt = obj[F("value")].size();
|
|
||||||
DPRINTLN(DBG_DEBUG, "ArraySize: " + String(cnt));
|
|
||||||
|
|
||||||
for (uint16_t i = 0; i < cnt; i++) {
|
|
||||||
uint16_t val = obj[F("value")][i];
|
|
||||||
p->addValue(val);
|
|
||||||
// DPRINT(DBG_VERBOSE, "value " + String(i) + ": " + String(val) + ", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (err.code()) {
|
|
||||||
case DeserializationError::Ok:
|
|
||||||
break;
|
|
||||||
case DeserializationError::IncompleteInput:
|
|
||||||
DPRINTLN(DBG_DEBUG, F("Incomplete input"));
|
|
||||||
break;
|
|
||||||
case DeserializationError::InvalidInput:
|
|
||||||
DPRINTLN(DBG_DEBUG, F("Invalid input"));
|
|
||||||
break;
|
|
||||||
case DeserializationError::NoMemory:
|
|
||||||
DPRINTLN(DBG_DEBUG, F("Not enough memory ") + String(json.capacity()) + " bytes");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DPRINTLN(DBG_DEBUG, F("Deserialization failed"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
request->send(204); // Success with no page load
|
|
||||||
delete[] mTmpBuf;
|
|
||||||
mTmpBuf = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onApiPostBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
|
void onApiPostBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
|
||||||
DPRINTLN(DBG_VERBOSE, "onApiPostBody");
|
DPRINTLN(DBG_VERBOSE, "onApiPostBody");
|
||||||
|
|
||||||
|
@ -858,31 +779,29 @@ class RestApi {
|
||||||
getGeneric(request, obj.createNestedObject(F("generic")));
|
getGeneric(request, obj.createNestedObject(F("generic")));
|
||||||
obj[F("refresh")] = mConfig->inst.sendInterval;
|
obj[F("refresh")] = mConfig->inst.sendInterval;
|
||||||
obj[F("datapoints")] = HISTORY_DATA_ARR_LENGTH;
|
obj[F("datapoints")] = HISTORY_DATA_ARR_LENGTH;
|
||||||
uint16_t maximum = 0;
|
uint16_t max = 0;
|
||||||
TotalPowerHistory *p = mApp->getTotalPowerHistoryPtr();
|
|
||||||
for (uint16_t fld = 0; fld < HISTORY_DATA_ARR_LENGTH; fld++) {
|
for (uint16_t fld = 0; fld < HISTORY_DATA_ARR_LENGTH; fld++) {
|
||||||
uint16_t value = p->valueAt(fld);
|
uint16_t value = mApp->getHistoryValue(HistoryStorageType::POWER, fld);
|
||||||
obj[F("value")][fld] = value;
|
obj[F("value")][fld] = value;
|
||||||
if (value > maximum)
|
if (value > max)
|
||||||
maximum = value;
|
max = value;
|
||||||
}
|
}
|
||||||
obj[F("maximum")] = maximum;
|
obj[F("max")] = max;
|
||||||
obj[F("maximumDay")] = p->getMaximumDay();
|
obj[F("maxDay")] = mApp->getHistoryMaxDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void getYieldDayHistory(AsyncWebServerRequest *request, JsonObject obj) {
|
void getYieldDayHistory(AsyncWebServerRequest *request, JsonObject obj) {
|
||||||
getGeneric(request, obj.createNestedObject(F("generic")));
|
getGeneric(request, obj.createNestedObject(F("generic")));
|
||||||
obj[F("refresh")] = 86400; // 1 day
|
obj[F("refresh")] = 86400; // 1 day
|
||||||
obj[F("datapoints")] = HISTORY_DATA_ARR_LENGTH;
|
obj[F("datapoints")] = HISTORY_DATA_ARR_LENGTH;
|
||||||
uint16_t maximum = 0;
|
uint16_t max = 0;
|
||||||
YieldDayHistory *p = mApp->getYieldDayHistoryPtr();
|
|
||||||
for (uint16_t fld = 0; fld < HISTORY_DATA_ARR_LENGTH; fld++) {
|
for (uint16_t fld = 0; fld < HISTORY_DATA_ARR_LENGTH; fld++) {
|
||||||
uint16_t value = p->valueAt(fld);
|
uint16_t value = mApp->getHistoryValue(HistoryStorageType::YIELD, fld);
|
||||||
obj[F("value")][fld] = value;
|
obj[F("value")][fld] = value;
|
||||||
if (value > maximum)
|
if (value > max)
|
||||||
maximum = value;
|
max = value;
|
||||||
}
|
}
|
||||||
obj[F("maximum")] = maximum;
|
obj[F("max")] = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue