mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-22 21:36:11 +02:00
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
This commit is contained in:
parent
c59d26d858
commit
e5b5972cae
11 changed files with 199 additions and 136 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 7
|
||||
#define VERSION_PATCH 28
|
||||
#define VERSION_PATCH 29
|
||||
|
||||
//-------------------------------------
|
||||
typedef struct {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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("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");
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
|
@ -349,7 +350,11 @@ class RestApi {
|
|||
|
||||
void getInverter(JsonObject obj, uint8_t id) {
|
||||
Inverter<> *iv = mSys->getInverterByPos(id);
|
||||
if(NULL != iv) {
|
||||
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;
|
||||
|
@ -357,6 +362,7 @@ class RestApi {
|
|||
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;
|
||||
|
||||
|
@ -389,6 +395,23 @@ class RestApi {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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…
Add table
Add a link
Reference in a new issue