mirror of
https://github.com/lumapu/ahoy.git
synced 2025-07-23 03:07:12 +02:00
merge
This commit is contained in:
commit
aeeaf0feff
13 changed files with 245 additions and 87 deletions
45
ahoy.code-workspace
Normal file
45
ahoy.code-workspace
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "src"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"files.associations": {
|
||||||
|
"algorithm": "cpp",
|
||||||
|
"array": "cpp",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"deque": "cpp",
|
||||||
|
"format": "cpp",
|
||||||
|
"forward_list": "cpp",
|
||||||
|
"functional": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"iterator": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"memory": "cpp",
|
||||||
|
"queue": "cpp",
|
||||||
|
"random": "cpp",
|
||||||
|
"regex": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"xhash": "cpp",
|
||||||
|
"xlocmon": "cpp",
|
||||||
|
"xlocnum": "cpp",
|
||||||
|
"xmemory": "cpp",
|
||||||
|
"xstring": "cpp",
|
||||||
|
"xtree": "cpp",
|
||||||
|
"xutility": "cpp",
|
||||||
|
"*.tcc": "cpp",
|
||||||
|
"string": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"unordered_set": "cpp",
|
||||||
|
"string_view": "cpp",
|
||||||
|
"sstream": "cpp",
|
||||||
|
"istream": "cpp",
|
||||||
|
"ostream": "cpp"
|
||||||
|
},
|
||||||
|
"editor.formatOnSave": false
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,12 @@
|
||||||
# Development Changes
|
# Development Changes
|
||||||
|
|
||||||
|
## 0.8.57 - 2024-01-15
|
||||||
|
* merge PR: fix immediate clearing of display after sunset #1364
|
||||||
|
* merge PR: MI-MQTT and last retransmit #1363
|
||||||
|
* fixed DTU-ID, now built from the unique part of the MAC
|
||||||
|
* fix lang in `/system` #1346
|
||||||
|
* added protection to prevent update to wrong firmware (environment check)
|
||||||
|
|
||||||
## 0.8.56 - 2024-01-15
|
## 0.8.56 - 2024-01-15
|
||||||
* potential fix of update problems and random reboots #1359 #1354
|
* potential fix of update problems and random reboots #1359 #1354
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ void app::setup() {
|
||||||
}
|
}
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
if(mConfig->cmt.enabled) {
|
if(mConfig->cmt.enabled) {
|
||||||
mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb, false);
|
mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef ETHERNET
|
#ifdef ETHERNET
|
||||||
|
|
|
@ -13,7 +13,11 @@
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 8
|
#define VERSION_MINOR 8
|
||||||
|
<<<<<<< HEAD
|
||||||
#define VERSION_PATCH 560001
|
#define VERSION_PATCH 560001
|
||||||
|
=======
|
||||||
|
#define VERSION_PATCH 57
|
||||||
|
>>>>>>> f503516c9feba7a7cc6fb427954165ce05cd7746
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -11,10 +11,9 @@
|
||||||
#include "hmInverter.h"
|
#include "hmInverter.h"
|
||||||
#include "../utils/dbg.h"
|
#include "../utils/dbg.h"
|
||||||
|
|
||||||
// needs a '+1' because the comparison does not send if attempts is equal 0
|
#define DEFAULT_ATTEMPS 5
|
||||||
#define DEFAULT_ATTEMPS 5 + 1
|
#define MORE_ATTEMPS_ALARMDATA 15
|
||||||
#define MORE_ATTEMPS_ALARMDATA 15 + 1
|
#define MORE_ATTEMPS_GRIDONPROFILEPARA 15
|
||||||
#define MORE_ATTEMPS_GRIDONPROFILEPARA 15 + 1
|
|
||||||
|
|
||||||
template <uint8_t N=100>
|
template <uint8_t N=100>
|
||||||
class CommQueue {
|
class CommQueue {
|
||||||
|
|
|
@ -91,6 +91,7 @@ class Communication : public CommQueue<> {
|
||||||
mIsRetransmit = false;
|
mIsRetransmit = false;
|
||||||
if(NULL == q->iv->radio)
|
if(NULL == q->iv->radio)
|
||||||
cmdDone(false); // can't communicate while radio is not defined!
|
cmdDone(false); // can't communicate while radio is not defined!
|
||||||
|
mFirstTry = q->iv->isAvailable();
|
||||||
q->iv->mCmd = q->cmd;
|
q->iv->mCmd = q->cmd;
|
||||||
q->iv->mIsSingleframeReq = false;
|
q->iv->mIsSingleframeReq = false;
|
||||||
mState = States::START;
|
mState = States::START;
|
||||||
|
@ -140,8 +141,25 @@ class Communication : public CommQueue<> {
|
||||||
if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) {
|
if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) {
|
||||||
q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ));
|
q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ));
|
||||||
mWaitTime.startTimeMonitor(1000);
|
mWaitTime.startTimeMonitor(1000);
|
||||||
} else if(IV_MI == q->iv->ivGen)
|
} else {
|
||||||
q->iv->mIvTxCnt++;
|
if(IV_MI == q->iv->ivGen)
|
||||||
|
q->iv->mIvTxCnt++;
|
||||||
|
if(mFirstTry) {
|
||||||
|
mFirstTry = false;
|
||||||
|
setAttempt();
|
||||||
|
mHeu.evalTxChQuality(q->iv, false, 0, 0);
|
||||||
|
//q->iv->radioStatistics.rxFailNoAnser++;
|
||||||
|
q->iv->radioStatistics.retransmits++;
|
||||||
|
mWaitTime.stopTimeMonitor();
|
||||||
|
mState = States::START;
|
||||||
|
|
||||||
|
/*if(*mSerialDebug) {
|
||||||
|
DPRINT_IVID(DBG_INFO, q->iv->id);
|
||||||
|
DBGPRINTLN(F("second try"));
|
||||||
|
}*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
closeRequest(q, false);
|
closeRequest(q, false);
|
||||||
break;
|
break;
|
||||||
|
@ -178,11 +196,11 @@ class Communication : public CommQueue<> {
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0 == q->attempts) {
|
/*if(0 == q->attempts) {
|
||||||
DPRINT_IVID(DBG_INFO, q->iv->id);
|
DPRINT_IVID(DBG_INFO, q->iv->id);
|
||||||
DBGPRINT(F("no attempts left"));
|
DBGPRINT(F("no attempts left"));
|
||||||
closeRequest(q, false);
|
closeRequest(q, false);
|
||||||
} else {
|
} else {*/
|
||||||
if(q->iv->ivGen != IV_MI) {
|
if(q->iv->ivGen != IV_MI) {
|
||||||
mState = States::CHECK_PACKAGE;
|
mState = States::CHECK_PACKAGE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -207,7 +225,7 @@ class Communication : public CommQueue<> {
|
||||||
closeRequest(q, true);
|
closeRequest(q, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
//}
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -235,6 +253,12 @@ class Communication : public CommQueue<> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(framnr) {
|
if(framnr) {
|
||||||
|
if(0 == q->attempts) {
|
||||||
|
DPRINT_IVID(DBG_INFO, q->iv->id);
|
||||||
|
DBGPRINT(F("no attempts left"));
|
||||||
|
closeRequest(q, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setAttempt();
|
setAttempt();
|
||||||
|
|
||||||
if(*mSerialDebug) {
|
if(*mSerialDebug) {
|
||||||
|
@ -516,15 +540,15 @@ class Communication : public CommQueue<> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendRetransmit(const queue_s *q, uint8_t i) {
|
void sendRetransmit(const queue_s *q, uint8_t i) {
|
||||||
if(q->attempts) {
|
//if(q->attempts) {
|
||||||
q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true);
|
q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true);
|
||||||
q->iv->radioStatistics.retransmits++;
|
q->iv->radioStatistics.retransmits++;
|
||||||
mWaitTime.startTimeMonitor(SINGLEFR_TIMEOUT); // timeout
|
mWaitTime.startTimeMonitor(SINGLEFR_TIMEOUT); // timeout
|
||||||
mState = States::WAIT;
|
mState = States::WAIT;
|
||||||
} else {
|
/*} else {
|
||||||
//add(q, true);
|
//add(q, true);
|
||||||
closeRequest(q, false);
|
closeRequest(q, false);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -547,7 +571,6 @@ class Communication : public CommQueue<> {
|
||||||
q->iv->mGotLastMsg = false;
|
q->iv->mGotLastMsg = false;
|
||||||
q->iv->miMultiParts = 0;
|
q->iv->miMultiParts = 0;
|
||||||
mIsRetransmit = false;
|
mIsRetransmit = false;
|
||||||
mFirstTry = false; // for correct reset
|
|
||||||
mState = States::RESET;
|
mState = States::RESET;
|
||||||
DBGPRINTLN(F("-----"));
|
DBGPRINTLN(F("-----"));
|
||||||
}
|
}
|
||||||
|
@ -604,6 +627,8 @@ class Communication : public CommQueue<> {
|
||||||
rec->ts = q->ts;
|
rec->ts = q->ts;
|
||||||
q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1);
|
q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1);
|
||||||
q->iv->miMultiParts +=4;
|
q->iv->miMultiParts +=4;
|
||||||
|
rec->mqttSentStatus = MqttSentStatus::NEW_DATA;
|
||||||
|
|
||||||
} else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10
|
} else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10
|
||||||
DPRINT_IVID(DBG_INFO, q->iv->id);
|
DPRINT_IVID(DBG_INFO, q->iv->id);
|
||||||
if ( p->packet[9] == 0x01 ) {
|
if ( p->packet[9] == 0x01 ) {
|
||||||
|
@ -620,6 +645,7 @@ class Communication : public CommQueue<> {
|
||||||
record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure
|
record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure
|
||||||
rec->ts = q->ts;
|
rec->ts = q->ts;
|
||||||
q->iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1);
|
q->iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1);
|
||||||
|
rec->mqttSentStatus = MqttSentStatus::NEW_DATA;
|
||||||
|
|
||||||
if(*mSerialDebug) {
|
if(*mSerialDebug) {
|
||||||
DPRINT(DBG_INFO,F("HW_FB_TLmValue "));
|
DPRINT(DBG_INFO,F("HW_FB_TLmValue "));
|
||||||
|
@ -667,6 +693,7 @@ class Communication : public CommQueue<> {
|
||||||
inline void miGPFDecode(packet_t *p, const queue_s *q) {
|
inline void miGPFDecode(packet_t *p, const queue_s *q) {
|
||||||
record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure
|
record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure
|
||||||
rec->ts = q->ts;
|
rec->ts = q->ts;
|
||||||
|
rec->mqttSentStatus = MqttSentStatus::NEW_DATA;
|
||||||
|
|
||||||
q->iv->setValue(2, rec, (uint32_t) (((p->packet[10] << 8) | p->packet[11]))); //FLD_GRID_PROFILE_CODE
|
q->iv->setValue(2, rec, (uint32_t) (((p->packet[10] << 8) | p->packet[11]))); //FLD_GRID_PROFILE_CODE
|
||||||
q->iv->setValue(3, rec, (uint32_t) (((p->packet[12] << 8) | p->packet[13]))); //FLD_GRID_PROFILE_VERSION
|
q->iv->setValue(3, rec, (uint32_t) (((p->packet[12] << 8) | p->packet[13]))); //FLD_GRID_PROFILE_VERSION
|
||||||
|
@ -849,6 +876,8 @@ class Communication : public CommQueue<> {
|
||||||
if (!stsok) {
|
if (!stsok) {
|
||||||
q->iv->setValue(q->iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts);
|
q->iv->setValue(q->iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts);
|
||||||
q->iv->lastAlarm[0] = alarm_t(prntsts, q->ts, 0);
|
q->iv->lastAlarm[0] = alarm_t(prntsts, q->ts, 0);
|
||||||
|
rec->ts = q->ts;
|
||||||
|
rec->mqttSentStatus = MqttSentStatus::NEW_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) {
|
if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) {
|
||||||
|
@ -907,17 +936,12 @@ class Communication : public CommQueue<> {
|
||||||
iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10);
|
iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10);
|
||||||
|
|
||||||
iv->doCalculations();
|
iv->doCalculations();
|
||||||
|
rec->mqttSentStatus = MqttSentStatus::NEW_DATA;
|
||||||
// update status state-machine,
|
// update status state-machine,
|
||||||
if (ac_pow)
|
if (ac_pow)
|
||||||
iv->isProducing();
|
iv->isProducing();
|
||||||
//closeRequest(iv, iv->miMultiParts > 5);
|
|
||||||
|
|
||||||
//mHeu.setGotAll(iv);
|
|
||||||
//cmdDone(false);
|
|
||||||
if(NULL != mCbPayload)
|
if(NULL != mCbPayload)
|
||||||
(mCbPayload)(RealTimeRunData_Debug, iv);
|
(mCbPayload)(RealTimeRunData_Debug, iv);
|
||||||
|
|
||||||
//mState = States::RESET; // everything ok, next request
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -103,16 +103,19 @@ class Radio {
|
||||||
void generateDtuSn(void) {
|
void generateDtuSn(void) {
|
||||||
uint32_t chipID = 0;
|
uint32_t chipID = 0;
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
uint64_t MAC = ESP.getEfuseMac();
|
chipID = (ESP.getEfuseMac() & 0xffffffff);
|
||||||
chipID = ((MAC >> 8) & 0xFF0000) | ((MAC >> 24) & 0xFF00) | ((MAC >> 40) & 0xFF);
|
|
||||||
#else
|
#else
|
||||||
chipID = ESP.getChipId();
|
chipID = ESP.getChipId();
|
||||||
#endif
|
#endif
|
||||||
mDtuSn = 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal
|
|
||||||
for(int i = 0; i < 7; i++) {
|
uint8_t t;
|
||||||
mDtuSn |= (chipID % 10) << (i * 4);
|
for(int i = 0; i < (7 << 2); i += 4) {
|
||||||
chipID /= 10;
|
t = (chipID >> i) & 0x0f;
|
||||||
|
if(t > 0x09)
|
||||||
|
t -= 6;
|
||||||
|
mDtuSn |= (t << i);
|
||||||
}
|
}
|
||||||
|
mDtuSn |= 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t mDtuSn;
|
uint32_t mDtuSn;
|
||||||
|
|
|
@ -81,7 +81,7 @@ class DisplayMono {
|
||||||
mDispWidth = mDisplay->getDisplayWidth();
|
mDispWidth = mDisplay->getDisplayWidth();
|
||||||
mDispHeight = mDisplay->getDisplayHeight();
|
mDispHeight = mDisplay->getDisplayHeight();
|
||||||
mDispSwitchTime.stopTimeMonitor();
|
mDispSwitchTime.stopTimeMonitor();
|
||||||
if (mCfg->graph_ratio == 100) // if graph ratio is 100% start in graph mode
|
if (100 == mCfg->graph_ratio) // if graph ratio is 100% start in graph mode
|
||||||
mDispSwitchState = DispSwitchState::GRAPH;
|
mDispSwitchState = DispSwitchState::GRAPH;
|
||||||
else if (mCfg->graph_ratio != 0)
|
else if (mCfg->graph_ratio != 0)
|
||||||
mDispSwitchTime.startTimeMonitor(150 * (100 - mCfg->graph_ratio)); // start display mode change only if ratio is neither 0 nor 100
|
mDispSwitchTime.startTimeMonitor(150 * (100 - mCfg->graph_ratio)); // start display mode change only if ratio is neither 0 nor 100
|
||||||
|
@ -90,39 +90,82 @@ class DisplayMono {
|
||||||
// pixelshift screensaver with wipe effect
|
// pixelshift screensaver with wipe effect
|
||||||
void calcPixelShift(int range) {
|
void calcPixelShift(int range) {
|
||||||
int8_t mod = (millis() / 10000) % ((range >> 1) << 2);
|
int8_t mod = (millis() / 10000) % ((range >> 1) << 2);
|
||||||
mPixelshift = mCfg->screenSaver == 1 ? ((mod < range) ? mod - (range >> 1) : -(mod - range - (range >> 1) + 1)) : 0;
|
mPixelshift = (1 == mCfg->screenSaver) ? ((mod < range) ? mod - (range >> 1) : -(mod - range - (range >> 1) + 1)) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum class PowerGraphState {
|
||||||
|
NO_TIME_SYNC,
|
||||||
|
IN_PERIOD,
|
||||||
|
WAIT_4_NEW_PERIOD,
|
||||||
|
WAIT_4_RESTART
|
||||||
|
};
|
||||||
|
|
||||||
|
// initialize power graph and allocate data buffer based on pixel width
|
||||||
void initPowerGraph(uint8_t width, uint8_t height) {
|
void initPowerGraph(uint8_t width, uint8_t height) {
|
||||||
DBGPRINTLN(F("---- Init Power Graph ----"));
|
DBGPRINTLN(F("---- Init Power Graph ----"));
|
||||||
mPgWidth = width;
|
mPgWidth = width;
|
||||||
mPgHeight = height;
|
mPgHeight = height;
|
||||||
mPgData = new float[mPgWidth];
|
mPgData = new float[mPgWidth];
|
||||||
|
mPgState = PowerGraphState::NO_TIME_SYNC;
|
||||||
resetPowerGraph();
|
resetPowerGraph();
|
||||||
/*
|
|
||||||
Inverter<> *iv;
|
|
||||||
mPgMaxAvailPower = 0;
|
|
||||||
uint8_t nInv = mSys->getNumInverters();
|
|
||||||
for (uint8_t i = 0; i < nInv; i++) {
|
|
||||||
iv = mSys->getInverterByPos(i);
|
|
||||||
if (iv == NULL)
|
|
||||||
continue;
|
|
||||||
for (uint8_t ch = 0; ch < 6; ch++) {
|
|
||||||
mPgMaxAvailPower += iv->config->chMaxPwr[ch];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DBGPRINTLN("max. Power = " + String(mPgMaxAvailPower));*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add new value to power graph and maintain state engine for period times
|
||||||
void addPowerGraphEntry(float val) {
|
void addPowerGraphEntry(float val) {
|
||||||
if ((nullptr != mPgData) && (mDisplayData->utcTs > 0)) { // precondition: power graph initialized and utc time available
|
if (nullptr == mPgData) // power graph not initialized
|
||||||
calcPowerGraphValues();
|
return;
|
||||||
//mPgData[mPgLastPos] = std::max(mPgData[mPgLastPos], (uint8_t) (val * 255.0 / mPgMaxAvailPower)); // normalizing of data to 0-255
|
|
||||||
mPgData[mPgLastPos] = std::max(mPgData[mPgLastPos], val);
|
bool storeStartEndTimes = false;
|
||||||
mPgMaxPwr = std::max(mPgMaxPwr, val); // max value of stored data for scaling of y-axis
|
bool store_entry = false;
|
||||||
|
switch(mPgState) {
|
||||||
|
case PowerGraphState::NO_TIME_SYNC:
|
||||||
|
if ((mDisplayData->pGraphStartTime > 0)
|
||||||
|
&& (mDisplayData->pGraphEndTime > 0) // wait until period data is available ...
|
||||||
|
&& (mDisplayData->utcTs >= mDisplayData->pGraphStartTime)
|
||||||
|
&& (mDisplayData->utcTs < mDisplayData->pGraphEndTime)) // and current time is in period
|
||||||
|
{
|
||||||
|
storeStartEndTimes = true; // period was received -> store
|
||||||
|
store_entry = true;
|
||||||
|
mPgState = PowerGraphState::IN_PERIOD;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PowerGraphState::IN_PERIOD:
|
||||||
|
if (mDisplayData->utcTs > mPgEndTime) // check if end of day is reached ...
|
||||||
|
mPgState = PowerGraphState::WAIT_4_NEW_PERIOD; // then wait for new period setting
|
||||||
|
else
|
||||||
|
store_entry = true;
|
||||||
|
break;
|
||||||
|
case PowerGraphState::WAIT_4_NEW_PERIOD:
|
||||||
|
if ((mPgStartTime != mDisplayData->pGraphStartTime) || (mPgEndTime != mDisplayData->pGraphEndTime)) { // wait until new time period was received ...
|
||||||
|
storeStartEndTimes = true; // and store it for next period
|
||||||
|
mPgState = PowerGraphState::WAIT_4_RESTART;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PowerGraphState::WAIT_4_RESTART:
|
||||||
|
if ((mDisplayData->utcTs >= mPgStartTime) && (mDisplayData->utcTs < mPgEndTime)) { // wait until current time is in period again ...
|
||||||
|
resetPowerGraph(); // then reset power graph data
|
||||||
|
store_entry = true;
|
||||||
|
mPgState = PowerGraphState::IN_PERIOD;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store start and end times of current time period and calculate period length
|
||||||
|
if (storeStartEndTimes) {
|
||||||
|
mPgStartTime = mDisplayData->pGraphStartTime;
|
||||||
|
mPgEndTime = mDisplayData->pGraphEndTime;
|
||||||
|
mPgPeriod = mDisplayData->pGraphEndTime - mDisplayData->pGraphStartTime; // time period of power graph in sec for scaling of x-axis
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store_entry) {
|
||||||
|
mPgLastPos = std::min((uint8_t) sss2PgPos(mDisplayData->utcTs - mPgStartTime), (uint8_t) (mPgWidth - 1)); // current datapoint based on seconds since start
|
||||||
|
mPgData[mPgLastPos] = std::max(mPgData[mPgLastPos], val); // update current datapoint to maximum of all seen values
|
||||||
|
mPgMaxPwr = std::max(mPgMaxPwr, val); // update max value of stored data for scaling of y-axis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// plot power graph to given display offset
|
||||||
void plotPowerGraph(uint8_t xoff, uint8_t yoff) {
|
void plotPowerGraph(uint8_t xoff, uint8_t yoff) {
|
||||||
if (nullptr == mPgData) // power graph not initialized
|
if (nullptr == mPgData) // power graph not initialized
|
||||||
return;
|
return;
|
||||||
|
@ -146,7 +189,7 @@ class DisplayMono {
|
||||||
tm.Minute = 0;
|
tm.Minute = 0;
|
||||||
tm.Second = 0;
|
tm.Second = 0;
|
||||||
for (; tm.Hour <= endHour; tm.Hour++) {
|
for (; tm.Hour <= endHour; tm.Hour++) {
|
||||||
uint8_t x_pos_screen = getPowerGraphXpos(sss2pgpos((uint32_t) makeTime(tm) - mDisplayData->pGraphStartTime)); // scale horizontal axis
|
uint8_t x_pos_screen = getPowerGraphXpos(sss2PgPos((uint32_t) makeTime(tm) - mDisplayData->pGraphStartTime)); // scale horizontal axis
|
||||||
mDisplay->drawPixel(xoff + x_pos_screen, yoff - 1);
|
mDisplay->drawPixel(xoff + x_pos_screen, yoff - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,8 +206,8 @@ class DisplayMono {
|
||||||
|
|
||||||
// draw curve
|
// draw curve
|
||||||
for (uint8_t i = 1; i <= mPgLastPos; i++) {
|
for (uint8_t i = 1; i <= mPgLastPos; i++) {
|
||||||
mDisplay->drawLine(xoff + getPowerGraphXpos(i - 1), yoff - getPowerGraphYpos(i - 1),
|
mDisplay->drawLine(xoff + getPowerGraphXpos(i - 1), yoff - getPowerGraphValueYpos(i - 1),
|
||||||
xoff + getPowerGraphXpos(i), yoff - getPowerGraphYpos(i));
|
xoff + getPowerGraphXpos(i), yoff - getPowerGraphValueYpos(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// print max power value
|
// print max power value
|
||||||
|
@ -195,6 +238,7 @@ class DisplayMono {
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset power graph
|
||||||
void resetPowerGraph() {
|
void resetPowerGraph() {
|
||||||
if (mPgData != nullptr) {
|
if (mPgData != nullptr) {
|
||||||
mPgMaxPwr = 0.0;
|
mPgMaxPwr = 0.0;
|
||||||
|
@ -205,34 +249,28 @@ class DisplayMono {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sss2pgpos(uint seconds_since_start) {
|
// get power graph datapoint index, scaled to current time period, by seconds since start
|
||||||
uint32_t diff = (mDisplayData->pGraphEndTime - mDisplayData->pGraphStartTime);
|
uint8_t sss2PgPos(uint seconds_since_start) {
|
||||||
if(diff)
|
if(mPgPeriod)
|
||||||
return (seconds_since_start * (mPgWidth - 1) / diff);
|
return (seconds_since_start * (mPgWidth - 1) / mPgPeriod);
|
||||||
return 0;
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void calcPowerGraphValues() {
|
// get X-position of power graph, scaled to lastpos, by according data point index
|
||||||
mPgPeriod = mDisplayData->pGraphEndTime - mDisplayData->pGraphStartTime; // length of power graph for scaling of x-axis
|
uint8_t getPowerGraphXpos(uint8_t p) {
|
||||||
uint32_t oldTimeOfDay = mPgTimeOfDay;
|
|
||||||
mPgTimeOfDay = (mDisplayData->utcTs > mDisplayData->pGraphStartTime) ? mDisplayData->utcTs - mDisplayData->pGraphStartTime : 0; // current time of day with respect to current sunrise time
|
|
||||||
if (oldTimeOfDay > mPgTimeOfDay) // new day -> reset old data
|
|
||||||
resetPowerGraph();
|
|
||||||
if(0 == mPgPeriod)
|
|
||||||
mPgPeriod = 1;
|
|
||||||
mPgLastPos = std::min((uint8_t) (mPgTimeOfDay * (mPgWidth - 1) / mPgPeriod), (uint8_t) (mPgWidth - 1)); // current datapoint based on currenct time of day
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t getPowerGraphXpos(uint8_t p) {
|
|
||||||
if ((p <= mPgLastPos) && (mPgLastPos > 0))
|
if ((p <= mPgLastPos) && (mPgLastPos > 0))
|
||||||
return((p * (mPgWidth - 1)) / mPgLastPos); // scaling of x-axis
|
return((p * (mPgWidth - 1)) / mPgLastPos); // scaling of x-axis
|
||||||
return 0;
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getPowerGraphYpos(uint8_t p) {
|
// get Y-position of power graph, scaled to maximum value, by according datapoint index
|
||||||
|
uint8_t getPowerGraphValueYpos(uint8_t p) {
|
||||||
if ((p < mPgWidth) && (mPgMaxPwr > 0))
|
if ((p < mPgWidth) && (mPgMaxPwr > 0))
|
||||||
return((mPgData[p] * (uint32_t) mPgHeight / mPgMaxPwr)); // scaling of data to graph height
|
return((mPgData[p] * (uint32_t) mPgHeight / mPgMaxPwr)); // scaling of data to graph height
|
||||||
return 0;
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -254,9 +292,11 @@ class DisplayMono {
|
||||||
float *mPgData = nullptr;
|
float *mPgData = nullptr;
|
||||||
uint8_t mPgHeight = 0;
|
uint8_t mPgHeight = 0;
|
||||||
float mPgMaxPwr = 0.0;
|
float mPgMaxPwr = 0.0;
|
||||||
uint32_t mPgPeriod = 0; // seconds
|
uint32_t mPgStartTime = 0;
|
||||||
uint32_t mPgTimeOfDay = 0;
|
uint32_t mPgEndTime = 0;
|
||||||
|
uint32_t mPgPeriod = 0; // seconds
|
||||||
uint8_t mPgLastPos = 0;
|
uint8_t mPgLastPos = 0;
|
||||||
|
PowerGraphState mPgState = PowerGraphState::NO_TIME_SYNC;
|
||||||
|
|
||||||
uint16_t mDispHeight;
|
uint16_t mDispHeight;
|
||||||
uint8_t mLuminance;
|
uint8_t mLuminance;
|
||||||
|
|
|
@ -89,9 +89,8 @@ class DisplayMono128X64 : public DisplayMono {
|
||||||
calcPixelShift(pixelShiftRange);
|
calcPixelShift(pixelShiftRange);
|
||||||
|
|
||||||
// add new power data to power graph
|
// add new power data to power graph
|
||||||
if (mDisplayData->nrProducing > 0) {
|
if (mDisplayData->nrProducing > 0)
|
||||||
addPowerGraphEntry(mDisplayData->totalPower);
|
addPowerGraphEntry(mDisplayData->totalPower);
|
||||||
}
|
|
||||||
|
|
||||||
// print Date and time
|
// print Date and time
|
||||||
if (0 != mDisplayData->utcTs)
|
if (0 != mDisplayData->utcTs)
|
||||||
|
|
|
@ -326,8 +326,8 @@ class RestApi {
|
||||||
void getHtmlSystem(AsyncWebServerRequest *request, JsonObject obj) {
|
void getHtmlSystem(AsyncWebServerRequest *request, JsonObject obj) {
|
||||||
getSysInfo(request, obj.createNestedObject(F("system")));
|
getSysInfo(request, obj.createNestedObject(F("system")));
|
||||||
getGeneric(request, obj.createNestedObject(F("generic")));
|
getGeneric(request, obj.createNestedObject(F("generic")));
|
||||||
char tmp[100];
|
char tmp[200];
|
||||||
snprintf(tmp, 100, "<a href=\"/factory\" class=\"btn\">%s</a><br/><br/><a href=\"/reboot\" class=\"btn\">%s</a>", FACTORY_RESET, BTN_REBOOT);
|
snprintf(tmp, 200, "<a href=\"/factory\" class=\"btn\">%s</a><br/><br/><a href=\"/reboot\" class=\"btn\">%s</a>", FACTORY_RESET, BTN_REBOOT);
|
||||||
obj[F("html")] = String(tmp);
|
obj[F("html")] = String(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend class="des">{#SELECT_FILE} (*.bin)</legend>
|
<legend class="des">{#SELECT_FILE} (*.bin)</legend>
|
||||||
<p>{#INSTALLED_VERSION}: <span id="version" style="background-color: var(--input-bg); padding: 7px;"></span></p>
|
<p>{#INSTALLED_VERSION}:<br/><span id="version" style="background-color: var(--input-bg); padding: 7px; display: block; margin: 3px;"></span></p>
|
||||||
<form id="form" method="POST" action="/update" enctype="multipart/form-data" accept-charset="utf-8">
|
<form id="form" method="POST" action="/update" enctype="multipart/form-data" accept-charset="utf-8">
|
||||||
<input type="file" name="update">
|
<input type="file" name="update">
|
||||||
<input type="button" class="btn my-4" value="{#BTN_UPDATE}" onclick="hide()">
|
<input type="button" class="btn my-4" value="{#BTN_UPDATE}" onclick="hide()">
|
||||||
|
@ -23,17 +23,34 @@
|
||||||
</div>
|
</div>
|
||||||
{#HTML_FOOTER}
|
{#HTML_FOOTER}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
var env;
|
||||||
function parseGeneric(obj) {
|
function parseGeneric(obj) {
|
||||||
parseNav(obj);
|
parseNav(obj)
|
||||||
parseESP(obj);
|
parseESP(obj)
|
||||||
parseRssi(obj);
|
parseRssi(obj)
|
||||||
|
env = obj.env
|
||||||
document.getElementById("version").innerHTML = "{#VERSION_FULL}_" + obj.env + ".bin"
|
document.getElementById("version").innerHTML = "{#VERSION_FULL}_" + obj.env + ".bin"
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
document.getElementById("form").submit();
|
var bin = document.getElementsByName("update")[0].value.slice(-env.length-4, -4)
|
||||||
var e = document.getElementById("content");
|
if (bin !== env) {
|
||||||
e.replaceChildren(span("{#UPDATE_STARTED}"));
|
var html = ml("div", {class: "row"}, [
|
||||||
|
ml("div", {class: "row my-3"}, "{#WARN_DIFF_ENV}"),
|
||||||
|
ml("div", {class: "row"}, [
|
||||||
|
ml("div", {class: "col-6"}, ml("input", {type: "button", class: "btn", value: "{#CANCEL}", onclick: function() { modalClose(); }}, null)),
|
||||||
|
ml("div", {class: "col-6"}, ml("input", {type: "button", class: "btn", value: "{#CONTIUE}", onclick: function() { start(); modalClose(); }}, null))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
modal("{#UPDATE_MODAL}", html)
|
||||||
|
} else
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
document.getElementById("form").submit()
|
||||||
|
var e = document.getElementById("content")
|
||||||
|
e.replaceChildren(span("{#UPDATE_STARTED}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
getAjax("/api/generic", parseGeneric);
|
getAjax("/api/generic", parseGeneric);
|
||||||
|
|
|
@ -73,15 +73,15 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LANG_DE
|
#ifdef LANG_DE
|
||||||
#define FACTORY_RESET "Ahoy Factory Reset"
|
|
||||||
#else /*LANG_EN*/
|
|
||||||
#define FACTORY_RESET "Ahoy auf Werkseinstellungen zurücksetzen"
|
#define FACTORY_RESET "Ahoy auf Werkseinstellungen zurücksetzen"
|
||||||
|
#else /*LANG_EN*/
|
||||||
|
#define FACTORY_RESET "Ahoy Factory Reset"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LANG_DE
|
#ifdef LANG_DE
|
||||||
#define BTN_REBOOT "Reboot"
|
|
||||||
#else /*LANG_EN*/
|
|
||||||
#define BTN_REBOOT "Ahoy neustarten"
|
#define BTN_REBOOT "Ahoy neustarten"
|
||||||
|
#else /*LANG_EN*/
|
||||||
|
#define BTN_REBOOT "Reboot"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /*__LANG_H__*/
|
#endif /*__LANG_H__*/
|
||||||
|
|
|
@ -781,7 +781,7 @@
|
||||||
{
|
{
|
||||||
"token": "IRQ_WORKING",
|
"token": "IRQ_WORKING",
|
||||||
"en": "Interrupt Pin working",
|
"en": "Interrupt Pin working",
|
||||||
"de": "Interrupt Pin funktoniert"
|
"de": "Interrupt Pin funktioniert"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"token": "NRF24_DATA_RATE",
|
"token": "NRF24_DATA_RATE",
|
||||||
|
@ -1052,6 +1052,26 @@
|
||||||
"token": "UPDATE_STARTED",
|
"token": "UPDATE_STARTED",
|
||||||
"en": "update started",
|
"en": "update started",
|
||||||
"de": "Aktualisierung gestartet"
|
"de": "Aktualisierung gestartet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"token": "UPDATE_MODAL",
|
||||||
|
"en": "Warning",
|
||||||
|
"de": "Warnung"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"token": "WARN_DIFF_ENV",
|
||||||
|
"en": "your environment does not match the update file!",
|
||||||
|
"de": "Die ausgewählte Firmware passt uU. nicht zum Chipsatz!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"token": "CONTIUE",
|
||||||
|
"en": "continue",
|
||||||
|
"de": "fortfahren"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"token": "CANCEL",
|
||||||
|
"en": "cancel",
|
||||||
|
"de": "abbrechen"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue