diff --git a/src/CHANGES.md b/src/CHANGES.md index 88fef085..2066b189 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,11 @@ # Development Changes +## 0.7.29 - 2023-08-09 +* MqTT alarm data was never sent, fixed +* REST API: added alarm data +* REST API: made get record obsolete +* REST API: added power limit acknowledge `/api/inverter/id/[0-x]` #1072 + ## 0.7.28 - 2023-08-08 * fix MI inverter support #1078 diff --git a/src/app.cpp b/src/app.cpp index 88980ad0..01b370f9 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -99,8 +99,11 @@ void app::setup() { if (mMqttEnabled) { mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, &mSys, &mTimestamp, &mUptime); mMqtt.setSubscriptionCb(std::bind(&app::mqttSubRxCb, this, std::placeholders::_1)); - mPayload.addAlarmListener(std::bind(&PubMqttType::alarmEventListener, &mMqtt, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - mMiPayload.addAlarmListener(std::bind(&PubMqttType::alarmEventListener, &mMqtt, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + mPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); + mMiPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); + #if defined(ESP32) + mHmsPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); + #endif } #endif setupLed(); diff --git a/src/app.h b/src/app.h index 728215d7..73451523 100644 --- a/src/app.h +++ b/src/app.h @@ -177,6 +177,10 @@ class app : public IApp, public ah::Scheduler { mPayload.ivSendHighPrio(iv); else if (iv->ivGen == IV_MI) mMiPayload.ivSendHighPrio(iv); + #if defined(ESP32) + else if((iv->ivGen == IV_HMS) || (iv->ivGen == IV_HMT)) + mHmsPayload.ivSendHighPrio(iv); + #endif } } diff --git a/src/defines.h b/src/defines.h index 2a309994..e0b38506 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 28 +#define VERSION_PATCH 29 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 4e6dd77f..5d521261 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -66,6 +66,14 @@ struct record_t { uint8_t pyldLen; // expected payload length for plausibility check }; +struct alarm_t { + uint16_t code; + uint32_t start; + uint32_t end; + alarm_t(uint16_t c, uint32_t s, uint32_t e) : code(c), start(s), end(e) {} + alarm_t() : code(0), start(0), end(0) {} +}; + class CommandAbstract { public: CommandAbstract(uint8_t txType = 0, uint8_t cmd = 0) { @@ -120,6 +128,7 @@ class Inverter { uint16_t alarmMesIndex; // Last recorded Alarm Message Index uint16_t powerLimit[2]; // limit power output float actPowerLimit; // actual power limit + bool powerLimitAck; // acknowledged power limit (default: false) uint8_t devControlCmd; // carries the requested cmd serial_u radioId; // id converted to modbus uint8_t channels; // number of PV channels (1-4) @@ -131,6 +140,10 @@ class Inverter { 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) InverterStatus status; // indicates the current inverter status + std::array lastAlarm; // holds last 10 alarms + uint8_t alarmNxtWrPos; // indicates the position in array (rolling buffer) + uint16_t alarmCnt; // counts the total number of occured alarms + static uint32_t *timestamp; // system timestamp static cfgInst_t *generalConfig; // general inverter configuration from setup @@ -139,6 +152,7 @@ class Inverter { ivGen = IV_HM; powerLimit[0] = 0xffff; // 65535 W Limit -> unlimited powerLimit[1] = AbsolutNonPersistent; // default power limit setting + powerLimitAck = false; actPowerLimit = 0xffff; // init feedback from inverter to -1 mDevControlRequest = false; devControlCmd = InitDataState; @@ -147,6 +161,8 @@ class Inverter { alarmMesIndex = 0; isConnected = false; status = InverterStatus::OFF; + alarmNxtWrPos = 0; + alarmCnt = 0; } ~Inverter() { @@ -338,11 +354,6 @@ class Inverter { isProducing(); } - /*inline REC_TYP getPowerLimit(void) { - record_t<> *rec = getRecordStruct(SystemConfigPara); - return getChannelFieldValue(CH0, FLD_ACT_ACTIVE_PWR_LIMIT, rec); - }*/ - bool setValue(uint8_t pos, record_t<> *rec, REC_TYP val) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:setValue")); if(NULL == rec) @@ -530,27 +541,32 @@ class Inverter { } } - uint16_t parseAlarmLog(uint8_t id, uint8_t pyld[], uint8_t len, uint32_t *start, uint32_t *endTime) { + uint16_t 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 0; uint16_t wCode = ((uint16_t)pyld[startOff]) << 8 | pyld[startOff+1]; uint32_t startTimeOffset = 0, endTimeOffset = 0; + uint32_t start, endTime; 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; - *start = (((uint16_t)pyld[startOff + 4] << 8) | ((uint16_t)pyld[startOff + 5])) + startTimeOffset; - *endTime = (((uint16_t)pyld[startOff + 6] << 8) | ((uint16_t)pyld[startOff + 7])) + endTimeOffset; + start = (((uint16_t)pyld[startOff + 4] << 8) | ((uint16_t)pyld[startOff + 5])) + startTimeOffset; + endTime = (((uint16_t)pyld[startOff + 6] << 8) | ((uint16_t)pyld[startOff + 7])) + endTimeOffset; + + DPRINTLN(DBG_DEBUG, "Alarm #" + String(pyld[startOff+1]) + " '" + String(getAlarmStr(pyld[startOff+1])) + "' start: " + ah::getTimeStr(start) + ", end: " + ah::getTimeStr(endTime)); + addAlarm(pyld[startOff+1], start, endTime); + + alarmCnt++; - DPRINTLN(DBG_INFO, "Alarm #" + String(pyld[startOff+1]) + " '" + String(getAlarmStr(pyld[startOff+1])) + "' start: " + ah::getTimeStr(*start) + ", end: " + ah::getTimeStr(*endTime)); return pyld[startOff+1]; } - String getAlarmStr(uint16_t alarmCode) { + static 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")); @@ -625,6 +641,12 @@ class Inverter { } private: + inline void addAlarm(uint16_t code, uint32_t start, uint32_t end) { + lastAlarm[alarmNxtWrPos] = alarm_t(code, start, end); + if(++alarmNxtWrPos >= 10) // rolling buffer + alarmNxtWrPos = 0; + } + void toRadioId(void) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:toRadioId")); radioId.u64 = 0ULL; diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index ce8268c8..37a126fd 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -29,7 +29,7 @@ typedef struct { typedef std::function *)> payloadListenerType; -typedef std::function alarmListenerType; +typedef std::function *)> alarmListenerType; template @@ -143,6 +143,7 @@ class HmPayload { DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); } + iv->powerLimitAck = false; mRadio->sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); mPayload[iv->id].txCmd = iv->devControlCmd; //iv->clearCmdQueue(); @@ -190,9 +191,10 @@ 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)) { mApp->setMqttPowerLimitAck(iv); - else + iv->powerLimitAck = true; + } else ok = false; DPRINT_IVID(DBG_INFO, iv->id); @@ -289,10 +291,10 @@ class HmPayload { record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser mPayload[iv->id].complete = true; - uint8_t payload[128]; + uint8_t payload[100]; uint8_t payloadLen = 0; - memset(payload, 0, 128); + memset(payload, 0, 100); for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); @@ -324,14 +326,12 @@ class HmPayload { if(AlarmData == mPayload[iv->id].txCmd) { uint8_t i = 0; - uint16_t code; uint32_t start, end; while(1) { - code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); - if(0 == code) + if(0 == iv->parseAlarmLog(i++, payload, payloadLen)) break; if (NULL != mCbAlarm) - (mCbAlarm)(code, start, end); + (mCbAlarm)(iv); yield(); } } @@ -355,11 +355,6 @@ class HmPayload { (mCbPayload)(val, iv); } - void notify(uint16_t code, uint32_t start, uint32_t endTime) { - if (NULL != mCbAlarm) - (mCbAlarm)(code, start, endTime); - } - bool build(uint8_t id, bool *complete) { DPRINTLN(DBG_VERBOSE, F("build")); uint16_t crc = 0xffff, crcRcv = 0x0000; diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 03038283..516c7c9a 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -66,7 +66,7 @@ class MiPayload { } void addAlarmListener(alarmListenerType cb) { - mCbMiAlarm = cb; + mCbAlarm = cb; } void loop() { @@ -125,6 +125,7 @@ class MiPayload { DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); } + iv->powerLimitAck = false; mRadio->sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false, false); mPayload[iv->id].txCmd = iv->devControlCmd; mPayload[iv->id].limitrequested = true; @@ -313,6 +314,7 @@ const byteAssign_t InfoAssignment[] = { if ((p->packet[9] == 0x5a) && (p->packet[10] == 0x5a)) { mApp->setMqttPowerLimitAck(iv); + iv->powerLimitAck = true; DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("has accepted power limit set point ")); DBGPRINT(String(iv->powerLimit[0])); @@ -368,14 +370,11 @@ const byteAssign_t InfoAssignment[] = { if(AlarmData == mPayload[iv->id].txCmd) { uint8_t i = 0; - uint16_t code; - uint32_t start, end; while(1) { - code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); - if(0 == code) + if(0 == iv->parseAlarmLog(i++, payload, payloadLen)) break; - if (NULL != mCbMiAlarm) - (mCbMiAlarm)(code, start, end); + if (NULL != mCbAlarm) + (mCbAlarm)(iv); yield(); } } @@ -714,7 +713,7 @@ const byteAssign_t InfoAssignment[] = { code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); if(0 == code) break; - if (NULL != mCbMiAlarm) + if (NULL != mCbAlarm) (mCbAlarm)(code, start, end); yield(); } @@ -835,7 +834,7 @@ const byteAssign_t InfoAssignment[] = { bool mSerialDebug; Inverter<> *mHighPrioIv; - alarmListenerType mCbMiAlarm; + alarmListenerType mCbAlarm; payloadListenerType mCbMiPayload; }; diff --git a/src/hms/hmsPayload.h b/src/hms/hmsPayload.h index 5c7a08d2..d887253e 100644 --- a/src/hms/hmsPayload.h +++ b/src/hms/hmsPayload.h @@ -30,7 +30,7 @@ typedef struct { typedef std::function *)> payloadListenerType; -typedef std::function alarmListenerType; +typedef std::function *)> alarmListenerType; template @@ -50,7 +50,7 @@ class HmsPayload { mIvCmd56Cnt[i] = 0; } mSerialDebug = false; - //mHighPrioIv = NULL; + mHighPrioIv = NULL; mCbAlarm = NULL; mCbPayload = NULL; //mLastRx = 0; @@ -69,14 +69,14 @@ class HmsPayload { } void loop() { - /*if(NULL != mHighPrioIv) { + if(NULL != mHighPrioIv) { ivSend(mHighPrioIv, true); mHighPrioIv = NULL; - }*/ + } } void ivSendHighPrio(Inverter<> *iv) { - //mHighPrioIv = iv; + mHighPrioIv = iv; } void ivSend(Inverter<> *iv, bool highPrio = false) { @@ -127,6 +127,7 @@ class HmsPayload { DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); } + iv->powerLimitAck = false; mRadio->sendControlPacket(&iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); mPayload[iv->id].txCmd = iv->devControlCmd; //iv->clearCmdQueue(); @@ -178,9 +179,10 @@ class HmsPayload { if ((p->data[13] == ActivePowerContr) && (p->data[14] == 0x00)) { bool ok = true; - if((p->data[11] == 0x00) && (p->data[12] == 0x00)) + if((p->data[11] == 0x00) && (p->data[12] == 0x00)) { mApp->setMqttPowerLimitAck(iv); - else + iv->powerLimitAck = true; + } else ok = false; DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F(" has ")); @@ -192,6 +194,8 @@ class HmsPayload { iv->clearCmdQueue(); iv->enqueCommand(SystemConfigPara); // read back power limit + if(mHighPrioIv == NULL) // do it immediately if possible + mHighPrioIv = iv; } iv->devControlCmd = Init; } @@ -305,19 +309,17 @@ class HmsPayload { iv->doCalculations(); notify(mPayload[iv->id].txCmd, iv); - /*if(AlarmData == mPayload[iv->id].txCmd) { + if(AlarmData == mPayload[iv->id].txCmd) { uint8_t i = 0; - uint16_t code; uint32_t start, end; while(1) { - code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); - if(0 == code) + if(0 == iv->parseAlarmLog(i++, payload, payloadLen)) break; if (NULL != mCbAlarm) - (mCbAlarm)(code, start, end); + (mCbAlarm)(iv); yield(); } - }*/ + } } else { DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); DBGPRINT(String(rec->pyldLen)); @@ -338,11 +340,6 @@ class HmsPayload { (mCbPayload)(val, iv); } - void notify(uint16_t code, uint32_t start, uint32_t endTime) { - if (NULL != mCbAlarm) - (mCbAlarm)(code, start, endTime); - } - bool build(uint8_t id, bool *complete) { DPRINTLN(DBG_VERBOSE, F("build")); uint16_t crc = 0xffff, crcRcv = 0x0000; @@ -376,7 +373,7 @@ class HmsPayload { DPRINT(DBG_INFO, "resetPayload: id: "); DBGPRINTLN(String(id)); memset(&mPayload[id], 0, sizeof(hmsPayload_t)); - //mPayload[id].txCmd = 0; + mPayload[id].txCmd = 0; mPayload[id].gotFragment = false; //mPayload[id].retransmits = 0; mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index b821ed34..218e74a7 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -28,13 +28,6 @@ typedef std::function subscriptionCb; -struct alarm_t { - uint16_t code; - uint32_t start; - uint32_t end; - alarm_t(uint16_t c, uint32_t s, uint32_t e) : code(c), start(s), end(e) {} -}; - typedef struct { bool running; uint8_t lastIvId; @@ -76,10 +69,10 @@ class PubMqtt { if((strlen(mCfgMqtt->user) > 0) && (strlen(mCfgMqtt->pwd) > 0)) mClient.setCredentials(mCfgMqtt->user, mCfgMqtt->pwd); - if(strlen(mCfgMqtt->clientId) > 0) { - snprintf(mClientId, 23, "%s-", mCfgMqtt->clientId); - mClient.setClientId(mCfgMqtt->clientId); - } else{ + + if(strlen(mCfgMqtt->clientId) > 0) + snprintf(mClientId, 23, "%s", mCfgMqtt->clientId); + else{ snprintf(mClientId, 24, "%s-", mDevName); uint8_t pos = strlen(mClientId); mClientId[pos++] = WiFi.macAddress().substring( 9, 10).c_str()[0]; @@ -89,9 +82,9 @@ class PubMqtt { mClientId[pos++] = WiFi.macAddress().substring(15, 16).c_str()[0]; mClientId[pos++] = WiFi.macAddress().substring(16, 17).c_str()[0]; mClientId[pos++] = '\0'; - - mClient.setClientId(mClientId); } + + mClient.setClientId(mClientId); mClient.setServer(mCfgMqtt->broker, mCfgMqtt->port); mClient.setWill(mLwtTopic, QOS_0, true, mqttStr[MQTT_STR_LWT_NOT_CONN]); mClient.onConnect(std::bind(&PubMqtt::onConnect, this, std::placeholders::_1)); @@ -111,7 +104,6 @@ class PubMqtt { discoveryConfigLoop(); } - void tickerSecond() { if (mIntervalTimeout > 0) mIntervalTimeout--; @@ -130,6 +122,8 @@ class PubMqtt { sendIvData(); } } + + sendAlarmData(); } void tickerMinute() { @@ -179,10 +173,8 @@ class PubMqtt { } } - void alarmEventListener(uint16_t code, uint32_t start, uint32_t endTime) { - if(mClient.connected()) { - mAlarmList.push(alarm_t(code, start, endTime)); - } + void alarmEvent(Inverter<> *iv) { + mSendAlarm[iv->id] = true; } void publish(const char *subTopic, const char *payload, bool retained = false, bool addTopic = true) { @@ -509,15 +501,43 @@ class PubMqtt { } void sendAlarmData() { - if(mAlarmList.empty()) - return; - Inverter<> *iv = mSys->getInverterByPos(0, false); - while(!mAlarmList.empty()) { - alarm_t alarm = mAlarmList.front(); - publish(subtopics[MQTT_ALARM], iv->getAlarmStr(alarm.code).c_str()); - publish(subtopics[MQTT_ALARM_START], String(alarm.start).c_str()); - publish(subtopics[MQTT_ALARM_END], String(alarm.end).c_str()); - mAlarmList.pop(); + Inverter<> *iv; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + if(!mSendAlarm[i]) + continue; + + iv = mSys->getInverterByPos(i, false); + if (NULL == iv) + continue; + if (!iv->config->enabled) + continue; + + mSendAlarm[i] = false; + + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/cnt", iv->config->name); + snprintf(mVal, 40, "%d", iv->alarmCnt); + publish(mSubTopic, mVal, true); + + for(uint8_t j = 0; j < 10; j++) { + if(0 != iv->lastAlarm[j].code) { + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/%d/code", iv->config->name, j); + snprintf(mVal, 40, "%d", iv->lastAlarm[j].code); + publish(mSubTopic, mVal, true); + + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/%d/str", iv->config->name, j); + snprintf(mVal, 40, "%s", iv->getAlarmStr(iv->lastAlarm[j].code)); + publish(mSubTopic, mVal, true); + + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/%d/start", iv->config->name, j); + snprintf(mVal, 40, "%d", iv->lastAlarm[j].start); + publish(mSubTopic, mVal, true); + + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/%d/end", iv->config->name, j); + snprintf(mVal, 40, "%d", iv->lastAlarm[j].end); + publish(mSubTopic, mVal, true); + yield(); + } + } } } @@ -578,7 +598,7 @@ class PubMqtt { uint32_t *mUtcTimestamp, *mUptime; uint32_t mRxCnt, mTxCnt; std::queue mSendList; - std::queue mAlarmList; + std::array mSendAlarm{}; subscriptionCb mSubscriptionCb; bool mLastAnyAvail; bool mZeroValues; diff --git a/src/publisher/pubMqttDefs.h b/src/publisher/pubMqttDefs.h index 088023b7..f926883d 100644 --- a/src/publisher/pubMqttDefs.h +++ b/src/publisher/pubMqttDefs.h @@ -53,9 +53,6 @@ enum { MQTT_DEVICE, MQTT_IP_ADDR, MQTT_STATUS, - MQTT_ALARM, - MQTT_ALARM_START, - MQTT_ALARM_END, MQTT_LWT_ONLINE, MQTT_LWT_OFFLINE, MQTT_ACK_PWR_LMT @@ -77,9 +74,6 @@ const char* const subtopics[] PROGMEM = { "device", "ip_addr", "status", - "alarm", - "alarm_start", - "alarm_end", "connected", "not_connected", "ack_pwr_limit" diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 8843f061..9fc3d3ed 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -98,13 +98,15 @@ class RestApi { else if(path == "setup/networks") getNetworks(root); #endif /* !defined(ETHERNET) */ else if(path == "live") getLive(request,root); - else if(path == "record/info") getRecord(root, InverterDevInform_All); + /*else if(path == "record/info") getRecord(root, InverterDevInform_All); else if(path == "record/alarm") getRecord(root, AlarmData); else if(path == "record/config") getRecord(root, SystemConfigPara); - else if(path == "record/live") getRecord(root, RealTimeRunData_Debug); + else if(path == "record/live") getRecord(root, RealTimeRunData_Debug);*/ else { if(path.substring(0, 12) == "inverter/id/") getInverter(root, request->url().substring(17).toInt()); + else if(path.substring(0, 15) == "inverter/alarm/") + getIvAlarms(root, request->url().substring(20).toInt()); else getNotFound(root, F("http://") + request->host() + F("/api/")); } @@ -155,16 +157,15 @@ class RestApi { void getNotFound(JsonObject obj, String url) { JsonObject ep = obj.createNestedObject("avail_endpoints"); - ep[F("system")] = url + F("system"); - ep[F("statistics")] = url + F("statistics"); - ep[F("inverter/list")] = url + F("inverter/list"); - ep[F("index")] = url + F("index"); - ep[F("setup")] = url + F("setup"); - ep[F("live")] = url + F("live"); - ep[F("record/info")] = url + F("record/info"); - ep[F("record/alarm")] = url + F("record/alarm"); - ep[F("record/config")] = url + F("record/config"); - ep[F("record/live")] = url + F("record/live"); + ep[F("inverter/list")] = url + F("inverter/list"); + ep[F("inverter/id/0")] = url + F("inverter/id/0"); + ep[F("inverter/alarm/0")] = url + F("inverter/alarm/0"); + ep[F("statistics")] = url + F("statistics"); + ep[F("generic")] = url + F("generic"); + ep[F("index")] = url + F("index"); + ep[F("setup")] = url + F("setup"); + ep[F("system")] = url + F("system"); + ep[F("live")] = url + F("live"); } @@ -349,48 +350,70 @@ class RestApi { void getInverter(JsonObject obj, uint8_t id) { Inverter<> *iv = mSys->getInverterByPos(id); - if(NULL != iv) { - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - obj[F("id")] = id; - obj[F("enabled")] = (bool)iv->config->enabled; - obj[F("name")] = String(iv->config->name); - obj[F("serial")] = String(iv->config->serial.u64, HEX); - obj[F("version")] = String(iv->getFwVersion()); - obj[F("power_limit_read")] = ah::round3(iv->actPowerLimit); - obj[F("ts_last_success")] = rec->ts; - obj[F("generation")] = iv->ivGen; - - JsonArray ch = obj.createNestedArray("ch"); - - // AC - uint8_t pos; - obj[F("ch_name")][0] = "AC"; - JsonArray ch0 = ch.createNestedArray(); - if(IV_HMT == iv->ivGen) { - for (uint8_t fld = 0; fld < sizeof(acListHmt); fld++) { - pos = (iv->getPosByChFld(CH0, acListHmt[fld], rec)); - ch0[fld] = (0xff != pos) ? ah::round3(iv->getValue(pos, rec)) : 0.0; - } - } else { - for (uint8_t fld = 0; fld < sizeof(acList); fld++) { - pos = (iv->getPosByChFld(CH0, acList[fld], rec)); + if(NULL == iv) { + obj[F("error")] = F("inverter not found!"); + return; + } + + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + obj[F("id")] = id; + obj[F("enabled")] = (bool)iv->config->enabled; + obj[F("name")] = String(iv->config->name); + obj[F("serial")] = String(iv->config->serial.u64, HEX); + obj[F("version")] = String(iv->getFwVersion()); + obj[F("power_limit_read")] = ah::round3(iv->actPowerLimit); + obj[F("power_limit_ack")] = iv->powerLimitAck; + obj[F("ts_last_success")] = rec->ts; + obj[F("generation")] = iv->ivGen; + + JsonArray ch = obj.createNestedArray("ch"); + + // AC + uint8_t pos; + obj[F("ch_name")][0] = "AC"; + JsonArray ch0 = ch.createNestedArray(); + if(IV_HMT == iv->ivGen) { + for (uint8_t fld = 0; fld < sizeof(acListHmt); fld++) { + pos = (iv->getPosByChFld(CH0, acListHmt[fld], rec)); ch0[fld] = (0xff != pos) ? ah::round3(iv->getValue(pos, rec)) : 0.0; } - } + } else { + for (uint8_t fld = 0; fld < sizeof(acList); fld++) { + pos = (iv->getPosByChFld(CH0, acList[fld], rec)); + ch0[fld] = (0xff != pos) ? ah::round3(iv->getValue(pos, rec)) : 0.0; + } + } - // DC - for(uint8_t j = 0; j < iv->channels; j ++) { - obj[F("ch_name")][j+1] = iv->config->chName[j]; - obj[F("ch_max_pwr")][j+1] = iv->config->chMaxPwr[j]; - JsonArray cur = ch.createNestedArray(); - for (uint8_t fld = 0; fld < sizeof(dcList); fld++) { - pos = (iv->getPosByChFld((j+1), dcList[fld], rec)); - cur[fld] = (0xff != pos) ? ah::round3(iv->getValue(pos, rec)) : 0.0; - } + // DC + for(uint8_t j = 0; j < iv->channels; j ++) { + obj[F("ch_name")][j+1] = iv->config->chName[j]; + obj[F("ch_max_pwr")][j+1] = iv->config->chMaxPwr[j]; + JsonArray cur = ch.createNestedArray(); + for (uint8_t fld = 0; fld < sizeof(dcList); fld++) { + pos = (iv->getPosByChFld((j+1), dcList[fld], rec)); + cur[fld] = (0xff != pos) ? ah::round3(iv->getValue(pos, rec)) : 0.0; } } } + void getIvAlarms(JsonObject obj, uint8_t id) { + Inverter<> *iv = mSys->getInverterByPos(id); + if(NULL == iv) { + obj[F("error")] = F("inverter not found!"); + return; + } + + obj["cnt"] = iv->alarmCnt; + + JsonArray alarm = obj.createNestedArray(F("alarm")); + for(uint8_t i = 0; i < 10; i++) { + alarm[i][F("code")] = iv->lastAlarm[i].code; + alarm[i][F("str")] = iv->getAlarmStr(iv->lastAlarm[i].code); + alarm[i][F("start")] = iv->lastAlarm[i].start; + alarm[i][F("end")] = iv->lastAlarm[i].end; + } + } + void getMqtt(JsonObject obj) { obj[F("broker")] = String(mConfig->mqtt.broker); obj[F("clientId")] = String(mConfig->mqtt.clientId); @@ -563,7 +586,7 @@ class RestApi { } } - void getRecord(JsonObject obj, uint8_t recType) { + /*void getRecord(JsonObject obj, uint8_t recType) { JsonArray invArr = obj.createNestedArray(F("inverter")); Inverter<> *iv; @@ -583,7 +606,7 @@ class RestApi { } } } - } + }*/ bool setCtrl(JsonObject jsonIn, JsonObject jsonOut) { Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]);