mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-25 14:56:11 +02:00
Merge branch 'development03' into hms
This commit is contained in:
commit
997bfe41e7
11 changed files with 254 additions and 147 deletions
|
@ -2,6 +2,10 @@
|
|||
|
||||
(starting from release version `0.5.66`)
|
||||
|
||||
## 0.5.105
|
||||
* merged MI, thx @rejoe2 #788
|
||||
* fixed reboot message #793
|
||||
|
||||
## 0.5.104
|
||||
* further improved save settings
|
||||
* removed `#` character from ePaper
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 5
|
||||
#define VERSION_PATCH 104
|
||||
#define VERSION_PATCH 105
|
||||
|
||||
//-------------------------------------
|
||||
typedef struct {
|
||||
|
|
|
@ -144,7 +144,10 @@ class Inverter {
|
|||
template <typename T>
|
||||
void enqueCommand(uint8_t cmd) {
|
||||
_commandQueue.push(std::make_shared<T>(cmd));
|
||||
DPRINTLN(DBG_INFO, F("(#") + String(id) + F(") enqueuedCmd: 0x") + String(cmd, HEX));
|
||||
DPRINT(DBG_INFO, F("(#"));
|
||||
DBGPRINT(String(id));
|
||||
DBGPRINT(F(") enqueCommand: 0x"));
|
||||
DHEX(cmd);
|
||||
}
|
||||
|
||||
void setQueuedCmdFinished() {
|
||||
|
|
|
@ -209,7 +209,7 @@ class HmPayload {
|
|||
DBGPRINT(F("accepted power limit set point "));
|
||||
DBGPRINT(String(iv->powerLimit[0]));
|
||||
DBGPRINT(F(" with PowerLimitControl "));
|
||||
DBGPRINT(String(iv->powerLimit[1]));
|
||||
DBGPRINTLN(String(iv->powerLimit[1]));
|
||||
|
||||
iv->clearCmdQueue();
|
||||
iv->enqueCommand<InfoCommand>(SystemConfigPara); // read back power limit
|
||||
|
@ -245,7 +245,9 @@ class HmPayload {
|
|||
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"));
|
||||
DPRINT(DBG_INFO, F("(#"));
|
||||
DBGPRINT(String(iv->id));
|
||||
DPRINTLN(DBG_INFO, F(") retransmit power limit"));
|
||||
mRadio->sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true);
|
||||
} else {
|
||||
if(false == mPayload[iv->id].gotFragment) {
|
||||
|
@ -262,7 +264,9 @@ class HmPayload {
|
|||
} else {
|
||||
for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) {
|
||||
if (mPayload[iv->id].len[i] == 0) {
|
||||
DPRINT(DBG_WARN, F("Frame "));
|
||||
DPRINT(DBG_WARN, F("(#"));
|
||||
DBGPRINT(String(iv->id));
|
||||
DBGPRINT(F(") Frame "));
|
||||
DBGPRINT(String(i + 1));
|
||||
DBGPRINTLN(F(" missing: Request Retransmit"));
|
||||
mRadio->sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true);
|
||||
|
@ -282,15 +286,16 @@ class HmPayload {
|
|||
DPRINT(DBG_INFO, F("(#"));
|
||||
DBGPRINT(String(iv->id));
|
||||
DBGPRINT(F(") prepareDevInformCmd 0x"));
|
||||
DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX));
|
||||
DHEXLN(mPayload[iv->id].txCmd);
|
||||
mRadio->prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true);
|
||||
}
|
||||
} else { // payload complete
|
||||
DPRINT(DBG_INFO, F("procPyld: cmd: 0x"));
|
||||
DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX));
|
||||
DHEXLN(mPayload[iv->id].txCmd);
|
||||
DPRINT(DBG_INFO, F("procPyld: txid: 0x"));
|
||||
DBGPRINTLN(String(mPayload[iv->id].txId, HEX));
|
||||
DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId));
|
||||
DHEXLN(mPayload[iv->id].txId);
|
||||
DPRINTLN(DBG_DEBUG, F("procPyld: max: "));
|
||||
DBGPRINT(String(mPayload[iv->id].maxPackId));
|
||||
record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser
|
||||
mPayload[iv->id].complete = true;
|
||||
|
||||
|
|
|
@ -154,11 +154,12 @@ class HmRadio {
|
|||
mSerialDebug = true;
|
||||
}
|
||||
|
||||
void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit) {
|
||||
void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true) {
|
||||
DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x"));
|
||||
DBGPRINTLN(String(cmd, HEX));
|
||||
initPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME);
|
||||
uint8_t cnt = 10;
|
||||
if (isNoMI) {
|
||||
mTxBuf[cnt++] = cmd; // cmd -> 0 on, 1 off, 2 restart, 11 active power, 12 reactive power, 13 power factor
|
||||
mTxBuf[cnt++] = 0x00;
|
||||
if(cmd >= ActivePowerContr && cmd <= PFSet) { // ActivePowerContr, ReactivePowerContr, PFSet
|
||||
|
@ -167,6 +168,26 @@ class HmRadio {
|
|||
mTxBuf[cnt++] = ((data[1] ) >> 8) & 0xff; // setting for persistens handlings
|
||||
mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling
|
||||
}
|
||||
} else { //MI 2nd gen. specific
|
||||
switch (cmd) {
|
||||
case TurnOn:
|
||||
mTxBuf[9] = 0x55;
|
||||
mTxBuf[10] = 0xaa;
|
||||
break;
|
||||
case TurnOff:
|
||||
mTxBuf[9] = 0xaa;
|
||||
mTxBuf[10] = 0x55;
|
||||
break;
|
||||
case ActivePowerContr:
|
||||
cnt++;
|
||||
mTxBuf[9] = 0x5a;
|
||||
mTxBuf[10] = 0x5a;
|
||||
mTxBuf[11] = data[0]; // power limit
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
sendPacket(invId, cnt, isRetransmit);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,16 +15,17 @@
|
|||
typedef struct {
|
||||
uint32_t ts;
|
||||
bool requested;
|
||||
bool limitrequested;
|
||||
uint8_t txCmd;
|
||||
uint8_t len[MAX_PAYLOAD_ENTRIES];
|
||||
bool complete;
|
||||
bool dataAB[3];
|
||||
bool stsAB[3];
|
||||
uint8_t sts[5];
|
||||
uint16_t sts[6];
|
||||
uint8_t txId;
|
||||
uint8_t invId;
|
||||
uint8_t retransmits;
|
||||
uint8_t skipfirstrepeat;
|
||||
//uint8_t skipfirstrepeat;
|
||||
bool gotFragment;
|
||||
/*
|
||||
uint8_t data[MAX_PAYLOAD_ENTRIES][MAX_RF_PAYLOAD_SIZE];
|
||||
|
@ -48,7 +49,8 @@ class MiPayload {
|
|||
mMaxRetrans = maxRetransmits;
|
||||
mTimestamp = timestamp;
|
||||
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
|
||||
reset(i);
|
||||
reset(i, true);
|
||||
mPayload[i].limitrequested = true;
|
||||
}
|
||||
mSerialDebug = false;
|
||||
mHighPrioIv = NULL;
|
||||
|
@ -68,7 +70,7 @@ class MiPayload {
|
|||
}
|
||||
|
||||
void loop() {
|
||||
if(NULL != mHighPrioIv) {
|
||||
if(NULL != mHighPrioIv) { // && mHighPrioIv->ivGen == IV_MI) {
|
||||
ivSend(mHighPrioIv, true); // for devcontrol commands?
|
||||
mHighPrioIv = NULL;
|
||||
}
|
||||
|
@ -118,23 +120,34 @@ class MiPayload {
|
|||
if (mSerialDebug) {
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
DBGPRINT(F("Devcontrol request 0x"));
|
||||
DBGPRINT(String(iv->devControlCmd, HEX));
|
||||
DHEX(iv->devControlCmd);
|
||||
DBGPRINT(F(" power limit "));
|
||||
DBGPRINTLN(String(iv->powerLimit[0]));
|
||||
}
|
||||
mRadio->sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false);
|
||||
mRadio->sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false, false);
|
||||
mPayload[iv->id].txCmd = iv->devControlCmd;
|
||||
//iv->clearCmdQueue();
|
||||
//iv->enqueCommand<InfoCommand>(SystemConfigPara); // read back power limit
|
||||
mPayload[iv->id].limitrequested = true;
|
||||
|
||||
iv->clearCmdQueue();
|
||||
iv->enqueCommand<InfoCommand>(SystemConfigPara); // try to read back power limit
|
||||
} else {
|
||||
uint8_t cmd = iv->getQueuedCmd();
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
DBGPRINT(F("prepareDevInformCmd 0x"));
|
||||
DBGPRINTLN(String(cmd, HEX));
|
||||
DHEXLN(cmd);
|
||||
uint8_t cmd2 = cmd;
|
||||
if (cmd == 0x1 ) { //0x1
|
||||
cmd = 0x0f;
|
||||
cmd2 = 0x00;
|
||||
if ( cmd == SystemConfigPara ) { //0x05 for HM-types
|
||||
if (!mPayload[iv->id].limitrequested) { // only do once at startup
|
||||
iv->setQueuedCmdFinished();
|
||||
cmd = iv->getQueuedCmd();
|
||||
} else {
|
||||
mPayload[iv->id].limitrequested = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == 0x01 || cmd == SystemConfigPara ) { //0x1 and 0x05 for HM-types
|
||||
cmd = 0x0f; // for MI, these seem to make part of the Polling the device software and hardware version number command
|
||||
cmd2 = cmd == SystemConfigPara ? 0x01 : 0x00; //perhaps we can only try to get second frame?
|
||||
mRadio->sendCmdPacket(iv->radioId.u64, cmd, cmd2, false);
|
||||
} else {
|
||||
mRadio->prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd);
|
||||
|
@ -157,7 +170,6 @@ class MiPayload {
|
|||
|
||||
void add(Inverter<> *iv, packet_t *p) {
|
||||
//DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX));
|
||||
|
||||
if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09
|
||||
miStsDecode(iv, p);
|
||||
}
|
||||
|
@ -218,13 +230,34 @@ const byteAssign_t InfoAssignment[] = {
|
|||
for (uint8_t i = 0; i < 5; i++) {
|
||||
iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1);
|
||||
}
|
||||
/*iv->setQueuedCmdFinished();
|
||||
mStat->rxSuccess++;
|
||||
mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/
|
||||
} else if ( p->packet[9] == 0x01 ) {//second frame
|
||||
iv->isConnected = true;
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
DPRINT(DBG_INFO,F("HW_VER is "));
|
||||
DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25]));
|
||||
/*iv->setQueuedCmdFinished();
|
||||
mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/
|
||||
} else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
if ( p->packet[9] == 0x01 ) {
|
||||
DBGPRINTLN(F("got 2nd frame (hw info)"));
|
||||
//mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false);
|
||||
} else {
|
||||
DBGPRINTLN(F("3rd gen. inverter!")); // see table in OpenDTU code, DevInfoParser.cpp devInfo[]
|
||||
}
|
||||
// xlsx: HW_ECapValue is total energy?!? (data coll. inst. #154)
|
||||
DPRINT(DBG_INFO,F("HW_PartNo "));
|
||||
DBGPRINTLN(String((uint32_t) (((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13]));
|
||||
//DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13]));
|
||||
if ( p->packet[9] == 0x01 ) {
|
||||
DPRINT(DBG_INFO,F("HW_ECapValue "));
|
||||
DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21]));
|
||||
iv->setValue(iv->getPosByChFld(0, FLD_YT, rec), rec, (float) ((p->packet[20] << 8) + p->packet[21])/1);
|
||||
DPRINT(DBG_INFO,F("HW_FB_TLmValue "));
|
||||
DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15]));
|
||||
DPRINT(DBG_INFO,F("HW_FB_ReSPRT "));
|
||||
DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17]));
|
||||
DPRINT(DBG_INFO,F("HW_GridSamp_ResValule "));
|
||||
DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19]));
|
||||
}
|
||||
} else if ( p->packet[9] == 0x12 ) {//3rd frame
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
DBGPRINTLN(F("got 3rd frame (hw info)"));
|
||||
|
@ -232,20 +265,26 @@ const byteAssign_t InfoAssignment[] = {
|
|||
mStat->rxSuccess++;
|
||||
}
|
||||
|
||||
} else if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command
|
||||
} else if ( p->packet[0] == (TX_REQ_INFO + ALL_FRAMES) // response from get information command
|
||||
|| (p->packet[0] == 0xB6 && mPayload[iv->id].txCmd != 0x36)) { // strange short response from MI-1500 3rd gen; might be missleading!
|
||||
// atm, we just do nothing else than print out what we got...
|
||||
// for decoding see xls- Data collection instructions - #147ff
|
||||
mPayload[iv->id].txId = p->packet[0];
|
||||
//mPayload[iv->id].txId = p->packet[0];
|
||||
DPRINTLN(DBG_DEBUG, F("Response from info request received"));
|
||||
uint8_t *pid = &p->packet[9];
|
||||
if (*pid == 0x00) {
|
||||
DPRINT(DBG_DEBUG, F("fragment number zero received"));
|
||||
|
||||
iv->setQueuedCmdFinished();
|
||||
} //else {
|
||||
DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX));
|
||||
/*
|
||||
if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) {
|
||||
} else if (p->packet[9] == 0x81) { // might need some additional check, as this is only ment for short answers!
|
||||
DPRINT(DBG_WARN, F("(#"));
|
||||
DBGPRINT(String(iv->id));
|
||||
DBGPRINTLN(F(") seems to use 3rd gen. protocol - switching ivGen!"));
|
||||
iv->ivGen = IV_HM;
|
||||
iv->setQueuedCmdFinished();
|
||||
iv->clearCmdQueue();
|
||||
//DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX));
|
||||
/* (old else-tree)
|
||||
if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) {^
|
||||
memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], p->len - 11);
|
||||
mPayload[iv->id].len[(*pid & 0x7F) - 1] = p->len - 11;
|
||||
mPayload[iv->id].gotFragment = true;
|
||||
|
@ -257,34 +296,36 @@ const byteAssign_t InfoAssignment[] = {
|
|||
if (*pid > 0x81)
|
||||
mPayload[iv->id].lastFound = true;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
} */
|
||||
} else if (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
|
||||
|| p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES -1)) { // response from DRED instruction
|
||||
DPRINTHEAD(DBG_DEBUG, iv->id);
|
||||
DBGPRINTLN(F("Response from devcontrol request received"));
|
||||
|
||||
mPayload[iv->id].txId = p->packet[0];
|
||||
iv->clearDevControlRequest();
|
||||
|
||||
if ((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) {
|
||||
String msg = "";
|
||||
if((p->packet[10] == 0x00) && (p->packet[11] == 0x00))
|
||||
if ((p->packet[9] == 0x5a) && (p->packet[10] == 0x5a)) {
|
||||
mApp->setMqttPowerLimitAck(iv);
|
||||
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]));
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
DBGPRINTLN(F("has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1]));
|
||||
DBGPRINT(F("has accepted power limit set point "));
|
||||
DBGPRINT(String(iv->powerLimit[0]));
|
||||
DBGPRINT(F(" with PowerLimitControl "));
|
||||
DBGPRINTLN(String(iv->powerLimit[1]));
|
||||
|
||||
iv->clearCmdQueue();
|
||||
iv->enqueCommand<InfoCommand>(SystemConfigPara); // read back power limit
|
||||
}
|
||||
iv->devControlCmd = Init;
|
||||
} else { // some other response; copied from hmPayload:process; might not be correct to do that here!!!
|
||||
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));
|
||||
DPRINT(DBG_INFO, F("procPyld: cmd: 0x"));
|
||||
DHEXLN(mPayload[iv->id].txCmd);
|
||||
DPRINT(DBG_INFO, F("procPyld: txid: 0x"));
|
||||
DHEXLN(mPayload[iv->id].txId);
|
||||
//DPRINT(DBG_DEBUG, F("procPyld: max: "));
|
||||
//DBGPRINTLN(String(mPayload[iv->id].maxPackId));
|
||||
record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser
|
||||
mPayload[iv->id].complete = true;
|
||||
|
||||
|
@ -366,10 +407,10 @@ const byteAssign_t InfoAssignment[] = {
|
|||
|
||||
//delayed next message?
|
||||
//mPayload[iv->id].skipfirstrepeat++;
|
||||
if (mPayload[iv->id].skipfirstrepeat) {
|
||||
mPayload[iv->id].skipfirstrepeat = 0; //reset counter*/
|
||||
/*if (mPayload[iv->id].skipfirstrepeat) {
|
||||
mPayload[iv->id].skipfirstrepeat = 0; //reset counter
|
||||
continue; // skip to next inverter
|
||||
}
|
||||
}*/
|
||||
|
||||
if (!mPayload[iv->id].complete) {
|
||||
//DPRINTLN(DBG_INFO, F("Pyld incompl code")); //info for testing only
|
||||
|
@ -385,7 +426,7 @@ const byteAssign_t InfoAssignment[] = {
|
|||
} else if(iv->devControlCmd == ActivePowerContr) {
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
DBGPRINTLN(F("retransmit power limit"));
|
||||
mRadio->sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true);
|
||||
mRadio->sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true, false);
|
||||
} else {
|
||||
uint8_t cmd = mPayload[iv->id].txCmd;
|
||||
if (mPayload[iv->id].retransmits < mMaxRetrans) {
|
||||
|
@ -424,11 +465,14 @@ const byteAssign_t InfoAssignment[] = {
|
|||
}
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
if (change) {
|
||||
DBGPRINT(F("next request is 0x"));
|
||||
DBGPRINT(F("next request is"));
|
||||
//mPayload[iv->id].skipfirstrepeat = 0;
|
||||
} else {
|
||||
DBGPRINT(F("not complete: Request Retransmit 0x"));
|
||||
DBGPRINT(F("sth."));
|
||||
DBGPRINT(F(" missing: Request Retransmit"));
|
||||
}
|
||||
DBGPRINTLN(String(cmd, HEX));
|
||||
DBGPRINT(F(" 0x"));
|
||||
DHEXLN(cmd);
|
||||
//mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd, true);
|
||||
mRadio->prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, true, cmd);
|
||||
mPayload[iv->id].txCmd = cmd;
|
||||
|
@ -445,7 +489,8 @@ const byteAssign_t InfoAssignment[] = {
|
|||
mPayload[iv->id].txCmd = iv->getQueuedCmd();
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
|
||||
DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX));
|
||||
DBGPRINT(F("prepareDevInformCmd 0x"));
|
||||
DHEXLN(mPayload[iv->id].txCmd);
|
||||
mRadio->prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true);
|
||||
}
|
||||
}
|
||||
|
@ -455,16 +500,6 @@ const byteAssign_t InfoAssignment[] = {
|
|||
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
|
||||
mPayload[iv->id].complete = true;
|
||||
uint8_t ac_pow = 0;
|
||||
//if (mPayload[iv->id].sts[0] == 3) {
|
||||
ac_pow = calcPowerDcCh0(iv, 0)*9.5;
|
||||
//}
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser
|
||||
iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10));
|
||||
DPRINTLN(DBG_INFO, F("process: compl. set of msgs detected"));
|
||||
iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0));
|
||||
iv->doCalculations();
|
||||
//uint8_t payload[128];
|
||||
//uint8_t payloadLen = 0;
|
||||
//memset(payload, 0, 128);
|
||||
|
@ -526,30 +561,67 @@ const byteAssign_t InfoAssignment[] = {
|
|||
rec->ts = mPayload[iv->id].ts;
|
||||
mPayload[iv->id].gotFragment = true;
|
||||
mPayload[iv->id].txId = p->packet[0];
|
||||
|
||||
//uint8_t status = (p->packet[11] << 8) + p->packet[12];
|
||||
uint8_t status = (p->packet[9] << 8) + p->packet[10];
|
||||
//uint8_t stschan = p->packet[0] == 0x88 ? CH1 : CH2;
|
||||
mPayload[iv->id].sts[stschan] = status;
|
||||
miStsConsolidate(iv, stschan, rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]);
|
||||
mPayload[iv->id].stsAB[stschan] = true;
|
||||
if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2])
|
||||
mPayload[iv->id].stsAB[CH0] = true;
|
||||
if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) {
|
||||
mPayload[iv->id].sts[0] = status;
|
||||
iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status);
|
||||
//mPayload[iv->id].skipfirstrepeat = 1;
|
||||
if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) {
|
||||
miComplete(iv);
|
||||
}
|
||||
}
|
||||
|
||||
void miStsConsolidate(Inverter<> *iv, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) {
|
||||
//uint8_t status = (p->packet[11] << 8) + p->packet[12];
|
||||
uint16_t status = 3; // regular status for MI, change to 1 later?
|
||||
if ( uState < 3 ) {
|
||||
status = uState*100 + stschan; //first approach, needs review!
|
||||
if (lState)
|
||||
status += lState*10;
|
||||
} else if ( uState > 3 ) {
|
||||
status = uState*1000 + uEnum*10;
|
||||
if (lState)
|
||||
status += lState*100; //needs review, esp. for 4ch-8310 state!
|
||||
//if (lEnum)
|
||||
status += lEnum;
|
||||
if (uEnum < 6) {
|
||||
status += stschan;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t prntsts = status == 3 ? 1 : status;
|
||||
if ( status != mPayload[iv->id].sts[stschan] ) { //sth.'s changed?
|
||||
mPayload[iv->id].sts[stschan] = status;
|
||||
DPRINT(DBG_WARN, F("Status change for CH"));
|
||||
DBGPRINT(String(stschan)); DBGPRINT(F(": "));
|
||||
DBGPRINTLN(iv->getAlarmStr(prntsts));
|
||||
}
|
||||
|
||||
if ( !mPayload[iv->id].sts[0] || prntsts < mPayload[iv->id].sts[0] ) {
|
||||
mPayload[iv->id].sts[0] = prntsts;
|
||||
iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts);
|
||||
}
|
||||
|
||||
if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){
|
||||
iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!?
|
||||
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex));
|
||||
iv->enqueCommand<InfoCommand>(AlarmData);
|
||||
DBGPRINT(F("alarm ID incremented to "));
|
||||
DBGPRINTLN(String(iv->alarmMesIndex));
|
||||
}
|
||||
//mPayload[iv->id].skipfirstrepeat = 1;
|
||||
if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) {
|
||||
miComplete(iv);
|
||||
/*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)
|
||||
break;
|
||||
if (NULL != mCbAlarm)
|
||||
(mCbAlarm)(code, start, end);
|
||||
yield();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void miDataDecode(Inverter<> *iv, packet_t *p) {
|
||||
|
@ -594,12 +666,14 @@ const byteAssign_t InfoAssignment[] = {
|
|||
FCODE = (uint8_t)(p->packet[27]);
|
||||
}*/
|
||||
|
||||
uint8_t status = (uint8_t)(p->packet[23]);
|
||||
/*uint16_t status = (uint8_t)(p->packet[23]);
|
||||
mPayload[iv->id].sts[datachan] = status;
|
||||
if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) {
|
||||
mPayload[iv->id].sts[0] = status;
|
||||
iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status);
|
||||
}
|
||||
}*/
|
||||
miStsConsolidate(iv, datachan, rec, p->packet[23], p->packet[24]);
|
||||
|
||||
|
||||
if (p->packet[0] < (0x39 + ALL_FRAMES) ) {
|
||||
/*uint8_t cmd = p->packet[0] - ALL_FRAMES + 1;
|
||||
|
@ -615,14 +689,13 @@ const byteAssign_t InfoAssignment[] = {
|
|||
mPayload[iv->id].complete = true;
|
||||
}
|
||||
|
||||
//iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, calcMiSts(iv));yield();
|
||||
if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){
|
||||
/*if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){
|
||||
iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)];
|
||||
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex));
|
||||
//iv->enqueCommand<InfoCommand>(AlarmData);
|
||||
}
|
||||
DBGPRINT_TXT(TXT_INCRALM);
|
||||
DBGPRINTLN(String(iv->alarmMesIndex));
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
|
@ -652,8 +725,11 @@ const byteAssign_t InfoAssignment[] = {
|
|||
}
|
||||
|
||||
void miComplete(Inverter<> *iv) {
|
||||
if (mPayload[iv->id].complete)
|
||||
return; //if we got second message as well in repreated attempt
|
||||
mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short...
|
||||
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs"));
|
||||
DPRINTHEAD(DBG_INFO, iv->id);
|
||||
DBGPRINTLN(F("got all msgs"));
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0));
|
||||
|
||||
|
@ -677,6 +753,7 @@ const byteAssign_t InfoAssignment[] = {
|
|||
|
||||
bool build(uint8_t id, bool *complete) {
|
||||
DPRINTLN(DBG_VERBOSE, F("build"));
|
||||
//DPRINTLN_TXT(DBG_VERBOSE, TXT_BUILD);
|
||||
/*uint16_t crc = 0xffff, crcRcv = 0x0000;
|
||||
if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES)
|
||||
mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES;
|
||||
|
@ -706,14 +783,7 @@ const byteAssign_t InfoAssignment[] = {
|
|||
return true;
|
||||
}
|
||||
|
||||
/* void miDPRINTHead(uint8_t lvl, uint8_t id) {
|
||||
DPRINT(lvl, F("(#"));
|
||||
DBGPRINT(String(id));
|
||||
DBGPRINT(F(") "));
|
||||
}*/
|
||||
|
||||
void reset(uint8_t id) {
|
||||
//DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id));
|
||||
void reset(uint8_t id, bool clrSts = false) {
|
||||
DPRINTHEAD(DBG_INFO, id);
|
||||
DBGPRINTLN(F("resetPayload"));
|
||||
memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES);
|
||||
|
@ -729,14 +799,17 @@ const byteAssign_t InfoAssignment[] = {
|
|||
mPayload[id].stsAB[CH1] = true; //required for 1CH and 2CH devices
|
||||
mPayload[id].stsAB[CH2] = true; //only required for 2CH devices
|
||||
mPayload[id].txCmd = 0;
|
||||
mPayload[id].skipfirstrepeat = 0;
|
||||
//mPayload[id].skipfirstrepeat = 0;
|
||||
mPayload[id].requested = false;
|
||||
mPayload[id].ts = *mTimestamp;
|
||||
mPayload[id].sts[0] = 0;
|
||||
if (clrSts) { // only clear channel states at startup
|
||||
mPayload[id].sts[CH1] = 0;
|
||||
mPayload[id].sts[CH2] = 0;
|
||||
mPayload[id].sts[CH3] = 0;
|
||||
mPayload[id].sts[CH4] = 0;
|
||||
mPayload[id].sts[5] = 0; //remember last summarized state
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -60,6 +60,11 @@
|
|||
mCb(String(b, HEX));
|
||||
}
|
||||
}
|
||||
|
||||
inline void DHEXLN(uint8_t b) {
|
||||
DHEX(b);
|
||||
DBGPRINT(F("\r\n"));
|
||||
}
|
||||
/*inline void DHEX(uint16_t b) {
|
||||
if( b<0x10 ) DSERIAL.print(F("000"));
|
||||
else if( b<0x100 ) DSERIAL.print(F("00"));
|
||||
|
@ -160,36 +165,6 @@
|
|||
}\
|
||||
})
|
||||
|
||||
// available text variables
|
||||
#define TXT_NOPYLD 1
|
||||
#define TXT_INVSERNO 2
|
||||
#define TXT_GDEVINF 3
|
||||
#define TXT_DEVCTRL 4
|
||||
#define TXT_INCRALM 5
|
||||
|
||||
|
||||
#define DBGPRINT_TXT(text) ({\
|
||||
switch(text) {\
|
||||
case TXT_NOPYLD: DBGPRINT(F("no Payload received! (retransmits: ")); break; \
|
||||
case TXT_INVSERNO: DBGPRINT(F("Requesting Inv SN ")); break; \
|
||||
case TXT_GDEVINF: DBGPRINT(F("prepareDevInformCmd 0x")); break; \
|
||||
case TXT_DEVCTRL: DBGPRINT(F("Devcontrol request 0x")); break; \
|
||||
case TXT_INCRALM: DBGPRINT(F("alarm ID incremented to ")); break; \
|
||||
default: ; break; \
|
||||
}\
|
||||
})
|
||||
|
||||
// available text variables w. lf
|
||||
#define TXT_TIMEOUT 1
|
||||
#define TXT_NOPYLD2 2
|
||||
|
||||
#define DBGPRINTLN_TXT(text) ({\
|
||||
switch(text) {\
|
||||
case TXT_TIMEOUT: DBGPRINT(F("enqueued cmd failed/timeout\r\n")); break; \
|
||||
case TXT_NOPYLD2: DBGPRINT(F("nothing received\r\n")); break; \
|
||||
default: ; break; \
|
||||
}\
|
||||
})
|
||||
|
||||
/*class ahoyLog {
|
||||
public:
|
||||
|
|
|
@ -80,6 +80,7 @@ class RestApi {
|
|||
String path = request->url().substring(5);
|
||||
if(path == "html/system") getHtmlSystem(root);
|
||||
else if(path == "html/logout") getHtmlLogout(root);
|
||||
else if(path == "html/reboot") getHtmlReboot(root);
|
||||
else if(path == "html/save") getHtmlSave(root);
|
||||
else if(path == "system") getSysInfo(root);
|
||||
else if(path == "generic") getGeneric(root);
|
||||
|
@ -265,6 +266,13 @@ class RestApi {
|
|||
obj[F("html")] = F("succesfully logged out");
|
||||
}
|
||||
|
||||
void getHtmlReboot(JsonObject obj) {
|
||||
getGeneric(obj.createNestedObject(F("generic")));
|
||||
obj[F("refresh")] = 20;
|
||||
obj[F("refresh_url")] = "/";
|
||||
obj[F("html")] = F("rebooting ...");
|
||||
}
|
||||
|
||||
void getHtmlSave(JsonObject obj) {
|
||||
getGeneric(obj.createNestedObject(F("generic")));
|
||||
obj["pending"] = (bool)mApp->getSavePending();
|
||||
|
|
|
@ -9,7 +9,10 @@ import subprocess
|
|||
|
||||
|
||||
def get_git_sha():
|
||||
try:
|
||||
return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode('ascii').strip()
|
||||
except:
|
||||
return "0000000"
|
||||
|
||||
def readVersion(path):
|
||||
f = open(path, "r")
|
||||
|
|
|
@ -327,7 +327,7 @@ class Web {
|
|||
|
||||
mProtected = true;
|
||||
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len);
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len);
|
||||
response->addHeader(F("Content-Encoding"), "gzip");
|
||||
request->send(response);
|
||||
}
|
||||
|
@ -375,7 +375,7 @@ class Web {
|
|||
|
||||
void onReboot(AsyncWebServerRequest *request) {
|
||||
mApp->setRebootFlag();
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len);
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len);
|
||||
response->addHeader(F("Content-Encoding"), "gzip");
|
||||
request->send(response);
|
||||
}
|
||||
|
@ -600,7 +600,7 @@ class Web {
|
|||
|
||||
mApp->saveSettings((request->arg("reboot") == "on"));
|
||||
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len);
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, save_html_len);
|
||||
response->addHeader(F("Content-Encoding"), "gzip");
|
||||
request->send(response);
|
||||
}
|
||||
|
|
15
tools/rpi/Dockerfile
Normal file
15
tools/rpi/Dockerfile
Normal file
|
@ -0,0 +1,15 @@
|
|||
############################
|
||||
# build executable binary
|
||||
############################
|
||||
|
||||
FROM python:slim-bullseye
|
||||
|
||||
COPY . /hoymiles
|
||||
WORKDIR /hoymiles
|
||||
|
||||
RUN python3 -m pip install pyrf24 influxdb_client && \
|
||||
python3 -m pip list #watch for RF24 module - if its there its installed
|
||||
|
||||
RUN pip install crcmod pyyaml paho-mqtt SunTimes
|
||||
|
||||
CMD python3 -um hoymiles --log-transactions --verbose --config /etc/ahoy.yml
|
Loading…
Add table
Add a link
Reference in a new issue