Browse Source

0.7.29

* 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
pull/1093/head
lumapu 1 year ago
parent
commit
e5b5972cae
  1. 6
      src/CHANGES.md
  2. 7
      src/app.cpp
  3. 4
      src/app.h
  4. 2
      src/defines.h
  5. 42
      src/hm/hmInverter.h
  6. 23
      src/hm/hmPayload.h
  7. 17
      src/hm/miPayload.h
  8. 35
      src/hms/hmsPayload.h
  9. 76
      src/publisher/pubMqtt.h
  10. 6
      src/publisher/pubMqttDefs.h
  11. 121
      src/web/RestApi.h

6
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

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

4
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
}
}

2
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 {

42
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<alarm_t, 10> 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;

23
src/hm/hmPayload.h

@ -29,7 +29,7 @@ typedef struct {
typedef std::function<void(uint8_t, Inverter<> *)> payloadListenerType;
typedef std::function<void(uint16_t alarmCode, uint32_t start, uint32_t end)> alarmListenerType;
typedef std::function<void(Inverter<> *)> alarmListenerType;
template<class HMSYSTEM, class HMRADIO>
@ -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;

17
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;
};

35
src/hms/hmsPayload.h

@ -30,7 +30,7 @@ typedef struct {
typedef std::function<void(uint8_t, Inverter<> *)> payloadListenerType;
typedef std::function<void(uint16_t alarmCode, uint32_t start, uint32_t end)> alarmListenerType;
typedef std::function<void(Inverter<> *)> alarmListenerType;
template<class HMSYSTEM, class RADIO>
@ -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<InfoCommand>(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;

76
src/publisher/pubMqtt.h

@ -28,13 +28,6 @@
typedef std::function<void(JsonObject)> 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<sendListCmdIv> mSendList;
std::queue<alarm_t> mAlarmList;
std::array<bool, MAX_NUM_INVERTERS> mSendAlarm{};
subscriptionCb mSubscriptionCb;
bool mLastAnyAvail;
bool mZeroValues;

6
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"

121
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")]);

Loading…
Cancel
Save