diff --git a/src/CHANGES.md b/src/CHANGES.md index a7ec4f19..a0e1e35b 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,13 @@ (starting from release version `0.5.66`) +## 0.5.73 +* improved payload handling (request / retransmit) #464 +* included alarm ID parse to serial console (in development) + +## 0.5.72 +* repaired system, scheduler was not called any more #596 + ## 0.5.71 * improved wifi handling and tickers, many thanks to @beegee3 #571 * fixed YieldTotal correction calculation #589 diff --git a/src/app.cpp b/src/app.cpp index 5fbb5cf0..d0e2da51 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -92,7 +92,7 @@ void app::loopStandard(void) { yield(); - if (ah::checkTicker(&mRxTicker, 5)) { + if (ah::checkTicker(&mRxTicker, 4)) { bool rxRdy = mSys->Radio.switchRxCh(); if (!mSys->BufCtrl.empty()) { diff --git a/src/app.h b/src/app.h index 19512586..b66f4abf 100644 --- a/src/app.h +++ b/src/app.h @@ -66,7 +66,6 @@ class app : public IApp, public ah::Scheduler { void handleIntr(void); void cbMqtt(char* topic, byte* payload, unsigned int length); void saveValues(void); - void resetPayload(Inverter<>* iv); bool getWifiApActive(void); uint32_t getUptime() { diff --git a/src/defines.h b/src/defines.h index bc3ce3a5..e9ca58b2 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 72 +#define VERSION_PATCH 73 //------------------------------------- typedef struct { diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 21af98f0..fa7e08b2 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -106,7 +106,7 @@ const byteAssign_t AlarmDataAssignment[] = { }; #define HMALARMDATA_LIST_LEN (sizeof(AlarmDataAssignment) / sizeof(byteAssign_t)) #define HMALARMDATA_PAYLOAD_LEN 0 // 0: means check is off - +#define ALARM_LOG_ENTRY_SIZE 12 //------------------------------------- diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 4cc7de84..8ce0e390 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -105,32 +105,33 @@ const calcFunc_t calcFunctions[] = { template class Inverter { public: - cfgIv_t *config; // stored settings - uint8_t id; // unique id - uint8_t type; // integer which refers to inverter type - uint16_t alarmMesIndex; // Last recorded Alarm Message Index - uint16_t powerLimit[2]; // limit power output - float actPowerLimit; // actual power limit - uint8_t devControlCmd; // carries the requested cmd - bool devControlRequest; // true if change needed - serial_u radioId; // id converted to modbus - uint8_t channels; // number of PV channels (1-4) - record_t recordMeas; // structure for measured values - record_t recordInfo; // structure for info values - record_t recordConfig; // structure for system config values - record_t recordAlarm; // structure for alarm values + cfgIv_t *config; // stored settings + uint8_t id; // unique id + uint8_t type; // integer which refers to inverter type + uint16_t alarmMesIndex; // Last recorded Alarm Message Index + uint16_t powerLimit[2]; // limit power output + float actPowerLimit; // actual power limit + uint8_t devControlCmd; // carries the requested cmd + serial_u radioId; // id converted to modbus + uint8_t channels; // number of PV channels (1-4) + record_t recordMeas; // structure for measured values + record_t recordInfo; // structure for info values + record_t recordConfig; // structure for system config values + record_t recordAlarm; // structure for alarm values 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) Inverter() { - powerLimit[0] = 0xffff; // 65535 W Limit -> unlimited - powerLimit[1] = AbsolutNonPersistent; // default power limit setting - actPowerLimit = 0xffff; // init feedback from inverter to -1 - devControlRequest = false; - devControlCmd = InitDataState; - initialized = false; - lastAlarmMsg = "nothing"; - alarmMesIndex = 0; + powerLimit[0] = 0xffff; // 65535 W Limit -> unlimited + powerLimit[1] = AbsolutNonPersistent; // default power limit setting + actPowerLimit = 0xffff; // init feedback from inverter to -1 + mDevControlRequest = false; + devControlCmd = InitDataState; + initialized = false; + lastAlarmMsg = "nothing"; + alarmMesIndex = 0; + isConnected = false; } ~Inverter() { @@ -140,7 +141,7 @@ class Inverter { template void enqueCommand(uint8_t cmd) { _commandQueue.push(std::make_shared(cmd)); - DPRINTLN(DBG_INFO, F("(#") + String(id) + F(") enqueuedCmd: ") + String(cmd)); + DPRINTLN(DBG_INFO, F("(#") + String(id) + F(") enqueuedCmd: 0x") + String(cmd, HEX)); } void setQueuedCmdFinished() { @@ -161,10 +162,10 @@ class Inverter { uint8_t getQueuedCmd() { if (_commandQueue.empty()) { if (getFwVersion() == 0) - enqueCommand(InverterDevInform_All); - enqueCommand(RealTimeRunData_Debug); + enqueCommand(InverterDevInform_All); // firmware version + enqueCommand(RealTimeRunData_Debug); // live data if (actPowerLimit == 0xffff) - enqueCommand(SystemConfigPara); + enqueCommand(SystemConfigPara); // power limit info } return _commandQueue.front().get()->getCmd(); } @@ -219,6 +220,20 @@ class Inverter { return 0; } + bool setDevControlRequest() { + if(isConnected) + mDevControlRequest = true; + return isConnected; + } + + void clearDevControlRequest() { + mDevControlRequest = false; + } + + inline bool getDevControlRequest() { + return mDevControlRequest; + } + void addValue(uint8_t pos, uint8_t buf[], record_t<> *rec) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:addValue")); if(NULL != rec) { @@ -256,11 +271,10 @@ class Inverter { if (alarmMesIndex < rec->record[pos]){ alarmMesIndex = rec->record[pos]; //enqueCommand(AlarmUpdate); // What is the function of AlarmUpdate? + + DPRINTLN(DBG_INFO, "alarm ID incremented to " + String(alarmMesIndex)); enqueCommand(AlarmData); } - else { - alarmMesIndex = rec->record[pos]; // no change - } } } else if (rec->assign == InfoAssignment) { @@ -273,6 +287,7 @@ class Inverter { if (getPosByChFld(0, FLD_ACT_ACTIVE_PWR_LIMIT, rec) == pos){ actPowerLimit = rec->record[pos]; DPRINT(DBG_DEBUG, F("Inverter actual power limit: ") + String(actPowerLimit, 1)); + isConnected = true; } } else if (rec->assign == AlarmDataAssignment) { @@ -345,10 +360,10 @@ class Inverter { record_t<> *getRecordStruct(uint8_t cmd) { switch (cmd) { - case RealTimeRunData_Debug: return &recordMeas; - case InverterDevInform_All: return &recordInfo; - case SystemConfigPara: return &recordConfig; - case AlarmData: return &recordAlarm; + case RealTimeRunData_Debug: return &recordMeas; // 11 = 0x0b + case InverterDevInform_All: return &recordInfo; // 1 = 0x01 + case SystemConfigPara: return &recordConfig; // 5 = 0x05 + case AlarmData: return &recordAlarm; // 17 = 0x11 default: break; } return NULL; @@ -411,7 +426,27 @@ class Inverter { } } - String getAlarmStr(u_int16_t alarmCode) { + bool parseAlarmLog(uint8_t id, uint8_t pyld[], uint8_t len) { + uint8_t startOff = 2 + id * ALARM_LOG_ENTRY_SIZE; + if((startOff + ALARM_LOG_ENTRY_SIZE) > len) + return false; + + uint16_t wCode = ((uint16_t)pyld[startOff]) << 8 | pyld[startOff+1]; + uint32_t startTimeOffset = 0, endTimeOffset = 0; + + if (((wCode >> 13) & 0x01) == 1) // check if is AM or PM + startTimeOffset = 12 * 60 * 60; + if (((wCode >> 12) & 0x01) == 1) // check if is AM or PM + endTimeOffset = 12 * 60 * 60; + + uint32_t start = (((uint16_t)pyld[startOff + 4] << 8) | ((uint16_t)pyld[startOff + 5])) + startTimeOffset; + uint32_t end = (((uint16_t)pyld[startOff + 6] << 8) | ((uint16_t)pyld[startOff + 7])) + endTimeOffset; + + DPRINTLN(DBG_INFO, "Alarm #" + String(pyld[startOff+1]) + " '" + String(getAlarmStr(pyld[startOff+1])) + "' start: " + ah::getTimeStr(start) + ", end: " + ah::getTimeStr(end)); + return true; + } + + String getAlarmStr(uint16_t alarmCode) { switch (alarmCode) { // breaks are intentionally missing! case 1: return String(F("Inverter start")); case 2: return String(F("DTU command failed")); @@ -486,7 +521,6 @@ class Inverter { } private: - std::queue> _commandQueue; void toRadioId(void) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:toRadioId")); radioId.u64 = 0ULL; @@ -496,6 +530,9 @@ class Inverter { radioId.b[1] = config->serial.b[3]; radioId.b[0] = 0x01; } + + std::queue> _commandQueue; + bool mDevControlRequest; // true if change needed }; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 13508a47..2c4b6f07 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -195,7 +195,7 @@ class HmRadio { } void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data) { - DPRINTLN(DBG_INFO, F("sendControlPacket cmd: ") + String(cmd)); + DPRINTLN(DBG_INFO, F("sendControlPacket cmd: 0x") + String(cmd, HEX)); sendCmdPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME, false); uint8_t cnt = 0; mTxBuf[10 + cnt++] = cmd; // cmd -> 0 on, 1 off, 2 restart, 11 active power, 12 reactive power, 13 power factor @@ -219,7 +219,7 @@ class HmRadio { } void sendTimePacket(uint64_t invId, uint8_t cmd, uint32_t ts, uint16_t alarmMesId) { - DPRINTLN(DBG_INFO, F("sendTimePacket ") + String(cmd, HEX)); + DPRINTLN(DBG_DEBUG, F("sendTimePacket 0x") + String(cmd, HEX)); sendCmdPacket(invId, TX_REQ_INFO, ALL_FRAMES, false); mTxBuf[10] = cmd; // cid mTxBuf[11] = 0x00; diff --git a/src/hm/payload.h b/src/hm/payload.h index 4d94a889..db607e10 100644 --- a/src/hm/payload.h +++ b/src/hm/payload.h @@ -24,6 +24,7 @@ typedef struct { bool lastFound; uint8_t retransmits; bool requested; + bool gotFragment; } invPayload_t; @@ -41,7 +42,9 @@ class Payload : public Handler { mStat = stat; mMaxRetrans = maxRetransmits; mTimestamp = timestamp; - memset(mPayload, 0, (MAX_NUM_INVERTERS * sizeof(invPayload_t))); + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + reset(i); + } mSerialDebug = false; mHighPrioIv = NULL; } @@ -69,42 +72,44 @@ class Payload : public Handler { void ivSend(Inverter<> *iv, bool highPrio = false) { if(!highPrio) { - if (!mPayload[iv->id].complete) - process(false); - - if (!mPayload[iv->id].complete) { - if (0 == mPayload[iv->id].maxPackId) - mStat->rxFailNoAnser++; - else - mStat->rxFail++; - - iv->setQueuedCmdFinished(); // command failed - if (mSerialDebug) - DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); - if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#") + String(iv->id) + ") "); - DPRINTLN(DBG_INFO, F("no Payload received! (retransmits: ") + String(mPayload[iv->id].retransmits) + ")"); + if (mPayload[iv->id].requested) { + if (!mPayload[iv->id].complete) + process(false); // no retransmit + + if (!mPayload[iv->id].complete) { + if (MAX_PAYLOAD_ENTRIES == mPayload[iv->id].maxPackId) + mStat->rxFailNoAnser++; // got nothing + else + mStat->rxFail++; // got fragments but not complete response + + iv->setQueuedCmdFinished(); // command failed + if (mSerialDebug) + DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); + if (mSerialDebug) { + DPRINT(DBG_INFO, F("(#") + String(iv->id) + ") "); + DPRINTLN(DBG_INFO, F("no Payload received! (retransmits: ") + String(mPayload[iv->id].retransmits) + ")"); + } } } } - reset(iv); + reset(iv->id); mPayload[iv->id].requested = true; yield(); if (mSerialDebug) DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Requesting Inv SN ") + String(iv->config->serial.u64, HEX)); - if (iv->devControlRequest) { + if (iv->getDevControlRequest()) { if (mSerialDebug) - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request ") + String(iv->devControlCmd) + F(" power limit ") + String(iv->powerLimit[0])); + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request 0x") + String(iv->devControlCmd, HEX) + F(" power limit ") + String(iv->powerLimit[0])); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit); mPayload[iv->id].txCmd = iv->devControlCmd; - iv->clearCmdQueue(); - iv->enqueCommand(SystemConfigPara); // read back power limit + //iv->clearCmdQueue(); + //iv->enqueCommand(SystemConfigPara); // read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket")); + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket")); // + String(cmd, HEX)); mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex); mPayload[iv->id].txCmd = cmd; } @@ -112,7 +117,11 @@ class Payload : public Handler { void add(packet_t *p, uint8_t len) { Inverter<> *iv = mSys->findInverter(&p->packet[1]); - if ((NULL != iv) && (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES))) { // response from get information command + + if(NULL == iv) + return; + + if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // 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]; @@ -120,26 +129,26 @@ class Payload : public Handler { DPRINT(DBG_DEBUG, F("fragment number zero received and ignored")); } else { DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX)); - if ((*pid & 0x7F) < 5) { + if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) { memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], len - 11); mPayload[iv->id].len[(*pid & 0x7F) - 1] = len - 11; + mPayload[iv->id].gotFragment = true; } if ((*pid & ALL_FRAMES) == ALL_FRAMES) { // Last packet - if ((*pid & 0x7f) > mPayload[iv->id].maxPackId) { + if (((*pid & 0x7f) > mPayload[iv->id].maxPackId) || (MAX_PAYLOAD_ENTRIES == mPayload[iv->id].maxPackId)) { mPayload[iv->id].maxPackId = (*pid & 0x7f); if (*pid > 0x81) mPayload[iv->id].lastFound = true; } } } - } - if ((NULL != iv) && (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES))) { // response from dev control command + } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command DPRINTLN(DBG_DEBUG, F("Response from devcontrol request received")); mPayload[iv->id].txId = p->packet[0]; - iv->devControlRequest = false; + iv->clearDevControlRequest(); if ((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) { String msg = ""; @@ -148,31 +157,13 @@ class Payload : public Handler { else msg = "NOT "; DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + iv->clearCmdQueue(); + iv->enqueCommand(SystemConfigPara); // read back power limit } iv->devControlCmd = Init; } } - bool build(uint8_t id) { - DPRINTLN(DBG_VERBOSE, F("build")); - uint16_t crc = 0xffff, crcRcv = 0x0000; - if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) - mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; - - for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) { - if (mPayload[id].len[i] > 0) { - if (i == (mPayload[id].maxPackId - 1)) { - crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i] - 2, crc); - crcRcv = (mPayload[id].data[i][mPayload[id].len[i] - 2] << 8) | (mPayload[id].data[i][mPayload[id].len[i] - 1]); - } else - crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i], crc); - } - yield(); - } - - return (crc == crcRcv) ? true : false; - } - void process(bool retransmit) { for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { Inverter<> *iv = mSys->getInverterByPos(id); @@ -182,6 +173,7 @@ class Payload : public Handler { if ((mPayload[iv->id].txId != (TX_REQ_INFO + ALL_FRAMES)) && (0 != mPayload[iv->id].txId)) { // no processing needed if txId is not 0x95 mPayload[iv->id].complete = true; + continue; // skip to next inverter } if (!mPayload[iv->id].complete) { @@ -191,18 +183,21 @@ class Payload : public Handler { // This is required to prevent retransmissions without answer. DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; + } else if(iv->devControlCmd == ActivePowerContr) { + DPRINTLN(DBG_INFO, F("retransmit power limit")); + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit); } else { if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; - if(false == mPayload[iv->id].lastFound) { - DPRINTLN(DBG_WARN, F("while retrieving data: last frame missing: Request Complete Retransmit")); + 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(") sendTimePacket")); + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket 0x") + String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex); } else { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { if (mPayload[iv->id].len[i] == 0) { - DPRINTLN(DBG_WARN, F("while retrieving data: Frame ") + String(i + 1) + F(" missing: Request Retransmit")); + DPRINTLN(DBG_WARN, F("Frame ") + String(i + 1) + F(" missing: Request Retransmit")); mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true); break; // only request retransmit one frame per loop } @@ -214,7 +209,7 @@ class Payload : public Handler { } } } else { // payload complete - DPRINTLN(DBG_INFO, F("procPyld: cmd: ") + String(mPayload[iv->id].txCmd)); + DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); 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 @@ -250,6 +245,15 @@ class Payload : public Handler { } iv->doCalculations(); notify(mPayload[iv->id].txCmd); + + if(AlarmData == mPayload[iv->id].txCmd) { + uint8_t i = 0; + while(1) { + if(!iv->parseAlarmLog(i++, payload, payloadLen)) + break; + yield(); + } + } } else { DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); mStat->rxFail++; @@ -264,19 +268,40 @@ class Payload : public Handler { } } - void reset(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].lastFound = false; - mPayload[iv->id].complete = false; - mPayload[iv->id].requested = false; - mPayload[iv->id].ts = *mTimestamp; + private: + bool build(uint8_t id) { + DPRINTLN(DBG_VERBOSE, F("build")); + uint16_t crc = 0xffff, crcRcv = 0x0000; + if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) + mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; + + for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) { + if (mPayload[id].len[i] > 0) { + if (i == (mPayload[id].maxPackId - 1)) { + crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i] - 2, crc); + crcRcv = (mPayload[id].data[i][mPayload[id].len[i] - 2] << 8) | (mPayload[id].data[i][mPayload[id].len[i] - 1]); + } else + crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i], crc); + } + yield(); + } + + return (crc == crcRcv) ? true : false; + } + + void reset(uint8_t id) { + DPRINTLN(DBG_INFO, "resetPayload: id: " + String(id)); + memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); + mPayload[id].txCmd = 0; + mPayload[id].gotFragment = false; + mPayload[id].retransmits = 0; + mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; + mPayload[id].lastFound = false; + mPayload[id].complete = false; + mPayload[id].requested = false; + mPayload[id].ts = *mTimestamp; } - private: IApp *mApp; HMSYSTEM *mSys; statistics_t *mStat; diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 2e22269e..90e26b76 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -148,10 +148,10 @@ class PubMqtt { if(!mClient.connected()) return; - char topic[(MQTT_TOPIC_LEN << 1) + 2]; - snprintf(topic, ((MQTT_TOPIC_LEN << 1) + 2), "%s/%s", mCfgMqtt->topic, subTopic); - if(addTopic) - mClient.publish(topic, QOS_0, retained, payload); + if(addTopic) { + String topic = String(mCfgMqtt->topic) + "/" + String(subTopic); + mClient.publish(topic.c_str(), QOS_0, retained, payload); + } else mClient.publish(subTopic, QOS_0, retained, payload); mTxCnt++; diff --git a/src/utils/helper.cpp b/src/utils/helper.cpp index 6854a7e8..7d54e2f4 100644 --- a/src/utils/helper.cpp +++ b/src/utils/helper.cpp @@ -40,6 +40,15 @@ namespace ah { return String(str); } + String getTimeStr(time_t t) { + char str[9]; + if(0 == t) + sprintf(str, "n/a"); + else + sprintf(str, "%02d:%02d:%02d", hour(t), minute(t), second(t)); + return String(str); + } + uint64_t Serial2u64(const char *val) { char tmp[3]; uint64_t ret = 0ULL; diff --git a/src/utils/helper.h b/src/utils/helper.h index 7e908624..179e6078 100644 --- a/src/utils/helper.h +++ b/src/utils/helper.h @@ -21,6 +21,7 @@ namespace ah { void ip2Char(uint8_t ip[], char *str); double round3(double value); String getDateTimeStr(time_t t); + String getTimeStr(time_t t); uint64_t Serial2u64(const char *val); } diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 07c12994..7bf404db 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -20,6 +20,7 @@ class RestApi { RestApi() { mTimezoneOffset = 0; mFreeHeap = 0; + nr = 0; } void setup(IApp *app, HMSYSTEM *sys, AsyncWebServer *srv, settings_t *config) { @@ -539,6 +540,7 @@ class RestApi { bool setCtrl(JsonObject jsonIn, JsonObject jsonOut) { Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]); + bool accepted = true; if(NULL == iv) { jsonOut[F("error")] = F("inverter index invalid: ") + jsonIn[F("id")].as(); return false; @@ -546,10 +548,10 @@ class RestApi { if(F("power") == jsonIn[F("cmd")]) { iv->devControlCmd = (jsonIn[F("val")] == 1) ? TurnOn : TurnOff; - iv->devControlRequest = true; + accepted = iv->setDevControlRequest(); } else if(F("restart") == jsonIn[F("restart")]) { iv->devControlCmd = Restart; - iv->devControlRequest = true; + accepted = iv->setDevControlRequest(); } else if(0 == strncmp("limit_", jsonIn[F("cmd")].as(), 6)) { iv->powerLimit[0] = jsonIn["val"]; @@ -562,8 +564,9 @@ class RestApi { else if(F("limit_nonpersistent_absolute") == jsonIn[F("cmd")]) iv->powerLimit[1] = AbsolutNonPersistent; iv->devControlCmd = ActivePowerContr; - iv->devControlRequest = true; - mApp->ivSendHighPrio(iv); + accepted = iv->setDevControlRequest(); + if(accepted) + mApp->ivSendHighPrio(iv); } else if(F("dev") == jsonIn[F("cmd")]) { DPRINTLN(DBG_INFO, F("dev cmd")); @@ -574,6 +577,11 @@ class RestApi { return false; } + if(!accepted) { + jsonOut[F("error")] = F("inverter does not accept dev control request at this moment"); + return false; + } + return true; } @@ -605,6 +613,7 @@ class RestApi { uint32_t mTimezoneOffset; uint32_t mFreeHeap; + uint16_t nr; }; #endif /*__WEB_API_H__*/ diff --git a/src/web/web.h b/src/web/web.h index db67f8e5..0756e009 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -71,7 +71,7 @@ class Web { mWeb.on("/save", HTTP_ANY, std::bind(&Web::showSave, this, std::placeholders::_1)); mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1)); - mWeb.on("/api1", HTTP_POST, std::bind(&Web::showWebApi, this, std::placeholders::_1)); + //mWeb.on("/api1", HTTP_POST, std::bind(&Web::showWebApi, this, std::placeholders::_1)); #ifdef ENABLE_JSON_EP mWeb.on("/json", HTTP_ANY, std::bind(&Web::showJson, this, std::placeholders::_1)); @@ -584,7 +584,7 @@ class Web { request->send(response); } - void showWebApi(AsyncWebServerRequest *request) { + /*void showWebApi(AsyncWebServerRequest *request) { // TODO: remove DPRINTLN(DBG_VERBOSE, F("web::showWebApi")); DPRINTLN(DBG_DEBUG, request->arg("plain")); @@ -647,7 +647,7 @@ class Web { } } request->send(200, "text/json", "{success:true}"); - } + }*/ void onSerial(AsyncWebServerRequest *request) { DPRINTLN(DBG_VERBOSE, F("onSerial"));