Browse Source

Add files via upload

pull/1080/head
oberfritze 2 years ago
committed by GitHub
parent
commit
44e1cae4ea
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      src/hm/hmDefines.h
  2. 55
      src/hm/hmInverter.h
  3. 49
      src/hm/hmPayload.h
  4. 6
      src/hm/hmRadio.h
  5. 177
      src/hm/hmSystem.h
  6. 4
      src/hm/miPayload.h

27
src/hm/hmDefines.h

@ -9,6 +9,7 @@
#include "../utils/dbg.h"
#include <cstdint>
// 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

55
src/hm/hmInverter.h

@ -47,6 +47,12 @@ static T calcEffiencyCh0(Inverter<> *iv, uint8_t arg0);
template<class T=float>
static T calcIrradiation(Inverter<> *iv, uint8_t arg0);
template<class T=float>
static T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0);
template<class T=float>
static T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0);
template<class T=float>
using func_t = T (Inverter<> *, uint8_t);
@ -98,7 +104,9 @@ const calcFunc_t<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 <typename T>
void enqueCommand(uint8_t cmd) {
_commandQueue.push(std::make_shared<T>(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<class T=float>
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<class T=float>
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__*/

49
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"));
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);
*/
DPRINT_IVID(DBG_INFO, iv->id);
DBGPRINTLN(F("nothing received"));
mPayload[iv->id].retransmits = mMaxRetrans;
}
} 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;

6
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();

177
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 <uint8_t MAX_INVERTER=3, class INVERTERTYPE=Inverter<float>>
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__*/

4
src/hm/miPayload.h

@ -11,6 +11,7 @@
#include "../utils/crc.h"
#include "../config/config.h"
#include <Arduino.h>
#include <Timezone.h>
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++;

Loading…
Cancel
Save