From 66b70f24e5168e9f7c13a545f7586d49d73b3e67 Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 13 Sep 2022 21:58:32 +0200 Subject: [PATCH] * improved records in hmInverter * added records to api * removed unused endpoints from api --- tools/esp8266/app.cpp | 195 +++++++++++++++++++------------------ tools/esp8266/hmInverter.h | 23 ++++- tools/esp8266/hmRadio.h | 4 +- tools/esp8266/webApi.cpp | 27 +++++ tools/esp8266/webApi.h | 1 + 5 files changed, 150 insertions(+), 100 deletions(-) diff --git a/tools/esp8266/app.cpp b/tools/esp8266/app.cpp index bb431a50..c72983e4 100644 --- a/tools/esp8266/app.cpp +++ b/tools/esp8266/app.cpp @@ -94,26 +94,22 @@ void app::loop(void) { if(0 != len) { Inverter<> *iv = mSys->findInverter(&p->packet[1]); - if(NULL != iv && p->packet[0] == (TX_REQ_INFO + 0x80)) { // response from get information command + if((NULL != iv) && (p->packet[0] == (TX_REQ_INFO + 0x80))) { // response from get information command mPayload[iv->id].txId = p->packet[0]; DPRINTLN(DBG_DEBUG, F("Response from info request received")); uint8_t *pid = &p->packet[9]; if (*pid == 0x00) - { DPRINT(DBG_DEBUG, "fragment number zero received and ignored"); - } - else - { - if ((*pid & 0x7F) < 5) - { + else { + DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX)); + if ((*pid & 0x7F) < 5) { memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], len - 11); mPayload[iv->id].len[(*pid & 0x7F) - 1] = len - 11; } - if ((*pid & 0x80) == 0x80) - { // Last packet - if ((*pid & 0x7f) > mPayload[iv->id].maxPackId) - { + if ((*pid & 0x80) == 0x80) { + // Last packet + if ((*pid & 0x7f) > mPayload[iv->id].maxPackId) { mPayload[iv->id].maxPackId = (*pid & 0x7f); if (*pid > 0x81) mLastPacketId = *pid; @@ -121,34 +117,34 @@ void app::loop(void) { } } } - if(NULL != iv && p->packet[0] == (TX_REQ_DEVCONTROL + 0x80)) { // response from dev control command + if((NULL != iv) && (p->packet[0] == (TX_REQ_DEVCONTROL + 0x80))) { // response from dev control command mPayload[iv->id].txId = p->packet[0]; DPRINTLN(DBG_DEBUG, F("Response from devcontrol request received")); iv->devControlRequest = false; switch (p->packet[12]) { - case ActivePowerContr: - if (iv->devControlCmd >= ActivePowerContr && iv->devControlCmd <= PFSet) { // ok inverter accepted the set point copy it to dtu eeprom - if ((iv->powerLimit[1] & 0xff00) > 0) { // User want to have it persistent - mEep->write(ADDR_INV_PWR_LIM + iv->id * 2, iv->powerLimit[0]); - mEep->write(ADDR_INV_PWR_LIM_CON + iv->id * 2, iv->powerLimit[1]); - updateCrc(); - mEep->commit(); - DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1]) + F(", written to dtu eeprom")); - } else - DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + case ActivePowerContr: + if (iv->devControlCmd >= ActivePowerContr && iv->devControlCmd <= PFSet) { // ok inverter accepted the set point copy it to dtu eeprom + if ((iv->powerLimit[1] & 0xff00) > 0) { // User want to have it persistent + mEep->write(ADDR_INV_PWR_LIM + iv->id * 2, iv->powerLimit[0]); + mEep->write(ADDR_INV_PWR_LIM_CON + iv->id * 2, iv->powerLimit[1]); + updateCrc(); + mEep->commit(); + DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1]) + F(", written to dtu eeprom")); + } else + DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + iv->devControlCmd = Init; + } + break; + + default: + if (iv->devControlCmd == ActivePowerContr) { + //case inverter did not accept the sent limit; set back to last stored limit + mEep->read(ADDR_INV_PWR_LIM + iv->id * 2, (uint16_t *)&(iv->powerLimit[0])); + mEep->read(ADDR_INV_PWR_LIM_CON + iv->id * 2, (uint16_t *)&(iv->powerLimit[1])); + DPRINTLN(DBG_INFO, F("Inverter has not accepted power limit set point")); + } iv->devControlCmd = Init; - } - break; - - default: - if (iv->devControlCmd == ActivePowerContr) { - //case inverter did not accept the sent limit; set back to last stored limit - mEep->read(ADDR_INV_PWR_LIM + iv->id * 2, (uint16_t *)&(iv->powerLimit[0])); - mEep->read(ADDR_INV_PWR_LIM_CON + iv->id * 2, (uint16_t *)&(iv->powerLimit[1])); - DPRINTLN(DBG_INFO, F("Inverter has not accepted power limit set point")); - } - iv->devControlCmd = Init; - break; + break; } } } @@ -225,11 +221,13 @@ void app::loop(void) { int8_t maxLoop = MAX_NUM_INVERTERS; Inverter<> *iv = mSys->getInverterByPos(mSendLastIvId); do { - if(NULL != iv) - mPayload[iv->id].requested = false; + //if(NULL != iv) + // mPayload[iv->id].requested = false; mSendLastIvId = ((MAX_NUM_INVERTERS-1) == mSendLastIvId) ? 0 : mSendLastIvId + 1; iv = mSys->getInverterByPos(mSendLastIvId); } while((NULL == iv) && ((maxLoop--) > 0)); + resetPayload(iv); + mPayload[iv->id].requested = true; if(NULL != iv) { if(!mPayload[iv->id].complete) @@ -247,8 +245,6 @@ void app::loop(void) { } } - resetPayload(iv); - yield(); if(mConfig.serialDebug) { DPRINTLN(DBG_DEBUG, F("app:loop WiFi WiFi.status ") + String(WiFi.status())); @@ -316,12 +312,13 @@ void app::processPayload(bool retransmit) { boolean doMQTT = false; #endif - DPRINTLN(DBG_VERBOSE, F("app::processPayload")); + //DPRINTLN(DBG_INFO, F("processPayload")); for(uint8_t id = 0; id < mSys->getNumInverters(); id++) { Inverter<> *iv = mSys->getInverterByPos(id); if(NULL != iv) { if(mPayload[iv->id].txId != (TX_REQ_INFO + 0x80)) { // no processing needed if txId is not 0x95 + DPRINTLN(DBG_DEBUG, F("processPayload - set complete")); mPayload[iv->id].complete = true; } if(!mPayload[iv->id].complete ) { @@ -334,7 +331,7 @@ void app::processPayload(bool retransmit) { for(uint8_t i = 0; i < (mPayload[iv->id].maxPackId-1); i ++) { if(mPayload[iv->id].len[i] == 0) { if(mConfig.serialDebug) - DPRINTLN(DBG_ERROR, F("while retrieving data: Frame ") + String(i+1) + F(" missing: Request Retransmit")); + DPRINTLN(DBG_WARN, F("while retrieving data: Frame ") + String(i+1) + F(" missing: Request Retransmit")); mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME+i), true); break; // only retransmit one frame per loop } @@ -343,11 +340,13 @@ void app::processPayload(bool retransmit) { } else { if(mConfig.serialDebug) - DPRINTLN(DBG_ERROR, F("while retrieving data: last frame missing: Request Retransmit")); - //if(0x00 != mLastPacketId) - // mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, mLastPacketId, true); - //else - mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex); + DPRINTLN(DBG_WARN, F("while retrieving data: last frame missing: Request Retransmit")); + if(0x00 != mLastPacketId) + mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, mLastPacketId, true); + else { + mPayload[iv->id].txCmd = iv->getQueuedCmd(); + mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex); + } } mSys->Radio.switchRxCh(100); } @@ -356,14 +355,12 @@ void app::processPayload(bool retransmit) { } else { // payload complete DPRINTLN(DBG_INFO, F("procPyld: cmd: ") + String(mPayload[iv->id].txCmd)); - DPRINTLN(DBG_INFO, F("procPyld: txid: ") + String(mPayload[iv->id].txId)); - DPRINTLN(DBG_INFO, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); + DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); + DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser - if(NULL == rec) - DPRINTLN(DBG_ERROR, F("record is NULL!")); mPayload[iv->id].complete = true; - rec->ts = mPayload[iv->id].ts; mStat.rxSuccess++; + uint8_t payload[128]; uint8_t offs = 0; @@ -380,34 +377,38 @@ void app::processPayload(bool retransmit) { mSys->Radio.dumpBuf(NULL, payload, offs); } - for(uint8_t i = 0; i < rec->length; i++) { - iv->addValue(i, payload, rec); - yield(); - } - iv->doCalculations(); - - iv->setQueuedCmdFinished(); - - // MQTT send out - if(mMqttActive) { - char topic[30], val[10]; - float total[4]; - memset(total, 0, sizeof(float) * 4); - for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { - Inverter<> *iv = mSys->getInverterByPos(id); - if (NULL != iv) { - if(iv->getRecordStruct(RealTimeRunData_Debug) == rec) { + if(NULL == rec) + DPRINTLN(DBG_ERROR, F("record is NULL!")); + else { + rec->ts = mPayload[iv->id].ts; + for(uint8_t i = 0; i < rec->length; i++) { + iv->addValue(i, payload, rec); + yield(); + } + iv->doCalculations(); + + // MQTT send out + if(mMqttActive) { + record_t<> *recRealtime = iv->getRecordStruct(RealTimeRunData_Debug); + char topic[30], val[10]; + float total[4]; + memset(total, 0, sizeof(float) * 4); + for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { + Inverter<> *iv = mSys->getInverterByPos(id); + if (NULL != iv) { if (iv->isAvailable(mTimestamp, rec)) { for (uint8_t i = 0; i < rec->length; i++) { snprintf(topic, 30, "%s/ch%d/%s", iv->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); snprintf(val, 10, "%.3f", iv->getValue(i, rec)); mMqtt.sendMsg(topic, val); - if(CH0 == rec->assign[i].ch) { - switch(rec->assign[i].fieldId) { - case FLD_PAC: total[0] += iv->getValue(i, rec); break; - case FLD_YT: total[1] += iv->getValue(i, rec); break; - case FLD_YD: total[2] += iv->getValue(i, rec); break; - case FLD_PDC: total[3] += iv->getValue(i, rec); break; + if(recRealtime == rec) { + if(CH0 == rec->assign[i].ch) { + switch(rec->assign[i].fieldId) { + case FLD_PAC: total[0] += iv->getValue(i, rec); break; + case FLD_YT: total[1] += iv->getValue(i, rec); break; + case FLD_YD: total[2] += iv->getValue(i, rec); break; + case FLD_PDC: total[3] += iv->getValue(i, rec); break; + } } } yield(); @@ -415,26 +416,30 @@ void app::processPayload(bool retransmit) { } } } - } - // total values (sum of all inverters) - if(mSys->getNumInverters() > 1) { - uint8_t fieldId = 0; - for (uint8_t i = 0; i < 4; i++) { - switch(i) { - case 0: fieldId = FLD_PAC; break; - case 1: fieldId = FLD_YT; break; - case 2: fieldId = FLD_YD; break; - case 3: fieldId = FLD_PDC; break; + // total values (sum of all inverters) + if(recRealtime == rec) { + if(mSys->getNumInverters() > 1) { + uint8_t fieldId = 0; + for (uint8_t i = 0; i < 4; i++) { + switch(i) { + case 0: fieldId = FLD_PAC; break; + case 1: fieldId = FLD_YT; break; + case 2: fieldId = FLD_YD; break; + case 3: fieldId = FLD_PDC; break; + } + snprintf(topic, 30, "total/%s", fields[fieldId]); + snprintf(val, 10, "%.3f", total[i]); + mMqtt.sendMsg(topic, val); + } } - snprintf(topic, 30, "total/%s", fields[fieldId]); - snprintf(val, 10, "%.3f", total[i]); - mMqtt.sendMsg(topic, val); } } } - resetPayload(iv); + iv->setQueuedCmdFinished(); + + //resetPayload(iv); #ifdef __MQTT_AFTER_RX__ doMQTT = true; @@ -657,12 +662,7 @@ void app::resetSystem(void) { mShowRebootRequest = false; - Inverter<> *iv; - for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - iv = mSys->getInverterByPos(i, false); - if(NULL != iv) - resetPayload(iv); - } + memset(mPayload, 0, (MAX_NUM_INVERTERS * sizeof(invPayload_t))); memset(&mStat, 0, sizeof(statistics_t)); mLastPacketId = 0x00; } @@ -757,6 +757,12 @@ void app::loadEEpconfig(void) { mMqttInterval += mConfig.sendInterval; } } + + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + iv = mSys->getInverterByPos(i, false); + if(NULL != iv) + resetPayload(iv); + } } } @@ -825,11 +831,12 @@ void app::setupMqtt(void) { //----------------------------------------------------------------------------- void app::resetPayload(Inverter<>* iv) { + DPRINTLN(DBG_INFO, "resetPayload: id: " + String(iv->id)); memset(mPayload[iv->id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[iv->id].txCmd = 0; mPayload[iv->id].retransmits = 0; mPayload[iv->id].maxPackId = 0; mPayload[iv->id].complete = false; - mPayload[iv->id].requested = true; + mPayload[iv->id].requested = false; mPayload[iv->id].ts = mTimestamp; } diff --git a/tools/esp8266/hmInverter.h b/tools/esp8266/hmInverter.h index ea83587d..2d669a11 100644 --- a/tools/esp8266/hmInverter.h +++ b/tools/esp8266/hmInverter.h @@ -203,6 +203,10 @@ class Inverter { return 0xff; } + byteAssign_t *getByteAssign(uint8_t pos, record_t<> *rec) { + return &rec->assign[pos]; + } + const char *getFieldName(uint8_t pos, record_t<> *rec) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getFieldName")); if(NULL != rec) @@ -230,7 +234,8 @@ class Inverter { uint8_t ptr = rec->assign[pos].start; uint8_t end = ptr + rec->assign[pos].num; uint16_t div = rec->assign[pos].div; - if(rec == &recordMeas) { + + if(NULL != rec) { if(CMD_CALC != div) { uint32_t val = 0; do { @@ -242,6 +247,11 @@ class Inverter { else rec->record[pos] = (REC_TYP)(val); } + } + + if(rec == &recordMeas) { + DPRINTLN(DBG_VERBOSE, "add real time"); + // get last alarm message index and save it in the inverter object if (getPosByChFld(0, FLD_ALARM_MES_ID, rec) == pos){ if (alarmMesIndex < rec->record[pos]){ @@ -254,25 +264,30 @@ class Inverter { } } } - if (rec == &recordInfo) { + else if (rec->assign == InfoAssignment) { + DPRINTLN(DBG_INFO, "add info"); // get at least the firmware version and save it to the inverter object if (getPosByChFld(0, FLD_FW_VERSION, rec) == pos){ fwVersion = rec->record[pos]; DPRINT(DBG_DEBUG, F("Inverter FW-Version: ") + String(fwVersion)); } } - if (rec == &recordConfig) { + else if (rec->assign == SystemConfigParaAssignment) { + DPRINTLN(DBG_INFO, "add config"); // get at least the firmware version and save it to the inverter object if (getPosByChFld(0, FLD_ACT_PWR_LIMIT, rec) == pos){ actPowerLimit = rec->record[pos]; DPRINT(DBG_DEBUG, F("Inverter actual power limit: ") + String(actPowerLimit)); } } - if (rec == &recordAlarm){ + else if (rec->assign == AlarmDataAssignment) { + DPRINTLN(DBG_INFO, "add alarm"); if (getPosByChFld(0, FLD_LAST_ALARM_CODE, rec) == pos){ lastAlarmMsg = getAlarmStr(rec->record[pos]); } } + else + DPRINTLN(DBG_WARN, F("add with unknown assginment")); } else DPRINTLN(DBG_ERROR, F("addValue: assignment not found with cmd 0x")); diff --git a/tools/esp8266/hmRadio.h b/tools/esp8266/hmRadio.h index 8c04ffef..6a09f6a2 100644 --- a/tools/esp8266/hmRadio.h +++ b/tools/esp8266/hmRadio.h @@ -164,7 +164,7 @@ class HmRadio { } void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data) { - DPRINTLN(DBG_INFO, F("sendControlPacket")); + DPRINTLN(DBG_INFO, F("sendControlPacket cmd: ") + String(cmd)); sendCmdPacket(invId, TX_REQ_DEVCONTROL, ALL_FRAMES, false); // 0x80 implementation as original DTU code int cnt = 0; mTxBuf[10] = cmd; // cmd --> 0x0b => Type_ActivePowerContr, 0 on, 1 off, 2 restart, 12 reactive power, 13 power factor @@ -205,7 +205,7 @@ class HmRadio { } void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t pid, bool calcCrc = true) { - DPRINTLN(DBG_INFO, F("sendCmdPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); + DPRINTLN(DBG_VERBOSE, F("sendCmdPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE); mTxBuf[0] = mid; // message id CP_U32_BigEndian(&mTxBuf[1], (invId >> 8)); diff --git a/tools/esp8266/webApi.cpp b/tools/esp8266/webApi.cpp index accd3c26..1bf8ae53 100644 --- a/tools/esp8266/webApi.cpp +++ b/tools/esp8266/webApi.cpp @@ -39,6 +39,7 @@ void webApi::onApi(AsyncWebServerRequest *request) { AsyncJsonResponse* response = new AsyncJsonResponse(false, 2048); JsonObject root = response->getRoot(); + Inverter<> *iv = mApp->mSys->getInverterByPos(0, false); String path = request->url().substring(5); if(path == "system") getSystem(root); else if(path == "statistics") getStatistics(root); @@ -46,6 +47,10 @@ void webApi::onApi(AsyncWebServerRequest *request) { else if(path == "index") getIndex(root); else if(path == "setup") getSetup(root); else if(path == "live") getLive(root); + else if(path == "record/info") getRecord(root, iv->getRecordStruct(InverterDevInform_All)); + else if(path == "record/alarm") getRecord(root, iv->getRecordStruct(AlarmData)); + else if(path == "record/config") getRecord(root, iv->getRecordStruct(SystemConfigPara)); + else if(path == "record/live") getRecord(root, iv->getRecordStruct(RealTimeRunData_Debug)); else getNotFound(root, F("http://") + request->host() + F("/api/")); @@ -301,6 +306,28 @@ void webApi::getLive(JsonObject obj) { } +//----------------------------------------------------------------------------- +void webApi::getRecord(JsonObject obj, record_t<> *rec) { + JsonArray invArr = obj.createNestedArray(F("inverter")); + + Inverter<> *iv; + uint8_t pos; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { + iv = mApp->mSys->getInverterByPos(i); + if(NULL != iv) { + JsonArray obj2 = invArr.createNestedArray(); + for(uint8_t j = 0; j < rec->length; j++) { + byteAssign_t *assign = iv->getByteAssign(j, rec); + pos = (iv->getPosByChFld(assign->ch, assign->fieldId, rec)); + obj2[j]["fld"] = (0xff != pos) ? String(iv->getFieldName(pos, rec)) : F("n/a"); + obj2[j]["unit"] = (0xff != pos) ? String(iv->getUnit(pos, rec)) : F("n/a"); + obj2[j]["val"] = (0xff != pos) ? String(iv->getValue(pos, rec)) : F("n/a"); + } + } + } +} + + //----------------------------------------------------------------------------- bool webApi::setCtrl(DynamicJsonDocument jsonIn, JsonObject jsonOut) { uint8_t cmd = jsonIn[F("cmd")]; diff --git a/tools/esp8266/webApi.h b/tools/esp8266/webApi.h index e9d7e5e8..51d02adf 100644 --- a/tools/esp8266/webApi.h +++ b/tools/esp8266/webApi.h @@ -35,6 +35,7 @@ class webApi { void getIndex(JsonObject obj); void getSetup(JsonObject obj); void getLive(JsonObject obj); + void getRecord(JsonObject obj, record_t<> *rec); bool setCtrl(DynamicJsonDocument jsonIn, JsonObject jsonOut);