From 44e1cae4ea3ea740be2069d33a1fcb235206f61f Mon Sep 17 00:00:00 2001 From: oberfritze <139758614+oberfritze@users.noreply.github.com> Date: Fri, 4 Aug 2023 21:55:00 +0200 Subject: [PATCH] Add files via upload --- src/hm/hmDefines.h | 29 ++++++-- src/hm/hmInverter.h | 55 +++++++++++++- src/hm/hmPayload.h | 55 +++++++++++--- src/hm/hmRadio.h | 6 ++ src/hm/hmSystem.h | 177 +++++++++++++++++++++++++++++++++++++++++++- src/hm/miPayload.h | 4 +- 6 files changed, 303 insertions(+), 23 deletions(-) diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index bd12f72b..c7f853f5 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -9,6 +9,7 @@ #include "../utils/dbg.h" #include + // inverter generations enum {IV_HM = 0, IV_MI}; @@ -21,17 +22,17 @@ enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT, FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_T, FLD_PF, FLD_EFF, FLD_IRR, FLD_Q, FLD_EVT, FLD_FW_VERSION, FLD_FW_BUILD_YEAR, FLD_FW_BUILD_MONTH_DAY, FLD_FW_BUILD_HOUR_MINUTE, FLD_HW_ID, - FLD_ACT_ACTIVE_PWR_LIMIT, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE}; - + FLD_ACT_ACTIVE_PWR_LIMIT, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE, FLD_MP}; + const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal", "U_AC", "I_AC", "P_AC", "F_AC", "Temp", "PF_AC", "Efficiency", "Irradiation","Q_AC", "ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","FWBuildHourMinute","HWPartId", - "active_PowerLimit", /*"reactivePowerLimit","Powerfactor",*/ "LastAlarmCode"}; + "active_PowerLimit", /*"reactivePowerLimit","Powerfactor",*/ "LastAlarmCode", "MaxPower"}; const char* const notAvail = "n/a"; const uint8_t fieldUnits[] = {UNIT_V, UNIT_A, UNIT_W, UNIT_WH, UNIT_KWH, UNIT_KWH, UNIT_V, UNIT_A, UNIT_W, UNIT_HZ, UNIT_C, UNIT_NONE, UNIT_PCT, UNIT_PCT, UNIT_VAR, - UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_PCT, UNIT_NONE}; + UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_PCT, UNIT_NONE, UNIT_W}; // mqtt discovery device classes enum {DEVICE_CLS_NONE = 0, DEVICE_CLS_CURRENT, DEVICE_CLS_ENERGY, DEVICE_CLS_PWR, DEVICE_CLS_VOLTAGE, DEVICE_CLS_FREQ, DEVICE_CLS_TEMP}; @@ -62,7 +63,7 @@ const byteAssign_fieldDeviceClass deviceFieldAssignment[] = { #define DEVICE_CLS_ASSIGN_LIST_LEN (sizeof(deviceFieldAssignment) / sizeof(byteAssign_fieldDeviceClass)) // indices to calculation functions, defined in hmInverter.h -enum {CALC_YT_CH0 = 0, CALC_YD_CH0, CALC_UDC_CH, CALC_PDC_CH0, CALC_EFF_CH0, CALC_IRR_CH}; +enum {CALC_YT_CH0 = 0, CALC_YD_CH0, CALC_UDC_CH, CALC_PDC_CH0, CALC_EFF_CH0, CALC_IRR_CH, CALC_MPAC_CH0, CALC_MPDC_CH}; enum {CMD_CALC = 0xffff}; @@ -126,6 +127,7 @@ const byteAssign_t hm1chAssignment[] = { { FLD_YD, UNIT_WH, CH1, 12, 2, 1 }, { FLD_YT, UNIT_KWH, CH1, 8, 4, 1000 }, { FLD_IRR, UNIT_PCT, CH1, CALC_IRR_CH, CH1, CMD_CALC }, + { FLD_MP, UNIT_W, CH1, CALC_MPDC_CH, CH1, CMD_CALC }, { FLD_UAC, UNIT_V, CH0, 14, 2, 10 }, { FLD_IAC, UNIT_A, CH0, 22, 2, 100 }, @@ -138,7 +140,9 @@ const byteAssign_t hm1chAssignment[] = { { FLD_YD, UNIT_WH, CH0, CALC_YD_CH0, 0, CMD_CALC }, { FLD_YT, UNIT_KWH, CH0, CALC_YT_CH0, 0, CMD_CALC }, { FLD_PDC, UNIT_W, CH0, CALC_PDC_CH0, 0, CMD_CALC }, - { FLD_EFF, UNIT_PCT, CH0, CALC_EFF_CH0, 0, CMD_CALC } + { FLD_EFF, UNIT_PCT, CH0, CALC_EFF_CH0, 0, CMD_CALC }, + { FLD_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC } + }; #define HM1CH_LIST_LEN (sizeof(hm1chAssignment) / sizeof(byteAssign_t)) #define HM1CH_PAYLOAD_LEN 30 @@ -154,6 +158,7 @@ const byteAssign_t hm2chAssignment[] = { { FLD_YD, UNIT_WH, CH1, 22, 2, 1 }, { FLD_YT, UNIT_KWH, CH1, 14, 4, 1000 }, { FLD_IRR, UNIT_PCT, CH1, CALC_IRR_CH, CH1, CMD_CALC }, + { FLD_MP, UNIT_W, CH1, CALC_MPDC_CH, CH1, CMD_CALC }, { FLD_UDC, UNIT_V, CH2, 8, 2, 10 }, { FLD_IDC, UNIT_A, CH2, 10, 2, 100 }, @@ -161,6 +166,7 @@ const byteAssign_t hm2chAssignment[] = { { FLD_YD, UNIT_WH, CH2, 24, 2, 1 }, { FLD_YT, UNIT_KWH, CH2, 18, 4, 1000 }, { FLD_IRR, UNIT_PCT, CH2, CALC_IRR_CH, CH2, CMD_CALC }, + { FLD_MP, UNIT_W, CH2, CALC_MPDC_CH, CH2, CMD_CALC }, { FLD_UAC, UNIT_V, CH0, 26, 2, 10 }, { FLD_IAC, UNIT_A, CH0, 34, 2, 100 }, @@ -173,7 +179,8 @@ const byteAssign_t hm2chAssignment[] = { { FLD_YD, UNIT_WH, CH0, CALC_YD_CH0, 0, CMD_CALC }, { FLD_YT, UNIT_KWH, CH0, CALC_YT_CH0, 0, CMD_CALC }, { FLD_PDC, UNIT_W, CH0, CALC_PDC_CH0, 0, CMD_CALC }, - { FLD_EFF, UNIT_PCT, CH0, CALC_EFF_CH0, 0, CMD_CALC } + { FLD_EFF, UNIT_PCT, CH0, CALC_EFF_CH0, 0, CMD_CALC }, + { FLD_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC } }; #define HM2CH_LIST_LEN (sizeof(hm2chAssignment) / sizeof(byteAssign_t)) @@ -190,6 +197,7 @@ const byteAssign_t hm4chAssignment[] = { { FLD_YD, UNIT_WH, CH1, 20, 2, 1 }, { FLD_YT, UNIT_KWH, CH1, 12, 4, 1000 }, { FLD_IRR, UNIT_PCT, CH1, CALC_IRR_CH, CH1, CMD_CALC }, + { FLD_MP, UNIT_W, CH1, CALC_MPDC_CH, CH1, CMD_CALC }, { FLD_UDC, UNIT_V, CH2, CALC_UDC_CH, CH1, CMD_CALC }, { FLD_IDC, UNIT_A, CH2, 6, 2, 100 }, @@ -197,6 +205,7 @@ const byteAssign_t hm4chAssignment[] = { { FLD_YD, UNIT_WH, CH2, 22, 2, 1 }, { FLD_YT, UNIT_KWH, CH2, 16, 4, 1000 }, { FLD_IRR, UNIT_PCT, CH2, CALC_IRR_CH, CH2, CMD_CALC }, + { FLD_MP, UNIT_W, CH2, CALC_MPDC_CH, CH2, CMD_CALC }, { FLD_UDC, UNIT_V, CH3, 24, 2, 10 }, { FLD_IDC, UNIT_A, CH3, 26, 2, 100 }, @@ -204,6 +213,7 @@ const byteAssign_t hm4chAssignment[] = { { FLD_YD, UNIT_WH, CH3, 42, 2, 1 }, { FLD_YT, UNIT_KWH, CH3, 34, 4, 1000 }, { FLD_IRR, UNIT_PCT, CH3, CALC_IRR_CH, CH3, CMD_CALC }, + { FLD_MP, UNIT_W, CH3, CALC_MPDC_CH, CH3, CMD_CALC }, { FLD_UDC, UNIT_V, CH4, CALC_UDC_CH, CH3, CMD_CALC }, { FLD_IDC, UNIT_A, CH4, 28, 2, 100 }, @@ -211,6 +221,7 @@ const byteAssign_t hm4chAssignment[] = { { FLD_YD, UNIT_WH, CH4, 44, 2, 1 }, { FLD_YT, UNIT_KWH, CH4, 38, 4, 1000 }, { FLD_IRR, UNIT_PCT, CH4, CALC_IRR_CH, CH4, CMD_CALC }, + { FLD_MP, UNIT_W, CH4, CALC_MPDC_CH, CH4, CMD_CALC }, { FLD_UAC, UNIT_V, CH0, 46, 2, 10 }, { FLD_IAC, UNIT_A, CH0, 54, 2, 100 }, @@ -223,7 +234,9 @@ const byteAssign_t hm4chAssignment[] = { { FLD_YD, UNIT_WH, CH0, CALC_YD_CH0, 0, CMD_CALC }, { FLD_YT, UNIT_KWH, CH0, CALC_YT_CH0, 0, CMD_CALC }, { FLD_PDC, UNIT_W, CH0, CALC_PDC_CH0, 0, CMD_CALC }, - { FLD_EFF, UNIT_PCT, CH0, CALC_EFF_CH0, 0, CMD_CALC } + { FLD_EFF, UNIT_PCT, CH0, CALC_EFF_CH0, 0, CMD_CALC }, + { FLD_MP, UNIT_W, CH0, CALC_MPAC_CH0, 0, CMD_CALC } + }; #define HM4CH_LIST_LEN (sizeof(hm4chAssignment) / sizeof(byteAssign_t)) #define HM4CH_PAYLOAD_LEN 62 diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index b1390b29..c4a8af33 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -47,6 +47,12 @@ static T calcEffiencyCh0(Inverter<> *iv, uint8_t arg0); template static T calcIrradiation(Inverter<> *iv, uint8_t arg0); +template +static T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0); + +template +static T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0); + template using func_t = T (Inverter<> *, uint8_t); @@ -98,7 +104,9 @@ const calcFunc_t calcFunctions[] = { { CALC_UDC_CH, &calcUdcCh }, { CALC_PDC_CH0, &calcPowerDcCh0 }, { CALC_EFF_CH0, &calcEffiencyCh0 }, - { CALC_IRR_CH, &calcIrradiation } + { CALC_IRR_CH, &calcIrradiation }, + { CALC_MPAC_CH0, &calcMaxPowerAcCh0 }, + { CALC_MPDC_CH, &calcMaxPowerDc } }; @@ -122,6 +130,8 @@ class Inverter { //String lastAlarmMsg; 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) + uint32_t pac_sum; // average calc for Highcharts: sum of ac power values for cur interval + uint16_t pac_cnt; // average calc for Highcharts: number of ac power values for cur interval Inverter() { ivGen = IV_HM; @@ -143,9 +153,11 @@ class Inverter { template void enqueCommand(uint8_t cmd) { _commandQueue.push(std::make_shared(cmd)); +#ifdef undef DPRINT_IVID(DBG_INFO, id); DBGPRINT(F("enqueCommand: 0x")); DBGHEXLN(cmd); +#endif } void setQueuedCmdFinished() { @@ -677,4 +689,45 @@ static T calcIrradiation(Inverter<> *iv, uint8_t arg0) { return 0.0; } +template +static T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0) { + DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcMaxPowerAcCh0")); + T acMaxPower = 0.0; + if(NULL != iv) { + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + uint8_t pos = iv->getPosByChFld(CH0, FLD_PAC, rec); + T acPower = iv->getValue(pos, rec); + + for(uint8_t i = 0; i < rec->length; i++) { + if((FLD_MP == rec->assign[i].fieldId) && (0 == rec->assign[i].ch)) { + acMaxPower = iv->getValue(i, rec); + } + } + if(acPower > acMaxPower) + return acPower; + } + return acMaxPower; +} + +template +static T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0) { + DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcMaxPowerDc")); + // arg0 = channel + T dcMaxPower = 0.0; + if(NULL != iv) { + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + uint8_t pos = iv->getPosByChFld(arg0, FLD_PDC, rec); + T dcPower = iv->getValue(pos, rec); + + for(uint8_t i = 0; i < rec->length; i++) { + if((FLD_MP == rec->assign[i].fieldId) && (arg0 == rec->assign[i].ch)) { + dcMaxPower = iv->getValue(i, rec); + } + } + if(dcPower > dcMaxPower) + return dcPower; + } + return dcMaxPower; +} + #endif /*__HM_INVERTER_H__*/ diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 29f380fa..e7726397 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -24,6 +24,7 @@ typedef struct { uint8_t retransmits; bool requested; bool gotFragment; + bool rxTmo; } invPayload_t; @@ -77,6 +78,8 @@ class HmPayload { for(uint8_t ch = 0; ch <= iv->channels; ch++) { pos = iv->getPosByChFld(ch, FLD_YD, rec); iv->setValue(pos, rec, 0.0f); + pos = iv->getPosByChFld(ch, FLD_MP, rec); + iv->setValue(pos, rec, 0.0f); } } @@ -89,6 +92,7 @@ class HmPayload { switch(fld) { case FLD_YD: case FLD_YT: + case FLD_MP: continue; } pos = iv->getPosByChFld(ch, fld, rec); @@ -104,6 +108,8 @@ class HmPayload { } void ivSend(Inverter<> *iv, bool highPrio = false) { + bool save_rxTmo; + if(!highPrio) { if (mPayload[iv->id].requested) { if (!mPayload[iv->id].complete) @@ -129,15 +135,19 @@ class HmPayload { } } + save_rxTmo = mPayload[iv->id].rxTmo; reset(iv->id); + mPayload[iv->id].rxTmo = save_rxTmo; mPayload[iv->id].requested = true; yield(); +#ifdef undef if (mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("Requesting Inv SN ")); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } +#endif if (iv->getDevControlRequest()) { if (mSerialDebug) { @@ -194,11 +204,14 @@ class HmPayload { if ((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) { bool ok = true; - if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) + + if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) { +#ifdef AHOY_MQTT_SUPPORT mApp->setMqttPowerLimitAck(iv); - else +#endif + } else { ok = false; - + } DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("has ")); if(!ok) DBGPRINT(F("not ")); @@ -248,15 +261,16 @@ class HmPayload { mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else { if(false == mPayload[iv->id].gotFragment) { - /* - DPRINTLN(DBG_WARN, F("nothing received: Request Complete Retransmit")); - mPayload[iv->id].txCmd = iv->getQueuedCmd(); - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); - */ - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN(F("nothing received")); - mPayload[iv->id].retransmits = mMaxRetrans; + DPRINT_IVID(DBG_WARN, iv->id); + if (mPayload[iv->id].rxTmo) { + DBGPRINTLN(F("nothing received")); + mPayload[iv->id].retransmits = mMaxRetrans; + } else { + DBGPRINTLN(F("nothing received: complete retransmit")); + mPayload[iv->id].txCmd = iv->getQueuedCmd(); + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); + } } else { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { if (mPayload[iv->id].len[i] == 0) { @@ -271,6 +285,8 @@ class HmPayload { } } } + } else { + mPayload[iv->id].rxTmo = true; // inv might be down, no complete retransmit anymore } } } else if(!crcPass && pyldComplete) { // crc error on complete Payload @@ -284,14 +300,18 @@ class HmPayload { mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } else { // payload complete +#ifdef undef DPRINT(DBG_INFO, F("procPyld: cmd: 0x")); DBGHEXLN(mPayload[iv->id].txCmd); DPRINT(DBG_INFO, F("procPyld: txid: 0x")); DBGHEXLN(mPayload[iv->id].txId); +#endif DPRINT(DBG_DEBUG, F("procPyld: max: ")); DPRINTLN(DBG_DEBUG, String(mPayload[iv->id].maxPackId)); + record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser mPayload[iv->id].complete = true; + mPayload[iv->id].rxTmo = false; uint8_t payload[128]; uint8_t payloadLen = 0; @@ -305,12 +325,14 @@ class HmPayload { } payloadLen -= 2; +#ifdef undef if (mSerialDebug) { DPRINT(DBG_INFO, F("Payload (")); DBGPRINT(String(payloadLen)); DBGPRINT(F("): ")); mSys->Radio.dumpBuf(payload, payloadLen); } +#endif if (NULL == rec) { DPRINTLN(DBG_ERROR, F("record is NULL!")); @@ -324,6 +346,12 @@ class HmPayload { yield(); } iv->doCalculations(); + uint8_t pos = iv->getPosByChFld(CH0, FLD_PAC, rec); + if (pos != 0xff) { + float ac_power = iv->getValue(pos, rec); + mSys->handle_pac (iv, (uint16_t)(ac_power+0.5f)); + } + notify(mPayload[iv->id].txCmd); if(AlarmData == mPayload[iv->id].txCmd) { @@ -394,8 +422,10 @@ class HmPayload { } void reset(uint8_t id) { +#ifdef undef DPRINT_IVID(DBG_INFO, id); DBGPRINTLN(F("resetPayload")); +#endif memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].txCmd = 0; mPayload[id].gotFragment = false; @@ -405,6 +435,7 @@ class HmPayload { mPayload[id].complete = false; mPayload[id].requested = false; mPayload[id].ts = *mTimestamp; + mPayload[id].rxTmo = true; // design: dont start with complete retransmit } IApp *mApp; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 35993829..29d8ae0d 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -306,12 +306,14 @@ class HmRadio { } void initPacket(uint64_t invId, uint8_t mid, uint8_t pid) { +#ifdef undef if(mSerialDebug) { DPRINT(DBG_VERBOSE, F("initPacket, mid: ")); DHEX(mid); DBGPRINT(F(" pid: ")); DBGHEXLN(pid); } +#endif memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE); mTxBuf[0] = mid; // message id CP_U32_BigEndian(&mTxBuf[1], (invId >> 8)); @@ -341,10 +343,14 @@ class HmRadio { if(mSerialDebug) { DPRINT(DBG_INFO, F("TX ")); DBGPRINT(String(len)); +#ifdef undef DBGPRINT("B Ch"); DBGPRINT(String(mRfChLst[mTxChIdx])); DBGPRINT(F(" | ")); dumpBuf(mTxBuf, len); +#else + DBGPRINTLN (" Bytes"); +#endif } mNrf24.stopListening(); diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index a95d4d24..f6f42b7e 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -8,6 +8,10 @@ #include "hmInverter.h" #include "hmRadio.h" +#include "../config/settings.h" + +#define AC_POWER_PATH AHOY_HIST_PATH "/ac_power" +#define AC_FORMAT_FILE_NAME "%02u_%02u_%04u.bin" template > class HmSystem { @@ -21,7 +25,8 @@ class HmSystem { Radio.setup(); } - void setup(uint8_t ampPwr, uint8_t irqPin, uint8_t cePin, uint8_t csPin, uint8_t sclkPin, uint8_t mosiPin, uint8_t misoPin) { + void setup(uint32 *timestamp, uint8_t ampPwr, uint8_t irqPin, uint8_t cePin, uint8_t csPin, uint8_t sclkPin, uint8_t mosiPin, uint8_t misoPin) { + mTimestamp = timestamp; mNumInv = 0; Radio.setup(ampPwr, irqPin, cePin, csPin, sclkPin, mosiPin, misoPin); } @@ -128,9 +133,179 @@ class HmSystem { Radio.enableDebug(); } + //----------------------------------------------------------------------------- + void cleanup_history () + { + time_t time_today; + INVERTERTYPE *p; + uint16_t i; + + time_today = *mTimestamp; + + cur_pac_index = 0; + for (i = 0, p = mInverter; i < MAX_NUM_INVERTERS; i++, p++) { + p->pac_cnt = 0; + p->pac_sum = 0; + } + + if (time_today) { + Dir ac_power_dir; + struct tm tm_today; + char cur_file_name[sizeof (AC_FORMAT_FILE_NAME)]; + + localtime_r (&time_today, &tm_today); + snprintf (cur_file_name, sizeof (cur_file_name), AC_FORMAT_FILE_NAME, + tm_today.tm_mday, tm_today.tm_mon+1, tm_today.tm_year + 1900); + ac_power_dir = LittleFS.openDir (AC_POWER_PATH); + /* design: no dataserver, cleanup old history */ + + while (ac_power_dir.next()) { + if (ac_power_dir.fileName() != cur_file_name) { + DPRINTLN (DBG_INFO, "Remove file " + ac_power_dir.fileName() + + ", Size: " + String (ac_power_dir.fileSize())); + LittleFS.remove (AC_POWER_PATH "/" + ac_power_dir.fileName()); + } + } + } else { + DPRINTLN (DBG_WARN, "cleanup_history, no time yet"); + } + } + + //----------------------------------------------------------------------------- + File open_hist () + { + File file = (File) NULL; + char file_name[sizeof (AC_POWER_PATH) + sizeof (AC_FORMAT_FILE_NAME)]; + time_t time_today = *mTimestamp; + struct tm tm_today; + + localtime_r (&time_today, &tm_today); + snprintf (file_name, sizeof (file_name), AC_POWER_PATH "/" AC_FORMAT_FILE_NAME, + tm_today.tm_mday, tm_today.tm_mon+1, tm_today.tm_year + 1900); + file = LittleFS.open (file_name, "r"); + if (!file) { + DPRINT (DBG_WARN, "open_hist, failed to open "); + DBGPRINTLN (file_name); + } + return file; + } + + //----------------------------------------------------------------------------- + bool has_pac_value () + { + if (*mTimestamp) { + INVERTERTYPE *p; + uint16_t i; + + for (i = 0, p = mInverter; i < MAX_NUM_INVERTERS; i++, p++) { + if (p->config->serial.u64 && p->isConnected && p->pac_cnt) { + return true; + } + } + } + return false; + } + + //----------------------------------------------------------------------------- + uint16_t get_pac_average (bool cleanup) + { + uint32_t pac_average = 0; + INVERTERTYPE *p; + uint16_t i; + + for (i = 0, p = mInverter; i < MAX_NUM_INVERTERS; i++, p++) { + if (p->config->serial.u64 && p->isConnected && p->pac_cnt) { + pac_average += (p->pac_sum + (p->pac_cnt >> 1)) / p->pac_cnt; + } + if (cleanup) { + p->pac_sum = 0; + p->pac_cnt = 0; + } + } + if (pac_average > UINT16_MAX) { + pac_average = UINT16_MAX; + } + return (uint16_t)pac_average; + } + + //----------------------------------------------------------------------------- + bool get_cur_value (uint16_t *interval, uint16_t *pac) + { + if (has_pac_value()) { + *interval = cur_pac_index; + *pac = get_pac_average (false); + return true; + } + DPRINTLN (DBG_INFO, "get_cur_value: none"); + return false; + } + + //----------------------------------------------------------------------------- + void close_hist (File file) + { + if (file) { + file.close (); + } + } + + //----------------------------------------------------------------------------- + void handle_pac (INVERTERTYPE *p, uint16_t pac) + { + if (*mTimestamp) { + uint32_t pac_index = gTimezone.toLocal (*mTimestamp); + + pac_index = hour(pac_index) * 60 + minute(pac_index); + pac_index /= AHOY_PAC_INTERVAL; + if (pac_index != cur_pac_index) { + if (has_pac_value ()) { + /* calc sum of all inverter averages for last interval */ + /* and cleanup all counts and sums */ + uint16_t pac_average = get_pac_average(true); + File file; + char file_name[sizeof (AC_POWER_PATH) + sizeof (AC_FORMAT_FILE_NAME)]; + time_t time_today = *mTimestamp; + struct tm tm_today; + + localtime_r (&time_today, &tm_today); + snprintf (file_name, sizeof (file_name), AC_POWER_PATH "/" AC_FORMAT_FILE_NAME, + tm_today.tm_mday, tm_today.tm_mon+1, tm_today.tm_year + 1900); + // append last average + if ((file = LittleFS.open (file_name, "a"))) { + unsigned char buf[4]; + buf[0] = cur_pac_index & 0xff; + buf[1] = cur_pac_index >> 8; + buf[2] = pac_average & 0xff; + buf[3] = pac_average >> 8; + if (file.write (buf, sizeof (buf)) != sizeof (buf)) { + DPRINTLN (DBG_WARN, "handle_pac, failed_to_write"); + } else { + DPRINTLN (DBG_DEBUG, "handle_pac, write to " + String(file_name)); + } + file.close (); + } else { + DPRINTLN (DBG_WARN, "handle_pac, failed to open"); + } + } + cur_pac_index = pac_index; + } + if ((pac_index >= AHOY_MIN_PAC_SUN_HOUR * 60 / AHOY_PAC_INTERVAL) && + (pac_index < AHOY_MAX_PAC_SUN_HOUR * 60 / AHOY_PAC_INTERVAL)) { + p->pac_sum += pac; + p->pac_cnt++; + } else { + DPRINTLN (DBG_INFO, "handle_pac, outside daylight, minutes: " + String (pac_index * AHOY_PAC_INTERVAL)); + } + } else { + DPRINTLN (DBG_INFO, "handle_pac, no time2"); + } + } + private: INVERTERTYPE mInverter[MAX_INVERTER]; uint8_t mNumInv; + uint32_t *mTimestamp; + uint16_t cur_pac_index; + }; #endif /*__HM_SYSTEM_H__*/ diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index fd922c8b..f1d82aff 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -11,6 +11,7 @@ #include "../utils/crc.h" #include "../config/config.h" #include +#include typedef struct { uint32_t ts; @@ -311,7 +312,9 @@ const byteAssign_t InfoAssignment[] = { iv->clearDevControlRequest(); if ((p->packet[9] == 0x5a) && (p->packet[10] == 0x5a)) { +#ifdef AHOY_MQTT_SUPPORT mApp->setMqttPowerLimitAck(iv); +#endif DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("has accepted power limit set point ")); DBGPRINT(String(iv->powerLimit[0])); @@ -747,7 +750,6 @@ const byteAssign_t InfoAssignment[] = { } ac_pow = (int) (ac_pow*9.5); iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10); - iv->doCalculations(); iv->setQueuedCmdFinished(); mStat->rxSuccess++;