* new structure

* slim definitions of fields and units
* prepared multi inverter setup (not finished now)
This commit is contained in:
lumapu 2022-04-24 01:00:06 +02:00
parent 58d79beb8c
commit d0731f7065
17 changed files with 813 additions and 672 deletions

View file

@ -4,12 +4,11 @@
#include "html/h/hoymiles_html.h"
extern String setup_html;
#define DUMMY_RADIO_ID ((uint64_t)0xDEADBEEF01ULL)
//-----------------------------------------------------------------------------
app::app() : Main() {
mHoymiles = new hoymiles();
mDecoder = new hm1200Decode();
mBufCtrl = new CircularBuffer(mBuffer, PACKET_BUFFER_SIZE);
mSendCnt = 0;
mSendTicker = new Ticker();
mFlagSend = false;
@ -19,6 +18,8 @@ app::app() : Main() {
memset(mCmds, 0, sizeof(uint32_t));
memset(mChannelStat, 0, sizeof(uint32_t));
mSys = new HmSystemType();
}
@ -42,10 +43,12 @@ void app::setup(const char *ssid, const char *pwd, uint32_t timeout) {
if(mSettingsValid) {
uint16_t interval;
uint64_t invSerial;
// hoymiles
mEep->read(ADDR_INV0_ADDR, mHoymiles->mAddrBytes, INV_ADDR_LEN);
mEep->read(ADDR_INV0_ADDR, &invSerial);
mEep->read(ADDR_INV_INTERVAL, &interval);
mSys->addInverter("HM1200", invSerial, INV_TYPE_HM1200);
if(interval < 1000)
interval = 1000;
@ -74,10 +77,6 @@ void app::setup(const char *ssid, const char *pwd, uint32_t timeout) {
mMqtt.sendMsg("version", mVersion);
}
else {
memset(mHoymiles->mAddrBytes, 0, 6);
}
mHoymiles->serial2RadioId();
initRadio();
@ -90,26 +89,32 @@ void app::setup(const char *ssid, const char *pwd, uint32_t timeout) {
void app::loop(void) {
Main::loop();
if(!mBufCtrl->empty()) {
if(!mSys->BufCtrl.empty()) {
uint8_t len, rptCnt;
NRF24_packet_t *p = mBufCtrl->getBack();
packet_t *p = mSys->BufCtrl.getBack();
//dumpBuf("RAW ", p->packet, MAX_RF_PAYLOAD_SIZE);
//mHoymiles->dumpBuf("RAW ", p->packet, MAX_RF_PAYLOAD_SIZE);
if(mHoymiles->checkCrc(p->packet, &len, &rptCnt)) {
if(mSys->Radio.checkCrc(p->packet, &len, &rptCnt)) {
// process buffer only on first occurrence
if((0 != len) && (0 == rptCnt)) {
//Serial.println("CMD " + String(p->packet[11], HEX));
//mHoymiles->dumpBuf("Payload ", p->packet, len);
//Serial.println("CMD " + String(*cmd, HEX));
//dumpBuf("Payload ", p->packet, len);
mDecoder->convert(&p->packet[11], len);
uint8_t *cmd = &p->packet[11];
inverter_t *iv = mSys->findInverter(&p->packet[3]);
if(NULL != iv) {
for(uint8_t i = 0; i < iv->listLen; i++) {
if(iv->assign[i].cmdId == *cmd)
mSys->addValue(iv, i, &p->packet[11]);
}
}
if(p->packet[11] == 0x01) mCmds[0]++;
else if(p->packet[11] == 0x02) mCmds[1]++;
else if(p->packet[11] == 0x03) mCmds[2]++;
else if(p->packet[11] == 0x81) mCmds[3]++;
else if(p->packet[11] == 0x84) mCmds[4]++;
else mCmds[5]++;
if(*cmd == 0x01) mCmds[0]++;
else if(*cmd == 0x02) mCmds[1]++;
else if(*cmd == 0x03) mCmds[2]++;
else if(*cmd == 0x81) mCmds[3]++;
else if(*cmd == 0x84) mCmds[4]++;
else mCmds[5]++;
if(p->sendCh == 23) mChannelStat[0]++;
else if(p->sendCh == 40) mChannelStat[1]++;
@ -117,94 +122,72 @@ void app::loop(void) {
else mChannelStat[3]++;
}
}
mBufCtrl->popBack();
mSys->BufCtrl.popBack();
}
if(mFlagSend) {
mFlagSend = false;
uint8_t size = 0;
//if((mSendCnt % 6) == 0)
size = mHoymiles->getTimePacket(mSendBuf, mTimestamp);
/*else if((mSendCnt % 6) == 1)
size = mHoymiles->getCmdPacket(mSendBuf, 0x15, 0x81);
else if((mSendCnt % 6) == 2)
size = mHoymiles->getCmdPacket(mSendBuf, 0x15, 0x80);
else if((mSendCnt % 6) == 3)
size = mHoymiles->getCmdPacket(mSendBuf, 0x15, 0x83);
else if((mSendCnt % 6) == 4)
size = mHoymiles->getCmdPacket(mSendBuf, 0x15, 0x82);
else if((mSendCnt % 6) == 5)
size = mHoymiles->getCmdPacket(mSendBuf, 0x15, 0x84);*/
inverter_t *inv = mSys->getInverterByPos(0);
size = mSys->Radio.getTimePacket(&inv->radioId.u64, mSendBuf, mTimestamp);
//Serial.println("sent packet: #" + String(mSendCnt));
//dumpBuf(mSendBuf, size);
sendPacket(mSendBuf, size);
sendPacket(inv, mSendBuf, size);
mSendCnt++;
}
// mqtt
mMqtt.loop();
//mMqtt.loop();
if(mMqttEvt) {
mMqttEvt = false;
mMqtt.isConnected(true);
/*mMqtt.isConnected(true);
char topic[20], val[10];
for(uint8_t i = 0; i < 4; i++) {
for(uint8_t j = 0; j < 5; j++) {
switch(j) {
default:
sprintf(topic, "ch%d/%s", i, "voltage");
sprintf(val, "%.3f", mDecoder->mData.ch_dc[i/2].u);
break;
case 1:
sprintf(topic, "ch%d/%s", i, "current");
sprintf(val, "%.3f", mDecoder->mData.ch_dc[i].i);
break;
case 2:
sprintf(topic, "ch%d/%s", i, "power");
sprintf(val, "%.3f", mDecoder->mData.ch_dc[i].p);
break;
case 3:
sprintf(topic, "ch%d/%s", i, "yield_day");
sprintf(val, "%.3f", (double)mDecoder->mData.ch_dc[i].y_d);
break;
case 4:
sprintf(topic, "ch%d/%s", i, "yield");
sprintf(val, "%.3f", mDecoder->mData.ch_dc[i].y_t);
break;
for(uint8_t id = 0; id < mSys->getNumInverters(); id++) {
inverter_t *iv = mSys->getInverterByPos(id);
if(NULL != iv) {
for(uint8_t i = 0; i < iv->listLen; i++) {
if(0.0f != mSys->getValue(iv, i)) {
sprintf(topic, "%s/ch%d/%s", iv->name, iv->assign[i].ch, fields[iv->assign[i].fieldId]);
sprintf(val, "%.3f", mSys->getValue(iv, i));
mMqtt.sendMsg(topic, val);
delay(10);
}
}
if(0 != strncmp("0.000", val, 5)) {
mMqtt.sendMsg(topic, val);
delay(10);
}
}*/
// Serial debug
char topic[20], val[10];
for(uint8_t id = 0; id < mSys->getNumInverters(); id++) {
inverter_t *iv = mSys->getInverterByPos(id);
if(NULL != iv) {
for(uint8_t i = 0; i < iv->listLen; i++) {
//if(0.0f != mSys->getValue(iv, i)) {
sprintf(topic, "%s/ch%d/%s", iv->name, iv->assign[i].ch, mSys->getFieldName(iv, i));
sprintf(val, "%.3f %s", mSys->getValue(iv, i), mSys->getUnit(iv, i));
Serial.println(String(topic) + ": " + String(val));
//}
}
}
}
sprintf(val, "%.3f", mDecoder->mData.ch_ac.u);
mMqtt.sendMsg("ac/voltage", val);
delay(10);
sprintf(val, "%.3f", mDecoder->mData.ch_ac.i);
mMqtt.sendMsg("ac/current", val);
delay(10);
sprintf(val, "%.3f", mDecoder->mData.temp);
mMqtt.sendMsg("temperature", val);
delay(10);
}
}
//-----------------------------------------------------------------------------
void app::handleIntr(void) {
uint8_t lostCnt = 0, pipe, len;
NRF24_packet_t *p;
uint8_t pipe, len;
packet_t *p;
DISABLE_IRQ;
while(mRadio->available(&pipe)) {
if(!mBufCtrl->full()) {
p = mBufCtrl->getFront();
if(!mSys->BufCtrl.full()) {
p = mSys->BufCtrl.getFront();
memset(p->packet, 0xcc, MAX_RF_PAYLOAD_SIZE);
p->sendCh = mSendChannel;
len = mRadio->getPayloadSize();
@ -212,13 +195,10 @@ void app::handleIntr(void) {
len = MAX_RF_PAYLOAD_SIZE;
mRadio->read(p->packet, len);
mBufCtrl->pushFront(p);
lostCnt = 0;
mSys->BufCtrl.pushFront(p);
}
else {
bool tx_ok, tx_fail, rx_ready;
if(lostCnt < 255)
lostCnt++;
mRadio->whatHappened(tx_ok, tx_fail, rx_ready); // reset interrupt status
mRadio->flush_rx(); // drop the packet
}
@ -254,27 +234,27 @@ void app::initRadio(void) {
Serial.println("Radio Config:");
mRadio->printPrettyDetails();
mSendChannel = mHoymiles->getDefaultChannel();
mSendChannel = mSys->Radio.getDefaultChannel();
}
//-----------------------------------------------------------------------------
void app::sendPacket(uint8_t buf[], uint8_t len) {
void app::sendPacket(inverter_t *inv, uint8_t buf[], uint8_t len) {
DISABLE_IRQ;
mRadio->stopListening();
#ifdef CHANNEL_HOP
//if(mSendCnt % 6 == 0)
mSendChannel = mHoymiles->getNxtChannel();
mSendChannel = mSys->Radio.getNxtChannel();
//else
// mSendChannel = mHoymiles->getLastChannel();
// mSendChannel = mSys->Radio.getLastChannel();
#else
mSendChannel = mHoymiles->getDefaultChannel();
mSendChannel = mSys->Radio.getDefaultChannel();
#endif
mRadio->setChannel(mSendChannel);
//Serial.println("CH: " + String(mSendChannel));
mRadio->openWritingPipe(mHoymiles->mRadioId);
mRadio->openWritingPipe(inv->radioId.u64);
mRadio->setCRCLength(RF24_CRC_16);
mRadio->enableDynamicPayloads();
mRadio->setAutoAck(true);
@ -329,13 +309,32 @@ void app::showSetup(void) {
// PWD will be left at the default value (for protection)
// -> the PWD will only be changed if it does not match the placeholder "{PWD}"
char addr[20] = {0};
sprintf(addr, "%02X:%02X:%02X:%02X:%02X:%02X", mHoymiles->mAddrBytes[0], mHoymiles->mAddrBytes[1], mHoymiles->mAddrBytes[2], mHoymiles->mAddrBytes[3], mHoymiles->mAddrBytes[4], mHoymiles->mAddrBytes[5]);
html.replace("{INV0_ADDR}", String(addr));
html.replace("{DEVICE}", String(mDeviceName));
html.replace("{VERSION}", String(mVersion));
String inv;
inverter_t *pInv;
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
pInv = mSys->getInverterByPos(i);
inv += "<p class=\"subdes\">Inverter "+ String(i) + "</p>";
inv += "<label for=\"inv" + String(i) + "Addr\">Address</label>";
inv += "<input type=\"text\" class=\"text\" name=\"inv" + String(i) + "Addr\" value=\"";
inv += (NULL != pInv) ? String(mSys->getSerial(pInv), HEX) : "";
inv += "\"/>";
inv += "<label for=\"inv" + String(i) + "Name\">Name</label>";
inv += "<input type=\"text\" class=\"text\" name=\"inv" + String(i) + "Name\" value=\"";
inv += (NULL != pInv) ? String(pInv->name) : "";
inv += "\"/>";
inv += "<label for=\"inv" + String(i) + "Type\">Type</label>";
inv += "<input type=\"text\" class=\"text\" name=\"inv" + String(i) + "Name\" value=\"";
inv += (NULL != pInv) ? String(pInv->type) : "";
inv += "\"/>";
}
html.replace("{INVERTERS}", String(inv));
if(mSettingsValid) {
mEep->read(ADDR_INV_INTERVAL, &interval);
html.replace("{INV_INTERVAL}", String(interval));
@ -402,28 +401,46 @@ void app::showHoymiles(void) {
//-----------------------------------------------------------------------------
void app::showLiveData(void) {
String modHtml = "";
String modHtml = "<pre>";
String unit[5] = {"V", "A", "W", "Wh", "kWh"};
String info[5] = {"VOLTAGE", "CURRENT", "POWER", "YIELD DAY", "YIELD"};
for(uint8_t i = 0; i < 4; i++) {
modHtml += "<div class=\"module\"><span class=\"header\">CHANNEL " + String(i) + "</span>";
for(uint8_t j = 0; j < 5; j++) {
modHtml += "<span class=\"value\">";
switch(j) {
default: modHtml += String(mDecoder->mData.ch_dc[i/2].u); break;
case 1: modHtml += String(mDecoder->mData.ch_dc[i].i); break;
case 2: modHtml += String(mDecoder->mData.ch_dc[i].p); break;
case 3: modHtml += String(mDecoder->mData.ch_dc[i].y_d); break;
case 4: modHtml += String(mDecoder->mData.ch_dc[i].y_t); break;
char topic[20], val[10];
for(uint8_t id = 0; id < mSys->getNumInverters(); id++) {
inverter_t *iv = mSys->getInverterByPos(id);
if(NULL != iv) {
/*uint8_t modNum;
switch(iv->type) {
default: modNum = 1; break;
case INV_TYPE_HM600: modNum = 2; break;
case INV_TYPE_HM1200: modNum = 4; break;
}
for(uint8_t mod = 1; mod <= modNum; mod ++) {
modHtml += "<div class=\"module\"><span class=\"header\">CHANNEL " + String(i) + "</span>";
for(uint8_t j = 0; j < 5; j++) {
modHtml += "<span class=\"value\">";
switch(j) {
default: modHtml += String(mDecoder->mData.ch_dc[i/2].u); break;
case 1: modHtml += String(mDecoder->mData.ch_dc[i].i); break;
case 2: modHtml += String(mDecoder->mData.ch_dc[i].p); break;
case 3: modHtml += String(mDecoder->mData.ch_dc[i].y_d); break;
case 4: modHtml += String(mDecoder->mData.ch_dc[i].y_t); break;
}
modHtml += "<span class=\"unit\">" + unit[j] + "</span></span>";
modHtml += "<span class=\"info\">" + info[j] + "</span>";
}
modHtml += "</div>";
}*/
for(uint8_t i = 0; i < iv->listLen; i++) {
sprintf(topic, "%s/ch%d/%s", iv->name, iv->assign[i].ch, mSys->getFieldName(iv, i));
sprintf(val, "%.3f %s", mSys->getValue(iv, i), mSys->getUnit(iv, i));
modHtml += String(topic) + ": " + String(val) + "\n";
}
modHtml += "<span class=\"unit\">" + unit[j] + "</span></span>";
modHtml += "<span class=\"info\">" + info[j] + "</span>";
}
modHtml += "</div>";
}
modHtml += "</pre>";
mWeb->send(200, "text/html", modHtml);
}
@ -443,20 +460,24 @@ void app::saveValues(bool webSend = true) {
if(mWeb->args() > 0) {
char *p;
char addr[20] = {0};
char buf[20] = {0};
uint8_t i = 0;
uint16_t interval;
// hoymiles
memset(mHoymiles->mAddrBytes, 0, 6);
mWeb->arg("inv0Addr").toCharArray(addr, 20);
p = strtok(addr, ":");
while(NULL != p) {
mHoymiles->mAddrBytes[i++] = strtol(p, NULL, 16);
p = strtok(NULL, ":");
// inverter
serial_u addr;
mWeb->arg("inv0Addr").toCharArray(buf, 20);
addr.u64 = Serial2u64(buf);
mSys->updateSerial(mSys->getInverterByPos(0), addr.u64);
for(uint8_t i = 0; i < 8; i++) {
Serial.print(String(addr.b[i], HEX) + " ");
}
Serial.println();
Serial.println("addr: " + String(addr.u64, HEX));
interval = mWeb->arg("invInterval").toInt();
mEep->write(ADDR_INV0_ADDR, mHoymiles->mAddrBytes, INV_ADDR_LEN);
mEep->write(ADDR_INV0_ADDR, addr.u64);
mEep->write(ADDR_INV_INTERVAL, interval);
@ -465,9 +486,9 @@ void app::saveValues(bool webSend = true) {
char mqttUser[MQTT_USER_LEN];
char mqttPwd[MQTT_PWD_LEN];
char mqttTopic[MQTT_TOPIC_LEN];
mWeb->arg("mqttAddr").toCharArray(addr, 20);
mWeb->arg("mqttAddr").toCharArray(buf, 20);
i = 0;
p = strtok(addr, ".");
p = strtok(buf, ".");
while(NULL != p) {
mqttAddr[i++] = atoi(p);
p = strtok(NULL, ".");
@ -495,14 +516,3 @@ void app::saveValues(bool webSend = true) {
"<p>Error while saving</p></body></html>");
}
}
//-----------------------------------------------------------------------------
void app::dumpBuf(uint8_t buf[], uint8_t len) {
for(uint8_t i = 0; i < len; i ++) {
if((i % 8 == 0) && (i != 0))
Serial.println();
Serial.print(String(buf[i], HEX) + " ");
}
Serial.println();
}