mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-23 13:56:10 +02:00
parent
0be3a23603
commit
be9c505407
11 changed files with 83 additions and 44 deletions
|
@ -1,5 +1,9 @@
|
||||||
# Development Changes
|
# Development Changes
|
||||||
|
|
||||||
|
|
||||||
|
## 0.7.12 - 2023-07-09
|
||||||
|
* added inverter status - state-machine #1016
|
||||||
|
|
||||||
## 0.7.11 - 2023-07-09
|
## 0.7.11 - 2023-07-09
|
||||||
* fix MqTT endless loop #1013
|
* fix MqTT endless loop #1013
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ void app::setup() {
|
||||||
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
|
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mSys.setup(&mTimestamp);
|
||||||
mSys.addInverters(&mConfig->inst);
|
mSys.addInverters(&mConfig->inst);
|
||||||
if(mConfig->nrf.enabled) {
|
if(mConfig->nrf.enabled) {
|
||||||
mPayload.setup(this, &mSys, &mNrfRadio, &mStat, mConfig->nrf.maxRetransPerPyld, &mTimestamp);
|
mPayload.setup(this, &mSys, &mNrfRadio, &mStat, mConfig->nrf.maxRetransPerPyld, &mTimestamp);
|
||||||
|
@ -413,7 +414,7 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) {
|
||||||
continue; // skip to next inverter
|
continue; // skip to next inverter
|
||||||
|
|
||||||
if (checkAvail) {
|
if (checkAvail) {
|
||||||
if (!iv->isAvailable(mTimestamp))
|
if (!iv->isAvailable())
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,7 +497,7 @@ void app::updateLed(void) {
|
||||||
if (mConfig->led.led0 != 0xff) {
|
if (mConfig->led.led0 != 0xff) {
|
||||||
Inverter<> *iv = mSys.getInverterByPos(0);
|
Inverter<> *iv = mSys.getInverterByPos(0);
|
||||||
if (NULL != iv) {
|
if (NULL != iv) {
|
||||||
if (iv->isProducing(mTimestamp))
|
if (iv->isProducing())
|
||||||
digitalWrite(mConfig->led.led0, led_on);
|
digitalWrite(mConfig->led.led0, led_on);
|
||||||
else
|
else
|
||||||
digitalWrite(mConfig->led.led0, led_off);
|
digitalWrite(mConfig->led.led0, led_off);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 7
|
#define VERSION_MINOR 7
|
||||||
#define VERSION_PATCH 11
|
#define VERSION_PATCH 12
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -102,6 +102,13 @@ const calcFunc_t<T> calcFunctions[] = {
|
||||||
{ CALC_IRR_CH, &calcIrradiation }
|
{ CALC_IRR_CH, &calcIrradiation }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class InverterStatus : uint8_t {
|
||||||
|
OFF,
|
||||||
|
STARTING,
|
||||||
|
PRODUCING,
|
||||||
|
WAS_PRODUCING,
|
||||||
|
WAS_ON
|
||||||
|
};
|
||||||
|
|
||||||
template <class REC_TYP>
|
template <class REC_TYP>
|
||||||
class Inverter {
|
class Inverter {
|
||||||
|
@ -123,6 +130,9 @@ class Inverter {
|
||||||
//String lastAlarmMsg;
|
//String lastAlarmMsg;
|
||||||
bool initialized; // needed to check if the inverter was correctly added (ESP32 specific - union types are never null)
|
bool initialized; // needed to check if the inverter was correctly added (ESP32 specific - union types are never null)
|
||||||
bool isConnected; // shows if inverter was successfully identified (fw version and hardware info)
|
bool isConnected; // shows if inverter was successfully identified (fw version and hardware info)
|
||||||
|
InverterStatus status; // indicates the current inverter status
|
||||||
|
|
||||||
|
static uint32_t *timestamp; // system timestamp
|
||||||
|
|
||||||
Inverter() {
|
Inverter() {
|
||||||
ivGen = IV_HM;
|
ivGen = IV_HM;
|
||||||
|
@ -135,6 +145,7 @@ class Inverter {
|
||||||
//lastAlarmMsg = "nothing";
|
//lastAlarmMsg = "nothing";
|
||||||
alarmMesIndex = 0;
|
alarmMesIndex = 0;
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
|
status = InverterStatus::OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Inverter() {
|
~Inverter() {
|
||||||
|
@ -319,6 +330,9 @@ class Inverter {
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DPRINTLN(DBG_ERROR, F("addValue: assignment not found with cmd 0x"));
|
DPRINTLN(DBG_ERROR, F("addValue: assignment not found with cmd 0x"));
|
||||||
|
|
||||||
|
// update status state-machine
|
||||||
|
isProducing();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*inline REC_TYP getPowerLimit(void) {
|
/*inline REC_TYP getPowerLimit(void) {
|
||||||
|
@ -372,25 +386,39 @@ class Inverter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAvailable(uint32_t timestamp) {
|
bool isAvailable() {
|
||||||
if((timestamp - recordMeas.ts) < INACT_THRES_SEC)
|
bool val = false;
|
||||||
return true;
|
if((*timestamp - recordMeas.ts) < INACT_THRES_SEC)
|
||||||
if((timestamp - recordInfo.ts) < INACT_THRES_SEC)
|
val = true;
|
||||||
return true;
|
if((*timestamp - recordInfo.ts) < INACT_THRES_SEC)
|
||||||
if((timestamp - recordConfig.ts) < INACT_THRES_SEC)
|
val = true;
|
||||||
return true;
|
if((*timestamp - recordConfig.ts) < INACT_THRES_SEC)
|
||||||
if((timestamp - recordAlarm.ts) < INACT_THRES_SEC)
|
val = true;
|
||||||
return true;
|
if((*timestamp - recordAlarm.ts) < INACT_THRES_SEC)
|
||||||
return false;
|
val = true;
|
||||||
|
|
||||||
|
if(val) {
|
||||||
|
if((InverterStatus::OFF == status) || (InverterStatus::WAS_ON == status))
|
||||||
|
status = InverterStatus::STARTING;
|
||||||
|
} else
|
||||||
|
status = InverterStatus::WAS_ON;
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isProducing(uint32_t timestamp) {
|
bool isProducing() {
|
||||||
|
bool val = false;
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isProducing"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isProducing"));
|
||||||
if(isAvailable(timestamp)) {
|
if(isAvailable()) {
|
||||||
uint8_t pos = getPosByChFld(CH0, FLD_PAC, &recordMeas);
|
uint8_t pos = getPosByChFld(CH0, FLD_PAC, &recordMeas);
|
||||||
return (getValue(pos, &recordMeas) > INACT_PWR_THRESH);
|
val = (getValue(pos, &recordMeas) > INACT_PWR_THRESH);
|
||||||
|
|
||||||
|
if(val)
|
||||||
|
status = InverterStatus::PRODUCING;
|
||||||
|
else if(InverterStatus::PRODUCING == status)
|
||||||
|
status = InverterStatus::WAS_PRODUCING;
|
||||||
}
|
}
|
||||||
return false;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getFwVersion() {
|
uint16_t getFwVersion() {
|
||||||
|
@ -605,6 +633,9 @@ class Inverter {
|
||||||
bool mDevControlRequest; // true if change needed
|
bool mDevControlRequest; // true if change needed
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class REC_TYP>
|
||||||
|
uint32_t *Inverter<REC_TYP>::timestamp {0};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To calculate values which are not transmitted by the unit there is a generic
|
* To calculate values which are not transmitted by the unit there is a generic
|
||||||
|
|
|
@ -13,7 +13,8 @@ class HmSystem {
|
||||||
public:
|
public:
|
||||||
HmSystem() {}
|
HmSystem() {}
|
||||||
|
|
||||||
void setup() {
|
void setup(uint32_t *timestamp) {
|
||||||
|
mInverter[0].timestamp = timestamp;
|
||||||
mNumInv = 0;
|
mNumInv = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ lib_deps =
|
||||||
https://github.com/yubox-node-org/ESPAsyncWebServer
|
https://github.com/yubox-node-org/ESPAsyncWebServer
|
||||||
nrf24/RF24 @ 1.4.5
|
nrf24/RF24 @ 1.4.5
|
||||||
paulstoffregen/Time @ ^1.6.1
|
paulstoffregen/Time @ ^1.6.1
|
||||||
https://github.com/bertmelis/espMqttClient#v1.4.2
|
https://github.com/bertmelis/espMqttClient#v1.4.4
|
||||||
bblanchon/ArduinoJson @ ^6.21.2
|
bblanchon/ArduinoJson @ ^6.21.2
|
||||||
https://github.com/JChristensen/Timezone @ ^1.2.4
|
https://github.com/JChristensen/Timezone @ ^1.2.4
|
||||||
olikraus/U8g2 @ ^2.34.17
|
olikraus/U8g2 @ ^2.34.17
|
||||||
|
|
|
@ -89,7 +89,7 @@ class Display {
|
||||||
if (iv == NULL)
|
if (iv == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (iv->isProducing(*mUtcTs))
|
if (iv->isProducing())
|
||||||
isprod++;
|
isprod++;
|
||||||
|
|
||||||
totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec);
|
totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec);
|
||||||
|
|
|
@ -489,9 +489,9 @@ class PubMqtt {
|
||||||
|
|
||||||
// inverter status
|
// inverter status
|
||||||
uint8_t status = MQTT_STATUS_NOT_AVAIL_NOT_PROD;
|
uint8_t status = MQTT_STATUS_NOT_AVAIL_NOT_PROD;
|
||||||
if (iv->isAvailable(*mUtcTimestamp)) {
|
if (iv->isAvailable()) {
|
||||||
anyAvail = true;
|
anyAvail = true;
|
||||||
status = (iv->isProducing(*mUtcTimestamp)) ? MQTT_STATUS_AVAIL_PROD : MQTT_STATUS_AVAIL_NOT_PROD;
|
status = (iv->isProducing()) ? MQTT_STATUS_AVAIL_PROD : MQTT_STATUS_AVAIL_NOT_PROD;
|
||||||
}
|
}
|
||||||
else // inverter is enabled but not available
|
else // inverter is enabled but not available
|
||||||
allAvail = false;
|
allAvail = false;
|
||||||
|
@ -551,7 +551,7 @@ class PubMqtt {
|
||||||
switch (rec->assign[i].fieldId) {
|
switch (rec->assign[i].fieldId) {
|
||||||
case FLD_YT:
|
case FLD_YT:
|
||||||
case FLD_YD:
|
case FLD_YD:
|
||||||
if ((rec->assign[i].ch == CH0) && (!iv->isProducing(*mUtcTimestamp))) // avoids returns to 0 on restart
|
if ((rec->assign[i].ch == CH0) && (!iv->isProducing())) // avoids returns to 0 on restart
|
||||||
continue;
|
continue;
|
||||||
retained = true;
|
retained = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -67,6 +67,7 @@ class PubMqttIvData {
|
||||||
|
|
||||||
void stateStart() {
|
void stateStart() {
|
||||||
mLastIvId = 0;
|
mLastIvId = 0;
|
||||||
|
mTotalFound = false;
|
||||||
if(!mSendList->empty()) {
|
if(!mSendList->empty()) {
|
||||||
mCmd = mSendList->front().cmd;
|
mCmd = mSendList->front().cmd;
|
||||||
mIvSend = mSendList->front().iv;
|
mIvSend = mSendList->front().iv;
|
||||||
|
@ -99,7 +100,7 @@ class PubMqttIvData {
|
||||||
mPos = 0;
|
mPos = 0;
|
||||||
if(found)
|
if(found)
|
||||||
mState = SEND_DATA;
|
mState = SEND_DATA;
|
||||||
else if(mSendTotals)
|
else if(mSendTotals && mTotalFound)
|
||||||
mState = SEND_TOTALS;
|
mState = SEND_TOTALS;
|
||||||
else {
|
else {
|
||||||
mSendList->pop();
|
mSendList->pop();
|
||||||
|
@ -122,20 +123,21 @@ class PubMqttIvData {
|
||||||
if(FLD_YT == rec->assign[mPos].fieldId)
|
if(FLD_YT == rec->assign[mPos].fieldId)
|
||||||
retained = true;
|
retained = true;
|
||||||
else if(FLD_YD == rec->assign[mPos].fieldId) {
|
else if(FLD_YD == rec->assign[mPos].fieldId) {
|
||||||
/*if(!mZeroValues) {
|
if(!mZeroValues) {
|
||||||
if ((rec->assign[mPos].ch == CH0) && (!mIv->isProducing(*mUtcTimestamp))) { // avoids returns to 0 on restart
|
if ((rec->assign[mPos].ch == CH0) && (!mIv->isProducing())) { // avoids returns to 0 on restart
|
||||||
mPos++;
|
mPos++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
retained = true;
|
retained = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate total values for RealTimeRunData_Debug
|
// calculate total values for RealTimeRunData_Debug
|
||||||
if (CH0 == rec->assign[mPos].ch) {
|
if (CH0 == rec->assign[mPos].ch) {
|
||||||
|
if(mIv->status > InverterStatus::STARTING) {
|
||||||
|
mTotalFound = true;
|
||||||
switch (rec->assign[mPos].fieldId) {
|
switch (rec->assign[mPos].fieldId) {
|
||||||
case FLD_PAC:
|
case FLD_PAC:
|
||||||
if(mIv->isAvailable(*mUtcTimestamp))
|
|
||||||
mTotal[0] += mIv->getValue(mPos, rec);
|
mTotal[0] += mIv->getValue(mPos, rec);
|
||||||
break;
|
break;
|
||||||
case FLD_YT:
|
case FLD_YT:
|
||||||
|
@ -145,11 +147,11 @@ class PubMqttIvData {
|
||||||
mTotal[2] += mIv->getValue(mPos, rec);
|
mTotal[2] += mIv->getValue(mPos, rec);
|
||||||
break;
|
break;
|
||||||
case FLD_PDC:
|
case FLD_PDC:
|
||||||
if(mIv->isAvailable(*mUtcTimestamp))
|
|
||||||
mTotal[3] += mIv->getValue(mPos, rec);
|
mTotal[3] += mIv->getValue(mPos, rec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
mIvLastRTRpub[mIv->id] = lastTs;
|
mIvLastRTRpub[mIv->id] = lastTs;
|
||||||
|
|
||||||
|
@ -207,7 +209,7 @@ class PubMqttIvData {
|
||||||
|
|
||||||
uint8_t mCmd;
|
uint8_t mCmd;
|
||||||
uint8_t mLastIvId;
|
uint8_t mLastIvId;
|
||||||
bool mSendTotals;
|
bool mSendTotals, mTotalFound;
|
||||||
float mTotal[4];
|
float mTotal[4];
|
||||||
|
|
||||||
Inverter<> *mIv, *mIvSend;
|
Inverter<> *mIv, *mIvSend;
|
||||||
|
|
|
@ -28,7 +28,7 @@ class PubSerial {
|
||||||
Inverter<> *iv = mSys->getInverterByPos(id);
|
Inverter<> *iv = mSys->getInverterByPos(id);
|
||||||
if (NULL != iv) {
|
if (NULL != iv) {
|
||||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
if (iv->isAvailable(*mUtcTimestamp)) {
|
if (iv->isAvailable()) {
|
||||||
DPRINTLN(DBG_INFO, "Iv: " + String(id));
|
DPRINTLN(DBG_INFO, "Iv: " + String(id));
|
||||||
for (uint8_t i = 0; i < rec->length; i++) {
|
for (uint8_t i = 0; i < rec->length; i++) {
|
||||||
if (0.0f != iv->getValue(i, rec)) {
|
if (0.0f != iv->getValue(i, rec)) {
|
||||||
|
|
|
@ -472,8 +472,8 @@ class RestApi {
|
||||||
invObj[F("id")] = i;
|
invObj[F("id")] = i;
|
||||||
invObj[F("name")] = String(iv->config->name);
|
invObj[F("name")] = String(iv->config->name);
|
||||||
invObj[F("version")] = String(iv->getFwVersion());
|
invObj[F("version")] = String(iv->getFwVersion());
|
||||||
invObj[F("is_avail")] = iv->isAvailable(mApp->getTimestamp());
|
invObj[F("is_avail")] = iv->isAvailable();
|
||||||
invObj[F("is_producing")] = iv->isProducing(mApp->getTimestamp());
|
invObj[F("is_producing")] = iv->isProducing();
|
||||||
invObj[F("ts_last_success")] = iv->getLastTs(rec);
|
invObj[F("ts_last_success")] = iv->getLastTs(rec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue